@reforma/components 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 (32) hide show
  1. package/dist/Button/Button.module.css +1 -1
  2. package/dist/List/Menu.d.ts.map +1 -1
  3. package/dist/List/Menu.js +98 -84
  4. package/dist/List/Menu.js.map +1 -1
  5. package/dist/chat/Chip/Chip.js +9 -9
  6. package/dist/chat/Chip/Chip.module.css.js +8 -8
  7. package/dist/chat/Chip/helpers/cursorLines.d.ts +1 -0
  8. package/dist/chat/Chip/helpers/cursorLines.d.ts.map +1 -1
  9. package/dist/chat/Chip/helpers/cursorLines.js +27 -21
  10. package/dist/chat/Chip/helpers/cursorLines.js.map +1 -1
  11. package/dist/chat/Chip/index.d.ts +1 -1
  12. package/dist/chat/Chip/index.d.ts.map +1 -1
  13. package/dist/chat/Chip/index.js +9 -8
  14. package/dist/chat/Message/segments/MessagePhaseSection.module.css +1 -1
  15. package/dist/chat/Message/streamdown/options.d.ts +2 -0
  16. package/dist/chat/Message/streamdown/options.d.ts.map +1 -1
  17. package/dist/chat/Message/streamdown/options.js +13 -12
  18. package/dist/chat/Message/streamdown/options.js.map +1 -1
  19. package/dist/chat/Message/turn/MessageUserBubble.d.ts.map +1 -1
  20. package/dist/chat/Message/turn/MessageUserBubble.js +57 -54
  21. package/dist/chat/Message/turn/MessageUserBubble.js.map +1 -1
  22. package/dist/chat/Tool/mountTool.d.ts.map +1 -1
  23. package/dist/chat/Tool/remove-file/RemoveFileTool.d.ts +1 -1
  24. package/dist/chat/Tool/remove-file/RemoveFileTool.d.ts.map +1 -1
  25. package/dist/chat/Tool/remove-file/RemoveFileTool.js +82 -38
  26. package/dist/chat/Tool/remove-file/RemoveFileTool.js.map +1 -1
  27. package/dist/chat/Tool/remove-file/RemoveFileTool.module.css +1 -0
  28. package/dist/chat/Tool/remove-file/RemoveFileTool.module.css.js +8 -0
  29. package/dist/chat/Tool/remove-file/RemoveFileTool.module.css.js.map +1 -0
  30. package/dist/chat/index.js +110 -109
  31. package/dist/index.js +417 -416
  32. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","sources":["../../../../src/chat/Message/streamdown/options.ts"],"sourcesContent":["import { cjk } from '@streamdown/cjk';\nimport { defaultRehypePlugins, type StreamdownProps } from 'streamdown';\n\nimport { streamdownComponents } from './components';\n\nconst sanitize = defaultRehypePlugins.sanitize as [unknown, { protocols?: { src?: readonly string[] } }];\n\nexport const STREAMDOWN_OPTIONS = {\n plugins: { cjk },\n parseIncompleteMarkdown: true,\n caret: 'block',\n controls: false,\n rehypePlugins: [\n defaultRehypePlugins.raw,\n [sanitize[0], {\n ...sanitize[1],\n protocols: {\n ...sanitize[1].protocols,\n src: [...(sanitize[1].protocols?.src ?? []), 'data'],\n },\n }],\n defaultRehypePlugins.harden,\n ] as NonNullable<StreamdownProps['rehypePlugins']>,\n components: streamdownComponents,\n} satisfies StreamdownProps;\n"],"names":["sanitize","defaultRehypePlugins","STREAMDOWN_OPTIONS","cjk","streamdownComponents"],"mappings":";;;AAGA,MAAMA,IAAWC,EAAqB,UACzBC,IAAqB;AAAA,EAChC,SAAS;AAAA,IACP,KAAAC;AAAA,EAAA;AAAA,EAEF,yBAAyB;AAAA,EACzB,OAAO;AAAA,EACP,UAAU;AAAA,EACV,eAAe,CAACF,EAAqB,KAAK,CAACD,EAAS,CAAC,GAAG;AAAA,IACtD,GAAGA,EAAS,CAAC;AAAA,IACb,WAAW;AAAA,MACT,GAAGA,EAAS,CAAC,EAAE;AAAA,MACf,KAAK,CAAC,GAAIA,EAAS,CAAC,EAAE,WAAW,OAAO,CAAA,GAAK,MAAM;AAAA,IAAA;AAAA,EACrD,CACD,GAAGC,EAAqB,MAAM;AAAA,EAC/B,YAAYG;AACd;"}
1
+ {"version":3,"file":"options.js","sources":["../../../../src/chat/Message/streamdown/options.ts"],"sourcesContent":["import { cjk } from '@streamdown/cjk';\nimport { defaultRehypePlugins, type StreamdownProps } from 'streamdown';\n\nimport { streamdownComponents } from './components';\n\nconst sanitize = defaultRehypePlugins.sanitize as [unknown, { protocols?: { src?: readonly string[] } }];\n\nconst rehypeSanitize = [\n sanitize[0],\n {\n ...sanitize[1],\n protocols: {\n ...sanitize[1].protocols,\n src: [...(sanitize[1].protocols?.src ?? []), 'data'],\n },\n },\n] as NonNullable<StreamdownProps['rehypePlugins']>[number];\n\n/** Sanitize + harden, no rehype-raw. HTML tags stay characters; markdown still renders. */\nexport const USER_MESSAGE_REHYPE_PLUGINS = [\n rehypeSanitize,\n defaultRehypePlugins.harden,\n] as NonNullable<StreamdownProps['rehypePlugins']>;\n\nexport const STREAMDOWN_OPTIONS = {\n plugins: { cjk },\n parseIncompleteMarkdown: true,\n caret: 'block',\n controls: false,\n rehypePlugins: [\n defaultRehypePlugins.raw,\n ...USER_MESSAGE_REHYPE_PLUGINS,\n ] as NonNullable<StreamdownProps['rehypePlugins']>,\n components: streamdownComponents,\n} satisfies StreamdownProps;\n"],"names":["sanitize","defaultRehypePlugins","rehypeSanitize","USER_MESSAGE_REHYPE_PLUGINS","STREAMDOWN_OPTIONS","cjk","streamdownComponents"],"mappings":";;;AAGA,MAAMA,IAAWC,EAAqB,UAChCC,IAAiB,CAACF,EAAS,CAAC,GAAG;AAAA,EACnC,GAAGA,EAAS,CAAC;AAAA,EACb,WAAW;AAAA,IACT,GAAGA,EAAS,CAAC,EAAE;AAAA,IACf,KAAK,CAAC,GAAIA,EAAS,CAAC,EAAE,WAAW,OAAO,CAAA,GAAK,MAAM;AAAA,EAAA;AAEvD,CAAC,GAGYG,IAA8B,CAACD,GAAgBD,EAAqB,MAAM,GAC1EG,IAAqB;AAAA,EAChC,SAAS;AAAA,IACP,KAAAC;AAAA,EAAA;AAAA,EAEF,yBAAyB;AAAA,EACzB,OAAO;AAAA,EACP,UAAU;AAAA,EACV,eAAe,CAACJ,EAAqB,KAAK,GAAGE,CAA2B;AAAA,EACxE,YAAYG;AACd;"}
@@ -1 +1 @@
1
- {"version":3,"file":"MessageUserBubble.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/turn/MessageUserBubble.tsx"],"names":[],"mappings":"AA4BA,eAAO,MAAM,+BAA+B,MAAM,CAAC;AAqPnD,wFAAwF;AACxF,eAAO,MAAM,iBAAiB;;CA4D5B,CAAC"}
1
+ {"version":3,"file":"MessageUserBubble.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/turn/MessageUserBubble.tsx"],"names":[],"mappings":"AA6BA,eAAO,MAAM,+BAA+B,MAAM,CAAC;AAuPnD,wFAAwF;AACxF,eAAO,MAAM,iBAAiB;;CA4D5B,CAAC"}
@@ -1,42 +1,43 @@
1
- import { cn as x } from "@reforma/lib";
2
- import { resolveLayerCite as g, attachedLayerRefKey as S, formatLayerCite as v, codeEditorStateKey as M } from "@reforma/types";
1
+ import { cn as g } from "@reforma/lib";
2
+ import { resolveLayerCite as x, attachedLayerRefKey as E, formatLayerCite as v, codeEditorStateKey as M } from "@reforma/types";
3
3
  import { observer as N } from "mobx-react-lite";
4
- import { useState as E } from "react";
4
+ import { useState as L } from "react";
5
5
  import { For as $ } from "../../../For/For.js";
6
6
  import { Scrollable as w } from "../../../Scrollable/Scrollable.js";
7
7
  import { ScrollExpandChevronButton as B } from "../../../Scrollable/ScrollExpandChevronButton.js";
8
8
  import { Show as f } from "../../../Show/Show.js";
9
- import { Badge as L } from "../../../Tag/Badge.js";
10
- import { useChat as k } from "../../ChatContext.js";
11
- import { Chip as A } from "../../Chip/Chip.js";
12
- import { chipItemFromPath as U } from "../../Chip/helpers/chipPath.js";
13
- import { fileCite as _, fileChipDisplay as I } from "../../Chip/helpers/cursorLines.js";
9
+ import { Badge as A } from "../../../Tag/Badge.js";
10
+ import { useChat as P } from "../../ChatContext.js";
11
+ import { Chip as U } from "../../Chip/Chip.js";
12
+ import { chipItemFromPath as _ } from "../../Chip/helpers/chipPath.js";
13
+ import { clipLayerChipLabel as k, fileCite as R, fileChipDisplay as I } from "../../Chip/helpers/cursorLines.js";
14
14
  import { MessageText as y } from "../streamdown/MessageText.js";
15
+ import { USER_MESSAGE_REHYPE_PLUGINS as C } from "../streamdown/options.js";
15
16
  import i from "./Message.module.css.js";
16
- import { useMessageTurn as P } from "./messageTurnContext.js";
17
- import { jsx as l, jsxs as C } from "react/jsx-runtime";
18
- const R = 500, b = {
17
+ import { useMessageTurn as F } from "./messageTurnContext.js";
18
+ import { jsx as a, jsxs as S } from "react/jsx-runtime";
19
+ const T = 500, b = {
19
20
  expand: "Show full message",
20
21
  collapse: "Show less"
21
22
  };
22
- function F(s) {
23
- const a = U(s.path);
23
+ function G(s) {
24
+ const l = _(s.path);
24
25
  return {
25
26
  id: M(s),
26
- path: a?.path ?? s.path,
27
+ path: l?.path ?? s.path,
27
28
  label: I(s),
28
- tooltip: a?.tooltip,
29
- ...a?.icon ? {
30
- icon: a.icon
29
+ tooltip: l?.tooltip,
30
+ ...l?.icon ? {
31
+ icon: l.icon
31
32
  } : {},
32
33
  ...s.cursor ? {
33
34
  cursor: s.cursor
34
35
  } : {}
35
36
  };
36
37
  }
37
- function T(s, a) {
38
- const n = a?.attached?.files ?? [], p = a?.attached?.layers ?? [], m = [.../* @__PURE__ */ new Set([...a?.skills ?? [], ...a?.commands ?? []])], e = [...n.map((t) => {
39
- const r = _(t);
38
+ function j(s, l) {
39
+ const n = l?.attached?.files ?? [], p = l?.attached?.layers ?? [], m = [.../* @__PURE__ */ new Set([...l?.skills ?? [], ...l?.commands ?? []])], e = [...n.map((t) => {
40
+ const r = R(t);
40
41
  return {
41
42
  cite: r,
42
43
  segment: {
@@ -111,33 +112,35 @@ function T(s, a) {
111
112
  }
112
113
  function d({
113
114
  item: s,
114
- onOpenPath: a
115
+ onOpenPath: l
115
116
  }) {
116
- return /* @__PURE__ */ l(A, {
117
+ return /* @__PURE__ */ a(U, {
117
118
  className: i.userCite,
118
119
  item: s,
119
- onAction: s.href ? void 0 : a
120
+ onAction: s.href ? void 0 : l
120
121
  });
121
122
  }
122
- function j({
123
+ function H({
123
124
  text: s,
124
- metadata: a,
125
+ metadata: l,
125
126
  onOpenPath: n
126
127
  }) {
127
- const p = T(s, a);
128
- return p.length === 0 ? null : !p.some((e) => e.type !== "text") && p[0]?.type === "text" ? /* @__PURE__ */ l(y, {
128
+ const p = j(s, l);
129
+ return p.length === 0 ? null : !p.some((e) => e.type !== "text") && p[0]?.type === "text" ? /* @__PURE__ */ a(y, {
129
130
  className: i.userMessageBody,
130
131
  mode: "static",
132
+ rehypePlugins: C,
131
133
  children: p[0].value
132
- }) : /* @__PURE__ */ l("div", {
133
- className: x(i.userMessageBody, i.userMessageWithCites),
134
- children: /* @__PURE__ */ l($, {
134
+ }) : /* @__PURE__ */ a("div", {
135
+ className: g(i.userMessageBody, i.userMessageWithCites),
136
+ children: /* @__PURE__ */ a($, {
135
137
  each: p,
136
- children: (e, c) => e.type === "text" ? /* @__PURE__ */ l(y, {
138
+ children: (e, c) => e.type === "text" ? /* @__PURE__ */ a(y, {
137
139
  className: i.userMessageFragment,
138
140
  mode: "static",
141
+ rehypePlugins: C,
139
142
  children: e.value
140
- }, `t-${c}`) : e.type === "command" ? /* @__PURE__ */ l(L, {
143
+ }, `t-${c}`) : e.type === "command" ? /* @__PURE__ */ a(A, {
141
144
  size: "xs",
142
145
  color: "success",
143
146
  value: e.skill,
@@ -145,10 +148,10 @@ function j({
145
148
  "aria-label": e.cite,
146
149
  className: i.userCite,
147
150
  children: e.cite
148
- }, `c-${e.cite}-${c}`) : e.type === "file" ? /* @__PURE__ */ l(d, {
149
- item: F(e.file),
151
+ }, `c-${e.cite}-${c}`) : e.type === "file" ? /* @__PURE__ */ a(d, {
152
+ item: G(e.file),
150
153
  onOpenPath: n
151
- }, `f-${e.cite}-${c}`) : e.type === "link" ? /* @__PURE__ */ l(d, {
154
+ }, `f-${e.cite}-${c}`) : e.type === "link" ? /* @__PURE__ */ a(d, {
152
155
  item: {
153
156
  id: e.url,
154
157
  type: "link",
@@ -157,11 +160,11 @@ function j({
157
160
  href: e.url
158
161
  },
159
162
  onOpenPath: n
160
- }, `u-${e.cite}-${c}`) : /* @__PURE__ */ l(d, {
163
+ }, `u-${e.cite}-${c}`) : /* @__PURE__ */ a(d, {
161
164
  item: {
162
- id: S(e.layer),
165
+ id: E(e.layer),
163
166
  type: "element",
164
- label: e.layer.propName ? `${g(e.layer)}.${e.layer.propName}` : e.layer.text || e.layer.label || e.layer.layerId,
167
+ label: k(e.layer.propName ? `${x(e.layer)}.${e.layer.propName}` : e.layer.text || e.layer.label || e.layer.layerId),
165
168
  ...e.layer.icon ? {
166
169
  icon: e.layer.icon
167
170
  } : {}
@@ -171,10 +174,10 @@ function j({
171
174
  })
172
175
  });
173
176
  }
174
- const se = N(() => {
175
- const s = P(), {
176
- onOpenPath: a
177
- } = k(), [n, p] = E(!1);
177
+ const oe = N(() => {
178
+ const s = F(), {
179
+ onOpenPath: l
180
+ } = P(), [n, p] = L(!1);
178
181
  if (s?.role !== "user" || s.message.role !== "user")
179
182
  return null;
180
183
  const {
@@ -183,22 +186,22 @@ const se = N(() => {
183
186
  } = s, c = m.trim().length > 0, u = !!(e.metadata?.attached?.files?.length || e.metadata?.attached?.layers?.length || e.metadata?.skills?.length || e.metadata?.commands?.length);
184
187
  if (!c && !u)
185
188
  return null;
186
- const t = /* @__PURE__ */ l(j, {
189
+ const t = /* @__PURE__ */ a(H, {
187
190
  text: m,
188
191
  metadata: e.metadata,
189
- onOpenPath: a
190
- }), r = m.length > R;
191
- return /* @__PURE__ */ C("div", {
192
- className: x(i.messageBubble, i.userBubble),
193
- children: [/* @__PURE__ */ l(f, {
192
+ onOpenPath: l
193
+ }), r = m.length > T;
194
+ return /* @__PURE__ */ S("div", {
195
+ className: g(i.messageBubble, i.userBubble),
196
+ children: [/* @__PURE__ */ a(f, {
194
197
  when: !r,
195
- children: /* @__PURE__ */ l("div", {
198
+ children: /* @__PURE__ */ a("div", {
196
199
  className: i.parts,
197
200
  children: t
198
201
  })
199
- }), /* @__PURE__ */ C(f, {
202
+ }), /* @__PURE__ */ S(f, {
200
203
  when: r,
201
- children: [/* @__PURE__ */ l(w, {
204
+ children: [/* @__PURE__ */ a(w, {
202
205
  vertical: !0,
203
206
  edgeFade: !n,
204
207
  className: i.userMessageScroll,
@@ -206,7 +209,7 @@ const se = N(() => {
206
209
  contentClass: i.parts,
207
210
  "aria-expanded": n,
208
211
  children: t
209
- }), /* @__PURE__ */ l(B, {
212
+ }), /* @__PURE__ */ a(B, {
210
213
  expanded: n,
211
214
  onPress: () => p((o) => !o),
212
215
  labelExpand: b.expand,
@@ -217,7 +220,7 @@ const se = N(() => {
217
220
  });
218
221
  });
219
222
  export {
220
- R as MESSAGE_USER_COLLAPSE_MIN_CHARS,
221
- se as MessageUserBubble
223
+ T as MESSAGE_USER_COLLAPSE_MIN_CHARS,
224
+ oe as MessageUserBubble
222
225
  };
223
226
  //# sourceMappingURL=MessageUserBubble.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageUserBubble.js","sources":["../../../../src/chat/Message/turn/MessageUserBubble.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@reforma/lib';\nimport {\n attachedLayerRefKey,\n codeEditorStateKey,\n formatLayerCite,\n resolveLayerCite,\n type CodeEditorState,\n type SelectedLayerContext,\n} from '@reforma/types';\nimport { observer } from 'mobx-react-lite';\nimport { useState, type ReactNode } from 'react';\n\nimport { For } from '../../../For';\nimport { Scrollable, ScrollExpandChevronButton } from '../../../Scrollable';\nimport { Show } from '../../../Show';\nimport { Badge } from '../../../Tag/Badge';\nimport { useChat } from '../../ChatContext';\nimport { Chip, type ChipItem } from '../../Chip/Chip';\nimport { chipItemFromPath } from '../../Chip/helpers/chipPath';\nimport { fileChipDisplay, fileCite } from '../../Chip/helpers/cursorLines';\nimport { MessageText } from '../streamdown/MessageText';\nimport styles from './Message.module.css';\nimport { useMessageTurn } from './messageTurnContext';\n\nimport type { ReformaUserMessageMetadata } from '@reforma/types/sandbox';\n\nexport const MESSAGE_USER_COLLAPSE_MIN_CHARS = 500;\n\nconst USER_COLLAPSE_LABELS = {\n expand: 'Show full message',\n collapse: 'Show less',\n} as const;\n\ntype TextSegment = { type: 'text'; value: string };\ntype FileSegment = { type: 'file'; cite: string; file: CodeEditorState };\ntype LayerSegment = {\n type: 'layer';\n cite: string;\n layer: SelectedLayerContext;\n};\ntype CommandSegment = { type: 'command'; cite: string; skill: string };\ntype LinkSegment = { type: 'link'; cite: string; url: string; host: string };\ntype UserMessageSegment = TextSegment | FileSegment | LayerSegment | CommandSegment | LinkSegment;\n\nfunction fileCiteChipItem(file: CodeEditorState): ChipItem {\n const fromPath = chipItemFromPath(file.path);\n\n return {\n id: codeEditorStateKey(file),\n path: fromPath?.path ?? file.path,\n label: fileChipDisplay(file),\n tooltip: fromPath?.tooltip,\n ...(fromPath?.icon ? { icon: fromPath.icon } : {}),\n ...(file.cursor ? { cursor: file.cursor } : {}),\n };\n}\n\n/**\n * Split user prompt into text + chips for cites that appear in the prompt.\n * Forced meta pins (comment / ask-to-apply) stay in metadata for the agent — not rendered here.\n */\nfunction splitUserMessageSegments(\n text: string,\n metadata: ReformaUserMessageMetadata | undefined\n): UserMessageSegment[] {\n const files = metadata?.attached?.files ?? [];\n const layers = metadata?.attached?.layers ?? [];\n const slashNames = [...new Set([\n ...(metadata?.skills ?? []),\n ...(metadata?.commands ?? []),\n ])];\n\n const cites: Array<{ cite: string; segment: Exclude<UserMessageSegment, TextSegment> }> = [\n ...files.map((file) => {\n const cite = fileCite(file);\n\n return { cite, segment: { type: 'file' as const, cite, file } };\n }),\n ...layers.map((layer) => {\n const cite = formatLayerCite(layer);\n\n return { cite, segment: { type: 'layer' as const, cite, layer } };\n }),\n ...slashNames.map((raw) => {\n const name = raw.trim().replace(/^\\//, '');\n const cite = `/${ name }`;\n\n return { cite, segment: { type: 'command' as const, cite, skill: name } };\n }),\n ...[...text.matchAll(/@https?:\\/\\/[^\\s]+/gi)].map((match) => {\n const cite = match[0] ?? '';\n const url = cite.slice(1);\n let host = url;\n\n try {\n host = new URL(url).hostname.replace(/^www\\./, '') || url;\n }\n catch {\n // keep `url` as the chip label\n }\n\n return { cite, segment: { type: 'link' as const, cite, url, host } };\n }),\n ].sort((a, b) => b.cite.length - a.cite.length);\n\n if (cites.length === 0) {\n return text ? [{ type: 'text', value: text }] : [];\n }\n\n const segments: UserMessageSegment[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n let bestIdx = -1;\n let best: (typeof cites)[number] | undefined;\n\n for (const entry of cites) {\n const idx = remaining.indexOf(entry.cite);\n\n if (idx < 0) {\n continue;\n }\n\n if (\n bestIdx < 0\n || idx < bestIdx\n || (idx === bestIdx && entry.cite.length > (best?.cite.length ?? 0))\n ) {\n bestIdx = idx;\n best = entry;\n }\n }\n\n if (bestIdx < 0 || !best) {\n segments.push({ type: 'text', value: remaining });\n break;\n }\n\n if (bestIdx > 0) {\n segments.push({ type: 'text', value: remaining.slice(0, bestIdx) });\n }\n\n segments.push(best.segment);\n remaining = remaining.slice(bestIdx + best.cite.length);\n }\n\n return segments.filter(segment => segment.type !== 'text' || segment.value.length > 0);\n}\n\nfunction UserCiteChip({\n item,\n onOpenPath,\n}: {\n item: ChipItem;\n onOpenPath?: (item: ChipItem) => void;\n}): ReactNode {\n return (\n <Chip\n className={ styles.userCite }\n item={ item }\n onAction={ item.href ? undefined : onOpenPath }\n />\n );\n}\n\nfunction UserMessageBody({\n text,\n metadata,\n onOpenPath,\n}: {\n text: string;\n metadata: ReformaUserMessageMetadata | undefined;\n onOpenPath?: (item: ChipItem) => void;\n}): ReactNode {\n const segments = splitUserMessageSegments(text, metadata);\n\n if (segments.length === 0) {\n return null;\n }\n\n const hasCites = segments.some(segment => segment.type !== 'text');\n\n if (!hasCites && segments[0]?.type === 'text') {\n return (\n <MessageText\n className={ styles.userMessageBody }\n mode=\"static\"\n >\n { segments[0].value }\n </MessageText>\n );\n }\n\n return (\n <div className={ cn(styles.userMessageBody, styles.userMessageWithCites) }>\n <For each={ segments }>\n { (segment, index) => {\n if (segment.type === 'text') {\n return (\n <MessageText\n key={ `t-${ index }` }\n className={ styles.userMessageFragment }\n mode=\"static\"\n >\n { segment.value }\n </MessageText>\n );\n }\n\n if (segment.type === 'command') {\n return (\n <Badge\n key={ `c-${ segment.cite }-${ index }` }\n size=\"xs\"\n color=\"success\"\n value={ segment.skill }\n textValue={ segment.cite }\n aria-label={ segment.cite }\n className={ styles.userCite }\n >\n { segment.cite }\n </Badge>\n );\n }\n\n if (segment.type === 'file') {\n return (\n <UserCiteChip\n key={ `f-${ segment.cite }-${ index }` }\n item={ fileCiteChipItem(segment.file) }\n onOpenPath={ onOpenPath }\n />\n );\n }\n\n if (segment.type === 'link') {\n return (\n <UserCiteChip\n key={ `u-${ segment.cite }-${ index }` }\n item={ {\n id: segment.url,\n type: 'link',\n label: segment.host,\n tooltip: segment.url,\n href: segment.url,\n } }\n onOpenPath={ onOpenPath }\n />\n );\n }\n\n return (\n <UserCiteChip\n key={ `l-${ segment.cite }-${ index }` }\n item={ {\n id: attachedLayerRefKey(segment.layer),\n type: 'element',\n label: segment.layer.propName\n ? `${ resolveLayerCite(segment.layer) }.${ segment.layer.propName }`\n : (segment.layer.text || segment.layer.label || segment.layer.layerId),\n ...(segment.layer.icon ? { icon: segment.layer.icon } : {}),\n } }\n onOpenPath={ onOpenPath }\n />\n );\n } }\n </For>\n </div>\n );\n}\n\n/** User turn text bubble with collapsible long messages. Renders nothing when empty. */\nexport const MessageUserBubble = observer(() => {\n const turn = useMessageTurn();\n const { onOpenPath } = useChat();\n const [expanded, setExpanded] = useState(false);\n\n if (turn?.role !== 'user' || turn.message.role !== 'user') {\n return null;\n }\n\n const { text, message } = turn;\n const hasText = text.trim().length > 0;\n const hasAttached = Boolean(\n message.metadata?.attached?.files?.length\n || message.metadata?.attached?.layers?.length\n || message.metadata?.skills?.length\n || message.metadata?.commands?.length\n );\n\n if (!hasText && !hasAttached) {\n return null;\n }\n\n const body = (\n <UserMessageBody\n text={ text }\n metadata={ message.metadata }\n onOpenPath={ onOpenPath }\n />\n );\n const collapsible = text.length > MESSAGE_USER_COLLAPSE_MIN_CHARS;\n\n return (\n <div className={ cn(styles.messageBubble, styles.userBubble) }>\n <Show when={ !collapsible }>\n <div className={ styles.parts }>\n { body }\n </div>\n </Show>\n\n <Show when={ collapsible }>\n <Scrollable\n vertical\n edgeFade={ !expanded }\n className={ styles.userMessageScroll }\n containerClass={ styles.userMessageScrollPort }\n contentClass={ styles.parts }\n aria-expanded={ expanded }\n >\n { body }\n </Scrollable>\n <ScrollExpandChevronButton\n expanded={ expanded }\n onPress={ () => setExpanded(v => !v) }\n labelExpand={ USER_COLLAPSE_LABELS.expand }\n labelCollapse={ USER_COLLAPSE_LABELS.collapse }\n className={ styles.userMessageExpandToggle }\n />\n </Show>\n </div>\n );\n});\n"],"names":["MESSAGE_USER_COLLAPSE_MIN_CHARS","USER_COLLAPSE_LABELS","fileCiteChipItem","file","fromPath","chipItemFromPath","codeEditorStateKey","fileChipDisplay","splitUserMessageSegments","text","metadata","files","layers","slashNames","cites","cite","fileCite","layer","formatLayerCite","raw","name","match","url","host","a","b","segments","remaining","bestIdx","best","entry","idx","segment","UserCiteChip","item","onOpenPath","Chip","styles","UserMessageBody","MessageText","cn","For","index","Badge","attachedLayerRefKey","resolveLayerCite","MessageUserBubble","observer","turn","useMessageTurn","useChat","expanded","setExpanded","useState","message","hasText","hasAttached","body","collapsible","_jsx","Show","_jsxs","Scrollable","ScrollExpandChevronButton","v"],"mappings":"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"}
1
+ {"version":3,"file":"MessageUserBubble.js","sources":["../../../../src/chat/Message/turn/MessageUserBubble.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@reforma/lib';\nimport {\n attachedLayerRefKey,\n codeEditorStateKey,\n formatLayerCite,\n resolveLayerCite,\n type CodeEditorState,\n type SelectedLayerContext,\n} from '@reforma/types';\nimport { observer } from 'mobx-react-lite';\nimport { useState, type ReactNode } from 'react';\n\nimport { For } from '../../../For';\nimport { Scrollable, ScrollExpandChevronButton } from '../../../Scrollable';\nimport { Show } from '../../../Show';\nimport { Badge } from '../../../Tag/Badge';\nimport { useChat } from '../../ChatContext';\nimport { Chip, type ChipItem } from '../../Chip/Chip';\nimport { chipItemFromPath } from '../../Chip/helpers/chipPath';\nimport { clipLayerChipLabel, fileChipDisplay, fileCite } from '../../Chip/helpers/cursorLines';\nimport { MessageText } from '../streamdown/MessageText';\nimport { USER_MESSAGE_REHYPE_PLUGINS } from '../streamdown/options';\nimport styles from './Message.module.css';\nimport { useMessageTurn } from './messageTurnContext';\n\nimport type { ReformaUserMessageMetadata } from '@reforma/types/sandbox';\n\nexport const MESSAGE_USER_COLLAPSE_MIN_CHARS = 500;\n\nconst USER_COLLAPSE_LABELS = {\n expand: 'Show full message',\n collapse: 'Show less',\n} as const;\n\ntype TextSegment = { type: 'text'; value: string };\ntype FileSegment = { type: 'file'; cite: string; file: CodeEditorState };\ntype LayerSegment = {\n type: 'layer';\n cite: string;\n layer: SelectedLayerContext;\n};\ntype CommandSegment = { type: 'command'; cite: string; skill: string };\ntype LinkSegment = { type: 'link'; cite: string; url: string; host: string };\ntype UserMessageSegment = TextSegment | FileSegment | LayerSegment | CommandSegment | LinkSegment;\n\nfunction fileCiteChipItem(file: CodeEditorState): ChipItem {\n const fromPath = chipItemFromPath(file.path);\n\n return {\n id: codeEditorStateKey(file),\n path: fromPath?.path ?? file.path,\n label: fileChipDisplay(file),\n tooltip: fromPath?.tooltip,\n ...(fromPath?.icon ? { icon: fromPath.icon } : {}),\n ...(file.cursor ? { cursor: file.cursor } : {}),\n };\n}\n\n/**\n * Split user prompt into text + chips for cites that appear in the prompt.\n * Forced meta pins (comment / ask-to-apply) stay in metadata for the agent — not rendered here.\n */\nfunction splitUserMessageSegments(\n text: string,\n metadata: ReformaUserMessageMetadata | undefined\n): UserMessageSegment[] {\n const files = metadata?.attached?.files ?? [];\n const layers = metadata?.attached?.layers ?? [];\n const slashNames = [...new Set([\n ...(metadata?.skills ?? []),\n ...(metadata?.commands ?? []),\n ])];\n\n const cites: Array<{ cite: string; segment: Exclude<UserMessageSegment, TextSegment> }> = [\n ...files.map((file) => {\n const cite = fileCite(file);\n\n return { cite, segment: { type: 'file' as const, cite, file } };\n }),\n ...layers.map((layer) => {\n const cite = formatLayerCite(layer);\n\n return { cite, segment: { type: 'layer' as const, cite, layer } };\n }),\n ...slashNames.map((raw) => {\n const name = raw.trim().replace(/^\\//, '');\n const cite = `/${ name }`;\n\n return { cite, segment: { type: 'command' as const, cite, skill: name } };\n }),\n ...[...text.matchAll(/@https?:\\/\\/[^\\s]+/gi)].map((match) => {\n const cite = match[0] ?? '';\n const url = cite.slice(1);\n let host = url;\n\n try {\n host = new URL(url).hostname.replace(/^www\\./, '') || url;\n }\n catch {\n // keep `url` as the chip label\n }\n\n return { cite, segment: { type: 'link' as const, cite, url, host } };\n }),\n ].sort((a, b) => b.cite.length - a.cite.length);\n\n if (cites.length === 0) {\n return text ? [{ type: 'text', value: text }] : [];\n }\n\n const segments: UserMessageSegment[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n let bestIdx = -1;\n let best: (typeof cites)[number] | undefined;\n\n for (const entry of cites) {\n const idx = remaining.indexOf(entry.cite);\n\n if (idx < 0) {\n continue;\n }\n\n if (\n bestIdx < 0\n || idx < bestIdx\n || (idx === bestIdx && entry.cite.length > (best?.cite.length ?? 0))\n ) {\n bestIdx = idx;\n best = entry;\n }\n }\n\n if (bestIdx < 0 || !best) {\n segments.push({ type: 'text', value: remaining });\n break;\n }\n\n if (bestIdx > 0) {\n segments.push({ type: 'text', value: remaining.slice(0, bestIdx) });\n }\n\n segments.push(best.segment);\n remaining = remaining.slice(bestIdx + best.cite.length);\n }\n\n return segments.filter(segment => segment.type !== 'text' || segment.value.length > 0);\n}\n\nfunction UserCiteChip({\n item,\n onOpenPath,\n}: {\n item: ChipItem;\n onOpenPath?: (item: ChipItem) => void;\n}): ReactNode {\n return (\n <Chip\n className={ styles.userCite }\n item={ item }\n onAction={ item.href ? undefined : onOpenPath }\n />\n );\n}\n\nfunction UserMessageBody({\n text,\n metadata,\n onOpenPath,\n}: {\n text: string;\n metadata: ReformaUserMessageMetadata | undefined;\n onOpenPath?: (item: ChipItem) => void;\n}): ReactNode {\n const segments = splitUserMessageSegments(text, metadata);\n\n if (segments.length === 0) {\n return null;\n }\n\n const hasCites = segments.some(segment => segment.type !== 'text');\n\n if (!hasCites && segments[0]?.type === 'text') {\n return (\n <MessageText\n className={ styles.userMessageBody }\n mode=\"static\"\n rehypePlugins={ USER_MESSAGE_REHYPE_PLUGINS }\n >\n { segments[0].value }\n </MessageText>\n );\n }\n\n return (\n <div className={ cn(styles.userMessageBody, styles.userMessageWithCites) }>\n <For each={ segments }>\n { (segment, index) => {\n if (segment.type === 'text') {\n return (\n <MessageText\n key={ `t-${ index }` }\n className={ styles.userMessageFragment }\n mode=\"static\"\n rehypePlugins={ USER_MESSAGE_REHYPE_PLUGINS }\n >\n { segment.value }\n </MessageText>\n );\n }\n\n if (segment.type === 'command') {\n return (\n <Badge\n key={ `c-${ segment.cite }-${ index }` }\n size=\"xs\"\n color=\"success\"\n value={ segment.skill }\n textValue={ segment.cite }\n aria-label={ segment.cite }\n className={ styles.userCite }\n >\n { segment.cite }\n </Badge>\n );\n }\n\n if (segment.type === 'file') {\n return (\n <UserCiteChip\n key={ `f-${ segment.cite }-${ index }` }\n item={ fileCiteChipItem(segment.file) }\n onOpenPath={ onOpenPath }\n />\n );\n }\n\n if (segment.type === 'link') {\n return (\n <UserCiteChip\n key={ `u-${ segment.cite }-${ index }` }\n item={ {\n id: segment.url,\n type: 'link',\n label: segment.host,\n tooltip: segment.url,\n href: segment.url,\n } }\n onOpenPath={ onOpenPath }\n />\n );\n }\n\n return (\n <UserCiteChip\n key={ `l-${ segment.cite }-${ index }` }\n item={ {\n id: attachedLayerRefKey(segment.layer),\n type: 'element',\n label: clipLayerChipLabel(segment.layer.propName\n ? `${ resolveLayerCite(segment.layer) }.${ segment.layer.propName }`\n : (segment.layer.text || segment.layer.label || segment.layer.layerId)),\n ...(segment.layer.icon ? { icon: segment.layer.icon } : {}),\n } }\n onOpenPath={ onOpenPath }\n />\n );\n } }\n </For>\n </div>\n );\n}\n\n/** User turn text bubble with collapsible long messages. Renders nothing when empty. */\nexport const MessageUserBubble = observer(() => {\n const turn = useMessageTurn();\n const { onOpenPath } = useChat();\n const [expanded, setExpanded] = useState(false);\n\n if (turn?.role !== 'user' || turn.message.role !== 'user') {\n return null;\n }\n\n const { text, message } = turn;\n const hasText = text.trim().length > 0;\n const hasAttached = Boolean(\n message.metadata?.attached?.files?.length\n || message.metadata?.attached?.layers?.length\n || message.metadata?.skills?.length\n || message.metadata?.commands?.length\n );\n\n if (!hasText && !hasAttached) {\n return null;\n }\n\n const body = (\n <UserMessageBody\n text={ text }\n metadata={ message.metadata }\n onOpenPath={ onOpenPath }\n />\n );\n const collapsible = text.length > MESSAGE_USER_COLLAPSE_MIN_CHARS;\n\n return (\n <div className={ cn(styles.messageBubble, styles.userBubble) }>\n <Show when={ !collapsible }>\n <div className={ styles.parts }>\n { body }\n </div>\n </Show>\n\n <Show when={ collapsible }>\n <Scrollable\n vertical\n edgeFade={ !expanded }\n className={ styles.userMessageScroll }\n containerClass={ styles.userMessageScrollPort }\n contentClass={ styles.parts }\n aria-expanded={ expanded }\n >\n { body }\n </Scrollable>\n <ScrollExpandChevronButton\n expanded={ expanded }\n onPress={ () => setExpanded(v => !v) }\n labelExpand={ USER_COLLAPSE_LABELS.expand }\n labelCollapse={ USER_COLLAPSE_LABELS.collapse }\n className={ styles.userMessageExpandToggle }\n />\n </Show>\n </div>\n );\n});\n"],"names":["MESSAGE_USER_COLLAPSE_MIN_CHARS","USER_COLLAPSE_LABELS","fileCiteChipItem","file","fromPath","chipItemFromPath","codeEditorStateKey","fileChipDisplay","splitUserMessageSegments","text","metadata","files","layers","slashNames","cites","cite","fileCite","layer","formatLayerCite","raw","name","match","url","host","a","b","segments","remaining","bestIdx","best","entry","idx","segment","UserCiteChip","item","onOpenPath","Chip","styles","UserMessageBody","MessageText","USER_MESSAGE_REHYPE_PLUGINS","cn","For","index","Badge","attachedLayerRefKey","clipLayerChipLabel","resolveLayerCite","MessageUserBubble","observer","turn","useMessageTurn","useChat","expanded","setExpanded","useState","message","hasText","hasAttached","body","collapsible","_jsx","Show","_jsxs","Scrollable","ScrollExpandChevronButton","v"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mountTool.d.ts","sourceRoot":"","sources":["../../../src/chat/Tool/mountTool.tsx"],"names":[],"mappings":"AACA,OAAO,EAAO,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG5C,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS;IA2BjC,QAAQ;IACR,OAAO;EASd"}
1
+ {"version":3,"file":"mountTool.d.ts","sourceRoot":"","sources":["../../../src/chat/Tool/mountTool.tsx"],"names":[],"mappings":"AACA,OAAO,EAAO,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG5C,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS;IAgCjC,QAAQ;IACR,OAAO;EAWd"}
@@ -1,4 +1,4 @@
1
1
  import type { ToolRendererProps } from '../types';
2
- /** RemoveFile: label + paths as chips (no raw tool output). Errors/denials: label + tooltip, no duplicate danger line. */
2
+ /** RemoveFile: one path stays a chip. Several collapse to a count that opens the list. */
3
3
  export declare function RemoveFileTool({ part }: ToolRendererProps): import("react").JSX.Element | null;
4
4
  //# sourceMappingURL=RemoveFileTool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RemoveFileTool.d.ts","sourceRoot":"","sources":["../../../../src/chat/Tool/remove-file/RemoveFileTool.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElD,0HAA0H;AAC1H,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE,iBAAiB,sCA+CzD"}
1
+ {"version":3,"file":"RemoveFileTool.d.ts","sourceRoot":"","sources":["../../../../src/chat/Tool/remove-file/RemoveFileTool.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAuElD,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE,iBAAiB,sCAqCzD"}
@@ -1,58 +1,102 @@
1
1
  import { Trash as s } from "@reforma/icons/14";
2
- import { isToolUIPart as p, getToolName as h } from "ai";
3
- import { Box as d } from "../../../Box/Box.js";
4
- import { For as f } from "../../../For/For.js";
5
- import { Show as c } from "../../../Show/Show.js";
6
- import { Text as u } from "../../../Text/Text.js";
7
- import { Chip as v } from "../../Chip/Chip.js";
8
- import { chipItemFromPath as T } from "../../Chip/helpers/chipPath.js";
9
- import { getToolFailureRowState as x, removeFileLinesRemoved as F } from "../helpers.js";
10
- import { ToolLineCounts as R } from "../shell/ToolLineCounts.js";
11
- import { ToolShell as g, ToolShellHeader as w, ToolShellFooter as S } from "../shell/ToolShell.js";
12
- import { parseRemoveFileInput as I } from "./parseRemoveFileInput.js";
13
- import { jsxs as l, jsx as o } from "react/jsx-runtime";
14
- function z({
15
- part: r
2
+ import { plural as u, cn as a } from "@reforma/lib";
3
+ import { isToolUIPart as p, getToolName as f } from "ai";
4
+ import { Box as c } from "../../../Box/Box.js";
5
+ import { For as h } from "../../../For/For.js";
6
+ import { Pressable as d } from "react-aria-components";
7
+ import { Show as v } from "../../../Show/Show.js";
8
+ import { Text as T } from "../../../Text/Text.js";
9
+ import { Chip as g } from "../../Chip/Chip.js";
10
+ import { ChipContent as F } from "../../Chip/ChipContent.js";
11
+ import { chipItemFromPath as R } from "../../Chip/helpers/chipPath.js";
12
+ import b from "../../Chip/Chip.module.css.js";
13
+ import { getToolFailureRowState as x, removeFileLinesRemoved as P } from "../helpers.js";
14
+ import { ToolLineCounts as y } from "../shell/ToolLineCounts.js";
15
+ import { ToolPathListPopover as S } from "../shell/ToolPathListHoverCard.js";
16
+ import { ToolShell as j, ToolShellHeader as C, ToolShellFooter as I } from "../shell/ToolShell.js";
17
+ import { parseRemoveFileInput as w } from "./parseRemoveFileInput.js";
18
+ import L from "./RemoveFileTool.module.css.js";
19
+ import { jsxs as l, jsx as e } from "react/jsx-runtime";
20
+ function A(o) {
21
+ if (o == null || typeof o != "object")
22
+ return [];
23
+ const i = o.results;
24
+ return Array.isArray(i) ? i.flatMap((r) => {
25
+ if (r == null || typeof r != "object")
26
+ return [];
27
+ const t = r.path;
28
+ return typeof t == "string" && t.trim() !== "" ? [t] : [];
29
+ }) : [];
30
+ }
31
+ function N({
32
+ paths: o
16
33
  }) {
17
- if (!p(r) || h(r) !== "RemoveFile")
34
+ return o.length > 1 ? /* @__PURE__ */ e(S, {
35
+ trigger: /* @__PURE__ */ e(d, {
36
+ children: /* @__PURE__ */ e("button", {
37
+ type: "button",
38
+ className: a(b.chip, L.count),
39
+ "data-chip": !0,
40
+ "data-interactive": !0,
41
+ children: /* @__PURE__ */ e(F, {
42
+ item: {
43
+ label: u(o.length, "file", "files")
44
+ },
45
+ icon: null,
46
+ tooltip: !1
47
+ })
48
+ })
49
+ }),
50
+ paths: o
51
+ }) : /* @__PURE__ */ e(c, {
52
+ direction: "row",
53
+ gap: "xs",
54
+ wrap: !0,
55
+ children: /* @__PURE__ */ e(h, {
56
+ each: [...o],
57
+ children: (i, r) => {
58
+ const t = R(i);
59
+ return t ? /* @__PURE__ */ e(g, {
60
+ item: t
61
+ }, t.id ?? r) : null;
62
+ }
63
+ })
64
+ });
65
+ }
66
+ function _({
67
+ part: o
68
+ }) {
69
+ if (!p(o) || f(o) !== "RemoveFile")
18
70
  return null;
19
- const i = r.state, t = x(r), m = I(r.input).filePaths.map((e) => T(e)).filter((e) => e !== null), n = i === "output-available" ? F(r.output) : void 0;
20
- return /* @__PURE__ */ l(g, {
71
+ const i = o.state, r = x(o), t = A(o.output), n = t.length > 0 ? t : w(o.input).filePaths, m = i === "output-available" ? P(o.output) : void 0;
72
+ return /* @__PURE__ */ l(j, {
21
73
  "data-slot": "remove-file-tool",
22
- children: [/* @__PURE__ */ l(w, {
74
+ children: [/* @__PURE__ */ l(C, {
23
75
  state: i,
24
- statusDetail: t.tooltip,
76
+ statusDetail: r.tooltip,
25
77
  title: "Removed",
26
78
  titleInProgress: "Removing",
27
- icon: /* @__PURE__ */ o(s, {
79
+ icon: /* @__PURE__ */ e(s, {
28
80
  "aria-hidden": !0
29
81
  }),
30
- children: [/* @__PURE__ */ o(d, {
31
- direction: "row",
32
- gap: "xs",
33
- wrap: !0,
34
- children: /* @__PURE__ */ o(f, {
35
- each: m,
36
- children: (e, a) => /* @__PURE__ */ o(v, {
37
- item: e
38
- }, e.id ?? e.path ?? a)
39
- })
40
- }), /* @__PURE__ */ o(R, {
41
- removed: n
82
+ children: [/* @__PURE__ */ e(N, {
83
+ paths: n
84
+ }), /* @__PURE__ */ e(y, {
85
+ removed: m
42
86
  })]
43
- }), /* @__PURE__ */ o(c, {
44
- when: t.problemText,
45
- children: /* @__PURE__ */ o(S, {
46
- children: /* @__PURE__ */ o(u, {
87
+ }), /* @__PURE__ */ e(v, {
88
+ when: r.problemText,
89
+ children: /* @__PURE__ */ e(I, {
90
+ children: /* @__PURE__ */ e(T, {
47
91
  color: "danger",
48
92
  variant: "xs",
49
- children: t.problemText
93
+ children: r.problemText
50
94
  })
51
95
  })
52
96
  })]
53
97
  });
54
98
  }
55
99
  export {
56
- z as RemoveFileTool
100
+ _ as RemoveFileTool
57
101
  };
58
102
  //# sourceMappingURL=RemoveFileTool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RemoveFileTool.js","sources":["../../../../src/chat/Tool/remove-file/RemoveFileTool.tsx"],"sourcesContent":["import { Trash } from '@reforma/icons/14';\nimport { getToolName, isToolUIPart } from 'ai';\n\nimport { Box } from '../../../Box';\nimport { For } from '../../../For';\nimport { Show } from '../../../Show';\nimport { Text } from '../../../Text';\nimport { Chip, chipItemFromPath } from '../../Chip';\nimport { getToolFailureRowState, removeFileLinesRemoved } from '../helpers';\nimport { ToolLineCounts, ToolShell, ToolShellFooter, ToolShellHeader } from '../shell';\nimport { parseRemoveFileInput } from './parseRemoveFileInput';\n\nimport type { ToolRendererProps } from '../types';\n\n/** RemoveFile: label + paths as chips (no raw tool output). Errors/denials: label + tooltip, no duplicate danger line. */\nexport function RemoveFileTool({ part }: ToolRendererProps) {\n if (!isToolUIPart(part) || getToolName(part) !== 'RemoveFile') {\n return null;\n }\n\n const state = part.state;\n const failure = getToolFailureRowState(part);\n\n const items = parseRemoveFileInput(part.input)\n .filePaths\n .map(p => chipItemFromPath(p))\n .filter((item): item is NonNullable<typeof item> => item !== null);\n\n const linesRemoved = state === 'output-available'\n ? removeFileLinesRemoved(part.output)\n : undefined;\n\n return (\n <ToolShell data-slot=\"remove-file-tool\">\n <ToolShellHeader\n state={ state }\n statusDetail={ failure.tooltip }\n title=\"Removed\"\n titleInProgress=\"Removing\"\n icon={ <Trash aria-hidden /> }\n >\n <Box direction=\"row\" gap=\"xs\" wrap>\n <For each={ items }>\n { (item, index) => (\n <Chip\n key={ item.id ?? item.path ?? index }\n item={ item }\n />\n ) }\n </For>\n </Box>\n\n <ToolLineCounts removed={ linesRemoved } />\n </ToolShellHeader>\n\n <Show when={ failure.problemText }>\n <ToolShellFooter>\n <Text color=\"danger\" variant=\"xs\">{failure.problemText}</Text>\n </ToolShellFooter>\n </Show>\n </ToolShell>\n );\n}\n"],"names":["RemoveFileTool","part","isToolUIPart","getToolName","state","failure","getToolFailureRowState","items","parseRemoveFileInput","p","chipItemFromPath","item","linesRemoved","removeFileLinesRemoved","ToolShell","_jsxs","ToolShellHeader","Trash","_jsx","Box","For","index","Chip","ToolLineCounts","Show","ToolShellFooter","Text"],"mappings":";;;;;;;;;;;;;AAYO,SAASA,EAAe;AAAA,EAC7B,MAAAC;AACF,GAAG;AACD,MAAI,CAACC,EAAaD,CAAI,KAAKE,EAAYF,CAAI,MAAM;AAC/C,WAAO;AAET,QAAMG,IAAQH,EAAK,OACbI,IAAUC,EAAuBL,CAAI,GACrCM,IAAQC,EAAqBP,EAAK,KAAK,EAAE,UAAU,IAAI,CAAAQ,MAAKC,EAAiBD,CAAC,CAAC,EAAE,OAAO,CAAAE,MAAQA,MAAS,IAAI,GAC7GC,IAAeR,MAAU,qBAAqBS,EAAuBZ,EAAK,MAAM,IAAI;AAC1F,2BAA0Ba,GAAW;AAAA,IACnC,aAAa;AAAA,IACb,UAAU,CAAcC,gBAAAA,EAAMC,GAAiB;AAAA,MAC7C,OAAAZ;AAAA,MACA,cAAcC,EAAQ;AAAA,MACtB,OAAO;AAAA,MACP,iBAAiB;AAAA,MACjB,wBAAwBY,GAAO;AAAA,QAC7B,eAAe;AAAA,MAAA,CAChB;AAAA,MACD,UAAU,CAAcC,gBAAAA,EAAKC,GAAK;AAAA,QAChC,WAAW;AAAA,QACX,KAAK;AAAA,QACL,MAAM;AAAA,QACN,4BAA4BC,GAAK;AAAA,UAC/B,MAAMb;AAAA,UACN,UAAU,CAACI,GAAMU,wBAA4BC,GAAM;AAAA,YACjD,MAAAX;AAAA,UAAA,GACCA,EAAK,MAAMA,EAAK,QAAQU,CAAK;AAAA,QAAA,CACjC;AAAA,MAAA,CACF,GAAgBH,gBAAAA,EAAKK,GAAgB;AAAA,QACpC,SAASX;AAAA,MAAA,CACV,CAAC;AAAA,IAAA,CACH,GAAgBM,gBAAAA,EAAKM,GAAM;AAAA,MAC1B,MAAMnB,EAAQ;AAAA,MACd,4BAA4BoB,GAAiB;AAAA,QAC3C,4BAA4BC,GAAM;AAAA,UAChC,OAAO;AAAA,UACP,SAAS;AAAA,UACT,UAAUrB,EAAQ;AAAA,QAAA,CACnB;AAAA,MAAA,CACF;AAAA,IAAA,CACF,CAAC;AAAA,EAAA,CACH;AACH;"}
1
+ {"version":3,"file":"RemoveFileTool.js","sources":["../../../../src/chat/Tool/remove-file/RemoveFileTool.tsx"],"sourcesContent":["import { Trash } from '@reforma/icons/14';\nimport { cn, plural } from '@reforma/lib';\nimport { getToolName, isToolUIPart } from 'ai';\n\nimport { Box } from '../../../Box';\nimport { For } from '../../../For';\nimport { Pressable } from '../../../Pressable';\nimport { Show } from '../../../Show';\nimport { Text } from '../../../Text';\nimport { Chip, ChipContent, chipItemFromPath } from '../../Chip';\nimport chipStyles from '../../Chip/Chip.module.css';\nimport { getToolFailureRowState, removeFileLinesRemoved } from '../helpers';\nimport { ToolLineCounts, ToolPathListPopover, ToolShell, ToolShellFooter, ToolShellHeader } from '../shell';\nimport { parseRemoveFileInput } from './parseRemoveFileInput';\nimport styles from './RemoveFileTool.module.css';\n\nimport type { ToolRendererProps } from '../types';\n\nfunction pathsFromRemoveOutput(output: unknown): string[] {\n if (output == null || typeof output !== 'object') {\n return [];\n }\n\n const results = (output as { results?: unknown }).results;\n\n if (!Array.isArray(results)) {\n return [];\n }\n\n return results.flatMap((row) => {\n if (row == null || typeof row !== 'object') {\n return [];\n }\n\n const path = (row as { path?: unknown }).path;\n\n return typeof path === 'string' && path.trim() !== '' ? [path] : [];\n });\n}\n\nfunction RemoveFilePaths({ paths }: { paths: readonly string[] }) {\n if (paths.length > 1) {\n return (\n <ToolPathListPopover\n trigger={ (\n <Pressable>\n <button\n type=\"button\"\n className={ cn(chipStyles.chip, styles.count) }\n data-chip\n data-interactive\n >\n <ChipContent\n item={{ label: plural(paths.length, 'file', 'files') }}\n icon={ null }\n tooltip={ false }\n />\n </button>\n </Pressable>\n ) }\n paths={ paths }\n />\n );\n }\n\n return (\n <Box direction=\"row\" gap=\"xs\" wrap>\n <For each={ [...paths] }>\n { (path, index) => {\n const item = chipItemFromPath(path);\n\n if (!item) {\n return null;\n }\n\n return (\n <Chip\n key={ item.id ?? index }\n item={ item }\n />\n );\n } }\n </For>\n </Box>\n );\n}\n\n/** RemoveFile: one path stays a chip. Several collapse to a count that opens the list. */\nexport function RemoveFileTool({ part }: ToolRendererProps) {\n if (!isToolUIPart(part) || getToolName(part) !== 'RemoveFile') {\n return null;\n }\n\n const state = part.state;\n const failure = getToolFailureRowState(part);\n const outputPaths = pathsFromRemoveOutput(part.output);\n const paths = outputPaths.length > 0\n ? outputPaths\n : parseRemoveFileInput(part.input).filePaths;\n\n const linesRemoved = state === 'output-available'\n ? removeFileLinesRemoved(part.output)\n : undefined;\n\n return (\n <ToolShell data-slot=\"remove-file-tool\">\n <ToolShellHeader\n state={ state }\n statusDetail={ failure.tooltip }\n title=\"Removed\"\n titleInProgress=\"Removing\"\n icon={ <Trash aria-hidden /> }\n >\n <RemoveFilePaths paths={ paths } />\n\n <ToolLineCounts removed={ linesRemoved } />\n </ToolShellHeader>\n\n <Show when={ failure.problemText }>\n <ToolShellFooter>\n <Text color=\"danger\" variant=\"xs\">{failure.problemText}</Text>\n </ToolShellFooter>\n </Show>\n </ToolShell>\n );\n}\n"],"names":["pathsFromRemoveOutput","output","results","row","path","RemoveFilePaths","paths","ToolPathListPopover","Pressable","cn","chipStyles","styles","ChipContent","plural","Box","For","index","item","chipItemFromPath","Chip","RemoveFileTool","part","isToolUIPart","getToolName","state","failure","getToolFailureRowState","outputPaths","parseRemoveFileInput","linesRemoved","removeFileLinesRemoved","ToolShell","_jsxs","ToolShellHeader","Trash","_jsx","ToolLineCounts","Show","ToolShellFooter","Text"],"mappings":";;;;;;;;;;;;;;;;;;;AAeA,SAASA,EAAsBC,GAAQ;AACrC,MAAIA,KAAU,QAAQ,OAAOA,KAAW;AACtC,WAAO,CAAA;AAET,QAAMC,IAAUD,EAAO;AACvB,SAAK,MAAM,QAAQC,CAAO,IAGnBA,EAAQ,QAAQ,CAAAC,MAAO;AAC5B,QAAIA,KAAO,QAAQ,OAAOA,KAAQ;AAChC,aAAO,CAAA;AAET,UAAMC,IAAOD,EAAI;AACjB,WAAO,OAAOC,KAAS,YAAYA,EAAK,KAAA,MAAW,KAAK,CAACA,CAAI,IAAI,CAAA;AAAA,EACnE,CAAC,IARQ,CAAA;AASX;AACA,SAASC,EAAgB;AAAA,EACvB,OAAAC;AACF,GAAG;AACD,SAAIA,EAAM,SAAS,sBACQC,GAAqB;AAAA,IAC5C,2BAA2BC,GAAW;AAAA,MACpC,4BAA4B,UAAU;AAAA,QACpC,MAAM;AAAA,QACN,WAAWC,EAAGC,EAAW,MAAMC,EAAO,KAAK;AAAA,QAC3C,aAAa;AAAA,QACb,oBAAoB;AAAA,QACpB,4BAA4BC,GAAa;AAAA,UACvC,MAAM;AAAA,YACJ,OAAOC,EAAOP,EAAM,QAAQ,QAAQ,OAAO;AAAA,UAAA;AAAA,UAE7C,MAAM;AAAA,UACN,SAAS;AAAA,QAAA,CACV;AAAA,MAAA,CACF;AAAA,IAAA,CACF;AAAA,IACD,OAAAA;AAAA,EAAA,CACD,sBAEsBQ,GAAK;AAAA,IAC5B,WAAW;AAAA,IACX,KAAK;AAAA,IACL,MAAM;AAAA,IACN,4BAA4BC,GAAK;AAAA,MAC/B,MAAM,CAAC,GAAGT,CAAK;AAAA,MACf,UAAU,CAACF,GAAMY,MAAU;AACzB,cAAMC,IAAOC,EAAiBd,CAAI;AAClC,eAAKa,sBAGoBE,GAAM;AAAA,UAC7B,MAAAF;AAAA,QAAA,GACCA,EAAK,MAAMD,CAAK,IAJV;AAAA,MAKX;AAAA,IAAA,CACD;AAAA,EAAA,CACF;AACH;AAGO,SAASI,EAAe;AAAA,EAC7B,MAAAC;AACF,GAAG;AACD,MAAI,CAACC,EAAaD,CAAI,KAAKE,EAAYF,CAAI,MAAM;AAC/C,WAAO;AAET,QAAMG,IAAQH,EAAK,OACbI,IAAUC,EAAuBL,CAAI,GACrCM,IAAc3B,EAAsBqB,EAAK,MAAM,GAC/Cf,IAAQqB,EAAY,SAAS,IAAIA,IAAcC,EAAqBP,EAAK,KAAK,EAAE,WAChFQ,IAAeL,MAAU,qBAAqBM,EAAuBT,EAAK,MAAM,IAAI;AAC1F,2BAA0BU,GAAW;AAAA,IACnC,aAAa;AAAA,IACb,UAAU,CAAcC,gBAAAA,EAAMC,GAAiB;AAAA,MAC7C,OAAAT;AAAA,MACA,cAAcC,EAAQ;AAAA,MACtB,OAAO;AAAA,MACP,iBAAiB;AAAA,MACjB,wBAAwBS,GAAO;AAAA,QAC7B,eAAe;AAAA,MAAA,CAChB;AAAA,MACD,UAAU,CAAcC,gBAAAA,EAAK9B,GAAiB;AAAA,QAC5C,OAAAC;AAAA,MAAA,CACD,GAAgB6B,gBAAAA,EAAKC,GAAgB;AAAA,QACpC,SAASP;AAAA,MAAA,CACV,CAAC;AAAA,IAAA,CACH,GAAgBM,gBAAAA,EAAKE,GAAM;AAAA,MAC1B,MAAMZ,EAAQ;AAAA,MACd,4BAA4Ba,GAAiB;AAAA,QAC3C,4BAA4BC,GAAM;AAAA,UAChC,OAAO;AAAA,UACP,SAAS;AAAA,UACT,UAAUd,EAAQ;AAAA,QAAA,CACnB;AAAA,MAAA,CACF;AAAA,IAAA,CACF,CAAC;AAAA,EAAA,CACH;AACH;"}
@@ -0,0 +1 @@
1
+ @layer components{.RemoveFileTool_count_4OjF0D{-webkit-appearance:none;-moz-appearance:none;appearance:none;margin:0}.RemoveFileTool_count_4OjF0D:focus-visible{outline:var(--spacing-4) solid var(--color-primary-muted-border);outline-offset:0}}
@@ -0,0 +1,8 @@
1
+ const o = "RemoveFileTool_count_4OjF0D", t = {
2
+ count: o
3
+ };
4
+ export {
5
+ o as count,
6
+ t as default
7
+ };
8
+ //# sourceMappingURL=RemoveFileTool.module.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RemoveFileTool.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}