@ds-mo/ui 1.2.0 → 1.4.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.
Files changed (184) hide show
  1. package/README.md +82 -2
  2. package/dist/components/ds-badge.js +1 -1
  3. package/dist/components/ds-badge.js.map +1 -1
  4. package/dist/components/ds-banner.js +1 -1
  5. package/dist/components/ds-banner.js.map +1 -1
  6. package/dist/components/ds-bar-nav-action.js +1 -1
  7. package/dist/components/ds-bar-nav.js +1 -1
  8. package/dist/components/ds-bar-nav.js.map +1 -1
  9. package/dist/components/ds-breadcrumb.js +1 -1
  10. package/dist/components/ds-button-group.js +1 -1
  11. package/dist/components/ds-button.js +1 -1
  12. package/dist/components/ds-card.js +1 -1
  13. package/dist/components/ds-checkbox.js +1 -1
  14. package/dist/components/ds-chip.d.ts +11 -0
  15. package/dist/components/ds-chip.js +2 -0
  16. package/dist/components/ds-chip.js.map +1 -0
  17. package/dist/components/ds-divider.js +1 -1
  18. package/dist/components/ds-empty-state.js +1 -1
  19. package/dist/components/ds-fade.js +1 -1
  20. package/dist/components/ds-fade.js.map +1 -1
  21. package/dist/components/ds-field.js +1 -1
  22. package/dist/components/ds-header.js +1 -1
  23. package/dist/components/ds-icon.js +1 -1
  24. package/dist/components/ds-input.js +1 -1
  25. package/dist/components/ds-modal.js +1 -1
  26. package/dist/components/ds-modal.js.map +1 -1
  27. package/dist/components/ds-panel-nav.js +1 -1
  28. package/dist/components/ds-panel-nav.js.map +1 -1
  29. package/dist/components/ds-radio-group.js +1 -1
  30. package/dist/components/ds-radio-group.js.map +1 -1
  31. package/dist/components/ds-scrollbar.js +1 -1
  32. package/dist/components/ds-select.js +1 -1
  33. package/dist/components/ds-sidebar.js +1 -1
  34. package/dist/components/ds-sidebar.js.map +1 -1
  35. package/dist/components/ds-slider.js +1 -1
  36. package/dist/components/ds-surface.js +1 -1
  37. package/dist/components/ds-tab-group-nav.js +1 -1
  38. package/dist/components/ds-tab-group.js +1 -1
  39. package/dist/components/ds-tab-group.js.map +1 -1
  40. package/dist/components/ds-table.js +1 -1
  41. package/dist/components/ds-tag.js +1 -1
  42. package/dist/components/ds-tag.js.map +1 -1
  43. package/dist/components/ds-text.js +1 -1
  44. package/dist/components/ds-toast-provider.js +1 -1
  45. package/dist/components/ds-toggle-button-group.js +1 -1
  46. package/dist/components/ds-toggle-button.js +1 -1
  47. package/dist/components/ds-toggle.js +1 -1
  48. package/dist/components/ds-tooltip.js +1 -1
  49. package/dist/components/index.d.ts +3 -4
  50. package/dist/components/index.js +1 -1
  51. package/dist/components/index.js.map +1 -1
  52. package/dist/components/{p-COsKOwZR.js → p--YDw8Q4o.js} +2 -2
  53. package/dist/components/p-B_enucPQ.js +2 -0
  54. package/dist/components/p-B_enucPQ.js.map +1 -0
  55. package/dist/components/{p-Cj00JkJb.js → p-C9za7IDu.js} +2 -2
  56. package/dist/components/p-DceSoh5V.js +2 -0
  57. package/dist/components/p-DceSoh5V.js.map +1 -0
  58. package/dist/components/{p-H89PzqGU.js → p-DqBCQRRd.js} +2 -2
  59. package/dist/components/p-DznbYg1m.js +2 -0
  60. package/dist/components/p-DznbYg1m.js.map +1 -0
  61. package/dist/components/p-_LI2ymhS.js +2 -0
  62. package/dist/components/p-_LI2ymhS.js.map +1 -0
  63. package/dist/components/{p-CE5zeV1w.js → p-uMN1Ppw2.js} +2 -2
  64. package/dist/components/p-vW9EMP8s.js +2 -0
  65. package/dist/components/p-vW9EMP8s.js.map +1 -0
  66. package/dist/types/components/Badge/Badge.d.ts +20 -0
  67. package/dist/types/components/Badge/index.d.ts +2 -0
  68. package/dist/types/{.stencil → components}/BarNav/BarNav.d.ts +6 -17
  69. package/dist/types/components/BarNav/bar-nav-types.d.ts +14 -0
  70. package/dist/types/{.stencil → components}/BarNav/bar-nav-utils.d.ts +1 -1
  71. package/dist/types/components/BarNav/index.d.ts +3 -0
  72. package/dist/types/{.stencil → components}/BarNavAction/BarNavAction.d.ts +1 -1
  73. package/dist/types/components/Chip/Chip.d.ts +30 -0
  74. package/dist/types/components/Chip/index.d.ts +2 -0
  75. package/dist/types/components/Fade/Fade.d.ts +25 -0
  76. package/dist/types/components/Fade/index.d.ts +2 -0
  77. package/dist/types/{.stencil → components}/PanelNav/PanelNav.d.ts +11 -26
  78. package/dist/types/components/PanelNav/index.d.ts +4 -0
  79. package/dist/types/components/PanelNav/panel-nav-types.d.ts +20 -0
  80. package/dist/types/components/PanelNav/panel-nav-utils.d.ts +26 -0
  81. package/dist/types/{.stencil → components}/TabGroupNav/TabGroupNav.d.ts +1 -1
  82. package/dist/types/components/Tag/Tag.d.ts +15 -0
  83. package/dist/types/components/Tag/index.d.ts +2 -0
  84. package/dist/types/components.d.ts +256 -108
  85. package/dist/types/nav/index.d.ts +5 -0
  86. package/dist/types/nav/nav-chrome.d.ts +14 -0
  87. package/dist/types/nav/shell-view-transition.d.ts +21 -0
  88. package/package.json +18 -6
  89. package/src/angular/index.ts +1 -0
  90. package/src/angular/proxies.ts +51 -28
  91. package/src/react/components.ts +1 -0
  92. package/src/react/ds-chip.ts +35 -0
  93. package/src/react/ds-tag.ts +3 -12
  94. package/src/wc/components/Badge/Badge.tsx +58 -8
  95. package/src/wc/components/Badge/index.ts +1 -1
  96. package/src/wc/components/Banner/Banner.tsx +2 -2
  97. package/src/wc/components/BarNav/BarNav.tsx +24 -26
  98. package/src/wc/components/BarNav/bar-nav-types.ts +15 -0
  99. package/src/wc/components/BarNav/bar-nav-utils.ts +1 -1
  100. package/src/wc/components/BarNav/index.ts +2 -1
  101. package/src/wc/components/BarNavAction/BarNavAction.tsx +11 -2
  102. package/src/wc/components/Chip/Chip.tsx +127 -0
  103. package/src/wc/components/Chip/index.ts +1 -0
  104. package/src/wc/components/Fade/Fade.tsx +86 -6
  105. package/src/wc/components/Fade/index.ts +1 -1
  106. package/src/wc/components/PanelNav/PanelNav.tsx +63 -91
  107. package/src/wc/components/PanelNav/index.ts +9 -4
  108. package/src/wc/components/PanelNav/panel-nav-types.ts +22 -0
  109. package/src/wc/components/PanelNav/panel-nav-utils.ts +32 -64
  110. package/src/wc/components/TabGroup/TabGroup.tsx +9 -1
  111. package/src/wc/components/TabGroupNav/TabGroupNav.tsx +17 -3
  112. package/src/wc/components/Tag/Tag.tsx +3 -70
  113. package/src/wc/components/Tag/index.ts +1 -1
  114. package/src/wc/components.d.ts +256 -108
  115. package/src/wc/nav/index.ts +19 -0
  116. package/src/wc/nav/nav-chrome.ts +45 -0
  117. package/src/wc/nav/shell-view-transition.ts +102 -0
  118. package/dist/components/p-CQQe6VNo.js +0 -2
  119. package/dist/components/p-CQQe6VNo.js.map +0 -1
  120. package/dist/components/p-Vwlmhl4E.js +0 -2
  121. package/dist/components/p-Vwlmhl4E.js.map +0 -1
  122. package/dist/types/.stencil/Badge/Badge.d.ts +0 -8
  123. package/dist/types/.stencil/Badge/index.d.ts +0 -2
  124. package/dist/types/.stencil/BarNav/index.d.ts +0 -2
  125. package/dist/types/.stencil/Fade/Fade.d.ts +0 -10
  126. package/dist/types/.stencil/Fade/index.d.ts +0 -2
  127. package/dist/types/.stencil/PanelNav/index.d.ts +0 -3
  128. package/dist/types/.stencil/PanelNav/panel-nav-utils.d.ts +0 -27
  129. package/dist/types/.stencil/Tag/Tag.d.ts +0 -32
  130. package/dist/types/.stencil/Tag/index.d.ts +0 -2
  131. /package/dist/components/{p-COsKOwZR.js.map → p--YDw8Q4o.js.map} +0 -0
  132. /package/dist/components/{p-Cj00JkJb.js.map → p-C9za7IDu.js.map} +0 -0
  133. /package/dist/components/{p-H89PzqGU.js.map → p-DqBCQRRd.js.map} +0 -0
  134. /package/dist/components/{p-CE5zeV1w.js.map → p-uMN1Ppw2.js.map} +0 -0
  135. /package/dist/types/{.stencil → components}/Accordion/Accordion.d.ts +0 -0
  136. /package/dist/types/{.stencil → components}/Banner/Banner.d.ts +0 -0
  137. /package/dist/types/{.stencil → components}/BarNav/bar-nav-dom-utils.d.ts +0 -0
  138. /package/dist/types/{.stencil → components}/BarNav/bar-nav-tabs-menu-utils.d.ts +0 -0
  139. /package/dist/types/{.stencil → components}/BarNavAction/index.d.ts +0 -0
  140. /package/dist/types/{.stencil → components}/Breadcrumb/Breadcrumb.d.ts +0 -0
  141. /package/dist/types/{.stencil → components}/Button/Button.d.ts +0 -0
  142. /package/dist/types/{.stencil → components}/Button/index.d.ts +0 -0
  143. /package/dist/types/{.stencil → components}/ButtonGroup/ButtonGroup.d.ts +0 -0
  144. /package/dist/types/{.stencil → components}/Card/Card.d.ts +0 -0
  145. /package/dist/types/{.stencil → components}/Checkbox/Checkbox.d.ts +0 -0
  146. /package/dist/types/{.stencil → components}/Checkbox/index.d.ts +0 -0
  147. /package/dist/types/{.stencil → components}/Divider/Divider.d.ts +0 -0
  148. /package/dist/types/{.stencil → components}/Divider/index.d.ts +0 -0
  149. /package/dist/types/{.stencil → components}/EmptyState/EmptyState.d.ts +0 -0
  150. /package/dist/types/{.stencil → components}/Field/Field.d.ts +0 -0
  151. /package/dist/types/{.stencil → components}/Header/Header.d.ts +0 -0
  152. /package/dist/types/{.stencil → components}/Icon/Icon.d.ts +0 -0
  153. /package/dist/types/{.stencil → components}/Icon/flag-icon-catalog.d.ts +0 -0
  154. /package/dist/types/{.stencil → components}/Icon/index.d.ts +0 -0
  155. /package/dist/types/{.stencil → components}/Icon/system-icon-catalog.d.ts +0 -0
  156. /package/dist/types/{.stencil → components}/Input/Input.d.ts +0 -0
  157. /package/dist/types/{.stencil → components}/Input/index.d.ts +0 -0
  158. /package/dist/types/{.stencil → components}/Loader/Loader.d.ts +0 -0
  159. /package/dist/types/{.stencil → components}/Loader/index.d.ts +0 -0
  160. /package/dist/types/{.stencil → components}/Menu/Menu.d.ts +0 -0
  161. /package/dist/types/{.stencil → components}/Modal/Modal.d.ts +0 -0
  162. /package/dist/types/{.stencil → components}/Pagination/Pagination.d.ts +0 -0
  163. /package/dist/types/{.stencil → components}/RadioGroup/RadioGroup.d.ts +0 -0
  164. /package/dist/types/{.stencil → components}/RadioGroup/index.d.ts +0 -0
  165. /package/dist/types/{.stencil → components}/Scrollbar/Scrollbar.d.ts +0 -0
  166. /package/dist/types/{.stencil → components}/Select/Select.d.ts +0 -0
  167. /package/dist/types/{.stencil → components}/Sidebar/Sidebar.d.ts +0 -0
  168. /package/dist/types/{.stencil → components}/Skeleton/Skeleton.d.ts +0 -0
  169. /package/dist/types/{.stencil → components}/Skeleton/index.d.ts +0 -0
  170. /package/dist/types/{.stencil → components}/Slider/Slider.d.ts +0 -0
  171. /package/dist/types/{.stencil → components}/Slider/index.d.ts +0 -0
  172. /package/dist/types/{.stencil → components}/Surface/Surface.d.ts +0 -0
  173. /package/dist/types/{.stencil → components}/TabGroup/TabGroup.d.ts +0 -0
  174. /package/dist/types/{.stencil → components}/TabGroup/tab-item-utils.d.ts +0 -0
  175. /package/dist/types/{.stencil → components}/Table/Table.d.ts +0 -0
  176. /package/dist/types/{.stencil → components}/Text/Text.d.ts +0 -0
  177. /package/dist/types/{.stencil → components}/Text/index.d.ts +0 -0
  178. /package/dist/types/{.stencil → components}/Toast/Toast.d.ts +0 -0
  179. /package/dist/types/{.stencil → components}/Toast/toast-service.d.ts +0 -0
  180. /package/dist/types/{.stencil → components}/Toggle/Toggle.d.ts +0 -0
  181. /package/dist/types/{.stencil → components}/Toggle/index.d.ts +0 -0
  182. /package/dist/types/{.stencil → components}/ToggleButton/ToggleButton.d.ts +0 -0
  183. /package/dist/types/{.stencil → components}/ToggleButtonGroup/ToggleButtonGroup.d.ts +0 -0
  184. /package/dist/types/{.stencil → components}/Tooltip/Tooltip.d.ts +0 -0
@@ -0,0 +1,127 @@
1
+ import { Component, Prop, Event, EventEmitter, h, Host } from '@stencil/core';
2
+
3
+ export type ChipIntent = 'neutral' | 'brand' | 'ai' | 'negative' | 'warning' | 'caution' | 'positive';
4
+ export type ChipContrast = 'strong' | 'bold' | 'medium' | 'faint';
5
+ export type ChipElevation = 'none' | 'flat' | 'elevated';
6
+ export type ChipSize = 'md' | 'sm' | 'xs';
7
+ export type ChipBackground = 'faint' | 'medium' | 'bold' | 'strong' | 'always-dark';
8
+
9
+ const TEXT_VARIANT: Record<ChipSize, string> = {
10
+ md: 'text-body-medium',
11
+ sm: 'text-body-small',
12
+ xs: 'text-caption',
13
+ };
14
+
15
+ const ICON_SIZE: Record<ChipSize, number> = { md: 20, sm: 16, xs: 12 };
16
+
17
+ @Component({
18
+ tag: 'ds-chip',
19
+ styleUrl: 'Chip.css',
20
+ scoped: true,
21
+ })
22
+ export class Chip {
23
+ @Prop() label!: string;
24
+ @Prop() intent: ChipIntent = 'neutral';
25
+ @Prop() contrast: ChipContrast = 'faint';
26
+ @Prop() elevation: ChipElevation = 'none';
27
+ @Prop() size: ChipSize = 'md';
28
+ @Prop() rounded: boolean = false;
29
+ @Prop() removable: boolean = false;
30
+ @Prop() maxWidth: string | number | undefined;
31
+ @Prop() inactive: boolean = false;
32
+ @Prop() background: ChipBackground | undefined;
33
+ @Prop({ mutable: true }) pressed: boolean = false;
34
+
35
+ /** Fired when the remove button is clicked. */
36
+ @Event() dsRemove!: EventEmitter<void>;
37
+ /** Fired when an interactive chip is clicked. */
38
+ @Event() dsClick!: EventEmitter<void>;
39
+ /** Fired when the pressed state toggles. */
40
+ @Event() dsPressedChange!: EventEmitter<boolean>;
41
+
42
+ private handleClick = () => {
43
+ if (this.inactive) return;
44
+ this.pressed = !this.pressed;
45
+ this.dsPressedChange.emit(this.pressed);
46
+ this.dsClick.emit();
47
+ };
48
+
49
+ private handleKeyDown = (e: KeyboardEvent) => {
50
+ if (this.inactive) return;
51
+ if (e.key === 'Enter' || e.key === ' ') {
52
+ e.preventDefault();
53
+ this.handleClick();
54
+ }
55
+ };
56
+
57
+ private handleRemove = (e: MouseEvent) => {
58
+ e.stopPropagation();
59
+ this.dsRemove.emit();
60
+ };
61
+
62
+ render() {
63
+ const sz = this.size.toUpperCase() as 'MD' | 'SM' | 'XS';
64
+ const textVariant = TEXT_VARIANT[this.size];
65
+ const iconSize = ICON_SIZE[this.size];
66
+
67
+ const maxWidthStyle = this.maxWidth != null
68
+ ? { maxWidth: typeof this.maxWidth === 'number' ? `${this.maxWidth}px` : this.maxWidth }
69
+ : undefined;
70
+
71
+ const hostCls: Record<string, boolean> = {
72
+ 'tag': true,
73
+ [`tag--intent-${this.intent}`]: true,
74
+ [`tag--contrast-${this.contrast}`]: true,
75
+ [`tag--elevation-${this.elevation}`]: true,
76
+ [`tag--size-${this.size}`]: true,
77
+ 'tag--rounded': this.rounded,
78
+ 'tag--rounded-no-icon-left': this.rounded,
79
+ 'tag--rounded-no-remove-right': this.rounded && !this.removable,
80
+ [`tag--icon-left-${sz}`]: false,
81
+ [`tag--icon-right-${sz}`]: this.removable,
82
+ 'tag--removable': this.removable,
83
+ 'tag--interactive': true,
84
+ 'tag--inactive': this.inactive,
85
+ 'tag--pressed': this.pressed,
86
+ 'tag--on-medium': this.background === 'medium',
87
+ 'tag--on-bold': this.background === 'bold',
88
+ 'tag--on-strong': this.background === 'strong',
89
+ 'tag--on-always-dark': this.background === 'always-dark',
90
+ };
91
+
92
+ return (
93
+ <Host
94
+ class={hostCls}
95
+ style={maxWidthStyle}
96
+ onClick={this.handleClick}
97
+ onKeyDown={this.handleKeyDown}
98
+ role="button"
99
+ tabIndex={this.inactive ? -1 : 0}
100
+ aria-pressed={String(this.pressed)}
101
+ aria-disabled={this.inactive || undefined}
102
+ >
103
+ <span class="tag__icon-slot" style={{ fontSize: `${iconSize}px`, lineHeight: '0' }}>
104
+ <slot name="icon" />
105
+ </span>
106
+ <span class={{ 'tag__label': true, [textVariant]: true }}>
107
+ {this.label}
108
+ </span>
109
+ {this.removable && (
110
+ <button
111
+ type="button"
112
+ class="tag__remove"
113
+ onClick={this.handleRemove}
114
+ aria-label={`Remove ${this.label}`}
115
+ tabIndex={-1}
116
+ >
117
+ <slot name="remove-icon">
118
+ <span class="tag__remove-x" style={{ fontSize: `${iconSize}px`, lineHeight: '0' }}>
119
+
120
+ </span>
121
+ </slot>
122
+ </button>
123
+ )}
124
+ </Host>
125
+ );
126
+ }
127
+ }
@@ -0,0 +1 @@
1
+ export type { ChipIntent, ChipContrast, ChipElevation, ChipSize, ChipBackground } from './Chip';
@@ -1,30 +1,110 @@
1
1
  import { Component, Prop, h, Host } from '@stencil/core';
2
2
 
3
3
  export type FadeSide = 'top' | 'bottom' | 'left' | 'right';
4
+ export type FadeSurface =
5
+ | 'default'
6
+ | 'primary'
7
+ | 'secondary'
8
+ | 'navigation'
9
+ | 'media'
10
+ | 'always-dark'
11
+ | 'inverted';
12
+ export type FadeSizeToken =
13
+ | 'size-000'
14
+ | 'size-050'
15
+ | 'size-075'
16
+ | 'size-100'
17
+ | 'size-150'
18
+ | 'size-200'
19
+ | 'size-250'
20
+ | 'size-300'
21
+ | 'size-400'
22
+ | 'size-500'
23
+ | 'size-600'
24
+ | 'size-800';
25
+ export type FadeSize = FadeSizeToken | (string & {});
26
+
27
+ const SIZE_VALUE: Record<FadeSizeToken, string> = {
28
+ 'size-000': 'var(--dimension-size-000)',
29
+ 'size-050': 'var(--dimension-size-050)',
30
+ 'size-075': 'var(--dimension-size-075)',
31
+ 'size-100': 'var(--dimension-size-100)',
32
+ 'size-150': 'var(--dimension-size-150)',
33
+ 'size-200': 'var(--dimension-size-200)',
34
+ 'size-250': 'var(--dimension-size-250)',
35
+ 'size-300': 'var(--dimension-size-300)',
36
+ 'size-400': 'var(--dimension-size-400)',
37
+ 'size-500': 'var(--dimension-size-500)',
38
+ 'size-600': 'var(--dimension-size-600)',
39
+ 'size-800': 'var(--dimension-size-800)',
40
+ };
41
+
42
+ const SURFACE_BACKGROUND: Record<FadeSurface, string> = {
43
+ default: 'var(--color-background-secondary)',
44
+ primary: 'var(--color-background-primary)',
45
+ secondary: 'var(--color-background-secondary)',
46
+ navigation: 'var(--color-navigation-background)',
47
+ media: 'var(--color-media-background)',
48
+ 'always-dark': 'var(--color-always-dark-background)',
49
+ inverted: 'var(--color-inverted-background)',
50
+ };
4
51
 
5
52
  @Component({
6
53
  tag: 'ds-fade',
7
54
  styleUrl: 'Fade.css',
8
- shadow: true,
55
+ scoped: true,
9
56
  })
10
57
  export class Fade {
11
- @Prop() side!: FadeSide;
12
- /** Height (or width for left/right) of the fade overlay — any CSS value. */
58
+ /** Edge where the fade is anchored. */
59
+ @Prop() side: FadeSide = 'bottom';
60
+
61
+ /** Fade depth along the fade axis. Accepts dimension size token names or any CSS length. */
62
+ @Prop() size: FadeSize = 'size-600';
63
+
64
+ /**
65
+ * Deprecated alias for size. Kept for existing consumers that pass a raw CSS length.
66
+ * Prefer `size`.
67
+ */
13
68
  @Prop() height: string | undefined;
14
- /** Background color to fade from. Defaults to var(--color-background-secondary). */
69
+
70
+ /** Surface context used to choose the fade target background token. */
71
+ @Prop() surface: FadeSurface = 'default';
72
+
73
+ /** Direct background override for contexts that already expose a resolved surface var. */
15
74
  @Prop() background: string = 'var(--color-background-secondary)';
16
75
 
76
+ /** Controls visibility without removing the element from layout/positioning. */
77
+ @Prop() visible: boolean = true;
78
+
79
+ private resolveSize(): string {
80
+ if (this.height) return this.height;
81
+
82
+ return Object.prototype.hasOwnProperty.call(SIZE_VALUE, this.size)
83
+ ? SIZE_VALUE[this.size as FadeSizeToken]
84
+ : this.size;
85
+ }
86
+
87
+ private resolveBackground(): string {
88
+ if (this.background !== 'var(--color-background-secondary)') return this.background;
89
+ return SURFACE_BACKGROUND[this.surface];
90
+ }
91
+
17
92
  render() {
93
+ const isVerticalEdge = this.side === 'top' || this.side === 'bottom';
94
+
18
95
  return (
19
96
  <Host
20
97
  aria-hidden="true"
21
98
  class={{
22
99
  fade: true,
100
+ 'fade--hidden': !this.visible,
101
+ 'fade--vertical-edge': isVerticalEdge,
102
+ 'fade--horizontal-edge': !isVerticalEdge,
23
103
  [`fade--${this.side}`]: true,
24
104
  }}
25
105
  style={{
26
- height: this.height,
27
- '--ds-fade-bg': this.background,
106
+ '--ds-fade-size': this.resolveSize(),
107
+ '--ds-fade-bg': this.resolveBackground(),
28
108
  } as Record<string, string>}
29
109
  />
30
110
  );
@@ -1 +1 @@
1
- export type { FadeSide } from './Fade';
1
+ export type { FadeSide, FadeSize, FadeSizeToken, FadeSurface } from './Fade';
@@ -1,18 +1,22 @@
1
1
  import { Component, Prop, Event, EventEmitter, Watch, State, Element, h, Host } from '@stencil/core';
2
+ import type { NavChromeStyle } from '../../nav/nav-chrome';
3
+ import {
4
+ animateShellNavRadialReveal,
5
+ ensureShellNavVtStyle,
6
+ resolveShellNavRevealOrigin,
7
+ setShellNavRevealOriginVars,
8
+ } from '../../nav/shell-view-transition';
2
9
  import {
3
10
  deriveActiveIdFromUrl,
4
- ensurePanelNavVtStyle,
5
11
  parsePanelNavGroups,
6
12
  resolvePanelNavDisableVt,
7
- resolvePanelNavVariant,
13
+ resolvePanelNavStyle,
8
14
  shouldResyncPanelNavGroups,
9
- shouldResyncPanelNavVariant,
15
+ shouldResyncPanelNavStyle,
10
16
  } from './panel-nav-utils';
17
+ import type { PanelNavGroup, PanelNavItem, PanelNavRouterMode } from './panel-nav-types';
11
18
 
12
- // Module-level WeakMaps for per-instance VT state. Using WeakMaps instead of
13
- // class fields avoids Stencil generating getter-only property descriptors on
14
- // the host element for private fields, which throws in strict environments.
15
- // Minimal typings for the View Transitions API, which isn't in our TS lib target.
19
+ // Module-level WeakMaps
16
20
  interface ViewTransition {
17
21
  finished: Promise<void>;
18
22
  skipTransition: () => void;
@@ -24,50 +28,17 @@ type DocumentWithViewTransition = Document & {
24
28
  const vtTransitions = new WeakMap<object, ViewTransition>();
25
29
  const vtResolvers = new WeakMap<object, () => void>();
26
30
 
27
- /** Parse a CSS <time> value to milliseconds. Handles `s`, `ms`, and unitless
28
- * (assumed ms). Critically: `parseFloat('.75s')` is 0.75 — WAAPI treats that as
29
- * 0.75ms (instant/invisible), so the `s` unit must be scaled to ms. Design
30
- * tokens (e.g. `--effect-animation-duration-long-1`) are authored in seconds. */
31
- function parseCssTimeMs(value: string, fallback: number): number {
32
- const v = value.trim();
33
- const num = parseFloat(v);
34
- if (Number.isNaN(num)) return fallback;
35
- if (/ms\s*$/.test(v)) return num;
36
- if (/s\s*$/.test(v)) return num * 1000;
37
- return num;
38
- }
39
-
40
- export type PanelNavVariant = 'dashboard' | 'settings';
41
- export type PanelNavRouterMode = 'anchor' | 'event';
42
-
43
- export interface PanelNavItem {
44
- id: string;
45
- icon: string;
46
- label: string;
47
- /** Show a notification dot badge on the item */
48
- dot?: boolean;
49
- flag?: boolean;
50
- /** Route path used for `currentUrl` matching. In `anchor` mode also sets `<a href>`.
51
- * In `event` mode navigation is delegated to the host via `dsNavSelect`. */
52
- href?: string;
53
- }
54
-
55
- export interface PanelNavGroup {
56
- id?: string;
57
- label?: string;
58
- items: PanelNavItem[];
59
- }
60
-
61
31
  @Component({
62
32
  tag: 'ds-panel-nav',
63
33
  styleUrl: 'PanelNav.css',
64
34
  scoped: true,
65
35
  })
66
36
  export class PanelNav {
67
- /** Visual variant: `dashboard` = always-dark surface, `settings` = light surface */
68
- @Prop() variant: PanelNavVariant = 'dashboard';
37
+ /** Chrome style: `navigation` = navigation tokens, `default` = standard app tokens.
38
+ * Property: `navStyle`. HTML attribute: `nav-style`. */
39
+ @Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'navigation';
69
40
 
70
- /** When `true`, the component does not run its own View Transition on variant
41
+ /** When `true`, the component does not run its own View Transition on style
71
42
  * change — it just updates the rendered surface synchronously. Use this when
72
43
  * the host app orchestrates the page transition itself (e.g. Angular Router's
73
44
  * `withViewTransitions`), so the two don't fight or nest. */
@@ -122,9 +93,9 @@ export class PanelNav {
122
93
 
123
94
  @Element() el!: HTMLElement;
124
95
 
125
- /** Mirrors `variant` but is only updated inside the VT callback so the
96
+ /** Mirrors `style` but is only updated inside the VT callback so the
126
97
  * View Transition captures a clean before/after snapshot. */
127
- @State() private renderedVariant: PanelNavVariant = 'dashboard';
98
+ @State() private renderedStyle: NavChromeStyle = 'navigation';
128
99
 
129
100
  @State() private parsedGroups: PanelNavGroup[] = [];
130
101
  @State() private atBottom = false;
@@ -193,44 +164,35 @@ export class PanelNav {
193
164
  this.syncActiveFromUrl();
194
165
  }
195
166
 
196
- @Watch('variant')
197
- async onVariantChange(newVal: PanelNavVariant) {
167
+ @Watch('navStyle')
168
+ async onNavStyleChange(newVal: NavChromeStyle) {
198
169
  // Host app drives the transition (e.g. Angular Router withViewTransitions):
199
170
  // just reflect the new surface so the app's transition captures it.
200
171
  if (this.effectiveDisableViewTransition) {
201
- this.renderedVariant = newVal;
172
+ this.renderedStyle = newVal;
202
173
  return;
203
174
  }
204
175
 
205
- // Skip any in-progress transition immediately so rapid variant changes
206
- // (e.g. quick dashboard → settings → dashboard) never leave the nav stuck.
176
+ // Skip any in-progress transition immediately so rapid style changes never leave the nav stuck.
207
177
  vtTransitions.get(this)?.skipTransition();
208
178
  vtTransitions.delete(this);
209
179
 
210
180
  const doc = document as DocumentWithViewTransition;
211
181
  if (typeof doc.startViewTransition !== 'function') {
212
- this.renderedVariant = newVal;
182
+ this.renderedStyle = newVal;
213
183
  return;
214
184
  }
215
185
 
216
- ensurePanelNavVtStyle();
217
-
218
- const btn = this.el.querySelector('.panel-nav__footer-btn') as HTMLElement | null;
219
- const rect = btn?.getBoundingClientRect();
220
- const x = rect ? Math.round(rect.left + rect.width / 2) : Math.round(window.innerWidth / 2);
221
- const y = rect ? Math.round(rect.top + rect.height / 2) : Math.round(window.innerHeight / 2);
222
- const maxR = Math.ceil(Math.hypot(
223
- Math.max(x, window.innerWidth - x),
224
- Math.max(y, window.innerHeight - y),
225
- ));
226
-
227
- document.documentElement.style.setProperty('--vt-x', `${x}px`);
228
- document.documentElement.style.setProperty('--vt-y', `${y}px`);
186
+ ensureShellNavVtStyle();
187
+ const origin = resolveShellNavRevealOrigin(
188
+ this.el.querySelector('.panel-nav__footer-btn') as HTMLElement | null,
189
+ );
190
+ setShellNavRevealOriginVars(origin);
229
191
 
230
192
  const transition = doc.startViewTransition(() =>
231
193
  new Promise<void>(resolve => {
232
194
  vtResolvers.set(this, resolve);
233
- this.renderedVariant = newVal;
195
+ this.renderedStyle = newVal;
234
196
  })
235
197
  );
236
198
 
@@ -240,19 +202,13 @@ export class PanelNav {
240
202
  vtResolvers.delete(this);
241
203
  });
242
204
 
243
- transition.ready.then(() => {
244
- const durToken = getComputedStyle(document.documentElement)
245
- .getPropertyValue('--effect-animation-duration-long-1').trim();
246
- const duration = parseCssTimeMs(durToken, 750);
247
- document.documentElement.animate(
248
- { clipPath: [`circle(0px at ${x}px ${y}px)`, `circle(${maxR}px at ${x}px ${y}px)`] },
249
- { duration, easing: 'ease-in-out', fill: 'forwards', pseudoElement: '::view-transition-new(root)' },
250
- );
251
- }).catch(() => { /* transition was skipped or aborted */ });
205
+ transition.ready
206
+ .then(() => animateShellNavRadialReveal(origin))
207
+ .catch(() => { /* transition was skipped or aborted */ });
252
208
  }
253
209
 
254
210
  componentWillLoad() {
255
- this.renderedVariant = resolvePanelNavVariant(this.variant, this.el.getAttribute('variant'));
211
+ this.renderedStyle = resolvePanelNavStyle(this.navStyle, this.el.getAttribute('nav-style'));
256
212
  if (this.storageKey) {
257
213
  try {
258
214
  const stored = localStorage.getItem(this.storageKey);
@@ -331,7 +287,7 @@ export class PanelNav {
331
287
 
332
288
  /** Re-parse props assigned by the host after componentWillLoad (Angular ngAfterViewInit). */
333
289
  private syncHostPropsIfNeeded() {
334
- this.syncRenderedVariantIfNeeded();
290
+ this.syncRenderedStyleIfNeeded();
335
291
 
336
292
  if (shouldResyncPanelNavGroups(this.parsedGroups, this.groups)) {
337
293
  this.onGroupsChange(this.groups);
@@ -340,16 +296,16 @@ export class PanelNav {
340
296
  }
341
297
  }
342
298
 
343
- /** Align `renderedVariant` with `variant` when host bindings land after first paint. */
344
- private syncRenderedVariantIfNeeded() {
345
- if (!shouldResyncPanelNavVariant(this.renderedVariant, this.variant)) return;
299
+ /** Align `renderedStyle` with `style` when host bindings land after first paint. */
300
+ private syncRenderedStyleIfNeeded() {
301
+ if (!shouldResyncPanelNavStyle(this.renderedStyle, this.navStyle)) return;
346
302
 
347
303
  if (this.effectiveDisableViewTransition) {
348
304
  vtTransitions.get(this)?.skipTransition();
349
305
  vtTransitions.delete(this);
350
- this.renderedVariant = this.variant;
306
+ this.renderedStyle = this.navStyle;
351
307
  } else {
352
- void this.onVariantChange(this.variant);
308
+ void this.onNavStyleChange(this.navStyle);
353
309
  }
354
310
  }
355
311
 
@@ -517,7 +473,15 @@ export class PanelNav {
517
473
  </ds-text>
518
474
  </span>
519
475
  </span>,
520
- item.dot && <span class="panel-nav__item-dot" aria-hidden="true" />,
476
+ item.dot && (
477
+ <ds-badge
478
+ class="panel-nav__item-dot"
479
+ variant="dot"
480
+ background="var(--_nav-bg)"
481
+ label=""
482
+ aria-hidden="true"
483
+ />
484
+ ),
521
485
  ];
522
486
 
523
487
  const sharedProps = {
@@ -538,14 +502,14 @@ export class PanelNav {
538
502
  }
539
503
 
540
504
  render() {
541
- const isDashboard = this.renderedVariant === 'dashboard';
505
+ const isNavigation = this.renderedStyle === 'navigation';
542
506
  const collapsed = this.collapsed || this.viewportNarrow;
543
507
  const { userName, userInitial } = this;
544
508
 
545
509
  const navCls: Record<string, boolean> = {
546
510
  'panel-nav': true,
547
- 'panel-nav--dashboard': isDashboard,
548
- 'panel-nav--settings': !isDashboard,
511
+ 'panel-nav--navigation': isNavigation,
512
+ 'panel-nav--default': !isNavigation,
549
513
  'panel-nav--collapsed': collapsed,
550
514
  'panel-nav--animating': this.isAnimating,
551
515
  'panel-nav--at-bottom': this.atBottom,
@@ -553,7 +517,7 @@ export class PanelNav {
553
517
 
554
518
  return (
555
519
  <Host style={{ display: 'block', position: 'relative' }}>
556
- <nav class={navCls} aria-label={isDashboard ? 'Main navigation' : 'Settings navigation'}>
520
+ <nav class={navCls} aria-label={isNavigation ? 'Main navigation' : 'Settings navigation'}>
557
521
 
558
522
  {/* ── Header: Motive logo, reveals collapse toggle on hover ── */}
559
523
  <div class="panel-nav__header">
@@ -604,15 +568,23 @@ export class PanelNav {
604
568
 
605
569
  {/* ── Footer ── */}
606
570
  <div class="panel-nav__footer">
607
- {/* Left icon button — Gear in dashboard, Dashboard in settings */}
571
+ <ds-fade
572
+ class="panel-nav__footer-fade"
573
+ side="bottom"
574
+ size="size-600"
575
+ background="var(--_nav-bg)"
576
+ visible={!this.atBottom}
577
+ />
578
+
579
+ {/* Left icon button — Gear in navigation style, Dashboard in default style */}
608
580
  <button
609
581
  type="button"
610
582
  class="panel-nav__footer-btn"
611
- title={isDashboard ? 'Settings' : 'Dashboard'}
612
- aria-label={isDashboard ? 'Open settings' : 'Go to dashboard'}
583
+ title={isNavigation ? 'Settings' : 'Dashboard'}
584
+ aria-label={isNavigation ? 'Open settings' : 'Go to dashboard'}
613
585
  onClick={() => this.handleFooterAction()}
614
586
  >
615
- <ds-icon name={isDashboard ? 'Gear' : 'Dashboard'} size="md" color="inherit" />
587
+ <ds-icon name={isNavigation ? 'Gear' : 'Dashboard'} size="md" color="inherit" />
616
588
  </button>
617
589
 
618
590
  {/* Right user — label fades like nav items; right icon cross-fades chevron ↔ circle+initial */}
@@ -1,7 +1,12 @@
1
- export type { PanelNavVariant, PanelNavRouterMode, PanelNavItem, PanelNavGroup } from './PanelNav';
1
+ export type { PanelNavRouterMode, PanelNavItem, PanelNavGroup } from './panel-nav-types';
2
+ export type { NavChromeStyle } from '../../nav/nav-chrome';
2
3
  export {
3
- PANEL_NAV_VARIANT_HINT_ATTR,
4
- clearPanelNavVariantHint,
4
+ NAV_STYLE_HINT_ATTR,
5
+ setNavStyleHint,
6
+ clearNavStyleHint,
7
+ resolvePanelNavStyle,
8
+ shouldResyncPanelNavStyle,
5
9
  ensurePanelNavVtStyle,
6
- setPanelNavVariantHint,
10
+ deriveActiveIdFromUrl,
11
+ parsePanelNavGroups,
7
12
  } from './panel-nav-utils';
@@ -0,0 +1,22 @@
1
+ import type { NavChromeStyle } from '../../nav/nav-chrome';
2
+
3
+ export type { NavChromeStyle };
4
+ export type PanelNavRouterMode = 'anchor' | 'event';
5
+
6
+ export interface PanelNavItem {
7
+ id: string;
8
+ icon: string;
9
+ label: string;
10
+ /** Show a notification dot badge on the item */
11
+ dot?: boolean;
12
+ flag?: boolean;
13
+ /** Route path used for `currentUrl` matching. In `anchor` mode also sets `<a href>`.
14
+ * In `event` mode navigation is delegated to the host via `dsNavSelect`. */
15
+ href?: string;
16
+ }
17
+
18
+ export interface PanelNavGroup {
19
+ id?: string;
20
+ label?: string;
21
+ items: PanelNavItem[];
22
+ }