Initial commit: HMDesignSystem baseline
This commit is contained in:
commit
b6a0a61103
486 files changed
+68432
No files matched your search
@@ -0,0 +1,70 @@
|
||||
export function decorateHanmacNavigation(api) {
|
||||
let frame;
|
||||
const write = (node, key, value) => {
|
||||
const next = String(value);
|
||||
if (node.getAttribute(key) !== next) node.setAttribute(key, next);
|
||||
};
|
||||
const ancestors = (entry, refId) => {
|
||||
const result = [];
|
||||
const seen = new Set();
|
||||
while (entry?.parent && !seen.has(entry.parent)) {
|
||||
seen.add(entry.parent);
|
||||
entry = api.resolveStory(entry.parent, refId);
|
||||
if (entry) result.push(entry);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const decorate = () => {
|
||||
frame = undefined;
|
||||
const tree = document.querySelector('#storybook-explorer-tree');
|
||||
if (!tree) return;
|
||||
const selected = api.getCurrentStoryData();
|
||||
const currentParents = new Set(ancestors(selected, selected?.refId).map((item) => item.id));
|
||||
const rows = [...tree.querySelectorAll('[data-item-id]')];
|
||||
const rendered = new Set(rows.map((row) => `${row.dataset.refId}:${row.dataset.itemId}`));
|
||||
const groups = new Map();
|
||||
let section = 0;
|
||||
for (const row of rows) {
|
||||
const refId = row.dataset.refId === 'storybook_internal' ? undefined : row.dataset.refId;
|
||||
const entry = api.resolveStory(row.dataset.itemId, refId);
|
||||
if (!entry) continue;
|
||||
// Visual depth = rendered ancestors. A component with a single story of its own name is hoisted by Storybook (the
|
||||
// story replaces it at depth 1), while the API still reports the story at depth 2.
|
||||
write(row, 'data-hm-depth', ancestors(entry, refId).filter((item) => rendered.has(`${row.dataset.refId}:${item.id}`)).length);
|
||||
write(row, 'data-hm-current-parent', currentParents.has(entry.id) && refId === selected?.refId);
|
||||
if (entry.type === 'root') {
|
||||
write(row, 'data-hm-section', section++);
|
||||
continue;
|
||||
}
|
||||
// A single overlay covers the whole expanded branch, including deeper rows.
|
||||
const branch = [...ancestors(entry, refId).reverse(), entry].find((item) => item.type !== 'root');
|
||||
const owner = rows.find((candidate) => candidate.dataset.itemId === branch?.id && candidate.dataset.refId === row.dataset.refId);
|
||||
const expanded = owner?.querySelector(':scope > button[aria-expanded="true"]');
|
||||
write(row, 'data-hm-group', !!expanded);
|
||||
write(row, 'data-hm-group-start', false);
|
||||
write(row, 'data-hm-group-end', false);
|
||||
if (expanded) {
|
||||
const key = `${row.dataset.refId}:${branch.id}`;
|
||||
if (!groups.has(key)) groups.set(key, []);
|
||||
groups.get(key).push(row);
|
||||
}
|
||||
}
|
||||
for (const members of groups.values()) {
|
||||
write(members[0], 'data-hm-group-start', true);
|
||||
write(members.at(-1), 'data-hm-group-end', true);
|
||||
}
|
||||
};
|
||||
const schedule = () => { if (frame === undefined) frame = requestAnimationFrame(decorate); };
|
||||
const observer = new MutationObserver(schedule);
|
||||
observer.observe(document.body, {
|
||||
childList: true, subtree: true, attributes: true,
|
||||
attributeFilter: ['data-selected', 'aria-expanded', 'data-item-id'],
|
||||
});
|
||||
schedule();
|
||||
window.addEventListener('pagehide', () => {
|
||||
observer.disconnect();
|
||||
if (frame !== undefined) cancelAnimationFrame(frame);
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user