solid-tom-ui 1.0.10 → 1.0.14
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/README.md +246 -246
- package/dist/README.md +246 -246
- package/dist/components/avatar/avatar.js.map +1 -1
- package/dist/components/badge/badge.js.map +1 -1
- package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/carousel/carousel.js.map +1 -1
- package/dist/components/chat-bubble/chatBubble.js.map +1 -1
- package/dist/components/checkbox/checkbox.js.map +1 -1
- package/dist/components/collapse/collapse.js.map +1 -1
- package/dist/components/context-menu/context-menu.js.map +1 -1
- package/dist/components/context-menu/context-menu.store.js.map +1 -1
- package/dist/components/divider/divider.js.map +1 -1
- package/dist/components/dropdown/dropdown.js.map +1 -1
- package/dist/components/dropdown/dropdown.store.js.map +1 -1
- package/dist/components/float-button/float-button.js.map +1 -1
- package/dist/components/hover-3d-image/hover-3d-image.js.map +1 -1
- package/dist/components/image-preview/image-preview.js.map +1 -1
- package/dist/components/input/input.js.map +1 -1
- package/dist/components/input/input.utils.js.map +1 -1
- package/dist/components/input/variants/input-color.js.map +1 -1
- package/dist/components/input/variants/input-date.js.map +1 -1
- package/dist/components/input/variants/input-number.d.ts.map +1 -1
- package/dist/components/input/variants/input-number.js +1 -1
- package/dist/components/input/variants/input-number.js.map +1 -1
- package/dist/components/input/variants/input-otp.js.map +1 -1
- package/dist/components/input/variants/input-password.js.map +1 -1
- package/dist/components/input/variants/input-radio.js.map +1 -1
- package/dist/components/input/variants/input-range.js.map +1 -1
- package/dist/components/input/variants/input-text.d.ts.map +1 -1
- package/dist/components/input/variants/input-text.js +1 -1
- package/dist/components/input/variants/input-text.js.map +1 -1
- package/dist/components/input/variants/input-textarea.js.map +1 -1
- package/dist/components/loading/loading.js.map +1 -1
- package/dist/components/mansory/mansory.js.map +1 -1
- package/dist/components/menu/menu.js.map +1 -1
- package/dist/components/menu/menu.types.d.ts +2 -3
- package/dist/components/menu/menu.types.d.ts.map +1 -1
- package/dist/components/modal/modal.js.map +1 -1
- package/dist/components/modal/modalContext.js.map +1 -1
- package/dist/components/pagination/pagination.js.map +1 -1
- package/dist/components/progress-bar/progress-bar.js.map +1 -1
- package/dist/components/qr-code/qr-code.js.map +1 -1
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/select-zone/select-zone.js.map +1 -1
- package/dist/components/skeleton/skeleton.js.map +1 -1
- package/dist/components/slider/slider.js.map +1 -1
- package/dist/components/splitter/splitter.js.map +1 -1
- package/dist/components/steps/steps.js.map +1 -1
- package/dist/components/swap/swap.js.map +1 -1
- package/dist/components/switch/switch.js.map +1 -1
- package/dist/components/tab/tab.js.map +1 -1
- package/dist/components/table/table.js.map +1 -1
- package/dist/components/timeline/timeline.js.map +1 -1
- package/dist/components/toast/icons/ErrorIcon.js.map +1 -1
- package/dist/components/toast/icons/IconCircle.js.map +1 -1
- package/dist/components/toast/icons/InfoIcon.js.map +1 -1
- package/dist/components/toast/icons/LoaderIcon.js.map +1 -1
- package/dist/components/toast/icons/SuccessIcon.js.map +1 -1
- package/dist/components/toast/icons/WarningIcon.js.map +1 -1
- package/dist/components/toast/toast.js.map +1 -1
- package/dist/components/toast/toast.store.js.map +1 -1
- package/dist/components/tooltip/tooltip.js.map +1 -1
- package/dist/components/tour/tour.js.map +1 -1
- package/dist/components/upload/upload.js.map +1 -1
- package/dist/components/z-index/z-index.context.js.map +1 -1
- package/dist/components/z-index/z-index.js.map +1 -1
- package/dist/components/z-index/z-index.store.js.map +1 -1
- package/dist/components/z-index/z-index.types.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/skill/avatar.skill.md.txt +255 -255
- package/dist/skill/badge.skill.md.txt +223 -223
- package/dist/skill/breadcrumb.skill.md.txt +177 -177
- package/dist/skill/button.skill.md.txt +198 -198
- package/dist/skill/carousel.skill.md.txt +406 -406
- package/dist/skill/chat-bubble.skill.md.txt +342 -342
- package/dist/skill/checkbox.skill.md.txt +326 -326
- package/dist/skill/code-preview.skill.md.txt +240 -240
- package/dist/skill/collapse.skill.md.txt +329 -329
- package/dist/skill/context-menu.skill.md.txt +233 -233
- package/dist/skill/diff.skill.md.txt +244 -244
- package/dist/skill/divider.skill.md.txt +151 -151
- package/dist/skill/doc.skill.md.txt +191 -191
- package/dist/skill/drawer.skill.md.txt +157 -157
- package/dist/skill/dropdown.skill.md.txt +198 -198
- package/dist/skill/float-button.skill.md.txt +315 -315
- package/dist/skill/hover-3d-image.skill.md.txt +120 -120
- package/dist/skill/iframe.skill.md.txt +114 -114
- package/dist/skill/image-preview.skill.md.txt +162 -162
- package/dist/skill/indicator.skill.md.txt +60 -60
- package/dist/skill/input.skill.md.txt +489 -489
- package/dist/skill/loading.skill.md.txt +127 -127
- package/dist/skill/menu.skill.md.txt +476 -476
- package/dist/skill/modal.skill.md.txt +359 -359
- package/dist/skill/pagination.skill.md.txt +405 -405
- package/dist/skill/progress-bar.skill.md.txt +207 -207
- package/dist/skill/qr-code.skill.md.txt +136 -136
- package/dist/skill/rating.skill.md.txt +167 -167
- package/dist/skill/select-zone.skill.md.txt +93 -93
- package/dist/skill/select.skill.md.txt +663 -663
- package/dist/skill/skeleton.skill.md.txt +192 -192
- package/dist/skill/slider.skill.md.txt +404 -404
- package/dist/skill/splitter.skill.md.txt +411 -411
- package/dist/skill/steps.skill.md.txt +264 -264
- package/dist/skill/swap.skill.md.txt +139 -139
- package/dist/skill/switch.skill.md.txt +191 -191
- package/dist/skill/tab.skill.md.txt +484 -484
- package/dist/skill/table.example.header.md.txt +666 -666
- package/dist/skill/table.skill.md.txt +1407 -1407
- package/dist/skill/text-rotate.skill.md.txt +186 -186
- package/dist/skill/timeline.skill.md.txt +247 -247
- package/dist/skill/toast.skill.md.txt +531 -531
- package/dist/skill/tooltip.skill.md.txt +222 -222
- package/dist/skill/tour.skill.md.txt +156 -156
- package/dist/skill/upload.skill.md.txt +358 -358
- package/dist/utils/cn.js.map +1 -1
- package/dist/utils/element-tracker.js.map +1 -1
- package/dist/utils/helper.js.map +1 -1
- package/dist/utils/hoc.js.map +1 -1
- package/package.json +132 -133
|
@@ -1,191 +1,191 @@
|
|
|
1
|
-
## COMPONENT IDENTITY
|
|
2
|
-
- **Import**: `import { CodePreview } from '@/components/doc/CodePreview';`
|
|
3
|
-
- **Export**: `CodePreview` (named export)
|
|
4
|
-
- **Framework**: SolidJS
|
|
5
|
-
- **Purpose**: Internal documentation UI — the `doc` folder builds the library's documentation pages; NOT general-purpose UI components; NOT exported from `solid-tom-ui`
|
|
6
|
-
|
|
7
|
-
## PURPOSE
|
|
8
|
-
Renders a tabbed panel with two views:
|
|
9
|
-
1. **Preview tab**: renders the given SolidJS component visually.
|
|
10
|
-
2. **Code tab**: shows syntax-highlighted TypeScript/TSX source code with a copy button.
|
|
11
|
-
|
|
12
|
-
## TYPE SIGNATURE
|
|
13
|
-
```typescript
|
|
14
|
-
import { CodePreview } from 'solid-tom-ui';
|
|
15
|
-
import { Component } from 'solid-js';
|
|
16
|
-
|
|
17
|
-
<CodePreview
|
|
18
|
-
preview={Component<any>} // REQUIRED: SolidJS component to render as preview
|
|
19
|
-
code={string} // REQUIRED: source code string to display (raw TSX/TS)
|
|
20
|
-
title?={string} // optional title (currently not rendered in UI)
|
|
21
|
-
language?={string} // highlight.js language ID; default: 'typescript'
|
|
22
|
-
classNames?={{
|
|
23
|
-
previewBlock?: string; // extra class on the preview container div
|
|
24
|
-
}}
|
|
25
|
-
/>
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## USAGE PATTERN
|
|
29
|
-
```tsx
|
|
30
|
-
import { CodePreview } from '@/components/doc/CodePreview';
|
|
31
|
-
import { MyExampleComponent } from './my-component.example';
|
|
32
|
-
|
|
33
|
-
const exampleCode = `
|
|
34
|
-
import { MyComponent } from '@/components/my-component';
|
|
35
|
-
|
|
36
|
-
const Example = () => (
|
|
37
|
-
<MyComponent color="primary" size="md">
|
|
38
|
-
Hello
|
|
39
|
-
</MyComponent>
|
|
40
|
-
);
|
|
41
|
-
`.trim();
|
|
42
|
-
|
|
43
|
-
<CodePreview
|
|
44
|
-
preview={MyExampleComponent}
|
|
45
|
-
code={exampleCode}
|
|
46
|
-
/>
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## With custom preview container class
|
|
50
|
-
```tsx
|
|
51
|
-
<CodePreview
|
|
52
|
-
preview={DarkBgExample}
|
|
53
|
-
code={darkCode}
|
|
54
|
-
classNames={{ previewBlock: 'bg-gray-900 min-h-48' }}
|
|
55
|
-
/>
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## CONSTRAINTS
|
|
59
|
-
- `preview` must be a **component reference** (not rendered JSX). It is rendered via `<Dynamic component={props.preview} />`.
|
|
60
|
-
- `code` is formatted with a simple indentation normalizer (not a full prettier formatter). Pass clean, consistently-indented code strings.
|
|
61
|
-
- The copy button uses `navigator.clipboard.writeText` — only works in HTTPS or localhost contexts.
|
|
62
|
-
- `title` prop exists in the type but is not rendered in the current implementation.
|
|
63
|
-
- Syntax highlighting only works for languages registered with `hljs`. Currently only `typescript` is registered.
|
|
64
|
-
|
|
65
|
-
### ANTI-PATTERNS
|
|
66
|
-
```tsx
|
|
67
|
-
// ❌ Passing rendered JSX as preview
|
|
68
|
-
<CodePreview preview={<MyComponent />} code={...} /> // Wrong
|
|
69
|
-
// ✅ Pass component reference
|
|
70
|
-
<CodePreview preview={MyComponent} code={...} />
|
|
71
|
-
|
|
72
|
-
// ❌ Passing a different language without registering it with hljs
|
|
73
|
-
<CodePreview preview={CssExample} code={cssCode} language="css" />
|
|
74
|
-
// Only "typescript" is registered; other languages fall back to plain text
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## DocsNav
|
|
80
|
-
|
|
81
|
-
### IDENTITY
|
|
82
|
-
- **Import**: `@/components/doc/DocsNav`
|
|
83
|
-
- **Export**: `DocsNav` (named export)
|
|
84
|
-
- **Framework**: SolidJS + `@solidjs/router`
|
|
85
|
-
|
|
86
|
-
### PURPOSE
|
|
87
|
-
Sidebar navigation component for the documentation site. Groups doc entries by category and renders active-state links using `@solidjs/router`'s `<A>` component.
|
|
88
|
-
|
|
89
|
-
### CURRENT STATUS
|
|
90
|
-
> **⚠️ DocsNav currently renders an empty fragment (`<></>`)**. The component body is disabled (unreachable code after the early `return <></>`). It is a work-in-progress and not functional.
|
|
91
|
-
|
|
92
|
-
## TYPE SIGNATURE
|
|
93
|
-
```typescript
|
|
94
|
-
import { DocsNav } from '@/components/doc/DocsNav';
|
|
95
|
-
|
|
96
|
-
interface DocsNavProps {
|
|
97
|
-
docs?: DocInfo[]; // list of doc entries; falls back to global DOCS_TSX if omitted
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
<DocsNav docs?={DocInfo[]} />
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## TableOfContents
|
|
106
|
-
|
|
107
|
-
### IDENTITY
|
|
108
|
-
- **Import**: `@/components/doc/TableOfContents`
|
|
109
|
-
- **Export**: `TableOfContents` (named export), `Heading` (exported interface)
|
|
110
|
-
- **Framework**: SolidJS
|
|
111
|
-
|
|
112
|
-
### PURPOSE
|
|
113
|
-
Sticky right-side table of contents. Renders a list of heading anchors. Clicking a heading scrolls the nearest `<main>` container to that heading smoothly.
|
|
114
|
-
|
|
115
|
-
## TYPE SIGNATURE
|
|
116
|
-
```typescript
|
|
117
|
-
import { TableOfContents, Heading } from '@/components/doc/TableOfContents';
|
|
118
|
-
|
|
119
|
-
interface Heading {
|
|
120
|
-
id: string; // DOM element ID to scroll to
|
|
121
|
-
text: string; // display text
|
|
122
|
-
level: number; // heading level (2 = h2, 3 = h3, etc.)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
<TableOfContents
|
|
126
|
-
headings={Heading[]} // REQUIRED: array of heading descriptors
|
|
127
|
-
/>
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### BEHAVIOR
|
|
131
|
-
- Renders nothing when `headings` is empty (wrapped in `<Show when={props.headings.length > 0}>`).
|
|
132
|
-
- Scroll target is found via `document.getElementById(heading.id)`.
|
|
133
|
-
- Scrolls the closest `<main>` ancestor (with 80px top offset). Falls back to `scrollIntoView` if no `<main>` found.
|
|
134
|
-
- `level === 2` → `font-medium text-gray-700` (h2-level, bold)
|
|
135
|
-
- `level >= 3` → `ml-4 text-gray-600` (h3+, indented)
|
|
136
|
-
|
|
137
|
-
## USAGE PATTERN
|
|
138
|
-
```tsx
|
|
139
|
-
import { TableOfContents, Heading } from '@/components/doc/TableOfContents';
|
|
140
|
-
|
|
141
|
-
const headings: Heading[] = [
|
|
142
|
-
{ id: 'installation', text: 'Installation', level: 2 },
|
|
143
|
-
{ id: 'basic-usage', text: 'Basic Usage', level: 2 },
|
|
144
|
-
{ id: 'variants', text: 'Variants', level: 3 },
|
|
145
|
-
{ id: 'api', text: 'API Reference', level: 2 },
|
|
146
|
-
];
|
|
147
|
-
|
|
148
|
-
// Typically placed in a sticky right sidebar
|
|
149
|
-
<aside class="w-64 shrink-0">
|
|
150
|
-
<TableOfContents headings={headings} />
|
|
151
|
-
</aside>
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### GENERATING HEADINGS FROM MARKDOWN
|
|
155
|
-
When parsing markdown for headings, produce objects matching the `Heading` interface:
|
|
156
|
-
```typescript
|
|
157
|
-
// Example: parse h2 and h3 headings from markdown text
|
|
158
|
-
const parseHeadings = (markdown: string): Heading[] => {
|
|
159
|
-
const lines = markdown.split('\n');
|
|
160
|
-
return lines
|
|
161
|
-
.filter(line => line.startsWith('## ') || line.startsWith('### '))
|
|
162
|
-
.map(line => {
|
|
163
|
-
const level = line.startsWith('### ') ? 3 : 2;
|
|
164
|
-
const text = line.replace(/^#{2,3}\s/, '');
|
|
165
|
-
const id = text.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '');
|
|
166
|
-
return { id, text, level };
|
|
167
|
-
});
|
|
168
|
-
};
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## CONSTRAINTS
|
|
172
|
-
- Each heading's `id` must match an actual DOM element's `id` attribute in the page.
|
|
173
|
-
- The scroll offset is hardcoded at 80px (to account for sticky headers).
|
|
174
|
-
- Only works when rendered inside or near a `<main>` element ancestor.
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## DECISION RULES — Which doc component to use?
|
|
179
|
-
|
|
180
|
-
| Need | Component |
|
|
181
|
-
|------|-----------|
|
|
182
|
-
| Show a live preview + source code for a component example | `CodePreview` |
|
|
183
|
-
| Sidebar navigation list of doc pages | `DocsNav` (currently disabled/WIP) |
|
|
184
|
-
| Right-side table of contents for a doc page | `TableOfContents` |
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## Component Conventions
|
|
188
|
-
|
|
189
|
-
> **CSS encoding**: internal CSS classes use short encoded names (e.g. `dc01`, `dc02`) per project convention.
|
|
190
|
-
|
|
191
|
-
> **Unique IDs**: if this component needs to generate HTML `id` attributes, always use `createUniqueId()` from `solid-js` — never `Math.random()` or `Date.now()`.
|
|
1
|
+
## COMPONENT IDENTITY
|
|
2
|
+
- **Import**: `import { CodePreview } from '@/components/doc/CodePreview';`
|
|
3
|
+
- **Export**: `CodePreview` (named export)
|
|
4
|
+
- **Framework**: SolidJS
|
|
5
|
+
- **Purpose**: Internal documentation UI — the `doc` folder builds the library's documentation pages; NOT general-purpose UI components; NOT exported from `solid-tom-ui`
|
|
6
|
+
|
|
7
|
+
## PURPOSE
|
|
8
|
+
Renders a tabbed panel with two views:
|
|
9
|
+
1. **Preview tab**: renders the given SolidJS component visually.
|
|
10
|
+
2. **Code tab**: shows syntax-highlighted TypeScript/TSX source code with a copy button.
|
|
11
|
+
|
|
12
|
+
## TYPE SIGNATURE
|
|
13
|
+
```typescript
|
|
14
|
+
import { CodePreview } from 'solid-tom-ui';
|
|
15
|
+
import { Component } from 'solid-js';
|
|
16
|
+
|
|
17
|
+
<CodePreview
|
|
18
|
+
preview={Component<any>} // REQUIRED: SolidJS component to render as preview
|
|
19
|
+
code={string} // REQUIRED: source code string to display (raw TSX/TS)
|
|
20
|
+
title?={string} // optional title (currently not rendered in UI)
|
|
21
|
+
language?={string} // highlight.js language ID; default: 'typescript'
|
|
22
|
+
classNames?={{
|
|
23
|
+
previewBlock?: string; // extra class on the preview container div
|
|
24
|
+
}}
|
|
25
|
+
/>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## USAGE PATTERN
|
|
29
|
+
```tsx
|
|
30
|
+
import { CodePreview } from '@/components/doc/CodePreview';
|
|
31
|
+
import { MyExampleComponent } from './my-component.example';
|
|
32
|
+
|
|
33
|
+
const exampleCode = `
|
|
34
|
+
import { MyComponent } from '@/components/my-component';
|
|
35
|
+
|
|
36
|
+
const Example = () => (
|
|
37
|
+
<MyComponent color="primary" size="md">
|
|
38
|
+
Hello
|
|
39
|
+
</MyComponent>
|
|
40
|
+
);
|
|
41
|
+
`.trim();
|
|
42
|
+
|
|
43
|
+
<CodePreview
|
|
44
|
+
preview={MyExampleComponent}
|
|
45
|
+
code={exampleCode}
|
|
46
|
+
/>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## With custom preview container class
|
|
50
|
+
```tsx
|
|
51
|
+
<CodePreview
|
|
52
|
+
preview={DarkBgExample}
|
|
53
|
+
code={darkCode}
|
|
54
|
+
classNames={{ previewBlock: 'bg-gray-900 min-h-48' }}
|
|
55
|
+
/>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## CONSTRAINTS
|
|
59
|
+
- `preview` must be a **component reference** (not rendered JSX). It is rendered via `<Dynamic component={props.preview} />`.
|
|
60
|
+
- `code` is formatted with a simple indentation normalizer (not a full prettier formatter). Pass clean, consistently-indented code strings.
|
|
61
|
+
- The copy button uses `navigator.clipboard.writeText` — only works in HTTPS or localhost contexts.
|
|
62
|
+
- `title` prop exists in the type but is not rendered in the current implementation.
|
|
63
|
+
- Syntax highlighting only works for languages registered with `hljs`. Currently only `typescript` is registered.
|
|
64
|
+
|
|
65
|
+
### ANTI-PATTERNS
|
|
66
|
+
```tsx
|
|
67
|
+
// ❌ Passing rendered JSX as preview
|
|
68
|
+
<CodePreview preview={<MyComponent />} code={...} /> // Wrong
|
|
69
|
+
// ✅ Pass component reference
|
|
70
|
+
<CodePreview preview={MyComponent} code={...} />
|
|
71
|
+
|
|
72
|
+
// ❌ Passing a different language without registering it with hljs
|
|
73
|
+
<CodePreview preview={CssExample} code={cssCode} language="css" />
|
|
74
|
+
// Only "typescript" is registered; other languages fall back to plain text
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## DocsNav
|
|
80
|
+
|
|
81
|
+
### IDENTITY
|
|
82
|
+
- **Import**: `@/components/doc/DocsNav`
|
|
83
|
+
- **Export**: `DocsNav` (named export)
|
|
84
|
+
- **Framework**: SolidJS + `@solidjs/router`
|
|
85
|
+
|
|
86
|
+
### PURPOSE
|
|
87
|
+
Sidebar navigation component for the documentation site. Groups doc entries by category and renders active-state links using `@solidjs/router`'s `<A>` component.
|
|
88
|
+
|
|
89
|
+
### CURRENT STATUS
|
|
90
|
+
> **⚠️ DocsNav currently renders an empty fragment (`<></>`)**. The component body is disabled (unreachable code after the early `return <></>`). It is a work-in-progress and not functional.
|
|
91
|
+
|
|
92
|
+
## TYPE SIGNATURE
|
|
93
|
+
```typescript
|
|
94
|
+
import { DocsNav } from '@/components/doc/DocsNav';
|
|
95
|
+
|
|
96
|
+
interface DocsNavProps {
|
|
97
|
+
docs?: DocInfo[]; // list of doc entries; falls back to global DOCS_TSX if omitted
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
<DocsNav docs?={DocInfo[]} />
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## TableOfContents
|
|
106
|
+
|
|
107
|
+
### IDENTITY
|
|
108
|
+
- **Import**: `@/components/doc/TableOfContents`
|
|
109
|
+
- **Export**: `TableOfContents` (named export), `Heading` (exported interface)
|
|
110
|
+
- **Framework**: SolidJS
|
|
111
|
+
|
|
112
|
+
### PURPOSE
|
|
113
|
+
Sticky right-side table of contents. Renders a list of heading anchors. Clicking a heading scrolls the nearest `<main>` container to that heading smoothly.
|
|
114
|
+
|
|
115
|
+
## TYPE SIGNATURE
|
|
116
|
+
```typescript
|
|
117
|
+
import { TableOfContents, Heading } from '@/components/doc/TableOfContents';
|
|
118
|
+
|
|
119
|
+
interface Heading {
|
|
120
|
+
id: string; // DOM element ID to scroll to
|
|
121
|
+
text: string; // display text
|
|
122
|
+
level: number; // heading level (2 = h2, 3 = h3, etc.)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
<TableOfContents
|
|
126
|
+
headings={Heading[]} // REQUIRED: array of heading descriptors
|
|
127
|
+
/>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### BEHAVIOR
|
|
131
|
+
- Renders nothing when `headings` is empty (wrapped in `<Show when={props.headings.length > 0}>`).
|
|
132
|
+
- Scroll target is found via `document.getElementById(heading.id)`.
|
|
133
|
+
- Scrolls the closest `<main>` ancestor (with 80px top offset). Falls back to `scrollIntoView` if no `<main>` found.
|
|
134
|
+
- `level === 2` → `font-medium text-gray-700` (h2-level, bold)
|
|
135
|
+
- `level >= 3` → `ml-4 text-gray-600` (h3+, indented)
|
|
136
|
+
|
|
137
|
+
## USAGE PATTERN
|
|
138
|
+
```tsx
|
|
139
|
+
import { TableOfContents, Heading } from '@/components/doc/TableOfContents';
|
|
140
|
+
|
|
141
|
+
const headings: Heading[] = [
|
|
142
|
+
{ id: 'installation', text: 'Installation', level: 2 },
|
|
143
|
+
{ id: 'basic-usage', text: 'Basic Usage', level: 2 },
|
|
144
|
+
{ id: 'variants', text: 'Variants', level: 3 },
|
|
145
|
+
{ id: 'api', text: 'API Reference', level: 2 },
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
// Typically placed in a sticky right sidebar
|
|
149
|
+
<aside class="w-64 shrink-0">
|
|
150
|
+
<TableOfContents headings={headings} />
|
|
151
|
+
</aside>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### GENERATING HEADINGS FROM MARKDOWN
|
|
155
|
+
When parsing markdown for headings, produce objects matching the `Heading` interface:
|
|
156
|
+
```typescript
|
|
157
|
+
// Example: parse h2 and h3 headings from markdown text
|
|
158
|
+
const parseHeadings = (markdown: string): Heading[] => {
|
|
159
|
+
const lines = markdown.split('\n');
|
|
160
|
+
return lines
|
|
161
|
+
.filter(line => line.startsWith('## ') || line.startsWith('### '))
|
|
162
|
+
.map(line => {
|
|
163
|
+
const level = line.startsWith('### ') ? 3 : 2;
|
|
164
|
+
const text = line.replace(/^#{2,3}\s/, '');
|
|
165
|
+
const id = text.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '');
|
|
166
|
+
return { id, text, level };
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## CONSTRAINTS
|
|
172
|
+
- Each heading's `id` must match an actual DOM element's `id` attribute in the page.
|
|
173
|
+
- The scroll offset is hardcoded at 80px (to account for sticky headers).
|
|
174
|
+
- Only works when rendered inside or near a `<main>` element ancestor.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## DECISION RULES — Which doc component to use?
|
|
179
|
+
|
|
180
|
+
| Need | Component |
|
|
181
|
+
|------|-----------|
|
|
182
|
+
| Show a live preview + source code for a component example | `CodePreview` |
|
|
183
|
+
| Sidebar navigation list of doc pages | `DocsNav` (currently disabled/WIP) |
|
|
184
|
+
| Right-side table of contents for a doc page | `TableOfContents` |
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Component Conventions
|
|
188
|
+
|
|
189
|
+
> **CSS encoding**: internal CSS classes use short encoded names (e.g. `dc01`, `dc02`) per project convention.
|
|
190
|
+
|
|
191
|
+
> **Unique IDs**: if this component needs to generate HTML `id` attributes, always use `createUniqueId()` from `solid-js` — never `Math.random()` or `Date.now()`.
|