@ds-mo/ui 2.4.1 → 2.6.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/.build-stamp +1 -1
- package/dist/components/ds-app-shell.js +1 -1
- package/dist/components/ds-app-shell.js.map +1 -1
- package/dist/components/ds-bar-nav.js +1 -1
- package/dist/components/ds-bar-nav.js.map +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-panel-nav.js +1 -1
- package/dist/components/ds-panel-nav.js.map +1 -1
- package/dist/components/ds-select.js +1 -1
- package/dist/components/ds-select.js.map +1 -1
- package/dist/components/ds-shell-gradient-picker.d.ts +11 -0
- package/dist/components/ds-shell-gradient-picker.js +2 -0
- package/dist/components/ds-shell-gradient-picker.js.map +1 -0
- package/dist/components/ds-shell-gradient-swatch.d.ts +11 -0
- package/dist/components/ds-shell-gradient-swatch.js +2 -0
- package/dist/components/ds-shell-gradient-swatch.js.map +1 -0
- package/dist/components/ds-slider.js +1 -1
- package/dist/components/ds-toggle.js +1 -1
- package/dist/components/p-BU5fKLdO.js +2 -0
- package/dist/components/p-BU5fKLdO.js.map +1 -0
- package/dist/components/p-BgiK3sHs.js +2 -0
- package/dist/components/p-BgiK3sHs.js.map +1 -0
- package/dist/components/p-CLmK4lRE.js +2 -0
- package/dist/components/p-CLmK4lRE.js.map +1 -0
- package/dist/components/p-DKG6W4pb.js +2 -0
- package/dist/components/p-DKG6W4pb.js.map +1 -0
- package/dist/types/components/AppShell/AppShell.d.ts +6 -0
- package/dist/types/components/Menu/Menu.d.ts +4 -0
- package/dist/types/components/Menu/menu-placement.d.ts +21 -0
- package/dist/types/components/Menu/menu-types.d.ts +11 -1
- package/dist/types/components/PanelNav/index.d.ts +1 -1
- package/dist/types/components/PanelNav/panel-nav-types.d.ts +5 -0
- package/dist/types/components/ShellGradientPicker/ShellGradientPicker.d.ts +10 -0
- package/dist/types/components/ShellGradientSwatch/ShellGradientSwatch.d.ts +14 -0
- package/dist/types/components/ShellGradientSwatch/shell-gradient-swatch-types.d.ts +4 -0
- package/dist/types/components.d.ts +127 -0
- package/dist/types/nav/index.d.ts +4 -0
- package/dist/types/nav/shell-gradient-presets.d.ts +11 -0
- package/dist/types/nav/shell-gradient.d.ts +7 -4
- package/package.json +3 -3
- package/src/angular/index.ts +2 -0
- package/src/angular/proxies.ts +69 -3
- package/src/react/components.ts +2 -0
- package/src/react/ds-menu.ts +5 -3
- package/src/react/ds-shell-gradient-picker.ts +27 -0
- package/src/react/ds-shell-gradient-swatch.ts +27 -0
- package/src/wc/components/AppShell/AppShell.tsx +13 -1
- package/src/wc/components/BarNav/bar-nav-tabs-menu-utils.ts +2 -2
- package/src/wc/components/Menu/Menu.tsx +27 -4
- package/src/wc/components/Menu/menu-placement.ts +23 -0
- package/src/wc/components/Menu/menu-types.ts +23 -1
- package/src/wc/components/PanelNav/PanelNav.tsx +3 -2
- package/src/wc/components/PanelNav/index.ts +1 -1
- package/src/wc/components/PanelNav/panel-nav-types.ts +6 -0
- package/src/wc/components/ShellGradientPicker/ShellGradientPicker.tsx +49 -0
- package/src/wc/components/ShellGradientSwatch/ShellGradientSwatch.tsx +53 -0
- package/src/wc/components/ShellGradientSwatch/shell-gradient-swatch-types.ts +16 -0
- package/src/wc/components.d.ts +130 -0
- package/src/wc/nav/index.ts +13 -0
- package/src/wc/nav/shell-gradient-presets.ts +35 -0
- package/src/wc/nav/shell-gradient.ts +26 -8
- package/dist/components/p-YzIqPOqL.js +0 -2
- package/dist/components/p-YzIqPOqL.js.map +0 -1
package/src/angular/index.ts
CHANGED
package/src/angular/proxies.ts
CHANGED
|
@@ -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
|
})
|
package/src/react/components.ts
CHANGED
|
@@ -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";
|
package/src/react/ds-menu.ts
CHANGED
|
@@ -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:
|
|
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(
|
|
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={{
|
|
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
|
|
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>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TOKEN_DEFAULTS } from '../../utils';
|
|
2
|
+
import type { MenuAlign, MenuSide } from './menu-position';
|
|
3
|
+
|
|
4
|
+
/** Placement props bindable on `ds-menu` (side, align, offsets). */
|
|
5
|
+
export interface MenuPlacement {
|
|
6
|
+
side: MenuSide;
|
|
7
|
+
align: MenuAlign;
|
|
8
|
+
sideOffset: number | string;
|
|
9
|
+
alignOffset: number | string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Canonical `ds-menu` placement for the **panel-nav footer user menu**.
|
|
14
|
+
* Anchor from `dsNavUserAction` detail `{ anchor }` (id `ds-panel-nav-user-menu-anchor`).
|
|
15
|
+
*
|
|
16
|
+
* Not for BarNav overflow menus — those use `side="bottom"` / `align="end"` internally.
|
|
17
|
+
*/
|
|
18
|
+
export const PANEL_NAV_USER_MENU_PLACEMENT = {
|
|
19
|
+
side: 'right',
|
|
20
|
+
align: 'start',
|
|
21
|
+
sideOffset: TOKEN_DEFAULTS.space050,
|
|
22
|
+
alignOffset: 0,
|
|
23
|
+
} as const satisfies MenuPlacement;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import type { ShellGradientPreset } from '../../nav/shell-gradient-presets';
|
|
2
|
+
|
|
1
3
|
export type { MenuAlign, MenuSide } from './menu-position';
|
|
4
|
+
export {
|
|
5
|
+
PANEL_NAV_USER_MENU_PLACEMENT,
|
|
6
|
+
type MenuPlacement,
|
|
7
|
+
} from './menu-placement';
|
|
2
8
|
|
|
3
9
|
export interface MenuItemData {
|
|
4
10
|
label: string;
|
|
@@ -11,7 +17,23 @@ export interface MenuItemData {
|
|
|
11
17
|
toggleValue?: boolean;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
|
-
export interface
|
|
20
|
+
export interface MenuItemsSection {
|
|
15
21
|
header?: string;
|
|
16
22
|
items: MenuItemData[];
|
|
17
23
|
}
|
|
24
|
+
|
|
25
|
+
export interface MenuGradientPickerSection {
|
|
26
|
+
header?: string;
|
|
27
|
+
variant: 'gradient-picker';
|
|
28
|
+
value: ShellGradientPreset;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type MenuSection = MenuItemsSection | MenuGradientPickerSection;
|
|
32
|
+
|
|
33
|
+
export function isMenuGradientPickerSection(
|
|
34
|
+
section: MenuSection,
|
|
35
|
+
): section is MenuGradientPickerSection {
|
|
36
|
+
return 'variant' in section && section.variant === 'gradient-picker';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type { ShellGradientPreset };
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from './panel-nav-utils';
|
|
12
12
|
import {
|
|
13
13
|
PANEL_NAV_USER_MENU_ANCHOR_ID,
|
|
14
|
+
PANEL_NAV_USER_MENU_PLACEMENT,
|
|
14
15
|
type PanelNavGroup,
|
|
15
16
|
type PanelNavItem,
|
|
16
17
|
type PanelNavRouterMode,
|
|
@@ -336,7 +337,7 @@ export class PanelNav {
|
|
|
336
337
|
}
|
|
337
338
|
if (index === this.getUserRovingIndex()) {
|
|
338
339
|
const anchor = this.el.querySelector(`#${PANEL_NAV_USER_MENU_ANCHOR_ID}`) as HTMLElement | null;
|
|
339
|
-
if (anchor) this.dsNavUserAction.emit({ anchor });
|
|
340
|
+
if (anchor) this.dsNavUserAction.emit({ anchor, menuPlacement: PANEL_NAV_USER_MENU_PLACEMENT });
|
|
340
341
|
}
|
|
341
342
|
}
|
|
342
343
|
|
|
@@ -421,7 +422,7 @@ export class PanelNav {
|
|
|
421
422
|
|
|
422
423
|
private handleUserAction(e: MouseEvent) {
|
|
423
424
|
const anchor = e.currentTarget as HTMLElement;
|
|
424
|
-
this.dsNavUserAction.emit({ anchor });
|
|
425
|
+
this.dsNavUserAction.emit({ anchor, menuPlacement: PANEL_NAV_USER_MENU_PLACEMENT });
|
|
425
426
|
}
|
|
426
427
|
|
|
427
428
|
private clearEdgeOverlayTimer() {
|
|
@@ -4,7 +4,7 @@ export type {
|
|
|
4
4
|
PanelNavGroup,
|
|
5
5
|
PanelNavUserActionDetail,
|
|
6
6
|
} from './panel-nav-types';
|
|
7
|
-
export { PANEL_NAV_USER_MENU_ANCHOR_ID } from './panel-nav-types';
|
|
7
|
+
export { PANEL_NAV_USER_MENU_ANCHOR_ID, PANEL_NAV_USER_MENU_PLACEMENT } from './panel-nav-types';
|
|
8
8
|
export type { NavChromeStyle } from '../../nav/nav-chrome';
|
|
9
9
|
export {
|
|
10
10
|
NAV_STYLE_HINT_ATTR,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { MenuPlacement } from '../Menu/menu-placement';
|
|
2
|
+
import { PANEL_NAV_USER_MENU_PLACEMENT } from '../Menu/menu-placement';
|
|
1
3
|
import type { NavChromeStyle } from '../../nav/nav-chrome';
|
|
2
4
|
|
|
3
5
|
export type { NavChromeStyle };
|
|
@@ -27,4 +29,8 @@ export const PANEL_NAV_USER_MENU_ANCHOR_ID = 'ds-panel-nav-user-menu-anchor';
|
|
|
27
29
|
/** Detail for `dsNavUserAction` — anchor element for an external `ds-menu`. */
|
|
28
30
|
export interface PanelNavUserActionDetail {
|
|
29
31
|
anchor: HTMLElement;
|
|
32
|
+
/** Recommended `ds-menu` placement — spread onto external user menu instance. */
|
|
33
|
+
menuPlacement: MenuPlacement;
|
|
30
34
|
}
|
|
35
|
+
|
|
36
|
+
export { PANEL_NAV_USER_MENU_PLACEMENT };
|
|
@@ -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';
|