@pure-ds/storybook 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pds-reference.json +1 -1
- package/package.json +3 -3
- package/scripts/package-build.js +2 -4
- package/stories/GettingStarted.md +96 -96
- package/stories/components/PdsDrawer.stories.js +602 -19
- package/stories/components/PdsIcon.stories.js +22 -6
- package/stories/components/PdsTabstrip.stories.js +434 -26
- package/stories/foundations/Colors.stories.js +240 -75
- package/stories/foundations/Icons.stories.js +287 -177
- package/stories/foundations/Spacing.stories.js +161 -57
- package/stories/foundations/Typography.stories.js +945 -68
- package/stories/primitives/Alerts.stories.js +25 -31
- package/stories/primitives/Badges.stories.js +146 -35
- package/stories/primitives/Buttons.stories.js +213 -85
- package/stories/primitives/Cards.stories.js +330 -53
- package/stories/primitives/Forms.stories.js +92 -161
|
@@ -1,8 +1,139 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
|
|
3
|
+
const toRgb = (raw) => {
|
|
4
|
+
if (!raw) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const value = raw.trim();
|
|
9
|
+
|
|
10
|
+
if (!value) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const hexMatch = value.match(/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i);
|
|
15
|
+
if (hexMatch) {
|
|
16
|
+
let hex = hexMatch[1];
|
|
17
|
+
|
|
18
|
+
if (hex.length === 3) {
|
|
19
|
+
hex = hex
|
|
20
|
+
.split('')
|
|
21
|
+
.map((ch) => ch + ch)
|
|
22
|
+
.join('');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (hex.length === 8) {
|
|
26
|
+
hex = hex.slice(0, 6);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const intVal = parseInt(hex, 16);
|
|
30
|
+
return {
|
|
31
|
+
r: (intVal >> 16) & 255,
|
|
32
|
+
g: (intVal >> 8) & 255,
|
|
33
|
+
b: intVal & 255
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const rgbMatch = value.match(/rgba?\(([^)]+)\)/i);
|
|
38
|
+
if (rgbMatch) {
|
|
39
|
+
const parts = rgbMatch[1]
|
|
40
|
+
.split(',')
|
|
41
|
+
.map((part) => part.trim())
|
|
42
|
+
.map((part) => (part.endsWith('%') ? (255 * parseFloat(part)) / 100 : parseFloat(part)));
|
|
43
|
+
|
|
44
|
+
if (parts.length < 3 || parts.some((part) => Number.isNaN(part))) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
r: Math.max(0, Math.min(255, parts[0])),
|
|
50
|
+
g: Math.max(0, Math.min(255, parts[1])),
|
|
51
|
+
b: Math.max(0, Math.min(255, parts[2]))
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return null;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const toRelativeLuminance = ({ r, g, b }) => {
|
|
59
|
+
const channel = (value) => {
|
|
60
|
+
const normalized = value / 255;
|
|
61
|
+
return normalized <= 0.04045
|
|
62
|
+
? normalized / 12.92
|
|
63
|
+
: Math.pow((normalized + 0.055) / 1.055, 2.4);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const rLin = channel(r);
|
|
67
|
+
const gLin = channel(g);
|
|
68
|
+
const bLin = channel(b);
|
|
69
|
+
|
|
70
|
+
return 0.2126 * rLin + 0.7152 * gLin + 0.0722 * bLin;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const contrastRatio = (a, b) => {
|
|
74
|
+
const l1 = toRelativeLuminance(a);
|
|
75
|
+
const l2 = toRelativeLuminance(b);
|
|
76
|
+
|
|
77
|
+
const lighter = Math.max(l1, l2);
|
|
78
|
+
const darker = Math.min(l1, l2);
|
|
79
|
+
|
|
80
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Prefers the highest-contrast candidate for each swatch at runtime.
|
|
84
|
+
const chooseReadableTextColor = (colorName, shade, fallback) => {
|
|
85
|
+
if (typeof window === 'undefined' || !window.getComputedStyle) {
|
|
86
|
+
return fallback;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const style = window.getComputedStyle(document.documentElement);
|
|
90
|
+
const backgroundValue = style.getPropertyValue(`--color-${colorName}-${shade}`);
|
|
91
|
+
const background = toRgb(backgroundValue);
|
|
92
|
+
|
|
93
|
+
if (!background) {
|
|
94
|
+
return fallback;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const candidateSources = [
|
|
98
|
+
'--surface-inverse-text',
|
|
99
|
+
'--surface-text',
|
|
100
|
+
`--color-${colorName}-900`,
|
|
101
|
+
`--color-${colorName}-50`,
|
|
102
|
+
'#ffffff',
|
|
103
|
+
'#000000'
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
let best = { value: fallback, ratio: 0 };
|
|
107
|
+
|
|
108
|
+
for (const source of candidateSources) {
|
|
109
|
+
let raw = source;
|
|
110
|
+
|
|
111
|
+
if (source.startsWith('--')) {
|
|
112
|
+
raw = style.getPropertyValue(source);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const rgb = toRgb(raw);
|
|
116
|
+
|
|
117
|
+
if (!rgb) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const ratio = contrastRatio(background, rgb);
|
|
122
|
+
|
|
123
|
+
if (ratio > best.ratio) {
|
|
124
|
+
best = { value: `rgb(${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)})`, ratio };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return best.value || fallback;
|
|
129
|
+
};
|
|
130
|
+
|
|
3
131
|
export default {
|
|
4
132
|
title: 'Foundations/Colors',
|
|
5
133
|
parameters: {
|
|
134
|
+
pds: {
|
|
135
|
+
tags: ['colors']
|
|
136
|
+
},
|
|
6
137
|
docs: {
|
|
7
138
|
description: {
|
|
8
139
|
component: 'Design tokens - colors, typography, spacing, icons'
|
|
@@ -26,89 +157,123 @@ export default {
|
|
|
26
157
|
}
|
|
27
158
|
};
|
|
28
159
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
160
|
+
const colorNames = [
|
|
161
|
+
'primary',
|
|
162
|
+
'secondary',
|
|
163
|
+
'accent',
|
|
164
|
+
'success',
|
|
165
|
+
'warning',
|
|
166
|
+
'danger',
|
|
167
|
+
'info'
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
const colorShades = [50, 100, 200, 300, 400, 500, 600, 700, 800];
|
|
171
|
+
|
|
172
|
+
const getFallbackTextColor = (color, shade) =>
|
|
173
|
+
shade >= 400
|
|
174
|
+
? 'var(--surface-inverse-text, #ffffff)'
|
|
175
|
+
: `var(--color-${color}-900)`;
|
|
176
|
+
|
|
177
|
+
const colorScaleStoryStyles = html`
|
|
178
|
+
<style>
|
|
179
|
+
.color-scale-story-container {
|
|
180
|
+
padding: var(--spacing-8);
|
|
36
181
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (args.primaryColor || args.secondaryColor) {
|
|
40
|
-
import('../../../src/js/pds.js').then(({ PDS }) => {
|
|
41
|
-
PDS.applyDesign({
|
|
42
|
-
design: {
|
|
43
|
-
colors: {
|
|
44
|
-
primary: args.primaryColor,
|
|
45
|
-
secondary: args.secondaryColor
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
});
|
|
182
|
+
.color-scale-container {
|
|
183
|
+
margin-bottom: var(--spacing-8);
|
|
50
184
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
185
|
+
.color-scale-row {
|
|
186
|
+
display: flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
gap: var(--spacing-4);
|
|
189
|
+
}
|
|
190
|
+
.color-scale-label {
|
|
191
|
+
width: 7.5rem;
|
|
192
|
+
font-weight: 600;
|
|
193
|
+
}
|
|
194
|
+
.color-scale-swatches {
|
|
195
|
+
display: flex;
|
|
196
|
+
flex: 1;
|
|
197
|
+
}
|
|
198
|
+
.color-scale-swatch {
|
|
199
|
+
flex: 1;
|
|
200
|
+
min-height: 3.75rem;
|
|
201
|
+
padding: var(--spacing-4);
|
|
202
|
+
text-align: center;
|
|
203
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
204
|
+
cursor: pointer;
|
|
205
|
+
position: relative;
|
|
206
|
+
z-index: 1;
|
|
207
|
+
}
|
|
208
|
+
.color-scale-swatch--hover {
|
|
209
|
+
transform: translateY(-0.25rem);
|
|
210
|
+
z-index: 10;
|
|
211
|
+
box-shadow: var(--shadow-md);
|
|
212
|
+
}
|
|
213
|
+
${colorNames
|
|
214
|
+
.map((color) =>
|
|
215
|
+
colorShades
|
|
216
|
+
.map((shade) => {
|
|
217
|
+
const textColor = getFallbackTextColor(color, shade);
|
|
218
|
+
return `
|
|
219
|
+
.color-scale-swatch[data-color="${color}"][data-shade="${shade}"] {
|
|
220
|
+
background: var(--color-${color}-${shade});
|
|
221
|
+
color: ${textColor};
|
|
222
|
+
}
|
|
223
|
+
`;
|
|
224
|
+
})
|
|
225
|
+
.join('\n')
|
|
226
|
+
)
|
|
227
|
+
.join('\n')}
|
|
228
|
+
</style>
|
|
229
|
+
`;
|
|
79
230
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
<h3>Gray Scale (from Secondary)</h3>
|
|
96
|
-
<div class="gray-scale-grid">
|
|
97
|
-
${[50, 100, 200, 300, 400, 500, 600, 700, 800].map(
|
|
231
|
+
const handleSwatchHoverEnter = (event) => {
|
|
232
|
+
event.currentTarget.classList.add('color-scale-swatch--hover');
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const handleSwatchHoverLeave = (event) => {
|
|
236
|
+
event.currentTarget.classList.remove('color-scale-swatch--hover');
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const renderColorScale = (colorName) => html`
|
|
240
|
+
<div class="color-scale-container">
|
|
241
|
+
<div class="color-scale-row">
|
|
242
|
+
<div class="color-scale-label">${colorName}</div>
|
|
243
|
+
<div class="color-scale-swatches">
|
|
244
|
+
${colorShades.map(
|
|
98
245
|
(shade) => html`
|
|
99
|
-
<div
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
246
|
+
<div
|
|
247
|
+
class="color-scale-swatch"
|
|
248
|
+
data-color=${colorName}
|
|
249
|
+
data-shade=${shade}
|
|
250
|
+
style=${`color: ${chooseReadableTextColor(colorName, shade, getFallbackTextColor(colorName, shade))}`}
|
|
251
|
+
@mouseover=${handleSwatchHoverEnter}
|
|
252
|
+
@mouseout=${handleSwatchHoverLeave}
|
|
253
|
+
title="${colorName}-${shade}"
|
|
254
|
+
>
|
|
255
|
+
${shade}
|
|
106
256
|
</div>
|
|
107
257
|
`
|
|
108
258
|
)}
|
|
109
259
|
</div>
|
|
110
|
-
</
|
|
111
|
-
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
`;
|
|
263
|
+
|
|
264
|
+
export const Default = {
|
|
265
|
+
render: (args) => {
|
|
266
|
+
return html`
|
|
267
|
+
${colorScaleStoryStyles}
|
|
268
|
+
<div class="story-container color-scale-story-container">
|
|
269
|
+
<h2>Color Scales</h2>
|
|
270
|
+
${renderColorScale('primary')}
|
|
271
|
+
${renderColorScale('secondary')}
|
|
272
|
+
${renderColorScale('accent')}
|
|
273
|
+
${renderColorScale('success')}
|
|
274
|
+
${renderColorScale('warning')}
|
|
275
|
+
${renderColorScale('danger')}
|
|
276
|
+
${renderColorScale('info')}
|
|
112
277
|
</div>
|
|
113
278
|
`;
|
|
114
279
|
},
|