@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,13 +1,19 @@
1
1
  import { ReactNode } from 'react';
2
- export type ResultRowVariant = "report" | "chat" | "issue";
3
- export type ResultRowState = "idle" | "active";
2
+ import { EntryProps, EntryState, EntryVariant } from '../../components/Entry';
3
+ /** @deprecated Prefer `EntryVariant`. */
4
+ export type ResultRowVariant = EntryVariant;
5
+ /** @deprecated Prefer `EntryState`. */
6
+ export type ResultRowState = EntryState;
4
7
  export type ResultRowProps = {
5
- variant?: ResultRowVariant;
6
- state?: ResultRowState;
8
+ variant?: EntryVariant;
9
+ state?: EntryState;
7
10
  title?: ReactNode;
8
- /** Secondary line — excerpt, metadata, or highlighted query match. */
9
11
  subtitle?: ReactNode;
10
12
  onClick?: () => void;
11
13
  className?: string;
12
14
  };
15
+ /**
16
+ * @deprecated Prefer `Entry` — ResultRow is a thin alias for search lists.
17
+ */
13
18
  export declare const ResultRow: ({ variant, state, title, subtitle, onClick, className, }: ResultRowProps) => import("react/jsx-runtime").JSX.Element;
19
+ export type { EntryProps };
@@ -15,7 +15,8 @@ export declare const sidebarSectionShellCollapsed = "relative box-border flex w-
15
15
  export declare const sidebarUnreadOverlay = "pointer-events-none absolute left-0 top-0 size-6";
16
16
  /** Figma unread dot — ~6px, top-right of the 24px indicator overlay. */
17
17
  export declare const sidebarUnreadDot = "absolute right-0 top-0 size-1.5 rounded-full bg-[#802c20]";
18
- export declare const sidebarSectionContent = "flex w-full min-w-0 items-center gap-2 pl-1";
18
+ /** Icon + label row inside a section shell — no extra inset (shell already has p-2). */
19
+ export declare const sidebarSectionContent = "flex w-full min-w-0 items-center gap-2";
19
20
  export declare const sidebarSectionIconClass = "shrink-0 [&>svg]:size-4";
20
21
  export declare const sidebarSectionLabelClass = "min-w-0 flex-1 truncate text-caption-2 tracking-[0.01em]";
21
22
  /** Figma sidebar icon buttons — transparent idle, grey hover (no white fill). */
@@ -1,11 +1,14 @@
1
1
  import { ReactNode } from 'react';
2
- type BadgeColor = "blue" | "green" | "red" | "orange" | "purple" | "grey";
3
- type BadgeType = "label" | "icon";
2
+ export type BadgeColor = "blue" | "green" | "red" | "orange" | "purple" | "grey";
3
+ export type BadgeType = "label" | "icon";
4
4
  export type BadgeProps = {
5
5
  color: BadgeColor;
6
+ /** `label` grows with content (pill). `icon` is a compact circle for a glyph/digit. */
6
7
  type?: BadgeType;
7
8
  children: ReactNode;
8
9
  className?: string;
9
10
  };
10
- export declare const Badge: ({ color, type, children, className }: BadgeProps) => import("react/jsx-runtime").JSX.Element;
11
- export {};
11
+ /**
12
+ * Figma Badge (4365:74363) — padding + rounded-full; no fixed width on labels.
13
+ */
14
+ export declare const Badge: ({ color, type, children, className, }: BadgeProps) => import("react/jsx-runtime").JSX.Element;
@@ -13,10 +13,12 @@ export type ButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "childre
13
13
  disabled?: boolean;
14
14
  icon?: ComponentType<IconProps> | ReactNode;
15
15
  startIcon?: ComponentType<IconProps> | ReactNode;
16
+ /** Renders after the label, inside the same button (no split/dropdown segment). */
17
+ endIcon?: ComponentType<IconProps> | ReactNode;
16
18
  dropdownOptions?: ButtonDropdownOption[];
17
19
  dropdownOpen?: boolean;
18
20
  onDropdownOpenChange?: (open: boolean) => void;
19
21
  forcedState?: ButtonAppearance;
20
22
  children: ReactNode;
21
23
  };
22
- export declare const Button: ({ hierarchy, disabled, icon, startIcon, dropdownOptions, dropdownOpen, onDropdownOpenChange, forcedState, children, className, type, onClick, ...props }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
24
+ export declare const Button: ({ hierarchy, disabled, icon, startIcon, endIcon, dropdownOptions, dropdownOpen, onDropdownOpenChange, forcedState, children, className, type, onClick, ...props }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
@@ -4,4 +4,9 @@ export type SwitchProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onChang
4
4
  onChange: (checked: boolean) => void;
5
5
  disabled?: boolean;
6
6
  };
7
+ /**
8
+ * On/off control — Figma Switch (3068:65681).
9
+ * Track: 36×16 (grey-400 off / grey-900 on). Thumb: 24×24 white (grey-50 off),
10
+ * 1px border matching track, Raise-2 shadow. Off left / on right, edges flush.
11
+ */
7
12
  export declare const Switch: ({ checked, onChange, disabled, className, ...props }: SwitchProps) => import("react/jsx-runtime").JSX.Element;
@@ -11,5 +11,5 @@ export { Tooltip, TooltipProvider, type TooltipProps, type TooltipSide } from '.
11
11
  export { ThinkingDot, type ThinkingDotProps } from './ThinkingDot';
12
12
  export { Count, type CountProps } from './Count';
13
13
  export { Switch, type SwitchProps } from './Switch';
14
- export { Badge, type BadgeProps } from './Badge';
14
+ export { Badge, type BadgeProps, type BadgeColor, type BadgeType } from './Badge';
15
15
  export { Callout, type CalloutProps } from './Callout';
@@ -82,6 +82,10 @@ export declare const theme: {
82
82
  md: "6px";
83
83
  sm: "4px";
84
84
  };
85
+ /** Extends Tailwind’s max-width scale (7xl = 1280px). */
86
+ maxWidth: {
87
+ "8xl": string;
88
+ };
85
89
  colors: {
86
90
  grey: {
87
91
  readonly 50: "#fdfdfc";
@@ -233,10 +237,10 @@ export declare const theme: {
233
237
  };
234
238
  };
235
239
  accent: {
236
- onLight: string;
237
- onDark: string;
238
- bgLight: string;
239
- bgLighter: string;
240
+ "on-light": string;
241
+ "on-dark": string;
242
+ "bg-light": string;
243
+ "bg-lighter": string;
240
244
  };
241
245
  divider: {
242
246
  primary: string;
@@ -0,0 +1 @@
1
+ "use strict";const n={50:"#fdfdfc",100:"#f4f2ea",200:"#e1ddce",300:"#bfb9a5",400:"#969080",500:"#6e6960",600:"#524e47",700:"#3a3733",800:"#312e2a",900:"#262420"},o={50:"#f5f8f2",100:"#dde6d2",200:"#c5d4b3",300:"#a8bf8f",400:"#7a9a5e",500:"#5a7a42",600:"#456332",700:"#304624",800:"#223018",900:"#141c0e"},d={50:"#eef1f8",100:"#dae0ef",200:"#b8c4e0",300:"#8fa3cc",400:"#5274ae",500:"#3a5d96",600:"#154199",700:"#103480",800:"#0c2860",900:"#081c42"},c={50:"#faf3f1",100:"#f0d3cc",200:"#e4b0a5",300:"#c97a6b",400:"#b85a48",500:"#a0392a",600:"#802c20",700:"#621f16",800:"#45150f",900:"#2a0c08"},l={50:"#faf1de",100:"#f5e4c0",200:"#efd49a",300:"#e4bc6a",400:"#d9a03e",500:"#c48820",600:"#8f6318",700:"#5a3d0d",800:"#3d2a09",900:"#261a05"},s={50:"#f6f2f8",100:"#e2d9e8",200:"#cbbad6",300:"#b09bc3",400:"#957cb0",500:"#7a5d9d",600:"#5e4680",700:"#3d2e4a",800:"#2a2033",900:"#18121c"},p="#ffffff",a={grey:n,green:o,blue:d,red:c,orange:l,purple:s},t={raise1:"0 1px 2px rgba(38, 36, 32, 0.06), 0 1px 3px rgba(38, 36, 32, 0.04)",raise2:"0 2px 8px rgba(38, 36, 32, 0.08), 0 1px 2px rgba(38, 36, 32, 0.04)",raise3:"0 8px 24px rgba(38, 36, 32, 0.12), 0 2px 8px rgba(38, 36, 32, 0.06)"},r={control:"8px",lg:"8px",md:"6px",sm:"4px"},e=(v,i)=>[v,{lineHeight:i.lineHeight,letterSpacing:i.letterSpacing,...i.fontWeight?{fontWeight:String(i.fontWeight)}:{}}],g={fontFamily:{heading:['"TRY Vesterbro"',"Libre Baskerville","Georgia","serif"],sans:['"Matter-TRIAL"',"DM Sans","system-ui","sans-serif"],mono:["Roboto Mono","monospace"]},fontSize:{title:e("28px",{lineHeight:"34px",letterSpacing:"-0.02em"}),"title-em":e("28px",{lineHeight:"34px",letterSpacing:"-0.02em",fontWeight:500}),heading:e("22px",{lineHeight:"28px",letterSpacing:"0",fontWeight:500}),subheader:e("18px",{lineHeight:"28px",letterSpacing:"-0.01em"}),"subheader-em":e("18px",{lineHeight:"28px",letterSpacing:"-0.01em",fontWeight:500}),body:e("16px",{lineHeight:"24px",letterSpacing:"-0.01em"}),"body-em":e("16px",{lineHeight:"24px",letterSpacing:"-0.01em",fontWeight:500}),"caption-1":e("16px",{lineHeight:"22px",letterSpacing:"0.02em"}),"caption-1-em":e("16px",{lineHeight:"22px",letterSpacing:"0.02em",fontWeight:500}),"caption-2":e("14px",{lineHeight:"20px",letterSpacing:"0.01em"}),"caption-2-em":e("14px",{lineHeight:"20px",letterSpacing:"0.01em",fontWeight:500}),footnote:e("13px",{lineHeight:"17px",letterSpacing:"0"}),"footnote-em":e("13px",{lineHeight:"17px",letterSpacing:"0",fontWeight:500})},boxShadow:{raise1:t.raise1,raise2:t.raise2,raise3:t.raise3},borderRadius:{control:r.control,lg:r.lg,md:r.md,sm:r.sm},maxWidth:{"8xl":"1640px"},colors:{grey:a.grey,gray:a.grey,green:a.green,blue:a.blue,red:a.red,orange:a.orange,purple:a.purple,white:"#ffffff",action:{primary:{idle:"var(--action-primary-idle)","on-idle":"var(--action-primary-on-idle)",hover:"var(--action-primary-hover)","on-hover":"var(--action-primary-on-hover)",disabled:"var(--action-primary-disabled)","on-disabled":"var(--action-primary-on-disabled)"},secondary:{idle:"var(--action-secondary-idle)","on-idle":"var(--action-secondary-on-idle)",hover:"var(--action-secondary-hover)","on-hover":"var(--action-secondary-on-hover)",disabled:"var(--action-secondary-disabled)","on-disabled":"var(--action-secondary-on-disabled)"},tertiary:{idle:"var(--action-tertiary-idle)","on-idle":"var(--action-tertiary-on-idle)",hover:"var(--action-tertiary-hover)","on-hover":"var(--action-tertiary-on-hover)",disabled:"var(--action-tertiary-disabled)","on-disabled":"var(--action-tertiary-on-disabled)"},quaternary:{idle:"var(--action-quaternary-idle)","on-idle":"var(--action-quaternary-on-idle)",hover:"var(--action-quaternary-hover)","on-hover":"var(--action-quaternary-on-hover)",disabled:"var(--action-quaternary-disabled)","on-disabled":"var(--action-quaternary-on-disabled)"},destructive:{idle:"var(--action-destructive-idle)","on-idle":"var(--action-destructive-on-idle)",hover:"var(--action-destructive-hover)","on-hover":"var(--action-destructive-on-hover)",disabled:"var(--action-destructive-disabled)","on-disabled":"var(--action-destructive-on-disabled)"}},background:{primary:"var(--background-primary)",secondary:"var(--background-secondary)",tertiary:"var(--background-tertiary)",hover:"var(--background-hover)",selected:"var(--background-selected)",overlay:"var(--background-overlay)"},display:{"on-light":{primary:"var(--display-on-light-primary)",secondary:"var(--display-on-light-secondary)",tertiary:"var(--display-on-light-tertiary)",quaternary:"var(--display-on-light-quaternary)"},"on-dark":{primary:"var(--display-on-dark-primary)",secondary:"var(--display-on-dark-secondary)",tertiary:"var(--display-on-dark-tertiary)",quaternary:"var(--display-on-dark-quaternary)"}},accent:{"on-light":"var(--accent-on-light)","on-dark":"var(--accent-on-dark)","bg-light":"var(--accent-bg-light)","bg-lighter":"var(--accent-bg-lighter)"},divider:{primary:"var(--divider-primary)",secondary:"var(--divider-secondary)"},meta:{green:"var(--meta-green)",onGreen:"var(--meta-on-green)",orange:"var(--meta-orange)",onOrange:"var(--meta-on-orange)",red:"var(--meta-red)",onRed:"var(--meta-on-red)",blue:"var(--meta-blue)",onBlue:"var(--meta-on-blue)",purple:"var(--meta-purple)",onPurple:"var(--meta-on-purple)"},"text-primary":"var(--display-on-light-primary)","text-secondary":"var(--display-on-light-secondary)","text-tertiary":"var(--display-on-light-tertiary)","surface-primary":"var(--background-primary)","surface-secondary":"var(--background-secondary)","surface-hover":"var(--background-secondary)","border-light":"var(--divider-primary)","border-medium":"var(--divider-secondary)"}};exports.blue=d;exports.borderRadius=r;exports.colorScales=a;exports.elevation=t;exports.green=o;exports.grey=n;exports.orange=l;exports.purple=s;exports.red=c;exports.theme=g;exports.white=p;
@@ -53,7 +53,7 @@ const o = {
53
53
  700: "#5a3d0d",
54
54
  800: "#3d2a09",
55
55
  900: "#261a05"
56
- }, v = {
56
+ }, p = {
57
57
  50: "#f6f2f8",
58
58
  100: "#e2d9e8",
59
59
  200: "#cbbad6",
@@ -64,7 +64,7 @@ const o = {
64
64
  700: "#3d2e4a",
65
65
  800: "#2a2033",
66
66
  900: "#18121c"
67
- }, p = "#ffffff", a = { grey: o, green: d, blue: c, red: l, orange: s, purple: v }, t = {
67
+ }, v = "#ffffff", a = { grey: o, green: d, blue: c, red: l, orange: s, purple: p }, t = {
68
68
  raise1: "0 1px 2px rgba(38, 36, 32, 0.06), 0 1px 3px rgba(38, 36, 32, 0.04)",
69
69
  raise2: "0 2px 8px rgba(38, 36, 32, 0.08), 0 1px 2px rgba(38, 36, 32, 0.04)",
70
70
  raise3: "0 8px 24px rgba(38, 36, 32, 0.12), 0 2px 8px rgba(38, 36, 32, 0.06)"
@@ -140,6 +140,10 @@ const o = {
140
140
  md: i.md,
141
141
  sm: i.sm
142
142
  },
143
+ /** Extends Tailwind’s max-width scale (7xl = 1280px). */
144
+ maxWidth: {
145
+ "8xl": "1640px"
146
+ },
143
147
  colors: {
144
148
  grey: a.grey,
145
149
  gray: a.grey,
@@ -214,10 +218,10 @@ const o = {
214
218
  }
215
219
  },
216
220
  accent: {
217
- onLight: "var(--accent-on-light)",
218
- onDark: "var(--accent-on-dark)",
219
- bgLight: "var(--accent-bg-light)",
220
- bgLighter: "var(--accent-bg-lighter)"
221
+ "on-light": "var(--accent-on-light)",
222
+ "on-dark": "var(--accent-on-dark)",
223
+ "bg-light": "var(--accent-bg-light)",
224
+ "bg-lighter": "var(--accent-bg-lighter)"
221
225
  },
222
226
  divider: {
223
227
  primary: "var(--divider-primary)",
@@ -254,8 +258,8 @@ export {
254
258
  t as e,
255
259
  o as g,
256
260
  s as o,
257
- v as p,
261
+ p,
258
262
  l as r,
259
263
  g as t,
260
- p as w
264
+ v as w
261
265
  };
package/dist/theme.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./theme-entry-D2X3Ptjf.js");exports.tailwindTheme=e.theme;exports.theme=e.theme;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./theme-entry-Dwr2mV7_.js");exports.tailwindTheme=e.theme;exports.theme=e.theme;
package/dist/theme.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as a, t as m } from "./theme-entry-CxDa1D0_.mjs";
1
+ import { t as a, t as m } from "./theme-entry-tLBc6zGT.mjs";
2
2
  export {
3
3
  a as tailwindTheme,
4
4
  m as theme
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lateralus-ai/shipping-ui",
3
- "version": "2.0.0-dev.3",
3
+ "version": "2.0.0-dev.30",
4
4
  "description": "Shared UI theme and components for Lateralus shipping applications",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.esm.js",
@@ -50,7 +50,7 @@
50
50
  "release:dev:init": "npx release-it --config .release-it.dev.json major --preRelease=dev",
51
51
  "release:dev:init:publish": "npx release-it --config .release-it.dev.json --no-hooks.before:init major --preRelease=dev",
52
52
  "release:dev": "npx release-it --config .release-it.dev.json --preRelease=dev",
53
- "release:dev:publish": "npx release-it --config .release-it.dev.json --no-hooks.before:init --preRelease=dev"
53
+ "release:dev:publish": "npm run build && npx release-it --config .release-it.dev.json --no-hooks.before:init --preRelease=dev"
54
54
  },
55
55
  "repository": {
56
56
  "type": "git",
@@ -112,6 +112,7 @@
112
112
  "dependencies": {
113
113
  "@radix-ui/react-dialog": "^1.1.19",
114
114
  "@radix-ui/react-dropdown-menu": "^2.1.20",
115
+ "@radix-ui/react-popover": "^1.1.15",
115
116
  "@radix-ui/react-tabs": "^1.1.17",
116
117
  "@radix-ui/react-tooltip": "^1.2.8",
117
118
  "@react-hooks-library/core": "^0.6.2",
@@ -1,44 +1,44 @@
1
- import { type ReactNode } from "react";
2
- import { Button, type ButtonProps } from "../primitives";
3
- import { cn } from "../utils/cn";
4
-
5
- export type EmptyStateProps = {
6
- illustration?: ReactNode;
7
- title: string;
8
- description?: string;
9
- action?: Pick<ButtonProps, "children" | "onClick" | "hierarchy" | "icon" | "startIcon">;
10
- className?: string;
11
- };
12
-
13
- export const EmptyState = ({
14
- illustration,
15
- title,
16
- description,
17
- action,
18
- className,
19
- }: EmptyStateProps) => (
20
- <div
21
- className={cn(
22
- "flex max-w-sm flex-col items-center gap-4 px-6 py-10 text-center",
23
- className,
24
- )}
25
- >
26
- {illustration && <div className="shrink-0">{illustration}</div>}
27
- <div className="flex flex-col gap-1">
28
- <h3 className="text-subheader-em text-display-on-light-primary">{title}</h3>
29
- {description && (
30
- <p className="text-body text-display-on-light-secondary">{description}</p>
31
- )}
32
- </div>
33
- {action && (
34
- <Button
35
- hierarchy={action.hierarchy ?? "primary"}
36
- onClick={action.onClick}
37
- icon={action.icon}
38
- startIcon={action.startIcon}
39
- >
40
- {action.children}
41
- </Button>
42
- )}
43
- </div>
44
- );
1
+ import { type ReactNode } from "react";
2
+ import { Button, type ButtonProps } from "../primitives";
3
+ import { cn } from "../utils/cn";
4
+
5
+ export type EmptyStateProps = {
6
+ illustration?: ReactNode;
7
+ title: string;
8
+ description?: string;
9
+ action?: Pick<ButtonProps, "children" | "onClick" | "hierarchy" | "icon" | "startIcon">;
10
+ className?: string;
11
+ };
12
+
13
+ export const EmptyState = ({
14
+ illustration,
15
+ title,
16
+ description,
17
+ action,
18
+ className,
19
+ }: EmptyStateProps) => (
20
+ <div
21
+ className={cn(
22
+ "flex max-w-sm flex-col items-center gap-4 px-6 py-10 text-center",
23
+ className,
24
+ )}
25
+ >
26
+ {illustration && <div className="shrink-0">{illustration}</div>}
27
+ <div className="flex flex-col gap-1">
28
+ <h3 className="text-subheader-em text-display-on-light-primary">{title}</h3>
29
+ {description && (
30
+ <p className="text-body text-display-on-light-secondary">{description}</p>
31
+ )}
32
+ </div>
33
+ {action && (
34
+ <Button
35
+ hierarchy={action.hierarchy ?? "primary"}
36
+ onClick={action.onClick}
37
+ icon={action.icon}
38
+ startIcon={action.startIcon}
39
+ >
40
+ {action.children}
41
+ </Button>
42
+ )}
43
+ </div>
44
+ );
@@ -1,64 +1,138 @@
1
- import { type ReactNode } from "react";
2
- import { ChatIcon, IssuesIcon } from "../icons";
1
+ import {
2
+ type KeyboardEvent,
3
+ type ReactNode,
4
+ } from "react";
5
+ import { ChatIcon, IssuesIcon, ReportIcon, StatusIcon } from "../icons";
3
6
  import { cn } from "../utils/cn";
4
7
 
5
- export type EntryType = "chat" | "issue";
6
- export type EntryState = "idle" | "selected";
8
+ export type EntryVariant = "chat" | "issue" | "report";
9
+ /** @deprecated Prefer `EntryVariant`. */
10
+ export type EntryType = EntryVariant;
11
+ export type EntryState = "idle" | "active";
7
12
 
8
13
  export type EntryProps = {
9
- type: EntryType;
14
+ /** Visual type — drives the default leading icon. */
15
+ variant?: EntryVariant;
16
+ /** @deprecated Use `variant`. */
17
+ type?: EntryVariant;
10
18
  state?: EntryState;
11
- title: string;
12
- subtitle?: string;
13
- meta?: ReactNode;
19
+ title?: ReactNode;
20
+ /** Secondary line — excerpt, metadata, or highlighted query match. */
21
+ subtitle?: ReactNode;
22
+ /** Unread count badge in the title row (Figma red pill). */
23
+ count?: number;
24
+ /** Trailing actions (e.g. ellipsis menu). Shown on hover / when forced. */
25
+ trailing?: ReactNode;
26
+ /** Override the default variant icon. */
27
+ icon?: ReactNode;
14
28
  onClick?: () => void;
15
29
  className?: string;
30
+ /** @deprecated Use `count` or `trailing`. */
31
+ meta?: ReactNode;
16
32
  };
17
33
 
18
- const typeIcons: Record<EntryType, ReactNode> = {
19
- chat: <ChatIcon size="small" />,
20
- issue: <IssuesIcon size="small" />,
34
+ const variantIcons: Record<EntryVariant, ReactNode> = {
35
+ chat: <ChatIcon className="size-4" />,
36
+ issue: <StatusIcon className="size-4" />,
37
+ report: <ReportIcon className="size-4" />,
21
38
  };
22
39
 
40
+ /**
41
+ * List entry row — Figma `Entry` (389:10001).
42
+ * Shared by search results and activity lists.
43
+ *
44
+ * Renders a `div` (not `<button>`) so trailing controls can be real buttons
45
+ * without nested-button issues. Whole-row click uses `onClick` + keyboard.
46
+ */
23
47
  export const Entry = ({
48
+ variant,
24
49
  type,
25
50
  state = "idle",
26
- title,
51
+ title = "Title",
27
52
  subtitle,
28
- meta,
53
+ count,
54
+ trailing,
55
+ icon,
29
56
  onClick,
30
57
  className,
31
- }: EntryProps) => (
32
- <button
33
- type="button"
34
- data-type={type}
35
- data-state={state}
36
- onClick={onClick}
37
- className={cn(
38
- "flex w-full items-start gap-3 rounded-control px-3 py-2.5 text-left transition-colors",
39
- "hover:bg-background-secondary",
40
- "data-[state=selected]:bg-background-selected data-[state=selected]:text-display-on-dark-primary",
41
- "data-[state=selected]:[&_.entry-subtitle]:text-display-on-dark-secondary",
42
- "data-[state=selected]:[&_.entry-meta]:text-display-on-dark-tertiary",
43
- "data-[state=selected]:[&_.entry-icon]:text-display-on-dark-secondary",
44
- className,
45
- )}
46
- >
47
- <span className="entry-icon mt-0.5 shrink-0 text-display-on-light-secondary">
48
- {typeIcons[type]}
49
- </span>
50
- <span className="min-w-0 flex-1">
51
- <span className="block truncate text-caption-2-em">{title}</span>
52
- {subtitle && (
53
- <span className="entry-subtitle mt-0.5 block truncate text-footnote text-display-on-light-tertiary">
54
- {subtitle}
55
- </span>
58
+ meta,
59
+ }: EntryProps) => {
60
+ const resolvedVariant: EntryVariant = variant ?? type ?? "chat";
61
+ const isInteractive = typeof onClick === "function";
62
+
63
+ const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
64
+ if (!onClick) {
65
+ return;
66
+ }
67
+ if (event.key === "Enter" || event.key === " ") {
68
+ event.preventDefault();
69
+ onClick();
70
+ }
71
+ };
72
+
73
+ return (
74
+ <div
75
+ role={isInteractive ? "button" : undefined}
76
+ tabIndex={isInteractive ? 0 : undefined}
77
+ data-variant={resolvedVariant}
78
+ data-state={state}
79
+ onClick={onClick}
80
+ onKeyDown={handleKeyDown}
81
+ className={cn(
82
+ "group flex w-full items-center gap-4 rounded-control p-2 text-left transition-colors",
83
+ "hover:bg-[rgba(38,36,32,0.04)]",
84
+ state === "active" && "bg-[rgba(38,36,32,0.04)]",
85
+ isInteractive && "cursor-pointer",
86
+ className,
56
87
  )}
57
- </span>
58
- {meta && (
59
- <span className="entry-meta shrink-0 text-footnote text-display-on-light-quaternary">
60
- {meta}
88
+ >
89
+ <span className="shrink-0 text-display-on-light-secondary">
90
+ {icon ?? variantIcons[resolvedVariant] ?? (
91
+ <IssuesIcon className="size-4" />
92
+ )}
93
+ </span>
94
+
95
+ <span className="flex min-w-0 flex-1 flex-col">
96
+ <span className="flex min-h-6 w-full items-center gap-4">
97
+ <span className="min-w-0 flex-1 truncate text-caption-1-em text-display-on-light-primary">
98
+ {title}
99
+ </span>
100
+ {typeof count === "number" && count > 0 && (
101
+ <span
102
+ className="inline-flex min-h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-red-600 px-0.5 text-footnote-em text-white"
103
+ aria-label={`${count} unread`}
104
+ >
105
+ {count > 99 ? "99+" : count}
106
+ </span>
107
+ )}
108
+ {meta != null && typeof count !== "number" && (
109
+ <span className="shrink-0 text-footnote text-display-on-light-quaternary">
110
+ {meta}
111
+ </span>
112
+ )}
113
+ </span>
114
+
115
+ {(subtitle != null && subtitle !== false) || trailing ? (
116
+ <span className="flex min-h-6 w-full items-center gap-4">
117
+ {subtitle != null && subtitle !== false ? (
118
+ <span className="min-w-0 flex-1 truncate text-caption-2 text-display-on-light-secondary">
119
+ {subtitle}
120
+ </span>
121
+ ) : (
122
+ <span className="min-w-0 flex-1" />
123
+ )}
124
+ {trailing != null && (
125
+ <span
126
+ className="inline-flex size-5 shrink-0 items-center justify-center"
127
+ onClick={(event) => event.stopPropagation()}
128
+ onKeyDown={(event) => event.stopPropagation()}
129
+ >
130
+ {trailing}
131
+ </span>
132
+ )}
133
+ </span>
134
+ ) : null}
61
135
  </span>
62
- )}
63
- </button>
64
- );
136
+ </div>
137
+ );
138
+ };