@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
@@ -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,
@@ -170,6 +183,7 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
170
183
  max: undefined,
171
184
  step: 1,
172
185
  showSteppers: true,
186
+ corners: undefined,
173
187
  },
174
188
  page:
175
189
  {
@@ -248,9 +262,10 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
248
262
  select:
249
263
  {
250
264
  kind: undefined,
251
- size: 'md',
265
+ size: undefined,
252
266
  placeholder: 'Select...',
253
267
  disabled: false,
268
+ corners: undefined,
254
269
  },
255
270
  sidebar:
256
271
  {
@@ -338,7 +353,7 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
338
353
  'tags-input':
339
354
  {
340
355
  kind: undefined,
341
- size: 'md',
356
+ size: undefined,
342
357
  placeholder: 'Add tag...',
343
358
  disabled: false,
344
359
  max: undefined,
@@ -349,7 +364,7 @@ export const DEFAULTS : Record<string, Record<string, unknown>> =
349
364
  textarea:
350
365
  {
351
366
  kind: undefined,
352
- size: 'md',
367
+ size: undefined,
353
368
  placeholder: undefined,
354
369
  disabled: false,
355
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;
@@ -192,6 +206,7 @@ export interface SkNumberInputStaticProps extends ComponentCustomColors
192
206
  max ? : number;
193
207
  step ? : number;
194
208
  showSteppers ? : boolean;
209
+ corners ? : SkNumberInputCorner[];
195
210
  }
196
211
 
197
212
  export interface SkPageStaticProps extends ComponentCustomColors
@@ -283,6 +298,7 @@ export interface SkSelectStaticProps extends ComponentCustomColors
283
298
  size ? : SkSelectSize;
284
299
  placeholder ? : string;
285
300
  disabled ? : boolean;
301
+ corners ? : SkSelectCorner[];
286
302
  }
287
303
 
288
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