@ds-mo/ui 2.7.0 → 2.9.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/README.md +8 -9
- package/dist/.build-stamp +1 -1
- package/dist/components/ds-app-shell.js +1 -1
- package/dist/components/ds-banner.js +1 -1
- package/dist/components/ds-bar-nav.js +1 -1
- package/dist/components/{ds-toggle-button.d.ts → ds-button-filled.d.ts} +4 -4
- package/dist/components/ds-button-filled.js +2 -0
- package/dist/components/ds-button-unfilled-icon.js +1 -1
- package/dist/components/{ds-button-group.d.ts → ds-card-setting.d.ts} +4 -4
- package/dist/components/ds-card-setting.js +2 -0
- package/dist/components/ds-card-setting.js.map +1 -0
- package/dist/components/ds-card.js +1 -1
- package/dist/components/ds-checkbox.js +1 -1
- package/dist/components/ds-chip.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-field.js.map +1 -1
- package/dist/components/ds-header.js +1 -1
- package/dist/components/ds-icon.js +1 -1
- package/dist/components/ds-input.js +1 -1
- package/dist/components/ds-loader.js +1 -1
- package/dist/components/ds-loader.js.map +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-panel-nav.js.map +1 -1
- package/dist/components/ds-panel-tools.js +1 -1
- package/dist/components/ds-panel-tools.js.map +1 -1
- package/dist/components/ds-radio-group.js +1 -1
- package/dist/components/ds-scrollbar.js +1 -1
- package/dist/components/ds-select.js +1 -1
- package/dist/components/ds-shell-gradient-picker.js +1 -1
- package/dist/components/ds-shell-gradient-swatch.js +1 -1
- package/dist/components/ds-slider.js +1 -1
- package/dist/components/ds-surface.js +1 -1
- package/dist/components/ds-tab-group-nav.js +1 -1
- package/dist/components/ds-tab-group.js +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.js +1 -1
- package/dist/components/ds-tooltip.js +1 -1
- package/dist/components/ds-tooltip.js.map +1 -1
- package/dist/components/{p-D4zKc1RW.js → p-BA6a6P0b.js} +2 -2
- package/dist/components/p-CDNVPM2x.js +2 -0
- package/dist/components/p-CDNVPM2x.js.map +1 -0
- package/dist/components/{p-DqBCQRRd.js → p-CF4avTQw.js} +2 -2
- package/dist/components/{p-C9za7IDu.js → p-CJubWt1F.js} +2 -2
- package/dist/components/p-CKCBqwIw.js +2 -0
- package/dist/components/p-CKCBqwIw.js.map +1 -0
- package/dist/components/p-C_hgdYcC.js +2 -0
- package/dist/components/p-C_hgdYcC.js.map +1 -0
- package/dist/components/p-Cv5NDZug.js +2 -0
- package/dist/components/p-Cv5NDZug.js.map +1 -0
- package/dist/components/p-DnGr8qtq.js +2 -0
- package/dist/components/p-DnGr8qtq.js.map +1 -0
- package/dist/components/p-jjfqrXnP.js +2 -0
- package/dist/components/p-jjfqrXnP.js.map +1 -0
- package/dist/types/components/ButtonFilled/ButtonFilled.d.ts +26 -0
- package/dist/types/components/ButtonFilled/index.d.ts +2 -0
- package/dist/types/components/ButtonUnfilledIcon/ButtonUnfilledIcon.d.ts +9 -2
- package/dist/types/components/ButtonUnfilledIcon/index.d.ts +1 -1
- package/dist/types/components/CardSetting/CardSetting.d.ts +16 -0
- package/dist/types/components/CardSetting/index.d.ts +2 -0
- package/dist/types/components/Menu/menu-placement.d.ts +5 -3
- package/dist/types/components/ShellGradientSwatch/ShellGradientSwatch.d.ts +1 -1
- package/dist/types/components.d.ts +129 -414
- package/dist/types/utils/token-defaults.d.ts +1 -0
- package/package.json +1 -1
- package/src/angular/index.ts +2 -4
- package/src/angular/proxies.ts +40 -105
- package/src/react/components.ts +2 -4
- package/src/react/ds-button-filled.ts +27 -0
- package/src/react/ds-card-setting.ts +27 -0
- package/src/wc/components/ButtonFilled/ButtonFilled.tsx +86 -0
- package/src/wc/components/ButtonFilled/index.ts +1 -0
- package/src/wc/components/ButtonUnfilledIcon/ButtonUnfilledIcon.tsx +19 -11
- package/src/wc/components/ButtonUnfilledIcon/index.ts +1 -1
- package/src/wc/components/CardSetting/CardSetting.tsx +96 -0
- package/src/wc/components/CardSetting/index.ts +1 -0
- package/src/wc/components/Menu/Menu.tsx +1 -2
- package/src/wc/components/Menu/menu-placement.ts +5 -3
- package/src/wc/components/ShellGradientSwatch/ShellGradientSwatch.tsx +8 -2
- package/src/wc/components.d.ts +129 -414
- package/src/wc/utils/token-defaults.ts +2 -0
- package/dist/components/ds-button-group.js +0 -2
- package/dist/components/ds-button-group.js.map +0 -1
- package/dist/components/ds-button.d.ts +0 -11
- package/dist/components/ds-button.js +0 -2
- package/dist/components/ds-toggle-button-group.d.ts +0 -11
- package/dist/components/ds-toggle-button-group.js +0 -2
- package/dist/components/ds-toggle-button-group.js.map +0 -1
- package/dist/components/ds-toggle-button.js +0 -2
- package/dist/components/ds-toggle-button.js.map +0 -1
- package/dist/components/p-B4qYuM6y.js +0 -2
- package/dist/components/p-B4qYuM6y.js.map +0 -1
- package/dist/components/p-BHIptqCl.js +0 -2
- package/dist/components/p-BHIptqCl.js.map +0 -1
- package/dist/components/p-BTndnbR_.js +0 -2
- package/dist/components/p-BTndnbR_.js.map +0 -1
- package/dist/components/p-C4hnBQXI.js +0 -2
- package/dist/components/p-C4hnBQXI.js.map +0 -1
- package/dist/components/p-R7uKgEQg.js +0 -2
- package/dist/components/p-R7uKgEQg.js.map +0 -1
- package/dist/components/p-Sv1zgw__.js +0 -2
- package/dist/components/p-Sv1zgw__.js.map +0 -1
- package/dist/components/p-UngdVrfj.js +0 -2
- package/dist/components/p-UngdVrfj.js.map +0 -1
- package/dist/components/p-ska5qgNk.js +0 -2
- package/dist/components/p-ska5qgNk.js.map +0 -1
- package/dist/types/components/Button/Button.d.ts +0 -38
- package/dist/types/components/Button/index.d.ts +0 -2
- package/dist/types/components/ButtonGroup/ButtonGroup.d.ts +0 -29
- package/dist/types/components/ToggleButton/ToggleButton.d.ts +0 -37
- package/dist/types/components/ToggleButtonGroup/ToggleButtonGroup.d.ts +0 -33
- package/src/react/ds-button-group.ts +0 -27
- package/src/react/ds-button.ts +0 -35
- package/src/react/ds-toggle-button-group.ts +0 -27
- package/src/react/ds-toggle-button.ts +0 -27
- package/src/wc/components/Button/Button.tsx +0 -158
- package/src/wc/components/Button/index.ts +0 -1
- package/src/wc/components/ButtonGroup/ButtonGroup.tsx +0 -110
- package/src/wc/components/ToggleButton/ToggleButton.tsx +0 -124
- package/src/wc/components/ToggleButtonGroup/ToggleButtonGroup.tsx +0 -118
- /package/dist/components/{ds-button.js.map → ds-button-filled.js.map} +0 -0
- /package/dist/components/{p-D4zKc1RW.js.map → p-BA6a6P0b.js.map} +0 -0
- /package/dist/components/{p-DqBCQRRd.js.map → p-CF4avTQw.js.map} +0 -0
- /package/dist/components/{p-C9za7IDu.js.map → p-CJubWt1F.js.map} +0 -0
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { Component, Prop, Event, EventEmitter, Element, State, h, Host } from '@stencil/core';
|
|
2
|
-
|
|
3
|
-
export type ButtonVariant = 'primary' | 'secondary';
|
|
4
|
-
export type ButtonElevation = 'none' | 'flat' | 'elevated' | 'floating';
|
|
5
|
-
export type ButtonIntent = 'none' | 'neutral' | 'brand' | 'ai' | 'negative' | 'warning' | 'caution' | 'positive';
|
|
6
|
-
export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
7
|
-
export type ButtonContrast = 'strong' | 'bold' | 'medium' | 'faint';
|
|
8
|
-
export type ButtonBackground = 'faint' | 'medium' | 'bold' | 'strong' | 'always-dark';
|
|
9
|
-
|
|
10
|
-
const ICON_SIZE: Record<ButtonSize, number> = { xs: 12, sm: 16, md: 20, lg: 24 };
|
|
11
|
-
const TEXT_CLASS: Record<ButtonSize, string> = {
|
|
12
|
-
xs: 'text-caption-emphasis',
|
|
13
|
-
sm: 'text-body-small-emphasis',
|
|
14
|
-
md: 'text-body-medium-emphasis',
|
|
15
|
-
lg: 'text-body-large-emphasis',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
@Component({
|
|
19
|
-
tag: 'ds-button',
|
|
20
|
-
styleUrl: 'Button.css',
|
|
21
|
-
scoped: true,
|
|
22
|
-
})
|
|
23
|
-
export class Button {
|
|
24
|
-
@Element() el!: HTMLElement;
|
|
25
|
-
|
|
26
|
-
@Prop() variant: ButtonVariant = 'primary';
|
|
27
|
-
@Prop() intent: ButtonIntent = 'brand';
|
|
28
|
-
@Prop() size: ButtonSize = 'md';
|
|
29
|
-
@Prop() label: string | undefined;
|
|
30
|
-
@Prop() rounded: boolean = false;
|
|
31
|
-
@Prop() fullWidth: boolean = false;
|
|
32
|
-
@Prop() width: string | undefined;
|
|
33
|
-
@Prop() contrast: ButtonContrast = 'bold';
|
|
34
|
-
@Prop() background: ButtonBackground | undefined;
|
|
35
|
-
@Prop() dropdown: boolean = false;
|
|
36
|
-
@Prop() badgeCount: number | undefined;
|
|
37
|
-
@Prop() elevation: ButtonElevation | undefined;
|
|
38
|
-
@Prop() loading: boolean = false;
|
|
39
|
-
@Prop() inactive: boolean = false;
|
|
40
|
-
@Prop() href: string | undefined;
|
|
41
|
-
@Prop() target: string | undefined;
|
|
42
|
-
@Prop() type: 'button' | 'submit' | 'reset' = 'button';
|
|
43
|
-
@Prop({ attribute: 'aria-label' }) ariaLabel: string | undefined;
|
|
44
|
-
@Prop({ attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined;
|
|
45
|
-
|
|
46
|
-
@State() private hasIcon: boolean = false;
|
|
47
|
-
|
|
48
|
-
@Event() dsClick!: EventEmitter<MouseEvent>;
|
|
49
|
-
@Event() dsMouseEnter!: EventEmitter<MouseEvent>;
|
|
50
|
-
@Event() dsMouseLeave!: EventEmitter<MouseEvent>;
|
|
51
|
-
|
|
52
|
-
componentWillLoad() {
|
|
53
|
-
this.hasIcon = !!this.el.querySelector('[slot="icon"]');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
private handleClick = (e: MouseEvent) => {
|
|
57
|
-
if (this.inactive || this.loading) return;
|
|
58
|
-
this.dsClick.emit(e);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
private get effectiveElevation(): ButtonElevation {
|
|
62
|
-
return this.elevation ?? (this.variant === 'primary' ? 'none' : 'flat');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
render() {
|
|
66
|
-
const Tag = this.href ? 'a' : 'button';
|
|
67
|
-
const size = this.size;
|
|
68
|
-
const iconSize = ICON_SIZE[size];
|
|
69
|
-
const textClass = TEXT_CLASS[size];
|
|
70
|
-
const elev = this.effectiveElevation;
|
|
71
|
-
const hasLabel = !!this.label;
|
|
72
|
-
const showLeading = this.hasIcon || this.loading;
|
|
73
|
-
const isIconOnly = showLeading && !hasLabel;
|
|
74
|
-
const isLabelOnly = hasLabel && !showLeading;
|
|
75
|
-
const isIconAndLabel = showLeading && hasLabel;
|
|
76
|
-
const bg = this.background;
|
|
77
|
-
|
|
78
|
-
const btnCls: Record<string, boolean> = {
|
|
79
|
-
btn: true,
|
|
80
|
-
[this.variant]: true,
|
|
81
|
-
[`intent${cap(this.intent)}`]: true,
|
|
82
|
-
[`size${size.toUpperCase()}`]: size !== 'md',
|
|
83
|
-
rounded: this.rounded,
|
|
84
|
-
inactive: this.inactive || this.loading,
|
|
85
|
-
iconOnly: isIconOnly,
|
|
86
|
-
labelOnly: isLabelOnly,
|
|
87
|
-
iconAndLabel: isIconAndLabel,
|
|
88
|
-
dropdown: this.dropdown,
|
|
89
|
-
[`contrast${cap(this.contrast)}`]: this.variant === 'primary' && this.intent !== 'none' && this.contrast !== 'bold',
|
|
90
|
-
[`elevation${cap(elev)}`]: true,
|
|
91
|
-
onMedium: bg === 'medium',
|
|
92
|
-
onBold: bg === 'bold',
|
|
93
|
-
onStrong: bg === 'strong',
|
|
94
|
-
onAlwaysDark: bg === 'always-dark',
|
|
95
|
-
fullWidth: this.fullWidth,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const extraProps: Record<string, unknown> = {};
|
|
99
|
-
if (Tag === 'button') {
|
|
100
|
-
extraProps.type = this.type;
|
|
101
|
-
extraProps.disabled = this.inactive || this.loading;
|
|
102
|
-
}
|
|
103
|
-
if (this.href) extraProps.href = this.href;
|
|
104
|
-
if (this.target) extraProps.target = this.target;
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<Host class={{ 'btn-host': true, 'btn-host--full': this.fullWidth }}>
|
|
108
|
-
<Tag
|
|
109
|
-
class={btnCls}
|
|
110
|
-
style={this.width ? { width: this.width } : undefined}
|
|
111
|
-
aria-label={this.ariaLabel}
|
|
112
|
-
aria-labelledby={this.ariaLabelledby}
|
|
113
|
-
aria-disabled={this.inactive || this.loading || undefined}
|
|
114
|
-
aria-busy={this.loading || undefined}
|
|
115
|
-
onClick={this.handleClick}
|
|
116
|
-
onMouseEnter={(e: MouseEvent) => !this.inactive && !this.loading && this.dsMouseEnter.emit(e)}
|
|
117
|
-
onMouseLeave={(e: MouseEvent) => !this.inactive && !this.loading && this.dsMouseLeave.emit(e)}
|
|
118
|
-
{...extraProps}
|
|
119
|
-
>
|
|
120
|
-
{/* Leading icon / loader */}
|
|
121
|
-
<span class="btn__icon" style={{ fontSize: `${iconSize}px`, display: showLeading ? undefined : 'none' }}>
|
|
122
|
-
{this.loading
|
|
123
|
-
? <ds-loader size={iconSize} />
|
|
124
|
-
: <slot name="icon" />
|
|
125
|
-
}
|
|
126
|
-
</span>
|
|
127
|
-
{/* Label */}
|
|
128
|
-
{hasLabel && (
|
|
129
|
-
<span class={`btn__label ${textClass}`}>{this.label}</span>
|
|
130
|
-
)}
|
|
131
|
-
{/* Trailing chevron */}
|
|
132
|
-
{this.dropdown && (
|
|
133
|
-
<svg
|
|
134
|
-
class="btn__chevron"
|
|
135
|
-
width={iconSize}
|
|
136
|
-
height={iconSize}
|
|
137
|
-
viewBox="0 0 20 20"
|
|
138
|
-
fill="none"
|
|
139
|
-
aria-hidden="true"
|
|
140
|
-
>
|
|
141
|
-
<path d="M5 7.5L10 12.5L15 7.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
142
|
-
</svg>
|
|
143
|
-
)}
|
|
144
|
-
{/* Badge */}
|
|
145
|
-
{this.badgeCount != null && this.badgeCount > 0 && (
|
|
146
|
-
<span class="btn__badge">
|
|
147
|
-
{this.badgeCount > 9 ? '+' : this.badgeCount}
|
|
148
|
-
</span>
|
|
149
|
-
)}
|
|
150
|
-
</Tag>
|
|
151
|
-
</Host>
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function cap(s: string) {
|
|
157
|
-
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
158
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type { ButtonVariant, ButtonElevation, ButtonIntent, ButtonSize, ButtonContrast, ButtonBackground } from './Button';
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { Component, Prop, Event, EventEmitter, h, Host } from '@stencil/core';
|
|
2
|
-
|
|
3
|
-
export type ButtonGroupElevation = 'none' | 'flat' | 'elevated' | 'floating';
|
|
4
|
-
export type ButtonGroupSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
5
|
-
|
|
6
|
-
export interface ButtonGroupItem {
|
|
7
|
-
label?: string;
|
|
8
|
-
/** Icon name for <ds-icon>. Set via JS property. */
|
|
9
|
-
icon?: string;
|
|
10
|
-
variant?: 'primary' | 'secondary';
|
|
11
|
-
intent?: 'none' | 'neutral' | 'brand' | 'negative' | 'warning' | 'positive';
|
|
12
|
-
inactive?: boolean;
|
|
13
|
-
href?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
@Component({
|
|
17
|
-
tag: 'ds-button-group',
|
|
18
|
-
styleUrl: 'ButtonGroup.css',
|
|
19
|
-
scoped: true,
|
|
20
|
-
})
|
|
21
|
-
export class ButtonGroup {
|
|
22
|
-
/**
|
|
23
|
-
* Array of button descriptors. Set via JS property.
|
|
24
|
-
* @example el.items = [{ label: 'Filter', icon: 'Filter' }, { label: 'Sort' }];
|
|
25
|
-
*/
|
|
26
|
-
@Prop() items: ButtonGroupItem[] = [];
|
|
27
|
-
|
|
28
|
-
/** Chrome level for the group container. */
|
|
29
|
-
@Prop() elevation: ButtonGroupElevation = 'flat';
|
|
30
|
-
|
|
31
|
-
/** Size passed to each ds-button. */
|
|
32
|
-
@Prop() size: ButtonGroupSize = 'md';
|
|
33
|
-
|
|
34
|
-
/** Pill shape for group + buttons. */
|
|
35
|
-
@Prop() rounded: boolean = false;
|
|
36
|
-
|
|
37
|
-
/** Emits the index of the clicked item. */
|
|
38
|
-
@Event() dsClick!: EventEmitter<number>;
|
|
39
|
-
|
|
40
|
-
render() {
|
|
41
|
-
const items = this.items;
|
|
42
|
-
const count = items.length;
|
|
43
|
-
const elev = this.elevation;
|
|
44
|
-
const elevKey = elev.charAt(0).toUpperCase() + elev.slice(1);
|
|
45
|
-
const isGhost = elev === 'none';
|
|
46
|
-
|
|
47
|
-
const groupCls: Record<string, boolean> = {
|
|
48
|
-
group: true,
|
|
49
|
-
[`group${elevKey}`]: true,
|
|
50
|
-
groupRounded: this.rounded,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<Host>
|
|
55
|
-
<div class={groupCls} role="group">
|
|
56
|
-
{items.map((item, i) => {
|
|
57
|
-
const isFirst = i === 0;
|
|
58
|
-
const isLast = i === count - 1;
|
|
59
|
-
const isMid = !isFirst && !isLast;
|
|
60
|
-
const variant = item.variant ?? 'secondary';
|
|
61
|
-
const isIconOnly = !!item.icon && !item.label;
|
|
62
|
-
const needsRoundedCorrection = this.rounded && !isIconOnly && this.size !== 'xs';
|
|
63
|
-
const sizeKey = this.size.toUpperCase() as 'MD' | 'SM' | 'LG' | 'XS';
|
|
64
|
-
|
|
65
|
-
const itemCls: Record<string, boolean> = {
|
|
66
|
-
item: true,
|
|
67
|
-
first: isFirst,
|
|
68
|
-
last: isLast,
|
|
69
|
-
middle: isMid,
|
|
70
|
-
itemShort: isGhost && variant === 'secondary',
|
|
71
|
-
[`roundedFirst${sizeKey}`]: !!(needsRoundedCorrection && isFirst),
|
|
72
|
-
[`roundedLast${sizeKey}`]: !!(needsRoundedCorrection && isLast),
|
|
73
|
-
[`roundedMid${sizeKey}`]: !!(needsRoundedCorrection && isMid),
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const dividerCls: Record<string, boolean> = {
|
|
77
|
-
divider: true,
|
|
78
|
-
dividerGhost: isGhost,
|
|
79
|
-
dividerGhostXS: isGhost && this.size === 'xs',
|
|
80
|
-
dividerGhostSM: isGhost && this.size === 'sm',
|
|
81
|
-
dividerGhostLG: isGhost && this.size === 'lg',
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
return [
|
|
85
|
-
i > 0 && (
|
|
86
|
-
<div class={dividerCls} aria-hidden="true" />
|
|
87
|
-
),
|
|
88
|
-
<ds-button
|
|
89
|
-
class={itemCls}
|
|
90
|
-
variant={variant}
|
|
91
|
-
intent={item.intent ?? 'none'}
|
|
92
|
-
elevation={elev}
|
|
93
|
-
size={this.size}
|
|
94
|
-
label={item.label}
|
|
95
|
-
rounded={this.rounded}
|
|
96
|
-
inactive={item.inactive}
|
|
97
|
-
href={item.href}
|
|
98
|
-
onDsClick={() => this.dsClick.emit(i)}
|
|
99
|
-
>
|
|
100
|
-
{item.icon && (
|
|
101
|
-
<ds-icon slot="icon" name={item.icon} />
|
|
102
|
-
)}
|
|
103
|
-
</ds-button>,
|
|
104
|
-
];
|
|
105
|
-
})}
|
|
106
|
-
</div>
|
|
107
|
-
</Host>
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { Component, Prop, Event, EventEmitter, h, Host } from '@stencil/core';
|
|
2
|
-
import type { IconSize } from '../Icon/Icon';
|
|
3
|
-
import { resolveCssLengthPx, TOKEN_DEFAULTS } from '../../utils';
|
|
4
|
-
|
|
5
|
-
export type ToggleButtonElevation = 'none' | 'flat' | 'elevated' | 'floating';
|
|
6
|
-
export type ToggleButtonSize = 'md' | 'sm' | 'xs';
|
|
7
|
-
export type ToggleButtonBackground = 'faint' | 'medium' | 'bold' | 'strong' | 'always-dark';
|
|
8
|
-
|
|
9
|
-
const ICON_SIZE: Record<ToggleButtonSize, IconSize> = { md: 'md', sm: 'sm', xs: 'xs' };
|
|
10
|
-
|
|
11
|
-
const ICON_TOKEN: Record<ToggleButtonSize, string> = {
|
|
12
|
-
md: TOKEN_DEFAULTS.iconographyMd,
|
|
13
|
-
sm: TOKEN_DEFAULTS.iconographySm,
|
|
14
|
-
xs: TOKEN_DEFAULTS.iconographyXs,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const TEXT_CLASS: Record<ToggleButtonSize, string> = {
|
|
18
|
-
md: 'text-body-medium-emphasis',
|
|
19
|
-
sm: 'text-body-small-emphasis',
|
|
20
|
-
xs: 'text-caption-emphasis',
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
@Component({
|
|
24
|
-
tag: 'ds-toggle-button',
|
|
25
|
-
styleUrl: 'ToggleButton.css',
|
|
26
|
-
scoped: true,
|
|
27
|
-
})
|
|
28
|
-
export class ToggleButton {
|
|
29
|
-
/**
|
|
30
|
-
* Chrome level.
|
|
31
|
-
* none — ghost (transparent, no border, no shadow)
|
|
32
|
-
* flat — border only, transparent bg
|
|
33
|
-
* elevated — bg-primary + shadow [default]
|
|
34
|
-
* floating — bg-primary + FAB-strength shadow
|
|
35
|
-
*/
|
|
36
|
-
@Prop() elevation: ToggleButtonElevation = 'elevated';
|
|
37
|
-
|
|
38
|
-
/** Label text. */
|
|
39
|
-
@Prop() label: string | undefined;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Icon name for <ds-icon>. Set via JS property.
|
|
43
|
-
* @example el.icon = 'GridView';
|
|
44
|
-
*/
|
|
45
|
-
@Prop() icon: string | undefined;
|
|
46
|
-
|
|
47
|
-
/** Size: md (32px), sm (24px), xs (16px). */
|
|
48
|
-
@Prop() size: ToggleButtonSize = 'md';
|
|
49
|
-
|
|
50
|
-
/** Pill shape. */
|
|
51
|
-
@Prop() rounded: boolean = false;
|
|
52
|
-
|
|
53
|
-
/** Parent surface context — adjusts hover tokens for colored backgrounds. */
|
|
54
|
-
@Prop() background: ToggleButtonBackground | undefined;
|
|
55
|
-
|
|
56
|
-
/** Controlled pressed state. */
|
|
57
|
-
@Prop({ mutable: true }) pressed: boolean = false;
|
|
58
|
-
|
|
59
|
-
/** Disables interaction. */
|
|
60
|
-
@Prop() inactive: boolean = false;
|
|
61
|
-
|
|
62
|
-
@Prop({ attribute: 'aria-label' }) ariaLabel: string | undefined;
|
|
63
|
-
|
|
64
|
-
/** Emits the new pressed value (!pressed) on click. */
|
|
65
|
-
@Event() dsChange!: EventEmitter<boolean>;
|
|
66
|
-
|
|
67
|
-
private handleClick = () => {
|
|
68
|
-
if (this.inactive) return;
|
|
69
|
-
this.dsChange.emit(!this.pressed);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
render() {
|
|
73
|
-
const size = this.size;
|
|
74
|
-
const iconSize = ICON_SIZE[size];
|
|
75
|
-
const iconPx = resolveCssLengthPx(ICON_TOKEN[size], ICON_TOKEN[size]);
|
|
76
|
-
const textClass = TEXT_CLASS[size];
|
|
77
|
-
const hasIcon = !!this.icon;
|
|
78
|
-
const hasLabel = !!this.label;
|
|
79
|
-
const isIconOnly = hasIcon && !hasLabel;
|
|
80
|
-
const isLabelOnly = hasLabel && !hasIcon;
|
|
81
|
-
const isIconAndLabel = hasIcon && hasLabel;
|
|
82
|
-
const bg = this.background;
|
|
83
|
-
const elevKey = this.elevation.charAt(0).toUpperCase() + this.elevation.slice(1);
|
|
84
|
-
|
|
85
|
-
const cls: Record<string, boolean> = {
|
|
86
|
-
'toggle-btn': true,
|
|
87
|
-
[`elevation${elevKey}`]: true,
|
|
88
|
-
sizeSM: size === 'sm',
|
|
89
|
-
sizeXS: size === 'xs',
|
|
90
|
-
rounded: this.rounded,
|
|
91
|
-
inactive: this.inactive,
|
|
92
|
-
pressed: this.pressed,
|
|
93
|
-
iconOnly: isIconOnly,
|
|
94
|
-
labelOnly: isLabelOnly,
|
|
95
|
-
iconAndLabel: isIconAndLabel,
|
|
96
|
-
onMedium: bg === 'medium',
|
|
97
|
-
onBold: bg === 'bold',
|
|
98
|
-
onStrong: bg === 'strong',
|
|
99
|
-
onAlwaysDark: bg === 'always-dark',
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
return (
|
|
103
|
-
<Host>
|
|
104
|
-
<button
|
|
105
|
-
type="button"
|
|
106
|
-
class={cls}
|
|
107
|
-
disabled={this.inactive}
|
|
108
|
-
aria-label={this.ariaLabel ?? this.label ?? 'toggle'}
|
|
109
|
-
aria-pressed={this.pressed}
|
|
110
|
-
onClick={this.handleClick}
|
|
111
|
-
>
|
|
112
|
-
{hasIcon && (
|
|
113
|
-
<span class="toggle-btn__icon" style={{ fontSize: `${iconPx}px` }}>
|
|
114
|
-
<ds-icon name={this.icon} size={iconSize} />
|
|
115
|
-
</span>
|
|
116
|
-
)}
|
|
117
|
-
{hasLabel && (
|
|
118
|
-
<span class={`toggle-btn__label ${textClass}`}>{this.label}</span>
|
|
119
|
-
)}
|
|
120
|
-
</button>
|
|
121
|
-
</Host>
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { Component, Prop, Event, EventEmitter, h, Host } from '@stencil/core';
|
|
2
|
-
|
|
3
|
-
export type ToggleGroupElevation = 'none' | 'flat' | 'elevated' | 'floating';
|
|
4
|
-
export type ToggleGroupSize = 'md' | 'sm' | 'xs';
|
|
5
|
-
export type ToggleGroupBackground = 'faint' | 'medium' | 'bold' | 'strong' | 'always-dark';
|
|
6
|
-
|
|
7
|
-
export interface ToggleGroupItem {
|
|
8
|
-
id: string;
|
|
9
|
-
label?: string;
|
|
10
|
-
/** Icon name for <ds-icon>. */
|
|
11
|
-
icon?: string;
|
|
12
|
-
inactive?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@Component({
|
|
16
|
-
tag: 'ds-toggle-button-group',
|
|
17
|
-
styleUrl: 'ToggleButtonGroup.css',
|
|
18
|
-
scoped: true,
|
|
19
|
-
})
|
|
20
|
-
export class ToggleButtonGroup {
|
|
21
|
-
/**
|
|
22
|
-
* Array of item descriptors. Set via JS property.
|
|
23
|
-
* @example el.items = [{ id: 'list', label: 'List' }, { id: 'grid', icon: 'GridView' }];
|
|
24
|
-
*/
|
|
25
|
-
@Prop() items: ToggleGroupItem[] = [];
|
|
26
|
-
|
|
27
|
-
/** ID of the currently selected / pressed item. */
|
|
28
|
-
@Prop({ mutable: true }) value: string = '';
|
|
29
|
-
|
|
30
|
-
/** Chrome level for the group container. */
|
|
31
|
-
@Prop() elevation: ToggleGroupElevation = 'elevated';
|
|
32
|
-
|
|
33
|
-
/** Size passed to each ds-toggle-button. */
|
|
34
|
-
@Prop() size: ToggleGroupSize = 'md';
|
|
35
|
-
|
|
36
|
-
/** Pill shape for group + buttons. */
|
|
37
|
-
@Prop() rounded: boolean = false;
|
|
38
|
-
|
|
39
|
-
/** Parent surface context. */
|
|
40
|
-
@Prop() background: ToggleGroupBackground | undefined;
|
|
41
|
-
|
|
42
|
-
/** Emits the id of the newly selected item. */
|
|
43
|
-
@Event() dsChange!: EventEmitter<string>;
|
|
44
|
-
|
|
45
|
-
private handleItemChange(id: string) {
|
|
46
|
-
if (id === this.value) return;
|
|
47
|
-
this.value = id;
|
|
48
|
-
this.dsChange.emit(id);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
render() {
|
|
52
|
-
const items = this.items;
|
|
53
|
-
const count = items.length;
|
|
54
|
-
const elev = this.elevation;
|
|
55
|
-
const elevKey = elev.charAt(0).toUpperCase() + elev.slice(1);
|
|
56
|
-
const bg = this.background;
|
|
57
|
-
const isGhost = elev === 'none';
|
|
58
|
-
|
|
59
|
-
const groupCls: Record<string, boolean> = {
|
|
60
|
-
group: true,
|
|
61
|
-
[`group${elevKey}`]: true,
|
|
62
|
-
groupRounded: this.rounded,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<Host>
|
|
67
|
-
<div class={groupCls} role="group">
|
|
68
|
-
{items.map((item, i) => {
|
|
69
|
-
const isFirst = i === 0;
|
|
70
|
-
const isLast = i === count - 1;
|
|
71
|
-
const isMid = !isFirst && !isLast;
|
|
72
|
-
const isPressed = item.id === this.value;
|
|
73
|
-
const isIconOnly = !!item.icon && !item.label;
|
|
74
|
-
const needsRoundedCorrection = this.rounded && !isIconOnly && this.size !== 'xs';
|
|
75
|
-
const sizeKey = this.size.toUpperCase() as 'MD' | 'SM' | 'XS';
|
|
76
|
-
|
|
77
|
-
const itemCls: Record<string, boolean> = {
|
|
78
|
-
item: true,
|
|
79
|
-
first: isFirst,
|
|
80
|
-
last: isLast,
|
|
81
|
-
middle: isMid,
|
|
82
|
-
itemShort: isGhost,
|
|
83
|
-
itemPressed: isGhost && isPressed,
|
|
84
|
-
[`roundedFirst${sizeKey}`]: !!(needsRoundedCorrection && isFirst),
|
|
85
|
-
[`roundedLast${sizeKey}`]: !!(needsRoundedCorrection && isLast),
|
|
86
|
-
[`roundedMid${sizeKey}`]: !!(needsRoundedCorrection && isMid),
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const dividerCls: Record<string, boolean> = {
|
|
90
|
-
divider: true,
|
|
91
|
-
dividerGhost: isGhost,
|
|
92
|
-
dividerGhostXS: isGhost && this.size === 'xs',
|
|
93
|
-
dividerGhostSM: isGhost && this.size === 'sm',
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
return [
|
|
97
|
-
i > 0 && (
|
|
98
|
-
<div class={dividerCls} aria-hidden="true" />
|
|
99
|
-
),
|
|
100
|
-
<ds-toggle-button
|
|
101
|
-
class={itemCls}
|
|
102
|
-
elevation={elev}
|
|
103
|
-
size={this.size}
|
|
104
|
-
label={item.label}
|
|
105
|
-
icon={item.icon}
|
|
106
|
-
rounded={this.rounded}
|
|
107
|
-
background={bg}
|
|
108
|
-
pressed={isPressed}
|
|
109
|
-
inactive={item.inactive}
|
|
110
|
-
onDsChange={() => this.handleItemChange(item.id)}
|
|
111
|
-
/>,
|
|
112
|
-
];
|
|
113
|
-
})}
|
|
114
|
-
</div>
|
|
115
|
-
</Host>
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|