@skewedaspect/sleekspace-ui 0.8.1 → 0.9.0

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 (177) hide show
  1. package/dist/components/Dropdown/SkDropdown.vue.d.ts +9 -1
  2. package/dist/components/Dropdown/types.d.ts +2 -1
  3. package/dist/components/NavBar/SkNavBar.vue.d.ts +9 -1
  4. package/dist/components/NavBar/context.d.ts +2 -0
  5. package/dist/components/NavBar/types.d.ts +5 -1
  6. package/dist/components/Page/SkPage.vue.d.ts +9 -0
  7. package/dist/components/ScrollArea/SkScrollArea.vue.d.ts +105 -4
  8. package/dist/composables/useCustomColors.d.ts +18 -56
  9. package/{src → dist}/global.d.ts +6 -2
  10. package/dist/sleekspace-ui.css +4253 -1251
  11. package/dist/sleekspace-ui.es.js +204 -109
  12. package/dist/sleekspace-ui.umd.js +204 -109
  13. package/dist/static/classes.d.ts +18 -0
  14. package/dist/static/components/alert.d.ts +12 -0
  15. package/dist/static/components/avatar.d.ts +9 -0
  16. package/dist/static/components/breadcrumbs.d.ts +6 -0
  17. package/dist/static/components/button.d.ts +13 -0
  18. package/dist/static/components/card.d.ts +5 -0
  19. package/dist/static/components/checkbox.d.ts +10 -0
  20. package/dist/static/components/colorPicker.d.ts +8 -0
  21. package/dist/static/components/divider.d.ts +8 -0
  22. package/dist/static/components/dropdown.d.ts +8 -0
  23. package/dist/static/components/field.d.ts +15 -0
  24. package/dist/static/components/group.d.ts +5 -0
  25. package/dist/static/components/input.d.ts +14 -0
  26. package/dist/static/components/navBar.d.ts +16 -0
  27. package/dist/static/components/numberInput.d.ts +15 -0
  28. package/dist/static/components/page.d.ts +9 -0
  29. package/dist/static/components/pagination.d.ts +5 -0
  30. package/dist/static/components/panel.d.ts +11 -0
  31. package/dist/static/components/progress.d.ts +9 -0
  32. package/dist/static/components/radio.d.ts +11 -0
  33. package/dist/static/components/select.d.ts +10 -0
  34. package/dist/static/components/sidebar.d.ts +9 -0
  35. package/dist/static/components/skeleton.d.ts +11 -0
  36. package/dist/static/components/slider.d.ts +12 -0
  37. package/dist/static/components/spinner.d.ts +12 -0
  38. package/dist/static/components/switchInput.d.ts +10 -0
  39. package/dist/static/components/table.d.ts +12 -0
  40. package/dist/static/components/tag.d.ts +8 -0
  41. package/dist/static/components/tagsInput.d.ts +7 -0
  42. package/dist/static/components/textarea.d.ts +12 -0
  43. package/dist/static/components/toolbar.d.ts +12 -0
  44. package/dist/static/components/tooltip.d.ts +7 -0
  45. package/dist/static/escape.d.ts +2 -0
  46. package/dist/static/index.cjs.js +1 -0
  47. package/dist/static/index.d.ts +68 -0
  48. package/dist/static/index.es.js +732 -0
  49. package/dist/static/render.d.ts +12 -0
  50. package/dist/static/specs.d.ts +2 -0
  51. package/dist/static/types.d.ts +43 -0
  52. package/dist/tokens.css +322 -0
  53. package/dist/types/index.d.ts +36 -0
  54. package/docs/guides/installation.md +8 -2
  55. package/docs/guides/pure-css/_meta.yaml +8 -0
  56. package/docs/guides/pure-css/class-api.md +1070 -0
  57. package/docs/guides/pure-css/custom-elements.md +574 -0
  58. package/docs/guides/pure-css/index.md +86 -0
  59. package/docs/guides/pure-css/limitations.md +152 -0
  60. package/docs/guides/pure-css/static-helpers.md +1203 -0
  61. package/llms-full.txt +3736 -261
  62. package/package.json +16 -5
  63. package/src/components/Card/SkCard.vue +1 -0
  64. package/src/components/ContextMenu/SkContextMenuRadioGroup.vue +4 -1
  65. package/src/components/Dropdown/SkDropdown.vue +20 -3
  66. package/src/components/Dropdown/SkDropdownRadioGroup.vue +4 -1
  67. package/src/components/Dropdown/types.ts +2 -1
  68. package/src/components/NavBar/SkNavBar.vue +14 -4
  69. package/src/components/NavBar/context.ts +4 -2
  70. package/src/components/NavBar/types.ts +6 -1
  71. package/src/components/Page/SkPage.vue +11 -0
  72. package/src/components/Panel/SkPanel.vue +2 -1
  73. package/src/components/ScrollArea/SkScrollArea.vue +78 -5
  74. package/src/components/TreeView/SkTreeView.vue +7 -2
  75. package/src/composables/useCustomColors.ts +86 -77
  76. package/src/composables/usePortalContext.test.ts +0 -2
  77. package/src/shims.d.ts +10 -0
  78. package/src/static/__tests__/parity.test.ts +717 -0
  79. package/src/static/__tests__/parityHarness.test.ts +98 -0
  80. package/src/static/__tests__/parityHarness.ts +260 -0
  81. package/src/static/classes.test.ts +82 -0
  82. package/src/static/classes.ts +111 -0
  83. package/src/static/components/__tests__/helpers.test.ts +837 -0
  84. package/src/static/components/alert.ts +117 -0
  85. package/src/static/components/avatar.ts +86 -0
  86. package/src/static/components/breadcrumbs.ts +28 -0
  87. package/src/static/components/button.ts +75 -0
  88. package/src/static/components/card.ts +27 -0
  89. package/src/static/components/checkbox.ts +48 -0
  90. package/src/static/components/colorPicker.ts +45 -0
  91. package/src/static/components/divider.ts +39 -0
  92. package/src/static/components/dropdown.ts +36 -0
  93. package/src/static/components/field.ts +86 -0
  94. package/src/static/components/group.ts +27 -0
  95. package/src/static/components/input.ts +55 -0
  96. package/src/static/components/navBar.ts +94 -0
  97. package/src/static/components/numberInput.ts +64 -0
  98. package/src/static/components/page.ts +31 -0
  99. package/src/static/components/pagination.ts +27 -0
  100. package/src/static/components/panel.ts +33 -0
  101. package/src/static/components/progress.ts +31 -0
  102. package/src/static/components/radio.ts +53 -0
  103. package/src/static/components/select.ts +51 -0
  104. package/src/static/components/sidebar.ts +85 -0
  105. package/src/static/components/skeleton.ts +66 -0
  106. package/src/static/components/slider.ts +50 -0
  107. package/src/static/components/spinner.ts +94 -0
  108. package/src/static/components/switchInput.ts +49 -0
  109. package/src/static/components/table.ts +88 -0
  110. package/src/static/components/tag.ts +76 -0
  111. package/src/static/components/tagsInput.ts +35 -0
  112. package/src/static/components/textarea.ts +53 -0
  113. package/src/static/components/toolbar.ts +74 -0
  114. package/src/static/components/tooltip.ts +29 -0
  115. package/src/static/escape.test.ts +53 -0
  116. package/src/static/escape.ts +28 -0
  117. package/src/static/generated/defaults.ts +378 -0
  118. package/src/static/generated/propTypes.ts +425 -0
  119. package/src/static/index.ts +116 -0
  120. package/src/static/render.test.ts +83 -0
  121. package/src/static/render.ts +76 -0
  122. package/src/static/specs.test.ts +58 -0
  123. package/src/static/specs.ts +230 -0
  124. package/src/static/types.ts +176 -0
  125. package/src/styles/__tests__/testHelpers.ts +97 -0
  126. package/src/styles/base/_custom-elements.scss +51 -0
  127. package/src/styles/base/_index.scss +4 -0
  128. package/src/styles/components/__tests__/componentSelectors.test.ts +2575 -0
  129. package/src/styles/components/_alert.scss +82 -39
  130. package/src/styles/components/_avatar.scss +102 -47
  131. package/src/styles/components/_breadcrumbs.scss +39 -37
  132. package/src/styles/components/_button.scss +58 -5
  133. package/src/styles/components/_card.scss +64 -2
  134. package/src/styles/components/_checkbox.scss +35 -5
  135. package/src/styles/components/_color-picker.scss +48 -13
  136. package/src/styles/components/_divider.scss +86 -52
  137. package/src/styles/components/_dropdown.scss +214 -0
  138. package/src/styles/components/_field.scss +76 -23
  139. package/src/styles/components/_group.scss +190 -79
  140. package/src/styles/components/_index.scss +1 -0
  141. package/src/styles/components/_input.scss +81 -5
  142. package/src/styles/components/_menu.scss +1 -1
  143. package/src/styles/components/_navbar.scss +76 -45
  144. package/src/styles/components/_number-input.scss +88 -83
  145. package/src/styles/components/_page.scss +82 -23
  146. package/src/styles/components/_pagination.scss +240 -212
  147. package/src/styles/components/_panel.scss +268 -122
  148. package/src/styles/components/_progress.scss +120 -70
  149. package/src/styles/components/_radio.scss +35 -5
  150. package/src/styles/components/_scroll-area.scss +50 -22
  151. package/src/styles/components/_select.scss +40 -9
  152. package/src/styles/components/_sidebar.scss +59 -34
  153. package/src/styles/components/_skeleton.scss +111 -65
  154. package/src/styles/components/_slider.scss +34 -10
  155. package/src/styles/components/_spinner.scss +107 -56
  156. package/src/styles/components/_switch.scss +36 -5
  157. package/src/styles/components/_table.scss +150 -166
  158. package/src/styles/components/_tag.scss +244 -154
  159. package/src/styles/components/_tags-input.scss +46 -12
  160. package/src/styles/components/_textarea.scss +36 -5
  161. package/src/styles/components/_toolbar.scss +85 -31
  162. package/src/styles/components/_tooltip.scss +172 -3
  163. package/src/styles/mixins/_cut-border.scss +18 -4
  164. package/src/styles/mixins/_dual-selector.scss +192 -0
  165. package/src/styles/mixins/_index.scss +1 -0
  166. package/src/styles/mixins/dualSelector.test.ts +151 -0
  167. package/src/styles/themes/_colorful.scss +25 -0
  168. package/src/styles/themes/_greyscale.scss +25 -0
  169. package/src/styles/themes/_shade-scale.scss +39 -0
  170. package/src/styles/tokens/_semantic-color-kinds.scss +66 -0
  171. package/src/{types.ts → types/index.ts} +19 -11
  172. package/web-types.json +970 -137
  173. package/dist/composables/useCustomColors.test.d.ts +0 -1
  174. package/dist/composables/useFocusTrap.test.d.ts +0 -1
  175. package/dist/composables/usePortalContext.test.d.ts +0 -1
  176. package/dist/styles/mixins/fluidSize.test.d.ts +0 -1
  177. package/dist/types.d.ts +0 -29
@@ -0,0 +1,1203 @@
1
+ ---
2
+ title: Static Helpers Reference
3
+ description: Typed Node.js helper functions that generate Sleekspace HTML strings for SSGs and build scripts — zero runtime, zero Vue dependency.
4
+ ---
5
+
6
+ # Static Helpers Reference
7
+
8
+ The `/static` subpath exports typed helper functions that generate Sleekspace HTML strings.
9
+ They're intended for Node-based SSGs and build scripts where you want type-safe component
10
+ output without importing Vue or shipping a runtime dependency.
11
+
12
+ Each helper returns a `string` of plain HTML — zero side effects, zero global state.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @skewedaspect/sleekspace-ui
18
+ ```
19
+
20
+ The CSS is a separate import:
21
+
22
+ ```typescript
23
+ // In your bundler entry or HTML:
24
+ import '@skewedaspect/sleekspace-ui/style';
25
+ // or link the compiled CSS directly in your HTML
26
+ ```
27
+
28
+ ## Import
29
+
30
+ ```typescript
31
+ import { panel, button, alert, text, escapeAttr } from '@skewedaspect/sleekspace-ui/static';
32
+ ```
33
+
34
+ All 31 component helpers plus utilities are exported from this single entry point.
35
+
36
+ ## Helper signature
37
+
38
+ Every component helper has the same shape:
39
+
40
+ ```typescript
41
+ function helperName(props?: Props, children?: string): string
42
+ ```
43
+
44
+ - `props` — typed props object. All properties are optional with sensible defaults.
45
+ - `children` — inner HTML string. Pass pre-escaped content or use the `text()` utility.
46
+ - Returns — a complete HTML string for the component's root element.
47
+
48
+ Container helpers (panel, card, etc.) include children in the output. Void helpers
49
+ (input, slider, color-picker) ignore children.
50
+
51
+ ---
52
+
53
+ ## Utilities
54
+
55
+ ### `text(value)`
56
+
57
+ Escapes a plain string for safe HTML text content. Use whenever interpolating user-controlled
58
+ or data-driven strings into HTML.
59
+
60
+ ```typescript
61
+ import { text, panel } from '@skewedaspect/sleekspace-ui/static';
62
+
63
+ const html = panel({}, `<p>${ text(userInput) }</p>`);
64
+ ```
65
+
66
+ ### `escapeAttr(value)`
67
+
68
+ Escapes a string for use inside an HTML attribute value (double-quoted).
69
+
70
+ ```typescript
71
+ import { escapeAttr } from '@skewedaspect/sleekspace-ui/static';
72
+
73
+ const safe = `data-id="${ escapeAttr(rawId) }"`;
74
+ ```
75
+
76
+ ### `composeClasses(spec, props)`
77
+
78
+ Low-level class composition utility. Takes a `ClassSpec` describing how props map to modifier
79
+ classes, returns the space-separated class string. Useful when you need class output without
80
+ a full helper.
81
+
82
+ ```typescript
83
+ import { composeClasses } from '@skewedaspect/sleekspace-ui/static';
84
+
85
+ const classes = composeClasses({ base: 'sk-panel', kind: true }, { kind: 'primary' });
86
+ // → "sk-panel sk-primary"
87
+ ```
88
+
89
+ ### `render(spec, props, children)`
90
+
91
+ Generic renderer used internally by the thin-wrapper helpers (panel, card, progress, etc.).
92
+ Takes a `RenderSpec` and emits the class-API HTML string. Useful for building custom helpers
93
+ that follow the same class composition rules.
94
+
95
+ ```typescript
96
+ import { render } from '@skewedaspect/sleekspace-ui/static';
97
+
98
+ const html = render(
99
+ { tag: 'div', classSpec: { base: 'sk-panel', kind: true }, extraAttrs: { role: 'region' } },
100
+ { kind: 'accent' },
101
+ '<p>Custom region</p>'
102
+ );
103
+ // → '<div class="sk-panel sk-accent" role="region"><p>Custom region</p></div>'
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Framework Examples
109
+
110
+ ### VitePress
111
+
112
+ Use inside a `transformHtml` hook or a custom markdown-it plugin to render Sleekspace
113
+ components inside `.md` files.
114
+
115
+ ```typescript
116
+ // .vitepress/config.ts
117
+ import { defineConfig } from 'vitepress';
118
+ import { panel } from '@skewedaspect/sleekspace-ui/static';
119
+
120
+ export default defineConfig({
121
+ transformHtml(code) {
122
+ return code.replace(/<sk-callout kind="([^"]+)">([\s\S]*?)<\/sk-callout>/g, (_, kind, content) =>
123
+ panel({ kind }, content)
124
+ );
125
+ },
126
+ });
127
+ ```
128
+
129
+ Or add a custom markdown-it fence renderer:
130
+
131
+ ```typescript
132
+ // .vitepress/config.ts
133
+ import markdownItSleekspace from './plugins/markdownItSleekspace';
134
+
135
+ export default defineConfig({
136
+ markdown: {
137
+ config(md) {
138
+ md.use(markdownItSleekspace);
139
+ },
140
+ },
141
+ });
142
+ ```
143
+
144
+ ---
145
+
146
+ ### Astro
147
+
148
+ Import directly in `.astro` component files. Astro renders these at build time — no Vue runtime needed.
149
+
150
+ ```astro
151
+ ---
152
+ import { panel, button } from '@skewedaspect/sleekspace-ui/static';
153
+ import '@skewedaspect/sleekspace-ui/style';
154
+
155
+ const callout = panel(
156
+ { kind: 'accent', size: 'lg' },
157
+ `<p>Build-time rendered with no runtime cost.</p>`
158
+ );
159
+ ---
160
+
161
+ <Fragment set:html={callout} />
162
+ ```
163
+
164
+ For reuse across pages, wrap in a `.astro` component:
165
+
166
+ ```astro
167
+ ---
168
+ // src/components/Callout.astro
169
+ import { panel } from '@skewedaspect/sleekspace-ui/static';
170
+ const { kind = 'neutral', size = 'md' } = Astro.props;
171
+ const html = panel({ kind, size }, await Astro.slots.render('default'));
172
+ ---
173
+ <Fragment set:html={html} />
174
+ ```
175
+
176
+ ---
177
+
178
+ ### 11ty
179
+
180
+ Register as a paired shortcode in `.eleventy.js`:
181
+
182
+ ```javascript
183
+ // .eleventy.js
184
+ const { panel, button, alert } = require('@skewedaspect/sleekspace-ui/static');
185
+
186
+ module.exports = function(eleventyConfig) {
187
+ eleventyConfig.addPairedShortcode('panel', (content, kind = 'neutral', size = 'md') =>
188
+ panel({ kind, size }, content)
189
+ );
190
+
191
+ eleventyConfig.addPairedShortcode('alert', (content, kind = 'info') =>
192
+ alert({ kind }, content)
193
+ );
194
+
195
+ eleventyConfig.addShortcode('button', (label, kind = 'primary', href) =>
196
+ button({ kind, href }, label)
197
+ );
198
+ };
199
+ ```
200
+
201
+ Then in your Nunjucks / Liquid templates:
202
+
203
+ ```njk
204
+ {% panel "primary", "lg" %}
205
+ <p>This panel is rendered at build time.</p>
206
+ {% endpanel %}
207
+ ```
208
+
209
+ ---
210
+
211
+ ### Vanilla Node build script
212
+
213
+ ```typescript
214
+ import { writeFileSync } from 'fs';
215
+ import { panel, navBar, button, text } from '@skewedaspect/sleekspace-ui/static';
216
+
217
+ const nav = navBar(
218
+ { kind: 'neutral', sticky: true, brand: `<span>${ text('MySite') }</span>` },
219
+ `<a href="/docs">Docs</a>`
220
+ );
221
+
222
+ const hero = panel({ kind: 'primary', size: 'xl' },
223
+ `<h1>Hello world</h1>`
224
+ + button({ kind: 'accent', size: 'lg' }, text('Get started'))
225
+ );
226
+
227
+ const page = `<!doctype html>
228
+ <html lang="en">
229
+ <head>
230
+ <meta charset="utf-8" />
231
+ <link rel="stylesheet" href="/sleekspace-ui.css" />
232
+ </head>
233
+ <body>
234
+ ${ nav }
235
+ <main>${ hero }</main>
236
+ </body>
237
+ </html>`;
238
+
239
+ writeFileSync('dist/index.html', page);
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Component Helper Reference
245
+
246
+ All 31 helpers are documented below with their props and actual emitted HTML output.
247
+
248
+ ---
249
+
250
+ ### panel
251
+
252
+ ```typescript
253
+ panel(props?: PanelStaticProps, children?: string): string
254
+ ```
255
+
256
+ **Props:**
257
+
258
+ | Prop | Type | Default | Description |
259
+ |------|------|---------|-------------|
260
+ | `kind` | `SkPanelKind` | `'neutral'` | Kind color |
261
+ | `size` | `SkPanelSize` | `'md'` | Corner decoration size |
262
+ | `corners` | `SkPanelCorner[]` | `['bottom-right']` | Which corners are beveled |
263
+ | `decorationCorner` | `SkPanelCorner` | `'bottom-right'` | Which corner shows accent stripe |
264
+ | `noBorder` | `boolean` | `false` | Remove border |
265
+ | `noDecoration` | `boolean` | `false` | Hide accent stripe |
266
+ | `baseColor` | `string` | — | Override via `--sk-panel-color-base` |
267
+
268
+ **Output:**
269
+
270
+ ```html
271
+ <div class="sk-panel sk-neutral sk-md sk-cut-bottom-right sk-decoration-bottom-right">
272
+ <!-- children -->
273
+ </div>
274
+ ```
275
+
276
+ ---
277
+
278
+ ### card
279
+
280
+ ```typescript
281
+ card(props?: CardStaticProps, children?: string): string
282
+ ```
283
+
284
+ **Props:**
285
+
286
+ | Prop | Type | Default | Description |
287
+ |------|------|---------|-------------|
288
+ | `kind` | `SkCardKind` | `'neutral'` | Kind color |
289
+ | `baseColor` | `string` | — | Override via `--sk-panel-color-base` |
290
+
291
+ **Output:**
292
+
293
+ ```html
294
+ <div class="sk-card sk-neutral"><!-- children --></div>
295
+ ```
296
+
297
+ ---
298
+
299
+ ### alert {#alert}
300
+
301
+ ```typescript
302
+ alert(props?: AlertStaticProps, children?: string): string
303
+ ```
304
+
305
+ **Props:**
306
+
307
+ | Prop | Type | Default | Description |
308
+ |------|------|---------|-------------|
309
+ | `kind` | `SkAlertKind` | `'info'` | Kind color |
310
+ | `subtle` | `boolean` | `false` | Lower-contrast variant |
311
+ | `icon` | `string \| false` | `undefined` | Custom icon HTML, `false` to suppress, or omit for auto |
312
+ | `baseColor` | `string` | — | Override via `--sk-alert-color-base` |
313
+ | `textColor` | `string` | — | Override via `--sk-alert-fg` |
314
+
315
+ When `icon` is omitted, icons are auto-selected for feedback kinds (info, success, warning, danger).
316
+ Non-feedback kinds (neutral, primary, accent) emit no icon container. Pass `icon: false` to
317
+ suppress the icon on a feedback kind. Pass `icon: '<svg>…</svg>'` for a custom icon.
318
+
319
+ **Output (info kind — default):**
320
+
321
+ ```html
322
+ <div class="sk-alert sk-info" role="alert">
323
+ <div class="sk-alert-icon">
324
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
325
+ <circle cx="12" cy="12" r="10"></circle>
326
+ <line x1="12" y1="16" x2="12" y2="12"></line>
327
+ <circle cx="12" cy="8" r="0.5" fill="currentColor"></circle>
328
+ </svg>
329
+ </div>
330
+ <div class="sk-alert-content"><!-- children --></div>
331
+ </div>
332
+ ```
333
+
334
+ **Output (neutral kind — no icon):**
335
+
336
+ ```html
337
+ <div class="sk-alert sk-neutral" role="alert">
338
+ <div class="sk-alert-content"><!-- children --></div>
339
+ </div>
340
+ ```
341
+
342
+ **Output (icon: false):**
343
+
344
+ ```html
345
+ <div class="sk-alert sk-success" role="alert">
346
+ <div class="sk-alert-content"><!-- children --></div>
347
+ </div>
348
+ ```
349
+
350
+ ---
351
+
352
+ ### divider
353
+
354
+ ```typescript
355
+ divider(props?: DividerStaticProps): string
356
+ ```
357
+
358
+ **Props:**
359
+
360
+ | Prop | Type | Default | Description |
361
+ |------|------|---------|-------------|
362
+ | `kind` | `ComponentKind` | `'neutral'` | Kind color |
363
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Layout axis |
364
+ | `size` | `ComponentSize` | `'md'` | Line thickness |
365
+ | `variant` | `'subtle'` | — | Reduced-contrast variant |
366
+
367
+ Note: divider renders as an `<hr>` element, not a `<div>`.
368
+
369
+ **Output:**
370
+
371
+ ```html
372
+ <hr class="sk-divider sk-horizontal sk-neutral sk-md" role="separator">
373
+ ```
374
+
375
+ ---
376
+
377
+ ### page
378
+
379
+ ```typescript
380
+ page(props?: PageStaticProps, children?: string): string
381
+ ```
382
+
383
+ **Props:**
384
+
385
+ | Prop | Type | Default | Description |
386
+ |------|------|---------|-------------|
387
+ | `fixedHeader` | `boolean` | `false` | Stick header to viewport top |
388
+ | `fixedFooter` | `boolean` | `false` | Stick footer to viewport bottom |
389
+ | `flush` | `boolean` | `false` | Remove outer padding |
390
+ | `sidebarMode` | `SkPagePanelMode` | — | Sidebar panel mode |
391
+ | `asideMode` | `SkPagePanelMode` | — | Aside panel mode |
392
+
393
+ **Output:**
394
+
395
+ ```html
396
+ <div class="sk-page"><!-- children --></div>
397
+ ```
398
+
399
+ ---
400
+
401
+ ### group
402
+
403
+ ```typescript
404
+ group(props?: GroupStaticProps, children?: string): string
405
+ ```
406
+
407
+ **Props:**
408
+
409
+ | Prop | Type | Default | Description |
410
+ |------|------|---------|-------------|
411
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Flex direction |
412
+
413
+ **Output:**
414
+
415
+ ```html
416
+ <div class="sk-group sk-horizontal"><!-- children --></div>
417
+ ```
418
+
419
+ ---
420
+
421
+ ### skeleton {#skeleton}
422
+
423
+ ```typescript
424
+ skeleton(props?: SkeletonStaticProps): string
425
+ ```
426
+
427
+ **Props:**
428
+
429
+ | Prop | Type | Default | Description |
430
+ |------|------|---------|-------------|
431
+ | `variant` | `'text' \| 'circular' \| 'rectangular' \| 'square'` | `'text'` | Shape preset |
432
+ | `animation` | `'shimmer' \| 'pulse' \| 'none'` | `'shimmer'` | Animation style |
433
+ | `width` | `string` | — | CSS width (e.g. `'200px'`, `'100%'`) — emitted as inline style |
434
+ | `height` | `string` | — | CSS height — emitted as inline style |
435
+
436
+ For `circular` and `square` variants, if only `width` is set, `height` is automatically
437
+ set to the same value.
438
+
439
+ **Output (text, defaults):**
440
+
441
+ ```html
442
+ <div class="sk-skeleton sk-text sk-shimmer"></div>
443
+ ```
444
+
445
+ **Output (rect with dimensions):**
446
+
447
+ ```html
448
+ <div class="sk-skeleton sk-rectangular sk-shimmer" style="width: 200px; height: 40px;"></div>
449
+ ```
450
+
451
+ **Output (animation: 'none'):**
452
+
453
+ ```html
454
+ <div class="sk-skeleton sk-text"></div>
455
+ ```
456
+
457
+ ---
458
+
459
+ ### progress
460
+
461
+ ```typescript
462
+ progress(props?: ProgressStaticProps): string
463
+ ```
464
+
465
+ **Props:**
466
+
467
+ | Prop | Type | Default | Description |
468
+ |------|------|---------|-------------|
469
+ | `kind` | `ComponentKind` | `'neutral'` | Kind color |
470
+ | `size` | `SkProgressSize` | `'md'` | Bar height |
471
+ | `indeterminate` | `boolean` | `false` | Animated indeterminate state |
472
+ | `value` | `number \| null` | — | Progress value (native attribute) |
473
+ | `max` | `number` | — | Max value (native attribute) |
474
+
475
+ **Output:**
476
+
477
+ ```html
478
+ <progress class="sk-progress sk-neutral sk-md" value="40" max="100"></progress>
479
+ ```
480
+
481
+ ---
482
+
483
+ ### spinner {#spinner}
484
+
485
+ ```typescript
486
+ spinner(props?: SpinnerStaticProps): string
487
+ ```
488
+
489
+ **Props:**
490
+
491
+ | Prop | Type | Default | Description |
492
+ |------|------|---------|-------------|
493
+ | `kind` | `ComponentKind` | `'primary'` | Kind color |
494
+ | `size` | `SkSpinnerSize` | `'md'` | Spinner diameter |
495
+ | `variant` | `'circular' \| 'dots' \| 'crosshair'` | `'circular'` | Visual style |
496
+ | `color` | `string` | — | Override via `--sk-spinner-color` inline style |
497
+
498
+ Always emits `role="status"`, `aria-live="polite"`, `aria-label="Loading"`. Inner DOM
499
+ varies by variant.
500
+
501
+ **Output (circular — default):**
502
+
503
+ ```html
504
+ <div class="sk-spinner sk-primary sk-md sk-variant-circular"
505
+ role="status" aria-live="polite" aria-label="Loading">
506
+ <div class="sk-spinner-circular">
507
+ <div class="sk-arc sk-arc-large"></div>
508
+ <div class="sk-arc sk-arc-small"></div>
509
+ </div>
510
+ </div>
511
+ ```
512
+
513
+ **Output (dots):**
514
+
515
+ ```html
516
+ <div class="sk-spinner sk-primary sk-md sk-variant-dots"
517
+ role="status" aria-live="polite" aria-label="Loading">
518
+ <div class="sk-spinner-dots">
519
+ <div class="sk-dot"></div>
520
+ <div class="sk-dot"></div>
521
+ <div class="sk-dot"></div>
522
+ </div>
523
+ </div>
524
+ ```
525
+
526
+ **Output (crosshair):**
527
+
528
+ ```html
529
+ <div class="sk-spinner sk-primary sk-md sk-variant-crosshair"
530
+ role="status" aria-live="polite" aria-label="Loading">
531
+ <div class="sk-crosshair-loader"></div>
532
+ </div>
533
+ ```
534
+
535
+ ---
536
+
537
+ ### navBar {#navbar}
538
+
539
+ ```typescript
540
+ navBar(props?: NavBarStaticProps, children?: string): string
541
+ ```
542
+
543
+ **Props:**
544
+
545
+ | Prop | Type | Default | Description |
546
+ |------|------|---------|-------------|
547
+ | `kind` | `SkNavBarKind` | `'neutral'` | Kind color |
548
+ | `sticky` | `boolean` | `true` | Apply `sk-sticky` class |
549
+ | `leading` | `string` | — | HTML for leading slot (sidebar toggle, etc.) |
550
+ | `brand` | `string` | — | HTML for brand slot (logo / site name) |
551
+ | `actions` | `string` | — | HTML for actions slot (right-aligned CTAs / user menu) |
552
+ | `baseColor` | `string` | — | Override via `--sk-navbar-color-base` |
553
+ | `textColor` | `string` | — | Override via `--sk-navbar-fg` |
554
+
555
+ `children` maps to the nav links slot (`sk-navbar-nav`). Each slot region (`leading`, `brand`,
556
+ nav links, `actions`) is only emitted when it has content.
557
+
558
+ **Output (brand + nav only):**
559
+
560
+ ```html
561
+ <nav class="sk-navbar sk-neutral sk-sticky">
562
+ <div class="sk-navbar-content">
563
+ <div class="sk-navbar-brand">MySite</div>
564
+ <div class="sk-navbar-nav">
565
+ <a href="/docs">Docs</a>
566
+ </div>
567
+ </div>
568
+ </nav>
569
+ ```
570
+
571
+ **Output (all slots):**
572
+
573
+ ```html
574
+ <nav class="sk-navbar sk-neutral sk-sticky">
575
+ <div class="sk-navbar-content">
576
+ <div class="sk-navbar-leading"><!-- sidebar toggle --></div>
577
+ <div class="sk-navbar-brand">MySite</div>
578
+ <div class="sk-navbar-nav"><!-- nav links --></div>
579
+ <div class="sk-navbar-actions"><!-- user menu --></div>
580
+ </div>
581
+ </nav>
582
+ ```
583
+
584
+ ---
585
+
586
+ ### toolbar {#toolbar}
587
+
588
+ ```typescript
589
+ toolbar(props?: ToolbarStaticProps, children?: string): string
590
+ ```
591
+
592
+ **Props:**
593
+
594
+ | Prop | Type | Default | Description |
595
+ |------|------|---------|-------------|
596
+ | `kind` | `SkToolbarKind` | — | Kind color |
597
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Layout axis |
598
+ | `corners` | `SkToolbarCorner[]` | `['top-left', 'top-right', 'bottom-right', 'bottom-left']` | Beveled corners |
599
+ | `baseColor` | `string` | — | Override via `--sk-toolbar-color-base` |
600
+ | `textColor` | `string` | — | Override via `--sk-toolbar-fg` |
601
+
602
+ Always emits `role="toolbar"`. Orientation uses `sk-horizontal` / `sk-vertical` directly.
603
+ By default all four corners are cut.
604
+
605
+ **Output (defaults):**
606
+
607
+ ```html
608
+ <div class="sk-toolbar sk-horizontal sk-cut-top-left sk-cut-top-right sk-cut-bottom-right sk-cut-bottom-left"
609
+ role="toolbar">
610
+ <!-- children -->
611
+ </div>
612
+ ```
613
+
614
+ **Output (with kind, no corners):**
615
+
616
+ ```html
617
+ <div class="sk-toolbar sk-neutral sk-horizontal" role="toolbar">
618
+ <!-- children -->
619
+ </div>
620
+ ```
621
+
622
+ ---
623
+
624
+ ### sidebar
625
+
626
+ ```typescript
627
+ sidebar(props?: SidebarStaticProps, children?: string): string
628
+ ```
629
+
630
+ **Props:**
631
+
632
+ | Prop | Type | Default | Description |
633
+ |------|------|---------|-------------|
634
+ | `kind` | `SkSidebarKind` | `'neutral'` | Kind color |
635
+ | `side` | `'left' \| 'right'` | `'left'` | Mount side |
636
+ | `dense` | `boolean` | `false` | Compact item padding |
637
+ | `width` | `string` | — | CSS width (not reflected in classes) |
638
+ | `baseColor` | `string` | — | Override via `--sk-sidebar-color-base` |
639
+
640
+ Children are wrapped in `sk-sidebar-nav`. The helper emits the full inner panel structure.
641
+
642
+ **Output (left sidebar, neutral):**
643
+
644
+ ```html
645
+ <aside class="sk-sidebar sk-neutral">
646
+ <div class="sk-panel sk-neutral sk-md sk-cut-bottom-right sk-decoration-bottom-right sk-sidebar-panel">
647
+ <div class="sk-panel-scroll-content">
648
+ <nav class="sk-sidebar-nav"><!-- children --></nav>
649
+ </div>
650
+ </div>
651
+ </aside>
652
+ ```
653
+
654
+ **Output (right sidebar):**
655
+
656
+ ```html
657
+ <aside class="sk-sidebar sk-neutral sk-sidebar-right">
658
+ <div class="sk-panel sk-neutral sk-md sk-cut-bottom-left sk-decoration-bottom-left sk-sidebar-panel">
659
+ <div class="sk-panel-scroll-content">
660
+ <nav class="sk-sidebar-nav"><!-- children --></nav>
661
+ </div>
662
+ </div>
663
+ </aside>
664
+ ```
665
+
666
+ ---
667
+
668
+ ### breadcrumbs
669
+
670
+ ```typescript
671
+ breadcrumbs(props?: BreadcrumbsStaticProps, children?: string): string
672
+ ```
673
+
674
+ **Props:**
675
+
676
+ | Prop | Type | Default | Description |
677
+ |------|------|---------|-------------|
678
+ | `kind` | `SkBreadcrumbsKind` | `'neutral'` | Kind color |
679
+ | `separator` | `string` | — | Separator character/HTML |
680
+ | `baseColor` | `string` | — | Custom color override |
681
+
682
+ **Output:**
683
+
684
+ ```html
685
+ <nav class="sk-breadcrumbs sk-neutral" aria-label="Breadcrumbs"><!-- children --></nav>
686
+ ```
687
+
688
+ ---
689
+
690
+ ### pagination
691
+
692
+ ```typescript
693
+ pagination(props?: PaginationStaticProps, children?: string): string
694
+ ```
695
+
696
+ **Props:**
697
+
698
+ | Prop | Type | Default | Description |
699
+ |------|------|---------|-------------|
700
+ | `kind` | `SkPaginationKind` | `'neutral'` | Kind color |
701
+ | `baseColor` | `string` | — | Custom color override |
702
+
703
+ **Output:**
704
+
705
+ ```html
706
+ <nav class="sk-pagination sk-neutral" aria-label="Pagination"><!-- children --></nav>
707
+ ```
708
+
709
+ ---
710
+
711
+ ### tag {#tag}
712
+
713
+ ```typescript
714
+ tag(props?: TagStaticProps, children?: string): string
715
+ ```
716
+
717
+ **Props:**
718
+
719
+ | Prop | Type | Default | Description |
720
+ |------|------|---------|-------------|
721
+ | `kind` | `ComponentKind` | `'neutral'` | Kind color |
722
+ | `variant` | `SkTagVariant` | `'solid'` | Visual style |
723
+ | `size` | `SkTagSize` | `'md'` | Tag size |
724
+ | `removable` | `boolean` | `false` | Show remove button |
725
+ | `baseColor` | `string` | — | Override via `--sk-tag-color-base` |
726
+ | `textColor` | `string` | — | Override via `--sk-tag-fg` |
727
+
728
+ Content is always wrapped in `sk-tag-content`. The remove button is only emitted when
729
+ `removable: true`.
730
+
731
+ **Output (simple):**
732
+
733
+ ```html
734
+ <span class="sk-tag sk-neutral sk-solid sk-md">
735
+ <span class="sk-tag-content">Label</span>
736
+ </span>
737
+ ```
738
+
739
+ **Output (removable):**
740
+
741
+ ```html
742
+ <span class="sk-tag sk-neutral sk-solid sk-md sk-removable">
743
+ <span class="sk-tag-content">Label</span>
744
+ <button type="button" class="sk-tag-remove" aria-label="Remove">
745
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
746
+ viewBox="0 0 24 24" fill="none" stroke="currentColor"
747
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
748
+ <line x1="18" y1="6" x2="6" y2="18"></line>
749
+ <line x1="6" y1="6" x2="18" y2="18"></line>
750
+ </svg>
751
+ </button>
752
+ </span>
753
+ ```
754
+
755
+ ---
756
+
757
+ ### avatar {#avatar}
758
+
759
+ ```typescript
760
+ avatar(props?: AvatarStaticProps): string
761
+ ```
762
+
763
+ **Props:**
764
+
765
+ | Prop | Type | Default | Description |
766
+ |------|------|---------|-------------|
767
+ | `kind` | `ComponentKind` | `'neutral'` | Kind color |
768
+ | `size` | `SkAvatarSize` | `'md'` | Avatar size |
769
+ | `src` | `string` | — | Image URL — highest priority |
770
+ | `alt` | `string` | `''` | Image alt text (used with `src`) |
771
+ | `initials` | `string` | — | Up to 2 chars shown when no `src` — second priority |
772
+ | `baseColor` | `string` | — | Override via `--sk-avatar-color-base` |
773
+ | `textColor` | `string` | — | Override via `--sk-avatar-fg` |
774
+
775
+ Note: no `shape` prop — the Vue component doesn't expose one.
776
+
777
+ Fallback priority: `src` → `initials` → default person icon SVG.
778
+
779
+ **Output (with src):**
780
+
781
+ ```html
782
+ <div class="sk-avatar sk-neutral sk-md">
783
+ <img src="/avatar.jpg" alt="User name" class="sk-avatar-image">
784
+ </div>
785
+ ```
786
+
787
+ **Output (with initials "John Doe" → "JO"):**
788
+
789
+ ```html
790
+ <div class="sk-avatar sk-primary sk-md">
791
+ <span class="sk-avatar-initials">JO</span>
792
+ </div>
793
+ ```
794
+
795
+ **Output (default fallback):**
796
+
797
+ ```html
798
+ <div class="sk-avatar sk-neutral sk-md">
799
+ <svg class="sk-avatar-icon" viewBox="0 0 24 24" fill="currentColor">
800
+ <path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path>
801
+ </svg>
802
+ </div>
803
+ ```
804
+
805
+ ---
806
+
807
+ ### field {#field}
808
+
809
+ ```typescript
810
+ field(props?: FieldStaticProps, children?: string): string
811
+ ```
812
+
813
+ **Props:**
814
+
815
+ | Prop | Type | Default | Description |
816
+ |------|------|---------|-------------|
817
+ | `label` | `string` | — | Label text |
818
+ | `description` | `string` | — | Help text below the input (suppressed when `error` is set) |
819
+ | `error` | `string` | — | Error message — also triggers `sk-has-error` class |
820
+ | `required` | `boolean` | `false` | Adds `*` span to label |
821
+ | `labelPosition` | `SkFieldLabelPosition` | `'top'` | Label placement |
822
+ | `id` | `string` | — | Field ID — forwarded to `label[for]` and error/description `id` attrs |
823
+
824
+ The `sk-field-input-wrapper` div is always emitted. Label, description, and error paragraphs
825
+ are only emitted when their props are set. Description is suppressed when an error is present.
826
+
827
+ **Output (label + input):**
828
+
829
+ ```html
830
+ <div class="sk-field sk-label-top">
831
+ <label for="email" class="sk-field-label">Email</label>
832
+ <div class="sk-field-input-wrapper"><!-- children --></div>
833
+ </div>
834
+ ```
835
+
836
+ **Output (with error):**
837
+
838
+ ```html
839
+ <div class="sk-field sk-label-top sk-has-error">
840
+ <label for="email" class="sk-field-label">Email</label>
841
+ <div class="sk-field-input-wrapper"><!-- children --></div>
842
+ <p id="email-error" class="sk-field-error">Please enter a valid email.</p>
843
+ </div>
844
+ ```
845
+
846
+ **Output (required + description):**
847
+
848
+ ```html
849
+ <div class="sk-field sk-label-top">
850
+ <label for="bio" class="sk-field-label">Bio<span class="sk-field-required">*</span></label>
851
+ <div class="sk-field-input-wrapper"><!-- children --></div>
852
+ <p id="bio-description" class="sk-field-description">Max 160 characters.</p>
853
+ </div>
854
+ ```
855
+
856
+ ---
857
+
858
+ ### table {#table}
859
+
860
+ ```typescript
861
+ table(props?: TableStaticProps, children?: string): string
862
+ ```
863
+
864
+ **Props:**
865
+
866
+ | Prop | Type | Default | Description |
867
+ |------|------|---------|-------------|
868
+ | `kind` | `SkTableKind` | `'neutral'` | Kind color |
869
+ | `variant` | `SkTableVariant` | `'default'` | Visual variant |
870
+ | `striped` | `boolean` | `false` | Alternating row backgrounds |
871
+ | `hoverable` | `boolean` | `true` | Row hover highlight |
872
+ | `bordered` | `boolean` | `true` | Outer border |
873
+ | `innerBorders` | `boolean` | `false` | Inner cell borders (suppressed by default) |
874
+ | `darkBackground` | `boolean` | `false` | Dark background on wrapper |
875
+ | `subtle` | `boolean` | `false` | Reduced contrast on wrapper + table |
876
+ | `baseColor` | `string` | — | Override via `--sk-table-color-base` |
877
+ | `textColor` | `string` | — | Override via `--sk-table-fg` |
878
+
879
+ Emits a `sk-table-wrapper` div wrapping a `<table>`. Both elements receive modifier classes.
880
+
881
+ **Output (defaults — hoverable + bordered + no-inner-borders):**
882
+
883
+ ```html
884
+ <div class="sk-table-wrapper sk-table-wrapper-neutral">
885
+ <table class="sk-table sk-neutral sk-default sk-hoverable sk-bordered sk-no-inner-borders">
886
+ <!-- thead + tbody -->
887
+ </table>
888
+ </div>
889
+ ```
890
+
891
+ **Output (striped, inner borders enabled, dark background):**
892
+
893
+ ```html
894
+ <div class="sk-table-wrapper sk-table-wrapper-neutral sk-dark-background">
895
+ <table class="sk-table sk-neutral sk-default sk-striped sk-hoverable sk-bordered">
896
+ <!-- thead + tbody -->
897
+ </table>
898
+ </div>
899
+ ```
900
+
901
+ ---
902
+
903
+ ### tooltip
904
+
905
+ ```typescript
906
+ tooltip(props?: TooltipStaticProps, children?: string): string
907
+ ```
908
+
909
+ **Props:**
910
+
911
+ | Prop | Type | Default | Description |
912
+ |------|------|---------|-------------|
913
+ | `kind` | `SkTooltipKind` | `'neutral'` | Kind color |
914
+ | `variant` | `SkTooltipVariant` | `'solid'` | Visual style |
915
+ | `placement` | `SkTooltipSide` | `'top'` | Tooltip position |
916
+ | `baseColor` | `string` | — | Custom color override |
917
+
918
+ **Output:**
919
+
920
+ ```html
921
+ <div class="sk-tooltip sk-neutral sk-solid sk-placement-top" role="tooltip">
922
+ <!-- children -->
923
+ </div>
924
+ ```
925
+
926
+ ---
927
+
928
+ ### button
929
+
930
+ ```typescript
931
+ button(props?: ButtonStaticProps, children?: string): string
932
+ ```
933
+
934
+ **Props:**
935
+
936
+ | Prop | Type | Default | Description |
937
+ |------|------|---------|-------------|
938
+ | `kind` | `SkButtonKind` | `'neutral'` | Kind color |
939
+ | `size` | `SkButtonSize` | `'md'` | Button size |
940
+ | `variant` | `SkButtonVariant` | `'solid'` | Visual style |
941
+ | `type` | `SkButtonType` | `'button'` | HTML button type |
942
+ | `disabled` | `boolean` | `false` | Disabled state |
943
+ | `loading` | `boolean` | `false` | Loading state (adds `aria-busy="true"`) |
944
+ | `pressed` | `boolean` | `false` | Pressed state (adds `aria-pressed="true"`) |
945
+ | `dense` | `boolean` | `false` | Compact padding |
946
+ | `href` | `string` | — | Render as `<a>` instead of `<button>` |
947
+
948
+ Children are always wrapped in `sk-button-chrome`.
949
+
950
+ **Output (button):**
951
+
952
+ ```html
953
+ <button class="sk-button sk-neutral sk-md sk-solid" type="button">
954
+ <span class="sk-button-chrome">Label</span>
955
+ </button>
956
+ ```
957
+
958
+ **Output (anchor):**
959
+
960
+ ```html
961
+ <a class="sk-button sk-accent sk-md sk-outline" href="/docs">
962
+ <span class="sk-button-chrome">Read the docs</span>
963
+ </a>
964
+ ```
965
+
966
+ ---
967
+
968
+ ### input
969
+
970
+ ```typescript
971
+ input(props?: InputStaticProps): string
972
+ ```
973
+
974
+ **Props:** `kind`, `size`, `type`, `value`, `placeholder`, `name`, `id`, `disabled`, `readonly`, `required`
975
+
976
+ **Output:**
977
+
978
+ ```html
979
+ <input class="sk-input sk-neutral sk-md" type="text" />
980
+ ```
981
+
982
+ ---
983
+
984
+ ### textarea
985
+
986
+ ```typescript
987
+ textarea(props?: TextareaStaticProps, children?: string): string
988
+ ```
989
+
990
+ **Props:** `kind`, `size`, `placeholder`, `name`, `id`, `disabled`, `readonly`, `required`
991
+
992
+ **Output:**
993
+
994
+ ```html
995
+ <textarea class="sk-textarea sk-neutral sk-md"></textarea>
996
+ ```
997
+
998
+ ---
999
+
1000
+ ### select
1001
+
1002
+ ```typescript
1003
+ select(props?: SelectStaticProps, children?: string): string
1004
+ ```
1005
+
1006
+ **Props:** `kind`, `size`, `name`, `id`, `disabled`, `required`
1007
+
1008
+ Children are `<option>` elements composed by the caller.
1009
+
1010
+ **Output:**
1011
+
1012
+ ```html
1013
+ <select class="sk-select sk-neutral sk-md">
1014
+ <option value="">Choose…</option>
1015
+ <option value="a">Option A</option>
1016
+ </select>
1017
+ ```
1018
+
1019
+ ---
1020
+
1021
+ ### slider
1022
+
1023
+ ```typescript
1024
+ slider(props?: SliderStaticProps): string
1025
+ ```
1026
+
1027
+ **Props:** `kind`, `size`, `min`, `max`, `step`, `value`, `name`, `disabled`
1028
+
1029
+ Single thumb only. All numeric props are accepted as strings.
1030
+
1031
+ **Output:**
1032
+
1033
+ ```html
1034
+ <input class="sk-slider sk-neutral sk-md" type="range" min="0" max="100" value="40" />
1035
+ ```
1036
+
1037
+ ---
1038
+
1039
+ ### colorPicker
1040
+
1041
+ ```typescript
1042
+ colorPicker(props?: ColorPickerStaticProps): string
1043
+ ```
1044
+
1045
+ **Props:** `size`, `value`, `name`, `disabled`
1046
+
1047
+ Note: no `kind` prop — ColorPicker has no kind modifier.
1048
+
1049
+ **Output:**
1050
+
1051
+ ```html
1052
+ <input class="sk-color-picker sk-md" type="color" value="#c4842d" />
1053
+ ```
1054
+
1055
+ ---
1056
+
1057
+ ### checkbox
1058
+
1059
+ ```typescript
1060
+ checkbox(props?: CheckboxStaticProps, children?: string): string
1061
+ ```
1062
+
1063
+ **Props:** `kind`, `size`, `checked`, `disabled`, `required`, `name`
1064
+
1065
+ Children become the label text inside `sk-checkbox-label`.
1066
+
1067
+ **Output:**
1068
+
1069
+ ```html
1070
+ <label class="sk-checkbox sk-neutral sk-md">
1071
+ <input type="checkbox" />
1072
+ <span class="sk-checkbox-box"></span>
1073
+ <span class="sk-checkbox-label">I agree to the terms</span>
1074
+ </label>
1075
+ ```
1076
+
1077
+ ---
1078
+
1079
+ ### radio
1080
+
1081
+ ```typescript
1082
+ radio(props?: RadioStaticProps, children?: string): string
1083
+ ```
1084
+
1085
+ **Props:** `kind`, `size`, `name`, `value`, `checked`, `disabled`, `required`
1086
+
1087
+ **Output:**
1088
+
1089
+ ```html
1090
+ <label class="sk-radio sk-neutral sk-md">
1091
+ <input type="radio" name="color" value="red" />
1092
+ <span class="sk-radio-dot"></span>
1093
+ <span class="sk-radio-label">Red</span>
1094
+ </label>
1095
+ ```
1096
+
1097
+ ---
1098
+
1099
+ ### switchInput
1100
+
1101
+ ```typescript
1102
+ switchInput(props?: SwitchStaticProps, children?: string): string
1103
+ ```
1104
+
1105
+ Named `switchInput` because `switch` is a reserved word in TypeScript/JavaScript.
1106
+
1107
+ **Props:** `kind`, `size`, `name`, `checked`, `disabled`, `required`
1108
+
1109
+ **Output:**
1110
+
1111
+ ```html
1112
+ <label class="sk-switch sk-neutral sk-md">
1113
+ <input type="checkbox" />
1114
+ <span class="sk-switch-track">
1115
+ <span class="sk-switch-thumb"></span>
1116
+ </span>
1117
+ <span class="sk-switch-label">Enable notifications</span>
1118
+ </label>
1119
+ ```
1120
+
1121
+ ---
1122
+
1123
+ ### numberInput
1124
+
1125
+ ```typescript
1126
+ numberInput(props?: NumberInputStaticProps): string
1127
+ ```
1128
+
1129
+ Stepper buttons are intentionally omitted — they require JS.
1130
+
1131
+ **Props:** `kind`, `size`, `value`, `min`, `max`, `step`, `name`, `placeholder`, `disabled`, `readonly`, `required`
1132
+
1133
+ **Output:**
1134
+
1135
+ ```html
1136
+ <div class="sk-number-input-wrapper sk-neutral sk-md">
1137
+ <input class="sk-number-input-field" type="number" />
1138
+ </div>
1139
+ ```
1140
+
1141
+ ---
1142
+
1143
+ ### tagsInput
1144
+
1145
+ ```typescript
1146
+ tagsInput(props?: TagsInputStaticProps, children?: string): string
1147
+ ```
1148
+
1149
+ **Props:** `kind`, `size`, `disabled`
1150
+
1151
+ Children are pre-composed `tag()` elements. The add/remove chip behavior requires Vue.
1152
+
1153
+ **Output:**
1154
+
1155
+ ```html
1156
+ <div class="sk-tags-input sk-neutral sk-md">
1157
+ <!-- tag chip elements -->
1158
+ </div>
1159
+ ```
1160
+
1161
+ ---
1162
+
1163
+ ### dropdown
1164
+
1165
+ ```typescript
1166
+ dropdown(props: DropdownStaticProps, children?: string): string
1167
+ ```
1168
+
1169
+ Note: `summary` is a **required** prop.
1170
+
1171
+ **Props:**
1172
+
1173
+ | Prop | Type | Default | Description |
1174
+ |------|------|---------|-------------|
1175
+ | `summary` | `string` | — | **Required.** Text/HTML for the `<summary>` trigger |
1176
+ | `kind` | `SemanticKind` | `'neutral'` | Kind color |
1177
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size |
1178
+ | `open` | `boolean` | `false` | Initial open state |
1179
+
1180
+ This is a disclosure widget (`<details>`), not a menu. No focus trap, no keyboard navigation.
1181
+
1182
+ **Output:**
1183
+
1184
+ ```html
1185
+ <details class="sk-dropdown sk-neutral sk-md">
1186
+ <summary>Options ▾</summary>
1187
+ <!-- children -->
1188
+ </details>
1189
+ ```
1190
+
1191
+ ---
1192
+
1193
+ ## Type safety notes
1194
+
1195
+ All helpers export their props interface. Import them if you want to type your own wrapper:
1196
+
1197
+ ```typescript
1198
+ import type { PanelStaticProps } from '@skewedaspect/sleekspace-ui/static';
1199
+
1200
+ function myPanel(props: PanelStaticProps, content: string): string {
1201
+ return panel(props, content);
1202
+ }
1203
+ ```