@usefidel/design-system 0.6.0 → 0.8.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/index.js CHANGED
@@ -174,14 +174,7 @@ function ElementRow({
174
174
  /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__element-count", children: plural(element.properties.length, "property", "properties") }),
175
175
  hasDetail && /* @__PURE__ */ jsx3(Chevron2, { open, className: "fds-diff-section__element-caret" })
176
176
  ] }),
177
- /* @__PURE__ */ jsx3("div", { className: "fds-diff-section__lines", children: element.properties.map((line, li) => /* @__PURE__ */ jsxs3("div", { className: "fds-diff-section__line", children: [
178
- /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__prop", children: line.property }),
179
- /* @__PURE__ */ jsxs3("span", { className: "fds-diff-section__delta", children: [
180
- /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__live", children: line.live }),
181
- /* @__PURE__ */ jsx3(Arrow, {}),
182
- /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__design", children: line.design })
183
- ] })
184
- ] }, `${line.property}-${li}`)) })
177
+ /* @__PURE__ */ jsx3(DiffPropertyList, { properties: element.properties })
185
178
  ] });
186
179
  return /* @__PURE__ */ jsxs3(
187
180
  "div",
@@ -208,6 +201,18 @@ function ElementRow({
208
201
  }
209
202
  );
210
203
  }
204
+ function DiffPropertyList({ properties, className, ...rest }) {
205
+ const classes = ["fds-diff-section__lines", className].filter(Boolean).join(" ");
206
+ return /* @__PURE__ */ jsx3("div", { className: classes, ...rest, children: properties.map((line, li) => /* @__PURE__ */ jsxs3("div", { className: "fds-diff-section__line", children: [
207
+ /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__prop", children: line.property }),
208
+ /* @__PURE__ */ jsxs3("span", { className: "fds-diff-section__delta", children: [
209
+ /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__live", children: line.live }),
210
+ /* @__PURE__ */ jsx3(Arrow, {}),
211
+ /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__design", children: line.design })
212
+ ] }),
213
+ line.trailing != null && /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__trailing", children: line.trailing })
214
+ ] }, `${line.property}-${li}`)) });
215
+ }
211
216
  function Chevron2({ open, className }) {
212
217
  const classes = [
213
218
  "fds-diff-section__chevron",
@@ -248,8 +253,281 @@ function Arrow() {
248
253
  }
249
254
  );
250
255
  }
256
+
257
+ // src/components/Select/Select.tsx
258
+ import {
259
+ forwardRef,
260
+ useEffect,
261
+ useId,
262
+ useImperativeHandle,
263
+ useMemo,
264
+ useRef,
265
+ useState as useState3
266
+ } from "react";
267
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
268
+ function ChevronIcon() {
269
+ return /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 20 20", width: "18", height: "18", fill: "none", "aria-hidden": "true", className: "fds-select__chevronIcon", children: /* @__PURE__ */ jsx4("path", { d: "M6 8l4 4 4-4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) });
270
+ }
271
+ function CheckIcon() {
272
+ return /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 20 20", width: "18", height: "18", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("path", { d: "M4.5 10.5l3 3 8-8.5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) });
273
+ }
274
+ var Select = forwardRef(function Select2({
275
+ options,
276
+ value,
277
+ onChange,
278
+ placeholder = "Select\u2026",
279
+ label,
280
+ hint,
281
+ error,
282
+ disabled = false,
283
+ searchable = false,
284
+ searchPlaceholder = "Search\u2026",
285
+ leadingIcon,
286
+ id,
287
+ name,
288
+ className,
289
+ containerClassName
290
+ }, ref) {
291
+ const genId = useId();
292
+ const triggerId = id ?? genId;
293
+ const listId = `${genId}-list`;
294
+ const msgId = `${genId}-msg`;
295
+ const rootRef = useRef(null);
296
+ const triggerRef = useRef(null);
297
+ const listRef = useRef(null);
298
+ const searchRef = useRef(null);
299
+ useImperativeHandle(ref, () => triggerRef.current, []);
300
+ const [open, setOpen] = useState3(false);
301
+ const [query, setQuery] = useState3("");
302
+ const [activeIndex, setActiveIndex] = useState3(-1);
303
+ const selected = options.find((o) => o.value === value) ?? null;
304
+ const filtered = useMemo(() => {
305
+ if (!searchable || !query.trim()) return options;
306
+ const q = query.trim().toLowerCase();
307
+ return options.filter(
308
+ (o) => o.label.toLowerCase().includes(q) || (o.secondary?.toLowerCase().includes(q) ?? false)
309
+ );
310
+ }, [options, searchable, query]);
311
+ const hasMessage = Boolean(error ?? hint);
312
+ const firstEnabled = (list) => list.findIndex((o) => !o.disabled);
313
+ useEffect(() => {
314
+ if (!open) return;
315
+ const onDown = (e) => {
316
+ if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
317
+ };
318
+ document.addEventListener("mousedown", onDown);
319
+ return () => document.removeEventListener("mousedown", onDown);
320
+ }, [open]);
321
+ useEffect(() => {
322
+ if (!open) {
323
+ setQuery("");
324
+ return;
325
+ }
326
+ const selIdx = filtered.findIndex((o) => o.value === value);
327
+ setActiveIndex(selIdx >= 0 ? selIdx : firstEnabled(filtered));
328
+ const raf = requestAnimationFrame(() => {
329
+ if (searchable) searchRef.current?.focus();
330
+ else listRef.current?.focus();
331
+ });
332
+ return () => cancelAnimationFrame(raf);
333
+ }, [open]);
334
+ const close = () => {
335
+ setOpen(false);
336
+ triggerRef.current?.focus();
337
+ };
338
+ const move = (dir) => {
339
+ setActiveIndex((prev) => {
340
+ if (filtered.length === 0) return -1;
341
+ let i = prev;
342
+ for (let k = 0; k < filtered.length; k++) {
343
+ i = (i + dir + filtered.length) % filtered.length;
344
+ if (!filtered[i].disabled) return i;
345
+ }
346
+ return prev;
347
+ });
348
+ };
349
+ const choose = (i) => {
350
+ const o = filtered[i];
351
+ if (o && !o.disabled) {
352
+ onChange?.(o.value);
353
+ close();
354
+ }
355
+ };
356
+ const onKeyDown = (e) => {
357
+ if (!open) {
358
+ if (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Enter" || e.key === " ") {
359
+ e.preventDefault();
360
+ setOpen(true);
361
+ }
362
+ return;
363
+ }
364
+ if (e.key === "ArrowDown") {
365
+ e.preventDefault();
366
+ move(1);
367
+ } else if (e.key === "ArrowUp") {
368
+ e.preventDefault();
369
+ move(-1);
370
+ } else if (e.key === "Home") {
371
+ e.preventDefault();
372
+ setActiveIndex(firstEnabled(filtered));
373
+ } else if (e.key === "End") {
374
+ e.preventDefault();
375
+ for (let i = filtered.length - 1; i >= 0; i--) {
376
+ if (!filtered[i].disabled) {
377
+ setActiveIndex(i);
378
+ break;
379
+ }
380
+ }
381
+ } else if (e.key === "Enter") {
382
+ e.preventDefault();
383
+ choose(activeIndex);
384
+ } else if (e.key === "Escape") {
385
+ e.preventDefault();
386
+ close();
387
+ }
388
+ };
389
+ const triggerClasses = [
390
+ "fds-select__trigger",
391
+ error ? "fds-select__trigger--error" : "",
392
+ open ? "fds-select__trigger--open" : "",
393
+ className
394
+ ].filter(Boolean).join(" ");
395
+ return /* @__PURE__ */ jsxs4(
396
+ "div",
397
+ {
398
+ ref: rootRef,
399
+ className: ["fds-select-field", containerClassName].filter(Boolean).join(" "),
400
+ children: [
401
+ label != null && /* @__PURE__ */ jsx4("label", { htmlFor: triggerId, className: "fds-select__label", children: label }),
402
+ /* @__PURE__ */ jsxs4("div", { className: "fds-select", children: [
403
+ /* @__PURE__ */ jsxs4(
404
+ "button",
405
+ {
406
+ type: "button",
407
+ id: triggerId,
408
+ ref: triggerRef,
409
+ className: triggerClasses,
410
+ disabled,
411
+ "aria-haspopup": "listbox",
412
+ "aria-expanded": open,
413
+ "aria-controls": open ? listId : void 0,
414
+ "aria-invalid": error ? true : void 0,
415
+ "aria-describedby": hasMessage ? msgId : void 0,
416
+ onClick: () => !disabled && setOpen((o) => !o),
417
+ onKeyDown,
418
+ children: [
419
+ (selected?.avatar ?? leadingIcon) != null && /* @__PURE__ */ jsx4("span", { className: "fds-select__lead", children: selected?.avatar ?? leadingIcon }),
420
+ /* @__PURE__ */ jsx4(
421
+ "span",
422
+ {
423
+ className: `fds-select__value${selected ? "" : " fds-select__value--placeholder"}`,
424
+ children: selected ? selected.label : placeholder
425
+ }
426
+ ),
427
+ /* @__PURE__ */ jsx4("span", { className: "fds-select__chevron", children: /* @__PURE__ */ jsx4(ChevronIcon, {}) })
428
+ ]
429
+ }
430
+ ),
431
+ open && /* @__PURE__ */ jsxs4("div", { className: "fds-select__popover", children: [
432
+ searchable && /* @__PURE__ */ jsx4("div", { className: "fds-select__search", children: /* @__PURE__ */ jsx4(
433
+ "input",
434
+ {
435
+ ref: searchRef,
436
+ className: "fds-select__searchInput",
437
+ placeholder: searchPlaceholder,
438
+ value: query,
439
+ onChange: (e) => setQuery(e.target.value),
440
+ onKeyDown,
441
+ role: "combobox",
442
+ "aria-expanded": true,
443
+ "aria-controls": listId,
444
+ "aria-autocomplete": "list"
445
+ }
446
+ ) }),
447
+ /* @__PURE__ */ jsxs4(
448
+ "div",
449
+ {
450
+ ref: listRef,
451
+ id: listId,
452
+ role: "listbox",
453
+ tabIndex: searchable ? -1 : 0,
454
+ className: "fds-select__list",
455
+ "aria-activedescendant": activeIndex >= 0 ? `${listId}-opt-${activeIndex}` : void 0,
456
+ onKeyDown: searchable ? void 0 : onKeyDown,
457
+ children: [
458
+ filtered.length === 0 && /* @__PURE__ */ jsx4("div", { className: "fds-select__empty", children: "No results" }),
459
+ filtered.map((o, i) => /* @__PURE__ */ jsxs4(
460
+ "div",
461
+ {
462
+ id: `${listId}-opt-${i}`,
463
+ role: "option",
464
+ "aria-selected": o.value === value,
465
+ "aria-disabled": o.disabled || void 0,
466
+ className: [
467
+ "fds-select__option",
468
+ i === activeIndex ? "fds-select__option--active" : "",
469
+ o.disabled ? "fds-select__option--disabled" : ""
470
+ ].filter(Boolean).join(" "),
471
+ onMouseEnter: () => !o.disabled && setActiveIndex(i),
472
+ onMouseDown: (e) => e.preventDefault(),
473
+ onClick: () => choose(i),
474
+ children: [
475
+ o.avatar != null && /* @__PURE__ */ jsx4("span", { className: "fds-select__optAvatar", children: o.avatar }),
476
+ /* @__PURE__ */ jsxs4("span", { className: "fds-select__optText", children: [
477
+ /* @__PURE__ */ jsx4("span", { className: "fds-select__optLabel", children: o.label }),
478
+ o.secondary != null && /* @__PURE__ */ jsx4("span", { className: "fds-select__optSecondary", children: o.secondary })
479
+ ] }),
480
+ o.value === value && /* @__PURE__ */ jsx4("span", { className: "fds-select__check", children: /* @__PURE__ */ jsx4(CheckIcon, {}) })
481
+ ]
482
+ },
483
+ o.value
484
+ ))
485
+ ]
486
+ }
487
+ )
488
+ ] })
489
+ ] }),
490
+ hasMessage && /* @__PURE__ */ jsx4("p", { id: msgId, className: error ? "fds-select__error" : "fds-select__hint", children: error ?? hint }),
491
+ name != null && /* @__PURE__ */ jsx4("input", { type: "hidden", name, value: value ?? "" })
492
+ ]
493
+ }
494
+ );
495
+ });
496
+
497
+ // src/components/Toggle/Toggle.tsx
498
+ import { forwardRef as forwardRef2, useId as useId2 } from "react";
499
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
500
+ var Toggle = forwardRef2(function Toggle2({ size = "medium", label, description, className, id, disabled, ...rest }, ref) {
501
+ const generatedId = useId2();
502
+ const inputId = id ?? generatedId;
503
+ const classes = ["fds-toggle", `fds-toggle--${size}`, className].filter(Boolean).join(" ");
504
+ return /* @__PURE__ */ jsxs5("div", { className: classes, "data-disabled": disabled ? "" : void 0, children: [
505
+ /* @__PURE__ */ jsx5(
506
+ "input",
507
+ {
508
+ ...rest,
509
+ id: inputId,
510
+ ref,
511
+ type: "checkbox",
512
+ role: "switch",
513
+ disabled,
514
+ className: "fds-toggle__input"
515
+ }
516
+ ),
517
+ /* @__PURE__ */ jsxs5("label", { htmlFor: inputId, className: "fds-toggle__control", children: [
518
+ /* @__PURE__ */ jsx5("span", { className: "fds-toggle__track", "aria-hidden": "true", children: /* @__PURE__ */ jsx5("span", { className: "fds-toggle__thumb" }) }),
519
+ (label != null || description != null) && /* @__PURE__ */ jsxs5("span", { className: "fds-toggle__text", children: [
520
+ label != null && /* @__PURE__ */ jsx5("span", { className: "fds-toggle__label", children: label }),
521
+ description != null && /* @__PURE__ */ jsx5("span", { className: "fds-toggle__description", children: description })
522
+ ] })
523
+ ] })
524
+ ] });
525
+ });
251
526
  export {
252
527
  Button,
528
+ DiffPropertyList,
253
529
  DiffSection,
254
- MismatchCard
530
+ MismatchCard,
531
+ Select,
532
+ Toggle
255
533
  };
package/dist/landing.css CHANGED
@@ -47,11 +47,14 @@
47
47
  --font-display: 'Rethink Sans', system-ui, -apple-system, sans-serif;
48
48
  --font-body: 'Rethink Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
49
49
  --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
50
- --radius-xs: 4px;
51
- --radius-sm: 6px;
52
- --radius-md: 8px;
53
- --radius-lg: 12px;
54
- --radius-xl: 16px;
50
+ --radius-none: 0px;
51
+ --radius-xs: 2px;
52
+ --radius-sm: 4px;
53
+ --radius-md: 6px;
54
+ --radius-lg: 8px;
55
+ --radius-xl: 12px;
56
+ --radius-2xl: 16px;
57
+ --radius-3xl: 24px;
55
58
  --radius-pill: 9999px;
56
59
  --radius-full: 9999px;
57
60
  --spacing-1: 4px;
package/dist/theme.css CHANGED
@@ -49,11 +49,14 @@
49
49
  --font-display: 'Rethink Sans', system-ui, -apple-system, sans-serif;
50
50
  --font-body: 'Rethink Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
51
51
  --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
52
- --radius-xs: 4px;
53
- --radius-sm: 6px;
54
- --radius-md: 8px;
55
- --radius-lg: 12px;
56
- --radius-xl: 16px;
52
+ --radius-none: 0px;
53
+ --radius-xs: 2px;
54
+ --radius-sm: 4px;
55
+ --radius-md: 6px;
56
+ --radius-lg: 8px;
57
+ --radius-xl: 12px;
58
+ --radius-2xl: 16px;
59
+ --radius-3xl: 24px;
57
60
  --radius-pill: 9999px;
58
61
  --radius-full: 9999px;
59
62
  --spacing-1: 4px;
package/dist/webapp.css CHANGED
@@ -47,11 +47,14 @@
47
47
  --font-display: 'Rethink Sans', system-ui, -apple-system, sans-serif;
48
48
  --font-body: 'Rethink Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
49
49
  --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
50
- --radius-xs: 4px;
51
- --radius-sm: 6px;
52
- --radius-md: 8px;
53
- --radius-lg: 12px;
54
- --radius-xl: 16px;
50
+ --radius-none: 0px;
51
+ --radius-xs: 2px;
52
+ --radius-sm: 4px;
53
+ --radius-md: 6px;
54
+ --radius-lg: 8px;
55
+ --radius-xl: 12px;
56
+ --radius-2xl: 16px;
57
+ --radius-3xl: 24px;
55
58
  --radius-pill: 9999px;
56
59
  --radius-full: 9999px;
57
60
  --spacing-1: 4px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefidel/design-system",
3
- "version": "0.6.0",
3
+ "version": "0.8.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",
@@ -16,6 +16,11 @@
16
16
  "require": "./dist/index.cjs"
17
17
  },
18
18
  "./styles.css": "./dist/index.css",
19
+ "./icons": {
20
+ "types": "./dist/icons.d.ts",
21
+ "import": "./dist/icons.js",
22
+ "require": "./dist/icons.cjs"
23
+ },
19
24
  "./dist/*": "./dist/*"
20
25
  },
21
26
  "publishConfig": {
@@ -51,5 +56,8 @@
51
56
  "style-dictionary": "^4.3.0",
52
57
  "tsup": "^8.3.5",
53
58
  "typescript": "^5.6.3"
59
+ },
60
+ "dependencies": {
61
+ "lucide-react": "^1.33.0"
54
62
  }
55
63
  }
@@ -264,26 +264,38 @@
264
264
  }
265
265
  },
266
266
  "radius": {
267
+ "none": {
268
+ "$value": "0px",
269
+ "$type": "dimension"
270
+ },
267
271
  "xs": {
268
- "$value": "4px",
272
+ "$value": "2px",
269
273
  "$type": "dimension"
270
274
  },
271
275
  "sm": {
272
- "$value": "6px",
276
+ "$value": "4px",
273
277
  "$type": "dimension"
274
278
  },
275
279
  "md": {
276
- "$value": "8px",
280
+ "$value": "6px",
277
281
  "$type": "dimension"
278
282
  },
279
283
  "lg": {
280
- "$value": "12px",
284
+ "$value": "8px",
281
285
  "$type": "dimension"
282
286
  },
283
287
  "xl": {
288
+ "$value": "12px",
289
+ "$type": "dimension"
290
+ },
291
+ "2xl": {
284
292
  "$value": "16px",
285
293
  "$type": "dimension"
286
294
  },
295
+ "3xl": {
296
+ "$value": "24px",
297
+ "$type": "dimension"
298
+ },
287
299
  "pill": {
288
300
  "$value": "9999px",
289
301
  "$type": "dimension",