@pure-ds/storybook 0.1.3 → 0.1.4

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.
@@ -1,139 +1,8 @@
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
-
131
3
  export default {
132
4
  title: 'Foundations/Colors',
133
5
  parameters: {
134
- pds: {
135
- tags: ['colors']
136
- },
137
6
  docs: {
138
7
  description: {
139
8
  component: 'Design tokens - colors, typography, spacing, icons'
@@ -157,123 +26,89 @@ export default {
157
26
  }
158
27
  };
159
28
 
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);
181
- }
182
- .color-scale-container {
183
- margin-bottom: var(--spacing-8);
184
- }
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;
29
+ export const Default = {
30
+ render: (args) => {
31
+ // Apply preset if changed
32
+ if (args.preset) {
33
+ import('../../../src/js/pds.js').then(({ PDS }) => {
34
+ PDS.applyDesign({ preset: args.preset });
35
+ });
207
36
  }
208
- .color-scale-swatch--hover {
209
- transform: translateY(-0.25rem);
210
- z-index: 10;
211
- box-shadow: var(--shadow-md);
37
+
38
+ // Apply color overrides
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
+ });
212
50
  }
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
- `;
230
-
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
- };
51
+
52
+
53
+ const renderColorCard = (name, color) => html`
54
+ <div class="color-card">
55
+ <div class="color-swatch" style="background-color: var(--color-${color}-500);"></div>
56
+ <div class="color-info">
57
+ <strong>${name}</strong>
58
+ <code>var(--color-${color}-500)</code>
59
+ </div>
60
+ <div class="color-scale" style="--scale-color: var(--color-${color}-500);">
61
+ ${[50, 100, 200, 300, 400, 500, 600, 700, 800, 900].map(
62
+ (shade) => html`<div style="--value: ${shade}"></div>`
63
+ )}
64
+ </div>
65
+ </div>
66
+ `;
67
+
68
+ const renderColorScale = (color) => html`
69
+ <div class="color-scale-row">
70
+ ${[50, 100, 200, 300, 400, 500, 600, 700, 800, 900].map(shade => html`
71
+ <div class="scale-item">
72
+ <div class="swatch" style="background-color: var(--color-${color}-${shade})"></div>
73
+ <span class="label">${shade}</span>
74
+ </div>
75
+ `)}
76
+ </div>
77
+ `;
78
+
238
79
 
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(
80
+ return html`
81
+ <div class="story-container" style="padding: 2rem;">
82
+
83
+ <section class="showcase-section" data-section="color-system">
84
+ <h2><pds-icon icon="palette" size="lg" class="icon-primary"></pds-icon> Color System</h2>
85
+ <div class="color-grid">
86
+ ${renderColorCard("Primary", "primary")}
87
+ ${renderColorCard("Secondary", "secondary")}
88
+ ${renderColorCard("Accent", "accent")}
89
+ ${renderColorCard("Success", "success")}
90
+ ${renderColorCard("Warning", "warning")}
91
+ ${renderColorCard("Danger", "danger")}
92
+ ${renderColorCard("Info", "info")}
93
+ </div>
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(
245
98
  (shade) => html`
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}
99
+ <div class="gray-scale-item">
100
+ <div
101
+ class="gray-scale-swatch"
102
+ style="background-color: var(--color-gray-${shade});"
103
+ title="gray-${shade}"
104
+ ></div>
105
+ <div class="gray-scale-label">${shade}</div>
256
106
  </div>
257
107
  `
258
108
  )}
259
109
  </div>
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')}
110
+ </section>
111
+
277
112
  </div>
278
113
  `;
279
114
  },