@mirror-physics/fractal-ui 0.2.0-next.52 → 0.2.0-next.54
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.cjs +115 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +121 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -296,7 +296,10 @@ var codeTheme = import_view.EditorView.theme({
|
|
|
296
296
|
overscrollBehavior: "none"
|
|
297
297
|
},
|
|
298
298
|
".cm-content": { padding: "10px 0" },
|
|
299
|
-
".cm-line": {
|
|
299
|
+
".cm-line": {
|
|
300
|
+
padding: "0 12px 0 calc(12px + var(--fractal-code-wrap-indent, 0ch))",
|
|
301
|
+
textIndent: "calc(0px - var(--fractal-code-wrap-indent, 0ch))"
|
|
302
|
+
},
|
|
300
303
|
".cm-cursor, .cm-dropCursor": { borderLeftColor: "var(--fg-primary)" },
|
|
301
304
|
".cm-gutters": {
|
|
302
305
|
backgroundColor: "var(--bg-canvas)",
|
|
@@ -306,22 +309,23 @@ var codeTheme = import_view.EditorView.theme({
|
|
|
306
309
|
".cm-lineNumbers .cm-gutterElement": { padding: "0 10px 0 4px" },
|
|
307
310
|
".cm-foldGutter": { width: "14px" },
|
|
308
311
|
".cm-foldGutter .cm-gutterElement": {
|
|
309
|
-
|
|
312
|
+
position: "relative",
|
|
313
|
+
display: "block",
|
|
310
314
|
width: "14px",
|
|
311
|
-
|
|
312
|
-
justifyContent: "flex-end",
|
|
313
|
-
padding: "0 1px 0 0"
|
|
315
|
+
padding: "0"
|
|
314
316
|
},
|
|
315
317
|
".cm-foldGutter .cm-gutterElement > span": {
|
|
318
|
+
position: "absolute",
|
|
319
|
+
top: "2px",
|
|
320
|
+
left: "0",
|
|
316
321
|
display: "inline-flex",
|
|
317
|
-
width: "
|
|
318
|
-
height: "
|
|
322
|
+
width: "14px",
|
|
323
|
+
height: "14px",
|
|
319
324
|
alignItems: "center",
|
|
320
325
|
justifyContent: "center",
|
|
321
326
|
padding: "0",
|
|
322
327
|
color: "var(--fg-tertiary)",
|
|
323
|
-
lineHeight: "
|
|
324
|
-
transform: "translateY(-1px)",
|
|
328
|
+
lineHeight: "14px",
|
|
325
329
|
transition: "color 120ms ease"
|
|
326
330
|
},
|
|
327
331
|
".cm-foldGutter .cm-gutterElement > span:hover": { color: "var(--fg-secondary)" },
|
|
@@ -359,24 +363,113 @@ var fractalHighlightStyle = import_language.HighlightStyle.define([
|
|
|
359
363
|
var jsonSupport = (0, import_lang_json.json)();
|
|
360
364
|
var JSON_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["json", "jsonl", "ndjson", "geojson"]);
|
|
361
365
|
var JSON_LINES_LANGUAGE_NAMES = /* @__PURE__ */ new Set(["jsonl", "ndjson"]);
|
|
366
|
+
var JSON_LINES_PRETTY_PRINT_THRESHOLD = 160;
|
|
367
|
+
var JSON_PROPERTY_PREFIX = /^(\s*"(?:\\.|[^"\\])*"\s*:\s*)/;
|
|
368
|
+
function countVisualColumns(value) {
|
|
369
|
+
let columns = 0;
|
|
370
|
+
for (const character of value) columns += character === " " ? 2 : 1;
|
|
371
|
+
return columns;
|
|
372
|
+
}
|
|
373
|
+
function getWrappedLineIndent(line) {
|
|
374
|
+
const propertyPrefix = line.match(JSON_PROPERTY_PREFIX)?.[1];
|
|
375
|
+
if (propertyPrefix) return Math.min(countVisualColumns(propertyPrefix), 24);
|
|
376
|
+
const leadingWhitespace = line.match(/^\s*/)?.[0] ?? "";
|
|
377
|
+
return Math.min(countVisualColumns(leadingWhitespace) + 2, 12);
|
|
378
|
+
}
|
|
379
|
+
function buildWrappedLineIndentation(view) {
|
|
380
|
+
const decorations = [];
|
|
381
|
+
const decoratedLines = /* @__PURE__ */ new Set();
|
|
382
|
+
for (const visibleRange of view.visibleRanges) {
|
|
383
|
+
let position = visibleRange.from;
|
|
384
|
+
while (position <= visibleRange.to) {
|
|
385
|
+
const line = view.state.doc.lineAt(position);
|
|
386
|
+
if (!decoratedLines.has(line.from)) {
|
|
387
|
+
const indent = getWrappedLineIndent(line.text);
|
|
388
|
+
decorations.push(import_view.Decoration.line({
|
|
389
|
+
attributes: { style: `--fractal-code-wrap-indent: ${indent}ch` }
|
|
390
|
+
}).range(line.from));
|
|
391
|
+
decoratedLines.add(line.from);
|
|
392
|
+
}
|
|
393
|
+
if (line.to >= visibleRange.to) break;
|
|
394
|
+
position = line.to + 1;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return import_view.Decoration.set(decorations, true);
|
|
398
|
+
}
|
|
399
|
+
var wrappedLineIndentation = import_view.ViewPlugin.fromClass(class {
|
|
400
|
+
constructor(view) {
|
|
401
|
+
this.decorations = buildWrappedLineIndentation(view);
|
|
402
|
+
}
|
|
403
|
+
update(update) {
|
|
404
|
+
this.decorations = buildWrappedLineIndentation(update.view);
|
|
405
|
+
}
|
|
406
|
+
}, {
|
|
407
|
+
decorations: (plugin) => plugin.decorations
|
|
408
|
+
});
|
|
409
|
+
function formatJsonLinesForDisplay(value) {
|
|
410
|
+
return value.split(/\r?\n/).map((line) => {
|
|
411
|
+
const firstContentIndex = line.search(/\S/);
|
|
412
|
+
if (firstContentIndex < 0 || line.length - firstContentIndex <= JSON_LINES_PRETTY_PRINT_THRESHOLD) return line;
|
|
413
|
+
const indentation = line.slice(0, firstContentIndex);
|
|
414
|
+
try {
|
|
415
|
+
const parsed = JSON.parse(line.slice(firstContentIndex));
|
|
416
|
+
if (parsed === null || typeof parsed !== "object") return line;
|
|
417
|
+
return JSON.stringify(parsed, null, 2).split("\n").map((formattedLine) => `${indentation}${formattedLine}`).join("\n");
|
|
418
|
+
} catch {
|
|
419
|
+
return line;
|
|
420
|
+
}
|
|
421
|
+
}).join("\n");
|
|
422
|
+
}
|
|
423
|
+
function findJsonContainerEnd(document2, start) {
|
|
424
|
+
const openingCharacter = document2[start];
|
|
425
|
+
if (openingCharacter !== "{" && openingCharacter !== "[") return null;
|
|
426
|
+
const closingCharacters = [];
|
|
427
|
+
let isInsideString = false;
|
|
428
|
+
let isEscaped = false;
|
|
429
|
+
for (let index = start; index < document2.length; index += 1) {
|
|
430
|
+
const character = document2[index];
|
|
431
|
+
if (isInsideString) {
|
|
432
|
+
if (isEscaped) {
|
|
433
|
+
isEscaped = false;
|
|
434
|
+
} else if (character === "\\") {
|
|
435
|
+
isEscaped = true;
|
|
436
|
+
} else if (character === '"') {
|
|
437
|
+
isInsideString = false;
|
|
438
|
+
}
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
if (character === '"') {
|
|
442
|
+
isInsideString = true;
|
|
443
|
+
} else if (character === "{") {
|
|
444
|
+
closingCharacters.push("}");
|
|
445
|
+
} else if (character === "[") {
|
|
446
|
+
closingCharacters.push("]");
|
|
447
|
+
} else if (character === "}" || character === "]") {
|
|
448
|
+
if (closingCharacters.pop() !== character) return null;
|
|
449
|
+
if (closingCharacters.length === 0) return index;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
362
454
|
var jsonLinesFoldSupport = import_language.foldService.of((state, lineStart, lineEnd) => {
|
|
363
455
|
const line = state.doc.sliceString(lineStart, lineEnd);
|
|
364
456
|
const firstContentIndex = line.search(/\S/);
|
|
365
457
|
if (firstContentIndex < 0) return null;
|
|
366
|
-
const
|
|
458
|
+
const containerStart = lineStart + firstContentIndex;
|
|
367
459
|
const openingCharacter = line[firstContentIndex];
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
|
|
460
|
+
if (openingCharacter !== "{" && openingCharacter !== "[") return null;
|
|
461
|
+
const document2 = state.doc.toString();
|
|
462
|
+
const containerEnd = findJsonContainerEnd(document2, containerStart);
|
|
463
|
+
if (containerEnd === null || containerEnd - containerStart < 2) return null;
|
|
371
464
|
try {
|
|
372
|
-
const parsed = JSON.parse(
|
|
465
|
+
const parsed = JSON.parse(document2.slice(containerStart, containerEnd + 1));
|
|
373
466
|
if (parsed === null || typeof parsed !== "object") return null;
|
|
374
467
|
} catch {
|
|
375
468
|
return null;
|
|
376
469
|
}
|
|
377
470
|
return {
|
|
378
|
-
from:
|
|
379
|
-
to:
|
|
471
|
+
from: containerStart + 1,
|
|
472
|
+
to: containerEnd
|
|
380
473
|
};
|
|
381
474
|
});
|
|
382
475
|
function resolveLanguage(language, fileName) {
|
|
@@ -413,6 +506,10 @@ function CodeBlock({
|
|
|
413
506
|
...props
|
|
414
507
|
}) {
|
|
415
508
|
const resolvedLanguage = (0, import_react.useMemo)(() => resolveLanguage(language, fileName), [fileName, language]);
|
|
509
|
+
const displayValue = (0, import_react.useMemo)(
|
|
510
|
+
() => !editable && resolvedLanguage.isJsonLines ? formatJsonLinesForDisplay(value) : value,
|
|
511
|
+
[editable, resolvedLanguage.isJsonLines, value]
|
|
512
|
+
);
|
|
416
513
|
const [copyStatus, setCopyStatus] = (0, import_react.useState)("idle");
|
|
417
514
|
const copyResetTimer = (0, import_react.useRef)(null);
|
|
418
515
|
(0, import_react.useEffect)(() => () => {
|
|
@@ -424,7 +521,7 @@ function CodeBlock({
|
|
|
424
521
|
...resolvedLanguage.support ? [resolvedLanguage.support] : [],
|
|
425
522
|
...resolvedLanguage.isJsonLines ? [jsonLinesFoldSupport] : [],
|
|
426
523
|
...lineNumbers ? [(0, import_language.foldGutter)(), (0, import_view.lineNumbers)()] : [],
|
|
427
|
-
...wrap ? [import_view.EditorView.lineWrapping] : []
|
|
524
|
+
...wrap ? [import_view.EditorView.lineWrapping, wrappedLineIndentation] : []
|
|
428
525
|
], [lineNumbers, resolvedLanguage.isJsonLines, resolvedLanguage.support, wrap]);
|
|
429
526
|
const languageLabel = resolvedLanguage.label;
|
|
430
527
|
const toolbarLabel = label ?? fileName ?? languageLabel;
|
|
@@ -475,7 +572,7 @@ function CodeBlock({
|
|
|
475
572
|
import_react_codemirror.default,
|
|
476
573
|
{
|
|
477
574
|
"aria-label": surfaceLabel,
|
|
478
|
-
value,
|
|
575
|
+
value: displayValue,
|
|
479
576
|
editable,
|
|
480
577
|
readOnly: !editable,
|
|
481
578
|
onChange,
|