@neuronection/assistant-ui 0.6.0 → 0.7.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 (51) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +2 -0
  3. package/dist/ai-magic-fill.js +1 -1
  4. package/dist/chunk-AHLNXCP2.js +74 -0
  5. package/dist/chunk-AHLNXCP2.js.map +1 -0
  6. package/dist/chunk-FE26R5RN.js +63 -0
  7. package/dist/chunk-FE26R5RN.js.map +1 -0
  8. package/dist/{chunk-L4NM55XW.js → chunk-I2RXO6ZU.js} +3 -3
  9. package/dist/{chunk-L4NM55XW.js.map → chunk-I2RXO6ZU.js.map} +1 -1
  10. package/dist/chunk-IQKP2BWE.js +78 -0
  11. package/dist/chunk-IQKP2BWE.js.map +1 -0
  12. package/dist/chunk-J4OELYDR.js +125 -0
  13. package/dist/chunk-J4OELYDR.js.map +1 -0
  14. package/dist/chunk-RJSN4TVT.js +89 -0
  15. package/dist/chunk-RJSN4TVT.js.map +1 -0
  16. package/dist/chunk-RLFND34I.js +3 -0
  17. package/dist/chunk-RLFND34I.js.map +1 -0
  18. package/dist/chunk-UWHUCQC6.js +73 -0
  19. package/dist/chunk-UWHUCQC6.js.map +1 -0
  20. package/dist/chunk-VKV464ZF.js +3 -0
  21. package/dist/chunk-VKV464ZF.js.map +1 -0
  22. package/dist/chunk-W2HORE44.js +92 -0
  23. package/dist/chunk-W2HORE44.js.map +1 -0
  24. package/dist/{chunk-W5WDGME5.js → chunk-XHHEAJHN.js} +8 -5
  25. package/dist/chunk-XHHEAJHN.js.map +1 -0
  26. package/dist/combobox.d.ts +1 -0
  27. package/dist/combobox.js +1 -1
  28. package/dist/connection-test-row.js +1 -71
  29. package/dist/connection-test-row.js.map +1 -1
  30. package/dist/file-card.d.ts +25 -0
  31. package/dist/file-card.js +3 -0
  32. package/dist/file-card.js.map +1 -0
  33. package/dist/file-queue.d.ts +32 -0
  34. package/dist/file-queue.js +3 -0
  35. package/dist/file-queue.js.map +1 -0
  36. package/dist/index.d.ts +30 -2
  37. package/dist/index.js +143 -5
  38. package/dist/index.js.map +1 -1
  39. package/dist/model-picker.d.ts +38 -0
  40. package/dist/model-picker.js +3 -0
  41. package/dist/model-picker.js.map +1 -0
  42. package/dist/provider-form.js +1 -87
  43. package/dist/provider-form.js.map +1 -1
  44. package/dist/settings-shell.js +1 -72
  45. package/dist/settings-shell.js.map +1 -1
  46. package/dist/styles.css +1 -1
  47. package/dist/task-assignment-picker.d.ts +27 -0
  48. package/dist/task-assignment-picker.js +3 -0
  49. package/dist/task-assignment-picker.js.map +1 -0
  50. package/package.json +21 -1
  51. package/dist/chunk-W5WDGME5.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @neuronection/assistant-ui
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`8022462`](https://github.com/neuronection/assistant-ui/commit/80224625682e6f59b1d40e2622f4935a50494063) Thanks [@constLiakos](https://github.com/constLiakos)! - Phase-4 file-attachment surface (presentational; upload controllers stay
8
+ app-side): `UploadDropzone` (block/row variants, drag events + file-picker
9
+ results out via `onFiles`, optional folder picker, uploading state),
10
+ `FileCard` (name/size/status/thumbnail, remove, include-in-processing
11
+ toggle) and `FileQueue` (aggregate summary, drag-to-reorder intent via
12
+ `onReorder(fromId, toId)`).
13
+
14
+ - [`58445ab`](https://github.com/neuronection/assistant-ui/commit/58445ab109ec5c9dce8073b04b9f780f11d8ad50) Thanks [@constLiakos](https://github.com/constLiakos)! - Phase-4 settings-trio blocks (part 2): `ModelPicker` (grouped, searchable
15
+ provider → model combobox with capability chips) and
16
+ `TaskAssignmentPicker` (task → model mapping rows with inline pickers and
17
+ clear buttons). `ComboboxOption` gains an optional `badge` chip.
18
+
19
+ ### Patch Changes
20
+
21
+ - [`6202ef0`](https://github.com/neuronection/assistant-ui/commit/6202ef0957e2edaaecdd9dce8aa8d25ca5d65344) Thanks [@constLiakos](https://github.com/constLiakos)! - Fix the package-root re-exports for `SettingsShell`, `ProviderForm` and
22
+ `ConnectionTestRow` (missing from `index.d.ts` in 0.6.0 — the per-module
23
+ entry points `/settings-shell`, `/provider-form`, `/connection-test-row`
24
+ were unaffected).
25
+
3
26
  ## 0.6.0
4
27
 
5
28
  ### Minor Changes
package/README.md CHANGED
@@ -88,10 +88,12 @@ files in the package's `dist/`. Visual reference:
88
88
  | `check-indicator` / `selection-bar` / `view-toggle` | `CheckIndicator` (tri-state) · `SelectionBar` (bulk-select bar) · `ViewToggle` (grid/list) |
89
89
  | `error-banner` / `undo-notice` / `empty-state` / `spinner` | presentational feedback: alert banner with `action` slot · undo toast · `EmptyState` · `Spinner` |
90
90
  | `info-button` / `field-label` | `InfoButton` (info popover) · `FieldLabel` (label + info affordance) |
91
+ | `model-picker` / `task-assignment-picker` | `ModelPicker` (grouped provider→model combobox, capability chips) · `TaskAssignmentPicker` (task → model mapping rows) |
91
92
  | `settings-shell` / `provider-form` / `connection-test-row` | `SettingsShell` (controlled two-pane nav) · `ProviderForm` (write-only key field) · `ConnectionTestRow` (idle/testing/ok/fail) |
92
93
  | `copy-button` / `breadcrumbs` | `CopyButton` (clipboard + copied state) · `Breadcrumbs` (SPA links via `linkComponent`) |
93
94
  | `ai-magic-fill` | `AiMagicFill` (describe-in-words → structured data prompt modal; app applies the data) |
94
95
  | `ai-button` / `ai-actions-dropdown` | `AiButton` (suggestions + prompt + response slot) · `AiActionsDropdown` (action list + custom prompt) |
96
+ | `upload-dropzone` / `file-card` / `file-queue` | file attachment surface: dropzone (block/row) · card (status, include toggle) · queue (summary + reorder) |
95
97
  | `marquee` | `useMarquee`, `MarqueeSurface`, `MarqueeBand` (rubber-band selection) |
96
98
  | `portal` / `theme-scope` / `tokens` | `Portal` · `ThemeScope` · token name lists + types |
97
99
 
@@ -1,3 +1,3 @@
1
- export { AiMagicFill } from './chunk-L4NM55XW.js';
1
+ export { AiMagicFill } from './chunk-I2RXO6ZU.js';
2
2
  //# sourceMappingURL=ai-magic-fill.js.map
3
3
  //# sourceMappingURL=ai-magic-fill.js.map
@@ -0,0 +1,74 @@
1
+ import { cn } from './chunk-BLJWR4ZV.js';
2
+ import * as React from 'react';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ var SettingsShell = React.forwardRef(
6
+ function SettingsShell2({ nav, active, onNavigate, header, children, className, navClassName }, ref) {
7
+ const HeaderIcon = header?.icon;
8
+ return /* @__PURE__ */ jsxs(
9
+ "div",
10
+ {
11
+ ref,
12
+ "data-as": "settings-shell",
13
+ className: cn("grid grid-cols-1 gap-8 lg:grid-cols-4", className),
14
+ children: [
15
+ /* @__PURE__ */ jsx("nav", { className: "lg:col-span-1", "aria-label": "Settings sections", children: /* @__PURE__ */ jsxs(
16
+ "div",
17
+ {
18
+ className: cn(
19
+ "space-y-1 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-3 lg:sticky lg:top-24",
20
+ navClassName
21
+ ),
22
+ children: [
23
+ header ? /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2.5 border-b border-[var(--as-border)] px-3 py-2", children: [
24
+ HeaderIcon ? /* @__PURE__ */ jsx(
25
+ HeaderIcon,
26
+ {
27
+ className: "size-5 shrink-0 text-[var(--as-primary)]",
28
+ "aria-hidden": true
29
+ }
30
+ ) : null,
31
+ /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-bold text-[var(--as-fg)]", children: header.title })
32
+ ] }) : null,
33
+ nav.map(({ id, label, description, icon: Icon }) => {
34
+ const isActive = id === active;
35
+ return /* @__PURE__ */ jsxs(
36
+ "button",
37
+ {
38
+ type: "button",
39
+ "aria-current": isActive ? "page" : void 0,
40
+ onClick: () => onNavigate(id),
41
+ className: cn(
42
+ "flex w-full cursor-pointer items-start rounded-[var(--as-radius)] px-3 py-2.5 text-left text-sm transition-colors focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
43
+ isActive ? "bg-[color-mix(in_srgb,var(--as-primary)_12%,transparent)] font-bold text-[var(--as-primary)]" : "font-medium text-[var(--as-fg)] hover:bg-[var(--as-muted)]"
44
+ ),
45
+ children: [
46
+ Icon ? /* @__PURE__ */ jsx(
47
+ Icon,
48
+ {
49
+ className: "mr-3 mt-0.5 size-4 shrink-0",
50
+ "aria-hidden": true
51
+ }
52
+ ) : null,
53
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
54
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: label }),
55
+ description ? /* @__PURE__ */ jsx("span", { className: "text-[11px] font-normal text-[var(--as-muted-fg)]", children: description }) : null
56
+ ] })
57
+ ]
58
+ },
59
+ id
60
+ );
61
+ })
62
+ ]
63
+ }
64
+ ) }),
65
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 lg:col-span-3", children })
66
+ ]
67
+ }
68
+ );
69
+ }
70
+ );
71
+
72
+ export { SettingsShell };
73
+ //# sourceMappingURL=chunk-AHLNXCP2.js.map
74
+ //# sourceMappingURL=chunk-AHLNXCP2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/settings-shell/SettingsShell.tsx"],"names":["SettingsShell"],"mappings":";;;;AAqBO,IAAM,aAAA,GAAsB,KAAA,CAAA,UAAA;AAAA,EACjC,SAASA,cAAAA,CACP,EAAE,GAAA,EAAK,MAAA,EAAQ,UAAA,EAAY,MAAA,EAAQ,QAAA,EAAU,SAAA,EAAW,YAAA,EAAa,EACrE,GAAA,EACA;AACA,IAAA,MAAM,aAAa,MAAA,EAAQ,IAAA;AAC3B,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAQ,gBAAA;AAAA,QACR,SAAA,EAAW,EAAA,CAAG,uCAAA,EAAyC,SAAS,CAAA;AAAA,QAEhE,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,eAAA,EAAgB,YAAA,EAAW,mBAAA,EACxC,QAAA,kBAAA,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAW,EAAA;AAAA,gBACT,gIAAA;AAAA,gBACA;AAAA,eACF;AAAA,cAEC,QAAA,EAAA;AAAA,gBAAA,MAAA,mBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6EAAA,EACZ,QAAA,EAAA;AAAA,kBAAA,UAAA,mBACC,GAAA;AAAA,oBAAC,UAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,0CAAA;AAAA,sBACV,aAAA,EAAW;AAAA;AAAA,mBACb,GACE,IAAA;AAAA,kCACJ,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gDAAA,EACb,iBAAO,KAAA,EACV;AAAA,iBAAA,EACF,CAAA,GACE,IAAA;AAAA,gBACH,GAAA,CAAI,IAAI,CAAC,EAAE,IAAI,KAAA,EAAO,WAAA,EAAa,IAAA,EAAM,IAAA,EAAK,KAAM;AACnD,kBAAA,MAAM,WAAW,EAAA,KAAO,MAAA;AACxB,kBAAA,uBACE,IAAA;AAAA,oBAAC,QAAA;AAAA,oBAAA;AAAA,sBAEC,IAAA,EAAK,QAAA;AAAA,sBACL,cAAA,EAAc,WAAW,MAAA,GAAS,MAAA;AAAA,sBAClC,OAAA,EAAS,MAAM,UAAA,CAAW,EAAE,CAAA;AAAA,sBAC5B,SAAA,EAAW,EAAA;AAAA,wBACT,uNAAA;AAAA,wBACA,WACI,8FAAA,GACA;AAAA,uBACN;AAAA,sBAEC,QAAA,EAAA;AAAA,wBAAA,IAAA,mBACC,GAAA;AAAA,0BAAC,IAAA;AAAA,0BAAA;AAAA,4BACC,SAAA,EAAU,6BAAA;AAAA,4BACV,aAAA,EAAW;AAAA;AAAA,yBACb,GACE,IAAA;AAAA,wCACJ,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uBAAA,EACd,QAAA,EAAA;AAAA,0CAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,0BACjC,8BACC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mDAAA,EACb,uBACH,CAAA,GACE;AAAA,yBAAA,EACN;AAAA;AAAA,qBAAA;AAAA,oBAxBK;AAAA,mBAyBP;AAAA,gBAEJ,CAAC;AAAA;AAAA;AAAA,WACH,EACF,CAAA;AAAA,0BACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uBAAA,EAAyB,QAAA,EAAS;AAAA;AAAA;AAAA,KACnD;AAAA,EAEJ;AACF","file":"chunk-AHLNXCP2.js","sourcesContent":["import * as React from 'react'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nexport interface SettingsNavItem {\n id: string\n label: string\n description?: string\n icon?: LucideIcon\n}\n\nexport interface SettingsShellProps {\n nav: SettingsNavItem[]\n active: string\n onNavigate: (id: string) => void\n header?: { icon?: LucideIcon; title: string }\n children: React.ReactNode\n className?: string\n navClassName?: string\n}\n\nexport const SettingsShell = React.forwardRef<HTMLDivElement, SettingsShellProps>(\n function SettingsShell(\n { nav, active, onNavigate, header, children, className, navClassName },\n ref,\n ) {\n const HeaderIcon = header?.icon\n return (\n <div\n ref={ref}\n data-as=\"settings-shell\"\n className={cn('grid grid-cols-1 gap-8 lg:grid-cols-4', className)}\n >\n <nav className=\"lg:col-span-1\" aria-label=\"Settings sections\">\n <div\n className={cn(\n 'space-y-1 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-3 lg:sticky lg:top-24',\n navClassName,\n )}\n >\n {header ? (\n <div className=\"mb-2 flex items-center gap-2.5 border-b border-[var(--as-border)] px-3 py-2\">\n {HeaderIcon ? (\n <HeaderIcon\n className=\"size-5 shrink-0 text-[var(--as-primary)]\"\n aria-hidden\n />\n ) : null}\n <span className=\"truncate text-sm font-bold text-[var(--as-fg)]\">\n {header.title}\n </span>\n </div>\n ) : null}\n {nav.map(({ id, label, description, icon: Icon }) => {\n const isActive = id === active\n return (\n <button\n key={id}\n type=\"button\"\n aria-current={isActive ? 'page' : undefined}\n onClick={() => onNavigate(id)}\n className={cn(\n 'flex w-full cursor-pointer items-start rounded-[var(--as-radius)] px-3 py-2.5 text-left text-sm transition-colors focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]',\n isActive\n ? 'bg-[color-mix(in_srgb,var(--as-primary)_12%,transparent)] font-bold text-[var(--as-primary)]'\n : 'font-medium text-[var(--as-fg)] hover:bg-[var(--as-muted)]',\n )}\n >\n {Icon ? (\n <Icon\n className=\"mr-3 mt-0.5 size-4 shrink-0\"\n aria-hidden\n />\n ) : null}\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate\">{label}</span>\n {description ? (\n <span className=\"text-[11px] font-normal text-[var(--as-muted-fg)]\">\n {description}\n </span>\n ) : null}\n </span>\n </button>\n )\n })}\n </div>\n </nav>\n <div className=\"min-w-0 lg:col-span-3\">{children}</div>\n </div>\n )\n },\n)\n"]}
@@ -0,0 +1,63 @@
1
+ import { Combobox } from './chunk-XHHEAJHN.js';
2
+ import { cn } from './chunk-BLJWR4ZV.js';
3
+ import * as React from 'react';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ var ModelPicker = React.forwardRef(
7
+ function ModelPicker2({
8
+ providers,
9
+ value,
10
+ onChange,
11
+ placeholder = "Select a model\u2026",
12
+ searchPlaceholder = "Search models\u2026",
13
+ searchLabel,
14
+ emptyLabel,
15
+ loading = false,
16
+ disabled = false,
17
+ clearable = false,
18
+ clearLabel,
19
+ label,
20
+ error,
21
+ id,
22
+ className,
23
+ panelClassName
24
+ }, ref) {
25
+ const options = React.useMemo(
26
+ () => providers.flatMap(
27
+ (provider) => provider.models.map((model) => ({
28
+ value: model.id,
29
+ label: model.name,
30
+ group: provider.name,
31
+ badge: model.capability
32
+ }))
33
+ ),
34
+ [providers]
35
+ );
36
+ return /* @__PURE__ */ jsx(
37
+ Combobox,
38
+ {
39
+ ref,
40
+ options,
41
+ value,
42
+ onChange,
43
+ placeholder,
44
+ searchPlaceholder,
45
+ searchLabel,
46
+ emptyLabel,
47
+ loading,
48
+ disabled,
49
+ clearable,
50
+ clearLabel,
51
+ label,
52
+ error,
53
+ id,
54
+ className: cn("w-full", className),
55
+ panelClassName
56
+ }
57
+ );
58
+ }
59
+ );
60
+
61
+ export { ModelPicker };
62
+ //# sourceMappingURL=chunk-FE26R5RN.js.map
63
+ //# sourceMappingURL=chunk-FE26R5RN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/model-picker/ModelPicker.tsx"],"names":["ModelPicker"],"mappings":";;;;;AA2CO,IAAM,WAAA,GAAoB,KAAA,CAAA,UAAA;AAAA,EAC/B,SAASA,YAAAA,CACP;AAAA,IACE,SAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA,GAAc,sBAAA;AAAA,IACd,iBAAA,GAAoB,qBAAA;AAAA,IACpB,WAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA,GAAU,KAAA;AAAA,IACV,QAAA,GAAW,KAAA;AAAA,IACX,SAAA,GAAY,KAAA;AAAA,IACZ,UAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAA;AAAA,IACA,EAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,KAEF,GAAA,EACA;AACA,IAAA,MAAM,OAAA,GAAkC,KAAA,CAAA,OAAA;AAAA,MACtC,MACE,SAAA,CAAU,OAAA;AAAA,QAAQ,CAAC,QAAA,KACjB,QAAA,CAAS,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,UAC9B,OAAO,KAAA,CAAM,EAAA;AAAA,UACb,OAAO,KAAA,CAAM,IAAA;AAAA,UACb,OAAO,QAAA,CAAS,IAAA;AAAA,UAChB,OAAO,KAAA,CAAM;AAAA,SACf,CAAE;AAAA,OACJ;AAAA,MACF,CAAC,SAAS;AAAA,KACZ;AAEA,IAAA,uBACE,GAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,OAAA;AAAA,QACA,KAAA;AAAA,QACA,QAAA;AAAA,QACA,WAAA;AAAA,QACA,iBAAA;AAAA,QACA,WAAA;AAAA,QACA,UAAA;AAAA,QACA,OAAA;AAAA,QACA,QAAA;AAAA,QACA,SAAA;AAAA,QACA,UAAA;AAAA,QACA,KAAA;AAAA,QACA,KAAA;AAAA,QACA,EAAA;AAAA,QACA,SAAA,EAAW,EAAA,CAAG,QAAA,EAAU,SAAS,CAAA;AAAA,QACjC;AAAA;AAAA,KACF;AAAA,EAEJ;AACF","file":"chunk-FE26R5RN.js","sourcesContent":["import * as React from 'react'\nimport { cn } from '../../lib/utils'\nimport {\n Combobox,\n type ComboboxOption,\n} from '../combobox'\n\nexport interface ModelPickerModel {\n id: string\n name: string\n /** Short capability chip, e.g. `vision` or `tools`. */\n capability?: string\n}\n\nexport interface ModelPickerProvider {\n id: string\n name: string\n models: ModelPickerModel[]\n}\n\nexport interface ModelPickerProps {\n providers: ModelPickerProvider[]\n value?: string\n onChange: (modelId: string) => void\n placeholder?: string\n searchPlaceholder?: string\n searchLabel?: string\n emptyLabel?: string\n loading?: boolean\n disabled?: boolean\n clearable?: boolean\n clearLabel?: string\n label?: string\n error?: string\n id?: string\n className?: string\n panelClassName?: string\n}\n\n/**\n * Grouped, searchable provider → model picker. Presentational: the model\n * list comes in via props, selection goes out via `onChange`.\n */\nexport const ModelPicker = React.forwardRef<HTMLButtonElement, ModelPickerProps>(\n function ModelPicker(\n {\n providers,\n value,\n onChange,\n placeholder = 'Select a model…',\n searchPlaceholder = 'Search models…',\n searchLabel,\n emptyLabel,\n loading = false,\n disabled = false,\n clearable = false,\n clearLabel,\n label,\n error,\n id,\n className,\n panelClassName,\n },\n ref,\n ) {\n const options: ComboboxOption[] = React.useMemo(\n () =>\n providers.flatMap((provider) =>\n provider.models.map((model) => ({\n value: model.id,\n label: model.name,\n group: provider.name,\n badge: model.capability,\n })),\n ),\n [providers],\n )\n\n return (\n <Combobox\n ref={ref}\n options={options}\n value={value}\n onChange={onChange}\n placeholder={placeholder}\n searchPlaceholder={searchPlaceholder}\n searchLabel={searchLabel}\n emptyLabel={emptyLabel}\n loading={loading}\n disabled={disabled}\n clearable={clearable}\n clearLabel={clearLabel}\n label={label}\n error={error}\n id={id}\n className={cn('w-full', className)}\n panelClassName={panelClassName}\n />\n )\n },\n)\n"]}
@@ -1,5 +1,5 @@
1
- import { Textarea } from './chunk-C74WWM23.js';
2
1
  import { FormModal } from './chunk-2EPZAT3X.js';
2
+ import { Textarea } from './chunk-C74WWM23.js';
3
3
  import * as React from 'react';
4
4
  import { Sparkles } from 'lucide-react';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -70,5 +70,5 @@ function AiMagicFill({
70
70
  }
71
71
 
72
72
  export { AiMagicFill };
73
- //# sourceMappingURL=chunk-L4NM55XW.js.map
74
- //# sourceMappingURL=chunk-L4NM55XW.js.map
73
+ //# sourceMappingURL=chunk-I2RXO6ZU.js.map
74
+ //# sourceMappingURL=chunk-I2RXO6ZU.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/ai-magic-fill/AiMagicFill.tsx"],"names":[],"mappings":";;;;;;AAqBO,SAAS,WAAA,CAAY;AAAA,EAC1B,IAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA,GAAO,KAAA;AAAA,EACP,KAAA;AAAA,EACA,KAAA,GAAQ,YAAA;AAAA,EACR,QAAA,GAAW,4BAAA;AAAA,EACX,WAAA;AAAA,EACA,WAAA,GAAc,kBAAA;AAAA,EACd,WAAA,GAAc,8BAAA;AAAA,EACd,WAAA;AAAA,EACA,WAAA,GAAc,QAAA;AAAA,EACd;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAU,eAAS,EAAE,CAAA;AAE7C,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,MAAM,OAAA,GAAU,OAAO,IAAA,EAAK;AAC5B,IAAA,IAAI,CAAC,WAAW,IAAA,EAAM;AACtB,IAAA,QAAA,CAAS,OAAO,CAAA;AAChB,IAAA,SAAA,CAAU,EAAE,CAAA;AAAA,EACd,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,YAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA,EAAa,QAAA;AAAA,MACb,IAAA,EAAM,QAAA;AAAA,MACN,WAAA,EAAa,WAAA,IAAe,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA;AAAA,MAC1C,WAAA;AAAA,MACA,UAAA,EAAY,IAAA;AAAA,MACZ,cAAA,EAAgB,CAAC,MAAA,CAAO,IAAA,EAAK;AAAA,MAC7B,QAAA,EAAU,MAAA;AAAA,MACV,gBAAA,EAAkB,SAAA;AAAA,MAElB,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAQ,eAAA,EAAgB,WAAU,qBAAA,EACrC,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uBAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAQ,sBAAA;AAAA,cACR,SAAA,EAAU,6EAAA;AAAA,cAET,QAAA,EAAA;AAAA;AAAA,WACH;AAAA,0BACA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,EAAA,EAAG,sBAAA;AAAA,cACH,IAAA,EAAM,CAAA;AAAA,cACN,KAAA,EAAO,MAAA;AAAA,cACP,UAAU,CAAC,KAAA,KACT,SAAA,CAAU,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,cAE9B,WAAA;AAAA,cACA,SAAA,EAAU;AAAA;AAAA;AACZ,SAAA,EACF,CAAA;AAAA,QACC,8BACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4MAAA,EACV,uBACH,CAAA,GACE,IAAA;AAAA,QACH,KAAA,uBACE,GAAA,EAAA,EAAE,IAAA,EAAK,SAAQ,SAAA,EAAU,+CAAA,EACvB,iBACH,CAAA,GACE;AAAA,OAAA,EACN;AAAA;AAAA,GACF;AAEJ","file":"chunk-L4NM55XW.js","sourcesContent":["import * as React from 'react'\nimport { Sparkles } from 'lucide-react'\nimport { FormModal } from '../form-modal/FormModal'\nimport { Textarea } from '../textarea/Textarea'\n\nexport interface AiMagicFillProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onSubmit: (prompt: string) => void\n busy?: boolean\n error?: string | null\n title?: string\n subtitle?: string\n description?: string\n promptLabel?: string\n placeholder?: string\n submitLabel?: string\n cancelLabel?: string\n className?: string\n}\n\nexport function AiMagicFill({\n open,\n onOpenChange,\n onSubmit,\n busy = false,\n error,\n title = 'Magic Fill',\n subtitle = 'AI-powered data extraction',\n description,\n promptLabel = 'Describe details',\n placeholder = 'Describe the data here…',\n submitLabel,\n cancelLabel = 'Cancel',\n className,\n}: AiMagicFillProps) {\n const [prompt, setPrompt] = React.useState('')\n\n const submit = () => {\n const trimmed = prompt.trim()\n if (!trimmed || busy) return\n onSubmit(trimmed)\n setPrompt('')\n }\n\n return (\n <FormModal\n open={open}\n onOpenChange={onOpenChange}\n title={title}\n description={subtitle}\n icon={Sparkles}\n submitLabel={submitLabel ?? `Apply ${title}`}\n cancelLabel={cancelLabel}\n submitting={busy}\n submitDisabled={!prompt.trim()}\n onSubmit={submit}\n contentClassName={className}\n >\n <div data-as=\"ai-magic-fill\" className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-1.5\">\n <label\n htmlFor=\"ai-magic-fill-prompt\"\n className=\"text-[11px] font-bold uppercase tracking-[0.18em] text-[var(--as-muted-fg)]\"\n >\n {promptLabel}\n </label>\n <Textarea\n id=\"ai-magic-fill-prompt\"\n rows={5}\n value={prompt}\n onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) =>\n setPrompt(event.target.value)\n }\n placeholder={placeholder}\n className=\"resize-none leading-relaxed\"\n />\n </div>\n {description ? (\n <p className=\"rounded-[var(--as-radius)] border border-[color-mix(in_srgb,var(--as-ai)_25%,transparent)] bg-[color-mix(in_srgb,var(--as-ai)_8%,transparent)] p-3 text-xs font-medium leading-relaxed text-[var(--as-fg)]\">\n {description}\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"text-xs font-semibold text-[var(--as-danger)]\">\n {error}\n </p>\n ) : null}\n </div>\n </FormModal>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/components/ai-magic-fill/AiMagicFill.tsx"],"names":[],"mappings":";;;;;;AAqBO,SAAS,WAAA,CAAY;AAAA,EAC1B,IAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA,GAAO,KAAA;AAAA,EACP,KAAA;AAAA,EACA,KAAA,GAAQ,YAAA;AAAA,EACR,QAAA,GAAW,4BAAA;AAAA,EACX,WAAA;AAAA,EACA,WAAA,GAAc,kBAAA;AAAA,EACd,WAAA,GAAc,8BAAA;AAAA,EACd,WAAA;AAAA,EACA,WAAA,GAAc,QAAA;AAAA,EACd;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAU,eAAS,EAAE,CAAA;AAE7C,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,MAAM,OAAA,GAAU,OAAO,IAAA,EAAK;AAC5B,IAAA,IAAI,CAAC,WAAW,IAAA,EAAM;AACtB,IAAA,QAAA,CAAS,OAAO,CAAA;AAChB,IAAA,SAAA,CAAU,EAAE,CAAA;AAAA,EACd,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,YAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA,EAAa,QAAA;AAAA,MACb,IAAA,EAAM,QAAA;AAAA,MACN,WAAA,EAAa,WAAA,IAAe,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA;AAAA,MAC1C,WAAA;AAAA,MACA,UAAA,EAAY,IAAA;AAAA,MACZ,cAAA,EAAgB,CAAC,MAAA,CAAO,IAAA,EAAK;AAAA,MAC7B,QAAA,EAAU,MAAA;AAAA,MACV,gBAAA,EAAkB,SAAA;AAAA,MAElB,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAQ,eAAA,EAAgB,WAAU,qBAAA,EACrC,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uBAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAQ,sBAAA;AAAA,cACR,SAAA,EAAU,6EAAA;AAAA,cAET,QAAA,EAAA;AAAA;AAAA,WACH;AAAA,0BACA,GAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,EAAA,EAAG,sBAAA;AAAA,cACH,IAAA,EAAM,CAAA;AAAA,cACN,KAAA,EAAO,MAAA;AAAA,cACP,UAAU,CAAC,KAAA,KACT,SAAA,CAAU,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,cAE9B,WAAA;AAAA,cACA,SAAA,EAAU;AAAA;AAAA;AACZ,SAAA,EACF,CAAA;AAAA,QACC,8BACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4MAAA,EACV,uBACH,CAAA,GACE,IAAA;AAAA,QACH,KAAA,uBACE,GAAA,EAAA,EAAE,IAAA,EAAK,SAAQ,SAAA,EAAU,+CAAA,EACvB,iBACH,CAAA,GACE;AAAA,OAAA,EACN;AAAA;AAAA,GACF;AAEJ","file":"chunk-I2RXO6ZU.js","sourcesContent":["import * as React from 'react'\nimport { Sparkles } from 'lucide-react'\nimport { FormModal } from '../form-modal/FormModal'\nimport { Textarea } from '../textarea/Textarea'\n\nexport interface AiMagicFillProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onSubmit: (prompt: string) => void\n busy?: boolean\n error?: string | null\n title?: string\n subtitle?: string\n description?: string\n promptLabel?: string\n placeholder?: string\n submitLabel?: string\n cancelLabel?: string\n className?: string\n}\n\nexport function AiMagicFill({\n open,\n onOpenChange,\n onSubmit,\n busy = false,\n error,\n title = 'Magic Fill',\n subtitle = 'AI-powered data extraction',\n description,\n promptLabel = 'Describe details',\n placeholder = 'Describe the data here…',\n submitLabel,\n cancelLabel = 'Cancel',\n className,\n}: AiMagicFillProps) {\n const [prompt, setPrompt] = React.useState('')\n\n const submit = () => {\n const trimmed = prompt.trim()\n if (!trimmed || busy) return\n onSubmit(trimmed)\n setPrompt('')\n }\n\n return (\n <FormModal\n open={open}\n onOpenChange={onOpenChange}\n title={title}\n description={subtitle}\n icon={Sparkles}\n submitLabel={submitLabel ?? `Apply ${title}`}\n cancelLabel={cancelLabel}\n submitting={busy}\n submitDisabled={!prompt.trim()}\n onSubmit={submit}\n contentClassName={className}\n >\n <div data-as=\"ai-magic-fill\" className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-1.5\">\n <label\n htmlFor=\"ai-magic-fill-prompt\"\n className=\"text-[11px] font-bold uppercase tracking-[0.18em] text-[var(--as-muted-fg)]\"\n >\n {promptLabel}\n </label>\n <Textarea\n id=\"ai-magic-fill-prompt\"\n rows={5}\n value={prompt}\n onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) =>\n setPrompt(event.target.value)\n }\n placeholder={placeholder}\n className=\"resize-none leading-relaxed\"\n />\n </div>\n {description ? (\n <p className=\"rounded-[var(--as-radius)] border border-[color-mix(in_srgb,var(--as-ai)_25%,transparent)] bg-[color-mix(in_srgb,var(--as-ai)_8%,transparent)] p-3 text-xs font-medium leading-relaxed text-[var(--as-fg)]\">\n {description}\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"text-xs font-semibold text-[var(--as-danger)]\">\n {error}\n </p>\n ) : null}\n </div>\n </FormModal>\n )\n}\n"]}
@@ -0,0 +1,78 @@
1
+ import { formatBytes, FileCard } from './chunk-J4OELYDR.js';
2
+ import { cn } from './chunk-BLJWR4ZV.js';
3
+ import * as React from 'react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ var FileQueue = React.forwardRef(
7
+ function FileQueue2({
8
+ files,
9
+ onRemove,
10
+ onToggleInclude,
11
+ onOpen,
12
+ onReorder,
13
+ reorderable = Boolean(onReorder),
14
+ emptyText,
15
+ summary,
16
+ removeLabel = "Remove file",
17
+ includeLabel = "Include in processing",
18
+ className
19
+ }, ref) {
20
+ const dragId = React.useRef(null);
21
+ const [dropTarget, setDropTarget] = React.useState(null);
22
+ if (files.length === 0 && emptyText) {
23
+ return /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-[var(--as-muted-fg)]", className), children: emptyText });
24
+ }
25
+ return /* @__PURE__ */ jsxs("div", { ref, "data-as": "file-queue", className: cn("flex w-full flex-col gap-2", className), children: [
26
+ files.length > 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--as-muted-fg)]", children: summary ?? `${files.length} ${files.length === 1 ? "file" : "files"}${files.some((f) => f.sizeBytes != null) ? ` \xB7 ${formatBytes(files.reduce((total, f) => total + (f.sizeBytes ?? 0), 0))}` : ""}` }) : null,
27
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: files.map((file) => /* @__PURE__ */ jsx(
28
+ "div",
29
+ {
30
+ onDragOver: reorderable ? (event) => {
31
+ event.preventDefault();
32
+ if (dragId.current && dragId.current !== file.id) setDropTarget(file.id);
33
+ } : void 0,
34
+ onDrop: reorderable ? (event) => {
35
+ event.preventDefault();
36
+ if (dragId.current && dragId.current !== file.id) {
37
+ onReorder?.(dragId.current, file.id);
38
+ }
39
+ dragId.current = null;
40
+ setDropTarget(null);
41
+ } : void 0,
42
+ className: cn(
43
+ dropTarget === file.id && "ring-2 ring-[var(--as-focus-ring)] ring-offset-2"
44
+ ),
45
+ children: /* @__PURE__ */ jsx(
46
+ FileCard,
47
+ {
48
+ name: file.name,
49
+ sizeBytes: file.sizeBytes,
50
+ status: file.status,
51
+ error: file.error,
52
+ thumbnailUrl: file.thumbnailUrl,
53
+ included: file.included,
54
+ onToggleInclude: onToggleInclude ? () => onToggleInclude(file.id) : void 0,
55
+ onRemove: onRemove ? () => onRemove(file.id) : void 0,
56
+ onOpen: onOpen ? () => onOpen(file.id) : void 0,
57
+ draggable: reorderable,
58
+ onDragStart: () => {
59
+ dragId.current = file.id;
60
+ },
61
+ onDragEnd: () => {
62
+ dragId.current = null;
63
+ setDropTarget(null);
64
+ },
65
+ removeLabel,
66
+ includeLabel
67
+ }
68
+ )
69
+ },
70
+ file.id
71
+ )) })
72
+ ] });
73
+ }
74
+ );
75
+
76
+ export { FileQueue };
77
+ //# sourceMappingURL=chunk-IQKP2BWE.js.map
78
+ //# sourceMappingURL=chunk-IQKP2BWE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/file-queue/FileQueue.tsx"],"names":["FileQueue"],"mappings":"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","file":"chunk-IQKP2BWE.js","sourcesContent":["import * as React from 'react'\nimport { cn } from '../../lib/utils'\nimport {\n FileCard,\n formatBytes,\n type FileCardStatus,\n} from '../file-card/FileCard'\n\nexport interface FileQueueItem {\n id: string\n name: string\n sizeBytes?: number\n status?: FileCardStatus\n error?: string | null\n thumbnailUrl?: string | null\n included?: boolean\n}\n\nexport interface FileQueueProps {\n files: FileQueueItem[]\n onRemove?: (id: string) => void\n onToggleInclude?: (id: string) => void\n onOpen?: (id: string) => void\n onReorder?: (fromId: string, toId: string) => void\n reorderable?: boolean\n emptyText?: string\n summary?: React.ReactNode\n removeLabel?: string\n includeLabel?: string\n className?: string\n}\n\n/**\n * FileCard grid with aggregate summary and optional drag-to-reorder\n * (reports intent via `onReorder(fromId, toId)` — the app owns ordering).\n */\nexport const FileQueue = React.forwardRef<HTMLDivElement, FileQueueProps>(\n function FileQueue(\n {\n files,\n onRemove,\n onToggleInclude,\n onOpen,\n onReorder,\n reorderable = Boolean(onReorder),\n emptyText,\n summary,\n removeLabel = 'Remove file',\n includeLabel = 'Include in processing',\n className,\n },\n ref,\n ) {\n const dragId = React.useRef<string | null>(null)\n const [dropTarget, setDropTarget] = React.useState<string | null>(null)\n\n if (files.length === 0 && emptyText) {\n return (\n <p ref={ref} className={cn('text-sm text-[var(--as-muted-fg)]', className)}>\n {emptyText}\n </p>\n )\n }\n\n return (\n <div ref={ref} data-as=\"file-queue\" className={cn('flex w-full flex-col gap-2', className)}>\n {files.length > 0 ? (\n <p className=\"text-xs text-[var(--as-muted-fg)]\">\n {summary ??\n `${files.length} ${files.length === 1 ? 'file' : 'files'}${\n files.some((f) => f.sizeBytes != null)\n ? ` · ${formatBytes(files.reduce((total, f) => total + (f.sizeBytes ?? 0), 0))}`\n : ''\n }`}\n </p>\n ) : null}\n <div className=\"flex flex-wrap gap-2\">\n {files.map((file) => (\n <div\n key={file.id}\n onDragOver={reorderable ? (event) => {\n event.preventDefault()\n if (dragId.current && dragId.current !== file.id) setDropTarget(file.id)\n } : undefined}\n onDrop={reorderable ? (event) => {\n event.preventDefault()\n if (dragId.current && dragId.current !== file.id) {\n onReorder?.(dragId.current, file.id)\n }\n dragId.current = null\n setDropTarget(null)\n } : undefined}\n className={cn(\n dropTarget === file.id && 'ring-2 ring-[var(--as-focus-ring)] ring-offset-2',\n )}\n >\n <FileCard\n name={file.name}\n sizeBytes={file.sizeBytes}\n status={file.status}\n error={file.error}\n thumbnailUrl={file.thumbnailUrl}\n included={file.included}\n onToggleInclude={onToggleInclude ? () => onToggleInclude(file.id) : undefined}\n onRemove={onRemove ? () => onRemove(file.id) : undefined}\n onOpen={onOpen ? () => onOpen(file.id) : undefined}\n draggable={reorderable}\n onDragStart={() => {\n dragId.current = file.id\n }}\n onDragEnd={() => {\n dragId.current = null\n setDropTarget(null)\n }}\n removeLabel={removeLabel}\n includeLabel={includeLabel}\n />\n </div>\n ))}\n </div>\n </div>\n )\n },\n)\n"]}
@@ -0,0 +1,125 @@
1
+ import { cn } from './chunk-BLJWR4ZV.js';
2
+ import * as React from 'react';
3
+ import { GripVertical, X, FileText, Loader2, TriangleAlert, Check } from 'lucide-react';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
+
6
+ function formatBytes(bytes) {
7
+ if (bytes < 1024) return `${bytes} B`;
8
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
9
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
10
+ }
11
+ var FileCard = React.forwardRef(
12
+ function FileCard2({
13
+ name,
14
+ sizeBytes,
15
+ status = "queued",
16
+ error,
17
+ thumbnailUrl,
18
+ included = true,
19
+ onToggleInclude,
20
+ onRemove,
21
+ onOpen,
22
+ draggable = false,
23
+ onDragStart,
24
+ onDragEnd,
25
+ removeLabel = "Remove file",
26
+ includeLabel = "Include in processing",
27
+ className
28
+ }, ref) {
29
+ return /* @__PURE__ */ jsxs(
30
+ "div",
31
+ {
32
+ ref,
33
+ "data-as": "file-card",
34
+ "data-status": status,
35
+ draggable,
36
+ onDragStart: (event) => {
37
+ if (!draggable) return;
38
+ event.dataTransfer.effectAllowed = "move";
39
+ onDragStart?.();
40
+ },
41
+ onDragEnd: draggable ? onDragEnd : void 0,
42
+ onClick: onOpen,
43
+ className: cn(
44
+ "group relative flex w-40 flex-col overflow-hidden rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] shadow-[var(--as-shadow-1)] transition-shadow hover:shadow-[var(--as-shadow-2)]",
45
+ onOpen && "cursor-pointer",
46
+ !included && "opacity-60",
47
+ className
48
+ ),
49
+ children: [
50
+ draggable ? /* @__PURE__ */ jsx(
51
+ "span",
52
+ {
53
+ "aria-hidden": true,
54
+ className: "absolute left-1 top-1 z-10 cursor-grab rounded p-0.5 text-[var(--as-muted-fg)] opacity-0 transition-opacity group-hover:opacity-100",
55
+ children: /* @__PURE__ */ jsx(GripVertical, { className: "size-3.5" })
56
+ }
57
+ ) : null,
58
+ onRemove ? /* @__PURE__ */ jsx(
59
+ "button",
60
+ {
61
+ type: "button",
62
+ "aria-label": `${removeLabel} \u2014 ${name}`,
63
+ onClick: (event) => {
64
+ event.stopPropagation();
65
+ onRemove();
66
+ },
67
+ className: "absolute right-1 top-1 z-10 cursor-pointer rounded-full bg-[var(--as-surface-raised)] p-1 text-[var(--as-muted-fg)] opacity-0 shadow-[var(--as-shadow-1)] transition-opacity hover:text-[var(--as-danger)] focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-[var(--as-focus-ring)] group-hover:opacity-100",
68
+ children: /* @__PURE__ */ jsx(X, { className: "size-3", "aria-hidden": true })
69
+ }
70
+ ) : null,
71
+ /* @__PURE__ */ jsx("div", { className: "flex h-20 w-full items-center justify-center overflow-hidden bg-[var(--as-muted)]", children: thumbnailUrl ? /* @__PURE__ */ jsx("img", { src: thumbnailUrl, alt: "", className: "size-full object-cover" }) : /* @__PURE__ */ jsx(
72
+ FileText,
73
+ {
74
+ className: cn(
75
+ "size-7",
76
+ status === "failed" ? "text-[var(--as-danger)]" : "text-[var(--as-muted-fg)]"
77
+ ),
78
+ "aria-hidden": true
79
+ }
80
+ ) }),
81
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1 p-2", children: [
82
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs font-semibold text-[var(--as-fg)]", title: name, children: name }),
83
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-[var(--as-muted-fg)]", children: [
84
+ status === "processing" ? /* @__PURE__ */ jsxs(Fragment, { children: [
85
+ /* @__PURE__ */ jsx(Loader2, { className: "size-3 animate-spin", "aria-hidden": true }),
86
+ /* @__PURE__ */ jsx("span", { role: "status", children: "Processing\u2026" })
87
+ ] }) : status === "failed" ? /* @__PURE__ */ jsxs(Fragment, { children: [
88
+ /* @__PURE__ */ jsx(TriangleAlert, { className: "size-3 text-[var(--as-danger)]", "aria-hidden": true }),
89
+ /* @__PURE__ */ jsx("span", { className: "truncate text-[var(--as-danger)]", children: error ?? "Failed" })
90
+ ] }) : status === "done" ? /* @__PURE__ */ jsxs(Fragment, { children: [
91
+ /* @__PURE__ */ jsx(Check, { className: "size-3 text-[var(--as-success)]", "aria-hidden": true }),
92
+ /* @__PURE__ */ jsx("span", { children: "Done" })
93
+ ] }) : null,
94
+ sizeBytes != null ? /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0", children: formatBytes(sizeBytes) }) : null
95
+ ] })
96
+ ] }),
97
+ onToggleInclude ? /* @__PURE__ */ jsxs(
98
+ "label",
99
+ {
100
+ onClick: (event) => event.stopPropagation(),
101
+ className: "flex cursor-pointer items-center gap-1.5 border-t border-[var(--as-border)] px-2 py-1.5 text-[10px] font-medium text-[var(--as-muted-fg)]",
102
+ children: [
103
+ /* @__PURE__ */ jsx(
104
+ "input",
105
+ {
106
+ type: "checkbox",
107
+ checked: included,
108
+ onChange: () => onToggleInclude(),
109
+ "aria-label": `${includeLabel} \u2014 ${name}`,
110
+ className: "accent-[var(--as-primary)]"
111
+ }
112
+ ),
113
+ includeLabel
114
+ ]
115
+ }
116
+ ) : null
117
+ ]
118
+ }
119
+ );
120
+ }
121
+ );
122
+
123
+ export { FileCard, formatBytes };
124
+ //# sourceMappingURL=chunk-J4OELYDR.js.map
125
+ //# sourceMappingURL=chunk-J4OELYDR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/file-card/FileCard.tsx"],"names":["FileCard"],"mappings":"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","file":"chunk-J4OELYDR.js","sourcesContent":["import * as React from 'react'\nimport { Check, FileText, GripVertical, Loader2, TriangleAlert, X } from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nexport type FileCardStatus = 'queued' | 'processing' | 'done' | 'failed'\n\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nexport interface FileCardProps {\n name: string\n sizeBytes?: number\n status?: FileCardStatus\n error?: string | null\n /** Small preview URL (app owns object-URL lifecycle). */\n thumbnailUrl?: string | null\n included?: boolean\n onToggleInclude?: () => void\n onRemove?: () => void\n onOpen?: () => void\n draggable?: boolean\n onDragStart?: () => void\n onDragEnd?: () => void\n removeLabel?: string\n includeLabel?: string\n className?: string\n}\n\nexport const FileCard = React.forwardRef<HTMLDivElement, FileCardProps>(\n function FileCard(\n {\n name,\n sizeBytes,\n status = 'queued',\n error,\n thumbnailUrl,\n included = true,\n onToggleInclude,\n onRemove,\n onOpen,\n draggable = false,\n onDragStart,\n onDragEnd,\n removeLabel = 'Remove file',\n includeLabel = 'Include in processing',\n className,\n },\n ref,\n ) {\n return (\n <div\n ref={ref}\n data-as=\"file-card\"\n data-status={status}\n draggable={draggable}\n onDragStart={(event) => {\n if (!draggable) return\n event.dataTransfer.effectAllowed = 'move'\n onDragStart?.()\n }}\n onDragEnd={draggable ? onDragEnd : undefined}\n onClick={onOpen}\n className={cn(\n 'group relative flex w-40 flex-col overflow-hidden rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] shadow-[var(--as-shadow-1)] transition-shadow hover:shadow-[var(--as-shadow-2)]',\n onOpen && 'cursor-pointer',\n !included && 'opacity-60',\n className,\n )}\n >\n {draggable ? (\n <span\n aria-hidden\n className=\"absolute left-1 top-1 z-10 cursor-grab rounded p-0.5 text-[var(--as-muted-fg)] opacity-0 transition-opacity group-hover:opacity-100\"\n >\n <GripVertical className=\"size-3.5\" />\n </span>\n ) : null}\n {onRemove ? (\n <button\n type=\"button\"\n aria-label={`${removeLabel} — ${name}`}\n onClick={(event) => {\n event.stopPropagation()\n onRemove()\n }}\n className=\"absolute right-1 top-1 z-10 cursor-pointer rounded-full bg-[var(--as-surface-raised)] p-1 text-[var(--as-muted-fg)] opacity-0 shadow-[var(--as-shadow-1)] transition-opacity hover:text-[var(--as-danger)] focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-[var(--as-focus-ring)] group-hover:opacity-100\"\n >\n <X className=\"size-3\" aria-hidden />\n </button>\n ) : null}\n <div className=\"flex h-20 w-full items-center justify-center overflow-hidden bg-[var(--as-muted)]\">\n {thumbnailUrl ? (\n <img src={thumbnailUrl} alt=\"\" className=\"size-full object-cover\" />\n ) : (\n <FileText\n className={cn(\n 'size-7',\n status === 'failed' ? 'text-[var(--as-danger)]' : 'text-[var(--as-muted-fg)]',\n )}\n aria-hidden\n />\n )}\n </div>\n <div className=\"flex min-w-0 flex-col gap-1 p-2\">\n <p className=\"truncate text-xs font-semibold text-[var(--as-fg)]\" title={name}>\n {name}\n </p>\n <div className=\"flex items-center gap-1.5 text-[10px] text-[var(--as-muted-fg)]\">\n {status === 'processing' ? (\n <>\n <Loader2 className=\"size-3 animate-spin\" aria-hidden />\n <span role=\"status\">Processing…</span>\n </>\n ) : status === 'failed' ? (\n <>\n <TriangleAlert className=\"size-3 text-[var(--as-danger)]\" aria-hidden />\n <span className=\"truncate text-[var(--as-danger)]\">{error ?? 'Failed'}</span>\n </>\n ) : status === 'done' ? (\n <>\n <Check className=\"size-3 text-[var(--as-success)]\" aria-hidden />\n <span>Done</span>\n </>\n ) : null}\n {sizeBytes != null ? (\n <span className=\"ml-auto shrink-0\">{formatBytes(sizeBytes)}</span>\n ) : null}\n </div>\n </div>\n {onToggleInclude ? (\n <label\n onClick={(event) => event.stopPropagation()}\n className=\"flex cursor-pointer items-center gap-1.5 border-t border-[var(--as-border)] px-2 py-1.5 text-[10px] font-medium text-[var(--as-muted-fg)]\"\n >\n <input\n type=\"checkbox\"\n checked={included}\n onChange={() => onToggleInclude()}\n aria-label={`${includeLabel} — ${name}`}\n className=\"accent-[var(--as-primary)]\"\n />\n {includeLabel}\n </label>\n ) : null}\n </div>\n )\n },\n)\n"]}
@@ -0,0 +1,89 @@
1
+ import { Input } from './chunk-M4V7XHL7.js';
2
+ import { cn } from './chunk-BLJWR4ZV.js';
3
+ import * as React from 'react';
4
+ import { KeyRound } from 'lucide-react';
5
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
+
7
+ var ProviderForm = React.forwardRef(
8
+ function ProviderForm2({
9
+ name,
10
+ onNameChange,
11
+ baseUrl,
12
+ onBaseUrlChange,
13
+ apiKey,
14
+ onApiKeyChange,
15
+ namePlaceholder = "Provider name",
16
+ baseUrlPlaceholder = "https://api.example.com/v1",
17
+ nameLabel = "Name",
18
+ baseUrlLabel = "API base URL",
19
+ apiKeyLabel = "API key",
20
+ apiKeyHelp,
21
+ hasStoredKey = false,
22
+ storedKeyLabel = "Stored \u2014 leave empty to keep",
23
+ keyPlaceholder = "sk-\u2026",
24
+ error,
25
+ children,
26
+ className,
27
+ ...props
28
+ }, ref) {
29
+ return /* @__PURE__ */ jsxs(
30
+ "div",
31
+ {
32
+ ref,
33
+ "data-as": "provider-form",
34
+ className: cn("flex w-full flex-col gap-4", className),
35
+ ...props,
36
+ children: [
37
+ /* @__PURE__ */ jsx(
38
+ Input,
39
+ {
40
+ label: nameLabel,
41
+ value: name,
42
+ onChange: (event) => onNameChange(event.target.value),
43
+ placeholder: namePlaceholder
44
+ }
45
+ ),
46
+ /* @__PURE__ */ jsx(
47
+ Input,
48
+ {
49
+ label: baseUrlLabel,
50
+ value: baseUrl,
51
+ onChange: (event) => onBaseUrlChange(event.target.value),
52
+ placeholder: baseUrlPlaceholder,
53
+ className: "font-mono"
54
+ }
55
+ ),
56
+ /* @__PURE__ */ jsx(
57
+ Input,
58
+ {
59
+ label: hasStoredKey ? /* @__PURE__ */ jsxs(Fragment, { children: [
60
+ apiKeyLabel,
61
+ " ",
62
+ /* @__PURE__ */ jsxs("span", { className: "font-normal text-[var(--as-muted-fg)]", children: [
63
+ "(",
64
+ storedKeyLabel,
65
+ ")"
66
+ ] })
67
+ ] }) : apiKeyLabel,
68
+ type: "password",
69
+ value: apiKey,
70
+ onChange: (event) => onApiKeyChange(event.target.value),
71
+ placeholder: hasStoredKey ? "\u2022\u2022\u2022" : keyPlaceholder,
72
+ autoComplete: "new-password",
73
+ hint: apiKeyHelp ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
74
+ /* @__PURE__ */ jsx(KeyRound, { className: "size-3", "aria-hidden": true }),
75
+ apiKeyHelp
76
+ ] }) : void 0
77
+ }
78
+ ),
79
+ children,
80
+ error ? /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm font-medium text-[var(--as-danger)]", children: error }) : null
81
+ ]
82
+ }
83
+ );
84
+ }
85
+ );
86
+
87
+ export { ProviderForm };
88
+ //# sourceMappingURL=chunk-RJSN4TVT.js.map
89
+ //# sourceMappingURL=chunk-RJSN4TVT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/provider-form/ProviderForm.tsx"],"names":["ProviderForm"],"mappings":";;;;;;AAgCO,IAAM,YAAA,GAAqB,KAAA,CAAA,UAAA;AAAA,EAChC,SAASA,aAAAA,CACP;AAAA,IACE,IAAA;AAAA,IACA,YAAA;AAAA,IACA,OAAA;AAAA,IACA,eAAA;AAAA,IACA,MAAA;AAAA,IACA,cAAA;AAAA,IACA,eAAA,GAAkB,eAAA;AAAA,IAClB,kBAAA,GAAqB,4BAAA;AAAA,IACrB,SAAA,GAAY,MAAA;AAAA,IACZ,YAAA,GAAe,cAAA;AAAA,IACf,WAAA,GAAc,SAAA;AAAA,IACd,UAAA;AAAA,IACA,YAAA,GAAe,KAAA;AAAA,IACf,cAAA,GAAiB,mCAAA;AAAA,IACjB,cAAA,GAAiB,WAAA;AAAA,IACjB,KAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,GAAG;AAAA,KAEL,GAAA,EACA;AACA,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAQ,eAAA;AAAA,QACR,SAAA,EAAW,EAAA,CAAG,4BAAA,EAA8B,SAAS,CAAA;AAAA,QACpD,GAAG,KAAA;AAAA,QAEJ,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAO,SAAA;AAAA,cACP,KAAA,EAAO,IAAA;AAAA,cACP,UAAU,CAAC,KAAA,KAAU,YAAA,CAAa,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,cACpD,WAAA,EAAa;AAAA;AAAA,WACf;AAAA,0BACA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAO,YAAA;AAAA,cACP,KAAA,EAAO,OAAA;AAAA,cACP,UAAU,CAAC,KAAA,KAAU,eAAA,CAAgB,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,cACvD,WAAA,EAAa,kBAAA;AAAA,cACb,SAAA,EAAU;AAAA;AAAA,WACZ;AAAA,0BACA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,KAAA,EACE,+BACE,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,gBAAA,WAAA;AAAA,gBAAa,GAAA;AAAA,gCACd,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uCAAA,EAAwC,QAAA,EAAA;AAAA,kBAAA,GAAA;AAAA,kBACpD,cAAA;AAAA,kBAAe;AAAA,iBAAA,EACnB;AAAA,eAAA,EACF,CAAA,GAEA,WAAA;AAAA,cAGJ,IAAA,EAAK,UAAA;AAAA,cACL,KAAA,EAAO,MAAA;AAAA,cACP,UAAU,CAAC,KAAA,KAAU,cAAA,CAAe,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,cACtD,WAAA,EAAa,eAAe,oBAAA,GAAQ,cAAA;AAAA,cACpC,YAAA,EAAa,cAAA;AAAA,cACb,IAAA,EACE,UAAA,mBACE,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,gCAAA,EACd,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,QAAA,EAAS,aAAA,EAAW,IAAA,EAAC,CAAA;AAAA,gBACxC;AAAA,eAAA,EACH,CAAA,GACE;AAAA;AAAA,WAER;AAAA,UACC,QAAA;AAAA,UACA,KAAA,uBACE,GAAA,EAAA,EAAE,IAAA,EAAK,SAAQ,SAAA,EAAU,6CAAA,EACvB,iBACH,CAAA,GACE;AAAA;AAAA;AAAA,KACN;AAAA,EAEJ;AACF","file":"chunk-RJSN4TVT.js","sourcesContent":["import * as React from 'react'\nimport { KeyRound } from 'lucide-react'\nimport { cn } from '../../lib/utils'\nimport { Input } from '../input/Input'\n\nexport interface ProviderFormProps extends React.ComponentProps<'div'> {\n name: string\n onNameChange: (value: string) => void\n baseUrl: string\n onBaseUrlChange: (value: string) => void\n apiKey: string\n onApiKeyChange: (value: string) => void\n namePlaceholder?: string\n baseUrlPlaceholder?: string\n nameLabel?: string\n baseUrlLabel?: string\n apiKeyLabel?: string\n /** Hint under the key field; apps mention keyring storage here. */\n apiKeyHelp?: string\n /** The provider already stores a key (write-only field shows no value). */\n hasStoredKey?: boolean\n storedKeyLabel?: string\n keyPlaceholder?: string\n error?: string\n children?: React.ReactNode\n}\n\n/**\n * Standard provider credential fields: name, base URL and a **write-only**\n * masked API key (`onChange` only — the library never renders a stored key;\n * keyring/storage is the app's business, ADR-006).\n */\nexport const ProviderForm = React.forwardRef<HTMLDivElement, ProviderFormProps>(\n function ProviderForm(\n {\n name,\n onNameChange,\n baseUrl,\n onBaseUrlChange,\n apiKey,\n onApiKeyChange,\n namePlaceholder = 'Provider name',\n baseUrlPlaceholder = 'https://api.example.com/v1',\n nameLabel = 'Name',\n baseUrlLabel = 'API base URL',\n apiKeyLabel = 'API key',\n apiKeyHelp,\n hasStoredKey = false,\n storedKeyLabel = 'Stored — leave empty to keep',\n keyPlaceholder = 'sk-…',\n error,\n children,\n className,\n ...props\n },\n ref,\n ) {\n return (\n <div\n ref={ref}\n data-as=\"provider-form\"\n className={cn('flex w-full flex-col gap-4', className)}\n {...props}\n >\n <Input\n label={nameLabel}\n value={name}\n onChange={(event) => onNameChange(event.target.value)}\n placeholder={namePlaceholder}\n />\n <Input\n label={baseUrlLabel}\n value={baseUrl}\n onChange={(event) => onBaseUrlChange(event.target.value)}\n placeholder={baseUrlPlaceholder}\n className=\"font-mono\"\n />\n <Input\n label={\n hasStoredKey ? (\n <>\n {apiKeyLabel}{' '}\n <span className=\"font-normal text-[var(--as-muted-fg)]\">\n ({storedKeyLabel})\n </span>\n </>\n ) : (\n apiKeyLabel\n )\n }\n type=\"password\"\n value={apiKey}\n onChange={(event) => onApiKeyChange(event.target.value)}\n placeholder={hasStoredKey ? '•••' : keyPlaceholder}\n autoComplete=\"new-password\"\n hint={\n apiKeyHelp ? (\n <span className=\"inline-flex items-center gap-1\">\n <KeyRound className=\"size-3\" aria-hidden />\n {apiKeyHelp}\n </span>\n ) : undefined\n }\n />\n {children}\n {error ? (\n <p role=\"alert\" className=\"text-sm font-medium text-[var(--as-danger)]\">\n {error}\n </p>\n ) : null}\n </div>\n )\n },\n)\n"]}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-RLFND34I.js.map
3
+ //# sourceMappingURL=chunk-RLFND34I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-RLFND34I.js"}