@lateralus-ai/shipping-ui 2.0.0-dev.3 → 2.0.0-dev.30

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.
Files changed (98) hide show
  1. package/dist/components/Entry.d.ts +27 -7
  2. package/dist/components/PageHeader.d.ts +41 -0
  3. package/dist/components/ScrollableList.d.ts +22 -0
  4. package/dist/components/Tabs.d.ts +5 -5
  5. package/dist/components/index.d.ts +4 -2
  6. package/dist/domain/Filters/FilterDropdown.d.ts +119 -0
  7. package/dist/domain/Filters/FilterPill.d.ts +22 -5
  8. package/dist/domain/Filters/FilterPills.d.ts +18 -0
  9. package/dist/domain/Filters/FilteredPill.d.ts +15 -5
  10. package/dist/domain/Filters/formatActiveFilterChipLabel.d.ts +11 -0
  11. package/dist/domain/Filters/index.d.ts +8 -3
  12. package/dist/index.cjs +33 -33
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.esm.js +6383 -4792
  15. package/dist/patterns/Search/ResultRow.d.ts +11 -5
  16. package/dist/patterns/Sidebar/sidebar-styles.d.ts +2 -1
  17. package/dist/primitives/Badge.d.ts +7 -4
  18. package/dist/primitives/Button.d.ts +3 -1
  19. package/dist/primitives/Switch.d.ts +5 -0
  20. package/dist/primitives/index.d.ts +1 -1
  21. package/dist/tailwind-theme.d.ts +8 -4
  22. package/dist/theme-entry-Dwr2mV7_.js +1 -0
  23. package/dist/{theme-entry-CxDa1D0_.mjs → theme-entry-tLBc6zGT.mjs} +12 -8
  24. package/dist/theme.cjs +1 -1
  25. package/dist/theme.esm.js +1 -1
  26. package/package.json +3 -2
  27. package/src/components/EmptyState.tsx +44 -44
  28. package/src/components/Entry.tsx +119 -45
  29. package/src/components/Modal.tsx +141 -141
  30. package/src/components/PageHeader.tsx +132 -0
  31. package/src/components/ScrollableList.tsx +61 -0
  32. package/src/components/Tabs.tsx +33 -26
  33. package/src/components/index.ts +15 -1
  34. package/src/domain/Filters/FilterDropdown.tsx +540 -0
  35. package/src/domain/Filters/FilterPill.tsx +74 -25
  36. package/src/domain/Filters/FilterPills.tsx +34 -0
  37. package/src/domain/Filters/FilteredPill.tsx +59 -39
  38. package/src/domain/Filters/FiltersBar.tsx +72 -76
  39. package/src/domain/Filters/formatActiveFilterChipLabel.ts +23 -0
  40. package/src/domain/Filters/index.ts +37 -3
  41. package/src/icons/arrow-paths.ts +8 -8
  42. package/src/icons/chevron-paths.ts +17 -17
  43. package/src/icons/icons-data.ts +656 -656
  44. package/src/index.ts +11 -0
  45. package/src/patterns/Search/ResultRow.tsx +24 -38
  46. package/src/patterns/Search/SearchModal.tsx +26 -8
  47. package/src/patterns/Sidebar/CollapsibleNavGroup.tsx +1 -1
  48. package/src/patterns/Sidebar/SidebarAction.tsx +26 -17
  49. package/src/patterns/Sidebar/SidebarEntry.tsx +54 -39
  50. package/src/patterns/Sidebar/SidebarLink.tsx +30 -20
  51. package/src/patterns/Sidebar/assets/logo-compliance-mark.png +5 -5
  52. package/src/patterns/Sidebar/assets/logo-compliance-mask.png +13 -13
  53. package/src/patterns/Sidebar/assets/logo-compliance.svg +17 -17
  54. package/src/patterns/Sidebar/assets/logo-technical-avatar.svg +17 -17
  55. package/src/patterns/Sidebar/assets/logo-technical-mark.png +5 -5
  56. package/src/patterns/Sidebar/assets/logo-technical.svg +16 -16
  57. package/src/patterns/Sidebar/sidebar-styles.ts +2 -1
  58. package/src/primitives/Badge.tsx +20 -10
  59. package/src/primitives/Button.tsx +21 -11
  60. package/src/primitives/Logo.tsx +20 -8
  61. package/src/primitives/Switch.tsx +27 -7
  62. package/src/primitives/button-styles.ts +92 -92
  63. package/src/primitives/index.ts +1 -1
  64. package/src/stories/canvases/ButtonsCanvas.tsx +107 -107
  65. package/src/stories/canvases/ButtonsMatrixCanvas.tsx +65 -65
  66. package/src/stories/canvases/ContentCanvas.tsx +253 -14
  67. package/src/stories/canvases/FiltersCanvas.tsx +171 -41
  68. package/src/stories/canvases/figma-buttons-layout.ts +83 -83
  69. package/src/stories/canvases/figma-widths.ts +28 -28
  70. package/src/stories/canvases/helpers.tsx +146 -146
  71. package/src/stories/components/Buttons.stories.tsx +11 -11
  72. package/src/stories/components/Chat.stories.tsx +11 -11
  73. package/src/stories/components/Content.stories.tsx +11 -11
  74. package/src/stories/components/Core.stories.tsx +11 -11
  75. package/src/stories/components/DomainForms.stories.tsx +11 -11
  76. package/src/stories/components/Filters.stories.tsx +11 -11
  77. package/src/stories/components/Forms.stories.tsx +11 -11
  78. package/src/stories/components/Icons.stories.tsx +11 -11
  79. package/src/stories/components/Illustrations.stories.tsx +11 -11
  80. package/src/stories/components/Library.stories.tsx +11 -11
  81. package/src/stories/components/Modals.stories.tsx +11 -11
  82. package/src/stories/components/Report.stories.tsx +11 -11
  83. package/src/stories/components/ReportLayout.stories.tsx +11 -11
  84. package/src/stories/components/Search.stories.tsx +11 -11
  85. package/src/stories/components/Settings.stories.tsx +11 -11
  86. package/src/stories/components/Ships.stories.tsx +11 -11
  87. package/src/stories/components/SidebarLayouts.stories.tsx +11 -11
  88. package/src/stories/components/Skeletons.stories.tsx +11 -11
  89. package/src/stories/components/Workflows.stories.tsx +11 -11
  90. package/src/stories/style-guide/Buttons.stories.tsx +11 -11
  91. package/src/stories/style-guide/ColorTokens.stories.tsx +11 -11
  92. package/src/stories/style-guide/Colors.stories.tsx +11 -11
  93. package/src/stories/style-guide/RaiseLevels.stories.tsx +11 -11
  94. package/src/stories/style-guide/Typography.stories.tsx +11 -11
  95. package/src/tailwind-theme.ts +8 -4
  96. package/src/theme-entry.ts +2 -2
  97. package/src/utils/cn.ts +28 -1
  98. package/dist/theme-entry-D2X3Ptjf.js +0 -1
@@ -1,30 +1,40 @@
1
1
  import { type ReactNode } from "react";
2
2
  import { cn } from "../utils/cn";
3
3
 
4
- type BadgeColor = "blue" | "green" | "red" | "orange" | "purple" | "grey";
5
- type BadgeType = "label" | "icon";
4
+ export type BadgeColor = "blue" | "green" | "red" | "orange" | "purple" | "grey";
5
+ export type BadgeType = "label" | "icon";
6
6
 
7
7
  export type BadgeProps = {
8
8
  color: BadgeColor;
9
+ /** `label` grows with content (pill). `icon` is a compact circle for a glyph/digit. */
9
10
  type?: BadgeType;
10
11
  children: ReactNode;
11
12
  className?: string;
12
13
  };
13
14
 
14
15
  const colorStyles: Record<BadgeColor, string> = {
15
- blue: "bg-meta-blue text-meta-on-blue",
16
- green: "bg-meta-green text-meta-on-green",
17
- red: "bg-meta-red text-meta-on-red",
18
- orange: "bg-meta-orange text-meta-on-orange",
19
- purple: "bg-meta-purple text-meta-on-purple",
16
+ blue: "bg-meta-blue text-meta-onBlue",
17
+ green: "bg-meta-green text-meta-onGreen",
18
+ red: "bg-meta-red text-meta-onRed",
19
+ orange: "bg-meta-orange text-meta-onOrange",
20
+ purple: "bg-meta-purple text-meta-onPurple",
20
21
  grey: "bg-grey-100 text-display-on-light-secondary",
21
22
  };
22
23
 
23
- export const Badge = ({ color, type = "label", children, className }: BadgeProps) => (
24
+ /**
25
+ * Figma Badge (4365:74363) — padding + rounded-full; no fixed width on labels.
26
+ */
27
+ export const Badge = ({
28
+ color,
29
+ type = "label",
30
+ children,
31
+ className,
32
+ }: BadgeProps) => (
24
33
  <span
25
34
  className={cn(
26
- "inline-flex shrink-0 items-center justify-center text-footnote-em",
27
- type === "label" ? "rounded-control px-2 py-0.5" : "size-6 rounded-full",
35
+ "inline-flex shrink-0 items-center justify-center text-footnote-em leading-none",
36
+ type === "label" && "rounded-full px-1.5 py-0.5",
37
+ type === "icon" && "size-5 rounded-full [&>svg]:size-3",
28
38
  colorStyles[color],
29
39
  className,
30
40
  )}
@@ -34,6 +34,8 @@ export type ButtonProps = Omit<
34
34
  disabled?: boolean;
35
35
  icon?: ComponentType<IconProps> | ReactNode;
36
36
  startIcon?: ComponentType<IconProps> | ReactNode;
37
+ /** Renders after the label, inside the same button (no split/dropdown segment). */
38
+ endIcon?: ComponentType<IconProps> | ReactNode;
37
39
  dropdownOptions?: ButtonDropdownOption[];
38
40
  dropdownOpen?: boolean;
39
41
  onDropdownOpenChange?: (open: boolean) => void;
@@ -110,6 +112,7 @@ export const Button = ({
110
112
  disabled = false,
111
113
  icon,
112
114
  startIcon,
115
+ endIcon,
113
116
  dropdownOptions,
114
117
  dropdownOpen,
115
118
  onDropdownOpenChange,
@@ -121,6 +124,9 @@ export const Button = ({
121
124
  ...props
122
125
  }: ButtonProps) => {
123
126
  const resolvedIcon = icon ?? startIcon;
127
+ const renderedIcon = renderIcon(resolvedIcon);
128
+ const renderedEndIcon = renderIcon(endIcon);
129
+ const hasIcon = renderedIcon != null || renderedEndIcon != null;
124
130
  const hasDropdown = Boolean(dropdownOptions?.length);
125
131
  const dropdownDisabled = !dropdownOptions?.some((option) => !option.disabled);
126
132
  const mainAppearance = getAppearance(disabled, forcedState);
@@ -135,11 +141,19 @@ export const Button = ({
135
141
  dropdownAppearance,
136
142
  forcedState,
137
143
  );
138
- const label = (
139
- <>
140
- {renderIcon(resolvedIcon)}
141
- <span className="px-2">{children}</span>
142
- </>
144
+
145
+ /** Label-only: centered text. With start icon: gap between icon and label. */
146
+ const content = (
147
+ <span
148
+ className={cn(
149
+ "flex min-h-6 items-center justify-center",
150
+ hasIcon && "gap-2",
151
+ )}
152
+ >
153
+ {renderedIcon}
154
+ <span>{children}</span>
155
+ {renderedEndIcon}
156
+ </span>
143
157
  );
144
158
 
145
159
  if (!hasDropdown) {
@@ -156,9 +170,7 @@ export const Button = ({
156
170
  )}
157
171
  {...props}
158
172
  >
159
- <span className="flex min-h-6 items-center [&>*:first-child]:-mr-1 [&>*:last-child]:-mr-1">
160
- {label}
161
- </span>
173
+ {content}
162
174
  </button>
163
175
  );
164
176
  }
@@ -175,9 +187,7 @@ export const Button = ({
175
187
  )}
176
188
  {...props}
177
189
  >
178
- <span className="flex min-h-6 items-center [&>*:first-child]:-mr-1 [&>*:last-child]:-mr-1">
179
- {label}
180
- </span>
190
+ {content}
181
191
  </button>
182
192
  );
183
193
 
@@ -8,20 +8,32 @@ export type LogoProps = {
8
8
  muted?: boolean;
9
9
  };
10
10
 
11
+ // The "A" body only — no topper. Technical adds a straight bar; Compliance
12
+ // adds a curved arc. Previously the bar lived inside this shared path, so the
13
+ // Compliance glyph rendered the technical bar (plus a faint arc) and looked
14
+ // identical to Technical.
11
15
  const ASK_CHIEF_A =
12
- "M9.89258 5.62793L13.2041 14.625H11.9316L9.20117 11.8926H9.03223L6.29785 14.623C6.29785 14.623 6.29573 14.6211 6.29395 14.6211V14.625H5.0625L8.38867 5.62793H9.89258ZM9.01172 7.12305L7.16016 12.2334L8.87109 10.5234H9.36133L11.0762 12.2402L9.23828 7.12305H9.01172ZM12.6904 3.375V4.64355H5.61328V3.375H12.6904Z";
16
+ "M9.89258 5.62793L13.2041 14.625H11.9316L9.20117 11.8926H9.03223L6.29785 14.623C6.29785 14.623 6.29573 14.6211 6.29395 14.6211V14.625H5.0625L8.38867 5.62793H9.89258ZM9.01172 7.12305L7.16016 12.2334L8.87109 10.5234H9.36133L11.0762 12.2402L9.23828 7.12305H9.01172Z";
13
17
 
14
- const TechnicalGlyph = () => <path d={ASK_CHIEF_A} fill="currentColor" />;
18
+ const TECHNICAL_BAR = "M12.6904 3.375V4.64355H5.61328V3.375H12.6904Z";
15
19
 
16
- const ComplianceGlyph = () => (
20
+ const TechnicalGlyph = () => (
17
21
  <>
18
22
  <path d={ASK_CHIEF_A} fill="currentColor" />
23
+ <path d={TECHNICAL_BAR} fill="currentColor" />
24
+ </>
25
+ );
26
+
27
+ // Exact Figma export (Logo → Compliance): filled "A" body + filled crescent.
28
+ const ComplianceGlyph = () => (
29
+ <>
30
+ <path
31
+ d="M8.30335 5.84666L5.18335 14.2917H6.33835V14.2883C6.34002 14.2883 6.34168 14.29 6.34168 14.29L8.90668 11.7267H9.06668L11.6283 14.2917H12.8233L9.71668 5.84666H8.30502H8.30335ZM9.21502 10.4433H8.75668L7.15168 12.0483L8.89002 7.25166H9.10168L10.825 12.055L9.21668 10.4433H9.21502Z"
32
+ fill="currentColor"
33
+ />
19
34
  <path
20
- d="M6.2 5.2C7.4 4.1 10.6 4.1 11.8 5.2"
21
- stroke="currentColor"
22
- strokeWidth="0.9"
23
- fill="none"
24
- strokeLinecap="round"
35
+ d="M8.98839 4.85833C9.87172 4.85833 10.6817 5.23 11.3117 5.84666H12.7967C11.9251 4.54666 10.5434 3.70667 8.98839 3.70667C7.43339 3.70667 6.05172 4.54666 5.18005 5.84666H6.66505C7.29339 5.23 8.10505 4.85833 8.98839 4.85833Z"
36
+ fill="currentColor"
25
37
  />
26
38
  </>
27
39
  );
@@ -1,12 +1,20 @@
1
1
  import { type ButtonHTMLAttributes } from "react";
2
2
  import { cn } from "../utils/cn";
3
3
 
4
- export type SwitchProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onChange"> & {
4
+ export type SwitchProps = Omit<
5
+ ButtonHTMLAttributes<HTMLButtonElement>,
6
+ "onChange"
7
+ > & {
5
8
  checked: boolean;
6
9
  onChange: (checked: boolean) => void;
7
10
  disabled?: boolean;
8
11
  };
9
12
 
13
+ /**
14
+ * On/off control — Figma Switch (3068:65681).
15
+ * Track: 36×16 (grey-400 off / grey-900 on). Thumb: 24×24 white (grey-50 off),
16
+ * 1px border matching track, Raise-2 shadow. Off left / on right, edges flush.
17
+ */
10
18
  export const Switch = ({
11
19
  checked,
12
20
  onChange,
@@ -19,19 +27,31 @@ export const Switch = ({
19
27
  role="switch"
20
28
  aria-checked={checked}
21
29
  disabled={disabled}
22
- onClick={() => onChange(!checked)}
30
+ onClick={(event) => {
31
+ event.stopPropagation();
32
+ onChange(!checked);
33
+ }}
23
34
  className={cn(
24
- "relative inline-flex h-6 w-10 shrink-0 items-center rounded-full transition-colors disabled:cursor-not-allowed",
25
- checked ? "bg-blue-600" : "bg-grey-200",
26
- disabled && "opacity-50",
35
+ "relative inline-flex h-6 w-9 shrink-0 items-center",
36
+ "disabled:cursor-not-allowed disabled:opacity-50",
27
37
  className,
28
38
  )}
29
39
  {...props}
30
40
  >
31
41
  <span
42
+ aria-hidden
32
43
  className={cn(
33
- "inline-block size-5 rounded-full bg-white shadow-raise1 transition-transform",
34
- checked ? "translate-x-[18px]" : "translate-x-0.5",
44
+ "pointer-events-none absolute inset-x-0 top-1/2 h-4 -translate-y-1/2 rounded-full transition-colors",
45
+ checked ? "bg-grey-900" : "bg-grey-400",
46
+ )}
47
+ />
48
+ <span
49
+ aria-hidden
50
+ className={cn(
51
+ "relative inline-block size-6 rounded-full border border-solid shadow-raise2 transition-[transform,border-color,background-color]",
52
+ checked
53
+ ? "translate-x-3 border-grey-900 bg-white"
54
+ : "translate-x-0 border-grey-400 bg-grey-50",
35
55
  )}
36
56
  />
37
57
  </button>
@@ -1,92 +1,92 @@
1
- export type ButtonHierarchy =
2
- | "primary"
3
- | "secondary"
4
- | "tertiary"
5
- | "quaternary"
6
- | "destructive";
7
-
8
- export type ButtonAppearance = "idle" | "hover" | "disabled";
9
-
10
- type HierarchyStyleMap = Record<ButtonAppearance, string>;
11
-
12
- const primaryStyles: HierarchyStyleMap = {
13
- idle: "bg-action-primary-idle text-action-primary-on-idle",
14
- hover: "bg-action-primary-hover text-action-primary-on-hover",
15
- disabled: "bg-action-primary-disabled text-action-primary-on-disabled",
16
- };
17
-
18
- const secondaryStyles: HierarchyStyleMap = {
19
- idle:
20
- "border border-divider-primary bg-action-secondary-idle text-action-secondary-on-idle",
21
- hover:
22
- "border border-divider-secondary bg-action-secondary-hover text-action-secondary-on-hover",
23
- disabled:
24
- "border border-divider-primary bg-action-secondary-disabled text-action-secondary-on-disabled",
25
- };
26
-
27
- const tertiaryStyles: HierarchyStyleMap = {
28
- idle: "bg-action-tertiary-idle text-action-tertiary-on-idle",
29
- hover: "bg-action-tertiary-hover text-action-tertiary-on-hover",
30
- disabled: "bg-action-tertiary-disabled text-action-tertiary-on-disabled",
31
- };
32
-
33
- const quaternaryStyles: HierarchyStyleMap = {
34
- idle: "bg-action-quaternary-idle text-action-quaternary-on-idle",
35
- hover: "bg-action-quaternary-hover text-action-quaternary-on-hover",
36
- disabled: "bg-action-quaternary-disabled text-action-quaternary-on-disabled",
37
- };
38
-
39
- const destructiveStyles: HierarchyStyleMap = {
40
- idle: "bg-action-destructive-idle text-action-destructive-on-idle",
41
- hover: "bg-action-destructive-hover text-action-destructive-on-hover",
42
- disabled:
43
- "bg-action-destructive-disabled text-action-destructive-on-disabled",
44
- };
45
-
46
- const hierarchyStyles: Record<ButtonHierarchy, HierarchyStyleMap> = {
47
- primary: primaryStyles,
48
- secondary: secondaryStyles,
49
- tertiary: tertiaryStyles,
50
- quaternary: quaternaryStyles,
51
- destructive: destructiveStyles,
52
- };
53
-
54
- const interactiveHierarchyStyles: Record<ButtonHierarchy, string> = {
55
- primary:
56
- "bg-action-primary-idle text-action-primary-on-idle hover:bg-action-primary-hover hover:text-action-primary-on-hover",
57
- secondary:
58
- "border border-divider-primary bg-action-secondary-idle text-action-secondary-on-idle hover:border-divider-secondary hover:bg-action-secondary-hover hover:text-action-secondary-on-hover",
59
- tertiary:
60
- "bg-action-tertiary-idle text-action-tertiary-on-idle hover:bg-action-tertiary-hover hover:text-action-tertiary-on-hover",
61
- quaternary:
62
- "bg-action-quaternary-idle text-action-quaternary-on-idle hover:bg-action-quaternary-hover hover:text-action-quaternary-on-hover",
63
- destructive:
64
- "bg-action-destructive-idle text-action-destructive-on-idle hover:bg-action-destructive-hover hover:text-action-destructive-on-hover",
65
- };
66
-
67
- const disabledHierarchyStyles: Record<ButtonHierarchy, string> = {
68
- primary: "bg-action-primary-disabled text-action-primary-on-disabled",
69
- secondary:
70
- "border border-divider-primary bg-action-secondary-disabled text-action-secondary-on-disabled",
71
- tertiary: "bg-action-tertiary-disabled text-action-tertiary-on-disabled",
72
- quaternary:
73
- "bg-action-quaternary-disabled text-action-quaternary-on-disabled",
74
- destructive:
75
- "bg-action-destructive-disabled text-action-destructive-on-disabled",
76
- };
77
-
78
- export const getButtonAppearanceClasses = (
79
- hierarchy: ButtonHierarchy,
80
- appearance: ButtonAppearance,
81
- ) => hierarchyStyles[hierarchy][appearance];
82
-
83
- export const getButtonInteractiveClasses = (
84
- hierarchy: ButtonHierarchy,
85
- disabled: boolean,
86
- ) => {
87
- if (disabled) {
88
- return disabledHierarchyStyles[hierarchy];
89
- }
90
-
91
- return interactiveHierarchyStyles[hierarchy];
92
- };
1
+ export type ButtonHierarchy =
2
+ | "primary"
3
+ | "secondary"
4
+ | "tertiary"
5
+ | "quaternary"
6
+ | "destructive";
7
+
8
+ export type ButtonAppearance = "idle" | "hover" | "disabled";
9
+
10
+ type HierarchyStyleMap = Record<ButtonAppearance, string>;
11
+
12
+ const primaryStyles: HierarchyStyleMap = {
13
+ idle: "bg-action-primary-idle text-action-primary-on-idle",
14
+ hover: "bg-action-primary-hover text-action-primary-on-hover",
15
+ disabled: "bg-action-primary-disabled text-action-primary-on-disabled",
16
+ };
17
+
18
+ const secondaryStyles: HierarchyStyleMap = {
19
+ idle:
20
+ "border border-divider-primary bg-action-secondary-idle text-action-secondary-on-idle",
21
+ hover:
22
+ "border border-divider-secondary bg-action-secondary-hover text-action-secondary-on-hover",
23
+ disabled:
24
+ "border border-divider-primary bg-action-secondary-disabled text-action-secondary-on-disabled",
25
+ };
26
+
27
+ const tertiaryStyles: HierarchyStyleMap = {
28
+ idle: "bg-action-tertiary-idle text-action-tertiary-on-idle",
29
+ hover: "bg-action-tertiary-hover text-action-tertiary-on-hover",
30
+ disabled: "bg-action-tertiary-disabled text-action-tertiary-on-disabled",
31
+ };
32
+
33
+ const quaternaryStyles: HierarchyStyleMap = {
34
+ idle: "bg-action-quaternary-idle text-action-quaternary-on-idle",
35
+ hover: "bg-action-quaternary-hover text-action-quaternary-on-hover",
36
+ disabled: "bg-action-quaternary-disabled text-action-quaternary-on-disabled",
37
+ };
38
+
39
+ const destructiveStyles: HierarchyStyleMap = {
40
+ idle: "bg-action-destructive-idle text-action-destructive-on-idle",
41
+ hover: "bg-action-destructive-hover text-action-destructive-on-hover",
42
+ disabled:
43
+ "bg-action-destructive-disabled text-action-destructive-on-disabled",
44
+ };
45
+
46
+ const hierarchyStyles: Record<ButtonHierarchy, HierarchyStyleMap> = {
47
+ primary: primaryStyles,
48
+ secondary: secondaryStyles,
49
+ tertiary: tertiaryStyles,
50
+ quaternary: quaternaryStyles,
51
+ destructive: destructiveStyles,
52
+ };
53
+
54
+ const interactiveHierarchyStyles: Record<ButtonHierarchy, string> = {
55
+ primary:
56
+ "bg-action-primary-idle text-action-primary-on-idle hover:bg-action-primary-hover hover:text-action-primary-on-hover",
57
+ secondary:
58
+ "border border-divider-primary bg-action-secondary-idle text-action-secondary-on-idle hover:border-divider-secondary hover:bg-action-secondary-hover hover:text-action-secondary-on-hover",
59
+ tertiary:
60
+ "bg-action-tertiary-idle text-action-tertiary-on-idle hover:bg-action-tertiary-hover hover:text-action-tertiary-on-hover",
61
+ quaternary:
62
+ "bg-action-quaternary-idle text-action-quaternary-on-idle hover:bg-action-quaternary-hover hover:text-action-quaternary-on-hover",
63
+ destructive:
64
+ "bg-action-destructive-idle text-action-destructive-on-idle hover:bg-action-destructive-hover hover:text-action-destructive-on-hover",
65
+ };
66
+
67
+ const disabledHierarchyStyles: Record<ButtonHierarchy, string> = {
68
+ primary: "bg-action-primary-disabled text-action-primary-on-disabled",
69
+ secondary:
70
+ "border border-divider-primary bg-action-secondary-disabled text-action-secondary-on-disabled",
71
+ tertiary: "bg-action-tertiary-disabled text-action-tertiary-on-disabled",
72
+ quaternary:
73
+ "bg-action-quaternary-disabled text-action-quaternary-on-disabled",
74
+ destructive:
75
+ "bg-action-destructive-disabled text-action-destructive-on-disabled",
76
+ };
77
+
78
+ export const getButtonAppearanceClasses = (
79
+ hierarchy: ButtonHierarchy,
80
+ appearance: ButtonAppearance,
81
+ ) => hierarchyStyles[hierarchy][appearance];
82
+
83
+ export const getButtonInteractiveClasses = (
84
+ hierarchy: ButtonHierarchy,
85
+ disabled: boolean,
86
+ ) => {
87
+ if (disabled) {
88
+ return disabledHierarchyStyles[hierarchy];
89
+ }
90
+
91
+ return interactiveHierarchyStyles[hierarchy];
92
+ };
@@ -14,5 +14,5 @@ export { Tooltip, TooltipProvider, type TooltipProps, type TooltipSide } from ".
14
14
  export { ThinkingDot, type ThinkingDotProps } from "./ThinkingDot";
15
15
  export { Count, type CountProps } from "./Count";
16
16
  export { Switch, type SwitchProps } from "./Switch";
17
- export { Badge, type BadgeProps } from "./Badge";
17
+ export { Badge, type BadgeProps, type BadgeColor, type BadgeType } from "./Badge";
18
18
  export { Callout, type CalloutProps } from "./Callout";
@@ -1,107 +1,107 @@
1
- import { AttachmentIcon } from "../../icons";
2
- import { Button } from "../../primitives";
3
- import { FigmaContent, FigmaPage, FigmaSection } from "../_layout";
4
- import { FIGMA_WIDTHS } from "./figma-widths";
5
- import {
6
- BUTTON_VARIANT_SLOTS,
7
- FIGMA_BUTTON_SLOTS,
8
- FIGMA_BUTTONS_CANVAS,
9
- FIGMA_BUTTONS_GRID,
10
- type ButtonVisualState,
11
- } from "./figma-buttons-layout";
12
- import { IconButtonSnapshot } from "./helpers";
13
-
14
- const demoDropdownOptions = [
15
- { label: "Option A", onSelect: () => undefined },
16
- { label: "Option B", onSelect: () => undefined },
17
- ];
18
-
19
- const slotProps = (visualState: ButtonVisualState) => ({
20
- forcedState: visualState === "idle" ? undefined : visualState,
21
- disabled: visualState === "disabled",
22
- });
23
-
24
- export const ButtonsCanvas = () => (
25
- <FigmaPage title="Buttons" width={FIGMA_WIDTHS.buttons}>
26
- <FigmaContent padding={0}>
27
- <div className="px-8 pb-8 pt-6">
28
- <FigmaSection label="Button">
29
- <div
30
- className="relative"
31
- style={{
32
- width: FIGMA_BUTTONS_CANVAS.width,
33
- height: FIGMA_BUTTONS_CANVAS.height,
34
- }}
35
- >
36
- <div
37
- data-figma-buttons-grid
38
- className="absolute left-0 top-0"
39
- style={{
40
- width: FIGMA_BUTTONS_GRID.width,
41
- height: FIGMA_BUTTONS_GRID.height,
42
- }}
43
- >
44
- {FIGMA_BUTTON_SLOTS.map((slot) => (
45
- <div
46
- key={`${slot.hierarchy}-${slot.visualState}`}
47
- className="absolute"
48
- style={{ left: slot.x, top: slot.y }}
49
- >
50
- <Button
51
- hierarchy={slot.hierarchy}
52
- icon={AttachmentIcon}
53
- dropdownOptions={demoDropdownOptions}
54
- {...slotProps(slot.visualState)}
55
- >
56
- Button
57
- </Button>
58
- </div>
59
- ))}
60
- </div>
61
-
62
- {BUTTON_VARIANT_SLOTS.map((slot) => (
63
- <div
64
- key={`${slot.hierarchy}-${slot.variant}`}
65
- data-visual-test-only
66
- className="absolute"
67
- style={{ left: slot.x, top: slot.y }}
68
- >
69
- {slot.variant === "noIcon" ? (
70
- <Button
71
- hierarchy={slot.hierarchy}
72
- dropdownOptions={demoDropdownOptions}
73
- >
74
- Button
75
- </Button>
76
- ) : (
77
- <Button hierarchy={slot.hierarchy} icon={AttachmentIcon}>
78
- Button
79
- </Button>
80
- )}
81
- </div>
82
- ))}
83
- </div>
84
- </FigmaSection>
85
-
86
- <FigmaSection label="Icon Button" className="mt-8">
87
- <div className="flex flex-wrap items-center gap-6">
88
- <IconButtonSnapshot hierarchy="tertiary" visualState="idle" />
89
- <IconButtonSnapshot hierarchy="tertiary" visualState="hover" />
90
- <IconButtonSnapshot hierarchy="quaternary" visualState="idle" />
91
- <IconButtonSnapshot hierarchy="quaternary" visualState="hover" />
92
- <IconButtonSnapshot
93
- hierarchy="quaternary"
94
- visualState="idle"
95
- size="small"
96
- />
97
- <IconButtonSnapshot
98
- hierarchy="quaternary"
99
- visualState="hover"
100
- size="small"
101
- />
102
- </div>
103
- </FigmaSection>
104
- </div>
105
- </FigmaContent>
106
- </FigmaPage>
107
- );
1
+ import { AttachmentIcon } from "../../icons";
2
+ import { Button } from "../../primitives";
3
+ import { FigmaContent, FigmaPage, FigmaSection } from "../_layout";
4
+ import { FIGMA_WIDTHS } from "./figma-widths";
5
+ import {
6
+ BUTTON_VARIANT_SLOTS,
7
+ FIGMA_BUTTON_SLOTS,
8
+ FIGMA_BUTTONS_CANVAS,
9
+ FIGMA_BUTTONS_GRID,
10
+ type ButtonVisualState,
11
+ } from "./figma-buttons-layout";
12
+ import { IconButtonSnapshot } from "./helpers";
13
+
14
+ const demoDropdownOptions = [
15
+ { label: "Option A", onSelect: () => undefined },
16
+ { label: "Option B", onSelect: () => undefined },
17
+ ];
18
+
19
+ const slotProps = (visualState: ButtonVisualState) => ({
20
+ forcedState: visualState === "idle" ? undefined : visualState,
21
+ disabled: visualState === "disabled",
22
+ });
23
+
24
+ export const ButtonsCanvas = () => (
25
+ <FigmaPage title="Buttons" width={FIGMA_WIDTHS.buttons}>
26
+ <FigmaContent padding={0}>
27
+ <div className="px-8 pb-8 pt-6">
28
+ <FigmaSection label="Button">
29
+ <div
30
+ className="relative"
31
+ style={{
32
+ width: FIGMA_BUTTONS_CANVAS.width,
33
+ height: FIGMA_BUTTONS_CANVAS.height,
34
+ }}
35
+ >
36
+ <div
37
+ data-figma-buttons-grid
38
+ className="absolute left-0 top-0"
39
+ style={{
40
+ width: FIGMA_BUTTONS_GRID.width,
41
+ height: FIGMA_BUTTONS_GRID.height,
42
+ }}
43
+ >
44
+ {FIGMA_BUTTON_SLOTS.map((slot) => (
45
+ <div
46
+ key={`${slot.hierarchy}-${slot.visualState}`}
47
+ className="absolute"
48
+ style={{ left: slot.x, top: slot.y }}
49
+ >
50
+ <Button
51
+ hierarchy={slot.hierarchy}
52
+ icon={AttachmentIcon}
53
+ dropdownOptions={demoDropdownOptions}
54
+ {...slotProps(slot.visualState)}
55
+ >
56
+ Button
57
+ </Button>
58
+ </div>
59
+ ))}
60
+ </div>
61
+
62
+ {BUTTON_VARIANT_SLOTS.map((slot) => (
63
+ <div
64
+ key={`${slot.hierarchy}-${slot.variant}`}
65
+ data-visual-test-only
66
+ className="absolute"
67
+ style={{ left: slot.x, top: slot.y }}
68
+ >
69
+ {slot.variant === "noIcon" ? (
70
+ <Button
71
+ hierarchy={slot.hierarchy}
72
+ dropdownOptions={demoDropdownOptions}
73
+ >
74
+ Button
75
+ </Button>
76
+ ) : (
77
+ <Button hierarchy={slot.hierarchy} icon={AttachmentIcon}>
78
+ Button
79
+ </Button>
80
+ )}
81
+ </div>
82
+ ))}
83
+ </div>
84
+ </FigmaSection>
85
+
86
+ <FigmaSection label="Icon Button" className="mt-8">
87
+ <div className="flex flex-wrap items-center gap-6">
88
+ <IconButtonSnapshot hierarchy="tertiary" visualState="idle" />
89
+ <IconButtonSnapshot hierarchy="tertiary" visualState="hover" />
90
+ <IconButtonSnapshot hierarchy="quaternary" visualState="idle" />
91
+ <IconButtonSnapshot hierarchy="quaternary" visualState="hover" />
92
+ <IconButtonSnapshot
93
+ hierarchy="quaternary"
94
+ visualState="idle"
95
+ size="small"
96
+ />
97
+ <IconButtonSnapshot
98
+ hierarchy="quaternary"
99
+ visualState="hover"
100
+ size="small"
101
+ />
102
+ </div>
103
+ </FigmaSection>
104
+ </div>
105
+ </FigmaContent>
106
+ </FigmaPage>
107
+ );