@nbt-dev/components 0.0.8 → 0.0.10

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 (36) hide show
  1. package/dist/{chunk-WBZS7I6V.js → chunk-AI2LKTA4.js} +30 -2
  2. package/dist/chunk-AI2LKTA4.js.map +7 -0
  3. package/dist/{chunk-ZOGIPYYM.js → chunk-BNA2MLFE.js} +153 -18
  4. package/dist/chunk-BNA2MLFE.js.map +7 -0
  5. package/dist/{chunk-VDIHQ2NS.js → chunk-HTAPMIK6.js} +11 -3
  6. package/dist/chunk-HTAPMIK6.js.map +7 -0
  7. package/dist/{chunk-S7VBQE6Y.js → chunk-TNIHD62H.js} +115 -31
  8. package/dist/chunk-TNIHD62H.js.map +7 -0
  9. package/dist/core/auth.d.ts +2 -0
  10. package/dist/core/index.d.ts +1 -1
  11. package/dist/core/use-cartridge-info.d.ts +1 -0
  12. package/dist/editor/editor-themes.d.ts +8 -0
  13. package/dist/editor/index.d.ts +2 -0
  14. package/dist/editor/index.js +7 -3
  15. package/dist/editor/nbt-editor.d.ts +4 -0
  16. package/dist/graph/index.js +2 -2
  17. package/dist/index.js +20 -8
  18. package/dist/index.js.map +2 -2
  19. package/dist/styles.css +1 -1
  20. package/dist/table/column-widths.d.ts +2 -0
  21. package/dist/table/index.js +2 -2
  22. package/package.json +3 -2
  23. package/src/core/auth.ts +40 -0
  24. package/src/core/data-store.ts +5 -1
  25. package/src/core/index.ts +2 -0
  26. package/src/core/use-cartridge-info.ts +15 -4
  27. package/src/editor/editor-themes.ts +77 -0
  28. package/src/editor/index.ts +2 -0
  29. package/src/editor/nbt-editor.tsx +60 -26
  30. package/src/graph/diagram.tsx +16 -0
  31. package/src/table/column-widths.ts +34 -0
  32. package/src/table/data-table.tsx +148 -16
  33. package/dist/chunk-S7VBQE6Y.js.map +0 -7
  34. package/dist/chunk-VDIHQ2NS.js.map +0 -7
  35. package/dist/chunk-WBZS7I6V.js.map +0 -7
  36. package/dist/chunk-ZOGIPYYM.js.map +0 -7
@@ -1,8 +1,10 @@
1
1
  // CodeMirror 6 React wrapper for one NBT buffer. Recreated per uri (keyed by
2
2
  // the host); owns the EditorView lifecycle, Ctrl+S save, and the LSP wiring.
3
+ // Theme / font size / line-wrap / tab size are live-tunable via compartments so
4
+ // changing a setting doesn't blow away cursor + scroll.
3
5
 
4
6
  import React from "react";
5
- import { EditorState } from "@codemirror/state";
7
+ import { Compartment, EditorState, Prec } from "@codemirror/state";
6
8
  import {
7
9
  EditorView,
8
10
  keymap,
@@ -20,40 +22,34 @@ import {
20
22
  syntaxHighlighting,
21
23
  defaultHighlightStyle,
22
24
  bracketMatching,
25
+ indentUnit,
23
26
  } from "@codemirror/language";
24
27
  import { lintGutter } from "@codemirror/lint";
25
28
  import { searchKeymap } from "@codemirror/search";
26
29
  import { completionKeymap, closeBrackets } from "@codemirror/autocomplete";
27
30
  import { nbtLanguageSupport } from "./nbt-language";
31
+ import { themeExtension } from "./editor-themes";
28
32
  import { lspExtensions, type GotoDefHandler } from "./lsp-extensions";
29
33
  import { NbtLspClient } from "./lsp-client";
30
34
 
31
- // Match the devtools panel chrome via its CSS variables (we render inside the
32
- // .nimbit-devtools subtree, so these resolve to the scoped theme).
33
- const nbtTheme = EditorView.theme(
34
- {
35
- "&": {
36
- height: "100%",
37
- fontSize: "12px",
38
- backgroundColor: "var(--background)",
39
- color: "var(--foreground)",
40
- },
35
+ // Sizing only — the selected color theme owns the rest. Built per font-size so
36
+ // the theme compartment can carry both.
37
+ function sizingTheme(fontSize: number) {
38
+ return EditorView.theme({
39
+ "&": { height: "100%", fontSize: `${fontSize}px` },
41
40
  ".cm-content": { fontFamily: "ui-monospace, monospace" },
42
- ".cm-gutters": {
43
- backgroundColor: "var(--background)",
44
- color: "var(--muted-foreground)",
45
- borderRight: "1px solid var(--border)",
46
- },
47
- ".cm-activeLine": { backgroundColor: "color-mix(in srgb, var(--accent) 35%, transparent)" },
48
41
  "&.cm-focused": { outline: "none" },
49
- ".cm-tooltip": {
50
- backgroundColor: "var(--popover)",
51
- color: "var(--popover-foreground)",
52
- border: "1px solid var(--border)",
53
- },
54
- },
55
- { dark: true },
56
- );
42
+ });
43
+ }
44
+
45
+ // `Prec.high` so this wins the indentUnit/tabSize facets over the
46
+ // `indentUnit.of(" ")` baked into nbtLanguageSupport().
47
+ function indentConfig(tabSize: number) {
48
+ return Prec.high([
49
+ indentUnit.of(" ".repeat(tabSize)),
50
+ EditorState.tabSize.of(tabSize),
51
+ ]);
52
+ }
57
53
 
58
54
  export type NbtEditorProps = {
59
55
  uri: string;
@@ -63,6 +59,10 @@ export type NbtEditorProps = {
63
59
  onChange?: (text: string) => void;
64
60
  onSave?: (text: string) => void;
65
61
  onGotoDefinition?: GotoDefHandler;
62
+ theme?: string;
63
+ fontSize?: number;
64
+ lineWrap?: boolean;
65
+ tabSize?: number;
66
66
  };
67
67
 
68
68
  export const NbtEditor: React.FC<NbtEditorProps> = ({
@@ -73,6 +73,10 @@ export const NbtEditor: React.FC<NbtEditorProps> = ({
73
73
  onChange,
74
74
  onSave,
75
75
  onGotoDefinition,
76
+ theme = "default",
77
+ fontSize = 12,
78
+ lineWrap = false,
79
+ tabSize = 2,
76
80
  }) => {
77
81
  const hostRef = React.useRef<HTMLDivElement | null>(null);
78
82
  const viewRef = React.useRef<EditorView | null>(null);
@@ -85,10 +89,20 @@ export const NbtEditor: React.FC<NbtEditorProps> = ({
85
89
  const onGotoRef = React.useRef(onGotoDefinition);
86
90
  onGotoRef.current = onGotoDefinition;
87
91
 
92
+ // Live-tunable settings live in compartments. Keep the latest values in a ref
93
+ // so a view rebuild (new uri/mode) seeds the right config without listing the
94
+ // settings in the create-effect deps.
95
+ const themeComp = React.useRef(new Compartment());
96
+ const wrapComp = React.useRef(new Compartment());
97
+ const indentComp = React.useRef(new Compartment());
98
+ const settingsRef = React.useRef({ theme, fontSize, lineWrap, tabSize });
99
+ settingsRef.current = { theme, fontSize, lineWrap, tabSize };
100
+
88
101
  React.useEffect(() => {
89
102
  const host = hostRef.current;
90
103
  if (!host) return;
91
104
 
105
+ const s = settingsRef.current;
92
106
  const extensions = [
93
107
  lineNumbers(),
94
108
  history(),
@@ -99,7 +113,9 @@ export const NbtEditor: React.FC<NbtEditorProps> = ({
99
113
  lintGutter(),
100
114
  syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
101
115
  nbtLanguageSupport(),
102
- nbtTheme,
116
+ indentComp.current.of(indentConfig(s.tabSize)),
117
+ themeComp.current.of([sizingTheme(s.fontSize), themeExtension(s.theme)]),
118
+ wrapComp.current.of(s.lineWrap ? EditorView.lineWrapping : []),
103
119
  keymap.of([
104
120
  {
105
121
  key: "Mod-s",
@@ -135,8 +151,26 @@ export const NbtEditor: React.FC<NbtEditorProps> = ({
135
151
  viewRef.current = null;
136
152
  };
137
153
  // Recreate per buffer identity / mode; `value` is only the initial doc.
154
+ // Settings changes are handled by the reconfigure effect below.
138
155
  // eslint-disable-next-line react-hooks/exhaustive-deps
139
156
  }, [uri, readOnly, lsp]);
140
157
 
158
+ // Retune the live view when a setting changes — no destroy, so cursor/scroll
159
+ // survive.
160
+ React.useEffect(() => {
161
+ const view = viewRef.current;
162
+ if (!view) return;
163
+ view.dispatch({
164
+ effects: [
165
+ themeComp.current.reconfigure([
166
+ sizingTheme(fontSize),
167
+ themeExtension(theme),
168
+ ]),
169
+ wrapComp.current.reconfigure(lineWrap ? EditorView.lineWrapping : []),
170
+ indentComp.current.reconfigure(indentConfig(tabSize)),
171
+ ],
172
+ });
173
+ }, [theme, fontSize, lineWrap, tabSize]);
174
+
141
175
  return <div ref={hostRef} className="h-full min-h-0 overflow-hidden" />;
142
176
  };
@@ -8,6 +8,7 @@ import {
8
8
  ReactFlowProvider,
9
9
  useNodesInitialized,
10
10
  useReactFlow,
11
+ useStore,
11
12
  type Edge,
12
13
  type Node,
13
14
  } from "@xyflow/react";
@@ -35,9 +36,24 @@ const nodeTypes = { entity: EntityNode };
35
36
  const FitOnReady: React.FC<{ fitKey: string }> = ({ fitKey }) => {
36
37
  const initialized = useNodesInitialized();
37
38
  const { fitView } = useReactFlow();
39
+ // Container dimensions tracked by ReactFlow's store; change when the canvas is
40
+ // resized (window, sidebar, or the selection rail opening on the right).
41
+ const width = useStore((s) => s.width);
42
+ const height = useStore((s) => s.height);
43
+
38
44
  React.useEffect(() => {
39
45
  if (initialized) fitView({ padding: 0.25, duration: 200 });
40
46
  }, [initialized, fitKey, fitView]);
47
+
48
+ // When the selection rail opens it shrinks the canvas; without a refit a node
49
+ // near the right edge ends up hidden behind the rail. Refit on any resize,
50
+ // debounced so dragging the rail's resize handle stays smooth.
51
+ React.useEffect(() => {
52
+ if (!initialized || width === 0 || height === 0) return;
53
+ const t = setTimeout(() => fitView({ padding: 0.25, duration: 200 }), 120);
54
+ return () => clearTimeout(t);
55
+ }, [width, height, initialized, fitView]);
56
+
41
57
  return null;
42
58
  };
43
59
 
@@ -0,0 +1,34 @@
1
+ // Per-table column-width overrides, persisted to localStorage. Keyed by
2
+ // `<cart>:<entity>` so each table keeps its own widths; the inner map is
3
+ // fieldName -> pixel width. A missing entry means "use the default heuristic".
4
+
5
+ const KEY = "nbt_devtools_colw:v1";
6
+
7
+ type Blob = Record<string, Record<string, number>>;
8
+
9
+ function readBlob(): Blob {
10
+ try {
11
+ const raw = localStorage.getItem(KEY);
12
+ if (!raw) return {};
13
+ const parsed = JSON.parse(raw);
14
+ return typeof parsed === "object" && parsed ? (parsed as Blob) : {};
15
+ } catch {
16
+ return {};
17
+ }
18
+ }
19
+
20
+ export function loadColWidths(cart: string, entity: string): Record<string, number> {
21
+ const blob = readBlob();
22
+ return blob[`${cart}:${entity}`] ?? {};
23
+ }
24
+
25
+ export function saveColWidth(cart: string, entity: string, col: string, w: number): void {
26
+ try {
27
+ const blob = readBlob();
28
+ const k = `${cart}:${entity}`;
29
+ (blob[k] ??= {})[col] = w;
30
+ localStorage.setItem(KEY, JSON.stringify(blob));
31
+ } catch {
32
+ /* storage unavailable (private mode / SSR) — widths stay in-memory only */
33
+ }
34
+ }
@@ -3,10 +3,12 @@ import { useBulkSubscription } from "../core/use-bulk-stream";
3
3
  import { cn } from "../core/utils";
4
4
  import { TYPE_DATETIME, TYPE_DOCUMENT } from "../generated/bulk-protocol";
5
5
  import ValuePopover, { type ValuePopoverData } from "./value-popover";
6
+ import { loadColWidths, saveColWidth } from "./column-widths";
6
7
 
7
8
  const ROW_H = 22;
8
9
  const OVERSCAN = 6;
9
10
  const MIN_COL_W = 80;
11
+ const MAX_COL_W = 600;
10
12
  const GUTTER_W = 32;
11
13
 
12
14
  const READONLY_FIELDS = new Set(["id", "createdAt", "updatedAt"]);
@@ -19,7 +21,7 @@ type DataTableProps = {
19
21
  onSelectRow: (rowJson: Record<string, string>) => void;
20
22
  };
21
23
 
22
- function colWidth(name: string): number {
24
+ function defaultColWidth(name: string): number {
23
25
  if (name === "id") return 220;
24
26
  if (name === "createdAt" || name === "updatedAt") return 180;
25
27
  if (name === "email" || name === "phone") return 180;
@@ -27,6 +29,85 @@ function colWidth(name: string): number {
27
29
  return Math.max(MIN_COL_W, Math.min(240, name.length * 9 + 24));
28
30
  }
29
31
 
32
+ // Shared offscreen canvas for measuring text width during auto-fit (no DOM reflow).
33
+ let measureCanvas: HTMLCanvasElement | null = null;
34
+ function measureCtx(): CanvasRenderingContext2D | null {
35
+ if (!measureCanvas) measureCanvas = document.createElement("canvas");
36
+ return measureCanvas.getContext("2d");
37
+ }
38
+
39
+ // Drag handle pinned to a header cell's right edge. Resizes by mutating the
40
+ // column's CSS var on the scroll root each frame (no React churn across the
41
+ // virtualized rows), committing the final width on release. Double-click
42
+ // auto-fits the column to its loaded content.
43
+ const ColResizeHandle: React.FC<{
44
+ index: number;
45
+ startWidth: number;
46
+ scrollerRef: React.RefObject<HTMLDivElement | null>;
47
+ onCommit: (w: number) => void;
48
+ onAutoFit: () => void;
49
+ }> = ({ index, startWidth, scrollerRef, onCommit, onAutoFit }) => {
50
+ const onPointerDown = (e: React.PointerEvent) => {
51
+ e.preventDefault();
52
+ e.stopPropagation();
53
+ const root = scrollerRef.current;
54
+ if (!root) return;
55
+ const handle = e.currentTarget as HTMLElement;
56
+ handle.setPointerCapture(e.pointerId);
57
+ const startX = e.clientX;
58
+ let last = startWidth;
59
+ let moved = false;
60
+ let raf = 0;
61
+ let pending: number | null = null;
62
+ const flush = () => {
63
+ raf = 0;
64
+ if (pending == null) return;
65
+ last = pending;
66
+ root.style.setProperty(`--cw-${index}`, `${pending}px`);
67
+ pending = null;
68
+ };
69
+ const onMove = (ev: PointerEvent) => {
70
+ ev.preventDefault();
71
+ moved = true;
72
+ pending = Math.max(MIN_COL_W, Math.min(MAX_COL_W, startWidth + (ev.clientX - startX)));
73
+ if (!raf) raf = requestAnimationFrame(flush);
74
+ };
75
+ const onUp = () => {
76
+ if (raf) cancelAnimationFrame(raf);
77
+ flush();
78
+ if (moved) onCommit(last);
79
+ handle.removeEventListener("pointermove", onMove);
80
+ handle.removeEventListener("pointerup", onUp);
81
+ handle.removeEventListener("pointercancel", onUp);
82
+ try {
83
+ handle.releasePointerCapture(e.pointerId);
84
+ } catch {
85
+ /* already released */
86
+ }
87
+ document.body.style.userSelect = "";
88
+ document.body.style.cursor = "";
89
+ };
90
+ document.body.style.userSelect = "none";
91
+ document.body.style.cursor = "ew-resize";
92
+ handle.addEventListener("pointermove", onMove);
93
+ handle.addEventListener("pointerup", onUp);
94
+ handle.addEventListener("pointercancel", onUp);
95
+ };
96
+ return (
97
+ <div
98
+ onPointerDown={onPointerDown}
99
+ onDoubleClick={(e) => {
100
+ e.preventDefault();
101
+ e.stopPropagation();
102
+ onAutoFit();
103
+ }}
104
+ title="Drag to resize · double-click to fit"
105
+ style={{ touchAction: "none" }}
106
+ className="absolute right-0 top-0 bottom-0 z-20 w-1.5 cursor-ew-resize hover:bg-accent/40"
107
+ />
108
+ );
109
+ };
110
+
30
111
  const DataTable: React.FC<DataTableProps> = ({ cart, entity, searchFields, onSelectRow }) => {
31
112
  const stream = useBulkSubscription(cart, entity);
32
113
  const scrollerRef = React.useRef<HTMLDivElement | null>(null);
@@ -37,12 +118,24 @@ const DataTable: React.FC<DataTableProps> = ({ cart, entity, searchFields, onSel
37
118
  const [popover, setPopover] = React.useState<ValuePopoverData | null>(null);
38
119
  // Bump on every chunk arrival without re-rendering each FRAME_DATA.
39
120
  const [tick, setTick] = React.useState(0);
121
+ // Per-column width overrides (px), keyed by field name. Seeded from
122
+ // localStorage; remounts on cart/entity change (keyed at the call site).
123
+ const [overrides, setOverrides] = React.useState<Record<string, number>>(
124
+ () => loadColWidths(cart, entity),
125
+ );
126
+ const widthFor = (name: string) => overrides[name] ?? defaultColWidth(name);
40
127
 
41
128
  React.useEffect(() => {
42
129
  stream.setOnRender(() => setTick((n) => n + 1));
43
130
  return () => stream.setOnRender(null);
44
131
  }, [stream]);
45
132
 
133
+ // Re-run once the scroller actually mounts. On first load columns are empty,
134
+ // so the "Waiting for schema…" placeholder renders instead of the scroller —
135
+ // scrollerRef is null and the observer never attaches, leaving viewportH at 0
136
+ // (only OVERSCAN rows windowed). Keying on columns-present re-attaches the
137
+ // moment the schema arrives and the scroller appears.
138
+ const hasScroller = stream.columns.length > 0;
46
139
  React.useEffect(() => {
47
140
  const el = scrollerRef.current;
48
141
  if (!el) return;
@@ -50,7 +143,7 @@ const DataTable: React.FC<DataTableProps> = ({ cart, entity, searchFields, onSel
50
143
  ro.observe(el);
51
144
  setViewportH(el.clientHeight);
52
145
  return () => ro.disconnect();
53
- }, []);
146
+ }, [hasScroller]);
54
147
 
55
148
  const rows = stream.store.rows;
56
149
  const columns = stream.columns;
@@ -78,9 +171,41 @@ const DataTable: React.FC<DataTableProps> = ({ cart, entity, searchFields, onSel
78
171
  };
79
172
 
80
173
  const searchDisabled = searchFields.length === 0;
81
- const totalColW = GUTTER_W + columns.reduce((s, c) => s + colWidth(c.name), 0);
82
174
  const idColIndex = columns.findIndex((c) => c.name === "id");
83
175
 
176
+ // Drive every width off CSS vars on the scroll root so a drag mutates one
177
+ // property and resizes the whole virtualized column with no React re-render.
178
+ const widthVars = React.useMemo(() => {
179
+ const style: React.CSSProperties & Record<string, string> = { ["--gw"]: `${GUTTER_W}px` };
180
+ const parts = ["var(--gw)"];
181
+ columns.forEach((c, i) => {
182
+ style[`--cw-${i}`] = `${widthFor(c.name)}px`;
183
+ parts.push(`var(--cw-${i})`);
184
+ });
185
+ style["--total-w"] = `calc(${parts.join(" + ")})`;
186
+ return style;
187
+ // eslint-disable-next-line react-hooks/exhaustive-deps
188
+ }, [columns, overrides]);
189
+
190
+ const commitWidth = (name: string, w: number) => {
191
+ setOverrides((o) => ({ ...o, [name]: w }));
192
+ saveColWidth(cart, entity, name, w);
193
+ };
194
+
195
+ const autoFit = (colIndex: number, name: string) => {
196
+ const ctx = measureCtx();
197
+ const root = scrollerRef.current;
198
+ if (!ctx || !root) return;
199
+ ctx.font = `12px ${getComputedStyle(root).fontFamily}`;
200
+ let w = ctx.measureText(name).width;
201
+ const cap = Math.min(rows.length, 1000);
202
+ for (let r = 0; r < cap; r++) w = Math.max(w, ctx.measureText(rows[r]?.[colIndex] ?? "").width);
203
+ // px-2 padding (16) + border slack (2).
204
+ const fitted = Math.max(MIN_COL_W, Math.min(MAX_COL_W, Math.ceil(w) + 18));
205
+ root.style.setProperty(`--cw-${colIndex}`, `${fitted}px`);
206
+ commitWidth(name, fitted);
207
+ };
208
+
84
209
  const scrollRowIntoView = (r: number) => {
85
210
  const el = scrollerRef.current;
86
211
  if (!el) return;
@@ -137,8 +262,8 @@ const DataTable: React.FC<DataTableProps> = ({ cart, entity, searchFields, onSel
137
262
  <div className="shrink-0 text-[11px] text-muted-foreground tabular-nums">
138
263
  {stream.error ? (
139
264
  <span className="text-red-400">{stream.error}</span>
140
- ) : !stream.connected ? (
141
- <span>connecting…</span>
265
+ ) : columns.length === 0 ? (
266
+ <span>{stream.connected ? "loading…" : "connecting…"}</span>
142
267
  ) : (
143
268
  <span>
144
269
  {stream.loadedRows.toLocaleString()} / {stream.totalRows.toLocaleString()} rows
@@ -163,29 +288,36 @@ const DataTable: React.FC<DataTableProps> = ({ cart, entity, searchFields, onSel
163
288
  }}
164
289
  className="group/table relative min-h-0 flex-1 overflow-auto font-mono outline-none"
165
290
  >
166
- <div style={{ width: totalColW }}>
291
+ <div style={{ ...widthVars, width: "var(--total-w)" }}>
167
292
  {/* Sticky header lives inside the scroller so it shares the native
168
293
  horizontal scroll with the rows — no JS transform sync, no jitter. */}
169
294
  <div
170
- className="sticky top-0 z-10 flex h-6 select-none border-b border-border bg-background text-[11px] uppercase tracking-wider text-muted-foreground"
171
- style={{ width: totalColW }}
295
+ className="sticky top-0 z-10 flex h-6 select-none border-b border-border bg-background text-[11px] text-muted-foreground"
296
+ style={{ width: "var(--total-w)" }}
172
297
  >
173
298
  <div
174
- style={{ width: GUTTER_W }}
299
+ style={{ width: "var(--gw)" }}
175
300
  className="shrink-0 border-r border-border"
176
301
  />
177
- {columns.map((c) => (
302
+ {columns.map((c, ci) => (
178
303
  <div
179
304
  key={c.name}
180
- style={{ width: colWidth(c.name) }}
181
- className="flex items-center overflow-hidden border-r border-border px-2"
305
+ style={{ width: `var(--cw-${ci})` }}
306
+ className="relative flex items-center overflow-hidden border-r border-border px-2"
182
307
  >
183
308
  <span className="truncate">{c.name}</span>
309
+ <ColResizeHandle
310
+ index={ci}
311
+ startWidth={widthFor(c.name)}
312
+ scrollerRef={scrollerRef}
313
+ onCommit={(w) => commitWidth(c.name, w)}
314
+ onAutoFit={() => autoFit(ci, c.name)}
315
+ />
184
316
  </div>
185
317
  ))}
186
318
  </div>
187
319
 
188
- <div style={{ height: totalH, width: totalColW, position: "relative" }}>
320
+ <div style={{ height: totalH, width: "var(--total-w)", position: "relative" }}>
189
321
  {rows.slice(start, end).map((row, i) => {
190
322
  const rowIdx = start + i;
191
323
  return (
@@ -194,7 +326,7 @@ const DataTable: React.FC<DataTableProps> = ({ cart, entity, searchFields, onSel
194
326
  style={{
195
327
  top: rowIdx * ROW_H,
196
328
  height: ROW_H,
197
- width: totalColW,
329
+ width: "var(--total-w)",
198
330
  }}
199
331
  className={cn(
200
332
  "absolute left-0 flex text-[12px] leading-none",
@@ -205,7 +337,7 @@ const DataTable: React.FC<DataTableProps> = ({ cart, entity, searchFields, onSel
205
337
  type="button"
206
338
  title="Open row detail"
207
339
  onClick={() => handleRowClick(rowIdx)}
208
- style={{ width: GUTTER_W }}
340
+ style={{ width: "var(--gw)" }}
209
341
  className={cn(
210
342
  "flex shrink-0 items-center justify-center border-r border-border/60",
211
343
  "cursor-pointer text-[10px] tabular-nums text-muted-foreground/60",
@@ -245,7 +377,7 @@ const DataTable: React.FC<DataTableProps> = ({ cart, entity, searchFields, onSel
245
377
  editable,
246
378
  });
247
379
  }}
248
- style={{ width: colWidth(c.name) }}
380
+ style={{ width: `var(--cw-${ci})` }}
249
381
  className={cn(
250
382
  "flex cursor-pointer items-center overflow-hidden border-r border-border/60 px-2",
251
383
  "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground",
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/editor/nbt-editor.tsx", "../src/editor/nbt-language.ts", "../src/editor/lsp-extensions.ts", "../src/editor/lsp-client.ts"],
4
- "sourcesContent": ["// CodeMirror 6 React wrapper for one NBT buffer. Recreated per uri (keyed by\n// the host); owns the EditorView lifecycle, Ctrl+S save, and the LSP wiring.\n\nimport React from \"react\";\nimport { EditorState } from \"@codemirror/state\";\nimport {\n EditorView,\n keymap,\n lineNumbers,\n drawSelection,\n highlightActiveLine,\n} from \"@codemirror/view\";\nimport {\n defaultKeymap,\n history,\n historyKeymap,\n indentWithTab,\n} from \"@codemirror/commands\";\nimport {\n syntaxHighlighting,\n defaultHighlightStyle,\n bracketMatching,\n} from \"@codemirror/language\";\nimport { lintGutter } from \"@codemirror/lint\";\nimport { searchKeymap } from \"@codemirror/search\";\nimport { completionKeymap, closeBrackets } from \"@codemirror/autocomplete\";\nimport { nbtLanguageSupport } from \"./nbt-language\";\nimport { lspExtensions, type GotoDefHandler } from \"./lsp-extensions\";\nimport { NbtLspClient } from \"./lsp-client\";\n\n// Match the devtools panel chrome via its CSS variables (we render inside the\n// .nimbit-devtools subtree, so these resolve to the scoped theme).\nconst nbtTheme = EditorView.theme(\n {\n \"&\": {\n height: \"100%\",\n fontSize: \"12px\",\n backgroundColor: \"var(--background)\",\n color: \"var(--foreground)\",\n },\n \".cm-content\": { fontFamily: \"ui-monospace, monospace\" },\n \".cm-gutters\": {\n backgroundColor: \"var(--background)\",\n color: \"var(--muted-foreground)\",\n borderRight: \"1px solid var(--border)\",\n },\n \".cm-activeLine\": { backgroundColor: \"color-mix(in srgb, var(--accent) 35%, transparent)\" },\n \"&.cm-focused\": { outline: \"none\" },\n \".cm-tooltip\": {\n backgroundColor: \"var(--popover)\",\n color: \"var(--popover-foreground)\",\n border: \"1px solid var(--border)\",\n },\n },\n { dark: true },\n);\n\nexport type NbtEditorProps = {\n uri: string;\n value: string;\n readOnly?: boolean;\n lsp?: NbtLspClient | null;\n onChange?: (text: string) => void;\n onSave?: (text: string) => void;\n onGotoDefinition?: GotoDefHandler;\n};\n\nexport const NbtEditor: React.FC<NbtEditorProps> = ({\n uri,\n value,\n readOnly = false,\n lsp,\n onChange,\n onSave,\n onGotoDefinition,\n}) => {\n const hostRef = React.useRef<HTMLDivElement | null>(null);\n const viewRef = React.useRef<EditorView | null>(null);\n\n // Latest callbacks without recreating the view.\n const onChangeRef = React.useRef(onChange);\n onChangeRef.current = onChange;\n const onSaveRef = React.useRef(onSave);\n onSaveRef.current = onSave;\n const onGotoRef = React.useRef(onGotoDefinition);\n onGotoRef.current = onGotoDefinition;\n\n React.useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n const extensions = [\n lineNumbers(),\n history(),\n drawSelection(),\n highlightActiveLine(),\n bracketMatching(),\n closeBrackets(),\n lintGutter(),\n syntaxHighlighting(defaultHighlightStyle, { fallback: true }),\n nbtLanguageSupport(),\n nbtTheme,\n keymap.of([\n {\n key: \"Mod-s\",\n run: (view) => {\n onSaveRef.current?.(view.state.doc.toString());\n return true;\n },\n },\n ...defaultKeymap,\n ...historyKeymap,\n ...searchKeymap,\n ...completionKeymap,\n indentWithTab,\n ]),\n EditorView.updateListener.of((u) => {\n if (u.docChanged) onChangeRef.current?.(u.state.doc.toString());\n }),\n EditorState.readOnly.of(readOnly),\n ];\n if (lsp && !readOnly) {\n extensions.push(\n lspExtensions(lsp, uri, (defUri, line) => onGotoRef.current?.(defUri, line)),\n );\n }\n\n const view = new EditorView({\n state: EditorState.create({ doc: value, extensions }),\n parent: host,\n });\n viewRef.current = view;\n return () => {\n view.destroy();\n viewRef.current = null;\n };\n // Recreate per buffer identity / mode; `value` is only the initial doc.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uri, readOnly, lsp]);\n\n return <div ref={hostRef} className=\"h-full min-h-0 overflow-hidden\" />;\n};\n", "// NBT syntax highlighting for CodeMirror 6 \u2014 a StreamLanguage tokenizer ported\n// from the console tokenizer (modules/lang_common/scan.jai) and the VSCode\n// grammar (editors/vscode/nbt/syntaxes/nbt.tmLanguage.json). Highlighting is\n// local; everything semantic (diagnostics/completion/hover) comes via the LSP.\n\nimport {\n StreamLanguage,\n LanguageSupport,\n indentUnit,\n type StreamParser,\n} from \"@codemirror/language\";\n\nconst KEYWORDS = new Set([\n \"entity\", \"enum\", \"struct\", \"const\", \"export\", \"extends\",\n \"fn\", \"on\", \"action\", \"activity\", \"task\", \"variant\", \"workflow\", \"command\",\n \"middleware\", \"schedule\", \"every\", \"jai\",\n \"migration\", \"test\", \"mock\", \"assert\",\n \"cartridge\", \"service\", \"component\", \"app\", \"route\", \"layout\",\n \"import\", \"from\",\n \"if\", \"elif\", \"else\", \"while\", \"for\", \"in\", \"return\", \"break\", \"continue\",\n \"delete\", \"defer\", \"print\", \"sleep\", \"fail\",\n]);\n\nconst TYPES = new Set([\n \"string\", \"bool\", \"ulid\", \"document\", \"dict\", \"blob\", \"DateTime\",\n \"u8\", \"u16\", \"u32\", \"u64\", \"s8\", \"s16\", \"s32\", \"s64\",\n \"int\", \"integer\", \"float\", \"float64\", \"f32\", \"f64\", \"double\",\n \"time\", \"bytes\", \"any\", \"name\", \"ref\",\n]);\n\ntype NbtState = {\n tripleString: boolean;\n};\n\n// NBT strings carry NO escapes (scan.jai consumes to the bare closing quote),\n// so a backslash before a quote does not extend the string.\nfunction eatSingleLineString(stream: StringStream, quote: string): string {\n while (!stream.eol()) {\n if (stream.next() === quote) break;\n }\n return \"string\";\n}\n\ntype StringStream = Parameters<StreamParser<NbtState>[\"token\"]>[0];\n\nconst nbtParser: StreamParser<NbtState> = {\n name: \"nbt\",\n startState: () => ({ tripleString: false }),\n token(stream, state) {\n if (state.tripleString) {\n while (!stream.eol()) {\n if (stream.match('\"\"\"')) {\n state.tripleString = false;\n return \"string\";\n }\n stream.next();\n }\n return \"string\";\n }\n\n if (stream.eatSpace()) return null;\n\n const ch = stream.peek();\n if (ch == null) return null;\n\n if (ch === \"#\") {\n stream.skipToEnd();\n return \"comment\";\n }\n\n if (stream.match('\"\"\"')) {\n state.tripleString = true;\n // Rest of line is string body unless it closes on the same line.\n while (!stream.eol()) {\n if (stream.match('\"\"\"')) {\n state.tripleString = false;\n return \"string\";\n }\n stream.next();\n }\n return \"string\";\n }\n\n if (ch === '\"') {\n stream.next();\n return eatSingleLineString(stream, '\"');\n }\n if (ch === \"'\") {\n // Like the scanner: only a string opener when not glued to an identifier\n // (lets contractions inside docs pass).\n const before = stream.string.charAt(stream.pos - 1);\n if (!/[A-Za-z0-9_]/.test(before)) {\n stream.next();\n return eatSingleLineString(stream, \"'\");\n }\n stream.next();\n return null;\n }\n\n // f-strings: f\"...\" \u2014 body highlighted as a string (interpolation holes\n // are cosmetic only).\n if (ch === \"f\" && stream.string.charAt(stream.pos + 1) === '\"') {\n stream.next();\n stream.next();\n return eatSingleLineString(stream, '\"');\n }\n\n // @attr / @@attr\n if (ch === \"@\") {\n stream.next();\n stream.eat(\"@\");\n stream.eatWhile(/[A-Za-z0-9_]/);\n return \"meta\";\n }\n\n // Numbers. The optional fraction backtracks on `0..9` ranges (matches \"0\",\n // not \"0.\").\n if (/\\d/.test(ch)) {\n stream.match(/^\\d+(\\.\\d+)?/);\n return \"number\";\n }\n\n if (/[A-Za-z_]/.test(ch)) {\n stream.eatWhile(/[A-Za-z0-9_]/);\n const word = stream.current();\n if (word === \"true\" || word === \"false\") return \"atom\";\n if (KEYWORDS.has(word)) return \"keyword\";\n if (TYPES.has(word)) return \"typeName\";\n if (/^[A-Z]/.test(word)) return \"typeName\"; // entity/enum references\n return \"variableName\";\n }\n\n if (/[+\\-*/=<>!&|?.,:;]/.test(ch)) {\n stream.next();\n stream.eatWhile(/[+\\-*/=<>!&|.]/);\n return \"operator\";\n }\n\n stream.next();\n return null;\n },\n languageData: {\n commentTokens: { line: \"#\" },\n },\n};\n\nexport const nbtLanguage = StreamLanguage.define(nbtParser);\n\nexport function nbtLanguageSupport(): LanguageSupport {\n return new LanguageSupport(nbtLanguage, [indentUnit.of(\" \")]);\n}\n", "// CodeMirror extensions wiring an editor buffer to the NbtLspClient:\n// full-text didChange sync (debounced), pushed publishDiagnostics \u2192 lint,\n// completion, hover, and F12 go-to-definition.\n\nimport { type Extension, type Text } from \"@codemirror/state\";\nimport {\n EditorView,\n ViewPlugin,\n type ViewUpdate,\n hoverTooltip,\n keymap,\n} from \"@codemirror/view\";\nimport {\n autocompletion,\n type CompletionContext,\n type CompletionResult,\n} from \"@codemirror/autocomplete\";\nimport { setDiagnostics, type Diagnostic } from \"@codemirror/lint\";\nimport {\n NbtLspClient,\n type LspDiagnostic,\n type LspPosition,\n type LspCompletionItem,\n type LspLocation,\n} from \"./lsp-client\";\n\nfunction toLspPos(doc: Text, offset: number): LspPosition {\n const line = doc.lineAt(offset);\n return { line: line.number - 1, character: offset - line.from };\n}\n\nfunction fromLspPos(doc: Text, pos: LspPosition): number {\n const lineNo = Math.min(Math.max(pos.line + 1, 1), doc.lines);\n const line = doc.line(lineNo);\n return Math.min(line.from + Math.max(pos.character, 0), line.to);\n}\n\nfunction toCmDiagnostics(doc: Text, diags: LspDiagnostic[]): Diagnostic[] {\n return diags.map((d) => {\n const from = fromLspPos(doc, d.range.start);\n let to = fromLspPos(doc, d.range.end);\n if (to <= from) to = Math.min(from + 1, doc.length);\n const severity =\n d.severity === 2 ? \"warning\" : d.severity === 3 || d.severity === 4 ? \"info\" : \"error\";\n return { from, to, severity, message: d.message, source: d.source ?? \"nbt\" };\n });\n}\n\n// LSP CompletionItemKind \u2192 CM completion type (drives the icon).\nfunction completionType(kind?: number): string {\n switch (kind) {\n case 3: return \"function\";\n case 5: return \"property\";\n case 13: return \"enum\";\n case 14: return \"keyword\";\n case 22: return \"class\";\n default: return \"variable\";\n }\n}\n\nexport type GotoDefHandler = (uri: string, line: number) => void;\n\nexport function lspExtensions(\n client: NbtLspClient,\n uri: string,\n onGotoDefinition?: GotoDefHandler,\n): Extension[] {\n // Sync + diagnostics plugin. didOpen on create, debounced didChange,\n // diagnostics pushed by the server are dispatched into the lint state.\n const syncPlugin = ViewPlugin.fromClass(\n class {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private unsubscribe: () => void;\n\n constructor(readonly view: EditorView) {\n client.didOpen(uri, view.state.doc.toString());\n this.unsubscribe = client.onDiagnostics(uri, (diags) => {\n const cm = toCmDiagnostics(this.view.state.doc, diags);\n this.view.dispatch(setDiagnostics(this.view.state, cm));\n });\n }\n\n update(u: ViewUpdate) {\n if (!u.docChanged) return;\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.timer = null;\n client.didChange(uri, this.view.state.doc.toString());\n }, 200);\n }\n\n destroy() {\n if (this.timer) {\n clearTimeout(this.timer);\n client.didChange(uri, this.view.state.doc.toString());\n }\n this.unsubscribe();\n }\n },\n );\n\n const completionSource = async (\n ctx: CompletionContext,\n ): Promise<CompletionResult | null> => {\n const word = ctx.matchBefore(/\\w*/);\n if (!word) return null;\n if (word.from === word.to && !ctx.explicit) {\n // Only fire automatically right after a trigger character.\n const before = ctx.state.doc.sliceString(Math.max(0, ctx.pos - 1), ctx.pos);\n if (before !== \".\" && before !== \":\" && before !== '\"') return null;\n }\n // Flush any pending edit so the server completes against the live buffer.\n client.didChange(uri, ctx.state.doc.toString());\n let result;\n try {\n result = await client.completion(uri, toLspPos(ctx.state.doc, ctx.pos));\n } catch {\n return null;\n }\n const items: LspCompletionItem[] = Array.isArray(result)\n ? result\n : (result?.items ?? []);\n if (items.length === 0) return null;\n return {\n from: word.from,\n options: items.map((it) => ({\n label: it.label,\n type: completionType(it.kind),\n detail: it.detail,\n })),\n };\n };\n\n const hover = hoverTooltip(async (view, pos) => {\n let result;\n try {\n result = await client.hover(uri, toLspPos(view.state.doc, pos));\n } catch {\n return null;\n }\n const value = result?.contents?.value;\n if (!value) return null;\n return {\n pos,\n create: () => {\n const dom = document.createElement(\"pre\");\n dom.className = \"nbt-hover-tooltip\";\n dom.style.cssText =\n \"margin:0;padding:6px 8px;max-width:480px;white-space:pre-wrap;font-size:11px;\";\n // Server emits fenced markdown code blocks; strip the fences, show text.\n dom.textContent = value.replace(/```\\w*\\n?/g, \"\");\n return { dom };\n },\n };\n });\n\n const gotoDef = keymap.of([\n {\n key: \"F12\",\n run: (view) => {\n const pos = toLspPos(view.state.doc, view.state.selection.main.head);\n client\n .definition(uri, pos)\n .then((result) => {\n const loc: LspLocation | null = Array.isArray(result)\n ? (result[0] ?? null)\n : result;\n if (!loc?.uri) return;\n if (loc.uri === uri) {\n const off = fromLspPos(view.state.doc, loc.range.start);\n view.dispatch({\n selection: { anchor: off },\n scrollIntoView: true,\n });\n } else {\n onGotoDefinition?.(loc.uri, loc.range.start.line);\n }\n })\n .catch(() => {});\n return true;\n },\n },\n ]);\n\n return [\n syncPlugin,\n autocompletion({ override: [completionSource] }),\n hover,\n gotoDef,\n ];\n}\n", "// Minimal LSP client over WebSocket for the console's dev-mode nbt_lsp bridge\n// (/_console/dev/lsp). One JSON-RPC message per WS text frame \u2014 no\n// Content-Length framing (the bridge's write_proc emits bare JSON).\n//\n// Hand-rolled on purpose: the server speaks ~10 methods with full-text sync,\n// and a library client (codemirror-languageserver) would drag transitive\n// runtime deps into every host app.\n\nexport type LspPosition = { line: number; character: number };\nexport type LspRange = { start: LspPosition; end: LspPosition };\nexport type LspDiagnostic = {\n range: LspRange;\n severity?: number; // 1=error 2=warning 3=info 4=hint\n message: string;\n source?: string;\n};\nexport type LspCompletionItem = {\n label: string;\n kind?: number;\n detail?: string;\n};\nexport type LspLocation = { uri: string; range: LspRange };\n\ntype Pending = {\n resolve: (v: unknown) => void;\n reject: (e: Error) => void;\n};\n\nexport class NbtLspClient {\n private url: string;\n private rootUri: string | null = null;\n private ws: WebSocket | null = null;\n private nextId = 1;\n private pending = new Map<number, Pending>();\n private diagHandlers = new Map<string, (d: LspDiagnostic[]) => void>();\n // Open buffers, kept for replay across reconnects.\n private docs = new Map<string, { text: string; version: number }>();\n private ready = false;\n private queue: string[] = [];\n private closed = false;\n private retryMs = 500;\n\n constructor(url: string) {\n this.url = url;\n this.connect();\n }\n\n dispose() {\n this.closed = true;\n this.ws?.close();\n this.pending.forEach((p) => p.reject(new Error(\"lsp client disposed\")));\n this.pending.clear();\n }\n\n private connect() {\n if (this.closed) return;\n const ws = new WebSocket(this.url);\n this.ws = ws;\n ws.onopen = () => {\n this.retryMs = 500;\n if (this.rootUri) this.sendInitialize(this.rootUri);\n };\n ws.onmessage = (ev) => {\n if (typeof ev.data !== \"string\") return;\n this.onMessage(ev.data);\n };\n ws.onclose = () => {\n this.ready = false;\n this.ws = null;\n for (const p of this.pending.values())\n p.reject(new Error(\"lsp connection closed\"));\n this.pending.clear();\n if (!this.closed) {\n setTimeout(() => this.connect(), this.retryMs);\n this.retryMs = Math.min(this.retryMs * 2, 10_000);\n }\n };\n }\n\n // Called once by the host with file://<projectRoot>; also re-sent after every\n // reconnect, followed by didOpen replays for tracked buffers.\n initialize(rootUri: string) {\n this.rootUri = rootUri;\n if (this.ws?.readyState === WebSocket.OPEN) this.sendInitialize(rootUri);\n }\n\n private sendInitialize(rootUri: string) {\n const id = this.nextId++;\n this.pending.set(id, {\n resolve: () => {\n this.sendRaw({ jsonrpc: \"2.0\", method: \"initialized\", params: {} });\n this.ready = true;\n for (const [uri, d] of this.docs) {\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didOpen\",\n params: {\n textDocument: {\n uri,\n languageId: \"nbt\",\n version: d.version,\n text: d.text,\n },\n },\n });\n }\n const q = this.queue;\n this.queue = [];\n for (const m of q) this.ws?.send(m);\n },\n reject: () => {},\n });\n this.ws?.send(\n JSON.stringify({\n jsonrpc: \"2.0\",\n id,\n method: \"initialize\",\n params: { rootUri },\n }),\n );\n }\n\n private sendRaw(msg: object) {\n const s = JSON.stringify(msg);\n if (this.ready && this.ws?.readyState === WebSocket.OPEN) this.ws.send(s);\n else this.queue.push(s);\n }\n\n private onMessage(data: string) {\n let msg: any;\n try {\n msg = JSON.parse(data);\n } catch {\n return;\n }\n if (msg.id != null && (msg.result !== undefined || msg.error)) {\n const p = this.pending.get(msg.id);\n if (!p) return;\n this.pending.delete(msg.id);\n if (msg.error) p.reject(new Error(msg.error.message ?? \"lsp error\"));\n else p.resolve(msg.result);\n return;\n }\n if (msg.method === \"textDocument/publishDiagnostics\") {\n const uri = msg.params?.uri as string;\n const handler = this.diagHandlers.get(uri);\n if (handler) handler((msg.params?.diagnostics ?? []) as LspDiagnostic[]);\n }\n }\n\n request<T>(method: string, params: object): Promise<T> {\n const id = this.nextId++;\n const p = new Promise<T>((resolve, reject) => {\n this.pending.set(id, { resolve: resolve as Pending[\"resolve\"], reject });\n });\n this.sendRaw({ jsonrpc: \"2.0\", id, method, params });\n return p;\n }\n\n onDiagnostics(uri: string, handler: (d: LspDiagnostic[]) => void): () => void {\n this.diagHandlers.set(uri, handler);\n return () => {\n if (this.diagHandlers.get(uri) === handler) this.diagHandlers.delete(uri);\n };\n }\n\n didOpen(uri: string, text: string) {\n const existing = this.docs.get(uri);\n if (existing) {\n // Re-opening an already-tracked buffer (tab switch) \u2014 just resync.\n this.didChange(uri, text);\n return;\n }\n this.docs.set(uri, { text, version: 1 });\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didOpen\",\n params: { textDocument: { uri, languageId: \"nbt\", version: 1, text } },\n });\n }\n\n didChange(uri: string, text: string) {\n const d = this.docs.get(uri);\n if (!d) return this.didOpen(uri, text);\n if (d.text === text) return;\n d.text = text;\n d.version += 1;\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didChange\",\n params: {\n textDocument: { uri, version: d.version },\n contentChanges: [{ text }],\n },\n });\n }\n\n didClose(uri: string) {\n if (!this.docs.delete(uri)) return;\n this.sendRaw({\n jsonrpc: \"2.0\",\n method: \"textDocument/didClose\",\n params: { textDocument: { uri } },\n });\n }\n\n completion(uri: string, pos: LspPosition): Promise<{ items: LspCompletionItem[] } | LspCompletionItem[] | null> {\n return this.request(\"textDocument/completion\", {\n textDocument: { uri },\n position: pos,\n });\n }\n\n hover(uri: string, pos: LspPosition): Promise<{ contents?: { value?: string } } | null> {\n return this.request(\"textDocument/hover\", {\n textDocument: { uri },\n position: pos,\n });\n }\n\n definition(uri: string, pos: LspPosition): Promise<LspLocation | LspLocation[] | null> {\n return this.request(\"textDocument/definition\", {\n textDocument: { uri },\n position: pos,\n });\n }\n}\n"],
5
- "mappings": ";;;AAGA,OAAO,WAAW;AAClB,SAAS,mBAAmB;AAC5B;AAAA,EACE,cAAAA;AAAA,EACA,UAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB,qBAAqB;;;ACpBhD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,IAAM,WAAW,oBAAI,IAAI;AAAA,EACvB;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAS;AAAA,EAAU;AAAA,EAC/C;AAAA,EAAM;AAAA,EAAM;AAAA,EAAU;AAAA,EAAY;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAY;AAAA,EACjE;AAAA,EAAc;AAAA,EAAY;AAAA,EAAS;AAAA,EACnC;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAC7B;AAAA,EAAa;AAAA,EAAW;AAAA,EAAa;AAAA,EAAO;AAAA,EAAS;AAAA,EACrD;AAAA,EAAU;AAAA,EACV;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAM;AAAA,EAAU;AAAA,EAAS;AAAA,EAC/D;AAAA,EAAU;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AACvC,CAAC;AAED,IAAM,QAAQ,oBAAI,IAAI;AAAA,EACpB;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACtD;AAAA,EAAM;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAM;AAAA,EAAO;AAAA,EAAO;AAAA,EAC/C;AAAA,EAAO;AAAA,EAAW;AAAA,EAAS;AAAA,EAAW;AAAA,EAAO;AAAA,EAAO;AAAA,EACpD;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAQ;AAClC,CAAC;AAQD,SAAS,oBAAoB,QAAsB,OAAuB;AACxE,SAAO,CAAC,OAAO,IAAI,GAAG;AACpB,QAAI,OAAO,KAAK,MAAM,MAAO;AAAA,EAC/B;AACA,SAAO;AACT;AAIA,IAAM,YAAoC;AAAA,EACxC,MAAM;AAAA,EACN,YAAY,OAAO,EAAE,cAAc,MAAM;AAAA,EACzC,MAAM,QAAQ,OAAO;AACnB,QAAI,MAAM,cAAc;AACtB,aAAO,CAAC,OAAO,IAAI,GAAG;AACpB,YAAI,OAAO,MAAM,KAAK,GAAG;AACvB,gBAAM,eAAe;AACrB,iBAAO;AAAA,QACT;AACA,eAAO,KAAK;AAAA,MACd;AACA,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,SAAS,EAAG,QAAO;AAE9B,UAAM,KAAK,OAAO,KAAK;AACvB,QAAI,MAAM,KAAM,QAAO;AAEvB,QAAI,OAAO,KAAK;AACd,aAAO,UAAU;AACjB,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,MAAM,KAAK,GAAG;AACvB,YAAM,eAAe;AAErB,aAAO,CAAC,OAAO,IAAI,GAAG;AACpB,YAAI,OAAO,MAAM,KAAK,GAAG;AACvB,gBAAM,eAAe;AACrB,iBAAO;AAAA,QACT;AACA,eAAO,KAAK;AAAA,MACd;AACA,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,KAAK;AACd,aAAO,KAAK;AACZ,aAAO,oBAAoB,QAAQ,GAAG;AAAA,IACxC;AACA,QAAI,OAAO,KAAK;AAGd,YAAM,SAAS,OAAO,OAAO,OAAO,OAAO,MAAM,CAAC;AAClD,UAAI,CAAC,eAAe,KAAK,MAAM,GAAG;AAChC,eAAO,KAAK;AACZ,eAAO,oBAAoB,QAAQ,GAAG;AAAA,MACxC;AACA,aAAO,KAAK;AACZ,aAAO;AAAA,IACT;AAIA,QAAI,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM,CAAC,MAAM,KAAK;AAC9D,aAAO,KAAK;AACZ,aAAO,KAAK;AACZ,aAAO,oBAAoB,QAAQ,GAAG;AAAA,IACxC;AAGA,QAAI,OAAO,KAAK;AACd,aAAO,KAAK;AACZ,aAAO,IAAI,GAAG;AACd,aAAO,SAAS,cAAc;AAC9B,aAAO;AAAA,IACT;AAIA,QAAI,KAAK,KAAK,EAAE,GAAG;AACjB,aAAO,MAAM,cAAc;AAC3B,aAAO;AAAA,IACT;AAEA,QAAI,YAAY,KAAK,EAAE,GAAG;AACxB,aAAO,SAAS,cAAc;AAC9B,YAAM,OAAO,OAAO,QAAQ;AAC5B,UAAI,SAAS,UAAU,SAAS,QAAS,QAAO;AAChD,UAAI,SAAS,IAAI,IAAI,EAAG,QAAO;AAC/B,UAAI,MAAM,IAAI,IAAI,EAAG,QAAO;AAC5B,UAAI,SAAS,KAAK,IAAI,EAAG,QAAO;AAChC,aAAO;AAAA,IACT;AAEA,QAAI,qBAAqB,KAAK,EAAE,GAAG;AACjC,aAAO,KAAK;AACZ,aAAO,SAAS,gBAAgB;AAChC,aAAO;AAAA,IACT;AAEA,WAAO,KAAK;AACZ,WAAO;AAAA,EACT;AAAA,EACA,cAAc;AAAA,IACZ,eAAe,EAAE,MAAM,IAAI;AAAA,EAC7B;AACF;AAEO,IAAM,cAAc,eAAe,OAAO,SAAS;AAEnD,SAAS,qBAAsC;AACpD,SAAO,IAAI,gBAAgB,aAAa,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;AAC/D;;;ACjJA;AAAA,EAEE;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,OAGK;AACP,SAAS,sBAAuC;AAShD,SAAS,SAAS,KAAW,QAA6B;AACxD,QAAM,OAAO,IAAI,OAAO,MAAM;AAC9B,SAAO,EAAE,MAAM,KAAK,SAAS,GAAG,WAAW,SAAS,KAAK,KAAK;AAChE;AAEA,SAAS,WAAW,KAAW,KAA0B;AACvD,QAAM,SAAS,KAAK,IAAI,KAAK,IAAI,IAAI,OAAO,GAAG,CAAC,GAAG,IAAI,KAAK;AAC5D,QAAM,OAAO,IAAI,KAAK,MAAM;AAC5B,SAAO,KAAK,IAAI,KAAK,OAAO,KAAK,IAAI,IAAI,WAAW,CAAC,GAAG,KAAK,EAAE;AACjE;AAEA,SAAS,gBAAgB,KAAW,OAAsC;AACxE,SAAO,MAAM,IAAI,CAAC,MAAM;AACtB,UAAM,OAAO,WAAW,KAAK,EAAE,MAAM,KAAK;AAC1C,QAAI,KAAK,WAAW,KAAK,EAAE,MAAM,GAAG;AACpC,QAAI,MAAM,KAAM,MAAK,KAAK,IAAI,OAAO,GAAG,IAAI,MAAM;AAClD,UAAM,WACJ,EAAE,aAAa,IAAI,YAAY,EAAE,aAAa,KAAK,EAAE,aAAa,IAAI,SAAS;AACjF,WAAO,EAAE,MAAM,IAAI,UAAU,SAAS,EAAE,SAAS,QAAQ,EAAE,UAAU,MAAM;AAAA,EAC7E,CAAC;AACH;AAGA,SAAS,eAAe,MAAuB;AAC7C,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAG,aAAO;AAAA,IACf,KAAK;AAAG,aAAO;AAAA,IACf,KAAK;AAAI,aAAO;AAAA,IAChB,KAAK;AAAI,aAAO;AAAA,IAChB,KAAK;AAAI,aAAO;AAAA,IAChB;AAAS,aAAO;AAAA,EAClB;AACF;AAIO,SAAS,cACd,QACA,KACA,kBACa;AAGb,QAAM,aAAa,WAAW;AAAA,IAC5B,MAAM;AAAA,MAIJ,YAAqB,MAAkB;AAAlB;AAHrB,aAAQ,QAA8C;AAIpD,eAAO,QAAQ,KAAK,KAAK,MAAM,IAAI,SAAS,CAAC;AAC7C,aAAK,cAAc,OAAO,cAAc,KAAK,CAAC,UAAU;AACtD,gBAAM,KAAK,gBAAgB,KAAK,KAAK,MAAM,KAAK,KAAK;AACrD,eAAK,KAAK,SAAS,eAAe,KAAK,KAAK,OAAO,EAAE,CAAC;AAAA,QACxD,CAAC;AAAA,MACH;AAAA,MAEA,OAAO,GAAe;AACpB,YAAI,CAAC,EAAE,WAAY;AACnB,YAAI,KAAK,MAAO,cAAa,KAAK,KAAK;AACvC,aAAK,QAAQ,WAAW,MAAM;AAC5B,eAAK,QAAQ;AACb,iBAAO,UAAU,KAAK,KAAK,KAAK,MAAM,IAAI,SAAS,CAAC;AAAA,QACtD,GAAG,GAAG;AAAA,MACR;AAAA,MAEA,UAAU;AACR,YAAI,KAAK,OAAO;AACd,uBAAa,KAAK,KAAK;AACvB,iBAAO,UAAU,KAAK,KAAK,KAAK,MAAM,IAAI,SAAS,CAAC;AAAA,QACtD;AACA,aAAK,YAAY;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,mBAAmB,OACvB,QACqC;AACrC,UAAM,OAAO,IAAI,YAAY,KAAK;AAClC,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI,KAAK,SAAS,KAAK,MAAM,CAAC,IAAI,UAAU;AAE1C,YAAM,SAAS,IAAI,MAAM,IAAI,YAAY,KAAK,IAAI,GAAG,IAAI,MAAM,CAAC,GAAG,IAAI,GAAG;AAC1E,UAAI,WAAW,OAAO,WAAW,OAAO,WAAW,IAAK,QAAO;AAAA,IACjE;AAEA,WAAO,UAAU,KAAK,IAAI,MAAM,IAAI,SAAS,CAAC;AAC9C,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,OAAO,WAAW,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,GAAG,CAAC;AAAA,IACxE,QAAQ;AACN,aAAO;AAAA,IACT;AACA,UAAM,QAA6B,MAAM,QAAQ,MAAM,IACnD,SACC,QAAQ,SAAS,CAAC;AACvB,QAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,SAAS,MAAM,IAAI,CAAC,QAAQ;AAAA,QAC1B,OAAO,GAAG;AAAA,QACV,MAAM,eAAe,GAAG,IAAI;AAAA,QAC5B,QAAQ,GAAG;AAAA,MACb,EAAE;AAAA,IACJ;AAAA,EACF;AAEA,QAAM,QAAQ,aAAa,OAAO,MAAM,QAAQ;AAC9C,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,OAAO,MAAM,KAAK,SAAS,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,IAChE,QAAQ;AACN,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,QAAQ,UAAU;AAChC,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,MAAM;AACZ,cAAM,MAAM,SAAS,cAAc,KAAK;AACxC,YAAI,YAAY;AAChB,YAAI,MAAM,UACR;AAEF,YAAI,cAAc,MAAM,QAAQ,cAAc,EAAE;AAChD,eAAO,EAAE,IAAI;AAAA,MACf;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,UAAU,OAAO,GAAG;AAAA,IACxB;AAAA,MACE,KAAK;AAAA,MACL,KAAK,CAAC,SAAS;AACb,cAAM,MAAM,SAAS,KAAK,MAAM,KAAK,KAAK,MAAM,UAAU,KAAK,IAAI;AACnE,eACG,WAAW,KAAK,GAAG,EACnB,KAAK,CAAC,WAAW;AAChB,gBAAM,MAA0B,MAAM,QAAQ,MAAM,IAC/C,OAAO,CAAC,KAAK,OACd;AACJ,cAAI,CAAC,KAAK,IAAK;AACf,cAAI,IAAI,QAAQ,KAAK;AACnB,kBAAM,MAAM,WAAW,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK;AACtD,iBAAK,SAAS;AAAA,cACZ,WAAW,EAAE,QAAQ,IAAI;AAAA,cACzB,gBAAgB;AAAA,YAClB,CAAC;AAAA,UACH,OAAO;AACL,+BAAmB,IAAI,KAAK,IAAI,MAAM,MAAM,IAAI;AAAA,UAClD;AAAA,QACF,CAAC,EACA,MAAM,MAAM;AAAA,QAAC,CAAC;AACjB,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,eAAe,EAAE,UAAU,CAAC,gBAAgB,EAAE,CAAC;AAAA,IAC/C;AAAA,IACA;AAAA,EACF;AACF;;;AFlDS;AA5GT,IAAM,WAAWC,YAAW;AAAA,EAC1B;AAAA,IACE,KAAK;AAAA,MACH,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,iBAAiB;AAAA,MACjB,OAAO;AAAA,IACT;AAAA,IACA,eAAe,EAAE,YAAY,0BAA0B;AAAA,IACvD,eAAe;AAAA,MACb,iBAAiB;AAAA,MACjB,OAAO;AAAA,MACP,aAAa;AAAA,IACf;AAAA,IACA,kBAAkB,EAAE,iBAAiB,qDAAqD;AAAA,IAC1F,gBAAgB,EAAE,SAAS,OAAO;AAAA,IAClC,eAAe;AAAA,MACb,iBAAiB;AAAA,MACjB,OAAO;AAAA,MACP,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EACA,EAAE,MAAM,KAAK;AACf;AAYO,IAAM,YAAsC,CAAC;AAAA,EAClD;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,UAAU,MAAM,OAA8B,IAAI;AACxD,QAAM,UAAU,MAAM,OAA0B,IAAI;AAGpD,QAAM,cAAc,MAAM,OAAO,QAAQ;AACzC,cAAY,UAAU;AACtB,QAAM,YAAY,MAAM,OAAO,MAAM;AACrC,YAAU,UAAU;AACpB,QAAM,YAAY,MAAM,OAAO,gBAAgB;AAC/C,YAAU,UAAU;AAEpB,QAAM,UAAU,MAAM;AACpB,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AAEX,UAAM,aAAa;AAAA,MACjB,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,oBAAoB;AAAA,MACpB,gBAAgB;AAAA,MAChB,cAAc;AAAA,MACd,WAAW;AAAA,MACX,mBAAmB,uBAAuB,EAAE,UAAU,KAAK,CAAC;AAAA,MAC5D,mBAAmB;AAAA,MACnB;AAAA,MACAC,QAAO,GAAG;AAAA,QACR;AAAA,UACE,KAAK;AAAA,UACL,KAAK,CAACC,UAAS;AACb,sBAAU,UAAUA,MAAK,MAAM,IAAI,SAAS,CAAC;AAC7C,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,QACA,GAAG;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,QACH;AAAA,MACF,CAAC;AAAA,MACDF,YAAW,eAAe,GAAG,CAAC,MAAM;AAClC,YAAI,EAAE,WAAY,aAAY,UAAU,EAAE,MAAM,IAAI,SAAS,CAAC;AAAA,MAChE,CAAC;AAAA,MACD,YAAY,SAAS,GAAG,QAAQ;AAAA,IAClC;AACA,QAAI,OAAO,CAAC,UAAU;AACpB,iBAAW;AAAA,QACT,cAAc,KAAK,KAAK,CAAC,QAAQ,SAAS,UAAU,UAAU,QAAQ,IAAI,CAAC;AAAA,MAC7E;AAAA,IACF;AAEA,UAAM,OAAO,IAAIA,YAAW;AAAA,MAC1B,OAAO,YAAY,OAAO,EAAE,KAAK,OAAO,WAAW,CAAC;AAAA,MACpD,QAAQ;AAAA,IACV,CAAC;AACD,YAAQ,UAAU;AAClB,WAAO,MAAM;AACX,WAAK,QAAQ;AACb,cAAQ,UAAU;AAAA,IACpB;AAAA,EAGF,GAAG,CAAC,KAAK,UAAU,GAAG,CAAC;AAEvB,SAAO,oBAAC,SAAI,KAAK,SAAS,WAAU,kCAAiC;AACvE;;;AGjHO,IAAM,eAAN,MAAmB;AAAA,EAcxB,YAAY,KAAa;AAZzB,SAAQ,UAAyB;AACjC,SAAQ,KAAuB;AAC/B,SAAQ,SAAS;AACjB,SAAQ,UAAU,oBAAI,IAAqB;AAC3C,SAAQ,eAAe,oBAAI,IAA0C;AAErE;AAAA,SAAQ,OAAO,oBAAI,IAA+C;AAClE,SAAQ,QAAQ;AAChB,SAAQ,QAAkB,CAAC;AAC3B,SAAQ,SAAS;AACjB,SAAQ,UAAU;AAGhB,SAAK,MAAM;AACX,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,UAAU;AACR,SAAK,SAAS;AACd,SAAK,IAAI,MAAM;AACf,SAAK,QAAQ,QAAQ,CAAC,MAAM,EAAE,OAAO,IAAI,MAAM,qBAAqB,CAAC,CAAC;AACtE,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEQ,UAAU;AAChB,QAAI,KAAK,OAAQ;AACjB,UAAM,KAAK,IAAI,UAAU,KAAK,GAAG;AACjC,SAAK,KAAK;AACV,OAAG,SAAS,MAAM;AAChB,WAAK,UAAU;AACf,UAAI,KAAK,QAAS,MAAK,eAAe,KAAK,OAAO;AAAA,IACpD;AACA,OAAG,YAAY,CAAC,OAAO;AACrB,UAAI,OAAO,GAAG,SAAS,SAAU;AACjC,WAAK,UAAU,GAAG,IAAI;AAAA,IACxB;AACA,OAAG,UAAU,MAAM;AACjB,WAAK,QAAQ;AACb,WAAK,KAAK;AACV,iBAAW,KAAK,KAAK,QAAQ,OAAO;AAClC,UAAE,OAAO,IAAI,MAAM,uBAAuB,CAAC;AAC7C,WAAK,QAAQ,MAAM;AACnB,UAAI,CAAC,KAAK,QAAQ;AAChB,mBAAW,MAAM,KAAK,QAAQ,GAAG,KAAK,OAAO;AAC7C,aAAK,UAAU,KAAK,IAAI,KAAK,UAAU,GAAG,GAAM;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,WAAW,SAAiB;AAC1B,SAAK,UAAU;AACf,QAAI,KAAK,IAAI,eAAe,UAAU,KAAM,MAAK,eAAe,OAAO;AAAA,EACzE;AAAA,EAEQ,eAAe,SAAiB;AACtC,UAAM,KAAK,KAAK;AAChB,SAAK,QAAQ,IAAI,IAAI;AAAA,MACnB,SAAS,MAAM;AACb,aAAK,QAAQ,EAAE,SAAS,OAAO,QAAQ,eAAe,QAAQ,CAAC,EAAE,CAAC;AAClE,aAAK,QAAQ;AACb,mBAAW,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM;AAChC,eAAK,QAAQ;AAAA,YACX,SAAS;AAAA,YACT,QAAQ;AAAA,YACR,QAAQ;AAAA,cACN,cAAc;AAAA,gBACZ;AAAA,gBACA,YAAY;AAAA,gBACZ,SAAS,EAAE;AAAA,gBACX,MAAM,EAAE;AAAA,cACV;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AACA,cAAM,IAAI,KAAK;AACf,aAAK,QAAQ,CAAC;AACd,mBAAW,KAAK,EAAG,MAAK,IAAI,KAAK,CAAC;AAAA,MACpC;AAAA,MACA,QAAQ,MAAM;AAAA,MAAC;AAAA,IACjB,CAAC;AACD,SAAK,IAAI;AAAA,MACP,KAAK,UAAU;AAAA,QACb,SAAS;AAAA,QACT;AAAA,QACA,QAAQ;AAAA,QACR,QAAQ,EAAE,QAAQ;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,QAAQ,KAAa;AAC3B,UAAM,IAAI,KAAK,UAAU,GAAG;AAC5B,QAAI,KAAK,SAAS,KAAK,IAAI,eAAe,UAAU,KAAM,MAAK,GAAG,KAAK,CAAC;AAAA,QACnE,MAAK,MAAM,KAAK,CAAC;AAAA,EACxB;AAAA,EAEQ,UAAU,MAAc;AAC9B,QAAI;AACJ,QAAI;AACF,YAAM,KAAK,MAAM,IAAI;AAAA,IACvB,QAAQ;AACN;AAAA,IACF;AACA,QAAI,IAAI,MAAM,SAAS,IAAI,WAAW,UAAa,IAAI,QAAQ;AAC7D,YAAM,IAAI,KAAK,QAAQ,IAAI,IAAI,EAAE;AACjC,UAAI,CAAC,EAAG;AACR,WAAK,QAAQ,OAAO,IAAI,EAAE;AAC1B,UAAI,IAAI,MAAO,GAAE,OAAO,IAAI,MAAM,IAAI,MAAM,WAAW,WAAW,CAAC;AAAA,UAC9D,GAAE,QAAQ,IAAI,MAAM;AACzB;AAAA,IACF;AACA,QAAI,IAAI,WAAW,mCAAmC;AACpD,YAAM,MAAM,IAAI,QAAQ;AACxB,YAAM,UAAU,KAAK,aAAa,IAAI,GAAG;AACzC,UAAI,QAAS,SAAS,IAAI,QAAQ,eAAe,CAAC,CAAqB;AAAA,IACzE;AAAA,EACF;AAAA,EAEA,QAAW,QAAgB,QAA4B;AACrD,UAAM,KAAK,KAAK;AAChB,UAAM,IAAI,IAAI,QAAW,CAAC,SAAS,WAAW;AAC5C,WAAK,QAAQ,IAAI,IAAI,EAAE,SAAwC,OAAO,CAAC;AAAA,IACzE,CAAC;AACD,SAAK,QAAQ,EAAE,SAAS,OAAO,IAAI,QAAQ,OAAO,CAAC;AACnD,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,KAAa,SAAmD;AAC5E,SAAK,aAAa,IAAI,KAAK,OAAO;AAClC,WAAO,MAAM;AACX,UAAI,KAAK,aAAa,IAAI,GAAG,MAAM,QAAS,MAAK,aAAa,OAAO,GAAG;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,QAAQ,KAAa,MAAc;AACjC,UAAM,WAAW,KAAK,KAAK,IAAI,GAAG;AAClC,QAAI,UAAU;AAEZ,WAAK,UAAU,KAAK,IAAI;AACxB;AAAA,IACF;AACA,SAAK,KAAK,IAAI,KAAK,EAAE,MAAM,SAAS,EAAE,CAAC;AACvC,SAAK,QAAQ;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,QAAQ,EAAE,cAAc,EAAE,KAAK,YAAY,OAAO,SAAS,GAAG,KAAK,EAAE;AAAA,IACvE,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,KAAa,MAAc;AACnC,UAAM,IAAI,KAAK,KAAK,IAAI,GAAG;AAC3B,QAAI,CAAC,EAAG,QAAO,KAAK,QAAQ,KAAK,IAAI;AACrC,QAAI,EAAE,SAAS,KAAM;AACrB,MAAE,OAAO;AACT,MAAE,WAAW;AACb,SAAK,QAAQ;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN,cAAc,EAAE,KAAK,SAAS,EAAE,QAAQ;AAAA,QACxC,gBAAgB,CAAC,EAAE,KAAK,CAAC;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,SAAS,KAAa;AACpB,QAAI,CAAC,KAAK,KAAK,OAAO,GAAG,EAAG;AAC5B,SAAK,QAAQ;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE;AAAA,IAClC,CAAC;AAAA,EACH;AAAA,EAEA,WAAW,KAAa,KAAwF;AAC9G,WAAO,KAAK,QAAQ,2BAA2B;AAAA,MAC7C,cAAc,EAAE,IAAI;AAAA,MACpB,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,KAAa,KAAqE;AACtF,WAAO,KAAK,QAAQ,sBAAsB;AAAA,MACxC,cAAc,EAAE,IAAI;AAAA,MACpB,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,WAAW,KAAa,KAA+D;AACrF,WAAO,KAAK,QAAQ,2BAA2B;AAAA,MAC7C,cAAc,EAAE,IAAI;AAAA,MACpB,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AACF;",
6
- "names": ["EditorView", "keymap", "EditorView", "keymap", "view"]
7
- }