castle-web-cli 0.4.119 → 0.4.120
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/api.js +13 -2
- package/dist/castle-host/host.d.ts +16 -0
- package/dist/castle-host/host.js +249 -11
- package/dist/castle-host/leaderboardPanel.d.ts +73 -0
- package/dist/castle-host/leaderboardPanel.js +714 -0
- package/dist/ide.d.ts +2 -0
- package/dist/ide.js +35 -0
- package/dist/index.js +1 -6
- package/dist/preview.d.ts +0 -1
- package/dist/preview.js +18 -23
- package/dist/save-deck.js +33 -2
- package/dist/serve.js +9 -4
- package/dist/shell/assets/index-BkJ87APM.css +1 -0
- package/dist/shell/assets/index-Cxmq9Sed.js +434 -0
- package/dist/shell/index.html +2 -2
- package/kits/physics-2d/CLAUDE.md +8 -4
- package/kits/physics-2d/castle.json +1 -1
- package/kits/physics-2d/editors/SceneEditor.jsx +11 -2
- package/kits/physics-2d/editors/pixelInspector.jsx +30 -9
- package/kits/physics-2d/editors/pxArtTimeline.jsx +147 -18
- package/kits/physics-2d/engine/ui.module.css +1 -0
- package/package.json +1 -1
- package/dist/shell/assets/index-WtgFx1s8.js +0 -144
- package/dist/shell/assets/index-Y6cJRRCX.css +0 -1
package/dist/shell/index.html
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
<link rel="icon" type="image/png" sizes="32x32" href="/__castle/ide/favicon-32x32.png" />
|
|
11
11
|
<link rel="icon" type="image/png" sizes="16x16" href="/__castle/ide/favicon-16x16.png" />
|
|
12
12
|
<link rel="icon" href="/__castle/ide/favicon.ico" sizes="any" />
|
|
13
|
-
<script type="module" crossorigin src="/__castle/ide/assets/index-
|
|
14
|
-
<link rel="stylesheet" crossorigin href="/__castle/ide/assets/index-
|
|
13
|
+
<script type="module" crossorigin src="/__castle/ide/assets/index-Cxmq9Sed.js"></script>
|
|
14
|
+
<link rel="stylesheet" crossorigin href="/__castle/ide/assets/index-BkJ87APM.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
17
17
|
<div id="root"></div>
|
|
@@ -192,10 +192,14 @@ make it move.**
|
|
|
192
192
|
(`mode`, `width`/`height`, `offsetX`/`offsetY`, `debug`) it has:
|
|
193
193
|
- `shape: 'box' | 'circle'` — the physics shape (default `box`). A circle uses
|
|
194
194
|
`radius`, or half the smaller collider dimension if `radius` is 0.
|
|
195
|
-
- A collider can hold **multiple shapes** (a compound body) — edit them
|
|
196
|
-
inspector's shape list.
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
- A collider can hold **multiple shapes** (a compound body) — add and edit them
|
|
196
|
+
in the inspector's shape list. Each entry in `shapes` is `{ type, ... }` sized
|
|
197
|
+
in **fractions of the Layout box** (`0.5` = centered, `1` = full width), so a
|
|
198
|
+
shape keeps its proportions when the actor is resized: a box takes
|
|
199
|
+
`x`/`y`/`w`/`h`, a circle `x`/`y`/`r`.
|
|
200
|
+
- A **box shape takes an `angle`** (degrees), so one actor can have an angled
|
|
201
|
+
collider (e.g. a skateboard: a flat deck box plus an upturned nose and tail
|
|
202
|
+
box) instead of gluing separate actors together.
|
|
199
203
|
- `isTrigger` — a **sensor**: detects overlaps (fires collision callbacks) but
|
|
200
204
|
does **not** block. Use for pickups, goals, zones.
|
|
201
205
|
- `bounciness` — restitution, 0 (dead) to ~1 (very bouncy), can exceed 1.
|
|
@@ -442,8 +442,16 @@ export function SceneEditor({
|
|
|
442
442
|
sceneData,
|
|
443
443
|
files
|
|
444
444
|
);
|
|
445
|
-
|
|
446
|
-
|
|
445
|
+
// Add both generated files to the live map before committing the instance.
|
|
446
|
+
// Otherwise another + click can mint the same numbered paths while the fs
|
|
447
|
+
// watcher's asynchronous echo of these direct writes is still pending.
|
|
448
|
+
if (onChangeFile) {
|
|
449
|
+
onChangeFile(drawingFile.path, drawingFile.text);
|
|
450
|
+
onChangeFile(blueprintFile.path, blueprintFile.text);
|
|
451
|
+
} else {
|
|
452
|
+
void writeFile(drawingFile.path, drawingFile.text);
|
|
453
|
+
void writeFile(blueprintFile.path, blueprintFile.text);
|
|
454
|
+
}
|
|
447
455
|
history.commit(serialize(next));
|
|
448
456
|
onSelectActorIds([newId]);
|
|
449
457
|
};
|
|
@@ -1675,6 +1683,7 @@ function BlueprintInspector({
|
|
|
1675
1683
|
selectedActor={templateActor}
|
|
1676
1684
|
rawActor={templateActor}
|
|
1677
1685
|
files={files}
|
|
1686
|
+
sprites={sprites}
|
|
1678
1687
|
onSetComponent={(actorId, behaviorName, nextProps) => onSetComponent(behaviorName, nextProps)}
|
|
1679
1688
|
onAddBehavior={(actorId, behaviorName) => onAddBehavior(behaviorName)}
|
|
1680
1689
|
onRemoveBehavior={(actorId, behaviorName) => onRemoveBehavior(behaviorName)}
|
|
@@ -271,15 +271,36 @@ export function PalettePopover({ open, anchorRef, onClose, children }) {
|
|
|
271
271
|
|
|
272
272
|
useLayoutEffect(() => {
|
|
273
273
|
if (!open || !anchorRef.current) return;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
274
|
+
|
|
275
|
+
function positionPopover() {
|
|
276
|
+
const anchor = anchorRef.current.getBoundingClientRect();
|
|
277
|
+
const rect = popoverRef.current?.getBoundingClientRect();
|
|
278
|
+
const margin = 8;
|
|
279
|
+
const width = rect?.width ?? 280;
|
|
280
|
+
const height = rect?.height ?? 320;
|
|
281
|
+
const maxLeft = Math.max(margin, window.innerWidth - width - margin);
|
|
282
|
+
const maxTop = Math.max(margin, window.innerHeight - height - margin);
|
|
283
|
+
const leftSide = anchor.left - width - margin;
|
|
284
|
+
const rightSide = anchor.right + margin;
|
|
285
|
+
// Prefer the side with room, then clamp a too-wide picker inside this
|
|
286
|
+
// iframe rather than sending it beyond either viewport edge.
|
|
287
|
+
const left =
|
|
288
|
+
leftSide >= margin
|
|
289
|
+
? leftSide
|
|
290
|
+
: rightSide <= maxLeft
|
|
291
|
+
? rightSide
|
|
292
|
+
: Math.min(maxLeft, Math.max(margin, anchor.left + anchor.width / 2 - width / 2));
|
|
293
|
+
const top = Math.min(maxTop, Math.max(margin, anchor.top));
|
|
294
|
+
setPosition({ top, left });
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
positionPopover();
|
|
298
|
+
window.addEventListener('resize', positionPopover);
|
|
299
|
+
window.addEventListener('scroll', positionPopover, true);
|
|
300
|
+
return () => {
|
|
301
|
+
window.removeEventListener('resize', positionPopover);
|
|
302
|
+
window.removeEventListener('scroll', positionPopover, true);
|
|
303
|
+
};
|
|
283
304
|
}, [open, anchorRef]);
|
|
284
305
|
|
|
285
306
|
useEffect(() => {
|
|
@@ -31,6 +31,8 @@ const SHOW_PER_FRAME_DURATION = false;
|
|
|
31
31
|
// re-renders the count input, so this is a trivial, easily-revertible toggle.
|
|
32
32
|
const SHOW_ONION_RANGE = false;
|
|
33
33
|
const ONION_RANGE = 1;
|
|
34
|
+
const TIMELINE_LONG_PRESS_MS = 500;
|
|
35
|
+
const TIMELINE_LONG_PRESS_MOVE_TOLERANCE = 10;
|
|
34
36
|
|
|
35
37
|
// faClapperboard ships in Font Awesome 6, but this kit is pinned to FA5 (see
|
|
36
38
|
// package.json), which doesn't export it. Rather than silently swap in a
|
|
@@ -328,26 +330,58 @@ function TimelineGrid({ sprite, text, selection, actions }) {
|
|
|
328
330
|
const [convertConfirm, setConvertConfirm] = useState(null);
|
|
329
331
|
const closeMenu = useCallback(() => setMenu(null), []);
|
|
330
332
|
|
|
331
|
-
//
|
|
332
|
-
//
|
|
333
|
-
//
|
|
333
|
+
// A timeline entity is selected independently by its relevant axis: a layer
|
|
334
|
+
// by layer index, a frame by frame index, and a cel by the complete pair.
|
|
335
|
+
// First tap selects; a second tap on that same entity opens its action menu.
|
|
336
|
+
// A touch long-press always selects its target and opens the same menu.
|
|
337
|
+
const selectTarget = useCallback(
|
|
338
|
+
(target) => {
|
|
339
|
+
if (target.kind === 'layer') actions.selectCell(target.layerIndex, selection.frameIndex);
|
|
340
|
+
else if (target.kind === 'frame') actions.selectCell(selection.layerIndex, target.frameIndex);
|
|
341
|
+
else actions.selectCell(target.layerIndex, target.frameIndex);
|
|
342
|
+
},
|
|
343
|
+
[actions, selection.frameIndex, selection.layerIndex]
|
|
344
|
+
);
|
|
345
|
+
const targetIsSelected = useCallback(
|
|
346
|
+
(target) => {
|
|
347
|
+
if (target.kind === 'layer') return selection.layerIndex === target.layerIndex;
|
|
348
|
+
if (target.kind === 'frame') return selection.frameIndex === target.frameIndex;
|
|
349
|
+
return selection.layerIndex === target.layerIndex && selection.frameIndex === target.frameIndex;
|
|
350
|
+
},
|
|
351
|
+
[selection.frameIndex, selection.layerIndex]
|
|
352
|
+
);
|
|
353
|
+
const openMenu = useCallback(
|
|
354
|
+
(target, event) => {
|
|
355
|
+
selectTarget(target);
|
|
356
|
+
const rect = event.currentTarget?.getBoundingClientRect?.();
|
|
357
|
+
const x = Number.isFinite(event.clientX) ? event.clientX : rect?.left + rect?.width / 2;
|
|
358
|
+
const y = Number.isFinite(event.clientY) ? event.clientY : rect?.top + rect?.height / 2;
|
|
359
|
+
setMenu({ ...target, x: x ?? 0, y: y ?? 0 });
|
|
360
|
+
},
|
|
361
|
+
[selectTarget]
|
|
362
|
+
);
|
|
363
|
+
const press = useTimelineItemPress(openMenu);
|
|
364
|
+
const activateTarget = (target, event) => {
|
|
365
|
+
if (isTimelineNestedControl(event) || press.consumeClick(target)) return;
|
|
366
|
+
if (targetIsSelected(target)) openMenu(target, event);
|
|
367
|
+
else selectTarget(target);
|
|
368
|
+
};
|
|
369
|
+
// Right-click keeps the desktop path and deliberately opens its target even
|
|
370
|
+
// when it was not already selected.
|
|
334
371
|
const openLayerMenu = (event, layerIndex) => {
|
|
335
372
|
event.preventDefault();
|
|
336
373
|
event.stopPropagation();
|
|
337
|
-
|
|
374
|
+
openMenu({ kind: 'layer', layerIndex }, event);
|
|
338
375
|
};
|
|
339
376
|
const openFrameMenu = (event, frameIndex) => {
|
|
340
377
|
event.preventDefault();
|
|
341
378
|
event.stopPropagation();
|
|
342
|
-
|
|
379
|
+
openMenu({ kind: 'frame', frameIndex }, event);
|
|
343
380
|
};
|
|
344
381
|
const openCellMenu = (event, layerIndex, frameIndex) => {
|
|
345
382
|
event.preventDefault();
|
|
346
383
|
event.stopPropagation();
|
|
347
|
-
|
|
348
|
-
// menu re-renders with rebuilt actions that target (layerIndex, frameIndex).
|
|
349
|
-
actions.selectCell(layerIndex, frameIndex);
|
|
350
|
-
setMenu({ kind: 'cell', x: event.clientX, y: event.clientY, layerIndex, frameIndex });
|
|
384
|
+
openMenu({ kind: 'cell', layerIndex, frameIndex }, event);
|
|
351
385
|
};
|
|
352
386
|
|
|
353
387
|
return (
|
|
@@ -361,7 +395,8 @@ function TimelineGrid({ sprite, text, selection, actions }) {
|
|
|
361
395
|
index={f}
|
|
362
396
|
globalMs={sprite.defaultDurationMs}
|
|
363
397
|
active={f === selection.frameIndex}
|
|
364
|
-
|
|
398
|
+
onActivate={(event) => activateTarget({ kind: 'frame', frameIndex: f }, event)}
|
|
399
|
+
onPointerDown={(event) => press.onPointerDown(event, { kind: 'frame', frameIndex: f })}
|
|
365
400
|
onDuration={(ms) => actions.setFrameDuration(f, ms)}
|
|
366
401
|
onContextMenu={(event) => openFrameMenu(event, f)}
|
|
367
402
|
/>
|
|
@@ -373,7 +408,8 @@ function TimelineGrid({ sprite, text, selection, actions }) {
|
|
|
373
408
|
layer={sprite.layers[li]}
|
|
374
409
|
index={li}
|
|
375
410
|
active={li === selection.layerIndex}
|
|
376
|
-
|
|
411
|
+
onActivate={(event) => activateTarget({ kind: 'layer', layerIndex: li }, event)}
|
|
412
|
+
onPointerDown={(event) => press.onPointerDown(event, { kind: 'layer', layerIndex: li })}
|
|
377
413
|
actions={actions}
|
|
378
414
|
onContextMenu={openLayerMenu}
|
|
379
415
|
/>
|
|
@@ -385,7 +421,8 @@ function TimelineGrid({ sprite, text, selection, actions }) {
|
|
|
385
421
|
layerIndex={li}
|
|
386
422
|
frameIndex={f}
|
|
387
423
|
active={li === selection.layerIndex && f === selection.frameIndex}
|
|
388
|
-
|
|
424
|
+
onActivate={(event) => activateTarget({ kind: 'cell', layerIndex: li, frameIndex: f }, event)}
|
|
425
|
+
onPointerDown={(event) => press.onPointerDown(event, { kind: 'cell', layerIndex: li, frameIndex: f })}
|
|
389
426
|
onContextMenu={(event) => openCellMenu(event, li, f)}
|
|
390
427
|
/>
|
|
391
428
|
))}
|
|
@@ -425,6 +462,93 @@ function TimelineGrid({ sprite, text, selection, actions }) {
|
|
|
425
462
|
);
|
|
426
463
|
}
|
|
427
464
|
|
|
465
|
+
function targetKey(target) {
|
|
466
|
+
if (target.kind === 'layer') return `layer:${target.layerIndex}`;
|
|
467
|
+
if (target.kind === 'frame') return `frame:${target.frameIndex}`;
|
|
468
|
+
return `cell:${target.layerIndex}:${target.frameIndex}`;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Form controls inside a selectable timeline header keep their direct behavior;
|
|
472
|
+
// pressing the layer visibility toggle or a duration input must not arm a menu.
|
|
473
|
+
function isTimelineNestedControl(event) {
|
|
474
|
+
if (!(event.target instanceof Element) || event.target === event.currentTarget) return false;
|
|
475
|
+
return Boolean(event.target.closest('input, select, textarea, [data-timeline-control]'));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Touch-only long press. Scroll intent cancels it after a small move threshold;
|
|
479
|
+
// the subsequent synthetic click is consumed after a successful hold so it
|
|
480
|
+
// doesn't immediately close/reopen the action menu.
|
|
481
|
+
function useTimelineItemPress(openMenu) {
|
|
482
|
+
const openMenuRef = useRef(openMenu);
|
|
483
|
+
const pressRef = useRef(null);
|
|
484
|
+
const suppressClickRef = useRef(null);
|
|
485
|
+
openMenuRef.current = openMenu;
|
|
486
|
+
|
|
487
|
+
useEffect(() => {
|
|
488
|
+
const clearPress = () => {
|
|
489
|
+
const press = pressRef.current;
|
|
490
|
+
if (!press) return null;
|
|
491
|
+
window.clearTimeout(press.timer);
|
|
492
|
+
pressRef.current = null;
|
|
493
|
+
return press;
|
|
494
|
+
};
|
|
495
|
+
const onPointerMove = (event) => {
|
|
496
|
+
const press = pressRef.current;
|
|
497
|
+
if (!press || press.pointerId !== event.pointerId || press.opened) return;
|
|
498
|
+
if (Math.hypot(event.clientX - press.startX, event.clientY - press.startY) <= TIMELINE_LONG_PRESS_MOVE_TOLERANCE) return;
|
|
499
|
+
clearPress();
|
|
500
|
+
};
|
|
501
|
+
const onPointerEnd = (event) => {
|
|
502
|
+
const press = pressRef.current;
|
|
503
|
+
if (!press || press.pointerId !== event.pointerId) return;
|
|
504
|
+
const ended = clearPress();
|
|
505
|
+
if (ended?.opened) suppressClickRef.current = targetKey(ended.target);
|
|
506
|
+
};
|
|
507
|
+
window.addEventListener('pointermove', onPointerMove);
|
|
508
|
+
window.addEventListener('pointerup', onPointerEnd);
|
|
509
|
+
window.addEventListener('pointercancel', onPointerEnd);
|
|
510
|
+
return () => {
|
|
511
|
+
clearPress();
|
|
512
|
+
window.removeEventListener('pointermove', onPointerMove);
|
|
513
|
+
window.removeEventListener('pointerup', onPointerEnd);
|
|
514
|
+
window.removeEventListener('pointercancel', onPointerEnd);
|
|
515
|
+
};
|
|
516
|
+
}, []);
|
|
517
|
+
|
|
518
|
+
const onPointerDown = useCallback((event, target) => {
|
|
519
|
+
if (event.pointerType !== 'touch' || event.button !== 0 || isTimelineNestedControl(event)) return;
|
|
520
|
+
const prior = pressRef.current;
|
|
521
|
+
if (prior) window.clearTimeout(prior.timer);
|
|
522
|
+
const menuEvent = {
|
|
523
|
+
clientX: event.clientX,
|
|
524
|
+
clientY: event.clientY,
|
|
525
|
+
currentTarget: event.currentTarget,
|
|
526
|
+
};
|
|
527
|
+
const press = {
|
|
528
|
+
pointerId: event.pointerId,
|
|
529
|
+
target,
|
|
530
|
+
startX: event.clientX,
|
|
531
|
+
startY: event.clientY,
|
|
532
|
+
opened: false,
|
|
533
|
+
timer: 0,
|
|
534
|
+
};
|
|
535
|
+
press.timer = window.setTimeout(() => {
|
|
536
|
+
if (pressRef.current !== press) return;
|
|
537
|
+
press.opened = true;
|
|
538
|
+
openMenuRef.current(target, menuEvent);
|
|
539
|
+
}, TIMELINE_LONG_PRESS_MS);
|
|
540
|
+
pressRef.current = press;
|
|
541
|
+
}, []);
|
|
542
|
+
|
|
543
|
+
const consumeClick = useCallback((target) => {
|
|
544
|
+
if (suppressClickRef.current !== targetKey(target)) return false;
|
|
545
|
+
suppressClickRef.current = null;
|
|
546
|
+
return true;
|
|
547
|
+
}, []);
|
|
548
|
+
|
|
549
|
+
return { onPointerDown, consumeClick };
|
|
550
|
+
}
|
|
551
|
+
|
|
428
552
|
// Cursor-anchored right-click menu. Reuses the scene editor's "Arrange" menu
|
|
429
553
|
// chrome (the shared `selArrangeMenu`/`selArrangeItem` classes from
|
|
430
554
|
// engine/ui.module.css) for visual consistency, switching to fixed positioning
|
|
@@ -588,12 +712,14 @@ function cellMenuItems(menu, sprite, actions) {
|
|
|
588
712
|
];
|
|
589
713
|
}
|
|
590
714
|
|
|
591
|
-
function FrameHeader({ frame, index, globalMs, active,
|
|
715
|
+
function FrameHeader({ frame, index, globalMs, active, onActivate, onPointerDown, onDuration, onContextMenu }) {
|
|
592
716
|
return (
|
|
593
717
|
<div
|
|
594
718
|
className={active ? tl.frameHead + ' ' + tl.frameHeadActive : tl.frameHead}
|
|
719
|
+
onPointerDown={onPointerDown}
|
|
720
|
+
onClick={onActivate}
|
|
595
721
|
onContextMenu={onContextMenu}>
|
|
596
|
-
<button type="button" className={tl.frameNum}
|
|
722
|
+
<button type="button" className={tl.frameNum} style={btnReset}>
|
|
597
723
|
{index + 1}
|
|
598
724
|
</button>
|
|
599
725
|
{SHOW_PER_FRAME_DURATION ? (
|
|
@@ -681,11 +807,12 @@ function FaGlyph({ icon, className = tl.visGlyph }) {
|
|
|
681
807
|
);
|
|
682
808
|
}
|
|
683
809
|
|
|
684
|
-
function LayerHeader({ layer, index, active,
|
|
810
|
+
function LayerHeader({ layer, index, active, onActivate, onPointerDown, actions, onContextMenu }) {
|
|
685
811
|
return (
|
|
686
812
|
<div
|
|
687
813
|
className={active ? tl.layerHead + ' ' + tl.layerHeadActive : tl.layerHead}
|
|
688
|
-
|
|
814
|
+
onPointerDown={onPointerDown}
|
|
815
|
+
onClick={onActivate}
|
|
689
816
|
onContextMenu={(event) => onContextMenu(event, index)}>
|
|
690
817
|
<div className={tl.layerTopRow}>
|
|
691
818
|
<span
|
|
@@ -710,6 +837,7 @@ function LayerHeader({ layer, index, active, onSelect, actions, onContextMenu })
|
|
|
710
837
|
/>
|
|
711
838
|
<button
|
|
712
839
|
type="button"
|
|
840
|
+
data-timeline-control
|
|
713
841
|
className={layer.visible ? tl.visBtn : tl.visBtn + ' ' + tl.visOff}
|
|
714
842
|
title={layer.visible ? 'Hide layer' : 'Show layer'}
|
|
715
843
|
onClick={(event) => {
|
|
@@ -723,7 +851,7 @@ function LayerHeader({ layer, index, active, onSelect, actions, onContextMenu })
|
|
|
723
851
|
);
|
|
724
852
|
}
|
|
725
853
|
|
|
726
|
-
function CellThumb({ sprite, text, layerIndex, frameIndex, active,
|
|
854
|
+
function CellThumb({ sprite, text, layerIndex, frameIndex, active, onActivate, onPointerDown, onContextMenu }) {
|
|
727
855
|
const canvasRef = useRef(null);
|
|
728
856
|
const layer = sprite.layers[layerIndex];
|
|
729
857
|
const kind = cellKind(layer, frameIndex);
|
|
@@ -743,7 +871,8 @@ function CellThumb({ sprite, text, layerIndex, frameIndex, active, onSelect, onC
|
|
|
743
871
|
type="button"
|
|
744
872
|
className={active ? tl.cell + ' ' + tl.cellActive : tl.cell}
|
|
745
873
|
title={`Layer ${layerIndex + 1}, frame ${frameIndex + 1} (${kind})`}
|
|
746
|
-
|
|
874
|
+
onPointerDown={onPointerDown}
|
|
875
|
+
onClick={onActivate}
|
|
747
876
|
onContextMenu={onContextMenu}>
|
|
748
877
|
{kind === 'empty' ? (
|
|
749
878
|
<span className={tl.empty} />
|
|
@@ -1797,6 +1797,7 @@
|
|
|
1797
1797
|
z-index: 200;
|
|
1798
1798
|
width: min(280px, calc(100vw - 16px));
|
|
1799
1799
|
max-height: min(420px, calc(100vh - 16px));
|
|
1800
|
+
box-sizing: border-box;
|
|
1800
1801
|
overflow: auto;
|
|
1801
1802
|
padding: 12px 14px 14px;
|
|
1802
1803
|
border: 1px solid var(--castle-inspector-border);
|