@parallelworks/ui 0.41.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/ai/components/AllocationSelector.d.ts +3 -4
- package/dist/ai/components/AllocationSelector.js +37 -33
- package/dist/ai/components/AttachmentManager.js +7 -7
- package/dist/ai/components/AttachmentUpload.js +5 -5
- package/dist/ai/components/BranchNavigator.js +1 -1
- package/dist/ai/components/ChatEmptyState.js +2 -2
- package/dist/ai/components/ChatInput.js +10 -8
- package/dist/ai/components/ChatLayout.js +4 -5
- package/dist/ai/components/ChatMessage.js +12 -12
- package/dist/ai/components/ChatMessageList.js +9 -9
- package/dist/ai/components/ChatSidebar.js +8 -9
- package/dist/ai/components/ChatThread.js +4 -4
- package/dist/ai/components/ComposerChrome.d.ts +2 -2
- package/dist/ai/components/ComposerChrome.js +3 -6
- package/dist/ai/components/DragOverlay.js +2 -2
- package/dist/ai/components/ModelSelector.d.ts +5 -3
- package/dist/ai/components/ModelSelector.js +102 -339
- package/dist/ai/components/PastedText.js +11 -11
- package/dist/ai/components/ProviderIssueBanner.d.ts +2 -0
- package/dist/ai/components/ProviderIssueBanner.js +34 -16
- package/dist/ai/components/Reasoning.js +4 -4
- package/dist/ai/components/ShareDialog.js +43 -35
- package/dist/ai/components/SlashMenu.d.ts +12 -2
- package/dist/ai/components/SlashMenu.js +29 -13
- package/dist/ai/components/agent/ActivityLine.js +3 -3
- package/dist/ai/components/agent/AgentMessageParts.js +20 -20
- package/dist/ai/components/agent/PermissionPicker.js +13 -11
- package/dist/ai/components/conversationActions.d.ts +4 -6
- package/dist/ai/components/conversationActions.js +9 -13
- package/dist/ai/core/ChatProvider.js +1 -1
- package/dist/ai/core/config.js +1 -1
- package/dist/ai/core/providerIssues.d.ts +7 -0
- package/dist/ai/core/providerIssues.js +9 -1
- package/dist/ai/core/useKeyboardShortcuts.d.ts +4 -0
- package/dist/ai/core/useKeyboardShortcuts.js +8 -2
- package/dist/ai/index.d.ts +0 -1
- package/dist/ai/index.js +1 -2
- package/dist/ai/strings.d.ts +19 -0
- package/dist/ai/strings.js +18 -1
- package/dist/ai/ui/Avatar.js +5 -5
- package/dist/ai/ui/ConversationSidebar.d.ts +0 -1
- package/dist/ai/ui/ConversationSidebar.js +6 -7
- package/dist/ai/ui/Markdown.js +3 -3
- package/dist/ai/ui/Notice.js +6 -6
- package/dist/ai/ui/chip.d.ts +4 -0
- package/dist/ai/ui/chip.js +8 -0
- package/dist/ai/ui/sidebar.d.ts +6 -5
- package/dist/ai/ui/sidebar.js +39 -43
- package/dist/components/ActionMenu.d.ts +13 -0
- package/dist/components/ActionMenu.js +30 -0
- package/dist/components/Avatar.js +6 -6
- package/dist/components/Breadcrumbs.js +1 -1
- package/dist/components/Button.js +10 -10
- package/dist/components/Callout.js +2 -2
- package/dist/components/Card.js +3 -3
- package/dist/components/Combobox.d.ts +49 -0
- package/dist/components/Combobox.js +405 -0
- package/dist/components/ConfirmModal.js +11 -11
- package/dist/components/ContextMenu.d.ts +23 -0
- package/dist/components/ContextMenu.js +89 -0
- package/dist/components/CopyToClipboard.js +2 -2
- package/dist/components/CreateModal.d.ts +19 -38
- package/dist/components/CreateModal.js +116 -267
- package/dist/components/DescriptionList.js +8 -8
- package/dist/components/Filter.js +2 -2
- package/dist/components/FilterPill.js +2 -2
- package/dist/components/HoverCard.d.ts +14 -0
- package/dist/components/HoverCard.js +33 -0
- package/dist/components/IconButton.d.ts +5 -5
- package/dist/components/IconButton.js +18 -22
- package/dist/components/InfoTip.d.ts +15 -0
- package/dist/components/InfoTip.js +60 -0
- package/dist/components/Input.js +5 -5
- package/dist/components/LetterBadge.js +2 -2
- package/dist/components/Loader.js +3 -3
- package/dist/components/Markdown.js +1 -1
- package/dist/components/MarkdownImpl.js +2 -2
- package/dist/components/Menu.d.ts +33 -0
- package/dist/components/Menu.js +86 -0
- package/dist/components/MenuEntries.d.ts +56 -0
- package/dist/components/MenuEntries.js +123 -0
- package/dist/components/Modal.d.ts +29 -0
- package/dist/components/Modal.js +47 -0
- package/dist/components/Overview.js +11 -10
- package/dist/components/PageHeader.d.ts +10 -16
- package/dist/components/PageHeader.js +69 -95
- package/dist/components/Pagination.js +5 -5
- package/dist/components/Provider.d.ts +5 -11
- package/dist/components/Provider.js +11 -14
- package/dist/components/Radio.d.ts +8 -0
- package/dist/components/Radio.js +16 -0
- package/dist/components/SectionHeader.js +2 -2
- package/dist/components/SegmentedControl.d.ts +6 -5
- package/dist/components/SegmentedControl.js +34 -30
- package/dist/components/Select.d.ts +27 -0
- package/dist/components/Select.js +78 -0
- package/dist/components/SettingModeOption.d.ts +5 -8
- package/dist/components/SettingModeOption.js +10 -12
- package/dist/components/SettingRow.js +4 -4
- package/dist/components/SettingsCard.js +4 -4
- package/dist/components/SettingsGroup.js +2 -2
- package/dist/components/Sort.js +1 -1
- package/dist/components/StatusBadge.js +7 -7
- package/dist/components/StatusIcons.js +4 -4
- package/dist/components/Switch.d.ts +22 -0
- package/dist/components/Switch.js +28 -0
- package/dist/components/Table.js +11 -11
- package/dist/components/Tooltip.d.ts +24 -20
- package/dist/components/Tooltip.js +58 -76
- package/dist/components/comboboxItems.d.ts +24 -0
- package/dist/components/comboboxItems.js +10 -0
- package/dist/components/floating.d.ts +14 -0
- package/dist/components/floating.js +21 -0
- package/dist/components/search.d.ts +2 -0
- package/dist/components/search.js +14 -0
- package/dist/editor/Editor.js +1 -1
- package/dist/editor/EditorField.js +16 -21
- package/dist/editor/FormCodePanel.js +19 -19
- package/dist/editor/Monaco.js +3 -3
- package/dist/file-explorer/FileExplorer.js +77 -81
- package/dist/file-explorer/FileExplorerContext.js +2 -2
- package/dist/file-explorer/FilePreview/CodePreviewEditor.js +1 -1
- package/dist/file-explorer/FilePreview/Inline.js +1 -1
- package/dist/file-explorer/FilePreview/StreamedBadge.js +5 -6
- package/dist/file-explorer/FilePreview/Viewer.js +8 -8
- package/dist/file-explorer/FilePreview/index.d.ts +1 -1
- package/dist/file-explorer/FilePreview/index.js +49 -83
- package/dist/file-explorer/FileRow.d.ts +4 -3
- package/dist/file-explorer/FileRow.js +32 -38
- package/dist/file-explorer/FileRowsWindow.d.ts +3 -2
- package/dist/file-explorer/FileRowsWindow.js +4 -4
- package/dist/file-explorer/FileTable.d.ts +3 -2
- package/dist/file-explorer/FileTable.js +3 -3
- package/dist/file-explorer/LoadMoreRow.js +1 -1
- package/dist/file-explorer/TreeView.js +11 -16
- package/dist/file-explorer/helpers.js +11 -12
- package/dist/file-explorer/toasts.js +11 -11
- package/dist/form/FieldGroup.d.ts +11 -0
- package/dist/form/FieldGroup.js +36 -0
- package/dist/form/FieldWrapper.js +4 -4
- package/dist/form/Fields/BooleanField.js +23 -33
- package/dist/form/Fields/CheckboxGroupField.d.ts +1 -1
- package/dist/form/Fields/CheckboxGroupField.js +9 -13
- package/dist/form/Fields/ColorField.d.ts +1 -2
- package/dist/form/Fields/ColorField.js +6 -11
- package/dist/form/Fields/DropdownField.d.ts +3 -13
- package/dist/form/Fields/DropdownField.js +40 -27
- package/dist/form/Fields/DurationField.d.ts +1 -2
- package/dist/form/Fields/DurationField.js +25 -32
- package/dist/form/Fields/LabelField.js +2 -2
- package/dist/form/Fields/MultiDropdownField.d.ts +6 -12
- package/dist/form/Fields/MultiDropdownField.js +31 -22
- package/dist/form/Fields/NumberField.d.ts +1 -1
- package/dist/form/Fields/NumberField.js +65 -35
- package/dist/form/Fields/ObjectField.d.ts +1 -1
- package/dist/form/Fields/ObjectField.js +12 -43
- package/dist/form/Fields/RadioField.d.ts +1 -1
- package/dist/form/Fields/RadioField.js +30 -41
- package/dist/form/Fields/RangeField.d.ts +1 -2
- package/dist/form/Fields/RangeField.js +23 -16
- package/dist/form/Fields/StringField.d.ts +1 -2
- package/dist/form/Fields/StringField.js +58 -26
- package/dist/form/Fields/TextAreaField.js +12 -10
- package/dist/form/Form.d.ts +30 -48
- package/dist/form/Form.js +306 -412
- package/dist/form/FormLayout.js +9 -9
- package/dist/form/Wizard/WizardContainer.d.ts +1 -4
- package/dist/form/Wizard/WizardContainer.js +40 -56
- package/dist/form/Wizard/WizardNavigation.js +1 -1
- package/dist/form/Wizard/WizardStepContent.d.ts +1 -5
- package/dist/form/Wizard/WizardStepContent.js +11 -16
- package/dist/form/Wizard/WizardStepIndicator.js +6 -6
- package/dist/form/Wizard/types.d.ts +0 -14
- package/dist/form/fieldRegistry.d.ts +1 -1
- package/dist/form/fieldRegistry.js +6 -6
- package/dist/form/formEditing.js +1 -1
- package/dist/form/index.d.ts +5 -4
- package/dist/form/index.js +6 -7
- package/dist/form/lib.js +3 -2
- package/dist/form/types/fieldComponentTypes.d.ts +8 -10
- package/dist/form/useChoiceField.d.ts +18 -0
- package/dist/form/useChoiceField.js +46 -0
- package/dist/form/useFieldValue.d.ts +7 -0
- package/dist/form/useFieldValue.js +20 -0
- package/dist/form/useParsedOpts.d.ts +3 -1
- package/dist/form/useParsedOpts.js +12 -17
- package/dist/form/utils/dependentOptions.d.ts +8 -4
- package/dist/form/utils/dependentOptions.js +25 -17
- package/dist/form/utils/fieldItems.d.ts +32 -0
- package/dist/form/utils/fieldItems.js +32 -0
- package/dist/form/utils/fieldPath.d.ts +10 -0
- package/dist/form/utils/fieldPath.js +20 -0
- package/dist/form/utils/shareEqual.d.ts +6 -0
- package/dist/form/utils/shareEqual.js +38 -0
- package/dist/graph/AnnotationBanner.js +8 -8
- package/dist/graph/Collapse.d.ts +1 -0
- package/dist/graph/Collapse.js +6 -27
- package/dist/graph/Connectors.js +5 -5
- package/dist/graph/DependencyGraph.js +20 -19
- package/dist/graph/GraphEditor.js +30 -41
- package/dist/graph/GraphEditorDialogs.js +17 -17
- package/dist/graph/GraphNode.js +1 -1
- package/dist/graph/InputDialog.js +19 -22
- package/dist/graph/InputsEditor.js +58 -66
- package/dist/graph/JobSummary.js +42 -39
- package/dist/graph/MatrixGroup.js +1 -1
- package/dist/graph/ProblemsButton.js +18 -19
- package/dist/graph/Reveal.js +1 -1
- package/dist/graph/ShortcutsButton.js +15 -18
- package/dist/graph/SuggestionInput.d.ts +5 -10
- package/dist/graph/SuggestionInput.js +14 -18
- package/dist/graph/ToolbarPopover.d.ts +11 -6
- package/dist/graph/ToolbarPopover.js +35 -67
- package/dist/graph/TreeView.js +24 -37
- package/dist/graph/WorkflowSettingsDialog.js +4 -4
- package/dist/graph/editorChrome.js +13 -12
- package/dist/graph/editorFields.js +29 -29
- package/dist/graph/editorPrimitives.d.ts +1 -1
- package/dist/graph/editorPrimitives.js +10 -7
- package/dist/graph/editorRows.js +103 -97
- package/dist/graph/fieldProblems.js +2 -2
- package/dist/graph/graphEditorState.d.ts +4 -3
- package/dist/graph/inputRefs.js +9 -9
- package/dist/graph/settingsViews.js +6 -7
- package/dist/graph/stepWith.js +6 -6
- package/dist/index.d.ts +14 -15
- package/dist/index.js +15 -14
- package/dist/list/ActionToolbar.d.ts +6 -14
- package/dist/list/ActionToolbar.js +48 -96
- package/dist/list/ListPage.d.ts +6 -12
- package/dist/list/ListPage.js +46 -29
- package/dist/list/ListPager.js +4 -4
- package/dist/list/ListTable.js +5 -5
- package/dist/list/ListViewControls.d.ts +5 -4
- package/dist/list/ListViewControls.js +177 -267
- package/dist/list/UserHoverCard.d.ts +3 -17
- package/dist/list/UserHoverCard.js +21 -45
- package/dist/list/index.d.ts +3 -4
- package/dist/list/index.js +3 -4
- package/dist/list/listSearch.js +12 -11
- package/dist/list/rowMenu.d.ts +68 -0
- package/dist/list/rowMenu.js +136 -0
- package/dist/logviewer/LogViewer.js +26 -26
- package/dist/styles.css +1 -1
- package/package.json +7 -13
- package/dist/ai/ui/Dropdown.d.ts +0 -31
- package/dist/ai/ui/Dropdown.js +0 -110
- package/dist/components/AddMenu.d.ts +0 -18
- package/dist/components/AddMenu.js +0 -46
- package/dist/components/BareModal.d.ts +0 -17
- package/dist/components/BareModal.js +0 -77
- package/dist/components/CollapsiblePanel.d.ts +0 -27
- package/dist/components/CollapsiblePanel.js +0 -77
- package/dist/components/Dropdown.d.ts +0 -28
- package/dist/components/Dropdown.js +0 -355
- package/dist/components/Listbox.d.ts +0 -21
- package/dist/components/Listbox.js +0 -119
- package/dist/components/MultiSelect.d.ts +0 -22
- package/dist/components/MultiSelect.js +0 -168
- package/dist/components/SwitchToggle.d.ts +0 -15
- package/dist/components/SwitchToggle.js +0 -57
- package/dist/components/SwitchToggleSmall.d.ts +0 -6
- package/dist/components/SwitchToggleSmall.js +0 -14
- package/dist/components/Toggle.d.ts +0 -6
- package/dist/components/Toggle.js +0 -20
- package/dist/components/dropdownUtils.d.ts +0 -37
- package/dist/components/dropdownUtils.js +0 -99
- package/dist/form/SpecialTypes/DropdownWrapper.d.ts +0 -25
- package/dist/form/SpecialTypes/DropdownWrapper.js +0 -28
- package/dist/form/SpecialTypes/FormikCustomDropdown.d.ts +0 -51
- package/dist/form/SpecialTypes/FormikCustomDropdown.js +0 -119
- package/dist/form/SpecialTypes/FormikCustomInput.d.ts +0 -19
- package/dist/form/SpecialTypes/FormikCustomInput.js +0 -121
- package/dist/form/SpecialTypes/FormikMultiSelectDropdown.d.ts +0 -13
- package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +0 -31
- package/dist/form/SpecialTypes/FormikNumericInput.d.ts +0 -9
- package/dist/form/SpecialTypes/FormikNumericInput.js +0 -60
- package/dist/form/SpecialTypes/index.d.ts +0 -3
- package/dist/list/HoverCard.d.ts +0 -24
- package/dist/list/HoverCard.js +0 -73
- package/dist/list/RowContextMenu.d.ts +0 -127
- package/dist/list/RowContextMenu.js +0 -515
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useStrings } from "./Provider.js";
|
|
2
|
-
import
|
|
3
|
-
import { useState } from "react";
|
|
2
|
+
import { clsx } from "clsx";
|
|
4
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useState } from "react";
|
|
5
5
|
//#region src/components/Avatar.tsx
|
|
6
6
|
var SIZE_CLASSES = {
|
|
7
7
|
xs: "w-4 h-4 text-[9px]",
|
|
@@ -30,19 +30,19 @@ function Avatar({ src, name, size = "md", status, className }) {
|
|
|
30
30
|
const [erroredUrl, setErroredUrl] = useState(null);
|
|
31
31
|
const showImage = !!src && erroredUrl !== src;
|
|
32
32
|
return /* @__PURE__ */ jsxs("div", {
|
|
33
|
-
className:
|
|
33
|
+
className: clsx("relative inline-flex", className),
|
|
34
34
|
children: [showImage ? /* @__PURE__ */ jsx("img", {
|
|
35
35
|
src,
|
|
36
36
|
alt: name || strings.common.userAvatar,
|
|
37
37
|
loading: "lazy",
|
|
38
38
|
onError: () => setErroredUrl(src),
|
|
39
|
-
className:
|
|
39
|
+
className: clsx("rounded-full object-cover", SIZE_CLASSES[size])
|
|
40
40
|
}) : /* @__PURE__ */ jsx("div", {
|
|
41
|
-
className:
|
|
41
|
+
className: clsx("rounded-full flex items-center justify-center font-medium", "bg-gradient-to-br from-[var(--gradient-start,var(--theme-element))] to-[var(--gradient-mid,var(--theme-link))] text-white", SIZE_CLASSES[size]),
|
|
42
42
|
children: size === "xs" ? avatarInitials(name).charAt(0) : avatarInitials(name)
|
|
43
43
|
}), status && /* @__PURE__ */ jsx("span", {
|
|
44
44
|
"data-testid": "online-indicator",
|
|
45
|
-
className:
|
|
45
|
+
className: clsx("absolute bottom-0 right-0 block rounded-full ring-2 ring-(--theme-app-bg)", STATUS_CLASSES[status], size === "xs" || size === "sm" ? "w-1.5 h-1.5" : "w-2.5 h-2.5")
|
|
46
46
|
})]
|
|
47
47
|
});
|
|
48
48
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { createContext, useContext, useEffect, useLayoutEffect, useMemo } from "react";
|
|
2
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { createContext, useContext, useEffect, useLayoutEffect, useMemo } from "react";
|
|
3
3
|
//#region src/components/Breadcrumbs.tsx
|
|
4
4
|
var BreadcrumbContext = createContext({
|
|
5
5
|
breadcrumbs: [],
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { useLink } from "./Provider.js";
|
|
2
1
|
import { FaAngleRight } from "../icons/fa/FaAngleRight.js";
|
|
3
2
|
import { LoaderIcon } from "./StatusIcons.js";
|
|
4
|
-
import
|
|
3
|
+
import { useLink } from "./Provider.js";
|
|
4
|
+
import { clsx } from "clsx";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
6
|
import { forwardRef } from "react";
|
|
6
|
-
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/components/Button.tsx
|
|
8
8
|
var Button = forwardRef(({ children, variant = "primary", size = "default", loading, icon, iconPosition = "right", fullWidth = true, className = "", disabled, ...props }, ref) => {
|
|
9
9
|
const baseClasses = "inline-flex items-center justify-center gap-2 font-semibold rounded-lg transition-all duration-200 cursor-pointer border-none mt-2 disabled:opacity-50 disabled:cursor-not-allowed";
|
|
@@ -23,9 +23,9 @@ var Button = forwardRef(({ children, variant = "primary", size = "default", load
|
|
|
23
23
|
ref,
|
|
24
24
|
type: "button",
|
|
25
25
|
disabled: disabled || loading,
|
|
26
|
-
className:
|
|
26
|
+
className: clsx(baseClasses, variantClasses[variant], sizeClasses[size], widthClass, className),
|
|
27
27
|
...props,
|
|
28
|
-
children: loading ? /* @__PURE__ */ jsxs(Fragment
|
|
28
|
+
children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(LoaderIcon, { className: "size-[18px]" }), children] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
29
29
|
icon && iconPosition === "left" && /* @__PURE__ */ jsx("span", {
|
|
30
30
|
className: "flex items-center",
|
|
31
31
|
children: icon
|
|
@@ -43,7 +43,7 @@ function MethodButton({ icon, label, description, href, loading, disabled, class
|
|
|
43
43
|
const Link = useLink();
|
|
44
44
|
const baseClasses = "flex items-center w-full p-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-xl text-[var(--theme-app)] text-[0.9375rem] font-medium cursor-pointer transition-all duration-200 no-underline mb-3 last:mb-0 hover:bg-[var(--theme-border)] hover:border-[var(--theme-muted-text-color)] hover:-translate-y-0.5 active:translate-y-0";
|
|
45
45
|
const disabledClasses = "disabled:opacity-60 disabled:cursor-not-allowed disabled:hover:bg-[var(--ds-muted)] disabled:hover:border-[var(--ds-border)] disabled:hover:translate-y-0";
|
|
46
|
-
const content = /* @__PURE__ */ jsxs(Fragment
|
|
46
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
47
47
|
icon && /* @__PURE__ */ jsx("span", {
|
|
48
48
|
className: "size-10 rounded-lg bg-gradient-to-br from-[var(--gradient-start,var(--theme-element))] to-[var(--gradient-mid,var(--theme-link))] flex items-center justify-center shrink-0 mr-4 [&_svg]:size-5 [&_svg]:text-white",
|
|
49
49
|
children: icon
|
|
@@ -63,18 +63,18 @@ function MethodButton({ icon, label, description, href, loading, disabled, class
|
|
|
63
63
|
if (href) {
|
|
64
64
|
if (href.startsWith("/api/") || href.startsWith("http")) return /* @__PURE__ */ jsx("a", {
|
|
65
65
|
href,
|
|
66
|
-
className:
|
|
66
|
+
className: clsx("group", baseClasses, className),
|
|
67
67
|
children: content
|
|
68
68
|
});
|
|
69
69
|
return /* @__PURE__ */ jsx(Link, {
|
|
70
|
-
|
|
71
|
-
className:
|
|
70
|
+
href,
|
|
71
|
+
className: clsx("group", baseClasses, className),
|
|
72
72
|
children: content
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
75
|
return /* @__PURE__ */ jsx("button", {
|
|
76
76
|
type: "button",
|
|
77
|
-
className:
|
|
77
|
+
className: clsx("group", baseClasses, disabledClasses, className),
|
|
78
78
|
disabled: disabled || loading,
|
|
79
79
|
...props,
|
|
80
80
|
children: content
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FaInfoCircle } from "../icons/fa/FaInfoCircle.js";
|
|
2
2
|
import { TbAlertTriangle } from "../icons/tb/TbAlertTriangle.js";
|
|
3
|
-
import
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/Callout.tsx
|
|
6
6
|
function CalloutIcon({ type }) {
|
|
@@ -9,7 +9,7 @@ function CalloutIcon({ type }) {
|
|
|
9
9
|
}
|
|
10
10
|
function Callout({ type, className = "", children }) {
|
|
11
11
|
return /* @__PURE__ */ jsx("div", {
|
|
12
|
-
className:
|
|
12
|
+
className: clsx(className, type === "warning" && "bg-orange-100 border-orange-500 text-orange-700", type === "error" && "bg-red-100 border-red-500 text-red-700", type === "info" && "bg-blue-100 border-blue-500 text-blue-700", "border-t-4 rounded-b px-4 py-3 shadow-md my-4"),
|
|
13
13
|
role: "alert",
|
|
14
14
|
children: /* @__PURE__ */ jsxs("div", {
|
|
15
15
|
className: "flex",
|
package/dist/components/Card.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { clsx } from "clsx";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
//#region src/components/Card.tsx
|
|
4
4
|
function Card({ children, className = "", wide, compact, interactive, authShadow }) {
|
|
5
5
|
return /* @__PURE__ */ jsx("div", {
|
|
6
|
-
className:
|
|
6
|
+
className: clsx("w-full bg-[var(--theme-card-bg)] backdrop-blur-xl border border-[var(--theme-border)] rounded-2xl", authShadow ? "shadow-[var(--theme-auth-shadow)]" : "shadow-[var(--theme-shadow)]", wide && "max-w-[560px] p-8", compact && "max-w-[400px] p-6", !wide && !compact && "max-w-[520px] p-10", interactive && "ds-card-interactive cursor-pointer", className),
|
|
7
7
|
children
|
|
8
8
|
});
|
|
9
9
|
}
|
|
10
10
|
function CardHeader({ badge, title, description, className = "", align = "center" }) {
|
|
11
11
|
return /* @__PURE__ */ jsxs("div", {
|
|
12
|
-
className:
|
|
12
|
+
className: clsx(align === "center" ? "text-center" : "text-left", "mb-6", className),
|
|
13
13
|
children: [
|
|
14
14
|
badge && /* @__PURE__ */ jsx("div", {
|
|
15
15
|
className: "inline-flex items-center gap-1.5 py-1.5 px-3 text-xs font-medium bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-full text-[var(--theme-muted-text-color)] mb-4 transition-colors duration-200",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode } from 'react';
|
|
2
|
+
import { type ComboboxItems } from './comboboxItems.js';
|
|
3
|
+
export type { ComboboxGroup, ComboboxItem, ComboboxItems, ComboboxLeaf, } from './comboboxItems.js';
|
|
4
|
+
interface FieldProps {
|
|
5
|
+
id?: string | undefined;
|
|
6
|
+
placeholder?: string | undefined;
|
|
7
|
+
disabled?: boolean | undefined;
|
|
8
|
+
required?: boolean | undefined;
|
|
9
|
+
'aria-label'?: string | undefined;
|
|
10
|
+
'aria-labelledby'?: string | undefined;
|
|
11
|
+
'aria-describedby'?: string | undefined;
|
|
12
|
+
'aria-invalid'?: boolean | undefined;
|
|
13
|
+
/** Classes for the field box: border, background, size. */
|
|
14
|
+
className?: string | undefined;
|
|
15
|
+
}
|
|
16
|
+
type SelectionProps<Value> = {
|
|
17
|
+
multiple?: false | undefined;
|
|
18
|
+
value?: Value | null | undefined;
|
|
19
|
+
defaultValue?: Value | null | undefined;
|
|
20
|
+
onValueChange?: ((value: NoInfer<Value> | null) => void) | undefined;
|
|
21
|
+
} | {
|
|
22
|
+
multiple: true;
|
|
23
|
+
value?: readonly Value[] | undefined;
|
|
24
|
+
defaultValue?: readonly Value[] | undefined;
|
|
25
|
+
onValueChange?: ((value: NoInfer<Value>[]) => void) | undefined;
|
|
26
|
+
};
|
|
27
|
+
export type ComboboxProps<Value = string> = FieldProps & SelectionProps<Value> & {
|
|
28
|
+
items: ComboboxItems<Value>;
|
|
29
|
+
/** Matches a value to its item. Defaults to deep equality, so object values can be recreated. */
|
|
30
|
+
isItemEqualToValue?: ((itemValue: Value, value: Value) => boolean) | undefined;
|
|
31
|
+
/** Labels a selected value that no item has, such as a saved choice the list no longer offers. */
|
|
32
|
+
itemToStringLabel?: ((value: Value) => string) | undefined;
|
|
33
|
+
/** Renders the field as this button, with the search input inside the popup, for compact
|
|
34
|
+
* pickers such as a toolbar pill. The button shows the selection itself. */
|
|
35
|
+
trigger?: ReactElement | undefined;
|
|
36
|
+
/** A hint on the trigger button. */
|
|
37
|
+
triggerTooltip?: ReactNode;
|
|
38
|
+
};
|
|
39
|
+
export interface AutocompleteProps extends FieldProps {
|
|
40
|
+
/** Suggestions; any typed text is also a valid value. */
|
|
41
|
+
items: ComboboxItems<string>;
|
|
42
|
+
value?: string | undefined;
|
|
43
|
+
defaultValue?: string | undefined;
|
|
44
|
+
onValueChange?: ((value: string) => void) | undefined;
|
|
45
|
+
}
|
|
46
|
+
/** A pick-from-the-list field: one value, or several with `multiple`. Typing filters the list. */
|
|
47
|
+
export declare function Combobox<Value = string>(props: ComboboxProps<Value>): import("react").JSX.Element;
|
|
48
|
+
/** A free-text field that suggests values as you type. */
|
|
49
|
+
export declare function Autocomplete({ items, value, defaultValue, onValueChange, className, placeholder, disabled, required, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, 'aria-invalid': ariaInvalid, }: AutocompleteProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { FaCaretDown } from "../icons/fa/FaCaretDown.js";
|
|
2
|
+
import { FaCheck } from "../icons/fa/FaCheck.js";
|
|
3
|
+
import { FiX } from "../icons/fi/FiX.js";
|
|
4
|
+
import { panelClassName, panelItemClassName, portalContainer, positionerClassName } from "./floating.js";
|
|
5
|
+
import { Tooltip } from "./Tooltip.js";
|
|
6
|
+
import { useStrings } from "./Provider.js";
|
|
7
|
+
import { useQueryMatch } from "./search.js";
|
|
8
|
+
import { isComboboxGroup } from "./comboboxItems.js";
|
|
9
|
+
import { clsx } from "clsx";
|
|
10
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
import { useCallback, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
12
|
+
import { Combobox } from "@base-ui/react/combobox";
|
|
13
|
+
import { Autocomplete } from "@base-ui/react/autocomplete";
|
|
14
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
15
|
+
import { dequal } from "dequal";
|
|
16
|
+
//#region src/components/Combobox.tsx
|
|
17
|
+
function toEntry(item, group) {
|
|
18
|
+
const entry = typeof item === "string" ? {
|
|
19
|
+
value: item,
|
|
20
|
+
label: item
|
|
21
|
+
} : item;
|
|
22
|
+
return group === void 0 ? entry : {
|
|
23
|
+
...entry,
|
|
24
|
+
group
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Base UI takes either flat items or groups, and filters and navigates by the leaf items, so
|
|
28
|
+
* items listed between groups gather into headless groups where they sit. */
|
|
29
|
+
function useEntries(items) {
|
|
30
|
+
return useMemo(() => {
|
|
31
|
+
if (!items.some(isComboboxGroup)) {
|
|
32
|
+
const flat = items.map((item) => toEntry(item));
|
|
33
|
+
return {
|
|
34
|
+
items: flat,
|
|
35
|
+
flat,
|
|
36
|
+
statusGroups: []
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const groups = [];
|
|
40
|
+
for (const item of items) {
|
|
41
|
+
if (isComboboxGroup(item)) {
|
|
42
|
+
groups.push({
|
|
43
|
+
label: item.label,
|
|
44
|
+
icon: item.icon,
|
|
45
|
+
description: item.description,
|
|
46
|
+
items: item.items.map((leaf) => toEntry(leaf, item.label)),
|
|
47
|
+
order: groups.length
|
|
48
|
+
});
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const last = groups.at(-1);
|
|
52
|
+
if (last?.headless) last.items.push(toEntry(item));
|
|
53
|
+
else groups.push({
|
|
54
|
+
label: "",
|
|
55
|
+
items: [toEntry(item)],
|
|
56
|
+
order: groups.length,
|
|
57
|
+
headless: true
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
items: groups,
|
|
62
|
+
flat: groups.flatMap((g) => g.items),
|
|
63
|
+
statusGroups: groups.filter((g) => g.items.length === 0)
|
|
64
|
+
};
|
|
65
|
+
}, [items]);
|
|
66
|
+
}
|
|
67
|
+
function useEntryFilter() {
|
|
68
|
+
const match = useQueryMatch();
|
|
69
|
+
return useCallback((entry, query) => match(query, entry.label, typeof entry.value === "string" ? entry.value : void 0, entry.group), [match]);
|
|
70
|
+
}
|
|
71
|
+
var entryLabel = (entry) => entry?.label ?? "";
|
|
72
|
+
var fieldClassName = "theme-input relative flex min-h-8 w-full items-center gap-1 rounded-md border text-sm focus-within:border-(--theme-element) focus-within:ring-1 focus-within:ring-(--theme-element) has-[[aria-invalid=true]]:border-(--theme-error) has-[input:disabled]:cursor-not-allowed has-[input:disabled]:bg-(--theme-input-disabled-bg) has-[input:disabled]:text-(--theme-input-disabled-text)";
|
|
73
|
+
var inputClassName = "h-full min-w-12 flex-1 self-stretch border-0 bg-transparent py-1.5 pl-3 text-inherit outline-none placeholder:text-(--theme-muted-text-color) disabled:cursor-not-allowed";
|
|
74
|
+
var triggerClassName = "flex shrink-0 items-center self-stretch px-2 text-(--theme-muted-text-color) disabled:cursor-not-allowed";
|
|
75
|
+
var popupInputClassName = "theme-input h-7 w-full rounded-md border px-2 text-sm outline-none placeholder:text-(--theme-muted-text-color) focus:border-(--theme-element)";
|
|
76
|
+
/** A pick-from-the-list field: one value, or several with `multiple`. Typing filters the list. */
|
|
77
|
+
function Combobox$1(props) {
|
|
78
|
+
const { items, isItemEqualToValue = dequal, itemToStringLabel = String, className, placeholder, disabled, required, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, trigger, triggerTooltip } = props;
|
|
79
|
+
const entries = useEntries(items);
|
|
80
|
+
const filter = useEntryFilter();
|
|
81
|
+
const strings = useStrings();
|
|
82
|
+
const t = strings.dropdown;
|
|
83
|
+
const list = useRef(null);
|
|
84
|
+
const [inputValue, setInputValue] = useState(null);
|
|
85
|
+
const entryOf = (value) => entries.flat.find((entry) => isItemEqualToValue(entry.value, value)) ?? {
|
|
86
|
+
value,
|
|
87
|
+
label: itemToStringLabel(value)
|
|
88
|
+
};
|
|
89
|
+
const toEntries = (values) => values?.map(entryOf);
|
|
90
|
+
const toSingle = (value) => value === void 0 ? void 0 : value === null ? null : entryOf(value);
|
|
91
|
+
const selected = props.multiple ? void 0 : toSingle(props.value);
|
|
92
|
+
const selectedIcon = selected?.icon && (inputValue === null || inputValue === selected.label) ? selected.icon : null;
|
|
93
|
+
const input = /* @__PURE__ */ jsx(Combobox.Input, {
|
|
94
|
+
id: trigger ? void 0 : id,
|
|
95
|
+
placeholder,
|
|
96
|
+
"aria-label": ariaLabel || void 0,
|
|
97
|
+
"aria-labelledby": ariaLabelledBy,
|
|
98
|
+
"aria-describedby": ariaDescribedBy,
|
|
99
|
+
"aria-invalid": ariaInvalid || void 0,
|
|
100
|
+
autoComplete: "off",
|
|
101
|
+
className: trigger ? popupInputClassName : inputClassName
|
|
102
|
+
});
|
|
103
|
+
const itemRow = (entry, rowProps) => /* @__PURE__ */ jsxs(Combobox.Item, {
|
|
104
|
+
value: entry,
|
|
105
|
+
disabled: entry.disabled,
|
|
106
|
+
...rowProps.props,
|
|
107
|
+
className: itemClassName,
|
|
108
|
+
children: [/* @__PURE__ */ jsx(ItemContent, { entry }), /* @__PURE__ */ jsx(Combobox.ItemIndicator, {
|
|
109
|
+
className: "ml-auto flex shrink-0 items-center",
|
|
110
|
+
children: /* @__PURE__ */ jsx(FaCheck, { className: "size-3.5" })
|
|
111
|
+
})]
|
|
112
|
+
}, rowProps.key);
|
|
113
|
+
const parts = trigger ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Tooltip, {
|
|
114
|
+
content: triggerTooltip,
|
|
115
|
+
children: /* @__PURE__ */ jsx(Combobox.Trigger, {
|
|
116
|
+
id,
|
|
117
|
+
"aria-label": ariaLabel || void 0,
|
|
118
|
+
"aria-labelledby": ariaLabelledBy,
|
|
119
|
+
"aria-describedby": ariaDescribedBy,
|
|
120
|
+
"aria-invalid": ariaInvalid || void 0,
|
|
121
|
+
render: trigger
|
|
122
|
+
})
|
|
123
|
+
}), /* @__PURE__ */ jsx(ListPopup, {
|
|
124
|
+
listRef: list,
|
|
125
|
+
empty: t.noOptionsFound,
|
|
126
|
+
statusGroups: entries.statusGroups,
|
|
127
|
+
query: inputValue ?? "",
|
|
128
|
+
header: /* @__PURE__ */ jsx("div", {
|
|
129
|
+
className: "border-b border-(--theme-border) p-1.5",
|
|
130
|
+
children: input
|
|
131
|
+
}),
|
|
132
|
+
className: "w-max min-w-(--anchor-width) max-w-[min(28rem,var(--available-width))]",
|
|
133
|
+
renderItem: itemRow
|
|
134
|
+
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Combobox.InputGroup, {
|
|
135
|
+
"data-testid": "combobox",
|
|
136
|
+
className: clsx(fieldClassName, className),
|
|
137
|
+
children: [props.multiple ? /* @__PURE__ */ jsxs(Combobox.Chips, {
|
|
138
|
+
className: "flex min-w-0 flex-1 flex-wrap items-center gap-1 py-1 pl-1",
|
|
139
|
+
children: [/* @__PURE__ */ jsx(Combobox.Value, { children: (values) => values.map((entry) => /* @__PURE__ */ jsxs(Combobox.Chip, {
|
|
140
|
+
"aria-label": entry.label,
|
|
141
|
+
className: "flex items-center gap-1 rounded bg-(--theme-muted-panel-bg) py-0.5 pr-0.5 pl-1.5 text-xs outline-none data-highlighted:bg-(--theme-hover)",
|
|
142
|
+
children: [entry.label, /* @__PURE__ */ jsx(Combobox.ChipRemove, {
|
|
143
|
+
"aria-label": `${strings.common.remove} ${entry.label}`,
|
|
144
|
+
className: "flex size-4 items-center justify-center rounded hover:bg-(--theme-hover)",
|
|
145
|
+
children: /* @__PURE__ */ jsx(FiX, { className: "size-3" })
|
|
146
|
+
})]
|
|
147
|
+
}, entry.label)) }), input]
|
|
148
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [selectedIcon && /* @__PURE__ */ jsx("span", {
|
|
149
|
+
className: "flex shrink-0 items-center pl-3",
|
|
150
|
+
children: selectedIcon
|
|
151
|
+
}), input] }), /* @__PURE__ */ jsx(Combobox.Trigger, {
|
|
152
|
+
"aria-label": t.showOptions,
|
|
153
|
+
"data-testid": "combobox-button",
|
|
154
|
+
className: triggerClassName,
|
|
155
|
+
children: /* @__PURE__ */ jsx(FaCaretDown, { className: "size-3" })
|
|
156
|
+
})]
|
|
157
|
+
}), /* @__PURE__ */ jsx(ListPopup, {
|
|
158
|
+
listRef: list,
|
|
159
|
+
empty: t.noOptionsFound,
|
|
160
|
+
statusGroups: entries.statusGroups,
|
|
161
|
+
query: inputValue ?? "",
|
|
162
|
+
renderItem: itemRow
|
|
163
|
+
})] });
|
|
164
|
+
const root = {
|
|
165
|
+
items: entries.items,
|
|
166
|
+
filter,
|
|
167
|
+
isItemEqualToValue: (a, b) => isItemEqualToValue(a.value, b.value),
|
|
168
|
+
itemToStringLabel: entryLabel,
|
|
169
|
+
onInputValueChange: setInputValue,
|
|
170
|
+
onItemHighlighted: (_, { index, reason }) => list.current?.reveal(index, reason),
|
|
171
|
+
disabled,
|
|
172
|
+
required,
|
|
173
|
+
virtualized: true,
|
|
174
|
+
children: parts
|
|
175
|
+
};
|
|
176
|
+
return props.multiple ? /* @__PURE__ */ jsx(Combobox.Root, {
|
|
177
|
+
...root,
|
|
178
|
+
multiple: true,
|
|
179
|
+
value: toEntries(props.value),
|
|
180
|
+
defaultValue: toEntries(props.defaultValue),
|
|
181
|
+
onValueChange: (next) => props.onValueChange?.(next.map((entry) => entry.value))
|
|
182
|
+
}) : /* @__PURE__ */ jsx(Combobox.Root, {
|
|
183
|
+
...root,
|
|
184
|
+
value: selected,
|
|
185
|
+
defaultValue: toSingle(props.defaultValue),
|
|
186
|
+
onValueChange: (next) => props.onValueChange?.(next?.value ?? null)
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
/** A free-text field that suggests values as you type. */
|
|
190
|
+
function Autocomplete$1({ items, value, defaultValue, onValueChange, className, placeholder, disabled, required, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid }) {
|
|
191
|
+
const entries = useEntries(items);
|
|
192
|
+
const filter = useEntryFilter();
|
|
193
|
+
const t = useStrings().dropdown;
|
|
194
|
+
const list = useRef(null);
|
|
195
|
+
return /* @__PURE__ */ jsxs(Autocomplete.Root, {
|
|
196
|
+
items: entries.items,
|
|
197
|
+
filter,
|
|
198
|
+
itemToStringValue: (entry) => entry.value,
|
|
199
|
+
value,
|
|
200
|
+
defaultValue,
|
|
201
|
+
onValueChange: (next) => onValueChange?.(next),
|
|
202
|
+
onItemHighlighted: (_, { index, reason }) => list.current?.reveal(index, reason),
|
|
203
|
+
disabled,
|
|
204
|
+
required,
|
|
205
|
+
virtualized: true,
|
|
206
|
+
children: [/* @__PURE__ */ jsxs(Autocomplete.InputGroup, {
|
|
207
|
+
"data-testid": "combobox",
|
|
208
|
+
className: clsx(fieldClassName, className),
|
|
209
|
+
children: [/* @__PURE__ */ jsx(Autocomplete.Input, {
|
|
210
|
+
id,
|
|
211
|
+
placeholder,
|
|
212
|
+
"aria-label": ariaLabel || void 0,
|
|
213
|
+
"aria-labelledby": ariaLabelledBy,
|
|
214
|
+
"aria-describedby": ariaDescribedBy,
|
|
215
|
+
"aria-invalid": ariaInvalid || void 0,
|
|
216
|
+
autoComplete: "off",
|
|
217
|
+
className: inputClassName
|
|
218
|
+
}), entries.flat.length > 0 && /* @__PURE__ */ jsx(Autocomplete.Trigger, {
|
|
219
|
+
"aria-label": t.showOptions,
|
|
220
|
+
"data-testid": "combobox-button",
|
|
221
|
+
className: triggerClassName,
|
|
222
|
+
children: /* @__PURE__ */ jsx(FaCaretDown, { className: "size-3" })
|
|
223
|
+
})]
|
|
224
|
+
}), /* @__PURE__ */ jsx(ListPopup, {
|
|
225
|
+
listRef: list,
|
|
226
|
+
renderItem: (entry, rowProps) => /* @__PURE__ */ jsx(Autocomplete.Item, {
|
|
227
|
+
value: entry,
|
|
228
|
+
disabled: entry.disabled,
|
|
229
|
+
...rowProps.props,
|
|
230
|
+
className: itemClassName,
|
|
231
|
+
children: /* @__PURE__ */ jsx(ItemContent, { entry })
|
|
232
|
+
}, rowProps.key)
|
|
233
|
+
})]
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
var itemClassName = clsx(panelItemClassName, "data-selected:font-medium");
|
|
237
|
+
function ItemContent({ entry }) {
|
|
238
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [entry.icon && /* @__PURE__ */ jsx("span", {
|
|
239
|
+
className: "flex shrink-0 items-center",
|
|
240
|
+
children: entry.icon
|
|
241
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
242
|
+
className: "flex min-w-0 flex-col",
|
|
243
|
+
children: [/* @__PURE__ */ jsx(Tooltip, {
|
|
244
|
+
content: entry.label,
|
|
245
|
+
overflowOnly: true,
|
|
246
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
247
|
+
className: "truncate",
|
|
248
|
+
children: entry.label
|
|
249
|
+
})
|
|
250
|
+
}), entry.description && /* @__PURE__ */ jsx("span", {
|
|
251
|
+
className: "text-xs leading-snug text-(--theme-muted-text-color)",
|
|
252
|
+
children: entry.description
|
|
253
|
+
})]
|
|
254
|
+
})] });
|
|
255
|
+
}
|
|
256
|
+
function GroupHeading({ group }) {
|
|
257
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
258
|
+
group.icon && /* @__PURE__ */ jsx("span", {
|
|
259
|
+
className: "flex shrink-0 items-center",
|
|
260
|
+
children: group.icon
|
|
261
|
+
}),
|
|
262
|
+
/* @__PURE__ */ jsx("span", {
|
|
263
|
+
className: "shrink-0 font-semibold",
|
|
264
|
+
children: group.label
|
|
265
|
+
}),
|
|
266
|
+
group.description && /* @__PURE__ */ jsx(Tooltip, {
|
|
267
|
+
content: group.description,
|
|
268
|
+
overflowOnly: true,
|
|
269
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
270
|
+
className: "min-w-0 truncate",
|
|
271
|
+
children: ["· ", group.description]
|
|
272
|
+
})
|
|
273
|
+
})
|
|
274
|
+
] });
|
|
275
|
+
}
|
|
276
|
+
/** Portal, positioner and popup shared by Combobox and Autocomplete; both use the same parts. */
|
|
277
|
+
function ListPopup({ listRef, empty, statusGroups = [], query = "", header, className = "w-(--anchor-width) max-w-(--available-width)", renderItem }) {
|
|
278
|
+
return /* @__PURE__ */ jsx(Combobox.Portal, {
|
|
279
|
+
container: portalContainer(),
|
|
280
|
+
children: /* @__PURE__ */ jsx(Combobox.Positioner, {
|
|
281
|
+
align: "start",
|
|
282
|
+
sideOffset: 4,
|
|
283
|
+
className: positionerClassName,
|
|
284
|
+
children: /* @__PURE__ */ jsxs(Combobox.Popup, {
|
|
285
|
+
className: clsx("overflow-hidden", className, panelClassName),
|
|
286
|
+
children: [
|
|
287
|
+
header,
|
|
288
|
+
empty && statusGroups.length === 0 && /* @__PURE__ */ jsx(Combobox.Empty, {
|
|
289
|
+
className: "px-3 py-2 text-(--theme-muted-text-color) empty:hidden",
|
|
290
|
+
children: empty
|
|
291
|
+
}),
|
|
292
|
+
/* @__PURE__ */ jsx(Combobox.List, { children: /* @__PURE__ */ jsx(VirtualList, {
|
|
293
|
+
ref: listRef,
|
|
294
|
+
statusGroups,
|
|
295
|
+
query,
|
|
296
|
+
renderItem
|
|
297
|
+
}) })
|
|
298
|
+
]
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
function toRows(filtered, statusGroups) {
|
|
304
|
+
const nodes = statusGroups.length ? [...filtered, ...statusGroups].sort((a, b) => ("order" in a ? a.order : 0) - ("order" in b ? b.order : 0)) : filtered;
|
|
305
|
+
const rows = [];
|
|
306
|
+
const rowOfItem = [];
|
|
307
|
+
for (const node of nodes) {
|
|
308
|
+
const leaves = "items" in node ? node.items : [node];
|
|
309
|
+
if ("items" in node && !node.headless) rows.push({
|
|
310
|
+
kind: "group",
|
|
311
|
+
group: node
|
|
312
|
+
});
|
|
313
|
+
for (const entry of leaves) {
|
|
314
|
+
rowOfItem.push(rows.length);
|
|
315
|
+
rows.push({
|
|
316
|
+
kind: "item",
|
|
317
|
+
entry,
|
|
318
|
+
index: rowOfItem.length - 1
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
rows,
|
|
324
|
+
rowOfItem
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function VirtualList({ ref, statusGroups, query, renderItem }) {
|
|
328
|
+
const filtered = Combobox.useFilteredItems();
|
|
329
|
+
const match = useQueryMatch();
|
|
330
|
+
const { rows, rowOfItem } = useMemo(() => {
|
|
331
|
+
const q = query.trim();
|
|
332
|
+
const shown = q ? statusGroups.filter((g) => match(q, g.label, g.description)) : statusGroups;
|
|
333
|
+
return toRows(filtered, shown);
|
|
334
|
+
}, [
|
|
335
|
+
filtered,
|
|
336
|
+
statusGroups,
|
|
337
|
+
query,
|
|
338
|
+
match
|
|
339
|
+
]);
|
|
340
|
+
const scroller = useRef(null);
|
|
341
|
+
const virtualizer = useVirtualizer({
|
|
342
|
+
count: rows.length,
|
|
343
|
+
getScrollElement: () => scroller.current,
|
|
344
|
+
estimateSize: (i) => rows[i]?.kind === "group" ? 28 : 36,
|
|
345
|
+
overscan: 10,
|
|
346
|
+
paddingStart: 4,
|
|
347
|
+
paddingEnd: 4,
|
|
348
|
+
scrollPaddingStart: 4,
|
|
349
|
+
scrollPaddingEnd: 4
|
|
350
|
+
});
|
|
351
|
+
useImperativeHandle(ref, () => ({ reveal(index, reason) {
|
|
352
|
+
const row = index === void 0 ? void 0 : rowOfItem[index];
|
|
353
|
+
if (row === void 0 || reason === "pointer") return;
|
|
354
|
+
queueMicrotask(() => virtualizer.scrollToIndex(row, { align: "auto" }));
|
|
355
|
+
} }), [rowOfItem, virtualizer]);
|
|
356
|
+
const scrollerRef = useCallback((element) => {
|
|
357
|
+
scroller.current = element;
|
|
358
|
+
if (element) virtualizer.measure();
|
|
359
|
+
}, [virtualizer]);
|
|
360
|
+
if (rows.length === 0) return null;
|
|
361
|
+
const total = virtualizer.getTotalSize();
|
|
362
|
+
return /* @__PURE__ */ jsx("div", {
|
|
363
|
+
role: "presentation",
|
|
364
|
+
ref: scrollerRef,
|
|
365
|
+
className: "max-h-[min(15rem,var(--available-height))] overflow-auto overscroll-contain",
|
|
366
|
+
style: { height: total },
|
|
367
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
368
|
+
role: "presentation",
|
|
369
|
+
className: "relative w-full",
|
|
370
|
+
style: { height: total },
|
|
371
|
+
children: virtualizer.getVirtualItems().map((virtual) => {
|
|
372
|
+
const row = rows[virtual.index];
|
|
373
|
+
const style = {
|
|
374
|
+
position: "absolute",
|
|
375
|
+
top: 0,
|
|
376
|
+
left: 0,
|
|
377
|
+
width: "100%",
|
|
378
|
+
transform: `translateY(${virtual.start}px)`
|
|
379
|
+
};
|
|
380
|
+
if (!row) return null;
|
|
381
|
+
if (row.kind === "group") return /* @__PURE__ */ jsx("div", {
|
|
382
|
+
role: "presentation",
|
|
383
|
+
"data-index": virtual.index,
|
|
384
|
+
ref: virtualizer.measureElement,
|
|
385
|
+
style,
|
|
386
|
+
className: "flex items-center gap-1.5 px-3 pt-2 pb-1 text-xs text-(--theme-muted-text-color)",
|
|
387
|
+
children: /* @__PURE__ */ jsx(GroupHeading, { group: row.group })
|
|
388
|
+
}, virtual.key);
|
|
389
|
+
return renderItem(row.entry, {
|
|
390
|
+
key: virtual.key,
|
|
391
|
+
props: {
|
|
392
|
+
index: row.index,
|
|
393
|
+
ref: virtualizer.measureElement,
|
|
394
|
+
"data-index": virtual.index,
|
|
395
|
+
"aria-setsize": rowOfItem.length,
|
|
396
|
+
"aria-posinset": row.index + 1,
|
|
397
|
+
style
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
})
|
|
401
|
+
})
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
//#endregion
|
|
405
|
+
export { Autocomplete$1 as Autocomplete, Combobox$1 as Combobox };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useStrings } from "./Provider.js";
|
|
2
|
-
import { BareModal, modalPanelClasses } from "./BareModal.js";
|
|
3
2
|
import { dangerButtonClasses, ghostButtonClasses, primaryButtonClasses } from "./ghostButton.js";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import { Modal, ModalDescription, ModalTitle } from "./Modal.js";
|
|
4
|
+
import { clsx } from "clsx";
|
|
6
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
7
7
|
//#region src/components/ConfirmModal.tsx
|
|
8
8
|
function ConfirmModal({ open, onClose, title, description, children, confirmLabel, onConfirm, confirmDisabled = false, destructive = false, align = "top", cancelLabel, closeOnConfirm = true }) {
|
|
9
9
|
const strings = useStrings();
|
|
@@ -29,21 +29,21 @@ function ConfirmModal({ open, onClose, title, description, children, confirmLabe
|
|
|
29
29
|
setPending(false);
|
|
30
30
|
}
|
|
31
31
|
}, [onConfirm, closeOnConfirm]);
|
|
32
|
-
return /* @__PURE__ */ jsxs(
|
|
32
|
+
return /* @__PURE__ */ jsxs(Modal, {
|
|
33
|
+
alert: destructive,
|
|
33
34
|
open,
|
|
34
35
|
onClose,
|
|
35
|
-
ariaLabel: title,
|
|
36
36
|
align,
|
|
37
|
-
|
|
38
|
-
className:
|
|
37
|
+
dismissible: !pending,
|
|
38
|
+
className: "w-[480px] max-w-full",
|
|
39
39
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
40
40
|
className: "px-5 pt-5",
|
|
41
41
|
children: [
|
|
42
|
-
/* @__PURE__ */ jsx(
|
|
42
|
+
/* @__PURE__ */ jsx(ModalTitle, {
|
|
43
43
|
className: "text-lg font-semibold text-(--theme-app)",
|
|
44
44
|
children: title
|
|
45
45
|
}),
|
|
46
|
-
description !== null && description !== void 0 && /* @__PURE__ */ jsx(
|
|
46
|
+
description !== null && description !== void 0 && /* @__PURE__ */ jsx(ModalDescription, {
|
|
47
47
|
className: "mt-1.5 text-sm text-(--theme-muted-text-color)",
|
|
48
48
|
children: description
|
|
49
49
|
}),
|
|
@@ -58,13 +58,13 @@ function ConfirmModal({ open, onClose, title, description, children, confirmLabe
|
|
|
58
58
|
type: "button",
|
|
59
59
|
onClick: onClose,
|
|
60
60
|
disabled: pending,
|
|
61
|
-
className:
|
|
61
|
+
className: clsx(ghostButtonClasses, pending && "cursor-wait"),
|
|
62
62
|
children: cancelLabel ?? strings.modal.cancel
|
|
63
63
|
}), /* @__PURE__ */ jsx("button", {
|
|
64
64
|
type: "button",
|
|
65
65
|
onClick: runConfirm,
|
|
66
66
|
disabled: confirmDisabled || pending,
|
|
67
|
-
className:
|
|
67
|
+
className: clsx(destructive ? dangerButtonClasses : primaryButtonClasses, "disabled:cursor-not-allowed disabled:opacity-50", pending && "cursor-wait"),
|
|
68
68
|
children: confirmLabel
|
|
69
69
|
})]
|
|
70
70
|
})]
|