sdocs 0.0.36 → 0.0.37
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/CHANGELOG.md +31 -0
- package/dist/explorer/views/ApiTable.svelte +138 -0
- package/dist/explorer/views/ApiTable.svelte.d.ts +14 -0
- package/dist/explorer/views/ComponentView.svelte +154 -87
- package/dist/explorer/views/CssPropControl.svelte +27 -0
- package/dist/explorer/views/CssPropControl.svelte.d.ts +14 -0
- package/dist/explorer/views/DataTable.svelte +46 -4
- package/dist/explorer/views/PreviewFrame.svelte +11 -1
- package/dist/explorer/views/PreviewFrame.svelte.d.ts +4 -1
- package/dist/explorer/views/PropControl.svelte +69 -0
- package/dist/explorer/views/PropControl.svelte.d.ts +14 -0
- package/dist/explorer/views/format.d.ts +6 -0
- package/dist/explorer/views/format.js +44 -0
- package/dist/server/snippet-compiler.d.ts +3 -2
- package/dist/server/snippet-compiler.js +36 -4
- package/dist/ui/Control/Checkbox.svelte +6 -3
- package/dist/ui/Control/Color.svelte +6 -3
- package/dist/ui/Control/Dimension.svelte +8 -4
- package/dist/ui/Control/Number.svelte +6 -4
- package/dist/ui/Control/Select.svelte +6 -4
- package/dist/ui/Control/Text.svelte +6 -3
- package/dist/ui/Icon/Icon.svelte +10 -0
- package/dist/ui/Icon/icons/database.svg +5 -0
- package/dist/ui/Icon/icons/palette.svg +7 -0
- package/dist/ui/Icon/icons/sliders-horizontal.svg +11 -0
- package/dist/ui/Icon/icons/square-function.svg +5 -0
- package/dist/ui/Icon/icons/zap.svg +3 -0
- package/dist/ui/styles/sdocs.css +49 -0
- package/dist/vite.js +2 -1
- package/package.json +1 -1
- package/dist/explorer/views/ControlsPanel.svelte +0 -186
- package/dist/explorer/views/ControlsPanel.svelte.d.ts +0 -14
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.0.37] - 2026-07-03
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **The component page is a live API reference.** The separate Controls
|
|
15
|
+
panel is gone — controls sit inside the API tables, on the row of the
|
|
16
|
+
prop or CSS custom property they drive. Props, CSS Props, Events, and
|
|
17
|
+
Snippets share a composite row layout: name (with a red `*` when
|
|
18
|
+
required), type and description stacked in the middle, an explicit
|
|
19
|
+
Default column (`—` when absent), and a fixed control rail. Reset moved
|
|
20
|
+
next to the Props title.
|
|
21
|
+
- **Sections instead of collapsible panels.** The reference sections render
|
|
22
|
+
flat with icon titles; only the preview and its code stay in the bordered
|
|
23
|
+
card (Preview Code still collapses). "State" is now "States", matching
|
|
24
|
+
the plural sibling sections. The page grew to 1120px.
|
|
25
|
+
- **Color-coded types and values.** Type chips are tinted by kind — strings
|
|
26
|
+
green, numbers and dimensions amber, booleans purple, callbacks blue,
|
|
27
|
+
snippets pink, colors cyan, `void` slate — union members render as
|
|
28
|
+
individual chips, and default/state literals are colored plain text.
|
|
29
|
+
Both themes are handled explicitly.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **Run buttons for methods.** Zero-argument methods can be invoked
|
|
34
|
+
directly from the Methods table and act on the live preview; methods
|
|
35
|
+
with parameters show a disabled button.
|
|
36
|
+
- **Live state values.** The States table shows each exported state's
|
|
37
|
+
current value, streamed from the preview as it changes.
|
|
38
|
+
- Section icons (sliders, palette, zap, function, database) join the UI
|
|
39
|
+
icon set.
|
|
40
|
+
|
|
10
41
|
## [0.0.36] - 2026-07-03
|
|
11
42
|
|
|
12
43
|
### Fixed
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { typeClass, typeParts, valueClass } from './format.js';
|
|
4
|
+
|
|
5
|
+
interface Row {
|
|
6
|
+
name: string;
|
|
7
|
+
type?: string | null;
|
|
8
|
+
default?: string | null;
|
|
9
|
+
description?: string | null;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
rows: Row[];
|
|
15
|
+
/** Renders the per-row control in the fixed right rail */
|
|
16
|
+
control?: Snippet<[Row]>;
|
|
17
|
+
/** Show the Default column (rows without defaults, e.g. events, turn it off) */
|
|
18
|
+
showDefault?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let { rows, control, showDefault = true }: Props = $props();
|
|
22
|
+
|
|
23
|
+
const gridColumns = $derived(
|
|
24
|
+
['200px', 'minmax(0, 1fr)', ...(showDefault ? ['120px'] : []), ...(control ? ['200px'] : [])].join(' '),
|
|
25
|
+
);
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
{#if rows.length > 0}
|
|
29
|
+
<div class="sdocs-api-list">
|
|
30
|
+
<div class="sdocs-api-header" style:grid-template-columns={gridColumns}>
|
|
31
|
+
<div>Name</div>
|
|
32
|
+
<div>Details</div>
|
|
33
|
+
{#if showDefault}<div>Default</div>{/if}
|
|
34
|
+
{#if control}<div>Control</div>{/if}
|
|
35
|
+
</div>
|
|
36
|
+
{#each rows as row (row.name)}
|
|
37
|
+
<div class="sdocs-api-row" style:grid-template-columns={gridColumns}>
|
|
38
|
+
<div class="sdocs-api-name">
|
|
39
|
+
{row.name}{#if row.required}<span class="sdocs-api-required" title="Required">*</span>{/if}
|
|
40
|
+
</div>
|
|
41
|
+
<div class="sdocs-api-middle">
|
|
42
|
+
{#if row.type}
|
|
43
|
+
<div class="sdocs-api-meta">
|
|
44
|
+
{#each typeParts(row.type) as part, i (i)}
|
|
45
|
+
{#if i > 0}<span class="sdocs-typesep">|</span>{/if}
|
|
46
|
+
<code class="sdocs-type-{typeClass(row.type)}">{part}</code>
|
|
47
|
+
{/each}
|
|
48
|
+
</div>
|
|
49
|
+
{/if}
|
|
50
|
+
{#if row.description}
|
|
51
|
+
<div class="sdocs-api-desc">{row.description}</div>
|
|
52
|
+
{/if}
|
|
53
|
+
</div>
|
|
54
|
+
{#if showDefault}
|
|
55
|
+
<div class="sdocs-api-default">
|
|
56
|
+
{#if row.default != null}
|
|
57
|
+
<span class="sdocs-value sdocs-value-{valueClass(row.default)}">{row.default}</span>
|
|
58
|
+
{:else}
|
|
59
|
+
<span class="sdocs-api-empty">—</span>
|
|
60
|
+
{/if}
|
|
61
|
+
</div>
|
|
62
|
+
{/if}
|
|
63
|
+
{#if control}
|
|
64
|
+
<div class="sdocs-api-control">
|
|
65
|
+
{@render control(row)}
|
|
66
|
+
</div>
|
|
67
|
+
{/if}
|
|
68
|
+
</div>
|
|
69
|
+
{/each}
|
|
70
|
+
</div>
|
|
71
|
+
{:else}
|
|
72
|
+
<p class="sdocs-api-none">None</p>
|
|
73
|
+
{/if}
|
|
74
|
+
|
|
75
|
+
<style>
|
|
76
|
+
.sdocs-api-list {
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
}
|
|
80
|
+
.sdocs-api-header {
|
|
81
|
+
display: grid;
|
|
82
|
+
grid-template-columns: 200px minmax(0, 1fr) 120px 200px;
|
|
83
|
+
gap: 20px;
|
|
84
|
+
padding: 6px 12px;
|
|
85
|
+
border-bottom: 2px solid var(--color-base-200);
|
|
86
|
+
font-size: 12px;
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
color: var(--color-base-600);
|
|
89
|
+
}
|
|
90
|
+
.sdocs-api-row {
|
|
91
|
+
display: grid;
|
|
92
|
+
grid-template-columns: 200px minmax(0, 1fr) 120px 200px;
|
|
93
|
+
gap: 20px;
|
|
94
|
+
align-items: start;
|
|
95
|
+
padding: 12px 12px;
|
|
96
|
+
border-bottom: 1px solid var(--color-base-100);
|
|
97
|
+
font-size: 13px;
|
|
98
|
+
}
|
|
99
|
+
.sdocs-api-name {
|
|
100
|
+
font-weight: 600;
|
|
101
|
+
color: var(--color-base-900);
|
|
102
|
+
overflow-wrap: break-word;
|
|
103
|
+
}
|
|
104
|
+
.sdocs-api-required {
|
|
105
|
+
color: var(--color-red-500);
|
|
106
|
+
}
|
|
107
|
+
.sdocs-api-middle {
|
|
108
|
+
display: flex;
|
|
109
|
+
flex-direction: column;
|
|
110
|
+
gap: 8px;
|
|
111
|
+
min-width: 0;
|
|
112
|
+
}
|
|
113
|
+
.sdocs-api-meta {
|
|
114
|
+
display: flex;
|
|
115
|
+
flex-wrap: wrap;
|
|
116
|
+
align-items: baseline;
|
|
117
|
+
gap: 6px;
|
|
118
|
+
}
|
|
119
|
+
.sdocs-api-desc {
|
|
120
|
+
color: var(--color-base-500);
|
|
121
|
+
}
|
|
122
|
+
.sdocs-api-default {
|
|
123
|
+
overflow-wrap: break-word;
|
|
124
|
+
min-width: 0;
|
|
125
|
+
}
|
|
126
|
+
.sdocs-api-empty {
|
|
127
|
+
color: var(--color-base-300);
|
|
128
|
+
}
|
|
129
|
+
.sdocs-api-control {
|
|
130
|
+
min-width: 0;
|
|
131
|
+
}
|
|
132
|
+
.sdocs-api-none {
|
|
133
|
+
color: var(--color-base-400);
|
|
134
|
+
font-size: 13px;
|
|
135
|
+
font-style: italic;
|
|
136
|
+
margin: 0;
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: Record<string, never>;
|
|
4
|
+
events: {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
};
|
|
7
|
+
slots: {};
|
|
8
|
+
};
|
|
9
|
+
export type ApiTableProps = typeof __propDef.props;
|
|
10
|
+
export type ApiTableEvents = typeof __propDef.events;
|
|
11
|
+
export type ApiTableSlots = typeof __propDef.slots;
|
|
12
|
+
export default class ApiTable extends SvelteComponentTyped<ApiTableProps, ApiTableEvents, ApiTableSlots> {
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
import { highlightSvelte } from '../highlighter.js';
|
|
5
5
|
import CollapsiblePanel from './CollapsiblePanel.svelte';
|
|
6
6
|
import PreviewFrame from './PreviewFrame.svelte';
|
|
7
|
-
import ControlsPanel from './ControlsPanel.svelte';
|
|
8
7
|
import DataTable from './DataTable.svelte';
|
|
8
|
+
import ApiTable from './ApiTable.svelte';
|
|
9
|
+
import PropControl from './PropControl.svelte';
|
|
10
|
+
import CssPropControl from './CssPropControl.svelte';
|
|
9
11
|
|
|
10
12
|
interface Props {
|
|
11
13
|
doc: DocEntry;
|
|
@@ -32,6 +34,10 @@
|
|
|
32
34
|
let propValues = $state<Record<string, unknown>>({});
|
|
33
35
|
let cssValues = $state<Record<string, string>>({});
|
|
34
36
|
|
|
37
|
+
// Live wiring to the default preview: method invocation + exported state values
|
|
38
|
+
let defaultPreview = $state<{ callMethod: (name: string) => void }>();
|
|
39
|
+
let liveStateValues = $state<Record<string, unknown>>({});
|
|
40
|
+
|
|
35
41
|
// Initialize from meta.args (build new objects to avoid read+write loop)
|
|
36
42
|
$effect(() => {
|
|
37
43
|
propValues = { ...(meta.args ?? {}) };
|
|
@@ -200,13 +206,17 @@
|
|
|
200
206
|
cssValues = newCss;
|
|
201
207
|
}
|
|
202
208
|
|
|
209
|
+
const hasEditableControls = $derived(
|
|
210
|
+
!!cd && (cd.props.some((p) => p.category === 'prop') || cd.cssProps.length > 0),
|
|
211
|
+
);
|
|
212
|
+
|
|
203
213
|
// Table data builders
|
|
204
214
|
const propsRows = $derived(
|
|
205
215
|
(cd?.props ?? []).filter((p) => p.category === 'prop').map((p) => ({
|
|
206
216
|
name: p.name,
|
|
207
217
|
type: p.type,
|
|
208
218
|
default: p.default,
|
|
209
|
-
required: p.required
|
|
219
|
+
required: p.required,
|
|
210
220
|
description: p.description,
|
|
211
221
|
})),
|
|
212
222
|
);
|
|
@@ -247,6 +257,7 @@
|
|
|
247
257
|
|
|
248
258
|
const stateRows = $derived(
|
|
249
259
|
(cd?.state ?? []).map((s) => ({
|
|
260
|
+
value: s.name in liveStateValues ? JSON.stringify(liveStateValues[s.name]) : undefined,
|
|
250
261
|
name: s.name,
|
|
251
262
|
type: s.type,
|
|
252
263
|
description: s.description,
|
|
@@ -282,10 +293,12 @@
|
|
|
282
293
|
{#if defaultSnippet}
|
|
283
294
|
<div class="sdocs-preview-wrapper">
|
|
284
295
|
<PreviewFrame
|
|
296
|
+
bind:this={defaultPreview}
|
|
285
297
|
src={defaultSnippet.previewUrl ?? ''}
|
|
286
298
|
props={propValues}
|
|
287
299
|
cssVars={cssValues}
|
|
288
300
|
{activeStylesheet}
|
|
301
|
+
onStateValues={(values) => (liveStateValues = values)}
|
|
289
302
|
/>
|
|
290
303
|
</div>
|
|
291
304
|
|
|
@@ -299,92 +312,101 @@
|
|
|
299
312
|
</div>
|
|
300
313
|
</CollapsiblePanel>
|
|
301
314
|
{/if}
|
|
315
|
+
</div>
|
|
302
316
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
cssProps={cd.cssProps}
|
|
308
|
-
{propValues}
|
|
309
|
-
{cssValues}
|
|
310
|
-
onPropChange={handlePropChange}
|
|
311
|
-
onCssChange={handleCssChange}
|
|
312
|
-
onReset={handleReset}
|
|
313
|
-
/>
|
|
314
|
-
</CollapsiblePanel>
|
|
317
|
+
{#snippet propControl(row: Record<string, unknown>)}
|
|
318
|
+
{@const prop = cd?.props.find((p) => p.name === row.name && p.category === 'prop')}
|
|
319
|
+
{#if prop}
|
|
320
|
+
<PropControl {prop} value={propValues[prop.name]} onchange={(v) => handlePropChange(prop.name, v)} />
|
|
315
321
|
{/if}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
/>
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
/>
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
<
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
</
|
|
322
|
+
{/snippet}
|
|
323
|
+
|
|
324
|
+
{#snippet methodControl(row: Record<string, unknown>)}
|
|
325
|
+
{@const hasParams = String(row.params ?? '').trim().length > 0}
|
|
326
|
+
<button
|
|
327
|
+
class="sdocs-run-btn"
|
|
328
|
+
disabled={hasParams || !defaultPreview}
|
|
329
|
+
title={hasParams ? 'Only methods without parameters can be run here' : `Run ${row.name}() on the preview`}
|
|
330
|
+
onclick={() => defaultPreview?.callMethod(String(row.name))}
|
|
331
|
+
>
|
|
332
|
+
Run
|
|
333
|
+
</button>
|
|
334
|
+
{/snippet}
|
|
335
|
+
|
|
336
|
+
{#snippet cssPropControl(row: Record<string, unknown>)}
|
|
337
|
+
{@const cssProp = cd?.cssProps.find((p) => p.name === row.name)}
|
|
338
|
+
{#if cssProp}
|
|
339
|
+
<CssPropControl {cssProp} value={cssValues[cssProp.name]} onchange={(v) => handleCssChange(cssProp.name, v)} />
|
|
340
|
+
{/if}
|
|
341
|
+
{/snippet}
|
|
342
|
+
|
|
343
|
+
<section class="sdocs-doc-section">
|
|
344
|
+
<h2 class="sdocs-doc-section-title">
|
|
345
|
+
<Icon name="sliders-horizontal" --w="15px" --h="15px" --fill="var(--color-base-500)" />
|
|
346
|
+
Props
|
|
347
|
+
{#if hasEditableControls}
|
|
348
|
+
<button class="sdocs-reset-btn" onclick={handleReset}>Reset</button>
|
|
349
|
+
{/if}
|
|
350
|
+
</h2>
|
|
351
|
+
<ApiTable rows={propsRows} control={propControl} />
|
|
352
|
+
</section>
|
|
353
|
+
|
|
354
|
+
<section class="sdocs-doc-section">
|
|
355
|
+
<h2 class="sdocs-doc-section-title">
|
|
356
|
+
<Icon name="palette" --w="15px" --h="15px" --fill="var(--color-base-500)" />
|
|
357
|
+
CSS Props
|
|
358
|
+
</h2>
|
|
359
|
+
<ApiTable rows={cssPropsRows} control={cssPropControl} />
|
|
360
|
+
</section>
|
|
361
|
+
|
|
362
|
+
<section class="sdocs-doc-section">
|
|
363
|
+
<h2 class="sdocs-doc-section-title">
|
|
364
|
+
<Icon name="zap" --w="15px" --h="15px" --fill="var(--color-base-500)" />
|
|
365
|
+
Events
|
|
366
|
+
</h2>
|
|
367
|
+
<ApiTable rows={eventsRows} showDefault={false} />
|
|
368
|
+
</section>
|
|
369
|
+
|
|
370
|
+
<section class="sdocs-doc-section">
|
|
371
|
+
<h2 class="sdocs-doc-section-title">
|
|
372
|
+
<Icon name="code" --w="15px" --h="15px" --fill="var(--color-base-500)" />
|
|
373
|
+
Snippets
|
|
374
|
+
</h2>
|
|
375
|
+
<ApiTable rows={snippetsRows} showDefault={false} />
|
|
376
|
+
</section>
|
|
377
|
+
|
|
378
|
+
<section class="sdocs-doc-section">
|
|
379
|
+
<h2 class="sdocs-doc-section-title">
|
|
380
|
+
<Icon name="square-function" --w="15px" --h="15px" --fill="var(--color-base-500)" />
|
|
381
|
+
Methods
|
|
382
|
+
</h2>
|
|
383
|
+
<DataTable
|
|
384
|
+
columns={[
|
|
385
|
+
{ key: 'name', label: 'Name', kind: 'name' },
|
|
386
|
+
{ key: 'params', label: 'Parameters' },
|
|
387
|
+
{ key: 'returns', label: 'Returns', kind: 'type' },
|
|
388
|
+
{ key: 'description', label: 'Description', kind: 'text' },
|
|
389
|
+
]}
|
|
390
|
+
rows={methodsRows}
|
|
391
|
+
control={methodsRows.length > 0 ? methodControl : undefined}
|
|
392
|
+
/>
|
|
393
|
+
</section>
|
|
394
|
+
|
|
395
|
+
<section class="sdocs-doc-section">
|
|
396
|
+
<h2 class="sdocs-doc-section-title">
|
|
397
|
+
<Icon name="database" --w="15px" --h="15px" --fill="var(--color-base-500)" />
|
|
398
|
+
States
|
|
399
|
+
</h2>
|
|
400
|
+
<DataTable
|
|
401
|
+
columns={[
|
|
402
|
+
{ key: 'name', label: 'Name', kind: 'name' },
|
|
403
|
+
{ key: 'type', label: 'Type', kind: 'type' },
|
|
404
|
+
{ key: 'value', label: 'Current value', kind: 'value' },
|
|
405
|
+
{ key: 'description', label: 'Description', kind: 'text' },
|
|
406
|
+
]}
|
|
407
|
+
rows={stateRows}
|
|
408
|
+
/>
|
|
409
|
+
</section>
|
|
388
410
|
|
|
389
411
|
{#if exampleSnippets.length > 0}
|
|
390
412
|
<hr class="sdocs-divider" />
|
|
@@ -421,9 +443,54 @@
|
|
|
421
443
|
<style>
|
|
422
444
|
.sdocs-component-view {
|
|
423
445
|
padding: 24px 32px;
|
|
424
|
-
max-width:
|
|
446
|
+
max-width: 1120px;
|
|
425
447
|
font-family: var(--sans);
|
|
426
448
|
}
|
|
449
|
+
.sdocs-doc-section {
|
|
450
|
+
margin-top: 28px;
|
|
451
|
+
}
|
|
452
|
+
.sdocs-doc-section-title {
|
|
453
|
+
display: flex;
|
|
454
|
+
align-items: center;
|
|
455
|
+
gap: 8px;
|
|
456
|
+
margin: 0 0 10px;
|
|
457
|
+
font-size: 14px;
|
|
458
|
+
font-weight: 600;
|
|
459
|
+
color: var(--color-base-800);
|
|
460
|
+
}
|
|
461
|
+
.sdocs-doc-section-title .sdocs-reset-btn {
|
|
462
|
+
margin-left: auto;
|
|
463
|
+
}
|
|
464
|
+
.sdocs-reset-btn {
|
|
465
|
+
padding: 4px 12px;
|
|
466
|
+
border: 1px solid var(--color-base-200);
|
|
467
|
+
border-radius: 4px;
|
|
468
|
+
background: var(--color-base-0);
|
|
469
|
+
font: inherit;
|
|
470
|
+
font-size: 12px;
|
|
471
|
+
color: var(--color-base-600);
|
|
472
|
+
cursor: pointer;
|
|
473
|
+
}
|
|
474
|
+
.sdocs-reset-btn:hover {
|
|
475
|
+
background: var(--color-base-100);
|
|
476
|
+
}
|
|
477
|
+
.sdocs-run-btn {
|
|
478
|
+
padding: 3px 12px;
|
|
479
|
+
border: 1px solid var(--color-base-200);
|
|
480
|
+
border-radius: 4px;
|
|
481
|
+
background: var(--color-base-0);
|
|
482
|
+
font: inherit;
|
|
483
|
+
font-size: 12px;
|
|
484
|
+
color: var(--color-base-600);
|
|
485
|
+
cursor: pointer;
|
|
486
|
+
}
|
|
487
|
+
.sdocs-run-btn:hover:not(:disabled) {
|
|
488
|
+
background: var(--color-base-100);
|
|
489
|
+
}
|
|
490
|
+
.sdocs-run-btn:disabled {
|
|
491
|
+
opacity: 0.4;
|
|
492
|
+
cursor: default;
|
|
493
|
+
}
|
|
427
494
|
.sdocs-view-header {
|
|
428
495
|
margin-bottom: 24px;
|
|
429
496
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ParsedCssProp } from '../../types.js';
|
|
3
|
+
import { Text as TextControl, Color as ColorControl, Dimension as DimensionControl } from '../../ui/Control/index.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
cssProp: ParsedCssProp;
|
|
7
|
+
value: string | undefined;
|
|
8
|
+
onchange: (value: string) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { cssProp, value, onchange }: Props = $props();
|
|
12
|
+
|
|
13
|
+
const controlType = $derived.by(() => {
|
|
14
|
+
const t = cssProp.type?.toLowerCase() ?? '';
|
|
15
|
+
if (t === 'color') return 'color';
|
|
16
|
+
if (t === 'dimension') return 'dimension';
|
|
17
|
+
return 'text';
|
|
18
|
+
});
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
{#if controlType === 'color'}
|
|
22
|
+
<ColorControl value={value ?? cssProp.default ?? '#000000'} {onchange} />
|
|
23
|
+
{:else if controlType === 'dimension'}
|
|
24
|
+
<DimensionControl value={value ?? cssProp.default ?? '0px'} {onchange} />
|
|
25
|
+
{:else}
|
|
26
|
+
<TextControl value={value ?? cssProp.default ?? ''} {onchange} />
|
|
27
|
+
{/if}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: Record<string, never>;
|
|
4
|
+
events: {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
};
|
|
7
|
+
slots: {};
|
|
8
|
+
};
|
|
9
|
+
export type CssPropControlProps = typeof __propDef.props;
|
|
10
|
+
export type CssPropControlEvents = typeof __propDef.events;
|
|
11
|
+
export type CssPropControlSlots = typeof __propDef.slots;
|
|
12
|
+
export default class CssPropControl extends SvelteComponentTyped<CssPropControlProps, CssPropControlEvents, CssPropControlSlots> {
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { typeClass, typeParts, valueClass } from './format.js';
|
|
4
|
+
|
|
2
5
|
interface Column {
|
|
3
6
|
key: string;
|
|
4
7
|
label: string;
|
|
8
|
+
/** 'name' renders as bold plain text, 'text' as plain text,
|
|
9
|
+
* 'type' as a code chip color-coded by the type,
|
|
10
|
+
* 'value' as mono text color-coded by the literal; default is a code chip */
|
|
11
|
+
kind?: 'name' | 'text' | 'type' | 'value';
|
|
5
12
|
}
|
|
6
13
|
|
|
7
14
|
interface Props {
|
|
8
15
|
columns: Column[];
|
|
9
16
|
rows: Record<string, unknown>[];
|
|
17
|
+
/** When set, adds a Control column rendering this snippet per row */
|
|
18
|
+
control?: Snippet<[Record<string, unknown>]>;
|
|
10
19
|
}
|
|
11
20
|
|
|
12
|
-
let { columns, rows }: Props = $props();
|
|
21
|
+
let { columns, rows, control }: Props = $props();
|
|
22
|
+
|
|
23
|
+
|
|
13
24
|
</script>
|
|
14
25
|
|
|
15
26
|
{#if rows.length > 0}
|
|
@@ -19,6 +30,9 @@
|
|
|
19
30
|
{#each columns as col (col.key)}
|
|
20
31
|
<th>{col.label}</th>
|
|
21
32
|
{/each}
|
|
33
|
+
{#if control}
|
|
34
|
+
<th class="sdocs-table-control-col">Control</th>
|
|
35
|
+
{/if}
|
|
22
36
|
</tr>
|
|
23
37
|
</thead>
|
|
24
38
|
<tbody>
|
|
@@ -26,13 +40,31 @@
|
|
|
26
40
|
<tr>
|
|
27
41
|
{#each columns as col (col.key)}
|
|
28
42
|
<td>
|
|
29
|
-
{#if row[col.key]
|
|
30
|
-
<code>{row[col.key]}</code>
|
|
31
|
-
{:else}
|
|
43
|
+
{#if row[col.key] == null}
|
|
32
44
|
<span class="sdocs-table-empty">—</span>
|
|
45
|
+
{:else if col.kind === 'name'}
|
|
46
|
+
<span class="sdocs-table-name">
|
|
47
|
+
{row[col.key]}{#if row.required === true}<span class="sdocs-table-required" title="Required">*</span>{/if}
|
|
48
|
+
</span>
|
|
49
|
+
{:else if col.kind === 'text'}
|
|
50
|
+
{row[col.key]}
|
|
51
|
+
{:else if col.kind === 'type'}
|
|
52
|
+
{#each typeParts(row[col.key]) as part, i (i)}
|
|
53
|
+
{#if i > 0}<span class="sdocs-typesep">|</span>{/if}
|
|
54
|
+
<code class="sdocs-type-{typeClass(row[col.key])}">{part}</code>
|
|
55
|
+
{/each}
|
|
56
|
+
{:else if col.kind === 'value'}
|
|
57
|
+
<span class="sdocs-value sdocs-value-{valueClass(row[col.key])}">{row[col.key]}</span>
|
|
58
|
+
{:else}
|
|
59
|
+
<code>{row[col.key]}</code>
|
|
33
60
|
{/if}
|
|
34
61
|
</td>
|
|
35
62
|
{/each}
|
|
63
|
+
{#if control}
|
|
64
|
+
<td class="sdocs-table-control-col">
|
|
65
|
+
{@render control(row)}
|
|
66
|
+
</td>
|
|
67
|
+
{/if}
|
|
36
68
|
</tr>
|
|
37
69
|
{/each}
|
|
38
70
|
</tbody>
|
|
@@ -67,6 +99,16 @@
|
|
|
67
99
|
padding: 1px 4px;
|
|
68
100
|
border-radius: 3px;
|
|
69
101
|
}
|
|
102
|
+
.sdocs-table-name {
|
|
103
|
+
font-weight: 600;
|
|
104
|
+
}
|
|
105
|
+
.sdocs-table-required {
|
|
106
|
+
color: var(--color-red-500);
|
|
107
|
+
}
|
|
108
|
+
.sdocs-table-control-col {
|
|
109
|
+
width: 220px;
|
|
110
|
+
min-width: 180px;
|
|
111
|
+
}
|
|
70
112
|
.sdocs-table-empty {
|
|
71
113
|
color: var(--color-base-300);
|
|
72
114
|
}
|
|
@@ -7,9 +7,16 @@
|
|
|
7
7
|
cssVars?: Record<string, string>;
|
|
8
8
|
activeStylesheet?: string;
|
|
9
9
|
fullHeight?: boolean;
|
|
10
|
+
/** Called with the preview component's exported state values whenever they change */
|
|
11
|
+
onStateValues?: (values: Record<string, unknown>) => void;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
let { src, props = {}, cssVars = {}, activeStylesheet, fullHeight = false }: Props = $props();
|
|
14
|
+
let { src, props = {}, cssVars = {}, activeStylesheet, fullHeight = false, onStateValues }: Props = $props();
|
|
15
|
+
|
|
16
|
+
/** Invoke a zero-argument method on the preview's root component */
|
|
17
|
+
export function callMethod(name: string): void {
|
|
18
|
+
iframe?.contentWindow?.postMessage({ type: 'sdocs:call-method', name }, '*');
|
|
19
|
+
}
|
|
13
20
|
|
|
14
21
|
// Preview URLs are root-absolute; hosts serving under a sub-path pass the
|
|
15
22
|
// prefix via the Explorer's previewBase prop (see Explorer.svelte).
|
|
@@ -30,6 +37,9 @@
|
|
|
30
37
|
if (e.data?.type === 'sdocs:resize' && e.source === iframe?.contentWindow) {
|
|
31
38
|
contentHeight = e.data.height;
|
|
32
39
|
}
|
|
40
|
+
if (e.data?.type === 'sdocs:state-values' && e.source === iframe?.contentWindow) {
|
|
41
|
+
onStateValues?.(e.data.values);
|
|
42
|
+
}
|
|
33
43
|
}
|
|
34
44
|
window.addEventListener('message', onMessage);
|
|
35
45
|
return () => window.removeEventListener('message', onMessage);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
2
|
declare const __propDef: {
|
|
3
|
-
props:
|
|
3
|
+
props: {
|
|
4
|
+
callMethod?: (name: string) => void;
|
|
5
|
+
};
|
|
4
6
|
events: {
|
|
5
7
|
[evt: string]: CustomEvent<any>;
|
|
6
8
|
};
|
|
@@ -10,5 +12,6 @@ export type PreviewFrameProps = typeof __propDef.props;
|
|
|
10
12
|
export type PreviewFrameEvents = typeof __propDef.events;
|
|
11
13
|
export type PreviewFrameSlots = typeof __propDef.slots;
|
|
12
14
|
export default class PreviewFrame extends SvelteComponentTyped<PreviewFrameProps, PreviewFrameEvents, PreviewFrameSlots> {
|
|
15
|
+
get callMethod(): (name: string) => void;
|
|
13
16
|
}
|
|
14
17
|
export {};
|