@vielzeug/refine 1.5.0 → 1.5.2

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 (246) hide show
  1. package/dist/async.cjs +9 -9
  2. package/dist/async.cjs.map +1 -1
  3. package/dist/async.js +30 -31
  4. package/dist/async.js.map +1 -1
  5. package/dist/button.cjs +6 -6
  6. package/dist/button.cjs.map +1 -1
  7. package/dist/button.js +29 -30
  8. package/dist/button.js.map +1 -1
  9. package/dist/calendar.cjs +44 -44
  10. package/dist/calendar.cjs.map +1 -1
  11. package/dist/calendar.js +115 -117
  12. package/dist/calendar.js.map +1 -1
  13. package/dist/checkbox-group.cjs +7 -7
  14. package/dist/checkbox-group.cjs.map +1 -1
  15. package/dist/checkbox-group.js +71 -73
  16. package/dist/checkbox-group.js.map +1 -1
  17. package/dist/checkbox.cjs +3 -3
  18. package/dist/checkbox.cjs.map +1 -1
  19. package/dist/checkbox.js +28 -29
  20. package/dist/checkbox.js.map +1 -1
  21. package/dist/code-window.cjs +7 -7
  22. package/dist/code-window.cjs.map +1 -1
  23. package/dist/code-window.js +17 -18
  24. package/dist/code-window.js.map +1 -1
  25. package/dist/combobox.cjs +1 -1
  26. package/dist/combobox.cjs.map +1 -1
  27. package/dist/combobox.js +11 -12
  28. package/dist/combobox.js.map +1 -1
  29. package/dist/custom-elements.json +3581 -3581
  30. package/dist/datagrid.cjs +66 -66
  31. package/dist/datagrid.cjs.map +1 -1
  32. package/dist/datagrid.js +267 -268
  33. package/dist/datagrid.js.map +1 -1
  34. package/dist/date-picker.cjs +11 -11
  35. package/dist/date-picker.cjs.map +1 -1
  36. package/dist/date-picker.js +8 -9
  37. package/dist/date-picker.js.map +1 -1
  38. package/dist/file-input.cjs +6 -6
  39. package/dist/file-input.cjs.map +1 -1
  40. package/dist/file-input.js +50 -51
  41. package/dist/file-input.js.map +1 -1
  42. package/dist/grid.cjs +1 -1
  43. package/dist/grid.cjs.map +1 -1
  44. package/dist/grid.js +47 -48
  45. package/dist/grid.js.map +1 -1
  46. package/dist/icon.cjs +1 -1
  47. package/dist/icon.cjs.map +1 -1
  48. package/dist/icon.js +26 -27
  49. package/dist/icon.js.map +1 -1
  50. package/dist/input.cjs +20 -20
  51. package/dist/input.cjs.map +1 -1
  52. package/dist/input.js +98 -100
  53. package/dist/input.js.map +1 -1
  54. package/dist/layout/navbar/navbar.css.cjs +1 -1
  55. package/dist/layout/navbar/navbar.css.cjs.map +1 -1
  56. package/dist/layout/navbar/navbar.css.js +1 -1
  57. package/dist/layout/navbar/navbar.css.js.map +1 -1
  58. package/dist/layout/navbar/navbar.d.ts +1 -0
  59. package/dist/layout/navbar/navbar.d.ts.map +1 -1
  60. package/dist/message-composer.cjs +18 -18
  61. package/dist/message-composer.cjs.map +1 -1
  62. package/dist/message-composer.js +113 -115
  63. package/dist/message-composer.js.map +1 -1
  64. package/dist/navbar.cjs +16 -13
  65. package/dist/navbar.cjs.map +1 -1
  66. package/dist/navbar.js +84 -79
  67. package/dist/navbar.js.map +1 -1
  68. package/dist/otp-input.cjs +4 -4
  69. package/dist/otp-input.cjs.map +1 -1
  70. package/dist/otp-input.js +31 -32
  71. package/dist/otp-input.js.map +1 -1
  72. package/dist/progress.cjs +13 -13
  73. package/dist/progress.cjs.map +1 -1
  74. package/dist/progress.js +45 -46
  75. package/dist/progress.js.map +1 -1
  76. package/dist/radio-group.cjs +5 -5
  77. package/dist/radio-group.cjs.map +1 -1
  78. package/dist/radio-group.js +83 -85
  79. package/dist/radio-group.js.map +1 -1
  80. package/dist/radio.cjs +3 -3
  81. package/dist/radio.cjs.map +1 -1
  82. package/dist/radio.js +27 -28
  83. package/dist/radio.js.map +1 -1
  84. package/dist/rating.cjs +4 -4
  85. package/dist/rating.cjs.map +1 -1
  86. package/dist/rating.js +30 -31
  87. package/dist/rating.js.map +1 -1
  88. package/dist/refine.cjs +8 -5
  89. package/dist/refine.cjs.map +1 -1
  90. package/dist/refine.iife.js +8 -5
  91. package/dist/refine.iife.js.map +1 -1
  92. package/dist/refine.js +8 -5
  93. package/dist/refine.js.map +1 -1
  94. package/dist/select.cjs +4 -4
  95. package/dist/select.cjs.map +1 -1
  96. package/dist/select.js +88 -89
  97. package/dist/select.js.map +1 -1
  98. package/dist/sidebar.cjs +11 -11
  99. package/dist/sidebar.cjs.map +1 -1
  100. package/dist/sidebar.js +97 -98
  101. package/dist/sidebar.js.map +1 -1
  102. package/dist/skeleton.cjs +3 -3
  103. package/dist/skeleton.cjs.map +1 -1
  104. package/dist/skeleton.js +23 -24
  105. package/dist/skeleton.js.map +1 -1
  106. package/dist/slider.cjs +3 -3
  107. package/dist/slider.cjs.map +1 -1
  108. package/dist/slider.js +65 -66
  109. package/dist/slider.js.map +1 -1
  110. package/dist/switch.cjs +3 -3
  111. package/dist/switch.cjs.map +1 -1
  112. package/dist/switch.js +23 -24
  113. package/dist/switch.js.map +1 -1
  114. package/dist/tab-panel.cjs +7 -7
  115. package/dist/tab-panel.cjs.map +1 -1
  116. package/dist/tab-panel.js +21 -23
  117. package/dist/tab-panel.js.map +1 -1
  118. package/dist/testing.cjs +1 -1
  119. package/dist/testing.cjs.map +1 -1
  120. package/dist/testing.js +4 -5
  121. package/dist/testing.js.map +1 -1
  122. package/dist/textarea.cjs +13 -13
  123. package/dist/textarea.cjs.map +1 -1
  124. package/dist/textarea.js +92 -94
  125. package/dist/textarea.js.map +1 -1
  126. package/dist/time-picker.cjs +9 -9
  127. package/dist/time-picker.cjs.map +1 -1
  128. package/dist/time-picker.js +47 -48
  129. package/dist/time-picker.js.map +1 -1
  130. package/package.json +1 -1
  131. package/dist/ore/dist/_dev.cjs +0 -2
  132. package/dist/ore/dist/_dev.cjs.map +0 -1
  133. package/dist/ore/dist/_dev.js +0 -12
  134. package/dist/ore/dist/_dev.js.map +0 -1
  135. package/dist/ore/dist/base-element.cjs +0 -2
  136. package/dist/ore/dist/base-element.cjs.map +0 -1
  137. package/dist/ore/dist/base-element.js +0 -158
  138. package/dist/ore/dist/base-element.js.map +0 -1
  139. package/dist/ore/dist/context.cjs +0 -2
  140. package/dist/ore/dist/context.cjs.map +0 -1
  141. package/dist/ore/dist/context.js +0 -11
  142. package/dist/ore/dist/context.js.map +0 -1
  143. package/dist/ore/dist/define.cjs +0 -2
  144. package/dist/ore/dist/define.cjs.map +0 -1
  145. package/dist/ore/dist/define.js +0 -27
  146. package/dist/ore/dist/define.js.map +0 -1
  147. package/dist/ore/dist/directives/classMap.cjs +0 -1
  148. package/dist/ore/dist/directives/classMap.js +0 -1
  149. package/dist/ore/dist/directives/each.cjs +0 -1
  150. package/dist/ore/dist/directives/each.js +0 -5
  151. package/dist/ore/dist/directives/live.cjs +0 -2
  152. package/dist/ore/dist/directives/live.cjs.map +0 -1
  153. package/dist/ore/dist/directives/live.js +0 -6
  154. package/dist/ore/dist/directives/live.js.map +0 -1
  155. package/dist/ore/dist/directives/model.cjs +0 -1
  156. package/dist/ore/dist/directives/model.js +0 -3
  157. package/dist/ore/dist/directives/raw.cjs +0 -2
  158. package/dist/ore/dist/directives/raw.cjs.map +0 -1
  159. package/dist/ore/dist/directives/raw.js +0 -38
  160. package/dist/ore/dist/directives/raw.js.map +0 -1
  161. package/dist/ore/dist/directives/styleMap.cjs +0 -2
  162. package/dist/ore/dist/directives/styleMap.cjs.map +0 -1
  163. package/dist/ore/dist/directives/styleMap.js +0 -20
  164. package/dist/ore/dist/directives/styleMap.js.map +0 -1
  165. package/dist/ore/dist/directives/when.cjs +0 -2
  166. package/dist/ore/dist/directives/when.cjs.map +0 -1
  167. package/dist/ore/dist/directives/when.js +0 -38
  168. package/dist/ore/dist/directives/when.js.map +0 -1
  169. package/dist/ore/dist/directives.cjs +0 -1
  170. package/dist/ore/dist/directives.js +0 -8
  171. package/dist/ore/dist/errors.cjs +0 -3
  172. package/dist/ore/dist/errors.cjs.map +0 -1
  173. package/dist/ore/dist/errors.js +0 -50
  174. package/dist/ore/dist/errors.js.map +0 -1
  175. package/dist/ore/dist/forms/context.cjs +0 -2
  176. package/dist/ore/dist/forms/context.cjs.map +0 -1
  177. package/dist/ore/dist/forms/context.js +0 -6
  178. package/dist/ore/dist/forms/context.js.map +0 -1
  179. package/dist/ore/dist/forms/field.cjs +0 -2
  180. package/dist/ore/dist/forms/field.cjs.map +0 -1
  181. package/dist/ore/dist/forms/field.js +0 -42
  182. package/dist/ore/dist/forms/field.js.map +0 -1
  183. package/dist/ore/dist/forms.cjs +0 -1
  184. package/dist/ore/dist/forms.js +0 -3
  185. package/dist/ore/dist/observers/intersection-observe.cjs +0 -2
  186. package/dist/ore/dist/observers/intersection-observe.cjs.map +0 -1
  187. package/dist/ore/dist/observers/intersection-observe.js +0 -12
  188. package/dist/ore/dist/observers/intersection-observe.js.map +0 -1
  189. package/dist/ore/dist/observers/media-observe.cjs +0 -1
  190. package/dist/ore/dist/observers/media-observe.js +0 -1
  191. package/dist/ore/dist/observers/mutation-observe.cjs +0 -1
  192. package/dist/ore/dist/observers/mutation-observe.js +0 -1
  193. package/dist/ore/dist/observers/resize-observe.cjs +0 -2
  194. package/dist/ore/dist/observers/resize-observe.cjs.map +0 -1
  195. package/dist/ore/dist/observers/resize-observe.js +0 -20
  196. package/dist/ore/dist/observers/resize-observe.js.map +0 -1
  197. package/dist/ore/dist/observers.cjs +0 -1
  198. package/dist/ore/dist/observers.js +0 -5
  199. package/dist/ore/dist/props.cjs +0 -2
  200. package/dist/ore/dist/props.cjs.map +0 -1
  201. package/dist/ore/dist/props.js +0 -56
  202. package/dist/ore/dist/props.js.map +0 -1
  203. package/dist/ore/dist/runtime.cjs +0 -2
  204. package/dist/ore/dist/runtime.cjs.map +0 -1
  205. package/dist/ore/dist/runtime.js +0 -25
  206. package/dist/ore/dist/runtime.js.map +0 -1
  207. package/dist/ore/dist/testing/flush.cjs +0 -2
  208. package/dist/ore/dist/testing/flush.cjs.map +0 -1
  209. package/dist/ore/dist/testing/flush.js +0 -11
  210. package/dist/ore/dist/testing/flush.js.map +0 -1
  211. package/dist/ore/dist/testing/mount.cjs +0 -2
  212. package/dist/ore/dist/testing/mount.cjs.map +0 -1
  213. package/dist/ore/dist/testing/mount.js +0 -94
  214. package/dist/ore/dist/testing/mount.js.map +0 -1
  215. package/dist/ore/dist/testing/query.cjs +0 -2
  216. package/dist/ore/dist/testing/query.cjs.map +0 -1
  217. package/dist/ore/dist/testing/query.js +0 -12
  218. package/dist/ore/dist/testing/query.js.map +0 -1
  219. package/dist/ore/dist/testing/render-hook.cjs +0 -1
  220. package/dist/ore/dist/testing/render-hook.js +0 -3
  221. package/dist/ore/dist/testing/testing.cjs +0 -1
  222. package/dist/ore/dist/testing/testing.js +0 -4
  223. package/dist/ore/dist/testing/wait.cjs +0 -1
  224. package/dist/ore/dist/testing/wait.js +0 -1
  225. package/dist/ore/dist/testing.cjs +0 -1
  226. package/dist/ore/dist/testing.js +0 -6
  227. package/dist/ore/dist/types/bindings.cjs +0 -2
  228. package/dist/ore/dist/types/bindings.cjs.map +0 -1
  229. package/dist/ore/dist/types/bindings.js +0 -15
  230. package/dist/ore/dist/types/bindings.js.map +0 -1
  231. package/dist/ore/dist/types.cjs +0 -2
  232. package/dist/ore/dist/types.cjs.map +0 -1
  233. package/dist/ore/dist/types.js +0 -15
  234. package/dist/ore/dist/types.js.map +0 -1
  235. package/dist/ore/dist/utils/css.cjs +0 -2
  236. package/dist/ore/dist/utils/css.cjs.map +0 -1
  237. package/dist/ore/dist/utils/css.js +0 -18
  238. package/dist/ore/dist/utils/css.js.map +0 -1
  239. package/dist/ore/dist/utils/dom.cjs +0 -2
  240. package/dist/ore/dist/utils/dom.cjs.map +0 -1
  241. package/dist/ore/dist/utils/dom.js +0 -43
  242. package/dist/ore/dist/utils/dom.js.map +0 -1
  243. package/dist/ore/dist/utils/id.cjs +0 -2
  244. package/dist/ore/dist/utils/id.cjs.map +0 -1
  245. package/dist/ore/dist/utils/id.js +0 -4
  246. package/dist/ore/dist/utils/id.js.map +0 -1
package/dist/grid.js CHANGED
@@ -1,7 +1,6 @@
1
- import { resizeObserver as e } from "./ore/dist/observers/resize-observe.js";
2
- import "./ore/dist/observers.js";
3
- import t from "./layout/grid/grid.css.js";
4
- import { define as n, getHost as r, html as i, onMounted as a, prop as o, watchEffect as s } from "@vielzeug/ore";
1
+ import e from "./layout/grid/grid.css.js";
2
+ import { define as t, getHost as n, html as r, onMounted as i, prop as a, watchEffect as o } from "@vielzeug/ore";
3
+ import { resizeObserver as s } from "@vielzeug/ore/observers";
5
4
  //#region src/layout/grid/grid.ts
6
5
  var c = [
7
6
  ["cols2xl", "--size-screen-2xl"],
@@ -25,64 +24,64 @@ var c = [
25
24
  "--size-screen-sm": 640,
26
25
  "--size-screen-xl": 1280
27
26
  }, f = "ore-grid";
28
- n(f, {
27
+ t(f, {
29
28
  props: {
30
- align: o.string(),
31
- areas: o.string(),
32
- areas2xl: o.string(),
33
- areasLg: o.string(),
34
- areasMd: o.string(),
35
- areasSm: o.string(),
36
- areasXl: o.string(),
37
- cols: o.string(),
38
- cols2xl: o.string(),
39
- colsLg: o.string(),
40
- colsMd: o.string(),
41
- colsSm: o.string(),
42
- colsXl: o.string(),
43
- flow: o.string(),
44
- fullwidth: o.bool(!1),
45
- gap: o.string(),
46
- justify: o.string(),
47
- minColWidth: o.string(),
48
- responsive: o.bool(!1),
49
- rows: o.string()
29
+ align: a.string(),
30
+ areas: a.string(),
31
+ areas2xl: a.string(),
32
+ areasLg: a.string(),
33
+ areasMd: a.string(),
34
+ areasSm: a.string(),
35
+ areasXl: a.string(),
36
+ cols: a.string(),
37
+ cols2xl: a.string(),
38
+ colsLg: a.string(),
39
+ colsMd: a.string(),
40
+ colsSm: a.string(),
41
+ colsXl: a.string(),
42
+ flow: a.string(),
43
+ fullwidth: a.bool(!1),
44
+ gap: a.string(),
45
+ justify: a.string(),
46
+ minColWidth: a.string(),
47
+ responsive: a.bool(!1),
48
+ rows: a.string()
50
49
  },
51
- setup(t) {
52
- let n = r(), o = s, f = (e, t, n) => e === "auto" || !e && t ? `repeat(auto-fit, minmax(${n || "250px"}, 1fr))` : e ? `repeat(${e}, 1fr)` : null, p = () => {
53
- let e = n.offsetWidth, r = !!t.responsive.value, i = t.minColWidth.value ?? "", a;
54
- for (let [r, i] of c) if (e >= u(n, i, d[i]) && t[r].value) {
55
- a = t[r].value;
50
+ setup(e) {
51
+ let t = n(), a = o, f = (e, t, n) => e === "auto" || !e && t ? `repeat(auto-fit, minmax(${n || "250px"}, 1fr))` : e ? `repeat(${e}, 1fr)` : null, p = () => {
52
+ let n = t.offsetWidth, r = !!e.responsive.value, i = e.minColWidth.value ?? "", a;
53
+ for (let [r, i] of c) if (n >= u(t, i, d[i]) && e[r].value) {
54
+ a = e[r].value;
56
55
  break;
57
56
  }
58
- a ||= t.cols.value || void 0;
57
+ a ||= e.cols.value || void 0;
59
58
  let o = f(a, r, i);
60
- o ? n.style.setProperty("--_cols", o) : n.style.removeProperty("--_cols");
59
+ o ? t.style.setProperty("--_cols", o) : t.style.removeProperty("--_cols");
61
60
  };
62
- o(() => {
63
- t.cols.value, t.colsSm.value, t.colsMd.value, t.colsLg.value, t.colsXl.value, t.cols2xl.value, t.responsive.value, t.minColWidth.value, p();
61
+ a(() => {
62
+ e.cols.value, e.colsSm.value, e.colsMd.value, e.colsLg.value, e.colsXl.value, e.cols2xl.value, e.responsive.value, e.minColWidth.value, p();
64
63
  });
65
64
  let m = () => {
66
- let e = n.offsetWidth, r = "";
67
- for (let [i, a] of l) if (e >= u(n, a, d[a]) && t[i].value) {
68
- r = t[i].value;
65
+ let n = t.offsetWidth, r = "";
66
+ for (let [i, a] of l) if (n >= u(t, a, d[a]) && e[i].value) {
67
+ r = e[i].value;
69
68
  break;
70
69
  }
71
- r ||= t.areas.value || "", r ? n.style.setProperty("grid-template-areas", r) : n.style.removeProperty("grid-template-areas");
70
+ r ||= e.areas.value || "", r ? t.style.setProperty("grid-template-areas", r) : t.style.removeProperty("grid-template-areas");
72
71
  };
73
- return o(() => {
74
- let e = t.rows.value;
75
- e && e !== "auto" ? n.style.setProperty("--_rows", `repeat(${e}, 1fr)`) : n.style.removeProperty("--_rows");
76
- }), o(() => {
77
- t.areas.value, t.areasSm.value, t.areasMd.value, t.areasLg.value, t.areasXl.value, t.areas2xl.value, m();
72
+ return a(() => {
73
+ let n = e.rows.value;
74
+ n && n !== "auto" ? t.style.setProperty("--_rows", `repeat(${n}, 1fr)`) : t.style.removeProperty("--_rows");
78
75
  }), a(() => {
79
- let t = e(n);
80
- o(() => {
81
- t.value, p(), m();
76
+ e.areas.value, e.areasSm.value, e.areasMd.value, e.areasLg.value, e.areasXl.value, e.areas2xl.value, m();
77
+ }), i(() => {
78
+ let e = s(t);
79
+ a(() => {
80
+ e.value, p(), m();
82
81
  });
83
- }), i`<slot></slot>`;
82
+ }), r`<slot></slot>`;
84
83
  },
85
- styles: [t]
84
+ styles: [e]
86
85
  });
87
86
  //#endregion
88
87
  export { f as GRID_TAG };
package/dist/grid.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"grid.js","names":[],"sources":["../src/layout/grid/grid.ts"],"sourcesContent":["import { define, html, prop, getHost, onMounted, watchEffect } from '@vielzeug/ore';\nimport { resizeObserver } from '@vielzeug/ore/observers';\n\nimport styles from './grid.css?inline';\n\nconst BREAKPOINTS: ['cols2xl' | 'colsXl' | 'colsLg' | 'colsMd' | 'colsSm', string][] = [\n ['cols2xl', '--size-screen-2xl'],\n ['colsXl', '--size-screen-xl'],\n ['colsLg', '--size-screen-lg'],\n ['colsMd', '--size-screen-md'],\n ['colsSm', '--size-screen-sm'],\n];\n\nconst AREAS_BREAKPOINTS: ['areas2xl' | 'areasXl' | 'areasLg' | 'areasMd' | 'areasSm', string][] = [\n ['areas2xl', '--size-screen-2xl'],\n ['areasXl', '--size-screen-xl'],\n ['areasLg', '--size-screen-lg'],\n ['areasMd', '--size-screen-md'],\n ['areasSm', '--size-screen-sm'],\n];\n\nconst resolveBp = (host: HTMLElement, varName: string, fallback: number): number => {\n const raw = getComputedStyle(host).getPropertyValue(varName).trim();\n const parsed = Number.parseFloat(raw);\n\n return Number.isFinite(parsed) ? parsed : fallback;\n};\n\nconst BP_FALLBACKS: Record<string, number> = {\n '--size-screen-2xl': 1536,\n '--size-screen-lg': 1024,\n '--size-screen-md': 768,\n '--size-screen-sm': 640,\n '--size-screen-xl': 1280,\n};\n\ntype ColCount = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'auto';\n\n/** Grid component properties */\nexport type OreGridProps = {\n /** Align items vertically */\n align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';\n /** CSS grid-template-areas value */\n areas?: string;\n /** grid-template-areas at 2xl breakpoint (≥1536px) */\n areas2xl?: string;\n /** grid-template-areas at lg breakpoint (≥1024px) */\n areasLg?: string;\n /** grid-template-areas at md breakpoint (≥768px) */\n areasMd?: string;\n /** grid-template-areas at sm breakpoint (≥640px) */\n areasSm?: string;\n /** grid-template-areas at xl breakpoint (≥1280px) */\n areasXl?: string;\n /** Number of columns: '1'-'12' | 'auto' */\n cols?: ColCount;\n /** Columns at 2xl breakpoint (≥1536px) */\n cols2xl?: ColCount;\n /** Columns at lg breakpoint (≥1024px) */\n colsLg?: ColCount;\n /** Columns at md breakpoint (≥768px) */\n colsMd?: ColCount;\n /** Columns at sm breakpoint (≥640px) */\n colsSm?: ColCount;\n /** Columns at xl breakpoint (≥1280px) */\n colsXl?: ColCount;\n /** Grid auto flow direction */\n flow?: 'row' | 'column' | 'row-dense' | 'column-dense';\n /** Stretch the grid to fill its container's full width */\n fullwidth?: boolean;\n /** Gap between items */\n gap?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Justify items horizontally */\n justify?: 'start' | 'center' | 'end' | 'stretch';\n /** Minimum column width for responsive mode (default: 250px) */\n minColWidth?: string;\n /** Use auto-fit responsive columns */\n responsive?: boolean;\n /** Number of rows: '1'-'12' | 'auto' */\n rows?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'auto';\n};\n\n/**\n * ore-grid — Flexible grid layout with responsive column control.\n *\n * Columns are computed in JS and applied as `--_cols` inline, so they respond\n * to the element's own width via ResizeObserver. CSS custom properties\n * `--grid-cols`, `--grid-rows`, `--grid-gap`, `--grid-row-gap`, `--grid-col-gap`\n * are honoured as fallbacks when no attribute is set.\n *\n * @element ore-grid\n *\n * @attr {string} cols - Column count: '1'–'12' | 'auto'\n * @attr {string} cols-sm - Columns when width ≥ 640px\n * @attr {string} cols-md - Columns when width ≥ 768px\n * @attr {string} cols-lg - Columns when width ≥ 1024px\n * @attr {string} cols-xl - Columns when width ≥ 1280px\n * @attr {string} cols-2xl - Columns when width ≥ 1536px\n * @attr {string} rows - Row count: '1'–'12' | 'auto'\n * @attr {string} gap - Gap token: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n * @attr {string} align - align-items: 'start' | 'center' | 'end' | 'stretch' | 'baseline'\n * @attr {string} justify - justify-items: 'start' | 'center' | 'end' | 'stretch'\n * @attr {string} flow - grid-auto-flow: 'row' | 'column' | 'row-dense' | 'column-dense'\n * @attr {boolean} responsive - Enables auto-fit columns without a fixed count\n * @attr {string} min-col-width - Min column width for responsive mode (default: 250px)\n * @attr {boolean} fullwidth - Stretch the grid to fill its container's full width\n * @attr {string} areas - CSS grid-template-areas value (e.g. \"'header header' 'nav main'\")\n * @attr {string} areas-sm - grid-template-areas when width ≥ 640px\n * @attr {string} areas-md - grid-template-areas when width ≥ 768px\n * @attr {string} areas-lg - grid-template-areas when width ≥ 1024px\n * @attr {string} areas-xl - grid-template-areas when width ≥ 1280px\n * @attr {string} areas-2xl - grid-template-areas when width ≥ 1536px\n *\n * @slot - Grid items\n *\n * @cssprop --grid-cols - Fallback column template (used when no cols attr is set)\n * @cssprop --grid-rows - Fallback row template\n * @cssprop --grid-gap - Fallback gap\n * @cssprop --grid-row-gap - Fallback row gap\n * @cssprop --grid-col-gap - Fallback column gap\n *\n * @example\n * <ore-grid cols=\"1\" cols-sm=\"2\" cols-lg=\"4\" gap=\"md\">\n * <div>Item</div>\n * </ore-grid>\n *\n * @example\n * <!-- Responsive auto-fit -->\n * <ore-grid responsive min-col-width=\"200px\" gap=\"sm\">\n * <div>Card</div>\n * </ore-grid>\n *\n * @example\n * <!-- Named grid areas -->\n * <ore-grid cols=\"2\" rows=\"2\" areas=\"'header header' 'nav main'\">\n * <header style=\"grid-area: header\">Header</header>\n * <nav style=\"grid-area: nav\">Nav</nav>\n * <main style=\"grid-area: main\">Main</main>\n * </ore-grid>\n */\nexport const GRID_TAG = 'ore-grid' as const;\ndefine<OreGridProps>(GRID_TAG, {\n props: {\n align: prop.string<'start' | 'center' | 'end' | 'stretch' | 'baseline'>(),\n areas: prop.string(),\n areas2xl: prop.string(),\n areasLg: prop.string(),\n areasMd: prop.string(),\n areasSm: prop.string(),\n areasXl: prop.string(),\n cols: prop.string<ColCount>(),\n cols2xl: prop.string<ColCount>(),\n colsLg: prop.string<ColCount>(),\n colsMd: prop.string<ColCount>(),\n colsSm: prop.string<ColCount>(),\n colsXl: prop.string<ColCount>(),\n flow: prop.string<'row' | 'column' | 'row-dense' | 'column-dense'>(),\n fullwidth: prop.bool(false),\n gap: prop.string<'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>(),\n justify: prop.string<'start' | 'center' | 'end' | 'stretch'>(),\n minColWidth: prop.string(),\n responsive: prop.bool(false),\n rows: prop.string<'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'auto'>(),\n },\n\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const computeCols = (activeCols: string | undefined, responsive: boolean, minW: string): string | null => {\n if (activeCols === 'auto' || (!activeCols && responsive)) {\n return `repeat(auto-fit, minmax(${minW || '250px'}, 1fr))`;\n }\n\n return activeCols ? `repeat(${activeCols}, 1fr)` : null;\n };\n const updateCols = () => {\n const w = el.offsetWidth;\n const responsive = Boolean(props.responsive.value);\n const minW = props.minColWidth.value ?? '';\n let activeCols: string | undefined;\n\n for (const [key, cssVar] of BREAKPOINTS) {\n if (w >= resolveBp(el, cssVar, BP_FALLBACKS[cssVar]) && props[key].value) {\n activeCols = props[key].value!;\n break;\n }\n }\n activeCols ||= props.cols.value || undefined;\n\n const colsValue = computeCols(activeCols, responsive, minW);\n\n if (colsValue) {\n el.style.setProperty('--_cols', colsValue);\n } else {\n el.style.removeProperty('--_cols');\n }\n };\n\n // Re-run cols whenever any responsive prop changes\n watch(() => {\n void [\n props.cols.value,\n props.colsSm.value,\n props.colsMd.value,\n props.colsLg.value,\n props.colsXl.value,\n props.cols2xl.value,\n props.responsive.value,\n props.minColWidth.value,\n ];\n updateCols();\n });\n\n const updateAreas = () => {\n const w = el.offsetWidth;\n let active = '';\n\n for (const [key, cssVar] of AREAS_BREAKPOINTS) {\n if (w >= resolveBp(el, cssVar, BP_FALLBACKS[cssVar]) && props[key].value) {\n active = props[key].value!;\n break;\n }\n }\n active ||= props.areas.value || '';\n\n if (active) {\n el.style.setProperty('grid-template-areas', active);\n } else {\n el.style.removeProperty('grid-template-areas');\n }\n };\n\n // Rows\n watch(() => {\n const rows = props.rows.value;\n\n if (rows && rows !== 'auto') {\n el.style.setProperty('--_rows', `repeat(${rows}, 1fr)`);\n } else {\n el.style.removeProperty('--_rows');\n }\n });\n // Grid template areas (responsive)\n watch(() => {\n void [\n props.areas.value,\n props.areasSm.value,\n props.areasMd.value,\n props.areasLg.value,\n props.areasXl.value,\n props.areas2xl.value,\n ];\n updateAreas();\n });\n\n // Also, update on element resize (drives breakpoint switching)\n onMounted(() => {\n const size = resizeObserver(el);\n\n watch(() => {\n void size.value;\n updateCols();\n updateAreas();\n });\n });\n\n return html`<slot></slot>`;\n },\n\n styles: [styles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"grid.js","names":[],"sources":["../src/layout/grid/grid.ts"],"sourcesContent":["import { define, html, prop, getHost, onMounted, watchEffect } from '@vielzeug/ore';\nimport { resizeObserver } from '@vielzeug/ore/observers';\n\nimport styles from './grid.css?inline';\n\nconst BREAKPOINTS: ['cols2xl' | 'colsXl' | 'colsLg' | 'colsMd' | 'colsSm', string][] = [\n ['cols2xl', '--size-screen-2xl'],\n ['colsXl', '--size-screen-xl'],\n ['colsLg', '--size-screen-lg'],\n ['colsMd', '--size-screen-md'],\n ['colsSm', '--size-screen-sm'],\n];\n\nconst AREAS_BREAKPOINTS: ['areas2xl' | 'areasXl' | 'areasLg' | 'areasMd' | 'areasSm', string][] = [\n ['areas2xl', '--size-screen-2xl'],\n ['areasXl', '--size-screen-xl'],\n ['areasLg', '--size-screen-lg'],\n ['areasMd', '--size-screen-md'],\n ['areasSm', '--size-screen-sm'],\n];\n\nconst resolveBp = (host: HTMLElement, varName: string, fallback: number): number => {\n const raw = getComputedStyle(host).getPropertyValue(varName).trim();\n const parsed = Number.parseFloat(raw);\n\n return Number.isFinite(parsed) ? parsed : fallback;\n};\n\nconst BP_FALLBACKS: Record<string, number> = {\n '--size-screen-2xl': 1536,\n '--size-screen-lg': 1024,\n '--size-screen-md': 768,\n '--size-screen-sm': 640,\n '--size-screen-xl': 1280,\n};\n\ntype ColCount = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'auto';\n\n/** Grid component properties */\nexport type OreGridProps = {\n /** Align items vertically */\n align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';\n /** CSS grid-template-areas value */\n areas?: string;\n /** grid-template-areas at 2xl breakpoint (≥1536px) */\n areas2xl?: string;\n /** grid-template-areas at lg breakpoint (≥1024px) */\n areasLg?: string;\n /** grid-template-areas at md breakpoint (≥768px) */\n areasMd?: string;\n /** grid-template-areas at sm breakpoint (≥640px) */\n areasSm?: string;\n /** grid-template-areas at xl breakpoint (≥1280px) */\n areasXl?: string;\n /** Number of columns: '1'-'12' | 'auto' */\n cols?: ColCount;\n /** Columns at 2xl breakpoint (≥1536px) */\n cols2xl?: ColCount;\n /** Columns at lg breakpoint (≥1024px) */\n colsLg?: ColCount;\n /** Columns at md breakpoint (≥768px) */\n colsMd?: ColCount;\n /** Columns at sm breakpoint (≥640px) */\n colsSm?: ColCount;\n /** Columns at xl breakpoint (≥1280px) */\n colsXl?: ColCount;\n /** Grid auto flow direction */\n flow?: 'row' | 'column' | 'row-dense' | 'column-dense';\n /** Stretch the grid to fill its container's full width */\n fullwidth?: boolean;\n /** Gap between items */\n gap?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Justify items horizontally */\n justify?: 'start' | 'center' | 'end' | 'stretch';\n /** Minimum column width for responsive mode (default: 250px) */\n minColWidth?: string;\n /** Use auto-fit responsive columns */\n responsive?: boolean;\n /** Number of rows: '1'-'12' | 'auto' */\n rows?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'auto';\n};\n\n/**\n * ore-grid — Flexible grid layout with responsive column control.\n *\n * Columns are computed in JS and applied as `--_cols` inline, so they respond\n * to the element's own width via ResizeObserver. CSS custom properties\n * `--grid-cols`, `--grid-rows`, `--grid-gap`, `--grid-row-gap`, `--grid-col-gap`\n * are honoured as fallbacks when no attribute is set.\n *\n * @element ore-grid\n *\n * @attr {string} cols - Column count: '1'–'12' | 'auto'\n * @attr {string} cols-sm - Columns when width ≥ 640px\n * @attr {string} cols-md - Columns when width ≥ 768px\n * @attr {string} cols-lg - Columns when width ≥ 1024px\n * @attr {string} cols-xl - Columns when width ≥ 1280px\n * @attr {string} cols-2xl - Columns when width ≥ 1536px\n * @attr {string} rows - Row count: '1'–'12' | 'auto'\n * @attr {string} gap - Gap token: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n * @attr {string} align - align-items: 'start' | 'center' | 'end' | 'stretch' | 'baseline'\n * @attr {string} justify - justify-items: 'start' | 'center' | 'end' | 'stretch'\n * @attr {string} flow - grid-auto-flow: 'row' | 'column' | 'row-dense' | 'column-dense'\n * @attr {boolean} responsive - Enables auto-fit columns without a fixed count\n * @attr {string} min-col-width - Min column width for responsive mode (default: 250px)\n * @attr {boolean} fullwidth - Stretch the grid to fill its container's full width\n * @attr {string} areas - CSS grid-template-areas value (e.g. \"'header header' 'nav main'\")\n * @attr {string} areas-sm - grid-template-areas when width ≥ 640px\n * @attr {string} areas-md - grid-template-areas when width ≥ 768px\n * @attr {string} areas-lg - grid-template-areas when width ≥ 1024px\n * @attr {string} areas-xl - grid-template-areas when width ≥ 1280px\n * @attr {string} areas-2xl - grid-template-areas when width ≥ 1536px\n *\n * @slot - Grid items\n *\n * @cssprop --grid-cols - Fallback column template (used when no cols attr is set)\n * @cssprop --grid-rows - Fallback row template\n * @cssprop --grid-gap - Fallback gap\n * @cssprop --grid-row-gap - Fallback row gap\n * @cssprop --grid-col-gap - Fallback column gap\n *\n * @example\n * <ore-grid cols=\"1\" cols-sm=\"2\" cols-lg=\"4\" gap=\"md\">\n * <div>Item</div>\n * </ore-grid>\n *\n * @example\n * <!-- Responsive auto-fit -->\n * <ore-grid responsive min-col-width=\"200px\" gap=\"sm\">\n * <div>Card</div>\n * </ore-grid>\n *\n * @example\n * <!-- Named grid areas -->\n * <ore-grid cols=\"2\" rows=\"2\" areas=\"'header header' 'nav main'\">\n * <header style=\"grid-area: header\">Header</header>\n * <nav style=\"grid-area: nav\">Nav</nav>\n * <main style=\"grid-area: main\">Main</main>\n * </ore-grid>\n */\nexport const GRID_TAG = 'ore-grid' as const;\ndefine<OreGridProps>(GRID_TAG, {\n props: {\n align: prop.string<'start' | 'center' | 'end' | 'stretch' | 'baseline'>(),\n areas: prop.string(),\n areas2xl: prop.string(),\n areasLg: prop.string(),\n areasMd: prop.string(),\n areasSm: prop.string(),\n areasXl: prop.string(),\n cols: prop.string<ColCount>(),\n cols2xl: prop.string<ColCount>(),\n colsLg: prop.string<ColCount>(),\n colsMd: prop.string<ColCount>(),\n colsSm: prop.string<ColCount>(),\n colsXl: prop.string<ColCount>(),\n flow: prop.string<'row' | 'column' | 'row-dense' | 'column-dense'>(),\n fullwidth: prop.bool(false),\n gap: prop.string<'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>(),\n justify: prop.string<'start' | 'center' | 'end' | 'stretch'>(),\n minColWidth: prop.string(),\n responsive: prop.bool(false),\n rows: prop.string<'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'auto'>(),\n },\n\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const computeCols = (activeCols: string | undefined, responsive: boolean, minW: string): string | null => {\n if (activeCols === 'auto' || (!activeCols && responsive)) {\n return `repeat(auto-fit, minmax(${minW || '250px'}, 1fr))`;\n }\n\n return activeCols ? `repeat(${activeCols}, 1fr)` : null;\n };\n const updateCols = () => {\n const w = el.offsetWidth;\n const responsive = Boolean(props.responsive.value);\n const minW = props.minColWidth.value ?? '';\n let activeCols: string | undefined;\n\n for (const [key, cssVar] of BREAKPOINTS) {\n if (w >= resolveBp(el, cssVar, BP_FALLBACKS[cssVar]) && props[key].value) {\n activeCols = props[key].value!;\n break;\n }\n }\n activeCols ||= props.cols.value || undefined;\n\n const colsValue = computeCols(activeCols, responsive, minW);\n\n if (colsValue) {\n el.style.setProperty('--_cols', colsValue);\n } else {\n el.style.removeProperty('--_cols');\n }\n };\n\n // Re-run cols whenever any responsive prop changes\n watch(() => {\n void [\n props.cols.value,\n props.colsSm.value,\n props.colsMd.value,\n props.colsLg.value,\n props.colsXl.value,\n props.cols2xl.value,\n props.responsive.value,\n props.minColWidth.value,\n ];\n updateCols();\n });\n\n const updateAreas = () => {\n const w = el.offsetWidth;\n let active = '';\n\n for (const [key, cssVar] of AREAS_BREAKPOINTS) {\n if (w >= resolveBp(el, cssVar, BP_FALLBACKS[cssVar]) && props[key].value) {\n active = props[key].value!;\n break;\n }\n }\n active ||= props.areas.value || '';\n\n if (active) {\n el.style.setProperty('grid-template-areas', active);\n } else {\n el.style.removeProperty('grid-template-areas');\n }\n };\n\n // Rows\n watch(() => {\n const rows = props.rows.value;\n\n if (rows && rows !== 'auto') {\n el.style.setProperty('--_rows', `repeat(${rows}, 1fr)`);\n } else {\n el.style.removeProperty('--_rows');\n }\n });\n // Grid template areas (responsive)\n watch(() => {\n void [\n props.areas.value,\n props.areasSm.value,\n props.areasMd.value,\n props.areasLg.value,\n props.areasXl.value,\n props.areas2xl.value,\n ];\n updateAreas();\n });\n\n // Also, update on element resize (drives breakpoint switching)\n onMounted(() => {\n const size = resizeObserver(el);\n\n watch(() => {\n void size.value;\n updateCols();\n updateAreas();\n });\n });\n\n return html`<slot></slot>`;\n },\n\n styles: [styles],\n});\n"],"mappings":"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"}
package/dist/icon.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./_virtual/_rolldown/runtime.cjs"),t=require("./ore/dist/directives/raw.cjs");require("./ore/dist/directives.cjs");const n=require("./_dev.cjs"),r=require("./content/icon/icon.css.cjs");let i=require("@vielzeug/ore"),a=require("@vielzeug/ripple"),o=require("lucide");o=e.__toESM(o,1);var s=16,c=2,l=24,u=new Set([`circle`,`clipPath`,`defs`,`ellipse`,`g`,`line`,`linearGradient`,`mask`,`path`,`polygon`,`polyline`,`radialGradient`,`rect`,`stop`,`symbol`,`use`]),d=/^[a-zA-Z][a-zA-Z0-9:_-]*$/,f=/^(on|xlink:|xml:|href$)/i,p=new Map(Object.entries(o.icons));function m(e){for(let[t,n]of Object.entries(e))p.set(t,n)}var h=e=>Object.entries(e).filter(([e])=>d.test(e)&&!f.test(e)).map(([e,t])=>`${e}="${String(t).replace(/&/g,`&amp;`).replace(/"/g,`&quot;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}"`).join(` `),g=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).split(/[^a-zA-Z0-9]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(``),_=e=>{if(e==null||e===``)return s;let t=Number(e);return Number.isFinite(t)&&t>0&&/^\d+(\.\d+)?$/.test(e.trim())?t:e},v=`ore-icon`;(0,i.define)(v,{props:{absoluteStrokeWidth:i.prop.bool(),label:i.prop.string(),name:i.prop.string(),size:{default:s,parse:_,reflect:!1},solid:i.prop.bool(),strokeWidth:i.prop.number(c)},setup(e){return(0,i.bind)({attr:{"aria-hidden":()=>(e.label.value??``).trim()?null:`true`,"aria-label":()=>(e.label.value??``).trim()||null,role:()=>(e.label.value??``).trim()?`img`:null},style:{"--_size-px":()=>{let t=e.size.value;return typeof t==`number`?`${t}px`:String(t)}}}),i.html`${t.raw((0,a.computed)(()=>{let t=(e.name.value??``).trim();if(!t)return``;let r=p.get(t)??p.get(g(t));if(!r)return n.warn(`ore-icon: icon not found: "${String(t).slice(0,64)}"`),``;let i=e.size.value,a=typeof i==`number`?i:l,o=e.absoluteStrokeWidth.value&&!e.solid.value?e.strokeWidth.value*(l/a):e.strokeWidth.value,s=r.filter(([e])=>u.has(e)).map(([e,t])=>{let n={};for(let[e,r]of Object.entries(t))r!==void 0&&(n[e]=r);return`<${e} ${h(n)} />`}).join(``);return`<svg ${h({fill:e.solid.value?`currentColor`:`none`,part:`svg`,stroke:e.solid.value?`none`:`currentColor`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"stroke-width":e.solid.value?0:o,style:`width:100%;height:100%`,viewBox:`0 0 24 24`,xmlns:`http://www.w3.org/2000/svg`})}>${s}</svg>`}))}`},styles:[r.default]}),exports.ICON_TAG=v,exports.registerIcons=m;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./_virtual/_rolldown/runtime.cjs"),t=require("./_dev.cjs"),n=require("./content/icon/icon.css.cjs");let r=require("@vielzeug/ore"),i=require("@vielzeug/ore/directives"),a=require("@vielzeug/ripple"),o=require("lucide");o=e.__toESM(o,1);var s=16,c=2,l=24,u=new Set([`circle`,`clipPath`,`defs`,`ellipse`,`g`,`line`,`linearGradient`,`mask`,`path`,`polygon`,`polyline`,`radialGradient`,`rect`,`stop`,`symbol`,`use`]),d=/^[a-zA-Z][a-zA-Z0-9:_-]*$/,f=/^(on|xlink:|xml:|href$)/i,p=new Map(Object.entries(o.icons));function m(e){for(let[t,n]of Object.entries(e))p.set(t,n)}var h=e=>Object.entries(e).filter(([e])=>d.test(e)&&!f.test(e)).map(([e,t])=>`${e}="${String(t).replace(/&/g,`&amp;`).replace(/"/g,`&quot;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}"`).join(` `),g=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).split(/[^a-zA-Z0-9]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(``),_=e=>{if(e==null||e===``)return s;let t=Number(e);return Number.isFinite(t)&&t>0&&/^\d+(\.\d+)?$/.test(e.trim())?t:e},v=`ore-icon`;(0,r.define)(v,{props:{absoluteStrokeWidth:r.prop.bool(),label:r.prop.string(),name:r.prop.string(),size:{default:s,parse:_,reflect:!1},solid:r.prop.bool(),strokeWidth:r.prop.number(c)},setup(e){return(0,r.bind)({attr:{"aria-hidden":()=>(e.label.value??``).trim()?null:`true`,"aria-label":()=>(e.label.value??``).trim()||null,role:()=>(e.label.value??``).trim()?`img`:null},style:{"--_size-px":()=>{let t=e.size.value;return typeof t==`number`?`${t}px`:String(t)}}}),r.html`${(0,i.raw)((0,a.computed)(()=>{let n=(e.name.value??``).trim();if(!n)return``;let r=p.get(n)??p.get(g(n));if(!r)return t.warn(`ore-icon: icon not found: "${String(n).slice(0,64)}"`),``;let i=e.size.value,a=typeof i==`number`?i:l,o=e.absoluteStrokeWidth.value&&!e.solid.value?e.strokeWidth.value*(l/a):e.strokeWidth.value,s=r.filter(([e])=>u.has(e)).map(([e,t])=>{let n={};for(let[e,r]of Object.entries(t))r!==void 0&&(n[e]=r);return`<${e} ${h(n)} />`}).join(``);return`<svg ${h({fill:e.solid.value?`currentColor`:`none`,part:`svg`,stroke:e.solid.value?`none`:`currentColor`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"stroke-width":e.solid.value?0:o,style:`width:100%;height:100%`,viewBox:`0 0 24 24`,xmlns:`http://www.w3.org/2000/svg`})}>${s}</svg>`}))}`},styles:[n.default]}),exports.ICON_TAG=v,exports.registerIcons=m;
2
2
  //# sourceMappingURL=icon.cjs.map
package/dist/icon.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"icon.cjs","names":[],"sources":["../src/content/icon/icon.ts"],"sourcesContent":["import { define, html, prop, bind } from '@vielzeug/ore';\nimport { raw } from '@vielzeug/ore/directives';\nimport { computed } from '@vielzeug/ripple';\nimport * as lucideModule from 'lucide';\n\nimport { warn } from '../../_dev';\nimport styles from './icon.css?inline';\n\nexport type IconNode = Array<[string, Record<string, string | number | undefined>]>;\n\nconst DEFAULT_SIZE = 16;\nconst DEFAULT_STROKE_WIDTH = 2;\nconst LUCIDE_VIEWBOX_SIZE = 24;\n\n/**\n * Allowlisted SVG shape/structure element names. Only these tags are permitted\n * when building the SVG markup from an IconNode, preventing arbitrary element\n * injection (e.g. <script>, event-handler-bearing elements).\n */\nconst ALLOWED_SVG_TAGS = new Set([\n 'circle',\n 'clipPath',\n 'defs',\n 'ellipse',\n 'g',\n 'line',\n 'linearGradient',\n 'mask',\n 'path',\n 'polygon',\n 'polyline',\n 'radialGradient',\n 'rect',\n 'stop',\n 'symbol',\n 'use',\n]);\n\n/**\n * Allowlisted SVG presentation / structural attribute names.\n * Event handler attributes (on*) and \"xlink:href\" are excluded.\n */\nconst ATTR_KEY_RE = /^[a-zA-Z][a-zA-Z0-9:_-]*$/;\nconst BLOCKED_ATTR_RE = /^(on|xlink:|xml:|href$)/i;\n\n// Sync registry seeded from lucide at module load; extend at any time via registerIcons()\nconst registry = new Map<string, IconNode>(\n Object.entries((lucideModule as unknown as { icons: Record<string, IconNode> }).icons),\n);\n\n/**\n * Register additional icons (or override existing ones) by name.\n * Keys may be kebab-case or PascalCase — both are accepted by `ore-icon`.\n */\nexport function registerIcons(icons: Record<string, IconNode>): void {\n for (const [name, node] of Object.entries(icons)) {\n registry.set(name, node);\n }\n}\n\nconst toAttrString = (attrs: Record<string, string | number>): string =>\n Object.entries(attrs)\n .filter(([k]) => ATTR_KEY_RE.test(k) && !BLOCKED_ATTR_RE.test(k))\n .map(\n ([k, v]) =>\n `${k}=\"${String(v).replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}\"`,\n )\n .join(' ');\n\nconst toPascalCase = (value: string): string =>\n value\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase())\n .join('');\n\nconst parseSize = (value: string | null): number | string => {\n if (value == null || value === '') return DEFAULT_SIZE;\n\n const n = Number(value);\n\n return Number.isFinite(n) && n > 0 && /^\\d+(\\.\\d+)?$/.test(value.trim()) ? n : value;\n};\n\n/** Icon component properties */\nexport type OreIconProps = {\n /** Keep stroke width visually consistent when icon size changes */\n absoluteStrokeWidth?: boolean;\n /** Accessible text label. Decorative icons should omit this. */\n label?: string;\n /** Lucide icon name, e.g. `search` or `chevron-right` */\n name?: string;\n /** Icon width/height in px by default. Accepts CSS lengths. */\n size?: number | string;\n /** Render as a filled/solid shape instead of a stroked outline */\n solid?: boolean;\n /** SVG stroke width */\n strokeWidth?: number;\n};\n\n/**\n * Icon wrapper for consistent Lucide rendering across Block.\n *\n * @element ore-icon\n *\n * @attr {string} name - Lucide icon name, e.g. `search` or `chevron-right`\n * @attr {number|string} size - Width/height (default: 16)\n * @attr {number} stroke-width - SVG stroke width (default: 2)\n * @attr {boolean} absolute-stroke-width - Keep stroke width visually stable across icon sizes\n * @attr {boolean} solid - Render as filled shape instead of stroked outline\n * @attr {string} label - Accessible label; when omitted the icon is decorative\n *\n * @csspart svg - Internal SVG element\n *\n * @example\n * ```html\n * <ore-icon name=\"search\"></ore-icon>\n * <ore-icon name=\"chevron-right\" size=\"18\"></ore-icon>\n * <ore-icon name=\"trash-2\" label=\"Delete\"></ore-icon>\n * <ore-icon name=\"star\" solid></ore-icon>\n * ```\n */\nexport const ICON_TAG = 'ore-icon' as const;\ndefine<OreIconProps>(ICON_TAG, {\n props: {\n absoluteStrokeWidth: prop.bool(),\n label: prop.string(),\n name: prop.string(),\n size: { default: DEFAULT_SIZE as number | string, parse: parseSize, reflect: false },\n solid: prop.bool(),\n strokeWidth: prop.number(DEFAULT_STROKE_WIDTH),\n },\n setup(props) {\n bind({\n attr: {\n 'aria-hidden': () => ((props.label.value ?? '').trim() ? null : 'true'),\n 'aria-label': () => (props.label.value ?? '').trim() || null,\n role: () => ((props.label.value ?? '').trim() ? 'img' : null),\n },\n style: {\n '--_size-px': () => {\n const s = props.size.value;\n\n return typeof s === 'number' ? `${s}px` : String(s);\n },\n },\n });\n\n const markup = computed(() => {\n const name = (props.name.value ?? '').trim();\n\n if (!name) return '';\n\n const iconNode = registry.get(name) ?? registry.get(toPascalCase(name));\n\n if (!iconNode) {\n warn(`ore-icon: icon not found: \"${String(name).slice(0, 64)}\"`);\n\n return '';\n }\n\n const size = props.size.value;\n const numericSize = typeof size === 'number' ? size : LUCIDE_VIEWBOX_SIZE;\n\n const strokeWidth =\n props.absoluteStrokeWidth.value && !props.solid.value\n ? props.strokeWidth.value! * (LUCIDE_VIEWBOX_SIZE / numericSize)\n : props.strokeWidth.value!;\n\n const nodes = iconNode\n .filter(([tag]) => ALLOWED_SVG_TAGS.has(tag))\n .map(([tag, tagAttrs]) => {\n const attrs: Record<string, string | number> = {};\n\n for (const [k, v] of Object.entries(tagAttrs)) {\n if (v !== undefined) attrs[k] = v;\n }\n\n return `<${tag} ${toAttrString(attrs)} />`;\n })\n .join('');\n\n const svgAttrs = toAttrString({\n fill: props.solid.value ? 'currentColor' : 'none',\n part: 'svg',\n stroke: props.solid.value ? 'none' : 'currentColor',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'stroke-width': props.solid.value ? 0 : strokeWidth,\n style: `width:100%;height:100%`,\n viewBox: '0 0 24 24',\n xmlns: 'http://www.w3.org/2000/svg',\n });\n\n return `<svg ${svgAttrs}>${nodes}</svg>`;\n });\n\n return html`${raw(markup)}`;\n },\n styles: [styles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"icon.cjs","names":[],"sources":["../src/content/icon/icon.ts"],"sourcesContent":["import { define, html, prop, bind } from '@vielzeug/ore';\nimport { raw } from '@vielzeug/ore/directives';\nimport { computed } from '@vielzeug/ripple';\nimport * as lucideModule from 'lucide';\n\nimport { warn } from '../../_dev';\nimport styles from './icon.css?inline';\n\nexport type IconNode = Array<[string, Record<string, string | number | undefined>]>;\n\nconst DEFAULT_SIZE = 16;\nconst DEFAULT_STROKE_WIDTH = 2;\nconst LUCIDE_VIEWBOX_SIZE = 24;\n\n/**\n * Allowlisted SVG shape/structure element names. Only these tags are permitted\n * when building the SVG markup from an IconNode, preventing arbitrary element\n * injection (e.g. <script>, event-handler-bearing elements).\n */\nconst ALLOWED_SVG_TAGS = new Set([\n 'circle',\n 'clipPath',\n 'defs',\n 'ellipse',\n 'g',\n 'line',\n 'linearGradient',\n 'mask',\n 'path',\n 'polygon',\n 'polyline',\n 'radialGradient',\n 'rect',\n 'stop',\n 'symbol',\n 'use',\n]);\n\n/**\n * Allowlisted SVG presentation / structural attribute names.\n * Event handler attributes (on*) and \"xlink:href\" are excluded.\n */\nconst ATTR_KEY_RE = /^[a-zA-Z][a-zA-Z0-9:_-]*$/;\nconst BLOCKED_ATTR_RE = /^(on|xlink:|xml:|href$)/i;\n\n// Sync registry seeded from lucide at module load; extend at any time via registerIcons()\nconst registry = new Map<string, IconNode>(\n Object.entries((lucideModule as unknown as { icons: Record<string, IconNode> }).icons),\n);\n\n/**\n * Register additional icons (or override existing ones) by name.\n * Keys may be kebab-case or PascalCase — both are accepted by `ore-icon`.\n */\nexport function registerIcons(icons: Record<string, IconNode>): void {\n for (const [name, node] of Object.entries(icons)) {\n registry.set(name, node);\n }\n}\n\nconst toAttrString = (attrs: Record<string, string | number>): string =>\n Object.entries(attrs)\n .filter(([k]) => ATTR_KEY_RE.test(k) && !BLOCKED_ATTR_RE.test(k))\n .map(\n ([k, v]) =>\n `${k}=\"${String(v).replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}\"`,\n )\n .join(' ');\n\nconst toPascalCase = (value: string): string =>\n value\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase())\n .join('');\n\nconst parseSize = (value: string | null): number | string => {\n if (value == null || value === '') return DEFAULT_SIZE;\n\n const n = Number(value);\n\n return Number.isFinite(n) && n > 0 && /^\\d+(\\.\\d+)?$/.test(value.trim()) ? n : value;\n};\n\n/** Icon component properties */\nexport type OreIconProps = {\n /** Keep stroke width visually consistent when icon size changes */\n absoluteStrokeWidth?: boolean;\n /** Accessible text label. Decorative icons should omit this. */\n label?: string;\n /** Lucide icon name, e.g. `search` or `chevron-right` */\n name?: string;\n /** Icon width/height in px by default. Accepts CSS lengths. */\n size?: number | string;\n /** Render as a filled/solid shape instead of a stroked outline */\n solid?: boolean;\n /** SVG stroke width */\n strokeWidth?: number;\n};\n\n/**\n * Icon wrapper for consistent Lucide rendering across Block.\n *\n * @element ore-icon\n *\n * @attr {string} name - Lucide icon name, e.g. `search` or `chevron-right`\n * @attr {number|string} size - Width/height (default: 16)\n * @attr {number} stroke-width - SVG stroke width (default: 2)\n * @attr {boolean} absolute-stroke-width - Keep stroke width visually stable across icon sizes\n * @attr {boolean} solid - Render as filled shape instead of stroked outline\n * @attr {string} label - Accessible label; when omitted the icon is decorative\n *\n * @csspart svg - Internal SVG element\n *\n * @example\n * ```html\n * <ore-icon name=\"search\"></ore-icon>\n * <ore-icon name=\"chevron-right\" size=\"18\"></ore-icon>\n * <ore-icon name=\"trash-2\" label=\"Delete\"></ore-icon>\n * <ore-icon name=\"star\" solid></ore-icon>\n * ```\n */\nexport const ICON_TAG = 'ore-icon' as const;\ndefine<OreIconProps>(ICON_TAG, {\n props: {\n absoluteStrokeWidth: prop.bool(),\n label: prop.string(),\n name: prop.string(),\n size: { default: DEFAULT_SIZE as number | string, parse: parseSize, reflect: false },\n solid: prop.bool(),\n strokeWidth: prop.number(DEFAULT_STROKE_WIDTH),\n },\n setup(props) {\n bind({\n attr: {\n 'aria-hidden': () => ((props.label.value ?? '').trim() ? null : 'true'),\n 'aria-label': () => (props.label.value ?? '').trim() || null,\n role: () => ((props.label.value ?? '').trim() ? 'img' : null),\n },\n style: {\n '--_size-px': () => {\n const s = props.size.value;\n\n return typeof s === 'number' ? `${s}px` : String(s);\n },\n },\n });\n\n const markup = computed(() => {\n const name = (props.name.value ?? '').trim();\n\n if (!name) return '';\n\n const iconNode = registry.get(name) ?? registry.get(toPascalCase(name));\n\n if (!iconNode) {\n warn(`ore-icon: icon not found: \"${String(name).slice(0, 64)}\"`);\n\n return '';\n }\n\n const size = props.size.value;\n const numericSize = typeof size === 'number' ? size : LUCIDE_VIEWBOX_SIZE;\n\n const strokeWidth =\n props.absoluteStrokeWidth.value && !props.solid.value\n ? props.strokeWidth.value! * (LUCIDE_VIEWBOX_SIZE / numericSize)\n : props.strokeWidth.value!;\n\n const nodes = iconNode\n .filter(([tag]) => ALLOWED_SVG_TAGS.has(tag))\n .map(([tag, tagAttrs]) => {\n const attrs: Record<string, string | number> = {};\n\n for (const [k, v] of Object.entries(tagAttrs)) {\n if (v !== undefined) attrs[k] = v;\n }\n\n return `<${tag} ${toAttrString(attrs)} />`;\n })\n .join('');\n\n const svgAttrs = toAttrString({\n fill: props.solid.value ? 'currentColor' : 'none',\n part: 'svg',\n stroke: props.solid.value ? 'none' : 'currentColor',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'stroke-width': props.solid.value ? 0 : strokeWidth,\n style: `width:100%;height:100%`,\n viewBox: '0 0 24 24',\n xmlns: 'http://www.w3.org/2000/svg',\n });\n\n return `<svg ${svgAttrs}>${nodes}</svg>`;\n });\n\n return html`${raw(markup)}`;\n },\n styles: [styles],\n});\n"],"mappings":"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"}
package/dist/icon.js CHANGED
@@ -1,8 +1,7 @@
1
- import { raw as e } from "./ore/dist/directives/raw.js";
2
- import "./ore/dist/directives.js";
3
- import { warn as t } from "./_dev.js";
4
- import n from "./content/icon/icon.css.js";
5
- import { bind as r, define as i, html as a, prop as o } from "@vielzeug/ore";
1
+ import { warn as e } from "./_dev.js";
2
+ import t from "./content/icon/icon.css.js";
3
+ import { bind as n, define as r, html as i, prop as a } from "@vielzeug/ore";
4
+ import { raw as o } from "@vielzeug/ore/directives";
6
5
  import { computed as s } from "@vielzeug/ripple";
7
6
  import * as c from "lucide";
8
7
  //#region src/content/icon/icon.ts
@@ -32,54 +31,54 @@ var _ = (e) => Object.entries(e).filter(([e]) => p.test(e) && !m.test(e)).map(([
32
31
  let t = Number(e);
33
32
  return Number.isFinite(t) && t > 0 && /^\d+(\.\d+)?$/.test(e.trim()) ? t : e;
34
33
  }, b = "ore-icon";
35
- i(b, {
34
+ r(b, {
36
35
  props: {
37
- absoluteStrokeWidth: o.bool(),
38
- label: o.string(),
39
- name: o.string(),
36
+ absoluteStrokeWidth: a.bool(),
37
+ label: a.string(),
38
+ name: a.string(),
40
39
  size: {
41
40
  default: l,
42
41
  parse: y,
43
42
  reflect: !1
44
43
  },
45
- solid: o.bool(),
46
- strokeWidth: o.number(u)
44
+ solid: a.bool(),
45
+ strokeWidth: a.number(u)
47
46
  },
48
- setup(n) {
49
- return r({
47
+ setup(t) {
48
+ return n({
50
49
  attr: {
51
- "aria-hidden": () => (n.label.value ?? "").trim() ? null : "true",
52
- "aria-label": () => (n.label.value ?? "").trim() || null,
53
- role: () => (n.label.value ?? "").trim() ? "img" : null
50
+ "aria-hidden": () => (t.label.value ?? "").trim() ? null : "true",
51
+ "aria-label": () => (t.label.value ?? "").trim() || null,
52
+ role: () => (t.label.value ?? "").trim() ? "img" : null
54
53
  },
55
54
  style: { "--_size-px": () => {
56
- let e = n.size.value;
55
+ let e = t.size.value;
57
56
  return typeof e == "number" ? `${e}px` : String(e);
58
57
  } }
59
- }), a`${e(s(() => {
60
- let e = (n.name.value ?? "").trim();
61
- if (!e) return "";
62
- let r = h.get(e) ?? h.get(v(e));
63
- if (!r) return t(`ore-icon: icon not found: "${String(e).slice(0, 64)}"`), "";
64
- let i = n.size.value, a = typeof i == "number" ? i : d, o = n.absoluteStrokeWidth.value && !n.solid.value ? n.strokeWidth.value * (d / a) : n.strokeWidth.value, s = r.filter(([e]) => f.has(e)).map(([e, t]) => {
58
+ }), i`${o(s(() => {
59
+ let n = (t.name.value ?? "").trim();
60
+ if (!n) return "";
61
+ let r = h.get(n) ?? h.get(v(n));
62
+ if (!r) return e(`ore-icon: icon not found: "${String(n).slice(0, 64)}"`), "";
63
+ let i = t.size.value, a = typeof i == "number" ? i : d, o = t.absoluteStrokeWidth.value && !t.solid.value ? t.strokeWidth.value * (d / a) : t.strokeWidth.value, s = r.filter(([e]) => f.has(e)).map(([e, t]) => {
65
64
  let n = {};
66
65
  for (let [e, r] of Object.entries(t)) r !== void 0 && (n[e] = r);
67
66
  return `<${e} ${_(n)} />`;
68
67
  }).join("");
69
68
  return `<svg ${_({
70
- fill: n.solid.value ? "currentColor" : "none",
69
+ fill: t.solid.value ? "currentColor" : "none",
71
70
  part: "svg",
72
- stroke: n.solid.value ? "none" : "currentColor",
71
+ stroke: t.solid.value ? "none" : "currentColor",
73
72
  "stroke-linecap": "round",
74
73
  "stroke-linejoin": "round",
75
- "stroke-width": n.solid.value ? 0 : o,
74
+ "stroke-width": t.solid.value ? 0 : o,
76
75
  style: "width:100%;height:100%",
77
76
  viewBox: "0 0 24 24",
78
77
  xmlns: "http://www.w3.org/2000/svg"
79
78
  })}>${s}</svg>`;
80
79
  }))}`;
81
80
  },
82
- styles: [n]
81
+ styles: [t]
83
82
  });
84
83
  //#endregion
85
84
  export { b as ICON_TAG, g as registerIcons };
package/dist/icon.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"icon.js","names":[],"sources":["../src/content/icon/icon.ts"],"sourcesContent":["import { define, html, prop, bind } from '@vielzeug/ore';\nimport { raw } from '@vielzeug/ore/directives';\nimport { computed } from '@vielzeug/ripple';\nimport * as lucideModule from 'lucide';\n\nimport { warn } from '../../_dev';\nimport styles from './icon.css?inline';\n\nexport type IconNode = Array<[string, Record<string, string | number | undefined>]>;\n\nconst DEFAULT_SIZE = 16;\nconst DEFAULT_STROKE_WIDTH = 2;\nconst LUCIDE_VIEWBOX_SIZE = 24;\n\n/**\n * Allowlisted SVG shape/structure element names. Only these tags are permitted\n * when building the SVG markup from an IconNode, preventing arbitrary element\n * injection (e.g. <script>, event-handler-bearing elements).\n */\nconst ALLOWED_SVG_TAGS = new Set([\n 'circle',\n 'clipPath',\n 'defs',\n 'ellipse',\n 'g',\n 'line',\n 'linearGradient',\n 'mask',\n 'path',\n 'polygon',\n 'polyline',\n 'radialGradient',\n 'rect',\n 'stop',\n 'symbol',\n 'use',\n]);\n\n/**\n * Allowlisted SVG presentation / structural attribute names.\n * Event handler attributes (on*) and \"xlink:href\" are excluded.\n */\nconst ATTR_KEY_RE = /^[a-zA-Z][a-zA-Z0-9:_-]*$/;\nconst BLOCKED_ATTR_RE = /^(on|xlink:|xml:|href$)/i;\n\n// Sync registry seeded from lucide at module load; extend at any time via registerIcons()\nconst registry = new Map<string, IconNode>(\n Object.entries((lucideModule as unknown as { icons: Record<string, IconNode> }).icons),\n);\n\n/**\n * Register additional icons (or override existing ones) by name.\n * Keys may be kebab-case or PascalCase — both are accepted by `ore-icon`.\n */\nexport function registerIcons(icons: Record<string, IconNode>): void {\n for (const [name, node] of Object.entries(icons)) {\n registry.set(name, node);\n }\n}\n\nconst toAttrString = (attrs: Record<string, string | number>): string =>\n Object.entries(attrs)\n .filter(([k]) => ATTR_KEY_RE.test(k) && !BLOCKED_ATTR_RE.test(k))\n .map(\n ([k, v]) =>\n `${k}=\"${String(v).replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}\"`,\n )\n .join(' ');\n\nconst toPascalCase = (value: string): string =>\n value\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase())\n .join('');\n\nconst parseSize = (value: string | null): number | string => {\n if (value == null || value === '') return DEFAULT_SIZE;\n\n const n = Number(value);\n\n return Number.isFinite(n) && n > 0 && /^\\d+(\\.\\d+)?$/.test(value.trim()) ? n : value;\n};\n\n/** Icon component properties */\nexport type OreIconProps = {\n /** Keep stroke width visually consistent when icon size changes */\n absoluteStrokeWidth?: boolean;\n /** Accessible text label. Decorative icons should omit this. */\n label?: string;\n /** Lucide icon name, e.g. `search` or `chevron-right` */\n name?: string;\n /** Icon width/height in px by default. Accepts CSS lengths. */\n size?: number | string;\n /** Render as a filled/solid shape instead of a stroked outline */\n solid?: boolean;\n /** SVG stroke width */\n strokeWidth?: number;\n};\n\n/**\n * Icon wrapper for consistent Lucide rendering across Block.\n *\n * @element ore-icon\n *\n * @attr {string} name - Lucide icon name, e.g. `search` or `chevron-right`\n * @attr {number|string} size - Width/height (default: 16)\n * @attr {number} stroke-width - SVG stroke width (default: 2)\n * @attr {boolean} absolute-stroke-width - Keep stroke width visually stable across icon sizes\n * @attr {boolean} solid - Render as filled shape instead of stroked outline\n * @attr {string} label - Accessible label; when omitted the icon is decorative\n *\n * @csspart svg - Internal SVG element\n *\n * @example\n * ```html\n * <ore-icon name=\"search\"></ore-icon>\n * <ore-icon name=\"chevron-right\" size=\"18\"></ore-icon>\n * <ore-icon name=\"trash-2\" label=\"Delete\"></ore-icon>\n * <ore-icon name=\"star\" solid></ore-icon>\n * ```\n */\nexport const ICON_TAG = 'ore-icon' as const;\ndefine<OreIconProps>(ICON_TAG, {\n props: {\n absoluteStrokeWidth: prop.bool(),\n label: prop.string(),\n name: prop.string(),\n size: { default: DEFAULT_SIZE as number | string, parse: parseSize, reflect: false },\n solid: prop.bool(),\n strokeWidth: prop.number(DEFAULT_STROKE_WIDTH),\n },\n setup(props) {\n bind({\n attr: {\n 'aria-hidden': () => ((props.label.value ?? '').trim() ? null : 'true'),\n 'aria-label': () => (props.label.value ?? '').trim() || null,\n role: () => ((props.label.value ?? '').trim() ? 'img' : null),\n },\n style: {\n '--_size-px': () => {\n const s = props.size.value;\n\n return typeof s === 'number' ? `${s}px` : String(s);\n },\n },\n });\n\n const markup = computed(() => {\n const name = (props.name.value ?? '').trim();\n\n if (!name) return '';\n\n const iconNode = registry.get(name) ?? registry.get(toPascalCase(name));\n\n if (!iconNode) {\n warn(`ore-icon: icon not found: \"${String(name).slice(0, 64)}\"`);\n\n return '';\n }\n\n const size = props.size.value;\n const numericSize = typeof size === 'number' ? size : LUCIDE_VIEWBOX_SIZE;\n\n const strokeWidth =\n props.absoluteStrokeWidth.value && !props.solid.value\n ? props.strokeWidth.value! * (LUCIDE_VIEWBOX_SIZE / numericSize)\n : props.strokeWidth.value!;\n\n const nodes = iconNode\n .filter(([tag]) => ALLOWED_SVG_TAGS.has(tag))\n .map(([tag, tagAttrs]) => {\n const attrs: Record<string, string | number> = {};\n\n for (const [k, v] of Object.entries(tagAttrs)) {\n if (v !== undefined) attrs[k] = v;\n }\n\n return `<${tag} ${toAttrString(attrs)} />`;\n })\n .join('');\n\n const svgAttrs = toAttrString({\n fill: props.solid.value ? 'currentColor' : 'none',\n part: 'svg',\n stroke: props.solid.value ? 'none' : 'currentColor',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'stroke-width': props.solid.value ? 0 : strokeWidth,\n style: `width:100%;height:100%`,\n viewBox: '0 0 24 24',\n xmlns: 'http://www.w3.org/2000/svg',\n });\n\n return `<svg ${svgAttrs}>${nodes}</svg>`;\n });\n\n return html`${raw(markup)}`;\n },\n styles: [styles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"icon.js","names":[],"sources":["../src/content/icon/icon.ts"],"sourcesContent":["import { define, html, prop, bind } from '@vielzeug/ore';\nimport { raw } from '@vielzeug/ore/directives';\nimport { computed } from '@vielzeug/ripple';\nimport * as lucideModule from 'lucide';\n\nimport { warn } from '../../_dev';\nimport styles from './icon.css?inline';\n\nexport type IconNode = Array<[string, Record<string, string | number | undefined>]>;\n\nconst DEFAULT_SIZE = 16;\nconst DEFAULT_STROKE_WIDTH = 2;\nconst LUCIDE_VIEWBOX_SIZE = 24;\n\n/**\n * Allowlisted SVG shape/structure element names. Only these tags are permitted\n * when building the SVG markup from an IconNode, preventing arbitrary element\n * injection (e.g. <script>, event-handler-bearing elements).\n */\nconst ALLOWED_SVG_TAGS = new Set([\n 'circle',\n 'clipPath',\n 'defs',\n 'ellipse',\n 'g',\n 'line',\n 'linearGradient',\n 'mask',\n 'path',\n 'polygon',\n 'polyline',\n 'radialGradient',\n 'rect',\n 'stop',\n 'symbol',\n 'use',\n]);\n\n/**\n * Allowlisted SVG presentation / structural attribute names.\n * Event handler attributes (on*) and \"xlink:href\" are excluded.\n */\nconst ATTR_KEY_RE = /^[a-zA-Z][a-zA-Z0-9:_-]*$/;\nconst BLOCKED_ATTR_RE = /^(on|xlink:|xml:|href$)/i;\n\n// Sync registry seeded from lucide at module load; extend at any time via registerIcons()\nconst registry = new Map<string, IconNode>(\n Object.entries((lucideModule as unknown as { icons: Record<string, IconNode> }).icons),\n);\n\n/**\n * Register additional icons (or override existing ones) by name.\n * Keys may be kebab-case or PascalCase — both are accepted by `ore-icon`.\n */\nexport function registerIcons(icons: Record<string, IconNode>): void {\n for (const [name, node] of Object.entries(icons)) {\n registry.set(name, node);\n }\n}\n\nconst toAttrString = (attrs: Record<string, string | number>): string =>\n Object.entries(attrs)\n .filter(([k]) => ATTR_KEY_RE.test(k) && !BLOCKED_ATTR_RE.test(k))\n .map(\n ([k, v]) =>\n `${k}=\"${String(v).replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}\"`,\n )\n .join(' ');\n\nconst toPascalCase = (value: string): string =>\n value\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase())\n .join('');\n\nconst parseSize = (value: string | null): number | string => {\n if (value == null || value === '') return DEFAULT_SIZE;\n\n const n = Number(value);\n\n return Number.isFinite(n) && n > 0 && /^\\d+(\\.\\d+)?$/.test(value.trim()) ? n : value;\n};\n\n/** Icon component properties */\nexport type OreIconProps = {\n /** Keep stroke width visually consistent when icon size changes */\n absoluteStrokeWidth?: boolean;\n /** Accessible text label. Decorative icons should omit this. */\n label?: string;\n /** Lucide icon name, e.g. `search` or `chevron-right` */\n name?: string;\n /** Icon width/height in px by default. Accepts CSS lengths. */\n size?: number | string;\n /** Render as a filled/solid shape instead of a stroked outline */\n solid?: boolean;\n /** SVG stroke width */\n strokeWidth?: number;\n};\n\n/**\n * Icon wrapper for consistent Lucide rendering across Block.\n *\n * @element ore-icon\n *\n * @attr {string} name - Lucide icon name, e.g. `search` or `chevron-right`\n * @attr {number|string} size - Width/height (default: 16)\n * @attr {number} stroke-width - SVG stroke width (default: 2)\n * @attr {boolean} absolute-stroke-width - Keep stroke width visually stable across icon sizes\n * @attr {boolean} solid - Render as filled shape instead of stroked outline\n * @attr {string} label - Accessible label; when omitted the icon is decorative\n *\n * @csspart svg - Internal SVG element\n *\n * @example\n * ```html\n * <ore-icon name=\"search\"></ore-icon>\n * <ore-icon name=\"chevron-right\" size=\"18\"></ore-icon>\n * <ore-icon name=\"trash-2\" label=\"Delete\"></ore-icon>\n * <ore-icon name=\"star\" solid></ore-icon>\n * ```\n */\nexport const ICON_TAG = 'ore-icon' as const;\ndefine<OreIconProps>(ICON_TAG, {\n props: {\n absoluteStrokeWidth: prop.bool(),\n label: prop.string(),\n name: prop.string(),\n size: { default: DEFAULT_SIZE as number | string, parse: parseSize, reflect: false },\n solid: prop.bool(),\n strokeWidth: prop.number(DEFAULT_STROKE_WIDTH),\n },\n setup(props) {\n bind({\n attr: {\n 'aria-hidden': () => ((props.label.value ?? '').trim() ? null : 'true'),\n 'aria-label': () => (props.label.value ?? '').trim() || null,\n role: () => ((props.label.value ?? '').trim() ? 'img' : null),\n },\n style: {\n '--_size-px': () => {\n const s = props.size.value;\n\n return typeof s === 'number' ? `${s}px` : String(s);\n },\n },\n });\n\n const markup = computed(() => {\n const name = (props.name.value ?? '').trim();\n\n if (!name) return '';\n\n const iconNode = registry.get(name) ?? registry.get(toPascalCase(name));\n\n if (!iconNode) {\n warn(`ore-icon: icon not found: \"${String(name).slice(0, 64)}\"`);\n\n return '';\n }\n\n const size = props.size.value;\n const numericSize = typeof size === 'number' ? size : LUCIDE_VIEWBOX_SIZE;\n\n const strokeWidth =\n props.absoluteStrokeWidth.value && !props.solid.value\n ? props.strokeWidth.value! * (LUCIDE_VIEWBOX_SIZE / numericSize)\n : props.strokeWidth.value!;\n\n const nodes = iconNode\n .filter(([tag]) => ALLOWED_SVG_TAGS.has(tag))\n .map(([tag, tagAttrs]) => {\n const attrs: Record<string, string | number> = {};\n\n for (const [k, v] of Object.entries(tagAttrs)) {\n if (v !== undefined) attrs[k] = v;\n }\n\n return `<${tag} ${toAttrString(attrs)} />`;\n })\n .join('');\n\n const svgAttrs = toAttrString({\n fill: props.solid.value ? 'currentColor' : 'none',\n part: 'svg',\n stroke: props.solid.value ? 'none' : 'currentColor',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'stroke-width': props.solid.value ? 0 : strokeWidth,\n style: `width:100%;height:100%`,\n viewBox: '0 0 24 24',\n xmlns: 'http://www.w3.org/2000/svg',\n });\n\n return `<svg ${svgAttrs}>${nodes}</svg>`;\n });\n\n return html`${raw(markup)}`;\n },\n styles: [styles],\n});\n"],"mappings":"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"}
package/dist/input.cjs CHANGED
@@ -1,7 +1,7 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./ore/dist/directives/live.cjs");require("./ore/dist/directives.cjs");const t=require("./styles/mixins/shape.css.cjs"),n=require("./styles/mixins/theme.css.cjs"),r=require("./styles/index.cjs"),i=require("./shared/prop-bundles.cjs"),a=require("./shared/size-presets.cjs"),o=require("./headless/ore.cjs"),s=require("./headless/text-field.cjs"),c=require("./ore/dist/forms/field.cjs");require("./ore/dist/forms.cjs");const l=require("./inputs/shared/field-binding.cjs"),u=require("./inputs/shared/form-context.cjs"),d=require("./inputs/input/input.css.cjs");let f=require("@vielzeug/ore"),p=require("@vielzeug/ripple");var m=[`text`,`email`,`password`,`search`,`url`,`tel`,`number`,`date`,`time`,`datetime-local`,`month`,`week`],h=`ore-input`;(0,f.define)(h,{formAssociated:!0,props:{...i.themableBundle,...i.sizableBundle,...i.disablableBundle,...i.roundableBundle,autocomplete:f.prop.string(),clearable:f.prop.bool(!1),error:f.prop.string(),fullwidth:f.prop.bool(!1),helper:f.prop.string(),inputmode:f.prop.string(),label:f.prop.string(),"label-placement":f.prop.oneOf([`inset`,`outside`],`inset`),maxlength:f.prop.json(void 0),minlength:f.prop.json(void 0),name:f.prop.string(),pattern:f.prop.string(),placeholder:f.prop.string(),readonly:f.prop.bool(!1),ref:f.prop.json(void 0),required:f.prop.bool(!1),type:f.prop.oneOf(m,`text`),value:f.prop.string(),variant:f.prop.string()},setup(t){let n=(0,f.useEmit)(),r=(0,f.useSlots)(),i=(0,f.inject)(u.FORM_CTX),a=u.useFormContext(t,i),d=(0,p.signal)(!1),m=(0,f.ref)(),h=(0,p.computed)(()=>!!t.label.value||r.has(`label`).value),g=o.lifecycleSignal(f.onCleanup),_=s.createTextField({disabled:a.disabled,error:t.error,hasLabel:h,helper:t.helper,label:t.label,labelPlacement:t[`label-placement`],maxLength:t.maxlength,onChange:(e,t)=>{n(`change`,{originalEvent:e,value:t})},onInput:(e,t)=>{n(`input`,{originalEvent:e,value:t})},prefix:`input`,readonly:t.readonly,required:t.required,signal:g,validateOn:i?.validateOn,value:t.value});_.attachFormField(c.useField({disabled:_.disabled,onReset:_.reset,toFormValue:e=>e,validationMessage:_.validationMessage,validity:_.validity,value:_.value}));let{ariaDescribedBy:v,ariaErrorMessage:y,ariaInvalid:b,ariaLabelledBy:x,assistiveId:S,clear:C,counter:w,errorId:T,errorText:E,fieldId:D,helperText:O,labelId:k,labelVisible:A,value:j,wire:M}=_;return(0,f.onElement)(m,e=>{M(e,g),t.ref.value?.(e);let n=(0,p.watch)(t.ref,t=>{t?.(e)});return()=>{n.dispose(),t.ref.value?.(null)}}),(0,f.bind)({attr:{error:l.errorAttr(E),"has-value":()=>j.value?!0:void 0,size:a.size,variant:a.variant}}),f.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/shape.css.cjs"),t=require("./styles/mixins/theme.css.cjs"),n=require("./styles/index.cjs"),r=require("./shared/prop-bundles.cjs"),i=require("./shared/size-presets.cjs"),a=require("./headless/ore.cjs"),o=require("./headless/text-field.cjs"),s=require("./inputs/shared/field-binding.cjs"),c=require("./inputs/shared/form-context.cjs"),l=require("./inputs/input/input.css.cjs");let u=require("@vielzeug/ore"),d=require("@vielzeug/ore/directives"),f=require("@vielzeug/ripple"),p=require("@vielzeug/ore/forms");var m=[`text`,`email`,`password`,`search`,`url`,`tel`,`number`,`date`,`time`,`datetime-local`,`month`,`week`],h=`ore-input`;(0,u.define)(h,{formAssociated:!0,props:{...r.themableBundle,...r.sizableBundle,...r.disablableBundle,...r.roundableBundle,autocomplete:u.prop.string(),clearable:u.prop.bool(!1),error:u.prop.string(),fullwidth:u.prop.bool(!1),helper:u.prop.string(),inputmode:u.prop.string(),label:u.prop.string(),"label-placement":u.prop.oneOf([`inset`,`outside`],`inset`),maxlength:u.prop.json(void 0),minlength:u.prop.json(void 0),name:u.prop.string(),pattern:u.prop.string(),placeholder:u.prop.string(),readonly:u.prop.bool(!1),ref:u.prop.json(void 0),required:u.prop.bool(!1),type:u.prop.oneOf(m,`text`),value:u.prop.string(),variant:u.prop.string()},setup(e){let t=(0,u.useEmit)(),n=(0,u.useSlots)(),r=(0,u.inject)(c.FORM_CTX),i=c.useFormContext(e,r),l=(0,f.signal)(!1),m=(0,u.ref)(),h=(0,f.computed)(()=>!!e.label.value||n.has(`label`).value),g=a.lifecycleSignal(u.onCleanup),_=o.createTextField({disabled:i.disabled,error:e.error,hasLabel:h,helper:e.helper,label:e.label,labelPlacement:e[`label-placement`],maxLength:e.maxlength,onChange:(e,n)=>{t(`change`,{originalEvent:e,value:n})},onInput:(e,n)=>{t(`input`,{originalEvent:e,value:n})},prefix:`input`,readonly:e.readonly,required:e.required,signal:g,validateOn:r?.validateOn,value:e.value});_.attachFormField((0,p.useField)({disabled:_.disabled,onReset:_.reset,toFormValue:e=>e,validationMessage:_.validationMessage,validity:_.validity,value:_.value}));let{ariaDescribedBy:v,ariaErrorMessage:y,ariaInvalid:b,ariaLabelledBy:x,assistiveId:S,clear:C,counter:w,errorId:T,errorText:E,fieldId:D,helperText:O,labelId:k,labelVisible:A,value:j,wire:M}=_;return(0,u.onElement)(m,t=>{M(t,g),e.ref.value?.(t);let n=(0,f.watch)(e.ref,e=>{e?.(t)});return()=>{n.dispose(),e.ref.value?.(null)}}),(0,u.bind)({attr:{error:s.errorAttr(E),"has-value":()=>j.value?!0:void 0,size:i.size,variant:i.variant}}),u.html`
2
2
  <div class="input-wrapper" part="wrapper">
3
3
  <label class="label" for="${D}" id="${k}" part="label" ?hidden="${()=>!A.value}"
4
- ><slot name="label">${t.label}</slot></label
4
+ ><slot name="label">${e.label}</slot></label
5
5
  >
6
6
  <div class="field" part="field">
7
7
  <div class="input-row" part="input-row">
@@ -9,18 +9,18 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
9
9
  <input
10
10
  part="input"
11
11
  id="${D}"
12
- :type="${()=>t.type.value===`password`&&d.value?`text`:t.type.value??`text`}"
13
- :name="${t.name}"
14
- :placeholder="${t.placeholder}"
15
- :autocomplete="${t.autocomplete}"
16
- :inputmode="${t.inputmode}"
17
- :maxlength="${t.maxlength}"
18
- :minlength="${t.minlength}"
19
- :pattern="${t.pattern}"
20
- ?disabled="${t.disabled}"
21
- ?readonly="${t.readonly}"
22
- ?required="${t.required}"
23
- :value="${e.live(j)}"
12
+ :type="${()=>e.type.value===`password`&&l.value?`text`:e.type.value??`text`}"
13
+ :name="${e.name}"
14
+ :placeholder="${e.placeholder}"
15
+ :autocomplete="${e.autocomplete}"
16
+ :inputmode="${e.inputmode}"
17
+ :maxlength="${e.maxlength}"
18
+ :minlength="${e.minlength}"
19
+ :pattern="${e.pattern}"
20
+ ?disabled="${e.disabled}"
21
+ ?readonly="${e.readonly}"
22
+ ?required="${e.required}"
23
+ :value="${(0,d.live)(j)}"
24
24
  :aria-labelledby="${x}"
25
25
  :aria-describedby="${v}"
26
26
  :aria-errormessage="${y}"
@@ -31,11 +31,11 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
31
31
  class="pwd-toggle-btn"
32
32
  part="pwd-toggle"
33
33
  type="button"
34
- :aria-label="${()=>d.value?`Hide password`:`Show password`}"
35
- :aria-pressed="${()=>String(d.value)}"
36
- :tabindex="${()=>t.type.value===`password`?`0`:`-1`}"
37
- @click="${()=>{d.value=!d.value,m.value?.focus()}}">
38
- ${()=>d.value?f.html`<ore-icon name="eye-off" size="14" stroke-width="2" aria-hidden="true"></ore-icon>`:f.html`<ore-icon name="eye" size="14" stroke-width="2" aria-hidden="true"></ore-icon>`}
34
+ :aria-label="${()=>l.value?`Hide password`:`Show password`}"
35
+ :aria-pressed="${()=>String(l.value)}"
36
+ :tabindex="${()=>e.type.value===`password`?`0`:`-1`}"
37
+ @click="${()=>{l.value=!l.value,m.value?.focus()}}">
38
+ ${()=>l.value?u.html`<ore-icon name="eye-off" size="14" stroke-width="2" aria-hidden="true"></ore-icon>`:u.html`<ore-icon name="eye" size="14" stroke-width="2" aria-hidden="true"></ore-icon>`}
39
39
  </button>
40
40
  <button
41
41
  aria-label="Clear"
@@ -63,5 +63,5 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
63
63
  ${()=>w?.value.counterText??``}
64
64
  </div>
65
65
  </div>
66
- `},shadow:{delegatesFocus:!0},styles:[...r.fieldMixins,t.sizeVariantMixin(a.FIELD_SIZE_PRESET),n.forcedColorsFocusMixin(`input`),d.default]}),exports.INPUT_TAG=h;
66
+ `},shadow:{delegatesFocus:!0},styles:[...n.fieldMixins,e.sizeVariantMixin(i.FIELD_SIZE_PRESET),t.forcedColorsFocusMixin(`input`),l.default]}),exports.INPUT_TAG=h;
67
67
  //# sourceMappingURL=input.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.cjs","names":[],"sources":["../src/inputs/input/input.ts"],"sourcesContent":["import { define, html, inject, prop, ref, bind, onCleanup, onElement, useEmit, useSlots } from '@vielzeug/ore';\nimport { live } from '@vielzeug/ore/directives';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { TextFieldProps } from '../../shared';\nimport type { InputType, VisualVariant } from '../../types';\n\nimport { lifecycleSignal, createTextField } from '../../headless';\nimport { disablableBundle, FIELD_SIZE_PRESET, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport '../../content/icon/icon';\nimport { fieldMixins, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { errorAttr } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './input.css?inline';\n\n/** Input component properties */\n\nexport type OreInputEvents = {\n change: { originalEvent: Event; value: string };\n input: { originalEvent: Event; value: string };\n};\n\nexport type OreInputProps = TextFieldProps<Exclude<VisualVariant, 'frost'>> & {\n /** Autocomplete hint */\n autocomplete?: string;\n /** Show a clear (×) button when the field has a value */\n clearable?: boolean;\n /** Virtual keyboard hint for mobile devices */\n inputmode?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';\n /** Maximum character length — shows a counter below the input */\n maxlength?: number;\n /** Minimum character length */\n minlength?: number;\n /** HTML pattern attribute for client-side validation */\n pattern?: string;\n /**\n * JS-only callback fired with the inner `<input>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw input element.\n * Set as a JS property: `bitInput.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLInputElement | null) => void) | null;\n /** HTML input type */\n type?: InputType;\n};\n\nconst VALID_INPUT_TYPES = [\n 'text',\n 'email',\n 'password',\n 'search',\n 'url',\n 'tel',\n 'number',\n 'date',\n 'time',\n 'datetime-local',\n 'month',\n 'week',\n] as const;\n\n/**\n * A customizable text input component with multiple variants, label placements, and form features.\n *\n * @element ore-input\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - Label placement: 'inset' | 'outside'\n * @attr {string} type - HTML input type: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search'\n * @attr {string} value - Current input value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {string} helper - Helper text displayed below the input (fallback when the `helper` slot is empty)\n * @attr {string} error - Error message — marks the field as invalid (fallback when the `error` slot is empty)\n * @attr {boolean} disabled - Disable input interaction\n * @attr {boolean} readonly - Make the input read-only\n * @attr {boolean} required - Mark the field as required\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text'\n * @attr {string} size - Input size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Emitted when input value changes (on every keystroke). detail: { value: string; originalEvent: Event }\n * @fires change - Emitted when input loses focus with changed value. detail: { value: string; originalEvent: Event }\n *\n * @slot prefix - Content before the input (e.g., icons)\n * @slot suffix - Content after the input (e.g., clear button, validation icon)\n * @slot label - Replaces the label text — slotted content takes precedence over the `label` prop\n * @slot helper - Replaces the helper text — slotted content takes precedence over the `helper` prop\n * @slot error - Replaces the error text — slotted content takes precedence over the `error` prop\n *\n * @part wrapper - The input wrapper element\n * @part label - The label element (inset or outside)\n * @part field - The field container element\n * @part input-row - The input row container element\n * @part input - The input element\n * @part helper - The helper text element\n *\n * @cssprop --input-bg - Background color\n * @cssprop --input-color - Text color\n * @cssprop --input-border-color - Border color\n * @cssprop --input-placeholder-color - Placeholder text color\n * @cssprop --input-radius - Border radius\n * @cssprop --input-padding - Inner padding (block inline)\n * @cssprop --input-gap - Gap between prefix/suffix icons and input text\n * @cssprop --input-font-size - Font size\n * @cssprop --input-height - Field height\n * @cssprop --input-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --input-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --input-focus-bg - Field background when focused (flat variant)\n * @cssprop --input-focus-border-color - Field border when focused (flat/text variants)\n *\n * @example\n * ```html\n * <ore-input type=\"email\" label=\"Email\" placeholder=\"you@example.com\" />\n * <ore-input label=\"Name\" variant=\"bordered\" color=\"primary\" />\n * ```\n */\nexport const INPUT_TAG = 'ore-input' as const;\ndefine<OreInputProps>(INPUT_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n autocomplete: prop.string(),\n clearable: prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n inputmode: prop.string<'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url'>(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n maxlength: prop.json(undefined as number | undefined),\n minlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n pattern: prop.string(),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.json(undefined as ((el: HTMLInputElement | null) => void) | null | undefined),\n required: prop.bool(false),\n type: prop.oneOf(VALID_INPUT_TYPES, 'text'),\n value: prop.string(),\n variant: prop.string<'flat' | 'text' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const emit = useEmit<OreInputEvents>();\n const slots = useSlots();\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n const showPassword = signal(false);\n const inputRef = ref<HTMLInputElement>();\n\n const hasLabel = computed(() => !!props.label.value || slots.has('label').value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: fCtxProps.disabled,\n error: props.error,\n hasLabel,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onChange: (event: Event, value: string) => {\n emit('change', { originalEvent: event, value });\n },\n onInput: (event: Event, value: string) => {\n emit('input', { originalEvent: event, value });\n },\n prefix: 'input',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n tf.attachFormField(\n useField<string>({\n disabled: tf.disabled,\n onReset: tf.reset,\n toFormValue: (v) => v,\n validationMessage: tf.validationMessage,\n validity: tf.validity,\n value: tf.value,\n }),\n );\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n clear: clearValue,\n counter,\n errorId,\n errorText,\n fieldId: inputId,\n helperText,\n labelId,\n labelVisible,\n value: fieldValue,\n wire,\n } = tf;\n\n onElement(inputRef, (el) => {\n wire(el, abortSignal);\n\n // Immediate fire for when the prop is already set on mount.\n props.ref.value?.(el);\n\n // Reactive watcher so that if props.ref is set *after* the inner\n // <input> mounts (e.g. parent sets it via a ref callback after render),\n // the new callback still receives the live element.\n const sub = watch(props.ref, (cb) => {\n cb?.(el);\n });\n\n return () => {\n sub.dispose();\n props.ref.value?.(null);\n };\n });\n\n const clear = (event?: Event): void => {\n clearValue(event);\n inputRef.value?.focus();\n };\n\n const resolvedInputType = (): string =>\n props.type.value === 'password' && showPassword.value ? 'text' : (props.type.value ?? 'text');\n\n bind({\n attr: {\n error: errorAttr(errorText),\n 'has-value': () => (fieldValue.value ? true : undefined),\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const labelHidden = () => !labelVisible.value;\n const passwordToggleLabel = () => (showPassword.value ? 'Hide password' : 'Show password');\n const passwordTogglePressed = () => String(showPassword.value);\n const passwordToggleIcon = () =>\n showPassword.value\n ? html`<ore-icon name=\"eye-off\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>`\n : html`<ore-icon name=\"eye\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>`;\n const helperHidden = () => !!errorText.value || !helperText.value;\n const errorHidden = () => !errorText.value;\n const counterNearLimit = () => (counter?.value.counterNearLimit && !counter?.value.counterAtLimit ? '' : null);\n const counterAtLimit = () => (counter?.value.counterAtLimit ? '' : null);\n const counterHidden = () => !counter;\n const counterText = () => counter?.value.counterText ?? '';\n\n const clearTabIndex = () => (fieldValue.value ? '0' : '-1');\n const pwdToggleTabIndex = () => (props.type.value === 'password' ? '0' : '-1');\n\n const togglePassword = () => {\n showPassword.value = !showPassword.value;\n inputRef.value?.focus();\n };\n\n return html`\n <div class=\"input-wrapper\" part=\"wrapper\">\n <label class=\"label\" for=\"${inputId}\" id=\"${labelId}\" part=\"label\" ?hidden=\"${labelHidden}\"\n ><slot name=\"label\">${props.label}</slot></label\n >\n <div class=\"field\" part=\"field\">\n <div class=\"input-row\" part=\"input-row\">\n <slot name=\"prefix\"></slot>\n <input\n part=\"input\"\n id=\"${inputId}\"\n :type=\"${resolvedInputType}\"\n :name=\"${props.name}\"\n :placeholder=\"${props.placeholder}\"\n :autocomplete=\"${props.autocomplete}\"\n :inputmode=\"${props.inputmode}\"\n :maxlength=\"${props.maxlength}\"\n :minlength=\"${props.minlength}\"\n :pattern=\"${props.pattern}\"\n ?disabled=\"${props.disabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n :value=\"${live(fieldValue)}\"\n :aria-labelledby=\"${ariaLabelledBy}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n :aria-errormessage=\"${ariaErrorMessage}\"\n :aria-invalid=\"${ariaInvalid}\"\n ref=\"${inputRef}\" />\n <slot name=\"suffix\"></slot>\n <button\n class=\"pwd-toggle-btn\"\n part=\"pwd-toggle\"\n type=\"button\"\n :aria-label=\"${passwordToggleLabel}\"\n :aria-pressed=\"${passwordTogglePressed}\"\n :tabindex=\"${pwdToggleTabIndex}\"\n @click=\"${togglePassword}\">\n ${passwordToggleIcon}\n </button>\n <button\n aria-label=\"Clear\"\n class=\"clear-btn\"\n part=\"clear\"\n type=\"button\"\n :tabindex=\"${clearTabIndex}\"\n @click=\"${clear}\">\n <ore-icon aria-hidden=\"true\" name=\"x\" size=\"12\" stroke-width=\"2.5\"></ore-icon>\n </button>\n </div>\n </div>\n <div class=\"helper-text\" aria-live=\"polite\" id=\"${assistiveId}\" part=\"helper\" ?hidden=\"${helperHidden}\">\n <slot name=\"helper\">${() => helperText.value}</slot>\n </div>\n <div class=\"helper-text\" id=\"${errorId}\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n <slot name=\"error\">${() => errorText.value}</slot>\n </div>\n <div\n class=\"char-counter\"\n part=\"char-counter\"\n :data-near-limit=\"${counterNearLimit}\"\n :data-at-limit=\"${counterAtLimit}\"\n ?hidden=\"${counterHidden}\">\n ${counterText}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [...fieldMixins, sizeVariantMixin(FIELD_SIZE_PRESET), forcedColorsFocusMixin('input'), componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"input.cjs","names":[],"sources":["../src/inputs/input/input.ts"],"sourcesContent":["import { define, html, inject, prop, ref, bind, onCleanup, onElement, useEmit, useSlots } from '@vielzeug/ore';\nimport { live } from '@vielzeug/ore/directives';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport type { TextFieldProps } from '../../shared';\nimport type { InputType, VisualVariant } from '../../types';\n\nimport { lifecycleSignal, createTextField } from '../../headless';\nimport { disablableBundle, FIELD_SIZE_PRESET, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport '../../content/icon/icon';\nimport { fieldMixins, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { errorAttr } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './input.css?inline';\n\n/** Input component properties */\n\nexport type OreInputEvents = {\n change: { originalEvent: Event; value: string };\n input: { originalEvent: Event; value: string };\n};\n\nexport type OreInputProps = TextFieldProps<Exclude<VisualVariant, 'frost'>> & {\n /** Autocomplete hint */\n autocomplete?: string;\n /** Show a clear (×) button when the field has a value */\n clearable?: boolean;\n /** Virtual keyboard hint for mobile devices */\n inputmode?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';\n /** Maximum character length — shows a counter below the input */\n maxlength?: number;\n /** Minimum character length */\n minlength?: number;\n /** HTML pattern attribute for client-side validation */\n pattern?: string;\n /**\n * JS-only callback fired with the inner `<input>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw input element.\n * Set as a JS property: `bitInput.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLInputElement | null) => void) | null;\n /** HTML input type */\n type?: InputType;\n};\n\nconst VALID_INPUT_TYPES = [\n 'text',\n 'email',\n 'password',\n 'search',\n 'url',\n 'tel',\n 'number',\n 'date',\n 'time',\n 'datetime-local',\n 'month',\n 'week',\n] as const;\n\n/**\n * A customizable text input component with multiple variants, label placements, and form features.\n *\n * @element ore-input\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - Label placement: 'inset' | 'outside'\n * @attr {string} type - HTML input type: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search'\n * @attr {string} value - Current input value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {string} helper - Helper text displayed below the input (fallback when the `helper` slot is empty)\n * @attr {string} error - Error message — marks the field as invalid (fallback when the `error` slot is empty)\n * @attr {boolean} disabled - Disable input interaction\n * @attr {boolean} readonly - Make the input read-only\n * @attr {boolean} required - Mark the field as required\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text'\n * @attr {string} size - Input size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Emitted when input value changes (on every keystroke). detail: { value: string; originalEvent: Event }\n * @fires change - Emitted when input loses focus with changed value. detail: { value: string; originalEvent: Event }\n *\n * @slot prefix - Content before the input (e.g., icons)\n * @slot suffix - Content after the input (e.g., clear button, validation icon)\n * @slot label - Replaces the label text — slotted content takes precedence over the `label` prop\n * @slot helper - Replaces the helper text — slotted content takes precedence over the `helper` prop\n * @slot error - Replaces the error text — slotted content takes precedence over the `error` prop\n *\n * @part wrapper - The input wrapper element\n * @part label - The label element (inset or outside)\n * @part field - The field container element\n * @part input-row - The input row container element\n * @part input - The input element\n * @part helper - The helper text element\n *\n * @cssprop --input-bg - Background color\n * @cssprop --input-color - Text color\n * @cssprop --input-border-color - Border color\n * @cssprop --input-placeholder-color - Placeholder text color\n * @cssprop --input-radius - Border radius\n * @cssprop --input-padding - Inner padding (block inline)\n * @cssprop --input-gap - Gap between prefix/suffix icons and input text\n * @cssprop --input-font-size - Font size\n * @cssprop --input-height - Field height\n * @cssprop --input-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --input-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --input-focus-bg - Field background when focused (flat variant)\n * @cssprop --input-focus-border-color - Field border when focused (flat/text variants)\n *\n * @example\n * ```html\n * <ore-input type=\"email\" label=\"Email\" placeholder=\"you@example.com\" />\n * <ore-input label=\"Name\" variant=\"bordered\" color=\"primary\" />\n * ```\n */\nexport const INPUT_TAG = 'ore-input' as const;\ndefine<OreInputProps>(INPUT_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n autocomplete: prop.string(),\n clearable: prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n inputmode: prop.string<'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url'>(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n maxlength: prop.json(undefined as number | undefined),\n minlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n pattern: prop.string(),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.json(undefined as ((el: HTMLInputElement | null) => void) | null | undefined),\n required: prop.bool(false),\n type: prop.oneOf(VALID_INPUT_TYPES, 'text'),\n value: prop.string(),\n variant: prop.string<'flat' | 'text' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const emit = useEmit<OreInputEvents>();\n const slots = useSlots();\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n const showPassword = signal(false);\n const inputRef = ref<HTMLInputElement>();\n\n const hasLabel = computed(() => !!props.label.value || slots.has('label').value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: fCtxProps.disabled,\n error: props.error,\n hasLabel,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onChange: (event: Event, value: string) => {\n emit('change', { originalEvent: event, value });\n },\n onInput: (event: Event, value: string) => {\n emit('input', { originalEvent: event, value });\n },\n prefix: 'input',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n tf.attachFormField(\n useField<string>({\n disabled: tf.disabled,\n onReset: tf.reset,\n toFormValue: (v) => v,\n validationMessage: tf.validationMessage,\n validity: tf.validity,\n value: tf.value,\n }),\n );\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n clear: clearValue,\n counter,\n errorId,\n errorText,\n fieldId: inputId,\n helperText,\n labelId,\n labelVisible,\n value: fieldValue,\n wire,\n } = tf;\n\n onElement(inputRef, (el) => {\n wire(el, abortSignal);\n\n // Immediate fire for when the prop is already set on mount.\n props.ref.value?.(el);\n\n // Reactive watcher so that if props.ref is set *after* the inner\n // <input> mounts (e.g. parent sets it via a ref callback after render),\n // the new callback still receives the live element.\n const sub = watch(props.ref, (cb) => {\n cb?.(el);\n });\n\n return () => {\n sub.dispose();\n props.ref.value?.(null);\n };\n });\n\n const clear = (event?: Event): void => {\n clearValue(event);\n inputRef.value?.focus();\n };\n\n const resolvedInputType = (): string =>\n props.type.value === 'password' && showPassword.value ? 'text' : (props.type.value ?? 'text');\n\n bind({\n attr: {\n error: errorAttr(errorText),\n 'has-value': () => (fieldValue.value ? true : undefined),\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const labelHidden = () => !labelVisible.value;\n const passwordToggleLabel = () => (showPassword.value ? 'Hide password' : 'Show password');\n const passwordTogglePressed = () => String(showPassword.value);\n const passwordToggleIcon = () =>\n showPassword.value\n ? html`<ore-icon name=\"eye-off\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>`\n : html`<ore-icon name=\"eye\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>`;\n const helperHidden = () => !!errorText.value || !helperText.value;\n const errorHidden = () => !errorText.value;\n const counterNearLimit = () => (counter?.value.counterNearLimit && !counter?.value.counterAtLimit ? '' : null);\n const counterAtLimit = () => (counter?.value.counterAtLimit ? '' : null);\n const counterHidden = () => !counter;\n const counterText = () => counter?.value.counterText ?? '';\n\n const clearTabIndex = () => (fieldValue.value ? '0' : '-1');\n const pwdToggleTabIndex = () => (props.type.value === 'password' ? '0' : '-1');\n\n const togglePassword = () => {\n showPassword.value = !showPassword.value;\n inputRef.value?.focus();\n };\n\n return html`\n <div class=\"input-wrapper\" part=\"wrapper\">\n <label class=\"label\" for=\"${inputId}\" id=\"${labelId}\" part=\"label\" ?hidden=\"${labelHidden}\"\n ><slot name=\"label\">${props.label}</slot></label\n >\n <div class=\"field\" part=\"field\">\n <div class=\"input-row\" part=\"input-row\">\n <slot name=\"prefix\"></slot>\n <input\n part=\"input\"\n id=\"${inputId}\"\n :type=\"${resolvedInputType}\"\n :name=\"${props.name}\"\n :placeholder=\"${props.placeholder}\"\n :autocomplete=\"${props.autocomplete}\"\n :inputmode=\"${props.inputmode}\"\n :maxlength=\"${props.maxlength}\"\n :minlength=\"${props.minlength}\"\n :pattern=\"${props.pattern}\"\n ?disabled=\"${props.disabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n :value=\"${live(fieldValue)}\"\n :aria-labelledby=\"${ariaLabelledBy}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n :aria-errormessage=\"${ariaErrorMessage}\"\n :aria-invalid=\"${ariaInvalid}\"\n ref=\"${inputRef}\" />\n <slot name=\"suffix\"></slot>\n <button\n class=\"pwd-toggle-btn\"\n part=\"pwd-toggle\"\n type=\"button\"\n :aria-label=\"${passwordToggleLabel}\"\n :aria-pressed=\"${passwordTogglePressed}\"\n :tabindex=\"${pwdToggleTabIndex}\"\n @click=\"${togglePassword}\">\n ${passwordToggleIcon}\n </button>\n <button\n aria-label=\"Clear\"\n class=\"clear-btn\"\n part=\"clear\"\n type=\"button\"\n :tabindex=\"${clearTabIndex}\"\n @click=\"${clear}\">\n <ore-icon aria-hidden=\"true\" name=\"x\" size=\"12\" stroke-width=\"2.5\"></ore-icon>\n </button>\n </div>\n </div>\n <div class=\"helper-text\" aria-live=\"polite\" id=\"${assistiveId}\" part=\"helper\" ?hidden=\"${helperHidden}\">\n <slot name=\"helper\">${() => helperText.value}</slot>\n </div>\n <div class=\"helper-text\" id=\"${errorId}\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n <slot name=\"error\">${() => errorText.value}</slot>\n </div>\n <div\n class=\"char-counter\"\n part=\"char-counter\"\n :data-near-limit=\"${counterNearLimit}\"\n :data-at-limit=\"${counterAtLimit}\"\n ?hidden=\"${counterHidden}\">\n ${counterText}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [...fieldMixins, sizeVariantMixin(FIELD_SIZE_PRESET), forcedColorsFocusMixin('input'), componentStyles],\n});\n"],"mappings":"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"}