@dust-tt/sparkle 0.5.0 → 0.5.2-rc-1

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 (104) hide show
  1. package/dist/cjs/index.js +10 -10
  2. package/dist/cjs/index.js.map +3 -3
  3. package/dist/esm/components/Avatar.d.ts +2 -1
  4. package/dist/esm/components/Avatar.d.ts.map +1 -1
  5. package/dist/esm/components/Avatar.js +34 -10
  6. package/dist/esm/components/Avatar.js.map +1 -1
  7. package/dist/esm/components/Button.d.ts.map +1 -1
  8. package/dist/esm/components/Button.js.map +1 -1
  9. package/dist/esm/components/ButtonGroup.d.ts.map +1 -1
  10. package/dist/esm/components/ButtonGroup.js.map +1 -1
  11. package/dist/esm/components/ButtonsSwitch.d.ts.map +1 -1
  12. package/dist/esm/components/ButtonsSwitch.js.map +1 -1
  13. package/dist/esm/components/Card.d.ts.map +1 -1
  14. package/dist/esm/components/Card.js.map +1 -1
  15. package/dist/esm/components/Checkbox.d.ts.map +1 -1
  16. package/dist/esm/components/Checkbox.js.map +1 -1
  17. package/dist/esm/components/Citation.d.ts.map +1 -1
  18. package/dist/esm/components/Citation.js.map +1 -1
  19. package/dist/esm/components/Collapsible.d.ts.map +1 -1
  20. package/dist/esm/components/Collapsible.js.map +1 -1
  21. package/dist/esm/components/ConversationMessage.d.ts.map +1 -1
  22. package/dist/esm/components/ConversationMessage.js.map +1 -1
  23. package/dist/esm/components/Counter.d.ts.map +1 -1
  24. package/dist/esm/components/Counter.js.map +1 -1
  25. package/dist/esm/components/DataTable.d.ts.map +1 -1
  26. package/dist/esm/components/DataTable.js.map +1 -1
  27. package/dist/esm/components/Dialog.d.ts.map +1 -1
  28. package/dist/esm/components/Dialog.js.map +1 -1
  29. package/dist/esm/components/Dropdown.d.ts.map +1 -1
  30. package/dist/esm/components/Dropdown.js.map +1 -1
  31. package/dist/esm/components/Hoverable.d.ts.map +1 -1
  32. package/dist/esm/components/Hoverable.js.map +1 -1
  33. package/dist/esm/components/IconButton.d.ts.map +1 -1
  34. package/dist/esm/components/IconButton.js.map +1 -1
  35. package/dist/esm/components/Input.d.ts.map +1 -1
  36. package/dist/esm/components/Input.js.map +1 -1
  37. package/dist/esm/components/Label.d.ts.map +1 -1
  38. package/dist/esm/components/Label.js.map +1 -1
  39. package/dist/esm/components/MultiPageDialog.d.ts.map +1 -1
  40. package/dist/esm/components/MultiPageDialog.js.map +1 -1
  41. package/dist/esm/components/MultiPageSheet.d.ts.map +1 -1
  42. package/dist/esm/components/MultiPageSheet.js.map +1 -1
  43. package/dist/esm/components/NavigationList.d.ts +18 -1
  44. package/dist/esm/components/NavigationList.d.ts.map +1 -1
  45. package/dist/esm/components/NavigationList.js +34 -5
  46. package/dist/esm/components/NavigationList.js.map +1 -1
  47. package/dist/esm/components/Popover.d.ts.map +1 -1
  48. package/dist/esm/components/Popover.js.map +1 -1
  49. package/dist/esm/components/RadioGroup.d.ts.map +1 -1
  50. package/dist/esm/components/RadioGroup.js.map +1 -1
  51. package/dist/esm/components/ScrollArea.d.ts.map +1 -1
  52. package/dist/esm/components/ScrollArea.js.map +1 -1
  53. package/dist/esm/components/Sheet.d.ts.map +1 -1
  54. package/dist/esm/components/Sheet.js.map +1 -1
  55. package/dist/esm/components/TextArea.d.ts.map +1 -1
  56. package/dist/esm/components/TextArea.js.map +1 -1
  57. package/dist/esm/components/Timeline.d.ts.map +1 -1
  58. package/dist/esm/components/Timeline.js.map +1 -1
  59. package/dist/esm/components/Tooltip.d.ts.map +1 -1
  60. package/dist/esm/components/Tooltip.js.map +1 -1
  61. package/dist/esm/components/markdown/CodeBlockWithExtendedSupport.d.ts.map +1 -1
  62. package/dist/esm/components/markdown/CodeBlockWithExtendedSupport.js +9 -4
  63. package/dist/esm/components/markdown/CodeBlockWithExtendedSupport.js.map +1 -1
  64. package/dist/esm/stories/Avatar.stories.d.ts.map +1 -1
  65. package/dist/esm/stories/Avatar.stories.js +56 -0
  66. package/dist/esm/stories/Avatar.stories.js.map +1 -1
  67. package/dist/esm/stories/NavigationList.stories.d.ts +1 -0
  68. package/dist/esm/stories/NavigationList.stories.d.ts.map +1 -1
  69. package/dist/esm/stories/NavigationList.stories.js +70 -1
  70. package/dist/esm/stories/NavigationList.stories.js.map +1 -1
  71. package/dist/esm/styles/global.css +2 -1
  72. package/dist/sparkle.css +33 -0
  73. package/package.json +35 -15
  74. package/src/components/Avatar.tsx +45 -9
  75. package/src/components/Button.tsx +2 -1
  76. package/src/components/ButtonGroup.tsx +2 -1
  77. package/src/components/ButtonsSwitch.tsx +6 -3
  78. package/src/components/Card.tsx +3 -6
  79. package/src/components/Checkbox.tsx +2 -1
  80. package/src/components/Citation.tsx +2 -4
  81. package/src/components/Collapsible.tsx +4 -2
  82. package/src/components/ConversationMessage.tsx +4 -5
  83. package/src/components/Counter.tsx +2 -1
  84. package/src/components/DataTable.tsx +4 -4
  85. package/src/components/Dialog.tsx +3 -2
  86. package/src/components/Dropdown.tsx +7 -4
  87. package/src/components/Hoverable.tsx +2 -4
  88. package/src/components/IconButton.tsx +4 -5
  89. package/src/components/Input.tsx +4 -2
  90. package/src/components/Label.tsx +2 -1
  91. package/src/components/MultiPageDialog.tsx +1 -2
  92. package/src/components/MultiPageSheet.tsx +1 -2
  93. package/src/components/NavigationList.tsx +151 -15
  94. package/src/components/Popover.tsx +3 -2
  95. package/src/components/RadioGroup.tsx +4 -2
  96. package/src/components/ScrollArea.tsx +6 -6
  97. package/src/components/Sheet.tsx +6 -4
  98. package/src/components/TextArea.tsx +1 -2
  99. package/src/components/Timeline.tsx +2 -1
  100. package/src/components/Tooltip.tsx +3 -2
  101. package/src/components/markdown/CodeBlockWithExtendedSupport.tsx +12 -4
  102. package/src/stories/Avatar.stories.tsx +79 -0
  103. package/src/stories/NavigationList.stories.tsx +148 -0
  104. package/src/styles/global.css +2 -1
@@ -257,6 +257,7 @@ interface AvatarStackProps {
257
257
  isRounded?: boolean;
258
258
  hasMagnifier?: boolean;
259
259
  tooltipTriggerAsChild?: boolean;
260
+ orientation?: "horizontal" | "vertical";
260
261
  }
261
262
 
262
263
  const sizeClassesPx: Record<AvatarStackSizeType, number> = {
@@ -272,6 +273,7 @@ Avatar.Stack = function ({
272
273
  isRounded = false,
273
274
  hasMagnifier = true,
274
275
  tooltipTriggerAsChild = false,
276
+ orientation = "horizontal",
275
277
  }: AvatarStackProps) {
276
278
  const [isHovered, setIsHovered] = useState(false);
277
279
 
@@ -294,6 +296,8 @@ Avatar.Stack = function ({
294
296
  marginLeft: 0,
295
297
  widthHovered: sizeClassesPx[size] * 0.6,
296
298
  width: sizeClassesPx[size] * 0.25,
299
+ heightHovered: sizeClassesPx[size] * 0.6,
300
+ height: sizeClassesPx[size] * 0.25,
297
301
  };
298
302
 
299
303
  const collapsedWidth =
@@ -306,7 +310,20 @@ Avatar.Stack = function ({
306
310
  (visibleAvatars.length + Number(Boolean(remainingCount))) +
307
311
  (sizeClassesPx[size] - sizeSetting.widthHovered);
308
312
 
309
- const transitionSettings = "width 200ms ease-out";
313
+ const collapsedHeight =
314
+ sizeSetting.height *
315
+ (visibleAvatars.length + Number(Boolean(remainingCount))) +
316
+ (sizeClassesPx[size] - sizeSetting.height);
317
+
318
+ const openedHeight =
319
+ sizeSetting.heightHovered *
320
+ (visibleAvatars.length + Number(Boolean(remainingCount))) +
321
+ (sizeClassesPx[size] - sizeSetting.heightHovered);
322
+
323
+ const transitionSettings =
324
+ orientation === "vertical"
325
+ ? "height 200ms ease-out"
326
+ : "width 200ms ease-out";
310
327
 
311
328
  return (
312
329
  <Tooltip
@@ -315,13 +332,24 @@ Avatar.Stack = function ({
315
332
  trigger={
316
333
  <>
317
334
  <div
318
- className="s-flex s-flex-row"
335
+ className={cn(
336
+ "s-flex",
337
+ orientation === "vertical" ? "s-flex-col" : "s-flex-row"
338
+ )}
319
339
  onMouseEnter={() => visibleAvatars.length > 1 && setIsHovered(true)}
320
340
  onMouseLeave={() =>
321
341
  visibleAvatars.length > 1 && setIsHovered(false)
322
342
  }
323
343
  style={{
324
- width: `${isHovered ? openedWidth : collapsedWidth}px`,
344
+ [orientation === "vertical" ? "height" : "width"]: `${
345
+ isHovered
346
+ ? orientation === "vertical"
347
+ ? openedHeight
348
+ : openedWidth
349
+ : orientation === "vertical"
350
+ ? collapsedHeight
351
+ : collapsedWidth
352
+ }px`,
325
353
  transition: transitionSettings,
326
354
  }}
327
355
  >
@@ -330,9 +358,13 @@ Avatar.Stack = function ({
330
358
  key={i}
331
359
  className="s-cursor-pointer s-drop-shadow-md"
332
360
  style={{
333
- width: isHovered
334
- ? sizeSetting.widthHovered
335
- : sizeSetting.width,
361
+ [orientation === "vertical" ? "height" : "width"]: isHovered
362
+ ? orientation === "vertical"
363
+ ? sizeSetting.heightHovered
364
+ : sizeSetting.widthHovered
365
+ : orientation === "vertical"
366
+ ? sizeSetting.height
367
+ : sizeSetting.width,
336
368
  transition: transitionSettings,
337
369
  }}
338
370
  >
@@ -359,9 +391,13 @@ Avatar.Stack = function ({
359
391
  <div
360
392
  className="s-cursor-pointer s-drop-shadow-md"
361
393
  style={{
362
- width: isHovered
363
- ? sizeSetting.widthHovered
364
- : sizeSetting.width,
394
+ [orientation === "vertical" ? "height" : "width"]: isHovered
395
+ ? orientation === "vertical"
396
+ ? sizeSetting.heightHovered
397
+ : sizeSetting.widthHovered
398
+ : orientation === "vertical"
399
+ ? sizeSetting.height
400
+ : sizeSetting.width,
365
401
  transition: transitionSettings,
366
402
  }}
367
403
  >
@@ -204,7 +204,8 @@ const chevronVariantMap = {
204
204
  } as const;
205
205
 
206
206
  export interface MetaButtonProps
207
- extends React.ButtonHTMLAttributes<HTMLButtonElement>,
207
+ extends
208
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
208
209
  VariantProps<typeof buttonVariants> {
209
210
  asChild?: boolean;
210
211
  isRounded?: boolean;
@@ -80,7 +80,8 @@ const buttonGroupVariants = cva("s-inline-flex", {
80
80
  });
81
81
 
82
82
  export interface ButtonGroupProps
83
- extends Omit<React.HTMLAttributes<HTMLDivElement>, "children">,
83
+ extends
84
+ Omit<React.HTMLAttributes<HTMLDivElement>, "children">,
84
85
  VariantProps<typeof buttonGroupVariants> {
85
86
  /**
86
87
  * Array of button or dropdown items to render in the group.
@@ -54,7 +54,8 @@ const listStyles = cva(
54
54
  );
55
55
 
56
56
  export interface ButtonsSwitchListProps
57
- extends React.HTMLAttributes<HTMLDivElement>,
57
+ extends
58
+ React.HTMLAttributes<HTMLDivElement>,
58
59
  VariantProps<typeof listStyles> {
59
60
  size?: ButtonSize;
60
61
  disabled?: boolean;
@@ -115,8 +116,10 @@ export const ButtonsSwitchList = React.forwardRef<
115
116
  );
116
117
  ButtonsSwitchList.displayName = "ButtonsSwitchList";
117
118
 
118
- interface ButtonsSwitchProps
119
- extends Omit<React.ComponentProps<typeof Button>, "size" | "variant"> {
119
+ interface ButtonsSwitchProps extends Omit<
120
+ React.ComponentProps<typeof Button>,
121
+ "size" | "variant"
122
+ > {
120
123
  value: string;
121
124
  label?: string;
122
125
  icon?: React.ComponentProps<typeof Button>["icon"];
@@ -89,8 +89,7 @@ interface CardLinkProps extends CommonProps, LinkWrapperProps {
89
89
  }
90
90
 
91
91
  interface CardButtonProps
92
- extends CommonProps,
93
- React.ButtonHTMLAttributes<HTMLDivElement> {
92
+ extends CommonProps, React.ButtonHTMLAttributes<HTMLDivElement> {
94
93
  href?: never;
95
94
  target?: never;
96
95
  rel?: never;
@@ -176,15 +175,13 @@ interface CardPropsBase {
176
175
  }
177
176
 
178
177
  interface CardPropsWithLink
179
- extends CardPropsBase,
180
- Omit<CardLinkProps, keyof CardPropsBase> {
178
+ extends CardPropsBase, Omit<CardLinkProps, keyof CardPropsBase> {
181
179
  href: string;
182
180
  onClick?: never;
183
181
  }
184
182
 
185
183
  interface CardPropsWithButton
186
- extends CardPropsBase,
187
- Omit<CardButtonProps, keyof CardPropsBase> {
184
+ extends CardPropsBase, Omit<CardButtonProps, keyof CardPropsBase> {
188
185
  href?: never;
189
186
  }
190
187
 
@@ -44,7 +44,8 @@ const checkboxStyles = cva(
44
44
  type CheckBoxStateType = boolean | "partial";
45
45
 
46
46
  interface CheckboxProps
47
- extends Omit<
47
+ extends
48
+ Omit<
48
49
  React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
49
50
  "checked" | "defaultChecked"
50
51
  >,
@@ -132,8 +132,7 @@ const CitationGrid = React.forwardRef<HTMLDivElement, CitationGridProps>(
132
132
  );
133
133
  CitationGrid.displayName = "CitationGrid";
134
134
 
135
- interface CitationCloseProps
136
- extends React.ButtonHTMLAttributes<HTMLButtonElement> {
135
+ interface CitationCloseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
137
136
  className?: string;
138
137
  onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
139
138
  }
@@ -260,8 +259,7 @@ const CitationTitle = React.forwardRef<HTMLDivElement, CitationTitleProps>(
260
259
  );
261
260
  CitationTitle.displayName = "CitationTitle";
262
261
 
263
- interface CitationDescriptionProps
264
- extends React.HTMLAttributes<HTMLDivElement> {
262
+ interface CitationDescriptionProps extends React.HTMLAttributes<HTMLDivElement> {
265
263
  children: ReactNode;
266
264
  }
267
265
 
@@ -63,7 +63,8 @@ const Collapsible = React.forwardRef<
63
63
  Collapsible.displayName = "Collapsible";
64
64
 
65
65
  export interface CollapsibleTriggerProps
66
- extends React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Trigger>,
66
+ extends
67
+ React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Trigger>,
67
68
  Omit<VariantProps<typeof labelVariants>, "disabled"> {
68
69
  label?: string;
69
70
  isOpen?: boolean;
@@ -130,7 +131,8 @@ const contentVariants = cva("s-overflow-hidden s-transition-all", {
130
131
  });
131
132
 
132
133
  export interface CollapsibleContentProps
133
- extends React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Content>,
134
+ extends
135
+ React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Content>,
134
136
  VariantProps<typeof contentVariants> {}
135
137
 
136
138
  const CollapsibleContent = React.forwardRef<
@@ -34,7 +34,8 @@ export const ConversationContainer = React.forwardRef<
34
34
  ConversationContainer.displayName = "ConversationContainer";
35
35
 
36
36
  interface ConversationMessageProps
37
- extends React.HTMLAttributes<HTMLDivElement>,
37
+ extends
38
+ React.HTMLAttributes<HTMLDivElement>,
38
39
  VariantProps<typeof messageVariants> {
39
40
  actions?: ConversationMessageAction[];
40
41
  avatarBusy?: boolean;
@@ -141,8 +142,7 @@ export const ConversationMessage = React.forwardRef<
141
142
 
142
143
  ConversationMessage.displayName = "ConversationMessage";
143
144
 
144
- interface ConversationMessageContentProps
145
- extends React.HTMLAttributes<HTMLDivElement> {
145
+ interface ConversationMessageContentProps extends React.HTMLAttributes<HTMLDivElement> {
146
146
  children: React.ReactNode;
147
147
  citations?: React.ReactElement[];
148
148
  type: ConversationMessageType;
@@ -173,8 +173,7 @@ export const ConversationMessageContent = React.forwardRef<
173
173
 
174
174
  ConversationMessageContent.displayName = "ConversationMessageContent";
175
175
 
176
- interface ConversationMessageHeaderProps
177
- extends React.HTMLAttributes<HTMLDivElement> {
176
+ interface ConversationMessageHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
178
177
  actions?: ConversationMessageAction[];
179
178
  avatarUrl?: string | React.ReactNode;
180
179
  isBusy?: boolean;
@@ -94,7 +94,8 @@ const counterVariants = cva(
94
94
  );
95
95
 
96
96
  export interface CounterProps
97
- extends React.HTMLAttributes<HTMLDivElement>,
97
+ extends
98
+ React.HTMLAttributes<HTMLDivElement>,
98
99
  VariantProps<typeof counterVariants> {
99
100
  value: number;
100
101
  }
@@ -333,8 +333,9 @@ export function DataTable<TData extends TBaseData>({
333
333
  );
334
334
  }
335
335
 
336
- export interface ScrollableDataTableProps<TData extends TBaseData>
337
- extends DataTableProps<TData> {
336
+ export interface ScrollableDataTableProps<
337
+ TData extends TBaseData,
338
+ > extends DataTableProps<TData> {
338
339
  maxHeight?: string | boolean;
339
340
  onLoadMore?: () => void;
340
341
  isLoading?: boolean;
@@ -871,8 +872,7 @@ interface BaseMenuItem {
871
872
  }
872
873
 
873
874
  interface RegularMenuItem
874
- extends BaseMenuItem,
875
- Omit<DropdownMenuItemProps, "children" | "label"> {
875
+ extends BaseMenuItem, Omit<DropdownMenuItemProps, "children" | "label"> {
876
876
  kind: "item";
877
877
  }
878
878
 
@@ -73,8 +73,9 @@ const dialogVariants = cva(
73
73
  }
74
74
  );
75
75
 
76
- interface DialogContentProps
77
- extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
76
+ interface DialogContentProps extends React.ComponentPropsWithoutRef<
77
+ typeof DialogPrimitive.Content
78
+ > {
78
79
  size?: DialogSizeType;
79
80
  height?: DialogHeightType;
80
81
  trapFocusScope?: boolean;
@@ -242,8 +242,9 @@ const DropdownMenuSubContent = React.forwardRef<
242
242
  DropdownMenuSubContent.displayName =
243
243
  DropdownMenuPrimitive.SubContent.displayName;
244
244
 
245
- interface DropdownMenuContentProps
246
- extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> {
245
+ interface DropdownMenuContentProps extends React.ComponentPropsWithoutRef<
246
+ typeof DropdownMenuPrimitive.Content
247
+ > {
247
248
  mountPortal?: boolean;
248
249
  mountPortalContainer?: HTMLElement;
249
250
  dropdownHeaders?: React.ReactNode;
@@ -486,8 +487,10 @@ const DropdownMenuRadioItem = React.forwardRef<
486
487
  ));
487
488
  DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
488
489
 
489
- interface DropdownMenuTagItemProps
490
- extends Omit<DropdownMenuItemProps, "label" | "icon" | "onClick"> {
490
+ interface DropdownMenuTagItemProps extends Omit<
491
+ DropdownMenuItemProps,
492
+ "label" | "icon" | "onClick"
493
+ > {
491
494
  label: string;
492
495
  size?: React.ComponentProps<typeof Chip>["size"];
493
496
  color?: React.ComponentProps<typeof Chip>["color"];
@@ -42,8 +42,7 @@ const variantStyle = cva(
42
42
  );
43
43
 
44
44
  interface MetaHoverableProps
45
- extends React.HTMLAttributes<HTMLElement>,
46
- VariantProps<typeof variantStyle> {
45
+ extends React.HTMLAttributes<HTMLElement>, VariantProps<typeof variantStyle> {
47
46
  asChild?: boolean;
48
47
  }
49
48
 
@@ -64,8 +63,7 @@ const MetaHoverable = React.forwardRef<HTMLElement, MetaHoverableProps>(
64
63
  MetaHoverable.displayName = "MetaHoverable";
65
64
 
66
65
  export interface HoverableProps
67
- extends MetaHoverableProps,
68
- Omit<LinkWrapperProps, "children"> {}
66
+ extends MetaHoverableProps, Omit<LinkWrapperProps, "children"> {}
69
67
 
70
68
  const Hoverable = React.forwardRef<HTMLElement, HoverableProps>(
71
69
  ({ href, target, rel, children, variant, className, ...props }, ref) => {
@@ -69,11 +69,10 @@ const iconButtonVariants = cva(
69
69
  }
70
70
  );
71
71
 
72
- export interface IconButtonProps
73
- extends Omit<
74
- React.ComponentPropsWithoutRef<typeof Button>,
75
- "label" | "variant"
76
- > {
72
+ export interface IconButtonProps extends Omit<
73
+ React.ComponentPropsWithoutRef<typeof Button>,
74
+ "label" | "variant"
75
+ > {
77
76
  variant?: IconButtonVariantType;
78
77
  onClick?: MouseEventHandler<HTMLButtonElement>;
79
78
  tooltip?: string;
@@ -11,8 +11,10 @@ const MESSAGE_STATUS = ["info", "default", "error"] as const;
11
11
 
12
12
  type MessageStatus = (typeof MESSAGE_STATUS)[number];
13
13
 
14
- export interface InputProps
15
- extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "value"> {
14
+ export interface InputProps extends Omit<
15
+ React.InputHTMLAttributes<HTMLInputElement>,
16
+ "value"
17
+ > {
16
18
  message?: string | null;
17
19
  messageStatus?: MessageStatus;
18
20
  value?: string | null;
@@ -26,7 +26,8 @@ const labelVariants = cva(
26
26
  );
27
27
 
28
28
  export interface LabelProps
29
- extends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>,
29
+ extends
30
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>,
30
31
  VariantProps<typeof labelVariants> {
31
32
  isMuted?: boolean;
32
33
  }
@@ -32,8 +32,7 @@ const MultiPageDialogRoot = Dialog;
32
32
  const MultiPageDialogTrigger = DialogTrigger;
33
33
  const MultiPageDialogClose = DialogClose;
34
34
 
35
- interface MultiPageDialogFooterProps
36
- extends React.HTMLAttributes<HTMLDivElement> {
35
+ interface MultiPageDialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {
37
36
  addTopSeparator: boolean;
38
37
  leftButton?: React.ComponentProps<typeof Button>;
39
38
  centerButton?: React.ComponentProps<typeof Button>;
@@ -52,8 +52,7 @@ const MultiPageSheetRoot = Sheet;
52
52
  const MultiPageSheetTrigger = SheetTrigger;
53
53
  const MultiPageSheetClose = SheetClose;
54
54
 
55
- interface MultiPageSheetFooterProps
56
- extends React.HTMLAttributes<HTMLDivElement> {
55
+ interface MultiPageSheetFooterProps extends React.HTMLAttributes<HTMLDivElement> {
57
56
  addTopSeparator: boolean;
58
57
  leftButton?: React.ComponentProps<typeof Button>;
59
58
  centerButton?: React.ComponentProps<typeof Button>;
@@ -1,3 +1,4 @@
1
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
1
2
  import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
2
3
  import { cva, type VariantProps } from "class-variance-authority";
3
4
  import * as React from "react";
@@ -10,7 +11,11 @@ import {
10
11
  ScrollBar,
11
12
  } from "@sparkle/components/";
12
13
  import { Button } from "@sparkle/components/Button";
13
- import { MoreIcon } from "@sparkle/icons/app";
14
+ import {
15
+ Collapsible,
16
+ CollapsibleContent,
17
+ } from "@sparkle/components/Collapsible";
18
+ import { ArrowDownSIcon, ArrowRightSIcon, MoreIcon } from "@sparkle/icons/app";
14
19
  import { cn } from "@sparkle/lib/utils";
15
20
 
16
21
  const NavigationListItemStyles = cva(
@@ -215,37 +220,168 @@ const variantStyles = cva("", {
215
220
  });
216
221
 
217
222
  const labelStyles = cva(
218
- "s-pt-4 s-pb-2 s-pl-3 s-heading-xs s-whitespace-nowrap s-overflow-hidden s-text-ellipsis"
223
+ "s-flex s-items-center s-justify-between s-gap-2 s-pt-4 s-pb-2 s-heading-xs s-whitespace-nowrap s-overflow-hidden s-text-ellipsis"
219
224
  );
220
225
 
226
+ interface NavigationListLabelButtonProps
227
+ extends React.ButtonHTMLAttributes<HTMLButtonElement> {
228
+ icon?: React.ComponentType;
229
+ children?: React.ReactNode;
230
+ }
231
+
232
+ const NavigationListLabelButton = React.forwardRef<
233
+ HTMLButtonElement,
234
+ NavigationListLabelButtonProps
235
+ >(({ className, icon, children, disabled, ...props }, ref) => {
236
+ return (
237
+ <button
238
+ ref={ref}
239
+ type="button"
240
+ disabled={disabled}
241
+ className={cn(
242
+ "s-inline-flex s-flex-shrink-0 s-items-center s-justify-center",
243
+ "s-rounded-md s-transition-colors s-duration-200",
244
+ "s-text-muted-foreground dark:s-text-muted-foreground-night",
245
+ "hover:s-text-foreground dark:hover:s-text-foreground-night",
246
+ "hover:s-bg-primary-150 dark:hover:s-bg-primary-150-night",
247
+ "active:s-bg-primary-200 dark:active:s-bg-primary-200-night",
248
+ "focus-visible:s-outline-none focus-visible:s-ring-2 focus-visible:s-ring-ring focus-visible:s-ring-offset-1",
249
+ "disabled:s-cursor-not-allowed disabled:s-opacity-50",
250
+ "disabled:hover:s-text-muted-foreground dark:disabled:hover:s-text-muted-foreground-night",
251
+ "disabled:hover:s-bg-transparent dark:disabled:hover:s-bg-transparent",
252
+ className
253
+ )}
254
+ {...props}
255
+ >
256
+ {icon ? <Icon visual={icon} size="xs" /> : children}
257
+ </button>
258
+ );
259
+ });
260
+
261
+ NavigationListLabelButton.displayName = "NavigationListLabelButton";
262
+
221
263
  interface NavigationListLabelProps
222
264
  extends React.HTMLAttributes<HTMLDivElement>,
223
265
  VariantProps<typeof variantStyles> {
224
266
  label: string;
267
+ isCollapsible?: boolean;
268
+ isOpen?: boolean;
269
+ action?: React.ReactNode;
225
270
  }
226
271
 
227
272
  const NavigationListLabel = React.forwardRef<
228
273
  HTMLDivElement,
229
274
  NavigationListLabelProps
230
- >(({ className, variant, label, isSticky, ...props }, ref) => (
231
- <div
232
- ref={ref}
233
- className={cn(
234
- labelStyles(),
235
- variantStyles({ variant, isSticky }),
236
- className
237
- )}
238
- {...props}
239
- >
240
- {label}
241
- </div>
242
- ));
275
+ >(
276
+ (
277
+ {
278
+ className,
279
+ variant,
280
+ label,
281
+ isSticky,
282
+ isCollapsible,
283
+ isOpen,
284
+ action,
285
+ ...props
286
+ },
287
+ ref
288
+ ) => (
289
+ <div
290
+ ref={ref}
291
+ className={cn(
292
+ labelStyles(),
293
+ variantStyles({ variant, isSticky }),
294
+ isCollapsible ? "s-pl-1.5" : "s-pl-3",
295
+ className
296
+ )}
297
+ {...props}
298
+ >
299
+ <div className="s-flex s-items-center s-gap-1 s-overflow-hidden s-text-ellipsis">
300
+ {isCollapsible && (
301
+ <NavigationListLabelButton
302
+ icon={isOpen ? ArrowDownSIcon : ArrowRightSIcon}
303
+ aria-label={isOpen ? "Collapse section" : "Expand section"}
304
+ />
305
+ )}
306
+ <span className="s-overflow-hidden s-text-ellipsis">{label}</span>
307
+ </div>
308
+ {action}
309
+ </div>
310
+ )
311
+ );
243
312
 
244
313
  NavigationListLabel.displayName = "NavigationListLabel";
245
314
 
315
+ interface NavigationListCollapsibleSectionProps
316
+ extends React.HTMLAttributes<HTMLDivElement> {
317
+ label: string;
318
+ action?: React.ReactNode;
319
+ defaultOpen?: boolean;
320
+ open?: boolean;
321
+ onOpenChange?: (open: boolean) => void;
322
+ children: React.ReactNode;
323
+ }
324
+
325
+ const NavigationListCollapsibleSection = React.forwardRef<
326
+ React.ElementRef<typeof Collapsible>,
327
+ NavigationListCollapsibleSectionProps
328
+ >(
329
+ (
330
+ {
331
+ label,
332
+ action,
333
+ defaultOpen,
334
+ open,
335
+ onOpenChange,
336
+ children,
337
+ className,
338
+ ...props
339
+ },
340
+ ref
341
+ ) => {
342
+ const [internalOpen, setInternalOpen] = React.useState(
343
+ defaultOpen ?? false
344
+ );
345
+ const isControlled = open !== undefined;
346
+ const isOpen = isControlled ? open : internalOpen;
347
+
348
+ const handleOpenChange = (newOpen: boolean) => {
349
+ if (!isControlled) {
350
+ setInternalOpen(newOpen);
351
+ }
352
+ onOpenChange?.(newOpen);
353
+ };
354
+
355
+ return (
356
+ <Collapsible
357
+ ref={ref}
358
+ open={isOpen}
359
+ onOpenChange={handleOpenChange}
360
+ className={className}
361
+ {...props}
362
+ >
363
+ <CollapsiblePrimitive.Trigger asChild>
364
+ <NavigationListLabel
365
+ label={label}
366
+ isCollapsible={true}
367
+ isOpen={isOpen}
368
+ action={action}
369
+ />
370
+ </CollapsiblePrimitive.Trigger>
371
+ <CollapsibleContent>{children}</CollapsibleContent>
372
+ </Collapsible>
373
+ );
374
+ }
375
+ );
376
+
377
+ NavigationListCollapsibleSection.displayName =
378
+ "NavigationListCollapsibleSection";
379
+
246
380
  export {
247
381
  NavigationList,
382
+ NavigationListCollapsibleSection,
248
383
  NavigationListItem,
249
384
  NavigationListItemAction,
250
385
  NavigationListLabel,
386
+ NavigationListLabelButton,
251
387
  };
@@ -9,8 +9,9 @@ const PopoverTrigger = PopoverPrimitive.Trigger;
9
9
  const PopoverPortal = PopoverPrimitive.Portal;
10
10
  const PopoverAnchor = PopoverPrimitive.Anchor;
11
11
 
12
- export interface PopoverContentProps
13
- extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> {
12
+ export interface PopoverContentProps extends React.ComponentPropsWithoutRef<
13
+ typeof PopoverPrimitive.Content
14
+ > {
14
15
  fullWidth?: boolean;
15
16
  mountPortal?: boolean;
16
17
  mountPortalContainer?: HTMLElement;
@@ -63,7 +63,8 @@ const RadioGroup = React.forwardRef<
63
63
  RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
64
64
 
65
65
  interface RadioGroupItemProps
66
- extends Omit<
66
+ extends
67
+ Omit<
67
68
  React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>,
68
69
  "children"
69
70
  >,
@@ -127,7 +128,8 @@ const RadioGroupItem = React.forwardRef<
127
128
  type IconPosition = "start" | "center" | "end";
128
129
 
129
130
  interface RadioGroupCustomItemProps
130
- extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>,
131
+ extends
132
+ React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>,
131
133
  VariantProps<typeof radioStyles> {
132
134
  iconPosition?: IconPosition;
133
135
  customItem: React.ReactNode;