@ds-mo/ui 2.4.1 → 2.5.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 (54) hide show
  1. package/dist/.build-stamp +1 -1
  2. package/dist/components/ds-app-shell.js +1 -1
  3. package/dist/components/ds-app-shell.js.map +1 -1
  4. package/dist/components/ds-bar-nav.js +1 -1
  5. package/dist/components/ds-bar-nav.js.map +1 -1
  6. package/dist/components/ds-menu.js +1 -1
  7. package/dist/components/ds-select.js +1 -1
  8. package/dist/components/ds-select.js.map +1 -1
  9. package/dist/components/ds-shell-gradient-picker.d.ts +11 -0
  10. package/dist/components/ds-shell-gradient-picker.js +2 -0
  11. package/dist/components/ds-shell-gradient-picker.js.map +1 -0
  12. package/dist/components/ds-shell-gradient-swatch.d.ts +11 -0
  13. package/dist/components/ds-shell-gradient-swatch.js +2 -0
  14. package/dist/components/ds-shell-gradient-swatch.js.map +1 -0
  15. package/dist/components/ds-slider.js +1 -1
  16. package/dist/components/ds-toggle.js +1 -1
  17. package/dist/components/p-BU5fKLdO.js +2 -0
  18. package/dist/components/p-BU5fKLdO.js.map +1 -0
  19. package/dist/components/p-BgiK3sHs.js +2 -0
  20. package/dist/components/p-BgiK3sHs.js.map +1 -0
  21. package/dist/components/p-CLmK4lRE.js +2 -0
  22. package/dist/components/p-CLmK4lRE.js.map +1 -0
  23. package/dist/components/p-DKG6W4pb.js +2 -0
  24. package/dist/components/p-DKG6W4pb.js.map +1 -0
  25. package/dist/types/components/AppShell/AppShell.d.ts +6 -0
  26. package/dist/types/components/Menu/Menu.d.ts +4 -0
  27. package/dist/types/components/Menu/menu-types.d.ts +10 -1
  28. package/dist/types/components/ShellGradientPicker/ShellGradientPicker.d.ts +10 -0
  29. package/dist/types/components/ShellGradientSwatch/ShellGradientSwatch.d.ts +14 -0
  30. package/dist/types/components/ShellGradientSwatch/shell-gradient-swatch-types.d.ts +4 -0
  31. package/dist/types/components.d.ts +127 -0
  32. package/dist/types/nav/index.d.ts +2 -0
  33. package/dist/types/nav/shell-gradient-presets.d.ts +11 -0
  34. package/dist/types/nav/shell-gradient.d.ts +7 -4
  35. package/package.json +2 -2
  36. package/src/angular/index.ts +2 -0
  37. package/src/angular/proxies.ts +69 -3
  38. package/src/react/components.ts +2 -0
  39. package/src/react/ds-menu.ts +5 -3
  40. package/src/react/ds-shell-gradient-picker.ts +27 -0
  41. package/src/react/ds-shell-gradient-swatch.ts +27 -0
  42. package/src/wc/components/AppShell/AppShell.tsx +13 -1
  43. package/src/wc/components/BarNav/bar-nav-tabs-menu-utils.ts +2 -2
  44. package/src/wc/components/Menu/Menu.tsx +27 -4
  45. package/src/wc/components/Menu/menu-types.ts +19 -1
  46. package/src/wc/components/ShellGradientPicker/ShellGradientPicker.tsx +49 -0
  47. package/src/wc/components/ShellGradientSwatch/ShellGradientSwatch.tsx +53 -0
  48. package/src/wc/components/ShellGradientSwatch/shell-gradient-swatch-types.ts +16 -0
  49. package/src/wc/components.d.ts +127 -0
  50. package/src/wc/nav/index.ts +9 -0
  51. package/src/wc/nav/shell-gradient-presets.ts +35 -0
  52. package/src/wc/nav/shell-gradient.ts +26 -8
  53. package/dist/components/p-YzIqPOqL.js +0 -2
  54. package/dist/components/p-YzIqPOqL.js.map +0 -1
@@ -36,14 +36,14 @@ export declare interface DsAccordion extends Components.DsAccordion {
36
36
 
37
37
 
38
38
  @ProxyCmp({
39
- inputs: ['gradient', 'gradientSrc', 'grid', 'navStyle', 'shortcutsEnabled']
39
+ inputs: ['gradient', 'gradientPreset', 'gradientSrc', 'grid', 'navStyle', 'shortcutsEnabled']
40
40
  })
41
41
  @Component({
42
42
  selector: 'ds-app-shell',
43
43
  changeDetection: ChangeDetectionStrategy.OnPush,
44
44
  template: '<ng-content></ng-content>',
45
45
  // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
46
- inputs: ['gradient', 'gradientSrc', 'grid', 'navStyle', 'shortcutsEnabled'],
46
+ inputs: ['gradient', 'gradientPreset', 'gradientSrc', 'grid', 'navStyle', 'shortcutsEnabled'],
47
47
  standalone: false
48
48
  })
49
49
  export class DsAppShell {
@@ -558,13 +558,14 @@ export declare interface DsLoader extends Components.DsLoader {}
558
558
  template: '<ng-content></ng-content>',
559
559
  // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
560
560
  inputs: ['align', 'alignOffset', 'anchor', 'anchorId', 'initialFocusVisible', 'items', 'menuWidth', 'minWidth', 'open', 'sections', 'side', 'sideOffset'],
561
- outputs: ['dsClose', 'dsSelect'],
561
+ outputs: ['dsClose', 'dsSelect', 'dsGradientSelect'],
562
562
  standalone: false
563
563
  })
564
564
  export class DsMenu {
565
565
  protected el: HTMLDsMenuElement;
566
566
  @Output() dsClose = new EventEmitter<CustomEvent<void>>();
567
567
  @Output() dsSelect = new EventEmitter<CustomEvent<IDsMenuMenuItemData>>();
568
+ @Output() dsGradientSelect = new EventEmitter<CustomEvent<IDsMenuShellGradientPreset>>();
568
569
  constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
569
570
  c.detach();
570
571
  this.el = r.nativeElement;
@@ -573,12 +574,17 @@ export class DsMenu {
573
574
 
574
575
 
575
576
  import type { MenuItemData as IDsMenuMenuItemData } from '@ds-mo/ui';
577
+ import type { ShellGradientPreset as IDsMenuShellGradientPreset } from '@ds-mo/ui';
576
578
 
577
579
  export declare interface DsMenu extends Components.DsMenu {
578
580
 
579
581
  dsClose: EventEmitter<CustomEvent<void>>;
580
582
 
581
583
  dsSelect: EventEmitter<CustomEvent<IDsMenuMenuItemData>>;
584
+ /**
585
+ * Emitted when a `gradient-picker` section swatch is chosen.
586
+ */
587
+ dsGradientSelect: EventEmitter<CustomEvent<IDsMenuShellGradientPreset>>;
582
588
  }
583
589
 
584
590
 
@@ -818,6 +824,66 @@ export declare interface DsSelect extends Components.DsSelect {
818
824
  }
819
825
 
820
826
 
827
+ @ProxyCmp({
828
+ inputs: ['value']
829
+ })
830
+ @Component({
831
+ selector: 'ds-shell-gradient-picker',
832
+ changeDetection: ChangeDetectionStrategy.OnPush,
833
+ template: '<ng-content></ng-content>',
834
+ // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
835
+ inputs: ['value'],
836
+ outputs: ['dsChange'],
837
+ standalone: false
838
+ })
839
+ export class DsShellGradientPicker {
840
+ protected el: HTMLDsShellGradientPickerElement;
841
+ @Output() dsChange = new EventEmitter<CustomEvent<IDsShellGradientPickerShellGradientPreset>>();
842
+ constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
843
+ c.detach();
844
+ this.el = r.nativeElement;
845
+ }
846
+ }
847
+
848
+
849
+ import type { ShellGradientPreset as IDsShellGradientPickerShellGradientPreset } from '@ds-mo/ui';
850
+
851
+ export declare interface DsShellGradientPicker extends Components.DsShellGradientPicker {
852
+
853
+ dsChange: EventEmitter<CustomEvent<IDsShellGradientPickerShellGradientPreset>>;
854
+ }
855
+
856
+
857
+ @ProxyCmp({
858
+ inputs: ['ariaLabel', 'inactive', 'preset', 'selected']
859
+ })
860
+ @Component({
861
+ selector: 'ds-shell-gradient-swatch',
862
+ changeDetection: ChangeDetectionStrategy.OnPush,
863
+ template: '<ng-content></ng-content>',
864
+ // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
865
+ inputs: ['ariaLabel', 'inactive', 'preset', 'selected'],
866
+ outputs: ['dsSelect'],
867
+ standalone: false
868
+ })
869
+ export class DsShellGradientSwatch {
870
+ protected el: HTMLDsShellGradientSwatchElement;
871
+ @Output() dsSelect = new EventEmitter<CustomEvent<IDsShellGradientSwatchShellGradientPreset>>();
872
+ constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
873
+ c.detach();
874
+ this.el = r.nativeElement;
875
+ }
876
+ }
877
+
878
+
879
+ import type { ShellGradientPreset as IDsShellGradientSwatchShellGradientPreset } from '@ds-mo/ui';
880
+
881
+ export declare interface DsShellGradientSwatch extends Components.DsShellGradientSwatch {
882
+
883
+ dsSelect: EventEmitter<CustomEvent<IDsShellGradientSwatchShellGradientPreset>>;
884
+ }
885
+
886
+
821
887
  @ProxyCmp({
822
888
  inputs: ['height', 'lines', 'shimmer', 'variant', 'width']
823
889
  })
@@ -32,6 +32,8 @@ export { DsPanelTools } from "./ds-panel-tools.js";
32
32
  export { DsRadioGroup } from "./ds-radio-group.js";
33
33
  export { DsScrollbar } from "./ds-scrollbar.js";
34
34
  export { DsSelect } from "./ds-select.js";
35
+ export { DsShellGradientPicker } from "./ds-shell-gradient-picker.js";
36
+ export { DsShellGradientSwatch } from "./ds-shell-gradient-swatch.js";
35
37
  export { DsSkeleton } from "./ds-skeleton.js";
36
38
  export { DsSlider } from "./ds-slider.js";
37
39
  export { DsSurface } from "./ds-surface.js";
@@ -11,13 +11,14 @@ import type { EventName, StencilReactComponent } from '@stencil/react-output-tar
11
11
  import { createComponent } from '@stencil/react-output-target/runtime';
12
12
  import React from 'react';
13
13
 
14
- import { type DsMenuCustomEvent, type MenuItemData } from "@ds-mo/ui";
14
+ import { type DsMenuCustomEvent, type MenuItemData, type ShellGradientPreset } from "@ds-mo/ui";
15
15
  import type { Components } from "@ds-mo/ui/dist/components";
16
16
  import { DsMenu as DsMenuElement, defineCustomElement as defineDsMenu } from "@ds-mo/ui/dist/components/ds-menu.js";
17
17
 
18
18
  export type DsMenuEvents = {
19
19
  onDsClose: EventName<DsMenuCustomEvent<void>>,
20
- onDsSelect: EventName<DsMenuCustomEvent<MenuItemData>>
20
+ onDsSelect: EventName<DsMenuCustomEvent<MenuItemData>>,
21
+ onDsGradientSelect: EventName<DsMenuCustomEvent<ShellGradientPreset>>
21
22
  };
22
23
 
23
24
  export const DsMenu: StencilReactComponent<DsMenuElement, DsMenuEvents, Components.DsMenu> = /*@__PURE__*/ createComponent<DsMenuElement, DsMenuEvents, Components.DsMenu>({
@@ -27,7 +28,8 @@ export const DsMenu: StencilReactComponent<DsMenuElement, DsMenuEvents, Componen
27
28
  react: React,
28
29
  events: {
29
30
  onDsClose: 'dsClose',
30
- onDsSelect: 'dsSelect'
31
+ onDsSelect: 'dsSelect',
32
+ onDsGradientSelect: 'dsGradientSelect'
31
33
  } as DsMenuEvents,
32
34
  defineCustomElement: defineDsMenu
33
35
  });
@@ -0,0 +1,27 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * This file was automatically generated by the Stencil React Output Target.
5
+ * Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
6
+ */
7
+
8
+ /* eslint-disable */
9
+
10
+ import type { EventName, StencilReactComponent } from '@stencil/react-output-target/runtime';
11
+ import { createComponent } from '@stencil/react-output-target/runtime';
12
+ import React from 'react';
13
+
14
+ import { type DsShellGradientPickerCustomEvent, type ShellGradientPreset } from "@ds-mo/ui";
15
+ import type { Components } from "@ds-mo/ui/dist/components";
16
+ import { DsShellGradientPicker as DsShellGradientPickerElement, defineCustomElement as defineDsShellGradientPicker } from "@ds-mo/ui/dist/components/ds-shell-gradient-picker.js";
17
+
18
+ export type DsShellGradientPickerEvents = { onDsChange: EventName<DsShellGradientPickerCustomEvent<ShellGradientPreset>> };
19
+
20
+ export const DsShellGradientPicker: StencilReactComponent<DsShellGradientPickerElement, DsShellGradientPickerEvents, Components.DsShellGradientPicker> = /*@__PURE__*/ createComponent<DsShellGradientPickerElement, DsShellGradientPickerEvents, Components.DsShellGradientPicker>({
21
+ tagName: 'ds-shell-gradient-picker',
22
+ elementClass: DsShellGradientPickerElement,
23
+ // @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
24
+ react: React,
25
+ events: { onDsChange: 'dsChange' } as DsShellGradientPickerEvents,
26
+ defineCustomElement: defineDsShellGradientPicker
27
+ });
@@ -0,0 +1,27 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * This file was automatically generated by the Stencil React Output Target.
5
+ * Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
6
+ */
7
+
8
+ /* eslint-disable */
9
+
10
+ import type { EventName, StencilReactComponent } from '@stencil/react-output-target/runtime';
11
+ import { createComponent } from '@stencil/react-output-target/runtime';
12
+ import React from 'react';
13
+
14
+ import { type DsShellGradientSwatchCustomEvent, type ShellGradientPreset } from "@ds-mo/ui";
15
+ import type { Components } from "@ds-mo/ui/dist/components";
16
+ import { DsShellGradientSwatch as DsShellGradientSwatchElement, defineCustomElement as defineDsShellGradientSwatch } from "@ds-mo/ui/dist/components/ds-shell-gradient-swatch.js";
17
+
18
+ export type DsShellGradientSwatchEvents = { onDsSelect: EventName<DsShellGradientSwatchCustomEvent<ShellGradientPreset>> };
19
+
20
+ export const DsShellGradientSwatch: StencilReactComponent<DsShellGradientSwatchElement, DsShellGradientSwatchEvents, Components.DsShellGradientSwatch> = /*@__PURE__*/ createComponent<DsShellGradientSwatchElement, DsShellGradientSwatchEvents, Components.DsShellGradientSwatch>({
21
+ tagName: 'ds-shell-gradient-swatch',
22
+ elementClass: DsShellGradientSwatchElement,
23
+ // @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
24
+ react: React,
25
+ events: { onDsSelect: 'dsSelect' } as DsShellGradientSwatchEvents,
26
+ defineCustomElement: defineDsShellGradientSwatch
27
+ });
@@ -5,6 +5,10 @@ import {
5
5
  resolveShellShortcut,
6
6
  } from '../../nav/shell-shortcuts';
7
7
  import type { PanelToolsToolId } from '../PanelTools/panel-tools-types';
8
+ import {
9
+ DEFAULT_SHELL_GRADIENT_PRESET,
10
+ type ShellGradientPreset,
11
+ } from '../../nav/shell-gradient-presets';
8
12
  import {
9
13
  CHROME_TRANSITION_END,
10
14
  CHROME_TRANSITION_START,
@@ -53,6 +57,13 @@ export class AppShell {
53
57
  */
54
58
  @Prop() gradientSrc: string = '';
55
59
 
60
+ /**
61
+ * Built-in shell wash preset when `gradient` is true.
62
+ * `cool` (blue), `neutral` (grey), `warm` (yellow). `gradientSrc` overrides when set.
63
+ */
64
+ @Prop({ attribute: 'gradient-preset', reflect: true }) gradientPreset: ShellGradientPreset =
65
+ DEFAULT_SHELL_GRADIENT_PRESET;
66
+
56
67
  /** When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native. */
57
68
  @Prop({ attribute: 'shortcuts-enabled' }) shortcutsEnabled: boolean = true;
58
69
 
@@ -98,6 +109,7 @@ export class AppShell {
98
109
  @Watch('gradient')
99
110
  @Watch('grid')
100
111
  @Watch('gradientSrc')
112
+ @Watch('gradientPreset')
101
113
  onShellPropsChange() {
102
114
  this.syncSlottedNavStyle();
103
115
  this.scheduleChromeSync();
@@ -311,7 +323,7 @@ export class AppShell {
311
323
 
312
324
  const image = this.gradientSrc.trim()
313
325
  ? `url(${this.gradientSrc.trim()})`
314
- : buildShellRadialGradient();
326
+ : buildShellRadialGradient(this.gradientPreset);
315
327
 
316
328
  const size = shellGradientSize({
317
329
  width: viewport.width,
@@ -1,4 +1,4 @@
1
- import type { MenuSection } from '../Menu/menu-types';
1
+ import type { MenuItemData, MenuSection } from '../Menu/menu-types';
2
2
  import {
3
3
  getSelectableTabs,
4
4
  isTabDivider,
@@ -9,7 +9,7 @@ import {
9
9
  /** Map BarNav tabs to menu sections, preserving `{ type: 'divider' }` as section breaks. */
10
10
  export function tabsToMenuSections(tabs: TabItem[], selectedId: string): MenuSection[] {
11
11
  const sections: MenuSection[] = [];
12
- let batch: MenuSection['items'] = [];
12
+ let batch: MenuItemData[] = [];
13
13
 
14
14
  for (const item of tabs) {
15
15
  if (isTabDivider(item)) {
@@ -2,6 +2,8 @@ import { Component, Prop, State, Event, EventEmitter, Element, Watch, Listen, h,
2
2
  import { resolveCssLengthPx, resolveCssTimeMs, TOKEN_DEFAULTS } from '../../utils';
3
3
  import { computeMenuPosition, type MenuAlign, type MenuSide } from './menu-position';
4
4
  import type { MenuItemData, MenuSection } from './menu-types';
5
+ import { isMenuGradientPickerSection } from './menu-types';
6
+ import type { ShellGradientPreset } from '../../nav/shell-gradient-presets';
5
7
 
6
8
  /** rAF retries while the popup mounts or the anchor resolves. */
7
9
  const POSITION_RETRY_BUDGET = 8;
@@ -41,6 +43,8 @@ export class Menu {
41
43
 
42
44
  @Event() dsClose!: EventEmitter<void>;
43
45
  @Event() dsSelect!: EventEmitter<MenuItemData>;
46
+ /** Emitted when a `gradient-picker` section swatch is chosen. */
47
+ @Event() dsGradientSelect!: EventEmitter<ShellGradientPreset>;
44
48
 
45
49
  private clickOutsideHandler: ((e: MouseEvent) => void) | null = null;
46
50
  private scrollResizeHandler: (() => void) | null = null;
@@ -136,7 +140,9 @@ export class Menu {
136
140
  }
137
141
 
138
142
  private get flatItems(): MenuItemData[] {
139
- return this.activeSections.flatMap(s => s.items);
143
+ return this.activeSections.flatMap(section =>
144
+ isMenuGradientPickerSection(section) ? [] : section.items,
145
+ );
140
146
  }
141
147
 
142
148
  private cancelPositionRetry() {
@@ -309,6 +315,10 @@ export class Menu {
309
315
  this.close();
310
316
  }
311
317
 
318
+ private handleGradientSelect(preset: ShellGradientPreset) {
319
+ this.dsGradientSelect.emit(preset);
320
+ }
321
+
312
322
  render() {
313
323
  if (!this.shouldRender) return <Host style={{ display: 'contents' }} />;
314
324
 
@@ -339,7 +349,11 @@ export class Menu {
339
349
  {sections.map((section, si) => (
340
350
  <div
341
351
  key={si}
342
- class={{ 'menu-section': true, 'menu-section--divided': si < sections.length - 1 }}
352
+ class={{
353
+ 'menu-section': true,
354
+ 'menu-section--divided': si < sections.length - 1,
355
+ 'menu-section--gradient-picker': isMenuGradientPickerSection(section),
356
+ }}
343
357
  role={section.header ? 'group' : undefined}
344
358
  aria-label={section.header}
345
359
  >
@@ -348,7 +362,16 @@ export class Menu {
348
362
  <span class="text-body-small-emphasis section-label">{section.header}</span>
349
363
  </div>
350
364
  )}
351
- {section.items.map(item => {
365
+ {isMenuGradientPickerSection(section) ? (
366
+ <ds-shell-gradient-picker
367
+ value={section.value}
368
+ onDsChange={(e: CustomEvent<ShellGradientPreset>) => {
369
+ e.stopPropagation();
370
+ this.handleGradientSelect(e.detail);
371
+ }}
372
+ />
373
+ ) : (
374
+ section.items.map(item => {
352
375
  const idx = flatIdx++;
353
376
  const isFocused = this.focusedIndex === idx;
354
377
  return (
@@ -387,7 +410,7 @@ export class Menu {
387
410
  )}
388
411
  </button>
389
412
  );
390
- })}
413
+ }))}
391
414
  </div>
392
415
  ))}
393
416
  </div>
@@ -1,3 +1,5 @@
1
+ import type { ShellGradientPreset } from '../../nav/shell-gradient-presets';
2
+
1
3
  export type { MenuAlign, MenuSide } from './menu-position';
2
4
 
3
5
  export interface MenuItemData {
@@ -11,7 +13,23 @@ export interface MenuItemData {
11
13
  toggleValue?: boolean;
12
14
  }
13
15
 
14
- export interface MenuSection {
16
+ export interface MenuItemsSection {
15
17
  header?: string;
16
18
  items: MenuItemData[];
17
19
  }
20
+
21
+ export interface MenuGradientPickerSection {
22
+ header?: string;
23
+ variant: 'gradient-picker';
24
+ value: ShellGradientPreset;
25
+ }
26
+
27
+ export type MenuSection = MenuItemsSection | MenuGradientPickerSection;
28
+
29
+ export function isMenuGradientPickerSection(
30
+ section: MenuSection,
31
+ ): section is MenuGradientPickerSection {
32
+ return 'variant' in section && section.variant === 'gradient-picker';
33
+ }
34
+
35
+ export type { ShellGradientPreset };
@@ -0,0 +1,49 @@
1
+ import { Component, Prop, Event, EventEmitter, h, Host } from '@stencil/core';
2
+ import {
3
+ SHELL_GRADIENT_PRESETS,
4
+ DEFAULT_SHELL_GRADIENT_PRESET,
5
+ type ShellGradientPreset,
6
+ } from '../ShellGradientSwatch/shell-gradient-swatch-types';
7
+
8
+ @Component({
9
+ tag: 'ds-shell-gradient-picker',
10
+ styleUrl: 'ShellGradientPicker.css',
11
+ scoped: true,
12
+ })
13
+ export class ShellGradientPicker {
14
+ /** Active shell wash preset. */
15
+ @Prop({ mutable: true, reflect: true }) value: ShellGradientPreset =
16
+ DEFAULT_SHELL_GRADIENT_PRESET;
17
+
18
+ @Event() dsChange!: EventEmitter<ShellGradientPreset>;
19
+
20
+ private handleSwatchSelect = (preset: ShellGradientPreset) => {
21
+ if (preset === this.value) return;
22
+ this.value = preset;
23
+ this.dsChange.emit(preset);
24
+ };
25
+
26
+ render() {
27
+ return (
28
+ <Host>
29
+ <div
30
+ class="shell-gradient-picker"
31
+ role="radiogroup"
32
+ aria-label="Shell gradient theme"
33
+ >
34
+ {SHELL_GRADIENT_PRESETS.map(preset => (
35
+ <ds-shell-gradient-swatch
36
+ key={preset}
37
+ preset={preset}
38
+ selected={this.value === preset}
39
+ onDsSelect={(e: CustomEvent<ShellGradientPreset>) => {
40
+ e.stopPropagation();
41
+ this.handleSwatchSelect(e.detail);
42
+ }}
43
+ />
44
+ ))}
45
+ </div>
46
+ </Host>
47
+ );
48
+ }
49
+ }
@@ -0,0 +1,53 @@
1
+ import { Component, Prop, Event, EventEmitter, h, Host } from '@stencil/core';
2
+ import {
3
+ SHELL_GRADIENT_PRESET_LABELS,
4
+ buildShellRadialGradientForPreset,
5
+ DEFAULT_SHELL_GRADIENT_PRESET,
6
+ type ShellGradientPreset,
7
+ } from './shell-gradient-swatch-types';
8
+
9
+ @Component({
10
+ tag: 'ds-shell-gradient-swatch',
11
+ styleUrl: 'ShellGradientSwatch.css',
12
+ scoped: true,
13
+ })
14
+ export class ShellGradientSwatch {
15
+ /** Wash preset this orb previews. */
16
+ @Prop({ reflect: true }) preset: ShellGradientPreset = DEFAULT_SHELL_GRADIENT_PRESET;
17
+
18
+ /** Selected state — shows an inset brand ring. */
19
+ @Prop({ reflect: true }) selected = false;
20
+
21
+ @Prop() inactive = false;
22
+
23
+ @Prop({ attribute: 'aria-label' }) ariaLabel: string | undefined;
24
+
25
+ @Event() dsSelect!: EventEmitter<ShellGradientPreset>;
26
+
27
+ private handleClick = () => {
28
+ if (this.inactive) return;
29
+ this.dsSelect.emit(this.preset);
30
+ };
31
+
32
+ render() {
33
+ const label = this.ariaLabel ?? SHELL_GRADIENT_PRESET_LABELS[this.preset];
34
+
35
+ return (
36
+ <Host>
37
+ <button
38
+ type="button"
39
+ class={{
40
+ 'shell-gradient-swatch': true,
41
+ 'ds-focus-ring-inset': true,
42
+ 'shell-gradient-swatch--selected': this.selected,
43
+ }}
44
+ style={{ backgroundImage: buildShellRadialGradientForPreset(this.preset) }}
45
+ aria-label={label}
46
+ aria-pressed={this.selected ? 'true' : 'false'}
47
+ disabled={this.inactive}
48
+ onClick={this.handleClick}
49
+ />
50
+ </Host>
51
+ );
52
+ }
53
+ }
@@ -0,0 +1,16 @@
1
+ import type { ShellGradientPreset } from '../../nav/shell-gradient-presets';
2
+ import {
3
+ SHELL_GRADIENT_PRESET_LABELS,
4
+ buildShellRadialGradientForPreset,
5
+ } from '../../nav/shell-gradient-presets';
6
+
7
+ export type { ShellGradientPreset };
8
+
9
+ export {
10
+ DEFAULT_SHELL_GRADIENT_PRESET,
11
+ SHELL_GRADIENT_PRESETS,
12
+ SHELL_GRADIENT_PRESET_LABELS,
13
+ buildShellRadialGradientForPreset,
14
+ isShellGradientPreset,
15
+ shellGradientPresetStopToken,
16
+ } from '../../nav/shell-gradient-presets';