@parallelworks/ui 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunks/memoryStore-CC91S5LP.js → ai/adapter/memoryStore.js} +2 -2
  3. package/dist/ai/adapter/mock/index.js +2 -80
  4. package/dist/ai/adapter/mock/mockAdapter.js +81 -0
  5. package/dist/ai/adapter/openai/createOpenAIStream.js +33 -0
  6. package/dist/ai/adapter/openai/errors.js +37 -0
  7. package/dist/ai/adapter/openai/index.js +5 -333
  8. package/dist/ai/adapter/openai/openaiAdapter.js +54 -0
  9. package/dist/ai/adapter/openai/responses.js +108 -0
  10. package/dist/ai/adapter/openai/sse.js +112 -0
  11. package/dist/{chunks/types-Yy0NrerF.js → ai/adapter/types.js} +1 -1
  12. package/dist/ai/agent/classifier.js +12 -0
  13. package/dist/ai/agent/diff.js +223 -0
  14. package/dist/ai/agent/diffHighlight.js +101 -0
  15. package/dist/ai/agent/permissions.js +29 -0
  16. package/dist/ai/agent/toolfmt.js +383 -0
  17. package/dist/ai/agent/transcript.js +127 -0
  18. package/dist/ai/components/AllocationSelector.js +56 -0
  19. package/dist/ai/components/AttachmentManager.js +147 -0
  20. package/dist/ai/components/AttachmentUpload.js +179 -0
  21. package/dist/ai/components/BlockedGroupBanner.js +29 -0
  22. package/dist/ai/components/BranchNavigator.js +57 -0
  23. package/dist/ai/components/ChatEmptyState.js +171 -0
  24. package/dist/ai/components/ChatInput.js +265 -0
  25. package/dist/ai/components/ChatLayout.js +15 -0
  26. package/dist/ai/components/ChatMessage.js +341 -0
  27. package/dist/ai/components/ChatMessageList.js +301 -0
  28. package/dist/ai/components/ChatSidebar.js +345 -0
  29. package/dist/ai/components/ChatThread.js +198 -0
  30. package/dist/ai/components/ComposerChrome.js +50 -0
  31. package/dist/ai/components/ComposerFrame.js +33 -0
  32. package/dist/ai/components/DragOverlay.js +20 -0
  33. package/dist/ai/components/ModelSelector.js +343 -0
  34. package/dist/ai/components/ShareDialog.js +260 -0
  35. package/dist/ai/components/SlashMenu.js +91 -0
  36. package/dist/ai/components/agent/ActivityLine.js +151 -0
  37. package/dist/ai/components/agent/AgentMessageParts.js +721 -0
  38. package/dist/ai/components/agent/PermissionPicker.js +38 -0
  39. package/dist/ai/components/attachmentKeys.js +10 -0
  40. package/dist/ai/core/ChatProvider.js +848 -0
  41. package/dist/ai/core/KeyboardShortcutsProvider.js +9 -0
  42. package/dist/ai/core/chatReducer.js +223 -0
  43. package/dist/ai/core/config.js +46 -0
  44. package/dist/ai/core/events.js +4 -0
  45. package/dist/ai/core/exportConversation.js +42 -0
  46. package/dist/ai/core/greeting.js +38 -0
  47. package/dist/ai/core/parts.js +84 -0
  48. package/dist/ai/core/useDragDrop.js +36 -0
  49. package/dist/ai/core/useKeyboardShortcuts.js +77 -0
  50. package/dist/ai/core/useSSEStream.js +98 -0
  51. package/dist/ai/index.js +43 -6644
  52. package/dist/ai/strings.js +175 -0
  53. package/dist/ai/ui/Avatar.js +35 -0
  54. package/dist/ai/ui/Dropdown.js +110 -0
  55. package/dist/ai/ui/Markdown.js +79 -0
  56. package/dist/ai/ui/Notice.js +77 -0
  57. package/dist/ai/ui/codeBreaks.js +36 -0
  58. package/dist/ai/ui/prose.js +13 -0
  59. package/dist/ai/ui/sidebar.js +148 -0
  60. package/dist/ai/utils.js +23 -0
  61. package/dist/assets/editor.worker-DfmPPyOL.js +60 -0
  62. package/dist/assets/json.worker-Dqgjpq9F.js +92 -0
  63. package/dist/assets/yaml.worker-DLx0whrM.js +1441 -0
  64. package/dist/components/AddMenu.js +46 -0
  65. package/dist/components/Avatar.js +46 -0
  66. package/dist/{chunks/BareModal-BtRiQezg.js → components/BareModal.js} +1 -1
  67. package/dist/components/Breadcrumbs.js +83 -0
  68. package/dist/components/Button.js +83 -0
  69. package/dist/components/Callout.js +23 -0
  70. package/dist/components/Card.js +31 -0
  71. package/dist/components/CollapsiblePanel.js +77 -0
  72. package/dist/{chunks/ConfirmModal-aOR4O1QE.js → components/ConfirmModal.js} +4 -9
  73. package/dist/components/CopyToClipboard.js +81 -0
  74. package/dist/{chunks/Markdown-CM-FenNE.js → components/CreateModal.js} +9 -116
  75. package/dist/components/DescriptionList.js +42 -0
  76. package/dist/components/Dropdown.js +349 -0
  77. package/dist/components/EmptyState.js +27 -0
  78. package/dist/components/Filter.js +32 -0
  79. package/dist/components/FilterPill.js +13 -0
  80. package/dist/components/IconButton.js +34 -0
  81. package/dist/{chunks/Indicator-hBSIxOPK.js → components/Indicator.js} +1 -1
  82. package/dist/components/Input.js +88 -0
  83. package/dist/components/LetterBadge.js +13 -0
  84. package/dist/components/Listbox.js +123 -0
  85. package/dist/{chunks/Loader-BXoXTZGc.js → components/Loader.js} +1 -1
  86. package/dist/components/Markdown.js +15 -0
  87. package/dist/components/MultiSelect.js +171 -0
  88. package/dist/components/Overview.js +39 -0
  89. package/dist/components/PageHeader.js +194 -0
  90. package/dist/components/Pagination.js +35 -0
  91. package/dist/{chunks/Provider-CDYurraE.js → components/Provider.js} +13 -5
  92. package/dist/{chunks/RequiredMark-DfLdYbYZ.js → components/RequiredMark.js} +1 -1
  93. package/dist/components/SectionHeader.js +11 -0
  94. package/dist/components/SettingModeOption.js +30 -0
  95. package/dist/components/SettingRow.js +35 -0
  96. package/dist/components/SettingsCard.js +31 -0
  97. package/dist/components/SettingsGroup.js +17 -0
  98. package/dist/components/Sort.js +42 -0
  99. package/dist/components/StatusBadge.js +63 -0
  100. package/dist/components/SwitchToggle.js +59 -0
  101. package/dist/{chunks/SwitchToggleSmall-FcsaYSTs.js → components/SwitchToggleSmall.js} +1 -1
  102. package/dist/{chunks/Table-DU2MW8xz.js → components/Table.js} +3 -3
  103. package/dist/components/Toggle.js +20 -0
  104. package/dist/{chunks/Tooltip-K5HJr4_p.js → components/Tooltip.js} +2 -27
  105. package/dist/{chunks/StatusBadge-C1Blx_cW.js → components/dropdownUtils.js} +2 -63
  106. package/dist/{chunks/focus-D_iZJTW1.js → components/focus.js} +1 -1
  107. package/dist/components/ghostButton.js +7 -0
  108. package/dist/components/inputClasses.js +4 -0
  109. package/dist/components/keys.js +27 -0
  110. package/dist/components/relativeTime.js +32 -0
  111. package/dist/{chunks/useCssIsDark-DHr05dG2.js → components/useCssIsDark.js} +1 -1
  112. package/dist/{chunks/duration-BOv8Phl8.js → duration.js} +1 -1
  113. package/dist/editor/Editor.js +13 -0
  114. package/dist/editor/EditorField.js +53 -0
  115. package/dist/editor/FormCodePanel.js +173 -0
  116. package/dist/{chunks/Monaco-DJ8MW-Dq.js → editor/Monaco.js} +5 -26
  117. package/dist/editor/index.js +6 -1
  118. package/dist/editor/themes.js +91 -0
  119. package/dist/editor/workers.d.ts +5 -0
  120. package/dist/editor/workers.js +35 -0
  121. package/dist/editor/yaml.d.ts +9 -1
  122. package/dist/editor/yaml.js +15 -0
  123. package/dist/editor/yaml.worker.d.ts +1 -0
  124. package/dist/editor/yamlLanguage.d.ts +6 -0
  125. package/dist/editor/yamlLanguage.js +312 -0
  126. package/dist/file-explorer/FileExplorer.js +1405 -0
  127. package/dist/file-explorer/FileExplorerContext.js +370 -0
  128. package/dist/{chunks/CodePreviewEditor-YqQBz1YL.js → file-explorer/FilePreview/CodePreviewEditor.js} +3 -2
  129. package/dist/file-explorer/FilePreview/Inline.js +45 -0
  130. package/dist/file-explorer/FilePreview/StreamedBadge.js +16 -0
  131. package/dist/file-explorer/FilePreview/Viewer.js +526 -0
  132. package/dist/file-explorer/FilePreview/index.js +266 -0
  133. package/dist/file-explorer/FilePreview/parse.js +63 -0
  134. package/dist/file-explorer/FilePreview/previewCache.js +98 -0
  135. package/dist/file-explorer/FilePreview/previewType.js +151 -0
  136. package/dist/file-explorer/FilePreview/readCappedBytes.js +196 -0
  137. package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +95 -0
  138. package/dist/file-explorer/FilePreview/useObjectText.js +109 -0
  139. package/dist/file-explorer/FilePreview/usePresignedUrl.js +73 -0
  140. package/dist/file-explorer/FileRow.js +165 -0
  141. package/dist/file-explorer/FileRowsWindow.js +92 -0
  142. package/dist/file-explorer/FileTable.js +172 -0
  143. package/dist/file-explorer/FileTableHeaders.js +49 -0
  144. package/dist/file-explorer/LoadMoreRow.js +46 -0
  145. package/dist/file-explorer/TreeView.js +376 -0
  146. package/dist/file-explorer/helpers.js +537 -0
  147. package/dist/file-explorer/index.js +7 -5671
  148. package/dist/file-explorer/lib/batch.js +39 -0
  149. package/dist/file-explorer/lib/errors.js +9 -0
  150. package/dist/file-explorer/lib/paging.js +124 -0
  151. package/dist/file-explorer/lib/utils.js +322 -0
  152. package/dist/file-explorer/toasts.js +400 -0
  153. package/dist/file-explorer/treeRows.js +73 -0
  154. package/dist/file-explorer/useNearEnd.js +27 -0
  155. package/dist/form/FieldWrapper.js +54 -0
  156. package/dist/form/Fields/BooleanField.js +51 -0
  157. package/dist/form/Fields/CheckboxGroupField.js +72 -0
  158. package/dist/form/Fields/ColorField.js +33 -0
  159. package/dist/form/Fields/DropdownField.js +49 -0
  160. package/dist/form/Fields/DurationField.js +130 -0
  161. package/dist/form/Fields/LabelField.js +19 -0
  162. package/dist/form/Fields/MultiDropdownField.js +40 -0
  163. package/dist/form/Fields/NumberField.js +51 -0
  164. package/dist/form/Fields/ObjectField.js +54 -0
  165. package/dist/form/Fields/RadioField.js +49 -0
  166. package/dist/form/Fields/RangeField.js +58 -0
  167. package/dist/form/Fields/ResourceOptionIcon.js +21 -0
  168. package/dist/form/Fields/StepField.js +6 -0
  169. package/dist/form/Fields/StringField.js +37 -0
  170. package/dist/form/Fields/TextAreaField.js +31 -0
  171. package/dist/form/Fields/durationValidity.js +11 -0
  172. package/dist/form/Form.js +643 -0
  173. package/dist/form/SpecialTypes/DropdownWrapper.js +30 -0
  174. package/dist/form/SpecialTypes/FormikCustomDropdown.js +122 -0
  175. package/dist/form/SpecialTypes/FormikCustomInput.js +111 -0
  176. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +31 -0
  177. package/dist/form/SpecialTypes/FormikNumericInput.js +60 -0
  178. package/dist/form/Wizard/WizardContainer.js +138 -0
  179. package/dist/form/Wizard/WizardNavigation.js +92 -0
  180. package/dist/form/Wizard/WizardStepContent.js +35 -0
  181. package/dist/form/Wizard/WizardStepIndicator.js +108 -0
  182. package/dist/form/Wizard/useWizardState.js +118 -0
  183. package/dist/form/Wizard/utils.js +34 -0
  184. package/dist/form/fieldContext.js +26 -0
  185. package/dist/form/fieldRegistry.js +50 -0
  186. package/dist/form/index.js +17 -2321
  187. package/dist/{chunks/FieldWrapper-Cszwg-4B.js → form/lib.js} +2 -97
  188. package/dist/form/useParsedOpts.js +62 -0
  189. package/dist/form/usePrevious.js +11 -0
  190. package/dist/form/utils/checkShowIfObject.js +14 -0
  191. package/dist/form/utils/duration.js +69 -0
  192. package/dist/form/utils/getParentValue.js +23 -0
  193. package/dist/form/utils/getPlaceholder.js +9 -0
  194. package/dist/form/utils/getValueUsingPath.js +23 -0
  195. package/dist/form/utils/secondaryField.js +22 -0
  196. package/dist/graph/AnnotationBanner.js +141 -0
  197. package/dist/graph/Collapse.js +41 -0
  198. package/dist/graph/DependencyGraph.js +1398 -0
  199. package/dist/graph/JobSummary.js +104 -0
  200. package/dist/graph/MatrixGroup.js +107 -0
  201. package/dist/graph/Reveal.js +57 -0
  202. package/dist/graph/TreeView.js +711 -0
  203. package/dist/graph/index.js +1 -2519
  204. package/dist/graph/types.js +6 -0
  205. package/dist/icons.d.ts +4 -4
  206. package/dist/icons.js +5 -5
  207. package/dist/index.js +46 -599
  208. package/dist/list/ActionToolbar.js +184 -0
  209. package/dist/list/HoverCard.js +73 -0
  210. package/dist/list/ListPage.js +145 -0
  211. package/dist/list/ListPager.js +59 -0
  212. package/dist/list/ListTable.js +163 -0
  213. package/dist/list/ListViewControls.js +372 -0
  214. package/dist/list/RowContextMenu.js +351 -0
  215. package/dist/list/UserHoverCard.js +117 -0
  216. package/dist/list/index.js +11 -2
  217. package/dist/list/listSearch.js +137 -0
  218. package/dist/list/listView.js +210 -0
  219. package/dist/list/textEntry.js +10 -0
  220. package/dist/{chunks/logviewer-BTKuQWzw.js → logviewer/LogViewer.js} +4 -82
  221. package/dist/logviewer/index.js +2 -1
  222. package/dist/logviewer/segments.js +80 -0
  223. package/dist/safeUrl.d.ts +6 -0
  224. package/dist/safeUrl.js +22 -0
  225. package/package.json +7 -9
  226. package/dist/assets/editor.worker-BmHUIVG4.js +0 -14807
  227. package/dist/assets/json.worker-D8bJ92nw.js +0 -22207
  228. package/dist/assets/yaml.worker-C4gyGAko.js +0 -50201
  229. package/dist/chunks/PageHeader-0kG_iypP.js +0 -692
  230. package/dist/chunks/SwitchToggle-DShNdcao.js +0 -758
  231. package/dist/chunks/editor-Dk1rbV75.js +0 -361
  232. package/dist/chunks/list-CJm875m7.js +0 -1418
  233. /package/dist/{chunks/MarkdownImpl-CyeTVvSt.js → components/MarkdownImpl.js} +0 -0
@@ -0,0 +1,42 @@
1
+ import { TooltipInfo } from "./Tooltip.js";
2
+ import cx from "classnames";
3
+ import React from "react";
4
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/components/DescriptionList.tsx
6
+ function DescriptionListItem({ label, children, tooltip, className, ...props }) {
7
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("dt", {
8
+ className: cx("text-[13px] leading-6 col-span-1 font-normal flex gap-1", className),
9
+ children: [/* @__PURE__ */ jsx("span", {
10
+ className: "min-w-0 truncate",
11
+ children: label
12
+ }), tooltip && /* @__PURE__ */ jsx(TooltipInfo, {
13
+ className: "pr-2",
14
+ text: tooltip
15
+ })]
16
+ }), /* @__PURE__ */ jsx("dd", {
17
+ ...props,
18
+ className: "flex text-[13px] leading-6 col-span-4 font-light items-center overflow-auto",
19
+ children
20
+ })] });
21
+ }
22
+ function DescriptionList({ children, title, separators = true, subtitle, className, wrapperClassName, vertical = false }) {
23
+ return /* @__PURE__ */ jsxs("div", {
24
+ className: cx("w-full", wrapperClassName),
25
+ children: [
26
+ title && /* @__PURE__ */ jsx("h2", {
27
+ className: "text-sm font-semibold w-full mb-1",
28
+ children: title
29
+ }),
30
+ subtitle && /* @__PURE__ */ jsx("div", {
31
+ className: "max-w-2xl text-sm/6 w-full",
32
+ children: subtitle
33
+ }),
34
+ /* @__PURE__ */ jsx("dl", {
35
+ className: cx("grid", separators && "*:not-last-of-type:border-b-1", vertical ? "grid-cols-1" : "grid-cols-5 gap-x-4 gap-y-0.5 *:pb-0.5", className),
36
+ children: Array.isArray(children) ? React.Children.toArray(children) : children
37
+ })
38
+ ]
39
+ });
40
+ }
41
+ //#endregion
42
+ export { DescriptionListItem, DescriptionList as default };
@@ -0,0 +1,349 @@
1
+ import { useStrings } from "./Provider.js";
2
+ import { CaretDownIcon } from "../icons.js";
3
+ import { truncationTooltipProps } from "./Tooltip.js";
4
+ import { DropdownCaret, flattenDisplayOptions, isCategory, toggleSetMember } from "./dropdownUtils.js";
5
+ import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions } from "@headlessui/react";
6
+ import cx from "classnames";
7
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
8
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
+ import { createPortal } from "react-dom";
10
+ import deepEqual from "fast-deep-equal";
11
+ import { usePopper } from "react-popper";
12
+ //#region src/components/Dropdown.tsx
13
+ var defaultCollapsedLabel = (count) => `${count} more`;
14
+ function isNamedValue(value) {
15
+ return typeof value === "object" && value !== null && "name" in value && typeof value.name === "string";
16
+ }
17
+ var checkEquals = (val, opt) => {
18
+ if (typeof val === "object" && !Array.isArray(val)) return deepEqual(val, opt);
19
+ return val === opt;
20
+ };
21
+ function getOptionFromValue(value, options) {
22
+ if (value === void 0) return {
23
+ label: "",
24
+ value: ""
25
+ };
26
+ const found = options?.find((option) => {
27
+ if (typeof option === "string") return checkEquals(value, option);
28
+ else if (isCategory(option)) return option.options.find((opt) => checkEquals(value, opt.value));
29
+ else return checkEquals(value, option.value);
30
+ });
31
+ if (found) {
32
+ if (typeof found === "string") return {
33
+ label: found,
34
+ value: found
35
+ };
36
+ else if (isCategory(found)) return found.options.find((opt) => checkEquals(value, opt.value)) || {
37
+ label: JSON.stringify(value),
38
+ value
39
+ };
40
+ else return found;
41
+ }
42
+ const isNamedObject = isNamedValue(value);
43
+ const fallbackLabel = typeof value === "string" ? value : isNamedObject ? value.name : JSON.stringify(value);
44
+ return {
45
+ label: fallbackLabel,
46
+ value: isNamedObject ? value : fallbackLabel
47
+ };
48
+ }
49
+ function Dropdown(props) {
50
+ const { onChange, value, options = [], ...others } = props;
51
+ const val = useMemo(() => {
52
+ return getOptionFromValue(value, options);
53
+ }, [value, options]);
54
+ const wrapperOnchange = (value) => {
55
+ if (onChange) onChange(value?.value);
56
+ };
57
+ const transformedOptions = useMemo(() => {
58
+ if (!options || options.length === 0) return [];
59
+ return options.map((item) => {
60
+ if (isCategory(item)) return {
61
+ ...item,
62
+ options: item.options.map((opt) => {
63
+ if (typeof opt === "string") return {
64
+ label: opt,
65
+ value: opt
66
+ };
67
+ return opt;
68
+ })
69
+ };
70
+ else if (typeof item === "string") return {
71
+ label: item,
72
+ value: item
73
+ };
74
+ return item;
75
+ });
76
+ }, [options]);
77
+ return /* @__PURE__ */ jsx(DropdownHelper, {
78
+ value: val,
79
+ onChange: wrapperOnchange,
80
+ options: transformedOptions,
81
+ ...others
82
+ });
83
+ }
84
+ function ActiveWatcher({ active, onChange }) {
85
+ const prev = useRef(null);
86
+ useEffect(() => {
87
+ if (prev.current !== active) {
88
+ onChange?.(active?.value);
89
+ prev.current = active;
90
+ }
91
+ }, [active, onChange]);
92
+ return null;
93
+ }
94
+ function OptionContent({ label, description, icon }) {
95
+ return /* @__PURE__ */ jsxs("span", {
96
+ className: cx("flex gap-1.5", description ? "items-start min-w-0" : "items-center truncate"),
97
+ ...truncationTooltipProps(label, (anchor) => anchor.lastElementChild),
98
+ children: [icon, description ? /* @__PURE__ */ jsxs("span", {
99
+ className: "flex flex-col min-w-0",
100
+ children: [/* @__PURE__ */ jsx("span", {
101
+ className: "truncate",
102
+ children: label
103
+ }), /* @__PURE__ */ jsx("span", {
104
+ className: "text-(--theme-muted-text-color) text-xs leading-snug",
105
+ children: description
106
+ })]
107
+ }) : /* @__PURE__ */ jsx("span", {
108
+ className: "truncate",
109
+ children: label
110
+ })]
111
+ });
112
+ }
113
+ function ToggleOption({ option, category, expanded, onToggle, ...virtualRowProps }) {
114
+ return /* @__PURE__ */ jsx(ComboboxOption, {
115
+ ...virtualRowProps,
116
+ "data-testid": "combobox-toggle",
117
+ value: option,
118
+ className: "w-full h-10 flex items-center pl-3",
119
+ children: /* @__PURE__ */ jsxs("button", {
120
+ type: "button",
121
+ "aria-expanded": expanded,
122
+ className: "flex items-center gap-1.5 cursor-pointer text-(--theme-muted-text-color) hover:text-(--theme-app)",
123
+ onMouseDown: (e) => e.preventDefault(),
124
+ onClick: (e) => {
125
+ e.preventDefault();
126
+ e.stopPropagation();
127
+ onToggle(category);
128
+ },
129
+ children: [/* @__PURE__ */ jsx(CaretDownIcon, { className: cx("w-3 h-3", !expanded && "-rotate-90") }), option.label]
130
+ })
131
+ });
132
+ }
133
+ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassName = "w-full", options = [], onChange, onActiveChange, value, id, ariaLabel, "aria-describedby": describedBy, required, disabled = false, placeholder = "", loading = false, allowCustomValue = false, customValueLabel = "Use", collapsedLabel = defaultCollapsedLabel, portalEl, compact = false }) {
134
+ const DEBOUNCE_MS = 500;
135
+ const t = useStrings().dropdown;
136
+ const [query, setQuery] = useState("");
137
+ const [selectedIconWidth, setSelectedIconWidth] = useState(0);
138
+ const selectedIconRef = useCallback((node) => {
139
+ setSelectedIconWidth(node?.offsetWidth ?? 0);
140
+ }, []);
141
+ const selectedIcon = query === "" ? value?.icon : void 0;
142
+ const [referenceElement, setReferenceElement] = useState(null);
143
+ const [popperElement, setPopperElement] = useState(null);
144
+ const [boundaryEl, setBoundaryEl] = useState(null);
145
+ useEffect(() => {
146
+ if (!referenceElement) {
147
+ setBoundaryEl(null);
148
+ return;
149
+ }
150
+ const ref = referenceElement;
151
+ const dialog = ref.closest("[role=\"dialog\"]");
152
+ if (!dialog) {
153
+ setBoundaryEl(null);
154
+ return;
155
+ }
156
+ let node = ref.parentElement;
157
+ while (node) {
158
+ const style = getComputedStyle(node);
159
+ if (/(auto|scroll|hidden)/.test(`${style.overflowX} ${style.overflowY}`)) {
160
+ setBoundaryEl(node);
161
+ return;
162
+ }
163
+ if (node === dialog) break;
164
+ node = node.parentElement;
165
+ }
166
+ setBoundaryEl(dialog);
167
+ }, [referenceElement]);
168
+ const sameWidthModifier = useMemo(() => ({
169
+ name: "sameWidth",
170
+ enabled: true,
171
+ phase: "beforeWrite",
172
+ requires: ["computeStyles"],
173
+ fn: ({ state }) => {
174
+ const popperStyles = state.styles["popper"];
175
+ if (popperStyles) popperStyles.width = `${state.rects.reference.width}px`;
176
+ },
177
+ effect: ({ state }) => {
178
+ const { popper, reference } = state.elements;
179
+ if (reference instanceof HTMLElement) popper.style.width = `${reference.offsetWidth}px`;
180
+ }
181
+ }), []);
182
+ const popperModifiers = useMemo(() => boundaryEl ? [
183
+ sameWidthModifier,
184
+ {
185
+ name: "flip",
186
+ options: { boundary: boundaryEl }
187
+ },
188
+ {
189
+ name: "preventOverflow",
190
+ options: { boundary: boundaryEl }
191
+ }
192
+ ] : [sameWidthModifier], [boundaryEl, sameWidthModifier]);
193
+ const { styles, attributes } = usePopper(referenceElement, popperElement, {
194
+ strategy: "fixed",
195
+ modifiers: popperModifiers
196
+ });
197
+ const debounceRef = useRef(null);
198
+ const buttonRef = useRef(null);
199
+ const [expandedCategories, setExpandedCategories] = useState(/* @__PURE__ */ new Set());
200
+ const selectedCategory = useMemo(() => options.find((o) => isCategory(o) && o.options.some((opt) => checkEquals(value.value, opt.value)))?.category, [options, value]);
201
+ const lastAutoExpandedValue = useRef(void 0);
202
+ useEffect(() => {
203
+ if (!selectedCategory || checkEquals(lastAutoExpandedValue.current, value.value)) return;
204
+ lastAutoExpandedValue.current = value.value;
205
+ setExpandedCategories((prev) => prev.size === 1 && prev.has(selectedCategory) ? prev : /* @__PURE__ */ new Set([selectedCategory]));
206
+ }, [selectedCategory, value]);
207
+ const toggleCategory = (category) => setExpandedCategories((prev) => toggleSetMember(prev, category));
208
+ const flushCustomValue = useCallback((val) => {
209
+ onChange({
210
+ label: val,
211
+ value: val
212
+ });
213
+ }, [onChange]);
214
+ const onQueryChange = (val) => {
215
+ setQuery(val);
216
+ if (allowCustomValue) {
217
+ if (debounceRef.current) clearTimeout(debounceRef.current);
218
+ debounceRef.current = setTimeout(() => {
219
+ flushCustomValue(val);
220
+ debounceRef.current = null;
221
+ }, DEBOUNCE_MS);
222
+ }
223
+ };
224
+ const onInputBlur = () => {
225
+ if (allowCustomValue && debounceRef.current) {
226
+ clearTimeout(debounceRef.current);
227
+ debounceRef.current = null;
228
+ flushCustomValue(query);
229
+ }
230
+ setQuery("");
231
+ };
232
+ const onComboboxChange = (val) => {
233
+ if (debounceRef.current) {
234
+ clearTimeout(debounceRef.current);
235
+ debounceRef.current = null;
236
+ }
237
+ onChange(val);
238
+ };
239
+ const flattenedOptions = useMemo(() => flattenDisplayOptions({
240
+ options,
241
+ query,
242
+ expandedCategories,
243
+ collapsedLabel,
244
+ selectedValue: value?.value,
245
+ allowCustomValue,
246
+ customValueLabel
247
+ }), [
248
+ options,
249
+ query,
250
+ expandedCategories,
251
+ collapsedLabel,
252
+ value,
253
+ allowCustomValue,
254
+ customValueLabel
255
+ ]);
256
+ const comboOptions = /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(ComboboxOptions, {
257
+ modal: false,
258
+ ref: setPopperElement,
259
+ style: styles["popper"],
260
+ className: cx("bg-(--theme-input-bg) border-(--theme-border) text-(--theme-app) max-h-60! empty:invisible border overflow-auto rounded-md shadow-lg focus:outline-hidden z-9999 data-[popper-reference-hidden=true]:invisible data-[popper-reference-hidden=true]:pointer-events-none", compact ? "text-xs" : "sm:text-sm"),
261
+ ...attributes["popper"],
262
+ children: ({ option }) => {
263
+ const optionLabel = typeof option === "string" ? option : option.label;
264
+ const optionDescription = typeof option !== "string" ? option.description : void 0;
265
+ const isCategoryRow = typeof option !== "string" && Boolean(option.category);
266
+ const toggleTarget = typeof option !== "string" ? option.toggle : void 0;
267
+ const isPinned = typeof option !== "string" && Boolean(option.pinned);
268
+ if (toggleTarget !== void 0) return /* @__PURE__ */ jsx(ToggleOption, {
269
+ option,
270
+ category: toggleTarget,
271
+ expanded: expandedCategories.has(toggleTarget),
272
+ onToggle: toggleCategory
273
+ });
274
+ return /* @__PURE__ */ jsx(ComboboxOption, {
275
+ "data-testid": "combobox-option",
276
+ value: option,
277
+ className: cx("w-full group relative flex", optionDescription ? "min-h-10 py-2" : compact ? "h-8" : "h-10", isCategoryRow ? "text-[14px] font-bold pl-1 items-center" : "data-disabled:text-(--theme-muted-text-color) data-disabled:bg-(--theme-muted-panel-bg) data-disabled:cursor-not-allowed cursor-pointer items-center pr-9 pl-3 leading-5 data-focus:bg-(--theme-muted-panel-bg) data-focus:text-(--theme-app) data-focus:outline-hidden", "data-selected:border-l-2 data-selected:border-(--theme-link) data-selected:bg-(--theme-muted-panel-bg) data-selected:text-(--theme-app)", isPinned && "border-t border-(--theme-border) font-medium"),
278
+ children: /* @__PURE__ */ jsx(OptionContent, {
279
+ label: optionLabel,
280
+ description: optionDescription,
281
+ icon: typeof option !== "string" && option.icon
282
+ })
283
+ });
284
+ }
285
+ }) });
286
+ return /* @__PURE__ */ jsx("div", {
287
+ className: cx("relative rounded-md flex items-center", wrapperClassName),
288
+ children: /* @__PURE__ */ jsx(Combobox, {
289
+ "data-testid": "combobox",
290
+ className: cx("relative w-full", className),
291
+ as: "div",
292
+ by: checkEquals,
293
+ value,
294
+ onChange: onComboboxChange,
295
+ onClose: () => {
296
+ setQuery("");
297
+ setExpandedCategories(new Set(selectedCategory ? [selectedCategory] : []));
298
+ },
299
+ immediate: true,
300
+ virtual: {
301
+ options: flattenedOptions,
302
+ disabled: (option) => Boolean(option.disabled)
303
+ },
304
+ disabled,
305
+ children: ({ activeOption, open }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
306
+ onActiveChange && /* @__PURE__ */ jsx(ActiveWatcher, {
307
+ active: activeOption,
308
+ onChange: onActiveChange
309
+ }),
310
+ selectedIcon && /* @__PURE__ */ jsx("span", {
311
+ ref: selectedIconRef,
312
+ className: "pointer-events-none absolute inset-y-0 left-3 z-10 flex items-center",
313
+ children: selectedIcon
314
+ }, value.label),
315
+ /* @__PURE__ */ jsx(ComboboxInput, {
316
+ id,
317
+ "aria-label": ariaLabel || void 0,
318
+ "aria-describedby": describedBy,
319
+ "aria-required": required || void 0,
320
+ placeholder: loading ? "Loading..." : placeholder,
321
+ onBlur: onInputBlur,
322
+ ref: setReferenceElement,
323
+ onClick: () => {
324
+ if (!open) buttonRef.current?.click();
325
+ },
326
+ style: selectedIcon && selectedIconWidth > 0 ? { paddingLeft: selectedIconWidth + 18 } : void 0,
327
+ className: cx("placeholder:text-xs bg-(--theme-input-bg) border-(--theme-border) text-(--theme-app) focus:border-(--theme-element) focus:outline-none focus:ring-1 focus:ring-(--theme-element) w-full h-full text-ellipsis pr-8", "disabled:bg-(--theme-input-disabled-bg) disabled:text-(--theme-input-disabled-text) disabled:cursor-not-allowed", textBoxClassName),
328
+ autoComplete: "off",
329
+ onChange: (event) => onQueryChange(event.target.value),
330
+ displayValue: (opt) => {
331
+ return opt?.label?.replaceAll("\"", "") || query || "";
332
+ },
333
+ disabled
334
+ }),
335
+ /* @__PURE__ */ jsx(ComboboxButton, {
336
+ ref: buttonRef,
337
+ "aria-label": t.showOptions,
338
+ className: "absolute inset-y-0 right-0 flex items-center pr-3 disabled:cursor-not-allowed",
339
+ "data-testid": "combobox-button",
340
+ disabled,
341
+ children: /* @__PURE__ */ jsx(DropdownCaret, {})
342
+ }),
343
+ typeof document !== "undefined" && createPortal(comboOptions, portalEl ?? document.querySelector(".ds-root") ?? document.body)
344
+ ] })
345
+ })
346
+ });
347
+ }
348
+ //#endregion
349
+ export { Dropdown as default };
@@ -0,0 +1,27 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ //#region src/components/EmptyState.tsx
3
+ function EmptyState({ title, description, action, icon: Icon }) {
4
+ return /* @__PURE__ */ jsxs("div", {
5
+ className: "border-solid rounded-2xl border border-(--theme-border) theme-panel flex flex-col items-center justify-center py-12 px-6",
6
+ children: [
7
+ Icon && /* @__PURE__ */ jsx("div", {
8
+ className: "w-10 h-10 rounded-full bg-(--theme-muted-panel-bg) flex items-center justify-center mb-3",
9
+ children: /* @__PURE__ */ jsx(Icon, { className: "w-5 h-5 theme-muted-text" })
10
+ }),
11
+ /* @__PURE__ */ jsx("p", {
12
+ className: "text-sm font-medium mb-1",
13
+ children: title
14
+ }),
15
+ description && /* @__PURE__ */ jsx("p", {
16
+ className: "text-xs theme-muted-text text-center max-w-xs",
17
+ children: description
18
+ }),
19
+ action && /* @__PURE__ */ jsx("div", {
20
+ className: "mt-4",
21
+ children: action
22
+ })
23
+ ]
24
+ });
25
+ }
26
+ //#endregion
27
+ export { EmptyState as default };
@@ -0,0 +1,32 @@
1
+ import { FilterIcon } from "../icons.js";
2
+ import cx from "classnames";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/components/Filter.tsx
5
+ function Filter({ filter, setFilter, placeholder = "Filter...", pills, activePill, onPillChange }) {
6
+ return /* @__PURE__ */ jsxs("div", {
7
+ className: "flex items-center gap-2",
8
+ children: [/* @__PURE__ */ jsxs("div", {
9
+ className: "relative flex items-center",
10
+ children: [/* @__PURE__ */ jsx("input", {
11
+ placeholder,
12
+ type: "text",
13
+ value: filter,
14
+ onChange: (e) => setFilter(e.target.value.toLowerCase()),
15
+ className: "shadow-sm focus:ring-1 block w-full pr-3 sm:text-sm theme-border rounded-md py-1.5 pl-8"
16
+ }), /* @__PURE__ */ jsx("div", {
17
+ className: "absolute inset-y-0 left-0 flex py-2.5 pl-2",
18
+ children: /* @__PURE__ */ jsx(FilterIcon, {})
19
+ })]
20
+ }), pills && onPillChange && /* @__PURE__ */ jsx("div", {
21
+ className: "flex gap-1",
22
+ children: pills.map((pill) => /* @__PURE__ */ jsx("button", {
23
+ type: "button",
24
+ onClick: () => onPillChange(pill.value),
25
+ className: cx("px-2.5 py-1 text-xs rounded-full transition-colors border", activePill === pill.value ? "bg-(--theme-element) text-(--theme-element-text) border-transparent" : "theme-border theme-text hover:theme-hover"),
26
+ children: pill.label
27
+ }, pill.value))
28
+ })]
29
+ });
30
+ }
31
+ //#endregion
32
+ export { Filter as default };
@@ -0,0 +1,13 @@
1
+ import cx from "classnames";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/components/FilterPill.tsx
4
+ function FilterPill({ active, onClick, children }) {
5
+ return /* @__PURE__ */ jsx("button", {
6
+ type: "button",
7
+ onClick,
8
+ className: cx("px-3 py-1.5 text-xs font-medium rounded-full border transition-all duration-200", active ? "bg-[var(--theme-panel-bg)] border-[var(--theme-border)] text-[var(--theme-panel)] shadow-sm" : "bg-transparent border-transparent text-[var(--theme-muted-text-color)] hover:text-[var(--theme-panel)] hover:bg-[var(--theme-hover)]"),
9
+ children
10
+ });
11
+ }
12
+ //#endregion
13
+ export { FilterPill };
@@ -0,0 +1,34 @@
1
+ import { TOOLTIP_ID } from "./Tooltip.js";
2
+ import cx from "classnames";
3
+ import { forwardRef } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/components/IconButton.tsx
6
+ var IconButton = forwardRef(({ icon, label, variant = "default", size = "md", active = false, showTooltip = true, className, disabled, ...props }, ref) => {
7
+ const sizeClasses = {
8
+ sm: "w-7 h-7 [&_svg]:w-3.5 [&_svg]:h-3.5",
9
+ md: "w-9 h-9 [&_svg]:w-4 [&_svg]:h-4",
10
+ lg: "w-11 h-11 [&_svg]:w-5 [&_svg]:h-5"
11
+ };
12
+ const variantClasses = {
13
+ default: cx("bg-[var(--theme-muted-panel-bg)] text-[var(--theme-muted-text-color)]", "hover:bg-[var(--theme-border)] hover:text-[var(--theme-app)]", active && "bg-[var(--theme-element)]/10 text-[var(--theme-element)]"),
14
+ ghost: cx("bg-transparent text-[var(--theme-muted-text-color)]", "hover:bg-[var(--theme-muted-panel-bg)] hover:text-[var(--theme-app)]", active && "text-[var(--theme-element)]"),
15
+ primary: cx("bg-[var(--theme-element)] text-white", "hover:bg-[var(--theme-element)]/90", active && "ring-2 ring-[var(--theme-element)]/50"),
16
+ success: cx("bg-[#22c55e] text-white", "hover:bg-[#22c55e]/90", active && "ring-2 ring-[#22c55e]/50")
17
+ };
18
+ return /* @__PURE__ */ jsx("button", {
19
+ ref,
20
+ type: "button",
21
+ "aria-label": label,
22
+ disabled,
23
+ ...showTooltip ? { "data-tooltip-id": TOOLTIP_ID } : {},
24
+ "data-tooltip-content": label,
25
+ "data-tooltip-delay-show": 300,
26
+ "data-tooltip-class-name": "!bg-[var(--theme-app)] !text-[var(--theme-app-bg)] !text-xs !py-1 !px-2 !rounded-md",
27
+ className: cx("inline-flex items-center justify-center rounded-lg", "transition-all duration-200 cursor-pointer", "disabled:opacity-50 disabled:cursor-not-allowed", sizeClasses[size], variantClasses[variant], className),
28
+ ...props,
29
+ children: icon
30
+ });
31
+ });
32
+ IconButton.displayName = "IconButton";
33
+ //#endregion
34
+ export { IconButton };
@@ -36,4 +36,4 @@ function Indicator({ status }) {
36
36
  });
37
37
  }
38
38
  //#endregion
39
- export { Indicator as t };
39
+ export { Indicator };
@@ -0,0 +1,88 @@
1
+ import { AlertIcon, EyeIcon, EyeOffIcon } from "../icons.js";
2
+ import { RequiredMark } from "./RequiredMark.js";
3
+ import cx from "classnames";
4
+ import { forwardRef, useId, useState } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/Input.tsx
7
+ var Input = forwardRef(({ label, error, className = "", mono, type, required, ...props }, ref) => {
8
+ const [showPassword, setShowPassword] = useState(false);
9
+ const isPassword = type === "password";
10
+ const inputType = isPassword && showPassword ? "text" : type;
11
+ const generatedId = useId();
12
+ const id = props.id ?? generatedId;
13
+ const errorId = `${id}-error`;
14
+ const describedBy = [props["aria-describedby"], error ? errorId : void 0].filter(Boolean).join(" ") || void 0;
15
+ const inputClasses = cx("w-full py-3 px-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-lg text-[var(--theme-app)] text-sm transition-all duration-200 box-border", "focus:outline-none focus:border-[var(--theme-element)] focus:shadow-[0_0_0_3px_color-mix(in_srgb,var(--theme-element)_25%,transparent)]", "placeholder:text-[var(--theme-muted-text-color)]", "disabled:bg-[var(--theme-muted-panel-bg)] disabled:text-[var(--theme-muted-text-color)] disabled:cursor-not-allowed disabled:opacity-70", mono && "font-mono text-[0.8125rem]", error && "border-[#ef4444]", isPassword && "pr-11", className);
16
+ return /* @__PURE__ */ jsxs("div", {
17
+ className: "flex flex-col gap-1.5",
18
+ children: [
19
+ label && /* @__PURE__ */ jsxs("label", {
20
+ className: "text-[0.8125rem] font-medium text-[var(--theme-app)]",
21
+ htmlFor: id,
22
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
23
+ }),
24
+ /* @__PURE__ */ jsxs("div", {
25
+ className: isPassword ? "relative w-full" : "",
26
+ children: [/* @__PURE__ */ jsx("input", {
27
+ ref,
28
+ type: inputType,
29
+ className: inputClasses,
30
+ ...props,
31
+ id,
32
+ required,
33
+ "aria-invalid": error ? true : props["aria-invalid"],
34
+ "aria-describedby": describedBy
35
+ }), isPassword && /* @__PURE__ */ jsx("button", {
36
+ type: "button",
37
+ className: "absolute right-3 top-1/2 -translate-y-1/2 bg-transparent border-none text-[var(--theme-muted-text-color)] cursor-pointer p-1 transition-colors duration-200 flex items-center justify-center hover:text-[var(--theme-app)]",
38
+ onClick: () => setShowPassword(!showPassword),
39
+ tabIndex: -1,
40
+ "aria-label": showPassword ? "Hide password" : "Show password",
41
+ children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, { className: "w-5 h-5" }) : /* @__PURE__ */ jsx(EyeIcon, { className: "w-5 h-5" })
42
+ })]
43
+ }),
44
+ error && /* @__PURE__ */ jsxs("span", {
45
+ id: errorId,
46
+ role: "alert",
47
+ className: "text-[0.8125rem] text-[#ef4444] flex items-center gap-1.5",
48
+ children: [/* @__PURE__ */ jsx(AlertIcon, { className: "w-4 h-4" }), error]
49
+ })
50
+ ]
51
+ });
52
+ });
53
+ Input.displayName = "Input";
54
+ var Textarea = forwardRef(({ label, error, className = "", mono, required, ...props }, ref) => {
55
+ const generatedId = useId();
56
+ const id = props.id ?? generatedId;
57
+ const errorId = `${id}-error`;
58
+ const describedBy = [props["aria-describedby"], error ? errorId : void 0].filter(Boolean).join(" ") || void 0;
59
+ const textareaClasses = cx("w-full py-3 px-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-lg text-[var(--theme-app)] text-sm transition-all duration-200 box-border min-h-[140px] resize-y", "focus:outline-none focus:border-[var(--theme-element)] focus:shadow-[0_0_0_3px_color-mix(in_srgb,var(--theme-element)_25%,transparent)]", "placeholder:text-[var(--theme-muted-text-color)]", mono && "font-mono text-[0.8125rem]", error && "border-[#ef4444]", className);
60
+ return /* @__PURE__ */ jsxs("div", {
61
+ className: "flex flex-col gap-1.5",
62
+ children: [
63
+ label && /* @__PURE__ */ jsxs("label", {
64
+ className: "text-[0.8125rem] font-medium text-[var(--theme-app)]",
65
+ htmlFor: id,
66
+ children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
67
+ }),
68
+ /* @__PURE__ */ jsx("textarea", {
69
+ ref,
70
+ className: textareaClasses,
71
+ ...props,
72
+ id,
73
+ required,
74
+ "aria-invalid": error ? true : props["aria-invalid"],
75
+ "aria-describedby": describedBy
76
+ }),
77
+ error && /* @__PURE__ */ jsxs("span", {
78
+ id: errorId,
79
+ role: "alert",
80
+ className: "text-[0.8125rem] text-[#ef4444] flex items-center gap-1.5",
81
+ children: [/* @__PURE__ */ jsx(AlertIcon, { className: "w-4 h-4" }), error]
82
+ })
83
+ ]
84
+ });
85
+ });
86
+ Textarea.displayName = "Textarea";
87
+ //#endregion
88
+ export { Input, Textarea };
@@ -0,0 +1,13 @@
1
+ import cx from "classnames";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/components/LetterBadge.tsx
4
+ /** A compact letter badge ("AI", "PUB", "SSH") used as a type mark in place of
5
+ * an icon. Size the box and text via className (e.g. "h-5 w-5 text-[8px]"). */
6
+ function LetterBadge({ text, className }) {
7
+ return /* @__PURE__ */ jsx("span", {
8
+ className: cx("inline-flex shrink-0 items-center justify-center rounded-[3px] border theme-border font-bold leading-none tracking-tight text-(--theme-app)", className),
9
+ children: text
10
+ });
11
+ }
12
+ //#endregion
13
+ export { LetterBadge };