@ds-mo/ui 15.0.0 → 15.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +6 -0
- package/README.md +7 -0
- package/dist/.package-ready.json +1 -1
- package/dist/agent-patterns.json +1 -1
- package/dist/agent.json +2320 -90
- package/dist/components/ds-agent-questionnaire.js +1 -1
- package/dist/components/ds-agent-response.js +1 -1
- package/dist/components/ds-banner.js +1 -1
- package/dist/components/ds-banner.js.map +1 -1
- package/dist/components/ds-card-chart.js +1 -1
- package/dist/components/ds-card-chart.js.map +1 -1
- package/dist/components/ds-card-overview.js +1 -1
- package/dist/components/ds-card-overview.js.map +1 -1
- package/dist/components/ds-card-setting.js +1 -1
- package/dist/components/ds-card-setting.js.map +1 -1
- package/dist/components/ds-chart.js +1 -1
- package/dist/components/ds-chart.js.map +1 -1
- package/dist/components/ds-checkbox.js +1 -1
- package/dist/components/ds-conversation-list-item.js +1 -1
- package/dist/components/ds-conversation-list-item.js.map +1 -1
- package/dist/components/ds-data-filter.js +1 -1
- package/dist/components/ds-data-preferences.js +1 -1
- package/dist/components/ds-data-saved-views.js +1 -1
- package/dist/components/ds-data-search.js +1 -1
- package/dist/components/ds-data-search.js.map +1 -1
- package/dist/components/ds-filter-menu.js +1 -1
- package/dist/components/ds-message-scroller.js.map +1 -1
- package/dist/components/ds-mobile-sheet-nav.js +1 -1
- package/dist/components/ds-pagination.js +1 -1
- package/dist/components/ds-scroll-overlay.js.map +1 -1
- package/dist/components/ds-select.js +1 -1
- package/dist/components/ds-shell-app.js +1 -1
- package/dist/components/ds-table.js +1 -1
- package/dist/components/{p-Dpr2y6_S.js → p-B_jdoM7e.js} +2 -2
- package/dist/components/{p-CElUM-xU.js → p-C6xVxqOn.js} +2 -2
- package/dist/components/{p-MG4lcN0D.js → p-CdGXzRP8.js} +2 -2
- package/dist/components/{p-D6Wl3dRO.js → p-Cqc2U1ZQ.js} +2 -2
- package/dist/components/{p-D6Wl3dRO.js.map → p-Cqc2U1ZQ.js.map} +1 -1
- package/dist/components/{p-Nc76seSq.js → p-DEW7r0U9.js} +2 -2
- package/dist/components/{p-IEq_06J0.js → p-Dfs98tpL.js} +2 -2
- package/dist/components/{p-IEq_06J0.js.map → p-Dfs98tpL.js.map} +1 -1
- package/dist/components/p-ZhP2tVmM.js.map +1 -1
- package/dist/components/p-etifxiDc.js.map +1 -1
- package/dist/docs/components.json +1 -1
- package/dist/lint/STYLELINT-LICENSE +20 -0
- package/dist/lint/THIRD-PARTY-NOTICES +553 -0
- package/dist/lint/index.d.ts +7 -0
- package/dist/lint/index.js +51385 -0
- package/dist/lint/types.d.ts +13 -0
- package/dist/mcp-data/registry/agent-activity.json +6 -1
- package/dist/mcp-data/registry/agent-questionnaire.json +6 -1
- package/dist/mcp-data/registry/agent-response.json +12 -1
- package/dist/mcp-data/registry/agent-source-list.json +6 -1
- package/dist/mcp-data/registry/agent-tool-call.json +6 -1
- package/dist/mcp-data/registry/attachment-list.json +6 -1
- package/dist/mcp-data/registry/avatar.json +21 -1
- package/dist/mcp-data/registry/badge.json +30 -2
- package/dist/mcp-data/registry/banner.json +28 -2
- package/dist/mcp-data/registry/bar-action.json +24 -1
- package/dist/mcp-data/registry/bar-nav.json +6 -1
- package/dist/mcp-data/registry/bar-page-title.json +24 -1
- package/dist/mcp-data/registry/bar-title.json +26 -1
- package/dist/mcp-data/registry/bar-workflow.json +24 -1
- package/dist/mcp-data/registry/breadcrumb.json +6 -1
- package/dist/mcp-data/registry/button-filled.json +68 -1
- package/dist/mcp-data/registry/button-inverted.json +64 -1
- package/dist/mcp-data/registry/button-unfilled.json +66 -1
- package/dist/mcp-data/registry/calendar.json +14 -1
- package/dist/mcp-data/registry/card-action-center.json +24 -1
- package/dist/mcp-data/registry/card-chart.json +37 -2
- package/dist/mcp-data/registry/card-navigation.json +36 -1
- package/dist/mcp-data/registry/card-overview.json +27 -2
- package/dist/mcp-data/registry/card-setting.json +35 -2
- package/dist/mcp-data/registry/card-settings-scope.json +24 -1
- package/dist/mcp-data/registry/chart-legend.json +6 -1
- package/dist/mcp-data/registry/chart.json +7 -2
- package/dist/mcp-data/registry/checkbox.json +38 -2
- package/dist/mcp-data/registry/chip.json +50 -1
- package/dist/mcp-data/registry/code-block.json +30 -1
- package/dist/mcp-data/registry/conversation-list-item.json +25 -2
- package/dist/mcp-data/registry/conversation-list-section.json +14 -1
- package/dist/mcp-data/registry/conversation-list.json +6 -1
- package/dist/mcp-data/registry/data-customize.json +26 -1
- package/dist/mcp-data/registry/data-filter.json +26 -1
- package/dist/mcp-data/registry/data-group.json +26 -1
- package/dist/mcp-data/registry/data-preferences.json +26 -1
- package/dist/mcp-data/registry/data-saved-views.json +26 -1
- package/dist/mcp-data/registry/data-search.json +27 -2
- package/dist/mcp-data/registry/data-sort.json +26 -1
- package/dist/mcp-data/registry/data-toolbar.json +14 -1
- package/dist/mcp-data/registry/divider.json +6 -1
- package/dist/mcp-data/registry/empty-state.json +6 -1
- package/dist/mcp-data/registry/field.json +14 -1
- package/dist/mcp-data/registry/filter-menu.json +48 -1
- package/dist/mcp-data/registry/icon.json +21 -1
- package/dist/mcp-data/registry/input-date.json +48 -1
- package/dist/mcp-data/registry/input-time.json +48 -1
- package/dist/mcp-data/registry/input.json +48 -1
- package/dist/mcp-data/registry/loader.json +21 -1
- package/dist/mcp-data/registry/markdown.json +17 -1
- package/dist/mcp-data/registry/menu.json +26 -1
- package/dist/mcp-data/registry/message-actions.json +6 -1
- package/dist/mcp-data/registry/message-bubble.json +26 -1
- package/dist/mcp-data/registry/message-composer.json +24 -1
- package/dist/mcp-data/registry/message-scroller.json +12 -1
- package/dist/mcp-data/registry/message.json +6 -1
- package/dist/mcp-data/registry/mobile-bar-nav.json +24 -1
- package/dist/mcp-data/registry/mobile-header.json +26 -1
- package/dist/mcp-data/registry/mobile-section-switcher.json +26 -1
- package/dist/mcp-data/registry/mobile-sheet-nav.json +27 -2
- package/dist/mcp-data/registry/modal.json +24 -1
- package/dist/mcp-data/registry/pagination.json +6 -1
- package/dist/mcp-data/registry/panel-nav.json +28 -2
- package/dist/mcp-data/registry/panel-sub-nav.json +25 -0
- package/dist/mcp-data/registry/panel-tool-header.json +24 -1
- package/dist/mcp-data/registry/panel-tool-search.json +24 -1
- package/dist/mcp-data/registry/panel-tools.json +25 -1
- package/dist/mcp-data/registry/paper-texture.json +6 -1
- package/dist/mcp-data/registry/radio.json +35 -1
- package/dist/mcp-data/registry/registry.json +2319 -89
- package/dist/mcp-data/registry/score.json +38 -1
- package/dist/mcp-data/registry/scroll-overlay.json +6 -1
- package/dist/mcp-data/registry/select.json +52 -1
- package/dist/mcp-data/registry/shell-app.json +26 -1
- package/dist/mcp-data/registry/shell-page.json +6 -1
- package/dist/mcp-data/registry/shell-tools.json +25 -1
- package/dist/mcp-data/registry/skeleton.json +41 -1
- package/dist/mcp-data/registry/slider.json +42 -1
- package/dist/mcp-data/registry/swatch-picker.json +24 -1
- package/dist/mcp-data/registry/switch.json +37 -1
- package/dist/mcp-data/registry/tab-group.json +49 -1
- package/dist/mcp-data/registry/table.json +102 -1
- package/dist/mcp-data/registry/tag.json +52 -1
- package/dist/mcp-data/registry/text.json +22 -1
- package/dist/mcp-data/registry/textarea.json +38 -1
- package/dist/mcp-data/registry/time-picker.json +14 -1
- package/dist/mcp-data/registry/toast.json +24 -1
- package/dist/mcp-data/registry/tooltip-chart.json +24 -1
- package/dist/mcp-data/registry/tooltip.json +26 -1
- package/dist/mcp-data/registry/typing-indicator.json +6 -1
- package/package.json +32 -7
- /package/dist/components/{p-Dpr2y6_S.js.map → p-B_jdoM7e.js.map} +0 -0
- /package/dist/components/{p-CElUM-xU.js.map → p-C6xVxqOn.js.map} +0 -0
- /package/dist/components/{p-MG4lcN0D.js.map → p-CdGXzRP8.js.map} +0 -0
- /package/dist/components/{p-Nc76seSq.js.map → p-DEW7r0U9.js.map} +0 -0
|
@@ -54,7 +54,18 @@
|
|
|
54
54
|
"label": "Storybook examples",
|
|
55
55
|
"path": "src/wc/components/MessageScroller/MessageScroller.stories.ts"
|
|
56
56
|
}
|
|
57
|
-
]
|
|
57
|
+
],
|
|
58
|
+
"styling": {
|
|
59
|
+
"rationale": "The application owns host dimensions and may customize the transcript measure through its public hook.",
|
|
60
|
+
"protected": [],
|
|
61
|
+
"customProperties": [
|
|
62
|
+
{
|
|
63
|
+
"name": "--ds-message-scroller-content-max-width",
|
|
64
|
+
"source": "src/wc/components/MessageScroller/MessageScroller.css",
|
|
65
|
+
"reason": "Readable transcript measure inside a full-width scrollport."
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
58
69
|
},
|
|
59
70
|
"api": {
|
|
60
71
|
"props": {
|
|
@@ -49,7 +49,12 @@
|
|
|
49
49
|
"label": "Storybook examples",
|
|
50
50
|
"path": "src/wc/components/MessageScroller/MessageScroller.stories.ts"
|
|
51
51
|
}
|
|
52
|
-
]
|
|
52
|
+
],
|
|
53
|
+
"styling": {
|
|
54
|
+
"rationale": "The row composes content whose presentation is owned by its children and the transcript layout.",
|
|
55
|
+
"protected": [],
|
|
56
|
+
"customProperties": []
|
|
57
|
+
}
|
|
53
58
|
},
|
|
54
59
|
"api": {
|
|
55
60
|
"props": {
|
|
@@ -50,7 +50,30 @@
|
|
|
50
50
|
"label": "Storybook",
|
|
51
51
|
"path": "src/wc/components/MobileBarNav/MobileBarNav.stories.ts"
|
|
52
52
|
}
|
|
53
|
-
]
|
|
53
|
+
],
|
|
54
|
+
"styling": {
|
|
55
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
56
|
+
"protected": [
|
|
57
|
+
{
|
|
58
|
+
"properties": [
|
|
59
|
+
"background",
|
|
60
|
+
"border",
|
|
61
|
+
"box-shadow",
|
|
62
|
+
"color"
|
|
63
|
+
],
|
|
64
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
65
|
+
"props": []
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"properties": [
|
|
69
|
+
"border-radius"
|
|
70
|
+
],
|
|
71
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
72
|
+
"props": []
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"customProperties": []
|
|
76
|
+
}
|
|
54
77
|
},
|
|
55
78
|
"api": {
|
|
56
79
|
"props": {
|
|
@@ -55,7 +55,32 @@
|
|
|
55
55
|
"label": "Storybook",
|
|
56
56
|
"path": "src/wc/components/MobileHeader/MobileHeader.stories.ts"
|
|
57
57
|
}
|
|
58
|
-
]
|
|
58
|
+
],
|
|
59
|
+
"styling": {
|
|
60
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
61
|
+
"protected": [
|
|
62
|
+
{
|
|
63
|
+
"properties": [
|
|
64
|
+
"background",
|
|
65
|
+
"border",
|
|
66
|
+
"box-shadow",
|
|
67
|
+
"color"
|
|
68
|
+
],
|
|
69
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
70
|
+
"props": [
|
|
71
|
+
"tone"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"properties": [
|
|
76
|
+
"border-radius"
|
|
77
|
+
],
|
|
78
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
79
|
+
"props": []
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"customProperties": []
|
|
83
|
+
}
|
|
59
84
|
},
|
|
60
85
|
"api": {
|
|
61
86
|
"props": {
|
|
@@ -55,7 +55,32 @@
|
|
|
55
55
|
"label": "Surface ownership and trigger state",
|
|
56
56
|
"path": "src/docs/SurfaceOwnership.mdx"
|
|
57
57
|
}
|
|
58
|
-
]
|
|
58
|
+
],
|
|
59
|
+
"styling": {
|
|
60
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
61
|
+
"protected": [
|
|
62
|
+
{
|
|
63
|
+
"properties": [
|
|
64
|
+
"background",
|
|
65
|
+
"border",
|
|
66
|
+
"box-shadow",
|
|
67
|
+
"color"
|
|
68
|
+
],
|
|
69
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
70
|
+
"props": [
|
|
71
|
+
"presentation"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"properties": [
|
|
76
|
+
"border-radius"
|
|
77
|
+
],
|
|
78
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
79
|
+
"props": []
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"customProperties": []
|
|
83
|
+
}
|
|
59
84
|
},
|
|
60
85
|
"api": {
|
|
61
86
|
"props": {
|
|
@@ -53,7 +53,32 @@
|
|
|
53
53
|
"label": "Storybook",
|
|
54
54
|
"path": "src/wc/components/MobileSheetNav/MobileSheetNav.stories.ts"
|
|
55
55
|
}
|
|
56
|
-
]
|
|
56
|
+
],
|
|
57
|
+
"styling": {
|
|
58
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
59
|
+
"protected": [
|
|
60
|
+
{
|
|
61
|
+
"properties": [
|
|
62
|
+
"background",
|
|
63
|
+
"border",
|
|
64
|
+
"box-shadow",
|
|
65
|
+
"color"
|
|
66
|
+
],
|
|
67
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
68
|
+
"props": [
|
|
69
|
+
"presentation"
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"properties": [
|
|
74
|
+
"border-radius"
|
|
75
|
+
],
|
|
76
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
77
|
+
"props": []
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
"customProperties": []
|
|
81
|
+
}
|
|
57
82
|
},
|
|
58
83
|
"api": {
|
|
59
84
|
"props": {
|
|
@@ -393,7 +418,7 @@
|
|
|
393
418
|
},
|
|
394
419
|
{
|
|
395
420
|
"path": "src/wc/components/MobileSheetNav/MobileSheetNav.tsx",
|
|
396
|
-
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Listen,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport type { NavChromeStyle } from '../../shell/nav-chrome';\nimport { derivePanelNavSelectionFromUrl } from '../PanelNav/panel-nav-utils';\nimport type {\n PanelNavChildItem,\n PanelNavChildSelectDetail,\n PanelNavGroup,\n PanelNavItem,\n PanelNavPresentation,\n} from '../PanelNav/panel-nav-types';\n\ntype MobileSheetNavHeaderDestinationId = 'account' | 'help';\n\nconst CONTEXT_TABS = [\n { id: 'dashboard', label: 'Dashboard', icon: 'Dashboard', variant: 'icon' as const },\n { id: 'settings', label: 'Settings', icon: 'Gear', variant: 'icon' as const },\n];\nlet nextSheetId = 0;\n\n@Component({\n tag: 'ds-mobile-sheet-nav',\n styleUrl: 'MobileSheetNav.css',\n scoped: true,\n})\nexport class MobileSheetNav {\n @Element() el!: HTMLElement;\n\n @Prop({ reflect: true }) open: boolean = false;\n @Prop() browseContext: NavChromeStyle = 'dashboard';\n @Prop() dashboardGroups: PanelNavGroup[] = [];\n @Prop() settingsGroups: PanelNavGroup[] = [];\n @Prop() currentUrl: string = '';\n /** Flat area navigation or inline disclosure of each area's child routes. */\n @Prop() presentation: PanelNavPresentation = 'flat';\n /** Whether the router-derived current area owns the active mobile stage. */\n @Prop() routeSelectionActive: boolean = true;\n @Prop() navigationLabel: string = 'Application navigation';\n @Prop() dashboardLabel: string = 'Dashboard';\n @Prop() settingsLabel: string = 'Settings';\n @Prop() accountLabel: string = 'Account';\n @Prop() helpLabel: string = 'Help & Support';\n /** Show the optional Account shortcut in the sheet header. */\n @Prop() showAccount: boolean = true;\n\n @Event() dsAreaSelect!: EventEmitter<string>;\n /** Selecting a child requests routing; expanding its parent never navigates. */\n @Event() dsNavChildSelect!: EventEmitter<PanelNavChildSelectDetail>;\n @Event() dsBrowseContextChange!: EventEmitter<NavChromeStyle>;\n @Event() dsClose!: EventEmitter<void>;\n @State() private expandedParentId = '';\n private readonly instanceId = nextSheetId++;\n\n private get groups(): PanelNavGroup[] {\n return this.browseContext === 'settings' ? this.settingsGroups : this.dashboardGroups;\n }\n\n private get selection() {\n return derivePanelNavSelectionFromUrl(\n this.routeSelectionActive ? this.currentUrl : '',\n this.groups.flatMap(group => group.items)\n );\n }\n\n componentWillLoad() {\n this.syncExpandedParent();\n }\n\n @Watch('presentation')\n @Watch('currentUrl')\n @Watch('browseContext')\n @Watch('routeSelectionActive')\n syncExpandedParent() {\n this.expandedParentId = this.presentation === 'nested' ? this.selection.parentId : '';\n }\n\n @Watch('open')\n handleOpenChange(open: boolean) {\n if (!open) return;\n this.syncExpandedParent();\n requestAnimationFrame(() => {\n const selected = this.el.querySelector<HTMLElement>('[aria-current=\"page\"]');\n const first = this.el.querySelector<HTMLElement>('.mobile-sheet-nav__item:not(:disabled)');\n (selected ?? first)?.focus({ preventScroll: true });\n });\n }\n\n @Listen('keydown')\n handleKeyDown(event: KeyboardEvent) {\n if (!this.open || event.key !== 'Escape') return;\n event.preventDefault();\n this.dsClose.emit();\n }\n\n private handleContextChange = (event: CustomEvent<string>) => {\n const next = event.detail === 'settings' ? 'settings' : 'dashboard';\n if (next === this.browseContext) return;\n this.dsBrowseContextChange.emit(next);\n };\n\n private renderItem(item: PanelNavItem) {\n const selected = item.id === this.selection.parentId;\n const disclosure = this.presentation === 'nested' && !!item.children?.length;\n const expanded = disclosure && item.id === this.expandedParentId;\n return (\n <button\n id={this.parentId(item.id)}\n type=\"button\"\n class={{\n 'mobile-sheet-nav__item': true,\n 'mobile-sheet-nav__item--selected': selected,\n 'mobile-sheet-nav__parent--muted':\n this.presentation === 'nested' &&\n this.expandedParentId !== '' &&\n this.expandedParentId !== item.id,\n 'ds-control--lg': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n aria-current={selected && !disclosure ? 'page' : undefined}\n aria-expanded={disclosure ? String(expanded) : undefined}\n aria-controls={disclosure ? this.childrenId(item.id) : undefined}\n onClick={() =>\n disclosure\n ? (this.expandedParentId = expanded ? '' : item.id)\n : this.dsAreaSelect.emit(item.id)\n }\n >\n <ds-icon class=\"ds-interaction-fill__content\" name={item.icon} size=\"lg\" color=\"inherit\" />\n <ds-text\n class=\"mobile-sheet-nav__item-label ds-interaction-fill__content\"\n as=\"span\"\n variant=\"text-body-large\"\n emphasis={selected}\n color=\"inherit\"\n lineTruncation={1}\n >\n {item.label}\n </ds-text>\n {item.dot && (\n <ds-badge\n class=\"mobile-sheet-nav__dot ds-interaction-fill__content\"\n variant=\"dot\"\n hasRing={false}\n label=\"\"\n aria-hidden=\"true\"\n />\n )}\n </button>\n );\n }\n\n private parentId(id: string) {\n return `mobile-sheet-${this.instanceId}-${encodeURIComponent(id)}`;\n }\n private childrenId(id: string) {\n return `${this.parentId(id)}-children`;\n }\n\n private renderChild(parent: PanelNavItem, child: PanelNavChildItem, index: number) {\n const selected = parent.id === this.selection.parentId && child.id === this.selection.childId;\n return (\n <button\n type=\"button\"\n disabled={child.isInactive}\n class={{\n 'mobile-sheet-nav__item': true,\n 'mobile-sheet-nav__child': true,\n 'mobile-sheet-nav__item--selected': selected,\n 'ds-nav-disclosure__item': true,\n 'ds-control--lg': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n style={{\n '--ds-nav-disclosure-index': String(index),\n '--ds-nav-disclosure-reverse-index': String((parent.children?.length ?? 0) - index - 1),\n }}\n aria-current={selected ? 'page' : undefined}\n onClick={() => {\n if (!child.isInactive)\n this.dsNavChildSelect.emit({\n parentId: parent.id,\n childId: child.id,\n href: child.href,\n });\n }}\n onKeyDown={(event: KeyboardEvent) => {\n if (event.key === 'ArrowLeft') {\n event.preventDefault();\n this.expandedParentId = '';\n this.el.querySelector<HTMLElement>(`#${CSS.escape(this.parentId(parent.id))}`)?.focus();\n }\n }}\n >\n <ds-text\n class=\"mobile-sheet-nav__item-label ds-interaction-fill__content\"\n as=\"span\"\n variant=\"text-body-large\"\n emphasis={selected}\n color=\"inherit\"\n lineTruncation={1}\n >\n {child.label}\n </ds-text>\n {child.dot ? (\n <ds-badge\n class=\"mobile-sheet-nav__dot ds-interaction-fill__content\"\n variant=\"dot\"\n hasRing={false}\n label=\"\"\n aria-hidden=\"true\"\n />\n ) : null}\n </button>\n );\n }\n\n private renderBranchDivider(position: 'before' | 'after', expanded: boolean) {\n return (\n <div\n class={{\n 'ds-nav-disclosure-divider': true,\n 'ds-nav-disclosure-divider--open': expanded,\n 'mobile-sheet-nav__divider': true,\n [`mobile-sheet-nav__divider--${position}`]: true,\n }}\n aria-hidden=\"true\"\n >\n <div class=\"ds-nav-disclosure-divider__clip\">\n <span class=\"mobile-sheet-nav__divider-line\" />\n </div>\n </div>\n );\n }\n\n private renderBranch(item: PanelNavItem, index: number, count: number) {\n const hasChildren = this.presentation === 'nested' && !!item.children?.length;\n const expanded = hasChildren && this.expandedParentId === item.id;\n return (\n <div key={item.id} class=\"mobile-sheet-nav__branch\">\n {hasChildren && index > 0 ? this.renderBranchDivider('before', expanded) : null}\n {this.renderItem(item)}\n {this.presentation === 'nested' && item.children?.length ? (\n <div\n class={{ 'ds-nav-disclosure': true, 'ds-nav-disclosure--open': expanded }}\n inert={!expanded ? true : undefined}\n aria-hidden={!expanded ? 'true' : undefined}\n >\n <div\n class=\"mobile-sheet-nav__children\"\n id={this.childrenId(item.id)}\n role=\"group\"\n aria-labelledby={this.parentId(item.id)}\n >\n {item.children.map((child, index) => this.renderChild(item, child, index))}\n </div>\n </div>\n ) : null}\n {hasChildren && index < count - 1 ? this.renderBranchDivider('after', expanded) : null}\n </div>\n );\n }\n\n private renderLogo() {\n return (\n <span class=\"mobile-sheet-nav__logo\" aria-hidden=\"true\">\n {/* eslint-disable-next-line local/prefer-ds-icon -- Motive brand mark is not part of the IcoMo runtime catalog. */}\n <svg\n class=\"mobile-sheet-nav__logo-mark\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n focusable=\"false\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M11.1159 4.31537H7.67021L2.53401 13.0703H0V15.6875H4.02716L8.24319 8.49978V15.6846H11.6342L15.8289 8.47829V15.6846H18.7122V4.3125H15.2559L11.1159 11.3648V4.31537Z\"\n fill=\"currentColor\"\n />\n </svg>\n </span>\n );\n }\n\n private renderHeaderDestination(\n id: MobileSheetNavHeaderDestinationId,\n icon: string,\n label: string\n ) {\n return (\n <ds-tooltip label={label} side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n variant=\"icon\"\n size=\"lg\"\n icon={icon}\n aria-label={label}\n activeFill={false}\n hasBorder={false}\n onDsClick={() => this.dsAreaSelect.emit(id)}\n />\n </ds-tooltip>\n );\n }\n\n render() {\n const contextTabs = [\n { ...CONTEXT_TABS[0], label: this.dashboardLabel },\n { ...CONTEXT_TABS[1], label: this.settingsLabel },\n ];\n\n return (\n <Host aria-hidden={this.open ? undefined : 'true'} inert={this.open ? undefined : true}>\n <section id=\"ds-mobile-sheet-nav\" class=\"mobile-sheet-nav\">\n <header\n class={{\n 'mobile-sheet-nav__header': true,\n 'mobile-sheet-nav__header--expanded-context': !this.showAccount,\n 'ds-chrome-grid': true,\n 'ds-chrome-space--md': true,\n }}\n >\n <div class=\"mobile-sheet-nav__brand\">{this.renderLogo()}</div>\n <ds-tab-group\n class=\"mobile-sheet-nav__context\"\n tabs={contextTabs}\n value={this.browseContext}\n size=\"lg\"\n width={this.showAccount ? 'hug' : 'fill'}\n aria-label=\"Browse context\"\n onDsChange={this.handleContextChange}\n />\n <div class=\"mobile-sheet-nav__actions\">\n {this.renderHeaderDestination('help', 'QuestionCircle', this.helpLabel)}\n {this.showAccount\n ? this.renderHeaderDestination('account', 'PersonCircle', this.accountLabel)\n : null}\n </div>\n </header>\n\n <nav\n class=\"mobile-sheet-nav__body ds-chrome-column ds-chrome-space--md\"\n aria-label={this.navigationLabel}\n >\n <div class=\"mobile-sheet-nav__sections\">\n {this.groups\n .filter(group => group.items.length > 0)\n .map(group => (\n <div class=\"mobile-sheet-nav__items\">\n {group.items.map((item, index) =>\n this.renderBranch(item, index, group.items.length)\n )}\n </div>\n ))}\n </div>\n </nav>\n </section>\n </Host>\n );\n }\n}\n",
|
|
421
|
+
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Listen,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport type { NavChromeStyle } from '../../shell/nav-chrome';\nimport { derivePanelNavSelectionFromUrl } from '../PanelNav/panel-nav-utils';\nimport type {\n PanelNavChildItem,\n PanelNavChildSelectDetail,\n PanelNavGroup,\n PanelNavItem,\n PanelNavPresentation,\n} from '../PanelNav/panel-nav-types';\n\ntype MobileSheetNavHeaderDestinationId = 'account' | 'help';\n\nconst CONTEXT_TABS = [\n { id: 'dashboard', label: 'Dashboard', icon: 'Dashboard', variant: 'icon' as const },\n { id: 'settings', label: 'Settings', icon: 'Gear', variant: 'icon' as const },\n];\nlet nextSheetId = 0;\n\n@Component({\n tag: 'ds-mobile-sheet-nav',\n styleUrl: 'MobileSheetNav.css',\n scoped: true,\n})\nexport class MobileSheetNav {\n @Element() el!: HTMLElement;\n\n @Prop({ reflect: true }) open: boolean = false;\n @Prop() browseContext: NavChromeStyle = 'dashboard';\n @Prop() dashboardGroups: PanelNavGroup[] = [];\n @Prop() settingsGroups: PanelNavGroup[] = [];\n @Prop() currentUrl: string = '';\n /** Flat area navigation or inline disclosure of each area's child routes. */\n @Prop() presentation: PanelNavPresentation = 'flat';\n /** Whether the router-derived current area owns the active mobile stage. */\n @Prop() routeSelectionActive: boolean = true;\n @Prop() navigationLabel: string = 'Application navigation';\n @Prop() dashboardLabel: string = 'Dashboard';\n @Prop() settingsLabel: string = 'Settings';\n @Prop() accountLabel: string = 'Account';\n @Prop() helpLabel: string = 'Help & Support';\n /** Show the optional Account shortcut in the sheet header. */\n @Prop() showAccount: boolean = true;\n\n @Event() dsAreaSelect!: EventEmitter<string>;\n /** Selecting a child requests routing; expanding its parent never navigates. */\n @Event() dsNavChildSelect!: EventEmitter<PanelNavChildSelectDetail>;\n @Event() dsBrowseContextChange!: EventEmitter<NavChromeStyle>;\n @Event() dsClose!: EventEmitter<void>;\n @State() private expandedParentId = '';\n private readonly instanceId = nextSheetId++;\n\n private get groups(): PanelNavGroup[] {\n return this.browseContext === 'settings' ? this.settingsGroups : this.dashboardGroups;\n }\n\n private get selection() {\n return derivePanelNavSelectionFromUrl(\n this.routeSelectionActive ? this.currentUrl : '',\n this.groups.flatMap(group => group.items)\n );\n }\n\n componentWillLoad() {\n this.syncExpandedParent();\n }\n\n @Watch('presentation')\n @Watch('currentUrl')\n @Watch('browseContext')\n @Watch('routeSelectionActive')\n syncExpandedParent() {\n this.expandedParentId = this.presentation === 'nested' ? this.selection.parentId : '';\n }\n\n @Watch('open')\n handleOpenChange(open: boolean) {\n if (!open) return;\n this.syncExpandedParent();\n requestAnimationFrame(() => {\n const selected = this.el.querySelector<HTMLElement>('[aria-current=\"page\"]');\n const first = this.el.querySelector<HTMLElement>('.mobile-sheet-nav__item:not(:disabled)');\n (selected ?? first)?.focus({ preventScroll: true });\n });\n }\n\n @Listen('keydown')\n handleKeyDown(event: KeyboardEvent) {\n if (!this.open || event.key !== 'Escape') return;\n event.preventDefault();\n this.dsClose.emit();\n }\n\n private handleContextChange = (event: CustomEvent<string>) => {\n const next = event.detail === 'settings' ? 'settings' : 'dashboard';\n if (next === this.browseContext) return;\n this.dsBrowseContextChange.emit(next);\n };\n\n private renderItem(item: PanelNavItem) {\n const selected = item.id === this.selection.parentId;\n const disclosure = this.presentation === 'nested' && !!item.children?.length;\n const expanded = disclosure && item.id === this.expandedParentId;\n return (\n <button\n id={this.parentId(item.id)}\n type=\"button\"\n class={{\n 'mobile-sheet-nav__item': true,\n 'mobile-sheet-nav__item--selected': selected,\n 'mobile-sheet-nav__parent--muted':\n this.presentation === 'nested' &&\n this.expandedParentId !== '' &&\n this.expandedParentId !== item.id,\n 'ds-control--lg': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n aria-current={selected && !disclosure ? 'page' : undefined}\n aria-expanded={disclosure ? String(expanded) : undefined}\n aria-controls={disclosure ? this.childrenId(item.id) : undefined}\n onClick={() =>\n disclosure\n ? (this.expandedParentId = expanded ? '' : item.id)\n : this.dsAreaSelect.emit(item.id)\n }\n >\n <ds-icon class=\"ds-interaction-fill__content\" name={item.icon} size=\"lg\" color=\"inherit\" />\n <ds-text\n class=\"mobile-sheet-nav__item-label ds-interaction-fill__content\"\n as=\"span\"\n variant=\"text-body-large\"\n emphasis={selected}\n color=\"inherit\"\n lineTruncation={1}\n >\n {item.label}\n </ds-text>\n {item.dot && (\n <ds-badge\n class=\"mobile-sheet-nav__dot ds-interaction-fill__content\"\n variant=\"dot\"\n hasRing={false}\n label=\"\"\n aria-hidden=\"true\"\n />\n )}\n </button>\n );\n }\n\n private parentId(id: string) {\n return `mobile-sheet-${this.instanceId}-${encodeURIComponent(id)}`;\n }\n private childrenId(id: string) {\n return `${this.parentId(id)}-children`;\n }\n\n private renderChild(parent: PanelNavItem, child: PanelNavChildItem, index: number) {\n const selected = parent.id === this.selection.parentId && child.id === this.selection.childId;\n return (\n <button\n type=\"button\"\n disabled={child.isInactive}\n class={{\n 'mobile-sheet-nav__item': true,\n 'mobile-sheet-nav__child': true,\n 'mobile-sheet-nav__item--selected': selected,\n 'ds-nav-disclosure__item': true,\n 'ds-control--lg': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n style={{\n '--ds-nav-disclosure-index': String(index),\n '--ds-nav-disclosure-reverse-index': String((parent.children?.length ?? 0) - index - 1),\n }}\n aria-current={selected ? 'page' : undefined}\n onClick={() => {\n if (!child.isInactive)\n this.dsNavChildSelect.emit({\n parentId: parent.id,\n childId: child.id,\n href: child.href,\n });\n }}\n onKeyDown={(event: KeyboardEvent) => {\n if (event.key === 'ArrowLeft') {\n event.preventDefault();\n this.expandedParentId = '';\n this.el.querySelector<HTMLElement>(`#${CSS.escape(this.parentId(parent.id))}`)?.focus();\n }\n }}\n >\n <ds-text\n class=\"mobile-sheet-nav__item-label ds-interaction-fill__content\"\n as=\"span\"\n variant=\"text-body-large\"\n emphasis={selected}\n color=\"inherit\"\n lineTruncation={1}\n >\n {child.label}\n </ds-text>\n {child.dot ? (\n <ds-badge\n class=\"mobile-sheet-nav__dot ds-interaction-fill__content\"\n variant=\"dot\"\n hasRing={false}\n label=\"\"\n aria-hidden=\"true\"\n />\n ) : null}\n </button>\n );\n }\n\n private renderBranchDivider(position: 'before' | 'after', expanded: boolean) {\n return (\n <div\n class={{\n 'ds-nav-disclosure-divider': true,\n 'ds-nav-disclosure-divider--open': expanded,\n 'mobile-sheet-nav__divider': true,\n [`mobile-sheet-nav__divider--${position}`]: true,\n }}\n aria-hidden=\"true\"\n >\n <div class=\"ds-nav-disclosure-divider__clip\">\n <span class=\"mobile-sheet-nav__divider-line\" />\n </div>\n </div>\n );\n }\n\n private renderBranch(item: PanelNavItem, index: number, count: number) {\n const hasChildren = this.presentation === 'nested' && !!item.children?.length;\n const expanded = hasChildren && this.expandedParentId === item.id;\n return (\n <div key={item.id} class=\"mobile-sheet-nav__branch\">\n {hasChildren && index > 0 ? this.renderBranchDivider('before', expanded) : null}\n {this.renderItem(item)}\n {this.presentation === 'nested' && item.children?.length ? (\n <div\n class={{ 'ds-nav-disclosure': true, 'ds-nav-disclosure--open': expanded }}\n inert={!expanded ? true : undefined}\n aria-hidden={!expanded ? 'true' : undefined}\n >\n <div\n class=\"mobile-sheet-nav__children\"\n id={this.childrenId(item.id)}\n role=\"group\"\n aria-labelledby={this.parentId(item.id)}\n >\n {item.children.map((child, index) => this.renderChild(item, child, index))}\n </div>\n </div>\n ) : null}\n {hasChildren && index < count - 1 ? this.renderBranchDivider('after', expanded) : null}\n </div>\n );\n }\n\n private renderLogo() {\n return (\n <span class=\"mobile-sheet-nav__logo\" aria-hidden=\"true\">\n {/* eslint-disable-next-line compomo/prefer-ds-icon -- Motive brand mark is not part of the IcoMo runtime catalog. */}\n <svg\n class=\"mobile-sheet-nav__logo-mark\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n focusable=\"false\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M11.1159 4.31537H7.67021L2.53401 13.0703H0V15.6875H4.02716L8.24319 8.49978V15.6846H11.6342L15.8289 8.47829V15.6846H18.7122V4.3125H15.2559L11.1159 11.3648V4.31537Z\"\n fill=\"currentColor\"\n />\n </svg>\n </span>\n );\n }\n\n private renderHeaderDestination(\n id: MobileSheetNavHeaderDestinationId,\n icon: string,\n label: string\n ) {\n return (\n <ds-tooltip label={label} side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n variant=\"icon\"\n size=\"lg\"\n icon={icon}\n aria-label={label}\n activeFill={false}\n hasBorder={false}\n onDsClick={() => this.dsAreaSelect.emit(id)}\n />\n </ds-tooltip>\n );\n }\n\n render() {\n const contextTabs = [\n { ...CONTEXT_TABS[0], label: this.dashboardLabel },\n { ...CONTEXT_TABS[1], label: this.settingsLabel },\n ];\n\n return (\n <Host aria-hidden={this.open ? undefined : 'true'} inert={this.open ? undefined : true}>\n <section id=\"ds-mobile-sheet-nav\" class=\"mobile-sheet-nav\">\n <header\n class={{\n 'mobile-sheet-nav__header': true,\n 'mobile-sheet-nav__header--expanded-context': !this.showAccount,\n 'ds-chrome-grid': true,\n 'ds-chrome-space--md': true,\n }}\n >\n <div class=\"mobile-sheet-nav__brand\">{this.renderLogo()}</div>\n <ds-tab-group\n class=\"mobile-sheet-nav__context\"\n tabs={contextTabs}\n value={this.browseContext}\n size=\"lg\"\n width={this.showAccount ? 'hug' : 'fill'}\n aria-label=\"Browse context\"\n onDsChange={this.handleContextChange}\n />\n <div class=\"mobile-sheet-nav__actions\">\n {this.renderHeaderDestination('help', 'QuestionCircle', this.helpLabel)}\n {this.showAccount\n ? this.renderHeaderDestination('account', 'PersonCircle', this.accountLabel)\n : null}\n </div>\n </header>\n\n <nav\n class=\"mobile-sheet-nav__body ds-chrome-column ds-chrome-space--md\"\n aria-label={this.navigationLabel}\n >\n <div class=\"mobile-sheet-nav__sections\">\n {this.groups\n .filter(group => group.items.length > 0)\n .map(group => (\n <div class=\"mobile-sheet-nav__items\">\n {group.items.map((item, index) =>\n this.renderBranch(item, index, group.items.length)\n )}\n </div>\n ))}\n </div>\n </nav>\n </section>\n </Host>\n );\n }\n}\n",
|
|
397
422
|
"type": "registry:ui"
|
|
398
423
|
}
|
|
399
424
|
]
|
|
@@ -104,7 +104,30 @@
|
|
|
104
104
|
"label": "Reduced-motion overlay coverage",
|
|
105
105
|
"path": "tests/e2e/reduced-motion.spec.ts"
|
|
106
106
|
}
|
|
107
|
-
]
|
|
107
|
+
],
|
|
108
|
+
"styling": {
|
|
109
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
110
|
+
"protected": [
|
|
111
|
+
{
|
|
112
|
+
"properties": [
|
|
113
|
+
"background",
|
|
114
|
+
"border",
|
|
115
|
+
"box-shadow",
|
|
116
|
+
"color"
|
|
117
|
+
],
|
|
118
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
119
|
+
"props": []
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"properties": [
|
|
123
|
+
"border-radius"
|
|
124
|
+
],
|
|
125
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
126
|
+
"props": []
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
"customProperties": []
|
|
130
|
+
}
|
|
108
131
|
},
|
|
109
132
|
"api": {
|
|
110
133
|
"props": {
|
|
@@ -63,7 +63,12 @@
|
|
|
63
63
|
"label": "Storybook review states",
|
|
64
64
|
"path": "src/wc/components/Pagination/Pagination.stories.ts"
|
|
65
65
|
}
|
|
66
|
-
]
|
|
66
|
+
],
|
|
67
|
+
"styling": {
|
|
68
|
+
"rationale": "The host is a layout composition of controls; individual controls own their recipes.",
|
|
69
|
+
"protected": [],
|
|
70
|
+
"customProperties": []
|
|
71
|
+
}
|
|
67
72
|
},
|
|
68
73
|
"api": {
|
|
69
74
|
"props": {
|
|
@@ -122,7 +122,33 @@
|
|
|
122
122
|
"label": "Surface ownership and trigger state",
|
|
123
123
|
"path": "src/docs/SurfaceOwnership.mdx"
|
|
124
124
|
}
|
|
125
|
-
]
|
|
125
|
+
],
|
|
126
|
+
"styling": {
|
|
127
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
128
|
+
"protected": [
|
|
129
|
+
{
|
|
130
|
+
"properties": [
|
|
131
|
+
"background",
|
|
132
|
+
"border",
|
|
133
|
+
"box-shadow",
|
|
134
|
+
"color"
|
|
135
|
+
],
|
|
136
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
137
|
+
"props": [
|
|
138
|
+
"presentation",
|
|
139
|
+
"navStyle"
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"properties": [
|
|
144
|
+
"border-radius"
|
|
145
|
+
],
|
|
146
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
147
|
+
"props": []
|
|
148
|
+
}
|
|
149
|
+
],
|
|
150
|
+
"customProperties": []
|
|
151
|
+
}
|
|
126
152
|
},
|
|
127
153
|
"api": {
|
|
128
154
|
"props": {
|
|
@@ -708,7 +734,7 @@
|
|
|
708
734
|
"files": [
|
|
709
735
|
{
|
|
710
736
|
"path": "src/wc/components/PanelNav/PanelNav.css",
|
|
711
|
-
"content": "@import '../../utils/radius.css';\n@import '../../utils/control-density.css';\n@import '../../utils/chrome-layout.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n@import '../../utils/scrollbar-hidden.css';\n@import '../../utils/nav-disclosure.css';\n\n/* ── Theme variables ──────────────────────────────────────────────────────── */\n\n.panel-nav {\n /* ─ Sizes ─ */\n --_nav-width: var(--dimension-panel-width-2xs);\n --_nav-width-collapsed: var(--dimension-size-600);\n --_nav-item-height: var(--dimension-size-400, 32px);\n --_nav-padding-x: var(--dimension-space-100, 8px);\n --_nav-padding-y: var(--dimension-space-100, 8px);\n /* gear button outer width = padding*2 + icon */\n --_nav-footer-btn-w: calc(\n var(--dimension-space-075, 6px) * 2 + var(--dimension-iconography-md, 20px)\n );\n\n /* ─ Motion ─ */\n /* --ds-panel-nav-speed: unitless multiplier; override in Storybook to slow-mo (e.g. 10 = 10×).\n *-dur vars are duration-only (needed for calc); *-motion vars add easing for use in transitions. */\n --_nav-speed: var(--ds-panel-nav-speed, 1);\n --_nav-expand-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-expand-motion: var(--_nav-expand-dur) var(--effect-animation-easing-ease-in-out, ease);\n --_nav-label-fade-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-label-fade-motion: var(--_nav-label-fade-dur)\n var(--effect-animation-easing-ease-in-out, ease);\n --_nav-label-fade-out-dur: calc(\n var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms)\n );\n --_nav-label-fade-out-motion: var(--_nav-label-fade-out-dur)\n var(--effect-animation-easing-ease-in-out, ease);\n\n /* ─ Colours – default chrome (app surfaces) ─ */\n --_nav-bg: var(--color-background-secondary);\n --_nav-border: var(--color-border-tertiary);\n --_nav-divider: var(--color-border-tertiary);\n --_nav-fg-primary: var(--color-foreground-primary);\n --_nav-fg-secondary: var(--color-foreground-secondary);\n --_nav-fg-tertiary: var(--color-foreground-tertiary);\n --_nav-hover: var(--color-interaction-hover);\n --_nav-pressed: var(--color-interaction-pressed);\n --_nav-focus: var(--color-interaction-focus);\n --_nav-dot: var(--color-foreground-bold-brand);\n --ds-interaction-hover: var(--_nav-hover);\n --ds-interaction-pressed: var(--_nav-pressed);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Default chrome overrides ────────────────────────────────────────────── */\n\n/* Shell-owned chrome (bg + wash) — panel is a transparent frame. */\n:host-context(ds-shell-app:not([gradient-preset='none'])) .panel-nav,\n:host-context(ds-shell-app.shell-app--paper-texture) .panel-nav {\n background-color: transparent;\n}\n\n/* Style slots — same app tokens for now; hook texture/glyph layers on these classes later. */\n.panel-nav--dashboard,\n.panel-nav--settings {\n --_nav-bg: var(--color-background-secondary);\n --_nav-border: var(--color-border-tertiary);\n --_nav-divider: var(--color-border-tertiary);\n --_nav-fg-primary: var(--color-foreground-primary);\n --_nav-fg-secondary: var(--color-foreground-secondary);\n --_nav-fg-tertiary: var(--color-foreground-tertiary);\n --_nav-hover: var(--color-interaction-hover);\n --_nav-pressed: var(--color-interaction-pressed);\n --_nav-focus: var(--color-interaction-focus);\n --_nav-dot: var(--color-foreground-bold-brand);\n --ds-interaction-hover: var(--_nav-hover);\n --ds-interaction-pressed: var(--_nav-pressed);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Shell ───────────────────────────────────────────────────────────────── */\n\n.panel-nav {\n display: flex;\n flex-direction: column;\n position: relative;\n width: var(--_nav-width);\n min-width: var(--_nav-width);\n height: 100%;\n background-color: var(--_nav-bg);\n border-right: var(--dimension-stroke-width-012, 1px) solid var(--_nav-border);\n box-sizing: border-box;\n overflow: visible;\n transition:\n width var(--_nav-expand-motion),\n min-width var(--_nav-expand-motion),\n background-color var(--effect-motion-short-3, 200ms ease),\n border-color var(--effect-motion-short-3, 200ms ease);\n font-family: var(--typography-font-family-ui, system-ui);\n isolation: isolate;\n}\n\n.panel-nav__header,\n.panel-nav__body,\n.panel-nav__footer {\n position: relative;\n z-index: 3;\n}\n\n.panel-nav--collapsed {\n width: var(--_nav-width-collapsed);\n min-width: var(--_nav-width-collapsed);\n}\n\n/* ── Header ──────────────────────────────────────────────────────────────── */\n\n.panel-nav__header {\n height: var(--dimension-size-600, 48px);\n flex-shrink: 0;\n border-bottom: var(--dimension-stroke-width-012, 1px) solid var(--_nav-divider);\n transition: border-color var(--effect-motion-short-3, 200ms ease);\n}\n\n.panel-nav__header-btn {\n all: unset;\n /* Re-assert after unset — required for `.ds-interaction-fill` stacking. */\n position: relative;\n z-index: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--dimension-space-075, 6px);\n border-radius: var(--ds-control-radius, var(--dimension-radius-025, 2px));\n cursor: default;\n color: var(--_nav-fg-primary);\n flex-shrink: 0;\n box-sizing: border-box;\n transition: color var(--effect-motion-short-3, 200ms ease);\n /* Hover/press: `.ds-interaction-fill` (tokens from --_nav-* via --ds-interaction-*). */\n}\n\n.panel-nav--breakpoint-locked .panel-nav__header-btn {\n cursor: default;\n}\n\n/* Logo — visible by default; instant swap to toggle on hover (no crossfade overlap) */\n.panel-nav__header-logo {\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n z-index: 2;\n opacity: 1;\n}\n\n.panel-nav__m-mark {\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n display: block;\n}\n\n/* Toggle icon — stacked on logo; under hover wash (::after z-index 3) */\n.panel-nav__header-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n inset: 0;\n z-index: 2;\n opacity: 0;\n pointer-events: none;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .panel-nav:not(.panel-nav--breakpoint-locked)\n .panel-nav__header-btn:hover\n .panel-nav__header-logo {\n opacity: 0;\n }\n\n .panel-nav:not(.panel-nav--breakpoint-locked)\n .panel-nav__header-btn:hover\n .panel-nav__header-toggle {\n opacity: 1;\n }\n}\n/* ── Scrollable body ─────────────────────────────────────────────────────── */\n\n.panel-nav__body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n/* The collapsed rail's outer width includes its 1px divider. Return that pixel\n to the content box so body items match the other 32px rail controls. */\n.panel-nav--collapsed .panel-nav__body {\n padding-inline-end: calc(var(--_nav-padding-x) - var(--dimension-stroke-width-012));\n}\n\n.panel-nav__sections {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-200, 16px);\n width: 100%;\n}\n\n/* ── Group ───────────────────────────────────────────────────────────────── */\n\n.panel-nav__group {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050, 4px);\n}\n\n.panel-nav__branch {\n display: flex;\n flex-direction: column;\n}\n\n.panel-nav__branch-divider-line {\n display: block;\n height: var(--dimension-stroke-width-012);\n margin-inline: var(--dimension-space-075);\n background: var(--_nav-divider);\n}\n\n.panel-nav__branch-divider--before .panel-nav__branch-divider-line {\n margin-block: var(--dimension-space-050) var(--dimension-space-100);\n}\n\n.panel-nav__branch-divider--after .panel-nav__branch-divider-line {\n margin-block: var(--dimension-space-100) var(--dimension-space-050);\n}\n\n.panel-nav__children-accordion,\n.panel-nav__branch-divider {\n --ds-nav-disclosure-duration: var(\n --_panel-nav-nested-section-duration,\n calc(var(--effect-animation-duration-short-3) * 2 + var(--effect-animation-duration-short-2))\n );\n --ds-nav-disclosure-wait: var(\n --_panel-nav-nested-transition-wait,\n calc(var(--effect-animation-duration-short-3) + var(--effect-animation-duration-short-1))\n );\n --ds-nav-disclosure-fade: var(\n --_panel-nav-nested-child-fade-duration,\n var(--ds-nav-disclosure-duration)\n );\n --ds-nav-disclosure-stagger: var(\n --_panel-nav-nested-child-stagger,\n var(--effect-animation-duration-short-1)\n );\n}\n\n.panel-nav__children {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050, 4px);\n min-height: 0;\n overflow: hidden;\n}\n\n/* Margin lives on the first child so closed 0fr accordions still collapse to 0. */\n.panel-nav__children > .panel-nav__child:first-child {\n margin-block-start: var(--dimension-space-050, 4px);\n}\n\n/*\n * Section headers — typography via ds-text (text-caption + emphasis).\n * Element selector so display:flex beats Text's inline-block, and padding\n * isn't clobbered by sharing `.panel-nav__item-label-text` on the same host.\n */\nds-text.panel-nav__group-label {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n text-transform: uppercase;\n color: var(--_nav-fg-secondary);\n user-select: none;\n height: var(--dimension-size-300, 24px);\n /* Former nested pad: group-label (075) + item-label-text (025). */\n padding: 0 calc(var(--dimension-space-075, 6px) + var(--ds-control-label-inset));\n white-space: nowrap;\n overflow: hidden;\n max-height: var(--dimension-size-300, 24px);\n opacity: 1;\n transition:\n opacity var(--_nav-label-fade-motion) 0ms,\n max-height var(--_nav-label-fade-motion) 0ms,\n padding var(--_nav-label-fade-motion) 0ms,\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Item ────────────────────────────────────────────────────────────────── */\n\n.panel-nav__item {\n all: unset;\n /* Re-assert after unset — required for `.ds-interaction-fill` stacking. */\n position: relative;\n z-index: 0;\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050, 4px);\n padding: 0 var(--dimension-space-075, 6px);\n height: var(--dimension-size-400, 32px);\n border-radius: var(--ds-control-radius, var(--dimension-radius-025, 2px));\n cursor: default;\n color: var(--_nav-fg-secondary);\n box-sizing: border-box;\n width: 100%;\n user-select: none;\n transition: color var(--effect-motion-short-1, 50ms ease-in-out);\n /* Hover/press: `.ds-interaction-fill` — no --selected (icon/type weight only). */\n}\n\n/* ── Active item ─────────────────────────────────────────────────────────── */\n\n.panel-nav__item--active {\n color: var(--_nav-fg-primary);\n /* Bold typography via ds-text (text-body-medium + emphasis) on the label */\n}\n\n.panel-nav__parent--muted {\n color: var(--_nav-fg-secondary);\n}\n\n.panel-nav__child {\n flex: 0 0 var(--_nav-item-height);\n padding-inline-start: calc(\n var(--dimension-space-075, 6px) + var(--dimension-iconography-md) + var(--dimension-space-050)\n );\n}\n\n.panel-nav__children-accordion:not(.panel-nav__children-accordion--open) .panel-nav__child {\n color: var(--_nav-fg-secondary);\n}\n\n.panel-nav__child-dot {\n position: relative;\n z-index: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 var(--dimension-iconography-md);\n width: var(--dimension-iconography-md);\n height: var(--dimension-iconography-md);\n}\n\n.panel-nav__child--inactive {\n color: var(--_nav-fg-tertiary);\n}\n\n.panel-nav__child--inactive::after {\n display: none;\n}\n\n/* ── Item icon ───────────────────────────────────────────────────────────── */\n\n.panel-nav__item-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n position: relative;\n z-index: 2;\n}\n\n/* ── Item label ──────────────────────────────────────────────────────────── */\n\n.panel-nav__item-label {\n position: relative;\n z-index: 2;\n flex: 1;\n min-width: 0;\n height: var(--typography-lineheight-md, 20px);\n opacity: 1;\n /* Gradient wipe: mask sweeps left-to-right on expand, right-to-left on collapse */\n /* stylelint-disable-next-line color-named -- mask luminance stops, not theme colors */\n mask-image: linear-gradient(to right, black 50%, transparent 100%);\n /* stylelint-disable-next-line color-named -- mask luminance stops, not theme colors */\n -webkit-mask-image: linear-gradient(to right, black 50%, transparent 100%);\n mask-size: 200% 100%;\n -webkit-mask-size: 200% 100%;\n mask-position: 0% 0;\n -webkit-mask-position: 0% 0;\n transition:\n opacity var(--_nav-label-fade-motion) 0ms,\n mask-position var(--_nav-label-fade-motion) 0ms,\n -webkit-mask-position var(--_nav-label-fade-motion) 0ms;\n}\n\n.panel-nav__item-label-text {\n padding: 0 var(--ds-control-label-inset);\n}\n\n/* ── Item notification dot — 20px suffix zone matches the icon geometry ──── */\n\n.panel-nav__item-dot-box {\n position: absolute;\n z-index: 2;\n right: var(--dimension-space-075, 6px);\n top: var(--dimension-space-075, 6px);\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n pointer-events: none;\n}\n\n.panel-nav__item-dot {\n transition: transform var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__item-dot {\n transform: translate(\n calc(var(--dimension-space-075, 6px) + var(--dimension-stroke-width-012, 1px)),\n calc(0px - var(--dimension-space-075, 6px) - var(--dimension-stroke-width-012, 1px))\n );\n}\n\n.panel-nav--animating .panel-nav__item-label {\n text-overflow: clip;\n}\n\n.panel-nav--collapsed .panel-nav__item-label {\n opacity: 0;\n pointer-events: none;\n text-overflow: clip;\n mask-position: 100% 0;\n -webkit-mask-position: 100% 0;\n transition:\n opacity var(--_nav-label-fade-out-motion) 0ms,\n mask-position var(--_nav-label-fade-out-motion) 0ms,\n -webkit-mask-position var(--_nav-label-fade-out-motion) 0ms;\n}\n\n.panel-nav--collapsed.panel-nav--animating .panel-nav__children-accordion {\n transition-duration: var(--_nav-expand-dur);\n transition-delay: var(--effect-animation-duration-instant);\n}\n\n.panel-nav--animating .panel-nav__branch-divider {\n transition-duration: var(--_nav-expand-dur), var(--_nav-expand-dur);\n transition-delay:\n var(--effect-animation-duration-instant), var(--effect-animation-duration-instant);\n}\n\n.panel-nav--collapsed:not(.panel-nav--animating) .panel-nav__children {\n display: none;\n}\n\n.panel-nav--collapsed ds-text.panel-nav__group-label {\n opacity: 0;\n max-height: 0;\n padding: 0 calc(var(--dimension-space-075, 6px) + var(--ds-control-label-inset));\n pointer-events: none;\n transition:\n opacity var(--_nav-label-fade-out-motion) 0ms,\n max-height var(--_nav-label-fade-out-motion) 0ms,\n padding var(--_nav-label-fade-out-motion) 0ms,\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Footer ──────────────────────────────────────────────────────────────── */\n\n.panel-nav__footer {\n position: relative;\n flex-shrink: 0;\n /* single row: padding*2 + item */\n height: calc(var(--_nav-padding-y) * 2 + var(--_nav-item-height));\n transition: height var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer {\n /* two rows: padding*2 + item*2 + gap */\n height: calc(\n var(--_nav-padding-y) * 2 + var(--_nav-item-height) * 2 + var(--dimension-space-050, 4px)\n );\n}\n\n/* ── Footer icon button (gear / dashboard) ───────────────────────────────── */\n\n.panel-nav__footer-btn {\n position: absolute;\n left: var(--_nav-padding-x);\n top: var(--_nav-padding-y);\n --ds-button-unfilled-fg: var(--_nav-fg-secondary);\n --ds-button-unfilled-fg-active: var(--_nav-fg-primary);\n --ds-interaction-hover: var(--_nav-hover);\n --ds-interaction-pressed: var(--_nav-pressed);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Footer user — absolutely positioned, slides from row to below gear ───── */\n\n.panel-nav__footer-user {\n position: absolute;\n /* Expanded row: balanced shell inset with an 8px gear-to-user gap. */\n left: calc(var(--_nav-padding-x) + var(--_nav-footer-btn-w) + var(--dimension-space-100, 8px));\n right: var(--_nav-padding-x);\n top: var(--_nav-padding-y);\n width: auto;\n min-width: 0;\n transition:\n left var(--_nav-expand-motion),\n right var(--_nav-expand-motion),\n top var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user {\n /* Resolve one shared square control while keeping both inline edges animatable. */\n left: var(--_nav-padding-x);\n right: calc(100% - var(--_nav-padding-x) - var(--_nav-item-height));\n top: calc(var(--_nav-padding-y) + var(--_nav-item-height) + var(--dimension-space-050, 4px));\n}\n\n/* Label: absolute so it stays in place and only fades — no mask slide */\n.panel-nav__footer-user-label {\n text-align: right;\n position: absolute;\n left: var(--dimension-space-075, 6px);\n right: calc(\n var(--dimension-space-075, 6px) + var(--dimension-iconography-md, 20px) +\n var(--dimension-space-050, 4px)\n );\n top: 50%;\n transform: translateY(-50%);\n flex: none;\n height: var(--typography-lineheight-md, 20px);\n mask-image: none;\n -webkit-mask-image: none;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user-label {\n opacity: 0;\n pointer-events: none;\n mask-position: 0% 0;\n -webkit-mask-position: 0% 0;\n}\n\n/* ── Footer user icon — cross-fades chevron ↔ circle+initial ────────────── */\n\n/* Absolute — right-anchored in expanded, left-anchored in collapsed to match regular item icon position */\n.panel-nav__footer-user-icon {\n position: absolute;\n left: calc(100% - var(--dimension-iconography-md, 20px) - var(--dimension-space-075, 6px));\n top: 0;\n bottom: 0;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: left var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user-icon {\n left: var(--dimension-space-075, 6px);\n}\n\n.panel-nav__footer-icon-expanded,\n.panel-nav__footer-icon-collapsed {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.panel-nav__footer-icon-expanded {\n opacity: 1;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav__footer-icon-collapsed {\n opacity: 0;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-icon-expanded {\n opacity: 0;\n transition: opacity var(--_nav-label-fade-out-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-icon-collapsed {\n opacity: 1;\n transition: opacity var(--_nav-label-fade-out-motion);\n}\n\n/* ── User initial — overlaid on the circle icon ─────────────────────────── */\n\n/*\n * Center the caption glyph on the Circle icon. Don't use inset:0 + flex — the\n * inner `.ds-text__element { width: 100% }` stretches and left-aligns the letter.\n * Translate-centering keeps the complete caption metric box on the icon center;\n * the caption variant remains the sole owner of its line-height.\n * (Do not set `inset: auto` after top/left — it resets them.)\n */\nds-text.panel-nav__user-initial,\nds-text.panel-nav__user-initial.ds-text--caption {\n position: absolute;\n top: 50%;\n left: 50%;\n right: auto;\n bottom: auto;\n transform: translate(-50%, -50%);\n display: block;\n width: max-content;\n max-width: none;\n min-width: 0;\n text-align: center;\n color: inherit;\n pointer-events: none;\n}\n\n/* ── Drag-to-resize handle ───────────────────────────────────────────────── */\n\n/* The resize overlay line — extends past the right edge; keep above workspace content */\n.panel-nav__resize-handle {\n position: absolute;\n top: 0;\n /* Centered on the right edge: --dimension-space-050 outside + inside = --dimension-space-100 hit zone */\n right: var(--dimension-space-n050, -4px);\n bottom: 0;\n width: var(--dimension-space-100, 8px);\n z-index: 20;\n cursor: ew-resize;\n touch-action: none;\n /* Needs a real background for Safari hit-testing */\n background: transparent;\n}\n\n/* Safari requires non-transparent fill for hit testing */\n.panel-nav__resize-handle::before {\n content: '';\n position: absolute;\n inset: 0;\n /* stylelint-disable-next-line color-named -- near-invisible hit-test fill; not a theme color */\n background: rgba(0, 0, 0, 0.001);\n}\n\n/* Resize overlay line */\n.panel-nav__resize-handle::after {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n width: var(--dimension-stroke-width-025, 2px);\n background: var(--color-foreground-primary);\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--effect-motion-short-2, 100ms ease-in-out);\n}\n\n.panel-nav__resize-handle--overlay::after {\n opacity: 1;\n}\n\n/* ── Reduced motion ──────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .panel-nav,\n .panel-nav *,\n .panel-nav *::before,\n .panel-nav *::after,\n .panel-nav__resize-handle,\n .panel-nav__resize-handle::before,\n .panel-nav__resize-handle::after {\n /* Near-instant — browsers treat 0 as \"no transition\" and can skip the end state. */\n transition-duration: var(--effect-animation-duration-instant) !important;\n animation-duration: var(--effect-animation-duration-instant) !important;\n transition-delay: var(--effect-animation-duration-instant) !important;\n }\n}\n",
|
|
737
|
+
"content": "@import '../../utils/radius.css';\n@import '../../utils/control-density.css';\n@import '../../utils/chrome-layout.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n@import '../../utils/scrollbar-hidden.css';\n@import '../../utils/nav-disclosure.css';\n\n/* ── Theme variables ──────────────────────────────────────────────────────── */\n\n.panel-nav {\n /* ─ Sizes ─ */\n --_nav-width: var(--dimension-panel-width-2xs);\n --_nav-width-collapsed: var(--dimension-size-600);\n --_nav-item-height: var(--dimension-size-400, 32px);\n --_nav-padding-x: var(--dimension-space-100, 8px);\n --_nav-padding-y: var(--dimension-space-100, 8px);\n /* gear button outer width = padding*2 + icon */\n --_nav-footer-btn-w: calc(\n var(--dimension-space-075, 6px) * 2 + var(--dimension-iconography-md, 20px)\n );\n\n /* ─ Motion ─ */\n /* --ds-panel-nav-speed: unitless multiplier; override in Storybook to slow-mo (e.g. 10 = 10×).\n *-dur vars are duration-only (needed for calc); *-motion vars add easing for use in transitions. */\n --_nav-speed: var(--ds-panel-nav-speed, 1);\n --_nav-expand-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-expand-motion: var(--_nav-expand-dur) var(--effect-animation-easing-ease-in-out, ease);\n --_nav-label-fade-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-label-fade-motion: var(--_nav-label-fade-dur)\n var(--effect-animation-easing-ease-in-out, ease);\n --_nav-label-fade-out-dur: calc(\n var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms)\n );\n --_nav-label-fade-out-motion: var(--_nav-label-fade-out-dur)\n var(--effect-animation-easing-ease-in-out, ease);\n\n /* ─ Colours – default chrome (app surfaces) ─ */\n --_nav-bg: var(--color-background-secondary);\n --_nav-border: var(--color-border-tertiary);\n --_nav-divider: var(--color-border-tertiary);\n --_nav-fg-primary: var(--color-foreground-primary);\n --_nav-fg-secondary: var(--color-foreground-secondary);\n --_nav-fg-tertiary: var(--color-foreground-tertiary);\n --_nav-hover: var(--color-interaction-hover);\n --_nav-pressed: var(--color-interaction-pressed);\n --_nav-focus: var(--color-interaction-focus);\n --_nav-dot: var(--color-foreground-bold-brand);\n --ds-interaction-hover: var(--_nav-hover);\n --ds-interaction-pressed: var(--_nav-pressed);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Default chrome overrides ────────────────────────────────────────────── */\n\n/* Shell-owned chrome (bg + wash) — panel is a transparent frame. */\n:host-context(ds-shell-app:not([gradient-preset='none'])) .panel-nav,\n:host-context(ds-shell-app.shell-app--paper-texture) .panel-nav {\n background-color: transparent;\n}\n\n/* Style slots — same app tokens for now; hook texture/glyph layers on these classes later. */\n.panel-nav--dashboard,\n.panel-nav--settings {\n --_nav-bg: var(--color-background-secondary);\n --_nav-border: var(--color-border-tertiary);\n --_nav-divider: var(--color-border-tertiary);\n --_nav-fg-primary: var(--color-foreground-primary);\n --_nav-fg-secondary: var(--color-foreground-secondary);\n --_nav-fg-tertiary: var(--color-foreground-tertiary);\n --_nav-hover: var(--color-interaction-hover);\n --_nav-pressed: var(--color-interaction-pressed);\n --_nav-focus: var(--color-interaction-focus);\n --_nav-dot: var(--color-foreground-bold-brand);\n --ds-interaction-hover: var(--_nav-hover);\n --ds-interaction-pressed: var(--_nav-pressed);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Shell ───────────────────────────────────────────────────────────────── */\n\n.panel-nav {\n display: flex;\n flex-direction: column;\n position: relative;\n width: var(--_nav-width);\n min-width: var(--_nav-width);\n height: 100%;\n background-color: var(--_nav-bg);\n border-right: var(--dimension-stroke-width-012, 1px) solid var(--_nav-border);\n box-sizing: border-box;\n overflow: visible;\n transition:\n width var(--_nav-expand-motion),\n min-width var(--_nav-expand-motion),\n background-color var(--effect-motion-short-3, 200ms ease),\n border-color var(--effect-motion-short-3, 200ms ease);\n font-family: var(--typography-font-family-ui, system-ui);\n isolation: isolate;\n}\n\n.panel-nav__header,\n.panel-nav__body,\n.panel-nav__footer {\n position: relative;\n z-index: 3;\n}\n\n.panel-nav--collapsed {\n width: var(--_nav-width-collapsed);\n min-width: var(--_nav-width-collapsed);\n}\n\n/* ── Header ──────────────────────────────────────────────────────────────── */\n\n.panel-nav__header {\n height: var(--dimension-size-600, 48px);\n flex-shrink: 0;\n border-bottom: var(--dimension-stroke-width-012, 1px) solid var(--_nav-divider);\n transition: border-color var(--effect-motion-short-3, 200ms ease);\n}\n\n.panel-nav__header-btn {\n all: unset;\n /* Re-assert after unset — required for `.ds-interaction-fill` stacking. */\n position: relative;\n z-index: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--dimension-space-075, 6px);\n border-radius: var(--ds-control-radius, var(--dimension-radius-025, 2px));\n cursor: default;\n color: var(--_nav-fg-primary);\n flex-shrink: 0;\n box-sizing: border-box;\n transition: color var(--effect-motion-short-3, 200ms ease);\n /* Hover/press: `.ds-interaction-fill` (tokens from --_nav-* via --ds-interaction-*). */\n}\n\n.panel-nav--breakpoint-locked .panel-nav__header-btn {\n cursor: default;\n}\n\n/* Logo — visible by default; instant swap to toggle on hover (no crossfade overlap) */\n.panel-nav__header-logo {\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n z-index: 2;\n opacity: 1;\n}\n\n.panel-nav__m-mark {\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n display: block;\n}\n\n/* Toggle icon — stacked on logo; under hover wash (::after z-index 3) */\n.panel-nav__header-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n inset: 0;\n z-index: 2;\n opacity: 0;\n pointer-events: none;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .panel-nav:not(.panel-nav--breakpoint-locked)\n .panel-nav__header-btn:hover\n .panel-nav__header-logo {\n opacity: 0;\n }\n\n .panel-nav:not(.panel-nav--breakpoint-locked)\n .panel-nav__header-btn:hover\n .panel-nav__header-toggle {\n opacity: 1;\n }\n}\n/* ── Scrollable body ─────────────────────────────────────────────────────── */\n\n.panel-nav__body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n/* The collapsed rail's outer width includes its 1px divider. Return that pixel\n to the content box so body items match the other 32px rail controls. */\n.panel-nav--collapsed .panel-nav__body {\n padding-inline-end: calc(var(--_nav-padding-x) - var(--dimension-stroke-width-012));\n}\n\n.panel-nav__sections {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-200, 16px);\n width: 100%;\n}\n\n/* ── Group ───────────────────────────────────────────────────────────────── */\n\n.panel-nav__group {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050, 4px);\n}\n\n.panel-nav__branch {\n display: flex;\n flex-direction: column;\n}\n\n.panel-nav__branch-divider-line {\n display: block;\n height: var(--dimension-stroke-width-012);\n margin-inline: var(--dimension-space-075);\n background: var(--_nav-divider);\n}\n\n.panel-nav__branch-divider--before .panel-nav__branch-divider-line {\n margin-block: var(--dimension-space-050) var(--dimension-space-100);\n}\n\n.panel-nav__branch-divider--after .panel-nav__branch-divider-line {\n margin-block: var(--dimension-space-100) var(--dimension-space-050);\n}\n\n.panel-nav__children-accordion,\n.panel-nav__branch-divider {\n --ds-nav-disclosure-duration: var(\n --_panel-nav-nested-section-duration,\n calc(var(--effect-animation-duration-short-3) * 2 + var(--effect-animation-duration-short-2))\n );\n --ds-nav-disclosure-wait: var(\n --_panel-nav-nested-transition-wait,\n calc(var(--effect-animation-duration-short-3) + var(--effect-animation-duration-short-1))\n );\n --ds-nav-disclosure-fade: var(\n --_panel-nav-nested-child-fade-duration,\n var(--ds-nav-disclosure-duration)\n );\n --ds-nav-disclosure-stagger: var(\n --_panel-nav-nested-child-stagger,\n var(--effect-animation-duration-short-1)\n );\n}\n\n.panel-nav__children {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050, 4px);\n min-height: 0;\n overflow: hidden;\n}\n\n/* Margin lives on the first child so closed 0fr accordions still collapse to 0. */\n.panel-nav__children > .panel-nav__child:first-child {\n margin-block-start: var(--dimension-space-050, 4px);\n}\n\n/*\n * Section headers — typography via ds-text (text-caption + emphasis).\n * Element selector so display:flex beats Text's inline-block, and padding\n * isn't clobbered by sharing `.panel-nav__item-label-text` on the same host.\n */\nds-text.panel-nav__group-label {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n text-transform: uppercase;\n color: var(--_nav-fg-secondary);\n user-select: none;\n height: var(--dimension-size-300, 24px);\n /* Former nested pad: group-label (075) + item-label-text (025). */\n padding: 0 calc(var(--dimension-space-075, 6px) + var(--ds-control-label-inset));\n white-space: nowrap;\n overflow: hidden;\n max-height: var(--dimension-size-300, 24px);\n opacity: 1;\n transition:\n opacity var(--_nav-label-fade-motion) 0ms,\n max-height var(--_nav-label-fade-motion) 0ms,\n padding var(--_nav-label-fade-motion) 0ms,\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Item ────────────────────────────────────────────────────────────────── */\n\n.panel-nav__item {\n all: unset;\n /* Re-assert after unset — required for `.ds-interaction-fill` stacking. */\n position: relative;\n z-index: 0;\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050, 4px);\n padding: 0 var(--dimension-space-075, 6px);\n height: var(--dimension-size-400, 32px);\n border-radius: var(--ds-control-radius, var(--dimension-radius-025, 2px));\n cursor: default;\n color: var(--_nav-fg-secondary);\n box-sizing: border-box;\n width: 100%;\n user-select: none;\n transition: color var(--effect-motion-short-1, 50ms ease-in-out);\n /* Hover/press: `.ds-interaction-fill` — no --selected (icon/type weight only). */\n}\n\n/* ── Active item ─────────────────────────────────────────────────────────── */\n\n.panel-nav__item--active {\n color: var(--_nav-fg-primary);\n /* Bold typography via ds-text (text-body-medium + emphasis) on the label */\n}\n\n.panel-nav__parent--muted {\n color: var(--_nav-fg-secondary);\n}\n\n.panel-nav__child {\n flex: 0 0 var(--_nav-item-height);\n padding-inline-start: calc(\n var(--dimension-space-075, 6px) + var(--dimension-iconography-md) + var(--dimension-space-050)\n );\n}\n\n.panel-nav__children-accordion:not(.panel-nav__children-accordion--open) .panel-nav__child {\n color: var(--_nav-fg-secondary);\n}\n\n.panel-nav__child-dot {\n position: relative;\n z-index: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 var(--dimension-iconography-md);\n width: var(--dimension-iconography-md);\n height: var(--dimension-iconography-md);\n}\n\n.panel-nav__child--inactive {\n color: var(--_nav-fg-tertiary);\n}\n\n.panel-nav__child--inactive::after {\n display: none;\n}\n\n/* ── Item icon ───────────────────────────────────────────────────────────── */\n\n.panel-nav__item-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n position: relative;\n z-index: 2;\n}\n\n/* ── Item label ──────────────────────────────────────────────────────────── */\n\n.panel-nav__item-label {\n position: relative;\n z-index: 2;\n flex: 1;\n min-width: 0;\n height: var(--typography-lineheight-md, 20px);\n opacity: 1;\n /* Gradient wipe: mask sweeps left-to-right on expand, right-to-left on collapse */\n /* eslint-disable-next-line compomo/color-named -- mask luminance stops, not theme colors */\n mask-image: linear-gradient(to right, black 50%, transparent 100%);\n /* eslint-disable-next-line compomo/color-named -- mask luminance stops, not theme colors */\n -webkit-mask-image: linear-gradient(to right, black 50%, transparent 100%);\n mask-size: 200% 100%;\n -webkit-mask-size: 200% 100%;\n mask-position: 0% 0;\n -webkit-mask-position: 0% 0;\n transition:\n opacity var(--_nav-label-fade-motion) 0ms,\n mask-position var(--_nav-label-fade-motion) 0ms,\n -webkit-mask-position var(--_nav-label-fade-motion) 0ms;\n}\n\n.panel-nav__item-label-text {\n padding: 0 var(--ds-control-label-inset);\n}\n\n/* ── Item notification dot — 20px suffix zone matches the icon geometry ──── */\n\n.panel-nav__item-dot-box {\n position: absolute;\n z-index: 2;\n right: var(--dimension-space-075, 6px);\n top: var(--dimension-space-075, 6px);\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n pointer-events: none;\n}\n\n.panel-nav__item-dot {\n transition: transform var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__item-dot {\n transform: translate(\n calc(var(--dimension-space-075, 6px) + var(--dimension-stroke-width-012, 1px)),\n calc(0px - var(--dimension-space-075, 6px) - var(--dimension-stroke-width-012, 1px))\n );\n}\n\n.panel-nav--animating .panel-nav__item-label {\n text-overflow: clip;\n}\n\n.panel-nav--collapsed .panel-nav__item-label {\n opacity: 0;\n pointer-events: none;\n text-overflow: clip;\n mask-position: 100% 0;\n -webkit-mask-position: 100% 0;\n transition:\n opacity var(--_nav-label-fade-out-motion) 0ms,\n mask-position var(--_nav-label-fade-out-motion) 0ms,\n -webkit-mask-position var(--_nav-label-fade-out-motion) 0ms;\n}\n\n.panel-nav--collapsed.panel-nav--animating .panel-nav__children-accordion {\n transition-duration: var(--_nav-expand-dur);\n transition-delay: var(--effect-animation-duration-instant);\n}\n\n.panel-nav--animating .panel-nav__branch-divider {\n transition-duration: var(--_nav-expand-dur), var(--_nav-expand-dur);\n transition-delay:\n var(--effect-animation-duration-instant), var(--effect-animation-duration-instant);\n}\n\n.panel-nav--collapsed:not(.panel-nav--animating) .panel-nav__children {\n display: none;\n}\n\n.panel-nav--collapsed ds-text.panel-nav__group-label {\n opacity: 0;\n max-height: 0;\n padding: 0 calc(var(--dimension-space-075, 6px) + var(--ds-control-label-inset));\n pointer-events: none;\n transition:\n opacity var(--_nav-label-fade-out-motion) 0ms,\n max-height var(--_nav-label-fade-out-motion) 0ms,\n padding var(--_nav-label-fade-out-motion) 0ms,\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Footer ──────────────────────────────────────────────────────────────── */\n\n.panel-nav__footer {\n position: relative;\n flex-shrink: 0;\n /* single row: padding*2 + item */\n height: calc(var(--_nav-padding-y) * 2 + var(--_nav-item-height));\n transition: height var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer {\n /* two rows: padding*2 + item*2 + gap */\n height: calc(\n var(--_nav-padding-y) * 2 + var(--_nav-item-height) * 2 + var(--dimension-space-050, 4px)\n );\n}\n\n/* ── Footer icon button (gear / dashboard) ───────────────────────────────── */\n\n.panel-nav__footer-btn {\n position: absolute;\n left: var(--_nav-padding-x);\n top: var(--_nav-padding-y);\n --ds-button-unfilled-fg: var(--_nav-fg-secondary);\n --ds-button-unfilled-fg-active: var(--_nav-fg-primary);\n --ds-interaction-hover: var(--_nav-hover);\n --ds-interaction-pressed: var(--_nav-pressed);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Footer user — absolutely positioned, slides from row to below gear ───── */\n\n.panel-nav__footer-user {\n position: absolute;\n /* Expanded row: balanced shell inset with an 8px gear-to-user gap. */\n left: calc(var(--_nav-padding-x) + var(--_nav-footer-btn-w) + var(--dimension-space-100, 8px));\n right: var(--_nav-padding-x);\n top: var(--_nav-padding-y);\n width: auto;\n min-width: 0;\n transition:\n left var(--_nav-expand-motion),\n right var(--_nav-expand-motion),\n top var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user {\n /* Resolve one shared square control while keeping both inline edges animatable. */\n left: var(--_nav-padding-x);\n right: calc(100% - var(--_nav-padding-x) - var(--_nav-item-height));\n top: calc(var(--_nav-padding-y) + var(--_nav-item-height) + var(--dimension-space-050, 4px));\n}\n\n/* Label: absolute so it stays in place and only fades — no mask slide */\n.panel-nav__footer-user-label {\n text-align: right;\n position: absolute;\n left: var(--dimension-space-075, 6px);\n right: calc(\n var(--dimension-space-075, 6px) + var(--dimension-iconography-md, 20px) +\n var(--dimension-space-050, 4px)\n );\n top: 50%;\n transform: translateY(-50%);\n flex: none;\n height: var(--typography-lineheight-md, 20px);\n mask-image: none;\n -webkit-mask-image: none;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user-label {\n opacity: 0;\n pointer-events: none;\n mask-position: 0% 0;\n -webkit-mask-position: 0% 0;\n}\n\n/* ── Footer user icon — cross-fades chevron ↔ circle+initial ────────────── */\n\n/* Absolute — right-anchored in expanded, left-anchored in collapsed to match regular item icon position */\n.panel-nav__footer-user-icon {\n position: absolute;\n left: calc(100% - var(--dimension-iconography-md, 20px) - var(--dimension-space-075, 6px));\n top: 0;\n bottom: 0;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: left var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user-icon {\n left: var(--dimension-space-075, 6px);\n}\n\n.panel-nav__footer-icon-expanded,\n.panel-nav__footer-icon-collapsed {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.panel-nav__footer-icon-expanded {\n opacity: 1;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav__footer-icon-collapsed {\n opacity: 0;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-icon-expanded {\n opacity: 0;\n transition: opacity var(--_nav-label-fade-out-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-icon-collapsed {\n opacity: 1;\n transition: opacity var(--_nav-label-fade-out-motion);\n}\n\n/* ── User initial — overlaid on the circle icon ─────────────────────────── */\n\n/*\n * Center the caption glyph on the Circle icon. Don't use inset:0 + flex — the\n * inner `.ds-text__element { width: 100% }` stretches and left-aligns the letter.\n * Translate-centering keeps the complete caption metric box on the icon center;\n * the caption variant remains the sole owner of its line-height.\n * (Do not set `inset: auto` after top/left — it resets them.)\n */\nds-text.panel-nav__user-initial,\nds-text.panel-nav__user-initial.ds-text--caption {\n position: absolute;\n top: 50%;\n left: 50%;\n right: auto;\n bottom: auto;\n transform: translate(-50%, -50%);\n display: block;\n width: max-content;\n max-width: none;\n min-width: 0;\n text-align: center;\n color: inherit;\n pointer-events: none;\n}\n\n/* ── Drag-to-resize handle ───────────────────────────────────────────────── */\n\n/* The resize overlay line — extends past the right edge; keep above workspace content */\n.panel-nav__resize-handle {\n position: absolute;\n top: 0;\n /* Centered on the right edge: --dimension-space-050 outside + inside = --dimension-space-100 hit zone */\n right: var(--dimension-space-n050, -4px);\n bottom: 0;\n width: var(--dimension-space-100, 8px);\n z-index: 20;\n cursor: ew-resize;\n touch-action: none;\n /* Needs a real background for Safari hit-testing */\n background: transparent;\n}\n\n/* Safari requires non-transparent fill for hit testing */\n.panel-nav__resize-handle::before {\n content: '';\n position: absolute;\n inset: 0;\n /* eslint-disable-next-line compomo/color-named -- near-invisible hit-test fill; not a theme color */\n background: rgba(0, 0, 0, 0.001);\n}\n\n/* Resize overlay line */\n.panel-nav__resize-handle::after {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n width: var(--dimension-stroke-width-025, 2px);\n background: var(--color-foreground-primary);\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--effect-motion-short-2, 100ms ease-in-out);\n}\n\n.panel-nav__resize-handle--overlay::after {\n opacity: 1;\n}\n\n/* ── Reduced motion ──────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .panel-nav,\n .panel-nav *,\n .panel-nav *::before,\n .panel-nav *::after,\n .panel-nav__resize-handle,\n .panel-nav__resize-handle::before,\n .panel-nav__resize-handle::after {\n /* Near-instant — browsers treat 0 as \"no transition\" and can skip the end state. */\n transition-duration: var(--effect-animation-duration-instant) !important;\n animation-duration: var(--effect-animation-duration-instant) !important;\n transition-delay: var(--effect-animation-duration-instant) !important;\n }\n}\n",
|
|
712
738
|
"type": "registry:ui"
|
|
713
739
|
},
|
|
714
740
|
{
|
|
@@ -82,6 +82,31 @@
|
|
|
82
82
|
"angular": [
|
|
83
83
|
"Bind items and a valid value as properties, and handle dsChange to synchronize the visible panel."
|
|
84
84
|
]
|
|
85
|
+
},
|
|
86
|
+
"styling": {
|
|
87
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
88
|
+
"protected": [
|
|
89
|
+
{
|
|
90
|
+
"properties": [
|
|
91
|
+
"background",
|
|
92
|
+
"border",
|
|
93
|
+
"box-shadow",
|
|
94
|
+
"color"
|
|
95
|
+
],
|
|
96
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
97
|
+
"props": [
|
|
98
|
+
"background"
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"properties": [
|
|
103
|
+
"border-radius"
|
|
104
|
+
],
|
|
105
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
106
|
+
"props": []
|
|
107
|
+
}
|
|
108
|
+
],
|
|
109
|
+
"customProperties": []
|
|
85
110
|
}
|
|
86
111
|
},
|
|
87
112
|
"api": {
|
|
@@ -50,7 +50,30 @@
|
|
|
50
50
|
"label": "Surface ownership and trigger state",
|
|
51
51
|
"path": "src/docs/SurfaceOwnership.mdx"
|
|
52
52
|
}
|
|
53
|
-
]
|
|
53
|
+
],
|
|
54
|
+
"styling": {
|
|
55
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
56
|
+
"protected": [
|
|
57
|
+
{
|
|
58
|
+
"properties": [
|
|
59
|
+
"background",
|
|
60
|
+
"border",
|
|
61
|
+
"box-shadow",
|
|
62
|
+
"color"
|
|
63
|
+
],
|
|
64
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
65
|
+
"props": []
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"properties": [
|
|
69
|
+
"border-radius"
|
|
70
|
+
],
|
|
71
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
72
|
+
"props": []
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"customProperties": []
|
|
76
|
+
}
|
|
54
77
|
},
|
|
55
78
|
"api": {
|
|
56
79
|
"props": {
|
|
@@ -67,7 +67,30 @@
|
|
|
67
67
|
"label": "Surface ownership and trigger state",
|
|
68
68
|
"path": "src/docs/SurfaceOwnership.mdx"
|
|
69
69
|
}
|
|
70
|
-
]
|
|
70
|
+
],
|
|
71
|
+
"styling": {
|
|
72
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
73
|
+
"protected": [
|
|
74
|
+
{
|
|
75
|
+
"properties": [
|
|
76
|
+
"background",
|
|
77
|
+
"border",
|
|
78
|
+
"box-shadow",
|
|
79
|
+
"color"
|
|
80
|
+
],
|
|
81
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
82
|
+
"props": []
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"properties": [
|
|
86
|
+
"border-radius"
|
|
87
|
+
],
|
|
88
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
89
|
+
"props": []
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
"customProperties": []
|
|
93
|
+
}
|
|
71
94
|
},
|
|
72
95
|
"api": {
|
|
73
96
|
"props": {
|
|
@@ -138,7 +138,31 @@
|
|
|
138
138
|
"label": "Surface ownership and trigger state",
|
|
139
139
|
"path": "src/docs/SurfaceOwnership.mdx"
|
|
140
140
|
}
|
|
141
|
-
]
|
|
141
|
+
],
|
|
142
|
+
"styling": {
|
|
143
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
144
|
+
"protected": [
|
|
145
|
+
{
|
|
146
|
+
"properties": [
|
|
147
|
+
"background",
|
|
148
|
+
"border",
|
|
149
|
+
"box-shadow"
|
|
150
|
+
],
|
|
151
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
152
|
+
"props": [
|
|
153
|
+
"presentation"
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"properties": [
|
|
158
|
+
"border-radius"
|
|
159
|
+
],
|
|
160
|
+
"reason": "The component owns its surface radius; retain the shared recipe and customize an outer wrapper when needed.",
|
|
161
|
+
"props": []
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
"customProperties": []
|
|
165
|
+
}
|
|
142
166
|
},
|
|
143
167
|
"api": {
|
|
144
168
|
"props": {
|
|
@@ -56,7 +56,12 @@
|
|
|
56
56
|
"label": "Storybook parameter playground",
|
|
57
57
|
"path": "src/wc/components/PaperTexture/PaperTexture.stories.ts"
|
|
58
58
|
}
|
|
59
|
-
]
|
|
59
|
+
],
|
|
60
|
+
"styling": {
|
|
61
|
+
"rationale": "The decorative shader intentionally accepts custom parameters and observes application-owned host dimensions.",
|
|
62
|
+
"protected": [],
|
|
63
|
+
"customProperties": []
|
|
64
|
+
}
|
|
60
65
|
},
|
|
61
66
|
"api": {
|
|
62
67
|
"props": {
|
|
@@ -86,7 +86,41 @@
|
|
|
86
86
|
"label": "Cross-browser form and accessibility coverage",
|
|
87
87
|
"path": "tests/e2e/forms.spec.ts"
|
|
88
88
|
}
|
|
89
|
-
]
|
|
89
|
+
],
|
|
90
|
+
"styling": {
|
|
91
|
+
"rationale": "The component owns the protected recipes below; unspecified host properties and application layout remain customizable.",
|
|
92
|
+
"protected": [
|
|
93
|
+
{
|
|
94
|
+
"properties": [
|
|
95
|
+
"font",
|
|
96
|
+
"font-size",
|
|
97
|
+
"font-weight",
|
|
98
|
+
"font-family",
|
|
99
|
+
"line-height",
|
|
100
|
+
"letter-spacing",
|
|
101
|
+
"padding",
|
|
102
|
+
"border-radius"
|
|
103
|
+
],
|
|
104
|
+
"reason": "The field primitive owns its density and selection anatomy; use size and presentation props without replacing the recipe.",
|
|
105
|
+
"props": [
|
|
106
|
+
"size"
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"properties": [
|
|
111
|
+
"background",
|
|
112
|
+
"border",
|
|
113
|
+
"box-shadow",
|
|
114
|
+
"color"
|
|
115
|
+
],
|
|
116
|
+
"reason": "The component owns its surface and interaction treatment; use its semantic presentation props or compose an application-owned surrounding surface.",
|
|
117
|
+
"props": [
|
|
118
|
+
"size"
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
"customProperties": []
|
|
123
|
+
}
|
|
90
124
|
},
|
|
91
125
|
"api": {
|
|
92
126
|
"props": {
|