@langchain/macaw-components 1.0.0-beta.1 → 1.0.0-beta.6

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 (185) hide show
  1. package/dist/_chunks/{LoadingIndicator-DgtU9aqD.js → LoadingIndicator-CDcArsiM.js} +13 -12
  2. package/dist/_chunks/LoadingIndicator-CDcArsiM.js.map +1 -0
  3. package/dist/_chunks/render-attachment-icon-BWBEMxXZ.js +270 -0
  4. package/dist/_chunks/render-attachment-icon-BWBEMxXZ.js.map +1 -0
  5. package/dist/catalog.json +527 -408
  6. package/dist/components/Attachment/Attachment.d.ts +21 -0
  7. package/dist/components/Attachment/Attachment.js +165 -0
  8. package/dist/components/Attachment/Attachment.js.map +1 -0
  9. package/dist/components/Attachment/AttachmentList.d.ts +5 -0
  10. package/dist/components/Attachment/AttachmentList.js +32 -0
  11. package/dist/components/Attachment/AttachmentList.js.map +1 -0
  12. package/dist/components/Attachment/index.d.ts +4 -0
  13. package/dist/components/Attachment/index.js +3 -0
  14. package/dist/components/Attachment/render-attachment-icon.d.ts +3 -0
  15. package/dist/components/Attachment/render-attachment-icon.js +2 -0
  16. package/dist/components/Avatar/Avatar.js +2 -2
  17. package/dist/components/Badge/Badge.d.ts +2 -0
  18. package/dist/components/Badge/Badge.js +12 -1
  19. package/dist/components/Badge/Badge.js.map +1 -1
  20. package/dist/components/Banner/Banner.js +1 -1
  21. package/dist/components/Button/Button.js +1 -1
  22. package/dist/components/Button/constants.js +2 -2
  23. package/dist/components/Button/constants.js.map +1 -1
  24. package/dist/components/ChartCard/ChartCard.d.ts +1 -4
  25. package/dist/components/ChartCard/ChartCard.js +2 -2
  26. package/dist/components/ChartCard/ChartCard.js.map +1 -1
  27. package/dist/components/ChartCard/ChartCardSkeleton.d.ts +1 -1
  28. package/dist/components/ChartCard/ChartCardSkeleton.js +37 -0
  29. package/dist/components/ChartCard/ChartCardSkeleton.js.map +1 -1
  30. package/dist/components/ChartLegend/ChartLegend.js +2 -2
  31. package/dist/components/ChartLegend/ChartLegendItemRenderer.js +2 -2
  32. package/dist/components/ChartLegend/ChartLegendItemRenderer.js.map +1 -1
  33. package/dist/components/Code/Code.utils.d.ts +3 -2
  34. package/dist/components/Code/Code.utils.js +7 -3
  35. package/dist/components/Code/Code.utils.js.map +1 -1
  36. package/dist/components/Code/CodeLanguageSelect.d.ts +7 -0
  37. package/dist/components/Code/CodeLanguageSelect.js +29 -0
  38. package/dist/components/Code/CodeLanguageSelect.js.map +1 -0
  39. package/dist/components/Code/CodeLite.js +3 -0
  40. package/dist/components/Code/CodeLite.js.map +1 -1
  41. package/dist/components/Code/CodeToolbar.d.ts +7 -0
  42. package/dist/components/Code/CodeToolbar.js +19 -0
  43. package/dist/components/Code/CodeToolbar.js.map +1 -0
  44. package/dist/components/Code/codeLanguages.d.ts +7 -0
  45. package/dist/components/Code/codeLanguages.js +59 -0
  46. package/dist/components/Code/codeLanguages.js.map +1 -0
  47. package/dist/components/Code/index.d.ts +15 -2
  48. package/dist/components/Code/index.js +70 -50
  49. package/dist/components/Code/index.js.map +1 -1
  50. package/dist/components/Code/types.d.ts +1 -1
  51. package/dist/components/Command/Command.d.ts +10 -13
  52. package/dist/components/Command/Command.js +7 -2
  53. package/dist/components/Command/Command.js.map +1 -1
  54. package/dist/components/Command/CommandMenu.d.ts +7 -1
  55. package/dist/components/Command/CommandMenu.js +17 -9
  56. package/dist/components/Command/CommandMenu.js.map +1 -1
  57. package/dist/components/ContextMenu/ContextMenu.d.ts +6 -0
  58. package/dist/components/ContextMenu/ContextMenu.js +3 -2
  59. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  60. package/dist/components/CopyButton/CopyButton.js +2 -2
  61. package/dist/components/Dialog/index.js +2 -2
  62. package/dist/components/DropdownMenu/DropdownMenu.d.ts +11 -0
  63. package/dist/components/DropdownMenu/DropdownMenu.js +5 -4
  64. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  65. package/dist/components/ErrorMessage/ErrorMessage.js +1 -1
  66. package/dist/components/GroupedTabs/GroupedTabs.d.ts +5 -2
  67. package/dist/components/GroupedTabs/GroupedTabs.js +33 -26
  68. package/dist/components/GroupedTabs/GroupedTabs.js.map +1 -1
  69. package/dist/components/IconButton/IconButton.js +2 -2
  70. package/dist/components/Input/Input.js +1 -1
  71. package/dist/components/LineChart/LineChart.d.ts +2 -2
  72. package/dist/components/LineChart/LineChart.js +3 -1
  73. package/dist/components/LineChart/LineChart.js.map +1 -1
  74. package/dist/components/LineChart/LineChart.types.d.ts +16 -0
  75. package/dist/components/LineChart/LineChartPlot.d.ts +3 -2
  76. package/dist/components/LineChart/LineChartPlot.js +8 -1
  77. package/dist/components/LineChart/LineChartPlot.js.map +1 -1
  78. package/dist/components/LineChart/LineChartVerticalMarkers.d.ts +8 -0
  79. package/dist/components/LineChart/LineChartVerticalMarkers.js +47 -0
  80. package/dist/components/LineChart/LineChartVerticalMarkers.js.map +1 -0
  81. package/dist/components/LineChart/index.d.ts +1 -1
  82. package/dist/components/Logo/index.js +11 -6
  83. package/dist/components/Logo/index.js.map +1 -1
  84. package/dist/components/MetricChart/MetricChart.d.ts +2 -0
  85. package/dist/components/MetricChart/MetricChart.js +15 -4
  86. package/dist/components/MetricChart/MetricChart.js.map +1 -1
  87. package/dist/components/MetricChart/index.d.ts +1 -1
  88. package/dist/components/Pane/Pane.js +2 -2
  89. package/dist/components/SankeyChart/AnimatedSankeyLink.d.ts +17 -0
  90. package/dist/components/SankeyChart/AnimatedSankeyLink.js +44 -0
  91. package/dist/components/SankeyChart/AnimatedSankeyLink.js.map +1 -0
  92. package/dist/components/SankeyChart/AnimatedSankeyNode.d.ts +16 -0
  93. package/dist/components/SankeyChart/AnimatedSankeyNode.js +42 -0
  94. package/dist/components/SankeyChart/AnimatedSankeyNode.js.map +1 -0
  95. package/dist/components/SankeyChart/SankeyChart.d.ts +42 -0
  96. package/dist/components/SankeyChart/SankeyChart.js +185 -0
  97. package/dist/components/SankeyChart/SankeyChart.js.map +1 -0
  98. package/dist/components/SankeyChart/SankeyChart.types.d.ts +90 -0
  99. package/dist/components/SankeyChart/SankeyChart.types.js +0 -0
  100. package/dist/components/SankeyChart/SankeyChart.utils.d.ts +21 -0
  101. package/dist/components/SankeyChart/SankeyChart.utils.js +299 -0
  102. package/dist/components/SankeyChart/SankeyChart.utils.js.map +1 -0
  103. package/dist/components/SankeyChart/SankeyNodeLabel.d.ts +10 -0
  104. package/dist/components/SankeyChart/SankeyNodeLabel.js +30 -0
  105. package/dist/components/SankeyChart/SankeyNodeLabel.js.map +1 -0
  106. package/dist/components/SankeyChart/SankeyNodeLabel.utils.d.ts +9 -0
  107. package/dist/components/SankeyChart/SankeyNodeLabel.utils.js +29 -0
  108. package/dist/components/SankeyChart/SankeyNodeLabel.utils.js.map +1 -0
  109. package/dist/components/SankeyChart/constants.d.ts +22 -0
  110. package/dist/components/SankeyChart/constants.js +27 -0
  111. package/dist/components/SankeyChart/constants.js.map +1 -0
  112. package/dist/components/SankeyChart/index.d.ts +5 -0
  113. package/dist/components/SankeyChart/index.js +4 -0
  114. package/dist/components/Select/Select.js +5 -5
  115. package/dist/components/Select/Select.js.map +1 -1
  116. package/dist/components/Select/SelectPrimitive.d.ts +6 -0
  117. package/dist/components/Select/SelectPrimitive.js +3 -2
  118. package/dist/components/Select/SelectPrimitive.js.map +1 -1
  119. package/dist/components/Slider/Slider.js +10 -3
  120. package/dist/components/Slider/Slider.js.map +1 -1
  121. package/dist/components/SplitViewPane/SplitViewPane.d.ts +2 -1
  122. package/dist/components/SplitViewPane/SplitViewPane.js +113 -219
  123. package/dist/components/SplitViewPane/SplitViewPane.js.map +1 -1
  124. package/dist/components/SplitViewPane/SplitViewPaneHeader.js +2 -2
  125. package/dist/components/SplitViewPane/useShowChildren.d.ts +5 -0
  126. package/dist/components/SplitViewPane/useShowChildren.js +14 -0
  127. package/dist/components/SplitViewPane/useShowChildren.js.map +1 -0
  128. package/dist/components/SplitViewPane/useSplitViewPaneResize.d.ts +21 -0
  129. package/dist/components/SplitViewPane/useSplitViewPaneResize.js +145 -0
  130. package/dist/components/SplitViewPane/useSplitViewPaneResize.js.map +1 -0
  131. package/dist/components/Textarea/Textarea.d.ts +4 -3
  132. package/dist/components/Textarea/Textarea.js +7 -21
  133. package/dist/components/Textarea/Textarea.js.map +1 -1
  134. package/dist/components/ThinkingState/LoadingIndicator.d.ts +1 -0
  135. package/dist/components/ThinkingState/LoadingIndicator.js +1 -1
  136. package/dist/components/ThinkingState/ThinkingState.d.ts +1 -0
  137. package/dist/components/ThinkingState/ThinkingState.js +5 -4
  138. package/dist/components/ThinkingState/ThinkingState.js.map +1 -1
  139. package/dist/components/ThinkingState/index.js +1 -1
  140. package/dist/components/Toast/index.js +33 -28
  141. package/dist/components/Toast/index.js.map +1 -1
  142. package/dist/components/Tooltip/Tooltip.js +2 -2
  143. package/dist/components/Typeahead/Typeahead.js +18 -8
  144. package/dist/components/Typeahead/Typeahead.js.map +1 -1
  145. package/dist/components/Typeahead/Typeahead.types.d.ts +2 -0
  146. package/dist/components/Typeahead/TypeaheadParts.d.ts +3 -1
  147. package/dist/components/Typeahead/TypeaheadParts.js +7 -6
  148. package/dist/components/Typeahead/TypeaheadParts.js.map +1 -1
  149. package/dist/components/Typeahead/TypeaheadView.js +19 -13
  150. package/dist/components/Typeahead/TypeaheadView.js.map +1 -1
  151. package/dist/components/Typeahead/useTypeaheadDomSync.d.ts +1 -1
  152. package/dist/components/Typeahead/useTypeaheadDomSync.js +14 -8
  153. package/dist/components/Typeahead/useTypeaheadDomSync.js.map +1 -1
  154. package/dist/components/Typeahead/useTypeaheadUncontrolledInput.d.ts +2 -1
  155. package/dist/components/Typeahead/useTypeaheadUncontrolledInput.js +10 -9
  156. package/dist/components/Typeahead/useTypeaheadUncontrolledInput.js.map +1 -1
  157. package/dist/components/UnsavedChangesDialog.js +2 -2
  158. package/dist/components/index.d.ts +3 -1
  159. package/dist/components/index.js +7 -5
  160. package/dist/components.css +22 -18
  161. package/dist/hooks/useDebouncedCommit.d.ts +14 -0
  162. package/dist/hooks/useDebouncedCommit.js +35 -0
  163. package/dist/hooks/useDebouncedCommit.js.map +1 -0
  164. package/dist/icons/LongTailPhosphorIcons.js +1 -1
  165. package/dist/icons/PaddedPhosphorIcons.d.ts +1 -0
  166. package/dist/icons/PaddedPhosphorIcons.js +4 -2
  167. package/dist/icons/PaddedPhosphorIcons.js.map +1 -1
  168. package/dist/icons/WeightedPhosphorIcons.d.ts +1 -0
  169. package/dist/icons/WeightedPhosphorIcons.js +3 -1
  170. package/dist/icons/WeightedPhosphorIcons.js.map +1 -1
  171. package/dist/icons/index.js +3 -3
  172. package/dist/index.js +7 -5
  173. package/dist/utilities.css +1 -1
  174. package/dist/utils/chartColors.d.ts +2 -1
  175. package/dist/utils/chartColors.js +2 -1
  176. package/dist/utils/chartColors.js.map +1 -1
  177. package/dist/utils/componentSizes.d.ts +0 -1
  178. package/dist/utils/componentSizes.js.map +1 -1
  179. package/dist/utils/lazy-codemirror-loader.d.ts +0 -2
  180. package/dist/utils/lazy-codemirror-loader.js +1 -3
  181. package/dist/utils/lazy-codemirror-loader.js.map +1 -1
  182. package/docs/DESIGN.md +17 -0
  183. package/docs/STYLES.md +4 -1
  184. package/package.json +21 -8
  185. package/dist/_chunks/LoadingIndicator-DgtU9aqD.js.map +0 -1
@@ -1,9 +1,9 @@
1
1
  import { cn } from "../../utils/cn.js";
2
2
  import zIndices from "../../utils/zIndices.js";
3
3
  import { ZIndexProvider } from "../../utils/ZIndexContext.js";
4
- import { CheckIcon, XCloseIcon } from "../../icons/PaddedPhosphorIcons.js";
5
4
  import { Icon } from "../Icon/Icon.js";
6
5
  import { IconButton } from "../IconButton/IconButton.js";
6
+ import { CheckIcon, XCloseIcon } from "../../icons/PaddedPhosphorIcons.js";
7
7
  import { CopyIconButton } from "../CopyButton/CopyButton.js";
8
8
  import { ToastContext } from "./ToastContext.js";
9
9
  import React, { useCallback } from "react";
@@ -16,41 +16,41 @@ var DEFAULT_DURATION_MS = 5e3;
16
16
  var ERROR_DURATION_MS = Infinity;
17
17
  function ToastProvider({ children }) {
18
18
  const [open, setOpen] = React.useState(false);
19
- const [config, setConfig] = React.useState(null);
19
+ const [toast, setToast] = React.useState(null);
20
+ const config = toast?.config;
20
21
  const createToast = useCallback((titleOrConfig) => {
21
22
  const preConfig = typeof titleOrConfig === "string" ? { title: titleOrConfig } : titleOrConfig;
22
23
  const config = {
23
24
  duration: preConfig.error || preConfig.type === "error" ? ERROR_DURATION_MS : DEFAULT_DURATION_MS,
24
25
  ...preConfig
25
26
  };
26
- setConfig(config);
27
+ setToast((previous) => ({
28
+ id: (previous?.id ?? 0) + 1,
29
+ config
30
+ }));
27
31
  setOpen(true);
28
32
  }, []);
29
- return /* @__PURE__ */ jsx(ToastContext.Provider, {
33
+ return /* @__PURE__ */ jsxs(ToastContext.Provider, {
30
34
  value: { createToast },
31
- children: /* @__PURE__ */ jsxs(ToastLib.Provider, {
35
+ children: [children, /* @__PURE__ */ jsxs(ToastLib.Provider, {
32
36
  swipeDirection: "right",
33
- children: [
34
- children,
35
- /* @__PURE__ */ jsx(ZIndexProvider, {
36
- value: zIndices.toast,
37
- children: /* @__PURE__ */ jsx(Toast, {
38
- title: config?.title,
39
- description: config?.description,
40
- open,
41
- setOpen,
42
- action: config?.action,
43
- error: config?.error,
44
- duration: config?.duration,
45
- type: config?.type
46
- })
47
- }),
48
- /* @__PURE__ */ jsx(ToastLib.Viewport, {
49
- className: cn("fixed bottom-0 right-0 m-0 flex w-[390px] max-w-[100vw] list-none flex-col gap-[10px] p-[var(--viewport-padding)] outline-none [--viewport-padding:_25px]", config?.viewPortClassName),
50
- style: { zIndex: zIndices.toast }
37
+ children: [/* @__PURE__ */ jsx(ZIndexProvider, {
38
+ value: zIndices.toast,
39
+ children: /* @__PURE__ */ jsx(Toast, {
40
+ title: config?.title,
41
+ description: config?.description,
42
+ open,
43
+ setOpen,
44
+ action: config?.action,
45
+ error: config?.error,
46
+ duration: config?.duration,
47
+ type: config?.type
51
48
  })
52
- ]
53
- })
49
+ }), /* @__PURE__ */ jsx(ToastLib.Viewport, {
50
+ className: cn("fixed bottom-0 right-0 m-0 flex w-[390px] max-w-full list-none flex-col gap-[10px] p-[var(--viewport-padding)] outline-none [--viewport-padding:_25px]", config?.viewPortClassName),
51
+ style: { zIndex: zIndices.toast }
52
+ })]
53
+ }, toast?.id)]
54
54
  });
55
55
  }
56
56
  var stopSwipeOnTextSelect = (e) => e.stopPropagation();
@@ -65,29 +65,34 @@ function renderToastIcon(isError, type) {
65
65
  if (isError) return /* @__PURE__ */ jsx(Icon, {
66
66
  icon: ExclamationMarkIcon,
67
67
  weight: "regular",
68
+ size: "sm",
68
69
  rounded: true,
69
70
  color: "error"
70
71
  });
71
72
  if (type === "success") return /* @__PURE__ */ jsx(Icon, {
72
73
  icon: CheckIcon,
74
+ size: "sm",
73
75
  rounded: true,
74
76
  color: "success"
75
77
  });
76
78
  if (type === "warning") return /* @__PURE__ */ jsx(Icon, {
77
79
  icon: ExclamationMarkIcon,
78
80
  weight: "regular",
81
+ size: "sm",
79
82
  rounded: true,
80
83
  color: "warning"
81
84
  });
82
85
  if (type === "info") return /* @__PURE__ */ jsx(Icon, {
83
86
  icon: InfoIcon,
84
87
  weight: "fill",
88
+ size: "sm",
85
89
  rounded: true,
86
90
  color: "info"
87
91
  });
88
92
  return /* @__PURE__ */ jsx(Icon, {
89
93
  icon: InfoIcon,
90
94
  weight: "fill",
95
+ size: "sm",
91
96
  rounded: true,
92
97
  color: "neutral"
93
98
  });
@@ -128,14 +133,14 @@ function Toast({ title, open, setOpen, description, action, error, duration, typ
128
133
  onOpenChange: setOpen,
129
134
  duration,
130
135
  children: hasTitle ? /* @__PURE__ */ jsxs("div", {
131
- className: "flex w-full flex-col gap-space-2 pb-space-1",
136
+ className: cn("flex w-full flex-col gap-space-1", Boolean(description) && "pb-space-1"),
132
137
  children: [
133
138
  /* @__PURE__ */ jsxs("div", {
134
139
  className: "flex w-full items-center",
135
140
  children: [/* @__PURE__ */ jsxs("div", {
136
- className: "flex w-full items-center gap-space-2",
141
+ className: "flex w-full items-center gap-space-3",
137
142
  children: [renderToastIcon(isError, type), /* @__PURE__ */ jsx(ToastLib.Title, {
138
- className: "cursor-text select-text font-medium text-primary",
143
+ className: "cursor-text select-text text-sm font-medium text-primary",
139
144
  onPointerDown: stopSwipeOnTextSelect,
140
145
  children: title
141
146
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Toast/index.tsx"],"sourcesContent":["import React, { useCallback } from 'react';\n\nimport { ExclamationMarkIcon } from '@phosphor-icons/react/dist/ssr/ExclamationMark';\nimport { InfoIcon } from '@phosphor-icons/react/dist/ssr/Info';\nimport * as ToastLib from '@radix-ui/react-toast';\n\nimport { CheckIcon, XCloseIcon } from '../../icons/PaddedPhosphorIcons';\nimport { cn } from '../../utils/cn';\nimport { ZIndexProvider } from '../../utils/ZIndexContext';\nimport zIndices from '../../utils/zIndices';\nimport { CopyIconButton } from '../CopyButton';\nimport { Icon } from '../Icon';\nimport { IconButton } from '../IconButton';\nimport { ToastContext } from './ToastContext';\n\nconst DEFAULT_DURATION_MS = 5000;\n// Error toasts do not auto-dismiss; the user must click the close button.\nconst ERROR_DURATION_MS = Infinity;\n\n// Provider wraps whole application\nexport function ToastProvider({ children }: { children: React.ReactNode }) {\n // note this only supports one toast at a time currently\n const [open, setOpen] = React.useState(false);\n const [config, setConfig] = React.useState<ToastConfig | null>(null);\n\n const createToast = useCallback((titleOrConfig: ToastConfig | string) => {\n const preConfig =\n typeof titleOrConfig === 'string'\n ? { title: titleOrConfig }\n : titleOrConfig;\n const isError = preConfig.error || preConfig.type === 'error';\n const config: ToastConfig = {\n duration: isError ? ERROR_DURATION_MS : DEFAULT_DURATION_MS,\n ...preConfig,\n };\n\n setConfig(config);\n setOpen(true);\n }, []);\n\n return (\n <ToastContext.Provider value={{ createToast }}>\n <ToastLib.Provider swipeDirection=\"right\">\n {children}\n <ZIndexProvider value={zIndices.toast}>\n <Toast\n title={config?.title}\n description={config?.description}\n open={open}\n setOpen={setOpen}\n action={config?.action}\n error={config?.error}\n duration={config?.duration}\n type={config?.type}\n />\n </ZIndexProvider>\n <ToastLib.Viewport\n className={cn(\n 'fixed bottom-0 right-0 m-0 flex w-[390px] max-w-[100vw] list-none flex-col gap-[10px] p-[var(--viewport-padding)] outline-none [--viewport-padding:_25px]',\n config?.viewPortClassName\n )}\n style={{ zIndex: zIndices.toast }}\n />\n </ToastLib.Provider>\n </ToastContext.Provider>\n );\n}\n\nexport type ToastConfig = {\n title?: string | React.ReactNode;\n description?: React.ReactNode;\n action?: React.ReactNode;\n duration?: number;\n viewPortClassName?: string;\n error?: boolean;\n type?: 'error' | 'info' | 'warning' | 'success';\n};\n\nconst stopSwipeOnTextSelect = (e: React.PointerEvent) => e.stopPropagation();\n\nconst SURFACE_BY_TYPE = {\n default: 'bg-surface-level-2 border-subtle',\n error: 'bg-error border-error',\n warning: 'bg-warning border-warning',\n success: 'bg-success border-success',\n info: 'bg-brand-subtle border-brand-75',\n} as const;\n\nfunction renderToastIcon(isError: boolean, type: ToastConfig['type']) {\n if (isError)\n return (\n <Icon icon={ExclamationMarkIcon} weight=\"regular\" rounded color=\"error\" />\n );\n if (type === 'success')\n return <Icon icon={CheckIcon} rounded color=\"success\" />;\n if (type === 'warning')\n return (\n <Icon\n icon={ExclamationMarkIcon}\n weight=\"regular\"\n rounded\n color=\"warning\"\n />\n );\n if (type === 'info')\n return <Icon icon={InfoIcon} weight=\"fill\" rounded color=\"info\" />;\n return <Icon icon={InfoIcon} weight=\"fill\" rounded color=\"neutral\" />;\n}\n\nfunction Toast({\n title,\n open,\n setOpen,\n description,\n action,\n error,\n duration,\n type,\n}: {\n title?: string | React.ReactNode;\n open: boolean;\n setOpen?: (open: boolean) => void;\n description?: React.ReactNode;\n action?: React.ReactNode;\n error?: boolean;\n duration?: number;\n type?: 'error' | 'info' | 'warning' | 'success';\n}) {\n const isError = error || type === 'error';\n const surface = SURFACE_BY_TYPE[isError ? 'error' : (type ?? 'default')];\n const hasTitle = title !== undefined && title !== null && title !== '';\n const copyText =\n isError && typeof title === 'string'\n ? typeof description === 'string'\n ? `${title}\\n${description}`\n : title\n : null;\n\n const descriptionNode = description && (\n <ToastLib.Description asChild>\n <div\n className={cn(\n 'max-h-32 cursor-text select-text overflow-y-auto whitespace-pre-wrap',\n hasTitle\n ? 'ml-space-6 text-xxs text-secondary'\n : 'text-sm text-primary'\n )}\n onPointerDown={stopSwipeOnTextSelect}\n >\n {description}\n </div>\n </ToastLib.Description>\n );\n\n const trailingButtons = (\n <div className=\"flex gap-space-2\">\n {copyText && (\n <CopyIconButton\n size=\"xs\"\n copy={copyText}\n copyText=\"Copy error message\"\n />\n )}\n <ToastLib.Close asChild>\n <IconButton\n icon={XCloseIcon}\n label=\"Dismiss\"\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n />\n </ToastLib.Close>\n </div>\n );\n\n return (\n <ToastLib.Root\n className={cn(\n 'flex items-start gap-space-2 rounded-md border p-space-3',\n surface,\n 'shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px]',\n 'data-[swipe=cancel]:translate-x-0 data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[state=closed]:animate-hide data-[state=open]:animate-slideIn data-[swipe=end]:animate-swipeOut data-[swipe=cancel]:transition-[transform_200ms_ease-out]'\n )}\n open={open}\n onOpenChange={setOpen}\n duration={duration}\n >\n {hasTitle ? (\n <div className=\"flex w-full flex-col gap-space-2 pb-space-1\">\n <div className=\"flex w-full items-center\">\n <div className=\"flex w-full items-center gap-space-2\">\n {renderToastIcon(isError, type)}\n <ToastLib.Title\n className=\"cursor-text select-text font-medium text-primary\"\n onPointerDown={stopSwipeOnTextSelect}\n >\n {title}\n </ToastLib.Title>\n </div>\n {trailingButtons}\n </div>\n {descriptionNode}\n {action && <div className=\"ml-space-6\">{action}</div>}\n </div>\n ) : (\n <div className=\"flex w-full items-start gap-space-2\">\n {renderToastIcon(isError, type)}\n <div className=\"flex flex-1 flex-col gap-space-2\">\n {descriptionNode}\n {action}\n </div>\n {trailingButtons}\n </div>\n )}\n </ToastLib.Root>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Toast/index.tsx"],"sourcesContent":["import React, { useCallback } from 'react';\n\nimport { ExclamationMarkIcon } from '@phosphor-icons/react/dist/ssr/ExclamationMark';\nimport { InfoIcon } from '@phosphor-icons/react/dist/ssr/Info';\nimport * as ToastLib from '@radix-ui/react-toast';\n\nimport { CheckIcon, XCloseIcon } from '../../icons/PaddedPhosphorIcons';\nimport { cn } from '../../utils/cn';\nimport { ZIndexProvider } from '../../utils/ZIndexContext';\nimport zIndices from '../../utils/zIndices';\nimport { CopyIconButton } from '../CopyButton';\nimport { Icon } from '../Icon';\nimport { IconButton } from '../IconButton';\nimport { ToastContext } from './ToastContext';\n\nconst DEFAULT_DURATION_MS = 5000;\n// Error toasts do not auto-dismiss; the user must click the close button.\nconst ERROR_DURATION_MS = Infinity;\n\n// Provider wraps whole application\nexport function ToastProvider({ children }: { children: React.ReactNode }) {\n // note this only supports one toast at a time currently\n const [open, setOpen] = React.useState(false);\n const [toast, setToast] = React.useState<{\n id: number;\n config: ToastConfig;\n } | null>(null);\n const config = toast?.config;\n\n const createToast = useCallback((titleOrConfig: ToastConfig | string) => {\n const preConfig =\n typeof titleOrConfig === 'string'\n ? { title: titleOrConfig }\n : titleOrConfig;\n const isError = preConfig.error || preConfig.type === 'error';\n const config: ToastConfig = {\n duration: isError ? ERROR_DURATION_MS : DEFAULT_DURATION_MS,\n ...preConfig,\n };\n\n setToast((previous) => ({ id: (previous?.id ?? 0) + 1, config }));\n setOpen(true);\n }, []);\n\n return (\n <ToastContext.Provider value={{ createToast }}>\n {children}\n {/* Reset Radix's paused state without remounting application children. */}\n <ToastLib.Provider key={toast?.id} swipeDirection=\"right\">\n <ZIndexProvider value={zIndices.toast}>\n <Toast\n title={config?.title}\n description={config?.description}\n open={open}\n setOpen={setOpen}\n action={config?.action}\n error={config?.error}\n duration={config?.duration}\n type={config?.type}\n />\n </ZIndexProvider>\n <ToastLib.Viewport\n className={cn(\n 'fixed bottom-0 right-0 m-0 flex w-[390px] max-w-full list-none flex-col gap-[10px] p-[var(--viewport-padding)] outline-none [--viewport-padding:_25px]',\n config?.viewPortClassName\n )}\n style={{ zIndex: zIndices.toast }}\n />\n </ToastLib.Provider>\n </ToastContext.Provider>\n );\n}\n\nexport type ToastConfig = {\n title?: string | React.ReactNode;\n description?: React.ReactNode;\n action?: React.ReactNode;\n duration?: number;\n viewPortClassName?: string;\n error?: boolean;\n type?: 'error' | 'info' | 'warning' | 'success';\n};\n\nconst stopSwipeOnTextSelect = (e: React.PointerEvent) => e.stopPropagation();\n\nconst SURFACE_BY_TYPE = {\n default: 'bg-surface-level-2 border-subtle',\n error: 'bg-error border-error',\n warning: 'bg-warning border-warning',\n success: 'bg-success border-success',\n info: 'bg-brand-subtle border-brand-75',\n} as const;\n\nfunction renderToastIcon(isError: boolean, type: ToastConfig['type']) {\n if (isError)\n return (\n <Icon\n icon={ExclamationMarkIcon}\n weight=\"regular\"\n size=\"sm\"\n rounded\n color=\"error\"\n />\n );\n if (type === 'success')\n return <Icon icon={CheckIcon} size=\"sm\" rounded color=\"success\" />;\n if (type === 'warning')\n return (\n <Icon\n icon={ExclamationMarkIcon}\n weight=\"regular\"\n size=\"sm\"\n rounded\n color=\"warning\"\n />\n );\n if (type === 'info')\n return (\n <Icon icon={InfoIcon} weight=\"fill\" size=\"sm\" rounded color=\"info\" />\n );\n return (\n <Icon icon={InfoIcon} weight=\"fill\" size=\"sm\" rounded color=\"neutral\" />\n );\n}\n\nfunction Toast({\n title,\n open,\n setOpen,\n description,\n action,\n error,\n duration,\n type,\n}: {\n title?: string | React.ReactNode;\n open: boolean;\n setOpen?: (open: boolean) => void;\n description?: React.ReactNode;\n action?: React.ReactNode;\n error?: boolean;\n duration?: number;\n type?: 'error' | 'info' | 'warning' | 'success';\n}) {\n const isError = error || type === 'error';\n const surface = SURFACE_BY_TYPE[isError ? 'error' : (type ?? 'default')];\n const hasTitle = title !== undefined && title !== null && title !== '';\n const copyText =\n isError && typeof title === 'string'\n ? typeof description === 'string'\n ? `${title}\\n${description}`\n : title\n : null;\n\n const descriptionNode = description && (\n <ToastLib.Description asChild>\n <div\n className={cn(\n 'max-h-32 cursor-text select-text overflow-y-auto whitespace-pre-wrap',\n hasTitle\n ? 'ml-space-6 text-xxs text-secondary'\n : 'text-sm text-primary'\n )}\n onPointerDown={stopSwipeOnTextSelect}\n >\n {description}\n </div>\n </ToastLib.Description>\n );\n\n const trailingButtons = (\n <div className=\"flex gap-space-2\">\n {copyText && (\n <CopyIconButton\n size=\"xs\"\n copy={copyText}\n copyText=\"Copy error message\"\n />\n )}\n <ToastLib.Close asChild>\n <IconButton\n icon={XCloseIcon}\n label=\"Dismiss\"\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n />\n </ToastLib.Close>\n </div>\n );\n\n return (\n <ToastLib.Root\n className={cn(\n 'flex items-start gap-space-2 rounded-md border p-space-3',\n surface,\n 'shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px]',\n 'data-[swipe=cancel]:translate-x-0 data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[state=closed]:animate-hide data-[state=open]:animate-slideIn data-[swipe=end]:animate-swipeOut data-[swipe=cancel]:transition-[transform_200ms_ease-out]'\n )}\n open={open}\n onOpenChange={setOpen}\n duration={duration}\n >\n {hasTitle ? (\n <div\n className={cn(\n 'flex w-full flex-col gap-space-1',\n Boolean(description) && 'pb-space-1'\n )}\n >\n <div className=\"flex w-full items-center\">\n <div className=\"flex w-full items-center gap-space-3\">\n {renderToastIcon(isError, type)}\n <ToastLib.Title\n className=\"cursor-text select-text text-sm font-medium text-primary\"\n onPointerDown={stopSwipeOnTextSelect}\n >\n {title}\n </ToastLib.Title>\n </div>\n {trailingButtons}\n </div>\n {descriptionNode}\n {action && <div className=\"ml-space-6\">{action}</div>}\n </div>\n ) : (\n <div className=\"flex w-full items-start gap-space-2\">\n {renderToastIcon(isError, type)}\n <div className=\"flex flex-1 flex-col gap-space-2\">\n {descriptionNode}\n {action}\n </div>\n {trailingButtons}\n </div>\n )}\n </ToastLib.Root>\n );\n}\n"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import { cn } from "../../utils/cn.js";
2
+ import { Text } from "../Text/Text.js";
2
3
  import zIndices from "../../utils/zIndices.js";
3
4
  import { useZIndex } from "../../utils/useZIndex.js";
4
5
  import { ZIndexProvider } from "../../utils/ZIndexContext.js";
5
- import { Text } from "../Text/Text.js";
6
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
7
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
8
8
  //#region packages/components/src/components/Tooltip/Tooltip.tsx
9
9
  function Tooltip({ title, description, children, tooltipClassName, side = "top", sideOffset = 10, align = "center", alignOffset = 0, invert = false, delayDuration = 300, disabled = false, blockTriggerEvents = false, open, onOpenChange, disableHoverableContent = true }) {
10
10
  const zIndex = useZIndex(zIndices.tooltip);
@@ -5,7 +5,7 @@ import { useTypeaheadUncontrolledInput } from "./useTypeaheadUncontrolledInput.j
5
5
  import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  //#region packages/components/src/components/Typeahead/Typeahead.tsx
8
- function TypeaheadInner({ options, value, onChange, placeholder = "Search...", leftDecorator, showPlaceholderWithValues = false, emptyText = "No results found.", size = "md", disabled = false, isError = false, freeSolo = false, multiple, disableClearable = false, disableCloseOnSelect = false, filterOptions, forcePopupIcon = true, clearOnBlur, clearValueOnInputClear = false, displaySelectedValueWhenInputEmpty = false, maxVisibleOptions, hideEmptyList = false, emptyState, listFooter, onCreateNew, createNewLabel, inputValue: controlledInputValue, onInputChange, getOptionLabel, getOptionValue, getOptionDisabled, renderOption, renderTags, className, inputId, autoFocus, autoComplete, onKeyDown, onBlur, "aria-label": ariaLabel, "data-testid": dataTestId, ...rest }, ref) {
8
+ function TypeaheadInner({ options, value, onChange, placeholder = "Search...", leftDecorator, showPlaceholderWithValues = false, emptyText = "No results found.", size = "md", disabled = false, isError = false, freeSolo = false, multiple, disableClearable = false, disableCloseOnSelect = false, filterOptions, forcePopupIcon = true, clearOnBlur, clearValueOnInputClear = false, displaySelectedValueWhenInputEmpty = false, maxVisibleOptions, hideEmptyList = false, emptyState, listFooter, onCreateNew, createNewLabel, inputValue: controlledInputValue, onInputChange, onOpenChange, getOptionLabel, getOptionValue, getOptionDisabled, renderOption, renderTags, className, inputId, autoFocus, autoComplete, onKeyDown, onBlur, "aria-label": ariaLabel, "data-testid": dataTestId, ...rest }, ref) {
9
9
  const generatedId = useId();
10
10
  const resolvedInputId = inputId ?? generatedId;
11
11
  const listId = `${resolvedInputId}-listbox`;
@@ -16,12 +16,22 @@ function TypeaheadInner({ options, value, onChange, placeholder = "Search...", l
16
16
  const listRef = useRef(null);
17
17
  const popoverContentRef = useRef(null);
18
18
  const [open, setOpenState] = useState(false);
19
+ const openRef = useRef(false);
19
20
  const [uncontrolledInputValue, setUncontrolledInputValue] = useState("");
20
21
  const setOpen = useCallback((nextOpen) => {
21
- if (!disabled || !nextOpen) setOpenState(nextOpen);
22
- }, [disabled]);
22
+ if (disabled && nextOpen || openRef.current === nextOpen) return;
23
+ openRef.current = nextOpen;
24
+ setOpenState(nextOpen);
25
+ onOpenChange?.(nextOpen);
26
+ }, [disabled, onOpenChange]);
27
+ useEffect(() => {
28
+ if (disabled && open) setOpen(false);
29
+ }, [
30
+ disabled,
31
+ open,
32
+ setOpen
33
+ ]);
23
34
  useEffect(() => {
24
- if (disabled) setOpenState(false);
25
35
  if (autoFocus) requestAnimationFrame(() => internalInputRef.current?.focus());
26
36
  }, [autoFocus, disabled]);
27
37
  const inputValue = controlledInputValue ?? uncontrolledInputValue;
@@ -41,6 +51,7 @@ function TypeaheadInner({ options, value, onChange, placeholder = "Search...", l
41
51
  controlledInputValue,
42
52
  freeSolo,
43
53
  getLabel,
54
+ getValue,
44
55
  multiple,
45
56
  open,
46
57
  setUncontrolledInputValue,
@@ -210,14 +221,13 @@ function TypeaheadInner({ options, value, onChange, placeholder = "Search...", l
210
221
  removeAtIndex,
211
222
  selectedValues
212
223
  ]);
213
- const hasValue = selectedValues.length > 0;
214
- const showClearButton = !disabled && !disableClearable && (hasValue || !multiple && inputValue.length > 0);
224
+ const showClearButton = !disabled && !disableClearable && (selectedValues.length > 0 || !multiple && inputValue.length > 0);
215
225
  const selectedSummary = getTypeaheadSelectedSummary(selectedValues, getLabel, multiple);
216
226
  const displayInputValue = getTypeaheadDisplayInputValue(inputValue, selectedValues, getLabel, multiple, displaySelectedValueWhenInputEmpty);
217
227
  const setInputNode = useCallback((node) => {
218
228
  internalInputRef.current = node;
219
229
  }, []);
220
- useTypeaheadDomSync({
230
+ const setListNode = useTypeaheadDomSync({
221
231
  autoComplete,
222
232
  commandLabel,
223
233
  inputAriaLabel,
@@ -279,7 +289,7 @@ function TypeaheadInner({ options, value, onChange, placeholder = "Search...", l
279
289
  selectedSummary
280
290
  },
281
291
  list: {
282
- ref: listRef,
292
+ ref: setListNode,
283
293
  items: visibleItems,
284
294
  emptyText,
285
295
  emptyState,
@@ -1 +1 @@
1
- {"version":3,"file":"Typeahead.js","names":[],"sources":["../../../src/components/Typeahead/Typeahead.tsx"],"sourcesContent":["import type { FocusEvent, KeyboardEvent, ReactElement, Ref } from 'react';\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport type {\n TypeaheadMultipleValue,\n TypeaheadProps,\n TypeaheadSelectedValue,\n TypeaheadSingleValue,\n TypeaheadTagProps,\n} from './Typeahead.types';\nimport {\n defaultOptionLabel,\n defaultOptionValue,\n getTypeaheadCreateState,\n getTypeaheadDisplayInputValue,\n getTypeaheadListItems,\n getTypeaheadSelectedSummary,\n isActiveOptionSelected,\n isTypeaheadOption,\n} from './Typeahead.utils';\nimport { TypeaheadView } from './TypeaheadView';\nimport { useTypeaheadDomSync } from './useTypeaheadDomSync';\nimport { useTypeaheadUncontrolledInput } from './useTypeaheadUncontrolledInput';\n\nfunction TypeaheadInner<TOption = string>(\n {\n options,\n value,\n onChange,\n placeholder = 'Search...',\n leftDecorator,\n showPlaceholderWithValues = false,\n emptyText = 'No results found.',\n size = 'md',\n disabled = false,\n isError = false,\n freeSolo = false,\n multiple,\n disableClearable = false,\n disableCloseOnSelect = false,\n filterOptions,\n forcePopupIcon = true,\n clearOnBlur,\n clearValueOnInputClear = false,\n displaySelectedValueWhenInputEmpty = false,\n maxVisibleOptions,\n hideEmptyList = false,\n emptyState,\n listFooter,\n onCreateNew,\n createNewLabel,\n inputValue: controlledInputValue,\n onInputChange,\n getOptionLabel,\n getOptionValue,\n getOptionDisabled,\n renderOption,\n renderTags,\n className,\n inputId,\n autoFocus,\n autoComplete,\n onKeyDown,\n onBlur,\n 'aria-label': ariaLabel,\n 'data-testid': dataTestId,\n ...rest\n }: TypeaheadProps<TOption>,\n ref: Ref<HTMLDivElement>\n) {\n const generatedId = useId();\n const resolvedInputId = inputId ?? generatedId;\n const listId = `${resolvedInputId}-listbox`;\n const selectedSummaryId = `${resolvedInputId}-selected-summary`;\n const commandLabel = ariaLabel ?? placeholder;\n const inputAriaLabel = ariaLabel ?? (inputId ? undefined : placeholder);\n const internalInputRef = useRef<HTMLInputElement | null>(null);\n const listRef = useRef<HTMLDivElement | null>(null);\n const popoverContentRef = useRef<HTMLDivElement | null>(null);\n const [open, setOpenState] = useState(false);\n const [uncontrolledInputValue, setUncontrolledInputValue] = useState('');\n const setOpen = useCallback(\n (nextOpen: boolean) => {\n if (!disabled || !nextOpen) {\n setOpenState(nextOpen);\n }\n },\n [disabled]\n );\n useEffect(() => {\n if (disabled) setOpenState(false);\n if (autoFocus)\n requestAnimationFrame(() => internalInputRef.current?.focus());\n }, [autoFocus, disabled]);\n\n const inputValue = controlledInputValue ?? uncontrolledInputValue;\n const getLabel = useCallback(\n (option: TypeaheadSelectedValue<TOption>) =>\n getOptionLabel ? getOptionLabel(option) : defaultOptionLabel(option),\n [getOptionLabel]\n );\n const getValue = useCallback(\n (option: TypeaheadSelectedValue<TOption>) =>\n getOptionValue ? getOptionValue(option) : defaultOptionValue(option),\n [getOptionValue]\n );\n\n const selectedValues = useMemo<TypeaheadMultipleValue<TOption>>(() => {\n if (multiple) {\n return Array.isArray(value) ? value : [];\n }\n return value == null ? [] : [value];\n }, [multiple, value]);\n\n const selectedKeys = useMemo(\n () => new Set(selectedValues.map((selected) => getValue(selected))),\n [getValue, selectedValues]\n );\n\n const setInputValue = useCallback(\n (nextValue: string) => {\n if (controlledInputValue === undefined) {\n setUncontrolledInputValue(nextValue);\n }\n onInputChange?.(nextValue);\n },\n [controlledInputValue, onInputChange]\n );\n\n useTypeaheadUncontrolledInput({\n clearOnBlur,\n controlledInputValue,\n freeSolo,\n getLabel,\n multiple,\n open,\n setUncontrolledInputValue,\n value,\n });\n\n const visibleItems = getTypeaheadListItems({\n options,\n selectedValues,\n inputValue,\n getLabel,\n getValue,\n filterOptions,\n maxVisibleOptions,\n includeSelectedValues: multiple,\n });\n\n const optionIsDisabled = useCallback(\n (item: (typeof visibleItems)[number]) => {\n if (item.source === 'selected') return false;\n const option = item.option as TOption;\n return (\n getOptionDisabled?.(option) ??\n (isTypeaheadOption(option) ? !!option.disabled : false)\n );\n },\n [getOptionDisabled]\n );\n\n const {\n customCreateInputValue,\n showCreateOption,\n showFreeSoloCreateOption,\n trimmedInputValue,\n } = getTypeaheadCreateState(\n inputValue,\n options,\n selectedValues,\n getLabel,\n freeSolo,\n !!onCreateNew\n );\n const hasPopupContent =\n visibleItems.length > 0 ||\n showCreateOption ||\n emptyState != null ||\n listFooter != null ||\n !hideEmptyList;\n const popupOpen = open && hasPopupContent;\n const focusInput = useCallback(() => {\n requestAnimationFrame(() => internalInputRef.current?.focus());\n }, []);\n\n // `onChange` can't be narrowed from the single/multiple props union after destructuring; callers below branch on `multiple` first, so funnel both shapes through one callback.\n const emitChange = useCallback(\n (next: TypeaheadSingleValue<TOption> | TypeaheadMultipleValue<TOption>) =>\n (onChange as (value: typeof next) => void)(next),\n [onChange]\n );\n const selectValue = useCallback(\n (selected: TypeaheadSelectedValue<TOption>) => {\n if (disabled) return;\n if (multiple) {\n const selectedKey = getValue(selected);\n const nextValue = selectedKeys.has(selectedKey)\n ? selectedValues.filter((item) => getValue(item) !== selectedKey)\n : [...selectedValues, selected];\n\n emitChange(nextValue);\n setInputValue('');\n if (disableCloseOnSelect) {\n focusInput();\n } else {\n setOpen(false);\n }\n return;\n }\n\n emitChange(selected);\n setInputValue(\n displaySelectedValueWhenInputEmpty ? '' : getLabel(selected)\n );\n setOpen(false);\n },\n [\n disableCloseOnSelect,\n disabled,\n emitChange,\n focusInput,\n getLabel,\n getValue,\n displaySelectedValueWhenInputEmpty,\n multiple,\n selectedKeys,\n selectedValues,\n setInputValue,\n setOpen,\n ]\n );\n\n const createFreeSoloValue = useCallback(() => {\n if (!showFreeSoloCreateOption) return;\n selectValue(trimmedInputValue);\n }, [selectValue, showFreeSoloCreateOption, trimmedInputValue]);\n\n const createCustomValue = useCallback(() => {\n if (!onCreateNew) return;\n onCreateNew(customCreateInputValue);\n setOpen(false);\n }, [customCreateInputValue, onCreateNew, setOpen]);\n\n const removeAtIndex = useCallback(\n (index: number) => {\n if (!multiple || disabled || index < 0) return;\n emitChange(selectedValues.filter((_, i) => i !== index));\n focusInput();\n },\n [disabled, emitChange, focusInput, multiple, selectedValues]\n );\n\n const clearValue = useCallback(() => {\n if (disabled || disableClearable) return;\n if (multiple) {\n emitChange([]);\n } else {\n emitChange(null);\n }\n setInputValue('');\n setOpen(false);\n focusInput();\n }, [\n disableClearable,\n disabled,\n emitChange,\n focusInput,\n multiple,\n setInputValue,\n setOpen,\n ]);\n\n const handleInputValueChange = useCallback(\n (nextValue: string) => {\n if (disabled) return;\n if (\n clearValueOnInputClear &&\n !multiple &&\n nextValue.length === 0 &&\n selectedValues.length > 0\n ) {\n emitChange(null);\n }\n setInputValue(nextValue);\n setOpen(true);\n },\n [\n clearValueOnInputClear,\n disabled,\n emitChange,\n multiple,\n selectedValues.length,\n setInputValue,\n setOpen,\n ]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event);\n if (event.defaultPrevented || disabled) return;\n\n if (event.key === 'Backspace' && multiple && inputValue.length === 0) {\n removeAtIndex(selectedValues.length - 1);\n return;\n }\n\n if (\n event.key === 'Enter' &&\n multiple &&\n freeSolo &&\n popupOpen &&\n isActiveOptionSelected(listRef.current, selectedValues, getValue)\n ) {\n event.preventDefault();\n if (showFreeSoloCreateOption) createFreeSoloValue();\n else setInputValue('');\n return;\n }\n\n // When open, cmdk owns Enter so active options and create rows win over free-solo.\n if (event.key === 'ArrowDown' || event.key === 'Enter') {\n if (!open && hasPopupContent) {\n event.preventDefault();\n setOpen(true);\n }\n return;\n }\n\n if (event.key === 'Escape' && open) {\n if (popupOpen) {\n event.preventDefault();\n }\n setOpen(false);\n }\n },\n [\n createFreeSoloValue,\n disabled,\n freeSolo,\n getValue,\n hasPopupContent,\n inputValue.length,\n multiple,\n onKeyDown,\n open,\n popupOpen,\n removeAtIndex,\n selectedValues,\n setInputValue,\n setOpen,\n showFreeSoloCreateOption,\n ]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLDivElement>) => {\n onBlur?.(event);\n const nextTarget = event.relatedTarget as Node | null;\n if (\n !nextTarget ||\n (!event.currentTarget.contains(nextTarget) &&\n !popoverContentRef.current?.contains(nextTarget))\n ) {\n setOpen(false);\n }\n },\n [onBlur, setOpen]\n );\n\n const getTagProps = useCallback(\n ({ index }: { index: number }): TypeaheadTagProps => ({\n key: `${getValue(selectedValues[index])}-${index}`,\n tabIndex: -1,\n 'data-tag-index': index,\n onDelete: () => removeAtIndex(index),\n }),\n [getValue, removeAtIndex, selectedValues]\n );\n\n const hasValue = selectedValues.length > 0;\n const showClearButton =\n !disabled &&\n !disableClearable &&\n (hasValue || (!multiple && inputValue.length > 0));\n const selectedSummary = getTypeaheadSelectedSummary(\n selectedValues,\n getLabel,\n multiple\n );\n const displayInputValue = getTypeaheadDisplayInputValue(\n inputValue,\n selectedValues,\n getLabel,\n multiple,\n displaySelectedValueWhenInputEmpty\n );\n\n const setInputNode = useCallback((node: HTMLInputElement | null) => {\n internalInputRef.current = node;\n }, []);\n\n useTypeaheadDomSync({\n autoComplete,\n commandLabel,\n inputAriaLabel,\n inputRef: internalInputRef,\n inputValue,\n isError,\n listId,\n listRef,\n multiple,\n open: popupOpen,\n resolvedInputId,\n selectedSummaryId,\n });\n\n return (\n <TypeaheadView\n root={{\n ref,\n props: rest,\n handleBlur,\n dataTestId,\n className,\n }}\n state={{\n size,\n disabled,\n isError,\n multiple,\n open: popupOpen,\n setOpen,\n }}\n ids={{\n commandLabel,\n resolvedInputId,\n listId,\n selectedSummaryId,\n inputAriaLabel,\n }}\n input={{\n value: displayInputValue,\n onValueChange: handleInputValueChange,\n onKeyDown: handleKeyDown,\n placeholder,\n leftDecorator,\n showPlaceholderWithValues,\n autoFocus,\n autoComplete,\n setNode: setInputNode,\n focus: focusInput,\n }}\n selection={{\n selectedValues,\n selectedKeys,\n getTagProps,\n renderTags,\n getLabel,\n getValue,\n showClearButton,\n clearValue,\n forcePopupIcon,\n selectedSummary,\n }}\n list={{\n ref: listRef,\n items: visibleItems,\n emptyText,\n emptyState,\n listFooter,\n hideEmptyList,\n optionIsDisabled,\n selectValue,\n renderOption,\n }}\n createOption={{\n show: showCreateOption,\n inputValue: onCreateNew ? customCreateInputValue : trimmedInputValue,\n label: createNewLabel?.(customCreateInputValue),\n onCreate: onCreateNew ? createCustomValue : createFreeSoloValue,\n }}\n popoverContentRef={popoverContentRef}\n />\n );\n}\n\nexport const Typeahead = forwardRef(TypeaheadInner) as <TOption = string>(\n props: TypeaheadProps<TOption> & { ref?: Ref<HTMLDivElement> }\n) => ReactElement<unknown>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Typeahead.js","names":[],"sources":["../../../src/components/Typeahead/Typeahead.tsx"],"sourcesContent":["import type { FocusEvent, KeyboardEvent, ReactElement, Ref } from 'react';\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport type {\n TypeaheadMultipleValue,\n TypeaheadProps,\n TypeaheadSelectedValue,\n TypeaheadSingleValue,\n TypeaheadTagProps,\n} from './Typeahead.types';\nimport {\n defaultOptionLabel,\n defaultOptionValue,\n getTypeaheadCreateState,\n getTypeaheadDisplayInputValue,\n getTypeaheadListItems,\n getTypeaheadSelectedSummary,\n isActiveOptionSelected,\n isTypeaheadOption,\n} from './Typeahead.utils';\nimport { TypeaheadView } from './TypeaheadView';\nimport { useTypeaheadDomSync } from './useTypeaheadDomSync';\nimport { useTypeaheadUncontrolledInput } from './useTypeaheadUncontrolledInput';\n\nfunction TypeaheadInner<TOption = string>(\n {\n options,\n value,\n onChange,\n placeholder = 'Search...',\n leftDecorator,\n showPlaceholderWithValues = false,\n emptyText = 'No results found.',\n size = 'md',\n disabled = false,\n isError = false,\n freeSolo = false,\n multiple,\n disableClearable = false,\n disableCloseOnSelect = false,\n filterOptions,\n forcePopupIcon = true,\n clearOnBlur,\n clearValueOnInputClear = false,\n displaySelectedValueWhenInputEmpty = false,\n maxVisibleOptions,\n hideEmptyList = false,\n emptyState,\n listFooter,\n onCreateNew,\n createNewLabel,\n inputValue: controlledInputValue,\n onInputChange,\n onOpenChange,\n getOptionLabel,\n getOptionValue,\n getOptionDisabled,\n renderOption,\n renderTags,\n className,\n inputId,\n autoFocus,\n autoComplete,\n onKeyDown,\n onBlur,\n 'aria-label': ariaLabel,\n 'data-testid': dataTestId,\n ...rest\n }: TypeaheadProps<TOption>,\n ref: Ref<HTMLDivElement>\n) {\n const generatedId = useId();\n const resolvedInputId = inputId ?? generatedId;\n const listId = `${resolvedInputId}-listbox`;\n const selectedSummaryId = `${resolvedInputId}-selected-summary`;\n const commandLabel = ariaLabel ?? placeholder;\n const inputAriaLabel = ariaLabel ?? (inputId ? undefined : placeholder);\n const internalInputRef = useRef<HTMLInputElement | null>(null);\n const listRef = useRef<HTMLDivElement | null>(null);\n const popoverContentRef = useRef<HTMLDivElement | null>(null);\n const [open, setOpenState] = useState(false);\n const openRef = useRef(false);\n const [uncontrolledInputValue, setUncontrolledInputValue] = useState('');\n const setOpen = useCallback(\n (nextOpen: boolean) => {\n if ((disabled && nextOpen) || openRef.current === nextOpen) return;\n // Track the change immediately so batched events cannot notify twice.\n openRef.current = nextOpen;\n setOpenState(nextOpen);\n onOpenChange?.(nextOpen);\n },\n [disabled, onOpenChange]\n );\n useEffect(() => {\n if (disabled && open) setOpen(false);\n }, [disabled, open, setOpen]);\n useEffect(() => {\n if (autoFocus)\n requestAnimationFrame(() => internalInputRef.current?.focus());\n }, [autoFocus, disabled]);\n\n const inputValue = controlledInputValue ?? uncontrolledInputValue;\n const getLabel = useCallback(\n (option: TypeaheadSelectedValue<TOption>) =>\n getOptionLabel ? getOptionLabel(option) : defaultOptionLabel(option),\n [getOptionLabel]\n );\n const getValue = useCallback(\n (option: TypeaheadSelectedValue<TOption>) =>\n getOptionValue ? getOptionValue(option) : defaultOptionValue(option),\n [getOptionValue]\n );\n\n const selectedValues = useMemo<TypeaheadMultipleValue<TOption>>(() => {\n if (multiple) {\n return Array.isArray(value) ? value : [];\n }\n return value == null ? [] : [value];\n }, [multiple, value]);\n\n const selectedKeys = useMemo(\n () => new Set(selectedValues.map((selected) => getValue(selected))),\n [getValue, selectedValues]\n );\n\n const setInputValue = useCallback(\n (nextValue: string) => {\n if (controlledInputValue === undefined) {\n setUncontrolledInputValue(nextValue);\n }\n onInputChange?.(nextValue);\n },\n [controlledInputValue, onInputChange]\n );\n\n useTypeaheadUncontrolledInput({\n clearOnBlur,\n controlledInputValue,\n freeSolo,\n getLabel,\n getValue,\n multiple,\n open,\n setUncontrolledInputValue,\n value,\n });\n\n const visibleItems = getTypeaheadListItems({\n options,\n selectedValues,\n inputValue,\n getLabel,\n getValue,\n filterOptions,\n maxVisibleOptions,\n includeSelectedValues: multiple,\n });\n\n const optionIsDisabled = useCallback(\n (item: (typeof visibleItems)[number]) => {\n if (item.source === 'selected') return false;\n const option = item.option as TOption;\n return (\n getOptionDisabled?.(option) ??\n (isTypeaheadOption(option) ? !!option.disabled : false)\n );\n },\n [getOptionDisabled]\n );\n\n const {\n customCreateInputValue,\n showCreateOption,\n showFreeSoloCreateOption,\n trimmedInputValue,\n } = getTypeaheadCreateState(\n inputValue,\n options,\n selectedValues,\n getLabel,\n freeSolo,\n !!onCreateNew\n );\n const hasPopupContent =\n visibleItems.length > 0 ||\n showCreateOption ||\n emptyState != null ||\n listFooter != null ||\n !hideEmptyList;\n const popupOpen = open && hasPopupContent;\n const focusInput = useCallback(() => {\n requestAnimationFrame(() => internalInputRef.current?.focus());\n }, []);\n\n // `onChange` can't be narrowed from the single/multiple props union after destructuring; callers below branch on `multiple` first, so funnel both shapes through one callback.\n const emitChange = useCallback(\n (next: TypeaheadSingleValue<TOption> | TypeaheadMultipleValue<TOption>) =>\n (onChange as (value: typeof next) => void)(next),\n [onChange]\n );\n const selectValue = useCallback(\n (selected: TypeaheadSelectedValue<TOption>) => {\n if (disabled) return;\n if (multiple) {\n const selectedKey = getValue(selected);\n const nextValue = selectedKeys.has(selectedKey)\n ? selectedValues.filter((item) => getValue(item) !== selectedKey)\n : [...selectedValues, selected];\n\n emitChange(nextValue);\n setInputValue('');\n if (disableCloseOnSelect) {\n focusInput();\n } else {\n setOpen(false);\n }\n return;\n }\n\n emitChange(selected);\n setInputValue(\n displaySelectedValueWhenInputEmpty ? '' : getLabel(selected)\n );\n setOpen(false);\n },\n [\n disableCloseOnSelect,\n disabled,\n emitChange,\n focusInput,\n getLabel,\n getValue,\n displaySelectedValueWhenInputEmpty,\n multiple,\n selectedKeys,\n selectedValues,\n setInputValue,\n setOpen,\n ]\n );\n\n const createFreeSoloValue = useCallback(() => {\n if (!showFreeSoloCreateOption) return;\n selectValue(trimmedInputValue);\n }, [selectValue, showFreeSoloCreateOption, trimmedInputValue]);\n\n const createCustomValue = useCallback(() => {\n if (!onCreateNew) return;\n onCreateNew(customCreateInputValue);\n setOpen(false);\n }, [customCreateInputValue, onCreateNew, setOpen]);\n\n const removeAtIndex = useCallback(\n (index: number) => {\n if (!multiple || disabled || index < 0) return;\n emitChange(selectedValues.filter((_, i) => i !== index));\n focusInput();\n },\n [disabled, emitChange, focusInput, multiple, selectedValues]\n );\n\n const clearValue = useCallback(() => {\n if (disabled || disableClearable) return;\n if (multiple) {\n emitChange([]);\n } else {\n emitChange(null);\n }\n setInputValue('');\n setOpen(false);\n focusInput();\n }, [\n disableClearable,\n disabled,\n emitChange,\n focusInput,\n multiple,\n setInputValue,\n setOpen,\n ]);\n\n const handleInputValueChange = useCallback(\n (nextValue: string) => {\n if (disabled) return;\n if (\n clearValueOnInputClear &&\n !multiple &&\n nextValue.length === 0 &&\n selectedValues.length > 0\n ) {\n emitChange(null);\n }\n setInputValue(nextValue);\n setOpen(true);\n },\n [\n clearValueOnInputClear,\n disabled,\n emitChange,\n multiple,\n selectedValues.length,\n setInputValue,\n setOpen,\n ]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event);\n if (event.defaultPrevented || disabled) return;\n\n if (event.key === 'Backspace' && multiple && inputValue.length === 0) {\n removeAtIndex(selectedValues.length - 1);\n return;\n }\n\n if (\n event.key === 'Enter' &&\n multiple &&\n freeSolo &&\n popupOpen &&\n isActiveOptionSelected(listRef.current, selectedValues, getValue)\n ) {\n event.preventDefault();\n if (showFreeSoloCreateOption) createFreeSoloValue();\n else setInputValue('');\n return;\n }\n\n // When open, cmdk owns Enter so active options and create rows win over free-solo.\n if (event.key === 'ArrowDown' || event.key === 'Enter') {\n if (!open && hasPopupContent) {\n event.preventDefault();\n setOpen(true);\n }\n return;\n }\n\n if (event.key === 'Escape' && open) {\n if (popupOpen) {\n event.preventDefault();\n }\n setOpen(false);\n }\n },\n [\n createFreeSoloValue,\n disabled,\n freeSolo,\n getValue,\n hasPopupContent,\n inputValue.length,\n multiple,\n onKeyDown,\n open,\n popupOpen,\n removeAtIndex,\n selectedValues,\n setInputValue,\n setOpen,\n showFreeSoloCreateOption,\n ]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLDivElement>) => {\n onBlur?.(event);\n const nextTarget = event.relatedTarget as Node | null;\n if (\n !nextTarget ||\n (!event.currentTarget.contains(nextTarget) &&\n !popoverContentRef.current?.contains(nextTarget))\n ) {\n setOpen(false);\n }\n },\n [onBlur, setOpen]\n );\n\n const getTagProps = useCallback(\n ({ index }: { index: number }): TypeaheadTagProps => ({\n key: `${getValue(selectedValues[index])}-${index}`,\n tabIndex: -1,\n 'data-tag-index': index,\n onDelete: () => removeAtIndex(index),\n }),\n [getValue, removeAtIndex, selectedValues]\n );\n\n const showClearButton =\n !disabled &&\n !disableClearable &&\n (selectedValues.length > 0 || (!multiple && inputValue.length > 0));\n const selectedSummary = getTypeaheadSelectedSummary(\n selectedValues,\n getLabel,\n multiple\n );\n const displayInputValue = getTypeaheadDisplayInputValue(\n inputValue,\n selectedValues,\n getLabel,\n multiple,\n displaySelectedValueWhenInputEmpty\n );\n\n const setInputNode = useCallback((node: HTMLInputElement | null) => {\n internalInputRef.current = node;\n }, []);\n\n const setListNode = useTypeaheadDomSync({\n autoComplete,\n commandLabel,\n inputAriaLabel,\n inputRef: internalInputRef,\n inputValue,\n isError,\n listId,\n listRef,\n multiple,\n open: popupOpen,\n resolvedInputId,\n selectedSummaryId,\n });\n\n return (\n <TypeaheadView\n root={{\n ref,\n props: rest,\n handleBlur,\n dataTestId,\n className,\n }}\n state={{\n size,\n disabled,\n isError,\n multiple,\n open: popupOpen,\n setOpen,\n }}\n ids={{\n commandLabel,\n resolvedInputId,\n listId,\n selectedSummaryId,\n inputAriaLabel,\n }}\n input={{\n value: displayInputValue,\n onValueChange: handleInputValueChange,\n onKeyDown: handleKeyDown,\n placeholder,\n leftDecorator,\n showPlaceholderWithValues,\n autoFocus,\n autoComplete,\n setNode: setInputNode,\n focus: focusInput,\n }}\n selection={{\n selectedValues,\n selectedKeys,\n getTagProps,\n renderTags,\n getLabel,\n getValue,\n showClearButton,\n clearValue,\n forcePopupIcon,\n selectedSummary,\n }}\n list={{\n ref: setListNode,\n items: visibleItems,\n emptyText,\n emptyState,\n listFooter,\n hideEmptyList,\n optionIsDisabled,\n selectValue,\n renderOption,\n }}\n createOption={{\n show: showCreateOption,\n inputValue: onCreateNew ? customCreateInputValue : trimmedInputValue,\n label: createNewLabel?.(customCreateInputValue),\n onCreate: onCreateNew ? createCustomValue : createFreeSoloValue,\n }}\n popoverContentRef={popoverContentRef}\n />\n );\n}\n\nexport const Typeahead = forwardRef(TypeaheadInner) as <TOption = string>(\n props: TypeaheadProps<TOption> & { ref?: Ref<HTMLDivElement> }\n) => ReactElement<unknown>;\n"],"mappings":"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"}
@@ -60,6 +60,8 @@ interface TypeaheadBaseProps<TOption> extends Omit<HTMLAttributes<HTMLDivElement
60
60
  onCreateNew?: (inputValue: string) => void;
61
61
  createNewLabel?: (inputValue: string) => ReactNode;
62
62
  inputValue?: string;
63
+ /** Called once when the options popup opens or closes. */
64
+ onOpenChange?: (open: boolean) => void;
63
65
  onInputChange?: (value: string) => void;
64
66
  getOptionLabel?: (option: TypeaheadSelectedValue<TOption>) => string;
65
67
  getOptionValue?: (option: TypeaheadSelectedValue<TOption>) => string;
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
+ import type { OptionRowSize } from '../../utils/componentSizes.js';
2
3
  import type { TypeaheadRenderOptionState, TypeaheadSelectedValue, TypeaheadSize } from './Typeahead.types.js';
3
4
  export declare function TypeaheadClearButton({ label, onClick, size, }: {
4
5
  label: string;
@@ -14,10 +15,11 @@ export declare function TypeaheadDefaultTag<TOption>({ selected, index, disabled
14
15
  getValue: (option: TypeaheadSelectedValue<TOption>) => string;
15
16
  onRemove: () => void;
16
17
  }): import("react").JSX.Element;
17
- export declare function TypeaheadDefaultOption<TOption>({ option, state, getLabel, }: {
18
+ export declare function TypeaheadDefaultOption<TOption>({ option, state, getLabel, size, }: {
18
19
  option: TypeaheadSelectedValue<TOption>;
19
20
  state: TypeaheadRenderOptionState;
20
21
  getLabel: (option: TypeaheadSelectedValue<TOption>) => string;
22
+ size: OptionRowSize;
21
23
  }): import("react").JSX.Element;
22
24
  export declare function TypeaheadCreateOption({ inputValue, label, }: {
23
25
  inputValue: string;
@@ -1,9 +1,9 @@
1
1
  import { cn } from "../../utils/cn.js";
2
2
  import { Text } from "../Text/Text.js";
3
3
  import { Badge } from "../Badge/Badge.js";
4
- import { CheckIcon, PlusIcon, XIcon } from "../../icons/PaddedPhosphorIcons.js";
5
4
  import { Icon } from "../Icon/Icon.js";
6
5
  import { IconButton } from "../IconButton/IconButton.js";
6
+ import { CheckIcon, PlusIcon, XIcon } from "../../icons/PaddedPhosphorIcons.js";
7
7
  import { CONTROL_ICON_SIZES } from "../../utils/controlIconSizes.js";
8
8
  import { isTypeaheadOption } from "./Typeahead.utils.js";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -52,7 +52,7 @@ function TypeaheadDefaultTag({ selected, index, disabled, size, getLabel, getVal
52
52
  children: label
53
53
  }, `${getValue(selected)}-${index}`);
54
54
  }
55
- function TypeaheadDefaultOption({ option, state, getLabel }) {
55
+ function TypeaheadDefaultOption({ option, state, getLabel, size }) {
56
56
  const label = getLabel(option);
57
57
  const description = isTypeaheadOption(option) ? option.description : void 0;
58
58
  const rightDecorator = isTypeaheadOption(option) ? option.rightDecorator : void 0;
@@ -65,7 +65,8 @@ function TypeaheadDefaultOption({ option, state, getLabel }) {
65
65
  }),
66
66
  /* @__PURE__ */ jsx(OptionText, {
67
67
  label,
68
- description
68
+ description,
69
+ size
69
70
  }),
70
71
  rightDecorator && /* @__PURE__ */ jsx("div", {
71
72
  className: "ml-auto shrink-0",
@@ -73,13 +74,13 @@ function TypeaheadDefaultOption({ option, state, getLabel }) {
73
74
  })
74
75
  ] });
75
76
  }
76
- function OptionText({ label, description }) {
77
+ function OptionText({ label, description, size }) {
77
78
  return /* @__PURE__ */ jsxs("div", {
78
79
  className: "flex min-w-0 flex-1 flex-col",
79
80
  children: [/* @__PURE__ */ jsx(Text, {
80
81
  as: "span",
81
- variant: "sm",
82
- className: "truncate text-primary",
82
+ variant: size,
83
+ className: cn("truncate tracking-normal text-primary", size === "sm" ? "leading-4" : "leading-5"),
83
84
  children: label
84
85
  }), description && /* @__PURE__ */ jsx(Text, {
85
86
  as: "span",
@@ -1 +1 @@
1
- {"version":3,"file":"TypeaheadParts.js","names":[],"sources":["../../../src/components/Typeahead/TypeaheadParts.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { CheckIcon, PlusIcon, XIcon } from '../../icons/PaddedPhosphorIcons';\nimport { cn } from '../../utils/cn';\nimport { CONTROL_ICON_SIZES } from '../../utils/controlIconSizes';\nimport { Badge } from '../Badge';\nimport { Icon } from '../Icon';\nimport { IconButton } from '../IconButton';\nimport { Text } from '../Text';\nimport type {\n TypeaheadRenderOptionState,\n TypeaheadSelectedValue,\n TypeaheadSize,\n} from './Typeahead.types';\nimport { isTypeaheadOption } from './Typeahead.utils';\n\nexport function TypeaheadClearButton({\n label,\n onClick,\n size,\n}: {\n label: string;\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;\n size: TypeaheadSize;\n}) {\n // Let the click target extend vertically without making tag rows taller.\n return (\n <IconButton\n type=\"button\"\n icon={XIcon}\n iconWeight=\"regular\"\n label={label}\n variant=\"plain\"\n color=\"secondary\"\n size={CONTROL_ICON_SIZES[size].buttonSize}\n tooltipProps={{ title: null }}\n className=\"bg-transparent text-icon-tertiary shadow-none hover:bg-elevated-hover hover:text-icon-primary\"\n style={{ marginBlock: CONTROL_ICON_SIZES[size].actionOffset }}\n onMouseDown={(event) => event.preventDefault()}\n onClick={onClick}\n />\n );\n}\n\nexport function TypeaheadDefaultTag<TOption>({\n selected,\n index,\n disabled,\n size,\n getLabel,\n getValue,\n onRemove,\n}: {\n selected: TypeaheadSelectedValue<TOption>;\n index: number;\n disabled: boolean;\n size: TypeaheadSize;\n getLabel: (option: TypeaheadSelectedValue<TOption>) => string;\n getValue: (option: TypeaheadSelectedValue<TOption>) => string;\n onRemove: () => void;\n}) {\n const label = getLabel(selected);\n\n return (\n <Badge\n key={`${getValue(selected)}-${index}`}\n color=\"plain\"\n rounded=\"xs\"\n size={size === 'xs' || size === 'sm' ? 'xs' : 'sm'}\n textWeight=\"normal\"\n rightDecorator={!disabled ? XIcon : undefined}\n iconWeight=\"regular\"\n aria-label={!disabled ? `Remove ${label}` : undefined}\n role={!disabled ? 'button' : undefined}\n tabIndex={!disabled ? 0 : undefined}\n onMouseDown={(event) => event.preventDefault()}\n onKeyDown={(event) => {\n if (!disabled && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n event.stopPropagation();\n onRemove();\n }\n }}\n onClick={\n !disabled\n ? (event) => {\n event.stopPropagation();\n onRemove();\n }\n : undefined\n }\n className={cn(\n 'min-w-0 max-w-full justify-start border-default bg-surface-level-2 px-space-1 text-primary [&>span]:min-w-0 [&>span]:truncate [&>span]:text-xxs',\n size === 'xs' && 'border-0 py-0',\n !disabled &&\n 'cursor-pointer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--border-focus)]',\n disabled && 'cursor-not-allowed'\n )}\n >\n {label}\n </Badge>\n );\n}\n\nexport function TypeaheadDefaultOption<TOption>({\n option,\n state,\n getLabel,\n}: {\n option: TypeaheadSelectedValue<TOption>;\n state: TypeaheadRenderOptionState;\n getLabel: (option: TypeaheadSelectedValue<TOption>) => string;\n}) {\n const label = getLabel(option);\n const description = isTypeaheadOption(option)\n ? option.description\n : undefined;\n const rightDecorator = isTypeaheadOption(option)\n ? option.rightDecorator\n : undefined;\n\n return (\n <>\n <Icon\n aria-hidden=\"true\"\n icon={CheckIcon}\n size=\"md\"\n className={cn(\n 'shrink-0 text-icon-primary',\n state.selected ? 'opacity-100' : 'opacity-0'\n )}\n />\n <OptionText label={label} description={description} />\n {rightDecorator && (\n <div className=\"ml-auto shrink-0\">{rightDecorator}</div>\n )}\n </>\n );\n}\n\nfunction OptionText({\n label,\n description,\n}: {\n label: string;\n description: ReactNode;\n}) {\n return (\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <Text as=\"span\" variant=\"sm\" className=\"truncate text-primary\">\n {label}\n </Text>\n {description && (\n <Text as=\"span\" variant=\"xs\" className=\"truncate text-tertiary\">\n {description}\n </Text>\n )}\n </div>\n );\n}\n\nexport function TypeaheadCreateOption({\n inputValue,\n label,\n}: {\n inputValue: string;\n label?: ReactNode;\n}) {\n if (label != null) {\n return label;\n }\n\n return (\n <>\n <span\n aria-hidden\n className=\"inline-flex size-4 shrink-0 text-icon-secondary\"\n >\n <PlusIcon size=\"100%\" weight=\"regular\" />\n </span>\n <span className=\"min-w-0 truncate\">{inputValue || 'Add new'}</span>\n </>\n );\n}\n"],"mappings":";;;;;;;;;;AAgBA,SAAgB,qBAAqB,EACnC,OACA,SACA,QAKC;CAED,OACE,oBAAC,YAAD;EACE,MAAK;EACL,MAAM;EACN,YAAW;EACJ;EACP,SAAQ;EACR,OAAM;EACN,MAAM,mBAAmB,KAAK,CAAC;EAC/B,cAAc,EAAE,OAAO,KAAK;EAC5B,WAAU;EACV,OAAO,EAAE,aAAa,mBAAmB,KAAK,CAAC,aAAa;EAC5D,cAAc,UAAU,MAAM,eAAe;EACpC;CACV,CAAA;AAEL;AAEA,SAAgB,oBAA6B,EAC3C,UACA,OACA,UACA,MACA,UACA,UACA,YASC;CACD,MAAM,QAAQ,SAAS,QAAQ;CAE/B,OACE,oBAAC,OAAD;EAEE,OAAM;EACN,SAAQ;EACR,MAAM,SAAS,QAAQ,SAAS,OAAO,OAAO;EAC9C,YAAW;EACX,gBAAgB,CAAC,WAAW,QAAQ,KAAA;EACpC,YAAW;EACX,cAAY,CAAC,WAAW,UAAU,UAAU,KAAA;EAC5C,MAAM,CAAC,WAAW,WAAW,KAAA;EAC7B,UAAU,CAAC,WAAW,IAAI,KAAA;EAC1B,cAAc,UAAU,MAAM,eAAe;EAC7C,YAAY,UAAU;GACpB,IAAI,CAAC,aAAa,MAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM;IAC7D,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,SAAS;GACX;EACF;EACA,SACE,CAAC,YACI,UAAU;GACT,MAAM,gBAAgB;GACtB,SAAS;EACX,IACA,KAAA;EAEN,WAAW,GACT,mJACA,SAAS,QAAQ,iBACjB,CAAC,YACC,2IACF,YAAY,oBACd;EAEC,UAAA;CACI,GAnCA,GAAG,SAAS,QAAQ,EAAE,GAAG,OAmCzB;AAEX;AAEA,SAAgB,uBAAgC,EAC9C,QACA,OACA,YAKC;CACD,MAAM,QAAQ,SAAS,MAAM;CAC7B,MAAM,cAAc,kBAAkB,MAAM,IACxC,OAAO,cACP,KAAA;CACJ,MAAM,iBAAiB,kBAAkB,MAAM,IAC3C,OAAO,iBACP,KAAA;CAEJ,OACE,qBAAA,UAAA,EAAA,UAAA;EACE,oBAAC,MAAD;GACE,eAAY;GACZ,MAAM;GACN,MAAK;GACL,WAAW,GACT,8BACA,MAAM,WAAW,gBAAgB,WACnC;EACD,CAAA;EACD,oBAAC,YAAD;GAAmB;GAAoB;EAAc,CAAA;EACpD,kBACC,oBAAC,OAAD;GAAK,WAAU;GAAoB,UAAA;EAAoB,CAAA;CAEzD,EAAA,CAAA;AAEN;AAEA,SAAS,WAAW,EAClB,OACA,eAIC;CACD,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,oBAAC,MAAD;GAAM,IAAG;GAAO,SAAQ;GAAK,WAAU;GACpC,UAAA;EACG,CAAA,GACL,eACC,oBAAC,MAAD;GAAM,IAAG;GAAO,SAAQ;GAAK,WAAU;GACpC,UAAA;EACG,CAAA,CAEL;;AAET;AAEA,SAAgB,sBAAsB,EACpC,YACA,SAIC;CACD,IAAI,SAAS,MACX,OAAO;CAGT,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EACE,eAAA;EACA,WAAU;EAEV,UAAA,oBAAC,UAAD;GAAU,MAAK;GAAO,QAAO;EAAW,CAAA;CACpC,CAAA,GACN,oBAAC,QAAD;EAAM,WAAU;EAAoB,UAAA,cAAc;CAAgB,CAAA,CAClE,EAAA,CAAA;AAEN"}
1
+ {"version":3,"file":"TypeaheadParts.js","names":[],"sources":["../../../src/components/Typeahead/TypeaheadParts.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { CheckIcon, PlusIcon, XIcon } from '../../icons/PaddedPhosphorIcons';\nimport { cn } from '../../utils/cn';\nimport type { OptionRowSize } from '../../utils/componentSizes';\nimport { CONTROL_ICON_SIZES } from '../../utils/controlIconSizes';\nimport { Badge } from '../Badge';\nimport { Icon } from '../Icon';\nimport { IconButton } from '../IconButton';\nimport { Text } from '../Text';\nimport type {\n TypeaheadRenderOptionState,\n TypeaheadSelectedValue,\n TypeaheadSize,\n} from './Typeahead.types';\nimport { isTypeaheadOption } from './Typeahead.utils';\n\nexport function TypeaheadClearButton({\n label,\n onClick,\n size,\n}: {\n label: string;\n onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;\n size: TypeaheadSize;\n}) {\n // Let the click target extend vertically without making tag rows taller.\n return (\n <IconButton\n type=\"button\"\n icon={XIcon}\n iconWeight=\"regular\"\n label={label}\n variant=\"plain\"\n color=\"secondary\"\n size={CONTROL_ICON_SIZES[size].buttonSize}\n tooltipProps={{ title: null }}\n className=\"bg-transparent text-icon-tertiary shadow-none hover:bg-elevated-hover hover:text-icon-primary\"\n style={{ marginBlock: CONTROL_ICON_SIZES[size].actionOffset }}\n onMouseDown={(event) => event.preventDefault()}\n onClick={onClick}\n />\n );\n}\n\nexport function TypeaheadDefaultTag<TOption>({\n selected,\n index,\n disabled,\n size,\n getLabel,\n getValue,\n onRemove,\n}: {\n selected: TypeaheadSelectedValue<TOption>;\n index: number;\n disabled: boolean;\n size: TypeaheadSize;\n getLabel: (option: TypeaheadSelectedValue<TOption>) => string;\n getValue: (option: TypeaheadSelectedValue<TOption>) => string;\n onRemove: () => void;\n}) {\n const label = getLabel(selected);\n\n return (\n <Badge\n key={`${getValue(selected)}-${index}`}\n color=\"plain\"\n rounded=\"xs\"\n size={size === 'xs' || size === 'sm' ? 'xs' : 'sm'}\n textWeight=\"normal\"\n rightDecorator={!disabled ? XIcon : undefined}\n iconWeight=\"regular\"\n aria-label={!disabled ? `Remove ${label}` : undefined}\n role={!disabled ? 'button' : undefined}\n tabIndex={!disabled ? 0 : undefined}\n onMouseDown={(event) => event.preventDefault()}\n onKeyDown={(event) => {\n if (!disabled && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n event.stopPropagation();\n onRemove();\n }\n }}\n onClick={\n !disabled\n ? (event) => {\n event.stopPropagation();\n onRemove();\n }\n : undefined\n }\n className={cn(\n 'min-w-0 max-w-full justify-start border-default bg-surface-level-2 px-space-1 text-primary [&>span]:min-w-0 [&>span]:truncate [&>span]:text-xxs',\n size === 'xs' && 'border-0 py-0',\n !disabled &&\n 'cursor-pointer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--border-focus)]',\n disabled && 'cursor-not-allowed'\n )}\n >\n {label}\n </Badge>\n );\n}\n\nexport function TypeaheadDefaultOption<TOption>({\n option,\n state,\n getLabel,\n size,\n}: {\n option: TypeaheadSelectedValue<TOption>;\n state: TypeaheadRenderOptionState;\n getLabel: (option: TypeaheadSelectedValue<TOption>) => string;\n size: OptionRowSize;\n}) {\n const label = getLabel(option);\n const description = isTypeaheadOption(option)\n ? option.description\n : undefined;\n const rightDecorator = isTypeaheadOption(option)\n ? option.rightDecorator\n : undefined;\n\n return (\n <>\n <Icon\n aria-hidden=\"true\"\n icon={CheckIcon}\n size=\"md\"\n className={cn(\n 'shrink-0 text-icon-primary',\n state.selected ? 'opacity-100' : 'opacity-0'\n )}\n />\n <OptionText label={label} description={description} size={size} />\n {rightDecorator && (\n <div className=\"ml-auto shrink-0\">{rightDecorator}</div>\n )}\n </>\n );\n}\n\nfunction OptionText({\n label,\n description,\n size,\n}: {\n label: string;\n description: ReactNode;\n size: OptionRowSize;\n}) {\n return (\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <Text\n as=\"span\"\n variant={size}\n className={cn(\n 'truncate tracking-normal text-primary',\n size === 'sm' ? 'leading-4' : 'leading-5'\n )}\n >\n {label}\n </Text>\n {description && (\n <Text as=\"span\" variant=\"xs\" className=\"truncate text-tertiary\">\n {description}\n </Text>\n )}\n </div>\n );\n}\n\nexport function TypeaheadCreateOption({\n inputValue,\n label,\n}: {\n inputValue: string;\n label?: ReactNode;\n}) {\n if (label != null) {\n return label;\n }\n\n return (\n <>\n <span\n aria-hidden\n className=\"inline-flex size-4 shrink-0 text-icon-secondary\"\n >\n <PlusIcon size=\"100%\" weight=\"regular\" />\n </span>\n <span className=\"min-w-0 truncate\">{inputValue || 'Add new'}</span>\n </>\n );\n}\n"],"mappings":";;;;;;;;;;AAiBA,SAAgB,qBAAqB,EACnC,OACA,SACA,QAKC;CAED,OACE,oBAAC,YAAD;EACE,MAAK;EACL,MAAM;EACN,YAAW;EACJ;EACP,SAAQ;EACR,OAAM;EACN,MAAM,mBAAmB,KAAK,CAAC;EAC/B,cAAc,EAAE,OAAO,KAAK;EAC5B,WAAU;EACV,OAAO,EAAE,aAAa,mBAAmB,KAAK,CAAC,aAAa;EAC5D,cAAc,UAAU,MAAM,eAAe;EACpC;CACV,CAAA;AAEL;AAEA,SAAgB,oBAA6B,EAC3C,UACA,OACA,UACA,MACA,UACA,UACA,YASC;CACD,MAAM,QAAQ,SAAS,QAAQ;CAE/B,OACE,oBAAC,OAAD;EAEE,OAAM;EACN,SAAQ;EACR,MAAM,SAAS,QAAQ,SAAS,OAAO,OAAO;EAC9C,YAAW;EACX,gBAAgB,CAAC,WAAW,QAAQ,KAAA;EACpC,YAAW;EACX,cAAY,CAAC,WAAW,UAAU,UAAU,KAAA;EAC5C,MAAM,CAAC,WAAW,WAAW,KAAA;EAC7B,UAAU,CAAC,WAAW,IAAI,KAAA;EAC1B,cAAc,UAAU,MAAM,eAAe;EAC7C,YAAY,UAAU;GACpB,IAAI,CAAC,aAAa,MAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM;IAC7D,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,SAAS;GACX;EACF;EACA,SACE,CAAC,YACI,UAAU;GACT,MAAM,gBAAgB;GACtB,SAAS;EACX,IACA,KAAA;EAEN,WAAW,GACT,mJACA,SAAS,QAAQ,iBACjB,CAAC,YACC,2IACF,YAAY,oBACd;EAEC,UAAA;CACI,GAnCA,GAAG,SAAS,QAAQ,EAAE,GAAG,OAmCzB;AAEX;AAEA,SAAgB,uBAAgC,EAC9C,QACA,OACA,UACA,QAMC;CACD,MAAM,QAAQ,SAAS,MAAM;CAC7B,MAAM,cAAc,kBAAkB,MAAM,IACxC,OAAO,cACP,KAAA;CACJ,MAAM,iBAAiB,kBAAkB,MAAM,IAC3C,OAAO,iBACP,KAAA;CAEJ,OACE,qBAAA,UAAA,EAAA,UAAA;EACE,oBAAC,MAAD;GACE,eAAY;GACZ,MAAM;GACN,MAAK;GACL,WAAW,GACT,8BACA,MAAM,WAAW,gBAAgB,WACnC;EACD,CAAA;EACD,oBAAC,YAAD;GAAmB;GAAoB;GAAmB;EAAO,CAAA;EAChE,kBACC,oBAAC,OAAD;GAAK,WAAU;GAAoB,UAAA;EAAoB,CAAA;CAEzD,EAAA,CAAA;AAEN;AAEA,SAAS,WAAW,EAClB,OACA,aACA,QAKC;CACD,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,oBAAC,MAAD;GACE,IAAG;GACH,SAAS;GACT,WAAW,GACT,yCACA,SAAS,OAAO,cAAc,WAChC;GAEC,UAAA;EACG,CAAA,GACL,eACC,oBAAC,MAAD;GAAM,IAAG;GAAO,SAAQ;GAAK,WAAU;GACpC,UAAA;EACG,CAAA,CAEL;;AAET;AAEA,SAAgB,sBAAsB,EACpC,YACA,SAIC;CACD,IAAI,SAAS,MACX,OAAO;CAGT,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EACE,eAAA;EACA,WAAU;EAEV,UAAA,oBAAC,UAAD;GAAU,MAAK;GAAO,QAAO;EAAW,CAAA;CACpC,CAAA,GACN,oBAAC,QAAD;EAAM,WAAU;EAAoB,UAAA,cAAc;CAAgB,CAAA,CAClE,EAAA,CAAA;AAEN"}
@@ -1,11 +1,11 @@
1
1
  import { cn } from "../../utils/cn.js";
2
2
  import { CONTROL_SIZES } from "../../utils/componentSizes.js";
3
3
  import { Text } from "../Text/Text.js";
4
- import { CaretDownIcon } from "../../icons/PaddedPhosphorIcons.js";
5
4
  import { Icon } from "../Icon/Icon.js";
5
+ import { CaretDownIcon } from "../../icons/PaddedPhosphorIcons.js";
6
6
  import { Popover, PopoverAnchor, PopoverContent } from "../Popover/Popover.js";
7
- import { Command as Command$1, CommandEmpty, CommandItem, CommandList } from "../Command/Command.js";
8
7
  import { CONTROL_ICON_SIZES } from "../../utils/controlIconSizes.js";
8
+ import { Command as Command$1, CommandEmpty, CommandItem, CommandList } from "../Command/Command.js";
9
9
  import { isTypeaheadOption } from "./Typeahead.utils.js";
10
10
  import { TypeaheadClearButton, TypeaheadCreateOption, TypeaheadDefaultOption, TypeaheadDefaultTag } from "./TypeaheadParts.js";
11
11
  import { useRef } from "react";
@@ -36,6 +36,11 @@ function TypeaheadView({ root, state, ids, input, selection, list, createOption,
36
36
  const preventInputDismiss = (event) => {
37
37
  if (open && event.target instanceof HTMLInputElement && event.target.getAttribute("role") === "combobox" && controlRef.current?.contains(event.target)) event.preventDefault();
38
38
  };
39
+ const handleEscapeKeyDown = (event) => {
40
+ if (!open) return;
41
+ event.preventDefault();
42
+ setOpen(false);
43
+ };
39
44
  const { ref: rootRef, handleBlur, dataTestId, className } = root;
40
45
  const { size, disabled, isError, multiple, open, setOpen } = state;
41
46
  const { commandLabel, resolvedInputId, listId, selectedSummaryId, inputAriaLabel } = ids;
@@ -43,11 +48,10 @@ function TypeaheadView({ root, state, ids, input, selection, list, createOption,
43
48
  const { selectedValues, selectedKeys, getTagProps, renderTags, getLabel, getValue, showClearButton, clearValue, forcePopupIcon, selectedSummary } = selection;
44
49
  const { ref: listRef, items, emptyText, emptyState, listFooter, hideEmptyList, optionIsDisabled, selectValue, renderOption } = list;
45
50
  const hasValue = selectedValues.length > 0;
46
- const visibleItems = open ? items : [];
47
- const visibleShowCreateOption = open && createOption.show;
48
- const showEmptyState = open && visibleItems.length === 0 && !visibleShowCreateOption && (emptyState != null || !hideEmptyList);
51
+ const showEmptyState = items.length === 0 && !createOption.show && (emptyState != null || !hideEmptyList);
49
52
  const controlHeightClass = multiple ? CONTROL_SIZES[size].minHeightClassName : CONTROL_SIZES[size].heightClassName;
50
53
  const controlPaddingClass = size === "xs" || size === "sm" ? "px-space-2" : "px-space-3";
54
+ const itemRowSize = size === "xs" || size === "sm" ? "sm" : "md";
51
55
  const renderedTags = multiple && (renderTags ? renderTags(selectedValues, getTagProps) : selectedValues.map((selected, index) => {
52
56
  const tagProps = getTagProps({ index });
53
57
  return /* @__PURE__ */ jsx(TypeaheadDefaultTag, {
@@ -157,11 +161,10 @@ function TypeaheadView({ root, state, ids, input, selection, list, createOption,
157
161
  }),
158
162
  /* @__PURE__ */ jsx(PopoverContent, {
159
163
  ref: popoverContentRef,
160
- hidden: !open,
161
- className: cn("w-[var(--radix-popover-trigger-width)] min-w-48 max-w-[calc(100vw-1rem)] bg-elevated p-space-1 text-primary", !open && "hidden"),
164
+ className: "w-[var(--radix-popover-trigger-width)] min-w-48 max-w-[calc(100vw-1rem)] bg-elevated p-space-1 text-primary",
162
165
  align: "start",
163
166
  sideOffset: 4,
164
- forceMount: true,
167
+ onEscapeKeyDown: handleEscapeKeyDown,
165
168
  onOpenAutoFocus: (event) => event.preventDefault(),
166
169
  onCloseAutoFocus: (event) => event.preventDefault(),
167
170
  onFocusOutside: preventInputDismiss,
@@ -178,7 +181,7 @@ function TypeaheadView({ root, state, ids, input, selection, list, createOption,
178
181
  color: "secondary",
179
182
  children: emptyText
180
183
  }) }),
181
- visibleItems.map((item) => {
184
+ items.map((item) => {
182
185
  const { option } = item;
183
186
  const optionKey = getValue(option);
184
187
  const optionLabel = getLabel(option);
@@ -195,20 +198,23 @@ function TypeaheadView({ root, state, ids, input, selection, list, createOption,
195
198
  keywords: isTypeaheadOption(option) ? [optionLabel, ...option.keywords ?? []] : [optionLabel],
196
199
  onSelect: () => selectValue(option),
197
200
  "aria-checked": multiple ? selected : void 0,
198
- className: cn("flex items-center gap-space-2 rounded-sm px-space-2 py-space-2 text-sm text-primary hover:bg-surface-level-2 aria-selected:bg-surface-level-2", optionDisabled && "text-disabled"),
201
+ size: itemRowSize,
202
+ className: cn("flex items-center gap-space-2 text-primary hover:bg-surface-level-2 aria-selected:bg-surface-level-2", optionDisabled && "text-disabled"),
199
203
  children: renderOption && item.source === "option" ? renderOption(option, optionState) : /* @__PURE__ */ jsx(TypeaheadDefaultOption, {
200
204
  option,
201
205
  state: optionState,
202
- getLabel
206
+ getLabel,
207
+ size: itemRowSize
203
208
  })
204
209
  }, optionKey);
205
210
  }),
206
- visibleShowCreateOption && /* @__PURE__ */ jsx(CommandItem, {
211
+ createOption.show && /* @__PURE__ */ jsx(CommandItem, {
207
212
  value: `__typeahead_create__${createOption.inputValue}`,
208
213
  keywords: [createOption.inputValue],
209
214
  onSelect: createOption.onCreate,
215
+ size: itemRowSize,
210
216
  "aria-label": createOption.inputValue ? `Add ${createOption.inputValue}` : "Add new",
211
- className: "flex items-center gap-space-2 rounded-sm p-space-2 text-sm text-primary hover:bg-surface-level-2 aria-selected:bg-surface-level-2",
217
+ className: "flex items-center gap-space-2 text-primary hover:bg-surface-level-2 aria-selected:bg-surface-level-2",
212
218
  children: /* @__PURE__ */ jsx(TypeaheadCreateOption, {
213
219
  inputValue: createOption.inputValue,
214
220
  label: createOption.label