@dfosco/storyboard-core 3.2.0 → 3.3.1
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/storyboard-ui.css +1 -0
- package/dist/storyboard-ui.js +26304 -0
- package/dist/storyboard-ui.js.map +1 -0
- package/dist/tailwind.css +1 -1
- package/package.json +24 -18
- package/scaffold/manifest.json +35 -0
- package/scaffold/scripts/link.sh +26 -0
- package/scaffold/scripts/unlink.sh +10 -0
- package/scaffold/skills/create/SKILL.md +501 -0
- package/scaffold/skills/storyboard/SKILL.md +360 -0
- package/scaffold/skills/update-storyboard/SKILL.md +16 -0
- package/scaffold/skills/update-storyboard/update-storyboard-packages.sh +26 -0
- package/scaffold/skills/vitest/GENERATION.md +5 -0
- package/scaffold/skills/vitest/SKILL.md +52 -0
- package/scaffold/skills/vitest/references/advanced-environments.md +264 -0
- package/scaffold/skills/vitest/references/advanced-projects.md +300 -0
- package/scaffold/skills/vitest/references/advanced-type-testing.md +237 -0
- package/scaffold/skills/vitest/references/advanced-vi.md +249 -0
- package/scaffold/skills/vitest/references/core-cli.md +166 -0
- package/scaffold/skills/vitest/references/core-config.md +174 -0
- package/scaffold/skills/vitest/references/core-describe.md +193 -0
- package/scaffold/skills/vitest/references/core-expect.md +219 -0
- package/scaffold/skills/vitest/references/core-hooks.md +244 -0
- package/scaffold/skills/vitest/references/core-test-api.md +233 -0
- package/scaffold/skills/vitest/references/features-concurrency.md +250 -0
- package/scaffold/skills/vitest/references/features-context.md +238 -0
- package/scaffold/skills/vitest/references/features-coverage.md +207 -0
- package/scaffold/skills/vitest/references/features-filtering.md +211 -0
- package/scaffold/skills/vitest/references/features-mocking.md +265 -0
- package/scaffold/skills/vitest/references/features-snapshots.md +207 -0
- package/scaffold/skills/worktree/SKILL.md +51 -0
- package/scaffold/storyboard.config.json +26 -0
- package/scaffold/svelte.config.js +1 -0
- package/scaffold/toolbar.config.json +4 -0
- package/src/ActionMenuButton.svelte +1 -1
- package/src/CanvasCreateMenu.svelte +1 -1
- package/src/CoreUIBar.svelte +23 -12
- package/src/CreateMenuButton.svelte +1 -1
- package/src/InspectorPanel.svelte +144 -49
- package/src/SidePanel.svelte +10 -10
- package/src/commandActions.js +1 -1
- package/src/comments/index.js +0 -3
- package/src/devtools-consumer.js +28 -0
- package/src/devtools.js +4 -1
- package/src/index.js +8 -3
- package/src/inspector/highlighter.js +28 -17
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +1 -1
- package/src/lib/components/ui/trigger-button/trigger-button.svelte +8 -4
- package/src/mountStoryboardCore.js +223 -0
- package/src/scaffold.js +100 -0
- package/src/stores/themeStore.ts +29 -8
- package/src/styles/tailwind.css +16 -0
- package/src/svelte-plugin-ui/components/Viewfinder.svelte +18 -0
- package/src/ui-entry.js +30 -0
- package/src/vite/server-plugin.js +8 -24
- package/src/workshop/features/createCanvas/CreateCanvasForm.svelte +24 -6
- package/src/workshop/features/createFlow/CreateFlowForm.svelte +1 -1
- package/src/workshop/features/createFlow/index.js +0 -1
- package/src/workshop/features/createPrototype/CreatePrototypeForm.svelte +1 -1
- package/src/workshop/features/createPrototype/index.js +0 -1
- /package/{core-ui.config.json → toolbar.config.json} +0 -0
|
@@ -28,6 +28,59 @@
|
|
|
28
28
|
/** @type {Element | null} — the currently selected DOM element */
|
|
29
29
|
let selectedElement = $state(null)
|
|
30
30
|
|
|
31
|
+
// ── URL state helpers ─────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build a CSS selector that can re-find `el` later.
|
|
35
|
+
* Prefers id, then data-testid, then an nth-child path from <body>.
|
|
36
|
+
*/
|
|
37
|
+
function generateSelector(el) {
|
|
38
|
+
if (!(el instanceof Element)) return null
|
|
39
|
+
if (el.id) return `#${CSS.escape(el.id)}`
|
|
40
|
+
|
|
41
|
+
const testId = el.getAttribute('data-testid')
|
|
42
|
+
if (testId) return `[data-testid="${CSS.escape(testId)}"]`
|
|
43
|
+
|
|
44
|
+
const parts = []
|
|
45
|
+
let cur = el
|
|
46
|
+
while (cur && cur !== document.body && cur !== document.documentElement) {
|
|
47
|
+
let seg = cur.tagName.toLowerCase()
|
|
48
|
+
if (cur.id) {
|
|
49
|
+
parts.unshift(`#${CSS.escape(cur.id)}`)
|
|
50
|
+
break
|
|
51
|
+
}
|
|
52
|
+
const parent = cur.parentElement
|
|
53
|
+
if (parent) {
|
|
54
|
+
const siblings = Array.from(parent.children)
|
|
55
|
+
const idx = siblings.indexOf(cur) + 1
|
|
56
|
+
seg += `:nth-child(${idx})`
|
|
57
|
+
}
|
|
58
|
+
parts.unshift(seg)
|
|
59
|
+
cur = parent
|
|
60
|
+
}
|
|
61
|
+
return parts.length ? parts.join(' > ') : null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Read the `inspect` search param from the current URL. */
|
|
65
|
+
function getInspectParam() {
|
|
66
|
+
try {
|
|
67
|
+
return new URL(window.location.href).searchParams.get('inspect')
|
|
68
|
+
} catch { return null }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Set or clear the `inspect` search param without triggering navigation. */
|
|
72
|
+
function setInspectParam(selector) {
|
|
73
|
+
try {
|
|
74
|
+
const url = new URL(window.location.href)
|
|
75
|
+
if (selector) {
|
|
76
|
+
url.searchParams.set('inspect', selector)
|
|
77
|
+
} else {
|
|
78
|
+
url.searchParams.delete('inspect')
|
|
79
|
+
}
|
|
80
|
+
history.replaceState(history.state, '', url.toString())
|
|
81
|
+
} catch {}
|
|
82
|
+
}
|
|
83
|
+
|
|
31
84
|
/** @type {string[]} */
|
|
32
85
|
let knownFiles = []
|
|
33
86
|
|
|
@@ -44,7 +97,10 @@
|
|
|
44
97
|
async function loadStaticData() {
|
|
45
98
|
if (staticInspectorData) return staticInspectorData
|
|
46
99
|
try {
|
|
47
|
-
|
|
100
|
+
// Use window.location to derive base path at runtime, since
|
|
101
|
+
// import.meta.env.BASE_URL is baked at compile time in the UI bundle
|
|
102
|
+
const basePath = window.__STORYBOARD_BASE_PATH__ || '/'
|
|
103
|
+
const res = await fetch(`${basePath}_storyboard/inspector.json`)
|
|
48
104
|
if (res.ok) {
|
|
49
105
|
staticInspectorData = await res.json()
|
|
50
106
|
return staticInspectorData
|
|
@@ -55,12 +111,19 @@
|
|
|
55
111
|
|
|
56
112
|
/**
|
|
57
113
|
* Fetch source file content — uses dev middleware in dev, static JSON in prod.
|
|
114
|
+
* Uses runtime detection (not import.meta.env.DEV) so this works in the
|
|
115
|
+
* pre-compiled UI bundle where compile-time env vars are baked in.
|
|
58
116
|
*/
|
|
59
117
|
async function fetchSourceContent(filePath) {
|
|
60
|
-
|
|
118
|
+
// Try the dev middleware first — works when Vite server plugin is active
|
|
119
|
+
try {
|
|
61
120
|
const res = await fetch(`/_storyboard/docs/source?path=${encodeURIComponent(filePath)}`)
|
|
62
|
-
|
|
63
|
-
|
|
121
|
+
if (res.ok) {
|
|
122
|
+
const json = await res.json()
|
|
123
|
+
return json?.content || ''
|
|
124
|
+
}
|
|
125
|
+
} catch {}
|
|
126
|
+
// Fall back to static inspector JSON for deployed/production builds
|
|
64
127
|
const data = await loadStaticData()
|
|
65
128
|
return data?.sources?.[filePath] || ''
|
|
66
129
|
}
|
|
@@ -322,6 +385,8 @@
|
|
|
322
385
|
inspecting = false
|
|
323
386
|
// Show persistent highlight on the selected element
|
|
324
387
|
mouseMode?.showHighlight(el)
|
|
388
|
+
// Persist selection to URL
|
|
389
|
+
setInspectParam(generateSelector(el))
|
|
325
390
|
}
|
|
326
391
|
|
|
327
392
|
function handleDeactivate() {
|
|
@@ -333,6 +398,8 @@
|
|
|
333
398
|
mouseMode?.hideHighlight()
|
|
334
399
|
mouseMode?.activate()
|
|
335
400
|
inspecting = true
|
|
401
|
+
// Clear URL param while re-selecting
|
|
402
|
+
setInspectParam(null)
|
|
336
403
|
}
|
|
337
404
|
|
|
338
405
|
function stopInspecting() {
|
|
@@ -360,38 +427,62 @@
|
|
|
360
427
|
onDeactivate: handleDeactivate,
|
|
361
428
|
})
|
|
362
429
|
|
|
363
|
-
//
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
]
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
// Production: load from static build-time JSON
|
|
430
|
+
// Pre-fetch file list and repo info FIRST (needed for source resolution)
|
|
431
|
+
// Try dev middleware first, fall back to static JSON
|
|
432
|
+
let filesLoaded = false
|
|
433
|
+
try {
|
|
434
|
+
const [filesRes, repoRes] = await Promise.all([
|
|
435
|
+
fetch('/_storyboard/docs/files'),
|
|
436
|
+
fetch('/_storyboard/docs/repo'),
|
|
437
|
+
])
|
|
438
|
+
if (filesRes.ok) {
|
|
439
|
+
const data = await filesRes.json()
|
|
440
|
+
knownFiles = data.files || []
|
|
441
|
+
filesLoaded = true
|
|
442
|
+
}
|
|
443
|
+
if (repoRes.ok) {
|
|
444
|
+
repoInfo = await repoRes.json()
|
|
445
|
+
}
|
|
446
|
+
} catch {}
|
|
447
|
+
|
|
448
|
+
if (!filesLoaded) {
|
|
449
|
+
// Fall back to static build-time JSON
|
|
384
450
|
const data = await loadStaticData()
|
|
385
451
|
if (data) {
|
|
386
452
|
knownFiles = data.files || []
|
|
387
453
|
repoInfo = data.repo || null
|
|
388
454
|
}
|
|
389
455
|
}
|
|
456
|
+
|
|
457
|
+
// Restore inspector selection from URL param (after files are loaded)
|
|
458
|
+
const savedSelector = getInspectParam()
|
|
459
|
+
let restored = false
|
|
460
|
+
if (savedSelector) {
|
|
461
|
+
// Retry with delay — the React page may still be rendering
|
|
462
|
+
for (let attempt = 0; attempt < 5 && !restored; attempt++) {
|
|
463
|
+
if (attempt > 0) await new Promise(r => setTimeout(r, 300))
|
|
464
|
+
try {
|
|
465
|
+
const el = document.querySelector(savedSelector)
|
|
466
|
+
if (el) {
|
|
467
|
+
handleSelect(el)
|
|
468
|
+
restored = true
|
|
469
|
+
}
|
|
470
|
+
} catch {
|
|
471
|
+
break // invalid selector, don't retry
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (!restored) setInspectParam(null)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (!restored) {
|
|
478
|
+
startInspecting()
|
|
479
|
+
}
|
|
390
480
|
})
|
|
391
481
|
|
|
392
482
|
onDestroy(() => {
|
|
393
483
|
mouseMode?.deactivate()
|
|
394
484
|
mouseMode?.hideHighlight()
|
|
485
|
+
setInspectParam(null)
|
|
395
486
|
})
|
|
396
487
|
</script>
|
|
397
488
|
|
|
@@ -433,7 +524,7 @@
|
|
|
433
524
|
class="mt-2 px-4 py-1.5 text-xs font-medium rounded-md border cursor-pointer transition-colors"
|
|
434
525
|
style:background="transparent"
|
|
435
526
|
style:color="var(--fgColor-muted)"
|
|
436
|
-
style:border-color="var(--borderColor-default)"
|
|
527
|
+
style:border-color="var(--borderColor-default, var(--color-border, #d1d9e0))"
|
|
437
528
|
onclick={stopInspecting}
|
|
438
529
|
>
|
|
439
530
|
Cancel
|
|
@@ -442,29 +533,19 @@
|
|
|
442
533
|
|
|
443
534
|
<!-- Selected state -->
|
|
444
535
|
{:else}
|
|
445
|
-
<div class="flex flex-col flex-1 min-h-0 p-3 gap-3">
|
|
536
|
+
<div class="flex flex-col flex-1 min-h-0 p-3 pt-0 gap-3">
|
|
446
537
|
<!-- Component name -->
|
|
447
538
|
<div>
|
|
448
539
|
<h3 class="text-base font-bold m-0 inspector-mono" style:color="var(--color-purple, #7655a4)">
|
|
449
540
|
{componentInfo.name}
|
|
450
541
|
</h3>
|
|
451
|
-
|
|
452
|
-
<!-- Source file -->
|
|
453
|
-
{#if sourcePath}
|
|
454
|
-
<p class="inline-flex items-center gap-1 mt-1 text-xs m-0 inspector-mono" style:color="var(--fgColor-muted)">
|
|
455
|
-
<Icon name="primer/file-code" size={12} />
|
|
456
|
-
{sourcePath}
|
|
457
|
-
</p>
|
|
458
|
-
{/if}
|
|
459
542
|
</div>
|
|
460
543
|
|
|
461
544
|
<!-- Source code -->
|
|
462
545
|
{#if sourcePath}
|
|
463
|
-
<div class="border rounded-md overflow-hidden flex-1 min-h-0 flex flex-col" style:border-color="var(--borderColor-default)">
|
|
546
|
+
<div class="border rounded-md overflow-hidden flex-1 min-h-0 flex flex-col inspector-code-block" style:border-color="var(--borderColor-default, var(--color-border, #d1d9e0))">
|
|
464
547
|
<div
|
|
465
|
-
class="flex items-center justify-between w-full px-3 py-1.5 text-xs font-semibold shrink-0"
|
|
466
|
-
style:background="var(--bgColor-default)"
|
|
467
|
-
style:color="var(--fgColor-muted)"
|
|
548
|
+
class="flex items-center justify-between w-full px-3 py-1.5 text-xs font-semibold shrink-0 inspector-code-header"
|
|
468
549
|
>
|
|
469
550
|
<span class="flex items-center gap-1.5 min-w-0">
|
|
470
551
|
<Icon name="primer/file-code" size={12} />
|
|
@@ -475,8 +556,7 @@
|
|
|
475
556
|
href={githubUrl}
|
|
476
557
|
target="_blank"
|
|
477
558
|
rel="noopener noreferrer"
|
|
478
|
-
class="flex items-center gap-1 shrink-0 text-xs no-underline hover:underline inspector-mono"
|
|
479
|
-
style:color="var(--fgColor-muted)"
|
|
559
|
+
class="flex items-center gap-1 shrink-0 text-xs no-underline hover:underline inspector-mono inspector-code-link"
|
|
480
560
|
>
|
|
481
561
|
<Icon name="primer/mark-github" size={14} />
|
|
482
562
|
<span>GitHub</span>
|
|
@@ -484,9 +564,9 @@
|
|
|
484
564
|
{/if}
|
|
485
565
|
</div>
|
|
486
566
|
|
|
487
|
-
<div class="border-t flex-1 min-h-0 flex flex-col" style:border-color="
|
|
567
|
+
<div class="border-t flex-1 min-h-0 flex flex-col" style:border-color="#30363d">
|
|
488
568
|
{#if sourceLoading}
|
|
489
|
-
<div class="px-3 py-4 text-xs text-center" style:color="
|
|
569
|
+
<div class="px-3 py-4 text-xs text-center" style:color="#8b949e">
|
|
490
570
|
Loading source…
|
|
491
571
|
</div>
|
|
492
572
|
{:else if sourceCode}
|
|
@@ -494,11 +574,11 @@
|
|
|
494
574
|
{#if highlightedHtml}
|
|
495
575
|
<div class="shiki-wrapper">{@html highlightedHtml}</div>
|
|
496
576
|
{:else}
|
|
497
|
-
<pre class="m-0 text-xs leading-relaxed inspector-mono source-pre" style:color="
|
|
577
|
+
<pre class="m-0 text-xs leading-relaxed inspector-mono source-pre" style:color="#c9d1d9">{sourceCode}</pre>
|
|
498
578
|
{/if}
|
|
499
579
|
</div>
|
|
500
580
|
{:else}
|
|
501
|
-
<div class="px-3 py-4 text-xs text-center" style:color="
|
|
581
|
+
<div class="px-3 py-4 text-xs text-center" style:color="#8b949e">
|
|
502
582
|
Unable to load source
|
|
503
583
|
</div>
|
|
504
584
|
{/if}
|
|
@@ -526,10 +606,6 @@
|
|
|
526
606
|
font-family: "Ioskeley Mono", ui-monospace, monospace;
|
|
527
607
|
}
|
|
528
608
|
|
|
529
|
-
.inspector-toggle-active {
|
|
530
|
-
box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-purple, #7655a4) 30%, transparent);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
609
|
.inspector-pulse-dot {
|
|
534
610
|
width: 8px;
|
|
535
611
|
height: 8px;
|
|
@@ -584,4 +660,23 @@
|
|
|
584
660
|
background: color-mix(in srgb, var(--color-purple, #7655a4) 20%, transparent);
|
|
585
661
|
border-left: 2px solid var(--color-purple, #7655a4);
|
|
586
662
|
}
|
|
663
|
+
|
|
664
|
+
/* Force dark chrome on the code block — independent of page theme */
|
|
665
|
+
.inspector-code-block {
|
|
666
|
+
background: #0d1117;
|
|
667
|
+
border-color: #30363d !important;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.inspector-code-header {
|
|
671
|
+
background: #161b22;
|
|
672
|
+
color: #8b949e;
|
|
673
|
+
border-bottom: 1px solid #30363d;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.inspector-code-link {
|
|
677
|
+
color: #8b949e;
|
|
678
|
+
}
|
|
679
|
+
.inspector-code-link:hover {
|
|
680
|
+
color: #c9d1d9;
|
|
681
|
+
}
|
|
587
682
|
</style>
|
package/src/SidePanel.svelte
CHANGED
|
@@ -276,11 +276,11 @@
|
|
|
276
276
|
z-index: 9998;
|
|
277
277
|
display: flex;
|
|
278
278
|
flex-direction: column;
|
|
279
|
-
background-color: var(--bgColor-default, #
|
|
280
|
-
border-left: 1px solid var(--borderColor-default, #
|
|
279
|
+
background-color: var(--bgColor-default, var(--color-background, #ffffff));
|
|
280
|
+
border-left: 1px solid var(--borderColor-default, var(--color-border, #d0d7de));
|
|
281
281
|
box-shadow: -4px 0 24px rgba(0, 0, 0, 0.15);
|
|
282
282
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
283
|
-
color: var(--fgColor-default, #
|
|
283
|
+
color: var(--fgColor-default, var(--color-foreground, #1f2328));
|
|
284
284
|
animation: sb-sidepanel-slide-in 0.25s ease;
|
|
285
285
|
}
|
|
286
286
|
|
|
@@ -293,7 +293,7 @@
|
|
|
293
293
|
width: 100% !important;
|
|
294
294
|
height: var(--sidepanel-height, 300px);
|
|
295
295
|
border-left: none;
|
|
296
|
-
border-top: 1px solid var(--borderColor-default, #
|
|
296
|
+
border-top: 1px solid var(--borderColor-default, var(--color-border, #d0d7de));
|
|
297
297
|
box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.15);
|
|
298
298
|
animation: sb-sidepanel-slide-up 0.25s ease;
|
|
299
299
|
}
|
|
@@ -320,7 +320,7 @@
|
|
|
320
320
|
left: 0;
|
|
321
321
|
right: 0;
|
|
322
322
|
height: 3px;
|
|
323
|
-
background: var(--mode-color, var(--borderColor-default, #
|
|
323
|
+
background: var(--mode-color, var(--borderColor-default, var(--color-border, #d0d7de)));
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
/* Drag handle — side mode (left edge, vertical) */
|
|
@@ -378,7 +378,7 @@
|
|
|
378
378
|
font-weight: 600;
|
|
379
379
|
text-transform: uppercase;
|
|
380
380
|
letter-spacing: 0.05em;
|
|
381
|
-
color: var(--fgColor-muted, #
|
|
381
|
+
color: var(--fgColor-muted, var(--color-muted-foreground, #656d76));
|
|
382
382
|
padding-left: 4px;
|
|
383
383
|
}
|
|
384
384
|
|
|
@@ -392,7 +392,7 @@
|
|
|
392
392
|
appearance: none;
|
|
393
393
|
border: none;
|
|
394
394
|
background: transparent;
|
|
395
|
-
color: var(--fgColor-muted, #
|
|
395
|
+
color: var(--fgColor-muted, var(--color-muted-foreground, #656d76));
|
|
396
396
|
cursor: pointer;
|
|
397
397
|
padding: 6px;
|
|
398
398
|
border-radius: 6px;
|
|
@@ -404,7 +404,7 @@
|
|
|
404
404
|
|
|
405
405
|
.sb-sidepanel-action-btn:hover {
|
|
406
406
|
background: var(--bgColor-neutral-muted, rgba(110, 118, 129, 0.1));
|
|
407
|
-
color: var(--fgColor-default, #
|
|
407
|
+
color: var(--fgColor-default, var(--color-foreground, #1f2328));
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
/* Body */
|
|
@@ -425,8 +425,8 @@
|
|
|
425
425
|
.sb-sidepanel-spinner {
|
|
426
426
|
width: 20px;
|
|
427
427
|
height: 20px;
|
|
428
|
-
border: 2px solid var(--borderColor-default, #
|
|
429
|
-
border-top-color: var(--fgColor-muted, #
|
|
428
|
+
border: 2px solid var(--borderColor-default, var(--color-border, #d0d7de));
|
|
429
|
+
border-top-color: var(--fgColor-muted, var(--color-muted-foreground, #656d76));
|
|
430
430
|
border-radius: 50%;
|
|
431
431
|
animation: sb-spin 0.6s linear infinite;
|
|
432
432
|
}
|
package/src/commandActions.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Command Actions — config-driven registry for command menu entries.
|
|
3
3
|
*
|
|
4
|
-
* The command section of
|
|
4
|
+
* The command section of toolbar.config.json declares action metadata:
|
|
5
5
|
* id, label, type, hideFrom, separatorBefore
|
|
6
6
|
*
|
|
7
7
|
* Handler shapes by type:
|
package/src/comments/index.js
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consumer-safe proxy for mountDevTools.
|
|
3
|
+
*
|
|
4
|
+
* Delegates to the compiled UI bundle (@dfosco/storyboard-core/ui-runtime)
|
|
5
|
+
* so consumers don't need svelte installed. The real mountDevTools in
|
|
6
|
+
* devtools.js imports svelte directly and is only usable in the source repo
|
|
7
|
+
* or via the compiled UI bundle.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export async function mountDevTools(options = {}) {
|
|
11
|
+
const ui = await import('@dfosco/storyboard-core/ui-runtime')
|
|
12
|
+
return ui.mountDevTools(options)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function unmountDevTools() {
|
|
16
|
+
const ui = await import('@dfosco/storyboard-core/ui-runtime')
|
|
17
|
+
return ui.unmountDevTools()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** @deprecated Use mountDevTools instead. */
|
|
21
|
+
export function mountFlowDebug(options = {}) {
|
|
22
|
+
return mountDevTools(options)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** @deprecated Use mountDevTools instead. */
|
|
26
|
+
export function mountSceneDebug(options = {}) {
|
|
27
|
+
return mountDevTools(options)
|
|
28
|
+
}
|
package/src/devtools.js
CHANGED
|
@@ -30,6 +30,9 @@ export async function mountDevTools(options = {}) {
|
|
|
30
30
|
// Prevent double-mount
|
|
31
31
|
if (wrapper) return
|
|
32
32
|
|
|
33
|
+
// Skip mounting entirely when loaded inside a prototype embed iframe
|
|
34
|
+
if (typeof window !== 'undefined' && new URLSearchParams(window.location.search).has('_sb_embed')) return
|
|
35
|
+
|
|
33
36
|
const { mount } = await import('svelte')
|
|
34
37
|
const { default: CoreUIBar } = await import('./CoreUIBar.svelte')
|
|
35
38
|
|
|
@@ -105,7 +108,7 @@ export async function mountDevTools(options = {}) {
|
|
|
105
108
|
|
|
106
109
|
instance = mount(CoreUIBar, {
|
|
107
110
|
target: wrapper,
|
|
108
|
-
props: { basePath },
|
|
111
|
+
props: { basePath, toolbarConfig: options.toolbarConfig },
|
|
109
112
|
})
|
|
110
113
|
}
|
|
111
114
|
|
package/src/index.js
CHANGED
|
@@ -28,7 +28,7 @@ export { getByPath, setByPath, deepClone } from './dotPath.js'
|
|
|
28
28
|
export { getParam, setParam, getAllParams, removeParam } from './session.js'
|
|
29
29
|
|
|
30
30
|
// localStorage persistence
|
|
31
|
-
export { getLocal, setLocal, removeLocal, getAllLocal, subscribeToStorage, getStorageSnapshot } from './localStorage.js'
|
|
31
|
+
export { getLocal, setLocal, removeLocal, getAllLocal, subscribeToStorage, getStorageSnapshot, notifyChange } from './localStorage.js'
|
|
32
32
|
|
|
33
33
|
// Hide mode (clean URLs)
|
|
34
34
|
export { isHideMode, activateHideMode, deactivateHideMode, getShadow, setShadow, removeShadow, getAllShadows, pushSnapshot, getOverrideHistory, getCurrentSnapshot, getCurrentRoute, getCurrentIndex, getNextIndex, canUndo, canRedo, undo, redo, syncHashToHistory, installHistorySync } from './hideMode.js'
|
|
@@ -49,11 +49,16 @@ export { registerMode, unregisterMode, getRegisteredModes, getCurrentMode, activ
|
|
|
49
49
|
export { initTools, setToolAction, setToolState, getToolState, getToolsForMode, subscribeToTools, getToolsSnapshot } from './modes.js'
|
|
50
50
|
|
|
51
51
|
// Dev tools (vanilla JS, framework-agnostic)
|
|
52
|
-
|
|
52
|
+
// mountDevTools delegates to the compiled UI bundle so consumers
|
|
53
|
+
// don't need svelte installed — svelte is bundled into ui-runtime.
|
|
54
|
+
export { mountDevTools } from './devtools-consumer.js'
|
|
53
55
|
export { mountFlowDebug } from './sceneDebug.js'
|
|
54
56
|
// Deprecated alias
|
|
55
57
|
export { mountSceneDebug } from './sceneDebug.js'
|
|
56
58
|
|
|
59
|
+
// Single entry point for consumer apps
|
|
60
|
+
export { mountStoryboardCore } from './mountStoryboardCore.js'
|
|
61
|
+
|
|
57
62
|
// Viewfinder utilities
|
|
58
63
|
export { hash, resolveFlowRoute, getFlowMeta, buildPrototypeIndex } from './viewfinder.js'
|
|
59
64
|
// Deprecated aliases
|
|
@@ -63,7 +68,7 @@ export { resolveSceneRoute, getSceneMeta } from './viewfinder.js'
|
|
|
63
68
|
export { initFeatureFlags, getFlag, setFlag, toggleFlag, getAllFlags, resetFlags, getFlagKeys, syncFlagBodyClasses } from './featureFlags.js'
|
|
64
69
|
|
|
65
70
|
// Command actions (config-driven command menu entries)
|
|
66
|
-
export { initCommandActions, registerCommandAction, unregisterCommandAction, setDynamicActions, clearDynamicActions, getActionsForMode, executeAction, getActionChildren, subscribeToCommandActions, getCommandActionsSnapshot, setRoutingBasePath } from './commandActions.js'
|
|
71
|
+
export { initCommandActions, registerCommandAction, unregisterCommandAction, setDynamicActions, clearDynamicActions, getActionsForMode, executeAction, getActionChildren, subscribeToCommandActions, getCommandActionsSnapshot, setRoutingBasePath, isExcludedByRoute } from './commandActions.js'
|
|
67
72
|
|
|
68
73
|
// Plugin configuration
|
|
69
74
|
export { initPlugins, isPluginEnabled, getPluginsConfig } from './plugins.js'
|
|
@@ -4,24 +4,35 @@
|
|
|
4
4
|
* Uses shiki/core with only the four languages the inspector needs,
|
|
5
5
|
* avoiding the full shiki bundle that registers 200+ lazy-loaded
|
|
6
6
|
* language chunks (which break in deployed/static environments).
|
|
7
|
+
*
|
|
8
|
+
* Each import() has .catch() so consumer bundlers (esbuild dep optimizer)
|
|
9
|
+
* treat them as runtime-fallible and don't fail at build time when shiki
|
|
10
|
+
* isn't installed. Returns null when shiki is unavailable.
|
|
7
11
|
*/
|
|
8
|
-
import { createHighlighterCore } from 'shiki/core'
|
|
9
|
-
import { createOnigurumaEngine } from 'shiki/engine/oniguruma'
|
|
10
|
-
|
|
11
12
|
export async function createInspectorHighlighter() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
try {
|
|
14
|
+
const [shikiCore, oniguruma, tsx, jsx, javascript, typescript, githubDark, wasm] =
|
|
15
|
+
await Promise.all([
|
|
16
|
+
import('shiki/core').catch(() => null),
|
|
17
|
+
import('shiki/engine/oniguruma').catch(() => null),
|
|
18
|
+
import('shiki/dist/langs/tsx.mjs').catch(() => null),
|
|
19
|
+
import('shiki/dist/langs/jsx.mjs').catch(() => null),
|
|
20
|
+
import('shiki/dist/langs/javascript.mjs').catch(() => null),
|
|
21
|
+
import('shiki/dist/langs/typescript.mjs').catch(() => null),
|
|
22
|
+
import('shiki/dist/themes/github-dark.mjs').catch(() => null),
|
|
23
|
+
import('shiki/wasm').catch(() => null),
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
if (!shikiCore || !oniguruma || !tsx || !jsx || !javascript || !typescript || !githubDark || !wasm) {
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
return shikiCore.createHighlighterCore({
|
|
31
|
+
themes: [githubDark.default],
|
|
32
|
+
langs: [tsx.default, jsx.default, javascript.default, typescript.default],
|
|
33
|
+
engine: oniguruma.createOnigurumaEngine(wasm),
|
|
34
|
+
})
|
|
35
|
+
} catch {
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
27
38
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
{sideOffset}
|
|
20
20
|
{align}
|
|
21
21
|
class={cn(
|
|
22
|
-
"font-sans data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/
|
|
22
|
+
"font-sans data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 w-(--bits-dropdown-menu-anchor-width) data-closed:overflow-hidden z-[10000] bg-popover border-3 border-slate-400 text-slate-800 fill-slate-600 min-w-40 rounded-xl p-2 shadow-xl duration-100 overflow-x-hidden overflow-y-auto",
|
|
23
23
|
className
|
|
24
24
|
)}
|
|
25
25
|
{...restProps}
|
|
@@ -12,11 +12,15 @@
|
|
|
12
12
|
<script module>
|
|
13
13
|
import { cn } from "../../../utils/index.js";
|
|
14
14
|
|
|
15
|
-
// Register CSS Houdini paint worklet for superellipse masks
|
|
15
|
+
// Register CSS Houdini paint worklet for superellipse masks.
|
|
16
|
+
// Inlined from smooth-corners (MIT) to avoid Vite-specific ?url import
|
|
17
|
+
// that breaks when this source is consumed from node_modules.
|
|
16
18
|
if (typeof CSS !== 'undefined' && 'paintWorklet' in CSS) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
try {
|
|
20
|
+
const worklet = `class P{static get inputProperties(){return["--smooth-corners"]}superellipse(a,b,nX=4,nY){if(Number.isNaN(nX))nX=4;if(typeof nY==="undefined"||Number.isNaN(nY))nY=nX;if(nX>100)nX=100;if(nY>100)nY=100;if(nX<1e-11)nX=1e-11;if(nY<1e-11)nY=1e-11;const nX2=2/nX,nY2=nY?2/nY:nX2,steps=360,step=(2*Math.PI)/steps;return Array.from({length:steps},(_,i)=>{const t=i*step,cosT=Math.cos(t),sinT=Math.sin(t);return{x:Math.abs(cosT)**nX2*a*Math.sign(cosT),y:Math.abs(sinT)**nY2*b*Math.sign(sinT)}})}paint(ctx,geom,props){const[nX,nY]=props.get("--smooth-corners").toString().replace(/ /g,"").split(",");const w=geom.width/2,h=geom.height/2,s=this.superellipse(w,h,parseFloat(nX),parseFloat(nY));ctx.fillStyle="#000";ctx.setTransform(1,0,0,1,w,h);ctx.beginPath();for(let i=0;i<s.length;i++){const{x,y}=s[i];i===0?ctx.moveTo(x,y):ctx.lineTo(x,y)}ctx.closePath();ctx.fill()}}registerPaint("smooth-corners",P);`;
|
|
21
|
+
const blob = new Blob([worklet], { type: 'application/javascript' });
|
|
22
|
+
CSS.paintWorklet.addModule(URL.createObjectURL(blob));
|
|
23
|
+
} catch {}
|
|
20
24
|
}
|
|
21
25
|
</script>
|
|
22
26
|
|