feat(org-chart): implement expandable layout and multi-company navigation
Integrate P5-1B through P5-4 shared Core layout, collapse, zoom/pan/fit, company roots and keyboard accessibility. Include React/HTML examples, virtual 20/100/300 employee fixtures, focused checks and the additive data contract.
This commit is contained in:
1 parent
a92913d6bc
commit
064517ec46
30 files changed
+7532
-183
No files matched your search
@@ -1,92 +1,195 @@
|
||||
/* P5-1A flow preview only. Every rule is under the new presenter namespace;
|
||||
the fixed Workdesk composition and approved card internals stay unchanged.
|
||||
Ordinary flex wrapping is not the P5-1B automatic hierarchy layout. */
|
||||
/* Auto-only layout. P5-4 retains the current card geometry by user decision;
|
||||
no external SVG reconstruction is required for this presentation. */
|
||||
.hm-orgchart-expanded {
|
||||
--hm-orgchart-expanded-sibling-gap: var(--hm-orgchart-resolved-spacing-xxl);
|
||||
--hm-orgchart-expanded-level-gap: calc(2 * var(--hm-orgchart-resolved-spacing-xxl));
|
||||
--hm-orgchart-expanded-title-gap: var(--hm-orgchart-resolved-spacing-md);
|
||||
--hm-orgchart-expanded-employee-gap: var(--hm-orgchart-resolved-spacing-md);
|
||||
--hm-orgchart-expanded-line-width: var(--hm-orgchart-resolved-border-width);
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: var(--hm-orgchart-resolved-spacing-sm);
|
||||
gap: var(--hm-orgchart-resolved-spacing-lg);
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: var(--hm-orgchart-resolved-spacing-lg);
|
||||
background: var(--hm-orgchart-resolved-bg-content);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-heading { margin: 0; }
|
||||
.hm-orgchart-expanded .hm-orgchart-expanded-stage-note {
|
||||
margin: 0;
|
||||
color: var(--hm-orgchart-resolved-fg-primary);
|
||||
font-weight: var(--hm-orgchart-resolved-font-weight-bold);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-expanded-description {
|
||||
margin: 0;
|
||||
color: var(--hm-orgchart-resolved-fg-secondary);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-expanded-top-leaders {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: var(--hm-orgchart-resolved-spacing-lg);
|
||||
padding: var(--hm-orgchart-resolved-spacing-lg) 0;
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-viewport {
|
||||
padding: var(--hm-orgchart-resolved-spacing-lg);
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
height: clamp(320px, 65vh, 800px);
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
touch-action: none;
|
||||
cursor: grab;
|
||||
background: var(--hm-orgchart-resolved-bg-surface);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-forest {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: max-content;
|
||||
min-width: 0;
|
||||
transform-origin: 0 0;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
gap: var(--hm-orgchart-resolved-spacing-xxl);
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
gap: var(--hm-orgchart-expanded-sibling-gap);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-tree { flex: 0 0 auto; }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart { min-width: 0; padding: 0; }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .hierarchy:has(> .node[data-depth]) > .nodes {
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] {
|
||||
vertical-align: top;
|
||||
width: max-content;
|
||||
min-width: 146px;
|
||||
margin: 0;
|
||||
min-width: var(--hm-orgchart-resolved-card-width-leader);
|
||||
margin: 0 calc(var(--hm-orgchart-expanded-sibling-gap) / 2) var(--hm-orgchart-expanded-level-gap);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-organization {
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] > .hm-orgchart-organization {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
gap: var(--hm-orgchart-expanded-title-gap);
|
||||
width: max-content;
|
||||
min-width: var(--hm-orgchart-resolved-card-width-leader);
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
position: relative;
|
||||
}
|
||||
/* Same approved 1Depth title geometry; color resolves from the auto-only
|
||||
company variables supplied by the shared node decorator. */
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-organization-name {
|
||||
align-self: stretch;
|
||||
min-width: 146px;
|
||||
height: 36px;
|
||||
min-height: 36px;
|
||||
margin: 0;
|
||||
padding: 0 12px;
|
||||
background: var(--hm-orgchart-current-gradient);
|
||||
color: var(--hm-orgchart-resolved-on-action-primary);
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 36px;
|
||||
height: auto;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
background: var(--hm-orgchart-expanded-primary);
|
||||
color: var(--hm-orgchart-expanded-title-ink);
|
||||
font-size: var(--hm-orgchart-resolved-font-size-base);
|
||||
font-weight: var(--hm-orgchart-resolved-font-weight-bold);
|
||||
line-height: 1.5;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employee { margin: 0; }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employee.hm-orgchart-leader { margin: 8px 0 0; }
|
||||
.hm-orgchart-expanded .hm-orgchart-organization-link { color: inherit; }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employees {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
gap: var(--hm-orgchart-expanded-employee-gap);
|
||||
margin: 0;
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employees:empty { display: none; }
|
||||
/* Shared neutral cards, isolated from Fixed asset backgrounds and geometry. */
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employee[data-card-presentation="expanded"] {
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
border: var(--hm-orgchart-expanded-card-border-width, var(--hm-orgchart-resolved-border-width)) solid var(--hm-orgchart-resolved-stroke-default);
|
||||
background: var(--hm-orgchart-resolved-bg-surface);
|
||||
color: var(--hm-orgchart-resolved-fg-primary);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-employee[data-card-presentation="expanded"]::before { content: none; }
|
||||
.hm-orgchart-expanded .hm-orgchart-employee[data-card-presentation="expanded"] .hm-orgchart-avatar { border-radius: 0; }
|
||||
.hm-orgchart-expanded .hm-orgchart-person-text { display: flex; flex-direction: column; gap: 0; }
|
||||
.hm-orgchart-expanded .hm-orgchart-employee::after { content: none; }
|
||||
/* Keep dabeng's first/last/only-child horizontal branch geometry. Only change
|
||||
connector length and offsets to agree with the Auto vertical gap. */
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .hierarchy:has(> .node[data-depth]) > .nodes > .hierarchy::before {
|
||||
top: calc(-1 * var(--hm-orgchart-expanded-level-gap) / 2);
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
border-width: var(--hm-orgchart-expanded-line-width) 0 0;
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .hierarchy:has(> .node[data-depth]) > .nodes > .hierarchy:first-child::before { left: calc(50% - 1px); width: calc(50% + 1px); }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .hierarchy:has(> .node[data-depth]) > .nodes > .hierarchy:last-child::before { width: calc(50% + 1px); }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .hierarchy:has(> .node[data-depth]) > .nodes > .hierarchy:only-child::before { left: calc(50% - 1px); width: var(--hm-orgchart-expanded-line-width); }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart > ul > li > ul li > .node::before {
|
||||
top: calc(-1 * var(--hm-orgchart-expanded-level-gap) / 2);
|
||||
height: calc(var(--hm-orgchart-expanded-level-gap) / 2);
|
||||
width: var(--hm-orgchart-expanded-line-width);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .hierarchy:not(.couple) > .node:has(+ .nodes)::after {
|
||||
bottom: calc(-1 * var(--hm-orgchart-expanded-level-gap) / 2);
|
||||
height: calc(100% - var(--hm-orgchart-expanded-content-height) + var(--hm-orgchart-expanded-level-gap) / 2);
|
||||
width: var(--hm-orgchart-expanded-line-width);
|
||||
}
|
||||
|
||||
/* Standalone content variables, independent of Fixed and HM React controls. */
|
||||
.hm-orgchart-expanded {
|
||||
--hm-orgchart-expanded-card-border-width: 1px;
|
||||
--hm-orgchart-expanded-card-accent-width: 3px;
|
||||
--hm-orgchart-expanded-card-padding: 8px;
|
||||
--hm-orgchart-expanded-card-radius: var(--hm-orgchart-resolved-radius-container);
|
||||
--hm-orgchart-expanded-photo-size: 36px;
|
||||
--hm-orgchart-expanded-name-size: 13px;
|
||||
--hm-orgchart-expanded-position-size: 10px;
|
||||
--hm-orgchart-expanded-name-weight: var(--hm-orgchart-resolved-font-weight-bold);
|
||||
--hm-orgchart-expanded-person-gap: 0px;
|
||||
--hm-orgchart-expanded-title-padding: var(--hm-orgchart-resolved-spacing-sm) var(--hm-orgchart-resolved-spacing-md);
|
||||
--hm-orgchart-expanded-title-radius: var(--hm-orgchart-resolved-radius-control-md);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-organization-name { display: flex; border-radius: var(--hm-orgchart-expanded-title-radius); }
|
||||
.hm-orgchart-expanded-toggle {
|
||||
flex: 1; border: 0; background: none; color: inherit; font: inherit;
|
||||
cursor: pointer; padding: var(--hm-orgchart-expanded-title-padding); white-space: nowrap;
|
||||
border-radius: inherit;
|
||||
}
|
||||
.hm-orgchart-expanded-toggle:not(:disabled):hover,
|
||||
.hm-orgchart-expanded-link:hover { background: color-mix(in srgb, currentColor 12%, transparent); }
|
||||
.hm-orgchart-expanded-toggle:disabled { cursor: default; opacity: 0.75; }
|
||||
.hm-orgchart-expanded-link { display: inline-flex; align-items: center; padding-inline: var(--hm-orgchart-resolved-spacing-sm); color: inherit; }
|
||||
.hm-orgchart-expanded-toggle:focus-visible, .hm-orgchart-expanded-link:focus-visible,
|
||||
.hm-orgchart-expanded-toolbar button:focus-visible {
|
||||
outline: 3px solid var(--hm-orgchart-resolved-action-primary); outline-offset: 3px;
|
||||
}
|
||||
.hm-orgchart-expanded-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--hm-orgchart-resolved-spacing-sm); }
|
||||
.hm-orgchart-expanded-toolbar button {
|
||||
font: inherit; padding: var(--hm-orgchart-resolved-spacing-sm) var(--hm-orgchart-resolved-spacing-md);
|
||||
border: var(--hm-orgchart-resolved-border-width) solid var(--hm-orgchart-resolved-stroke-default);
|
||||
border-radius: var(--hm-orgchart-resolved-radius-control-md); background: var(--hm-orgchart-resolved-bg-surface);
|
||||
color: var(--hm-orgchart-resolved-fg-primary); cursor: pointer;
|
||||
}
|
||||
.hm-orgchart-expanded-toolbar button:disabled { opacity: 0.5; cursor: default; }
|
||||
.hm-orgchart-expanded-toolbar span { color: var(--hm-orgchart-resolved-fg-secondary); font-size: var(--hm-orgchart-resolved-font-size-meta); }
|
||||
.hm-orgchart-expanded-selection, .hm-orgchart-top-node-title { margin: 0; }
|
||||
.hm-orgchart-expanded-empty { padding: var(--hm-orgchart-resolved-spacing-lg); }
|
||||
.hm-orgchart-expanded .hm-orgchart-viewport[data-dragging] { cursor: grabbing; user-select: none; }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] { cursor: default; }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employees[data-connection-direction="left"],
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employees[data-connection-direction="right"] {
|
||||
padding-inline: var(--hm-orgchart-resolved-spacing-xxl);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-employee-connectors { position: absolute; inset: 0; overflow: visible; pointer-events: none; }
|
||||
.hm-orgchart-expanded .hm-orgchart-employee-connectors path { fill: none; stroke: var(--hm-orgchart-resolved-stroke-default); stroke-width: var(--hm-orgchart-expanded-line-width); }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employee[data-card-presentation="expanded"] {
|
||||
padding: var(--hm-orgchart-expanded-card-padding);
|
||||
border-radius: var(--hm-orgchart-expanded-card-radius);
|
||||
width: var(--hm-orgchart-expanded-card-width, var(--hm-orgchart-resolved-card-width-employee));
|
||||
min-width: 0;
|
||||
min-height: var(--hm-orgchart-expanded-card-height, var(--hm-orgchart-resolved-card-height-employee));
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-leader[data-card-presentation="expanded"] {
|
||||
width: var(--hm-orgchart-expanded-leader-width, var(--hm-orgchart-resolved-card-width-leader));
|
||||
min-height: var(--hm-orgchart-expanded-leader-height, var(--hm-orgchart-resolved-card-height-leader));
|
||||
}
|
||||
/* Inset accents preserve all outer dimensions even when accent width changes. */
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employee[data-card-presentation="expanded"][data-connection-direction="top"] {
|
||||
box-shadow: inset 0 var(--hm-orgchart-expanded-card-accent-width) 0 var(--hm-orgchart-expanded-card-primary);
|
||||
border-top-color: var(--hm-orgchart-expanded-card-primary);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employee[data-card-presentation="expanded"][data-connection-direction="left"] {
|
||||
box-shadow: inset var(--hm-orgchart-expanded-card-accent-width) 0 0 var(--hm-orgchart-expanded-card-primary);
|
||||
border-left-color: var(--hm-orgchart-expanded-card-primary);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employee[data-card-presentation="expanded"][data-connection-direction="right"] {
|
||||
box-shadow: inset calc(-1 * var(--hm-orgchart-expanded-card-accent-width)) 0 0 var(--hm-orgchart-expanded-card-primary);
|
||||
border-right-color: var(--hm-orgchart-expanded-card-primary);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-employee .hm-orgchart-avatar {
|
||||
width: var(--hm-orgchart-expanded-photo-size); height: var(--hm-orgchart-expanded-photo-size); flex-basis: var(--hm-orgchart-expanded-photo-size);
|
||||
}
|
||||
.hm-orgchart-expanded .hm-orgchart-person-text { gap: var(--hm-orgchart-expanded-person-gap); }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-person-name { font-size: var(--hm-orgchart-expanded-name-size); font-weight: var(--hm-orgchart-expanded-name-weight); }
|
||||
.hm-orgchart-expanded .hm-orgchart-engine.orgchart .node[data-depth] .hm-orgchart-person-role { font-size: var(--hm-orgchart-expanded-position-size); }
|
||||
Reference in new issue
Block a user