@usefidel/design-system 0.9.0 → 0.11.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/dist/admin.css CHANGED
@@ -7,6 +7,7 @@
7
7
  --color-text: #171717;
8
8
  --color-text-secondary: #525252;
9
9
  --color-text-muted: #a3a3a3;
10
+ --color-text-tertiary: #737373;
10
11
  --color-border: #e5e5e5;
11
12
  --color-border-light: #f5f5f5;
12
13
  --color-border-strong: #d4d4d4;
@@ -20,6 +21,7 @@
20
21
  --color-primary-hover: #262626;
21
22
  --color-primary-text: #ffffff;
22
23
  --color-critical: #ef4444;
24
+ --color-destructive: #eb2d2d;
23
25
  --color-high: #f59e0b;
24
26
  --color-high-bg: #fffbeb;
25
27
  --color-high-text: #92400e;
@@ -44,6 +46,8 @@
44
46
  --color-actual-text: #dc2626;
45
47
  --color-focus: #ea580c;
46
48
  --color-info: #1d4ed8;
49
+ --color-info-strong: #2563eb;
50
+ --color-info-surface: #eff6ff;
47
51
  --font-display: 'Rethink Sans', system-ui, -apple-system, sans-serif;
48
52
  --font-body: 'Rethink Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
49
53
  --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
@@ -55,6 +59,7 @@
55
59
  --radius-xl: 12px;
56
60
  --radius-2xl: 16px;
57
61
  --radius-3xl: 24px;
62
+ --radius-card: 14px;
58
63
  --radius-pill: 9999px;
59
64
  --radius-full: 9999px;
60
65
  --spacing-1: 4px;
@@ -7,6 +7,7 @@
7
7
  --color-text: #0f172a;
8
8
  --color-text-secondary: #475569;
9
9
  --color-text-muted: #a3a3a3;
10
+ --color-text-tertiary: #737373;
10
11
  --color-border: #e2e5ea;
11
12
  --color-border-light: #ebeff3;
12
13
  --color-border-strong: #d1d5db;
@@ -20,6 +21,7 @@
20
21
  --color-primary-hover: #1e293b;
21
22
  --color-primary-text: #ffffff;
22
23
  --color-critical: #ef4444;
24
+ --color-destructive: #eb2d2d;
23
25
  --color-high: #f59e0b;
24
26
  --color-high-bg: #fffbeb;
25
27
  --color-high-text: #92400e;
@@ -44,6 +46,8 @@
44
46
  --color-actual-text: #dc2626;
45
47
  --color-focus: #ea580c;
46
48
  --color-info: #1d4ed8;
49
+ --color-info-strong: #2563eb;
50
+ --color-info-surface: #eff6ff;
47
51
  --font-display: 'Rethink Sans', system-ui, -apple-system, sans-serif;
48
52
  --font-body: 'Rethink Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
49
53
  --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
@@ -55,6 +59,7 @@
55
59
  --radius-xl: 12px;
56
60
  --radius-2xl: 16px;
57
61
  --radius-3xl: 24px;
62
+ --radius-card: 14px;
58
63
  --radius-pill: 20px;
59
64
  --radius-full: 9999px;
60
65
  --spacing-1: 4px;
@@ -10,6 +10,6 @@
10
10
  "webapp.css"
11
11
  ],
12
12
  "storybookUrl": null,
13
- "packageVersion": "0.9.0",
14
- "resolvedSha": "e41a4c4ba174007088f26caf33a5d2c8ddd43094"
13
+ "packageVersion": "0.11.0",
14
+ "resolvedSha": "40acd49195f775e019c290143a6f0b6fa27ab9c9"
15
15
  }
package/dist/index.cjs CHANGED
@@ -68,6 +68,7 @@ function MismatchCard({
68
68
  const [expanded, setExpanded] = (0, import_react.useState)(defaultExpanded);
69
69
  const canToggle = properties.length > collapsedCount;
70
70
  const visible = expanded || !canToggle ? properties : properties.slice(0, collapsedCount);
71
+ const hiddenCount = properties.length - collapsedCount;
71
72
  const classes = ["fds-mismatch-card", className].filter(Boolean).join(" ");
72
73
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: classes, ...rest, children: [
73
74
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "fds-mismatch-card__content", children: [
@@ -89,19 +90,22 @@ function MismatchCard({
89
90
  onClick: () => setExpanded((v) => !v),
90
91
  children: [
91
92
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Chevron, { direction: expanded ? "up" : "down" }),
92
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fds-mismatch-card__toggle-label", children: expanded ? "Show less" : "Show more" })
93
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fds-mismatch-card__toggle-label", children: expanded ? "Show less" : showMoreLabel(hiddenCount) })
93
94
  ]
94
95
  }
95
96
  )
96
97
  ] });
97
98
  }
99
+ function showMoreLabel(hiddenCount) {
100
+ return `Show ${hiddenCount} more ${hiddenCount === 1 ? "mismatch" : "mismatches"}`;
101
+ }
98
102
  function Chevron({ direction }) {
99
103
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
100
104
  "svg",
101
105
  {
102
106
  className: `fds-mismatch-card__chevron fds-mismatch-card__chevron--${direction}`,
103
- width: "20",
104
- height: "20",
107
+ width: "18",
108
+ height: "18",
105
109
  viewBox: "0 0 20 20",
106
110
  fill: "none",
107
111
  "aria-hidden": "true",
@@ -162,11 +166,13 @@ function DiffSection({
162
166
  onClick: () => setExpanded((v) => !v),
163
167
  children: [
164
168
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "fds-diff-section__head-left", children: [
165
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Chevron2, { open: expanded }),
166
169
  number != null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__number", children: number }),
167
170
  name != null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__name", children: name })
168
171
  ] }),
169
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__count", children: plural(count, "mismatch", "mismatches") })
172
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "fds-diff-section__head-right", children: [
173
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__count", children: plural(count, "mismatch", "mismatches") }),
174
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(HeaderChevron, { expanded })
175
+ ] })
170
176
  ]
171
177
  }
172
178
  ),
@@ -227,6 +233,7 @@ function ElementRow({
227
233
  children: lines
228
234
  }
229
235
  ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fds-diff-section__element-head", children: lines }),
236
+ element.sourceUrl != null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ViewSource, { href: element.sourceUrl, label: element.sourceLabel ?? "View source" }),
230
237
  hasDetail && open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fds-diff-section__detail", children: element.detail })
231
238
  ]
232
239
  }
@@ -244,6 +251,47 @@ function DiffPropertyList({ properties, className, ...rest }) {
244
251
  line.trailing != null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__trailing", children: line.trailing })
245
252
  ] }, `${line.property}-${li}`)) });
246
253
  }
254
+ function ViewSource({ href, label }) {
255
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
256
+ "a",
257
+ {
258
+ className: "fds-diff-section__source",
259
+ href,
260
+ target: "_blank",
261
+ rel: "noreferrer noopener",
262
+ onClick: (e) => e.stopPropagation(),
263
+ children: [
264
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__source-label", children: label }),
265
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
266
+ "path",
267
+ {
268
+ d: "M7.5 12.5 12.5 7.5M8 7.5h4.5V12",
269
+ stroke: "currentColor",
270
+ strokeWidth: "1.5",
271
+ strokeLinecap: "round",
272
+ strokeLinejoin: "round"
273
+ }
274
+ ) })
275
+ ]
276
+ }
277
+ );
278
+ }
279
+ function HeaderChevron({ expanded }) {
280
+ const classes = [
281
+ "fds-diff-section__header-chevron",
282
+ expanded && "fds-diff-section__header-chevron--expanded"
283
+ ].filter(Boolean).join(" ");
284
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": "true", className: classes, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
285
+ "path",
286
+ {
287
+ d: "M5 11 9 7l4 4",
288
+ stroke: "currentColor",
289
+ strokeWidth: "1.5",
290
+ strokeLinecap: "round",
291
+ strokeLinejoin: "round"
292
+ }
293
+ ) });
294
+ }
247
295
  function Chevron2({ open, className }) {
248
296
  const classes = [
249
297
  "fds-diff-section__chevron",
package/dist/index.css CHANGED
@@ -129,19 +129,16 @@
129
129
  box-sizing: border-box;
130
130
  display: flex;
131
131
  flex-direction: column;
132
- align-items: center;
133
- gap: 14px;
132
+ align-items: flex-start;
133
+ gap: 10px;
134
134
  width: max-content;
135
- max-width: 368px;
136
- padding: var(--spacing-6);
137
- background: rgba(255, 255, 255, 0.4);
138
- backdrop-filter: blur(24px);
139
- -webkit-backdrop-filter: blur(24px);
140
- border: 2px solid var(--color-accent);
141
- border-radius: var(--radius-lg);
142
- box-shadow: 0 15px 35px 0 rgba(151, 151, 151, 0.2);
135
+ max-width: 300px;
136
+ padding: var(--spacing-4);
137
+ background: var(--color-bg);
138
+ border: 1px solid var(--color-border);
139
+ border-radius: var(--radius-card);
140
+ box-shadow: 0 15px 35px 0 rgba(151, 151, 151, 0.12);
143
141
  font-family: var(--font-body);
144
- overflow: clip;
145
142
  }
146
143
  .fds-mismatch-card *,
147
144
  .fds-mismatch-card *::before,
@@ -152,27 +149,24 @@
152
149
  display: flex;
153
150
  flex-direction: column;
154
151
  align-items: flex-start;
155
- gap: var(--spacing-5);
156
- width: 320px;
152
+ gap: 10px;
153
+ width: 100%;
157
154
  }
158
155
  .fds-mismatch-card__title {
159
156
  margin: 0;
160
157
  width: 100%;
161
158
  font-family: var(--font-display);
162
159
  font-weight: var(--font-weight-semibold);
163
- font-size: 16px;
164
- line-height: 24px;
165
- letter-spacing: -0.0288px;
160
+ font-size: var(--font-size-text-sm);
161
+ line-height: 20px;
166
162
  color: var(--color-text);
167
- white-space: nowrap;
168
- overflow: hidden;
169
- text-overflow: ellipsis;
163
+ overflow-wrap: break-word;
170
164
  }
171
165
  .fds-mismatch-card__rows {
172
166
  display: flex;
173
167
  flex-direction: column;
174
168
  align-items: flex-start;
175
- gap: var(--spacing-3);
169
+ gap: var(--spacing-2);
176
170
  width: 100%;
177
171
  }
178
172
  .fds-mismatch-card__row {
@@ -181,45 +175,48 @@
181
175
  align-items: flex-start;
182
176
  gap: var(--spacing-2);
183
177
  width: 100%;
184
- border-bottom: 1px solid var(--color-border-strong);
178
+ padding-bottom: var(--spacing-1);
179
+ border-bottom: 1px solid #fafafa;
185
180
  }
186
181
  .fds-mismatch-card__label {
187
182
  width: 100%;
183
+ font-family: var(--font-mono);
188
184
  font-weight: var(--font-weight-medium);
189
- font-size: 14px;
190
- line-height: 22px;
185
+ font-size: var(--font-size-label-xs);
186
+ line-height: var(--line-height-label-xs);
187
+ letter-spacing: -0.24px;
191
188
  color: var(--color-text-secondary);
192
189
  }
193
190
  .fds-mismatch-card__values {
194
191
  display: flex;
195
- justify-content: space-between;
192
+ gap: var(--spacing-8);
196
193
  width: 100%;
197
- padding: var(--spacing-1) 0;
198
194
  font-weight: var(--font-weight-medium);
199
- font-size: 14px;
200
- line-height: 22px;
195
+ font-size: var(--font-size-text-xs);
196
+ line-height: var(--line-height-text-xs);
201
197
  white-space: nowrap;
202
198
  }
203
199
  .fds-mismatch-card__live {
204
- color: var(--color-actual-text);
200
+ color: var(--color-destructive);
205
201
  }
206
202
  .fds-mismatch-card__design {
207
- color: #262626;
203
+ color: var(--color-text);
208
204
  }
209
205
  .fds-mismatch-card__toggle {
210
206
  display: flex;
211
207
  align-items: center;
212
208
  gap: 2px;
213
- width: 320px;
214
- padding: var(--spacing-2) 0;
209
+ width: 100%;
210
+ padding: var(--spacing-1) 0;
215
211
  border: 0;
216
212
  background: none;
217
- border-radius: var(--radius-md);
213
+ border-radius: var(--radius-lg);
218
214
  cursor: pointer;
219
215
  font-family: var(--font-display);
220
216
  font-weight: var(--font-weight-semibold);
221
- font-size: 14px;
222
- line-height: 20px;
217
+ font-size: var(--font-size-text-xs);
218
+ line-height: var(--line-height-text-xs);
219
+ text-align: left;
223
220
  color: var(--color-text-secondary);
224
221
  }
225
222
  .fds-mismatch-card__chevron {
@@ -295,6 +292,20 @@
295
292
  line-height: 22px;
296
293
  color: var(--color-text);
297
294
  }
295
+ .fds-diff-section__head-right {
296
+ display: flex;
297
+ align-items: center;
298
+ justify-content: center;
299
+ gap: var(--spacing-2);
300
+ }
301
+ .fds-diff-section__header-chevron {
302
+ flex-shrink: 0;
303
+ color: var(--color-text-secondary);
304
+ transition: transform var(--duration-quick, 150ms) ease;
305
+ }
306
+ .fds-diff-section__header-chevron--expanded {
307
+ transform: rotate(180deg);
308
+ }
298
309
  .fds-diff-section__count {
299
310
  font-weight: var(--font-weight-regular);
300
311
  font-size: 14px;
@@ -308,6 +319,7 @@
308
319
  gap: var(--spacing-3);
309
320
  }
310
321
  .fds-diff-section__element {
322
+ position: relative;
311
323
  display: flex;
312
324
  flex-direction: column;
313
325
  transition: background var(--duration-quick, 150ms) ease;
@@ -355,15 +367,21 @@
355
367
  border-top: 1px solid var(--color-border-light);
356
368
  }
357
369
  .fds-diff-section__element-name {
370
+ display: inline-flex;
371
+ align-items: center;
372
+ justify-content: center;
373
+ padding: 2px var(--spacing-1);
374
+ background: var(--color-info-surface);
375
+ border-radius: var(--radius-xs);
358
376
  font-weight: var(--font-weight-medium);
359
- font-size: 14px;
360
- line-height: 22px;
377
+ font-size: var(--font-size-text-xs);
378
+ line-height: var(--line-height-text-xs);
361
379
  color: var(--color-text);
362
380
  }
363
381
  .fds-diff-section__element-count {
364
382
  font-weight: var(--font-weight-regular);
365
- font-size: 12px;
366
- line-height: 18px;
383
+ font-size: var(--font-size-text-xs);
384
+ line-height: var(--line-height-text-xs);
367
385
  color: var(--color-text-secondary);
368
386
  }
369
387
  .fds-diff-section__lines {
@@ -381,9 +399,9 @@
381
399
  .fds-diff-section__prop {
382
400
  font-family: var(--font-mono);
383
401
  font-weight: var(--font-weight-regular);
384
- font-size: 14px;
385
- line-height: 22px;
386
- letter-spacing: -0.28px;
402
+ font-size: var(--font-size-label-xs);
403
+ line-height: var(--line-height-label-xs);
404
+ letter-spacing: -0.24px;
387
405
  color: var(--color-text-secondary);
388
406
  white-space: nowrap;
389
407
  }
@@ -394,9 +412,9 @@
394
412
  margin-left: auto;
395
413
  font-family: var(--font-mono);
396
414
  font-weight: var(--font-weight-medium);
397
- font-size: 14px;
398
- line-height: 22px;
399
- letter-spacing: -0.28px;
415
+ font-size: var(--font-size-label-xs);
416
+ line-height: var(--line-height-label-xs);
417
+ letter-spacing: -0.24px;
400
418
  white-space: nowrap;
401
419
  }
402
420
  .fds-diff-section__trailing {
@@ -407,14 +425,53 @@
407
425
  flex-shrink: 0;
408
426
  }
409
427
  .fds-diff-section__live {
410
- color: #ef4444;
428
+ color: var(--color-text-tertiary);
429
+ text-decoration: line-through;
430
+ text-decoration-skip-ink: none;
411
431
  }
412
432
  .fds-diff-section__arrow {
413
433
  flex-shrink: 0;
414
434
  color: var(--color-text-muted);
415
435
  }
416
436
  .fds-diff-section__design {
417
- color: #1e8902;
437
+ color: var(--color-info-strong);
438
+ }
439
+ .fds-diff-section__source {
440
+ position: absolute;
441
+ top: var(--spacing-6);
442
+ left: var(--spacing-6);
443
+ z-index: 2;
444
+ display: inline-flex;
445
+ align-items: center;
446
+ gap: var(--spacing-2);
447
+ padding: var(--spacing-1) var(--spacing-2);
448
+ border-radius: var(--radius-lg);
449
+ background: var(--color-text);
450
+ color: var(--color-primary-text);
451
+ font-family: var(--font-body);
452
+ font-weight: var(--font-weight-medium);
453
+ font-size: var(--font-size-text-xs);
454
+ line-height: var(--line-height-text-xs);
455
+ text-decoration: none;
456
+ white-space: nowrap;
457
+ box-shadow: var(--shadow-lg);
458
+ opacity: 0;
459
+ visibility: hidden;
460
+ transition: opacity var(--duration-quick, 150ms) ease, visibility var(--duration-quick, 150ms) ease;
461
+ }
462
+ .fds-diff-section__element:hover .fds-diff-section__source,
463
+ .fds-diff-section__source:focus-visible {
464
+ opacity: 1;
465
+ visibility: visible;
466
+ }
467
+ .fds-diff-section__source:focus-visible {
468
+ outline: 2px solid var(--color-focus);
469
+ outline-offset: 2px;
470
+ }
471
+ @media (prefers-reduced-motion: reduce) {
472
+ .fds-diff-section__source {
473
+ transition: none;
474
+ }
418
475
  }
419
476
 
420
477
  /* src/components/Select/select.css */
package/dist/index.d.cts CHANGED
@@ -48,16 +48,23 @@ interface MismatchCardProps extends HTMLAttributes<HTMLDivElement> {
48
48
  defaultExpanded?: boolean;
49
49
  }
50
50
  /**
51
- * Fidel design-system MismatchCard — the card shown when hovering a
52
- * highlighted mismatch region on a validation screenshot.
51
+ * Fidel design-system MismatchCard — the mismatch inspector card shown when
52
+ * hovering a highlighted region on a validation screenshot.
53
+ *
54
+ * Built 1:1 from Figma node 3704:13475 (Fidel Library → Mismatch Inspector
55
+ * Card): a solid white card, 1px subtle border, monospace property labels, and
56
+ * a counted expand toggle.
53
57
  *
54
58
  * Presentational only: it knows nothing about the diff taxonomy. Callers map
55
59
  * their own data (e.g. a ValidationDiff) onto `title` + `properties`.
56
60
  *
61
+ * The numbered marker badge and pointer drawn alongside the card in Figma are
62
+ * deliberately NOT rendered here — they are positioned relative to the
63
+ * highlighted region on the screenshot, which only the caller knows about.
64
+ *
57
65
  * Framing is Live → Design (founder decision 2026-04-24): the left value is
58
66
  * what shipped (live), the right value is the design target. When there are
59
- * more than `collapsedCount` properties, a Show more / Show less toggle
60
- * reveals the rest.
67
+ * more than `collapsedCount` properties, a counted toggle reveals the rest.
61
68
  */
62
69
  declare function MismatchCard({ title, properties, collapsedCount, defaultExpanded, className, ...rest }: MismatchCardProps): react.JSX.Element;
63
70
 
@@ -117,6 +124,15 @@ interface DiffElement {
117
124
  * annotation) without threading a ref through the component.
118
125
  */
119
126
  anchorId?: string;
127
+ /**
128
+ * Where this element came from — a repo permalink, a Storybook story, a
129
+ * Figma node. When set, a "View source" affordance appears on hover (and on
130
+ * keyboard focus) next to the element name. Omit it and no affordance
131
+ * renders at all: the DS never invents a destination it cannot know.
132
+ */
133
+ sourceUrl?: string;
134
+ /** Accessible label for the source link. @default "View source" */
135
+ sourceLabel?: string;
120
136
  }
121
137
  interface DiffSectionProps extends HTMLAttributes<HTMLDivElement> {
122
138
  /** Ordinal shown before the name, e.g. "01". Omitted in `headerless` mode. */
package/dist/index.d.ts CHANGED
@@ -48,16 +48,23 @@ interface MismatchCardProps extends HTMLAttributes<HTMLDivElement> {
48
48
  defaultExpanded?: boolean;
49
49
  }
50
50
  /**
51
- * Fidel design-system MismatchCard — the card shown when hovering a
52
- * highlighted mismatch region on a validation screenshot.
51
+ * Fidel design-system MismatchCard — the mismatch inspector card shown when
52
+ * hovering a highlighted region on a validation screenshot.
53
+ *
54
+ * Built 1:1 from Figma node 3704:13475 (Fidel Library → Mismatch Inspector
55
+ * Card): a solid white card, 1px subtle border, monospace property labels, and
56
+ * a counted expand toggle.
53
57
  *
54
58
  * Presentational only: it knows nothing about the diff taxonomy. Callers map
55
59
  * their own data (e.g. a ValidationDiff) onto `title` + `properties`.
56
60
  *
61
+ * The numbered marker badge and pointer drawn alongside the card in Figma are
62
+ * deliberately NOT rendered here — they are positioned relative to the
63
+ * highlighted region on the screenshot, which only the caller knows about.
64
+ *
57
65
  * Framing is Live → Design (founder decision 2026-04-24): the left value is
58
66
  * what shipped (live), the right value is the design target. When there are
59
- * more than `collapsedCount` properties, a Show more / Show less toggle
60
- * reveals the rest.
67
+ * more than `collapsedCount` properties, a counted toggle reveals the rest.
61
68
  */
62
69
  declare function MismatchCard({ title, properties, collapsedCount, defaultExpanded, className, ...rest }: MismatchCardProps): react.JSX.Element;
63
70
 
@@ -117,6 +124,15 @@ interface DiffElement {
117
124
  * annotation) without threading a ref through the component.
118
125
  */
119
126
  anchorId?: string;
127
+ /**
128
+ * Where this element came from — a repo permalink, a Storybook story, a
129
+ * Figma node. When set, a "View source" affordance appears on hover (and on
130
+ * keyboard focus) next to the element name. Omit it and no affordance
131
+ * renders at all: the DS never invents a destination it cannot know.
132
+ */
133
+ sourceUrl?: string;
134
+ /** Accessible label for the source link. @default "View source" */
135
+ sourceLabel?: string;
120
136
  }
121
137
  interface DiffSectionProps extends HTMLAttributes<HTMLDivElement> {
122
138
  /** Ordinal shown before the name, e.g. "01". Omitted in `headerless` mode. */
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ function MismatchCard({
37
37
  const [expanded, setExpanded] = useState(defaultExpanded);
38
38
  const canToggle = properties.length > collapsedCount;
39
39
  const visible = expanded || !canToggle ? properties : properties.slice(0, collapsedCount);
40
+ const hiddenCount = properties.length - collapsedCount;
40
41
  const classes = ["fds-mismatch-card", className].filter(Boolean).join(" ");
41
42
  return /* @__PURE__ */ jsxs2("div", { className: classes, ...rest, children: [
42
43
  /* @__PURE__ */ jsxs2("div", { className: "fds-mismatch-card__content", children: [
@@ -58,19 +59,22 @@ function MismatchCard({
58
59
  onClick: () => setExpanded((v) => !v),
59
60
  children: [
60
61
  /* @__PURE__ */ jsx2(Chevron, { direction: expanded ? "up" : "down" }),
61
- /* @__PURE__ */ jsx2("span", { className: "fds-mismatch-card__toggle-label", children: expanded ? "Show less" : "Show more" })
62
+ /* @__PURE__ */ jsx2("span", { className: "fds-mismatch-card__toggle-label", children: expanded ? "Show less" : showMoreLabel(hiddenCount) })
62
63
  ]
63
64
  }
64
65
  )
65
66
  ] });
66
67
  }
68
+ function showMoreLabel(hiddenCount) {
69
+ return `Show ${hiddenCount} more ${hiddenCount === 1 ? "mismatch" : "mismatches"}`;
70
+ }
67
71
  function Chevron({ direction }) {
68
72
  return /* @__PURE__ */ jsx2(
69
73
  "svg",
70
74
  {
71
75
  className: `fds-mismatch-card__chevron fds-mismatch-card__chevron--${direction}`,
72
- width: "20",
73
- height: "20",
76
+ width: "18",
77
+ height: "18",
74
78
  viewBox: "0 0 20 20",
75
79
  fill: "none",
76
80
  "aria-hidden": "true",
@@ -131,11 +135,13 @@ function DiffSection({
131
135
  onClick: () => setExpanded((v) => !v),
132
136
  children: [
133
137
  /* @__PURE__ */ jsxs3("span", { className: "fds-diff-section__head-left", children: [
134
- /* @__PURE__ */ jsx3(Chevron2, { open: expanded }),
135
138
  number != null && /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__number", children: number }),
136
139
  name != null && /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__name", children: name })
137
140
  ] }),
138
- /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__count", children: plural(count, "mismatch", "mismatches") })
141
+ /* @__PURE__ */ jsxs3("span", { className: "fds-diff-section__head-right", children: [
142
+ /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__count", children: plural(count, "mismatch", "mismatches") }),
143
+ /* @__PURE__ */ jsx3(HeaderChevron, { expanded })
144
+ ] })
139
145
  ]
140
146
  }
141
147
  ),
@@ -196,6 +202,7 @@ function ElementRow({
196
202
  children: lines
197
203
  }
198
204
  ) : /* @__PURE__ */ jsx3("div", { className: "fds-diff-section__element-head", children: lines }),
205
+ element.sourceUrl != null && /* @__PURE__ */ jsx3(ViewSource, { href: element.sourceUrl, label: element.sourceLabel ?? "View source" }),
199
206
  hasDetail && open && /* @__PURE__ */ jsx3("div", { className: "fds-diff-section__detail", children: element.detail })
200
207
  ]
201
208
  }
@@ -213,6 +220,47 @@ function DiffPropertyList({ properties, className, ...rest }) {
213
220
  line.trailing != null && /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__trailing", children: line.trailing })
214
221
  ] }, `${line.property}-${li}`)) });
215
222
  }
223
+ function ViewSource({ href, label }) {
224
+ return /* @__PURE__ */ jsxs3(
225
+ "a",
226
+ {
227
+ className: "fds-diff-section__source",
228
+ href,
229
+ target: "_blank",
230
+ rel: "noreferrer noopener",
231
+ onClick: (e) => e.stopPropagation(),
232
+ children: [
233
+ /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__source-label", children: label }),
234
+ /* @__PURE__ */ jsx3("svg", { width: "14", height: "14", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(
235
+ "path",
236
+ {
237
+ d: "M7.5 12.5 12.5 7.5M8 7.5h4.5V12",
238
+ stroke: "currentColor",
239
+ strokeWidth: "1.5",
240
+ strokeLinecap: "round",
241
+ strokeLinejoin: "round"
242
+ }
243
+ ) })
244
+ ]
245
+ }
246
+ );
247
+ }
248
+ function HeaderChevron({ expanded }) {
249
+ const classes = [
250
+ "fds-diff-section__header-chevron",
251
+ expanded && "fds-diff-section__header-chevron--expanded"
252
+ ].filter(Boolean).join(" ");
253
+ return /* @__PURE__ */ jsx3("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": "true", className: classes, children: /* @__PURE__ */ jsx3(
254
+ "path",
255
+ {
256
+ d: "M5 11 9 7l4 4",
257
+ stroke: "currentColor",
258
+ strokeWidth: "1.5",
259
+ strokeLinecap: "round",
260
+ strokeLinejoin: "round"
261
+ }
262
+ ) });
263
+ }
216
264
  function Chevron2({ open, className }) {
217
265
  const classes = [
218
266
  "fds-diff-section__chevron",
package/dist/landing.css CHANGED
@@ -7,6 +7,7 @@
7
7
  --color-text: #171717;
8
8
  --color-text-secondary: #525252;
9
9
  --color-text-muted: #a3a3a3;
10
+ --color-text-tertiary: #737373;
10
11
  --color-border: #e5e5e5;
11
12
  --color-border-light: #f5f5f5;
12
13
  --color-border-strong: #d4d4d4;
@@ -20,6 +21,7 @@
20
21
  --color-primary-hover: #262626;
21
22
  --color-primary-text: #ffffff;
22
23
  --color-critical: #ef4444;
24
+ --color-destructive: #eb2d2d;
23
25
  --color-high: #f59e0b;
24
26
  --color-high-bg: #fffbeb;
25
27
  --color-high-text: #92400e;
@@ -44,6 +46,8 @@
44
46
  --color-actual-text: #dc2626;
45
47
  --color-focus: #ea580c;
46
48
  --color-info: #1d4ed8;
49
+ --color-info-strong: #2563eb;
50
+ --color-info-surface: #eff6ff;
47
51
  --font-display: 'Rethink Sans', system-ui, -apple-system, sans-serif;
48
52
  --font-body: 'Rethink Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
49
53
  --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
@@ -55,6 +59,7 @@
55
59
  --radius-xl: 12px;
56
60
  --radius-2xl: 16px;
57
61
  --radius-3xl: 24px;
62
+ --radius-card: 14px;
58
63
  --radius-pill: 9999px;
59
64
  --radius-full: 9999px;
60
65
  --spacing-1: 4px;
package/dist/theme.css CHANGED
@@ -9,6 +9,7 @@
9
9
  --color-text: #171717;
10
10
  --color-text-secondary: #525252;
11
11
  --color-text-muted: #a3a3a3;
12
+ --color-text-tertiary: #737373;
12
13
  --color-border: #e5e5e5;
13
14
  --color-border-light: #f5f5f5;
14
15
  --color-border-strong: #d4d4d4;
@@ -22,6 +23,7 @@
22
23
  --color-primary-hover: #262626;
23
24
  --color-primary-text: #ffffff;
24
25
  --color-critical: #ef4444;
26
+ --color-destructive: #eb2d2d;
25
27
  --color-high: #f59e0b;
26
28
  --color-high-bg: #fffbeb;
27
29
  --color-high-text: #92400e;
@@ -46,6 +48,8 @@
46
48
  --color-actual-text: #dc2626;
47
49
  --color-focus: #ea580c;
48
50
  --color-info: #1d4ed8;
51
+ --color-info-strong: #2563eb;
52
+ --color-info-surface: #eff6ff;
49
53
  --font-display: 'Rethink Sans', system-ui, -apple-system, sans-serif;
50
54
  --font-body: 'Rethink Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
51
55
  --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
@@ -57,6 +61,7 @@
57
61
  --radius-xl: 12px;
58
62
  --radius-2xl: 16px;
59
63
  --radius-3xl: 24px;
64
+ --radius-card: 14px;
60
65
  --radius-pill: 9999px;
61
66
  --radius-full: 9999px;
62
67
  --spacing-1: 4px;
package/dist/webapp.css CHANGED
@@ -7,6 +7,7 @@
7
7
  --color-text: #171717;
8
8
  --color-text-secondary: #525252;
9
9
  --color-text-muted: #a3a3a3;
10
+ --color-text-tertiary: #737373;
10
11
  --color-border: #e5e5e5;
11
12
  --color-border-light: #f5f5f5;
12
13
  --color-border-strong: #d4d4d4;
@@ -20,6 +21,7 @@
20
21
  --color-primary-hover: #262626;
21
22
  --color-primary-text: #ffffff;
22
23
  --color-critical: #ef4444;
24
+ --color-destructive: #eb2d2d;
23
25
  --color-high: #f59e0b;
24
26
  --color-high-bg: #fffbeb;
25
27
  --color-high-text: #92400e;
@@ -44,6 +46,8 @@
44
46
  --color-actual-text: #dc2626;
45
47
  --color-focus: #ea580c;
46
48
  --color-info: #1d4ed8;
49
+ --color-info-strong: #2563eb;
50
+ --color-info-surface: #eff6ff;
47
51
  --font-display: 'Rethink Sans', system-ui, -apple-system, sans-serif;
48
52
  --font-body: 'Rethink Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
49
53
  --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
@@ -55,6 +59,7 @@
55
59
  --radius-xl: 12px;
56
60
  --radius-2xl: 16px;
57
61
  --radius-3xl: 24px;
62
+ --radius-card: 14px;
58
63
  --radius-pill: 9999px;
59
64
  --radius-full: 9999px;
60
65
  --spacing-1: 4px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefidel/design-system",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Fidel brand design tokens + React component library — DTCG token source of truth, generated per-surface CSS + Tailwind-v4 parser-compatibility output, and on-brand React components (Button, MismatchCard, DiffSection).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -60,6 +60,10 @@
60
60
  "$value": "#a3a3a3",
61
61
  "$type": "color"
62
62
  },
63
+ "text-tertiary": {
64
+ "$value": "#737373",
65
+ "$type": "color"
66
+ },
63
67
  "border": {
64
68
  "$value": "#e5e5e5",
65
69
  "$type": "color",
@@ -152,6 +156,10 @@
152
156
  "$value": "#ef4444",
153
157
  "$type": "color"
154
158
  },
159
+ "destructive": {
160
+ "$value": "#eb2d2d",
161
+ "$type": "color"
162
+ },
155
163
  "high": {
156
164
  "$value": "#f59e0b",
157
165
  "$type": "color"
@@ -247,6 +255,14 @@
247
255
  "info": {
248
256
  "$value": "#1d4ed8",
249
257
  "$type": "color"
258
+ },
259
+ "info-strong": {
260
+ "$value": "#2563eb",
261
+ "$type": "color"
262
+ },
263
+ "info-surface": {
264
+ "$value": "#eff6ff",
265
+ "$type": "color"
250
266
  }
251
267
  },
252
268
  "font": {
@@ -296,6 +312,10 @@
296
312
  "$value": "24px",
297
313
  "$type": "dimension"
298
314
  },
315
+ "card": {
316
+ "$value": "14px",
317
+ "$type": "dimension"
318
+ },
299
319
  "pill": {
300
320
  "$value": "9999px",
301
321
  "$type": "dimension",