@better-zap/react 0.2.1 → 0.2.2

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 (50) hide show
  1. package/dist/bubble.cjs +93 -0
  2. package/dist/bubble.d.cts +61 -0
  3. package/dist/bubble.d.mts +61 -0
  4. package/dist/bubble.mjs +89 -0
  5. package/dist/composer.cjs +220 -0
  6. package/dist/composer.d.cts +96 -0
  7. package/dist/composer.d.mts +96 -0
  8. package/dist/composer.mjs +211 -0
  9. package/dist/conversation-list-BlhJhDsc.d.cts +100 -0
  10. package/dist/conversation-list-BwQ4oK2J.d.mts +100 -0
  11. package/dist/conversation-list-C0EmReS-.mjs +293 -0
  12. package/dist/conversation-list-CVWdddJh.cjs +311 -0
  13. package/dist/conversation-list.cjs +6 -0
  14. package/dist/conversation-list.d.cts +2 -0
  15. package/dist/conversation-list.d.mts +2 -0
  16. package/dist/conversation-list.mjs +5 -0
  17. package/dist/index.cjs +49 -0
  18. package/dist/index.d.cts +19 -0
  19. package/dist/index.d.mts +19 -0
  20. package/dist/index.mjs +11 -0
  21. package/dist/message-bubble.cjs +116 -0
  22. package/dist/message-bubble.d.cts +38 -0
  23. package/dist/message-bubble.d.mts +38 -0
  24. package/dist/message-bubble.mjs +114 -0
  25. package/dist/message-input-CkaL6fb4.mjs +173 -0
  26. package/dist/message-input-DcEzHQ9t.cjs +191 -0
  27. package/dist/message-input.cjs +6 -0
  28. package/dist/message-input.d.cts +51 -0
  29. package/dist/message-input.d.mts +51 -0
  30. package/dist/message-input.mjs +5 -0
  31. package/dist/message-view.cjs +273 -0
  32. package/dist/message-view.d.cts +109 -0
  33. package/dist/message-view.d.mts +109 -0
  34. package/dist/message-view.mjs +266 -0
  35. package/dist/message.cjs +50 -0
  36. package/dist/message.d.cts +40 -0
  37. package/dist/message.d.mts +40 -0
  38. package/dist/message.mjs +43 -0
  39. package/dist/tailwind.css +33 -0
  40. package/dist/utils-Bp9IahGG.cjs +91 -0
  41. package/dist/utils.cjs +5 -0
  42. package/dist/utils.d.cts +20 -0
  43. package/dist/utils.d.mts +20 -0
  44. package/dist/utils.mjs +45 -0
  45. package/dist/whatsapp-dashboard.cjs +64 -0
  46. package/dist/whatsapp-dashboard.d.cts +33 -0
  47. package/dist/whatsapp-dashboard.d.mts +33 -0
  48. package/dist/whatsapp-dashboard.mjs +60 -0
  49. package/dist/wpp-bg.webp +0 -0
  50. package/package.json +1 -1
@@ -0,0 +1,93 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_utils = require("./utils-Bp9IahGG.cjs");
3
+ let react = require("react");
4
+ react = require_utils.__toESM(react);
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+ //#region src/bubble.tsx
7
+ const bubbleVariants = (0, require("class-variance-authority").cva)("relative w-fit max-w-full rounded-[7.5px] px-[9px] py-[6px] text-[14.2px] leading-[19px] shadow-[0_1px_0.5px_rgba(11,20,26,0.13)]", {
8
+ variants: { variant: {
9
+ default: "bg-white text-[#111b21]",
10
+ primary: "bg-[#d9fdd3] text-[#111b21]",
11
+ destructive: "bg-[#fdd8d5] text-[#111b21]",
12
+ outline: "border border-gray-300 bg-transparent text-[#111b21] shadow-none",
13
+ muted: "bg-gray-50 text-gray-500"
14
+ } },
15
+ defaultVariants: { variant: "default" }
16
+ });
17
+ const tailCornerByAlign = {
18
+ start: "rounded-tl-none",
19
+ end: "rounded-tr-none"
20
+ };
21
+ const tailColorByVariant = {
22
+ default: "text-white",
23
+ primary: "text-[#d9fdd3]",
24
+ destructive: "text-[#fdd8d5]",
25
+ outline: "text-transparent",
26
+ muted: "text-gray-50"
27
+ };
28
+ /** WhatsApp's bubble tail, drawn outside the top corner of the bubble. */
29
+ function BubbleTail({ align, variant }) {
30
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
31
+ "aria-hidden": true,
32
+ className: require_utils.cn("absolute top-0 block h-[13px] w-2", align === "start" ? "-left-2 -scale-x-100" : "-right-2", tailColorByVariant[variant]),
33
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
34
+ viewBox: "0 0 8 13",
35
+ width: "8",
36
+ height: "13",
37
+ fill: "none",
38
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
39
+ fill: "#0b141a",
40
+ opacity: "0.13",
41
+ d: "M5.188 1H0v11.193l6.467-8.625C7.526 2.156 6.958 1 5.188 1Z"
42
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
43
+ fill: "currentColor",
44
+ d: "M5.188 0H0v11.193l6.467-8.625C7.526 1.156 6.958 0 5.188 0Z"
45
+ })]
46
+ })
47
+ });
48
+ }
49
+ function Bubble({ variant = "default", align = "start", tail = true, className, children, ...props }) {
50
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
51
+ "data-variant": variant,
52
+ "data-align": align,
53
+ className: require_utils.cn(bubbleVariants({ variant }), tail && tailCornerByAlign[align], className),
54
+ ...props,
55
+ children: [tail && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleTail, {
56
+ align,
57
+ variant
58
+ }), children]
59
+ });
60
+ }
61
+ function BubbleContent({ render, className, children, ...props }) {
62
+ const contentClassName = require_utils.cn("whitespace-pre-wrap break-words select-text focus-visible:outline-2 focus-visible:outline-offset-2", className);
63
+ if (render) return require_utils.renderSlot(render, {
64
+ className: contentClassName,
65
+ ...props,
66
+ children
67
+ });
68
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
69
+ className: contentClassName,
70
+ ...props,
71
+ children
72
+ });
73
+ }
74
+ function BubbleReactions({ side = "bottom", align = "end", className, ...props }) {
75
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
76
+ "data-side": side,
77
+ "data-align": align,
78
+ className: require_utils.cn("absolute z-10 flex items-center gap-0.5 rounded-full border border-gray-200 bg-white px-1.5 py-0.5 text-xs shadow-sm", side === "bottom" ? "-bottom-2.5" : "-top-2.5", align === "start" ? "left-1" : "right-1", className),
79
+ ...props
80
+ });
81
+ }
82
+ function BubbleGroup({ align = "start", className, ...props }) {
83
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
84
+ "data-align": align,
85
+ className: require_utils.cn("flex w-full flex-col gap-0.5", align === "start" ? "items-start" : "items-end", className),
86
+ ...props
87
+ });
88
+ }
89
+ //#endregion
90
+ exports.Bubble = Bubble;
91
+ exports.BubbleContent = BubbleContent;
92
+ exports.BubbleGroup = BubbleGroup;
93
+ exports.BubbleReactions = BubbleReactions;
@@ -0,0 +1,61 @@
1
+ import React from "react";
2
+
3
+ //#region src/bubble.d.ts
4
+ type BubbleAlign = "start" | "end";
5
+ type BubbleVariant = "default" | "primary" | "destructive" | "outline" | "muted";
6
+ interface BubbleProps extends React.ComponentProps<"div"> {
7
+ /** Visual treatment. Presentational only — never domain terms. @default "default" */
8
+ variant?: BubbleVariant;
9
+ /** Which side the corner tail sits on. @default "start" */
10
+ align?: BubbleAlign;
11
+ /**
12
+ * Renders WhatsApp's corner tail and squares that corner. Show it on the
13
+ * first bubble of a group (or a lone bubble), hide it on follow-ups.
14
+ * @default true
15
+ */
16
+ tail?: boolean;
17
+ }
18
+ declare function Bubble({
19
+ variant,
20
+ align,
21
+ tail,
22
+ className,
23
+ children,
24
+ ...props
25
+ }: BubbleProps): React.JSX.Element;
26
+ interface BubbleContentProps extends React.ComponentProps<"div"> {
27
+ /**
28
+ * Element-only polymorphism (Base UI style). When provided, BubbleContent
29
+ * clones this element instead of rendering a &lt;div&gt;, merging props per renderSlot.
30
+ */
31
+ render?: React.ReactElement<Record<string, unknown>>;
32
+ }
33
+ declare function BubbleContent({
34
+ render,
35
+ className,
36
+ children,
37
+ ...props
38
+ }: BubbleContentProps): React.JSX.Element;
39
+ interface BubbleReactionsProps extends React.ComponentProps<"div"> {
40
+ /** @default "bottom" */
41
+ side?: "top" | "bottom";
42
+ /** @default "end" */
43
+ align?: BubbleAlign;
44
+ }
45
+ declare function BubbleReactions({
46
+ side,
47
+ align,
48
+ className,
49
+ ...props
50
+ }: BubbleReactionsProps): React.JSX.Element;
51
+ interface BubbleGroupProps extends React.ComponentProps<"div"> {
52
+ /** @default "start" */
53
+ align?: BubbleAlign;
54
+ }
55
+ declare function BubbleGroup({
56
+ align,
57
+ className,
58
+ ...props
59
+ }: BubbleGroupProps): React.JSX.Element;
60
+ //#endregion
61
+ export { Bubble, BubbleAlign, BubbleContent, BubbleContentProps, BubbleGroup, BubbleGroupProps, BubbleProps, BubbleReactions, BubbleReactionsProps, BubbleVariant };
@@ -0,0 +1,61 @@
1
+ import React from "react";
2
+
3
+ //#region src/bubble.d.ts
4
+ type BubbleAlign = "start" | "end";
5
+ type BubbleVariant = "default" | "primary" | "destructive" | "outline" | "muted";
6
+ interface BubbleProps extends React.ComponentProps<"div"> {
7
+ /** Visual treatment. Presentational only — never domain terms. @default "default" */
8
+ variant?: BubbleVariant;
9
+ /** Which side the corner tail sits on. @default "start" */
10
+ align?: BubbleAlign;
11
+ /**
12
+ * Renders WhatsApp's corner tail and squares that corner. Show it on the
13
+ * first bubble of a group (or a lone bubble), hide it on follow-ups.
14
+ * @default true
15
+ */
16
+ tail?: boolean;
17
+ }
18
+ declare function Bubble({
19
+ variant,
20
+ align,
21
+ tail,
22
+ className,
23
+ children,
24
+ ...props
25
+ }: BubbleProps): React.JSX.Element;
26
+ interface BubbleContentProps extends React.ComponentProps<"div"> {
27
+ /**
28
+ * Element-only polymorphism (Base UI style). When provided, BubbleContent
29
+ * clones this element instead of rendering a &lt;div&gt;, merging props per renderSlot.
30
+ */
31
+ render?: React.ReactElement<Record<string, unknown>>;
32
+ }
33
+ declare function BubbleContent({
34
+ render,
35
+ className,
36
+ children,
37
+ ...props
38
+ }: BubbleContentProps): React.JSX.Element;
39
+ interface BubbleReactionsProps extends React.ComponentProps<"div"> {
40
+ /** @default "bottom" */
41
+ side?: "top" | "bottom";
42
+ /** @default "end" */
43
+ align?: BubbleAlign;
44
+ }
45
+ declare function BubbleReactions({
46
+ side,
47
+ align,
48
+ className,
49
+ ...props
50
+ }: BubbleReactionsProps): React.JSX.Element;
51
+ interface BubbleGroupProps extends React.ComponentProps<"div"> {
52
+ /** @default "start" */
53
+ align?: BubbleAlign;
54
+ }
55
+ declare function BubbleGroup({
56
+ align,
57
+ className,
58
+ ...props
59
+ }: BubbleGroupProps): React.JSX.Element;
60
+ //#endregion
61
+ export { Bubble, BubbleAlign, BubbleContent, BubbleContentProps, BubbleGroup, BubbleGroupProps, BubbleProps, BubbleReactions, BubbleReactionsProps, BubbleVariant };
@@ -0,0 +1,89 @@
1
+ import { cn, renderSlot } from "./utils.mjs";
2
+ import "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { cva } from "class-variance-authority";
5
+ //#region src/bubble.tsx
6
+ const bubbleVariants = cva("relative w-fit max-w-full rounded-[7.5px] px-[9px] py-[6px] text-[14.2px] leading-[19px] shadow-[0_1px_0.5px_rgba(11,20,26,0.13)]", {
7
+ variants: { variant: {
8
+ default: "bg-white text-[#111b21]",
9
+ primary: "bg-[#d9fdd3] text-[#111b21]",
10
+ destructive: "bg-[#fdd8d5] text-[#111b21]",
11
+ outline: "border border-gray-300 bg-transparent text-[#111b21] shadow-none",
12
+ muted: "bg-gray-50 text-gray-500"
13
+ } },
14
+ defaultVariants: { variant: "default" }
15
+ });
16
+ const tailCornerByAlign = {
17
+ start: "rounded-tl-none",
18
+ end: "rounded-tr-none"
19
+ };
20
+ const tailColorByVariant = {
21
+ default: "text-white",
22
+ primary: "text-[#d9fdd3]",
23
+ destructive: "text-[#fdd8d5]",
24
+ outline: "text-transparent",
25
+ muted: "text-gray-50"
26
+ };
27
+ /** WhatsApp's bubble tail, drawn outside the top corner of the bubble. */
28
+ function BubbleTail({ align, variant }) {
29
+ return /* @__PURE__ */ jsx("span", {
30
+ "aria-hidden": true,
31
+ className: cn("absolute top-0 block h-[13px] w-2", align === "start" ? "-left-2 -scale-x-100" : "-right-2", tailColorByVariant[variant]),
32
+ children: /* @__PURE__ */ jsxs("svg", {
33
+ viewBox: "0 0 8 13",
34
+ width: "8",
35
+ height: "13",
36
+ fill: "none",
37
+ children: [/* @__PURE__ */ jsx("path", {
38
+ fill: "#0b141a",
39
+ opacity: "0.13",
40
+ d: "M5.188 1H0v11.193l6.467-8.625C7.526 2.156 6.958 1 5.188 1Z"
41
+ }), /* @__PURE__ */ jsx("path", {
42
+ fill: "currentColor",
43
+ d: "M5.188 0H0v11.193l6.467-8.625C7.526 1.156 6.958 0 5.188 0Z"
44
+ })]
45
+ })
46
+ });
47
+ }
48
+ function Bubble({ variant = "default", align = "start", tail = true, className, children, ...props }) {
49
+ return /* @__PURE__ */ jsxs("div", {
50
+ "data-variant": variant,
51
+ "data-align": align,
52
+ className: cn(bubbleVariants({ variant }), tail && tailCornerByAlign[align], className),
53
+ ...props,
54
+ children: [tail && /* @__PURE__ */ jsx(BubbleTail, {
55
+ align,
56
+ variant
57
+ }), children]
58
+ });
59
+ }
60
+ function BubbleContent({ render, className, children, ...props }) {
61
+ const contentClassName = cn("whitespace-pre-wrap break-words select-text focus-visible:outline-2 focus-visible:outline-offset-2", className);
62
+ if (render) return renderSlot(render, {
63
+ className: contentClassName,
64
+ ...props,
65
+ children
66
+ });
67
+ return /* @__PURE__ */ jsx("div", {
68
+ className: contentClassName,
69
+ ...props,
70
+ children
71
+ });
72
+ }
73
+ function BubbleReactions({ side = "bottom", align = "end", className, ...props }) {
74
+ return /* @__PURE__ */ jsx("div", {
75
+ "data-side": side,
76
+ "data-align": align,
77
+ className: cn("absolute z-10 flex items-center gap-0.5 rounded-full border border-gray-200 bg-white px-1.5 py-0.5 text-xs shadow-sm", side === "bottom" ? "-bottom-2.5" : "-top-2.5", align === "start" ? "left-1" : "right-1", className),
78
+ ...props
79
+ });
80
+ }
81
+ function BubbleGroup({ align = "start", className, ...props }) {
82
+ return /* @__PURE__ */ jsx("div", {
83
+ "data-align": align,
84
+ className: cn("flex w-full flex-col gap-0.5", align === "start" ? "items-start" : "items-end", className),
85
+ ...props
86
+ });
87
+ }
88
+ //#endregion
89
+ export { Bubble, BubbleContent, BubbleGroup, BubbleReactions };
@@ -0,0 +1,220 @@
1
+ "use client";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const require_utils = require("./utils-Bp9IahGG.cjs");
4
+ let react = require("react");
5
+ react = require_utils.__toESM(react);
6
+ let react_jsx_runtime = require("react/jsx-runtime");
7
+ let _hugeicons_react = require("@hugeicons/react");
8
+ let _hugeicons_core_free_icons = require("@hugeicons/core-free-icons");
9
+ //#region src/composer.tsx
10
+ const ComposerValueContext = (0, react.createContext)(null);
11
+ const ComposerStateContext = (0, react.createContext)(null);
12
+ /** The live draft string. Consumers re-render on every keystroke. */
13
+ function useComposerValue() {
14
+ const value = (0, react.useContext)(ComposerValueContext);
15
+ if (value === null) throw new Error("useComposerValue must be used within <Composer>");
16
+ return value;
17
+ }
18
+ /**
19
+ * Actions and boundary-stable flags without the live draft. Prefer this in
20
+ * children that don't display the text (send/attach buttons, error slots) so
21
+ * they don't re-render per keystroke.
22
+ */
23
+ function useComposerState() {
24
+ const ctx = (0, react.useContext)(ComposerStateContext);
25
+ if (!ctx) throw new Error("useComposerState must be used within <Composer>");
26
+ return ctx;
27
+ }
28
+ /** Full composer context. Subscribes to the draft: re-renders per keystroke. */
29
+ function useComposer() {
30
+ const ctx = (0, react.useContext)(ComposerStateContext);
31
+ const value = (0, react.useContext)(ComposerValueContext);
32
+ if (!ctx || value === null) throw new Error("useComposer must be used within <Composer>");
33
+ const { hasText: _hasText, ...rest } = ctx;
34
+ return {
35
+ ...rest,
36
+ value
37
+ };
38
+ }
39
+ const PILL_CLASS = "flex flex-wrap items-center gap-1 px-2 py-1 min-h-[52px] bg-white rounded-[24px] shadow-[0_1px_3px_rgba(11,20,26,0.12)]";
40
+ /**
41
+ * Owns draft/send state below the pill markup, so uncontrolled keystrokes
42
+ * re-render this provider and draft consumers only, never the pill div or
43
+ * children that stick to useComposerState.
44
+ */
45
+ function ComposerProvider({ value: valueProp, defaultValue, onValueChange, onSubmit, onError, disabled, children }) {
46
+ const isControlled = valueProp !== void 0;
47
+ const [internalValue, setInternalValue] = (0, react.useState)(defaultValue);
48
+ const [isSending, setIsSending] = (0, react.useState)(false);
49
+ const [error, setError] = (0, react.useState)(null);
50
+ const value = isControlled ? valueProp : internalValue;
51
+ const valueRef = (0, react.useRef)(value);
52
+ valueRef.current = value;
53
+ const disabledRef = (0, react.useRef)(disabled);
54
+ disabledRef.current = disabled;
55
+ const isSendingRef = (0, react.useRef)(false);
56
+ const onSubmitRef = (0, react.useRef)(onSubmit);
57
+ onSubmitRef.current = onSubmit;
58
+ const onErrorRef = (0, react.useRef)(onError);
59
+ onErrorRef.current = onError;
60
+ const onValueChangeRef = (0, react.useRef)(onValueChange);
61
+ onValueChangeRef.current = onValueChange;
62
+ const isControlledRef = (0, react.useRef)(isControlled);
63
+ isControlledRef.current = isControlled;
64
+ const setValue = (0, react.useCallback)((next) => {
65
+ if (!isControlledRef.current) setInternalValue(next);
66
+ onValueChangeRef.current?.(next);
67
+ }, []);
68
+ const clearError = (0, react.useCallback)(() => {
69
+ setError(null);
70
+ }, []);
71
+ const send = (0, react.useCallback)(() => {
72
+ (async () => {
73
+ const text = valueRef.current.trim();
74
+ if (!text || disabledRef.current || isSendingRef.current) return;
75
+ setError(null);
76
+ isSendingRef.current = true;
77
+ setIsSending(true);
78
+ try {
79
+ await onSubmitRef.current(text);
80
+ setValue("");
81
+ } catch (err) {
82
+ setError(err);
83
+ onErrorRef.current?.(err, { text });
84
+ } finally {
85
+ isSendingRef.current = false;
86
+ setIsSending(false);
87
+ }
88
+ })();
89
+ }, [setValue]);
90
+ const hasText = value.trim().length > 0;
91
+ const canSend = hasText && !disabled && !isSending;
92
+ const stateValue = (0, react.useMemo)(() => ({
93
+ setValue,
94
+ isSending,
95
+ disabled,
96
+ canSend,
97
+ hasText,
98
+ error,
99
+ clearError,
100
+ send
101
+ }), [
102
+ setValue,
103
+ isSending,
104
+ disabled,
105
+ canSend,
106
+ hasText,
107
+ error,
108
+ clearError,
109
+ send
110
+ ]);
111
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComposerStateContext.Provider, {
112
+ value: stateValue,
113
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComposerValueContext.Provider, {
114
+ value,
115
+ children
116
+ })
117
+ });
118
+ }
119
+ function Composer({ value, defaultValue = "", onValueChange, onSubmit, onError, disabled = false, className, children, ...props }) {
120
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
121
+ className: require_utils.cn(PILL_CLASS, className),
122
+ ...props,
123
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComposerProvider, {
124
+ value,
125
+ defaultValue,
126
+ onValueChange,
127
+ onSubmit,
128
+ onError,
129
+ disabled,
130
+ children
131
+ })
132
+ });
133
+ }
134
+ const TEXTAREA_CLASS = "flex-1 bg-transparent border-none text-[15px] leading-[22px] text-[#111b21] resize-none focus:outline-none max-h-[120px] placeholder:text-[#8696a0]";
135
+ function ComposerTextarea({ submitOnEnter = true, className, disabled: disabledProp, onKeyDown, onChange, ...props }) {
136
+ const value = useComposerValue();
137
+ const { setValue, disabled, isSending, send } = useComposerState();
138
+ const textareaRef = (0, react.useRef)(null);
139
+ const isDisabled = disabled || isSending || !!disabledProp;
140
+ (0, react.useEffect)(() => {
141
+ const el = textareaRef.current;
142
+ if (!el) return;
143
+ el.style.height = "auto";
144
+ if (value === "") return;
145
+ el.style.height = `${el.scrollHeight}px`;
146
+ }, [value]);
147
+ const handleKeyDown = (e) => {
148
+ onKeyDown?.(e);
149
+ if (e.defaultPrevented) return;
150
+ if (!submitOnEnter) return;
151
+ if (e.key !== "Enter" || e.shiftKey) return;
152
+ if (e.nativeEvent.isComposing) return;
153
+ e.preventDefault();
154
+ send();
155
+ };
156
+ const handleChange = (e) => {
157
+ setValue(e.target.value);
158
+ onChange?.(e);
159
+ };
160
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
161
+ ref: textareaRef,
162
+ className: require_utils.cn(TEXTAREA_CLASS, className),
163
+ name: "message",
164
+ autoComplete: "off",
165
+ rows: 1,
166
+ value,
167
+ onChange: handleChange,
168
+ onKeyDown: handleKeyDown,
169
+ disabled: isDisabled,
170
+ ...props
171
+ });
172
+ }
173
+ function ComposerSend({ className, disabled: disabledProp, onClick, children, type = "button", ...props }) {
174
+ const { canSend, send } = useComposerState();
175
+ const handleClick = (e) => {
176
+ send();
177
+ onClick?.(e);
178
+ };
179
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
180
+ type,
181
+ className: require_utils.cn("flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[#00a884] text-white transition-colors hover:bg-[#008f72] disabled:opacity-40 disabled:cursor-not-allowed", className),
182
+ disabled: !canSend || !!disabledProp,
183
+ onClick: handleClick,
184
+ ...props,
185
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_hugeicons_react.HugeiconsIcon, {
186
+ icon: _hugeicons_core_free_icons.Sent02Icon,
187
+ size: 20
188
+ })
189
+ });
190
+ }
191
+ function ComposerButton({ className, disabled: disabledProp, type = "button", ...props }) {
192
+ const { isSending } = useComposerState();
193
+ const isDisabled = disabledProp !== void 0 ? disabledProp : isSending;
194
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
195
+ type,
196
+ className: require_utils.cn("p-2 rounded-full hover:bg-black/5 transition-colors disabled:opacity-40", className),
197
+ disabled: isDisabled,
198
+ ...props
199
+ });
200
+ }
201
+ function ComposerError({ children, className, ...props }) {
202
+ const { error } = useComposerState();
203
+ if (error == null) return null;
204
+ const content = typeof children === "function" ? children(error) : children;
205
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
206
+ role: "alert",
207
+ className: require_utils.cn("w-full order-last", className),
208
+ ...props,
209
+ children: content
210
+ });
211
+ }
212
+ //#endregion
213
+ exports.Composer = Composer;
214
+ exports.ComposerButton = ComposerButton;
215
+ exports.ComposerError = ComposerError;
216
+ exports.ComposerSend = ComposerSend;
217
+ exports.ComposerTextarea = ComposerTextarea;
218
+ exports.useComposer = useComposer;
219
+ exports.useComposerState = useComposerState;
220
+ exports.useComposerValue = useComposerValue;
@@ -0,0 +1,96 @@
1
+ import React from "react";
2
+
3
+ //#region src/composer.d.ts
4
+ interface ComposerContextValue {
5
+ value: string;
6
+ setValue: (value: string) => void;
7
+ isSending: boolean;
8
+ disabled: boolean;
9
+ /** value.trim() is non-empty && !disabled && !isSending */
10
+ canSend: boolean;
11
+ /** null when no failed send is pending display */
12
+ error: unknown;
13
+ clearError: () => void;
14
+ /** Fire-and-forget; never rejects. See send() algorithm. */
15
+ send: () => void;
16
+ }
17
+ /**
18
+ * Everything except the live draft string. Changes only on boundary events
19
+ * (empty <-> non-empty, send lifecycle, errors), so consumers skip the
20
+ * per-keystroke re-render that `useComposer` implies.
21
+ */
22
+ interface ComposerStateContextValue extends Omit<ComposerContextValue, "value"> {
23
+ /** value.trim() is non-empty. Boundary-stable, unlike `value` itself. */
24
+ hasText: boolean;
25
+ }
26
+ /** The live draft string. Consumers re-render on every keystroke. */
27
+ declare function useComposerValue(): string;
28
+ /**
29
+ * Actions and boundary-stable flags without the live draft. Prefer this in
30
+ * children that don't display the text (send/attach buttons, error slots) so
31
+ * they don't re-render per keystroke.
32
+ */
33
+ declare function useComposerState(): ComposerStateContextValue;
34
+ /** Full composer context. Subscribes to the draft: re-renders per keystroke. */
35
+ declare function useComposer(): ComposerContextValue;
36
+ interface ComposerProps extends Omit<React.ComponentProps<"div">, "onSubmit" | "onError"> {
37
+ value?: string;
38
+ defaultValue?: string;
39
+ onValueChange?: (value: string) => void;
40
+ /** Required. Throw/reject to signal failure; the draft is preserved. */
41
+ onSubmit: (text: string) => void | Promise<void>;
42
+ onError?: (error: unknown, context: {
43
+ text: string;
44
+ }) => void;
45
+ disabled?: boolean;
46
+ }
47
+ declare function Composer({
48
+ value,
49
+ defaultValue,
50
+ onValueChange,
51
+ onSubmit,
52
+ onError,
53
+ disabled,
54
+ className,
55
+ children,
56
+ ...props
57
+ }: ComposerProps): React.JSX.Element;
58
+ interface ComposerTextareaProps extends React.ComponentProps<"textarea"> {
59
+ /** Enter sends (Shift+Enter = newline). Ignores IME composition. @default true */
60
+ submitOnEnter?: boolean;
61
+ }
62
+ declare function ComposerTextarea({
63
+ submitOnEnter,
64
+ className,
65
+ disabled: disabledProp,
66
+ onKeyDown,
67
+ onChange,
68
+ ...props
69
+ }: ComposerTextareaProps): React.JSX.Element;
70
+ type ComposerSendProps = React.ComponentProps<"button">;
71
+ declare function ComposerSend({
72
+ className,
73
+ disabled: disabledProp,
74
+ onClick,
75
+ children,
76
+ type,
77
+ ...props
78
+ }: ComposerSendProps): React.JSX.Element;
79
+ type ComposerButtonProps = React.ComponentProps<"button">;
80
+ declare function ComposerButton({
81
+ className,
82
+ disabled: disabledProp,
83
+ type,
84
+ ...props
85
+ }: ComposerButtonProps): React.JSX.Element;
86
+ interface ComposerErrorProps extends Omit<React.ComponentProps<"div">, "children"> {
87
+ /** Static node, or a function receiving the error. */
88
+ children?: React.ReactNode | ((error: unknown) => React.ReactNode);
89
+ }
90
+ declare function ComposerError({
91
+ children,
92
+ className,
93
+ ...props
94
+ }: ComposerErrorProps): React.JSX.Element | null;
95
+ //#endregion
96
+ export { Composer, ComposerButton, ComposerButtonProps, ComposerContextValue, ComposerError, ComposerErrorProps, ComposerProps, ComposerSend, ComposerSendProps, ComposerStateContextValue, ComposerTextarea, ComposerTextareaProps, useComposer, useComposerState, useComposerValue };