@ds-mo/ui 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ds-bar-nav-action.js +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-breadcrumb.js +1 -1
- package/dist/components/ds-button-group.js +1 -1
- package/dist/components/ds-button.js +1 -1
- package/dist/components/ds-card.js +1 -1
- package/dist/components/ds-card.js.map +1 -1
- package/dist/components/ds-checkbox.js +1 -1
- package/dist/components/ds-divider.js +1 -1
- package/dist/components/ds-empty-state.js +1 -1
- package/dist/components/ds-empty-state.js.map +1 -1
- package/dist/components/ds-fade.js +1 -1
- package/dist/components/ds-field.js +1 -1
- package/dist/components/ds-header.js +1 -1
- package/dist/components/ds-header.js.map +1 -1
- package/dist/components/ds-icon.js +1 -1
- package/dist/components/ds-input.js +1 -1
- package/dist/components/ds-label-wrap.js +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-modal.js +1 -1
- package/dist/components/ds-panel-nav.js +1 -1
- package/dist/components/ds-radio-group.js +1 -1
- package/dist/components/ds-radio-group.js.map +1 -1
- package/dist/components/ds-scrollbar.js +1 -1
- package/dist/components/ds-select.js +1 -1
- package/dist/components/ds-slider.js +1 -1
- package/dist/components/ds-slider.js.map +1 -1
- package/dist/components/ds-surface.js +1 -1
- package/dist/components/ds-tab-group-nav.d.ts +11 -0
- package/dist/components/ds-tab-group-nav.js +2 -0
- package/dist/components/ds-tab-group-nav.js.map +1 -0
- package/dist/components/ds-tab-group.js +1 -1
- package/dist/components/ds-tab-group.js.map +1 -1
- package/dist/components/ds-table.js +1 -1
- package/dist/components/ds-table.js.map +1 -1
- package/dist/components/ds-tag.js +1 -1
- package/dist/components/ds-text.js +1 -1
- package/dist/components/ds-toast-provider.js +1 -1
- package/dist/components/ds-toggle-button-group.js +1 -1
- package/dist/components/ds-toggle-button.js +1 -1
- package/dist/components/ds-toggle.js +1 -1
- package/dist/components/ds-tooltip.js +1 -1
- package/dist/components/p-BQq26pt9.js +2 -0
- package/dist/components/p-BQq26pt9.js.map +1 -0
- package/dist/components/p-CMyQsk0K.js +2 -0
- package/dist/components/p-CMyQsk0K.js.map +1 -0
- package/dist/components/{p-D3CwGoIu.js → p-COsKOwZR.js} +2 -2
- package/dist/components/p-CpbnmEu1.js +2 -0
- package/dist/components/p-CpbnmEu1.js.map +1 -0
- package/dist/components/{p-DouEVPmi.js → p-Dd0GrKaF.js} +2 -2
- package/dist/components/{p-BvxKLqNx.js → p-H89PzqGU.js} +2 -2
- package/dist/components/{p-BYe8Rfdg.js → p-Vwlmhl4E.js} +2 -2
- package/dist/components/{p-C4p1fG67.js → p-woooYulR.js} +2 -2
- package/dist/types/.stencil/BarNav/BarNav.d.ts +7 -2
- package/dist/types/.stencil/BarNav/bar-nav-dom-utils.d.ts +1 -2
- package/dist/types/.stencil/TabGroupNav/TabGroupNav.d.ts +27 -0
- package/dist/types/components.d.ts +68 -0
- package/package.json +37 -7
- package/src/angular/index.ts +1 -0
- package/src/angular/proxies.ts +28 -0
- package/src/react/components.ts +46 -0
- package/src/react/ds-accordion.ts +27 -0
- package/src/react/ds-badge.ts +26 -0
- package/src/react/ds-banner.ts +27 -0
- package/src/react/ds-bar-nav-action.ts +27 -0
- package/src/react/ds-bar-nav.ts +33 -0
- package/src/react/ds-breadcrumb.ts +27 -0
- package/src/react/ds-button-group.ts +27 -0
- package/src/react/ds-button.ts +35 -0
- package/src/react/ds-card.ts +26 -0
- package/src/react/ds-checkbox.ts +27 -0
- package/src/react/ds-divider.ts +26 -0
- package/src/react/ds-empty-state.ts +26 -0
- package/src/react/ds-fade.ts +26 -0
- package/src/react/ds-field.ts +26 -0
- package/src/react/ds-header.ts +26 -0
- package/src/react/ds-icon.ts +26 -0
- package/src/react/ds-input.ts +33 -0
- package/src/react/ds-label-wrap.ts +26 -0
- package/src/react/ds-loader.ts +26 -0
- package/src/react/ds-menu.ts +33 -0
- package/src/react/ds-modal.ts +27 -0
- package/src/react/ds-pagination.ts +27 -0
- package/src/react/ds-panel-nav.ts +37 -0
- package/src/react/ds-radio-group.ts +27 -0
- package/src/react/ds-scrollbar.ts +26 -0
- package/src/react/ds-select.ts +27 -0
- package/src/react/ds-sidebar.ts +33 -0
- package/src/react/ds-skeleton.ts +26 -0
- package/src/react/ds-slider.ts +27 -0
- package/src/react/ds-surface.ts +26 -0
- package/src/react/ds-tab-group-nav.ts +27 -0
- package/src/react/ds-tab-group.ts +27 -0
- package/src/react/ds-table.ts +35 -0
- package/src/react/ds-tag.ts +35 -0
- package/src/react/ds-text.ts +26 -0
- package/src/react/ds-toast-provider.ts +26 -0
- package/src/react/ds-toggle-button-group.ts +27 -0
- package/src/react/ds-toggle-button.ts +27 -0
- package/src/react/ds-toggle.ts +27 -0
- package/src/react/ds-tooltip.ts +26 -0
- package/src/wc/components/Accordion/Accordion.tsx +144 -0
- package/src/wc/components/Badge/Badge.tsx +34 -0
- package/src/wc/components/Badge/index.ts +1 -0
- package/src/wc/components/Banner/Banner.tsx +148 -0
- package/src/wc/components/BarNav/BarNav.tsx +605 -0
- package/src/wc/components/BarNav/bar-nav-dom-utils.ts +23 -0
- package/src/wc/components/BarNav/bar-nav-tabs-menu-utils.ts +59 -0
- package/src/wc/components/BarNav/bar-nav-utils.ts +76 -0
- package/src/wc/components/BarNav/index.ts +1 -0
- package/src/wc/components/BarNavAction/BarNavAction.tsx +67 -0
- package/src/wc/components/BarNavAction/index.ts +1 -0
- package/src/wc/components/Breadcrumb/Breadcrumb.tsx +61 -0
- package/src/wc/components/Button/Button.tsx +158 -0
- package/src/wc/components/Button/index.ts +1 -0
- package/src/wc/components/ButtonGroup/ButtonGroup.tsx +110 -0
- package/src/wc/components/Card/Card.tsx +26 -0
- package/src/wc/components/Checkbox/Checkbox.tsx +60 -0
- package/src/wc/components/Checkbox/index.ts +1 -0
- package/src/wc/components/Divider/Divider.tsx +23 -0
- package/src/wc/components/Divider/index.ts +2 -0
- package/src/wc/components/EmptyState/EmptyState.tsx +32 -0
- package/src/wc/components/Fade/Fade.tsx +32 -0
- package/src/wc/components/Fade/index.ts +1 -0
- package/src/wc/components/Field/Field.tsx +28 -0
- package/src/wc/components/Header/Header.tsx +33 -0
- package/src/wc/components/Icon/Icon.tsx +112 -0
- package/src/wc/components/Icon/flag-icon-catalog.ts +68 -0
- package/src/wc/components/Icon/index.ts +1 -0
- package/src/wc/components/Icon/system-icon-catalog.ts +798 -0
- package/src/wc/components/Input/Input.tsx +100 -0
- package/src/wc/components/Input/index.ts +1 -0
- package/src/wc/components/LabelWrap/LabelWrap.tsx +38 -0
- package/src/wc/components/Loader/Loader.tsx +47 -0
- package/src/wc/components/Loader/index.ts +1 -0
- package/src/wc/components/Menu/Menu.tsx +340 -0
- package/src/wc/components/Modal/Modal.tsx +197 -0
- package/src/wc/components/Pagination/Pagination.tsx +97 -0
- package/src/wc/components/PanelNav/PanelNav.tsx +666 -0
- package/src/wc/components/PanelNav/index.ts +7 -0
- package/src/wc/components/PanelNav/panel-nav-utils.ts +124 -0
- package/src/wc/components/RadioGroup/RadioGroup.tsx +128 -0
- package/src/wc/components/RadioGroup/index.ts +1 -0
- package/src/wc/components/Scrollbar/Scrollbar.tsx +189 -0
- package/src/wc/components/Select/Select.tsx +195 -0
- package/src/wc/components/Sidebar/Sidebar.tsx +245 -0
- package/src/wc/components/Skeleton/Skeleton.tsx +64 -0
- package/src/wc/components/Skeleton/index.ts +1 -0
- package/src/wc/components/Slider/Slider.tsx +68 -0
- package/src/wc/components/Slider/index.ts +1 -0
- package/src/wc/components/Surface/Surface.tsx +81 -0
- package/src/wc/components/TabGroup/TabGroup.tsx +188 -0
- package/src/wc/components/TabGroup/tab-item-utils.ts +24 -0
- package/src/wc/components/TabGroupNav/TabGroupNav.tsx +188 -0
- package/src/wc/components/Table/Table.tsx +268 -0
- package/src/wc/components/Tag/Tag.tsx +135 -0
- package/src/wc/components/Tag/index.ts +1 -0
- package/src/wc/components/Text/Text.tsx +100 -0
- package/src/wc/components/Text/index.ts +1 -0
- package/src/wc/components/Toast/Toast.tsx +174 -0
- package/src/wc/components/Toast/toast-service.ts +60 -0
- package/src/wc/components/Toggle/Toggle.tsx +43 -0
- package/src/wc/components/Toggle/index.ts +1 -0
- package/src/wc/components/ToggleButton/ToggleButton.tsx +120 -0
- package/src/wc/components/ToggleButtonGroup/ToggleButtonGroup.tsx +118 -0
- package/src/wc/components/Tooltip/Tooltip.tsx +196 -0
- package/src/wc/components.d.ts +3028 -0
- package/dist/components/p-DV8pmt1m.js +0 -2
- package/dist/components/p-DV8pmt1m.js.map +0 -1
- package/dist/components/p-STnE_bmQ.js +0 -2
- package/dist/components/p-STnE_bmQ.js.map +0 -1
- /package/dist/components/{p-D3CwGoIu.js.map → p-COsKOwZR.js.map} +0 -0
- /package/dist/components/{p-DouEVPmi.js.map → p-Dd0GrKaF.js.map} +0 -0
- /package/dist/components/{p-BvxKLqNx.js.map → p-H89PzqGU.js.map} +0 -0
- /package/dist/components/{p-BYe8Rfdg.js.map → p-Vwlmhl4E.js.map} +0 -0
- /package/dist/components/{p-C4p1fG67.js.map → p-woooYulR.js.map} +0 -0
|
@@ -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 DsToggleButtonCustomEvent } from "@ds-mo/ui";
|
|
15
|
+
import type { Components } from "@ds-mo/ui/dist/components";
|
|
16
|
+
import { DsToggleButton as DsToggleButtonElement, defineCustomElement as defineDsToggleButton } from "@ds-mo/ui/dist/components/ds-toggle-button.js";
|
|
17
|
+
|
|
18
|
+
export type DsToggleButtonEvents = { onDsChange: EventName<DsToggleButtonCustomEvent<boolean>> };
|
|
19
|
+
|
|
20
|
+
export const DsToggleButton: StencilReactComponent<DsToggleButtonElement, DsToggleButtonEvents, Components.DsToggleButton> = /*@__PURE__*/ createComponent<DsToggleButtonElement, DsToggleButtonEvents, Components.DsToggleButton>({
|
|
21
|
+
tagName: 'ds-toggle-button',
|
|
22
|
+
elementClass: DsToggleButtonElement,
|
|
23
|
+
// @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
|
|
24
|
+
react: React,
|
|
25
|
+
events: { onDsChange: 'dsChange' } as DsToggleButtonEvents,
|
|
26
|
+
defineCustomElement: defineDsToggleButton
|
|
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 DsToggleCustomEvent } from "@ds-mo/ui";
|
|
15
|
+
import type { Components } from "@ds-mo/ui/dist/components";
|
|
16
|
+
import { DsToggle as DsToggleElement, defineCustomElement as defineDsToggle } from "@ds-mo/ui/dist/components/ds-toggle.js";
|
|
17
|
+
|
|
18
|
+
export type DsToggleEvents = { onDsChange: EventName<DsToggleCustomEvent<boolean>> };
|
|
19
|
+
|
|
20
|
+
export const DsToggle: StencilReactComponent<DsToggleElement, DsToggleEvents, Components.DsToggle> = /*@__PURE__*/ createComponent<DsToggleElement, DsToggleEvents, Components.DsToggle>({
|
|
21
|
+
tagName: 'ds-toggle',
|
|
22
|
+
elementClass: DsToggleElement,
|
|
23
|
+
// @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
|
|
24
|
+
react: React,
|
|
25
|
+
events: { onDsChange: 'dsChange' } as DsToggleEvents,
|
|
26
|
+
defineCustomElement: defineDsToggle
|
|
27
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
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 { 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 { Components } from "@ds-mo/ui/dist/components";
|
|
15
|
+
import { DsTooltip as DsTooltipElement, defineCustomElement as defineDsTooltip } from "@ds-mo/ui/dist/components/ds-tooltip.js";
|
|
16
|
+
|
|
17
|
+
export type DsTooltipEvents = NonNullable<unknown>;
|
|
18
|
+
|
|
19
|
+
export const DsTooltip: StencilReactComponent<DsTooltipElement, DsTooltipEvents, Components.DsTooltip> = /*@__PURE__*/ createComponent<DsTooltipElement, DsTooltipEvents, Components.DsTooltip>({
|
|
20
|
+
tagName: 'ds-tooltip',
|
|
21
|
+
elementClass: DsTooltipElement,
|
|
22
|
+
// @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
|
|
23
|
+
react: React,
|
|
24
|
+
events: {} as DsTooltipEvents,
|
|
25
|
+
defineCustomElement: defineDsTooltip
|
|
26
|
+
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Component, Prop, State, Event, EventEmitter, Element, Watch, h, Host } from '@stencil/core';
|
|
2
|
+
|
|
3
|
+
export interface AccordionItemData {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
content?: string;
|
|
7
|
+
inactive?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let idCounter = 0;
|
|
11
|
+
|
|
12
|
+
@Component({
|
|
13
|
+
tag: 'ds-accordion',
|
|
14
|
+
styleUrl: 'Accordion.css',
|
|
15
|
+
scoped: true,
|
|
16
|
+
})
|
|
17
|
+
export class Accordion {
|
|
18
|
+
@Element() el!: HTMLElement;
|
|
19
|
+
|
|
20
|
+
@Prop() items: AccordionItemData[] = [];
|
|
21
|
+
@Prop() multiple: boolean = false;
|
|
22
|
+
/** Comma-separated list of expanded item IDs for controlled mode. */
|
|
23
|
+
@Prop({ mutable: true }) expandedIds: string = '';
|
|
24
|
+
|
|
25
|
+
@State() private internalIds: string[] = [];
|
|
26
|
+
@State() private heights: Record<string, number> = {};
|
|
27
|
+
|
|
28
|
+
@Event() dsExpandedChange!: EventEmitter<string[]>;
|
|
29
|
+
|
|
30
|
+
private instanceId = ++idCounter;
|
|
31
|
+
private resizeObservers: Map<string, ResizeObserver> = new Map();
|
|
32
|
+
|
|
33
|
+
private get activeIds(): string[] {
|
|
34
|
+
if (this.expandedIds) return this.expandedIds.split(',').map(s => s.trim()).filter(Boolean);
|
|
35
|
+
return this.internalIds;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
componentDidLoad() {
|
|
39
|
+
this.bindResizeObservers();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
disconnectedCallback() {
|
|
43
|
+
this.resizeObservers.forEach(ro => ro.disconnect());
|
|
44
|
+
this.resizeObservers.clear();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@Watch('items')
|
|
48
|
+
onItemsChange() {
|
|
49
|
+
requestAnimationFrame(() => {
|
|
50
|
+
this.bindResizeObservers();
|
|
51
|
+
this.measureAll();
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private bindResizeObservers() {
|
|
56
|
+
this.resizeObservers.forEach(ro => ro.disconnect());
|
|
57
|
+
this.resizeObservers.clear();
|
|
58
|
+
|
|
59
|
+
this.items.forEach(item => {
|
|
60
|
+
const inner = this.el.querySelector(`[data-inner="${item.id}"]`) as HTMLElement | null;
|
|
61
|
+
if (!inner) return;
|
|
62
|
+
const ro = new ResizeObserver(() => {
|
|
63
|
+
this.heights = { ...this.heights, [item.id]: inner.scrollHeight };
|
|
64
|
+
});
|
|
65
|
+
ro.observe(inner);
|
|
66
|
+
this.resizeObservers.set(item.id, ro);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private measureAll() {
|
|
71
|
+
const next: Record<string, number> = { ...this.heights };
|
|
72
|
+
this.items.forEach(item => {
|
|
73
|
+
const inner = this.el.querySelector(`[data-inner="${item.id}"]`) as HTMLElement | null;
|
|
74
|
+
if (inner) next[item.id] = inner.scrollHeight;
|
|
75
|
+
});
|
|
76
|
+
this.heights = next;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private toggle(id: string) {
|
|
80
|
+
const current = this.activeIds;
|
|
81
|
+
let next: string[];
|
|
82
|
+
if (current.includes(id)) {
|
|
83
|
+
next = current.filter(x => x !== id);
|
|
84
|
+
} else {
|
|
85
|
+
next = this.multiple ? [...current, id] : [id];
|
|
86
|
+
}
|
|
87
|
+
this.internalIds = next;
|
|
88
|
+
this.dsExpandedChange.emit(next);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
render() {
|
|
92
|
+
const activeIds = this.activeIds;
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<Host class="accordion">
|
|
96
|
+
{this.items.map(item => {
|
|
97
|
+
const isExpanded = activeIds.includes(item.id);
|
|
98
|
+
const triggerId = `ds-accordion-${this.instanceId}-trigger-${item.id}`;
|
|
99
|
+
const panelId = `ds-accordion-${this.instanceId}-panel-${item.id}`;
|
|
100
|
+
const bodyHeight = this.heights[item.id] ?? 0;
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<div
|
|
104
|
+
key={item.id}
|
|
105
|
+
class={{ item: true, 'item--inactive': !!item.inactive }}
|
|
106
|
+
>
|
|
107
|
+
<button
|
|
108
|
+
type="button"
|
|
109
|
+
id={triggerId}
|
|
110
|
+
class="trigger"
|
|
111
|
+
onClick={() => !item.inactive && this.toggle(item.id)}
|
|
112
|
+
aria-expanded={isExpanded}
|
|
113
|
+
aria-controls={panelId}
|
|
114
|
+
aria-disabled={item.inactive || undefined}
|
|
115
|
+
tabIndex={item.inactive ? -1 : 0}
|
|
116
|
+
>
|
|
117
|
+
<span class="text-body-medium-emphasis">{item.label}</span>
|
|
118
|
+
<span
|
|
119
|
+
class={{ chevron: true, 'chevron--open': isExpanded }}
|
|
120
|
+
aria-hidden="true"
|
|
121
|
+
>›</span>
|
|
122
|
+
</button>
|
|
123
|
+
<div
|
|
124
|
+
id={panelId}
|
|
125
|
+
role="region"
|
|
126
|
+
aria-labelledby={triggerId}
|
|
127
|
+
class="body"
|
|
128
|
+
style={{ height: isExpanded ? `${bodyHeight}px` : '0' }}
|
|
129
|
+
aria-hidden={!isExpanded}
|
|
130
|
+
>
|
|
131
|
+
<div class="body-inner" data-inner={item.id}>
|
|
132
|
+
{item.content
|
|
133
|
+
? <span class="text-body-medium">{item.content}</span>
|
|
134
|
+
: <slot name={item.id} />
|
|
135
|
+
}
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
})}
|
|
141
|
+
</Host>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Component, Prop, h, Host } from '@stencil/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
tag: 'ds-badge',
|
|
5
|
+
styleUrl: 'Badge.css',
|
|
6
|
+
scoped: true,
|
|
7
|
+
})
|
|
8
|
+
export class Badge {
|
|
9
|
+
@Prop() count: number = 0;
|
|
10
|
+
@Prop() isSelected: boolean = false;
|
|
11
|
+
/** Accessible label. Defaults to the count as a string. */
|
|
12
|
+
@Prop() label: string | undefined;
|
|
13
|
+
|
|
14
|
+
render() {
|
|
15
|
+
if (this.count === 0) return <Host style={{ display: 'none' }} />;
|
|
16
|
+
|
|
17
|
+
const display = this.count > 9 ? '+' : String(this.count);
|
|
18
|
+
const ariaLabel = this.label ?? String(this.count);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Host class="badge" aria-label={ariaLabel}>
|
|
22
|
+
<span
|
|
23
|
+
class={{
|
|
24
|
+
'text-caption-emphasis': true,
|
|
25
|
+
'badge__text': true,
|
|
26
|
+
'badge__text--selected': this.isSelected,
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
{display}
|
|
30
|
+
</span>
|
|
31
|
+
</Host>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type {} from './Badge';
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Component, Prop, State, Event, EventEmitter, Watch, h, Host } from '@stencil/core';
|
|
2
|
+
|
|
3
|
+
export type BannerIntent =
|
|
4
|
+
| 'brand' | 'positive' | 'negative' | 'warning' | 'caution'
|
|
5
|
+
| 'ai' | 'neutral' | 'walkthrough' | 'guide';
|
|
6
|
+
|
|
7
|
+
export type BannerContrast = 'faint' | 'medium' | 'bold' | 'strong';
|
|
8
|
+
|
|
9
|
+
const FADE_OUT_MS = 200;
|
|
10
|
+
const AUTO_DISMISS_MS = 4000;
|
|
11
|
+
|
|
12
|
+
@Component({
|
|
13
|
+
tag: 'ds-banner',
|
|
14
|
+
styleUrl: 'Banner.css',
|
|
15
|
+
scoped: true,
|
|
16
|
+
})
|
|
17
|
+
export class Banner {
|
|
18
|
+
@Prop() intent: BannerIntent = 'neutral';
|
|
19
|
+
@Prop() contrast: BannerContrast = 'medium';
|
|
20
|
+
@Prop() message: string = '';
|
|
21
|
+
/** Renders the diagonal-stripe accent bar above the body. */
|
|
22
|
+
@Prop() header: boolean = false;
|
|
23
|
+
/** Renders at a fixed position (centered top) and auto-dismisses after 4 s. */
|
|
24
|
+
@Prop() floating: boolean = false;
|
|
25
|
+
@Prop() showDismiss: boolean = false;
|
|
26
|
+
@Prop() dismissLabel: string = 'Dismiss';
|
|
27
|
+
|
|
28
|
+
@State() private closing: boolean = false;
|
|
29
|
+
|
|
30
|
+
@Event() dsDismiss!: EventEmitter<void>;
|
|
31
|
+
|
|
32
|
+
private dismissTimer: ReturnType<typeof setTimeout> | null = null;
|
|
33
|
+
private closeTimer: ReturnType<typeof setTimeout> | null = null;
|
|
34
|
+
|
|
35
|
+
componentDidLoad() {
|
|
36
|
+
if (this.floating && this.message) this.scheduleDismiss();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Watch('message')
|
|
40
|
+
onMessageChange(newVal: string) {
|
|
41
|
+
if (this.floating && newVal) {
|
|
42
|
+
this.closing = false;
|
|
43
|
+
this.scheduleDismiss();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
disconnectedCallback() {
|
|
48
|
+
this.clearTimers();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private clearTimers() {
|
|
52
|
+
if (this.dismissTimer) { clearTimeout(this.dismissTimer); this.dismissTimer = null; }
|
|
53
|
+
if (this.closeTimer) { clearTimeout(this.closeTimer); this.closeTimer = null; }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private scheduleDismiss() {
|
|
57
|
+
this.clearTimers();
|
|
58
|
+
this.dismissTimer = setTimeout(() => {
|
|
59
|
+
this.dismissTimer = null;
|
|
60
|
+
this.beginClose();
|
|
61
|
+
}, AUTO_DISMISS_MS);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private beginClose() {
|
|
65
|
+
this.clearTimers();
|
|
66
|
+
if (this.floating) {
|
|
67
|
+
this.closing = true;
|
|
68
|
+
this.closeTimer = setTimeout(() => {
|
|
69
|
+
this.closing = false;
|
|
70
|
+
this.closeTimer = null;
|
|
71
|
+
this.dsDismiss.emit();
|
|
72
|
+
}, FADE_OUT_MS);
|
|
73
|
+
} else {
|
|
74
|
+
this.dsDismiss.emit();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private getContentColor(): string {
|
|
79
|
+
if (this.contrast === 'bold') return 'var(--color-foreground-on-bold-background-primary)';
|
|
80
|
+
const c = this.contrast === 'faint' ? 'bold' : this.contrast === 'medium' ? 'strong' : 'medium';
|
|
81
|
+
return `var(--color-foreground-${c}-${this.intent})`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private getBg(): string {
|
|
85
|
+
return `var(--color-background-${this.contrast}-${this.intent})`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private getElevation(): string {
|
|
89
|
+
return this.floating
|
|
90
|
+
? 'var(--effect-elevation-elevated-floating, var(--effect-elevation-floating))'
|
|
91
|
+
: 'var(--effect-elevation-elevated)';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
render() {
|
|
95
|
+
const contentColor = this.getContentColor();
|
|
96
|
+
const isAssertive = this.intent === 'negative';
|
|
97
|
+
|
|
98
|
+
const bannerEl = (
|
|
99
|
+
<div
|
|
100
|
+
class={{ 'banner-wrapper': true }}
|
|
101
|
+
style={{ '--banner-content': contentColor } as { [key: string]: string }}
|
|
102
|
+
role={isAssertive ? 'alert' : 'status'}
|
|
103
|
+
aria-live={isAssertive ? undefined : 'polite'}
|
|
104
|
+
>
|
|
105
|
+
<div
|
|
106
|
+
class="banner-surface"
|
|
107
|
+
style={{
|
|
108
|
+
backgroundColor: this.getBg(),
|
|
109
|
+
boxShadow: this.getElevation(),
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
112
|
+
{this.header && (
|
|
113
|
+
<div class="banner-header-surface">
|
|
114
|
+
<div class="banner-header" />
|
|
115
|
+
</div>
|
|
116
|
+
)}
|
|
117
|
+
<div class="banner-body">
|
|
118
|
+
<span class="text-body-medium banner-message">{this.message}</span>
|
|
119
|
+
{this.showDismiss && (
|
|
120
|
+
<button
|
|
121
|
+
type="button"
|
|
122
|
+
class="banner-dismiss"
|
|
123
|
+
onClick={() => this.beginClose()}
|
|
124
|
+
aria-label={this.dismissLabel}
|
|
125
|
+
>
|
|
126
|
+
×
|
|
127
|
+
</button>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
if (this.floating) {
|
|
135
|
+
return (
|
|
136
|
+
<Host style={{ display: 'contents' }}>
|
|
137
|
+
<div class="floating-position" style={{ zIndex: '9998' }}>
|
|
138
|
+
<div class={{ 'floating-toast': true, 'floating-toast--closing': this.closing }}>
|
|
139
|
+
{bannerEl}
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</Host>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return <Host style={{ display: 'contents' }}>{bannerEl}</Host>;
|
|
147
|
+
}
|
|
148
|
+
}
|