sdocs 0.0.35 → 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.
Files changed (34) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/explorer/highlighter.d.ts +2 -0
  3. package/dist/explorer/highlighter.js +33 -0
  4. package/dist/explorer/views/ApiTable.svelte +138 -0
  5. package/dist/explorer/views/ApiTable.svelte.d.ts +14 -0
  6. package/dist/explorer/views/ComponentView.svelte +160 -108
  7. package/dist/explorer/views/CssPropControl.svelte +27 -0
  8. package/dist/explorer/views/CssPropControl.svelte.d.ts +14 -0
  9. package/dist/explorer/views/DataTable.svelte +46 -4
  10. package/dist/explorer/views/PreviewFrame.svelte +11 -1
  11. package/dist/explorer/views/PreviewFrame.svelte.d.ts +4 -1
  12. package/dist/explorer/views/PropControl.svelte +69 -0
  13. package/dist/explorer/views/PropControl.svelte.d.ts +14 -0
  14. package/dist/explorer/views/format.d.ts +6 -0
  15. package/dist/explorer/views/format.js +44 -0
  16. package/dist/server/snippet-compiler.d.ts +3 -2
  17. package/dist/server/snippet-compiler.js +36 -4
  18. package/dist/ui/Control/Checkbox.svelte +6 -3
  19. package/dist/ui/Control/Color.svelte +6 -3
  20. package/dist/ui/Control/Dimension.svelte +8 -4
  21. package/dist/ui/Control/Number.svelte +6 -4
  22. package/dist/ui/Control/Select.svelte +6 -4
  23. package/dist/ui/Control/Text.svelte +6 -3
  24. package/dist/ui/Icon/Icon.svelte +10 -0
  25. package/dist/ui/Icon/icons/database.svg +5 -0
  26. package/dist/ui/Icon/icons/palette.svg +7 -0
  27. package/dist/ui/Icon/icons/sliders-horizontal.svg +11 -0
  28. package/dist/ui/Icon/icons/square-function.svg +5 -0
  29. package/dist/ui/Icon/icons/zap.svg +3 -0
  30. package/dist/ui/styles/sdocs.css +49 -0
  31. package/dist/vite.js +2 -20
  32. package/package.json +1 -1
  33. package/dist/explorer/views/ControlsPanel.svelte +0 -186
  34. package/dist/explorer/views/ControlsPanel.svelte.d.ts +0 -14
package/CHANGELOG.md CHANGED
@@ -7,6 +7,48 @@ 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
+
41
+ ## [0.0.36] - 2026-07-03
42
+
43
+ ### Fixed
44
+
45
+ - **Usage code is syntax-highlighted in static builds.** The usage snippet
46
+ regenerates in the browser as controls change and used to be highlighted
47
+ through a dev-server endpoint — deployed builds fell back to plain text.
48
+ Highlighting now runs client-side (lazy-loaded Shiki with the JavaScript
49
+ regex engine), identical on the dev server and any static host; the
50
+ dev-server endpoint is gone.
51
+
10
52
  ## [0.0.35] - 2026-07-03
11
53
 
12
54
  ### Fixed
@@ -0,0 +1,2 @@
1
+ /** Highlight Svelte code, matching the build-time highlighter's output shape */
2
+ export declare function highlightSvelte(code: string): Promise<string>;
@@ -0,0 +1,33 @@
1
+ // Client-side Shiki for code that's generated in the browser (the usage
2
+ // snippet re-renders as controls change). Everything loads lazily on first
3
+ // use so the Explorer bundle stays lean, and the JavaScript regex engine
4
+ // avoids shipping wasm — highlighting works the same on the dev server and
5
+ // in static builds.
6
+ let highlighterPromise;
7
+ async function getHighlighter() {
8
+ highlighterPromise ??= (async () => {
9
+ const [{ createHighlighterCore }, { createJavaScriptRegexEngine }, { bundledLanguages }, { bundledThemes }] = await Promise.all([
10
+ import('shiki/core'),
11
+ import('shiki/engine/javascript'),
12
+ import('shiki/langs'),
13
+ import('shiki/themes'),
14
+ ]);
15
+ return createHighlighterCore({
16
+ langs: [bundledLanguages.svelte],
17
+ themes: [bundledThemes['github-light'], bundledThemes['github-dark']],
18
+ engine: createJavaScriptRegexEngine({ forgiving: true }),
19
+ });
20
+ })();
21
+ return highlighterPromise;
22
+ }
23
+ /** Highlight Svelte code, matching the build-time highlighter's output shape */
24
+ export async function highlightSvelte(code) {
25
+ const highlighter = await getHighlighter();
26
+ return highlighter.codeToHtml(code, {
27
+ lang: 'svelte',
28
+ themes: {
29
+ light: 'github-light',
30
+ dark: 'github-dark',
31
+ },
32
+ });
33
+ }
@@ -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 {};
@@ -1,10 +1,13 @@
1
1
  <script lang="ts">
2
2
  import type { DocEntry } from '../../types.js';
3
3
  import { Icon } from '../../ui/Icon/index.js';
4
+ import { highlightSvelte } from '../highlighter.js';
4
5
  import CollapsiblePanel from './CollapsiblePanel.svelte';
5
6
  import PreviewFrame from './PreviewFrame.svelte';
6
- import ControlsPanel from './ControlsPanel.svelte';
7
7
  import DataTable from './DataTable.svelte';
8
+ import ApiTable from './ApiTable.svelte';
9
+ import PropControl from './PropControl.svelte';
10
+ import CssPropControl from './CssPropControl.svelte';
8
11
 
9
12
  interface Props {
10
13
  doc: DocEntry;
@@ -31,6 +34,10 @@
31
34
  let propValues = $state<Record<string, unknown>>({});
32
35
  let cssValues = $state<Record<string, string>>({});
33
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
+
34
41
  // Initialize from meta.args (build new objects to avoid read+write loop)
35
42
  $effect(() => {
36
43
  propValues = { ...(meta.args ?? {}) };
@@ -169,36 +176,20 @@
169
176
  return generateFallbackCode(componentName, propValues, cssValues);
170
177
  });
171
178
 
172
- // Highlighted usage code via server-side Shiki. The endpoint is dev-server
173
- // middleware; in a production build it doesn't exist, so after the first
174
- // failure stop asking and fall back to plain code.
179
+ // Usage code is generated in the browser, so it's highlighted client-side
180
+ // (lazy Shiki see ../highlighter.ts). Debounced while controls change;
181
+ // stale results are dropped.
175
182
  let highlightedUsageHtml = $state('');
176
183
  let highlightTimer: ReturnType<typeof setTimeout> | undefined;
177
- let highlightAvailable = true;
178
184
 
179
185
  $effect(() => {
180
186
  const code = usageCode;
181
187
  clearTimeout(highlightTimer);
182
- if (!highlightAvailable) {
183
- highlightedUsageHtml = '';
184
- return;
185
- }
186
188
  highlightTimer = setTimeout(async () => {
187
189
  try {
188
- const res = await fetch('/__sdocs/highlight', {
189
- method: 'POST',
190
- headers: { 'Content-Type': 'application/json' },
191
- body: JSON.stringify({ code, lang: 'svelte' }),
192
- });
193
- if (res.ok) {
194
- const { html } = await res.json();
195
- highlightedUsageHtml = html;
196
- } else {
197
- highlightAvailable = false;
198
- highlightedUsageHtml = '';
199
- }
190
+ const html = await highlightSvelte(code);
191
+ if (code === usageCode) highlightedUsageHtml = html;
200
192
  } catch {
201
- highlightAvailable = false;
202
193
  highlightedUsageHtml = '';
203
194
  }
204
195
  }, 150);
@@ -215,13 +206,17 @@
215
206
  cssValues = newCss;
216
207
  }
217
208
 
209
+ const hasEditableControls = $derived(
210
+ !!cd && (cd.props.some((p) => p.category === 'prop') || cd.cssProps.length > 0),
211
+ );
212
+
218
213
  // Table data builders
219
214
  const propsRows = $derived(
220
215
  (cd?.props ?? []).filter((p) => p.category === 'prop').map((p) => ({
221
216
  name: p.name,
222
217
  type: p.type,
223
218
  default: p.default,
224
- required: p.required ? 'Yes' : '',
219
+ required: p.required,
225
220
  description: p.description,
226
221
  })),
227
222
  );
@@ -262,6 +257,7 @@
262
257
 
263
258
  const stateRows = $derived(
264
259
  (cd?.state ?? []).map((s) => ({
260
+ value: s.name in liveStateValues ? JSON.stringify(liveStateValues[s.name]) : undefined,
265
261
  name: s.name,
266
262
  type: s.type,
267
263
  description: s.description,
@@ -297,10 +293,12 @@
297
293
  {#if defaultSnippet}
298
294
  <div class="sdocs-preview-wrapper">
299
295
  <PreviewFrame
296
+ bind:this={defaultPreview}
300
297
  src={defaultSnippet.previewUrl ?? ''}
301
298
  props={propValues}
302
299
  cssVars={cssValues}
303
300
  {activeStylesheet}
301
+ onStateValues={(values) => (liveStateValues = values)}
304
302
  />
305
303
  </div>
306
304
 
@@ -314,92 +312,101 @@
314
312
  </div>
315
313
  </CollapsiblePanel>
316
314
  {/if}
315
+ </div>
317
316
 
318
- {#if cd && ((cd.props.filter((p) => p.category === 'prop').length > 0) || cd.cssProps.length > 0)}
319
- <CollapsiblePanel title="Controls">
320
- <ControlsPanel
321
- componentProps={cd.props}
322
- cssProps={cd.cssProps}
323
- {propValues}
324
- {cssValues}
325
- onPropChange={handlePropChange}
326
- onCssChange={handleCssChange}
327
- onReset={handleReset}
328
- />
329
- </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)} />
330
321
  {/if}
331
-
332
- <CollapsiblePanel title="Props">
333
- <DataTable
334
- columns={[
335
- { key: 'name', label: 'Name' },
336
- { key: 'type', label: 'Type' },
337
- { key: 'default', label: 'Default' },
338
- { key: 'required', label: 'Required' },
339
- { key: 'description', label: 'Description' },
340
- ]}
341
- rows={propsRows}
342
- />
343
- </CollapsiblePanel>
344
-
345
- <CollapsiblePanel title="CSS Props">
346
- <DataTable
347
- columns={[
348
- { key: 'name', label: 'Name' },
349
- { key: 'type', label: 'Type' },
350
- { key: 'default', label: 'Default' },
351
- { key: 'description', label: 'Description' },
352
- ]}
353
- rows={cssPropsRows}
354
- />
355
- </CollapsiblePanel>
356
-
357
- <CollapsiblePanel title="Events">
358
- <DataTable
359
- columns={[
360
- { key: 'name', label: 'Name' },
361
- { key: 'type', label: 'Type' },
362
- { key: 'description', label: 'Description' },
363
- ]}
364
- rows={eventsRows}
365
- />
366
- </CollapsiblePanel>
367
-
368
- <CollapsiblePanel title="Snippets">
369
- <DataTable
370
- columns={[
371
- { key: 'name', label: 'Name' },
372
- { key: 'type', label: 'Type' },
373
- { key: 'description', label: 'Description' },
374
- ]}
375
- rows={snippetsRows}
376
- />
377
- </CollapsiblePanel>
378
-
379
- <CollapsiblePanel title="Methods">
380
- <DataTable
381
- columns={[
382
- { key: 'name', label: 'Name' },
383
- { key: 'params', label: 'Parameters' },
384
- { key: 'returns', label: 'Returns' },
385
- { key: 'description', label: 'Description' },
386
- ]}
387
- rows={methodsRows}
388
- />
389
- </CollapsiblePanel>
390
-
391
- <CollapsiblePanel title="State">
392
- <DataTable
393
- columns={[
394
- { key: 'name', label: 'Name' },
395
- { key: 'type', label: 'Type' },
396
- { key: 'description', label: 'Description' },
397
- ]}
398
- rows={stateRows}
399
- />
400
- </CollapsiblePanel>
401
-
402
- </div>
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>
403
410
 
404
411
  {#if exampleSnippets.length > 0}
405
412
  <hr class="sdocs-divider" />
@@ -436,9 +443,54 @@
436
443
  <style>
437
444
  .sdocs-component-view {
438
445
  padding: 24px 32px;
439
- max-width: 960px;
446
+ max-width: 1120px;
440
447
  font-family: var(--sans);
441
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
+ }
442
494
  .sdocs-view-header {
443
495
  margin-bottom: 24px;
444
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 {};