@skewedaspect/sleekspace-ui 0.9.0 → 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 (210) 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 +15 -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 +836 -280
  39. package/dist/sleekspace-ui.es.js +3759 -2545
  40. package/dist/sleekspace-ui.umd.js +3765 -2543
  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/dist/utils/slots.d.ts +6 -0
  85. package/llms-full.txt +17 -9
  86. package/package.json +9 -3
  87. package/src/components/Accordion/SkAccordion.vue +5 -2
  88. package/src/components/Accordion/SkAccordionItem.vue +7 -4
  89. package/src/components/Accordion/context.ts +23 -0
  90. package/src/components/Alert/SkAlert.vue +4 -2
  91. package/src/components/Autocomplete/SkAutocomplete.test.ts +83 -0
  92. package/src/components/Autocomplete/SkAutocomplete.vue +305 -0
  93. package/src/components/Autocomplete/SkAutocompleteEmpty.vue +39 -0
  94. package/src/components/Autocomplete/SkAutocompleteGroup.vue +46 -0
  95. package/src/components/Autocomplete/SkAutocompleteGroupLabel.vue +39 -0
  96. package/src/components/Autocomplete/SkAutocompleteItem.vue +85 -0
  97. package/src/components/Autocomplete/SkAutocompleteSeparator.vue +39 -0
  98. package/src/components/Autocomplete/index.ts +13 -0
  99. package/src/components/Autocomplete/types.ts +10 -0
  100. package/src/components/Breadcrumbs/SkBreadcrumbItem.vue +8 -3
  101. package/src/components/Breadcrumbs/SkBreadcrumbSeparator.vue +8 -2
  102. package/src/components/Breadcrumbs/SkBreadcrumbs.vue +11 -14
  103. package/src/components/Breadcrumbs/context.ts +20 -0
  104. package/src/components/Button/SkButton.vue +54 -11
  105. package/src/components/Button/types.ts +6 -0
  106. package/src/components/Card/SkCard.vue +12 -5
  107. package/src/components/Checkbox/SkCheckbox.vue +9 -2
  108. package/src/components/ColorPicker/SkColorPicker.vue +27 -5
  109. package/src/components/ContextMenu/SkContextMenu.vue +4 -1
  110. package/src/components/ContextMenu/SkContextMenuSubmenu.vue +5 -2
  111. package/src/components/ContextMenu/context.ts +17 -0
  112. package/src/components/Dropdown/SkDropdown.vue +2 -1
  113. package/src/components/Dropdown/SkDropdownSubmenu.vue +4 -3
  114. package/src/components/Dropdown/context.ts +16 -0
  115. package/src/components/Field/SkField.test.ts +88 -0
  116. package/src/components/Field/SkField.vue +15 -7
  117. package/src/components/Input/SkInput.test.ts +61 -0
  118. package/src/components/Input/SkInput.vue +42 -7
  119. package/src/components/Input/types.ts +2 -0
  120. package/src/components/InputGroup/SkInputGroup.test.ts +171 -0
  121. package/src/components/InputGroup/SkInputGroup.vue +131 -0
  122. package/src/components/InputGroup/SkInputGroupAddon.test.ts +104 -0
  123. package/src/components/InputGroup/SkInputGroupAddon.vue +107 -0
  124. package/src/components/InputGroup/types.ts +27 -0
  125. package/src/components/Listbox/SkListbox.vue +27 -6
  126. package/src/components/Modal/SkModal.vue +11 -4
  127. package/src/components/NavBar/SkNavBar.vue +5 -4
  128. package/src/components/NumberInput/SkNumberInput.vue +49 -8
  129. package/src/components/NumberInput/types.ts +2 -0
  130. package/src/components/Page/SkPage.vue +18 -15
  131. package/src/components/Pagination/SkPagination.vue +6 -3
  132. package/src/components/Pagination/SkPaginationItem.vue +8 -5
  133. package/src/components/Pagination/context.ts +19 -0
  134. package/src/components/Panel/types.ts +3 -2
  135. package/src/components/Popover/SkPopover.vue +11 -4
  136. package/src/components/Radio/SkRadio.vue +14 -4
  137. package/src/components/Radio/SkRadioGroup.vue +4 -2
  138. package/src/components/Radio/context.ts +17 -0
  139. package/src/components/Select/SkSelect.vue +39 -7
  140. package/src/components/Select/types.ts +2 -0
  141. package/src/components/Switch/SkSwitch.vue +14 -13
  142. package/src/components/Tabs/SkTab.vue +10 -3
  143. package/src/components/Tabs/SkTabList.vue +4 -2
  144. package/src/components/Tabs/SkTabs.vue +5 -3
  145. package/src/components/Tabs/context.ts +19 -0
  146. package/src/components/TagsInput/SkTagsInput.vue +28 -7
  147. package/src/components/Textarea/SkTextarea.vue +27 -6
  148. package/src/components/TreeView/SkTreeItem.vue +10 -2
  149. package/src/composables/injectionKeys.ts +52 -0
  150. package/src/index.ts +28 -0
  151. package/src/static/__tests__/parity.test.ts +2 -1
  152. package/src/static/__tests__/parityHarness.ts +5 -2
  153. package/src/static/components/__tests__/helpers.test.ts +191 -99
  154. package/src/static/components/alert.ts +12 -11
  155. package/src/static/components/avatar.ts +15 -16
  156. package/src/static/components/breadcrumbs.ts +3 -2
  157. package/src/static/components/button.ts +23 -27
  158. package/src/static/components/card.ts +3 -2
  159. package/src/static/components/checkbox.ts +11 -14
  160. package/src/static/components/colorPicker.ts +7 -9
  161. package/src/static/components/divider.ts +4 -3
  162. package/src/static/components/dropdown.ts +15 -6
  163. package/src/static/components/field.ts +32 -15
  164. package/src/static/components/group.ts +3 -2
  165. package/src/static/components/input.ts +20 -15
  166. package/src/static/components/inputGroup.ts +30 -0
  167. package/src/static/components/inputGroupAddon.ts +29 -0
  168. package/src/static/components/navBar.ts +30 -17
  169. package/src/static/components/numberInput.ts +17 -17
  170. package/src/static/components/page.ts +3 -2
  171. package/src/static/components/pagination.ts +3 -2
  172. package/src/static/components/panel.ts +3 -2
  173. package/src/static/components/progress.ts +3 -2
  174. package/src/static/components/radio.ts +14 -20
  175. package/src/static/components/select.ts +18 -15
  176. package/src/static/components/sidebar.ts +9 -13
  177. package/src/static/components/skeleton.ts +7 -10
  178. package/src/static/components/slider.ts +7 -9
  179. package/src/static/components/spinner.ts +22 -22
  180. package/src/static/components/switchInput.ts +12 -14
  181. package/src/static/components/table.ts +8 -10
  182. package/src/static/components/tag.ts +17 -11
  183. package/src/static/components/tagsInput.ts +3 -3
  184. package/src/static/components/textarea.ts +8 -13
  185. package/src/static/components/toolbar.ts +7 -10
  186. package/src/static/components/tooltip.ts +3 -2
  187. package/src/static/generated/defaults.ts +25 -9
  188. package/src/static/generated/propTypes.ts +19 -2
  189. package/src/static/h.ts +16 -0
  190. package/src/static/index.ts +8 -0
  191. package/src/static/render.test.ts +14 -10
  192. package/src/static/render.ts +33 -18
  193. package/src/static/specs.test.ts +1 -0
  194. package/src/static/specs.ts +22 -2
  195. package/src/static/stringH.ts +104 -0
  196. package/src/static/types.ts +25 -0
  197. package/src/styles/components/_autocomplete.scss +498 -0
  198. package/src/styles/components/_button.scss +55 -6
  199. package/src/styles/components/_index.scss +2 -0
  200. package/src/styles/components/_input-group.scss +292 -0
  201. package/src/styles/components/_input.scss +57 -9
  202. package/src/styles/components/_number-input.scss +88 -14
  203. package/src/styles/components/_select.scss +56 -9
  204. package/src/styles/mixins/_cut-border.scss +83 -0
  205. package/src/styles/tailwind.scss +262 -0
  206. package/src/styles/tokens.scss +8 -255
  207. package/src/types/corners.ts +10 -0
  208. package/src/utils/slots.test.ts +89 -0
  209. package/src/utils/slots.ts +80 -0
  210. package/web-types.json +392 -12
@@ -9,8 +9,8 @@
9
9
 
10
10
  import type { ComponentKind, ComponentSize } 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
 
@@ -26,24 +26,22 @@ export interface SwitchStaticProps
26
26
 
27
27
  //----------------------------------------------------------------------------------------------------------------------
28
28
 
29
- export function switchInput(props : SwitchStaticProps = {}, children = '') : string
29
+ export function switchInput<T>(h : H<T>, props : SwitchStaticProps = {}, children ?: T | T[]) : T
30
30
  {
31
31
  const classes = composeClasses({ base: 'sk-switch', kind: true, size: true }, props as Record<string, unknown>);
32
32
 
33
- const inputAttrs : string[] = [ 'type="checkbox"' ];
34
- if(props.name)
35
- {
36
- inputAttrs.push(`name="${ escapeAttr(props.name) }"`);
37
- }
38
- if(props.checked === true) { inputAttrs.push('checked'); }
39
- if(props.disabled === true) { inputAttrs.push('disabled'); }
40
- if(props.required === true) { inputAttrs.push('required'); }
33
+ const inputAttrs : Record<string, unknown> = { type: 'checkbox' };
34
+ if(props.name) { inputAttrs.name = props.name; }
35
+ if(props.checked === true) { inputAttrs.checked = true; }
36
+ if(props.disabled === true) { inputAttrs.disabled = true; }
37
+ if(props.required === true) { inputAttrs.required = true; }
41
38
 
42
- const inputEl = `<input ${ inputAttrs.join(' ') } />`;
43
- const trackEl = `<span class="sk-switch-track"><span class="sk-switch-thumb"></span></span>`;
44
- const labelEl = `<span class="sk-switch-label">${ children }</span>`;
39
+ const inputEl = h('input', inputAttrs);
40
+ const thumbEl = h('span', { class: 'sk-switch-thumb' });
41
+ const trackEl = h('span', { class: 'sk-switch-track' }, thumbEl);
42
+ const labelEl = h('span', { class: 'sk-switch-label' }, children);
45
43
 
46
- return `<label class="${ escapeAttr(classes) }">${ inputEl }${ trackEl }${ labelEl }</label>`;
44
+ return h('label', { class: classes }, [ inputEl, trackEl, labelEl ]);
47
45
  }
48
46
 
49
47
  //----------------------------------------------------------------------------------------------------------------------
@@ -17,7 +17,7 @@
17
17
 
18
18
  import type { StaticCustomColors, TableKind, TableVariant } from '../types';
19
19
 
20
- import { escapeAttr } from '../escape';
20
+ import type { H } from '../h';
21
21
 
22
22
  //----------------------------------------------------------------------------------------------------------------------
23
23
 
@@ -35,7 +35,7 @@ export interface TableStaticProps extends StaticCustomColors
35
35
 
36
36
  //----------------------------------------------------------------------------------------------------------------------
37
37
 
38
- export function table(props : TableStaticProps = {}, children = '') : string
38
+ export function table<T>(h : H<T>, props : TableStaticProps = {}, children ?: T | T[]) : T
39
39
  {
40
40
  const kind = props.kind ?? 'neutral';
41
41
  const variant = props.variant ?? 'default';
@@ -61,28 +61,26 @@ export function table(props : TableStaticProps = {}, children = '') : string
61
61
  if(!innerBorders) { tableClasses.push('sk-no-inner-borders'); }
62
62
  if(subtle) { tableClasses.push('sk-subtle'); }
63
63
 
64
- const tableAttrs : string[] = [ `class="${ escapeAttr(tableClasses.join(' ')) }"` ];
64
+ const tableAttrs : Record<string, unknown> = { class: tableClasses.join(' ') };
65
65
 
66
66
  // Custom color vars — match Vue's useCustomColors('table', ...) output
67
67
  const styleParts : string[] = [];
68
68
  if(typeof props.baseColor === 'string')
69
69
  {
70
- styleParts.push(`--sk-table-color-base: ${ escapeAttr(props.baseColor) };`);
70
+ styleParts.push(`--sk-table-color-base: ${ props.baseColor };`);
71
71
  }
72
72
  if(typeof props.textColor === 'string')
73
73
  {
74
- styleParts.push(`--sk-table-fg: ${ escapeAttr(props.textColor) };`);
74
+ styleParts.push(`--sk-table-fg: ${ props.textColor };`);
75
75
  }
76
76
  if(styleParts.length > 0)
77
77
  {
78
- tableAttrs.push(`style="${ styleParts.join(' ') }"`);
78
+ tableAttrs.style = styleParts.join(' ');
79
79
  }
80
80
 
81
- const wrapperAttr = `class="${ escapeAttr(wrapperClasses.join(' ')) }"`;
81
+ const wrapperAttrs : Record<string, unknown> = { class: wrapperClasses.join(' ') };
82
82
 
83
- return `<div ${ wrapperAttr }>`
84
- + `<table ${ tableAttrs.join(' ') }>${ children }</table>`
85
- + '</div>';
83
+ return h('div', wrapperAttrs, h('table', tableAttrs, children));
86
84
  }
87
85
 
88
86
  //----------------------------------------------------------------------------------------------------------------------
@@ -14,7 +14,7 @@
14
14
 
15
15
  import type { ComponentKind, StaticCustomColors, TagSize, TagVariant } from '../types';
16
16
 
17
- import { escapeAttr } from '../escape';
17
+ import type { H } from '../h';
18
18
 
19
19
  //----------------------------------------------------------------------------------------------------------------------
20
20
 
@@ -38,7 +38,7 @@ const REMOVE_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="2
38
38
 
39
39
  //----------------------------------------------------------------------------------------------------------------------
40
40
 
41
- export function tag(props : TagStaticProps = {}, children = '') : string
41
+ export function tag<T>(h : H<T>, props : TagStaticProps = {}, children ?: T | T[]) : T
42
42
  {
43
43
  const kind = props.kind ?? 'neutral';
44
44
  const variant = props.variant ?? 'solid';
@@ -47,30 +47,36 @@ export function tag(props : TagStaticProps = {}, children = '') : string
47
47
  const classes : string[] = [ 'sk-tag', `sk-${ kind }`, `sk-${ variant }`, `sk-${ size }` ];
48
48
  if(props.removable) { classes.push('sk-removable'); }
49
49
 
50
- const attrs : string[] = [ `class="${ escapeAttr(classes.join(' ')) }"` ];
50
+ const attrs : Record<string, unknown> = { class: classes.join(' ') };
51
51
 
52
52
  // Custom color vars — match Vue's useCustomColors('tag', ...) output
53
53
  const styleParts : string[] = [];
54
54
  if(typeof props.baseColor === 'string')
55
55
  {
56
- styleParts.push(`--sk-tag-color-base: ${ escapeAttr(props.baseColor) };`);
56
+ styleParts.push(`--sk-tag-color-base: ${ props.baseColor };`);
57
57
  }
58
58
  if(typeof props.textColor === 'string')
59
59
  {
60
- styleParts.push(`--sk-tag-fg: ${ escapeAttr(props.textColor) };`);
60
+ styleParts.push(`--sk-tag-fg: ${ props.textColor };`);
61
61
  }
62
62
  if(styleParts.length > 0)
63
63
  {
64
- attrs.push(`style="${ styleParts.join(' ') }"`);
64
+ attrs.style = styleParts.join(' ');
65
65
  }
66
66
 
67
- const contentSpan = `<span class="sk-tag-content">${ children }</span>`;
67
+ const contentEl = h('span', { class: 'sk-tag-content' }, children);
68
+ const inner : T[] = [ contentEl ];
68
69
 
69
- const removeButton = props.removable
70
- ? `<button type="button" class="sk-tag-remove" aria-label="Remove">${ REMOVE_SVG }</button>`
71
- : '';
70
+ if(props.removable)
71
+ {
72
+ const removeEl = h(
73
+ 'button',
74
+ { 'type': 'button', 'class': 'sk-tag-remove', 'aria-label': 'Remove', 'innerHTML': REMOVE_SVG }
75
+ );
76
+ inner.push(removeEl);
77
+ }
72
78
 
73
- return `<span ${ attrs.join(' ') }>${ contentSpan }${ removeButton }</span>`;
79
+ return h('span', attrs, inner);
74
80
  }
75
81
 
76
82
  //----------------------------------------------------------------------------------------------------------------------
@@ -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
 
@@ -22,14 +22,14 @@ export interface TagsInputStaticProps
22
22
 
23
23
  //----------------------------------------------------------------------------------------------------------------------
24
24
 
25
- export function tagsInput(props : TagsInputStaticProps = {}, children = '') : string
25
+ export function tagsInput<T>(h : H<T>, props : TagsInputStaticProps = {}, children ?: T | T[]) : T
26
26
  {
27
27
  const classes = composeClasses(
28
28
  { base: 'sk-tags-input', kind: true, size: true },
29
29
  props as Record<string, unknown>
30
30
  );
31
31
 
32
- return `<div class="${ escapeAttr(classes) }">${ children }</div>`;
32
+ return h('div', { class: classes }, children);
33
33
  }
34
34
 
35
35
  //----------------------------------------------------------------------------------------------------------------------
@@ -7,8 +7,8 @@
7
7
 
8
8
  import type { ComponentKind, ComponentSize } 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
 
@@ -26,28 +26,23 @@ export interface TextareaStaticProps
26
26
 
27
27
  //----------------------------------------------------------------------------------------------------------------------
28
28
 
29
- export function textarea(props : TextareaStaticProps = {}, children = '') : string
29
+ export function textarea<T>(h : H<T>, props : TextareaStaticProps = {}, children ?: T | T[]) : T
30
30
  {
31
31
  const classes = composeClasses({ base: 'sk-textarea', kind: true, size: true }, props as Record<string, unknown>);
32
- const attrs : string[] = [ `class="${ escapeAttr(classes) }"` ];
32
+ const attrs : Record<string, unknown> = { class: classes };
33
33
 
34
34
  const passthroughString = [ 'placeholder', 'name', 'id' ] as const;
35
35
  for(const key of passthroughString)
36
36
  {
37
37
  const val = props[key];
38
- if(typeof val === 'string')
39
- {
40
- attrs.push(`${ key }="${ escapeAttr(val) }"`);
41
- }
38
+ if(typeof val === 'string') { attrs[key] = val; }
42
39
  }
43
40
 
44
- const passthroughBool = [ 'disabled', 'readonly', 'required' ] as const;
45
- for(const key of passthroughBool)
46
- {
47
- if(props[key] === true) { attrs.push(key); }
48
- }
41
+ if(props.disabled === true) { attrs.disabled = true; }
42
+ if(props.readonly === true) { attrs.readonly = true; }
43
+ if(props.required === true) { attrs.required = true; }
49
44
 
50
- return `<textarea ${ attrs.join(' ') }>${ children }</textarea>`;
45
+ return h('textarea', attrs, children);
51
46
  }
52
47
 
53
48
  //----------------------------------------------------------------------------------------------------------------------
@@ -15,7 +15,7 @@
15
15
 
16
16
  import type { StaticCustomColors, ToolbarCorner, ToolbarKind, ToolbarOrientation } from '../types';
17
17
 
18
- import { escapeAttr } from '../escape';
18
+ import type { H } from '../h';
19
19
 
20
20
  //----------------------------------------------------------------------------------------------------------------------
21
21
 
@@ -38,7 +38,7 @@ const DEFAULT_CORNERS : ToolbarCorner[] = [ 'top-left', 'top-right', 'bottom-rig
38
38
 
39
39
  //----------------------------------------------------------------------------------------------------------------------
40
40
 
41
- export function toolbar(props : ToolbarStaticProps = {}, children = '') : string
41
+ export function toolbar<T>(h : H<T>, props : ToolbarStaticProps = {}, children ?: T | T[]) : T
42
42
  {
43
43
  const kind = props.kind;
44
44
  const orientation = props.orientation ?? 'horizontal';
@@ -51,24 +51,21 @@ export function toolbar(props : ToolbarStaticProps = {}, children = '') : string
51
51
  parts.push(`sk-${ orientation }`);
52
52
  for(const corner of corners) { parts.push(`sk-cut-${ corner }`); }
53
53
 
54
- const attrs : string[] = [ `class="${ escapeAttr(parts.join(' ')) }"`, 'role="toolbar"' ];
54
+ const attrs : Record<string, unknown> = { class: parts.join(' '), role: 'toolbar' };
55
55
 
56
56
  // Custom color vars
57
57
  const styleParts : string[] = [];
58
58
  if(typeof props.baseColor === 'string')
59
59
  {
60
- styleParts.push(`--sk-toolbar-color-base: ${ escapeAttr(props.baseColor) };`);
60
+ styleParts.push(`--sk-toolbar-color-base: ${ props.baseColor };`);
61
61
  }
62
62
  if(typeof props.textColor === 'string')
63
63
  {
64
- styleParts.push(`--sk-toolbar-fg: ${ escapeAttr(props.textColor) };`);
65
- }
66
- if(styleParts.length > 0)
67
- {
68
- attrs.push(`style="${ styleParts.join(' ') }"`);
64
+ styleParts.push(`--sk-toolbar-fg: ${ props.textColor };`);
69
65
  }
66
+ if(styleParts.length > 0) { attrs.style = styleParts.join(' '); }
70
67
 
71
- return `<div ${ attrs.join(' ') }>${ children }</div>`;
68
+ return h('div', attrs, children);
72
69
  }
73
70
 
74
71
  //----------------------------------------------------------------------------------------------------------------------
@@ -7,6 +7,7 @@
7
7
 
8
8
  import type { StaticCustomColors, TooltipKind, TooltipSide, TooltipVariant } from '../types';
9
9
 
10
+ import type { H } from '../h';
10
11
  import { render } from '../render';
11
12
  import { SPECS } from '../specs';
12
13
 
@@ -21,9 +22,9 @@ export interface TooltipStaticProps extends StaticCustomColors
21
22
 
22
23
  //----------------------------------------------------------------------------------------------------------------------
23
24
 
24
- export function tooltip(props : TooltipStaticProps = {}, children = '') : string
25
+ export function tooltip<T>(h : H<T>, props : TooltipStaticProps = {}, children ?: T | T[]) : T
25
26
  {
26
- return render(SPECS.tooltip, props as Record<string, unknown>, children);
27
+ return render(h, SPECS.tooltip, props as Record<string, unknown>, children);
27
28
  }
28
29
 
29
30
  //----------------------------------------------------------------------------------------------------------------------
@@ -16,6 +16,17 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
16
16
  subtle: false,
17
17
  showIcon: undefined,
18
18
  },
19
+ autocomplete:
20
+ {
21
+ kind: undefined,
22
+ size: undefined,
23
+ placeholder: 'Search...',
24
+ disabled: false,
25
+ openOnFocus: true,
26
+ openOnClick: false,
27
+ clearable: false,
28
+ ignoreFilter: false,
29
+ },
19
30
  avatar:
20
31
  {
21
32
  src: undefined,
@@ -34,13 +45,14 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
34
45
  button:
35
46
  {
36
47
  type: 'button',
37
- kind: 'neutral',
48
+ kind: undefined,
38
49
  variant: 'solid',
39
- size: 'md',
50
+ size: undefined,
40
51
  disabled: false,
41
52
  loading: false,
42
53
  pressed: false,
43
54
  dense: false,
55
+ corners: undefined,
44
56
  href: undefined,
45
57
  to: undefined,
46
58
  },
@@ -77,7 +89,7 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
77
89
  'color-picker':
78
90
  {
79
91
  kind: undefined,
80
- size: 'md',
92
+ size: undefined,
81
93
  format: 'hexa',
82
94
  showAlpha: true,
83
95
  disabled: false,
@@ -124,7 +136,8 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
124
136
  {
125
137
  type: 'text',
126
138
  kind: undefined,
127
- size: 'md',
139
+ size: undefined,
140
+ corners: undefined,
128
141
  placeholder: undefined,
129
142
  disabled: false,
130
143
  readonly: false,
@@ -135,7 +148,7 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
135
148
  listbox:
136
149
  {
137
150
  kind: undefined,
138
- size: 'md',
151
+ size: undefined,
139
152
  placeholder: 'Search...',
140
153
  disabled: false,
141
154
  },
@@ -160,7 +173,7 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
160
173
  'number-input':
161
174
  {
162
175
  kind: undefined,
163
- size: 'md',
176
+ size: undefined,
164
177
  placeholder: undefined,
165
178
  disabled: false,
166
179
  readonly: false,
@@ -169,6 +182,8 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
169
182
  min: undefined,
170
183
  max: undefined,
171
184
  step: 1,
185
+ showSteppers: true,
186
+ corners: undefined,
172
187
  },
173
188
  page:
174
189
  {
@@ -247,9 +262,10 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
247
262
  select:
248
263
  {
249
264
  kind: undefined,
250
- size: 'md',
265
+ size: undefined,
251
266
  placeholder: 'Select...',
252
267
  disabled: false,
268
+ corners: undefined,
253
269
  },
254
270
  sidebar:
255
271
  {
@@ -337,7 +353,7 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
337
353
  'tags-input':
338
354
  {
339
355
  kind: undefined,
340
- size: 'md',
356
+ size: undefined,
341
357
  placeholder: 'Add tag...',
342
358
  disabled: false,
343
359
  max: undefined,
@@ -348,7 +364,7 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
348
364
  textarea:
349
365
  {
350
366
  kind: undefined,
351
- size: 'md',
367
+ size: undefined,
352
368
  placeholder: undefined,
353
369
  disabled: false,
354
370
  readonly: false,
@@ -22,6 +22,18 @@ export interface SkAlertStaticProps extends ComponentCustomColors
22
22
  showIcon ? : boolean;
23
23
  }
24
24
 
25
+ export interface SkAutocompleteStaticProps extends ComponentCustomColors
26
+ {
27
+ kind ? : SkAutocompleteKind;
28
+ size ? : SkAutocompleteSize;
29
+ placeholder ? : string;
30
+ disabled ? : boolean;
31
+ openOnFocus ? : boolean;
32
+ openOnClick ? : boolean;
33
+ clearable ? : boolean;
34
+ ignoreFilter ? : boolean;
35
+ }
36
+
25
37
  export interface SkAvatarStaticProps extends ComponentCustomColors
26
38
  {
27
39
  src ? : string;
@@ -49,6 +61,7 @@ export interface SkButtonStaticProps extends ComponentCustomColors
49
61
  loading ? : boolean;
50
62
  pressed ? : boolean;
51
63
  dense ? : boolean;
64
+ corners ? : SkButtonCorner[];
52
65
  href ? : string;
53
66
  to ? : string | Record<string, any>;
54
67
  }
@@ -129,8 +142,8 @@ export interface SkFieldStaticProps extends ComponentCustomColors
129
142
  labelPosition ? : SkFieldLabelPosition;
130
143
  id ? : string;
131
144
  state ? : boolean | null;
132
- validKind ? : string;
133
- invalidKind ? : string;
145
+ validKind ? : ComponentKind;
146
+ invalidKind ? : ComponentKind;
134
147
  }
135
148
 
136
149
  export interface SkGroupStaticProps extends ComponentCustomColors
@@ -143,6 +156,7 @@ export interface SkInputStaticProps extends ComponentCustomColors
143
156
  type ? : SkInputType;
144
157
  kind ? : SkInputKind;
145
158
  size ? : SkInputSize;
159
+ corners ? : SkInputCorner[];
146
160
  placeholder ? : string;
147
161
  disabled ? : boolean;
148
162
  readonly ? : boolean;
@@ -191,6 +205,8 @@ export interface SkNumberInputStaticProps extends ComponentCustomColors
191
205
  min ? : number;
192
206
  max ? : number;
193
207
  step ? : number;
208
+ showSteppers ? : boolean;
209
+ corners ? : SkNumberInputCorner[];
194
210
  }
195
211
 
196
212
  export interface SkPageStaticProps extends ComponentCustomColors
@@ -282,6 +298,7 @@ export interface SkSelectStaticProps extends ComponentCustomColors
282
298
  size ? : SkSelectSize;
283
299
  placeholder ? : string;
284
300
  disabled ? : boolean;
301
+ corners ? : SkSelectCorner[];
285
302
  }
286
303
 
287
304
  export interface SkSidebarStaticProps extends ComponentCustomColors
@@ -0,0 +1,16 @@
1
+ //----------------------------------------------------------------------------------------------------------------------
2
+ // H Adapter — Hyperscript-style createElement signature.
3
+ //
4
+ // Every static helper takes an `h` adapter as its first argument. The adapter is whatever
5
+ // createElement-like function the consumer's framework provides — Vue's `h`, React's
6
+ // `createElement`, or the `stringH` shipped here for plain HTML-string output.
7
+ //
8
+ // Attribute conventions are HTML-style: `class` (not `className`), `style` as a CSS string.
9
+ // Vue's `h` normalises these natively. React consumers should wrap their adapter to remap.
10
+ //----------------------------------------------------------------------------------------------------------------------
11
+
12
+ export type HAttrs = Record<string, unknown> | null;
13
+
14
+ export type H<T> = (tag : string, attrs : HAttrs, children ?: T | T[]) => T;
15
+
16
+ //----------------------------------------------------------------------------------------------------------------------
@@ -12,6 +12,8 @@ export { composeClasses } from './classes';
12
12
  export type { ClassSpec, ListFlagSpec, SingleChoiceFlagSpec } from './classes';
13
13
  export { render } from './render';
14
14
  export type { RenderSpec } from './render';
15
+ export { stringH } from './stringH';
16
+ export type { H, HAttrs } from './h';
15
17
 
16
18
  // Shared types
17
19
  export type * from './types';
@@ -81,6 +83,12 @@ export type { ButtonStaticProps } from './components/button';
81
83
  export { input } from './components/input';
82
84
  export type { InputStaticProps } from './components/input';
83
85
 
86
+ export { inputGroup } from './components/inputGroup';
87
+ export type { InputGroupStaticProps } from './components/inputGroup';
88
+
89
+ export { inputGroupAddon } from './components/inputGroupAddon';
90
+ export type { InputGroupAddonStaticProps } from './components/inputGroupAddon';
91
+
84
92
  export { textarea } from './components/textarea';
85
93
  export type { TextareaStaticProps } from './components/textarea';
86
94
 
@@ -1,10 +1,14 @@
1
1
  //----------------------------------------------------------------------------------------------------------------------
2
2
  // Render Core Tests
3
+ //
4
+ // Verifies render() against the stringH adapter. The output is HTML strings, but render()
5
+ // itself is adapter-agnostic — feed it Vue's h or React.createElement to get framework VNodes.
3
6
  //----------------------------------------------------------------------------------------------------------------------
4
7
 
5
8
  import { describe, expect, it } from 'vitest';
6
9
 
7
10
  import { type RenderSpec, render } from './render';
11
+ import { stringH } from './stringH';
8
12
 
9
13
  //----------------------------------------------------------------------------------------------------------------------
10
14
 
@@ -24,59 +28,59 @@ describe('render', () =>
24
28
  {
25
29
  it('emits a bare tag with base class when no props', () =>
26
30
  {
27
- expect(render(PANEL_SPEC, {}, '')).toBe('<div class="sk-panel"></div>');
31
+ expect(render(stringH, PANEL_SPEC, {}, '')).toBe('<div class="sk-panel"></div>');
28
32
  });
29
33
 
30
34
  it('appends children verbatim', () =>
31
35
  {
32
- expect(render(PANEL_SPEC, {}, 'Hello')).toBe('<div class="sk-panel">Hello</div>');
36
+ expect(render(stringH, PANEL_SPEC, {}, 'Hello')).toBe('<div class="sk-panel">Hello</div>');
33
37
  });
34
38
 
35
39
  it('embeds nested HTML children', () =>
36
40
  {
37
- expect(render(PANEL_SPEC, {}, '<span>inner</span>'))
41
+ expect(render(stringH, PANEL_SPEC, {}, '<span>inner</span>'))
38
42
  .toBe('<div class="sk-panel"><span>inner</span></div>');
39
43
  });
40
44
 
41
45
  it('includes classes from prop modifiers', () =>
42
46
  {
43
- expect(render(PANEL_SPEC, { kind: 'primary', size: 'lg' }, 'x'))
47
+ expect(render(stringH, PANEL_SPEC, { kind: 'primary', size: 'lg' }, 'x'))
44
48
  .toBe('<div class="sk-panel sk-primary sk-lg sk-size-lg">x</div>');
45
49
  });
46
50
 
47
51
  it('emits custom color inline style from baseColor / textColor', () =>
48
52
  {
49
- expect(render(PANEL_SPEC, { baseColor: '#f00', textColor: '#fff' }, 'x'))
53
+ expect(render(stringH, PANEL_SPEC, { baseColor: '#f00', textColor: '#fff' }, 'x'))
50
54
  .toBe('<div class="sk-panel" style="--sk-panel-color-base: #f00; --sk-panel-fg: #fff;">x</div>');
51
55
  });
52
56
 
53
57
  it('uses tag="button" when spec overrides', () =>
54
58
  {
55
59
  const spec : RenderSpec = { tag: 'button', classSpec: { base: 'sk-button' } };
56
- expect(render(spec, {}, 'Save')).toBe('<button class="sk-button" type="button">Save</button>');
60
+ expect(render(stringH, spec, {}, 'Save')).toBe('<button class="sk-button" type="button">Save</button>');
57
61
  });
58
62
 
59
63
  it('omits type="button" for non-button tags', () =>
60
64
  {
61
- expect(render(PANEL_SPEC, {}, 'x')).not.toMatch(/type="button"/);
65
+ expect(render(stringH, PANEL_SPEC, {}, 'x')).not.toMatch(/type="button"/);
62
66
  });
63
67
 
64
68
  it('respects `extraAttrs` from the spec', () =>
65
69
  {
66
70
  const spec : RenderSpec = { tag: 'div', classSpec: { base: 'sk-alert' }, extraAttrs: { role: 'alert' } };
67
- expect(render(spec, {}, 'warning')).toBe('<div class="sk-alert" role="alert">warning</div>');
71
+ expect(render(stringH, spec, {}, 'warning')).toBe('<div class="sk-alert" role="alert">warning</div>');
68
72
  });
69
73
 
70
74
  it('escapes attribute values containing dangerous characters', () =>
71
75
  {
72
- expect(render(PANEL_SPEC, { baseColor: '"><script>' }, 'x'))
76
+ expect(render(stringH, PANEL_SPEC, { baseColor: '"><script>' }, 'x'))
73
77
  .toContain('style="--sk-panel-color-base: &quot;&gt;&lt;script&gt;;"');
74
78
  });
75
79
 
76
80
  it('renders void/self-closing elements without children when spec.void is true', () =>
77
81
  {
78
82
  const spec : RenderSpec = { tag: 'input', classSpec: { base: 'sk-input' }, void: true };
79
- expect(render(spec, {}, '')).toBe('<input class="sk-input" />');
83
+ expect(render(stringH, spec, {}, '')).toBe('<input class="sk-input" />');
80
84
  });
81
85
  });
82
86