@nuvia-ui/components 4.0.1
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/package.json +27 -0
- package/src/ds-accordion/ds-accordion-item.js +288 -0
- package/src/ds-accordion/ds-accordion-item.stories.js +82 -0
- package/src/ds-accordion/ds-accordion.a11y.test.js +92 -0
- package/src/ds-accordion/ds-accordion.js +68 -0
- package/src/ds-accordion/ds-accordion.stories.js +118 -0
- package/src/ds-accordion/ds-accordion.test.js +146 -0
- package/src/ds-accordion/index.js +2 -0
- package/src/ds-action-bar/ds-action-bar.js +116 -0
- package/src/ds-action-bar/ds-action-bar.stories.js +86 -0
- package/src/ds-action-bar/ds-action-bar.test.js +64 -0
- package/src/ds-action-bar/index.js +1 -0
- package/src/ds-alert/ds-alert.a11y.test.js +151 -0
- package/src/ds-alert/ds-alert.js +223 -0
- package/src/ds-alert/ds-alert.mdx +142 -0
- package/src/ds-alert/ds-alert.stories.js +166 -0
- package/src/ds-alert/ds-alert.test.js +256 -0
- package/src/ds-alert/index.js +1 -0
- package/src/ds-avatar/ds-avatar.a11y.test.js +45 -0
- package/src/ds-avatar/ds-avatar.js +216 -0
- package/src/ds-avatar/ds-avatar.stories.js +120 -0
- package/src/ds-avatar/ds-avatar.test.js +83 -0
- package/src/ds-avatar/index.js +1 -0
- package/src/ds-avatar-extended/ds-avatar-extended.a11y.test.js +29 -0
- package/src/ds-avatar-extended/ds-avatar-extended.js +108 -0
- package/src/ds-avatar-extended/ds-avatar-extended.stories.js +93 -0
- package/src/ds-avatar-extended/ds-avatar-extended.test.js +66 -0
- package/src/ds-avatar-extended/index.js +1 -0
- package/src/ds-banner/ds-banner.a11y.test.js +51 -0
- package/src/ds-banner/ds-banner.js +233 -0
- package/src/ds-banner/ds-banner.stories.js +185 -0
- package/src/ds-banner/ds-banner.test.js +116 -0
- package/src/ds-banner/index.js +1 -0
- package/src/ds-breadcrumb-item/ds-breadcrumb-item.js +135 -0
- package/src/ds-breadcrumb-item/ds-breadcrumb-item.stories.js +49 -0
- package/src/ds-breadcrumb-item/ds-breadcrumb-item.test.js +55 -0
- package/src/ds-breadcrumbs/ds-breadcrumbs.js +194 -0
- package/src/ds-breadcrumbs/ds-breadcrumbs.stories.js +54 -0
- package/src/ds-breadcrumbs/ds-breadcrumbs.test.js +33 -0
- package/src/ds-button/ds-button.a11y.test.js +49 -0
- package/src/ds-button/ds-button.js +205 -0
- package/src/ds-button/ds-button.mdx +141 -0
- package/src/ds-button/ds-button.stories.js +152 -0
- package/src/ds-button/ds-button.test.js +62 -0
- package/src/ds-button/index.js +1 -0
- package/src/ds-button-group/ds-button-group.js +82 -0
- package/src/ds-button-group/ds-button-group.mdx +39 -0
- package/src/ds-button-group/ds-button-group.stories.js +47 -0
- package/src/ds-button-group/ds-button-group.test.js +47 -0
- package/src/ds-button-group/index.js +1 -0
- package/src/ds-checkbox/ds-checkbox.a11y.test.js +79 -0
- package/src/ds-checkbox/ds-checkbox.js +271 -0
- package/src/ds-checkbox/ds-checkbox.stories.js +77 -0
- package/src/ds-checkbox/ds-checkbox.test.js +191 -0
- package/src/ds-checkbox/index.js +1 -0
- package/src/ds-checkbox-group/ds-checkbox-group.a11y.test.js +146 -0
- package/src/ds-checkbox-group/ds-checkbox-group.js +235 -0
- package/src/ds-checkbox-group/ds-checkbox-group.stories.js +210 -0
- package/src/ds-checkbox-group/ds-checkbox-group.test.js +150 -0
- package/src/ds-checkbox-group/index.js +1 -0
- package/src/ds-dialog/ds-dialog.js +466 -0
- package/src/ds-dialog/ds-dialog.stories.js +274 -0
- package/src/ds-dialog/ds-dialog.test.js +441 -0
- package/src/ds-dialog/index.js +1 -0
- package/src/ds-dropdown/ds-dropdown.a11y.test.js +80 -0
- package/src/ds-dropdown/ds-dropdown.js +891 -0
- package/src/ds-dropdown/ds-dropdown.stories.js +259 -0
- package/src/ds-dropdown/ds-dropdown.test.js +268 -0
- package/src/ds-dropdown/index.js +1 -0
- package/src/ds-dropdown-group/ds-dropdown-group.js +55 -0
- package/src/ds-dropdown-panel/ds-dropdown-panel.js +34 -0
- package/src/ds-file-uploaded/ds-file-uploaded.a11y.test.js +40 -0
- package/src/ds-file-uploaded/ds-file-uploaded.js +135 -0
- package/src/ds-file-uploaded/ds-file-uploaded.mdx +33 -0
- package/src/ds-file-uploaded/ds-file-uploaded.stories.js +81 -0
- package/src/ds-file-uploaded/ds-file-uploaded.test.js +85 -0
- package/src/ds-file-uploader/ds-file-uploader.a11y.test.js +61 -0
- package/src/ds-file-uploader/ds-file-uploader.js +442 -0
- package/src/ds-file-uploader/ds-file-uploader.mdx +44 -0
- package/src/ds-file-uploader/ds-file-uploader.stories.js +76 -0
- package/src/ds-file-uploader/ds-file-uploader.test.js +142 -0
- package/src/ds-header/ds-header.a11y.test.js +38 -0
- package/src/ds-header/ds-header.js +149 -0
- package/src/ds-header/ds-header.stories.js +63 -0
- package/src/ds-header/ds-header.test.js +52 -0
- package/src/ds-header/index.js +1 -0
- package/src/ds-header-nav/ds-header-nav.a11y.test.js +69 -0
- package/src/ds-header-nav/ds-header-nav.js +114 -0
- package/src/ds-header-nav/ds-header-nav.stories.js +17 -0
- package/src/ds-header-nav/ds-header-nav.test.js +93 -0
- package/src/ds-header-nav-item/ds-header-nav-item.a11y.test.js +71 -0
- package/src/ds-header-nav-item/ds-header-nav-item.js +124 -0
- package/src/ds-header-nav-item/ds-header-nav-item.stories.js +43 -0
- package/src/ds-header-nav-item/ds-header-nav-item.test.js +61 -0
- package/src/ds-icon/ds-icon.a11y.test.js +49 -0
- package/src/ds-icon/ds-icon.js +75 -0
- package/src/ds-icon/ds-icon.mdx +36 -0
- package/src/ds-icon/ds-icon.stories.js +88 -0
- package/src/ds-icon/ds-icon.test.js +97 -0
- package/src/ds-icon/index.js +1 -0
- package/src/ds-icon-button/ds-icon-button.a11y.test.js +55 -0
- package/src/ds-icon-button/ds-icon-button.js +224 -0
- package/src/ds-icon-button/ds-icon-button.mdx +131 -0
- package/src/ds-icon-button/ds-icon-button.stories.js +128 -0
- package/src/ds-icon-button/ds-icon-button.test.js +90 -0
- package/src/ds-icon-button/index.js +1 -0
- package/src/ds-input/ds-input.a11y.test.js +145 -0
- package/src/ds-input/ds-input.js +645 -0
- package/src/ds-input/ds-input.mdx +251 -0
- package/src/ds-input/ds-input.stories.js +298 -0
- package/src/ds-input/ds-input.test.js +792 -0
- package/src/ds-input/index.js +1 -0
- package/src/ds-link/ds-link.js +111 -0
- package/src/ds-link/ds-link.stories.js +56 -0
- package/src/ds-link/ds-link.test.js +74 -0
- package/src/ds-list-item/ds-list-item.a11y.test.js +39 -0
- package/src/ds-list-item/ds-list-item.js +292 -0
- package/src/ds-list-item/ds-list-item.stories.js +101 -0
- package/src/ds-list-item/ds-list-item.test.js +63 -0
- package/src/ds-menu/ds-menu.js +30 -0
- package/src/ds-menu/ds-menu.stories.js +120 -0
- package/src/ds-menu/ds-menu.test.js +123 -0
- package/src/ds-menu-group/ds-menu-group.js +101 -0
- package/src/ds-menu-group/ds-menu-group.stories.js +99 -0
- package/src/ds-nav-item/ds-nav-item.a11y.test.js +91 -0
- package/src/ds-nav-item/ds-nav-item.js +307 -0
- package/src/ds-nav-item/ds-nav-item.stories.js +99 -0
- package/src/ds-nav-item/ds-nav-item.test.js +169 -0
- package/src/ds-nav-item/index.js +1 -0
- package/src/ds-nav-vertical/ds-nav-vertical.a11y.test.js +69 -0
- package/src/ds-nav-vertical/ds-nav-vertical.js +173 -0
- package/src/ds-nav-vertical/ds-nav-vertical.stories.js +124 -0
- package/src/ds-nav-vertical/ds-nav-vertical.test.js +176 -0
- package/src/ds-nav-vertical/index.js +1 -0
- package/src/ds-pagination/ds-pagination.a11y.test.js +50 -0
- package/src/ds-pagination/ds-pagination.js +232 -0
- package/src/ds-pagination/ds-pagination.stories.js +63 -0
- package/src/ds-pagination/ds-pagination.test.js +141 -0
- package/src/ds-pagination/index.js +1 -0
- package/src/ds-progress-bar/ds-progress-bar.a11y.test.js +25 -0
- package/src/ds-progress-bar/ds-progress-bar.js +81 -0
- package/src/ds-progress-bar/ds-progress-bar.stories.js +69 -0
- package/src/ds-progress-bar/ds-progress-bar.test.js +60 -0
- package/src/ds-radio/ds-radio.a11y.test.js +69 -0
- package/src/ds-radio/ds-radio.js +240 -0
- package/src/ds-radio/ds-radio.stories.js +102 -0
- package/src/ds-radio/ds-radio.test.js +114 -0
- package/src/ds-radio/index.js +1 -0
- package/src/ds-radio-group/ds-radio-group.a11y.test.js +164 -0
- package/src/ds-radio-group/ds-radio-group.js +257 -0
- package/src/ds-radio-group/ds-radio-group.stories.js +247 -0
- package/src/ds-radio-group/ds-radio-group.test.js +194 -0
- package/src/ds-radio-group/index.js +1 -0
- package/src/ds-rich-list/ds-rich-list.js +246 -0
- package/src/ds-rich-list/ds-rich-list.stories.js +368 -0
- package/src/ds-rich-list/ds-rich-list.test.js +293 -0
- package/src/ds-rich-list-item/ds-rich-list-item.js +579 -0
- package/src/ds-rich-list-item/ds-rich-list-item.stories.js +197 -0
- package/src/ds-rich-list-item/ds-rich-list-item.test.js +434 -0
- package/src/ds-slider/ds-slider.js +399 -0
- package/src/ds-slider/ds-slider.stories.js +107 -0
- package/src/ds-slider/ds-slider.test.js +308 -0
- package/src/ds-spinner/ds-spinner.js +173 -0
- package/src/ds-spinner/ds-spinner.stories.js +52 -0
- package/src/ds-spinner/ds-spinner.test.js +50 -0
- package/src/ds-status-border/ds-status-border.js +88 -0
- package/src/ds-status-border/ds-status-border.stories.js +242 -0
- package/src/ds-status-border/ds-status-border.test.js +168 -0
- package/src/ds-stepper/ds-stepper.a11y.test.js +198 -0
- package/src/ds-stepper/ds-stepper.js +207 -0
- package/src/ds-stepper/ds-stepper.stories.js +530 -0
- package/src/ds-stepper/ds-stepper.test.js +311 -0
- package/src/ds-stepper-item/ds-stepper-item.js +485 -0
- package/src/ds-stepper-item/ds-stepper-item.stories.js +288 -0
- package/src/ds-switch/ds-switch.js +348 -0
- package/src/ds-switch/ds-switch.stories.js +145 -0
- package/src/ds-switch/ds-switch.test.js +226 -0
- package/src/ds-switch/index.js +1 -0
- package/src/ds-tab-item/ds-tab-item.js +341 -0
- package/src/ds-tab-item/ds-tab-item.stories.js +69 -0
- package/src/ds-tabs/ds-tab-panel.js +48 -0
- package/src/ds-tabs/ds-tabs.a11y.test.js +56 -0
- package/src/ds-tabs/ds-tabs.js +180 -0
- package/src/ds-tabs/ds-tabs.stories.js +152 -0
- package/src/ds-tabs/ds-tabs.test.js +306 -0
- package/src/ds-tabs/index.js +3 -0
- package/src/ds-tag-action/ds-tag-action.a11y.test.js +32 -0
- package/src/ds-tag-action/ds-tag-action.js +185 -0
- package/src/ds-tag-action/ds-tag-action.stories.js +55 -0
- package/src/ds-tag-action/ds-tag-action.test.js +44 -0
- package/src/ds-tag-removable/ds-tag-removable.a11y.test.js +24 -0
- package/src/ds-tag-removable/ds-tag-removable.js +146 -0
- package/src/ds-tag-removable/ds-tag-removable.stories.js +52 -0
- package/src/ds-tag-removable/ds-tag-removable.test.js +46 -0
- package/src/ds-tag-status/ds-tag-status.a11y.test.js +93 -0
- package/src/ds-tag-status/ds-tag-status.js +164 -0
- package/src/ds-tag-status/ds-tag-status.stories.js +200 -0
- package/src/ds-tag-status/ds-tag-status.test.js +140 -0
- package/src/ds-tag-status/index.js +1 -0
- package/src/ds-textarea/ds-textarea-clearable.test.js +89 -0
- package/src/ds-textarea/ds-textarea.a11y.test.js +66 -0
- package/src/ds-textarea/ds-textarea.js +505 -0
- package/src/ds-textarea/ds-textarea.stories.js +335 -0
- package/src/ds-textarea/ds-textarea.test.js +218 -0
- package/src/ds-textarea/index.js +1 -0
- package/src/ds-thumbnail/ds-thumbnail.js +207 -0
- package/src/ds-thumbnail/ds-thumbnail.stories.js +217 -0
- package/src/ds-thumbnail/ds-thumbnail.test.js +220 -0
- package/src/ds-toast/ds-toast-provider.js +110 -0
- package/src/ds-toast/ds-toast.a11y.test.js +34 -0
- package/src/ds-toast/ds-toast.js +243 -0
- package/src/ds-toast/ds-toast.stories.js +143 -0
- package/src/ds-toast/ds-toast.test.js +93 -0
- package/src/ds-toast/index.js +2 -0
- package/src/ds-tooltip/ds-tooltip.a11y.test.js +110 -0
- package/src/ds-tooltip/ds-tooltip.js +217 -0
- package/src/ds-tooltip/ds-tooltip.mdx +75 -0
- package/src/ds-tooltip/ds-tooltip.stories.js +72 -0
- package/src/ds-tooltip/ds-tooltip.test.js +191 -0
- package/src/ds-tooltip/index.js +1 -0
- package/src/ds-tooltip/positioner.js +117 -0
- package/src/index.js +50 -0
- package/src/mixins/field-label.mixin.js +113 -0
- package/src/mixins/field-message.mixin.js +66 -0
- package/src/token-provider/index.js +1 -0
- package/src/token-provider/token-provider.a11y.test.js +44 -0
- package/src/token-provider/token-provider.js +85 -0
- package/src/token-provider/token-provider.stories.js +105 -0
- package/src/token-provider/token-provider.test.js +134 -0
- package/src/utils/number-input.utils.js +42 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import './ds-stepper-item.js';
|
|
3
|
+
import '../ds-stepper/ds-stepper.js';
|
|
4
|
+
import '../ds-icon/ds-icon.js';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Components/Stepper Item',
|
|
8
|
+
component: 'ds-stepper-item',
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component: 'Individual step within a `ds-stepper`. Supports `completed`, `current`, `disabled`, and `error` states. Normally used inside `ds-stepper`, but can be configured standalone for demonstration.'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
completed: { control: 'boolean', description: 'Whether this step is completed' },
|
|
18
|
+
current: { control: 'boolean', description: 'Whether this is the current active step' },
|
|
19
|
+
disabled: { control: 'boolean', description: 'Whether this step is disabled' },
|
|
20
|
+
error: { control: 'boolean', description: 'Whether this step has an error state' }
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Helper to manually set internal properties that are normally set by ds-stepper
|
|
25
|
+
const configureItem = (el, config = {}) => {
|
|
26
|
+
if (!el) return;
|
|
27
|
+
requestAnimationFrame(() => {
|
|
28
|
+
el._direction = config.direction || 'horizontal';
|
|
29
|
+
el._position = config.position || 'middle';
|
|
30
|
+
el._step = config.step || 1;
|
|
31
|
+
el._totalSteps = config.totalSteps || 4;
|
|
32
|
+
el._linear = config.linear || false;
|
|
33
|
+
el._prevCompleted = config.prevCompleted || false;
|
|
34
|
+
el._prevError = config.prevError || false;
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// ===== ALL STATES =====
|
|
39
|
+
export const AllStates = {
|
|
40
|
+
render: () => html`
|
|
41
|
+
<style>
|
|
42
|
+
.states-grid {
|
|
43
|
+
display: grid;
|
|
44
|
+
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
45
|
+
gap: 32px;
|
|
46
|
+
padding: 24px;
|
|
47
|
+
}
|
|
48
|
+
.state-card {
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
gap: 8px;
|
|
52
|
+
align-items: center;
|
|
53
|
+
}
|
|
54
|
+
.state-label {
|
|
55
|
+
font: var(--ds-typo-content-caption-bold);
|
|
56
|
+
color: var(--ds-color-text-secondary);
|
|
57
|
+
text-transform: uppercase;
|
|
58
|
+
letter-spacing: 0.05em;
|
|
59
|
+
}
|
|
60
|
+
</style>
|
|
61
|
+
<div class="states-grid">
|
|
62
|
+
<div class="state-card">
|
|
63
|
+
<span class="state-label">Default (Pending)</span>
|
|
64
|
+
<ds-stepper-item
|
|
65
|
+
id="state-default"
|
|
66
|
+
@click=${(e) => configureItem(e.target, { step: 3, position: 'middle' })}
|
|
67
|
+
>Pending Step</ds-stepper-item>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="state-card">
|
|
71
|
+
<span class="state-label">Current</span>
|
|
72
|
+
<ds-stepper-item
|
|
73
|
+
current
|
|
74
|
+
id="state-current"
|
|
75
|
+
>Current Step</ds-stepper-item>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="state-card">
|
|
79
|
+
<span class="state-label">Completed</span>
|
|
80
|
+
<ds-stepper-item
|
|
81
|
+
completed
|
|
82
|
+
id="state-completed"
|
|
83
|
+
>Completed Step</ds-stepper-item>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div class="state-card">
|
|
87
|
+
<span class="state-label">Error</span>
|
|
88
|
+
<ds-stepper-item
|
|
89
|
+
error
|
|
90
|
+
id="state-error"
|
|
91
|
+
>Error Step</ds-stepper-item>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div class="state-card">
|
|
95
|
+
<span class="state-label">Disabled</span>
|
|
96
|
+
<ds-stepper-item
|
|
97
|
+
disabled
|
|
98
|
+
id="state-disabled"
|
|
99
|
+
>Disabled Step</ds-stepper-item>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div class="state-card">
|
|
103
|
+
<span class="state-label">Completed + Error</span>
|
|
104
|
+
<ds-stepper-item
|
|
105
|
+
completed
|
|
106
|
+
error
|
|
107
|
+
id="state-completed-error"
|
|
108
|
+
>Completed Error</ds-stepper-item>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<script type="module">
|
|
113
|
+
requestAnimationFrame(() => {
|
|
114
|
+
const items = {
|
|
115
|
+
'state-default': { step: 3, position: 'middle' },
|
|
116
|
+
'state-current': { step: 2, position: 'middle' },
|
|
117
|
+
'state-completed': { step: 1, position: 'first' },
|
|
118
|
+
'state-error': { step: 3, position: 'middle' },
|
|
119
|
+
'state-disabled': { step: 4, position: 'last' },
|
|
120
|
+
'state-completed-error': { step: 2, position: 'middle' }
|
|
121
|
+
};
|
|
122
|
+
Object.entries(items).forEach(([id, config]) => {
|
|
123
|
+
const el = document.getElementById(id);
|
|
124
|
+
if (el) {
|
|
125
|
+
el._direction = 'horizontal';
|
|
126
|
+
el._position = config.position;
|
|
127
|
+
el._step = config.step;
|
|
128
|
+
el._totalSteps = 4;
|
|
129
|
+
el._linear = false;
|
|
130
|
+
el._prevCompleted = false;
|
|
131
|
+
el._prevError = false;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
</script>
|
|
136
|
+
`,
|
|
137
|
+
parameters: {
|
|
138
|
+
docs: {
|
|
139
|
+
description: {
|
|
140
|
+
story: 'Visual catalogue of all individual states for `ds-stepper-item`: Default (pending), Current, Completed, Error, Disabled, and combined Completed+Error.'
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// ===== WITHIN STEPPER CONTEXT =====
|
|
147
|
+
export const InStepperContext = {
|
|
148
|
+
render: () => html`
|
|
149
|
+
<style>
|
|
150
|
+
.context-section {
|
|
151
|
+
display: flex;
|
|
152
|
+
flex-direction: column;
|
|
153
|
+
gap: 32px;
|
|
154
|
+
padding: 24px;
|
|
155
|
+
}
|
|
156
|
+
.context-label {
|
|
157
|
+
font: var(--ds-typo-content-body-bold);
|
|
158
|
+
color: var(--ds-color-text-default);
|
|
159
|
+
margin-bottom: 8px;
|
|
160
|
+
}
|
|
161
|
+
.context-desc {
|
|
162
|
+
font: var(--ds-typo-content-caption-regular);
|
|
163
|
+
color: var(--ds-color-text-secondary);
|
|
164
|
+
margin-bottom: 16px;
|
|
165
|
+
}
|
|
166
|
+
</style>
|
|
167
|
+
<div class="context-section">
|
|
168
|
+
<div>
|
|
169
|
+
<p class="context-label">Horizontal — Step 2 active, step 1 completed</p>
|
|
170
|
+
<p class="context-desc">Shows how items relate to each other with connector lines.</p>
|
|
171
|
+
<ds-stepper active-step="1">
|
|
172
|
+
<ds-stepper-item>Account Setup</ds-stepper-item>
|
|
173
|
+
<ds-stepper-item>Personal Info</ds-stepper-item>
|
|
174
|
+
<ds-stepper-item>Preferences</ds-stepper-item>
|
|
175
|
+
<ds-stepper-item>Confirmation</ds-stepper-item>
|
|
176
|
+
</ds-stepper>
|
|
177
|
+
</div>
|
|
178
|
+
|
|
179
|
+
<div>
|
|
180
|
+
<p class="context-label">With Error on Step 2</p>
|
|
181
|
+
<p class="context-desc">Step 2 reports an error. Notice the red connector and indicator.</p>
|
|
182
|
+
<ds-stepper active-step="2">
|
|
183
|
+
<ds-stepper-item>Account Setup</ds-stepper-item>
|
|
184
|
+
<ds-stepper-item error>Personal Info</ds-stepper-item>
|
|
185
|
+
<ds-stepper-item>Preferences</ds-stepper-item>
|
|
186
|
+
<ds-stepper-item>Confirmation</ds-stepper-item>
|
|
187
|
+
</ds-stepper>
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<div>
|
|
191
|
+
<p class="context-label">With Disabled Step</p>
|
|
192
|
+
<p class="context-desc">Step 3 is disabled — no pointer events, dimmed styling.</p>
|
|
193
|
+
<ds-stepper active-step="1">
|
|
194
|
+
<ds-stepper-item>Account Setup</ds-stepper-item>
|
|
195
|
+
<ds-stepper-item>Personal Info</ds-stepper-item>
|
|
196
|
+
<ds-stepper-item disabled>Restricted</ds-stepper-item>
|
|
197
|
+
<ds-stepper-item>Confirmation</ds-stepper-item>
|
|
198
|
+
</ds-stepper>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<div>
|
|
202
|
+
<p class="context-label">Linear Mode — Only completed/current steps are clickable</p>
|
|
203
|
+
<p class="context-desc">Steps 3 and 4 are locked (not clickable) until previous steps are completed.</p>
|
|
204
|
+
<ds-stepper linear active-step="1">
|
|
205
|
+
<ds-stepper-item>Account Setup</ds-stepper-item>
|
|
206
|
+
<ds-stepper-item>Personal Info</ds-stepper-item>
|
|
207
|
+
<ds-stepper-item>Preferences</ds-stepper-item>
|
|
208
|
+
<ds-stepper-item>Confirmation</ds-stepper-item>
|
|
209
|
+
</ds-stepper>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
`,
|
|
213
|
+
parameters: {
|
|
214
|
+
docs: {
|
|
215
|
+
description: {
|
|
216
|
+
story: 'Shows `ds-stepper-item` within its parent `ds-stepper` context, demonstrating how items interact with connector lines, error states, disabled items, and linear mode.'
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// ===== VERTICAL ITEM STATES =====
|
|
223
|
+
export const VerticalStates = {
|
|
224
|
+
render: () => html`
|
|
225
|
+
<style>
|
|
226
|
+
.vertical-section {
|
|
227
|
+
display: flex;
|
|
228
|
+
gap: 48px;
|
|
229
|
+
padding: 24px;
|
|
230
|
+
}
|
|
231
|
+
.vertical-card {
|
|
232
|
+
display: flex;
|
|
233
|
+
flex-direction: column;
|
|
234
|
+
gap: 8px;
|
|
235
|
+
}
|
|
236
|
+
.v-label {
|
|
237
|
+
font: var(--ds-typo-content-caption-bold);
|
|
238
|
+
color: var(--ds-color-text-secondary);
|
|
239
|
+
text-transform: uppercase;
|
|
240
|
+
}
|
|
241
|
+
</style>
|
|
242
|
+
<div class="vertical-section">
|
|
243
|
+
<div class="vertical-card">
|
|
244
|
+
<span class="v-label">Normal Flow</span>
|
|
245
|
+
<ds-stepper direction="vertical" active-step="1">
|
|
246
|
+
<ds-stepper-item>Account</ds-stepper-item>
|
|
247
|
+
<ds-stepper-item>Details</ds-stepper-item>
|
|
248
|
+
<ds-stepper-item>Review</ds-stepper-item>
|
|
249
|
+
</ds-stepper>
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
<div class="vertical-card">
|
|
253
|
+
<span class="v-label">With Error</span>
|
|
254
|
+
<ds-stepper direction="vertical" active-step="2">
|
|
255
|
+
<ds-stepper-item>Account</ds-stepper-item>
|
|
256
|
+
<ds-stepper-item error>Details</ds-stepper-item>
|
|
257
|
+
<ds-stepper-item>Review</ds-stepper-item>
|
|
258
|
+
</ds-stepper>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<div class="vertical-card">
|
|
262
|
+
<span class="v-label">With Content Slot</span>
|
|
263
|
+
<ds-stepper direction="vertical" active-step="1">
|
|
264
|
+
<ds-stepper-item>
|
|
265
|
+
Account Setup
|
|
266
|
+
<div slot="content" style="font: var(--ds-typo-content-caption-regular); color: var(--ds-color-text-secondary); padding: 8px 0;">
|
|
267
|
+
Fill in your account credentials to get started.
|
|
268
|
+
</div>
|
|
269
|
+
</ds-stepper-item>
|
|
270
|
+
<ds-stepper-item>
|
|
271
|
+
Personal Details
|
|
272
|
+
<div slot="content" style="font: var(--ds-typo-content-caption-regular); color: var(--ds-color-text-secondary); padding: 8px 0;">
|
|
273
|
+
Provide your personal information.
|
|
274
|
+
</div>
|
|
275
|
+
</ds-stepper-item>
|
|
276
|
+
<ds-stepper-item>Review</ds-stepper-item>
|
|
277
|
+
</ds-stepper>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
`,
|
|
281
|
+
parameters: {
|
|
282
|
+
docs: {
|
|
283
|
+
description: {
|
|
284
|
+
story: 'Vertical layout variations showing individual item states, error handling, and the content slot for expandable step descriptions.'
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
};
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { LitElement, html, css } from 'lit';
|
|
2
|
+
import { FieldMessageMixin, fieldMessageStyles } from '../mixins/field-message.mixin.js';
|
|
3
|
+
import { FieldLabelMixin, fieldLabelStyles } from '../mixins/field-label.mixin.js';
|
|
4
|
+
import '../ds-icon-button/ds-icon-button.js';
|
|
5
|
+
import '../ds-tooltip/ds-tooltip.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Toggle Switch component for boolean settings.
|
|
9
|
+
*
|
|
10
|
+
* @element ds-switch
|
|
11
|
+
*
|
|
12
|
+
* @prop {boolean} checked - Whether the switch is checked
|
|
13
|
+
* @prop {string} label - Block-level field label (above switch)
|
|
14
|
+
* @prop {string} info - Info tooltip text for info button
|
|
15
|
+
* @prop {string} labelPosition - Label position: 'top' | 'inline-start' (default: 'top')
|
|
16
|
+
* @prop {string} labelWidth - Fixed label width for inline layout (e.g., '100px')
|
|
17
|
+
* @prop {string} statusLabel - Inline state description next to track
|
|
18
|
+
* @prop {string} helpText - Help text below switch
|
|
19
|
+
* @prop {string} errorText - Error text (shown only when validationStatus="error")
|
|
20
|
+
* @prop {string} name - Form name
|
|
21
|
+
* @prop {string} value - Form value (default: 'on')
|
|
22
|
+
* @prop {boolean} disabled - Disabled state
|
|
23
|
+
* @prop {boolean} required - Required field
|
|
24
|
+
* @prop {boolean} standalone - Removes padding for tight layouts
|
|
25
|
+
*
|
|
26
|
+
* @fires change - Fired when state changes
|
|
27
|
+
* @fires info-click - Fired when info button is clicked
|
|
28
|
+
*/
|
|
29
|
+
export class DsSwitch extends FieldMessageMixin(FieldLabelMixin(LitElement)) {
|
|
30
|
+
static properties = {
|
|
31
|
+
checked: { type: Boolean, reflect: true },
|
|
32
|
+
label: { type: String },
|
|
33
|
+
info: { type: String },
|
|
34
|
+
labelPosition: { type: String, attribute: 'label-position' },
|
|
35
|
+
labelWidth: { type: String, attribute: 'label-width' },
|
|
36
|
+
statusLabel: { type: String, attribute: 'status-label' },
|
|
37
|
+
helpText: { type: String, attribute: 'help-text' },
|
|
38
|
+
errorText: { type: String, attribute: 'error-text' },
|
|
39
|
+
name: { type: String },
|
|
40
|
+
value: { type: String },
|
|
41
|
+
disabled: { type: Boolean, reflect: true },
|
|
42
|
+
required: { type: Boolean, reflect: true },
|
|
43
|
+
validationStatus: { type: String, attribute: 'validation-status', reflect: true },
|
|
44
|
+
standalone: { type: Boolean, reflect: true }
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
static styles = [
|
|
48
|
+
fieldLabelStyles,
|
|
49
|
+
fieldMessageStyles,
|
|
50
|
+
css`
|
|
51
|
+
:host {
|
|
52
|
+
display: inline-block;
|
|
53
|
+
outline: none;
|
|
54
|
+
font-family: var(--ds-font-family-content);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.switch-row {
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
padding: var(--ds-size-6) var(--ds-space-sm);
|
|
62
|
+
min-height: var(--ds-size-32);
|
|
63
|
+
box-sizing: border-box;
|
|
64
|
+
transition: background-color 0.2s;
|
|
65
|
+
position: relative;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
:host([standalone]) .switch-row {
|
|
69
|
+
padding: 0;
|
|
70
|
+
min-height: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Hover effect on the whole row */
|
|
74
|
+
:host(:not([disabled])) .switch-row:hover {
|
|
75
|
+
background-color: var(--ds-color-bg-hover);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Focus state - border without offset */
|
|
79
|
+
.switch-row:has(input:focus-visible) {
|
|
80
|
+
outline: 2px solid var(--ds-color-border-focus);
|
|
81
|
+
outline-offset: 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Control Container - 20px height to match label line-height */
|
|
85
|
+
.control-container {
|
|
86
|
+
display: flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
justify-content: center;
|
|
89
|
+
height: var(--ds-size-20);
|
|
90
|
+
flex-shrink: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Hidden Native Input */
|
|
94
|
+
input {
|
|
95
|
+
position: absolute;
|
|
96
|
+
opacity: 0;
|
|
97
|
+
width: 100%;
|
|
98
|
+
height: 100%;
|
|
99
|
+
top: 0;
|
|
100
|
+
left: 0;
|
|
101
|
+
margin: 0;
|
|
102
|
+
cursor: inherit;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* The Track - 32px x 16px */
|
|
106
|
+
.track {
|
|
107
|
+
width: var(--ds-size-32);
|
|
108
|
+
height: var(--ds-size-16);
|
|
109
|
+
border-radius: var(--ds-size-8);
|
|
110
|
+
position: relative;
|
|
111
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
112
|
+
box-sizing: border-box;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Unchecked Track: 2px border icon-default */
|
|
116
|
+
:host(:not([checked])) .track {
|
|
117
|
+
border: 2px solid var(--ds-color-icon-default);
|
|
118
|
+
background-color: transparent;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Checked Track: Solid brand */
|
|
122
|
+
:host([checked]) .track {
|
|
123
|
+
background-color: var(--ds-color-bg-brand);
|
|
124
|
+
border: 2px solid var(--ds-color-bg-brand);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* The Thumb */
|
|
128
|
+
.thumb {
|
|
129
|
+
border-radius: 50%;
|
|
130
|
+
position: absolute;
|
|
131
|
+
top: 50%;
|
|
132
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
133
|
+
box-shadow: none; /* Flat design */
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Unchecked Thumb: 10px x 10px, color icon-default */
|
|
137
|
+
:host(:not([checked])) .thumb {
|
|
138
|
+
width: var(--ds-size-10);
|
|
139
|
+
height: var(--ds-size-10);
|
|
140
|
+
background-color: var(--ds-color-icon-default);
|
|
141
|
+
left: 1px;
|
|
142
|
+
transform: translateY(-50%);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Checked Thumb: 12px x 12px, color bg-default */
|
|
146
|
+
:host([checked]) .thumb {
|
|
147
|
+
width: var(--ds-size-12);
|
|
148
|
+
height: var(--ds-size-12);
|
|
149
|
+
background-color: var(--ds-color-bg-default);
|
|
150
|
+
left: 16px;
|
|
151
|
+
transform: translate(0, -50%);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* Status Label (inline next to track) */
|
|
155
|
+
.status-label {
|
|
156
|
+
margin-inline-start: var(--ds-space-sm);
|
|
157
|
+
font: var(--ds-typo-content-body-regular);
|
|
158
|
+
color: var(--ds-color-text-default);
|
|
159
|
+
user-select: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* ---------------------------------------------------------
|
|
163
|
+
Error State (validation-status="error")
|
|
164
|
+
--------------------------------------------------------- */
|
|
165
|
+
|
|
166
|
+
/* Unchecked Error */
|
|
167
|
+
:host([validation-status="error"]:not([checked])) .track {
|
|
168
|
+
border-color: var(--ds-color-icon-error);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
:host([validation-status="error"]:not([checked])) .thumb {
|
|
172
|
+
background-color: var(--ds-color-icon-error);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Checked Error */
|
|
176
|
+
:host([validation-status="error"][checked]) .track {
|
|
177
|
+
background-color: var(--ds-color-bg-error);
|
|
178
|
+
border-color: var(--ds-color-bg-error);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* ---------------------------------------------------------
|
|
182
|
+
Disabled State
|
|
183
|
+
--------------------------------------------------------- */
|
|
184
|
+
:host([disabled]) .switch-row {
|
|
185
|
+
cursor: not-allowed;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Unchecked Disabled: No background on track, icon-disabled border/thumb */
|
|
189
|
+
:host([disabled]:not([checked])) .track {
|
|
190
|
+
background-color: transparent;
|
|
191
|
+
border-color: var(--ds-color-icon-disabled);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
:host([disabled]:not([checked])) .thumb {
|
|
195
|
+
background-color: var(--ds-color-icon-disabled);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Checked Disabled: icon-disabled track fill, white thumb */
|
|
199
|
+
:host([disabled][checked]) .track {
|
|
200
|
+
background-color: var(--ds-color-icon-disabled);
|
|
201
|
+
border-color: var(--ds-color-icon-disabled);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
:host([disabled][checked]) .thumb {
|
|
205
|
+
background-color: var(--ds-color-bg-default);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
:host([disabled]) .status-label {
|
|
209
|
+
color: var(--ds-color-text-disabled);
|
|
210
|
+
}
|
|
211
|
+
`];
|
|
212
|
+
|
|
213
|
+
constructor() {
|
|
214
|
+
super();
|
|
215
|
+
this.checked = false;
|
|
216
|
+
this.label = '';
|
|
217
|
+
this.info = '';
|
|
218
|
+
this.labelPosition = 'top';
|
|
219
|
+
this.labelWidth = '';
|
|
220
|
+
this.statusLabel = '';
|
|
221
|
+
this.helpText = '';
|
|
222
|
+
this.errorText = '';
|
|
223
|
+
this.name = '';
|
|
224
|
+
this.value = 'on';
|
|
225
|
+
this.disabled = false;
|
|
226
|
+
this.required = false;
|
|
227
|
+
this.standalone = false;
|
|
228
|
+
this.validationStatus = undefined;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
_handleClick(e) {
|
|
232
|
+
if (this.disabled) return;
|
|
233
|
+
|
|
234
|
+
// We prevent default because we handle the state via this.checked
|
|
235
|
+
// The native checkbox will still update but we control it
|
|
236
|
+
e.preventDefault();
|
|
237
|
+
this.checked = !this.checked;
|
|
238
|
+
this._dispatchChange();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
_dispatchChange() {
|
|
242
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
243
|
+
detail: {
|
|
244
|
+
checked: this.checked,
|
|
245
|
+
value: this.value
|
|
246
|
+
},
|
|
247
|
+
bubbles: true,
|
|
248
|
+
composed: true
|
|
249
|
+
}));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
_getAriaLabel() {
|
|
253
|
+
return this.getAttribute('aria-label') || this.statusLabel || this.label || '';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Toggles the switch state programmatically
|
|
258
|
+
* @public
|
|
259
|
+
*/
|
|
260
|
+
toggle() {
|
|
261
|
+
if (this.disabled) return;
|
|
262
|
+
this.checked = !this.checked;
|
|
263
|
+
this._dispatchChange();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Focuses the switch input
|
|
268
|
+
* @public
|
|
269
|
+
*/
|
|
270
|
+
focus() {
|
|
271
|
+
const input = this.shadowRoot?.querySelector('input');
|
|
272
|
+
input?.focus();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
render() {
|
|
276
|
+
const isInline = this.labelPosition === 'inline-start';
|
|
277
|
+
const wrapperClass = isInline ? 'field-wrapper inline-label' : '';
|
|
278
|
+
const labelStyle = isInline && this.labelWidth ? `width: ${this.labelWidth}` : '';
|
|
279
|
+
|
|
280
|
+
const switchContent = html`
|
|
281
|
+
<div class="switch-row" @click="${this._handleClick}">
|
|
282
|
+
<input
|
|
283
|
+
type="checkbox"
|
|
284
|
+
role="switch"
|
|
285
|
+
.checked="${this.checked}"
|
|
286
|
+
?disabled="${this.disabled}"
|
|
287
|
+
?required="${this.required}"
|
|
288
|
+
name="${this.name}"
|
|
289
|
+
value="${this.value}"
|
|
290
|
+
aria-label="${this._getAriaLabel()}"
|
|
291
|
+
aria-checked="${this.checked}"
|
|
292
|
+
>
|
|
293
|
+
|
|
294
|
+
<div class="control-container">
|
|
295
|
+
<div class="track">
|
|
296
|
+
<div class="thumb"></div>
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
|
|
300
|
+
${this.statusLabel ? html`<span class="status-label">${this.statusLabel}</span>` : ''}
|
|
301
|
+
</div>
|
|
302
|
+
${this.validationStatus === 'error'
|
|
303
|
+
? this.renderFieldMessage('', this.errorText)
|
|
304
|
+
: this.renderFieldMessage(this.helpText, '')}
|
|
305
|
+
`;
|
|
306
|
+
|
|
307
|
+
if (isInline) {
|
|
308
|
+
return html`
|
|
309
|
+
<div class="${wrapperClass}">
|
|
310
|
+
<div class="label-row" part="label-row" style="${labelStyle}">
|
|
311
|
+
<label>${this.label}</label>
|
|
312
|
+
${this.info ? html`
|
|
313
|
+
<ds-tooltip content="${this.info}" placement="top">
|
|
314
|
+
<ds-icon-button
|
|
315
|
+
icon="info"
|
|
316
|
+
variant="action"
|
|
317
|
+
size="s"
|
|
318
|
+
aria-label="${this.info}"
|
|
319
|
+
@click=${this._handleInfoClick}
|
|
320
|
+
></ds-icon-button>
|
|
321
|
+
</ds-tooltip>
|
|
322
|
+
` : ''}
|
|
323
|
+
</div>
|
|
324
|
+
<div class="field-content">
|
|
325
|
+
${switchContent}
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
`;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return html`
|
|
332
|
+
${this.renderFieldLabel(this.label, this.info)}
|
|
333
|
+
${switchContent}
|
|
334
|
+
`;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
_handleInfoClick(e) {
|
|
338
|
+
e.preventDefault();
|
|
339
|
+
e.stopPropagation();
|
|
340
|
+
this.dispatchEvent(new CustomEvent('info-click', {
|
|
341
|
+
bubbles: true,
|
|
342
|
+
composed: true,
|
|
343
|
+
detail: { info: this.info }
|
|
344
|
+
}));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
customElements.define('ds-switch', DsSwitch);
|