@estiva-app/ui 0.11.0 → 0.12.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.
Files changed (42) hide show
  1. package/dist/Breadcrumb.d.ts +7 -1
  2. package/dist/Breadcrumb.d.ts.map +1 -1
  3. package/dist/Chip.d.ts.map +1 -1
  4. package/dist/CollapsibleSection.d.ts +42 -0
  5. package/dist/CollapsibleSection.d.ts.map +1 -0
  6. package/dist/EmptyState.d.ts +19 -5
  7. package/dist/EmptyState.d.ts.map +1 -1
  8. package/dist/NavItem.d.ts.map +1 -1
  9. package/dist/ScrollArea.d.ts.map +1 -1
  10. package/dist/SectionHeader.d.ts +31 -10
  11. package/dist/SectionHeader.d.ts.map +1 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +126 -55
  15. package/dist/index.js.map +4 -4
  16. package/package.json +1 -1
  17. package/src/Breadcrumb.mdx +6 -0
  18. package/src/Breadcrumb.stories.tsx +12 -0
  19. package/src/Breadcrumb.test.tsx +10 -0
  20. package/src/Breadcrumb.tsx +17 -2
  21. package/src/Chip.tsx +10 -2
  22. package/src/CollapsibleSection.mdx +72 -0
  23. package/src/CollapsibleSection.stories.tsx +38 -0
  24. package/src/CollapsibleSection.test.tsx +81 -0
  25. package/src/CollapsibleSection.tsx +92 -0
  26. package/src/EmptyState.mdx +30 -11
  27. package/src/EmptyState.stories.tsx +7 -3
  28. package/src/EmptyState.test.tsx +39 -0
  29. package/src/EmptyState.tsx +23 -6
  30. package/src/NavItem.tsx +5 -1
  31. package/src/ScrollArea.mdx +6 -0
  32. package/src/ScrollArea.stories.tsx +29 -0
  33. package/src/ScrollArea.test.tsx +15 -0
  34. package/src/ScrollArea.tsx +17 -4
  35. package/src/SectionHeader.mdx +26 -17
  36. package/src/SectionHeader.stories.tsx +4 -35
  37. package/src/SectionHeader.test.tsx +40 -0
  38. package/src/SectionHeader.tsx +70 -39
  39. package/src/Sidebar.mdx +14 -10
  40. package/src/Sidebar.stories.tsx +17 -15
  41. package/src/index.ts +1 -0
  42. package/stories/Choosing.mdx +2 -1
@@ -1,4 +1,4 @@
1
- import { type MouseEventHandler } from 'react';
1
+ import { type MouseEventHandler, type ReactNode } from 'react';
2
2
  /**
3
3
  * A trail: "Documents / Quarterly plan / DOC-12". Ship's Breadcrumb
4
4
  * (2026-09-01), which knows nothing about what the places are.
@@ -26,6 +26,12 @@ export interface Crumb {
26
26
  onClick?: MouseEventHandler<HTMLAnchorElement>;
27
27
  /** Set the item in the mono face — a ref, an id. */
28
28
  mono?: boolean;
29
+ /**
30
+ * 16px, stroke 1.5, before the label — what kind of place this is, so a
31
+ * container's name is not mistaken for an item's (Katerina, 2026-09-09).
32
+ * Decorative: the label says where you are; the icon says what it is.
33
+ */
34
+ icon?: ReactNode;
29
35
  /** Quieter — a label that is not a place. */
30
36
  muted?: boolean;
31
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Breadcrumb.d.ts","sourceRoot":"","sources":["../src/Breadcrumb.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4D,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAIxG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qFAAqF;IACrF,OAAO,CAAC,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;IAC9C,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,EAAE,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,eAAe,+BAyE/D"}
1
+ {"version":3,"file":"Breadcrumb.d.ts","sourceRoot":"","sources":["../src/Breadcrumb.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4D,KAAK,iBAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAIxH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qFAAqF;IACrF,OAAO,CAAC,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;IAC9C,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,EAAE,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,eAAe,+BAkF/D"}
@@ -1 +1 @@
1
- {"version":3,"file":"Chip.d.ts","sourceRoot":"","sources":["../src/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;AAErF,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAWD,wBAAgB,IAAI,CAAC,EAAE,IAAgB,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,SAAS,+BAUhG"}
1
+ {"version":3,"file":"Chip.d.ts","sourceRoot":"","sources":["../src/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;AAErF,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAWD,wBAAgB,IAAI,CAAC,EAAE,IAAgB,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,SAAS,+BAkBhG"}
@@ -0,0 +1,42 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type SectionAction } from './SectionHeader';
3
+ /**
4
+ * A section that opens and closes: a `SectionHeader` whose title is the
5
+ * toggle, and the rows under it, sliding shut and open (Katerina,
6
+ * 2026-09-09, for the sidebars of both apps). On Base UI's `Collapsible`
7
+ * (D6): the state, the title button's `aria-expanded` and `aria-controls`,
8
+ * Enter and Space, the panel's height for the slide, and `hiddenUntilFound`
9
+ * — the browser's find-in-page can find a row inside a closed section and
10
+ * open it, because the rows stay in the DOM while closed.
11
+ *
12
+ * Three ways to hold the state, from least to most work for the caller:
13
+ *
14
+ * - none: `defaultOpen` (open unless told otherwise), kept while mounted;
15
+ * - `storageKey`: the same, and this browser remembers it under that key
16
+ * across reloads — one prop for a sidebar that stays how you left it;
17
+ * - `open` + `onOpenChange`: the caller owns it.
18
+ *
19
+ * A closed section stays closed whatever is selected inside it (her
20
+ * ruling, 2026-09-09) — the reader closed it.
21
+ */
22
+ export interface CollapsibleSectionProps {
23
+ title: string;
24
+ /** Open unless told otherwise. */
25
+ defaultOpen?: boolean;
26
+ /** The caller owns the state. */
27
+ open?: boolean;
28
+ onOpenChange?: (open: boolean) => void;
29
+ /** Remember open or closed in this browser, under this key. The app prefixes it. */
30
+ storageKey?: string;
31
+ /** Beside the title, revealed on hover or focus — `SectionHeader`'s. */
32
+ actions?: SectionAction[];
33
+ showActions?: 'hover' | 'always';
34
+ /** The rows. */
35
+ children: ReactNode;
36
+ /** On the section's box: `mt-2` between groups, `shrink-0` in a scrolling column. */
37
+ className?: string;
38
+ /** On the box the rows sit in: the gap between them. */
39
+ contentClassName?: string;
40
+ }
41
+ export declare function CollapsibleSection({ title, defaultOpen, open: openProp, onOpenChange, storageKey, actions, showActions, children, className, contentClassName }: CollapsibleSectionProps): import("react").JSX.Element;
42
+ //# sourceMappingURL=CollapsibleSection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollapsibleSection.d.ts","sourceRoot":"","sources":["../src/CollapsibleSection.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAGhD,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEnE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,kCAAkC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,iCAAiC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,aAAa,EAAE,CAAA;IACzB,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAChC,gBAAgB;IAChB,QAAQ,EAAE,SAAS,CAAA;IACnB,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAwBD,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,WAAkB,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,EAAE,uBAAuB,+BAyB/L"}
@@ -1,14 +1,28 @@
1
1
  import type { ReactNode } from 'react';
2
2
  /**
3
- * Peek's EmptyState (2026-08-28), verbatim: a 16px icon over a centred line
4
- * of secondary text. The message is the caller's — a shared component has no
5
- * words of its own for what is missing.
3
+ * The place where content will be once there is some, in two manners
4
+ * (Katerina, 2026-09-09):
5
+ *
6
+ * - `page` — the whole page is empty: a 16px icon over a centred line of
7
+ * secondary text, **in the middle of its box both ways** (Katerina,
8
+ * 2026-09-09: it sat near the top). It grows to the room a flex column
9
+ * gives it (`flex-1`) and centres inside that; a caller that draws it
10
+ * straight into a page hands it the height (`className="h-full"`).
11
+ * Peek's EmptyState (2026-08-28) otherwise; the default.
12
+ * - `section` — one section of a page is empty, and the page has other
13
+ * things on it: the line alone, left-aligned, no icon. A section's
14
+ * emptiness is a line among the page's content, not a stage of its own.
15
+ *
16
+ * The message is the caller's — a shared component has no words of its own
17
+ * for what is missing.
6
18
  */
7
19
  export interface EmptyStateProps {
8
- /** 16px, stroke 1.5. A speech bubble when absent. */
20
+ /** 16px, stroke 1.5. A speech bubble when absent. Drawn for a `page` only. */
9
21
  icon?: ReactNode;
10
22
  message: string;
23
+ /** `page` when the whole page is empty; `section` when one part of it is. */
24
+ scope?: 'page' | 'section';
11
25
  className?: string;
12
26
  }
13
- export declare function EmptyState({ icon, message, className }: EmptyStateProps): import("react").JSX.Element;
27
+ export declare function EmptyState({ icon, message, scope, className }: EmptyStateProps): import("react").JSX.Element;
14
28
  //# sourceMappingURL=EmptyState.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../src/EmptyState.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,eAAe,+BAOvE"}
1
+ {"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../src/EmptyState.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAc,EAAE,SAAS,EAAE,EAAE,eAAe,+BAUvF"}
@@ -1 +1 @@
1
- {"version":3,"file":"NavItem.d.ts","sourceRoot":"","sources":["../src/NavItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAIhE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAC/E,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,wBAAwB;IACxB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,MAAc,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,YAAY,+BAwBlH"}
1
+ {"version":3,"file":"NavItem.d.ts","sourceRoot":"","sources":["../src/NavItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAIhE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAC/E,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,wBAAwB;IACxB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,MAAc,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,YAAY,+BA4BlH"}
@@ -1 +1 @@
1
- {"version":3,"file":"ScrollArea.d.ts","sourceRoot":"","sources":["../src/ScrollArea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAA;IAChD,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAKD,wBAAgB,UAAU,CAAC,EAAE,WAAwB,EAAE,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,EAAE,eAAe,+BA6BjI"}
1
+ {"version":3,"file":"ScrollArea.d.ts","sourceRoot":"","sources":["../src/ScrollArea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAA;IAChD,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAKD,wBAAgB,UAAU,CAAC,EAAE,WAAwB,EAAE,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,EAAE,eAAe,+BA0CjI"}
@@ -1,16 +1,32 @@
1
- import { type ReactNode } from 'react';
1
+ import type { ReactNode } from 'react';
2
+ import { useRender } from '@base-ui/react/use-render';
2
3
  /**
3
4
  * The 32px row a section starts with (Peek's SectionHeader, 2026-09-01):
4
- * a SectionLabel, an optional collapse chevron that makes the whole row the
5
- * toggle, and actions that appear only while the row is hovered, as
5
+ * a SectionLabel, an optional collapse chevron that makes the title the
6
+ * toggle, and actions that appear while the row is hovered or focused, as
6
7
  * IconButtons with tooltips.
7
8
  *
9
+ * Three things changed on 2026-09-09, for `CollapsibleSection`:
10
+ *
11
+ * - **The title is a button when it toggles.** It was a `div` with an
12
+ * `onClick`, so the keyboard could not open or close a section at all.
13
+ * The button fills the row up to the actions, so the whole row is still
14
+ * the hit target; the actions sit beside it rather than inside it,
15
+ * because a button inside a button is invalid HTML — and was why every
16
+ * action had to stop its click from also toggling.
17
+ * - **The hover is CSS.** The fill and the actions' reveal were React
18
+ * state (`isHovered`), which the README forbids — a mount cannot stay in
19
+ * step with a transition. `group-hover` now; the actions are in the row
20
+ * at `opacity-0` until hovered or focused, so a keyboard user reaches
21
+ * them too.
22
+ * - **`render`** lets `CollapsibleSection` hand in Base UI's
23
+ * `Collapsible.Trigger` as the title button — one header for the
24
+ * hand-held section (`isExpanded` / `onToggle`) and the Base UI one,
25
+ * with no second click handler.
26
+ *
8
27
  * One API change from Peek's original, safe because no call site used the
9
28
  * old shape yet: the two hard-wired action slots (add, sort) became
10
- * `actions` — the caller brings the icon, the tooltip and the handler; the
11
- * header owns the hover reveal and stops the click from also toggling the
12
- * section. Peek's add/sort pair is the WithActions story, in its original
13
- * order.
29
+ * `actions` — the caller brings the icon, the tooltip and the handler.
14
30
  */
15
31
  export interface SectionAction {
16
32
  /** 16px, stroke 1.5. */
@@ -20,15 +36,20 @@ export interface SectionAction {
20
36
  }
21
37
  export interface SectionHeaderProps {
22
38
  title: string;
23
- /** Collapsible: draws the chevron and makes the whole row the toggle. */
39
+ /** Collapsible: draws the chevron and makes the title a button that toggles. */
24
40
  chevron?: boolean;
25
41
  isExpanded?: boolean;
26
42
  onToggle?: () => void;
27
43
  /** Right-aligned, in the order given. */
28
44
  actions?: SectionAction[];
29
- /** `hover` reveals the actions only while the row is hovered; `always` keeps them. */
45
+ /** `hover` reveals the actions while the row is hovered or focused; `always` keeps them. */
30
46
  showActions?: 'hover' | 'always';
47
+ /**
48
+ * What the title renders as, in Base UI's manner. A plain button with
49
+ * `onToggle` by default; `CollapsibleSection` hands in `Collapsible.Trigger`.
50
+ */
51
+ render?: useRender.RenderProp;
31
52
  className?: string;
32
53
  }
33
- export declare function SectionHeader({ title, chevron, isExpanded, onToggle, actions, showActions, className }: SectionHeaderProps): import("react").JSX.Element;
54
+ export declare function SectionHeader({ title, chevron, isExpanded, onToggle, actions, showActions, render, className }: SectionHeaderProps): import("react").JSX.Element;
34
55
  //# sourceMappingURL=SectionHeader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SectionHeader.d.ts","sourceRoot":"","sources":["../src/SectionHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAMhD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B,wBAAwB;IACxB,IAAI,EAAE,SAAS,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,yCAAyC;IACzC,OAAO,CAAC,EAAE,aAAa,EAAE,CAAA;IACzB,sFAAsF;IACtF,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,OAAe,EAAE,UAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAqB,EAAE,SAAS,EAAE,EAAE,kBAAkB,+BA6CnJ"}
1
+ {"version":3,"file":"SectionHeader.d.ts","sourceRoot":"","sources":["../src/SectionHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAKrD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,aAAa;IAC5B,wBAAwB;IACxB,IAAI,EAAE,SAAS,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,yCAAyC;IACzC,OAAO,CAAC,EAAE,aAAa,EAAE,CAAA;IACzB,4FAA4F;IAC5F,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAChC;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC,UAAU,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,OAAe,EAAE,UAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAqB,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,kBAAkB,+BAuD3J"}
package/dist/index.d.ts CHANGED
@@ -49,6 +49,7 @@ export { Property, type PropertyProps } from './Property';
49
49
  export { Reaction, type ReactionProps } from './Reaction';
50
50
  export { SearchInput, type SearchInputProps } from './SearchInput';
51
51
  export { SectionHeader, type SectionAction, type SectionHeaderProps } from './SectionHeader';
52
+ export { CollapsibleSection, type CollapsibleSectionProps } from './CollapsibleSection';
52
53
  export { SectionLabel } from './SectionLabel';
53
54
  export { Tabs, type TabDef, type TabsProps } from './Tabs';
54
55
  export { Toast, ToastProvider, useToast, type ToastOptions, type ToastProps, type ToastType } from './Toast';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -419,9 +419,17 @@ var typeStyles = {
419
419
  error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
420
420
  };
421
421
  function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className }) {
422
- return /* @__PURE__ */ jsxs6("div", { className: cn("inline-flex items-center justify-center gap-1.5 rounded-full max-h-[20px] min-w-[16px] px-2 py-1", typeStyles[type], className), children: [
422
+ return /* @__PURE__ */ jsxs6("div", { className: cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className), children: [
423
423
  leadingIcon && /* @__PURE__ */ jsx11("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
424
- label && /* @__PURE__ */ jsx11("span", { className: "text-chip whitespace-nowrap signal:font-mono signal:text-[10px] signal:font-semibold signal:tracking-[0.02em] signal:tabular-nums", children: label }),
424
+ label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
425
+ // of growing past it — Ship's project chip on an issue row
426
+ // (2026-09-09). Clipped sideways only: `overflow-x-clip`, not
427
+ // `truncate`, because `truncate` is `overflow: hidden` on both axes and
428
+ // the label's line box (11px under Signal) is tighter than its glyphs —
429
+ // the screenshot diff caught every descender cut off. `clip` is the
430
+ // one overflow that leaves the other axis visible. A chip with no cap
431
+ // draws exactly as before.
432
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap text-chip signal:font-mono signal:text-[10px] signal:font-semibold signal:tracking-[0.02em] signal:tabular-nums", children: label }),
425
433
  trailingIcon && /* @__PURE__ */ jsx11("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
426
434
  ] });
427
435
  }
@@ -468,7 +476,16 @@ function ScrollArea({ orientation = "vertical", className, viewportClassName, co
468
476
  const vertical = orientation !== "horizontal";
469
477
  const horizontal = orientation !== "vertical";
470
478
  return /* @__PURE__ */ jsxs7(BaseScrollArea.Root, { className: cn("relative min-h-0 min-w-0", className), children: [
471
- /* @__PURE__ */ jsx12(BaseScrollArea.Viewport, { className: cn("h-full w-full overscroll-contain outline-none", viewportClassName), children: /* @__PURE__ */ jsx12(BaseScrollArea.Content, { className: contentClassName, style: horizontal ? void 0 : { minWidth: 0 }, children }) }),
479
+ /* @__PURE__ */ jsx12(
480
+ BaseScrollArea.Viewport,
481
+ {
482
+ className: cn(
483
+ "h-full w-full outline-none data-[has-overflow-x]:overscroll-x-contain data-[has-overflow-y]:overscroll-y-contain",
484
+ viewportClassName
485
+ ),
486
+ children: /* @__PURE__ */ jsx12(BaseScrollArea.Content, { className: contentClassName, style: horizontal ? void 0 : { minWidth: 0 }, children })
487
+ }
488
+ ),
472
489
  vertical && /* @__PURE__ */ jsx12(BaseScrollArea.Scrollbar, { orientation: "vertical", className: cn(BAR, "w-1.5 justify-center py-0.5 pr-0.5"), children: /* @__PURE__ */ jsx12(BaseScrollArea.Thumb, { className: cn(THUMB, "w-full") }) }),
473
490
  horizontal && /* @__PURE__ */ jsx12(BaseScrollArea.Scrollbar, { orientation: "horizontal", className: cn(BAR, "h-1.5 flex-col justify-center px-0.5 pb-0.5"), children: /* @__PURE__ */ jsx12(BaseScrollArea.Thumb, { className: cn(THUMB, "h-full") }) }),
474
491
  vertical && horizontal && /* @__PURE__ */ jsx12(BaseScrollArea.Corner, {})
@@ -1428,8 +1445,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
1428
1445
  // src/EmptyState.tsx
1429
1446
  import { IconMessage2 } from "@tabler/icons-react";
1430
1447
  import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
1431
- function EmptyState({ icon, message, className }) {
1432
- return /* @__PURE__ */ jsxs18("div", { className: cn("flex flex-col gap-2 items-center", className), children: [
1448
+ function EmptyState({ icon, message, scope = "page", className }) {
1449
+ if (scope === "section") {
1450
+ return /* @__PURE__ */ jsx27("p", { className: cn("text-body-2 text-text-secondary", className), children: message });
1451
+ }
1452
+ return /* @__PURE__ */ jsxs18("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
1433
1453
  /* @__PURE__ */ jsx27("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx27(IconMessage2, { size: 16, stroke: 1.5 }) }),
1434
1454
  /* @__PURE__ */ jsx27("p", { className: "text-body-2 text-text-secondary text-center", children: message })
1435
1455
  ] });
@@ -1475,13 +1495,14 @@ function Breadcrumb({ items, className }) {
1475
1495
  }, [measure, items]);
1476
1496
  return /* @__PURE__ */ jsx29("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-[14px] leading-[140%]", className), children: items.map((item, index) => {
1477
1497
  const last = index === items.length - 1;
1498
+ const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
1478
1499
  const text = cn(
1479
1500
  "truncate",
1480
1501
  // A mono crumb is a ref — the identity. It never gives up width to a
1481
1502
  // long name beside it (the LongName story always claimed "the ref
1482
1503
  // stays"; flexbox was squeezing it anyway until this line).
1483
1504
  item.mono && "shrink-0 font-mono text-[12px] leading-[120%]",
1484
- item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary"
1505
+ tone
1485
1506
  );
1486
1507
  const setLabelRef = (el) => {
1487
1508
  labelRefs.current[index] = el;
@@ -1489,6 +1510,7 @@ function Breadcrumb({ items, className }) {
1489
1510
  const crumb = item.href ? /* @__PURE__ */ jsx29("a", { ref: setLabelRef, href: item.href, onClick: item.onClick, className: cn(text, "hover:text-text-primary"), children: item.label }) : /* @__PURE__ */ jsx29("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
1490
1511
  return /* @__PURE__ */ jsxs20(Fragment4, { children: [
1491
1512
  index > 0 && /* @__PURE__ */ jsx29("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
1513
+ item.icon && /* @__PURE__ */ jsx29("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
1492
1514
  truncated.has(index) ? (
1493
1515
  // `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
1494
1516
  // must keep truncating inside it, or wrapping it would widen the
@@ -1519,7 +1541,7 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
1519
1541
  children: [
1520
1542
  icon && /* @__PURE__ */ jsx30("span", { className: "flex shrink-0 items-center", children: icon }),
1521
1543
  /* @__PURE__ */ jsx30("span", { className: "flex-1 truncate", children: label }),
1522
- count ? /* @__PURE__ */ jsx30(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx30("span", { className: "shrink-0 font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
1544
+ count ? /* @__PURE__ */ jsx30(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx30("span", { className: "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
1523
1545
  ]
1524
1546
  }
1525
1547
  );
@@ -1818,58 +1840,106 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
1818
1840
  }
1819
1841
 
1820
1842
  // src/SectionHeader.tsx
1821
- import { useState as useState6 } from "react";
1822
1843
  import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
1823
- import { jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
1824
- function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, actions, showActions = "hover", className }) {
1825
- const [isHovered, setIsHovered] = useState6(false);
1844
+ import { useRender } from "@base-ui/react/use-render";
1845
+ import { Fragment as Fragment5, jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
1846
+ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, actions, showActions = "hover", render, className }) {
1847
+ const titleElement = useRender({
1848
+ render: render ?? (chevron ? /* @__PURE__ */ jsx41("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx41("span", {})),
1849
+ props: {
1850
+ // `text-left`: a button centres its text. `h-full` and `flex-1`: the
1851
+ // whole row up to the actions is the hit target, as it was when the
1852
+ // row itself carried the click.
1853
+ className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
1854
+ children: /* @__PURE__ */ jsxs28(Fragment5, { children: [
1855
+ chevron && /* @__PURE__ */ jsx41(
1856
+ IconChevronRight2,
1857
+ {
1858
+ size: 12,
1859
+ stroke: 1.5,
1860
+ className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
1861
+ }
1862
+ ),
1863
+ /* @__PURE__ */ jsx41(SectionLabel, { children: title })
1864
+ ] })
1865
+ }
1866
+ });
1826
1867
  return /* @__PURE__ */ jsxs28(
1827
1868
  "div",
1828
1869
  {
1829
1870
  className: cn(
1830
- "flex h-[32px] items-center justify-between rounded-lg px-2 transition-colors",
1831
- isHovered && "bg-bg-hover",
1832
- chevron && "cursor-pointer",
1871
+ "group flex h-[32px] items-center gap-1 rounded-lg px-2 transition-colors",
1872
+ // The fill says "this does something": a row with a toggle or actions
1873
+ // lights up, a fixed heading over rows does not (2026-09-09, the
1874
+ // Sidebar's fixed group).
1875
+ (chevron || actions && actions.length > 0) && "hover:bg-bg-hover",
1833
1876
  className
1834
1877
  ),
1835
- onClick: chevron ? onToggle : void 0,
1836
- onMouseEnter: () => setIsHovered(true),
1837
- onMouseLeave: () => setIsHovered(false),
1838
1878
  children: [
1839
- /* @__PURE__ */ jsxs28("div", { className: "flex shrink-0 items-center gap-1", children: [
1840
- chevron && /* @__PURE__ */ jsx41(
1841
- IconChevronRight2,
1842
- {
1843
- size: 12,
1844
- stroke: 1.5,
1845
- className: cn("text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
1846
- }
1847
- ),
1848
- /* @__PURE__ */ jsx41(SectionLabel, { children: title })
1849
- ] }),
1850
- (showActions === "always" || isHovered) && actions && actions.length > 0 && /* @__PURE__ */ jsx41("div", { className: "flex items-center gap-1", children: actions.map((action) => /* @__PURE__ */ jsx41(
1851
- IconButton,
1879
+ titleElement,
1880
+ actions && actions.length > 0 && /* @__PURE__ */ jsx41(
1881
+ "div",
1852
1882
  {
1853
- tooltip: action.tooltip,
1854
- "aria-label": action.tooltip,
1855
- onClick: (event) => {
1856
- event.stopPropagation();
1857
- action.onClick();
1858
- },
1859
- children: action.icon
1860
- },
1861
- action.tooltip
1862
- )) })
1883
+ className: cn(
1884
+ "-mr-1 flex shrink-0 items-center gap-1",
1885
+ showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
1886
+ ),
1887
+ children: actions.map((action) => /* @__PURE__ */ jsx41(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
1888
+ }
1889
+ )
1863
1890
  ]
1864
1891
  }
1865
1892
  );
1866
1893
  }
1867
1894
 
1895
+ // src/CollapsibleSection.tsx
1896
+ import { useState as useState6 } from "react";
1897
+ import { Collapsible } from "@base-ui/react/collapsible";
1898
+ import { jsx as jsx42, jsxs as jsxs29 } from "react/jsx-runtime";
1899
+ var OPEN = "open";
1900
+ var CLOSED = "closed";
1901
+ function readStored(key) {
1902
+ if (!key) return void 0;
1903
+ try {
1904
+ const value = window.localStorage.getItem(key);
1905
+ return value === OPEN ? true : value === CLOSED ? false : void 0;
1906
+ } catch {
1907
+ return void 0;
1908
+ }
1909
+ }
1910
+ function writeStored(key, open) {
1911
+ if (!key) return;
1912
+ try {
1913
+ window.localStorage.setItem(key, open ? OPEN : CLOSED);
1914
+ } catch {
1915
+ }
1916
+ }
1917
+ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, actions, showActions, children, className, contentClassName }) {
1918
+ const [openState, setOpenState] = useState6(() => readStored(storageKey) ?? defaultOpen);
1919
+ const open = openProp ?? openState;
1920
+ const setOpen = (next) => {
1921
+ setOpenState(next);
1922
+ writeStored(storageKey, next);
1923
+ onOpenChange?.(next);
1924
+ };
1925
+ return /* @__PURE__ */ jsxs29(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
1926
+ /* @__PURE__ */ jsx42(SectionHeader, { title, chevron: true, isExpanded: open, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx42(Collapsible.Trigger, {}) }),
1927
+ /* @__PURE__ */ jsx42(
1928
+ Collapsible.Panel,
1929
+ {
1930
+ hiddenUntilFound: true,
1931
+ className: "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0",
1932
+ children: /* @__PURE__ */ jsx42("div", { className: cn("flex flex-col", contentClassName), children })
1933
+ }
1934
+ )
1935
+ ] });
1936
+ }
1937
+
1868
1938
  // src/Tabs.tsx
1869
1939
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
1870
- import { jsx as jsx42, jsxs as jsxs29 } from "react/jsx-runtime";
1940
+ import { jsx as jsx43, jsxs as jsxs30 } from "react/jsx-runtime";
1871
1941
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
1872
- return /* @__PURE__ */ jsx42(
1942
+ return /* @__PURE__ */ jsx43(
1873
1943
  BaseTabs.Root,
1874
1944
  {
1875
1945
  value: active,
@@ -1877,14 +1947,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
1877
1947
  if (details.reason === "none") onChange(value);
1878
1948
  },
1879
1949
  className,
1880
- children: /* @__PURE__ */ jsx42(
1950
+ children: /* @__PURE__ */ jsx43(
1881
1951
  BaseTabs.List,
1882
1952
  {
1883
1953
  activateOnFocus: true,
1884
1954
  "aria-label": aria["aria-label"],
1885
1955
  "aria-labelledby": aria["aria-labelledby"],
1886
1956
  className: "flex items-center gap-2",
1887
- children: tabs.map((tab) => /* @__PURE__ */ jsxs29(
1957
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs30(
1888
1958
  BaseTabs.Tab,
1889
1959
  {
1890
1960
  value: tab.id,
@@ -1897,9 +1967,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
1897
1967
  ),
1898
1968
  children: [
1899
1969
  tab.icon,
1900
- /* @__PURE__ */ jsxs29("span", { className: "flex items-baseline", children: [
1970
+ /* @__PURE__ */ jsxs30("span", { className: "flex items-baseline", children: [
1901
1971
  tab.label,
1902
- tab.count !== void 0 ? /* @__PURE__ */ jsx42("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
1972
+ tab.count !== void 0 ? /* @__PURE__ */ jsx43("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
1903
1973
  ] })
1904
1974
  ]
1905
1975
  },
@@ -1915,7 +1985,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
1915
1985
  import { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useEffect as useEffect3, useMemo as useMemo3, useState as useState7 } from "react";
1916
1986
  import { createPortal as createPortal2 } from "react-dom";
1917
1987
  import { IconCircleCheck } from "@tabler/icons-react";
1918
- import { jsx as jsx43, jsxs as jsxs30 } from "react/jsx-runtime";
1988
+ import { jsx as jsx44, jsxs as jsxs31 } from "react/jsx-runtime";
1919
1989
  var SURFACE_STYLES = {
1920
1990
  success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
1921
1991
  brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
@@ -1933,7 +2003,7 @@ var ACTION_BORDER_STYLES = {
1933
2003
  };
1934
2004
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
1935
2005
  const hasAction = !!(actionLabel && onAction);
1936
- return /* @__PURE__ */ jsxs30(
2006
+ return /* @__PURE__ */ jsxs31(
1937
2007
  "div",
1938
2008
  {
1939
2009
  className: cn(
@@ -1945,11 +2015,11 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
1945
2015
  className
1946
2016
  ),
1947
2017
  children: [
1948
- /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2 shrink-0", children: [
1949
- leadingIcon && /* @__PURE__ */ jsx43(IconCircleCheck, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) }),
1950
- /* @__PURE__ */ jsx43("span", { className: "font-normal text-[14px] leading-[1.4] text-text-primary whitespace-nowrap", children: label })
2018
+ /* @__PURE__ */ jsxs31("div", { className: "flex items-center gap-2 shrink-0", children: [
2019
+ leadingIcon && /* @__PURE__ */ jsx44(IconCircleCheck, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) }),
2020
+ /* @__PURE__ */ jsx44("span", { className: "font-normal text-[14px] leading-[1.4] text-text-primary whitespace-nowrap", children: label })
1951
2021
  ] }),
1952
- hasAction && /* @__PURE__ */ jsx43(
2022
+ hasAction && /* @__PURE__ */ jsx44(
1953
2023
  "button",
1954
2024
  {
1955
2025
  type: "button",
@@ -1959,7 +2029,7 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
1959
2029
  ACTION_BORDER_STYLES[type],
1960
2030
  type === "neutral" ? "hover:border-border-strong" : "hover:opacity-80"
1961
2031
  ),
1962
- children: /* @__PURE__ */ jsx43("span", { className: "font-medium text-[12px] leading-[12px] text-text-primary whitespace-nowrap", children: actionLabel })
2032
+ children: /* @__PURE__ */ jsx44("span", { className: "font-medium text-[12px] leading-[12px] text-text-primary whitespace-nowrap", children: actionLabel })
1963
2033
  }
1964
2034
  )
1965
2035
  ]
@@ -1986,10 +2056,10 @@ function ToastProvider({ children }) {
1986
2056
  return () => clearTimeout(timer);
1987
2057
  }, [toast]);
1988
2058
  const value = useMemo3(() => ({ showToast, dismissToast }), [showToast, dismissToast]);
1989
- return /* @__PURE__ */ jsxs30(ToastContext.Provider, { value, children: [
2059
+ return /* @__PURE__ */ jsxs31(ToastContext.Provider, { value, children: [
1990
2060
  children,
1991
2061
  toast && createPortal2(
1992
- /* @__PURE__ */ jsx43("div", { className: "fixed bottom-4 left-4 z-[100] pointer-events-none", children: /* @__PURE__ */ jsx43(
2062
+ /* @__PURE__ */ jsx44("div", { className: "fixed bottom-4 left-4 z-[100] pointer-events-none", children: /* @__PURE__ */ jsx44(
1993
2063
  Toast,
1994
2064
  {
1995
2065
  className: "pointer-events-auto",
@@ -2022,6 +2092,7 @@ export {
2022
2092
  Checkbox,
2023
2093
  Chip,
2024
2094
  ChipInput,
2095
+ CollapsibleSection,
2025
2096
  ConfirmDialog,
2026
2097
  DialogShell,
2027
2098
  Divider,