@skewedaspect/sleekspace-ui 0.9.1 → 0.10.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 (200) hide show
  1. package/dist/components/Accordion/context.d.ts +4 -0
  2. package/dist/components/Autocomplete/SkAutocomplete.vue.d.ts +87 -0
  3. package/dist/components/Autocomplete/SkAutocompleteEmpty.vue.d.ts +17 -0
  4. package/dist/components/Autocomplete/SkAutocompleteGroup.vue.d.ts +17 -0
  5. package/dist/components/Autocomplete/SkAutocompleteGroupLabel.vue.d.ts +17 -0
  6. package/dist/components/Autocomplete/SkAutocompleteItem.vue.d.ts +39 -0
  7. package/dist/components/Autocomplete/SkAutocompleteSeparator.vue.d.ts +2 -0
  8. package/dist/components/Autocomplete/index.d.ts +7 -0
  9. package/dist/components/Autocomplete/types.d.ts +3 -0
  10. package/dist/components/Breadcrumbs/context.d.ts +4 -0
  11. package/dist/components/Button/SkButton.vue.d.ts +8 -1
  12. package/dist/components/Button/types.d.ts +2 -0
  13. package/dist/components/Card/SkCard.vue.d.ts +1 -1
  14. package/dist/components/ContextMenu/context.d.ts +3 -0
  15. package/dist/components/Dropdown/SkDropdown.vue.d.ts +1 -1
  16. package/dist/components/Dropdown/context.d.ts +3 -0
  17. package/dist/components/Field/SkField.vue.d.ts +7 -6
  18. package/dist/components/Input/SkInput.vue.d.ts +9 -2
  19. package/dist/components/Input/types.d.ts +2 -0
  20. package/dist/components/InputGroup/SkInputGroup.vue.d.ts +23 -0
  21. package/dist/components/InputGroup/SkInputGroupAddon.vue.d.ts +33 -0
  22. package/dist/components/InputGroup/types.d.ts +13 -0
  23. package/dist/components/NumberInput/SkNumberInput.vue.d.ts +7 -1
  24. package/dist/components/NumberInput/types.d.ts +2 -0
  25. package/dist/components/Pagination/context.d.ts +5 -0
  26. package/dist/components/Panel/SkPanel.vue.d.ts +1 -1
  27. package/dist/components/Panel/types.d.ts +2 -1
  28. package/dist/components/Radio/context.d.ts +4 -0
  29. package/dist/components/Select/SkSelect.vue.d.ts +7 -1
  30. package/dist/components/Select/types.d.ts +2 -0
  31. package/dist/components/Sidebar/SkSidebar.vue.d.ts +1 -1
  32. package/dist/components/Tabs/context.d.ts +6 -0
  33. package/dist/components/Textarea/SkTextarea.vue.d.ts +1 -1
  34. package/dist/components/Tooltip/SkTooltip.vue.d.ts +1 -1
  35. package/dist/composables/injectionKeys.d.ts +9 -0
  36. package/dist/global.d.ts +4 -0
  37. package/dist/index.d.ts +18 -0
  38. package/dist/sleekspace-ui.css +831 -277
  39. package/dist/sleekspace-ui.es.js +3693 -2514
  40. package/dist/sleekspace-ui.umd.js +3700 -2513
  41. package/dist/static/components/alert.d.ts +2 -1
  42. package/dist/static/components/avatar.d.ts +2 -1
  43. package/dist/static/components/breadcrumbs.d.ts +2 -1
  44. package/dist/static/components/button.d.ts +4 -2
  45. package/dist/static/components/card.d.ts +2 -1
  46. package/dist/static/components/checkbox.d.ts +2 -1
  47. package/dist/static/components/colorPicker.d.ts +2 -1
  48. package/dist/static/components/divider.d.ts +2 -1
  49. package/dist/static/components/dropdown.d.ts +2 -1
  50. package/dist/static/components/field.d.ts +2 -1
  51. package/dist/static/components/group.d.ts +2 -1
  52. package/dist/static/components/input.d.ts +4 -2
  53. package/dist/static/components/inputGroup.d.ts +8 -0
  54. package/dist/static/components/inputGroupAddon.d.ts +7 -0
  55. package/dist/static/components/navBar.d.ts +2 -1
  56. package/dist/static/components/numberInput.d.ts +4 -2
  57. package/dist/static/components/page.d.ts +2 -1
  58. package/dist/static/components/pagination.d.ts +2 -1
  59. package/dist/static/components/panel.d.ts +2 -1
  60. package/dist/static/components/progress.d.ts +2 -1
  61. package/dist/static/components/radio.d.ts +2 -1
  62. package/dist/static/components/select.d.ts +4 -2
  63. package/dist/static/components/sidebar.d.ts +2 -1
  64. package/dist/static/components/skeleton.d.ts +2 -1
  65. package/dist/static/components/slider.d.ts +2 -1
  66. package/dist/static/components/spinner.d.ts +2 -1
  67. package/dist/static/components/switchInput.d.ts +2 -1
  68. package/dist/static/components/table.d.ts +2 -1
  69. package/dist/static/components/tag.d.ts +2 -1
  70. package/dist/static/components/tagsInput.d.ts +2 -1
  71. package/dist/static/components/textarea.d.ts +2 -1
  72. package/dist/static/components/toolbar.d.ts +2 -1
  73. package/dist/static/components/tooltip.d.ts +2 -1
  74. package/dist/static/h.d.ts +2 -0
  75. package/dist/static/index.cjs.js +1 -1
  76. package/dist/static/index.d.ts +6 -0
  77. package/dist/static/index.es.js +366 -216
  78. package/dist/static/render.d.ts +2 -1
  79. package/dist/static/stringH.d.ts +2 -0
  80. package/dist/static/types.d.ts +5 -0
  81. package/dist/tailwind.css +222 -0
  82. package/dist/tokens.css +0 -223
  83. package/dist/types/corners.d.ts +1 -0
  84. package/llms-full.txt +14 -9
  85. package/package.json +6 -3
  86. package/src/components/Accordion/SkAccordion.vue +5 -2
  87. package/src/components/Accordion/SkAccordionItem.vue +7 -4
  88. package/src/components/Accordion/context.ts +23 -0
  89. package/src/components/Autocomplete/SkAutocomplete.test.ts +83 -0
  90. package/src/components/Autocomplete/SkAutocomplete.vue +305 -0
  91. package/src/components/Autocomplete/SkAutocompleteEmpty.vue +39 -0
  92. package/src/components/Autocomplete/SkAutocompleteGroup.vue +46 -0
  93. package/src/components/Autocomplete/SkAutocompleteGroupLabel.vue +39 -0
  94. package/src/components/Autocomplete/SkAutocompleteItem.vue +85 -0
  95. package/src/components/Autocomplete/SkAutocompleteSeparator.vue +39 -0
  96. package/src/components/Autocomplete/index.ts +13 -0
  97. package/src/components/Autocomplete/types.ts +10 -0
  98. package/src/components/Breadcrumbs/SkBreadcrumbItem.vue +8 -3
  99. package/src/components/Breadcrumbs/SkBreadcrumbSeparator.vue +8 -2
  100. package/src/components/Breadcrumbs/SkBreadcrumbs.vue +5 -2
  101. package/src/components/Breadcrumbs/context.ts +20 -0
  102. package/src/components/Button/SkButton.vue +46 -6
  103. package/src/components/Button/types.ts +6 -0
  104. package/src/components/ColorPicker/SkColorPicker.vue +27 -5
  105. package/src/components/ContextMenu/SkContextMenu.vue +4 -1
  106. package/src/components/ContextMenu/SkContextMenuSubmenu.vue +5 -2
  107. package/src/components/ContextMenu/context.ts +17 -0
  108. package/src/components/Dropdown/SkDropdown.vue +2 -1
  109. package/src/components/Dropdown/SkDropdownSubmenu.vue +4 -3
  110. package/src/components/Dropdown/context.ts +16 -0
  111. package/src/components/Field/SkField.test.ts +88 -0
  112. package/src/components/Field/SkField.vue +15 -7
  113. package/src/components/Input/SkInput.test.ts +61 -0
  114. package/src/components/Input/SkInput.vue +42 -7
  115. package/src/components/Input/types.ts +2 -0
  116. package/src/components/InputGroup/SkInputGroup.test.ts +171 -0
  117. package/src/components/InputGroup/SkInputGroup.vue +131 -0
  118. package/src/components/InputGroup/SkInputGroupAddon.test.ts +104 -0
  119. package/src/components/InputGroup/SkInputGroupAddon.vue +107 -0
  120. package/src/components/InputGroup/types.ts +27 -0
  121. package/src/components/Listbox/SkListbox.vue +27 -6
  122. package/src/components/NumberInput/SkNumberInput.vue +39 -7
  123. package/src/components/NumberInput/types.ts +2 -0
  124. package/src/components/Pagination/SkPagination.vue +6 -3
  125. package/src/components/Pagination/SkPaginationItem.vue +8 -5
  126. package/src/components/Pagination/context.ts +19 -0
  127. package/src/components/Panel/types.ts +3 -2
  128. package/src/components/Radio/SkRadio.vue +6 -3
  129. package/src/components/Radio/SkRadioGroup.vue +4 -2
  130. package/src/components/Radio/context.ts +17 -0
  131. package/src/components/Select/SkSelect.vue +39 -7
  132. package/src/components/Select/types.ts +2 -0
  133. package/src/components/Tabs/SkTab.vue +4 -2
  134. package/src/components/Tabs/SkTabList.vue +4 -2
  135. package/src/components/Tabs/SkTabs.vue +5 -3
  136. package/src/components/Tabs/context.ts +19 -0
  137. package/src/components/TagsInput/SkTagsInput.vue +28 -7
  138. package/src/components/Textarea/SkTextarea.vue +27 -6
  139. package/src/composables/injectionKeys.ts +52 -0
  140. package/src/index.ts +28 -0
  141. package/src/static/__tests__/parity.test.ts +2 -1
  142. package/src/static/__tests__/parityHarness.ts +5 -2
  143. package/src/static/components/__tests__/helpers.test.ts +191 -99
  144. package/src/static/components/alert.ts +12 -11
  145. package/src/static/components/avatar.ts +15 -16
  146. package/src/static/components/breadcrumbs.ts +3 -2
  147. package/src/static/components/button.ts +23 -27
  148. package/src/static/components/card.ts +3 -2
  149. package/src/static/components/checkbox.ts +11 -14
  150. package/src/static/components/colorPicker.ts +7 -9
  151. package/src/static/components/divider.ts +4 -3
  152. package/src/static/components/dropdown.ts +15 -6
  153. package/src/static/components/field.ts +32 -15
  154. package/src/static/components/group.ts +3 -2
  155. package/src/static/components/input.ts +20 -15
  156. package/src/static/components/inputGroup.ts +30 -0
  157. package/src/static/components/inputGroupAddon.ts +29 -0
  158. package/src/static/components/navBar.ts +30 -17
  159. package/src/static/components/numberInput.ts +17 -17
  160. package/src/static/components/page.ts +3 -2
  161. package/src/static/components/pagination.ts +3 -2
  162. package/src/static/components/panel.ts +3 -2
  163. package/src/static/components/progress.ts +3 -2
  164. package/src/static/components/radio.ts +14 -20
  165. package/src/static/components/select.ts +18 -15
  166. package/src/static/components/sidebar.ts +9 -13
  167. package/src/static/components/skeleton.ts +7 -10
  168. package/src/static/components/slider.ts +7 -9
  169. package/src/static/components/spinner.ts +22 -22
  170. package/src/static/components/switchInput.ts +12 -14
  171. package/src/static/components/table.ts +8 -10
  172. package/src/static/components/tag.ts +17 -11
  173. package/src/static/components/tagsInput.ts +3 -3
  174. package/src/static/components/textarea.ts +8 -13
  175. package/src/static/components/toolbar.ts +7 -10
  176. package/src/static/components/tooltip.ts +3 -2
  177. package/src/static/generated/defaults.ts +24 -9
  178. package/src/static/generated/propTypes.ts +18 -2
  179. package/src/static/h.ts +16 -0
  180. package/src/static/index.ts +8 -0
  181. package/src/static/render.test.ts +14 -10
  182. package/src/static/render.ts +33 -18
  183. package/src/static/specs.test.ts +1 -0
  184. package/src/static/specs.ts +22 -2
  185. package/src/static/stringH.ts +104 -0
  186. package/src/static/types.ts +25 -0
  187. package/src/styles/components/_autocomplete.scss +498 -0
  188. package/src/styles/components/_button.scss +55 -6
  189. package/src/styles/components/_index.scss +2 -0
  190. package/src/styles/components/_input-group.scss +292 -0
  191. package/src/styles/components/_input.scss +57 -9
  192. package/src/styles/components/_number-input.scss +84 -18
  193. package/src/styles/components/_select.scss +56 -9
  194. package/src/styles/mixins/_cut-border.scss +83 -0
  195. package/src/styles/tailwind.scss +262 -0
  196. package/src/styles/tokens.scss +8 -255
  197. package/src/types/corners.ts +10 -0
  198. package/src/utils/slots.test.ts +89 -0
  199. package/src/utils/slots.ts +6 -1
  200. package/web-types.json +382 -12
@@ -0,0 +1,29 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // InputGroupAddon Static Helper
3
+ //
4
+ // Thin typed wrapper over the generic render() core. Emits a class-API <span> with
5
+ // sk-input-group-addon modifier classes derived from props.
6
+ //----------------------------------------------------------------------------------------------------------------------
7
+
8
+ import type { ComponentKind, ComponentSize } from '../types';
9
+
10
+ import type { H } from '../h';
11
+ import { render } from '../render';
12
+ import { SPECS } from '../specs';
13
+
14
+ //----------------------------------------------------------------------------------------------------------------------
15
+
16
+ export interface InputGroupAddonStaticProps
17
+ {
18
+ kind ?: ComponentKind;
19
+ size ?: ComponentSize;
20
+ }
21
+
22
+ //----------------------------------------------------------------------------------------------------------------------
23
+
24
+ export function inputGroupAddon<T>(h : H<T>, props : InputGroupAddonStaticProps = {}, children ?: T | T[]) : T
25
+ {
26
+ return render(h, SPECS.inputGroupAddon, props as Record<string, unknown>, children);
27
+ }
28
+
29
+ //----------------------------------------------------------------------------------------------------------------------
@@ -17,8 +17,8 @@
17
17
 
18
18
  import type { NavBarKind, StaticCustomColors } from '../types';
19
19
 
20
+ import type { H } from '../h';
20
21
  import { composeClasses } from '../classes';
21
- import { escapeAttr } from '../escape';
22
22
 
23
23
  //----------------------------------------------------------------------------------------------------------------------
24
24
 
@@ -44,7 +44,7 @@ export interface NavBarStaticProps extends StaticCustomColors
44
44
 
45
45
  //----------------------------------------------------------------------------------------------------------------------
46
46
 
47
- export function navBar(props : NavBarStaticProps = {}, children = '') : string
47
+ export function navBar<T>(h : H<T>, props : NavBarStaticProps = {}, children ?: T | T[]) : T
48
48
  {
49
49
  // Sticky defaults to true — matches Vue's withDefaults({ sticky: true })
50
50
  const sticky = props.sticky !== false;
@@ -62,33 +62,46 @@ export function navBar(props : NavBarStaticProps = {}, children = '') : string
62
62
  // Append sk-sticky when sticky is enabled
63
63
  const fullClasses = sticky ? `${ classes } sk-sticky` : classes;
64
64
 
65
- const attrs : string[] = [ `class="${ escapeAttr(fullClasses) }"` ];
65
+ const navAttrs : Record<string, unknown> = { class: fullClasses };
66
66
 
67
67
  // Custom color vars
68
68
  const styleParts : string[] = [];
69
69
  if(typeof props.baseColor === 'string')
70
70
  {
71
- styleParts.push(`--sk-navbar-color-base: ${ escapeAttr(props.baseColor) };`);
71
+ styleParts.push(`--sk-navbar-color-base: ${ props.baseColor };`);
72
72
  }
73
73
  if(typeof props.textColor === 'string')
74
74
  {
75
- styleParts.push(`--sk-navbar-fg: ${ escapeAttr(props.textColor) };`);
75
+ styleParts.push(`--sk-navbar-fg: ${ props.textColor };`);
76
76
  }
77
- if(styleParts.length > 0)
77
+ if(styleParts.length > 0) { navAttrs.style = styleParts.join(' '); }
78
+
79
+ // Build inner slot regions — each only emitted when content is non-empty, matching Vue's v-if
80
+ const inner : T[] = [];
81
+ if(props.leading)
78
82
  {
79
- attrs.push(`style="${ styleParts.join(' ') }"`);
83
+ inner.push(h('div', { class: 'sk-navbar-leading', innerHTML: props.leading }));
84
+ }
85
+ if(props.brand)
86
+ {
87
+ inner.push(h('div', { class: 'sk-navbar-brand', innerHTML: props.brand }));
88
+ }
89
+ if(children !== undefined)
90
+ {
91
+ // Only emit sk-navbar-nav when children is truthy (non-empty string / non-empty array)
92
+ const hasChildren = Array.isArray(children) ? children.length > 0 : Boolean(children);
93
+ if(hasChildren)
94
+ {
95
+ inner.push(h('div', { class: 'sk-navbar-nav' }, children));
96
+ }
97
+ }
98
+ if(props.actions)
99
+ {
100
+ inner.push(h('div', { class: 'sk-navbar-actions', innerHTML: props.actions }));
80
101
  }
81
102
 
82
- // Build inner slot regions each is only emitted when content is non-empty, matching Vue's v-if
83
- let inner = '';
84
- if(props.leading) { inner += `<div class="sk-navbar-leading">${ props.leading }</div>`; }
85
- if(props.brand) { inner += `<div class="sk-navbar-brand">${ props.brand }</div>`; }
86
- if(children) { inner += `<div class="sk-navbar-nav">${ children }</div>`; }
87
- if(props.actions) { inner += `<div class="sk-navbar-actions">${ props.actions }</div>`; }
88
-
89
- const content = `<div class="sk-navbar-content">${ inner }</div>`;
90
-
91
- return `<nav ${ attrs.join(' ') }>${ content }</nav>`;
103
+ const contentEl = h('div', { class: 'sk-navbar-content' }, inner);
104
+ return h('nav', navAttrs, contentEl);
92
105
  }
93
106
 
94
107
  //----------------------------------------------------------------------------------------------------------------------
@@ -7,10 +7,10 @@
7
7
  // meaningful in a static/SSG context.
8
8
  //----------------------------------------------------------------------------------------------------------------------
9
9
 
10
- import type { ComponentKind, ComponentSize } from '../types';
10
+ import type { ComponentKind, ComponentSize, NumberInputCorner } from '../types';
11
11
 
12
+ import type { H } from '../h';
12
13
  import { composeClasses } from '../classes';
13
- import { escapeAttr } from '../escape';
14
14
 
15
15
  //----------------------------------------------------------------------------------------------------------------------
16
16
 
@@ -18,6 +18,7 @@ export interface NumberInputStaticProps
18
18
  {
19
19
  kind ?: ComponentKind;
20
20
  size ?: ComponentSize;
21
+ corners ?: NumberInputCorner[];
21
22
  value ?: string;
22
23
  min ?: string;
23
24
  max ?: string;
@@ -31,34 +32,33 @@ export interface NumberInputStaticProps
31
32
 
32
33
  //----------------------------------------------------------------------------------------------------------------------
33
34
 
34
- export function numberInput(props : NumberInputStaticProps = {}) : string
35
+ export function numberInput<T>(h : H<T>, props : NumberInputStaticProps = {}) : T
35
36
  {
36
37
  const wrapperClasses = composeClasses(
37
- { base: 'sk-number-input-wrapper', kind: true, size: true },
38
+ {
39
+ base: 'sk-number-input-wrapper',
40
+ kind: true,
41
+ size: true,
42
+ listFlags: [ { prop: 'corners', family: 'cut' } ],
43
+ },
38
44
  props as Record<string, unknown>
39
45
  );
40
46
 
41
- const inputAttrs : string[] = [ 'class="sk-number-input-field"', 'type="number"' ];
47
+ const inputAttrs : Record<string, unknown> = { class: 'sk-number-input-field', type: 'number' };
42
48
 
43
49
  const passthroughString = [ 'value', 'min', 'max', 'step', 'name', 'placeholder' ] as const;
44
50
  for(const key of passthroughString)
45
51
  {
46
52
  const val = props[key];
47
- if(typeof val === 'string')
48
- {
49
- inputAttrs.push(`${ key }="${ escapeAttr(val) }"`);
50
- }
51
- }
52
-
53
- const passthroughBool = [ 'disabled', 'readonly', 'required' ] as const;
54
- for(const key of passthroughBool)
55
- {
56
- if(props[key] === true) { inputAttrs.push(key); }
53
+ if(typeof val === 'string') { inputAttrs[key] = val; }
57
54
  }
58
55
 
59
- const inputEl = `<input ${ inputAttrs.join(' ') } />`;
56
+ if(props.disabled === true) { inputAttrs.disabled = true; }
57
+ if(props.readonly === true) { inputAttrs.readonly = true; }
58
+ if(props.required === true) { inputAttrs.required = true; }
60
59
 
61
- return `<div class="${ escapeAttr(wrapperClasses) }">${ inputEl }</div>`;
60
+ const inputEl = h('input', inputAttrs);
61
+ return h('div', { class: wrapperClasses }, inputEl);
62
62
  }
63
63
 
64
64
  //----------------------------------------------------------------------------------------------------------------------
@@ -7,6 +7,7 @@
7
7
 
8
8
  import type { PagePanelMode } from '../types';
9
9
 
10
+ import type { H } from '../h';
10
11
  import { render } from '../render';
11
12
  import { SPECS } from '../specs';
12
13
 
@@ -23,9 +24,9 @@ export interface PageStaticProps
23
24
 
24
25
  //----------------------------------------------------------------------------------------------------------------------
25
26
 
26
- export function page(props : PageStaticProps = {}, children = '') : string
27
+ export function page<T>(h : H<T>, props : PageStaticProps = {}, children ?: T | T[]) : T
27
28
  {
28
- return render(SPECS.page, props as Record<string, unknown>, children);
29
+ return render(h, SPECS.page, props as Record<string, unknown>, children);
29
30
  }
30
31
 
31
32
  //----------------------------------------------------------------------------------------------------------------------
@@ -7,6 +7,7 @@
7
7
 
8
8
  import type { PaginationKind, StaticCustomColors } from '../types';
9
9
 
10
+ import type { H } from '../h';
10
11
  import { render } from '../render';
11
12
  import { SPECS } from '../specs';
12
13
 
@@ -19,9 +20,9 @@ export interface PaginationStaticProps extends StaticCustomColors
19
20
 
20
21
  //----------------------------------------------------------------------------------------------------------------------
21
22
 
22
- export function pagination(props : PaginationStaticProps = {}, children = '') : string
23
+ export function pagination<T>(h : H<T>, props : PaginationStaticProps = {}, children ?: T | T[]) : T
23
24
  {
24
- return render(SPECS.pagination, props as Record<string, unknown>, children);
25
+ return render(h, SPECS.pagination, props as Record<string, unknown>, children);
25
26
  }
26
27
 
27
28
  //----------------------------------------------------------------------------------------------------------------------
@@ -7,6 +7,7 @@
7
7
 
8
8
  import type { PanelCorner, PanelKind, PanelSize, StaticCustomColors } from '../types';
9
9
 
10
+ import type { H } from '../h';
10
11
  import { render } from '../render';
11
12
  import { SPECS } from '../specs';
12
13
 
@@ -25,9 +26,9 @@ export interface PanelStaticProps extends StaticCustomColors
25
26
 
26
27
  //----------------------------------------------------------------------------------------------------------------------
27
28
 
28
- export function panel(props : PanelStaticProps = {}, children = '') : string
29
+ export function panel<T>(h : H<T>, props : PanelStaticProps = {}, children ?: T | T[]) : T
29
30
  {
30
- return render(SPECS.panel, props as Record<string, unknown>, children);
31
+ return render(h, SPECS.panel, props as Record<string, unknown>, children);
31
32
  }
32
33
 
33
34
  //----------------------------------------------------------------------------------------------------------------------
@@ -7,6 +7,7 @@
7
7
 
8
8
  import type { ComponentKind, ProgressSize } from '../types';
9
9
 
10
+ import type { H } from '../h';
10
11
  import { render } from '../render';
11
12
  import { SPECS } from '../specs';
12
13
 
@@ -23,9 +24,9 @@ export interface ProgressStaticProps
23
24
 
24
25
  //----------------------------------------------------------------------------------------------------------------------
25
26
 
26
- export function progress(props : ProgressStaticProps = {}, children = '') : string
27
+ export function progress<T>(h : H<T>, props : ProgressStaticProps = {}, children ?: T | T[]) : T
27
28
  {
28
- return render(SPECS.progress, props as Record<string, unknown>, children);
29
+ return render(h, SPECS.progress, props as Record<string, unknown>, children);
29
30
  }
30
31
 
31
32
  //----------------------------------------------------------------------------------------------------------------------
@@ -8,8 +8,8 @@
8
8
 
9
9
  import type { ComponentKind, ComponentSize } from '../types';
10
10
 
11
+ import type { H } from '../h';
11
12
  import { composeClasses } from '../classes';
12
- import { escapeAttr } from '../escape';
13
13
 
14
14
  //----------------------------------------------------------------------------------------------------------------------
15
15
 
@@ -26,28 +26,22 @@ export interface RadioStaticProps
26
26
 
27
27
  //----------------------------------------------------------------------------------------------------------------------
28
28
 
29
- export function radio(props : RadioStaticProps = {}, children = '') : string
29
+ export function radio<T>(h : H<T>, props : RadioStaticProps = {}, children ?: T | T[]) : T
30
30
  {
31
31
  const classes = composeClasses({ base: 'sk-radio', kind: true, size: true }, props as Record<string, unknown>);
32
32
 
33
- const inputAttrs : string[] = [ 'type="radio"' ];
34
- if(props.name)
35
- {
36
- inputAttrs.push(`name="${ escapeAttr(props.name) }"`);
37
- }
38
- if(props.value !== undefined)
39
- {
40
- inputAttrs.push(`value="${ escapeAttr(props.value) }"`);
41
- }
42
- if(props.checked === true) { inputAttrs.push('checked'); }
43
- if(props.disabled === true) { inputAttrs.push('disabled'); }
44
- if(props.required === true) { inputAttrs.push('required'); }
45
-
46
- const inputEl = `<input ${ inputAttrs.join(' ') } />`;
47
- const dotEl = `<span class="sk-radio-dot"></span>`;
48
- const labelEl = `<span class="sk-radio-label">${ children }</span>`;
49
-
50
- return `<label class="${ escapeAttr(classes) }">${ inputEl }${ dotEl }${ labelEl }</label>`;
33
+ const inputAttrs : Record<string, unknown> = { type: 'radio' };
34
+ if(props.name) { inputAttrs.name = props.name; }
35
+ if(props.value !== undefined) { inputAttrs.value = props.value; }
36
+ if(props.checked === true) { inputAttrs.checked = true; }
37
+ if(props.disabled === true) { inputAttrs.disabled = true; }
38
+ if(props.required === true) { inputAttrs.required = true; }
39
+
40
+ const inputEl = h('input', inputAttrs);
41
+ const dotEl = h('span', { class: 'sk-radio-dot' });
42
+ const labelEl = h('span', { class: 'sk-radio-label' }, children);
43
+
44
+ return h('label', { class: classes }, [ inputEl, dotEl, labelEl ]);
51
45
  }
52
46
 
53
47
  //----------------------------------------------------------------------------------------------------------------------
@@ -5,10 +5,10 @@
5
5
  // composed by the caller. Passthrough attrs: name, id; booleans: disabled, required.
6
6
  //----------------------------------------------------------------------------------------------------------------------
7
7
 
8
- import type { ComponentKind, ComponentSize } from '../types';
8
+ import type { ComponentKind, ComponentSize, SelectCorner } from '../types';
9
9
 
10
+ import type { H } from '../h';
10
11
  import { composeClasses } from '../classes';
11
- import { escapeAttr } from '../escape';
12
12
 
13
13
  //----------------------------------------------------------------------------------------------------------------------
14
14
 
@@ -16,6 +16,7 @@ export interface SelectStaticProps
16
16
  {
17
17
  kind ?: ComponentKind;
18
18
  size ?: ComponentSize;
19
+ corners ?: SelectCorner[];
19
20
  name ?: string;
20
21
  id ?: string;
21
22
  disabled ?: boolean;
@@ -24,28 +25,30 @@ export interface SelectStaticProps
24
25
 
25
26
  //----------------------------------------------------------------------------------------------------------------------
26
27
 
27
- export function select(props : SelectStaticProps = {}, children = '') : string
28
+ export function select<T>(h : H<T>, props : SelectStaticProps = {}, children ?: T | T[]) : T
28
29
  {
29
- const classes = composeClasses({ base: 'sk-select', kind: true, size: true }, props as Record<string, unknown>);
30
- const attrs : string[] = [ `class="${ escapeAttr(classes) }"` ];
30
+ const classes = composeClasses(
31
+ {
32
+ base: 'sk-select',
33
+ kind: true,
34
+ size: true,
35
+ listFlags: [ { prop: 'corners', family: 'cut' } ],
36
+ },
37
+ props as Record<string, unknown>
38
+ );
39
+ const attrs : Record<string, unknown> = { class: classes };
31
40
 
32
41
  const passthroughString = [ 'name', 'id' ] as const;
33
42
  for(const key of passthroughString)
34
43
  {
35
44
  const val = props[key];
36
- if(typeof val === 'string')
37
- {
38
- attrs.push(`${ key }="${ escapeAttr(val) }"`);
39
- }
45
+ if(typeof val === 'string') { attrs[key] = val; }
40
46
  }
41
47
 
42
- const passthroughBool = [ 'disabled', 'required' ] as const;
43
- for(const key of passthroughBool)
44
- {
45
- if(props[key] === true) { attrs.push(key); }
46
- }
48
+ if(props.disabled === true) { attrs.disabled = true; }
49
+ if(props.required === true) { attrs.required = true; }
47
50
 
48
- return `<select ${ attrs.join(' ') }>${ children }</select>`;
51
+ return h('select', attrs, children);
49
52
  }
50
53
 
51
54
  //----------------------------------------------------------------------------------------------------------------------
@@ -20,7 +20,7 @@
20
20
 
21
21
  import type { SidebarKind, SidebarSide, StaticCustomColors } from '../types';
22
22
 
23
- import { escapeAttr } from '../escape';
23
+ import type { H } from '../h';
24
24
 
25
25
  //----------------------------------------------------------------------------------------------------------------------
26
26
 
@@ -36,7 +36,7 @@ export interface SidebarStaticProps extends StaticCustomColors
36
36
 
37
37
  //----------------------------------------------------------------------------------------------------------------------
38
38
 
39
- export function sidebar(props : SidebarStaticProps = {}, children = '') : string
39
+ export function sidebar<T>(h : H<T>, props : SidebarStaticProps = {}, children ?: T | T[]) : T
40
40
  {
41
41
  const kind = props.kind ?? 'neutral';
42
42
  const side = props.side ?? 'left';
@@ -61,25 +61,21 @@ export function sidebar(props : SidebarStaticProps = {}, children = '') : string
61
61
  'sk-sidebar-panel', // extra class SkSidebar adds to SkPanel
62
62
  ];
63
63
 
64
- const asideAttrs = `class="${ escapeAttr(asideParts.join(' ')) }"`;
65
- const panelAttrs = `class="${ escapeAttr(panelParts.join(' ')) }"`;
64
+ const asideAttrs : Record<string, unknown> = { class: asideParts.join(' ') };
66
65
 
67
66
  // Custom color styles go on the aside element (matching SkSidebar's sidebarStyles)
68
67
  const asideStyleParts : string[] = [];
69
68
  if(typeof props.baseColor === 'string')
70
69
  {
71
- asideStyleParts.push(`--sk-sidebar-color-base: ${ escapeAttr(props.baseColor) };`);
70
+ asideStyleParts.push(`--sk-sidebar-color-base: ${ props.baseColor };`);
72
71
  }
72
+ if(asideStyleParts.length > 0) { asideAttrs.style = asideStyleParts.join(' '); }
73
73
 
74
- const asideStyle = asideStyleParts.length > 0
75
- ? ` style="${ asideStyleParts.join(' ') }"`
76
- : '';
74
+ const navEl = h('nav', { class: 'sk-sidebar-nav' }, children);
75
+ const scrollEl = h('div', { class: 'sk-panel-scroll-content' }, navEl);
76
+ const panelEl = h('div', { class: panelParts.join(' ') }, scrollEl);
77
77
 
78
- const inner = `<div class="sk-panel-scroll-content"><nav class="sk-sidebar-nav">${ children }</nav></div>`;
79
-
80
- return `<aside ${ asideAttrs }${ asideStyle }>`
81
- + `<div ${ panelAttrs }>${ inner }</div>`
82
- + '</aside>';
78
+ return h('aside', asideAttrs, panelEl);
83
79
  }
84
80
 
85
81
  //----------------------------------------------------------------------------------------------------------------------
@@ -16,7 +16,7 @@
16
16
  // when needed.
17
17
  //----------------------------------------------------------------------------------------------------------------------
18
18
 
19
- import { escapeAttr } from '../escape';
19
+ import type { H } from '../h';
20
20
 
21
21
  //----------------------------------------------------------------------------------------------------------------------
22
22
 
@@ -37,7 +37,7 @@ export interface SkeletonStaticProps
37
37
 
38
38
  //----------------------------------------------------------------------------------------------------------------------
39
39
 
40
- export function skeleton(props : SkeletonStaticProps = {}) : string
40
+ export function skeleton<T>(h : H<T>, props : SkeletonStaticProps = {}) : T
41
41
  {
42
42
  const variant = props.variant ?? 'text';
43
43
  const animation = props.animation ?? 'shimmer';
@@ -45,7 +45,7 @@ export function skeleton(props : SkeletonStaticProps = {}) : string
45
45
  const classes : string[] = [ 'sk-skeleton', `sk-${ variant }` ];
46
46
  if(animation !== 'none') { classes.push(`sk-${ animation }`); }
47
47
 
48
- const attrs : string[] = [ `class="${ escapeAttr(classes.join(' ')) }"` ];
48
+ const attrs : Record<string, unknown> = { class: classes.join(' ') };
49
49
 
50
50
  // Inline style: forward width/height when provided.
51
51
  // For circular/square variants, height = width when only width is set — mirrors Vue's styles computed.
@@ -53,14 +53,11 @@ export function skeleton(props : SkeletonStaticProps = {}) : string
53
53
  const resolvedHeight = props.height
54
54
  ?? ((variant === 'circular' || variant === 'square') && props.width ? props.width : undefined);
55
55
 
56
- if(typeof props.width === 'string') { styleParts.push(`width: ${ escapeAttr(props.width) };`); }
57
- if(typeof resolvedHeight === 'string') { styleParts.push(`height: ${ escapeAttr(resolvedHeight) };`); }
58
- if(styleParts.length > 0)
59
- {
60
- attrs.push(`style="${ styleParts.join(' ') }"`);
61
- }
56
+ if(typeof props.width === 'string') { styleParts.push(`width: ${ props.width };`); }
57
+ if(typeof resolvedHeight === 'string') { styleParts.push(`height: ${ resolvedHeight };`); }
58
+ if(styleParts.length > 0) { attrs.style = styleParts.join(' '); }
62
59
 
63
- return `<div ${ attrs.join(' ') }></div>`;
60
+ return h('div', attrs);
64
61
  }
65
62
 
66
63
  //----------------------------------------------------------------------------------------------------------------------
@@ -8,8 +8,8 @@
8
8
 
9
9
  import type { ComponentKind, ComponentSize } from '../types';
10
10
 
11
+ import type { H } from '../h';
11
12
  import { composeClasses } from '../classes';
12
- import { escapeAttr } from '../escape';
13
13
 
14
14
  //----------------------------------------------------------------------------------------------------------------------
15
15
 
@@ -27,24 +27,22 @@ export interface SliderStaticProps
27
27
 
28
28
  //----------------------------------------------------------------------------------------------------------------------
29
29
 
30
- export function slider(props : SliderStaticProps = {}) : string
30
+ export function slider<T>(h : H<T>, props : SliderStaticProps = {}) : T
31
31
  {
32
32
  const classes = composeClasses({ base: 'sk-slider', kind: true, size: true }, props as Record<string, unknown>);
33
- const attrs : string[] = [ `class="${ escapeAttr(classes) }"`, 'type="range"' ];
33
+ const attrs : Record<string, unknown> = { class: classes, type: 'range' };
34
34
 
35
35
  const passthroughString = [ 'min', 'max', 'step', 'value', 'name' ] as const;
36
36
  for(const key of passthroughString)
37
37
  {
38
38
  const val = props[key];
39
- if(typeof val === 'string')
40
- {
41
- attrs.push(`${ key }="${ escapeAttr(val) }"`);
42
- }
39
+ if(typeof val === 'string') { attrs[key] = val; }
43
40
  }
44
41
 
45
- if(props.disabled === true) { attrs.push('disabled'); }
42
+ if(props.disabled === true) { attrs.disabled = true; }
46
43
 
47
- return `<input ${ attrs.join(' ') } />`;
44
+ // void element no children
45
+ return h('input', attrs);
48
46
  }
49
47
 
50
48
  //----------------------------------------------------------------------------------------------------------------------
@@ -23,7 +23,7 @@
23
23
 
24
24
  import type { ComponentKind, SpinnerSize, SpinnerVariant } from '../types';
25
25
 
26
- import { escapeAttr } from '../escape';
26
+ import type { H } from '../h';
27
27
 
28
28
  //----------------------------------------------------------------------------------------------------------------------
29
29
 
@@ -42,32 +42,32 @@ export interface SpinnerStaticProps
42
42
 
43
43
  //----------------------------------------------------------------------------------------------------------------------
44
44
 
45
- // Inner HTML per variant — mirrors Vue's v-if/v-else-if blocks.
46
- function innerHtml(variant : SpinnerVariant) : string
45
+ // Inner element per variant — mirrors Vue's v-if/v-else-if blocks.
46
+ function innerEl<T>(h : H<T>, variant : SpinnerVariant) : T
47
47
  {
48
48
  switch (variant)
49
49
  {
50
50
  case 'circular':
51
- return '<div class="sk-spinner-circular">'
52
- + '<div class="sk-arc sk-arc-large"></div>'
53
- + '<div class="sk-arc sk-arc-small"></div>'
54
- + '</div>';
51
+ return h('div', { class: 'sk-spinner-circular' }, [
52
+ h('div', { class: 'sk-arc sk-arc-large' }),
53
+ h('div', { class: 'sk-arc sk-arc-small' }),
54
+ ]);
55
55
 
56
56
  case 'dots':
57
- return '<div class="sk-spinner-dots">'
58
- + '<div class="sk-dot"></div>'
59
- + '<div class="sk-dot"></div>'
60
- + '<div class="sk-dot"></div>'
61
- + '</div>';
57
+ return h('div', { class: 'sk-spinner-dots' }, [
58
+ h('div', { class: 'sk-dot' }),
59
+ h('div', { class: 'sk-dot' }),
60
+ h('div', { class: 'sk-dot' }),
61
+ ]);
62
62
 
63
63
  case 'crosshair':
64
- return '<div class="sk-crosshair-loader"></div>';
64
+ return h('div', { class: 'sk-crosshair-loader' });
65
65
  }
66
66
  }
67
67
 
68
68
  //----------------------------------------------------------------------------------------------------------------------
69
69
 
70
- export function spinner(props : SpinnerStaticProps = {}) : string
70
+ export function spinner<T>(h : H<T>, props : SpinnerStaticProps = {}) : T
71
71
  {
72
72
  const kind = props.kind ?? 'primary';
73
73
  const size = props.size ?? 'md';
@@ -75,20 +75,20 @@ export function spinner(props : SpinnerStaticProps = {}) : string
75
75
 
76
76
  const classes = [ 'sk-spinner', `sk-${ kind }`, `sk-${ size }`, `sk-variant-${ variant }` ];
77
77
 
78
- const attrs : string[] = [
79
- `class="${ escapeAttr(classes.join(' ')) }"`,
80
- 'role="status"',
81
- 'aria-live="polite"',
82
- 'aria-label="Loading"',
83
- ];
78
+ const attrs : Record<string, unknown> = {
79
+ 'class': classes.join(' '),
80
+ 'role': 'status',
81
+ 'aria-live': 'polite',
82
+ 'aria-label': 'Loading',
83
+ };
84
84
 
85
85
  // Custom color var — emitted as inline style when `color` prop is provided.
86
86
  if(typeof props.color === 'string')
87
87
  {
88
- attrs.push(`style="--sk-spinner-color: ${ escapeAttr(props.color) };"`);
88
+ attrs.style = `--sk-spinner-color: ${ props.color };`;
89
89
  }
90
90
 
91
- return `<div ${ attrs.join(' ') }>${ innerHtml(variant) }</div>`;
91
+ return h('div', attrs, innerEl(h, variant));
92
92
  }
93
93
 
94
94
  //----------------------------------------------------------------------------------------------------------------------