@kubex/zinc 1.0.25 → 1.0.99
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/.claude/project.md +556 -0
- package/.github/workflows/js_build_and_deploy.yaml +9 -10
- package/dist/custom-elements.json +13575 -8856
- package/dist/vscode.html-custom-data.json +583 -48
- package/dist/web-types.json +1441 -181
- package/dist/zn.d.ts +1645 -660
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +1412 -893
- package/docs/_utilities/code-previews.cjs +10 -1
- package/docs/assets/scripts/docs.js +42 -18
- package/docs/data/data-table.json +229 -66
- package/docs/data/empty.json +6 -0
- package/docs/data/products-table.json +41 -193
- package/docs/pages/components/action-bar.md +121 -6
- package/docs/pages/components/alert.md +118 -15
- package/docs/pages/components/animated-button.md +299 -0
- package/docs/pages/components/audio-select.md +534 -0
- package/docs/pages/components/bulk-actions.md +79 -5
- package/docs/pages/components/button-group.md +235 -27
- package/docs/pages/components/button.md +139 -1
- package/docs/pages/components/chart.md +365 -9
- package/docs/pages/components/checkbox.md +387 -58
- package/docs/pages/components/chip.md +253 -33
- package/docs/pages/components/collapsible.md +393 -46
- package/docs/pages/components/cols.md +152 -30
- package/docs/pages/components/confirm.md +182 -16
- package/docs/pages/components/copy-button.md +169 -6
- package/docs/pages/components/data-select.md +194 -15
- package/docs/pages/components/data-table-filter.md +96 -5
- package/docs/pages/components/data-table-search.md +451 -0
- package/docs/pages/components/data-table-sort.md +66 -5
- package/docs/pages/components/data-table.md +727 -66
- package/docs/pages/components/datepicker.md +402 -7
- package/docs/pages/components/defined-label.md +120 -5
- package/docs/pages/components/dialog.md +339 -59
- package/docs/pages/components/dropdown.md +366 -11
- package/docs/pages/components/editor.md +604 -7
- package/docs/pages/components/empty-state.md +315 -16
- package/docs/pages/components/expanding-action.md +212 -28
- package/docs/pages/components/file.md +421 -12
- package/docs/pages/components/filter-container.md +158 -5
- package/docs/pages/components/filter-wrapper.md +167 -6
- package/docs/pages/components/form-group.md +383 -6
- package/docs/pages/components/hover-container.md +237 -6
- package/docs/pages/components/icon-picker.md +121 -0
- package/docs/pages/components/icon.md +454 -48
- package/docs/pages/components/inline-edit.md +787 -19
- package/docs/pages/components/input-group.md +207 -13
- package/docs/pages/components/input.md +194 -0
- package/docs/pages/components/item.md +18 -0
- package/docs/pages/components/key-container.md +115 -0
- package/docs/pages/components/key.md +101 -0
- package/docs/pages/components/menu.md +512 -6
- package/docs/pages/components/note.md +239 -36
- package/docs/pages/components/opt-group.md +107 -0
- package/docs/pages/components/pagination.md +332 -6
- package/docs/pages/components/pane.md +222 -6
- package/docs/pages/components/panel.md +213 -26
- package/docs/pages/components/popup.md +1354 -6
- package/docs/pages/components/priority-list.md +233 -0
- package/docs/pages/components/progress-bar.md +387 -6
- package/docs/pages/components/radio-group.md +242 -5
- package/docs/pages/components/radio.md +474 -6
- package/docs/pages/components/rating.md +331 -7
- package/docs/pages/components/reveal.md +524 -6
- package/docs/pages/components/scroll-container.md +552 -6
- package/docs/pages/components/select.md +762 -160
- package/docs/pages/components/skeleton.md +473 -30
- package/docs/pages/components/slideout.md +261 -5
- package/docs/pages/components/sp.md +99 -41
- package/docs/pages/components/split-button.md +347 -9
- package/docs/pages/components/split-pane.md +445 -6
- package/docs/pages/components/stat.md +549 -9
- package/docs/pages/components/status-indicator.md +230 -1
- package/docs/pages/components/stepper.md +563 -6
- package/docs/pages/components/tabs.md +439 -13
- package/docs/pages/components/textarea.md +415 -17
- package/docs/pages/components/tile.md +385 -26
- package/docs/pages/components/toggle.md +424 -6
- package/docs/pages/components/tooltip.md +367 -0
- package/docs/pages/components/translation-group.md +210 -0
- package/docs/pages/components/translations.md +319 -19
- package/docs/pages/components/vertical-stepper.md +401 -8
- package/docs/pages/components/well.md +300 -3
- package/docs/pages/getting-started/form-controls.md +162 -0
- package/docs/pages/index.md +116 -15
- package/package.json +5 -6
- package/scss/_global-spacing.scss +4 -0
- package/scss/_root.scss +2 -2
- package/scss/boot.scss +19 -0
- package/scss/shared/layout.scss +5 -0
- package/scss/themes/_light.scss +3 -3
- package/src/components/alert/alert.scss +1 -0
- package/src/components/animated-button/README.md +306 -0
- package/src/components/animated-button/animated-button.component.ts +229 -0
- package/src/components/animated-button/animated-button.scss +228 -0
- package/src/components/animated-button/animated-button.test.ts +143 -0
- package/src/components/animated-button/index.ts +12 -0
- package/src/components/button/button.component.ts +5 -0
- package/src/components/button-group/button-group.component.ts +25 -13
- package/src/components/button-group/button-group.scss +6 -0
- package/src/components/checkbox/checkbox.component.ts +4 -0
- package/src/components/checkbox/checkbox.scss +7 -4
- package/src/components/checkbox-group/checkbox-group.scss +7 -0
- package/src/components/chip/chip.component.ts +7 -2
- package/src/components/chip/chip.scss +16 -2
- package/src/components/collapsible/collapsible.component.ts +27 -20
- package/src/components/cols/cols.component.ts +14 -2
- package/src/components/cols/cols.scss +6 -12
- package/src/components/confirm/confirm.component.ts +7 -0
- package/src/components/copy-button/copy-button.component.ts +12 -11
- package/src/components/data-select/data-select.component.ts +215 -44
- package/src/components/data-select/data-select.scss +66 -6
- package/src/components/data-select/providers/currency-data-provider.ts +20 -6
- package/src/components/data-select/providers/provider.ts +1 -0
- package/src/components/data-select/providers/us-state-data-provider.ts +68 -0
- package/src/components/data-table/data-table.component.ts +81 -22
- package/src/components/data-table-search/data-table-search.component.ts +184 -0
- package/src/components/data-table-search/data-table-search.scss +17 -0
- package/src/components/data-table-search/data-table-search.test.ts +11 -0
- package/src/components/data-table-search/index.ts +12 -0
- package/src/components/datepicker/datepicker.component.ts +347 -13
- package/src/components/dialog/dialog.component.ts +1 -1
- package/src/components/empty-state/empty-state.scss +6 -1
- package/src/components/header/header.scss +3 -3
- package/src/components/icon/icon.component.ts +23 -1
- package/src/components/icon/icon.scss +23 -0
- package/src/components/icon-picker/brand-icons.ts +24 -0
- package/src/components/icon-picker/icon-picker.component.ts +407 -0
- package/src/components/icon-picker/icon-picker.scss +205 -0
- package/src/components/icon-picker/index.ts +12 -0
- package/src/components/icon-picker/line-icons.ts +612 -0
- package/src/components/icon-picker/material-icons.ts +14543 -0
- package/src/components/inline-edit/inline-edit.component.ts +190 -46
- package/src/components/inline-edit/inline-edit.scss +29 -0
- package/src/components/inline-edit/inline-edit.test.ts +314 -1
- package/src/components/input/input.component.ts +324 -5
- package/src/components/input/input.scss +87 -0
- package/src/components/input-group/input-group.component.ts +28 -7
- package/src/components/input-group/input-group.scss +48 -10
- package/src/components/item/item.component.ts +24 -3
- package/src/components/item/item.scss +18 -0
- package/src/components/key/index.ts +12 -0
- package/src/components/key/key.component.ts +47 -0
- package/src/components/key/key.scss +38 -0
- package/src/components/key-container/index.ts +12 -0
- package/src/components/key-container/key-container.component.ts +142 -0
- package/src/components/key-container/key-container.scss +33 -0
- package/src/components/menu-item/menu-item.component.ts +20 -0
- package/src/components/menu-item/menu-item.scss +69 -2
- package/src/components/navbar/navbar.component.ts +103 -11
- package/src/components/navbar/navbar.scss +6 -1
- package/src/components/opt-group/index.ts +12 -0
- package/src/components/opt-group/opt-group.component.ts +74 -0
- package/src/components/opt-group/opt-group.scss +37 -0
- package/src/components/opt-group/opt-group.test.ts +27 -0
- package/src/components/option/option.component.ts +1 -16
- package/src/components/option/option.scss +4 -0
- package/src/components/panel/panel.component.ts +10 -8
- package/src/components/panel/panel.scss +20 -0
- package/src/components/priority-list/index.ts +12 -0
- package/src/components/priority-list/priority-list.component.ts +611 -0
- package/src/components/priority-list/priority-list.scss +185 -0
- package/src/components/priority-list/priority-list.test.ts +139 -0
- package/src/components/progress-bar/progress-bar.component.ts +22 -16
- package/src/components/radio/radio.scss +10 -3
- package/src/components/select/select.component.ts +812 -72
- package/src/components/select/select.scss +108 -2
- package/src/components/select/select.test.ts +147 -2
- package/src/components/settings-container/settings-container.component.ts +44 -19
- package/src/components/settings-container/settings-container.scss +1 -1
- package/src/components/skeleton/skeleton.component.ts +6 -1
- package/src/components/slideout/slideout.scss +8 -3
- package/src/components/sp/sp.component.ts +3 -1
- package/src/components/sp/sp.scss +19 -0
- package/src/components/stepper/stepper.component.ts +16 -10
- package/src/components/textarea/textarea.scss +0 -4
- package/src/components/tile/tile.component.ts +12 -3
- package/src/components/tile/tile.scss +1 -1
- package/src/components/timer/timer.component.ts +15 -2
- package/src/components/toggle/toggle.component.ts +29 -26
- package/src/components/toggle/toggle.scss +13 -1
- package/src/components/translation-group/index.ts +12 -0
- package/src/components/translation-group/translation-group.component.ts +207 -0
- package/src/components/translation-group/translation-group.scss +8 -0
- package/src/components/translations/translations.component.ts +90 -44
- package/src/components/translations/translations.scss +4 -0
- package/src/components/vertical-stepper/vertical-stepper.component.ts +14 -9
- package/src/events/events.ts +12 -7
- package/src/events/zn-language-change.ts +7 -0
- package/src/events/zn-purchase.ts +11 -0
- package/src/events/zn-redirect.ts +7 -0
- package/src/events/zn-reorder.ts +7 -0
- package/src/events/zn-search-change.ts +11 -0
- package/src/events/zn-submit.ts +1 -1
- package/src/form-control.scss +4 -0
- package/src/internal/form-navigation.ts +510 -0
- package/src/internal/form.ts +6 -0
- package/src/zinc.ts +91 -83
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
@use "../../../scss/shared";
|
|
2
|
+
|
|
3
|
+
:host {
|
|
4
|
+
display: inline-block;
|
|
5
|
+
cursor: pointer;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
:host([disabled]) {
|
|
9
|
+
cursor: wait;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.animated-button {
|
|
13
|
+
@include shared.button;
|
|
14
|
+
position: relative;
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
min-width: 150px;
|
|
17
|
+
min-height: 40px;
|
|
18
|
+
gap: 8px;
|
|
19
|
+
transition:
|
|
20
|
+
transform var(--zn-transition-fast) ease,
|
|
21
|
+
opacity var(--zn-transition-fast) ease;
|
|
22
|
+
border: none;
|
|
23
|
+
font-size: 1rem;
|
|
24
|
+
font-family: inherit;
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
|
|
27
|
+
&:hover:not(:disabled) {
|
|
28
|
+
opacity: 0.9;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&:active:not(:disabled) {
|
|
32
|
+
transform: scale(0.98);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&:disabled {
|
|
36
|
+
cursor: wait;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&:focus-visible {
|
|
40
|
+
outline: 2px solid rgb(var(--zn-primary));
|
|
41
|
+
outline-offset: 2px;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.animated-button__content {
|
|
46
|
+
display: inline-flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
gap: 8px;
|
|
50
|
+
position: relative;
|
|
51
|
+
z-index: 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.animated-button__text {
|
|
55
|
+
font-weight: 600;
|
|
56
|
+
line-height: 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.animated-button__icon {
|
|
60
|
+
display: inline-flex;
|
|
61
|
+
flex-shrink: 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.animated-button__spinner {
|
|
65
|
+
display: inline-flex;
|
|
66
|
+
flex-shrink: 0;
|
|
67
|
+
animation: spin 1s linear infinite;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@keyframes spin {
|
|
71
|
+
from {
|
|
72
|
+
transform: rotate(0deg);
|
|
73
|
+
}
|
|
74
|
+
to {
|
|
75
|
+
transform: rotate(360deg);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Shimmer animation for processing state
|
|
80
|
+
.animated-button__shimmer {
|
|
81
|
+
position: absolute;
|
|
82
|
+
top: 0;
|
|
83
|
+
left: -100%;
|
|
84
|
+
width: 100%;
|
|
85
|
+
height: 100%;
|
|
86
|
+
background: linear-gradient(
|
|
87
|
+
90deg,
|
|
88
|
+
rgba(255, 255, 255, 0) 0%,
|
|
89
|
+
rgba(255, 255, 255, 0.3) 50%,
|
|
90
|
+
rgba(255, 255, 255, 0) 100%
|
|
91
|
+
);
|
|
92
|
+
animation: shimmer 1.5s infinite;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@keyframes shimmer {
|
|
96
|
+
0% {
|
|
97
|
+
left: -100%;
|
|
98
|
+
}
|
|
99
|
+
100% {
|
|
100
|
+
left: 100%;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// State: Idle (default blue)
|
|
105
|
+
.animated-button--idle {
|
|
106
|
+
background-color: rgb(var(--zn-primary)) !important;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// State: Processing (blue with shimmer)
|
|
110
|
+
.animated-button--processing {
|
|
111
|
+
background-color: rgb(var(--zn-primary)) !important;
|
|
112
|
+
cursor: wait;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// State: Success (green with fill animation)
|
|
116
|
+
.animated-button--success {
|
|
117
|
+
background-color: rgb(var(--zn-primary)) !important;
|
|
118
|
+
cursor: default;
|
|
119
|
+
|
|
120
|
+
&::before {
|
|
121
|
+
content: '';
|
|
122
|
+
position: absolute;
|
|
123
|
+
top: 0;
|
|
124
|
+
left: 0;
|
|
125
|
+
width: 100%;
|
|
126
|
+
height: 100%;
|
|
127
|
+
background-color: rgb(var(--zn-color-success));
|
|
128
|
+
animation: successFill var(--zn-transition-slow) ease-out forwards;
|
|
129
|
+
z-index: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.animated-button__content {
|
|
133
|
+
z-index: 1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.animated-button__icon--success {
|
|
137
|
+
opacity: 0;
|
|
138
|
+
animation: iconFadeIn 0.3s ease-out 0.4s forwards;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.animated-button__tick {
|
|
142
|
+
stroke-dasharray: 30;
|
|
143
|
+
stroke-dashoffset: 30;
|
|
144
|
+
animation: tickSwoosh 0.5s ease-out 0.4s forwards;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@keyframes successFill {
|
|
149
|
+
0% {
|
|
150
|
+
transform: translateY(100%);
|
|
151
|
+
}
|
|
152
|
+
100% {
|
|
153
|
+
transform: translateY(0);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@keyframes iconFadeIn {
|
|
158
|
+
to {
|
|
159
|
+
opacity: 1;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@keyframes tickSwoosh {
|
|
164
|
+
0% {
|
|
165
|
+
stroke-dashoffset: 30;
|
|
166
|
+
}
|
|
167
|
+
100% {
|
|
168
|
+
stroke-dashoffset: 0;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// State: Failure (red)
|
|
173
|
+
.animated-button--failure {
|
|
174
|
+
background-color: rgb(var(--zn-color-error)) !important;
|
|
175
|
+
cursor: not-allowed;
|
|
176
|
+
|
|
177
|
+
.animated-button__icon--failure {
|
|
178
|
+
animation: failureShake var(--zn-transition-medium) ease-out;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@keyframes failureShake {
|
|
183
|
+
0%,
|
|
184
|
+
100% {
|
|
185
|
+
transform: translateX(0);
|
|
186
|
+
}
|
|
187
|
+
25% {
|
|
188
|
+
transform: translateX(-4px);
|
|
189
|
+
}
|
|
190
|
+
75% {
|
|
191
|
+
transform: translateX(4px);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Respect user's motion preferences
|
|
196
|
+
@media (prefers-reduced-motion: reduce) {
|
|
197
|
+
.animated-button {
|
|
198
|
+
transition: none;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.animated-button--success::before {
|
|
202
|
+
animation: none;
|
|
203
|
+
transform: translateY(0);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.animated-button__shimmer {
|
|
207
|
+
animation: none;
|
|
208
|
+
display: none;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.animated-button__spinner {
|
|
212
|
+
animation: none;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.animated-button__icon--success {
|
|
216
|
+
animation: none;
|
|
217
|
+
opacity: 1;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.animated-button__tick {
|
|
221
|
+
animation: none;
|
|
222
|
+
stroke-dashoffset: 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.animated-button__icon--failure {
|
|
226
|
+
animation: none;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import '../../../dist/zn.min.js';
|
|
2
|
+
import { expect, fixture, html, waitUntil } from '@open-wc/testing';
|
|
3
|
+
import type ZnAnimatedButton from './animated-button.component';
|
|
4
|
+
|
|
5
|
+
describe('<zn-animated-button>', () => {
|
|
6
|
+
it('should be accessible', async () => {
|
|
7
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button></zn-animated-button>`);
|
|
8
|
+
await expect(el).to.be.accessible();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should render with default idle text', async () => {
|
|
12
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button></zn-animated-button>`);
|
|
13
|
+
const button = el.shadowRoot?.querySelector('button');
|
|
14
|
+
expect(button?.textContent?.trim()).to.equal('Purchase');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should render with custom idle text', async () => {
|
|
18
|
+
const el = await fixture<ZnAnimatedButton>(
|
|
19
|
+
html`<zn-animated-button idle-text="Buy Now"></zn-animated-button>`
|
|
20
|
+
);
|
|
21
|
+
const button = el.shadowRoot?.querySelector('button');
|
|
22
|
+
expect(button?.textContent?.trim()).to.equal('Buy Now');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should be disabled when processing', async () => {
|
|
26
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button></zn-animated-button>`);
|
|
27
|
+
const button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
|
|
28
|
+
|
|
29
|
+
expect(button.disabled).to.be.false;
|
|
30
|
+
|
|
31
|
+
button.click();
|
|
32
|
+
await el.updateComplete;
|
|
33
|
+
|
|
34
|
+
expect(button.disabled).to.be.true;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should emit zn-purchase event when clicked', async () => {
|
|
38
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button></zn-animated-button>`);
|
|
39
|
+
const button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
|
|
40
|
+
|
|
41
|
+
let eventFired = false;
|
|
42
|
+
el.addEventListener('zn-purchase', () => {
|
|
43
|
+
eventFired = true;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
button.click();
|
|
47
|
+
await el.updateComplete;
|
|
48
|
+
|
|
49
|
+
expect(eventFired).to.be.true;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should transition to success state when setSuccess is called', async () => {
|
|
53
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button></zn-animated-button>`);
|
|
54
|
+
|
|
55
|
+
el.setSuccess();
|
|
56
|
+
await el.updateComplete;
|
|
57
|
+
|
|
58
|
+
const button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
|
|
59
|
+
expect(button.classList.contains('purchase-button--success')).to.be.true;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should transition to failure state when setFailure is called', async () => {
|
|
63
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button></zn-animated-button>`);
|
|
64
|
+
|
|
65
|
+
el.setFailure('Payment failed');
|
|
66
|
+
await el.updateComplete;
|
|
67
|
+
|
|
68
|
+
const button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
|
|
69
|
+
expect(button.classList.contains('purchase-button--failure')).to.be.true;
|
|
70
|
+
expect(button.textContent).to.include('Payment failed');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should reset to idle state after failure timeout', async () => {
|
|
74
|
+
const el = await fixture<ZnAnimatedButton>(
|
|
75
|
+
html`<zn-animated-button failure-reset-delay="100"></zn-animated-button>`
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
el.setFailure('Error');
|
|
79
|
+
await el.updateComplete;
|
|
80
|
+
|
|
81
|
+
let button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
|
|
82
|
+
expect(button.classList.contains('purchase-button--failure')).to.be.true;
|
|
83
|
+
|
|
84
|
+
await waitUntil(
|
|
85
|
+
() => {
|
|
86
|
+
button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
|
|
87
|
+
return button.classList.contains('purchase-button--idle');
|
|
88
|
+
},
|
|
89
|
+
'',
|
|
90
|
+
{ timeout: 500 }
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
expect(button.classList.contains('purchase-button--idle')).to.be.true;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should show spinner icon in processing state', async () => {
|
|
97
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button></zn-animated-button>`);
|
|
98
|
+
|
|
99
|
+
const button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
|
|
100
|
+
button.click();
|
|
101
|
+
await el.updateComplete;
|
|
102
|
+
|
|
103
|
+
const spinner = el.shadowRoot?.querySelector('.purchase-button__spinner');
|
|
104
|
+
expect(spinner).to.exist;
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should show success icon in success state', async () => {
|
|
108
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button></zn-animated-button>`);
|
|
109
|
+
|
|
110
|
+
el.setSuccess();
|
|
111
|
+
await el.updateComplete;
|
|
112
|
+
|
|
113
|
+
const successIcon = el.shadowRoot?.querySelector('.purchase-button__icon--success');
|
|
114
|
+
expect(successIcon).to.exist;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should show failure icon in failure state', async () => {
|
|
118
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button></zn-animated-button>`);
|
|
119
|
+
|
|
120
|
+
el.setFailure();
|
|
121
|
+
await el.updateComplete;
|
|
122
|
+
|
|
123
|
+
const failureIcon = el.shadowRoot?.querySelector('.purchase-button__icon--failure');
|
|
124
|
+
expect(failureIcon).to.exist;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should respect disabled attribute', async () => {
|
|
128
|
+
const el = await fixture<ZnAnimatedButton>(html`<zn-animated-button disabled></zn-animated-button>`);
|
|
129
|
+
|
|
130
|
+
const button = el.shadowRoot?.querySelector('button') as HTMLButtonElement;
|
|
131
|
+
expect(button.disabled).to.be.true;
|
|
132
|
+
|
|
133
|
+
let eventFired = false;
|
|
134
|
+
el.addEventListener('zn-purchase', () => {
|
|
135
|
+
eventFired = true;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
button.click();
|
|
139
|
+
await el.updateComplete;
|
|
140
|
+
|
|
141
|
+
expect(eventFired).to.be.false;
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ZnAnimatedButton from './animated-button.component';
|
|
2
|
+
|
|
3
|
+
export * from './animated-button.component';
|
|
4
|
+
export default ZnAnimatedButton;
|
|
5
|
+
|
|
6
|
+
ZnAnimatedButton.define('zn-animated-button');
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface HTMLElementTagNameMap {
|
|
10
|
+
'zn-animated-button': ZnAnimatedButton;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -206,6 +206,11 @@ export default class ZnButton extends ZincElement implements ZincFormControl {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
// Override native HTMLButtonElement click method
|
|
210
|
+
click() {
|
|
211
|
+
this.handleClick()
|
|
212
|
+
}
|
|
213
|
+
|
|
209
214
|
handleClick = () => {
|
|
210
215
|
if (this.disabled) {
|
|
211
216
|
return;
|
|
@@ -38,22 +38,34 @@ export default class ZnButtonGroup extends ZincElement {
|
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
const allSlotted = [...this.defaultSlot.assignedElements({flatten: true})] as HTMLElement[];
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
// Collect buttons from direct zn-button elements and from zn-dropdown wrappers
|
|
44
|
+
const groupItems: {button: HTMLElement; wrapper?: HTMLElement}[] = [];
|
|
45
|
+
for (const el of allSlotted) {
|
|
46
|
+
if (el.tagName === 'ZN-BUTTON') {
|
|
47
|
+
groupItems.push({button: el});
|
|
48
|
+
} else if (el.tagName === 'ZN-DROPDOWN') {
|
|
49
|
+
const innerButton = el.querySelector('zn-button');
|
|
50
|
+
if (innerButton) {
|
|
51
|
+
groupItems.push({button: innerButton, wrapper: el});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
47
55
|
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
groupItems.forEach(({button, wrapper}, index) => {
|
|
57
|
+
button.toggleAttribute('data-zn-button-group__button--grow', this.grow);
|
|
50
58
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
if (!this.gap) {
|
|
60
|
+
button.toggleAttribute('data-zn-button-group__button', true);
|
|
61
|
+
button.toggleAttribute('data-zn-button-group__button--first', index === 0);
|
|
62
|
+
button.toggleAttribute('data-zn-button-group__button--inner', index > 0 && index < groupItems.length - 1);
|
|
63
|
+
button.toggleAttribute('data-zn-button-group__button--last', index === groupItems.length - 1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Mark the dropdown wrapper so it can be styled to not break the group layout
|
|
67
|
+
if (wrapper) {
|
|
68
|
+
wrapper.toggleAttribute('data-zn-button-group__dropdown', true);
|
|
57
69
|
}
|
|
58
70
|
});
|
|
59
71
|
}
|
|
@@ -23,6 +23,12 @@
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// Ensure dropdown wrappers inside button-group participate in the flex layout
|
|
27
|
+
// without introducing gaps. The data attribute is set by the component logic.
|
|
28
|
+
::slotted([data-zn-button-group__dropdown]) {
|
|
29
|
+
display: inline-flex !important;
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
:host([direction="vertical"]),
|
|
27
33
|
zn-button-group[direction="vertical"] {
|
|
28
34
|
width: 100%;
|
|
@@ -88,6 +88,9 @@ export default class ZnCheckbox extends ZincElement implements ZincFormControl {
|
|
|
88
88
|
/** Draws a container around the checkbox. */
|
|
89
89
|
@property({type: Boolean, reflect: true}) contained = false;
|
|
90
90
|
|
|
91
|
+
/** Removes a container around the checkbox. */
|
|
92
|
+
@property({type: Boolean, reflect: true}) borderless = false;
|
|
93
|
+
|
|
91
94
|
/** Applies styles relevant to checkboxes in a horizontal layout. */
|
|
92
95
|
@property({type: Boolean, reflect: true}) horizontal = false;
|
|
93
96
|
|
|
@@ -292,6 +295,7 @@ export default class ZnCheckbox extends ZincElement implements ZincFormControl {
|
|
|
292
295
|
'checkbox--focused': this.hasFocus,
|
|
293
296
|
'checkbox--indeterminate': this.indeterminate,
|
|
294
297
|
'checkbox--contained': this.contained,
|
|
298
|
+
'checkbox--no-border': this.borderless,
|
|
295
299
|
'checkbox--horizontal': this.horizontal,
|
|
296
300
|
'checkbox--small': this.size === 'small',
|
|
297
301
|
'checkbox--medium': this.size === 'medium',
|
|
@@ -142,7 +142,6 @@
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
.svg-icon {
|
|
145
|
-
width: max(16px, 70%);
|
|
146
145
|
height: max(16px, 70%);
|
|
147
146
|
--icon-color: var(--checkbox-icon-color);
|
|
148
147
|
|
|
@@ -251,6 +250,12 @@
|
|
|
251
250
|
-webkit-user-select: none;
|
|
252
251
|
}
|
|
253
252
|
|
|
253
|
+
.checkbox--no-border {
|
|
254
|
+
border: none !important;
|
|
255
|
+
outline: none !important;
|
|
256
|
+
border-radius: 0 !important;
|
|
257
|
+
}
|
|
258
|
+
|
|
254
259
|
/* Contained */
|
|
255
260
|
.checkbox--contained {
|
|
256
261
|
padding: 1.375rem var(--zn-spacing-large) 1.375rem var(--zn-spacing-medium);
|
|
@@ -291,9 +296,7 @@
|
|
|
291
296
|
.checkbox__control {
|
|
292
297
|
height: 100%;
|
|
293
298
|
width: 100%;
|
|
294
|
-
border
|
|
295
|
-
border-top: unset;
|
|
296
|
-
border-bottom: unset;
|
|
299
|
+
border: unset;
|
|
297
300
|
box-shadow: unset;
|
|
298
301
|
background-color: var(--zn-color-purple-50);
|
|
299
302
|
}
|
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
:host([horizontal]) .form-control-input {
|
|
10
10
|
display: flex;
|
|
11
11
|
column-gap: var(--zn-spacing-2x-large);
|
|
12
|
+
flex-wrap: wrap;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
::slotted(zn-checkbox[horizontal]) {
|
|
16
|
+
flex-basis: 20%;
|
|
17
|
+
min-width: 100px;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
:host([contained]) .form-control-input {
|
|
@@ -36,6 +42,7 @@
|
|
|
36
42
|
height: 100%;
|
|
37
43
|
}
|
|
38
44
|
|
|
45
|
+
|
|
39
46
|
.form-control {
|
|
40
47
|
position: relative;
|
|
41
48
|
border: none;
|
|
@@ -27,6 +27,9 @@ export default class ZnChip extends ZincElement {
|
|
|
27
27
|
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
28
28
|
|
|
29
29
|
@property() icon: string = '';
|
|
30
|
+
@property() caption: string = '';
|
|
31
|
+
|
|
32
|
+
@property({attribute: 'icon-size', type: Number}) iconSize: number = 18;
|
|
30
33
|
|
|
31
34
|
@property() type: 'info' | 'success' | 'warning' | 'error' | 'primary' |
|
|
32
35
|
'transparent' | 'custom' | 'neutral' = 'neutral';
|
|
@@ -63,9 +66,11 @@ export default class ZnChip extends ZincElement {
|
|
|
63
66
|
'chip--large': this.size === 'large',
|
|
64
67
|
})}">
|
|
65
68
|
${this.icon ? html`
|
|
66
|
-
<zn-icon src="${this.icon}" size="
|
|
69
|
+
<zn-icon src="${this.icon}" size="${this.iconSize}"></zn-icon>` : ''}
|
|
70
|
+
${this.caption ? html`
|
|
71
|
+
<span class="chip__caption">${this.caption}</span>` : ''}
|
|
67
72
|
${hasContent ? html`
|
|
68
|
-
<slot></slot>` : ''}
|
|
73
|
+
<span class="chip__value"><slot></slot></span>` : ''}
|
|
69
74
|
${this.hasSlotController.test('action') ? html`
|
|
70
75
|
<slot name="action" class="chip__action"></slot>` : ''}
|
|
71
76
|
</div>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
:host {
|
|
4
4
|
display: inline-block;
|
|
5
|
+
vertical-align: middle;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
.chip {
|
|
@@ -13,11 +14,11 @@
|
|
|
13
14
|
gap: 4px;
|
|
14
15
|
width: fit-content;
|
|
15
16
|
margin: 1px;
|
|
16
|
-
text-transform: capitalize;
|
|
17
17
|
justify-content: center;
|
|
18
18
|
align-items: center;
|
|
19
19
|
border: 1px solid transparent;
|
|
20
20
|
line-height: 24px;
|
|
21
|
+
white-space: nowrap;
|
|
21
22
|
|
|
22
23
|
&--flush {
|
|
23
24
|
padding: 0;
|
|
@@ -80,8 +81,21 @@
|
|
|
80
81
|
background-color: hsl(from var(--chip-color-override, inherit) h s l / 0.1);
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
.chip__value {
|
|
85
|
+
overflow: hidden;
|
|
86
|
+
text-overflow: ellipsis;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.chip__caption {
|
|
90
|
+
opacity: 0.7;
|
|
91
|
+
font-weight: 600;
|
|
92
|
+
|
|
93
|
+
&::after {
|
|
94
|
+
content: ":";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
83
98
|
.chip__action {
|
|
84
|
-
text-transform: unset;
|
|
85
99
|
}
|
|
86
100
|
|
|
87
101
|
.chip--small {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import {classMap} from "lit/directives/class-map.js";
|
|
2
|
+
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
3
|
+
import {HasSlotController} from "../../internal/slot";
|
|
4
|
+
import {property, state} from 'lit/decorators.js';
|
|
5
|
+
import {Store} from "../../internal/storage";
|
|
6
6
|
import ZincElement from '../../internal/zinc-element';
|
|
7
|
+
import type {ZnInputEvent} from "../../events/zn-input";
|
|
8
|
+
import type ZnToggle from "../toggle";
|
|
7
9
|
|
|
8
10
|
import styles from './collapsible.scss';
|
|
9
|
-
import { ZnInputEvent } from "../../events/zn-input";
|
|
10
|
-
import ZnToggle from "../toggle";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @summary Toggles between showing and hiding content when clicked
|
|
@@ -23,28 +23,28 @@ import ZnToggle from "../toggle";
|
|
|
23
23
|
export default class ZnCollapsible extends ZincElement {
|
|
24
24
|
static styles: CSSResultGroup = unsafeCSS(styles);
|
|
25
25
|
|
|
26
|
-
@property({
|
|
26
|
+
@property({reflect: true}) caption = '';
|
|
27
27
|
|
|
28
|
-
@property({
|
|
28
|
+
@property({reflect: true}) description: string;
|
|
29
29
|
|
|
30
|
-
@property({
|
|
30
|
+
@property({reflect: true}) label = '';
|
|
31
31
|
|
|
32
|
-
@property({
|
|
32
|
+
@property({type: Boolean, attribute: 'show-number', reflect: true}) showNumber: boolean = false;
|
|
33
33
|
|
|
34
34
|
// what element name to count
|
|
35
|
-
@property({
|
|
35
|
+
@property({type: String, attribute: 'count-element'}) countElement: string = '*';
|
|
36
36
|
|
|
37
|
-
@property({
|
|
37
|
+
@property({type: Boolean, reflect: true}) expanded: boolean = false;
|
|
38
38
|
|
|
39
|
-
@property({
|
|
39
|
+
@property({attribute: 'default'}) defaultState: 'open' | 'closed';
|
|
40
40
|
|
|
41
|
-
@property({
|
|
41
|
+
@property({attribute: 'local-storage', type: Boolean, reflect: true}) localStorage: boolean;
|
|
42
42
|
|
|
43
|
-
@property({
|
|
43
|
+
@property({attribute: 'store-key', reflect: true}) storeKey: string = "";
|
|
44
44
|
|
|
45
|
-
@property({
|
|
45
|
+
@property({attribute: 'store-ttl', type: Number, reflect: true}) storeTtl = 0;
|
|
46
46
|
|
|
47
|
-
@property({
|
|
47
|
+
@property({attribute: 'flush', type: Boolean, reflect: true}) flush: boolean = false;
|
|
48
48
|
|
|
49
49
|
@state() numberOfItems: number = 0;
|
|
50
50
|
|
|
@@ -74,7 +74,7 @@ export default class ZnCollapsible extends ZincElement {
|
|
|
74
74
|
this.observer = new MutationObserver(() => {
|
|
75
75
|
this.recalculateNumberOfItems();
|
|
76
76
|
});
|
|
77
|
-
this.observer.observe(slot, {
|
|
77
|
+
this.observer.observe(slot, {childList: true, subtree: true});
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
await this.updateComplete;
|
|
@@ -99,6 +99,13 @@ export default class ZnCollapsible extends ZincElement {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
protected updated(changedProperties: PropertyValues) {
|
|
103
|
+
super.updated(changedProperties);
|
|
104
|
+
if (changedProperties.has('expanded') && this.storeKey) {
|
|
105
|
+
this._store.set(this.storeKey, this.expanded.toString());
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
102
109
|
disconnectedCallback() {
|
|
103
110
|
super.disconnectedCallback();
|
|
104
111
|
if (this.observer) {
|
|
@@ -150,7 +157,7 @@ export default class ZnCollapsible extends ZincElement {
|
|
|
150
157
|
<slot name="label"><p class="label">${this.label}</p></slot>
|
|
151
158
|
${this.showNumber && !this.expanded ? html`
|
|
152
159
|
<zn-chip size="small" type="primary">${this.numberOfItems}</zn-chip>` : ''}
|
|
153
|
-
${this.showArrow
|
|
160
|
+
${this.showArrow ? html`
|
|
154
161
|
<zn-icon library="material-outlined" src="expand_more" class="expand"></zn-icon>` : ''}
|
|
155
162
|
</div>
|
|
156
163
|
</slot>
|