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.
Files changed (32) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/explorer/views/ApiTable.svelte +138 -0
  3. package/dist/explorer/views/ApiTable.svelte.d.ts +14 -0
  4. package/dist/explorer/views/ComponentView.svelte +154 -87
  5. package/dist/explorer/views/CssPropControl.svelte +27 -0
  6. package/dist/explorer/views/CssPropControl.svelte.d.ts +14 -0
  7. package/dist/explorer/views/DataTable.svelte +46 -4
  8. package/dist/explorer/views/PreviewFrame.svelte +11 -1
  9. package/dist/explorer/views/PreviewFrame.svelte.d.ts +4 -1
  10. package/dist/explorer/views/PropControl.svelte +69 -0
  11. package/dist/explorer/views/PropControl.svelte.d.ts +14 -0
  12. package/dist/explorer/views/format.d.ts +6 -0
  13. package/dist/explorer/views/format.js +44 -0
  14. package/dist/server/snippet-compiler.d.ts +3 -2
  15. package/dist/server/snippet-compiler.js +36 -4
  16. package/dist/ui/Control/Checkbox.svelte +6 -3
  17. package/dist/ui/Control/Color.svelte +6 -3
  18. package/dist/ui/Control/Dimension.svelte +8 -4
  19. package/dist/ui/Control/Number.svelte +6 -4
  20. package/dist/ui/Control/Select.svelte +6 -4
  21. package/dist/ui/Control/Text.svelte +6 -3
  22. package/dist/ui/Icon/Icon.svelte +10 -0
  23. package/dist/ui/Icon/icons/database.svg +5 -0
  24. package/dist/ui/Icon/icons/palette.svg +7 -0
  25. package/dist/ui/Icon/icons/sliders-horizontal.svg +11 -0
  26. package/dist/ui/Icon/icons/square-function.svg +5 -0
  27. package/dist/ui/Icon/icons/zap.svg +3 -0
  28. package/dist/ui/styles/sdocs.css +49 -0
  29. package/dist/vite.js +2 -1
  30. package/package.json +1 -1
  31. package/dist/explorer/views/ControlsPanel.svelte +0 -186
  32. package/dist/explorer/views/ControlsPanel.svelte.d.ts +0 -14
@@ -0,0 +1,69 @@
1
+ <script lang="ts">
2
+ import type { ParsedProp } from '../../types.js';
3
+ import { Text as TextControl, Number as NumberControl, Checkbox as CheckboxControl, Select as SelectControl } from '../../ui/Control/index.js';
4
+
5
+ interface Props {
6
+ prop: ParsedProp;
7
+ value: unknown;
8
+ onchange: (value: unknown) => void;
9
+ }
10
+
11
+ let { prop, value, onchange }: Props = $props();
12
+
13
+ /** Parse union type strings like "'sm' | 'md' | 'lg'" or "1 | 2 | 3" into option arrays */
14
+ function parseUnionOptions(type: string | null): string[] | null {
15
+ if (!type || !type.includes('|')) return null;
16
+ const parts = type.split('|').map((s) => s.trim());
17
+ const values: string[] = [];
18
+ let allStrings = true;
19
+ let allNumbers = true;
20
+ for (const part of parts) {
21
+ // Quoted string: 'value' or "value"
22
+ const strMatch = part.match(/^['"](.+)['"]$/);
23
+ if (strMatch) {
24
+ values.push(strMatch[1]);
25
+ allNumbers = false;
26
+ continue;
27
+ }
28
+ // Bare number: 1, 2, 3
29
+ if (/^\d+(\.\d+)?$/.test(part)) {
30
+ values.push(part);
31
+ allStrings = false;
32
+ continue;
33
+ }
34
+ // Mixed or unsupported (e.g. 'medium' | number) → null
35
+ return null;
36
+ }
37
+ if (values.length > 0 && (allStrings || allNumbers)) return values;
38
+ return null;
39
+ }
40
+
41
+ const controlType = $derived.by(() => {
42
+ const t = prop.type?.toLowerCase() ?? '';
43
+ if (t === 'string') return 'text';
44
+ if (t === 'number') return 'number';
45
+ if (t === 'boolean') return 'boolean';
46
+ if (parseUnionOptions(prop.type)) return 'select';
47
+ return 'readonly';
48
+ });
49
+
50
+ const options = $derived(parseUnionOptions(prop.type) ?? []);
51
+ </script>
52
+
53
+ {#if controlType === 'text'}
54
+ <TextControl value={String(value ?? prop.default ?? '')} {onchange} />
55
+ {:else if controlType === 'number'}
56
+ <NumberControl value={Number(value ?? prop.default ?? 0)} {onchange} />
57
+ {:else if controlType === 'boolean'}
58
+ <CheckboxControl value={Boolean(value ?? (prop.default === 'true'))} {onchange} />
59
+ {:else if controlType === 'select'}
60
+ <SelectControl value={String(value ?? prop.default ?? options[0] ?? '')} {options} {onchange} />
61
+ {:else}
62
+ <span class="sdocs-control-unsupported">—</span>
63
+ {/if}
64
+
65
+ <style>
66
+ .sdocs-control-unsupported {
67
+ color: var(--color-base-300);
68
+ }
69
+ </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 PropControlProps = typeof __propDef.props;
10
+ export type PropControlEvents = typeof __propDef.events;
11
+ export type PropControlSlots = typeof __propDef.slots;
12
+ export default class PropControl extends SvelteComponentTyped<PropControlProps, PropControlEvents, PropControlSlots> {
13
+ }
14
+ export {};
@@ -0,0 +1,6 @@
1
+ /** Classify a type string for color coding (conventions, not a formal standard) */
2
+ export declare function typeClass(value: unknown): string;
3
+ /** Classify a literal value for color coding (defaults, current state) */
4
+ export declare function valueClass(value: unknown): string;
5
+ /** Split a clean union type into its members; everything else stays whole */
6
+ export declare function typeParts(value: unknown): string[];
@@ -0,0 +1,44 @@
1
+ /** Classify a type string for color coding (conventions, not a formal standard) */
2
+ export function typeClass(value) {
3
+ const v = String(value).trim();
4
+ if (v === 'string' || /^'[^']*'(\s*\|\s*'[^']*')*$/.test(v))
5
+ return 'string';
6
+ if (v === 'number' || /^\d+(\.\d+)?(\s*\|\s*\d+(\.\d+)?)*$/.test(v))
7
+ return 'number';
8
+ if (v === 'boolean')
9
+ return 'boolean';
10
+ if (v.includes('=>'))
11
+ return 'function';
12
+ if (v.startsWith('Snippet'))
13
+ return 'snippet';
14
+ if (v === 'color')
15
+ return 'color';
16
+ if (v === 'dimension')
17
+ return 'dimension';
18
+ if (v === 'void' || v === 'undefined' || v === 'null')
19
+ return 'void';
20
+ return 'other';
21
+ }
22
+ /** Classify a literal value for color coding (defaults, current state) */
23
+ export function valueClass(value) {
24
+ const v = String(value).trim();
25
+ if (v === 'true' || v === 'false')
26
+ return 'boolean';
27
+ if (/^-?\d+(\.\d+)?$/.test(v))
28
+ return 'number';
29
+ if (/^-?\d+(\.\d+)?(px|rem|em|%|vh|vw|ch|pt)$/.test(v))
30
+ return 'dimension';
31
+ if (/^(#[0-9a-fA-F]{3,8}$|hsla?\(|rgba?\(|oklch\(|oklab\()/.test(v))
32
+ return 'color';
33
+ if (v.startsWith('{') || v.startsWith('['))
34
+ return 'other';
35
+ return 'string';
36
+ }
37
+ /** Split a clean union type into its members; everything else stays whole */
38
+ export function typeParts(value) {
39
+ const v = String(value).trim();
40
+ if (/^'[^']*'(\s*\|\s*'[^']*')+$/.test(v) || /^\d+(\.\d+)?(\s*\|\s*\d+(\.\d+)?)+$/.test(v)) {
41
+ return v.split('|').map((part) => part.trim());
42
+ }
43
+ return [v];
44
+ }
@@ -9,8 +9,9 @@ export declare function encodeDocPath(filePath: string): string;
9
9
  /** Resolve relative imports to absolute paths for use in virtual components */
10
10
  export declare function resolveImportsToAbsolute(imports: string[], docFilePath: string): string[];
11
11
  /** Generate a virtual Svelte iframe wrapper component for a snippet.
12
- * Includes $state for reactive prop updates via postMessage. */
13
- export declare function generateIframeComponent(absoluteImports: string[], snippetBody: string): string;
12
+ * Includes $state for reactive prop updates via postMessage, invokes
13
+ * component methods on request, and broadcasts exported state values. */
14
+ export declare function generateIframeComponent(absoluteImports: string[], snippetBody: string, stateNames?: string[]): string;
14
15
  /** The JS that boots a preview page: mount the wrapper + parent-frame messaging. */
15
16
  export declare function generateMountScript(iframeComponentId: string): string;
16
17
  /** Generate the HTML page served inside the iframe (dev / CLI-build inputs) */
@@ -35,23 +35,55 @@ export function resolveImportsToAbsolute(imports, docFilePath) {
35
35
  return imp;
36
36
  });
37
37
  }
38
+ /** Add bind:this to the snippet's root component so the wrapper can reach
39
+ * its exported methods and state. Skipped when the author already binds. */
40
+ function injectRootRef(snippetBody) {
41
+ if (snippetBody.includes('bind:this'))
42
+ return snippetBody;
43
+ const match = snippetBody.match(/<([A-Z][A-Za-z0-9_]*)/);
44
+ if (!match || match.index === undefined)
45
+ return snippetBody;
46
+ const insertAt = match.index + match[0].length;
47
+ return snippetBody.slice(0, insertAt) + ' bind:this={__sdocsRef}' + snippetBody.slice(insertAt);
48
+ }
38
49
  /** Generate a virtual Svelte iframe wrapper component for a snippet.
39
- * Includes $state for reactive prop updates via postMessage. */
40
- export function generateIframeComponent(absoluteImports, snippetBody) {
50
+ * Includes $state for reactive prop updates via postMessage, invokes
51
+ * component methods on request, and broadcasts exported state values. */
52
+ export function generateIframeComponent(absoluteImports, snippetBody, stateNames = []) {
41
53
  const importBlock = absoluteImports.length > 0
42
54
  ? absoluteImports.join('\n') + '\n'
43
55
  : '';
56
+ const stateBroadcast = stateNames.length > 0
57
+ ? `
58
+ $effect(() => {
59
+ const values: Record<string, unknown> = {};
60
+ for (const name of ${JSON.stringify(stateNames)}) {
61
+ try {
62
+ const v = (__sdocsRef as Record<string, unknown> | undefined)?.[name];
63
+ values[name] = v === undefined ? undefined : JSON.parse(JSON.stringify($state.snapshot(v)));
64
+ } catch {
65
+ values[name] = undefined;
66
+ }
67
+ }
68
+ window.parent.postMessage({ type: 'sdocs:state-values', values }, '*');
69
+ });
70
+ `
71
+ : '';
44
72
  // lang="ts" so lifted imports may carry type-only syntax (Svelte 5 erases it natively)
45
73
  return `<script lang="ts">
46
74
  ${importBlock}import { onMount } from 'svelte';
47
75
 
48
76
  let args = $state({});
49
-
77
+ let __sdocsRef = $state();
78
+ ${stateBroadcast}
50
79
  onMount(() => {
51
80
  window.addEventListener('message', (e) => {
52
81
  if (e.data?.type === 'sdocs:update-props') {
53
82
  args = { ...e.data.props };
54
83
  }
84
+ if (e.data?.type === 'sdocs:call-method') {
85
+ (__sdocsRef as Record<string, () => void> | undefined)?.[e.data.name]?.();
86
+ }
55
87
  if (e.data?.type === 'sdocs:update-css') {
56
88
  const el = document.getElementById('sdocs-preview');
57
89
  if (el) {
@@ -86,7 +118,7 @@ export function generateIframeComponent(absoluteImports, snippetBody) {
86
118
 
87
119
  <div id="sdocs-preview">
88
120
  {#snippet SdocsPreview(args)}
89
- ${snippetBody}
121
+ ${injectRootRef(snippetBody)}
90
122
  {/snippet}
91
123
  {@render SdocsPreview(args)}
92
124
  </div>`;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  interface Props {
3
- label: string;
3
+ /** Optional label; omit when the control sits next to its name (e.g. in a table) */
4
+ label?: string;
4
5
  value: boolean;
5
6
  onchange: (value: boolean) => void;
6
7
  }
@@ -9,7 +10,9 @@
9
10
  </script>
10
11
 
11
12
  <label class="sdocs-control">
12
- <span class="sdocs-control-label">{label}</span>
13
+ {#if label}
14
+ <span class="sdocs-control-label">{label}</span>
15
+ {/if}
13
16
  <input
14
17
  type="checkbox"
15
18
  checked={value}
@@ -28,7 +31,7 @@
28
31
  .sdocs-control-label {
29
32
  min-width: 100px;
30
33
  color: var(--color-base-600);
31
- font-weight: 500;
34
+ font-weight: 600;
32
35
  }
33
36
  .sdocs-control-checkbox {
34
37
  width: 16px;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  interface Props {
3
- label: string;
3
+ /** Optional label; omit when the control sits next to its name (e.g. in a table) */
4
+ label?: string;
4
5
  value: string;
5
6
  onchange: (value: string) => void;
6
7
  }
@@ -9,7 +10,9 @@
9
10
  </script>
10
11
 
11
12
  <label class="sdocs-control">
12
- <span class="sdocs-control-label">{label}</span>
13
+ {#if label}
14
+ <span class="sdocs-control-label">{label}</span>
15
+ {/if}
13
16
  <input
14
17
  type="color"
15
18
  {value}
@@ -29,7 +32,7 @@
29
32
  .sdocs-control-label {
30
33
  min-width: 100px;
31
34
  color: var(--color-base-600);
32
- font-weight: 500;
35
+ font-weight: 600;
33
36
  }
34
37
  .sdocs-control-color {
35
38
  width: 32px;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  interface Props {
3
- label: string;
3
+ /** Optional label; omit when the control sits next to its name (e.g. in a table) */
4
+ label?: string;
4
5
  value: string;
5
6
  onchange: (value: string) => void;
6
7
  }
@@ -10,7 +11,9 @@
10
11
  </script>
11
12
 
12
13
  <label class="sdocs-control">
13
- <span class="sdocs-control-label">{label}</span>
14
+ {#if label}
15
+ <span class="sdocs-control-label">{label}</span>
16
+ {/if}
14
17
  <div class="sdocs-control-dimension">
15
18
  <input
16
19
  type="number"
@@ -32,7 +35,7 @@
32
35
  .sdocs-control-label {
33
36
  min-width: 100px;
34
37
  color: var(--color-base-600);
35
- font-weight: 500;
38
+ font-weight: 600;
36
39
  }
37
40
  .sdocs-control-dimension {
38
41
  display: flex;
@@ -40,7 +43,8 @@
40
43
  gap: 4px;
41
44
  }
42
45
  .sdocs-control-input {
43
- width: 80px;
46
+ flex: 1;
47
+ min-width: 0;
44
48
  padding: 4px 8px;
45
49
  border: 1px solid var(--color-base-200);
46
50
  border-radius: 4px;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  interface Props {
3
- label: string;
3
+ /** Optional label; omit when the control sits next to its name (e.g. in a table) */
4
+ label?: string;
4
5
  value: number;
5
6
  onchange: (value: number) => void;
6
7
  }
@@ -9,7 +10,9 @@
9
10
  </script>
10
11
 
11
12
  <label class="sdocs-control">
12
- <span class="sdocs-control-label">{label}</span>
13
+ {#if label}
14
+ <span class="sdocs-control-label">{label}</span>
15
+ {/if}
13
16
  <input
14
17
  type="number"
15
18
  {value}
@@ -28,7 +31,7 @@
28
31
  .sdocs-control-label {
29
32
  min-width: 100px;
30
33
  color: var(--color-base-600);
31
- font-weight: 500;
34
+ font-weight: 600;
32
35
  }
33
36
  .sdocs-control-input {
34
37
  flex: 1;
@@ -39,6 +42,5 @@
39
42
  border-radius: 4px;
40
43
  font: inherit;
41
44
  font-size: 13px;
42
- max-width: 120px;
43
45
  }
44
46
  </style>
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  interface Props {
3
- label: string;
3
+ /** Optional label; omit when the control sits next to its name (e.g. in a table) */
4
+ label?: string;
4
5
  value: string;
5
6
  options: string[];
6
7
  onchange: (value: string) => void;
@@ -10,7 +11,9 @@
10
11
  </script>
11
12
 
12
13
  <label class="sdocs-control">
13
- <span class="sdocs-control-label">{label}</span>
14
+ {#if label}
15
+ <span class="sdocs-control-label">{label}</span>
16
+ {/if}
14
17
  <select
15
18
  class="sdocs-control-select"
16
19
  {value}
@@ -32,7 +35,7 @@
32
35
  .sdocs-control-label {
33
36
  min-width: 100px;
34
37
  color: var(--color-base-600);
35
- font-weight: 500;
38
+ font-weight: 600;
36
39
  }
37
40
  .sdocs-control-select {
38
41
  flex: 1;
@@ -43,6 +46,5 @@
43
46
  font-size: 13px;
44
47
  background: var(--color-base-0);
45
48
  color: var(--color-base-600);
46
- max-width: 200px;
47
49
  }
48
50
  </style>
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  interface Props {
3
- label: string;
3
+ /** Optional label; omit when the control sits next to its name (e.g. in a table) */
4
+ label?: string;
4
5
  value: string;
5
6
  onchange: (value: string) => void;
6
7
  }
@@ -9,7 +10,9 @@
9
10
  </script>
10
11
 
11
12
  <label class="sdocs-control">
12
- <span class="sdocs-control-label">{label}</span>
13
+ {#if label}
14
+ <span class="sdocs-control-label">{label}</span>
15
+ {/if}
13
16
  <input
14
17
  type="text"
15
18
  {value}
@@ -28,7 +31,7 @@
28
31
  .sdocs-control-label {
29
32
  min-width: 100px;
30
33
  color: var(--color-base-600);
31
- font-weight: 500;
34
+ font-weight: 600;
32
35
  }
33
36
  .sdocs-control-input {
34
37
  flex: 1;
@@ -7,13 +7,18 @@
7
7
  import codeSvg from './icons/code.svg?raw';
8
8
  import componentSvg from './icons/component.svg?raw';
9
9
  import copySvg from './icons/copy.svg?raw';
10
+ import databaseSvg from './icons/database.svg?raw';
10
11
  import diamondSvg from './icons/diamond.svg?raw';
11
12
  import fileCodeSvg from './icons/file-code.svg?raw';
12
13
  import fileTextSvg from './icons/file-text.svg?raw';
13
14
  import folderOpenSvg from './icons/folder-open.svg?raw';
14
15
  import folderSvg from './icons/folder.svg?raw';
16
+ import paletteSvg from './icons/palette.svg?raw';
15
17
  import panelsTopLeftSvg from './icons/panels-top-left.svg?raw';
16
18
  import sdocsSvg from './icons/sdocs.svg?raw';
19
+ import slidersHorizontalSvg from './icons/sliders-horizontal.svg?raw';
20
+ import squareFunctionSvg from './icons/square-function.svg?raw';
21
+ import zapSvg from './icons/zap.svg?raw';
17
22
 
18
23
  const icons: Record<string, string> = {
19
24
  'bookmark': bookmarkSvg,
@@ -24,13 +29,18 @@
24
29
  'code': codeSvg,
25
30
  'component': componentSvg,
26
31
  'copy': copySvg,
32
+ 'database': databaseSvg,
27
33
  'diamond': diamondSvg,
28
34
  'file-code': fileCodeSvg,
29
35
  'file-text': fileTextSvg,
30
36
  'folder-open': folderOpenSvg,
31
37
  'folder': folderSvg,
38
+ 'palette': paletteSvg,
32
39
  'panels-top-left': panelsTopLeftSvg,
33
40
  'sdocs': sdocsSvg,
41
+ 'sliders-horizontal': slidersHorizontalSvg,
42
+ 'square-function': squareFunctionSvg,
43
+ 'zap': zapSvg,
34
44
  };
35
45
 
36
46
  /**
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <ellipse cx="12" cy="5" rx="9" ry="3"/>
3
+ <path d="M3 5V19A9 3 0 0 0 21 19V5"/>
4
+ <path d="M3 12A9 3 0 0 0 21 12"/>
5
+ </svg>
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/>
3
+ <circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/>
4
+ <circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/>
5
+ <circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/>
6
+ <path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/>
7
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <line x1="21" x2="14" y1="4" y2="4"/>
3
+ <line x1="10" x2="3" y1="4" y2="4"/>
4
+ <line x1="21" x2="12" y1="12" y2="12"/>
5
+ <line x1="8" x2="3" y1="12" y2="12"/>
6
+ <line x1="21" x2="16" y1="20" y2="20"/>
7
+ <line x1="12" x2="3" y1="20" y2="20"/>
8
+ <line x1="14" x2="14" y1="2" y2="6"/>
9
+ <line x1="8" x2="8" y1="10" y2="14"/>
10
+ <line x1="16" x2="16" y1="18" y2="22"/>
11
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <rect width="18" height="18" x="3" y="3" rx="2"/>
3
+ <path d="M9 17c2 0 2.8-1 2.8-2.8V10c0-2 1-3.3 3.2-3"/>
4
+ <path d="M9 11.2h5.7"/>
5
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>
3
+ </svg>
@@ -28,6 +28,55 @@
28
28
  text-decoration: none;
29
29
  }
30
30
 
31
+ /* Type chips and value literals, color-coded by kind (shared by doc tables) */
32
+ .sdocs-app code[class*='sdocs-type-'] {
33
+ font-family: var(--mono);
34
+ font-size: 12px;
35
+ padding: 1px 4px;
36
+ border-radius: 3px;
37
+ }
38
+ .sdocs-app code.sdocs-type-string { color: var(--color-green-700); background: var(--color-green-100); }
39
+ .sdocs-app code.sdocs-type-number { color: var(--color-amber-700); background: var(--color-amber-100); }
40
+ .sdocs-app code.sdocs-type-boolean { color: var(--color-purple-700); background: var(--color-purple-100); }
41
+ .sdocs-app code.sdocs-type-function { color: var(--color-blue-700); background: var(--color-blue-100); }
42
+ .sdocs-app code.sdocs-type-snippet { color: var(--color-pink-700); background: var(--color-pink-100); }
43
+ .sdocs-app code.sdocs-type-color { color: var(--color-cyan-700); background: var(--color-cyan-100); }
44
+ .sdocs-app code.sdocs-type-dimension { color: var(--color-amber-700); background: var(--color-amber-100); }
45
+ .sdocs-app code.sdocs-type-void { color: var(--color-slate-500); background: var(--color-slate-100); }
46
+ .sdocs-app code.sdocs-type-other { color: var(--color-base-700); background: var(--color-base-100); }
47
+
48
+ .sdocs-app .sdocs-typesep {
49
+ font-family: var(--mono);
50
+ font-size: 12px;
51
+ color: var(--color-base-300);
52
+ }
53
+
54
+ .sdocs-app .sdocs-value {
55
+ font-family: var(--mono);
56
+ font-size: 12px;
57
+ }
58
+ .sdocs-app .sdocs-value-string { color: var(--color-green-700); }
59
+ .sdocs-app .sdocs-value-number { color: var(--color-amber-700); }
60
+ .sdocs-app .sdocs-value-boolean { color: var(--color-purple-700); }
61
+ .sdocs-app .sdocs-value-dimension { color: var(--color-amber-700); }
62
+ .sdocs-app .sdocs-value-color { color: var(--color-cyan-700); }
63
+ .sdocs-app .sdocs-value-other { color: var(--color-base-600); }
64
+
65
+ /* Raw hue tokens don't invert with the theme; flip shades for dark */
66
+ .sdocs-app[data-sdocs-theme='dark'] code.sdocs-type-string { color: var(--color-green-400); background: var(--color-green-950); }
67
+ .sdocs-app[data-sdocs-theme='dark'] code.sdocs-type-number { color: var(--color-amber-400); background: var(--color-amber-950); }
68
+ .sdocs-app[data-sdocs-theme='dark'] code.sdocs-type-boolean { color: var(--color-purple-400); background: var(--color-purple-950); }
69
+ .sdocs-app[data-sdocs-theme='dark'] code.sdocs-type-function { color: var(--color-blue-400); background: var(--color-blue-950); }
70
+ .sdocs-app[data-sdocs-theme='dark'] code.sdocs-type-snippet { color: var(--color-pink-400); background: var(--color-pink-950); }
71
+ .sdocs-app[data-sdocs-theme='dark'] code.sdocs-type-color { color: var(--color-cyan-400); background: var(--color-cyan-950); }
72
+ .sdocs-app[data-sdocs-theme='dark'] code.sdocs-type-dimension { color: var(--color-amber-400); background: var(--color-amber-950); }
73
+ .sdocs-app[data-sdocs-theme='dark'] code.sdocs-type-void { color: var(--color-slate-400); background: var(--color-slate-950); }
74
+ .sdocs-app[data-sdocs-theme='dark'] .sdocs-value-string { color: var(--color-green-400); }
75
+ .sdocs-app[data-sdocs-theme='dark'] .sdocs-value-number { color: var(--color-amber-400); }
76
+ .sdocs-app[data-sdocs-theme='dark'] .sdocs-value-boolean { color: var(--color-purple-400); }
77
+ .sdocs-app[data-sdocs-theme='dark'] .sdocs-value-dimension { color: var(--color-amber-400); }
78
+ .sdocs-app[data-sdocs-theme='dark'] .sdocs-value-color { color: var(--color-cyan-400); }
79
+
31
80
  .sdocs-app[data-sdocs-theme='dark'] {
32
81
  /* base — layouts, backgrounds, surfaces, borders, text (inverted) */
33
82
  --color-base-0: var(--color-zinc-1000);
package/dist/vite.js CHANGED
@@ -216,7 +216,8 @@ export function sdocsPlugin(userConfig) {
216
216
  if (!snippet)
217
217
  return null;
218
218
  const absoluteImports = docImportsCache.get(parsed.docFilePath) ?? [];
219
- return generateIframeComponent(absoluteImports, snippet.body);
219
+ const stateNames = (entry.componentData?.state ?? []).map((s) => s.name);
220
+ return generateIframeComponent(absoluteImports, snippet.body, stateNames);
220
221
  }
221
222
  // Virtual mount script for an emitted preview page
222
223
  if (id.startsWith('\0' + MOUNT_PREFIX)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdocs",
3
- "version": "0.0.36",
3
+ "version": "0.0.37",
4
4
  "description": "A lightweight documentation tool for Svelte 5 components",
5
5
  "type": "module",
6
6
  "license": "MIT",