@usefidel/design-system 0.14.0 → 0.15.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.
@@ -10,6 +10,6 @@
10
10
  "webapp.css"
11
11
  ],
12
12
  "storybookUrl": null,
13
- "packageVersion": "0.14.0",
14
- "resolvedSha": "2c6d6c9b1c4ca4dc54ec8a92f2a9d2d60dcaf34d"
13
+ "packageVersion": "0.15.0",
14
+ "resolvedSha": "51806455235b517cf1c3b2695f590570786af610"
15
15
  }
package/dist/index.cjs CHANGED
@@ -21,14 +21,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AppNav: () => AppNav,
24
+ Avatar: () => Avatar,
24
25
  Button: () => Button,
25
26
  DiffPropertyList: () => DiffPropertyList,
26
27
  DiffSection: () => DiffSection,
27
28
  MismatchCard: () => MismatchCard,
28
29
  Modal: () => Modal,
30
+ SectionHeader: () => SectionHeader,
29
31
  SegmentedControl: () => SegmentedControl,
30
32
  Select: () => Select,
31
33
  SettingsSection: () => SettingsSection,
34
+ Split: () => Split,
32
35
  TabNav: () => TabNav,
33
36
  Toggle: () => Toggle,
34
37
  breakpoints: () => breakpoints
@@ -867,17 +870,85 @@ var breakpoints = {
867
870
  /** Tablets, narrow windows. */
868
871
  lg: 900
869
872
  };
873
+
874
+ // src/components/Avatar/Avatar.tsx
875
+ var import_react9 = require("react");
876
+ var import_jsx_runtime11 = require("react/jsx-runtime");
877
+ function initialsFor(name) {
878
+ const words = name.trim().split(/[\s._@-]+/).filter(Boolean);
879
+ if (words.length === 0) return "?";
880
+ if (words.length === 1) return words[0].slice(0, 2).toUpperCase();
881
+ return (words[0][0] + words[1][0]).toUpperCase();
882
+ }
883
+ function Avatar({ name, src, size = "medium", className, ...rest }) {
884
+ const [failedSrc, setFailedSrc] = (0, import_react9.useState)(null);
885
+ const showImage = !!src && src !== failedSrc;
886
+ const classes = ["fds-avatar", `fds-avatar--${size}`, className].filter(Boolean).join(" ");
887
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: classes, role: "img", "aria-label": name, ...rest, children: showImage ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { className: "fds-avatar__img", src, alt: "", onError: () => setFailedSrc(src) }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", children: initialsFor(name) }) });
888
+ }
889
+
890
+ // src/components/SectionHeader/SectionHeader.tsx
891
+ var import_jsx_runtime12 = require("react/jsx-runtime");
892
+ function SectionHeader({
893
+ title,
894
+ description,
895
+ as: Heading = "h2",
896
+ titleId,
897
+ className,
898
+ ...rest
899
+ }) {
900
+ const classes = ["fds-section-header", className].filter(Boolean).join(" ");
901
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: classes, ...rest, children: [
902
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Heading, { id: titleId, className: "fds-section-header__title", children: title }),
903
+ description != null && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "fds-section-header__description", children: description })
904
+ ] });
905
+ }
906
+
907
+ // src/components/Split/Split.tsx
908
+ var import_jsx_runtime13 = require("react/jsx-runtime");
909
+ function Split({
910
+ aside,
911
+ children,
912
+ asideWidth = "280px",
913
+ sticky = false,
914
+ collapseBelow = "lg",
915
+ className,
916
+ style,
917
+ ...rest
918
+ }) {
919
+ const classes = [
920
+ "fds-split",
921
+ `fds-split--collapse-${collapseBelow}`,
922
+ sticky && "fds-split--sticky",
923
+ className
924
+ ].filter(Boolean).join(" ");
925
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
926
+ "div",
927
+ {
928
+ className: classes,
929
+ style: { "--fds-split-aside": asideWidth, ...style },
930
+ ...rest,
931
+ children: [
932
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fds-split__aside", children: aside }),
933
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "fds-split__main", children })
934
+ ]
935
+ }
936
+ );
937
+ }
870
938
  // Annotate the CommonJS export names for ESM import in node:
871
939
  0 && (module.exports = {
872
940
  AppNav,
941
+ Avatar,
873
942
  Button,
874
943
  DiffPropertyList,
875
944
  DiffSection,
876
945
  MismatchCard,
877
946
  Modal,
947
+ SectionHeader,
878
948
  SegmentedControl,
879
949
  Select,
880
950
  SettingsSection,
951
+ Split,
881
952
  TabNav,
882
953
  Toggle,
883
954
  breakpoints
package/dist/index.css CHANGED
@@ -1321,3 +1321,103 @@
1321
1321
  transparent);
1322
1322
  }
1323
1323
  }
1324
+
1325
+ /* src/components/Avatar/avatar.css */
1326
+ .fds-avatar {
1327
+ box-sizing: border-box;
1328
+ display: inline-grid;
1329
+ place-items: center;
1330
+ flex-shrink: 0;
1331
+ overflow: hidden;
1332
+ border-radius: var(--radius-full, 9999px);
1333
+ background: var(--color-accent-subtle, #ffedd5);
1334
+ color: var(--color-accent-text, #c2410c);
1335
+ font-family: var(--font-body, "Rethink Sans", system-ui, sans-serif);
1336
+ font-weight: 600;
1337
+ line-height: 1;
1338
+ user-select: none;
1339
+ }
1340
+ .fds-avatar--small {
1341
+ width: 24px;
1342
+ height: 24px;
1343
+ font-size: 10px;
1344
+ }
1345
+ .fds-avatar--medium {
1346
+ width: 32px;
1347
+ height: 32px;
1348
+ font-size: 12px;
1349
+ }
1350
+ .fds-avatar--large {
1351
+ width: 40px;
1352
+ height: 40px;
1353
+ font-size: 14px;
1354
+ }
1355
+ .fds-avatar__img {
1356
+ width: 100%;
1357
+ height: 100%;
1358
+ object-fit: cover;
1359
+ display: block;
1360
+ }
1361
+
1362
+ /* src/components/SectionHeader/section-header.css */
1363
+ .fds-section-header {
1364
+ display: flex;
1365
+ flex-direction: column;
1366
+ gap: var(--spacing-2, 8px);
1367
+ min-width: 0;
1368
+ }
1369
+ .fds-section-header__title {
1370
+ margin: 0;
1371
+ font-family: var(--font-display, "Rethink Sans", system-ui, sans-serif);
1372
+ font-size: 14.5px;
1373
+ font-weight: 600;
1374
+ line-height: 1.3;
1375
+ letter-spacing: -0.005em;
1376
+ color: var(--color-text, #171717);
1377
+ }
1378
+ .fds-section-header__description {
1379
+ margin: 0;
1380
+ max-width: 60ch;
1381
+ font-size: 12.5px;
1382
+ line-height: 1.55;
1383
+ color: var(--color-text-muted, #a3a3a3);
1384
+ }
1385
+
1386
+ /* src/components/Split/split.css */
1387
+ .fds-split {
1388
+ display: grid;
1389
+ grid-template-columns: var(--fds-split-aside, 280px) minmax(0, 1fr);
1390
+ gap: var(--spacing-12, 48px);
1391
+ align-items: start;
1392
+ }
1393
+ .fds-split__aside,
1394
+ .fds-split__main {
1395
+ min-width: 0;
1396
+ }
1397
+ .fds-split__main {
1398
+ display: flex;
1399
+ flex-direction: column;
1400
+ gap: var(--spacing-4, 16px);
1401
+ }
1402
+ .fds-split--sticky .fds-split__aside {
1403
+ position: sticky;
1404
+ top: var(--spacing-6, 24px);
1405
+ }
1406
+ @media (max-width: 900px) {
1407
+ .fds-split--collapse-lg {
1408
+ grid-template-columns: minmax(0, 1fr);
1409
+ gap: var(--spacing-4, 16px);
1410
+ }
1411
+ .fds-split--collapse-lg .fds-split__aside {
1412
+ position: static;
1413
+ }
1414
+ }
1415
+ @media (max-width: 640px) {
1416
+ .fds-split--collapse-md {
1417
+ grid-template-columns: minmax(0, 1fr);
1418
+ gap: var(--spacing-4, 16px);
1419
+ }
1420
+ .fds-split--collapse-md .fds-split__aside {
1421
+ position: static;
1422
+ }
1423
+ }
package/dist/index.d.cts CHANGED
@@ -296,6 +296,9 @@ interface SettingsSectionProps extends Omit<HTMLAttributes<HTMLElement>, 'title'
296
296
  children?: ReactNode;
297
297
  }
298
298
  /**
299
+ * @deprecated Compose `Split` and `SectionHeader` instead; this will be removed
300
+ * once fidel-web has moved off it.
301
+ *
299
302
  * Fidel design-system settings section: heading and description on the left,
300
303
  * content on the right, divided from the next section by a hairline. Stacks
301
304
  * into one column below 900px.
@@ -373,4 +376,49 @@ declare const breakpoints: {
373
376
  };
374
377
  type Breakpoint = keyof typeof breakpoints;
375
378
 
376
- export { AppNav, type AppNavProps, type Breakpoint, Button, type ButtonProps, type ButtonSize, type ButtonVariant, type DiffElement, type DiffPropertyLine, DiffPropertyList, type DiffPropertyListProps, DiffSection, type DiffSectionProps, MismatchCard, type MismatchCardProps, type MismatchProperty, Modal, type ModalProps, type ModalSize, type ModalTone, SegmentedControl, type SegmentedControlProps, type SegmentedOption, Select, type SelectOption, type SelectProps, SettingsSection, type SettingsSectionProps, TabNav, type TabNavProps, Toggle, type ToggleProps, type ToggleSize, breakpoints };
379
+ type AvatarSize = 'small' | 'medium' | 'large';
380
+ interface AvatarProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'children'> {
381
+ /** Person's name or handle; used for the initials and the accessible name. */
382
+ name: string;
383
+ /** Photo URL. Falls back to initials when missing or when it fails to load. */
384
+ src?: string | null;
385
+ /** small 24px, medium 32px, large 40px. @default 'medium' */
386
+ size?: AvatarSize;
387
+ }
388
+ /**
389
+ * Fidel design-system Avatar: a round photo, or initials on an accent tint
390
+ * when there is no photo. Exposes `name` as its accessible label.
391
+ */
392
+ declare function Avatar({ name, src, size, className, ...rest }: AvatarProps): react.JSX.Element;
393
+
394
+ interface SectionHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
395
+ title: ReactNode;
396
+ /** Short muted line under the heading. */
397
+ description?: ReactNode;
398
+ /** Heading level. @default 'h2' */
399
+ as?: 'h2' | 'h3' | 'h4';
400
+ /** Id for the heading, so a surrounding region can use `aria-labelledby`. */
401
+ titleId?: string;
402
+ }
403
+ /** Fidel design-system section header: a heading with an optional muted description under it. */
404
+ declare function SectionHeader({ title, description, as: Heading, titleId, className, ...rest }: SectionHeaderProps): react.JSX.Element;
405
+
406
+ interface SplitProps extends HTMLAttributes<HTMLDivElement> {
407
+ /** The narrow side column, e.g. a SectionHeader. */
408
+ aside: ReactNode;
409
+ /** The main column. */
410
+ children?: ReactNode;
411
+ /** Width of the side column. @default '280px' */
412
+ asideWidth?: string;
413
+ /** Keep the side column in view while the main column scrolls. @default false */
414
+ sticky?: boolean;
415
+ /** Breakpoint below which the columns stack, aside first: md 640px, lg 900px. @default 'lg' */
416
+ collapseBelow?: 'md' | 'lg';
417
+ }
418
+ /**
419
+ * Fidel design-system two-column layout: a fixed-width side column beside a
420
+ * flexible main column, stacking into one column below a breakpoint.
421
+ */
422
+ declare function Split({ aside, children, asideWidth, sticky, collapseBelow, className, style, ...rest }: SplitProps): react.JSX.Element;
423
+
424
+ export { AppNav, type AppNavProps, Avatar, type AvatarProps, type AvatarSize, type Breakpoint, Button, type ButtonProps, type ButtonSize, type ButtonVariant, type DiffElement, type DiffPropertyLine, DiffPropertyList, type DiffPropertyListProps, DiffSection, type DiffSectionProps, MismatchCard, type MismatchCardProps, type MismatchProperty, Modal, type ModalProps, type ModalSize, type ModalTone, SectionHeader, type SectionHeaderProps, SegmentedControl, type SegmentedControlProps, type SegmentedOption, Select, type SelectOption, type SelectProps, SettingsSection, type SettingsSectionProps, Split, type SplitProps, TabNav, type TabNavProps, Toggle, type ToggleProps, type ToggleSize, breakpoints };
package/dist/index.d.ts CHANGED
@@ -296,6 +296,9 @@ interface SettingsSectionProps extends Omit<HTMLAttributes<HTMLElement>, 'title'
296
296
  children?: ReactNode;
297
297
  }
298
298
  /**
299
+ * @deprecated Compose `Split` and `SectionHeader` instead; this will be removed
300
+ * once fidel-web has moved off it.
301
+ *
299
302
  * Fidel design-system settings section: heading and description on the left,
300
303
  * content on the right, divided from the next section by a hairline. Stacks
301
304
  * into one column below 900px.
@@ -373,4 +376,49 @@ declare const breakpoints: {
373
376
  };
374
377
  type Breakpoint = keyof typeof breakpoints;
375
378
 
376
- export { AppNav, type AppNavProps, type Breakpoint, Button, type ButtonProps, type ButtonSize, type ButtonVariant, type DiffElement, type DiffPropertyLine, DiffPropertyList, type DiffPropertyListProps, DiffSection, type DiffSectionProps, MismatchCard, type MismatchCardProps, type MismatchProperty, Modal, type ModalProps, type ModalSize, type ModalTone, SegmentedControl, type SegmentedControlProps, type SegmentedOption, Select, type SelectOption, type SelectProps, SettingsSection, type SettingsSectionProps, TabNav, type TabNavProps, Toggle, type ToggleProps, type ToggleSize, breakpoints };
379
+ type AvatarSize = 'small' | 'medium' | 'large';
380
+ interface AvatarProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'children'> {
381
+ /** Person's name or handle; used for the initials and the accessible name. */
382
+ name: string;
383
+ /** Photo URL. Falls back to initials when missing or when it fails to load. */
384
+ src?: string | null;
385
+ /** small 24px, medium 32px, large 40px. @default 'medium' */
386
+ size?: AvatarSize;
387
+ }
388
+ /**
389
+ * Fidel design-system Avatar: a round photo, or initials on an accent tint
390
+ * when there is no photo. Exposes `name` as its accessible label.
391
+ */
392
+ declare function Avatar({ name, src, size, className, ...rest }: AvatarProps): react.JSX.Element;
393
+
394
+ interface SectionHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
395
+ title: ReactNode;
396
+ /** Short muted line under the heading. */
397
+ description?: ReactNode;
398
+ /** Heading level. @default 'h2' */
399
+ as?: 'h2' | 'h3' | 'h4';
400
+ /** Id for the heading, so a surrounding region can use `aria-labelledby`. */
401
+ titleId?: string;
402
+ }
403
+ /** Fidel design-system section header: a heading with an optional muted description under it. */
404
+ declare function SectionHeader({ title, description, as: Heading, titleId, className, ...rest }: SectionHeaderProps): react.JSX.Element;
405
+
406
+ interface SplitProps extends HTMLAttributes<HTMLDivElement> {
407
+ /** The narrow side column, e.g. a SectionHeader. */
408
+ aside: ReactNode;
409
+ /** The main column. */
410
+ children?: ReactNode;
411
+ /** Width of the side column. @default '280px' */
412
+ asideWidth?: string;
413
+ /** Keep the side column in view while the main column scrolls. @default false */
414
+ sticky?: boolean;
415
+ /** Breakpoint below which the columns stack, aside first: md 640px, lg 900px. @default 'lg' */
416
+ collapseBelow?: 'md' | 'lg';
417
+ }
418
+ /**
419
+ * Fidel design-system two-column layout: a fixed-width side column beside a
420
+ * flexible main column, stacking into one column below a breakpoint.
421
+ */
422
+ declare function Split({ aside, children, asideWidth, sticky, collapseBelow, className, style, ...rest }: SplitProps): react.JSX.Element;
423
+
424
+ export { AppNav, type AppNavProps, Avatar, type AvatarProps, type AvatarSize, type Breakpoint, Button, type ButtonProps, type ButtonSize, type ButtonVariant, type DiffElement, type DiffPropertyLine, DiffPropertyList, type DiffPropertyListProps, DiffSection, type DiffSectionProps, MismatchCard, type MismatchCardProps, type MismatchProperty, Modal, type ModalProps, type ModalSize, type ModalTone, SectionHeader, type SectionHeaderProps, SegmentedControl, type SegmentedControlProps, type SegmentedOption, Select, type SelectOption, type SelectProps, SettingsSection, type SettingsSectionProps, Split, type SplitProps, TabNav, type TabNavProps, Toggle, type ToggleProps, type ToggleSize, breakpoints };
package/dist/index.js CHANGED
@@ -838,16 +838,84 @@ var breakpoints = {
838
838
  /** Tablets, narrow windows. */
839
839
  lg: 900
840
840
  };
841
+
842
+ // src/components/Avatar/Avatar.tsx
843
+ import { useState as useState5 } from "react";
844
+ import { jsx as jsx11 } from "react/jsx-runtime";
845
+ function initialsFor(name) {
846
+ const words = name.trim().split(/[\s._@-]+/).filter(Boolean);
847
+ if (words.length === 0) return "?";
848
+ if (words.length === 1) return words[0].slice(0, 2).toUpperCase();
849
+ return (words[0][0] + words[1][0]).toUpperCase();
850
+ }
851
+ function Avatar({ name, src, size = "medium", className, ...rest }) {
852
+ const [failedSrc, setFailedSrc] = useState5(null);
853
+ const showImage = !!src && src !== failedSrc;
854
+ const classes = ["fds-avatar", `fds-avatar--${size}`, className].filter(Boolean).join(" ");
855
+ return /* @__PURE__ */ jsx11("span", { className: classes, role: "img", "aria-label": name, ...rest, children: showImage ? /* @__PURE__ */ jsx11("img", { className: "fds-avatar__img", src, alt: "", onError: () => setFailedSrc(src) }) : /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", children: initialsFor(name) }) });
856
+ }
857
+
858
+ // src/components/SectionHeader/SectionHeader.tsx
859
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
860
+ function SectionHeader({
861
+ title,
862
+ description,
863
+ as: Heading = "h2",
864
+ titleId,
865
+ className,
866
+ ...rest
867
+ }) {
868
+ const classes = ["fds-section-header", className].filter(Boolean).join(" ");
869
+ return /* @__PURE__ */ jsxs10("div", { className: classes, ...rest, children: [
870
+ /* @__PURE__ */ jsx12(Heading, { id: titleId, className: "fds-section-header__title", children: title }),
871
+ description != null && /* @__PURE__ */ jsx12("p", { className: "fds-section-header__description", children: description })
872
+ ] });
873
+ }
874
+
875
+ // src/components/Split/Split.tsx
876
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
877
+ function Split({
878
+ aside,
879
+ children,
880
+ asideWidth = "280px",
881
+ sticky = false,
882
+ collapseBelow = "lg",
883
+ className,
884
+ style,
885
+ ...rest
886
+ }) {
887
+ const classes = [
888
+ "fds-split",
889
+ `fds-split--collapse-${collapseBelow}`,
890
+ sticky && "fds-split--sticky",
891
+ className
892
+ ].filter(Boolean).join(" ");
893
+ return /* @__PURE__ */ jsxs11(
894
+ "div",
895
+ {
896
+ className: classes,
897
+ style: { "--fds-split-aside": asideWidth, ...style },
898
+ ...rest,
899
+ children: [
900
+ /* @__PURE__ */ jsx13("div", { className: "fds-split__aside", children: aside }),
901
+ /* @__PURE__ */ jsx13("div", { className: "fds-split__main", children })
902
+ ]
903
+ }
904
+ );
905
+ }
841
906
  export {
842
907
  AppNav,
908
+ Avatar,
843
909
  Button,
844
910
  DiffPropertyList,
845
911
  DiffSection,
846
912
  MismatchCard,
847
913
  Modal,
914
+ SectionHeader,
848
915
  SegmentedControl,
849
916
  Select,
850
917
  SettingsSection,
918
+ Split,
851
919
  TabNav,
852
920
  Toggle,
853
921
  breakpoints
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefidel/design-system",
3
- "version": "0.14.0",
3
+ "version": "0.15.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",