prompt-area 0.1.0 → 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.
Files changed (44) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +11 -3
  3. package/dist/action-bar/index.js +1 -4
  4. package/dist/chat-prompt-layout/index.js +1 -4
  5. package/dist/chunk-23Y7B365.js +2 -0
  6. package/dist/chunk-2R57LWJO.js +3 -0
  7. package/dist/chunk-3D4ZBBYY.js +2 -0
  8. package/dist/chunk-6VISE4VA.js +2 -0
  9. package/dist/chunk-A6EFF4BI.js +1 -0
  10. package/dist/chunk-CRC4ST6U.js +3 -0
  11. package/dist/chunk-LJJ6HHR6.js +14 -0
  12. package/dist/chunk-MJSTEY4N.js +7 -0
  13. package/dist/chunk-VULUMPYE.js +2 -0
  14. package/dist/compact-prompt-area/index.js +1 -5
  15. package/dist/helpers/index.d.ts +3 -185
  16. package/dist/helpers/index.js +1 -291
  17. package/dist/index.d.ts +2 -1
  18. package/dist/index.js +1 -9
  19. package/dist/prompt-area/index.d.ts +4 -191
  20. package/dist/prompt-area/index.js +1 -5
  21. package/dist/status-bar/index.js +1 -4
  22. package/package.json +25 -13
  23. package/LICENSE +0 -21
  24. package/dist/action-bar/index.js.map +0 -1
  25. package/dist/chat-prompt-layout/index.js.map +0 -1
  26. package/dist/chunk-ANZZEZP2.js +0 -38
  27. package/dist/chunk-ANZZEZP2.js.map +0 -1
  28. package/dist/chunk-BPJO4DGM.js +0 -198
  29. package/dist/chunk-BPJO4DGM.js.map +0 -1
  30. package/dist/chunk-BWVBDP7C.js +0 -38
  31. package/dist/chunk-BWVBDP7C.js.map +0 -1
  32. package/dist/chunk-E7HUXORB.js +0 -2692
  33. package/dist/chunk-E7HUXORB.js.map +0 -1
  34. package/dist/chunk-NF2LHZIE.js +0 -12
  35. package/dist/chunk-NF2LHZIE.js.map +0 -1
  36. package/dist/chunk-UBBCAMJA.js +0 -116
  37. package/dist/chunk-UBBCAMJA.js.map +0 -1
  38. package/dist/chunk-XDKRP7UE.js +0 -125
  39. package/dist/chunk-XDKRP7UE.js.map +0 -1
  40. package/dist/compact-prompt-area/index.js.map +0 -1
  41. package/dist/helpers/index.js.map +0 -1
  42. package/dist/index.js.map +0 -1
  43. package/dist/prompt-area/index.js.map +0 -1
  44. package/dist/status-bar/index.js.map +0 -1
@@ -1,291 +1 @@
1
- // src/prompt-area/prompt-area-engine.ts
2
- function segmentsToPlainText(segments) {
3
- return segments.map((seg) => {
4
- if (seg.type === "text") return seg.text;
5
- return `${seg.trigger}${seg.displayText}`;
6
- }).join("");
7
- }
8
- function plainTextToSegments(text2) {
9
- if (!text2) return [];
10
- return [{ type: "text", text: text2 }];
11
- }
12
- function isValidTriggerPosition(text2, charIndex, position) {
13
- if (charIndex === 0) return true;
14
- const prevChar = text2[charIndex - 1];
15
- if (position === "start") {
16
- return prevChar === "\n";
17
- }
18
- return prevChar === " " || prevChar === "\n" || prevChar === " ";
19
- }
20
- function detectActiveTrigger(text2, cursorPos, triggers) {
21
- if (!text2 || cursorPos === 0 || triggers.length === 0) return null;
22
- for (let i = cursorPos - 1; i >= 0; i--) {
23
- const char = text2[i];
24
- if (char === " " || char === "\n" || char === " ") {
25
- if (i + 1 < cursorPos) {
26
- const nextChar = text2[i + 1];
27
- const matchingTrigger2 = triggers.find((t) => t.char === nextChar);
28
- if (matchingTrigger2 && isValidTriggerPosition(text2, i + 1, matchingTrigger2.position)) {
29
- return {
30
- config: matchingTrigger2,
31
- startOffset: i + 1,
32
- query: text2.slice(i + 2, cursorPos)
33
- };
34
- }
35
- }
36
- return null;
37
- }
38
- const matchingTrigger = triggers.find((t) => t.char === char);
39
- if (matchingTrigger && isValidTriggerPosition(text2, i, matchingTrigger.position)) {
40
- return {
41
- config: matchingTrigger,
42
- startOffset: i,
43
- query: text2.slice(i + 1, cursorPos)
44
- };
45
- }
46
- }
47
- return null;
48
- }
49
- function resolveChip(segments, activeTrigger, chip2) {
50
- const triggerStart = activeTrigger.startOffset;
51
- const triggerEnd = triggerStart + 1 + activeTrigger.query.length;
52
- const newSegments = [];
53
- let offset = 0;
54
- for (const seg of segments) {
55
- if (seg.type === "chip") {
56
- const chipText = `${seg.trigger}${seg.displayText}`;
57
- const chipStart = offset;
58
- const chipEnd = offset + chipText.length;
59
- if (chipEnd <= triggerStart || chipStart >= triggerEnd) {
60
- newSegments.push(seg);
61
- }
62
- offset = chipEnd;
63
- } else {
64
- const textStart = offset;
65
- const textEnd = offset + seg.text.length;
66
- if (textEnd <= triggerStart) {
67
- newSegments.push(seg);
68
- } else if (textStart >= triggerEnd) {
69
- newSegments.push(seg);
70
- } else {
71
- const beforeText = seg.text.slice(0, Math.max(0, triggerStart - textStart));
72
- const afterText = seg.text.slice(Math.min(seg.text.length, triggerEnd - textStart));
73
- if (beforeText) {
74
- newSegments.push({ type: "text", text: beforeText });
75
- }
76
- const newChip = {
77
- type: "chip",
78
- trigger: activeTrigger.config.char,
79
- value: chip2.value,
80
- displayText: chip2.displayText,
81
- ...chip2.data !== void 0 ? { data: chip2.data } : {},
82
- ...chip2.autoResolved ? { autoResolved: true } : {}
83
- };
84
- newSegments.push(newChip);
85
- if (afterText) {
86
- newSegments.push({ type: "text", text: " " + afterText.replace(/^\s/, "") });
87
- } else {
88
- newSegments.push({ type: "text", text: " " });
89
- }
90
- }
91
- offset = textEnd;
92
- }
93
- }
94
- const merged = mergeAdjacentTextSegments(newSegments);
95
- let lastChipEndOffset = -1;
96
- let runningOffset = 0;
97
- for (const seg of merged) {
98
- if (seg.type === "text") {
99
- runningOffset += seg.text.length;
100
- } else {
101
- runningOffset += seg.trigger.length + seg.displayText.length;
102
- if (seg.value === chip2.value && seg.displayText === chip2.displayText && seg.trigger === activeTrigger.config.char) {
103
- lastChipEndOffset = runningOffset;
104
- }
105
- }
106
- }
107
- const cursorOffset = lastChipEndOffset === -1 ? runningOffset : lastChipEndOffset + 1;
108
- return { segments: merged, cursorOffset };
109
- }
110
- function resolveTriggersInSegments(segments, triggers) {
111
- const autoResolveTriggers = triggers.filter((t) => t.resolveOnSpace);
112
- if (autoResolveTriggers.length === 0) return segments;
113
- const triggerChars = new Set(autoResolveTriggers.map((t) => t.char));
114
- const result = [];
115
- for (const seg of segments) {
116
- if (seg.type === "chip") {
117
- result.push(seg);
118
- continue;
119
- }
120
- const parts = splitTextByTriggerPatterns(seg.text, autoResolveTriggers, triggerChars);
121
- result.push(...parts);
122
- }
123
- return mergeAdjacentTextSegments(result);
124
- }
125
- function splitTextByTriggerPatterns(text2, triggers, triggerChars) {
126
- if (!text2) return [];
127
- const segments = [];
128
- let i = 0;
129
- while (i < text2.length) {
130
- const char = text2[i];
131
- if (triggerChars.has(char)) {
132
- const isAtBoundary = i === 0 || text2[i - 1] === " " || text2[i - 1] === "\n" || text2[i - 1] === " ";
133
- if (isAtBoundary) {
134
- const trigger = triggers.find((t) => t.char === char);
135
- if (trigger && isValidTriggerPosition(text2, i, trigger.position)) {
136
- let end = i + 1;
137
- while (end < text2.length && text2[end] !== " " && text2[end] !== "\n" && text2[end] !== " ") {
138
- end++;
139
- }
140
- const query = text2.slice(i + 1, end);
141
- if (query.length > 0) {
142
- const displayText = trigger.onSelect?.({ value: query, label: query }) || query;
143
- segments.push({
144
- type: "chip",
145
- trigger: char,
146
- value: query,
147
- displayText,
148
- autoResolved: true
149
- });
150
- i = end;
151
- continue;
152
- }
153
- }
154
- }
155
- }
156
- const start = i;
157
- i++;
158
- while (i < text2.length && !(triggerChars.has(text2[i]) && (text2[i - 1] === " " || text2[i - 1] === "\n" || text2[i - 1] === " "))) {
159
- i++;
160
- }
161
- segments.push({ type: "text", text: text2.slice(start, i) });
162
- }
163
- return segments;
164
- }
165
- function parseInlineMarkdown(text2) {
166
- if (!text2) return [];
167
- const tokens = [];
168
- const pattern = /(\*{3}(.+?)\*{3})|(\*{2}(.+?)\*{2})|(\*(.+?)\*)|(https?:\/\/[^\s),]+)/g;
169
- let lastIndex = 0;
170
- let match;
171
- while ((match = pattern.exec(text2)) !== null) {
172
- if (match.index > lastIndex) {
173
- tokens.push({ type: "plain", text: text2.slice(lastIndex, match.index) });
174
- }
175
- if (match[1] && match[2]) {
176
- tokens.push({ type: "bold-italic", text: match[2] });
177
- } else if (match[3] && match[4]) {
178
- tokens.push({ type: "bold", text: match[4] });
179
- } else if (match[5] && match[6]) {
180
- tokens.push({ type: "italic", text: match[6] });
181
- } else if (match[7]) {
182
- tokens.push({ type: "url", text: match[7] });
183
- }
184
- lastIndex = match.index + match[0].length;
185
- }
186
- if (lastIndex < text2.length) {
187
- tokens.push({ type: "plain", text: text2.slice(lastIndex) });
188
- }
189
- return tokens;
190
- }
191
- function segmentsEqual(a, b) {
192
- if (a === b) return true;
193
- if (a.length !== b.length) return false;
194
- for (let i = 0; i < a.length; i++) {
195
- const sa = a[i];
196
- const sb = b[i];
197
- if (sa.type !== sb.type) return false;
198
- if (sa.type === "text") {
199
- if (sb.type !== "text" || sa.text !== sb.text) return false;
200
- } else {
201
- if (sb.type !== "chip" || sa.trigger !== sb.trigger || sa.value !== sb.value || sa.displayText !== sb.displayText || sa.autoResolved !== sb.autoResolved)
202
- return false;
203
- }
204
- }
205
- return true;
206
- }
207
- function mergeAdjacentTextSegments(segments) {
208
- const result = [];
209
- for (const seg of segments) {
210
- if (seg.type === "text" && seg.text === "") continue;
211
- const last = result[result.length - 1];
212
- if (seg.type === "text" && last?.type === "text") {
213
- result[result.length - 1] = { type: "text", text: last.text + seg.text };
214
- } else {
215
- result.push(seg);
216
- }
217
- }
218
- return result;
219
- }
220
-
221
- // src/prompt-area/segment-helpers.ts
222
- function text(value) {
223
- return { type: "text", text: value };
224
- }
225
- function chip(opts) {
226
- return { type: "chip", ...opts };
227
- }
228
- function isSegmentsEmpty(segments) {
229
- if (segments.length === 0) return true;
230
- return segments.every((seg) => seg.type === "text" && seg.text.trim() === "");
231
- }
232
- function hasChips(segments) {
233
- return segments.some((seg) => seg.type === "chip");
234
- }
235
- function getChips(segments) {
236
- return segments.filter((seg) => seg.type === "chip");
237
- }
238
- function getChipsByTrigger(segments, trigger) {
239
- return segments.filter(
240
- (seg) => seg.type === "chip" && seg.trigger === trigger
241
- );
242
- }
243
-
244
- // src/prompt-area/trigger-presets.ts
245
- function mentionTrigger(opts = {}) {
246
- const { char = "@", ...rest } = opts;
247
- return {
248
- char,
249
- position: "any",
250
- mode: "dropdown",
251
- chipStyle: "pill",
252
- accessibilityLabel: "mention",
253
- ...rest
254
- };
255
- }
256
- function commandTrigger(opts = {}) {
257
- const { char = "/", ...rest } = opts;
258
- return {
259
- char,
260
- position: "start",
261
- mode: "dropdown",
262
- chipStyle: "inline",
263
- accessibilityLabel: "command",
264
- ...rest
265
- };
266
- }
267
- function hashtagTrigger(opts = {}) {
268
- const { char = "#", ...rest } = opts;
269
- return {
270
- char,
271
- position: "any",
272
- mode: "dropdown",
273
- chipStyle: "pill",
274
- resolveOnSpace: true,
275
- accessibilityLabel: "tag",
276
- ...rest
277
- };
278
- }
279
- function callbackTrigger(opts) {
280
- const { char, ...rest } = opts;
281
- return {
282
- char,
283
- position: "start",
284
- mode: "callback",
285
- ...rest
286
- };
287
- }
288
-
289
- export { callbackTrigger, chip, commandTrigger, detectActiveTrigger, getChips, getChipsByTrigger, hasChips, hashtagTrigger, isSegmentsEmpty, isValidTriggerPosition, mentionTrigger, mergeAdjacentTextSegments, parseInlineMarkdown, plainTextToSegments, resolveChip, resolveTriggersInSegments, segmentsEqual, segmentsToPlainText, text };
290
- //# sourceMappingURL=index.js.map
291
- //# sourceMappingURL=index.js.map
1
+ export{j as callbackTrigger,b as chip,h as commandTrigger,e as getChips,f as getChipsByTrigger,d as hasChips,i as hashtagTrigger,c as isSegmentsEmpty,g as mentionTrigger,a as text}from'../chunk-A6EFF4BI.js';export{d as detectActiveTrigger,c as isValidTriggerPosition,m as mergeAdjacentTextSegments,k as parseInlineMarkdown,b as plainTextToSegments,e as resolveChip,h as resolveTriggersInSegments,l as segmentsEqual,a as segmentsToPlainText}from'../chunk-MJSTEY4N.js';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export { CallbackTriggerOptions, CommandTriggerOptions, HashtagTriggerOptions, MarkdownToken, MentionTriggerOptions, PromptArea, PromptAreaBind, PromptAreaState, UsePromptAreaStateOptions, callbackTrigger, chip, commandTrigger, detectActiveTrigger, getChips, getChipsByTrigger, hasChips, hashtagTrigger, isSegmentsEmpty, isValidTriggerPosition, mentionTrigger, mergeAdjacentTextSegments, parseInlineMarkdown, plainTextToSegments, resolveChip, resolveTriggersInSegments, segmentsEqual, segmentsToPlainText, text, usePromptArea, usePromptAreaState } from './prompt-area/index.js';
1
+ export { PromptArea, PromptAreaBind, PromptAreaState, UsePromptAreaStateOptions, usePromptArea, usePromptAreaState } from './prompt-area/index.js';
2
2
  export { A as ActiveTrigger, C as ChipSegment, a as ChipStyle, P as PromptAreaFile, b as PromptAreaHandle, c as PromptAreaImage, d as PromptAreaProps, S as Segment, T as TextSegment, e as TriggerActivateContext, f as TriggerConfig, g as TriggerMode, h as TriggerPosition, i as TriggerSuggestion } from './types-C4BgDEpe.js';
3
+ export { CallbackTriggerOptions, CommandTriggerOptions, HashtagTriggerOptions, MarkdownToken, MentionTriggerOptions, callbackTrigger, chip, commandTrigger, detectActiveTrigger, getChips, getChipsByTrigger, hasChips, hashtagTrigger, isSegmentsEmpty, isValidTriggerPosition, mentionTrigger, mergeAdjacentTextSegments, parseInlineMarkdown, plainTextToSegments, resolveChip, resolveTriggersInSegments, segmentsEqual, segmentsToPlainText, text } from './helpers/index.js';
3
4
  export { ActionBar, ActionBarProps } from './action-bar/index.js';
4
5
  export { StatusBar, StatusBarProps } from './status-bar/index.js';
5
6
  export { CompactPromptArea, CompactPromptAreaProps } from './compact-prompt-area/index.js';
package/dist/index.js CHANGED
@@ -1,10 +1,2 @@
1
1
  'use client';
2
- export { callbackTrigger, chip, commandTrigger, getChips, getChipsByTrigger, hasChips, hashtagTrigger, isSegmentsEmpty, mentionTrigger, text, usePromptAreaState } from './chunk-UBBCAMJA.js';
3
- export { ActionBar } from './chunk-BWVBDP7C.js';
4
- export { StatusBar } from './chunk-ANZZEZP2.js';
5
- export { CompactPromptArea } from './chunk-BPJO4DGM.js';
6
- export { PromptArea, detectActiveTrigger, isValidTriggerPosition, mergeAdjacentTextSegments, parseInlineMarkdown, plainTextToSegments, resolveChip, resolveTriggersInSegments, segmentsEqual, segmentsToPlainText, usePromptArea } from './chunk-E7HUXORB.js';
7
- export { ChatPromptLayout } from './chunk-XDKRP7UE.js';
8
- import './chunk-NF2LHZIE.js';
9
- //# sourceMappingURL=index.js.map
10
- //# sourceMappingURL=index.js.map
2
+ export{a as usePromptAreaState}from'./chunk-3D4ZBBYY.js';export{a as ActionBar}from'./chunk-VULUMPYE.js';export{a as StatusBar}from'./chunk-6VISE4VA.js';export{a as CompactPromptArea}from'./chunk-2R57LWJO.js';export{c as PromptArea,b as usePromptArea}from'./chunk-LJJ6HHR6.js';export{a as ChatPromptLayout}from'./chunk-CRC4ST6U.js';import'./chunk-23Y7B365.js';export{j as callbackTrigger,b as chip,h as commandTrigger,e as getChips,f as getChipsByTrigger,d as hasChips,i as hashtagTrigger,c as isSegmentsEmpty,g as mentionTrigger,a as text}from'./chunk-A6EFF4BI.js';export{d as detectActiveTrigger,c as isValidTriggerPosition,m as mergeAdjacentTextSegments,k as parseInlineMarkdown,b as plainTextToSegments,e as resolveChip,h as resolveTriggersInSegments,l as segmentsEqual,a as segmentsToPlainText}from'./chunk-MJSTEY4N.js';
@@ -1,6 +1,7 @@
1
1
  import * as react from 'react';
2
- import { d as PromptAreaProps, b as PromptAreaHandle, S as Segment, f as TriggerConfig, C as ChipSegment, A as ActiveTrigger, i as TriggerSuggestion, h as TriggerPosition, T as TextSegment } from '../types-C4BgDEpe.js';
3
- export { a as ChipStyle, P as PromptAreaFile, c as PromptAreaImage, e as TriggerActivateContext, g as TriggerMode } from '../types-C4BgDEpe.js';
2
+ import { d as PromptAreaProps, b as PromptAreaHandle, S as Segment, f as TriggerConfig, C as ChipSegment, A as ActiveTrigger, i as TriggerSuggestion } from '../types-C4BgDEpe.js';
3
+ export { a as ChipStyle, P as PromptAreaFile, c as PromptAreaImage, T as TextSegment, e as TriggerActivateContext, g as TriggerMode, h as TriggerPosition } from '../types-C4BgDEpe.js';
4
+ export { CallbackTriggerOptions, CommandTriggerOptions, HashtagTriggerOptions, MarkdownToken, MentionTriggerOptions, callbackTrigger, chip, commandTrigger, detectActiveTrigger, getChips, getChipsByTrigger, hasChips, hashtagTrigger, isSegmentsEmpty, isValidTriggerPosition, mentionTrigger, mergeAdjacentTextSegments, parseInlineMarkdown, plainTextToSegments, resolveChip, resolveTriggersInSegments, segmentsEqual, segmentsToPlainText, text } from '../helpers/index.js';
4
5
 
5
6
  /**
6
7
  * PromptArea - A lightweight rich text input with trigger support.
@@ -136,192 +137,4 @@ type PromptAreaState = {
136
137
  };
137
138
  declare function usePromptAreaState(options?: UsePromptAreaStateOptions): PromptAreaState;
138
139
 
139
- /**
140
- * Pure logic engine for the PromptArea component.
141
- * No DOM dependencies - fully testable in Node.
142
- */
143
-
144
- /**
145
- * Converts an array of segments to a plain text string.
146
- * Chips are represented as `{trigger}{displayText}` (e.g., "@Alice").
147
- */
148
- declare function segmentsToPlainText(segments: Segment[]): string;
149
- /**
150
- * Converts plain text into a single text segment.
151
- * Used for initial value conversion from plain strings.
152
- */
153
- declare function plainTextToSegments(text: string): Segment[];
154
- /**
155
- * Checks whether a trigger character at the given position in text
156
- * is valid according to the position rule.
157
- *
158
- * @param text - The full text content
159
- * @param charIndex - The index of the trigger character in the text
160
- * @param position - The position rule to validate against
161
- */
162
- declare function isValidTriggerPosition(text: string, charIndex: number, position: TriggerPosition): boolean;
163
- /**
164
- * Scans backwards from the cursor position to detect if the user is
165
- * currently typing a trigger word.
166
- *
167
- * Returns the active trigger info, or null if no trigger is active.
168
- *
169
- * @param text - The full plain text content
170
- * @param cursorPos - The cursor position (character offset from start)
171
- * @param triggers - Available trigger configurations
172
- */
173
- declare function detectActiveTrigger(text: string, cursorPos: number, triggers: TriggerConfig[]): ActiveTrigger | null;
174
- /**
175
- * Resolves an active trigger into a chip within the segments array.
176
- * Replaces the trigger text (trigger char + query) with a chip segment.
177
- *
178
- * @param segments - Current document segments
179
- * @param activeTrigger - The active trigger to resolve
180
- * @param chip - The chip data (value, displayText, optional data)
181
- * @returns New segments array with the chip inserted, and the new cursor position
182
- */
183
- declare function resolveChip(segments: Segment[], activeTrigger: ActiveTrigger, chip: {
184
- value: string;
185
- displayText: string;
186
- data?: unknown;
187
- autoResolved?: boolean;
188
- }): {
189
- segments: Segment[];
190
- cursorOffset: number;
191
- };
192
- /**
193
- * Scans text segments for trigger patterns and auto-resolves them into chips.
194
- * Only resolves triggers that have `resolveOnSpace: true`.
195
- *
196
- * Trigger patterns must appear at word boundaries: start of text, after
197
- * whitespace, or after a newline. This avoids false positives like email
198
- * addresses (user@example.com).
199
- */
200
- declare function resolveTriggersInSegments(segments: Segment[], triggers: TriggerConfig[]): Segment[];
201
- type MarkdownToken = {
202
- type: 'plain';
203
- text: string;
204
- } | {
205
- type: 'bold';
206
- text: string;
207
- } | {
208
- type: 'italic';
209
- text: string;
210
- } | {
211
- type: 'bold-italic';
212
- text: string;
213
- } | {
214
- type: 'url';
215
- text: string;
216
- };
217
- /**
218
- * Parses text for simple inline markdown: bold, italic, bold-italic, and URLs.
219
- * Does NOT handle block-level markdown (lists, headings, etc.).
220
- */
221
- declare function parseInlineMarkdown(text: string): MarkdownToken[];
222
- /**
223
- * Shallow equality check for two segment arrays.
224
- * Compares type, text, trigger, value, displayText, and autoResolved fields.
225
- * Avoids JSON.stringify overhead for the common case.
226
- */
227
- declare function segmentsEqual(a: Segment[], b: Segment[]): boolean;
228
- /**
229
- * Merges adjacent text segments into single text segments.
230
- * Also removes empty text segments.
231
- */
232
- declare function mergeAdjacentTextSegments(segments: Segment[]): Segment[];
233
-
234
- /**
235
- * Convenience helpers for creating and inspecting Segments.
236
- *
237
- * These reduce boilerplate when building AI chat UIs that work with the
238
- * PromptArea document model.
239
- *
240
- * @example
241
- * ```ts
242
- * import { text, chip, isSegmentsEmpty, segmentsToPlainText } from './segment-helpers'
243
- *
244
- * const greeting = [text('Hello '), chip({ trigger: '@', value: 'u1', displayText: 'Alice' })]
245
- * isSegmentsEmpty(greeting) // false
246
- * segmentsToPlainText(greeting) // "Hello @Alice"
247
- * ```
248
- */
249
-
250
- /** Create a text segment. */
251
- declare function text(value: string): TextSegment;
252
- /** Create a chip segment. */
253
- declare function chip(opts: Omit<ChipSegment, 'type'>): ChipSegment;
254
- /** Returns `true` when the segment array is empty or contains only whitespace text. */
255
- declare function isSegmentsEmpty(segments: Segment[]): boolean;
256
- /** Returns `true` when the segment array contains at least one chip. */
257
- declare function hasChips(segments: Segment[]): boolean;
258
- /** Extracts all chip segments from a segment array. */
259
- declare function getChips(segments: Segment[]): ChipSegment[];
260
- /** Extracts chips matching a specific trigger character. */
261
- declare function getChipsByTrigger(segments: Segment[], trigger: string): ChipSegment[];
262
-
263
- /**
264
- * Pre-built trigger configuration factories for common AI chat patterns.
265
- *
266
- * Each factory returns a full `TriggerConfig` with sensible defaults.
267
- * Pass only what you need to override.
268
- *
269
- * @example
270
- * ```tsx
271
- * <PromptArea
272
- * triggers={[
273
- * mentionTrigger({ onSearch: searchUsers }),
274
- * commandTrigger({ onSearch: searchCommands }),
275
- * hashtagTrigger(),
276
- * ]}
277
- * />
278
- * ```
279
- */
280
-
281
- type TriggerPresetOptions = Omit<Partial<TriggerConfig>, 'char' | 'position' | 'mode'>;
282
- type MentionTriggerOptions = TriggerPresetOptions & {
283
- /** Override the trigger character. Defaults to `'@'`. */
284
- char?: string;
285
- };
286
- /**
287
- * Creates a **mention** trigger (`@`).
288
- *
289
- * Defaults: `position: 'any'`, `mode: 'dropdown'`, `chipStyle: 'pill'`,
290
- * accessible label `"mention"`.
291
- */
292
- declare function mentionTrigger(opts?: MentionTriggerOptions): TriggerConfig;
293
- type CommandTriggerOptions = TriggerPresetOptions & {
294
- /** Override the trigger character. Defaults to `'/'`. */
295
- char?: string;
296
- };
297
- /**
298
- * Creates a **command** trigger (`/`).
299
- *
300
- * Defaults: `position: 'start'`, `mode: 'dropdown'`, `chipStyle: 'inline'`,
301
- * accessible label `"command"`.
302
- */
303
- declare function commandTrigger(opts?: CommandTriggerOptions): TriggerConfig;
304
- type HashtagTriggerOptions = TriggerPresetOptions & {
305
- /** Override the trigger character. Defaults to `'#'`. */
306
- char?: string;
307
- };
308
- /**
309
- * Creates a **hashtag / tag** trigger (`#`).
310
- *
311
- * Defaults: `position: 'any'`, `mode: 'dropdown'`, `chipStyle: 'pill'`,
312
- * `resolveOnSpace: true`, accessible label `"tag"`.
313
- */
314
- declare function hashtagTrigger(opts?: HashtagTriggerOptions): TriggerConfig;
315
- type CallbackTriggerOptions = Omit<Partial<TriggerConfig>, 'mode'> & {
316
- /** The trigger character. Required. */
317
- char: string;
318
- };
319
- /**
320
- * Creates a **callback** trigger that fires `onActivate` instead of showing
321
- * a dropdown. Useful for opening file pickers, model selectors, etc.
322
- *
323
- * Defaults: `position: 'start'`, `mode: 'callback'`.
324
- */
325
- declare function callbackTrigger(opts: CallbackTriggerOptions): TriggerConfig;
326
-
327
- export { ActiveTrigger, type CallbackTriggerOptions, ChipSegment, type CommandTriggerOptions, type HashtagTriggerOptions, type MarkdownToken, type MentionTriggerOptions, PromptArea, type PromptAreaBind, PromptAreaHandle, PromptAreaProps, type PromptAreaState, Segment, TextSegment, TriggerConfig, TriggerPosition, TriggerSuggestion, type UsePromptAreaStateOptions, callbackTrigger, chip, commandTrigger, detectActiveTrigger, getChips, getChipsByTrigger, hasChips, hashtagTrigger, isSegmentsEmpty, isValidTriggerPosition, mentionTrigger, mergeAdjacentTextSegments, parseInlineMarkdown, plainTextToSegments, resolveChip, resolveTriggersInSegments, segmentsEqual, segmentsToPlainText, text, usePromptArea, usePromptAreaState };
140
+ export { ActiveTrigger, ChipSegment, PromptArea, type PromptAreaBind, PromptAreaHandle, PromptAreaProps, type PromptAreaState, Segment, TriggerConfig, TriggerSuggestion, type UsePromptAreaStateOptions, usePromptArea, usePromptAreaState };
@@ -1,6 +1,2 @@
1
1
  'use client';
2
- export { callbackTrigger, chip, commandTrigger, getChips, getChipsByTrigger, hasChips, hashtagTrigger, isSegmentsEmpty, mentionTrigger, text, usePromptAreaState } from '../chunk-UBBCAMJA.js';
3
- export { PromptArea, detectActiveTrigger, isValidTriggerPosition, mergeAdjacentTextSegments, parseInlineMarkdown, plainTextToSegments, resolveChip, resolveTriggersInSegments, segmentsEqual, segmentsToPlainText, usePromptArea } from '../chunk-E7HUXORB.js';
4
- import '../chunk-NF2LHZIE.js';
5
- //# sourceMappingURL=index.js.map
6
- //# sourceMappingURL=index.js.map
2
+ export{a as usePromptAreaState}from'../chunk-3D4ZBBYY.js';export{c as PromptArea,b as usePromptArea}from'../chunk-LJJ6HHR6.js';import'../chunk-23Y7B365.js';export{j as callbackTrigger,b as chip,h as commandTrigger,e as getChips,f as getChipsByTrigger,d as hasChips,i as hashtagTrigger,c as isSegmentsEmpty,g as mentionTrigger,a as text}from'../chunk-A6EFF4BI.js';export{d as detectActiveTrigger,c as isValidTriggerPosition,m as mergeAdjacentTextSegments,k as parseInlineMarkdown,b as plainTextToSegments,e as resolveChip,h as resolveTriggersInSegments,l as segmentsEqual,a as segmentsToPlainText}from'../chunk-MJSTEY4N.js';
@@ -1,5 +1,2 @@
1
1
  'use client';
2
- export { StatusBar } from '../chunk-ANZZEZP2.js';
3
- import '../chunk-NF2LHZIE.js';
4
- //# sourceMappingURL=index.js.map
5
- //# sourceMappingURL=index.js.map
2
+ export{a as StatusBar}from'../chunk-6VISE4VA.js';import'../chunk-23Y7B365.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prompt-area",
3
- "version": "0.1.0",
3
+ "version": "0.3.1",
4
4
  "description": "An opinionated, dependency-light React rich-text prompt input with trigger-based chips (@mentions, /commands, #tags), inline markdown, undo/redo, file & image attachments, and a complete chat-input layout. Ships as an npm package or a shadcn registry.",
5
5
  "keywords": [
6
6
  "react",
@@ -29,7 +29,8 @@
29
29
  "**/*.css"
30
30
  ],
31
31
  "files": [
32
- "dist"
32
+ "dist",
33
+ "CHANGELOG.md"
33
34
  ],
34
35
  "exports": {
35
36
  ".": {
@@ -64,12 +65,31 @@
64
65
  "./tailwind.css": "./dist/tailwind.css",
65
66
  "./package.json": "./package.json"
66
67
  },
68
+ "scripts": {
69
+ "build": "pnpm run clean && pnpm run build:js && pnpm run build:css",
70
+ "build:js": "tsup && node ./scripts/preserve-directives.mjs",
71
+ "build:css": "tailwindcss --input ./src/styles.css --output ./dist/styles.css --minify && node ./scripts/build-preset.mjs",
72
+ "clean": "rm -rf dist",
73
+ "typecheck": "tsc --noEmit",
74
+ "lint:exports": "publint && attw --pack . --profile esm-only --exclude-entrypoints styles.css tailwind.css",
75
+ "prepublishOnly": "pnpm run build"
76
+ },
67
77
  "engines": {
68
78
  "node": ">=18"
69
79
  },
70
80
  "peerDependencies": {
71
81
  "react": ">=18",
72
- "react-dom": ">=18"
82
+ "react-dom": ">=18",
83
+ "tailwindcss": ">=4",
84
+ "tw-animate-css": ">=1"
85
+ },
86
+ "peerDependenciesMeta": {
87
+ "tailwindcss": {
88
+ "optional": true
89
+ },
90
+ "tw-animate-css": {
91
+ "optional": true
92
+ }
73
93
  },
74
94
  "dependencies": {
75
95
  "clsx": "^2.1.1",
@@ -86,17 +106,9 @@
86
106
  "tailwindcss": "^4.3.0",
87
107
  "tsup": "^8.5.0",
88
108
  "tw-animate-css": "^1.4.0",
89
- "typescript": "^5.9.3"
109
+ "typescript": "^6.0.3"
90
110
  },
91
111
  "publishConfig": {
92
112
  "access": "public"
93
- },
94
- "scripts": {
95
- "build": "pnpm run clean && pnpm run build:js && pnpm run build:css",
96
- "build:js": "tsup && node ./scripts/preserve-directives.mjs",
97
- "build:css": "tailwindcss --input ./src/styles.css --output ./dist/styles.css --minify && node ./scripts/build-preset.mjs",
98
- "clean": "rm -rf dist",
99
- "typecheck": "tsc --noEmit",
100
- "lint:exports": "publint && attw --pack . --profile esm-only --exclude-entrypoints styles.css tailwind.css"
101
113
  }
102
- }
114
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Ilko Kacharov
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -1,38 +0,0 @@
1
- 'use client';
2
- import { cn } from './chunk-NF2LHZIE.js';
3
- import { jsxs, jsx } from 'react/jsx-runtime';
4
-
5
- function StatusBar({
6
- left,
7
- right,
8
- className,
9
- disabled = false,
10
- "aria-label": ariaLabel,
11
- "data-test-id": dataTestId,
12
- ref
13
- }) {
14
- return /* @__PURE__ */ jsxs(
15
- "div",
16
- {
17
- ref,
18
- role: "group",
19
- "aria-label": ariaLabel ?? "Status bar",
20
- "aria-disabled": disabled || void 0,
21
- "data-test-id": dataTestId,
22
- className: cn(
23
- "status-bar",
24
- "flex items-center justify-between gap-2 px-3 py-1.5 text-xs",
25
- disabled && "pointer-events-none opacity-50",
26
- className
27
- ),
28
- children: [
29
- left && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: left }),
30
- right && /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center gap-1.5", children: right })
31
- ]
32
- }
33
- );
34
- }
35
-
36
- export { StatusBar };
37
- //# sourceMappingURL=chunk-ANZZEZP2.js.map
38
- //# sourceMappingURL=chunk-ANZZEZP2.js.map