jaml-ui 0.24.16 → 0.24.18
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/components/DeckSprite.js +2 -0
- package/dist/components/GameCard.js +1 -0
- package/dist/components/JamlAestheticSelector.js +3 -2
- package/dist/components/JamlCurator.js +3 -2
- package/dist/components/JamlIde.d.ts +4 -3
- package/dist/components/JamlIde.js +3 -31
- package/dist/components/JamlIdeToolbar.d.ts +1 -1
- package/dist/components/JamlIdeToolbar.js +5 -5
- package/dist/components/JamlMapPreview.js +3 -37
- package/dist/components/Jimbolate.d.ts +7 -0
- package/dist/components/Jimbolate.js +17 -0
- package/dist/components/PaginatedFilterBrowser.d.ts +23 -0
- package/dist/components/PaginatedFilterBrowser.js +54 -0
- package/dist/components/RunConfigModal.js +11 -150
- package/dist/components/jamlMap/CategoryPicker.d.ts +1 -2
- package/dist/components/jamlMap/CategoryPicker.js +2 -1
- package/dist/components/jamlMap/JamlMapEditor.js +8 -10
- package/dist/components/jamlMap/JokerPicker.d.ts +1 -2
- package/dist/components/jamlMap/JokerPicker.js +3 -7
- package/dist/components/jamlMap/MysterySlot.js +0 -15
- package/dist/hooks/searchWorker.d.ts +1 -29
- package/dist/hooks/searchWorker.js +8 -6
- package/dist/hooks/useIntersectionObserver.js +5 -3
- package/dist/hooks/useSearch.js +5 -1
- package/dist/hooks/useShopStream.js +5 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/cardParser.d.ts +1 -1
- package/dist/lib/cardParser.js +19 -17
- package/dist/lib/classes/BuyMetaData.d.ts +2 -2
- package/dist/lib/const.d.ts +22 -13
- package/dist/lib/data/constants.js +10 -9
- package/dist/lib/hooks/useJamlFilter.js +5 -5
- package/dist/lib/hooks/useSeedAnalyzer.js +7 -1
- package/dist/lib/jaml/jamlSchema.d.ts +18 -3
- package/dist/lib/jaml/jamlSchema.js +2 -2
- package/dist/lib/parseDailyRitual.d.ts +1 -1
- package/dist/lib/parseDailyRitual.js +2 -1
- package/dist/r3f/Card3D.js +2 -0
- package/dist/r3f/JimboBillboard.d.ts +1 -1
- package/dist/r3f/JimboBillboard.js +5 -2
- package/dist/ui/JimboInputModal.js +8 -2
- package/dist/ui/PanelSplitter.js +4 -2
- package/dist/ui/hooks.js +14 -5
- package/dist/ui/ide/JamlEditor.js +53 -63
- package/dist/ui/jimbo.css +70 -16
- package/dist/ui/jimboTooltip.js +12 -6
- package/dist/ui/panel.d.ts +1 -2
- package/dist/ui/panel.js +2 -2
- package/dist/ui/radial/RadialButton.js +1 -1
- package/dist/ui/showcase.js +1 -1
- package/dist/utils/jamlMapPreview.js +2 -1
- package/dist/utils/jamlVisualFilter.js +3 -2
- package/package.json +12 -6
package/dist/r3f/Card3D.js
CHANGED
|
@@ -4,7 +4,9 @@ import { useRef, useMemo, useState, memo } from 'react';
|
|
|
4
4
|
import { useFrame, useLoader } from '@react-three/fiber';
|
|
5
5
|
import { useSpring, animated } from '@react-spring/three';
|
|
6
6
|
import * as THREE from 'three';
|
|
7
|
+
// eslint-disable-next-line react-refresh/only-export-components
|
|
7
8
|
export const CARD_DIMENSIONS = { WIDTH: 0.7, HEIGHT: 0.95, DEPTH: 0.02 };
|
|
9
|
+
// eslint-disable-next-line react-refresh/only-export-components
|
|
8
10
|
export const CARD_MAGNET = {
|
|
9
11
|
MAX_TILT_X: 0.36,
|
|
10
12
|
MAX_TILT_Y: 0.42,
|
|
@@ -7,4 +7,4 @@ export interface JimboBillboardProps {
|
|
|
7
7
|
yLockOnly?: boolean;
|
|
8
8
|
position?: [number, number, number];
|
|
9
9
|
}
|
|
10
|
-
export declare function JimboBillboard(
|
|
10
|
+
export declare function JimboBillboard(props: JimboBillboardProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -3,9 +3,12 @@ import { useMemo } from 'react';
|
|
|
3
3
|
import { Billboard } from '@react-three/drei';
|
|
4
4
|
import { useLoader } from '@react-three/fiber';
|
|
5
5
|
import * as THREE from 'three';
|
|
6
|
-
export function JimboBillboard(
|
|
7
|
-
if (!sprite)
|
|
6
|
+
export function JimboBillboard(props) {
|
|
7
|
+
if (!props.sprite)
|
|
8
8
|
return null;
|
|
9
|
+
return _jsx(JimboBillboardInner, { ...props, sprite: props.sprite });
|
|
10
|
+
}
|
|
11
|
+
function JimboBillboardInner({ sprite, width = 3.4, height = 4.5, yLockOnly = false, position = [0, 0, 0] }) {
|
|
9
12
|
// Memoize texture to avoid per-render allocation
|
|
10
13
|
const texture = useLoader(THREE.TextureLoader, sprite.atlasPath);
|
|
11
14
|
const clonedTexture = useMemo(() => {
|
|
@@ -11,14 +11,20 @@ export function JimboInputModal({ open, title, message, placeholder, initialValu
|
|
|
11
11
|
const [value, setValue] = useState(initialValue);
|
|
12
12
|
const [error, setError] = useState(null);
|
|
13
13
|
const inputRef = useRef(null);
|
|
14
|
-
|
|
14
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
15
|
+
if (open !== prevOpen) {
|
|
16
|
+
setPrevOpen(open);
|
|
15
17
|
if (open) {
|
|
16
18
|
setValue(initialValue);
|
|
17
19
|
setError(null);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (open) {
|
|
18
24
|
const t = setTimeout(() => inputRef.current?.focus(), 30);
|
|
19
25
|
return () => clearTimeout(t);
|
|
20
26
|
}
|
|
21
|
-
}, [open
|
|
27
|
+
}, [open]);
|
|
22
28
|
function submit() {
|
|
23
29
|
const err = validate?.(value) ?? null;
|
|
24
30
|
if (err) {
|
package/dist/ui/PanelSplitter.js
CHANGED
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
"use client";
|
|
4
4
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
5
|
import { JimboColorOption } from "./tokens.js";
|
|
6
|
-
import { useCallback, useEffect, useRef } from "react";
|
|
6
|
+
import { useCallback, useEffect, useRef, useLayoutEffect } from "react";
|
|
7
7
|
const C = JimboColorOption;
|
|
8
8
|
export function PanelSplitter({ orientation = "vertical", onDrag, onKeyAdjust, "aria-label": ariaLabel, }) {
|
|
9
9
|
const draggingRef = useRef(false);
|
|
10
10
|
const lastRef = useRef(0);
|
|
11
11
|
const onDragRef = useRef(onDrag);
|
|
12
|
-
|
|
12
|
+
useLayoutEffect(() => {
|
|
13
|
+
onDragRef.current = onDrag;
|
|
14
|
+
});
|
|
13
15
|
const handlePointerDown = useCallback((e) => {
|
|
14
16
|
e.preventDefault();
|
|
15
17
|
e.target.setPointerCapture(e.pointerId);
|
package/dist/ui/hooks.js
CHANGED
|
@@ -66,14 +66,22 @@ export function useSway(active) {
|
|
|
66
66
|
export function useDelayedVisibility(open, delay) {
|
|
67
67
|
const [visible, setVisible] = useState(open);
|
|
68
68
|
const [opacity, setOpacity] = useState(open ? 1 : 0);
|
|
69
|
-
|
|
69
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
70
|
+
if (open !== prevOpen) {
|
|
71
|
+
setPrevOpen(open);
|
|
70
72
|
if (open) {
|
|
71
73
|
setVisible(true);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
setOpacity(0);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (open) {
|
|
72
81
|
const frame = requestAnimationFrame(() => setOpacity(1));
|
|
73
82
|
return () => cancelAnimationFrame(frame);
|
|
74
83
|
}
|
|
75
84
|
else {
|
|
76
|
-
setOpacity(0);
|
|
77
85
|
const t = setTimeout(() => setVisible(false), delay);
|
|
78
86
|
return () => clearTimeout(t);
|
|
79
87
|
}
|
|
@@ -436,14 +444,15 @@ export function useJamlCardRenderer({ layers, invert = false, hoverTilt = false,
|
|
|
436
444
|
*/
|
|
437
445
|
export function useAnteTracker(antes, options = {}) {
|
|
438
446
|
const [currentAnte, setCurrentAnte] = useState(antes[0]?.ante ?? 0);
|
|
447
|
+
const [prevFirstAnte, setPrevFirstAnte] = useState(antes[0]?.ante);
|
|
439
448
|
const scrollRef = useRef(null);
|
|
440
449
|
const anteRefs = useRef(new Map());
|
|
441
|
-
|
|
442
|
-
|
|
450
|
+
if (antes[0]?.ante !== prevFirstAnte) {
|
|
451
|
+
setPrevFirstAnte(antes[0]?.ante);
|
|
443
452
|
if (antes.length > 0) {
|
|
444
453
|
setCurrentAnte(antes[0].ante);
|
|
445
454
|
}
|
|
446
|
-
}
|
|
455
|
+
}
|
|
447
456
|
useEffect(() => {
|
|
448
457
|
const root = scrollRef.current;
|
|
449
458
|
if (!root || antes.length === 0)
|
|
@@ -48,7 +48,7 @@ function SuggestionList({ suggestions, selectedIndex, onSelect, onHover }) {
|
|
|
48
48
|
`, children: [_jsx("span", { children: s.displayText }), isSelected && _jsx("span", { className: "opacity-50 text-[11px] ml-2", children: "\u21B5" })] }, `${s.text}-${idx}`));
|
|
49
49
|
}) }));
|
|
50
50
|
}
|
|
51
|
-
function AntesToggle({ values, onToggle,
|
|
51
|
+
function AntesToggle({ values, onToggle, color }) {
|
|
52
52
|
const [expanded, setExpanded] = useState(false);
|
|
53
53
|
const maxAnte = 8;
|
|
54
54
|
const selectedAntes = new Set(values.map(v => parseInt(v, 10)).filter(n => !isNaN(n)));
|
|
@@ -128,7 +128,6 @@ export default function JamlEditor({ initialJaml, onJamlChange, className }) {
|
|
|
128
128
|
const [editingLineId, setEditingLineId] = useState(null);
|
|
129
129
|
const [editingPart, setEditingPart] = useState(null);
|
|
130
130
|
const [editingArrayIndex, setEditingArrayIndex] = useState(null);
|
|
131
|
-
const [focusedLineIndex, setFocusedLineIndex] = useState(0);
|
|
132
131
|
const editorRef = useRef(null);
|
|
133
132
|
// -- Parsing Logic --
|
|
134
133
|
const parseJamlToLines = useCallback((text) => {
|
|
@@ -183,14 +182,14 @@ export default function JamlEditor({ initialJaml, onJamlChange, className }) {
|
|
|
183
182
|
});
|
|
184
183
|
}, []);
|
|
185
184
|
const linesToJaml = useCallback((linesList) => linesList.map(l => l.raw).join('\n'), []);
|
|
186
|
-
|
|
185
|
+
const [prevInitialJaml, setPrevInitialJaml] = useState(initialJaml);
|
|
186
|
+
if (initialJaml !== prevInitialJaml) {
|
|
187
|
+
setPrevInitialJaml(initialJaml);
|
|
187
188
|
const text = initialJaml || DEFAULT_JAML;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
setLines(parseJamlToLines(text));
|
|
193
|
-
}, [initialJaml, parseJamlToLines, lines, linesToJaml]);
|
|
189
|
+
if (lines.length === 0 || linesToJaml(lines) !== text) {
|
|
190
|
+
setLines(parseJamlToLines(text));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
194
193
|
const updateLineValue = useCallback((lineId, part, newValue) => {
|
|
195
194
|
const newLines = lines.map(line => {
|
|
196
195
|
if (line.id !== lineId)
|
|
@@ -291,28 +290,6 @@ export default function JamlEditor({ initialJaml, onJamlChange, className }) {
|
|
|
291
290
|
}
|
|
292
291
|
}
|
|
293
292
|
}, [lines, linesToJaml, onJamlChange]);
|
|
294
|
-
const addLineAfter = useCallback((afterLineId, content) => {
|
|
295
|
-
const index = lines.findIndex(l => l.id === afterLineId);
|
|
296
|
-
if (index === -1)
|
|
297
|
-
return;
|
|
298
|
-
const currentLine = lines[index];
|
|
299
|
-
const newLineRaw = ' '.repeat(currentLine.indent) + content;
|
|
300
|
-
const newParsed = parseJamlToLines(newLineRaw)[0];
|
|
301
|
-
const newLine = { ...newParsed, id: `line-new-${Date.now()}`, clauseType: currentLine.clauseType };
|
|
302
|
-
const newLines = [...lines];
|
|
303
|
-
newLines.splice(index + 1, 0, newLine);
|
|
304
|
-
const renumbered = newLines.map((l, i) => ({ ...l, lineNumber: i, id: `line-${i}` })); // simplified ID update
|
|
305
|
-
setLines(renumbered);
|
|
306
|
-
const txt = linesToJaml(renumbered);
|
|
307
|
-
if (onJamlChange) {
|
|
308
|
-
try {
|
|
309
|
-
onJamlChange(txt, yaml.load(txt), true);
|
|
310
|
-
}
|
|
311
|
-
catch {
|
|
312
|
-
onJamlChange(txt, null, false);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}, [lines, linesToJaml, onJamlChange, parseJamlToLines]);
|
|
316
293
|
const deleteLine = useCallback((lineId) => {
|
|
317
294
|
const filtered = lines.filter(l => l.id !== lineId);
|
|
318
295
|
const renumbered = filtered.map((l, i) => ({ ...l, lineNumber: i, id: `line-${i}` }));
|
|
@@ -338,22 +315,57 @@ export default function JamlEditor({ initialJaml, onJamlChange, className }) {
|
|
|
338
315
|
}
|
|
339
316
|
return byIndent;
|
|
340
317
|
}, [lines]);
|
|
341
|
-
return (_jsxs("div", { ref: editorRef, className: `flex flex-col bg-[#0f1416] text-white font-mono text-[13px] leading-[1.8] outline-none rounded-md p-4 overflow-auto min-h-[500px] border border-white/5 ${className}`, tabIndex: 0, children: [_jsx("div", { className: "flex flex-col gap-0.5", children: lines.map((line
|
|
318
|
+
return (_jsxs("div", { ref: editorRef, className: `flex flex-col bg-[#0f1416] text-white font-mono text-[13px] leading-[1.8] outline-none rounded-md p-4 overflow-auto min-h-[500px] border border-white/5 ${className}`, tabIndex: 0, children: [_jsx("div", { className: "flex flex-col gap-0.5", children: lines.map((line) => (_jsx(JamlLine, { line: line, keyWidth: maxKeyLengthByIndent[line.indent] || 8, isEditing: editingLineId === line.id, editingPart: editingLineId === line.id ? editingPart : null, editingArrayIndex: editingLineId === line.id ? editingArrayIndex : null, onStartEdit: (part, idx) => {
|
|
342
319
|
setEditingLineId(line.id);
|
|
343
320
|
setEditingPart(part);
|
|
344
321
|
setEditingArrayIndex(idx ?? null);
|
|
345
|
-
setFocusedLineIndex(index);
|
|
346
322
|
}, onEndEdit: () => {
|
|
347
323
|
setEditingLineId(null);
|
|
348
324
|
setEditingPart(null);
|
|
349
325
|
setEditingArrayIndex(null);
|
|
350
|
-
}, onChange: (part, val) => updateLineValue(line.id, part, val), onArrayItemChange: (idx, val) => updateArrayItem(line.id, idx, val), onArrayItemAdd: (val) => addArrayItem(line.id, val), onArrayItemRemove: (idx) => removeArrayItem(line.id, idx), onDelete: () => deleteLine(line.id)
|
|
326
|
+
}, onChange: (part, val) => updateLineValue(line.id, part, val), onArrayItemChange: (idx, val) => updateArrayItem(line.id, idx, val), onArrayItemAdd: (val) => addArrayItem(line.id, val), onArrayItemRemove: (idx) => removeArrayItem(line.id, idx), onDelete: () => deleteLine(line.id) }, line.id))) }), _jsxs("div", { className: "mt-4 p-2 bg-black/40 rounded border border-white/5 flex flex-wrap gap-4 text-[12px] text-white/50 font-mono", children: [_jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "jaml-legend-dot jaml-legend-dot--red" }), " required"] }), _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "jaml-legend-dot jaml-legend-dot--blue" }), " optional"] }), _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "jaml-legend-dot jaml-legend-dot--green" }), " complete"] }), _jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "jaml-legend-dot jaml-legend-dot--purple" }), " metadata"] }), _jsx("span", { className: "ml-auto opacity-40", children: "Click to edit \u2022 Tab to navigate" })] })] }));
|
|
351
327
|
}
|
|
352
|
-
function JamlLine({ line, keyWidth, isEditing, editingPart, editingArrayIndex, onStartEdit, onEndEdit, onChange, onArrayItemChange, onArrayItemAdd, onArrayItemRemove, onDelete
|
|
353
|
-
const [, setHovered] = useState(false);
|
|
354
|
-
const [suggestions, setSuggestions] = useState([]);
|
|
328
|
+
function JamlLine({ line, keyWidth, isEditing, editingPart, editingArrayIndex, onStartEdit, onEndEdit, onChange, onArrayItemChange, onArrayItemAdd, onArrayItemRemove, onDelete }) {
|
|
355
329
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
356
330
|
const [localValue, setLocalValue] = useState('');
|
|
331
|
+
const [prevContext, setPrevContext] = useState('');
|
|
332
|
+
const [prevEditState, setPrevEditState] = useState({ isEditing, editingPart, editingArrayIndex, lineRaw: line.raw });
|
|
333
|
+
if (isEditing !== prevEditState.isEditing ||
|
|
334
|
+
editingPart !== prevEditState.editingPart ||
|
|
335
|
+
editingArrayIndex !== prevEditState.editingArrayIndex ||
|
|
336
|
+
line.raw !== prevEditState.lineRaw) {
|
|
337
|
+
setPrevEditState({ isEditing, editingPart, editingArrayIndex, lineRaw: line.raw });
|
|
338
|
+
if (isEditing) {
|
|
339
|
+
if (editingPart === 'key')
|
|
340
|
+
setLocalValue(line.key || '');
|
|
341
|
+
else if (editingPart === 'value')
|
|
342
|
+
setLocalValue((line.value || '').replace(/^~|~$/g, ''));
|
|
343
|
+
else if (editingPart === 'arrayItem' && editingArrayIndex !== null)
|
|
344
|
+
setLocalValue(line.arrayValues?.[editingArrayIndex] || '');
|
|
345
|
+
else
|
|
346
|
+
setLocalValue('');
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const currentContext = useMemo(() => {
|
|
350
|
+
if (!isEditing || !editingPart)
|
|
351
|
+
return '';
|
|
352
|
+
if (editingPart === 'value' && line.key) {
|
|
353
|
+
return `${line.key}: ${localValue}`;
|
|
354
|
+
}
|
|
355
|
+
else if (editingPart === 'key') {
|
|
356
|
+
return localValue;
|
|
357
|
+
}
|
|
358
|
+
return line.raw;
|
|
359
|
+
}, [isEditing, editingPart, localValue, line.raw, line.key]);
|
|
360
|
+
const suggestions = useMemo(() => {
|
|
361
|
+
if (!currentContext)
|
|
362
|
+
return [];
|
|
363
|
+
return JamlCompletionService.getCompletions(currentContext).slice(0, 10);
|
|
364
|
+
}, [currentContext]);
|
|
365
|
+
if (currentContext !== prevContext) {
|
|
366
|
+
setPrevContext(currentContext);
|
|
367
|
+
setSelectedIndex(0);
|
|
368
|
+
}
|
|
357
369
|
const inputRef = useRef(null);
|
|
358
370
|
const targetRef = useRef(null);
|
|
359
371
|
const floatingCoords = useFloatingPosition(targetRef, isEditing && suggestions.length > 0);
|
|
@@ -378,35 +390,13 @@ function JamlLine({ line, keyWidth, isEditing, editingPart, editingArrayIndex, o
|
|
|
378
390
|
default: return '#FFF';
|
|
379
391
|
}
|
|
380
392
|
};
|
|
381
|
-
// Suggestions Logic
|
|
382
|
-
useEffect(() => {
|
|
383
|
-
if (isEditing && editingPart) {
|
|
384
|
-
let textContext = line.raw;
|
|
385
|
-
if (editingPart === 'value' && line.key) {
|
|
386
|
-
textContext = `${line.key}: ${localValue}`;
|
|
387
|
-
}
|
|
388
|
-
else if (editingPart === 'key') {
|
|
389
|
-
textContext = localValue;
|
|
390
|
-
}
|
|
391
|
-
const sugs = JamlCompletionService.getCompletions(textContext);
|
|
392
|
-
setSuggestions(sugs.slice(0, 10));
|
|
393
|
-
setSelectedIndex(0);
|
|
394
|
-
}
|
|
395
|
-
}, [isEditing, editingPart, localValue, line.raw, line.key]);
|
|
393
|
+
// Suggestions Logic derived above
|
|
396
394
|
// Input Focus
|
|
397
395
|
useEffect(() => {
|
|
398
396
|
if (isEditing && inputRef.current) {
|
|
399
397
|
inputRef.current.focus();
|
|
400
|
-
if (editingPart === 'key')
|
|
401
|
-
setLocalValue(line.key || '');
|
|
402
|
-
else if (editingPart === 'value')
|
|
403
|
-
setLocalValue((line.value || '').replace(/^~|~$/g, ''));
|
|
404
|
-
else if (editingPart === 'arrayItem' && editingArrayIndex !== null)
|
|
405
|
-
setLocalValue(line.arrayValues?.[editingArrayIndex] || '');
|
|
406
|
-
else
|
|
407
|
-
setLocalValue('');
|
|
408
398
|
}
|
|
409
|
-
}, [isEditing
|
|
399
|
+
}, [isEditing]);
|
|
410
400
|
const handleKeyDown = (e) => {
|
|
411
401
|
if (e.key === 'Enter') {
|
|
412
402
|
e.preventDefault();
|
|
@@ -457,7 +447,7 @@ function JamlLine({ line, keyWidth, isEditing, editingPart, editingArrayIndex, o
|
|
|
457
447
|
'--popover-left': `${floatingCoords.left}px`,
|
|
458
448
|
'--popover-transform': floatingCoords.position === 'top' ? 'translateY(-100%)' : 'none',
|
|
459
449
|
} : {};
|
|
460
|
-
return (_jsxs("div", { className: "relative flex items-center py-0.5 group",
|
|
450
|
+
return (_jsxs("div", { className: "relative flex items-center py-0.5 group", children: [_jsx("div", { className: "w-6 h-full flex items-center justify-center cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity", onClick: (e) => { e.stopPropagation(); onDelete(); }, children: _jsx(Minus, { size: 12, className: "text-orange-500 hover:bg-orange-100 rounded" }) }), _jsxs("span", { className: "whitespace-pre text-stone-400", children: [indentSpaces, prefix] }), line.key && (_jsxs("div", { className: "relative", children: [_jsx("div", { ref: editingPart === 'key' ? targetRef : null, onClick: (e) => { e.stopPropagation(); onStartEdit('key'); }, className: "jaml-block jaml-block--start", style: {
|
|
461
451
|
'--jaml-min-w': `${keyWidth}ch`,
|
|
462
452
|
'--jaml-color': (isEditing && editingPart === 'key') ? getBrightColor() : getBaseColor(),
|
|
463
453
|
'--jaml-bg': (isEditing && editingPart === 'key') ? `${getBrightColor()}15` : 'transparent',
|
|
@@ -470,7 +460,7 @@ function JamlLine({ line, keyWidth, isEditing, editingPart, editingArrayIndex, o
|
|
|
470
460
|
onArrayItemRemove(idx);
|
|
471
461
|
else
|
|
472
462
|
onArrayItemAdd(val);
|
|
473
|
-
},
|
|
463
|
+
}, color: getBrightColor() })) : (_jsxs("div", { className: "flex gap-0.5 items-center", children: [line.arrayValues.map((val, idx) => (_jsx("div", { onClick: (e) => { e.stopPropagation(); onStartEdit('arrayItem', idx); }, className: "jaml-block", style: {
|
|
474
464
|
'--jaml-min-w': '24px',
|
|
475
465
|
'--jaml-bg': `${getBaseColor()}15`,
|
|
476
466
|
'--jaml-border': `1px solid ${getBaseColor()}40`,
|
package/dist/ui/jimbo.css
CHANGED
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
Eyedropped from actual game shader output — not Lua hex values.
|
|
5
5
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
6
6
|
|
|
7
|
+
@font-face {
|
|
8
|
+
font-family: 'm6x11plus';
|
|
9
|
+
src: url('/fonts/m6x11plus.otf') format('opentype');
|
|
10
|
+
font-weight: normal;
|
|
11
|
+
font-style: normal;
|
|
12
|
+
font-display: swap;
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
/* Global Scrollbar Hide */
|
|
8
16
|
* {
|
|
9
17
|
scrollbar-width: none !important;
|
|
@@ -433,9 +441,12 @@
|
|
|
433
441
|
gap: var(--j-space-sm);
|
|
434
442
|
align-items: flex-end;
|
|
435
443
|
justify-content: center;
|
|
436
|
-
flex-wrap:
|
|
444
|
+
flex-wrap: nowrap;
|
|
437
445
|
width: 100%;
|
|
446
|
+
overflow-x: auto;
|
|
447
|
+
scrollbar-width: none;
|
|
438
448
|
}
|
|
449
|
+
.j-tabs::-webkit-scrollbar { display: none; }
|
|
439
450
|
|
|
440
451
|
.j-tab {
|
|
441
452
|
display: flex;
|
|
@@ -459,7 +470,7 @@
|
|
|
459
470
|
}
|
|
460
471
|
|
|
461
472
|
.j-tab__indicator[data-active="true"] {
|
|
462
|
-
animation: jimbo-bounce 0.
|
|
473
|
+
animation: jimbo-bounce 0.6s ease-in-out infinite;
|
|
463
474
|
}
|
|
464
475
|
|
|
465
476
|
.j-tab__indicator[data-active="false"] {
|
|
@@ -496,9 +507,6 @@
|
|
|
496
507
|
filter: brightness(1.08);
|
|
497
508
|
}
|
|
498
509
|
|
|
499
|
-
.j-tab__btn[data-active="false"] {
|
|
500
|
-
opacity: 0.82;
|
|
501
|
-
}
|
|
502
510
|
|
|
503
511
|
@keyframes jimbo-bounce {
|
|
504
512
|
|
|
@@ -600,11 +608,50 @@
|
|
|
600
608
|
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.8);
|
|
601
609
|
color: var(--j-white);
|
|
602
610
|
pointer-events: none;
|
|
603
|
-
z-index:
|
|
611
|
+
z-index: 9999;
|
|
604
612
|
transition: opacity 120ms ease;
|
|
605
613
|
}
|
|
606
614
|
|
|
607
615
|
|
|
616
|
+
|
|
617
|
+
/* ── Layout Utilities ─────────────────────────────────────────────────── */
|
|
618
|
+
|
|
619
|
+
.j-flex {
|
|
620
|
+
display: flex;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.j-flex-col {
|
|
624
|
+
display: flex;
|
|
625
|
+
flex-direction: column;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.j-items-center {
|
|
629
|
+
align-items: center;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.j-items-start {
|
|
633
|
+
align-items: flex-start;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.j-justify-center {
|
|
637
|
+
justify-content: center;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.j-justify-between {
|
|
641
|
+
justify-content: space-between;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
.j-gap-xs { gap: var(--j-space-xs); }
|
|
645
|
+
.j-gap-sm { gap: var(--j-space-sm); }
|
|
646
|
+
.j-gap-md { gap: var(--j-space-md); }
|
|
647
|
+
.j-gap-lg { gap: var(--j-space-lg); }
|
|
648
|
+
|
|
649
|
+
.j-w-full { width: 100%; }
|
|
650
|
+
.j-h-full { height: 100%; }
|
|
651
|
+
|
|
652
|
+
.j-text-center { text-align: center; }
|
|
653
|
+
|
|
654
|
+
|
|
608
655
|
/* ── Flank Nav ────────────────────────────────────────────────────────── */
|
|
609
656
|
|
|
610
657
|
.j-flank {
|
|
@@ -902,24 +949,31 @@
|
|
|
902
949
|
|
|
903
950
|
/* ── Modal ────────────────────────────────────────────────────────────── */
|
|
904
951
|
|
|
952
|
+
@keyframes jimbo-modal-in {
|
|
953
|
+
from { transform: scale(0.88); opacity: 0; }
|
|
954
|
+
to { transform: scale(1); opacity: 1; }
|
|
955
|
+
}
|
|
956
|
+
|
|
905
957
|
.j-modal-overlay {
|
|
906
|
-
position:
|
|
958
|
+
position: absolute;
|
|
907
959
|
inset: 0;
|
|
908
|
-
z-index:
|
|
960
|
+
z-index: 1000;
|
|
909
961
|
display: flex;
|
|
910
962
|
align-items: center;
|
|
911
963
|
justify-content: center;
|
|
912
|
-
padding: var(--j-space-
|
|
913
|
-
background: rgba(0, 0, 0, 0.
|
|
964
|
+
padding: var(--j-space-md);
|
|
965
|
+
background: rgba(0, 0, 0, 0.82);
|
|
914
966
|
}
|
|
915
967
|
|
|
916
968
|
.j-modal {
|
|
917
969
|
width: 100%;
|
|
918
|
-
max-width:
|
|
919
|
-
max-height:
|
|
970
|
+
max-width: 345px;
|
|
971
|
+
max-height: calc(100% - 32px);
|
|
920
972
|
display: flex;
|
|
921
973
|
flex-direction: column;
|
|
922
974
|
overflow: hidden;
|
|
975
|
+
border-radius: 12px;
|
|
976
|
+
animation: jimbo-modal-in 140ms cubic-bezier(0.2, 0, 0.2, 1.4) both;
|
|
923
977
|
}
|
|
924
978
|
|
|
925
979
|
.j-modal .j-panel__body {
|
|
@@ -1154,10 +1208,10 @@
|
|
|
1154
1208
|
.j-app {
|
|
1155
1209
|
container-type: inline-size;
|
|
1156
1210
|
container-name: jimbo;
|
|
1157
|
-
width:
|
|
1158
|
-
max-width:
|
|
1159
|
-
height:
|
|
1160
|
-
max-height:
|
|
1211
|
+
width: 375px;
|
|
1212
|
+
max-width: 375px;
|
|
1213
|
+
height: 667px;
|
|
1214
|
+
max-height: 667px;
|
|
1161
1215
|
margin: 0 auto;
|
|
1162
1216
|
display: flex;
|
|
1163
1217
|
flex-direction: column;
|
package/dist/ui/jimboTooltip.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { useCallback } from 'react';
|
|
3
3
|
import { useJimboTooltip } from './hooks.js';
|
|
4
|
+
function assignRef(ref, value) {
|
|
5
|
+
if (typeof ref === 'function')
|
|
6
|
+
ref(value);
|
|
7
|
+
else if (ref && typeof ref === 'object') {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
ref.current = value;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
4
12
|
/**
|
|
5
13
|
* Canonical Balatro-style tooltip: dark panel, silver border, pixel font.
|
|
6
14
|
* Wrap any target to get a hover/focus popover.
|
|
@@ -8,14 +16,12 @@ import { useJimboTooltip } from './hooks.js';
|
|
|
8
16
|
export function JimboTooltip({ content, children, mode = 'snap', placement = 'auto', delay = 80, maxWidth = 280, disabled = false, }) {
|
|
9
17
|
const { visible, pos, targetRef, tooltipRef, show, hide, handleMouseMove, } = useJimboTooltip({ mode, placement, delay, disabled });
|
|
10
18
|
const child = React.Children.only(children);
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
const childRef = child.ref;
|
|
11
21
|
const refHandler = useCallback((node) => {
|
|
12
22
|
targetRef.current = node;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
childRef(node);
|
|
16
|
-
else if (childRef && 'current' in childRef)
|
|
17
|
-
childRef.current = node;
|
|
18
|
-
}, [child, targetRef]);
|
|
23
|
+
assignRef(childRef, node);
|
|
24
|
+
}, [childRef, targetRef]);
|
|
19
25
|
const wrapped = React.cloneElement(child, {
|
|
20
26
|
ref: refHandler,
|
|
21
27
|
onMouseEnter: (e) => { show(); child.props.onMouseEnter?.(e); },
|
package/dist/ui/panel.d.ts
CHANGED
|
@@ -5,8 +5,7 @@ export interface JimboPanelProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
5
5
|
hideBack?: boolean;
|
|
6
6
|
}
|
|
7
7
|
export declare const JimboPanel: React.MemoExoticComponent<({ children, className, sway, onBack, hideBack, style, ...props }: JimboPanelProps) => import("react/jsx-runtime").JSX.Element>;
|
|
8
|
-
export
|
|
9
|
-
}
|
|
8
|
+
export type JimboInnerPanelProps = React.HTMLAttributes<HTMLDivElement>;
|
|
10
9
|
export declare const JimboInnerPanel: React.MemoExoticComponent<({ children, className, style, ...props }: JimboInnerPanelProps) => import("react/jsx-runtime").JSX.Element>;
|
|
11
10
|
export type JimboTone = 'orange' | 'red' | 'blue' | 'green' | 'tarot' | 'planet' | 'spectral' | 'grey';
|
|
12
11
|
export interface JimboButtonProps {
|
package/dist/ui/panel.js
CHANGED
|
@@ -17,8 +17,8 @@ export function JimboButton({ tone = 'orange', size = 'md', fullWidth = false, d
|
|
|
17
17
|
export function JimboBackButton({ onClick }) {
|
|
18
18
|
return (_jsx("div", { className: "j-flex j-justify-center j-w-full", style: { padding: '4px 0' }, children: _jsx(JimboButton, { tone: "orange", size: "md", fullWidth: true, onClick: onClick, className: "j-back-btn", children: "Back" }) }));
|
|
19
19
|
}
|
|
20
|
-
export function JimboModal({ children, open, onClose, title, className, showBack =
|
|
20
|
+
export function JimboModal({ children, open, onClose, title, className, showBack = true }) {
|
|
21
21
|
if (!open)
|
|
22
22
|
return null;
|
|
23
|
-
return (_jsx("div", { className: "j-modal-overlay",
|
|
23
|
+
return (_jsx("div", { className: "j-modal-overlay", children: _jsxs(JimboPanel, { onBack: showBack ? onClose : undefined, className: `j-modal ${className ?? ''}`, children: [title && _jsx(JimboText, { as: "h2", size: "lg", className: "j-modal__title", children: title }), children] }) }));
|
|
24
24
|
}
|
|
@@ -66,7 +66,7 @@ export function RadialButton(props) {
|
|
|
66
66
|
}, children: [variant === "toggle" && _jsx(ToggleDot, { active: props.active, disabled: isDisabled }), _jsx("span", { className: "jimbo-radial-label jimbo-radial-label--action", children: label }), variant === "count" && _jsx(CountBadge, { count: props.count, icon: props.icon })] }));
|
|
67
67
|
}
|
|
68
68
|
// ── Internal sub-components ───────────────────────────────────────────────────
|
|
69
|
-
function ToggleDot({ active
|
|
69
|
+
function ToggleDot({ active }) {
|
|
70
70
|
const dotStyle = active
|
|
71
71
|
? { backgroundColor: JimboColorOption.GREEN_TEXT, borderColor: JimboColorOption.BORDER_SILVER }
|
|
72
72
|
: { backgroundColor: JimboColorOption.DARK_RED, borderColor: JimboColorOption.DARK_GREY };
|
package/dist/ui/showcase.js
CHANGED
|
@@ -16,5 +16,5 @@ export function Showcase({ title = 'Balatro', subtitle = 'Seed Curator', hotFilt
|
|
|
16
16
|
padding: '3px 8px',
|
|
17
17
|
background: 'var(--j-dark-grey)', borderRadius: 4,
|
|
18
18
|
border: '1px solid var(--j-panel-edge)',
|
|
19
|
-
}, children: [_jsx(JimboText, { size: "micro", tone: "purple", children: mcpInfo.engine }), _jsx(JimboText, { size: "micro", tone: "grey", children: mcpInfo.features })] })), hotFilters.length > 0 && (_jsxs(_Fragment, { children: [_jsx(JimboSectionHeader, { label: "Filters", tone: "blue" }), _jsx("div", { className: "j-flex-col", style: { gap: 4 }, children: hotFilters.slice(0, 4).map((f, i) => (_jsxs(JimboInfoCard, { tone: f.tone, onClick: () => onFilterClick?.(f, i), style: { cursor: onFilterClick ? 'pointer' : undefined }, children: [_jsx("div", { className: "j-flex j-gap-xs", children: f.sample.slice(0, 2).map((name, j) => (_jsx("div", { style: { width: 22, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: _jsx(JimboSprite, { name: name, width: 20 }) }, j))) }), _jsxs(JimboInfoCardBody, { children: [_jsx(JimboInfoCardTitle, { children: f.name }), _jsxs(JimboInfoCardSub, { children: ["by ", f.author] })] }), _jsx(JimboInfoCardAside, { children: _jsx(JimboText, { size: "xs", tone: f.tone === 'gold' ? 'gold' : f.tone, children: f.hits }) })] }, i))) })] })), recentFinds.length > 0 && (_jsxs(_Fragment, { children: [_jsx(JimboSectionHeader, { label: "Recent", tone: "green" }), _jsx("div", { style: { lineHeight: 1.5 }, children: recentFinds.slice(0, 3).map((r, i) => (_jsxs("div", { className: "j-flex j-gap-sm", children: [_jsx(JimboText, { size: "micro", tone: "gold", children: r.seed }), _jsx(JimboText, { size: "micro", tone: "grey", children: r.filterName }), r.score > 0 && _jsxs(JimboText, { size: "micro", tone: "green", children: ["+", r.score] })] }, i))) })] }))] }), _jsxs(JimboAppFooter, { children: [_jsx(JimboButton, { tone: "green", fullWidth: true, size: "lg", onClick: onNewSearch, children: "New Search" }), _jsx(JimboButton, { tone: "blue", fullWidth: true, size: "lg", onClick: onBrowseFilters, children: "Browse Filters" }), _jsx(JimboBalatroFooter, {})] })
|
|
19
|
+
}, children: [_jsx(JimboText, { size: "micro", tone: "purple", children: mcpInfo.engine }), _jsx(JimboText, { size: "micro", tone: "grey", children: mcpInfo.features })] })), hotFilters.length > 0 && (_jsxs(_Fragment, { children: [_jsx(JimboSectionHeader, { label: "Filters", tone: "blue" }), _jsx("div", { className: "j-flex-col", style: { gap: 4 }, children: hotFilters.slice(0, 4).map((f, i) => (_jsxs(JimboInfoCard, { tone: f.tone, onClick: () => onFilterClick?.(f, i), style: { cursor: onFilterClick ? 'pointer' : undefined }, children: [_jsx("div", { className: "j-flex j-gap-xs", children: f.sample.slice(0, 2).map((name, j) => (_jsx("div", { style: { width: 22, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: _jsx(JimboSprite, { name: name, width: 20 }) }, j))) }), _jsxs(JimboInfoCardBody, { children: [_jsx(JimboInfoCardTitle, { children: f.name }), _jsxs(JimboInfoCardSub, { children: ["by ", f.author] })] }), _jsx(JimboInfoCardAside, { children: _jsx(JimboText, { size: "xs", tone: f.tone === 'gold' ? 'gold' : f.tone, children: f.hits }) })] }, i))) })] })), recentFinds.length > 0 && (_jsxs(_Fragment, { children: [_jsx(JimboSectionHeader, { label: "Recent", tone: "green" }), _jsx("div", { style: { lineHeight: 1.5 }, children: recentFinds.slice(0, 3).map((r, i) => (_jsxs("div", { className: "j-flex j-gap-sm", children: [_jsx(JimboText, { size: "micro", tone: "gold", children: r.seed }), _jsx(JimboText, { size: "micro", tone: "grey", children: r.filterName }), r.score > 0 && _jsxs(JimboText, { size: "micro", tone: "green", children: ["+", r.score] })] }, i))) })] }))] }), _jsxs(JimboAppFooter, { children: [_jsx(JimboButton, { tone: "green", fullWidth: true, size: "lg", onClick: onNewSearch, children: "New Search" }), _jsx(JimboButton, { tone: "blue", fullWidth: true, size: "lg", onClick: onBrowseFilters, children: "Browse Filters" })] }), _jsx(JimboBalatroFooter, {})] }));
|
|
20
20
|
}
|
|
@@ -61,7 +61,8 @@ function parseInlineValues(raw) {
|
|
|
61
61
|
export function extractVisualJamlItems(jaml) {
|
|
62
62
|
const groups = createEmptyGroups();
|
|
63
63
|
const seen = new Set();
|
|
64
|
-
const
|
|
64
|
+
const safeJaml = jaml || "";
|
|
65
|
+
const lines = safeJaml.replace(/\r\n/g, "\n").split("\n");
|
|
65
66
|
let currentSection = null;
|
|
66
67
|
for (const rawLine of lines) {
|
|
67
68
|
const trimmed = rawLine.trim();
|
|
@@ -59,7 +59,8 @@ function uid() {
|
|
|
59
59
|
return `clause-${++_uid}`;
|
|
60
60
|
}
|
|
61
61
|
export function jamlTextToVisualFilter(text) {
|
|
62
|
-
const
|
|
62
|
+
const safeText = text || "";
|
|
63
|
+
const lines = safeText.replace(/\r\n/g, "\n").split("\n");
|
|
63
64
|
const filter = { must: [], should: [], mustnot: [] };
|
|
64
65
|
filter.name = topLevelScalar(lines, "name");
|
|
65
66
|
filter.author = topLevelScalar(lines, "author");
|
|
@@ -161,7 +162,7 @@ export function jamlTextToVisualFilter(text) {
|
|
|
161
162
|
function q(s) {
|
|
162
163
|
if (!s)
|
|
163
164
|
return "";
|
|
164
|
-
return /[
|
|
165
|
+
return /[:#[\]{}|>&*!,'"?]/.test(s) ? `"${s.replace(/"/g, '\\"')}"` : s;
|
|
165
166
|
}
|
|
166
167
|
function serializeClause(clause) {
|
|
167
168
|
let out = ` - ${clause.type}: ${q(clause.value)}\n`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jaml-ui",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.18",
|
|
4
4
|
"description": "Balatro rendering components, sprite metadata, and optional Motely helpers for React apps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -37,8 +37,7 @@
|
|
|
37
37
|
"default": "./dist/r3f.js"
|
|
38
38
|
},
|
|
39
39
|
"./jimbo.css": "./dist/ui/jimbo.css",
|
|
40
|
-
"./fonts.css": "./fonts.css"
|
|
41
|
-
"./jaml.schema.json": "./jaml.schema.json"
|
|
40
|
+
"./fonts.css": "./fonts.css"
|
|
42
41
|
},
|
|
43
42
|
"sideEffects": [
|
|
44
43
|
"./fonts.css",
|
|
@@ -58,7 +57,7 @@
|
|
|
58
57
|
"LICENSE"
|
|
59
58
|
],
|
|
60
59
|
"scripts": {
|
|
61
|
-
"build": "tsc --pretty false && node -e \"const fs=require('fs');fs.mkdirSync('dist/ui',{recursive:true});fs.copyFileSync('src/ui/jimbo.css','dist/ui/jimbo.css')
|
|
60
|
+
"build": "tsc --pretty false && node -e \"const fs=require('fs');fs.mkdirSync('dist/ui',{recursive:true});fs.copyFileSync('src/ui/jimbo.css','dist/ui/jimbo.css');\"",
|
|
62
61
|
"dev": "tsc --watch",
|
|
63
62
|
"demo": "vite --config demo/vite.config.ts",
|
|
64
63
|
"typecheck": "tsc --noEmit --pretty false",
|
|
@@ -96,7 +95,7 @@
|
|
|
96
95
|
"@react-spring/three": ">=9.0.0",
|
|
97
96
|
"@react-three/drei": ">=9.0.0",
|
|
98
97
|
"@react-three/fiber": ">=8.0.0",
|
|
99
|
-
"motely-wasm": "^15.1.
|
|
98
|
+
"motely-wasm": "^15.1.3",
|
|
100
99
|
"react": "^18.2.0 || ^19.0.0",
|
|
101
100
|
"react-dom": "^18.2.0 || ^19.0.0",
|
|
102
101
|
"react-icons": ">=5.0.0",
|
|
@@ -124,6 +123,7 @@
|
|
|
124
123
|
},
|
|
125
124
|
"devDependencies": {
|
|
126
125
|
"@chromatic-com/storybook": "^5.1.2",
|
|
126
|
+
"@eslint/js": "^10.0.1",
|
|
127
127
|
"@google/design.md": "^0.1.1",
|
|
128
128
|
"@react-spring/three": "^10.0.3",
|
|
129
129
|
"@react-three/drei": ">=9.0.0",
|
|
@@ -140,7 +140,11 @@
|
|
|
140
140
|
"@vitejs/plugin-react": "^5.0.4",
|
|
141
141
|
"@vitest/browser-playwright": "^4.1.5",
|
|
142
142
|
"@vitest/coverage-v8": "^4.1.5",
|
|
143
|
-
"
|
|
143
|
+
"eslint": "^10.3.0",
|
|
144
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
145
|
+
"eslint-plugin-react-refresh": "^0.5.2",
|
|
146
|
+
"globals": "^17.6.0",
|
|
147
|
+
"motely-wasm": "^15.1.3",
|
|
144
148
|
"playwright": "^1.59.1",
|
|
145
149
|
"react": "^19.2.4",
|
|
146
150
|
"react-dom": "^19.2.4",
|
|
@@ -148,10 +152,12 @@
|
|
|
148
152
|
"storybook": "^10.3.6",
|
|
149
153
|
"three": "^0.184.0",
|
|
150
154
|
"typescript": "^5.9.3",
|
|
155
|
+
"typescript-eslint": "^8.59.2",
|
|
151
156
|
"vite": "^8.0.9",
|
|
152
157
|
"vitest": "^4.1.5"
|
|
153
158
|
},
|
|
154
159
|
"dependencies": {
|
|
160
|
+
"@codemirror/autocomplete": "^6.20.1",
|
|
155
161
|
"@codemirror/commands": "^6.10.3",
|
|
156
162
|
"@codemirror/lang-yaml": "^6.1.3",
|
|
157
163
|
"@codemirror/language": "^6.12.3",
|