@ds-mo/ui 13.11.1 → 13.12.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/dist/.package-ready.json +1 -1
- package/dist/agent-patterns.json +1 -1
- package/dist/agent.json +288 -10
- package/dist/angular/ds-mobile-header.d.ts +1 -1
- package/dist/angular/ds-mobile-header.js +3 -3
- package/dist/angular/ds-tab-group.d.ts +1 -1
- package/dist/angular/ds-tab-group.js +3 -3
- package/dist/angular/ds-table.d.ts +28 -0
- package/dist/angular/ds-table.js +54 -0
- package/dist/angular/ds-tag.d.ts +1 -1
- package/dist/angular/ds-tag.js +3 -3
- package/dist/angular/index.d.ts +1 -1
- package/dist/angular/index.js +1 -0
- package/dist/angular/proxies.d.ts +1 -0
- package/dist/angular/proxies.js +1 -0
- package/dist/components/ds-bar-nav.js +1 -1
- package/dist/components/ds-bar-title.js +1 -1
- package/dist/components/ds-bar-workflow.js +1 -1
- package/dist/components/ds-bar-workflow.js.map +1 -1
- package/dist/components/ds-card-overview.js +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-mobile-header.js +1 -1
- package/dist/components/ds-mobile-section-switcher.js +1 -1
- package/dist/components/ds-mobile-sheet-nav.js +1 -1
- package/dist/components/ds-modal.js +1 -1
- package/dist/components/ds-panel-sub-nav.js +1 -1
- package/dist/components/ds-radio.js +1 -1
- package/dist/components/ds-scroll-overlay.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-shell-app.js.map +1 -1
- package/dist/components/ds-shell-tools.js +1 -1
- package/dist/components/ds-skeleton.js +1 -1
- package/dist/components/ds-slider.js +1 -1
- package/dist/components/ds-switch.js +1 -1
- package/dist/components/ds-tab-group.js +1 -1
- package/dist/components/ds-table.d.ts +11 -0
- package/dist/components/ds-table.js +2 -0
- package/dist/components/ds-table.js.map +1 -0
- package/dist/components/ds-tag.js +1 -1
- package/dist/components/ds-tag.js.map +1 -1
- package/dist/components/ds-toast.js +1 -1
- package/dist/components/ds-typing-indicator.js +1 -1
- package/dist/components/index.d.ts +30 -0
- package/dist/components/{p-BHb3Ws8e.js → p-BFXN4ioL.js} +2 -2
- package/dist/components/{p-DgglLVCj.js → p-BYre-ZDg.js} +2 -2
- package/dist/components/p-B_eqa09C.js +2 -0
- package/dist/components/p-B_eqa09C.js.map +1 -0
- package/dist/components/{p-BnGJrBPG.js → p-Bj7KrXzw.js} +2 -2
- package/dist/components/p-BxJurXEn.js +2 -0
- package/dist/components/p-BxJurXEn.js.map +1 -0
- package/dist/components/{p-Dg9qiMDa.js → p-C9StMCWg.js} +2 -2
- package/dist/components/p-CFNG0K3m.js +2 -0
- package/dist/components/p-CFNG0K3m.js.map +1 -0
- package/dist/components/{p-BQ7Nzx9A.js → p-Ch5yT3UA.js} +2 -2
- package/dist/components/{p-DJGdoPMG.js → p-DKftz0O8.js} +2 -2
- package/dist/components/p-DxygUurH.js +2 -0
- package/dist/components/p-DxygUurH.js.map +1 -0
- package/dist/components/{p-DCN04sgt.js → p-x9jO4lZ7.js} +2 -2
- package/dist/components/{p-DCN04sgt.js.map → p-x9jO4lZ7.js.map} +1 -1
- package/dist/docs/components.json +1547 -100
- package/dist/lib/components/MobileHeader/mobile-header-types.d.ts +3 -2
- package/dist/mcp-data/registry/mobile-header.json +48 -10
- package/dist/mcp-data/registry/mobile-sheet-nav.json +2 -2
- package/dist/mcp-data/registry/registry.json +290 -9
- package/dist/mcp-data/registry/shell-app.json +4 -2
- package/dist/mcp-data/registry/shell-tools.json +4 -4
- package/dist/mcp-data/registry/tab-group.json +22 -2
- package/dist/mcp-data/registry/table.json +758 -0
- package/dist/mcp-data/registry/tag.json +22 -3
- package/dist/react/components.d.ts +1 -0
- package/dist/react/components.js +1 -0
- package/dist/react/ds-table.d.ts +16 -0
- package/dist/react/ds-table.js +18 -0
- package/dist/styles/table.css +677 -0
- package/dist/types/components/MobileHeader/MobileHeader.d.ts +8 -3
- package/dist/types/components/MobileHeader/index.d.ts +1 -1
- package/dist/types/components/MobileHeader/mobile-header-types.d.ts +3 -2
- package/dist/types/components/ShellApp/ShellApp.d.ts +8 -0
- package/dist/types/components/TabGroup/TabGroup.d.ts +3 -0
- package/dist/types/components/Table/Table.d.ts +115 -0
- package/dist/types/components/Table/index.d.ts +2 -0
- package/dist/types/components/Table/table-model.d.ts +29 -0
- package/dist/types/components/Table/table-types.d.ts +178 -0
- package/dist/types/components/Tag/Tag.d.ts +2 -0
- package/dist/types/components.d.ts +393 -6
- package/package.json +3 -2
- package/dist/components/p-CVmtbj-6.js +0 -2
- package/dist/components/p-CVmtbj-6.js.map +0 -1
- package/dist/components/p-DW9p068S.js +0 -2
- package/dist/components/p-DW9p068S.js.map +0 -1
- package/dist/components/p-Xftomzsv.js +0 -2
- package/dist/components/p-Xftomzsv.js.map +0 -1
- /package/dist/components/{p-BHb3Ws8e.js.map → p-BFXN4ioL.js.map} +0 -0
- /package/dist/components/{p-DgglLVCj.js.map → p-BYre-ZDg.js.map} +0 -0
- /package/dist/components/{p-BnGJrBPG.js.map → p-Bj7KrXzw.js.map} +0 -0
- /package/dist/components/{p-Dg9qiMDa.js.map → p-C9StMCWg.js.map} +0 -0
- /package/dist/components/{p-BQ7Nzx9A.js.map → p-Ch5yT3UA.js.map} +0 -0
- /package/dist/components/{p-DJGdoPMG.js.map → p-DKftz0O8.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TabGroupItem } from '../TabGroup/tab-item-utils';
|
|
2
2
|
export type MobileHeaderTone = 'default' | 'brand';
|
|
3
3
|
export type MobileHeaderHeadingLevel = 'h1' | 'h2';
|
|
4
|
-
export type
|
|
4
|
+
export type MobileHeaderSectionsPresentation = 'switcher' | 'segmented';
|
|
5
|
+
export type MobileHeaderSectionItem = TabGroupItem;
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"commonlyComposedWith": [
|
|
25
25
|
"component:ds-mobile-section-switcher",
|
|
26
|
+
"component:ds-tab-group",
|
|
26
27
|
"component:ds-shell-page",
|
|
27
28
|
"component:ds-shell-tools"
|
|
28
29
|
],
|
|
@@ -31,19 +32,19 @@
|
|
|
31
32
|
],
|
|
32
33
|
"accessibility": [
|
|
33
34
|
"Static screens render a real h1 or h2 according to headingLevel.",
|
|
34
|
-
"Section-switching screens expose an equivalent semantic heading alongside the accessible popup trigger.",
|
|
35
|
+
"Section-switching screens expose an equivalent semantic heading alongside the accessible popup trigger or named segmented TabGroup.",
|
|
35
36
|
"Subsections use a separately named navigation landmark and never replace the semantic page identity.",
|
|
36
37
|
"Leading and trailing slotted icon actions retain their own accessible names and tooltips."
|
|
37
38
|
],
|
|
38
39
|
"states": [
|
|
39
40
|
"Without multiple sections the center renders heading.",
|
|
40
|
-
"With multiple sections the center renders the controlled MobileSectionSwitcher.",
|
|
41
|
+
"With multiple sections the center renders the controlled MobileSectionSwitcher by default or an explicitly requested segmented TabGroup.",
|
|
41
42
|
"Optional subsections render in a second row and emit dsSubsectionChange without changing the primary section.",
|
|
42
43
|
"Sections represent peer destinations at the current navigation level; subsections represent local views beneath the selected page or detail identity.",
|
|
43
44
|
"Brand tone changes surface and foreground without changing geometry or interaction ownership."
|
|
44
45
|
],
|
|
45
46
|
"responsiveBehavior": [
|
|
46
|
-
"The primary
|
|
47
|
+
"The primary 56px lane matches the Mobile Sheet Nav header and Mobile Bar Nav; optional subsections add one subordinate 48px lane.",
|
|
47
48
|
"Equal flexible side lanes keep the center mathematically aligned when actions are asymmetric."
|
|
48
49
|
],
|
|
49
50
|
"references": [
|
|
@@ -74,8 +75,8 @@
|
|
|
74
75
|
"description": "Semantic heading level for the active mobile screen."
|
|
75
76
|
},
|
|
76
77
|
"sections": {
|
|
77
|
-
"type": "
|
|
78
|
-
"resolvedType": "
|
|
78
|
+
"type": "TabGroupItem[]",
|
|
79
|
+
"resolvedType": "TabGroupItem[]",
|
|
79
80
|
"default": "[]",
|
|
80
81
|
"required": false,
|
|
81
82
|
"mutable": false,
|
|
@@ -90,6 +91,24 @@
|
|
|
90
91
|
"mutable": false,
|
|
91
92
|
"description": "Accessible name for the section chooser."
|
|
92
93
|
},
|
|
94
|
+
"sectionsPresentation": {
|
|
95
|
+
"type": "MobileHeaderSectionsPresentation",
|
|
96
|
+
"resolvedType": "\"segmented\" | \"switcher\"",
|
|
97
|
+
"attribute": "sections-presentation",
|
|
98
|
+
"default": "'switcher'",
|
|
99
|
+
"required": false,
|
|
100
|
+
"mutable": false,
|
|
101
|
+
"description": "Popup switcher or an inline segmented TabGroup for peer sections."
|
|
102
|
+
},
|
|
103
|
+
"sectionsSize": {
|
|
104
|
+
"type": "TabGroupSize",
|
|
105
|
+
"resolvedType": "\"lg\" | \"md\" | \"sm\"",
|
|
106
|
+
"attribute": "sections-size",
|
|
107
|
+
"default": "'md'",
|
|
108
|
+
"required": false,
|
|
109
|
+
"mutable": false,
|
|
110
|
+
"description": "Density for the segmented sections presentation."
|
|
111
|
+
},
|
|
93
112
|
"subsections": {
|
|
94
113
|
"type": "TabItem[]",
|
|
95
114
|
"resolvedType": "TabItem[]",
|
|
@@ -176,8 +195,8 @@
|
|
|
176
195
|
"description": "Semantic heading level for the active mobile screen."
|
|
177
196
|
},
|
|
178
197
|
"sections": {
|
|
179
|
-
"type": "
|
|
180
|
-
"resolvedType": "
|
|
198
|
+
"type": "TabGroupItem[]",
|
|
199
|
+
"resolvedType": "TabGroupItem[]",
|
|
181
200
|
"default": "[]",
|
|
182
201
|
"required": false,
|
|
183
202
|
"mutable": false,
|
|
@@ -192,6 +211,24 @@
|
|
|
192
211
|
"mutable": false,
|
|
193
212
|
"description": "Accessible name for the section chooser."
|
|
194
213
|
},
|
|
214
|
+
"sectionsPresentation": {
|
|
215
|
+
"type": "MobileHeaderSectionsPresentation",
|
|
216
|
+
"resolvedType": "\"segmented\" | \"switcher\"",
|
|
217
|
+
"attribute": "sections-presentation",
|
|
218
|
+
"default": "'switcher'",
|
|
219
|
+
"required": false,
|
|
220
|
+
"mutable": false,
|
|
221
|
+
"description": "Popup switcher or an inline segmented TabGroup for peer sections."
|
|
222
|
+
},
|
|
223
|
+
"sectionsSize": {
|
|
224
|
+
"type": "TabGroupSize",
|
|
225
|
+
"resolvedType": "\"lg\" | \"md\" | \"sm\"",
|
|
226
|
+
"attribute": "sections-size",
|
|
227
|
+
"default": "'md'",
|
|
228
|
+
"required": false,
|
|
229
|
+
"mutable": false,
|
|
230
|
+
"description": "Density for the segmented sections presentation."
|
|
231
|
+
},
|
|
195
232
|
"subsections": {
|
|
196
233
|
"type": "TabItem[]",
|
|
197
234
|
"resolvedType": "TabItem[]",
|
|
@@ -293,22 +330,23 @@
|
|
|
293
330
|
],
|
|
294
331
|
"registryDependencies": [
|
|
295
332
|
"mobile-section-switcher",
|
|
333
|
+
"tab-group",
|
|
296
334
|
"text"
|
|
297
335
|
],
|
|
298
336
|
"files": [
|
|
299
337
|
{
|
|
300
338
|
"path": "src/wc/components/MobileHeader/MobileHeader.css",
|
|
301
|
-
"content": "@import '../../utils/chrome-layout.css';\n\n:host {\n display: block;\n min-width: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n color: var(--color-foreground-primary);\n}\n\n:host([tone='brand']) {\n background: var(--color-background-bold-brand);\n color: var(--color-foreground-on-bold);\n}\n\n.mobile-header {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n background: inherit;\n color: inherit;\n}\n\n.mobile-header__primary {\n grid-template-columns: minmax(var(--dimension-size-400), 1fr) minmax(0, auto) minmax(var(--dimension-size-400), 1fr);\n width: 100%;\n height: var(--dimension-size-
|
|
339
|
+
"content": "@import '../../utils/chrome-layout.css';\n\n:host {\n display: block;\n min-width: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n color: var(--color-foreground-primary);\n}\n\n:host([tone='brand']) {\n background: var(--color-background-bold-brand);\n color: var(--color-foreground-on-bold);\n}\n\n.mobile-header {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n background: inherit;\n color: inherit;\n}\n\n.mobile-header__primary {\n grid-template-columns: minmax(var(--dimension-size-400), 1fr) minmax(0, auto) minmax(var(--dimension-size-400), 1fr);\n width: 100%;\n height: calc(var(--dimension-size-500) + var(--dimension-space-200));\n min-width: 0;\n background: inherit;\n color: inherit;\n}\n\n:host(:not([tone='brand'])) .mobile-header::after {\n content: '';\n position: absolute;\n inset-inline: 0;\n inset-block-end: 0;\n height: var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.mobile-header__subsections {\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 0;\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100) var(--dimension-space-200);\n box-sizing: border-box;\n}\n\n.mobile-header__subsections ds-mobile-section-switcher {\n min-width: 0;\n max-width: 100%;\n}\n\n.mobile-header__lane {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.mobile-header__lane--leading {\n justify-content: flex-start;\n}\n\n.mobile-header__lane--trailing {\n justify-content: flex-end;\n}\n\n.mobile-header__center {\n position: relative;\n min-width: 0;\n max-width: 100%;\n justify-self: center;\n}\n\n.mobile-header__heading {\n display: block;\n min-width: 0;\n max-width: 100%;\n text-align: center;\n}\n\n.mobile-header__semantic-heading {\n position: absolute;\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-stroke-width-012);\n padding: 0;\n margin: calc(var(--dimension-stroke-width-012) * -1);\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n::slotted([slot='leading']),\n::slotted([slot='trailing']) {\n flex: 0 0 auto;\n}\n",
|
|
302
340
|
"type": "registry:ui"
|
|
303
341
|
},
|
|
304
342
|
{
|
|
305
343
|
"path": "src/wc/components/MobileHeader/MobileHeader.tsx",
|
|
306
|
-
"content": "import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';\nimport {
|
|
344
|
+
"content": "import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';\nimport {\n getSelectableTabs,\n type TabGroupItem,\n type TabItem,\n} from '../TabGroup/tab-item-utils';\nimport type { TabGroupSize } from '../TabGroup/TabGroup';\nimport type {\n MobileHeaderHeadingLevel,\n MobileHeaderSectionsPresentation,\n MobileHeaderTone,\n} from './mobile-header-types';\n\n@Component({\n tag: 'ds-mobile-header',\n styleUrl: 'MobileHeader.css',\n scoped: true,\n})\nexport class MobileHeader {\n /** Static title used when no peer sections are supplied. */\n @Prop() heading: string = '';\n /** Semantic heading level for the active mobile screen. */\n @Prop() headingLevel: MobileHeaderHeadingLevel = 'h1';\n /** Controlled peer sections. Their selected label replaces the static title. */\n @Prop() sections: TabGroupItem[] = [];\n /** Controlled selected section id. */\n @Prop() value: string = '';\n /** Accessible name for the section chooser. */\n @Prop() sectionsAriaLabel: string = 'Change page section';\n /** Popup switcher or an inline segmented TabGroup for peer sections. */\n @Prop() sectionsPresentation: MobileHeaderSectionsPresentation = 'switcher';\n /** Density for the segmented sections presentation. */\n @Prop() sectionsSize: TabGroupSize = 'md';\n /** Controlled child sections within the selected page or detail screen. */\n @Prop() subsections: TabItem[] = [];\n /** Controlled selected child-section id. */\n @Prop() subvalue: string = '';\n /** Accessible name for the child-section chooser. */\n @Prop() subsectionsAriaLabel: string = 'Change page subsection';\n /** Default page chrome or bold-brand workflow chrome. */\n @Prop({ reflect: true }) tone: MobileHeaderTone = 'default';\n\n /** Section selection intent. */\n @Event() dsSectionChange!: EventEmitter<string>;\n /** Child-section selection intent. */\n @Event() dsSubsectionChange!: EventEmitter<string>;\n\n private get resolvedSections(): TabGroupItem[] {\n return this.sections ?? [];\n }\n\n private get resolvedSubsections(): TabItem[] {\n return this.subsections ?? [];\n }\n\n private get selectedLabel(): string {\n const selectable = getSelectableTabs(this.resolvedSections);\n return selectable.find(section => section.id === this.value)?.label ??\n selectable[0]?.label ??\n this.heading;\n }\n\n private handleSectionChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n this.dsSectionChange.emit(event.detail);\n };\n\n private handleSubsectionChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n this.dsSubsectionChange.emit(event.detail);\n };\n\n render() {\n const Heading = this.headingLevel;\n const selectable = getSelectableTabs(this.resolvedSections);\n const hasSwitcher = selectable.length > 1;\n const hasSubsections = getSelectableTabs(this.resolvedSubsections).length > 1;\n const foreground = this.tone === 'brand' ? 'on-bold' : 'primary';\n\n return (\n <Host>\n <header class=\"mobile-header\">\n <div class=\"mobile-header__primary ds-chrome-grid ds-chrome-space--md\">\n <div class=\"mobile-header__lane mobile-header__lane--leading\">\n <slot name=\"leading\" />\n </div>\n <div class=\"mobile-header__center\">\n {hasSwitcher ? (\n [\n <span\n class=\"mobile-header__semantic-heading\"\n role=\"heading\"\n aria-level={this.headingLevel === 'h1' ? '1' : '2'}\n >\n {this.selectedLabel}\n </span>,\n this.sectionsPresentation === 'segmented' ? (\n <ds-tab-group\n tabs={this.resolvedSections}\n value={this.value}\n size={this.sectionsSize}\n ariaLabel={this.sectionsAriaLabel}\n onDsChange={this.handleSectionChange}\n />\n ) : (\n <ds-mobile-section-switcher\n sections={this.resolvedSections}\n value={this.value}\n navigationLabel={this.sectionsAriaLabel}\n onDsChange={this.handleSectionChange}\n />\n ),\n ]\n ) : (\n <ds-text\n class=\"mobile-header__heading\"\n as={Heading}\n variant=\"text-body-medium\"\n emphasis\n color={foreground}\n lineTruncation={1}\n >\n {this.selectedLabel}\n </ds-text>\n )}\n </div>\n <div class=\"mobile-header__lane mobile-header__lane--trailing\">\n <slot name=\"trailing\" />\n </div>\n </div>\n {hasSubsections ? (\n <nav class=\"mobile-header__subsections\" aria-label={this.subsectionsAriaLabel}>\n <ds-mobile-section-switcher\n sections={this.resolvedSubsections}\n value={this.subvalue}\n navigationLabel={this.subsectionsAriaLabel}\n onDsChange={this.handleSubsectionChange}\n />\n </nav>\n ) : null}\n </header>\n </Host>\n );\n }\n}\n",
|
|
307
345
|
"type": "registry:ui"
|
|
308
346
|
},
|
|
309
347
|
{
|
|
310
348
|
"path": "src/wc/components/MobileHeader/mobile-header-types.ts",
|
|
311
|
-
"content": "import type {
|
|
349
|
+
"content": "import type { TabGroupItem } from '../TabGroup/tab-item-utils';\n\nexport type MobileHeaderTone = 'default' | 'brand';\nexport type MobileHeaderHeadingLevel = 'h1' | 'h2';\nexport type MobileHeaderSectionsPresentation = 'switcher' | 'segmented';\nexport type MobileHeaderSectionItem = TabGroupItem;\n",
|
|
312
350
|
"type": "registry:ui"
|
|
313
351
|
}
|
|
314
352
|
]
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
],
|
|
40
40
|
"responsiveBehavior": [
|
|
41
41
|
"The pane fills the mobile content stage while the bottom bar remains available.",
|
|
42
|
-
"The sheet header and scrollable navigation body each use the shared 8px chrome inset;
|
|
42
|
+
"The sheet header and scrollable navigation body each use the shared 8px chrome inset; the context TabGroup and primary controls share a 40px height and 24px icon scale.",
|
|
43
43
|
"Dashboard and Settings preserve their supplied visual groups with an 8px gap between destinations inside a section and a 32px gap between sections."
|
|
44
44
|
],
|
|
45
45
|
"references": [
|
|
@@ -312,7 +312,7 @@
|
|
|
312
312
|
},
|
|
313
313
|
{
|
|
314
314
|
"path": "src/wc/components/MobileSheetNav/MobileSheetNav.tsx",
|
|
315
|
-
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Listen,\n Prop,\n Watch,\n} from '@stencil/core';\nimport type { NavChromeStyle } from '../../shell/nav-chrome';\nimport { deriveActiveIdFromUrl } from '../PanelNav/panel-nav-utils';\nimport type { PanelNavGroup, PanelNavItem } 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];\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 @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\n @Event() dsAreaSelect!: EventEmitter<string>;\n @Event() dsBrowseContextChange!: EventEmitter<NavChromeStyle>;\n @Event() dsClose!: EventEmitter<void>;\n\n private get groups(): PanelNavGroup[] {\n return this.browseContext === 'settings' ? this.settingsGroups : this.dashboardGroups;\n }\n\n private get activeId(): string {\n return deriveActiveIdFromUrl(this.currentUrl, [\n ...this.dashboardGroups.flatMap(group => group.items),\n ...this.settingsGroups.flatMap(group => group.items),\n ]);\n }\n\n @Watch('open')\n handleOpenChange(open: boolean) {\n if (!open) return;\n requestAnimationFrame(() => {\n const selected = this.el.querySelector<HTMLElement>('[aria-current=\"page\"]');\n const first = this.el.querySelector<HTMLElement>('.mobile-sheet-nav__item');\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.activeId;\n return (\n <button\n type=\"button\"\n class={{\n 'mobile-sheet-nav__item': true,\n 'mobile-sheet-nav__item--selected': selected,\n 'ds-control--lg': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n aria-current={selected ? 'page' : undefined}\n onClick={() => this.dsAreaSelect.emit(item.id)}\n >\n <ds-icon\n class=\"ds-interaction-fill__content\"\n name={item.icon}\n size=\"lg\"\n color=\"inherit\"\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 >\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 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\n id=\"ds-mobile-sheet-nav\"\n class=\"mobile-sheet-nav\"\n >\n <header class=\"mobile-sheet-nav__header ds-chrome-grid ds-chrome-space--md\">\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 aria-label=\"Browse context\"\n onDsChange={this.handleContextChange}\n />\n <div class=\"mobile-sheet-nav__actions\">\n {this.renderHeaderDestination('help', 'CircleQuestion', this.helpLabel)}\n {this.renderHeaderDestination('account', 'Avatar', this.accountLabel)}\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 => this.renderItem(item))}\n </div>\n ))}\n </div>\n </nav>\n </section>\n </Host>\n );\n }\n}\n",
|
|
315
|
+
"content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Listen,\n Prop,\n Watch,\n} from '@stencil/core';\nimport type { NavChromeStyle } from '../../shell/nav-chrome';\nimport { deriveActiveIdFromUrl } from '../PanelNav/panel-nav-utils';\nimport type { PanelNavGroup, PanelNavItem } 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];\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 @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\n @Event() dsAreaSelect!: EventEmitter<string>;\n @Event() dsBrowseContextChange!: EventEmitter<NavChromeStyle>;\n @Event() dsClose!: EventEmitter<void>;\n\n private get groups(): PanelNavGroup[] {\n return this.browseContext === 'settings' ? this.settingsGroups : this.dashboardGroups;\n }\n\n private get activeId(): string {\n return deriveActiveIdFromUrl(this.currentUrl, [\n ...this.dashboardGroups.flatMap(group => group.items),\n ...this.settingsGroups.flatMap(group => group.items),\n ]);\n }\n\n @Watch('open')\n handleOpenChange(open: boolean) {\n if (!open) return;\n requestAnimationFrame(() => {\n const selected = this.el.querySelector<HTMLElement>('[aria-current=\"page\"]');\n const first = this.el.querySelector<HTMLElement>('.mobile-sheet-nav__item');\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.activeId;\n return (\n <button\n type=\"button\"\n class={{\n 'mobile-sheet-nav__item': true,\n 'mobile-sheet-nav__item--selected': selected,\n 'ds-control--lg': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n aria-current={selected ? 'page' : undefined}\n onClick={() => this.dsAreaSelect.emit(item.id)}\n >\n <ds-icon\n class=\"ds-interaction-fill__content\"\n name={item.icon}\n size=\"lg\"\n color=\"inherit\"\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 >\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 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\n id=\"ds-mobile-sheet-nav\"\n class=\"mobile-sheet-nav\"\n >\n <header class=\"mobile-sheet-nav__header ds-chrome-grid ds-chrome-space--md\">\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 aria-label=\"Browse context\"\n onDsChange={this.handleContextChange}\n />\n <div class=\"mobile-sheet-nav__actions\">\n {this.renderHeaderDestination('help', 'CircleQuestion', this.helpLabel)}\n {this.renderHeaderDestination('account', 'Avatar', this.accountLabel)}\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 => this.renderItem(item))}\n </div>\n ))}\n </div>\n </nav>\n </section>\n </Host>\n );\n }\n}\n",
|
|
316
316
|
"type": "registry:ui"
|
|
317
317
|
}
|
|
318
318
|
]
|
|
@@ -4887,6 +4887,7 @@
|
|
|
4887
4887
|
],
|
|
4888
4888
|
"commonlyComposedWith": [
|
|
4889
4889
|
"component:ds-mobile-section-switcher",
|
|
4890
|
+
"component:ds-tab-group",
|
|
4890
4891
|
"component:ds-shell-page",
|
|
4891
4892
|
"component:ds-shell-tools"
|
|
4892
4893
|
],
|
|
@@ -4895,19 +4896,19 @@
|
|
|
4895
4896
|
],
|
|
4896
4897
|
"accessibility": [
|
|
4897
4898
|
"Static screens render a real h1 or h2 according to headingLevel.",
|
|
4898
|
-
"Section-switching screens expose an equivalent semantic heading alongside the accessible popup trigger.",
|
|
4899
|
+
"Section-switching screens expose an equivalent semantic heading alongside the accessible popup trigger or named segmented TabGroup.",
|
|
4899
4900
|
"Subsections use a separately named navigation landmark and never replace the semantic page identity.",
|
|
4900
4901
|
"Leading and trailing slotted icon actions retain their own accessible names and tooltips."
|
|
4901
4902
|
],
|
|
4902
4903
|
"states": [
|
|
4903
4904
|
"Without multiple sections the center renders heading.",
|
|
4904
|
-
"With multiple sections the center renders the controlled MobileSectionSwitcher.",
|
|
4905
|
+
"With multiple sections the center renders the controlled MobileSectionSwitcher by default or an explicitly requested segmented TabGroup.",
|
|
4905
4906
|
"Optional subsections render in a second row and emit dsSubsectionChange without changing the primary section.",
|
|
4906
4907
|
"Sections represent peer destinations at the current navigation level; subsections represent local views beneath the selected page or detail identity.",
|
|
4907
4908
|
"Brand tone changes surface and foreground without changing geometry or interaction ownership."
|
|
4908
4909
|
],
|
|
4909
4910
|
"responsiveBehavior": [
|
|
4910
|
-
"The primary
|
|
4911
|
+
"The primary 56px lane matches the Mobile Sheet Nav header and Mobile Bar Nav; optional subsections add one subordinate 48px lane.",
|
|
4911
4912
|
"Equal flexible side lanes keep the center mathematically aligned when actions are asymmetric."
|
|
4912
4913
|
],
|
|
4913
4914
|
"references": [
|
|
@@ -4927,13 +4928,21 @@
|
|
|
4927
4928
|
"required": false
|
|
4928
4929
|
},
|
|
4929
4930
|
"sections": {
|
|
4930
|
-
"type": "
|
|
4931
|
+
"type": "TabGroupItem[]",
|
|
4931
4932
|
"required": false
|
|
4932
4933
|
},
|
|
4933
4934
|
"sectionsAriaLabel": {
|
|
4934
4935
|
"type": "string",
|
|
4935
4936
|
"required": false
|
|
4936
4937
|
},
|
|
4938
|
+
"sectionsPresentation": {
|
|
4939
|
+
"type": "MobileHeaderSectionsPresentation",
|
|
4940
|
+
"required": false
|
|
4941
|
+
},
|
|
4942
|
+
"sectionsSize": {
|
|
4943
|
+
"type": "TabGroupSize",
|
|
4944
|
+
"required": false
|
|
4945
|
+
},
|
|
4937
4946
|
"subsections": {
|
|
4938
4947
|
"type": "TabItem[]",
|
|
4939
4948
|
"required": false
|
|
@@ -4978,6 +4987,7 @@
|
|
|
4978
4987
|
],
|
|
4979
4988
|
"registryDependencies": [
|
|
4980
4989
|
"mobile-section-switcher",
|
|
4990
|
+
"tab-group",
|
|
4981
4991
|
"text"
|
|
4982
4992
|
]
|
|
4983
4993
|
},
|
|
@@ -5106,7 +5116,7 @@
|
|
|
5106
5116
|
],
|
|
5107
5117
|
"responsiveBehavior": [
|
|
5108
5118
|
"The pane fills the mobile content stage while the bottom bar remains available.",
|
|
5109
|
-
"The sheet header and scrollable navigation body each use the shared 8px chrome inset;
|
|
5119
|
+
"The sheet header and scrollable navigation body each use the shared 8px chrome inset; the context TabGroup and primary controls share a 40px height and 24px icon scale.",
|
|
5110
5120
|
"Dashboard and Settings preserve their supplied visual groups with an 8px gap between destinations inside a section and a 32px gap between sections."
|
|
5111
5121
|
],
|
|
5112
5122
|
"references": [
|
|
@@ -6769,6 +6779,8 @@
|
|
|
6769
6779
|
"On desktop, PanelNav defaults expanded, permits user collapse or expansion, and respects the locally persisted desktop preference.",
|
|
6770
6780
|
"On tablet, ShellApp keeps PanelNav permanently collapsed and prevents user expansion without overwriting the desktop preference.",
|
|
6771
6781
|
"On mobile, ShellApp hides and inerts desktop chrome, uses a solid primary stage, and composes MobileHeader, MobileSheetNav, ShellTools, and the persistent MobileBarNav around the same application-owned content.",
|
|
6782
|
+
"Opening MobileSheetNav temporarily overlays the active routed page or global tool; closing it without selecting an area restores that same destination and its nested state.",
|
|
6783
|
+
"When a suspended mobile document returns to the foreground, ShellApp refreshes the complete stage paint layer without remounting routed content or tool owners.",
|
|
6772
6784
|
"When the application enables viewport-fit=cover, ShellApp reserves the shared top safe-area inset once for the complete mobile stage; nested routed, sheet, and tool headers must not add a second top inset.",
|
|
6773
6785
|
"A slotted Banner remains below the top safe-area inset and above routed, navigation, fullscreen-tool, and mobile global-surface presentations.",
|
|
6774
6786
|
"Mobile global surfaces conceal and inert the routed workspace without unmounting it, preserving nested routes and scroll state.",
|
|
@@ -7105,7 +7117,7 @@
|
|
|
7105
7117
|
"component:ds-shell-app",
|
|
7106
7118
|
"component:ds-panel-tool-header",
|
|
7107
7119
|
"component:ds-mobile-header",
|
|
7108
|
-
"component:ds-
|
|
7120
|
+
"component:ds-tab-group",
|
|
7109
7121
|
"component:ds-mobile-bar-nav"
|
|
7110
7122
|
],
|
|
7111
7123
|
"patterns": [
|
|
@@ -7114,7 +7126,7 @@
|
|
|
7114
7126
|
"accessibility": [
|
|
7115
7127
|
"Only the active mobile tool view participates in focus or the accessibility tree.",
|
|
7116
7128
|
"Header Back and application-owned header actions preserve the PanelTools event contract.",
|
|
7117
|
-
"Inbox uses
|
|
7129
|
+
"Mobile Inbox uses a named label-only TabGroup for Stacks and Activity; Messages remains a direct mobile destination."
|
|
7118
7130
|
],
|
|
7119
7131
|
"states": [
|
|
7120
7132
|
"The application owns open and activeTool and replaces headers when tool depth changes.",
|
|
@@ -7124,7 +7136,7 @@
|
|
|
7124
7136
|
],
|
|
7125
7137
|
"responsiveBehavior": [
|
|
7126
7138
|
"Desktop and tablet compose PanelTools-compatible rail and drawer chrome.",
|
|
7127
|
-
"Mobile renders one centered MobileHeader for every tool; Stacks and Activity use Inbox
|
|
7139
|
+
"Mobile renders one centered MobileHeader for every tool; Stacks and Activity use the large segmented Inbox control, while Messages remains a direct tool destination."
|
|
7128
7140
|
],
|
|
7129
7141
|
"frameworkCaveats": {
|
|
7130
7142
|
"customElements": [
|
|
@@ -7940,6 +7952,7 @@
|
|
|
7940
7952
|
"The parent owns the canonical selected value and adjacent view visibility, and should update both from dsChange.",
|
|
7941
7953
|
"A missing, empty, inactive, or unknown selected value is invalid when enabled tabs exist; the component does not choose a fallback selection.",
|
|
7942
7954
|
"Selection is singular and follows keyboard focus.",
|
|
7955
|
+
"Small, medium, and large use the shared 24px, 32px, and 40px control-density recipes for the outer track. Each segment uses the same-size inset recipe at 20px, 28px, and 36px while preserving that density's typography, icon, gap, and label metrics.",
|
|
7943
7956
|
"Use one consistent content variant across every selectable tab in a group.",
|
|
7944
7957
|
"Omitted background is for primary and secondary surfaces; pass the faint context explicitly on faint surfaces.",
|
|
7945
7958
|
"Only the omitted default context emphasizes visible selected label text and keeps the filled track; explicit faint follows the other surface contexts with a transparent track, stable text weight, surface border, and neutral active fill.",
|
|
@@ -7947,6 +7960,7 @@
|
|
|
7947
7960
|
],
|
|
7948
7961
|
"responsiveBehavior": [
|
|
7949
7962
|
"The component remains a single horizontal row and does not become vertical or wrap.",
|
|
7963
|
+
"Use the large size when a mobile composition aligns the group with 40px shell controls; size does not change automatically at a breakpoint.",
|
|
7950
7964
|
"The consuming layout owns narrow-width placement and overflow, or replaces the row with a more suitable navigation pattern."
|
|
7951
7965
|
],
|
|
7952
7966
|
"frameworkCaveats": {
|
|
@@ -7981,6 +7995,10 @@
|
|
|
7981
7995
|
"type": "TabBackground | undefined",
|
|
7982
7996
|
"required": false
|
|
7983
7997
|
},
|
|
7998
|
+
"size": {
|
|
7999
|
+
"type": "TabGroupSize",
|
|
8000
|
+
"required": false
|
|
8001
|
+
},
|
|
7984
8002
|
"tabs": {
|
|
7985
8003
|
"type": "TabGroupItem[]",
|
|
7986
8004
|
"required": false
|
|
@@ -8014,6 +8032,264 @@
|
|
|
8014
8032
|
"text"
|
|
8015
8033
|
]
|
|
8016
8034
|
},
|
|
8035
|
+
{
|
|
8036
|
+
"name": "table",
|
|
8037
|
+
"title": "Table",
|
|
8038
|
+
"description": "Semantic, controlled data table with durable visual primitives for cell geometry, column geometry, grouping, sorting, multi-selection, sticky overflow, and incremental loading.",
|
|
8039
|
+
"type": "registry:ui",
|
|
8040
|
+
"meta": {
|
|
8041
|
+
"library": "@ds-mo/ui",
|
|
8042
|
+
"distribution": "npm",
|
|
8043
|
+
"storybook": "https://zainadeel.github.io/compomo/?path=/story/table",
|
|
8044
|
+
"source": "src/wc/components/Table/Table.tsx",
|
|
8045
|
+
"intentStatus": "complete",
|
|
8046
|
+
"intent": {
|
|
8047
|
+
"audience": "general",
|
|
8048
|
+
"status": "experimental",
|
|
8049
|
+
"summary": "Semantic, controlled data table with durable visual primitives for cell geometry, column geometry, grouping, sorting, multi-selection, sticky overflow, and incremental loading.",
|
|
8050
|
+
"useWhen": [
|
|
8051
|
+
"A structured dataset needs native row and column relationships, optional one-level grouping, or comparable values across records.",
|
|
8052
|
+
"An application needs controlled sorting, loaded-row selection, or lazy loading while retaining ownership of the data query and transformations.",
|
|
8053
|
+
"A product table needs a token-backed recipe whose individual header, group, row, cell, selection, state, and load-more layers remain easy to restyle."
|
|
8054
|
+
],
|
|
8055
|
+
"avoidWhen": [
|
|
8056
|
+
"Content is primarily editorial prose; use semantic product-owned markup with the prose recipe instead.",
|
|
8057
|
+
"A small label/value set reads more clearly as a list, description list, or card.",
|
|
8058
|
+
"The interface requires tree-grid behavior, nested grouping, inline cell editing, row reordering, column pinning, or virtualization; those are outside this first contract.",
|
|
8059
|
+
"The application expects the component to fetch, paginate, sort, group, or mutate records internally."
|
|
8060
|
+
],
|
|
8061
|
+
"commonlyComposedWith": [
|
|
8062
|
+
"component:ds-empty-state",
|
|
8063
|
+
"component:ds-skeleton",
|
|
8064
|
+
"component:ds-loader",
|
|
8065
|
+
"component:ds-button-unfilled",
|
|
8066
|
+
"component:ds-tag",
|
|
8067
|
+
"component:ds-icon"
|
|
8068
|
+
],
|
|
8069
|
+
"accessibility": [
|
|
8070
|
+
"The rendered structure uses a native table, caption, column headers, row groups, and data cells; keep the caption non-empty even when it is visually hidden.",
|
|
8071
|
+
"Sorting controls remain buttons inside column headers. Member-row sort uses aria-sort, while independent group order is described by the grouped header control.",
|
|
8072
|
+
"Selection controls expose checkbox semantics and explicit row names; select-all affects selectable loaded rows only and preserves selected identities outside the loaded window.",
|
|
8073
|
+
"Scrollable table regions become keyboard focusable and named only when overflow exists.",
|
|
8074
|
+
"Incremental loading, newly appended row counts, failures, and end-of-results transitions are announced through a polite status region without replacing visible state."
|
|
8075
|
+
],
|
|
8076
|
+
"states": [
|
|
8077
|
+
"Columns, rows, groups, grouping, sorting, selected row IDs, and lazy-loading state are controlled inputs. Events communicate intent and never mutate those inputs.",
|
|
8078
|
+
"Grouping supports one level. The application supplies ordered groups and ordered member rows; group order and member-row sort are independent controls.",
|
|
8079
|
+
"An active member sort toggles only between ascending and descending; activating a different sortable label moves sorting to that key. Applications may still clear the controlled sort state explicitly. The grouped column toggles ascending and descending group order without clearing member sort.",
|
|
8080
|
+
"Compound headers can expose multiple related labels with independent sort keys. Each label owns only its content-width interaction target while the active direction remains in the column's alignment-aware sort lane.",
|
|
8081
|
+
"Initial loading uses row-shaped skeletons. Empty and initial error states remain inside the table. Incremental loading retains existing rows and supports automatic sentinel, manual load-more, retry, and terminal states.",
|
|
8082
|
+
"Lazy loading replaces pagination. The application owns requests, cancellation, cursors, deduplication, appended records, and query identity; loadIdentity resets the component request guard.",
|
|
8083
|
+
"Cells accept scalar content, standard primary-and-secondary or dual-primary text primitives, declarative Tag, icon-only, 16:9 Image, or ButtonUnfilled Action content, or explicit Empty and Blank absence values. Single-track text, selection, tag-only, icon-only, Action, Empty, and Blank cells resolve a 40px base contract while multi-track cells grow downward. Action cells primarily use an icon-only Ellipses treatment, render a 24px small ButtonUnfilled inside 8px padding, default to unbordered, and emit row, column, and action identities through dsCellAction. Image cells render a 52px-high bordered preview inside 6px outer padding, establishing a 64px row, and fall back to an accessible placeholder when no source is supplied. Empty means the data applies but has no value and renders an em dash with localized assistive text; Blank means the data is not applicable and renders no content. Nullish values remain backward-compatible Empty values. Stable type and variant hooks keep every cell family independently styleable.",
|
|
8084
|
+
"The public @ds-mo/ui/table.css export is the authoritative zero-specificity visual recipe. Override its --ds-table-* properties or target its stable element classes for product-specific styling."
|
|
8085
|
+
],
|
|
8086
|
+
"responsiveBehavior": [
|
|
8087
|
+
"The table keeps native semantics at narrow widths and scrolls horizontally instead of transforming into cards.",
|
|
8088
|
+
"Explicit column sizes establish the horizontal overflow width; unsized columns share remaining space.",
|
|
8089
|
+
"Prefer the named xs through xl column sizes, which resolve through TokoMo's table-column width tokens; numeric pixel sizes remain an escape hatch for exceptional application-owned widths.",
|
|
8090
|
+
"Column headers use one 32px geometry. Body rows use a 40px single-track minimum; cell-specific outer padding and track geometry align text, selection, Tag, icon, Action, Empty, Blank, and Image primitives while additional tracks grow downward.",
|
|
8091
|
+
"Long content truncates by default and can opt into wrapping at the column or cell level."
|
|
8092
|
+
],
|
|
8093
|
+
"frameworkCaveats": {
|
|
8094
|
+
"customElements": [
|
|
8095
|
+
"Assign columns, rows, groups, grouping, sort, and selectedRowIds through JavaScript properties rather than HTML attribute strings.",
|
|
8096
|
+
"Replace controlled property values in response to dsSortChange, dsGroupingChange, dsSelectionChange, and dsLoadMore."
|
|
8097
|
+
],
|
|
8098
|
+
"react": [
|
|
8099
|
+
"Pass new array and state-object references when the controlled data or query state changes.",
|
|
8100
|
+
"Apply emitted sort, grouping, selection, action, or loading detail to application state and perform data transformations in the owning layer."
|
|
8101
|
+
],
|
|
8102
|
+
"angular": [
|
|
8103
|
+
"Bind complex table inputs as properties and update the controlled values from the corresponding output events.",
|
|
8104
|
+
"Keep server cursor, query lifecycle, and cell-action handling in the owning service or container."
|
|
8105
|
+
]
|
|
8106
|
+
},
|
|
8107
|
+
"references": [
|
|
8108
|
+
{
|
|
8109
|
+
"label": "Storybook review matrix",
|
|
8110
|
+
"path": "src/wc/components/Table/Table.stories.ts"
|
|
8111
|
+
},
|
|
8112
|
+
{
|
|
8113
|
+
"label": "Public visual recipe",
|
|
8114
|
+
"path": "src/wc/styles/table.css"
|
|
8115
|
+
}
|
|
8116
|
+
]
|
|
8117
|
+
},
|
|
8118
|
+
"props": {
|
|
8119
|
+
"caption": {
|
|
8120
|
+
"type": "string",
|
|
8121
|
+
"required": true
|
|
8122
|
+
},
|
|
8123
|
+
"captionVisibility": {
|
|
8124
|
+
"type": "TableCaptionVisibility",
|
|
8125
|
+
"required": false
|
|
8126
|
+
},
|
|
8127
|
+
"columns": {
|
|
8128
|
+
"type": "TableColumn[]",
|
|
8129
|
+
"required": false
|
|
8130
|
+
},
|
|
8131
|
+
"emptyBody": {
|
|
8132
|
+
"type": "string",
|
|
8133
|
+
"required": false
|
|
8134
|
+
},
|
|
8135
|
+
"emptyCellLabel": {
|
|
8136
|
+
"type": "string",
|
|
8137
|
+
"required": false
|
|
8138
|
+
},
|
|
8139
|
+
"emptyHeading": {
|
|
8140
|
+
"type": "string",
|
|
8141
|
+
"required": false
|
|
8142
|
+
},
|
|
8143
|
+
"endOfResultsLabel": {
|
|
8144
|
+
"type": "string",
|
|
8145
|
+
"required": false
|
|
8146
|
+
},
|
|
8147
|
+
"error": {
|
|
8148
|
+
"type": "boolean",
|
|
8149
|
+
"required": false
|
|
8150
|
+
},
|
|
8151
|
+
"errorBody": {
|
|
8152
|
+
"type": "string",
|
|
8153
|
+
"required": false
|
|
8154
|
+
},
|
|
8155
|
+
"errorHeading": {
|
|
8156
|
+
"type": "string",
|
|
8157
|
+
"required": false
|
|
8158
|
+
},
|
|
8159
|
+
"grouping": {
|
|
8160
|
+
"type": "TableGroupingState | null",
|
|
8161
|
+
"required": false
|
|
8162
|
+
},
|
|
8163
|
+
"groups": {
|
|
8164
|
+
"type": "TableGroup[]",
|
|
8165
|
+
"required": false
|
|
8166
|
+
},
|
|
8167
|
+
"hasMore": {
|
|
8168
|
+
"type": "boolean",
|
|
8169
|
+
"required": false
|
|
8170
|
+
},
|
|
8171
|
+
"lazyLoading": {
|
|
8172
|
+
"type": "boolean",
|
|
8173
|
+
"required": false
|
|
8174
|
+
},
|
|
8175
|
+
"loadIdentity": {
|
|
8176
|
+
"type": "string | number",
|
|
8177
|
+
"required": false
|
|
8178
|
+
},
|
|
8179
|
+
"loadMoreError": {
|
|
8180
|
+
"type": "string | undefined",
|
|
8181
|
+
"required": false
|
|
8182
|
+
},
|
|
8183
|
+
"loadMoreLabel": {
|
|
8184
|
+
"type": "string",
|
|
8185
|
+
"required": false
|
|
8186
|
+
},
|
|
8187
|
+
"loadMoreMode": {
|
|
8188
|
+
"type": "TableLoadMoreMode",
|
|
8189
|
+
"required": false
|
|
8190
|
+
},
|
|
8191
|
+
"loadMoreThreshold": {
|
|
8192
|
+
"type": "number",
|
|
8193
|
+
"required": false
|
|
8194
|
+
},
|
|
8195
|
+
"loading": {
|
|
8196
|
+
"type": "boolean",
|
|
8197
|
+
"required": false
|
|
8198
|
+
},
|
|
8199
|
+
"loadingMore": {
|
|
8200
|
+
"type": "boolean",
|
|
8201
|
+
"required": false
|
|
8202
|
+
},
|
|
8203
|
+
"loadingMoreLabel": {
|
|
8204
|
+
"type": "string",
|
|
8205
|
+
"required": false
|
|
8206
|
+
},
|
|
8207
|
+
"maxHeight": {
|
|
8208
|
+
"type": "string | number | undefined",
|
|
8209
|
+
"required": false
|
|
8210
|
+
},
|
|
8211
|
+
"retryLabel": {
|
|
8212
|
+
"type": "string",
|
|
8213
|
+
"required": false
|
|
8214
|
+
},
|
|
8215
|
+
"rows": {
|
|
8216
|
+
"type": "TableRow[]",
|
|
8217
|
+
"required": false
|
|
8218
|
+
},
|
|
8219
|
+
"rowsLoadedLabel": {
|
|
8220
|
+
"type": "string",
|
|
8221
|
+
"required": false
|
|
8222
|
+
},
|
|
8223
|
+
"scrollLabel": {
|
|
8224
|
+
"type": "string | undefined",
|
|
8225
|
+
"required": false
|
|
8226
|
+
},
|
|
8227
|
+
"selectedRowIds": {
|
|
8228
|
+
"type": "string[]",
|
|
8229
|
+
"required": false
|
|
8230
|
+
},
|
|
8231
|
+
"selectionMode": {
|
|
8232
|
+
"type": "TableSelectionMode",
|
|
8233
|
+
"required": false
|
|
8234
|
+
},
|
|
8235
|
+
"skeletonRows": {
|
|
8236
|
+
"type": "number",
|
|
8237
|
+
"required": false
|
|
8238
|
+
},
|
|
8239
|
+
"sort": {
|
|
8240
|
+
"type": "TableSortState | null",
|
|
8241
|
+
"required": false
|
|
8242
|
+
},
|
|
8243
|
+
"stickyHeader": {
|
|
8244
|
+
"type": "boolean",
|
|
8245
|
+
"required": false
|
|
8246
|
+
}
|
|
8247
|
+
},
|
|
8248
|
+
"events": [
|
|
8249
|
+
{
|
|
8250
|
+
"name": "dsCellAction",
|
|
8251
|
+
"detail": "TableCellActionDetail"
|
|
8252
|
+
},
|
|
8253
|
+
{
|
|
8254
|
+
"name": "dsGroupingChange",
|
|
8255
|
+
"detail": "TableGroupingChangeDetail"
|
|
8256
|
+
},
|
|
8257
|
+
{
|
|
8258
|
+
"name": "dsLoadMore",
|
|
8259
|
+
"detail": "TableLoadMoreDetail"
|
|
8260
|
+
},
|
|
8261
|
+
{
|
|
8262
|
+
"name": "dsSelectionChange",
|
|
8263
|
+
"detail": "TableSelectionChangeDetail"
|
|
8264
|
+
},
|
|
8265
|
+
{
|
|
8266
|
+
"name": "dsSortChange",
|
|
8267
|
+
"detail": "TableSortChangeDetail"
|
|
8268
|
+
}
|
|
8269
|
+
],
|
|
8270
|
+
"slots": [],
|
|
8271
|
+
"exports": {
|
|
8272
|
+
"customElement": "ds-table",
|
|
8273
|
+
"react": "DsTable",
|
|
8274
|
+
"angular": "DsTable"
|
|
8275
|
+
}
|
|
8276
|
+
},
|
|
8277
|
+
"dependencies": [
|
|
8278
|
+
"@ds-mo/ui",
|
|
8279
|
+
"@ds-mo/tokens",
|
|
8280
|
+
"@ds-mo/icons"
|
|
8281
|
+
],
|
|
8282
|
+
"registryDependencies": [
|
|
8283
|
+
"button-unfilled",
|
|
8284
|
+
"checkbox",
|
|
8285
|
+
"empty-state",
|
|
8286
|
+
"icon",
|
|
8287
|
+
"loader",
|
|
8288
|
+
"skeleton",
|
|
8289
|
+
"tag",
|
|
8290
|
+
"text"
|
|
8291
|
+
]
|
|
8292
|
+
},
|
|
8017
8293
|
{
|
|
8018
8294
|
"name": "tag",
|
|
8019
8295
|
"title": "Tag",
|
|
@@ -8078,12 +8354,13 @@
|
|
|
8078
8354
|
"Warning signals higher urgency or risk than caution, which asks for attention before a possible issue.",
|
|
8079
8355
|
"Contrast changes visual prominence without changing semantic intent or parent surface context.",
|
|
8080
8356
|
"Rounded is an optional visual style with no semantic difference.",
|
|
8357
|
+
"isInset opts into reduced outer geometry only when Tag is nested inside a control of the same density; semantic styling, typography, icons, gaps, radius, and interaction remain unchanged.",
|
|
8081
8358
|
"Labels stay on one line and truncate only when the owner supplies a maximum width.",
|
|
8082
8359
|
"Omitted interactive renders static metadata with no focus, event, or suffix. Interactive adds the fixed ChevronUpDown suffix and emits dsClick without toggling expanded internally.",
|
|
8083
8360
|
"isInactive disables only the interactive button and applies the shared inactive treatment."
|
|
8084
8361
|
],
|
|
8085
8362
|
"responsiveBehavior": [
|
|
8086
|
-
"The owner selects md, sm, or xs density to match its local layout and owns collection wrapping, overflow, and condensation.",
|
|
8363
|
+
"The owner selects md, sm, or xs density to match its local layout and owns collection wrapping, overflow, and condensation. Use isInset only for same-density control nesting.",
|
|
8087
8364
|
"Tag does not change size or behavior automatically at breakpoints."
|
|
8088
8365
|
],
|
|
8089
8366
|
"frameworkCaveats": {
|
|
@@ -8133,6 +8410,10 @@
|
|
|
8133
8410
|
"type": "boolean",
|
|
8134
8411
|
"required": false
|
|
8135
8412
|
},
|
|
8413
|
+
"isInset": {
|
|
8414
|
+
"type": "boolean",
|
|
8415
|
+
"required": false
|
|
8416
|
+
},
|
|
8136
8417
|
"label": {
|
|
8137
8418
|
"type": "string",
|
|
8138
8419
|
"required": true
|