@mirror-physics/fractal-ui 0.2.0-next.50 → 0.2.0-next.52

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.
package/dist/index.js CHANGED
@@ -168,7 +168,7 @@ Button.displayName = "Button";
168
168
  // src/components/CodeBlock/CodeBlock.tsx
169
169
  import { useEffect, useMemo, useRef, useState as useState2 } from "react";
170
170
  import CodeMirror from "@uiw/react-codemirror";
171
- import { HighlightStyle, foldGutter, syntaxHighlighting } from "@codemirror/language";
171
+ import { HighlightStyle, foldGutter, foldService, syntaxHighlighting } from "@codemirror/language";
172
172
  import { json } from "@codemirror/lang-json";
173
173
  import { EditorView, lineNumbers as lineNumberGutter } from "@codemirror/view";
174
174
  import { tags } from "@lezer/highlight";
@@ -184,7 +184,7 @@ var codeTheme = EditorView.theme({
184
184
  ".cm-scroller": {
185
185
  fontFamily: "var(--font-mono)",
186
186
  lineHeight: "1.55",
187
- overscrollBehavior: "contain"
187
+ overscrollBehavior: "none"
188
188
  },
189
189
  ".cm-content": { padding: "10px 0" },
190
190
  ".cm-line": { padding: "0 12px" },
@@ -194,8 +194,28 @@ var codeTheme = EditorView.theme({
194
194
  borderRight: "1px solid var(--border-subtle)",
195
195
  color: "var(--fg-tertiary)"
196
196
  },
197
- ".cm-lineNumbers .cm-gutterElement": { padding: "0 10px 0 12px" },
198
- ".cm-foldGutter .cm-gutterElement": { padding: "0 8px 0 2px" },
197
+ ".cm-lineNumbers .cm-gutterElement": { padding: "0 10px 0 4px" },
198
+ ".cm-foldGutter": { width: "14px" },
199
+ ".cm-foldGutter .cm-gutterElement": {
200
+ display: "flex",
201
+ width: "14px",
202
+ alignItems: "center",
203
+ justifyContent: "flex-end",
204
+ padding: "0 1px 0 0"
205
+ },
206
+ ".cm-foldGutter .cm-gutterElement > span": {
207
+ display: "inline-flex",
208
+ width: "12px",
209
+ height: "100%",
210
+ alignItems: "center",
211
+ justifyContent: "center",
212
+ padding: "0",
213
+ color: "var(--fg-tertiary)",
214
+ lineHeight: "1",
215
+ transform: "translateY(-1px)",
216
+ transition: "color 120ms ease"
217
+ },
218
+ ".cm-foldGutter .cm-gutterElement > span:hover": { color: "var(--fg-secondary)" },
199
219
  ".cm-activeLine, .cm-activeLineGutter": { backgroundColor: "var(--bg-surface-1)" },
200
220
  ".cm-selectionBackground, &.cm-focused .cm-selectionBackground, ::selection": {
201
221
  backgroundColor: "var(--accent-surface-stroke) !important"
@@ -229,16 +249,40 @@ var fractalHighlightStyle = HighlightStyle.define([
229
249
  ]);
230
250
  var jsonSupport = json();
231
251
  var JSON_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["json", "jsonl", "ndjson", "geojson"]);
252
+ var JSON_LINES_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["jsonl", "ndjson"]);
253
+ var jsonLinesFoldSupport = foldService.of((state, lineStart, lineEnd) => {
254
+ const line = state.doc.sliceString(lineStart, lineEnd);
255
+ const firstContentIndex = line.search(/\S/);
256
+ if (firstContentIndex < 0) return null;
257
+ const lastContentIndex = line.search(/\s*$/) - 1;
258
+ const openingCharacter = line[firstContentIndex];
259
+ const closingCharacter = line[lastContentIndex];
260
+ const isContainer = openingCharacter === "{" && closingCharacter === "}" || openingCharacter === "[" && closingCharacter === "]";
261
+ if (!isContainer || lastContentIndex - firstContentIndex < 2) return null;
262
+ try {
263
+ const parsed = JSON.parse(line.slice(firstContentIndex, lastContentIndex + 1));
264
+ if (parsed === null || typeof parsed !== "object") return null;
265
+ } catch {
266
+ return null;
267
+ }
268
+ return {
269
+ from: lineStart + firstContentIndex + 1,
270
+ to: lineStart + lastContentIndex
271
+ };
272
+ });
232
273
  function resolveLanguage(language, fileName) {
233
274
  const normalized = language?.trim().toLowerCase();
234
275
  const extension = fileName?.split(/[?#]/, 1)[0].split(".").pop()?.toLowerCase();
235
276
  if (normalized && JSON_LANGUAGE_NAMES.has(normalized) || extension && JSON_LANGUAGE_NAMES.has(extension)) {
236
- return { label: normalized === "jsonl" || extension === "jsonl" ? "JSONL" : "JSON", support: jsonSupport };
277
+ const isJsonLines = Boolean(
278
+ normalized && JSON_LINES_LANGUAGE_NAMES.has(normalized) || extension && JSON_LINES_LANGUAGE_NAMES.has(extension)
279
+ );
280
+ return { label: isJsonLines ? "JSONL" : "JSON", support: jsonSupport, isJsonLines };
237
281
  }
238
282
  if (normalized && !["text", "txt", "plaintext", "plain"].includes(normalized)) {
239
- return { label: language?.trim(), support: null };
283
+ return { label: language?.trim(), support: null, isJsonLines: false };
240
284
  }
241
- return { support: null };
285
+ return { support: null, isJsonLines: false };
242
286
  }
243
287
  function CodeBlock({
244
288
  value,
@@ -269,9 +313,10 @@ function CodeBlock({
269
313
  codeTheme,
270
314
  syntaxHighlighting(fractalHighlightStyle),
271
315
  ...resolvedLanguage.support ? [resolvedLanguage.support] : [],
316
+ ...resolvedLanguage.isJsonLines ? [jsonLinesFoldSupport] : [],
272
317
  ...lineNumbers ? [foldGutter(), lineNumberGutter()] : [],
273
318
  ...wrap ? [EditorView.lineWrapping] : []
274
- ], [lineNumbers, resolvedLanguage.support, wrap]);
319
+ ], [lineNumbers, resolvedLanguage.isJsonLines, resolvedLanguage.support, wrap]);
275
320
  const languageLabel = resolvedLanguage.label;
276
321
  const toolbarLabel = label ?? fileName ?? languageLabel;
277
322
  const surfaceLabel = ariaLabel ?? (fileName ? `${fileName} ${editable ? "editor" : "viewer"}` : `Code ${editable ? "editor" : "viewer"}`);