@pure-ds/storybook 0.3.19 → 0.4.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/.storybook/addons/pds-configurator/SearchTool.js +44 -44
- package/dist/pds-reference.json +65 -13
- package/package.json +50 -50
- package/stories/components/PdsCalendar.stories.js +266 -263
- package/stories/components/PdsDrawer.stories.js +2 -2
- package/stories/components/PdsIcon.stories.js +2 -2
- package/stories/components/PdsJsonform.stories.js +2 -2
- package/stories/components/PdsRichtext.stories.js +367 -367
- package/stories/components/PdsScrollrow.stories.js +140 -140
- package/stories/components/PdsSplitpanel.stories.js +502 -502
- package/stories/components/PdsTabstrip.stories.js +2 -2
- package/stories/components/PdsToaster.stories.js +186 -186
- package/stories/components/PdsUpload.stories.js +66 -66
- package/stories/enhancements/Dropdowns.stories.js +185 -185
- package/stories/enhancements/InteractiveStates.stories.js +625 -625
- package/stories/enhancements/MeshGradients.stories.js +321 -320
- package/stories/enhancements/OpenGroups.stories.js +227 -227
- package/stories/enhancements/RangeSliders.stories.js +232 -232
- package/stories/enhancements/RequiredFields.stories.js +189 -189
- package/stories/enhancements/Toggles.stories.js +167 -167
- package/stories/foundations/Colors.stories.js +2 -1
- package/stories/foundations/Icons.stories.js +4 -0
- package/stories/foundations/SmartSurfaces.stories.js +485 -367
- package/stories/foundations/Spacing.stories.js +5 -1
- package/stories/foundations/Typography.stories.js +4 -0
- package/stories/foundations/ZIndex.stories.js +329 -325
- package/stories/layout/LayoutOverview.stories.js +247 -0
- package/stories/layout/LayoutSystem.stories.js +852 -0
- package/stories/patterns/BorderEffects.stories.js +74 -72
- package/stories/primitives/Accordion.stories.js +5 -3
- package/stories/primitives/Alerts.stories.js +261 -46
- package/stories/primitives/Badges.stories.js +4 -0
- package/stories/primitives/Buttons.stories.js +2 -2
- package/stories/primitives/Cards.stories.js +98 -170
- package/stories/primitives/Media.stories.js +442 -203
- package/stories/primitives/Tables.stories.js +358 -232
- package/stories/utilities/Backdrop.stories.js +197 -0
- package/stories/patterns/Layout.stories.js +0 -99
- package/stories/utilities/GridSystem.stories.js +0 -208
|
@@ -1,625 +1,625 @@
|
|
|
1
|
-
import { html } from 'lit';
|
|
2
|
-
|
|
3
|
-
const interactiveSkeletonStoryStyles = html`
|
|
4
|
-
<style>
|
|
5
|
-
.interactive-skeleton-card {
|
|
6
|
-
display: grid;
|
|
7
|
-
gap: var(--spacing-3);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.interactive-skeleton-block {
|
|
11
|
-
display: block;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.interactive-skeleton-height-24 {
|
|
15
|
-
height: 1.5rem;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.interactive-skeleton-height-20 {
|
|
19
|
-
height: 1.25rem;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.interactive-skeleton-height-16 {
|
|
23
|
-
height: 1rem;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.interactive-skeleton-height-14 {
|
|
27
|
-
height: 0.875rem;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.interactive-skeleton-width-60 {
|
|
31
|
-
width: 60%;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.interactive-skeleton-width-80 {
|
|
35
|
-
width: 80%;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.interactive-skeleton-width-70 {
|
|
39
|
-
width: 70%;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.interactive-skeleton-width-50 {
|
|
43
|
-
width: 50%;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.interactive-skeleton-width-40 {
|
|
47
|
-
width: 40%;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.interactive-skeleton-width-85 {
|
|
51
|
-
width: 85%;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.interactive-skeleton-margin-lg {
|
|
55
|
-
margin-bottom: var(--spacing-3);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.interactive-skeleton-margin-md {
|
|
59
|
-
margin-bottom: var(--spacing-2);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.interactive-skeleton-avatar {
|
|
63
|
-
width: 2.5rem;
|
|
64
|
-
height: 2.5rem;
|
|
65
|
-
border-radius: 50%;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.interactive-skeleton-list-item {
|
|
69
|
-
padding: var(--spacing-3);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.interactive-skeleton-details {
|
|
73
|
-
flex: 1;
|
|
74
|
-
}
|
|
75
|
-
</style>
|
|
76
|
-
`;
|
|
77
|
-
|
|
78
|
-
export default {
|
|
79
|
-
title: 'Enhancements/Interactive States',
|
|
80
|
-
tags: ['
|
|
81
|
-
parameters: {
|
|
82
|
-
pds: {
|
|
83
|
-
tags: ['interaction', 'accessibility', 'feedback']
|
|
84
|
-
},
|
|
85
|
-
docs: {
|
|
86
|
-
description: {
|
|
87
|
-
component: 'Interactive states including focus rings, hover effects, active states, disabled states, and working/loading states. All animations respect user preferences and accessibility settings.'
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export const FocusStates = () => html`
|
|
94
|
-
<div class="card">
|
|
95
|
-
<h2>Focus States</h2>
|
|
96
|
-
<p>Press <kbd>Tab</kbd> to navigate and see focus rings on interactive elements</p>
|
|
97
|
-
|
|
98
|
-
<div class="flex flex-wrap gap-sm align-center">
|
|
99
|
-
<button class="btn-primary">Button 1</button>
|
|
100
|
-
<button class="btn-secondary">Button 2</button>
|
|
101
|
-
<button class="btn-outline">Button 3</button>
|
|
102
|
-
<input type="text" placeholder="Focus me" />
|
|
103
|
-
<select>
|
|
104
|
-
<option>Option 1</option>
|
|
105
|
-
<option>Option 2</option>
|
|
106
|
-
<option>Option 3</option>
|
|
107
|
-
</select>
|
|
108
|
-
<a href="#" onclick="event.preventDefault();">Link Example</a>
|
|
109
|
-
</div>
|
|
110
|
-
</div>
|
|
111
|
-
|
|
112
|
-
<div class="card">
|
|
113
|
-
<h3>Form Controls</h3>
|
|
114
|
-
<div class="max-w-md">
|
|
115
|
-
<label>
|
|
116
|
-
<span>Text Input</span>
|
|
117
|
-
<input type="text" placeholder="Tab to focus" />
|
|
118
|
-
</label>
|
|
119
|
-
|
|
120
|
-
<label>
|
|
121
|
-
<span>Textarea</span>
|
|
122
|
-
<textarea rows="3" placeholder="Tab to focus"></textarea>
|
|
123
|
-
</label>
|
|
124
|
-
|
|
125
|
-
<fieldset role="group">
|
|
126
|
-
<legend>Options</legend>
|
|
127
|
-
<label>
|
|
128
|
-
<input type="checkbox" />
|
|
129
|
-
<span>Checkbox option 1</span>
|
|
130
|
-
</label>
|
|
131
|
-
<label>
|
|
132
|
-
<input type="checkbox" checked />
|
|
133
|
-
<span>Checkbox option 2</span>
|
|
134
|
-
</label>
|
|
135
|
-
</fieldset>
|
|
136
|
-
|
|
137
|
-
<fieldset role="radiogroup">
|
|
138
|
-
<legend>Choice</legend>
|
|
139
|
-
<label>
|
|
140
|
-
<input type="radio" name="choice" value="a" checked />
|
|
141
|
-
<span>Radio option A</span>
|
|
142
|
-
</label>
|
|
143
|
-
<label>
|
|
144
|
-
<input type="radio" name="choice" value="b" />
|
|
145
|
-
<span>Radio option B</span>
|
|
146
|
-
</label>
|
|
147
|
-
</fieldset>
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
`;
|
|
151
|
-
|
|
152
|
-
FocusStates.storyName = 'Focus States';
|
|
153
|
-
|
|
154
|
-
export const HoverStates = () => html`
|
|
155
|
-
<div class="card">
|
|
156
|
-
<h2>Hover States</h2>
|
|
157
|
-
<p>Hover over elements to see smooth transitions and state changes</p>
|
|
158
|
-
|
|
159
|
-
<h3>Buttons</h3>
|
|
160
|
-
<div class="flex flex-wrap gap-sm">
|
|
161
|
-
<button class="btn-primary">Hover Me</button>
|
|
162
|
-
<button class="btn-secondary">Hover Me</button>
|
|
163
|
-
<button class="btn-outline">Hover Me</button>
|
|
164
|
-
<button class="btn-primary btn-sm">Small</button>
|
|
165
|
-
<button class="btn-primary btn-lg">Large</button>
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
|
|
169
|
-
<div class="card">
|
|
170
|
-
<h3>Icon Buttons</h3>
|
|
171
|
-
<div class="flex flex-wrap gap-sm">
|
|
172
|
-
<button class="btn-primary icon-only" aria-label="Settings">
|
|
173
|
-
<pds-icon icon="gear"></pds-icon>
|
|
174
|
-
</button>
|
|
175
|
-
<button class="btn-secondary icon-only" aria-label="Search">
|
|
176
|
-
<pds-icon icon="magnifying-glass"></pds-icon>
|
|
177
|
-
</button>
|
|
178
|
-
<button class="btn-outline icon-only" aria-label="Heart">
|
|
179
|
-
<pds-icon icon="heart"></pds-icon>
|
|
180
|
-
</button>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
|
|
184
|
-
<div class="card">
|
|
185
|
-
<h3>Buttons with Icons</h3>
|
|
186
|
-
<div class="flex flex-wrap gap-sm">
|
|
187
|
-
<button class="btn-primary">
|
|
188
|
-
<pds-icon icon="plus" size="sm"></pds-icon>
|
|
189
|
-
Add Item
|
|
190
|
-
</button>
|
|
191
|
-
<button class="btn-secondary">
|
|
192
|
-
<pds-icon icon="download" size="sm"></pds-icon>
|
|
193
|
-
Download
|
|
194
|
-
</button>
|
|
195
|
-
<button class="btn-outline">
|
|
196
|
-
<pds-icon icon="share" size="sm"></pds-icon>
|
|
197
|
-
Share
|
|
198
|
-
</button>
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
|
|
202
|
-
<div class="card">
|
|
203
|
-
<h3>Links</h3>
|
|
204
|
-
<div class="flex flex-wrap gap-md">
|
|
205
|
-
<a href="#" onclick="event.preventDefault();">Text Link</a>
|
|
206
|
-
<a href="#" onclick="event.preventDefault();">
|
|
207
|
-
<pds-icon icon="arrow-right" size="sm"></pds-icon>
|
|
208
|
-
Link with Icon
|
|
209
|
-
</a>
|
|
210
|
-
</div>
|
|
211
|
-
</div>
|
|
212
|
-
`;
|
|
213
|
-
|
|
214
|
-
HoverStates.storyName = 'Hover States';
|
|
215
|
-
|
|
216
|
-
export const ActiveStates = () => html`
|
|
217
|
-
<div class="card">
|
|
218
|
-
<h2>Active States</h2>
|
|
219
|
-
<p>Click and hold to see active/pressed states</p>
|
|
220
|
-
|
|
221
|
-
<h3>Buttons</h3>
|
|
222
|
-
<div class="flex flex-wrap gap-sm">
|
|
223
|
-
<button class="btn-primary">Click and Hold</button>
|
|
224
|
-
<button class="btn-secondary">Click and Hold</button>
|
|
225
|
-
<button class="btn-outline">Click and Hold</button>
|
|
226
|
-
</div>
|
|
227
|
-
</div>
|
|
228
|
-
|
|
229
|
-
<div class="card">
|
|
230
|
-
<h3>Icon Buttons</h3>
|
|
231
|
-
<div class="flex flex-wrap gap-sm">
|
|
232
|
-
<button class="btn-primary icon-only" aria-label="Like">
|
|
233
|
-
<pds-icon icon="heart"></pds-icon>
|
|
234
|
-
</button>
|
|
235
|
-
<button class="btn-secondary icon-only" aria-label="Bookmark">
|
|
236
|
-
<pds-icon icon="bookmark"></pds-icon>
|
|
237
|
-
</button>
|
|
238
|
-
<button class="btn-outline icon-only" aria-label="Star">
|
|
239
|
-
<pds-icon icon="star"></pds-icon>
|
|
240
|
-
</button>
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
`;
|
|
244
|
-
|
|
245
|
-
ActiveStates.storyName = 'Active States';
|
|
246
|
-
|
|
247
|
-
export const TransitionSpeeds = () => {
|
|
248
|
-
const triggerAnimation = (speed) => {
|
|
249
|
-
const ball = document.getElementById(`ball-${speed}`);
|
|
250
|
-
if (!ball || ball.classList.contains('animating')) return;
|
|
251
|
-
|
|
252
|
-
ball.classList.add('animating');
|
|
253
|
-
ball.style.transition = `transform var(--transition-${speed})`;
|
|
254
|
-
ball.style.transform = 'translateX(250px)';
|
|
255
|
-
|
|
256
|
-
const duration = speed === 'fast' ? 150 : speed === 'slow' ? 500 : 250;
|
|
257
|
-
|
|
258
|
-
setTimeout(() => {
|
|
259
|
-
ball.style.transform = 'translateX(0)';
|
|
260
|
-
setTimeout(() => {
|
|
261
|
-
ball.classList.remove('animating');
|
|
262
|
-
}, duration);
|
|
263
|
-
}, duration);
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
return html`
|
|
267
|
-
<div class="card">
|
|
268
|
-
<h2>Transition Speeds</h2>
|
|
269
|
-
<p>The design system provides three transition speed tokens that can be configured globally.</p>
|
|
270
|
-
|
|
271
|
-
<div class="grid gap-lg">
|
|
272
|
-
${['fast', 'normal', 'slow'].map(speed => html`
|
|
273
|
-
<div>
|
|
274
|
-
<h3>--transition-${speed}</h3>
|
|
275
|
-
<button class="btn-primary btn-sm" @click=${() => triggerAnimation(speed)}>
|
|
276
|
-
<pds-icon icon="play" size="sm"></pds-icon>
|
|
277
|
-
Animate ${speed}
|
|
278
|
-
</button>
|
|
279
|
-
<div class="card surface-subtle">
|
|
280
|
-
<div id="ball-${speed}" class="badge badge-primary radius-full shadow-md">
|
|
281
|
-
<pds-icon icon="cursor-click" size="sm"></pds-icon>
|
|
282
|
-
</div>
|
|
283
|
-
</div>
|
|
284
|
-
</div>
|
|
285
|
-
`)}
|
|
286
|
-
</div>
|
|
287
|
-
</div>
|
|
288
|
-
|
|
289
|
-
<div class="card">
|
|
290
|
-
<h3>Code Example</h3>
|
|
291
|
-
<pre class="surface-subtle radius-md overflow-auto"><code>/* Use transition tokens in your CSS */
|
|
292
|
-
.button {
|
|
293
|
-
transition: background-color var(--transition-fast);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
.card {
|
|
297
|
-
transition:
|
|
298
|
-
transform var(--transition-normal),
|
|
299
|
-
box-shadow var(--transition-normal);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
.modal {
|
|
303
|
-
transition: opacity var(--transition-slow);
|
|
304
|
-
}</code></pre>
|
|
305
|
-
</div>
|
|
306
|
-
`;
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
TransitionSpeeds.storyName = 'Transition Speeds';
|
|
310
|
-
|
|
311
|
-
export const WorkingStates = () => {
|
|
312
|
-
const toggleWorking = (btn) => {
|
|
313
|
-
btn.classList.add('btn-working');
|
|
314
|
-
setTimeout(() => {
|
|
315
|
-
btn.classList.remove('btn-working');
|
|
316
|
-
}, 2000);
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
return html`
|
|
320
|
-
<div class="card">
|
|
321
|
-
<h2>Working/Loading States</h2>
|
|
322
|
-
<p>
|
|
323
|
-
Click buttons to see the <code>.btn-working</code> state with automatic spinner animation.
|
|
324
|
-
The PDS enhancer automatically swaps existing icons to spinners or adds a spinner if none exists.
|
|
325
|
-
</p>
|
|
326
|
-
|
|
327
|
-
<h3>Buttons Without Icons</h3>
|
|
328
|
-
<p class="text-muted text-sm">Enhancer automatically adds spinner icon</p>
|
|
329
|
-
<div class="flex flex-wrap gap-sm">
|
|
330
|
-
<button class="btn-primary" @click=${(e) => toggleWorking(e.target)}>
|
|
331
|
-
Save
|
|
332
|
-
</button>
|
|
333
|
-
<button class="btn-secondary" @click=${(e) => toggleWorking(e.target)}>
|
|
334
|
-
Upload
|
|
335
|
-
</button>
|
|
336
|
-
<button class="btn-outline" @click=${(e) => toggleWorking(e.target)}>
|
|
337
|
-
Download
|
|
338
|
-
</button>
|
|
339
|
-
</div>
|
|
340
|
-
</div>
|
|
341
|
-
|
|
342
|
-
<div class="card">
|
|
343
|
-
<h3>Buttons With Existing Icons</h3>
|
|
344
|
-
<p class="text-muted text-sm">Enhancer swaps icon to spinner, restores original when complete</p>
|
|
345
|
-
<div class="flex flex-wrap gap-sm">
|
|
346
|
-
<button class="btn-primary" @click=${(e) => toggleWorking(e.target)}>
|
|
347
|
-
<pds-icon icon="floppy-disk" size="sm"></pds-icon>
|
|
348
|
-
Save
|
|
349
|
-
</button>
|
|
350
|
-
<button class="btn-secondary" @click=${(e) => toggleWorking(e.target)}>
|
|
351
|
-
<pds-icon icon="upload" size="sm"></pds-icon>
|
|
352
|
-
Upload
|
|
353
|
-
</button>
|
|
354
|
-
<button class="btn-outline" @click=${(e) => toggleWorking(e.target)}>
|
|
355
|
-
<pds-icon icon="download" size="sm"></pds-icon>
|
|
356
|
-
Download
|
|
357
|
-
</button>
|
|
358
|
-
</div>
|
|
359
|
-
</div>
|
|
360
|
-
|
|
361
|
-
<div class="card">
|
|
362
|
-
<h3>Icon Buttons</h3>
|
|
363
|
-
<p class="text-muted text-sm">Icon-only buttons with automatic spinner swap</p>
|
|
364
|
-
<div class="flex flex-wrap gap-sm">
|
|
365
|
-
<button class="btn-primary icon-only" @click=${(e) => toggleWorking(e.target)} aria-label="Refresh">
|
|
366
|
-
<pds-icon icon="arrow-counter-clockwise"></pds-icon>
|
|
367
|
-
</button>
|
|
368
|
-
<button class="btn-secondary icon-only" @click=${(e) => toggleWorking(e.target)} aria-label="Sync">
|
|
369
|
-
<pds-icon icon="arrow-counter-clockwise"></pds-icon>
|
|
370
|
-
</button>
|
|
371
|
-
<button class="btn-outline icon-only" @click=${(e) => toggleWorking(e.target)} aria-label="Process">
|
|
372
|
-
<pds-icon icon="gear"></pds-icon>
|
|
373
|
-
</button>
|
|
374
|
-
</div>
|
|
375
|
-
</div>
|
|
376
|
-
|
|
377
|
-
<div class="card">
|
|
378
|
-
<h3>Different Sizes</h3>
|
|
379
|
-
<p class="text-muted text-sm">Spinner size adapts to button size</p>
|
|
380
|
-
<div class="flex flex-wrap gap-sm align-center">
|
|
381
|
-
<button class="btn-primary btn-sm" @click=${(e) => toggleWorking(e.target)}>
|
|
382
|
-
<pds-icon icon="paper-plane-tilt" size="sm"></pds-icon>
|
|
383
|
-
Small
|
|
384
|
-
</button>
|
|
385
|
-
<button class="btn-primary" @click=${(e) => toggleWorking(e.target)}>
|
|
386
|
-
<pds-icon icon="paper-plane-tilt" size="sm"></pds-icon>
|
|
387
|
-
Default
|
|
388
|
-
</button>
|
|
389
|
-
<button class="btn-primary btn-lg" @click=${(e) => toggleWorking(e.target)}>
|
|
390
|
-
<pds-icon icon="paper-plane-tilt"></pds-icon>
|
|
391
|
-
Large
|
|
392
|
-
</button>
|
|
393
|
-
</div>
|
|
394
|
-
</div>
|
|
395
|
-
|
|
396
|
-
<div class="card">
|
|
397
|
-
<h3>Permanent Working State</h3>
|
|
398
|
-
<p class="text-muted">Buttons in continuous working state</p>
|
|
399
|
-
<div class="flex flex-wrap gap-sm">
|
|
400
|
-
<button class="btn-primary btn-working">
|
|
401
|
-
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
402
|
-
Loading...
|
|
403
|
-
</button>
|
|
404
|
-
<button class="btn-secondary btn-working">
|
|
405
|
-
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
406
|
-
Processing...
|
|
407
|
-
</button>
|
|
408
|
-
<button class="btn-outline icon-only btn-working" aria-label="Loading">
|
|
409
|
-
<pds-icon icon="circle-notch"></pds-icon>
|
|
410
|
-
</button>
|
|
411
|
-
</div>
|
|
412
|
-
</div>
|
|
413
|
-
|
|
414
|
-
<div class="card">
|
|
415
|
-
<h3>Usage</h3>
|
|
416
|
-
<pre class="bg-surface-subtle radius-md overflow-auto"><code>// Simply toggle the class - PDS handles the rest
|
|
417
|
-
button.classList.add('btn-working');
|
|
418
|
-
|
|
419
|
-
// After async operation completes
|
|
420
|
-
button.classList.remove('btn-working');</code></pre>
|
|
421
|
-
</div>
|
|
422
|
-
`;
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
WorkingStates.storyName = 'Working States';
|
|
426
|
-
|
|
427
|
-
export const SkeletonLoading = () => html`
|
|
428
|
-
${interactiveSkeletonStoryStyles}
|
|
429
|
-
<div class="card">
|
|
430
|
-
<h2>Skeleton Loading</h2>
|
|
431
|
-
<p>Use the <code>.skeleton</code> class for content placeholders while loading</p>
|
|
432
|
-
|
|
433
|
-
<h3>Card Skeleton</h3>
|
|
434
|
-
<div class="max-w-xl">
|
|
435
|
-
<div class="card interactive-skeleton-card">
|
|
436
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-24 interactive-skeleton-width-60 interactive-skeleton-margin-lg"></div>
|
|
437
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
438
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
439
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-width-80"></div>
|
|
440
|
-
</div>
|
|
441
|
-
</div>
|
|
442
|
-
</div>
|
|
443
|
-
|
|
444
|
-
<div class="card">
|
|
445
|
-
<h3>List Skeleton</h3>
|
|
446
|
-
<div class="max-w-md">
|
|
447
|
-
${Array.from({ length: 4 }, () => html`
|
|
448
|
-
<div class="flex gap-sm align-center border-bottom interactive-skeleton-list-item">
|
|
449
|
-
<div class="skeleton interactive-skeleton-avatar"></div>
|
|
450
|
-
<div class="interactive-skeleton-details">
|
|
451
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-width-70 interactive-skeleton-margin-md"></div>
|
|
452
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-14 interactive-skeleton-width-50"></div>
|
|
453
|
-
</div>
|
|
454
|
-
</div>
|
|
455
|
-
`)}
|
|
456
|
-
</div>
|
|
457
|
-
</div>
|
|
458
|
-
|
|
459
|
-
<div class="card">
|
|
460
|
-
<h3>Text Skeleton</h3>
|
|
461
|
-
<div class="max-w-lg">
|
|
462
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-20 interactive-skeleton-width-40 interactive-skeleton-margin-lg"></div>
|
|
463
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
464
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
465
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
466
|
-
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-width-85"></div>
|
|
467
|
-
</div>
|
|
468
|
-
</div>
|
|
469
|
-
`;
|
|
470
|
-
|
|
471
|
-
SkeletonLoading.storyName = 'Skeleton Loading';
|
|
472
|
-
|
|
473
|
-
export const DisabledStates = () => html`
|
|
474
|
-
<div class="card">
|
|
475
|
-
<h2>Disabled States</h2>
|
|
476
|
-
<p>Disabled elements have reduced opacity and no pointer events</p>
|
|
477
|
-
|
|
478
|
-
<h3>Buttons</h3>
|
|
479
|
-
<div class="flex flex-wrap gap-sm">
|
|
480
|
-
<button class="btn-primary" disabled>Primary Disabled</button>
|
|
481
|
-
<button class="btn-secondary" disabled>Secondary Disabled</button>
|
|
482
|
-
<button class="btn-outline" disabled>Outline Disabled</button>
|
|
483
|
-
</div>
|
|
484
|
-
</div>
|
|
485
|
-
|
|
486
|
-
<div class="card">
|
|
487
|
-
<h3>Icon Buttons</h3>
|
|
488
|
-
<div class="flex flex-wrap gap-sm">
|
|
489
|
-
<button class="btn-primary icon-only" disabled aria-label="Settings">
|
|
490
|
-
<pds-icon icon="gear"></pds-icon>
|
|
491
|
-
</button>
|
|
492
|
-
<button class="btn-secondary icon-only" disabled aria-label="Search">
|
|
493
|
-
<pds-icon icon="magnifying-glass"></pds-icon>
|
|
494
|
-
</button>
|
|
495
|
-
<button class="btn-outline icon-only" disabled aria-label="Heart">
|
|
496
|
-
<pds-icon icon="heart"></pds-icon>
|
|
497
|
-
</button>
|
|
498
|
-
</div>
|
|
499
|
-
</div>
|
|
500
|
-
|
|
501
|
-
<div class="card">
|
|
502
|
-
<h3>Buttons with Icons</h3>
|
|
503
|
-
<div class="flex flex-wrap gap-sm">
|
|
504
|
-
<button class="btn-primary" disabled>
|
|
505
|
-
<pds-icon icon="plus" size="sm"></pds-icon>
|
|
506
|
-
Add Item
|
|
507
|
-
</button>
|
|
508
|
-
<button class="btn-secondary" disabled>
|
|
509
|
-
<pds-icon icon="download" size="sm"></pds-icon>
|
|
510
|
-
Download
|
|
511
|
-
</button>
|
|
512
|
-
</div>
|
|
513
|
-
</div>
|
|
514
|
-
|
|
515
|
-
<div class="card">
|
|
516
|
-
<h3>Form Controls</h3>
|
|
517
|
-
<div class="max-w-md">
|
|
518
|
-
<label>
|
|
519
|
-
<span>Disabled Input</span>
|
|
520
|
-
<input type="text" disabled value="Cannot edit" />
|
|
521
|
-
</label>
|
|
522
|
-
|
|
523
|
-
<label>
|
|
524
|
-
<span>Disabled Select</span>
|
|
525
|
-
<select disabled>
|
|
526
|
-
<option>Cannot select</option>
|
|
527
|
-
</select>
|
|
528
|
-
</label>
|
|
529
|
-
|
|
530
|
-
<label>
|
|
531
|
-
<span>Disabled Textarea</span>
|
|
532
|
-
<textarea disabled rows="3">Cannot edit this text</textarea>
|
|
533
|
-
</label>
|
|
534
|
-
|
|
535
|
-
<fieldset role="group">
|
|
536
|
-
<legend>Disabled Checkboxes</legend>
|
|
537
|
-
<label>
|
|
538
|
-
<input type="checkbox" disabled />
|
|
539
|
-
<span>Disabled unchecked</span>
|
|
540
|
-
</label>
|
|
541
|
-
<label>
|
|
542
|
-
<input type="checkbox" disabled checked />
|
|
543
|
-
<span>Disabled checked</span>
|
|
544
|
-
</label>
|
|
545
|
-
</fieldset>
|
|
546
|
-
</div>
|
|
547
|
-
</div>
|
|
548
|
-
`;
|
|
549
|
-
|
|
550
|
-
DisabledStates.storyName = 'Disabled States';
|
|
551
|
-
|
|
552
|
-
export const CombinedStates = () => html`
|
|
553
|
-
<div class="card">
|
|
554
|
-
<h2>Combined State Examples</h2>
|
|
555
|
-
<p>Comprehensive examples showing all interactive states together</p>
|
|
556
|
-
</div>
|
|
557
|
-
|
|
558
|
-
<div class="card">
|
|
559
|
-
<h3>Idle State</h3>
|
|
560
|
-
<div class="flex flex-wrap gap-sm">
|
|
561
|
-
<button class="btn-primary">Primary</button>
|
|
562
|
-
<button class="btn-secondary">Secondary</button>
|
|
563
|
-
<button class="btn-outline">Outline</button>
|
|
564
|
-
</div>
|
|
565
|
-
</div>
|
|
566
|
-
|
|
567
|
-
<div class="card">
|
|
568
|
-
<h3>Hover State</h3>
|
|
569
|
-
<p class="text-muted text-sm">Hover over buttons to see effect</p>
|
|
570
|
-
<div class="flex flex-wrap gap-sm">
|
|
571
|
-
<button class="btn-primary">Primary</button>
|
|
572
|
-
<button class="btn-secondary">Secondary</button>
|
|
573
|
-
<button class="btn-outline">Outline</button>
|
|
574
|
-
</div>
|
|
575
|
-
</div>
|
|
576
|
-
|
|
577
|
-
<div class="card">
|
|
578
|
-
<h3>Active State</h3>
|
|
579
|
-
<p class="text-muted text-sm">Click and hold to see effect</p>
|
|
580
|
-
<div class="flex flex-wrap gap-sm">
|
|
581
|
-
<button class="btn-primary">Primary</button>
|
|
582
|
-
<button class="btn-secondary">Secondary</button>
|
|
583
|
-
<button class="btn-outline">Outline</button>
|
|
584
|
-
</div>
|
|
585
|
-
</div>
|
|
586
|
-
|
|
587
|
-
<div class="card">
|
|
588
|
-
<h3>Focus State</h3>
|
|
589
|
-
<p class="text-muted text-sm">Tab to focus on buttons</p>
|
|
590
|
-
<div class="flex flex-wrap gap-sm">
|
|
591
|
-
<button class="btn-primary">Primary</button>
|
|
592
|
-
<button class="btn-secondary">Secondary</button>
|
|
593
|
-
<button class="btn-outline">Outline</button>
|
|
594
|
-
</div>
|
|
595
|
-
</div>
|
|
596
|
-
|
|
597
|
-
<div class="card">
|
|
598
|
-
<h3>Disabled State</h3>
|
|
599
|
-
<div class="flex flex-wrap gap-sm">
|
|
600
|
-
<button class="btn-primary" disabled>Primary</button>
|
|
601
|
-
<button class="btn-secondary" disabled>Secondary</button>
|
|
602
|
-
<button class="btn-outline" disabled>Outline</button>
|
|
603
|
-
</div>
|
|
604
|
-
</div>
|
|
605
|
-
|
|
606
|
-
<div class="card">
|
|
607
|
-
<h3>Working State</h3>
|
|
608
|
-
<div class="flex flex-wrap gap-sm">
|
|
609
|
-
<button class="btn-primary btn-working">
|
|
610
|
-
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
611
|
-
Primary
|
|
612
|
-
</button>
|
|
613
|
-
<button class="btn-secondary btn-working">
|
|
614
|
-
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
615
|
-
Secondary
|
|
616
|
-
</button>
|
|
617
|
-
<button class="btn-outline btn-working">
|
|
618
|
-
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
619
|
-
Outline
|
|
620
|
-
</button>
|
|
621
|
-
</div>
|
|
622
|
-
</div>
|
|
623
|
-
`;
|
|
624
|
-
|
|
625
|
-
CombinedStates.storyName = 'All States';
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
|
|
3
|
+
const interactiveSkeletonStoryStyles = html`
|
|
4
|
+
<style>
|
|
5
|
+
.interactive-skeleton-card {
|
|
6
|
+
display: grid;
|
|
7
|
+
gap: var(--spacing-3);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.interactive-skeleton-block {
|
|
11
|
+
display: block;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.interactive-skeleton-height-24 {
|
|
15
|
+
height: 1.5rem;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.interactive-skeleton-height-20 {
|
|
19
|
+
height: 1.25rem;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.interactive-skeleton-height-16 {
|
|
23
|
+
height: 1rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.interactive-skeleton-height-14 {
|
|
27
|
+
height: 0.875rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.interactive-skeleton-width-60 {
|
|
31
|
+
width: 60%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.interactive-skeleton-width-80 {
|
|
35
|
+
width: 80%;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.interactive-skeleton-width-70 {
|
|
39
|
+
width: 70%;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.interactive-skeleton-width-50 {
|
|
43
|
+
width: 50%;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.interactive-skeleton-width-40 {
|
|
47
|
+
width: 40%;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.interactive-skeleton-width-85 {
|
|
51
|
+
width: 85%;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.interactive-skeleton-margin-lg {
|
|
55
|
+
margin-bottom: var(--spacing-3);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.interactive-skeleton-margin-md {
|
|
59
|
+
margin-bottom: var(--spacing-2);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.interactive-skeleton-avatar {
|
|
63
|
+
width: 2.5rem;
|
|
64
|
+
height: 2.5rem;
|
|
65
|
+
border-radius: 50%;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.interactive-skeleton-list-item {
|
|
69
|
+
padding: var(--spacing-3);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.interactive-skeleton-details {
|
|
73
|
+
flex: 1;
|
|
74
|
+
}
|
|
75
|
+
</style>
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
export default {
|
|
79
|
+
title: 'Enhancements/Interactive States',
|
|
80
|
+
tags: ['hover', 'focus', 'active', 'disabled', 'loading', 'interaction'],
|
|
81
|
+
parameters: {
|
|
82
|
+
pds: {
|
|
83
|
+
tags: ['hover', 'focus', 'active', 'disabled', 'loading', 'working', 'interaction', 'accessibility', 'feedback', 'state']
|
|
84
|
+
},
|
|
85
|
+
docs: {
|
|
86
|
+
description: {
|
|
87
|
+
component: 'Interactive states including focus rings, hover effects, active states, disabled states, and working/loading states. All animations respect user preferences and accessibility settings.'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const FocusStates = () => html`
|
|
94
|
+
<div class="card">
|
|
95
|
+
<h2>Focus States</h2>
|
|
96
|
+
<p>Press <kbd>Tab</kbd> to navigate and see focus rings on interactive elements</p>
|
|
97
|
+
|
|
98
|
+
<div class="flex flex-wrap gap-sm align-center">
|
|
99
|
+
<button class="btn-primary">Button 1</button>
|
|
100
|
+
<button class="btn-secondary">Button 2</button>
|
|
101
|
+
<button class="btn-outline">Button 3</button>
|
|
102
|
+
<input type="text" placeholder="Focus me" />
|
|
103
|
+
<select>
|
|
104
|
+
<option>Option 1</option>
|
|
105
|
+
<option>Option 2</option>
|
|
106
|
+
<option>Option 3</option>
|
|
107
|
+
</select>
|
|
108
|
+
<a href="#" onclick="event.preventDefault();">Link Example</a>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<div class="card">
|
|
113
|
+
<h3>Form Controls</h3>
|
|
114
|
+
<div class="max-w-md">
|
|
115
|
+
<label>
|
|
116
|
+
<span>Text Input</span>
|
|
117
|
+
<input type="text" placeholder="Tab to focus" />
|
|
118
|
+
</label>
|
|
119
|
+
|
|
120
|
+
<label>
|
|
121
|
+
<span>Textarea</span>
|
|
122
|
+
<textarea rows="3" placeholder="Tab to focus"></textarea>
|
|
123
|
+
</label>
|
|
124
|
+
|
|
125
|
+
<fieldset role="group">
|
|
126
|
+
<legend>Options</legend>
|
|
127
|
+
<label>
|
|
128
|
+
<input type="checkbox" />
|
|
129
|
+
<span>Checkbox option 1</span>
|
|
130
|
+
</label>
|
|
131
|
+
<label>
|
|
132
|
+
<input type="checkbox" checked />
|
|
133
|
+
<span>Checkbox option 2</span>
|
|
134
|
+
</label>
|
|
135
|
+
</fieldset>
|
|
136
|
+
|
|
137
|
+
<fieldset role="radiogroup">
|
|
138
|
+
<legend>Choice</legend>
|
|
139
|
+
<label>
|
|
140
|
+
<input type="radio" name="choice" value="a" checked />
|
|
141
|
+
<span>Radio option A</span>
|
|
142
|
+
</label>
|
|
143
|
+
<label>
|
|
144
|
+
<input type="radio" name="choice" value="b" />
|
|
145
|
+
<span>Radio option B</span>
|
|
146
|
+
</label>
|
|
147
|
+
</fieldset>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
FocusStates.storyName = 'Focus States';
|
|
153
|
+
|
|
154
|
+
export const HoverStates = () => html`
|
|
155
|
+
<div class="card">
|
|
156
|
+
<h2>Hover States</h2>
|
|
157
|
+
<p>Hover over elements to see smooth transitions and state changes</p>
|
|
158
|
+
|
|
159
|
+
<h3>Buttons</h3>
|
|
160
|
+
<div class="flex flex-wrap gap-sm">
|
|
161
|
+
<button class="btn-primary">Hover Me</button>
|
|
162
|
+
<button class="btn-secondary">Hover Me</button>
|
|
163
|
+
<button class="btn-outline">Hover Me</button>
|
|
164
|
+
<button class="btn-primary btn-sm">Small</button>
|
|
165
|
+
<button class="btn-primary btn-lg">Large</button>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div class="card">
|
|
170
|
+
<h3>Icon Buttons</h3>
|
|
171
|
+
<div class="flex flex-wrap gap-sm">
|
|
172
|
+
<button class="btn-primary icon-only" aria-label="Settings">
|
|
173
|
+
<pds-icon icon="gear"></pds-icon>
|
|
174
|
+
</button>
|
|
175
|
+
<button class="btn-secondary icon-only" aria-label="Search">
|
|
176
|
+
<pds-icon icon="magnifying-glass"></pds-icon>
|
|
177
|
+
</button>
|
|
178
|
+
<button class="btn-outline icon-only" aria-label="Heart">
|
|
179
|
+
<pds-icon icon="heart"></pds-icon>
|
|
180
|
+
</button>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
<div class="card">
|
|
185
|
+
<h3>Buttons with Icons</h3>
|
|
186
|
+
<div class="flex flex-wrap gap-sm">
|
|
187
|
+
<button class="btn-primary">
|
|
188
|
+
<pds-icon icon="plus" size="sm"></pds-icon>
|
|
189
|
+
Add Item
|
|
190
|
+
</button>
|
|
191
|
+
<button class="btn-secondary">
|
|
192
|
+
<pds-icon icon="download" size="sm"></pds-icon>
|
|
193
|
+
Download
|
|
194
|
+
</button>
|
|
195
|
+
<button class="btn-outline">
|
|
196
|
+
<pds-icon icon="share" size="sm"></pds-icon>
|
|
197
|
+
Share
|
|
198
|
+
</button>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
<div class="card">
|
|
203
|
+
<h3>Links</h3>
|
|
204
|
+
<div class="flex flex-wrap gap-md">
|
|
205
|
+
<a href="#" onclick="event.preventDefault();">Text Link</a>
|
|
206
|
+
<a href="#" onclick="event.preventDefault();">
|
|
207
|
+
<pds-icon icon="arrow-right" size="sm"></pds-icon>
|
|
208
|
+
Link with Icon
|
|
209
|
+
</a>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
`;
|
|
213
|
+
|
|
214
|
+
HoverStates.storyName = 'Hover States';
|
|
215
|
+
|
|
216
|
+
export const ActiveStates = () => html`
|
|
217
|
+
<div class="card">
|
|
218
|
+
<h2>Active States</h2>
|
|
219
|
+
<p>Click and hold to see active/pressed states</p>
|
|
220
|
+
|
|
221
|
+
<h3>Buttons</h3>
|
|
222
|
+
<div class="flex flex-wrap gap-sm">
|
|
223
|
+
<button class="btn-primary">Click and Hold</button>
|
|
224
|
+
<button class="btn-secondary">Click and Hold</button>
|
|
225
|
+
<button class="btn-outline">Click and Hold</button>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
|
|
229
|
+
<div class="card">
|
|
230
|
+
<h3>Icon Buttons</h3>
|
|
231
|
+
<div class="flex flex-wrap gap-sm">
|
|
232
|
+
<button class="btn-primary icon-only" aria-label="Like">
|
|
233
|
+
<pds-icon icon="heart"></pds-icon>
|
|
234
|
+
</button>
|
|
235
|
+
<button class="btn-secondary icon-only" aria-label="Bookmark">
|
|
236
|
+
<pds-icon icon="bookmark"></pds-icon>
|
|
237
|
+
</button>
|
|
238
|
+
<button class="btn-outline icon-only" aria-label="Star">
|
|
239
|
+
<pds-icon icon="star"></pds-icon>
|
|
240
|
+
</button>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
`;
|
|
244
|
+
|
|
245
|
+
ActiveStates.storyName = 'Active States';
|
|
246
|
+
|
|
247
|
+
export const TransitionSpeeds = () => {
|
|
248
|
+
const triggerAnimation = (speed) => {
|
|
249
|
+
const ball = document.getElementById(`ball-${speed}`);
|
|
250
|
+
if (!ball || ball.classList.contains('animating')) return;
|
|
251
|
+
|
|
252
|
+
ball.classList.add('animating');
|
|
253
|
+
ball.style.transition = `transform var(--transition-${speed})`;
|
|
254
|
+
ball.style.transform = 'translateX(250px)';
|
|
255
|
+
|
|
256
|
+
const duration = speed === 'fast' ? 150 : speed === 'slow' ? 500 : 250;
|
|
257
|
+
|
|
258
|
+
setTimeout(() => {
|
|
259
|
+
ball.style.transform = 'translateX(0)';
|
|
260
|
+
setTimeout(() => {
|
|
261
|
+
ball.classList.remove('animating');
|
|
262
|
+
}, duration);
|
|
263
|
+
}, duration);
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
return html`
|
|
267
|
+
<div class="card">
|
|
268
|
+
<h2>Transition Speeds</h2>
|
|
269
|
+
<p>The design system provides three transition speed tokens that can be configured globally.</p>
|
|
270
|
+
|
|
271
|
+
<div class="grid gap-lg">
|
|
272
|
+
${['fast', 'normal', 'slow'].map(speed => html`
|
|
273
|
+
<div>
|
|
274
|
+
<h3>--transition-${speed}</h3>
|
|
275
|
+
<button class="btn-primary btn-sm" @click=${() => triggerAnimation(speed)}>
|
|
276
|
+
<pds-icon icon="play" size="sm"></pds-icon>
|
|
277
|
+
Animate ${speed}
|
|
278
|
+
</button>
|
|
279
|
+
<div class="card surface-subtle">
|
|
280
|
+
<div id="ball-${speed}" class="badge badge-primary radius-full shadow-md">
|
|
281
|
+
<pds-icon icon="cursor-click" size="sm"></pds-icon>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
`)}
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<div class="card">
|
|
290
|
+
<h3>Code Example</h3>
|
|
291
|
+
<pre class="surface-subtle radius-md overflow-auto"><code>/* Use transition tokens in your CSS */
|
|
292
|
+
.button {
|
|
293
|
+
transition: background-color var(--transition-fast);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.card {
|
|
297
|
+
transition:
|
|
298
|
+
transform var(--transition-normal),
|
|
299
|
+
box-shadow var(--transition-normal);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.modal {
|
|
303
|
+
transition: opacity var(--transition-slow);
|
|
304
|
+
}</code></pre>
|
|
305
|
+
</div>
|
|
306
|
+
`;
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
TransitionSpeeds.storyName = 'Transition Speeds';
|
|
310
|
+
|
|
311
|
+
export const WorkingStates = () => {
|
|
312
|
+
const toggleWorking = (btn) => {
|
|
313
|
+
btn.classList.add('btn-working');
|
|
314
|
+
setTimeout(() => {
|
|
315
|
+
btn.classList.remove('btn-working');
|
|
316
|
+
}, 2000);
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
return html`
|
|
320
|
+
<div class="card">
|
|
321
|
+
<h2>Working/Loading States</h2>
|
|
322
|
+
<p>
|
|
323
|
+
Click buttons to see the <code>.btn-working</code> state with automatic spinner animation.
|
|
324
|
+
The PDS enhancer automatically swaps existing icons to spinners or adds a spinner if none exists.
|
|
325
|
+
</p>
|
|
326
|
+
|
|
327
|
+
<h3>Buttons Without Icons</h3>
|
|
328
|
+
<p class="text-muted text-sm">Enhancer automatically adds spinner icon</p>
|
|
329
|
+
<div class="flex flex-wrap gap-sm">
|
|
330
|
+
<button class="btn-primary" @click=${(e) => toggleWorking(e.target)}>
|
|
331
|
+
Save
|
|
332
|
+
</button>
|
|
333
|
+
<button class="btn-secondary" @click=${(e) => toggleWorking(e.target)}>
|
|
334
|
+
Upload
|
|
335
|
+
</button>
|
|
336
|
+
<button class="btn-outline" @click=${(e) => toggleWorking(e.target)}>
|
|
337
|
+
Download
|
|
338
|
+
</button>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
|
|
342
|
+
<div class="card">
|
|
343
|
+
<h3>Buttons With Existing Icons</h3>
|
|
344
|
+
<p class="text-muted text-sm">Enhancer swaps icon to spinner, restores original when complete</p>
|
|
345
|
+
<div class="flex flex-wrap gap-sm">
|
|
346
|
+
<button class="btn-primary" @click=${(e) => toggleWorking(e.target)}>
|
|
347
|
+
<pds-icon icon="floppy-disk" size="sm"></pds-icon>
|
|
348
|
+
Save
|
|
349
|
+
</button>
|
|
350
|
+
<button class="btn-secondary" @click=${(e) => toggleWorking(e.target)}>
|
|
351
|
+
<pds-icon icon="upload" size="sm"></pds-icon>
|
|
352
|
+
Upload
|
|
353
|
+
</button>
|
|
354
|
+
<button class="btn-outline" @click=${(e) => toggleWorking(e.target)}>
|
|
355
|
+
<pds-icon icon="download" size="sm"></pds-icon>
|
|
356
|
+
Download
|
|
357
|
+
</button>
|
|
358
|
+
</div>
|
|
359
|
+
</div>
|
|
360
|
+
|
|
361
|
+
<div class="card">
|
|
362
|
+
<h3>Icon Buttons</h3>
|
|
363
|
+
<p class="text-muted text-sm">Icon-only buttons with automatic spinner swap</p>
|
|
364
|
+
<div class="flex flex-wrap gap-sm">
|
|
365
|
+
<button class="btn-primary icon-only" @click=${(e) => toggleWorking(e.target)} aria-label="Refresh">
|
|
366
|
+
<pds-icon icon="arrow-counter-clockwise"></pds-icon>
|
|
367
|
+
</button>
|
|
368
|
+
<button class="btn-secondary icon-only" @click=${(e) => toggleWorking(e.target)} aria-label="Sync">
|
|
369
|
+
<pds-icon icon="arrow-counter-clockwise"></pds-icon>
|
|
370
|
+
</button>
|
|
371
|
+
<button class="btn-outline icon-only" @click=${(e) => toggleWorking(e.target)} aria-label="Process">
|
|
372
|
+
<pds-icon icon="gear"></pds-icon>
|
|
373
|
+
</button>
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
|
|
377
|
+
<div class="card">
|
|
378
|
+
<h3>Different Sizes</h3>
|
|
379
|
+
<p class="text-muted text-sm">Spinner size adapts to button size</p>
|
|
380
|
+
<div class="flex flex-wrap gap-sm align-center">
|
|
381
|
+
<button class="btn-primary btn-sm" @click=${(e) => toggleWorking(e.target)}>
|
|
382
|
+
<pds-icon icon="paper-plane-tilt" size="sm"></pds-icon>
|
|
383
|
+
Small
|
|
384
|
+
</button>
|
|
385
|
+
<button class="btn-primary" @click=${(e) => toggleWorking(e.target)}>
|
|
386
|
+
<pds-icon icon="paper-plane-tilt" size="sm"></pds-icon>
|
|
387
|
+
Default
|
|
388
|
+
</button>
|
|
389
|
+
<button class="btn-primary btn-lg" @click=${(e) => toggleWorking(e.target)}>
|
|
390
|
+
<pds-icon icon="paper-plane-tilt"></pds-icon>
|
|
391
|
+
Large
|
|
392
|
+
</button>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
|
|
396
|
+
<div class="card">
|
|
397
|
+
<h3>Permanent Working State</h3>
|
|
398
|
+
<p class="text-muted">Buttons in continuous working state</p>
|
|
399
|
+
<div class="flex flex-wrap gap-sm">
|
|
400
|
+
<button class="btn-primary btn-working">
|
|
401
|
+
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
402
|
+
Loading...
|
|
403
|
+
</button>
|
|
404
|
+
<button class="btn-secondary btn-working">
|
|
405
|
+
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
406
|
+
Processing...
|
|
407
|
+
</button>
|
|
408
|
+
<button class="btn-outline icon-only btn-working" aria-label="Loading">
|
|
409
|
+
<pds-icon icon="circle-notch"></pds-icon>
|
|
410
|
+
</button>
|
|
411
|
+
</div>
|
|
412
|
+
</div>
|
|
413
|
+
|
|
414
|
+
<div class="card">
|
|
415
|
+
<h3>Usage</h3>
|
|
416
|
+
<pre class="bg-surface-subtle radius-md overflow-auto"><code>// Simply toggle the class - PDS handles the rest
|
|
417
|
+
button.classList.add('btn-working');
|
|
418
|
+
|
|
419
|
+
// After async operation completes
|
|
420
|
+
button.classList.remove('btn-working');</code></pre>
|
|
421
|
+
</div>
|
|
422
|
+
`;
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
WorkingStates.storyName = 'Working States';
|
|
426
|
+
|
|
427
|
+
export const SkeletonLoading = () => html`
|
|
428
|
+
${interactiveSkeletonStoryStyles}
|
|
429
|
+
<div class="card">
|
|
430
|
+
<h2>Skeleton Loading</h2>
|
|
431
|
+
<p>Use the <code>.skeleton</code> class for content placeholders while loading</p>
|
|
432
|
+
|
|
433
|
+
<h3>Card Skeleton</h3>
|
|
434
|
+
<div class="max-w-xl">
|
|
435
|
+
<div class="card interactive-skeleton-card">
|
|
436
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-24 interactive-skeleton-width-60 interactive-skeleton-margin-lg"></div>
|
|
437
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
438
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
439
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-width-80"></div>
|
|
440
|
+
</div>
|
|
441
|
+
</div>
|
|
442
|
+
</div>
|
|
443
|
+
|
|
444
|
+
<div class="card">
|
|
445
|
+
<h3>List Skeleton</h3>
|
|
446
|
+
<div class="max-w-md">
|
|
447
|
+
${Array.from({ length: 4 }, () => html`
|
|
448
|
+
<div class="flex gap-sm align-center border-bottom interactive-skeleton-list-item">
|
|
449
|
+
<div class="skeleton interactive-skeleton-avatar"></div>
|
|
450
|
+
<div class="interactive-skeleton-details">
|
|
451
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-width-70 interactive-skeleton-margin-md"></div>
|
|
452
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-14 interactive-skeleton-width-50"></div>
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
455
|
+
`)}
|
|
456
|
+
</div>
|
|
457
|
+
</div>
|
|
458
|
+
|
|
459
|
+
<div class="card">
|
|
460
|
+
<h3>Text Skeleton</h3>
|
|
461
|
+
<div class="max-w-lg">
|
|
462
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-20 interactive-skeleton-width-40 interactive-skeleton-margin-lg"></div>
|
|
463
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
464
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
465
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-margin-md"></div>
|
|
466
|
+
<div class="skeleton interactive-skeleton-block interactive-skeleton-height-16 interactive-skeleton-width-85"></div>
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
469
|
+
`;
|
|
470
|
+
|
|
471
|
+
SkeletonLoading.storyName = 'Skeleton Loading';
|
|
472
|
+
|
|
473
|
+
export const DisabledStates = () => html`
|
|
474
|
+
<div class="card">
|
|
475
|
+
<h2>Disabled States</h2>
|
|
476
|
+
<p>Disabled elements have reduced opacity and no pointer events</p>
|
|
477
|
+
|
|
478
|
+
<h3>Buttons</h3>
|
|
479
|
+
<div class="flex flex-wrap gap-sm">
|
|
480
|
+
<button class="btn-primary" disabled>Primary Disabled</button>
|
|
481
|
+
<button class="btn-secondary" disabled>Secondary Disabled</button>
|
|
482
|
+
<button class="btn-outline" disabled>Outline Disabled</button>
|
|
483
|
+
</div>
|
|
484
|
+
</div>
|
|
485
|
+
|
|
486
|
+
<div class="card">
|
|
487
|
+
<h3>Icon Buttons</h3>
|
|
488
|
+
<div class="flex flex-wrap gap-sm">
|
|
489
|
+
<button class="btn-primary icon-only" disabled aria-label="Settings">
|
|
490
|
+
<pds-icon icon="gear"></pds-icon>
|
|
491
|
+
</button>
|
|
492
|
+
<button class="btn-secondary icon-only" disabled aria-label="Search">
|
|
493
|
+
<pds-icon icon="magnifying-glass"></pds-icon>
|
|
494
|
+
</button>
|
|
495
|
+
<button class="btn-outline icon-only" disabled aria-label="Heart">
|
|
496
|
+
<pds-icon icon="heart"></pds-icon>
|
|
497
|
+
</button>
|
|
498
|
+
</div>
|
|
499
|
+
</div>
|
|
500
|
+
|
|
501
|
+
<div class="card">
|
|
502
|
+
<h3>Buttons with Icons</h3>
|
|
503
|
+
<div class="flex flex-wrap gap-sm">
|
|
504
|
+
<button class="btn-primary" disabled>
|
|
505
|
+
<pds-icon icon="plus" size="sm"></pds-icon>
|
|
506
|
+
Add Item
|
|
507
|
+
</button>
|
|
508
|
+
<button class="btn-secondary" disabled>
|
|
509
|
+
<pds-icon icon="download" size="sm"></pds-icon>
|
|
510
|
+
Download
|
|
511
|
+
</button>
|
|
512
|
+
</div>
|
|
513
|
+
</div>
|
|
514
|
+
|
|
515
|
+
<div class="card">
|
|
516
|
+
<h3>Form Controls</h3>
|
|
517
|
+
<div class="max-w-md">
|
|
518
|
+
<label>
|
|
519
|
+
<span>Disabled Input</span>
|
|
520
|
+
<input type="text" disabled value="Cannot edit" />
|
|
521
|
+
</label>
|
|
522
|
+
|
|
523
|
+
<label>
|
|
524
|
+
<span>Disabled Select</span>
|
|
525
|
+
<select disabled>
|
|
526
|
+
<option>Cannot select</option>
|
|
527
|
+
</select>
|
|
528
|
+
</label>
|
|
529
|
+
|
|
530
|
+
<label>
|
|
531
|
+
<span>Disabled Textarea</span>
|
|
532
|
+
<textarea disabled rows="3">Cannot edit this text</textarea>
|
|
533
|
+
</label>
|
|
534
|
+
|
|
535
|
+
<fieldset role="group">
|
|
536
|
+
<legend>Disabled Checkboxes</legend>
|
|
537
|
+
<label>
|
|
538
|
+
<input type="checkbox" disabled />
|
|
539
|
+
<span>Disabled unchecked</span>
|
|
540
|
+
</label>
|
|
541
|
+
<label>
|
|
542
|
+
<input type="checkbox" disabled checked />
|
|
543
|
+
<span>Disabled checked</span>
|
|
544
|
+
</label>
|
|
545
|
+
</fieldset>
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
548
|
+
`;
|
|
549
|
+
|
|
550
|
+
DisabledStates.storyName = 'Disabled States';
|
|
551
|
+
|
|
552
|
+
export const CombinedStates = () => html`
|
|
553
|
+
<div class="card">
|
|
554
|
+
<h2>Combined State Examples</h2>
|
|
555
|
+
<p>Comprehensive examples showing all interactive states together</p>
|
|
556
|
+
</div>
|
|
557
|
+
|
|
558
|
+
<div class="card">
|
|
559
|
+
<h3>Idle State</h3>
|
|
560
|
+
<div class="flex flex-wrap gap-sm">
|
|
561
|
+
<button class="btn-primary">Primary</button>
|
|
562
|
+
<button class="btn-secondary">Secondary</button>
|
|
563
|
+
<button class="btn-outline">Outline</button>
|
|
564
|
+
</div>
|
|
565
|
+
</div>
|
|
566
|
+
|
|
567
|
+
<div class="card">
|
|
568
|
+
<h3>Hover State</h3>
|
|
569
|
+
<p class="text-muted text-sm">Hover over buttons to see effect</p>
|
|
570
|
+
<div class="flex flex-wrap gap-sm">
|
|
571
|
+
<button class="btn-primary">Primary</button>
|
|
572
|
+
<button class="btn-secondary">Secondary</button>
|
|
573
|
+
<button class="btn-outline">Outline</button>
|
|
574
|
+
</div>
|
|
575
|
+
</div>
|
|
576
|
+
|
|
577
|
+
<div class="card">
|
|
578
|
+
<h3>Active State</h3>
|
|
579
|
+
<p class="text-muted text-sm">Click and hold to see effect</p>
|
|
580
|
+
<div class="flex flex-wrap gap-sm">
|
|
581
|
+
<button class="btn-primary">Primary</button>
|
|
582
|
+
<button class="btn-secondary">Secondary</button>
|
|
583
|
+
<button class="btn-outline">Outline</button>
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
|
|
587
|
+
<div class="card">
|
|
588
|
+
<h3>Focus State</h3>
|
|
589
|
+
<p class="text-muted text-sm">Tab to focus on buttons</p>
|
|
590
|
+
<div class="flex flex-wrap gap-sm">
|
|
591
|
+
<button class="btn-primary">Primary</button>
|
|
592
|
+
<button class="btn-secondary">Secondary</button>
|
|
593
|
+
<button class="btn-outline">Outline</button>
|
|
594
|
+
</div>
|
|
595
|
+
</div>
|
|
596
|
+
|
|
597
|
+
<div class="card">
|
|
598
|
+
<h3>Disabled State</h3>
|
|
599
|
+
<div class="flex flex-wrap gap-sm">
|
|
600
|
+
<button class="btn-primary" disabled>Primary</button>
|
|
601
|
+
<button class="btn-secondary" disabled>Secondary</button>
|
|
602
|
+
<button class="btn-outline" disabled>Outline</button>
|
|
603
|
+
</div>
|
|
604
|
+
</div>
|
|
605
|
+
|
|
606
|
+
<div class="card">
|
|
607
|
+
<h3>Working State</h3>
|
|
608
|
+
<div class="flex flex-wrap gap-sm">
|
|
609
|
+
<button class="btn-primary btn-working">
|
|
610
|
+
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
611
|
+
Primary
|
|
612
|
+
</button>
|
|
613
|
+
<button class="btn-secondary btn-working">
|
|
614
|
+
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
615
|
+
Secondary
|
|
616
|
+
</button>
|
|
617
|
+
<button class="btn-outline btn-working">
|
|
618
|
+
<pds-icon icon="circle-notch" size="sm"></pds-icon>
|
|
619
|
+
Outline
|
|
620
|
+
</button>
|
|
621
|
+
</div>
|
|
622
|
+
</div>
|
|
623
|
+
`;
|
|
624
|
+
|
|
625
|
+
CombinedStates.storyName = 'All States';
|