@langchain/macaw-components 1.0.0-beta.0 → 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.
- package/dist/_chunks/{LoadingIndicator-DgtU9aqD.js → LoadingIndicator-CDcArsiM.js} +13 -12
- package/dist/_chunks/LoadingIndicator-CDcArsiM.js.map +1 -0
- package/dist/_chunks/render-attachment-icon-BWBEMxXZ.js +270 -0
- package/dist/_chunks/render-attachment-icon-BWBEMxXZ.js.map +1 -0
- package/dist/catalog.json +527 -408
- package/dist/components/Attachment/Attachment.d.ts +21 -0
- package/dist/components/Attachment/Attachment.js +165 -0
- package/dist/components/Attachment/Attachment.js.map +1 -0
- package/dist/components/Attachment/AttachmentList.d.ts +5 -0
- package/dist/components/Attachment/AttachmentList.js +32 -0
- package/dist/components/Attachment/AttachmentList.js.map +1 -0
- package/dist/components/Attachment/index.d.ts +4 -0
- package/dist/components/Attachment/index.js +3 -0
- package/dist/components/Attachment/render-attachment-icon.d.ts +3 -0
- package/dist/components/Attachment/render-attachment-icon.js +2 -0
- package/dist/components/Avatar/Avatar.js +2 -2
- package/dist/components/Badge/Badge.d.ts +2 -0
- package/dist/components/Badge/Badge.js +12 -1
- package/dist/components/Badge/Badge.js.map +1 -1
- package/dist/components/Banner/Banner.js +1 -1
- package/dist/components/Button/Button.js +1 -1
- package/dist/components/Button/constants.js +2 -2
- package/dist/components/Button/constants.js.map +1 -1
- package/dist/components/ChartCard/ChartCard.d.ts +1 -4
- package/dist/components/ChartCard/ChartCard.js +2 -2
- package/dist/components/ChartCard/ChartCard.js.map +1 -1
- package/dist/components/ChartCard/ChartCardSkeleton.d.ts +1 -1
- package/dist/components/ChartCard/ChartCardSkeleton.js +37 -0
- package/dist/components/ChartCard/ChartCardSkeleton.js.map +1 -1
- package/dist/components/ChartLegend/ChartLegend.js +2 -2
- package/dist/components/ChartLegend/ChartLegendItemRenderer.js +2 -2
- package/dist/components/ChartLegend/ChartLegendItemRenderer.js.map +1 -1
- package/dist/components/Code/Code.utils.d.ts +3 -2
- package/dist/components/Code/Code.utils.js +7 -3
- package/dist/components/Code/Code.utils.js.map +1 -1
- package/dist/components/Code/CodeLanguageSelect.d.ts +7 -0
- package/dist/components/Code/CodeLanguageSelect.js +29 -0
- package/dist/components/Code/CodeLanguageSelect.js.map +1 -0
- package/dist/components/Code/CodeLite.js +3 -0
- package/dist/components/Code/CodeLite.js.map +1 -1
- package/dist/components/Code/CodeToolbar.d.ts +7 -0
- package/dist/components/Code/CodeToolbar.js +19 -0
- package/dist/components/Code/CodeToolbar.js.map +1 -0
- package/dist/components/Code/codeLanguages.d.ts +7 -0
- package/dist/components/Code/codeLanguages.js +59 -0
- package/dist/components/Code/codeLanguages.js.map +1 -0
- package/dist/components/Code/index.d.ts +15 -2
- package/dist/components/Code/index.js +70 -50
- package/dist/components/Code/index.js.map +1 -1
- package/dist/components/Code/types.d.ts +1 -1
- package/dist/components/Command/Command.d.ts +10 -13
- package/dist/components/Command/Command.js +7 -2
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/components/Command/CommandMenu.d.ts +7 -1
- package/dist/components/Command/CommandMenu.js +17 -9
- package/dist/components/Command/CommandMenu.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.d.ts +6 -0
- package/dist/components/ContextMenu/ContextMenu.js +3 -2
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/components/CopyButton/CopyButton.js +2 -2
- package/dist/components/Dialog/index.js +2 -2
- package/dist/components/DropdownMenu/DropdownMenu.d.ts +11 -0
- package/dist/components/DropdownMenu/DropdownMenu.js +5 -4
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/ErrorMessage/ErrorMessage.js +1 -1
- package/dist/components/GroupedTabs/GroupedTabs.d.ts +5 -2
- package/dist/components/GroupedTabs/GroupedTabs.js +33 -26
- package/dist/components/GroupedTabs/GroupedTabs.js.map +1 -1
- package/dist/components/IconButton/IconButton.js +2 -2
- package/dist/components/Input/Input.js +1 -1
- package/dist/components/LineChart/LineChart.d.ts +2 -2
- package/dist/components/LineChart/LineChart.js +3 -1
- package/dist/components/LineChart/LineChart.js.map +1 -1
- package/dist/components/LineChart/LineChart.types.d.ts +16 -0
- package/dist/components/LineChart/LineChartPlot.d.ts +3 -2
- package/dist/components/LineChart/LineChartPlot.js +8 -1
- package/dist/components/LineChart/LineChartPlot.js.map +1 -1
- package/dist/components/LineChart/LineChartVerticalMarkers.d.ts +8 -0
- package/dist/components/LineChart/LineChartVerticalMarkers.js +47 -0
- package/dist/components/LineChart/LineChartVerticalMarkers.js.map +1 -0
- package/dist/components/LineChart/index.d.ts +1 -1
- package/dist/components/Logo/index.js +11 -6
- package/dist/components/Logo/index.js.map +1 -1
- package/dist/components/MetricChart/MetricChart.d.ts +2 -0
- package/dist/components/MetricChart/MetricChart.js +15 -4
- package/dist/components/MetricChart/MetricChart.js.map +1 -1
- package/dist/components/MetricChart/formatters.js +15 -2
- package/dist/components/MetricChart/formatters.js.map +1 -1
- package/dist/components/MetricChart/index.d.ts +1 -1
- package/dist/components/Pane/Pane.js +2 -2
- package/dist/components/SankeyChart/AnimatedSankeyLink.d.ts +17 -0
- package/dist/components/SankeyChart/AnimatedSankeyLink.js +44 -0
- package/dist/components/SankeyChart/AnimatedSankeyLink.js.map +1 -0
- package/dist/components/SankeyChart/AnimatedSankeyNode.d.ts +16 -0
- package/dist/components/SankeyChart/AnimatedSankeyNode.js +42 -0
- package/dist/components/SankeyChart/AnimatedSankeyNode.js.map +1 -0
- package/dist/components/SankeyChart/SankeyChart.d.ts +42 -0
- package/dist/components/SankeyChart/SankeyChart.js +185 -0
- package/dist/components/SankeyChart/SankeyChart.js.map +1 -0
- package/dist/components/SankeyChart/SankeyChart.types.d.ts +90 -0
- package/dist/components/SankeyChart/SankeyChart.types.js +0 -0
- package/dist/components/SankeyChart/SankeyChart.utils.d.ts +21 -0
- package/dist/components/SankeyChart/SankeyChart.utils.js +299 -0
- package/dist/components/SankeyChart/SankeyChart.utils.js.map +1 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.d.ts +10 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.js +30 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.js.map +1 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.utils.d.ts +9 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.utils.js +29 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.utils.js.map +1 -0
- package/dist/components/SankeyChart/constants.d.ts +22 -0
- package/dist/components/SankeyChart/constants.js +27 -0
- package/dist/components/SankeyChart/constants.js.map +1 -0
- package/dist/components/SankeyChart/index.d.ts +5 -0
- package/dist/components/SankeyChart/index.js +4 -0
- package/dist/components/Select/Select.js +5 -5
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/SelectPrimitive.d.ts +6 -0
- package/dist/components/Select/SelectPrimitive.js +3 -2
- package/dist/components/Select/SelectPrimitive.js.map +1 -1
- package/dist/components/Slider/Slider.js +10 -3
- package/dist/components/Slider/Slider.js.map +1 -1
- package/dist/components/SplitViewPane/SplitViewPane.d.ts +2 -1
- package/dist/components/SplitViewPane/SplitViewPane.js +113 -219
- package/dist/components/SplitViewPane/SplitViewPane.js.map +1 -1
- package/dist/components/SplitViewPane/SplitViewPaneHeader.js +2 -2
- package/dist/components/SplitViewPane/useShowChildren.d.ts +5 -0
- package/dist/components/SplitViewPane/useShowChildren.js +14 -0
- package/dist/components/SplitViewPane/useShowChildren.js.map +1 -0
- package/dist/components/SplitViewPane/useSplitViewPaneResize.d.ts +21 -0
- package/dist/components/SplitViewPane/useSplitViewPaneResize.js +145 -0
- package/dist/components/SplitViewPane/useSplitViewPaneResize.js.map +1 -0
- package/dist/components/Textarea/Textarea.d.ts +4 -3
- package/dist/components/Textarea/Textarea.js +7 -21
- package/dist/components/Textarea/Textarea.js.map +1 -1
- package/dist/components/ThinkingState/LoadingIndicator.d.ts +1 -0
- package/dist/components/ThinkingState/LoadingIndicator.js +1 -1
- package/dist/components/ThinkingState/ThinkingState.d.ts +1 -0
- package/dist/components/ThinkingState/ThinkingState.js +5 -4
- package/dist/components/ThinkingState/ThinkingState.js.map +1 -1
- package/dist/components/ThinkingState/index.js +1 -1
- package/dist/components/Toast/index.js +33 -28
- package/dist/components/Toast/index.js.map +1 -1
- package/dist/components/Tooltip/Tooltip.js +2 -2
- package/dist/components/Typeahead/Typeahead.js +18 -8
- package/dist/components/Typeahead/Typeahead.js.map +1 -1
- package/dist/components/Typeahead/Typeahead.types.d.ts +2 -0
- package/dist/components/Typeahead/TypeaheadParts.d.ts +3 -1
- package/dist/components/Typeahead/TypeaheadParts.js +7 -6
- package/dist/components/Typeahead/TypeaheadParts.js.map +1 -1
- package/dist/components/Typeahead/TypeaheadView.js +19 -13
- package/dist/components/Typeahead/TypeaheadView.js.map +1 -1
- package/dist/components/Typeahead/useTypeaheadDomSync.d.ts +1 -1
- package/dist/components/Typeahead/useTypeaheadDomSync.js +14 -8
- package/dist/components/Typeahead/useTypeaheadDomSync.js.map +1 -1
- package/dist/components/Typeahead/useTypeaheadUncontrolledInput.d.ts +2 -1
- package/dist/components/Typeahead/useTypeaheadUncontrolledInput.js +10 -9
- package/dist/components/Typeahead/useTypeaheadUncontrolledInput.js.map +1 -1
- package/dist/components/UnsavedChangesDialog.js +2 -2
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.js +7 -5
- package/dist/components.css +22 -18
- package/dist/hooks/useDebouncedCommit.d.ts +14 -0
- package/dist/hooks/useDebouncedCommit.js +35 -0
- package/dist/hooks/useDebouncedCommit.js.map +1 -0
- package/dist/icons/LongTailPhosphorIcons.js +1 -1
- package/dist/icons/PaddedPhosphorIcons.d.ts +1 -0
- package/dist/icons/PaddedPhosphorIcons.js +4 -2
- package/dist/icons/PaddedPhosphorIcons.js.map +1 -1
- package/dist/icons/WeightedPhosphorIcons.d.ts +1 -0
- package/dist/icons/WeightedPhosphorIcons.js +3 -1
- package/dist/icons/WeightedPhosphorIcons.js.map +1 -1
- package/dist/icons/index.js +3 -3
- package/dist/index.js +7 -5
- package/dist/utilities.css +1 -1
- package/dist/utils/chartColors.d.ts +2 -1
- package/dist/utils/chartColors.js +2 -1
- package/dist/utils/chartColors.js.map +1 -1
- package/dist/utils/componentSizes.d.ts +0 -1
- package/dist/utils/componentSizes.js.map +1 -1
- package/dist/utils/lazy-codemirror-loader.d.ts +0 -2
- package/dist/utils/lazy-codemirror-loader.js +1 -3
- package/dist/utils/lazy-codemirror-loader.js.map +1 -1
- package/docs/DESIGN.md +17 -0
- package/docs/STYLES.md +4 -1
- package/package.json +21 -8
- 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 [
|
|
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
|
-
|
|
27
|
+
setToast((previous) => ({
|
|
28
|
+
id: (previous?.id ?? 0) + 1,
|
|
29
|
+
config
|
|
30
|
+
}));
|
|
27
31
|
setOpen(true);
|
|
28
32
|
}, []);
|
|
29
|
-
return /* @__PURE__ */
|
|
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
|
-
|
|
35
|
-
/* @__PURE__ */ jsx(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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-
|
|
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-
|
|
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 (
|
|
22
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|