@reforma/components 0.2.2 → 0.3.1

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.
@@ -1,3 +1,7 @@
1
- /** TipTap prompt field. Import this only when the plain textarea is not enough. */
2
- export declare function ComposerRichField(): import("react").JSX.Element;
1
+ import type { HTMLAttributes } from 'react';
2
+ import type { ComposerClassNames } from './types';
3
+ /** TipTap field with caller-owned wrapper and editable-element classes. */
4
+ export declare function ComposerRichField({ className, classNames: slots, style, ...props }: HTMLAttributes<HTMLDivElement> & {
5
+ classNames?: Pick<ComposerClassNames, 'textareaWrap' | 'editor'>;
6
+ }): import("react").JSX.Element;
3
7
  //# sourceMappingURL=RichField.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RichField.d.ts","sourceRoot":"","sources":["../../src/Composer/RichField.tsx"],"names":[],"mappings":"AAWA,mFAAmF;AACnF,wBAAgB,iBAAiB,gCAoChC"}
1
+ {"version":3,"file":"RichField.d.ts","sourceRoot":"","sources":["../../src/Composer/RichField.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,EAC9B,SAAS,EACT,UAAU,EAAE,KAAK,EACjB,KAAK,EACL,GAAG,KAAK,EACX,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG;IAChC,UAAU,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,QAAQ,CAAC,CAAC;CACpE,+BA4FA"}
@@ -1,44 +1,114 @@
1
- import { useMemo as x } from "react";
2
- import { plainTextToDoc as d, docToPlainText as h } from "../RichInput/composerDoc.js";
3
- import { RichInput as T } from "../RichInput/RichInput.js";
4
- import r from "./Composer.module.css.js";
5
- import { useComposer as F } from "./context.js";
6
- import { jsx as m } from "react/jsx-runtime";
7
- function H() {
1
+ import { cn as s } from "@reforma/lib";
2
+ import E from "@tiptap/extension-bold";
3
+ import S from "@tiptap/extension-code";
4
+ import w from "@tiptap/extension-document";
5
+ import F from "@tiptap/extension-hard-break";
6
+ import H from "@tiptap/extension-history";
7
+ import K from "@tiptap/extension-italic";
8
+ import { ListKit as O } from "@tiptap/extension-list";
9
+ import k from "@tiptap/extension-paragraph";
10
+ import v from "@tiptap/extension-placeholder";
11
+ import I from "@tiptap/extension-text";
12
+ import { useEditor as L, EditorContent as R } from "@tiptap/react";
13
+ import { useLayoutEffect as d, useEffect as j } from "react";
14
+ import { docToPlainText as f, plainTextToDoc as u } from "../RichInput/composerDoc.js";
15
+ import { handleComposerKeyDown as B } from "../RichInput/composerKeymap.js";
16
+ import { useComposer as J } from "./context.js";
17
+ import { jsx as h } from "react/jsx-runtime";
18
+ function at({
19
+ className: x,
20
+ classNames: n,
21
+ style: b,
22
+ ...m
23
+ }) {
8
24
  const {
9
- value: o,
10
- setPrompt: a,
11
- submit: i,
12
- placeholder: t,
13
- autoFocus: s,
14
- submitOnEnter: p,
15
- minHeight: n,
16
- focusRef: l,
17
- addFiles: c,
18
- pasteTextAsFile: u
19
- } = F(), f = x(() => d(o.prompt), [o.prompt]);
20
- return /* @__PURE__ */ m("div", {
21
- className: r.textareaWrap,
22
- children: /* @__PURE__ */ m(T, {
23
- ref: (e) => {
24
- l.current = e;
25
- },
26
- value: f,
27
- onChange: (e) => a(h(e)),
28
- autoFocus: s,
29
- minHeight: n,
30
- maxHeight: 280,
31
- placeholder: t,
32
- className: r.textarea,
33
- "aria-label": t,
34
- submitOnEnter: p,
35
- onSubmit: () => i(),
36
- onPasteFiles: (e) => c(e),
37
- onPasteText: u
25
+ value: r,
26
+ setPrompt: y,
27
+ submit: g,
28
+ placeholder: l,
29
+ autoFocus: C,
30
+ submitOnEnter: N,
31
+ focusRef: a,
32
+ addFiles: D,
33
+ pasteTextAsFile: P,
34
+ classNames: i,
35
+ minHeight: T
36
+ } = J(), p = {
37
+ attributes: {
38
+ class: s(i.editor, n?.editor),
39
+ role: "textbox",
40
+ "aria-multiline": "true",
41
+ "aria-label": m["aria-label"] ?? l,
42
+ "aria-placeholder": l,
43
+ "data-slot": "composer-editor"
44
+ },
45
+ handleKeyDown: (t, o) => B(t, o, {
46
+ submitOnEnter: N,
47
+ hasMenuItems: !1,
48
+ onSubmit: () => g()
49
+ }),
50
+ handlePaste: (t, o) => {
51
+ const c = o.clipboardData?.files;
52
+ return c?.length ? (D([...c]), !0) : P(o.clipboardData?.getData("text/plain") ?? "");
53
+ }
54
+ }, e = L({
55
+ immediatelyRender: !1,
56
+ injectCSS: !1,
57
+ autofocus: C && (typeof document > "u" || !document.activeElement?.matches('input, textarea, [contenteditable="true"]')) ? "end" : !1,
58
+ extensions: [w, k, I, F.extend({
59
+ addKeyboardShortcuts: () => ({})
60
+ }), H, E, K, S, O.configure({
61
+ taskItem: !1,
62
+ taskList: !1
63
+ }), v.configure({
64
+ placeholder: ({
65
+ editor: t
66
+ }) => {
67
+ const o = t.options.editorProps.attributes;
68
+ return (typeof o == "function" ? o(t.state) : o)?.["aria-placeholder"] ?? "";
69
+ }
70
+ })],
71
+ content: u(r.prompt),
72
+ editorProps: p,
73
+ onUpdate: ({
74
+ editor: t
75
+ }) => y(f(t.getJSON()))
76
+ });
77
+ return d(() => {
78
+ e?.setOptions({
79
+ editorProps: p
80
+ });
81
+ }), d(() => {
82
+ if (!e)
83
+ return;
84
+ const t = {
85
+ focus: () => {
86
+ e.chain().focus().run();
87
+ }
88
+ };
89
+ return a.current = t, () => {
90
+ a.current === t && (a.current = null);
91
+ };
92
+ }, [e, a]), j(() => {
93
+ !e || f(e.getJSON()) === r.prompt || e.chain().setMeta("addToHistory", !1).setContent(u(r.prompt), {
94
+ emitUpdate: !1
95
+ }).run();
96
+ }, [e, r.prompt]), /* @__PURE__ */ h("div", {
97
+ "data-slot": "composer-field-wrapper",
98
+ className: s(i.textareaWrap, n?.textareaWrap),
99
+ children: /* @__PURE__ */ h(R, {
100
+ ...m,
101
+ editor: e,
102
+ "data-slot": "composer-rich-field",
103
+ className: s(i.textarea, x),
104
+ style: {
105
+ "--composer-min-height": `${T}px`,
106
+ ...b
107
+ }
38
108
  })
39
109
  });
40
110
  }
41
111
  export {
42
- H as ComposerRichField
112
+ at as ComposerRichField
43
113
  };
44
114
  //# sourceMappingURL=RichField.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RichField.js","sources":["../../src/Composer/RichField.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\n\nimport { docToPlainText, plainTextToDoc } from '../RichInput';\nimport { RichInput } from '../RichInput/RichInput';\nimport styles from './Composer.module.css';\nimport { useComposer } from './context';\n\nimport type { RichInputHandle } from '../RichInput/types';\n\n/** TipTap prompt field. Import this only when the plain textarea is not enough. */\nexport function ComposerRichField() {\n const {\n value,\n setPrompt,\n submit,\n placeholder,\n autoFocus,\n submitOnEnter,\n minHeight,\n focusRef,\n addFiles,\n pasteTextAsFile,\n } = useComposer();\n const doc = useMemo(() => plainTextToDoc(value.prompt), [value.prompt]);\n\n return (\n <div className={ styles.textareaWrap }>\n <RichInput\n ref={ (node: RichInputHandle | null) => {\n focusRef.current = node;\n } }\n value={ doc }\n onChange={ (next) => setPrompt(docToPlainText(next)) }\n autoFocus={ autoFocus }\n minHeight={ minHeight }\n maxHeight={ 280 }\n placeholder={ placeholder }\n className={ styles.textarea }\n aria-label={ placeholder }\n submitOnEnter={ submitOnEnter }\n onSubmit={ () => submit() }\n onPasteFiles={ files => addFiles(files) }\n onPasteText={ pasteTextAsFile }\n />\n </div>\n );\n}\n"],"names":["ComposerRichField","value","setPrompt","submit","placeholder","autoFocus","submitOnEnter","minHeight","focusRef","addFiles","pasteTextAsFile","useComposer","doc","useMemo","plainTextToDoc","styles","RichInput","node","next","docToPlainText","files"],"mappings":";;;;;;AASO,SAASA,IAAoB;AAClC,QAAM;AAAA,IACJ,OAAAC;AAAA,IACA,WAAAC;AAAA,IACA,QAAAC;AAAA,IACA,aAAAC;AAAA,IACA,WAAAC;AAAA,IACA,eAAAC;AAAA,IACA,WAAAC;AAAA,IACA,UAAAC;AAAA,IACA,UAAAC;AAAA,IACA,iBAAAC;AAAA,EAAA,IACEC,EAAA,GACEC,IAAMC,EAAQ,MAAMC,EAAeb,EAAM,MAAM,GAAG,CAACA,EAAM,MAAM,CAAC;AACtE,2BAAyB,OAAO;AAAA,IAC9B,WAAWc,EAAO;AAAA,IAClB,4BAA4BC,GAAW;AAAA,MACrC,KAAK,CAAAC,MAAQ;AACX,QAAAT,EAAS,UAAUS;AAAA,MACrB;AAAA,MACA,OAAOL;AAAA,MACP,UAAU,CAAAM,MAAQhB,EAAUiB,EAAeD,CAAI,CAAC;AAAA,MAChD,WAAAb;AAAA,MACA,WAAAE;AAAA,MACA,WAAW;AAAA,MACX,aAAAH;AAAA,MACA,WAAWW,EAAO;AAAA,MAClB,cAAcX;AAAA,MACd,eAAAE;AAAA,MACA,UAAU,MAAMH,EAAA;AAAA,MAChB,cAAc,CAAAiB,MAASX,EAASW,CAAK;AAAA,MACrC,aAAaV;AAAA,IAAA,CACd;AAAA,EAAA,CACF;AACH;"}
1
+ {"version":3,"file":"RichField.js","sources":["../../src/Composer/RichField.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@reforma/lib';\nimport Bold from '@tiptap/extension-bold';\nimport Code from '@tiptap/extension-code';\nimport Document from '@tiptap/extension-document';\nimport HardBreak from '@tiptap/extension-hard-break';\nimport History from '@tiptap/extension-history';\nimport Italic from '@tiptap/extension-italic';\nimport { ListKit } from '@tiptap/extension-list';\nimport Paragraph from '@tiptap/extension-paragraph';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport Text from '@tiptap/extension-text';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport { useEffect, useLayoutEffect } from 'react';\n\nimport { docToPlainText, plainTextToDoc } from '../RichInput/composerDoc';\nimport { handleComposerKeyDown } from '../RichInput/composerKeymap';\nimport { useComposer } from './context';\n\nimport type { EditorOptions } from '@tiptap/core';\nimport type { CSSProperties, HTMLAttributes } from 'react';\nimport type { ComposerClassNames } from './types';\n\n/** TipTap field with caller-owned wrapper and editable-element classes. */\nexport function ComposerRichField({\n className,\n classNames: slots,\n style,\n ...props\n}: HTMLAttributes<HTMLDivElement> & {\n classNames?: Pick<ComposerClassNames, 'textareaWrap' | 'editor'>;\n}) {\n const {\n value, setPrompt, submit, placeholder, autoFocus, submitOnEnter,\n focusRef, addFiles, pasteTextAsFile, classNames, minHeight,\n } = useComposer();\n const editorClassName = cn(classNames.editor, slots?.editor);\n const editorProps: EditorOptions['editorProps'] = {\n attributes: {\n class: editorClassName,\n role: 'textbox',\n 'aria-multiline': 'true',\n 'aria-label': props['aria-label'] ?? placeholder,\n 'aria-placeholder': placeholder,\n 'data-slot': 'composer-editor',\n },\n handleKeyDown: (view, event) => handleComposerKeyDown(view, event, {\n submitOnEnter,\n hasMenuItems: false,\n onSubmit: () => submit(),\n }),\n handlePaste: (_view, event) => {\n const files = event.clipboardData?.files;\n if (files?.length) {\n addFiles([...files]);\n return true;\n }\n return pasteTextAsFile(event.clipboardData?.getData('text/plain') ?? '');\n },\n };\n const editor = useEditor({\n immediatelyRender: false,\n injectCSS: false,\n autofocus: autoFocus && (typeof document === 'undefined' || !document.activeElement?.matches('input, textarea, [contenteditable=\"true\"]')) ? 'end' : false,\n extensions: [\n Document,\n Paragraph,\n Text,\n HardBreak.extend({ addKeyboardShortcuts: () => ({}) }),\n History,\n Bold,\n Italic,\n Code,\n ListKit.configure({ taskItem: false, taskList: false }),\n Placeholder.configure({ placeholder: ({ editor: current }) => {\n const attributes = current.options.editorProps.attributes;\n return (typeof attributes === 'function' ? attributes(current.state) : attributes)?.['aria-placeholder'] ?? '';\n } }),\n ],\n content: plainTextToDoc(value.prompt),\n editorProps,\n onUpdate: ({ editor: current }) => setPrompt(docToPlainText(current.getJSON())),\n });\n\n useLayoutEffect(() => {\n editor?.setOptions({ editorProps });\n });\n\n useLayoutEffect(() => {\n if (!editor) {\n return;\n }\n const handle = { focus: () => {\n editor.chain().focus().run();\n } };\n focusRef.current = handle;\n return () => {\n if (focusRef.current === handle) {\n focusRef.current = null;\n }\n };\n }, [editor, focusRef]);\n\n useEffect(() => {\n if (!editor || docToPlainText(editor.getJSON()) === value.prompt) {\n return;\n }\n // Host resets do not become undo steps; local edits keep their rich document.\n editor.chain().setMeta('addToHistory', false)\n .setContent(plainTextToDoc(value.prompt), { emitUpdate: false }).run();\n }, [editor, value.prompt]);\n\n return (\n <div data-slot=\"composer-field-wrapper\" className={ cn(classNames.textareaWrap, slots?.textareaWrap) }>\n <EditorContent\n { ...props }\n editor={ editor }\n data-slot=\"composer-rich-field\"\n className={ cn(classNames.textarea, className) }\n style={ { '--composer-min-height': `${ minHeight }px`, ...style } as CSSProperties }\n />\n </div>\n );\n}\n"],"names":["ComposerRichField","className","slots","style","props","value","setPrompt","submit","placeholder","autoFocus","submitOnEnter","focusRef","addFiles","pasteTextAsFile","classNames","minHeight","useComposer","editorProps","cn","view","event","handleComposerKeyDown","_view","files","editor","useEditor","Document","Paragraph","Text","HardBreak","History","Bold","Italic","Code","ListKit","Placeholder","current","attributes","plainTextToDoc","docToPlainText","useLayoutEffect","handle","useEffect","EditorContent"],"mappings":"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"}
@@ -1,10 +1,11 @@
1
1
  import { type ReactNode, type RefObject } from 'react';
2
2
  import { useFileDrag } from '../hooks/useFileDrag';
3
- import type { ComposerUploadResult, ComposerValue } from './types';
3
+ import type { ComposerClassNames, ComposerNotice, ComposerUploadResult, ComposerValue } from './types';
4
4
  export type ComposerFieldHandle = {
5
5
  focus: () => void;
6
6
  };
7
7
  export type ComposerContextValue = {
8
+ classNames: ComposerClassNames;
8
9
  value: ComposerValue;
9
10
  setPrompt: (prompt: string) => void;
10
11
  setPlanMode: (planMode: boolean) => void;
@@ -28,6 +29,9 @@ export type ComposerContextValue = {
28
29
  };
29
30
  export declare function useComposer(): ComposerContextValue;
30
31
  export type ComposerProviderProps = {
32
+ classNames?: ComposerClassNames;
33
+ /** Report validation errors in the host UI. Defaults to an inline alert. */
34
+ onError?: (notice: ComposerNotice) => void;
31
35
  value: ComposerValue;
32
36
  onChange: (value: ComposerValue) => void;
33
37
  onSubmit: () => void;
@@ -40,5 +44,5 @@ export type ComposerProviderProps = {
40
44
  rows?: number;
41
45
  children: ReactNode;
42
46
  };
43
- export declare function ComposerProvider({ value, onChange, onSubmit, uploadFile, busy, placeholder, autoFocus, submitHotkey, rows, children, }: ComposerProviderProps): import("react").JSX.Element;
47
+ export declare function ComposerProvider({ classNames, onError, value, onChange, onSubmit, uploadFile, busy, placeholder, autoFocus, submitHotkey, rows, children, }: ComposerProviderProps): import("react").JSX.Element;
44
48
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/Composer/context.tsx"],"names":[],"mappings":"AASA,OAAO,EAQH,KAAK,SAAS,EACd,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,OAAO,KAAK,EAER,oBAAoB,EACpB,aAAa,EAChB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,mBAAmB,GAAG;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAC/B,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,WAAW,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,IAAI,EAAE,KAAK,IAAI,CAAC;IACtD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3C,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAChD,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;CACxC,CAAC;AAIF,wBAAgB,WAAW,IAAI,oBAAoB,CAQlD;AAmCD,MAAM,MAAM,qBAAqB,GAAG;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IACrC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,IAAY,EACZ,WAAkC,EAClC,SAAgB,EAChB,YAA0B,EAC1B,IAAQ,EACR,QAAQ,GACX,EAAE,qBAAqB,+BAgOvB"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/Composer/context.tsx"],"names":[],"mappings":"AASA,OAAO,EAQH,KAAK,SAAS,EACd,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,OAAO,KAAK,EAER,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,aAAa,EAChB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,mBAAmB,GAAG;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAC/B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,WAAW,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,IAAI,EAAE,KAAK,IAAI,CAAC;IACtD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3C,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAChD,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;CACxC,CAAC;AAIF,wBAAgB,WAAW,IAAI,oBAAoB,CAQlD;AAmCD,MAAM,MAAM,qBAAqB,GAAG;IAChC,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IACrC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC7B,UAAe,EACf,OAAO,EACP,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,IAAY,EACZ,WAAkC,EAClC,SAAgB,EAChB,YAA0B,EAC1B,IAAQ,EACR,QAAQ,GACX,EAAE,qBAAqB,+BAoQvB"}
@@ -1,70 +1,91 @@
1
- import { coerceUploadMimeType as z, MAX_CHAT_ATTACHMENT_BYTES_PER_FILE as y, MAX_CHAT_ATTACHMENT_BYTES_TOTAL as x, COMPOSER_PASTE_AS_FILE_MIN_CHARS as $ } from "@reforma/constants";
2
- import { revokeObjectURL as A, formatFileSize as F, createObjectURL as X } from "@reforma/lib";
3
- import { useRef as f, useState as Y, useLayoutEffect as W, useEffect as q, useCallback as R, use as G, createContext as J } from "react";
4
- import { useFileDrag as K } from "../hooks/useFileDrag.js";
5
- import { toast as T } from "../Toast/Toast.js";
6
- import { jsxs as Q, jsx as V } from "react/jsx-runtime";
7
- const M = /* @__PURE__ */ J(null);
8
- function it() {
9
- const o = G(M);
10
- if (!o)
1
+ import { coerceUploadMimeType as x, MAX_CHAT_ATTACHMENT_BYTES_PER_FILE as S, MAX_CHAT_ATTACHMENT_BYTES_TOTAL as O, COMPOSER_PASTE_AS_FILE_MIN_CHARS as Z } from "@reforma/constants";
2
+ import { revokeObjectURL as C, formatFileSize as P, createObjectURL as ee } from "@reforma/lib";
3
+ import { useState as k, useCallback as y, useRef as f, useLayoutEffect as B, useEffect as te, use as re, createContext as ne } from "react";
4
+ import { useFileDrag as oe } from "../hooks/useFileDrag.js";
5
+ import { Show as se } from "../Show/Show.js";
6
+ import { jsxs as D, jsx as H } from "react/jsx-runtime";
7
+ const L = /* @__PURE__ */ ne(null);
8
+ function fe() {
9
+ const s = re(L);
10
+ if (!s)
11
11
  throw new Error("Composer pieces must render inside ComposerProvider");
12
- return o;
13
- }
14
- function Z(o) {
15
- let s = 0;
16
- for (const c of o)
17
- typeof c.size == "number" && Number.isFinite(c.size) && (s += c.size);
18
12
  return s;
19
13
  }
20
- function tt(o) {
21
- return o.length === 0 ? !0 : o.every((s) => s.uploadStatus === "ready" && !!s.url);
14
+ function ae(s) {
15
+ let a = 0;
16
+ for (const i of s)
17
+ typeof i.size == "number" && Number.isFinite(i.size) && (a += i.size);
18
+ return a;
19
+ }
20
+ function ie(s) {
21
+ return s.length === 0 ? !0 : s.every((a) => a.uploadStatus === "ready" && !!a.url);
22
22
  }
23
- function v(o, s, c) {
23
+ function E(s, a, i) {
24
24
  return {
25
- ...o,
26
- attachments: o.attachments.map((m) => m.clientId === s ? {
25
+ ...s,
26
+ attachments: s.attachments.map((m) => m.clientId === a ? {
27
27
  ...m,
28
- ...c
28
+ ...i
29
29
  } : m)
30
30
  };
31
31
  }
32
- function ct({
33
- value: o,
34
- onChange: s,
35
- onSubmit: c,
36
- uploadFile: m,
37
- busy: E = !1,
38
- placeholder: b = "What should it do?",
39
- autoFocus: O = !0,
40
- submitHotkey: C = "mod+enter",
41
- rows: h = 3,
42
- children: P
32
+ function he({
33
+ classNames: s = {},
34
+ onError: a,
35
+ value: i,
36
+ onChange: m,
37
+ onSubmit: U,
38
+ uploadFile: _,
39
+ busy: z = !1,
40
+ placeholder: I = "What should it do?",
41
+ autoFocus: N = !0,
42
+ submitHotkey: j = "mod+enter",
43
+ rows: A = 3,
44
+ children: $
43
45
  }) {
44
- const S = f(null), _ = f(null), i = f(o), l = f(/* @__PURE__ */ new Map()), [B, D] = Y(!1);
45
- W(() => {
46
- i.current = o;
47
- }, [o]), q(() => {
48
- const t = l.current;
46
+ const [v, R] = k(null), h = y((e) => {
47
+ a ? a(e) : R(e);
48
+ }, [a]), w = f(null), F = f(null), c = f(i), M = f(m), d = f(/* @__PURE__ */ new Map()), [X, Y] = k(!1);
49
+ B(() => {
50
+ c.current = i;
51
+ }, [i]), B(() => {
52
+ M.current = m;
53
+ }, [m]);
54
+ const l = y((e) => {
55
+ c.current = e, M.current(e);
56
+ }, []);
57
+ te(() => {
58
+ const e = d.current;
49
59
  return () => {
50
- for (const n of i.current.attachments)
51
- A(n.preview);
52
- t.clear();
60
+ for (const n of c.current.attachments)
61
+ C(n.preview);
62
+ e.clear();
53
63
  };
54
64
  }, []);
55
- const w = !!o.prompt.trim() && tt(o.attachments) && !E, g = R(async (t, n) => {
56
- const r = await m(n), a = i.current;
57
- if (!a.attachments.some((u) => u.clientId === t)) {
58
- l.current.delete(t);
65
+ const b = !!i.prompt.trim() && ie(i.attachments) && !z, T = y(async (e, n) => {
66
+ let r;
67
+ try {
68
+ r = await _(n);
69
+ } catch (u) {
70
+ r = {
71
+ ok: !1,
72
+ message: u instanceof Error ? u.message : void 0
73
+ };
74
+ }
75
+ if (d.current.get(e) !== n)
76
+ return;
77
+ const o = c.current;
78
+ if (!o.attachments.some((u) => u.clientId === e)) {
79
+ d.current.delete(e);
59
80
  return;
60
81
  }
61
82
  if (r.ok) {
62
- const u = a.attachments.find((d) => d.clientId === t)?.preview;
63
- A(u), l.current.delete(t), s(v(a, t, {
83
+ const u = o.attachments.find((p) => p.clientId === e)?.preview;
84
+ C(u), d.current.delete(e), l(E(o, e, {
64
85
  id: r.data.id,
65
86
  url: r.data.url,
66
87
  filename: r.data.name ?? n.name,
67
- mediaType: r.data.mimeType ?? z(n.name, n.type),
88
+ mediaType: r.data.mimeType ?? x(n.name, n.type),
68
89
  size: r.data.size ?? n.size,
69
90
  uploadStatus: "ready",
70
91
  uploadError: void 0,
@@ -72,134 +93,141 @@ function ct({
72
93
  }));
73
94
  return;
74
95
  }
75
- s(v(a, t, {
96
+ l(E(o, e, {
76
97
  uploadStatus: "error",
77
98
  uploadError: r.message ?? "Upload failed"
78
99
  }));
79
- }, [s, m]), p = R((t) => {
80
- const n = [...t], r = [];
81
- let a = 0;
82
- const u = Z(i.current.attachments);
83
- for (const e of n) {
84
- if (e.size > y) {
85
- T.warning({
100
+ }, [l, _]), g = y((e) => {
101
+ R(null);
102
+ const n = [...e], r = [];
103
+ let o = 0;
104
+ const u = ae(c.current.attachments);
105
+ for (const t of n) {
106
+ if (t.size > S) {
107
+ h({
86
108
  title: "Attachment too large",
87
- message: `${e.name} is over the ${F(y, {
109
+ message: `${t.name} is over the ${P(S, {
88
110
  round: "up"
89
111
  })} per-file limit.`
90
112
  });
91
113
  continue;
92
114
  }
93
- if (u + a + e.size > x) {
94
- T.warning({
115
+ if (u + o + t.size > O) {
116
+ h({
95
117
  title: "Attachments too large",
96
- message: `Adding ${e.name} would exceed the ${F(x, {
118
+ message: `Adding ${t.name} would exceed the ${P(O, {
97
119
  round: "up"
98
120
  })} combined limit.`
99
121
  });
100
122
  continue;
101
123
  }
102
- r.push(e), a += e.size;
124
+ r.push(t), o += t.size;
103
125
  }
104
126
  if (r.length === 0)
105
127
  return;
106
- const d = r.map((e) => ({
128
+ const p = r.map((t) => ({
107
129
  clientId: crypto.randomUUID(),
108
- filename: e.name,
109
- mediaType: z(e.name, e.type),
110
- size: e.size,
111
- lastModified: e.lastModified,
130
+ filename: t.name,
131
+ mediaType: x(t.name, t.type),
132
+ size: t.size,
133
+ lastModified: t.lastModified,
112
134
  uploadStatus: "uploading",
113
- preview: X(e) ?? void 0
135
+ preview: ee(t) ?? void 0
114
136
  }));
115
- for (let e = 0; e < r.length; e++)
116
- l.current.set(d[e].clientId, r[e]);
117
- const N = {
118
- ...i.current,
119
- attachments: [...i.current.attachments, ...d]
137
+ for (let t = 0; t < r.length; t++)
138
+ d.current.set(p[t].clientId, r[t]);
139
+ const Q = {
140
+ ...c.current,
141
+ attachments: [...c.current.attachments, ...p]
120
142
  };
121
- s(N);
122
- for (let e = 0; e < r.length; e++)
123
- g(d[e].clientId, r[e]);
124
- }, [s, g]), H = K({
125
- onFileDragOver: D,
126
- onFilesDropped: (t) => p(t)
127
- }), I = (t) => {
128
- const n = i.current, r = n.attachments.find((a) => a.clientId === t);
129
- A(r?.preview), l.current.delete(t), s({
143
+ l(Q);
144
+ for (let t = 0; t < r.length; t++)
145
+ T(p[t].clientId, r[t]);
146
+ }, [l, T, h]), V = oe({
147
+ onFileDragOver: Y,
148
+ onFilesDropped: (e) => g(e)
149
+ }), W = (e) => {
150
+ const n = c.current, r = n.attachments.find((o) => o.clientId === e);
151
+ C(r?.preview), d.current.delete(e), l({
130
152
  ...n,
131
- attachments: n.attachments.filter((a) => a.clientId !== t)
153
+ attachments: n.attachments.filter((o) => o.clientId !== e)
132
154
  });
133
- }, L = (t) => {
134
- const n = i.current, r = n.attachments.find((u) => u.clientId === t), a = l.current.get(t);
155
+ }, q = (e) => {
156
+ const n = c.current, r = n.attachments.find((u) => u.clientId === e), o = d.current.get(e);
135
157
  if (!(!r || r.uploadStatus !== "error")) {
136
- if (!a) {
137
- T.warning({
158
+ if (!o) {
159
+ h({
138
160
  title: "Could not retry",
139
161
  message: "Remove the file and attach it again."
140
162
  });
141
163
  return;
142
164
  }
143
- s(v(n, t, {
165
+ l(E(n, e, {
144
166
  uploadStatus: "uploading",
145
167
  uploadError: void 0
146
- })), g(t, a);
168
+ })), T(e, o);
147
169
  }
148
- }, U = () => {
149
- w && c();
150
- }, k = (t) => {
151
- if (t.length < $)
170
+ }, G = () => {
171
+ b && U();
172
+ }, J = (e) => {
173
+ if (e.length < Z)
152
174
  return !1;
153
- const n = new File([t], "paste.txt", {
175
+ const n = new File([e], "paste.txt", {
154
176
  type: "text/plain"
155
177
  });
156
- return n.size > y ? !1 : (p([n]), !0);
157
- }, j = {
158
- value: o,
159
- setPrompt: (t) => s({
160
- ...i.current,
161
- prompt: t
178
+ return n.size > S ? !1 : (g([n]), !0);
179
+ }, K = {
180
+ classNames: s,
181
+ value: i,
182
+ setPrompt: (e) => l({
183
+ ...c.current,
184
+ prompt: e
162
185
  }),
163
- setPlanMode: (t) => s({
164
- ...i.current,
165
- planMode: t
186
+ setPlanMode: (e) => l({
187
+ ...c.current,
188
+ planMode: e
166
189
  }),
167
- addFiles: p,
168
- removeAttachment: I,
169
- retryAttachment: L,
170
- submit: U,
171
- canSubmit: w,
172
- busy: E,
173
- placeholder: b,
174
- autoFocus: O,
175
- submitOnEnter: C === "enter",
176
- rows: h,
177
- minHeight: h ? h * 22 : 20,
178
- pasteTextAsFile: k,
179
- openFilePicker: () => S.current?.click(),
180
- focus: () => _.current?.focus(),
181
- focusRef: _,
182
- fileDragOver: B,
183
- drag: H
190
+ addFiles: g,
191
+ removeAttachment: W,
192
+ retryAttachment: q,
193
+ submit: G,
194
+ canSubmit: b,
195
+ busy: z,
196
+ placeholder: I,
197
+ autoFocus: N,
198
+ submitOnEnter: j === "enter",
199
+ rows: A,
200
+ minHeight: A ? A * 22 : 20,
201
+ pasteTextAsFile: J,
202
+ openFilePicker: () => w.current?.click(),
203
+ focus: () => F.current?.focus(),
204
+ focusRef: F,
205
+ fileDragOver: X,
206
+ drag: V
184
207
  };
185
- return /* @__PURE__ */ Q(M, {
186
- value: j,
187
- children: [P, /* @__PURE__ */ V("input", {
188
- ref: S,
208
+ return /* @__PURE__ */ D(L, {
209
+ value: K,
210
+ children: [$, /* @__PURE__ */ H(se, {
211
+ when: v && !a,
212
+ children: /* @__PURE__ */ D("p", {
213
+ role: "alert",
214
+ className: s.notice,
215
+ children: [v?.title, ": ", v?.message]
216
+ })
217
+ }), /* @__PURE__ */ H("input", {
218
+ ref: w,
189
219
  type: "file",
190
220
  multiple: !0,
191
221
  tabIndex: -1,
192
- style: {
193
- display: "none"
194
- },
195
- onChange: (t) => {
196
- t.target.files?.length && p(t.target.files), t.target.value = "";
222
+ hidden: !0,
223
+ onChange: (e) => {
224
+ e.target.files?.length && g(e.target.files), e.target.value = "";
197
225
  }
198
226
  })]
199
227
  });
200
228
  }
201
229
  export {
202
- ct as ComposerProvider,
203
- it as useComposer
230
+ he as ComposerProvider,
231
+ fe as useComposer
204
232
  };
205
233
  //# sourceMappingURL=context.js.map