@vielzeug/refine 1.5.1 → 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 (234) 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 +5267 -5267
  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/message-composer.cjs +18 -18
  55. package/dist/message-composer.cjs.map +1 -1
  56. package/dist/message-composer.js +113 -115
  57. package/dist/message-composer.js.map +1 -1
  58. package/dist/navbar.cjs +11 -11
  59. package/dist/navbar.cjs.map +1 -1
  60. package/dist/navbar.js +78 -79
  61. package/dist/navbar.js.map +1 -1
  62. package/dist/otp-input.cjs +4 -4
  63. package/dist/otp-input.cjs.map +1 -1
  64. package/dist/otp-input.js +31 -32
  65. package/dist/otp-input.js.map +1 -1
  66. package/dist/progress.cjs +13 -13
  67. package/dist/progress.cjs.map +1 -1
  68. package/dist/progress.js +45 -46
  69. package/dist/progress.js.map +1 -1
  70. package/dist/radio-group.cjs +5 -5
  71. package/dist/radio-group.cjs.map +1 -1
  72. package/dist/radio-group.js +83 -85
  73. package/dist/radio-group.js.map +1 -1
  74. package/dist/radio.cjs +3 -3
  75. package/dist/radio.cjs.map +1 -1
  76. package/dist/radio.js +27 -28
  77. package/dist/radio.js.map +1 -1
  78. package/dist/rating.cjs +4 -4
  79. package/dist/rating.cjs.map +1 -1
  80. package/dist/rating.js +30 -31
  81. package/dist/rating.js.map +1 -1
  82. package/dist/select.cjs +4 -4
  83. package/dist/select.cjs.map +1 -1
  84. package/dist/select.js +88 -89
  85. package/dist/select.js.map +1 -1
  86. package/dist/sidebar.cjs +11 -11
  87. package/dist/sidebar.cjs.map +1 -1
  88. package/dist/sidebar.js +97 -98
  89. package/dist/sidebar.js.map +1 -1
  90. package/dist/skeleton.cjs +3 -3
  91. package/dist/skeleton.cjs.map +1 -1
  92. package/dist/skeleton.js +23 -24
  93. package/dist/skeleton.js.map +1 -1
  94. package/dist/slider.cjs +3 -3
  95. package/dist/slider.cjs.map +1 -1
  96. package/dist/slider.js +65 -66
  97. package/dist/slider.js.map +1 -1
  98. package/dist/switch.cjs +3 -3
  99. package/dist/switch.cjs.map +1 -1
  100. package/dist/switch.js +23 -24
  101. package/dist/switch.js.map +1 -1
  102. package/dist/tab-panel.cjs +7 -7
  103. package/dist/tab-panel.cjs.map +1 -1
  104. package/dist/tab-panel.js +21 -23
  105. package/dist/tab-panel.js.map +1 -1
  106. package/dist/testing.cjs +1 -1
  107. package/dist/testing.cjs.map +1 -1
  108. package/dist/testing.js +4 -5
  109. package/dist/testing.js.map +1 -1
  110. package/dist/textarea.cjs +13 -13
  111. package/dist/textarea.cjs.map +1 -1
  112. package/dist/textarea.js +92 -94
  113. package/dist/textarea.js.map +1 -1
  114. package/dist/time-picker.cjs +9 -9
  115. package/dist/time-picker.cjs.map +1 -1
  116. package/dist/time-picker.js +47 -48
  117. package/dist/time-picker.js.map +1 -1
  118. package/package.json +1 -1
  119. package/dist/ore/dist/_dev.cjs +0 -2
  120. package/dist/ore/dist/_dev.cjs.map +0 -1
  121. package/dist/ore/dist/_dev.js +0 -12
  122. package/dist/ore/dist/_dev.js.map +0 -1
  123. package/dist/ore/dist/base-element.cjs +0 -2
  124. package/dist/ore/dist/base-element.cjs.map +0 -1
  125. package/dist/ore/dist/base-element.js +0 -158
  126. package/dist/ore/dist/base-element.js.map +0 -1
  127. package/dist/ore/dist/context.cjs +0 -2
  128. package/dist/ore/dist/context.cjs.map +0 -1
  129. package/dist/ore/dist/context.js +0 -11
  130. package/dist/ore/dist/context.js.map +0 -1
  131. package/dist/ore/dist/define.cjs +0 -2
  132. package/dist/ore/dist/define.cjs.map +0 -1
  133. package/dist/ore/dist/define.js +0 -27
  134. package/dist/ore/dist/define.js.map +0 -1
  135. package/dist/ore/dist/directives/classMap.cjs +0 -1
  136. package/dist/ore/dist/directives/classMap.js +0 -1
  137. package/dist/ore/dist/directives/each.cjs +0 -1
  138. package/dist/ore/dist/directives/each.js +0 -5
  139. package/dist/ore/dist/directives/live.cjs +0 -2
  140. package/dist/ore/dist/directives/live.cjs.map +0 -1
  141. package/dist/ore/dist/directives/live.js +0 -6
  142. package/dist/ore/dist/directives/live.js.map +0 -1
  143. package/dist/ore/dist/directives/model.cjs +0 -1
  144. package/dist/ore/dist/directives/model.js +0 -3
  145. package/dist/ore/dist/directives/raw.cjs +0 -2
  146. package/dist/ore/dist/directives/raw.cjs.map +0 -1
  147. package/dist/ore/dist/directives/raw.js +0 -38
  148. package/dist/ore/dist/directives/raw.js.map +0 -1
  149. package/dist/ore/dist/directives/styleMap.cjs +0 -2
  150. package/dist/ore/dist/directives/styleMap.cjs.map +0 -1
  151. package/dist/ore/dist/directives/styleMap.js +0 -20
  152. package/dist/ore/dist/directives/styleMap.js.map +0 -1
  153. package/dist/ore/dist/directives/when.cjs +0 -2
  154. package/dist/ore/dist/directives/when.cjs.map +0 -1
  155. package/dist/ore/dist/directives/when.js +0 -38
  156. package/dist/ore/dist/directives/when.js.map +0 -1
  157. package/dist/ore/dist/directives.cjs +0 -1
  158. package/dist/ore/dist/directives.js +0 -8
  159. package/dist/ore/dist/errors.cjs +0 -3
  160. package/dist/ore/dist/errors.cjs.map +0 -1
  161. package/dist/ore/dist/errors.js +0 -50
  162. package/dist/ore/dist/errors.js.map +0 -1
  163. package/dist/ore/dist/forms/context.cjs +0 -2
  164. package/dist/ore/dist/forms/context.cjs.map +0 -1
  165. package/dist/ore/dist/forms/context.js +0 -6
  166. package/dist/ore/dist/forms/context.js.map +0 -1
  167. package/dist/ore/dist/forms/field.cjs +0 -2
  168. package/dist/ore/dist/forms/field.cjs.map +0 -1
  169. package/dist/ore/dist/forms/field.js +0 -42
  170. package/dist/ore/dist/forms/field.js.map +0 -1
  171. package/dist/ore/dist/forms.cjs +0 -1
  172. package/dist/ore/dist/forms.js +0 -3
  173. package/dist/ore/dist/observers/intersection-observe.cjs +0 -2
  174. package/dist/ore/dist/observers/intersection-observe.cjs.map +0 -1
  175. package/dist/ore/dist/observers/intersection-observe.js +0 -12
  176. package/dist/ore/dist/observers/intersection-observe.js.map +0 -1
  177. package/dist/ore/dist/observers/media-observe.cjs +0 -1
  178. package/dist/ore/dist/observers/media-observe.js +0 -1
  179. package/dist/ore/dist/observers/mutation-observe.cjs +0 -1
  180. package/dist/ore/dist/observers/mutation-observe.js +0 -1
  181. package/dist/ore/dist/observers/resize-observe.cjs +0 -2
  182. package/dist/ore/dist/observers/resize-observe.cjs.map +0 -1
  183. package/dist/ore/dist/observers/resize-observe.js +0 -20
  184. package/dist/ore/dist/observers/resize-observe.js.map +0 -1
  185. package/dist/ore/dist/observers.cjs +0 -1
  186. package/dist/ore/dist/observers.js +0 -5
  187. package/dist/ore/dist/props.cjs +0 -2
  188. package/dist/ore/dist/props.cjs.map +0 -1
  189. package/dist/ore/dist/props.js +0 -56
  190. package/dist/ore/dist/props.js.map +0 -1
  191. package/dist/ore/dist/runtime.cjs +0 -2
  192. package/dist/ore/dist/runtime.cjs.map +0 -1
  193. package/dist/ore/dist/runtime.js +0 -25
  194. package/dist/ore/dist/runtime.js.map +0 -1
  195. package/dist/ore/dist/testing/flush.cjs +0 -2
  196. package/dist/ore/dist/testing/flush.cjs.map +0 -1
  197. package/dist/ore/dist/testing/flush.js +0 -11
  198. package/dist/ore/dist/testing/flush.js.map +0 -1
  199. package/dist/ore/dist/testing/mount.cjs +0 -2
  200. package/dist/ore/dist/testing/mount.cjs.map +0 -1
  201. package/dist/ore/dist/testing/mount.js +0 -94
  202. package/dist/ore/dist/testing/mount.js.map +0 -1
  203. package/dist/ore/dist/testing/query.cjs +0 -2
  204. package/dist/ore/dist/testing/query.cjs.map +0 -1
  205. package/dist/ore/dist/testing/query.js +0 -12
  206. package/dist/ore/dist/testing/query.js.map +0 -1
  207. package/dist/ore/dist/testing/render-hook.cjs +0 -1
  208. package/dist/ore/dist/testing/render-hook.js +0 -3
  209. package/dist/ore/dist/testing/testing.cjs +0 -1
  210. package/dist/ore/dist/testing/testing.js +0 -4
  211. package/dist/ore/dist/testing/wait.cjs +0 -1
  212. package/dist/ore/dist/testing/wait.js +0 -1
  213. package/dist/ore/dist/testing.cjs +0 -1
  214. package/dist/ore/dist/testing.js +0 -6
  215. package/dist/ore/dist/types/bindings.cjs +0 -2
  216. package/dist/ore/dist/types/bindings.cjs.map +0 -1
  217. package/dist/ore/dist/types/bindings.js +0 -15
  218. package/dist/ore/dist/types/bindings.js.map +0 -1
  219. package/dist/ore/dist/types.cjs +0 -2
  220. package/dist/ore/dist/types.cjs.map +0 -1
  221. package/dist/ore/dist/types.js +0 -15
  222. package/dist/ore/dist/types.js.map +0 -1
  223. package/dist/ore/dist/utils/css.cjs +0 -2
  224. package/dist/ore/dist/utils/css.cjs.map +0 -1
  225. package/dist/ore/dist/utils/css.js +0 -18
  226. package/dist/ore/dist/utils/css.js.map +0 -1
  227. package/dist/ore/dist/utils/dom.cjs +0 -2
  228. package/dist/ore/dist/utils/dom.cjs.map +0 -1
  229. package/dist/ore/dist/utils/dom.js +0 -43
  230. package/dist/ore/dist/utils/dom.js.map +0 -1
  231. package/dist/ore/dist/utils/id.cjs +0 -2
  232. package/dist/ore/dist/utils/id.cjs.map +0 -1
  233. package/dist/ore/dist/utils/id.js +0 -4
  234. package/dist/ore/dist/utils/id.js.map +0 -1
package/dist/input.js CHANGED
@@ -1,19 +1,17 @@
1
- import { live as e } from "./ore/dist/directives/live.js";
2
- import "./ore/dist/directives.js";
3
- import { sizeVariantMixin as t } from "./styles/mixins/shape.css.js";
4
- import { forcedColorsFocusMixin as n } from "./styles/mixins/theme.css.js";
5
- import { fieldMixins as r } from "./styles/index.js";
6
- import { disablableBundle as i, roundableBundle as a, sizableBundle as o, themableBundle as s } from "./shared/prop-bundles.js";
7
- import { FIELD_SIZE_PRESET as c } from "./shared/size-presets.js";
8
- import { lifecycleSignal as l } from "./headless/ore.js";
9
- import { createTextField as u } from "./headless/text-field.js";
10
- import { useField as d } from "./ore/dist/forms/field.js";
11
- import "./ore/dist/forms.js";
12
- import { errorAttr as f } from "./inputs/shared/field-binding.js";
13
- import { FORM_CTX as p, useFormContext as m } from "./inputs/shared/form-context.js";
14
- import h from "./inputs/input/input.css.js";
15
- import { bind as g, define as _, html as v, inject as y, onCleanup as b, onElement as x, prop as S, ref as C, useEmit as w, useSlots as T } from "@vielzeug/ore";
16
- import { computed as E, signal as D, watch as O } from "@vielzeug/ripple";
1
+ import { sizeVariantMixin as e } from "./styles/mixins/shape.css.js";
2
+ import { forcedColorsFocusMixin as t } from "./styles/mixins/theme.css.js";
3
+ import { fieldMixins as n } from "./styles/index.js";
4
+ import { disablableBundle as r, roundableBundle as i, sizableBundle as a, themableBundle as o } from "./shared/prop-bundles.js";
5
+ import { FIELD_SIZE_PRESET as s } from "./shared/size-presets.js";
6
+ import { lifecycleSignal as c } from "./headless/ore.js";
7
+ import { createTextField as l } from "./headless/text-field.js";
8
+ import { errorAttr as u } from "./inputs/shared/field-binding.js";
9
+ import { FORM_CTX as d, useFormContext as f } from "./inputs/shared/form-context.js";
10
+ import p from "./inputs/input/input.css.js";
11
+ import { bind as m, define as h, html as g, inject as _, onCleanup as v, onElement as y, prop as b, ref as x, useEmit as S, useSlots as C } from "@vielzeug/ore";
12
+ import { live as w } from "@vielzeug/ore/directives";
13
+ import { computed as T, signal as E, watch as D } from "@vielzeug/ripple";
14
+ import { useField as O } from "@vielzeug/ore/forms";
17
15
  //#region src/inputs/input/input.ts
18
16
  var k = [
19
17
  "text",
@@ -29,87 +27,87 @@ var k = [
29
27
  "month",
30
28
  "week"
31
29
  ], A = "ore-input";
32
- _(A, {
30
+ h(A, {
33
31
  formAssociated: !0,
34
32
  props: {
35
- ...s,
36
33
  ...o,
37
- ...i,
38
34
  ...a,
39
- autocomplete: S.string(),
40
- clearable: S.bool(!1),
41
- error: S.string(),
42
- fullwidth: S.bool(!1),
43
- helper: S.string(),
44
- inputmode: S.string(),
45
- label: S.string(),
46
- "label-placement": S.oneOf(["inset", "outside"], "inset"),
47
- maxlength: S.json(void 0),
48
- minlength: S.json(void 0),
49
- name: S.string(),
50
- pattern: S.string(),
51
- placeholder: S.string(),
52
- readonly: S.bool(!1),
53
- ref: S.json(void 0),
54
- required: S.bool(!1),
55
- type: S.oneOf(k, "text"),
56
- value: S.string(),
57
- variant: S.string()
35
+ ...r,
36
+ ...i,
37
+ autocomplete: b.string(),
38
+ clearable: b.bool(!1),
39
+ error: b.string(),
40
+ fullwidth: b.bool(!1),
41
+ helper: b.string(),
42
+ inputmode: b.string(),
43
+ label: b.string(),
44
+ "label-placement": b.oneOf(["inset", "outside"], "inset"),
45
+ maxlength: b.json(void 0),
46
+ minlength: b.json(void 0),
47
+ name: b.string(),
48
+ pattern: b.string(),
49
+ placeholder: b.string(),
50
+ readonly: b.bool(!1),
51
+ ref: b.json(void 0),
52
+ required: b.bool(!1),
53
+ type: b.oneOf(k, "text"),
54
+ value: b.string(),
55
+ variant: b.string()
58
56
  },
59
- setup(t) {
60
- let n = w(), r = T(), i = y(p), a = m(t, i), o = D(!1), s = C(), c = E(() => !!t.label.value || r.has("label").value), h = l(b), _ = u({
61
- disabled: a.disabled,
62
- error: t.error,
63
- hasLabel: c,
64
- helper: t.helper,
65
- label: t.label,
66
- labelPlacement: t["label-placement"],
67
- maxLength: t.maxlength,
68
- onChange: (e, t) => {
69
- n("change", {
57
+ setup(e) {
58
+ let t = S(), n = C(), r = _(d), i = f(e, r), a = E(!1), o = x(), s = T(() => !!e.label.value || n.has("label").value), p = c(v), h = l({
59
+ disabled: i.disabled,
60
+ error: e.error,
61
+ hasLabel: s,
62
+ helper: e.helper,
63
+ label: e.label,
64
+ labelPlacement: e["label-placement"],
65
+ maxLength: e.maxlength,
66
+ onChange: (e, n) => {
67
+ t("change", {
70
68
  originalEvent: e,
71
- value: t
69
+ value: n
72
70
  });
73
71
  },
74
- onInput: (e, t) => {
75
- n("input", {
72
+ onInput: (e, n) => {
73
+ t("input", {
76
74
  originalEvent: e,
77
- value: t
75
+ value: n
78
76
  });
79
77
  },
80
78
  prefix: "input",
81
- readonly: t.readonly,
82
- required: t.required,
83
- signal: h,
84
- validateOn: i?.validateOn,
85
- value: t.value
79
+ readonly: e.readonly,
80
+ required: e.required,
81
+ signal: p,
82
+ validateOn: r?.validateOn,
83
+ value: e.value
86
84
  });
87
- _.attachFormField(d({
88
- disabled: _.disabled,
89
- onReset: _.reset,
85
+ h.attachFormField(O({
86
+ disabled: h.disabled,
87
+ onReset: h.reset,
90
88
  toFormValue: (e) => e,
91
- validationMessage: _.validationMessage,
92
- validity: _.validity,
93
- value: _.value
89
+ validationMessage: h.validationMessage,
90
+ validity: h.validity,
91
+ value: h.value
94
92
  }));
95
- let { ariaDescribedBy: S, ariaErrorMessage: k, ariaInvalid: A, ariaLabelledBy: j, assistiveId: M, clear: N, counter: P, errorId: F, errorText: I, fieldId: L, helperText: R, labelId: z, labelVisible: B, value: V, wire: H } = _;
96
- return x(s, (e) => {
97
- H(e, h), t.ref.value?.(e);
98
- let n = O(t.ref, (t) => {
99
- t?.(e);
93
+ let { ariaDescribedBy: b, ariaErrorMessage: k, ariaInvalid: A, ariaLabelledBy: j, assistiveId: M, clear: N, counter: P, errorId: F, errorText: I, fieldId: L, helperText: R, labelId: z, labelVisible: B, value: V, wire: H } = h;
94
+ return y(o, (t) => {
95
+ H(t, p), e.ref.value?.(t);
96
+ let n = D(e.ref, (e) => {
97
+ e?.(t);
100
98
  });
101
99
  return () => {
102
- n.dispose(), t.ref.value?.(null);
100
+ n.dispose(), e.ref.value?.(null);
103
101
  };
104
- }), g({ attr: {
105
- error: f(I),
102
+ }), m({ attr: {
103
+ error: u(I),
106
104
  "has-value": () => V.value ? !0 : void 0,
107
- size: a.size,
108
- variant: a.variant
109
- } }), v`
105
+ size: i.size,
106
+ variant: i.variant
107
+ } }), g`
110
108
  <div class="input-wrapper" part="wrapper">
111
109
  <label class="label" for="${L}" id="${z}" part="label" ?hidden="${() => !B.value}"
112
- ><slot name="label">${t.label}</slot></label
110
+ ><slot name="label">${e.label}</slot></label
113
111
  >
114
112
  <div class="field" part="field">
115
113
  <div class="input-row" part="input-row">
@@ -117,35 +115,35 @@ _(A, {
117
115
  <input
118
116
  part="input"
119
117
  id="${L}"
120
- :type="${() => t.type.value === "password" && o.value ? "text" : t.type.value ?? "text"}"
121
- :name="${t.name}"
122
- :placeholder="${t.placeholder}"
123
- :autocomplete="${t.autocomplete}"
124
- :inputmode="${t.inputmode}"
125
- :maxlength="${t.maxlength}"
126
- :minlength="${t.minlength}"
127
- :pattern="${t.pattern}"
128
- ?disabled="${t.disabled}"
129
- ?readonly="${t.readonly}"
130
- ?required="${t.required}"
131
- :value="${e(V)}"
118
+ :type="${() => e.type.value === "password" && a.value ? "text" : e.type.value ?? "text"}"
119
+ :name="${e.name}"
120
+ :placeholder="${e.placeholder}"
121
+ :autocomplete="${e.autocomplete}"
122
+ :inputmode="${e.inputmode}"
123
+ :maxlength="${e.maxlength}"
124
+ :minlength="${e.minlength}"
125
+ :pattern="${e.pattern}"
126
+ ?disabled="${e.disabled}"
127
+ ?readonly="${e.readonly}"
128
+ ?required="${e.required}"
129
+ :value="${w(V)}"
132
130
  :aria-labelledby="${j}"
133
- :aria-describedby="${S}"
131
+ :aria-describedby="${b}"
134
132
  :aria-errormessage="${k}"
135
133
  :aria-invalid="${A}"
136
- ref="${s}" />
134
+ ref="${o}" />
137
135
  <slot name="suffix"></slot>
138
136
  <button
139
137
  class="pwd-toggle-btn"
140
138
  part="pwd-toggle"
141
139
  type="button"
142
- :aria-label="${() => o.value ? "Hide password" : "Show password"}"
143
- :aria-pressed="${() => String(o.value)}"
144
- :tabindex="${() => t.type.value === "password" ? "0" : "-1"}"
140
+ :aria-label="${() => a.value ? "Hide password" : "Show password"}"
141
+ :aria-pressed="${() => String(a.value)}"
142
+ :tabindex="${() => e.type.value === "password" ? "0" : "-1"}"
145
143
  @click="${() => {
146
- o.value = !o.value, s.value?.focus();
144
+ a.value = !a.value, o.value?.focus();
147
145
  }}">
148
- ${() => o.value ? v`<ore-icon name="eye-off" size="14" stroke-width="2" aria-hidden="true"></ore-icon>` : v`<ore-icon name="eye" size="14" stroke-width="2" aria-hidden="true"></ore-icon>`}
146
+ ${() => a.value ? g`<ore-icon name="eye-off" size="14" stroke-width="2" aria-hidden="true"></ore-icon>` : g`<ore-icon name="eye" size="14" stroke-width="2" aria-hidden="true"></ore-icon>`}
149
147
  </button>
150
148
  <button
151
149
  aria-label="Clear"
@@ -154,7 +152,7 @@ _(A, {
154
152
  type="button"
155
153
  :tabindex="${() => V.value ? "0" : "-1"}"
156
154
  @click="${(e) => {
157
- N(e), s.value?.focus();
155
+ N(e), o.value?.focus();
158
156
  }}">
159
157
  <ore-icon aria-hidden="true" name="x" size="12" stroke-width="2.5"></ore-icon>
160
158
  </button>
@@ -179,10 +177,10 @@ _(A, {
179
177
  },
180
178
  shadow: { delegatesFocus: !0 },
181
179
  styles: [
182
- ...r,
183
- t(c),
184
- n("input"),
185
- h
180
+ ...n,
181
+ e(s),
182
+ t("input"),
183
+ p
186
184
  ]
187
185
  });
188
186
  //#endregion
package/dist/input.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","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.js","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,23 +1,23 @@
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/accessibility.css.cjs"),n=require("./styles/mixins/shape.css.cjs"),r=require("./styles/mixins/states.css.cjs"),i=require("./styles/mixins/theme.css.cjs"),a=require("./shared/prop-bundles.cjs"),o=require("./shared/size-presets.cjs"),s=require("./headless/ore.cjs"),c=require("./headless/auto-resize.cjs"),l=require("./headless/field-base.cjs"),u=require("./headless/text-field.cjs"),d=require("./headless/composer.cjs"),f=require("./ore/dist/forms/field.cjs");require("./ore/dist/forms.cjs");const p=require("./inputs/shared/field-binding.cjs"),m=require("./inputs/shared/form-context.cjs"),h=require("./inputs/message-composer/message-composer.css.cjs");let g=require("@vielzeug/ore"),_=require("@vielzeug/ripple");var v=`Send message`,y=`arrow-up`,b=`ore-message-composer`;(0,g.define)(b,{formAssociated:!0,props:{...a.themableBundle,...a.sizableBundle,...a.disablableBundle,...a.loadableBundle,"clear-on-send":g.prop.bool(!0),error:g.prop.string(),fullwidth:g.prop.bool(!1),helper:g.prop.string(),label:g.prop.string(),maxlength:g.prop.json(void 0),name:g.prop.string(),placeholder:g.prop.string(),readonly:g.prop.bool(!1),ref:g.prop.json(void 0),required:g.prop.bool(!1),rows:g.prop.json(void 0),"send-icon":g.prop.string(),"send-label":g.prop.string(),"send-shortcut":g.prop.oneOf([`enter`,`mod+enter`],`enter`),value:g.prop.string(),variant:g.prop.string()},setup(t){let n=(0,g.useEmit)(),r=(0,g.useSlots)(),i=(0,g.inject)(m.FORM_CTX),a=m.useFormContext(t,i),o=a.disabled,h=s.lifecycleSignal(g.onCleanup),b=(0,g.ref)(),x=c.createAutoResize(),S=u.createTextField({disabled:o,error:t.error,helper:t.helper,maxLength:t.maxlength,onInput:(e,t)=>n(`input`,{originalEvent:e,value:t}),prefix:`composer`,readonly:t.readonly,required:t.required,signal:h,validateOn:i?.validateOn,value:t.value});S.attachFormField(f.useField({disabled:S.disabled,onReset:()=>{S.reset(),x.recompute()},toFormValue:e=>e,validationMessage:S.validationMessage,validity:S.validity,value:S.value}));function C(e){n(`send`,{originalEvent:e,value:S.value.value.trim()})&&t[`clear-on-send`].value!==!1&&(S.clear(),x.recompute(),b.value?.focus())}let w=d.createComposerControl({disabled:o,loading:(0,_.computed)(()=>!!t.loading.value),onSend:C,sendShortcut:t[`send-shortcut`],value:S.value});return(0,g.onElement)(b,e=>{let n=S.wire(e),r=x.wire(e),i=e=>w.handleKeydown(e);e.addEventListener(`keydown`,i),t.ref.value?.(e);let a=(0,_.watch)(t.ref,t=>{t?.(e)});return()=>{e.removeEventListener(`keydown`,i),n(),r(),a.dispose(),t.ref.value?.(null)}}),(0,g.bind)({attr:{error:p.errorAttr(S.errorText),size:a.size,variant:a.variant}}),g.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./styles/mixins/shape.css.cjs"),n=require("./styles/mixins/states.css.cjs"),r=require("./styles/mixins/theme.css.cjs"),i=require("./shared/prop-bundles.cjs"),a=require("./shared/size-presets.cjs"),o=require("./headless/ore.cjs"),s=require("./headless/auto-resize.cjs"),c=require("./headless/field-base.cjs"),l=require("./headless/text-field.cjs"),u=require("./headless/composer.cjs"),d=require("./inputs/shared/field-binding.cjs"),f=require("./inputs/shared/form-context.cjs"),p=require("./inputs/message-composer/message-composer.css.cjs");let m=require("@vielzeug/ore"),h=require("@vielzeug/ore/directives"),g=require("@vielzeug/ripple"),_=require("@vielzeug/ore/forms");var v=`Send message`,y=`arrow-up`,b=`ore-message-composer`;(0,m.define)(b,{formAssociated:!0,props:{...i.themableBundle,...i.sizableBundle,...i.disablableBundle,...i.loadableBundle,"clear-on-send":m.prop.bool(!0),error:m.prop.string(),fullwidth:m.prop.bool(!1),helper:m.prop.string(),label:m.prop.string(),maxlength:m.prop.json(void 0),name:m.prop.string(),placeholder:m.prop.string(),readonly:m.prop.bool(!1),ref:m.prop.json(void 0),required:m.prop.bool(!1),rows:m.prop.json(void 0),"send-icon":m.prop.string(),"send-label":m.prop.string(),"send-shortcut":m.prop.oneOf([`enter`,`mod+enter`],`enter`),value:m.prop.string(),variant:m.prop.string()},setup(e){let t=(0,m.useEmit)(),n=(0,m.useSlots)(),r=(0,m.inject)(f.FORM_CTX),i=f.useFormContext(e,r),a=i.disabled,p=o.lifecycleSignal(m.onCleanup),b=(0,m.ref)(),x=s.createAutoResize(),S=l.createTextField({disabled:a,error:e.error,helper:e.helper,maxLength:e.maxlength,onInput:(e,n)=>t(`input`,{originalEvent:e,value:n}),prefix:`composer`,readonly:e.readonly,required:e.required,signal:p,validateOn:r?.validateOn,value:e.value});S.attachFormField((0,_.useField)({disabled:S.disabled,onReset:()=>{S.reset(),x.recompute()},toFormValue:e=>e,validationMessage:S.validationMessage,validity:S.validity,value:S.value}));function C(n){t(`send`,{originalEvent:n,value:S.value.value.trim()})&&e[`clear-on-send`].value!==!1&&(S.clear(),x.recompute(),b.value?.focus())}let w=u.createComposerControl({disabled:a,loading:(0,g.computed)(()=>!!e.loading.value),onSend:C,sendShortcut:e[`send-shortcut`],value:S.value});return(0,m.onElement)(b,t=>{let n=S.wire(t),r=x.wire(t),i=e=>w.handleKeydown(e);t.addEventListener(`keydown`,i),e.ref.value?.(t);let a=(0,g.watch)(e.ref,e=>{e?.(t)});return()=>{t.removeEventListener(`keydown`,i),n(),r(),a.dispose(),e.ref.value?.(null)}}),(0,m.bind)({attr:{error:d.errorAttr(S.errorText),size:i.size,variant:i.variant}}),m.html`
2
2
  <div class="composer" part="composer">
3
3
  <textarea
4
4
  class="field"
5
5
  part="field"
6
6
  ref="${b}"
7
- :rows="${()=>t.rows.value??1}"
8
- :name="${()=>t.name.value??``}"
9
- :placeholder="${()=>t.placeholder.value??`Message…`}"
10
- :maxlength="${()=>t.maxlength.value}"
11
- ?disabled="${o}"
12
- ?readonly="${()=>!!t.readonly.value}"
13
- ?required="${()=>!!t.required.value}"
14
- :value="${e.live(S.value)}"
15
- :aria-label="${()=>t.label.value||`Message`}"
7
+ :rows="${()=>e.rows.value??1}"
8
+ :name="${()=>e.name.value??``}"
9
+ :placeholder="${()=>e.placeholder.value??`Message…`}"
10
+ :maxlength="${()=>e.maxlength.value}"
11
+ ?disabled="${a}"
12
+ ?readonly="${()=>!!e.readonly.value}"
13
+ ?required="${()=>!!e.required.value}"
14
+ :value="${(0,h.live)(S.value)}"
15
+ :aria-label="${()=>e.label.value||`Message`}"
16
16
  :aria-keyshortcuts="${w.keyShortcutsHint}"
17
17
  :aria-describedby="${S.ariaDescribedBy}"
18
18
  :aria-errormessage="${S.ariaErrorMessage}"
19
19
  :aria-invalid="${S.ariaInvalid}"></textarea>
20
- <span class="${()=>l.counterClassName(S.counter?.value)}" aria-live="polite" ?hidden="${()=>!S.counter}">${()=>S.counter?.value.counterText.replace(` / `,`/`)??``}</span>
20
+ <span class="${()=>c.counterClassName(S.counter?.value)}" aria-live="polite" ?hidden="${()=>!S.counter}">${()=>S.counter?.value.counterText.replace(` / `,`/`)??``}</span>
21
21
  <div id="${S.assistiveId}" class="helper-text" aria-live="polite" part="helper" ?hidden="${()=>!!S.errorText.value||!S.helperText.value}">
22
22
  ${()=>S.helperText.value}
23
23
  </div>
@@ -31,22 +31,22 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
31
31
  <div class="toolbar-end" part="toolbar-end">
32
32
  <slot name="suffix"></slot>
33
33
  <slot name="send"></slot>
34
- ${()=>r.has(`send`).value?``:g.html`<ore-button
34
+ ${()=>n.has(`send`).value?``:m.html`<ore-button
35
35
  class="send-btn"
36
36
  part="send-button"
37
37
  type="button"
38
38
  icon-only
39
39
  variant="solid"
40
- :color="${()=>t.color.value||`primary`}"
41
- :size="${a.size}"
42
- :label="${()=>t[`send-label`].value||v}"
43
- ?loading="${()=>!!t.loading.value}"
40
+ :color="${()=>e.color.value||`primary`}"
41
+ :size="${i.size}"
42
+ :label="${()=>e[`send-label`].value||v}"
43
+ ?loading="${()=>!!e.loading.value}"
44
44
  ?disabled="${()=>!w.canSend.value}"
45
45
  @click="${e=>w.send(e)}">
46
- <ore-icon name="${()=>t[`send-icon`].value||y}" size="16"></ore-icon>
46
+ <ore-icon name="${()=>e[`send-icon`].value||y}" size="16"></ore-icon>
47
47
  </ore-button>`}
48
48
  </div>
49
49
  </div>
50
50
  </div>
51
- `},shadow:{delegatesFocus:!0},styles:[i.colorThemeMixin,t.coarsePointerMixin,t.reducedMotionMixin,r.disabledLoadingMixin,i.forcedColorsMixin,i.forcedColorsFocusMixin(`.field`),n.sizeVariantMixin(o.MESSAGE_COMPOSER_SIZE_PRESET),h.default]}),exports.MESSAGE_COMPOSER_TAG=b;
51
+ `},shadow:{delegatesFocus:!0},styles:[r.colorThemeMixin,e.coarsePointerMixin,e.reducedMotionMixin,n.disabledLoadingMixin,r.forcedColorsMixin,r.forcedColorsFocusMixin(`.field`),t.sizeVariantMixin(a.MESSAGE_COMPOSER_SIZE_PRESET),p.default]}),exports.MESSAGE_COMPOSER_TAG=b;
52
52
  //# sourceMappingURL=message-composer.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-composer.cjs","names":[],"sources":["../src/inputs/message-composer/message-composer.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, watch } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\n\nimport {\n counterClassName,\n createAutoResize,\n createComposerControl,\n createTextField,\n lifecycleSignal,\n type SendShortcut,\n} from '../../headless';\nimport {\n disablableBundle,\n loadableBundle,\n MESSAGE_COMPOSER_SIZE_PRESET,\n sizableBundle,\n themableBundle,\n} from '../../shared';\nimport {\n colorThemeMixin,\n coarsePointerMixin,\n disabledLoadingMixin,\n forcedColorsFocusMixin,\n forcedColorsMixin,\n reducedMotionMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { errorAttr } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport '../../content/icon/icon';\nimport '../button/button';\nimport componentStyles from './message-composer.css?inline';\n\nexport type { SendShortcut } from '../../headless';\n\nconst DEFAULT_SEND_LABEL = 'Send message';\nconst SEND_ICON = 'arrow-up';\n\n/** Events emitted by the message composer */\nexport type OreMessageComposerEvents = {\n /** Fired on every keystroke with the current value. */\n input: { originalEvent: Event; value: string };\n /**\n * Fired for a send attempt (the resolved `send-shortcut` or the send button) while the\n * composer isn't blank/disabled/loading. Cancelable — call `preventDefault()` to keep the\n * current text in the field instead of the default clear + refocus.\n */\n send: { originalEvent: KeyboardEvent | MouseEvent; value: string };\n};\n\n/** Message composer properties */\nexport type OreMessageComposerProps = {\n /** Clear the value and refocus after a non-cancelled `send` (default `true`) */\n 'clear-on-send'?: boolean;\n /** Theme color (card focus ring + default send button color) */\n color?: ThemeColor;\n /** Disable the whole composer (field, slots, and send action) */\n disabled?: boolean;\n /** Error message shown below the field */\n error?: string;\n /** Stretch the composer to the full width of its container */\n fullwidth?: boolean;\n /** Helper text shown below the field */\n helper?: string;\n /** Accessible name for the field — never rendered visually, only as `aria-label` */\n label?: string;\n /** Blocks further sends (e.g. a send is already in flight) without disabling editing */\n loading?: boolean;\n /** Maximum character count; shows a counter */\n maxlength?: number;\n /** Form field name */\n name?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Make the field read-only */\n readonly?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts, and with\n * `null` when it unmounts. Set as a JS property: `composer.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Require a non-blank value for `<ore-form>` validation */\n required?: boolean;\n /** Number of visible rows before auto-resize grows the field */\n rows?: number;\n /** Lucide icon name for the default send button (default `'arrow-up'`) */\n 'send-icon'?: string;\n /** Accessible label for the send button (default `'Send message'`) */\n 'send-label'?: string;\n /** Keyboard shortcut that sends: 'enter' (Shift+Enter for a newline) or 'mod+enter' (Enter always inserts a newline; Ctrl/Cmd+Enter sends) */\n 'send-shortcut'?: SendShortcut;\n /** Component size */\n size?: ComponentSize;\n /** Current text value */\n value?: string;\n /** Visual variant of the card — same variant set as `ore-textarea`, applied to the card. */\n variant?: Exclude<VisualVariant, 'frost' | 'text'>;\n};\n\n/**\n * A message/comment composer — a card with an auto-resizing field on top and a toolbar row\n * below it, built directly on the same headless primitives as `ore-textarea` (`createTextField`,\n * `createAutoResize`) rather than composing `ore-textarea` itself. Nesting a fully-styled sibling\n * component and suppressing most of its chrome (as an earlier version of this component did) is\n * a leaky composition — this owns its single `<textarea>` outright, so there's exactly one\n * implementation of the field's appearance to reason about, not two fighting each other.\n *\n * Handles the send gesture (Enter to send, Shift+Enter for a newline, or a Ctrl/Cmd+Enter\n * alternative), IME-safe composition, and clear-and-refocus after sending.\n *\n * @element ore-message-composer\n *\n * @attr {string} value - Current text value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} label - Accessible name for the field (not rendered visually)\n * @attr {string} name - Form field name\n * @attr {string} helper - Helper text shown below the field\n * @attr {string} error - Error message shown below the field\n * @attr {boolean} disabled - Disable the whole composer\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Require a non-blank value for `<ore-form>` validation\n * @attr {boolean} loading - Blocks further sends without disabling editing\n * @attr {number} maxlength - Max character count; shows a counter\n * @attr {number} rows - Visible rows before auto-resize grows the field (default 1)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant of the card: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {boolean} fullwidth - Stretch to the full width of the container\n * @attr {string} send-icon - Lucide icon name for the default send button (default 'arrow-up')\n * @attr {string} send-label - Accessible label for the send button (default 'Send message')\n * @attr {string} send-shortcut - 'enter' (default) | 'mod+enter'\n * @attr {boolean} clear-on-send - Clear the value and refocus after a non-cancelled send (default true)\n *\n * @fires input - Fired on every keystroke. detail: { value, originalEvent }\n * @fires send - Fired on a send attempt. Cancelable. detail: { value, originalEvent }\n *\n * @slot prefix - Content at the start of the toolbar row (e.g. an attach menu)\n * @slot suffix - Content at the end of the toolbar row, before the send button (e.g. a model picker)\n * @slot send - Replaces the default send button entirely — the only supported way to customize it\n *\n * @cssprop --message-composer-bg - Card background color\n * @cssprop --message-composer-border-color - Card border color\n * @cssprop --message-composer-radius - Card border radius\n * @cssprop --message-composer-padding - Card inner padding\n * @cssprop --message-composer-gap - Gap between the field/toolbar rows and between toolbar items\n * @cssprop --message-composer-placeholder-color - Field placeholder text color\n * @cssprop --message-composer-min-height - Minimum field height (default one line)\n * @cssprop --message-composer-hover-bg - Card background on hover (flat/ghost variants)\n * @cssprop --message-composer-hover-border-color - Card border on hover (flat/bordered variants)\n * @cssprop --message-composer-focus-bg - Card background when focused (flat variant)\n * @cssprop --message-composer-focus-border-color - Card border when focused (flat variant)\n *\n * @part composer - Root card container\n * @part field - The native `<textarea>` element\n * @part helper - Helper text element\n * @part error - Error text element (`role=\"alert\"`)\n * @part toolbar - Toolbar row below the field\n * @part toolbar-start - Toolbar group holding the `prefix` slot\n * @part toolbar-end - Toolbar group holding the `suffix` slot and the send button\n * @part send-button - The default send button (absent when the `send` slot is used)\n *\n * @example\n * ```html\n * <ore-message-composer placeholder=\"Message…\" send-shortcut=\"mod+enter\"></ore-message-composer>\n * ```\n */\nexport const MESSAGE_COMPOSER_TAG = 'ore-message-composer' as const;\ndefine<OreMessageComposerProps>(MESSAGE_COMPOSER_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...loadableBundle,\n 'clear-on-send': prop.bool(true),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.json(undefined as ((el: HTMLTextAreaElement | null) => void) | null | undefined),\n required: prop.bool(false),\n rows: prop.json(undefined as number | undefined),\n 'send-icon': prop.string(),\n 'send-label': prop.string(),\n 'send-shortcut': prop.oneOf(['enter', 'mod+enter'] as const, 'enter'),\n value: prop.string(),\n variant: prop.string<Exclude<VisualVariant, 'frost' | 'text'>>(),\n },\n setup(props) {\n const emit = useEmit<OreMessageComposerEvents>();\n const slots = useSlots<'prefix' | 'send' | 'suffix'>();\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n const isDisabled = fCtxProps.disabled;\n\n const abortSignal = lifecycleSignal(onCleanup);\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize();\n\n const tf = createTextField({\n disabled: isDisabled,\n error: props.error,\n helper: props.helper,\n maxLength: props.maxlength,\n onInput: (event, value) => emit('input', { originalEvent: event, value }),\n prefix: 'composer',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n // Directly form-associated now that the field is owned here rather than borrowed from a\n // nested `ore-textarea` (which previously registered with the ancestor `<form>` on this\n // component's behalf).\n tf.attachFormField(\n useField<string>({\n disabled: tf.disabled,\n onReset: () => {\n tf.reset();\n autoResize.recompute();\n },\n toFormValue: (v) => v,\n validationMessage: tf.validationMessage,\n validity: tf.validity,\n value: tf.value,\n }),\n );\n\n function attemptSend(event: KeyboardEvent | MouseEvent): void {\n const notPrevented = emit('send', { originalEvent: event, value: tf.value.value.trim() });\n\n // `preventDefault()` on `send` means \"keep the current text — skip the default clear\n // + refocus\" (see the event's own doc comment): both halves of that default are gated on\n // the same condition, not just the clear.\n if (notPrevented && props['clear-on-send'].value !== false) {\n tf.clear();\n autoResize.recompute();\n textareaRef.value?.focus();\n }\n }\n\n const composer = createComposerControl({\n disabled: isDisabled,\n loading: computed(() => Boolean(props.loading.value)),\n onSend: attemptSend,\n sendShortcut: props['send-shortcut'],\n value: tf.value,\n });\n\n onElement(textareaRef, (textareaEl) => {\n const unwireField = tf.wire(textareaEl);\n const unwireAutoResize = autoResize.wire(textareaEl);\n const handleKeydown = (e: KeyboardEvent) => composer.handleKeydown(e);\n\n textareaEl.addEventListener('keydown', handleKeydown);\n\n // Immediate fire for when the prop is already set on mount.\n props.ref.value?.(textareaEl);\n\n // Reactive watcher so that if props.ref is set *after* the inner <textarea> mounts\n // (e.g. a parent sets it via a ref callback after render), the new callback still\n // receives the live element.\n const refSub = watch(props.ref, (cb) => {\n cb?.(textareaEl);\n });\n\n return () => {\n textareaEl.removeEventListener('keydown', handleKeydown);\n unwireField();\n unwireAutoResize();\n refSub.dispose();\n props.ref.value?.(null);\n };\n });\n\n bind({\n attr: {\n error: errorAttr(tf.errorText),\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const counterClass = () => counterClassName(tf.counter?.value);\n const counterHidden = () => !tf.counter;\n const counterText = () => tf.counter?.value.counterText.replace(' / ', '/') ?? '';\n const helperHidden = () => !!tf.errorText.value || !tf.helperText.value;\n const errorHidden = () => !tf.errorText.value;\n\n return html`\n <div class=\"composer\" part=\"composer\">\n <textarea\n class=\"field\"\n part=\"field\"\n ref=\"${textareaRef}\"\n :rows=\"${() => props.rows.value ?? 1}\"\n :name=\"${() => props.name.value ?? ''}\"\n :placeholder=\"${() => props.placeholder.value ?? 'Message…'}\"\n :maxlength=\"${() => props.maxlength.value}\"\n ?disabled=\"${isDisabled}\"\n ?readonly=\"${() => Boolean(props.readonly.value)}\"\n ?required=\"${() => Boolean(props.required.value)}\"\n :value=\"${live(tf.value)}\"\n :aria-label=\"${() => props.label.value || 'Message'}\"\n :aria-keyshortcuts=\"${composer.keyShortcutsHint}\"\n :aria-describedby=\"${tf.ariaDescribedBy}\"\n :aria-errormessage=\"${tf.ariaErrorMessage}\"\n :aria-invalid=\"${tf.ariaInvalid}\"></textarea>\n <span class=\"${counterClass}\" aria-live=\"polite\" ?hidden=\"${counterHidden}\">${counterText}</span>\n <div id=\"${tf.assistiveId}\" class=\"helper-text\" aria-live=\"polite\" part=\"helper\" ?hidden=\"${helperHidden}\">\n ${() => tf.helperText.value}\n </div>\n <div id=\"${tf.errorId}\" class=\"helper-text\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n ${() => tf.errorText.value}\n </div>\n <div class=\"toolbar\" part=\"toolbar\">\n <div class=\"toolbar-start\" part=\"toolbar-start\">\n <slot name=\"prefix\"></slot>\n </div>\n <div class=\"toolbar-end\" part=\"toolbar-end\">\n <slot name=\"suffix\"></slot>\n <slot name=\"send\"></slot>\n ${() =>\n slots.has('send').value\n ? ''\n : html`<ore-button\n class=\"send-btn\"\n part=\"send-button\"\n type=\"button\"\n icon-only\n variant=\"solid\"\n :color=\"${() => props.color.value || 'primary'}\"\n :size=\"${fCtxProps.size}\"\n :label=\"${() => props['send-label'].value || DEFAULT_SEND_LABEL}\"\n ?loading=\"${() => Boolean(props.loading.value)}\"\n ?disabled=\"${() => !composer.canSend.value}\"\n @click=\"${(e: MouseEvent) => composer.send(e)}\">\n <ore-icon name=\"${() => props['send-icon'].value || SEND_ICON}\" size=\"16\"></ore-icon>\n </ore-button>`}\n </div>\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n disabledLoadingMixin,\n forcedColorsMixin,\n forcedColorsFocusMixin('.field'),\n sizeVariantMixin(MESSAGE_COMPOSER_SIZE_PRESET),\n componentStyles,\n ],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"message-composer.cjs","names":[],"sources":["../src/inputs/message-composer/message-composer.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, watch } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\n\nimport {\n counterClassName,\n createAutoResize,\n createComposerControl,\n createTextField,\n lifecycleSignal,\n type SendShortcut,\n} from '../../headless';\nimport {\n disablableBundle,\n loadableBundle,\n MESSAGE_COMPOSER_SIZE_PRESET,\n sizableBundle,\n themableBundle,\n} from '../../shared';\nimport {\n colorThemeMixin,\n coarsePointerMixin,\n disabledLoadingMixin,\n forcedColorsFocusMixin,\n forcedColorsMixin,\n reducedMotionMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { errorAttr } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport '../../content/icon/icon';\nimport '../button/button';\nimport componentStyles from './message-composer.css?inline';\n\nexport type { SendShortcut } from '../../headless';\n\nconst DEFAULT_SEND_LABEL = 'Send message';\nconst SEND_ICON = 'arrow-up';\n\n/** Events emitted by the message composer */\nexport type OreMessageComposerEvents = {\n /** Fired on every keystroke with the current value. */\n input: { originalEvent: Event; value: string };\n /**\n * Fired for a send attempt (the resolved `send-shortcut` or the send button) while the\n * composer isn't blank/disabled/loading. Cancelable — call `preventDefault()` to keep the\n * current text in the field instead of the default clear + refocus.\n */\n send: { originalEvent: KeyboardEvent | MouseEvent; value: string };\n};\n\n/** Message composer properties */\nexport type OreMessageComposerProps = {\n /** Clear the value and refocus after a non-cancelled `send` (default `true`) */\n 'clear-on-send'?: boolean;\n /** Theme color (card focus ring + default send button color) */\n color?: ThemeColor;\n /** Disable the whole composer (field, slots, and send action) */\n disabled?: boolean;\n /** Error message shown below the field */\n error?: string;\n /** Stretch the composer to the full width of its container */\n fullwidth?: boolean;\n /** Helper text shown below the field */\n helper?: string;\n /** Accessible name for the field — never rendered visually, only as `aria-label` */\n label?: string;\n /** Blocks further sends (e.g. a send is already in flight) without disabling editing */\n loading?: boolean;\n /** Maximum character count; shows a counter */\n maxlength?: number;\n /** Form field name */\n name?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Make the field read-only */\n readonly?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts, and with\n * `null` when it unmounts. Set as a JS property: `composer.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Require a non-blank value for `<ore-form>` validation */\n required?: boolean;\n /** Number of visible rows before auto-resize grows the field */\n rows?: number;\n /** Lucide icon name for the default send button (default `'arrow-up'`) */\n 'send-icon'?: string;\n /** Accessible label for the send button (default `'Send message'`) */\n 'send-label'?: string;\n /** Keyboard shortcut that sends: 'enter' (Shift+Enter for a newline) or 'mod+enter' (Enter always inserts a newline; Ctrl/Cmd+Enter sends) */\n 'send-shortcut'?: SendShortcut;\n /** Component size */\n size?: ComponentSize;\n /** Current text value */\n value?: string;\n /** Visual variant of the card — same variant set as `ore-textarea`, applied to the card. */\n variant?: Exclude<VisualVariant, 'frost' | 'text'>;\n};\n\n/**\n * A message/comment composer — a card with an auto-resizing field on top and a toolbar row\n * below it, built directly on the same headless primitives as `ore-textarea` (`createTextField`,\n * `createAutoResize`) rather than composing `ore-textarea` itself. Nesting a fully-styled sibling\n * component and suppressing most of its chrome (as an earlier version of this component did) is\n * a leaky composition — this owns its single `<textarea>` outright, so there's exactly one\n * implementation of the field's appearance to reason about, not two fighting each other.\n *\n * Handles the send gesture (Enter to send, Shift+Enter for a newline, or a Ctrl/Cmd+Enter\n * alternative), IME-safe composition, and clear-and-refocus after sending.\n *\n * @element ore-message-composer\n *\n * @attr {string} value - Current text value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} label - Accessible name for the field (not rendered visually)\n * @attr {string} name - Form field name\n * @attr {string} helper - Helper text shown below the field\n * @attr {string} error - Error message shown below the field\n * @attr {boolean} disabled - Disable the whole composer\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Require a non-blank value for `<ore-form>` validation\n * @attr {boolean} loading - Blocks further sends without disabling editing\n * @attr {number} maxlength - Max character count; shows a counter\n * @attr {number} rows - Visible rows before auto-resize grows the field (default 1)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant of the card: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {boolean} fullwidth - Stretch to the full width of the container\n * @attr {string} send-icon - Lucide icon name for the default send button (default 'arrow-up')\n * @attr {string} send-label - Accessible label for the send button (default 'Send message')\n * @attr {string} send-shortcut - 'enter' (default) | 'mod+enter'\n * @attr {boolean} clear-on-send - Clear the value and refocus after a non-cancelled send (default true)\n *\n * @fires input - Fired on every keystroke. detail: { value, originalEvent }\n * @fires send - Fired on a send attempt. Cancelable. detail: { value, originalEvent }\n *\n * @slot prefix - Content at the start of the toolbar row (e.g. an attach menu)\n * @slot suffix - Content at the end of the toolbar row, before the send button (e.g. a model picker)\n * @slot send - Replaces the default send button entirely — the only supported way to customize it\n *\n * @cssprop --message-composer-bg - Card background color\n * @cssprop --message-composer-border-color - Card border color\n * @cssprop --message-composer-radius - Card border radius\n * @cssprop --message-composer-padding - Card inner padding\n * @cssprop --message-composer-gap - Gap between the field/toolbar rows and between toolbar items\n * @cssprop --message-composer-placeholder-color - Field placeholder text color\n * @cssprop --message-composer-min-height - Minimum field height (default one line)\n * @cssprop --message-composer-hover-bg - Card background on hover (flat/ghost variants)\n * @cssprop --message-composer-hover-border-color - Card border on hover (flat/bordered variants)\n * @cssprop --message-composer-focus-bg - Card background when focused (flat variant)\n * @cssprop --message-composer-focus-border-color - Card border when focused (flat variant)\n *\n * @part composer - Root card container\n * @part field - The native `<textarea>` element\n * @part helper - Helper text element\n * @part error - Error text element (`role=\"alert\"`)\n * @part toolbar - Toolbar row below the field\n * @part toolbar-start - Toolbar group holding the `prefix` slot\n * @part toolbar-end - Toolbar group holding the `suffix` slot and the send button\n * @part send-button - The default send button (absent when the `send` slot is used)\n *\n * @example\n * ```html\n * <ore-message-composer placeholder=\"Message…\" send-shortcut=\"mod+enter\"></ore-message-composer>\n * ```\n */\nexport const MESSAGE_COMPOSER_TAG = 'ore-message-composer' as const;\ndefine<OreMessageComposerProps>(MESSAGE_COMPOSER_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...loadableBundle,\n 'clear-on-send': prop.bool(true),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.json(undefined as ((el: HTMLTextAreaElement | null) => void) | null | undefined),\n required: prop.bool(false),\n rows: prop.json(undefined as number | undefined),\n 'send-icon': prop.string(),\n 'send-label': prop.string(),\n 'send-shortcut': prop.oneOf(['enter', 'mod+enter'] as const, 'enter'),\n value: prop.string(),\n variant: prop.string<Exclude<VisualVariant, 'frost' | 'text'>>(),\n },\n setup(props) {\n const emit = useEmit<OreMessageComposerEvents>();\n const slots = useSlots<'prefix' | 'send' | 'suffix'>();\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n const isDisabled = fCtxProps.disabled;\n\n const abortSignal = lifecycleSignal(onCleanup);\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize();\n\n const tf = createTextField({\n disabled: isDisabled,\n error: props.error,\n helper: props.helper,\n maxLength: props.maxlength,\n onInput: (event, value) => emit('input', { originalEvent: event, value }),\n prefix: 'composer',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n // Directly form-associated now that the field is owned here rather than borrowed from a\n // nested `ore-textarea` (which previously registered with the ancestor `<form>` on this\n // component's behalf).\n tf.attachFormField(\n useField<string>({\n disabled: tf.disabled,\n onReset: () => {\n tf.reset();\n autoResize.recompute();\n },\n toFormValue: (v) => v,\n validationMessage: tf.validationMessage,\n validity: tf.validity,\n value: tf.value,\n }),\n );\n\n function attemptSend(event: KeyboardEvent | MouseEvent): void {\n const notPrevented = emit('send', { originalEvent: event, value: tf.value.value.trim() });\n\n // `preventDefault()` on `send` means \"keep the current text — skip the default clear\n // + refocus\" (see the event's own doc comment): both halves of that default are gated on\n // the same condition, not just the clear.\n if (notPrevented && props['clear-on-send'].value !== false) {\n tf.clear();\n autoResize.recompute();\n textareaRef.value?.focus();\n }\n }\n\n const composer = createComposerControl({\n disabled: isDisabled,\n loading: computed(() => Boolean(props.loading.value)),\n onSend: attemptSend,\n sendShortcut: props['send-shortcut'],\n value: tf.value,\n });\n\n onElement(textareaRef, (textareaEl) => {\n const unwireField = tf.wire(textareaEl);\n const unwireAutoResize = autoResize.wire(textareaEl);\n const handleKeydown = (e: KeyboardEvent) => composer.handleKeydown(e);\n\n textareaEl.addEventListener('keydown', handleKeydown);\n\n // Immediate fire for when the prop is already set on mount.\n props.ref.value?.(textareaEl);\n\n // Reactive watcher so that if props.ref is set *after* the inner <textarea> mounts\n // (e.g. a parent sets it via a ref callback after render), the new callback still\n // receives the live element.\n const refSub = watch(props.ref, (cb) => {\n cb?.(textareaEl);\n });\n\n return () => {\n textareaEl.removeEventListener('keydown', handleKeydown);\n unwireField();\n unwireAutoResize();\n refSub.dispose();\n props.ref.value?.(null);\n };\n });\n\n bind({\n attr: {\n error: errorAttr(tf.errorText),\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const counterClass = () => counterClassName(tf.counter?.value);\n const counterHidden = () => !tf.counter;\n const counterText = () => tf.counter?.value.counterText.replace(' / ', '/') ?? '';\n const helperHidden = () => !!tf.errorText.value || !tf.helperText.value;\n const errorHidden = () => !tf.errorText.value;\n\n return html`\n <div class=\"composer\" part=\"composer\">\n <textarea\n class=\"field\"\n part=\"field\"\n ref=\"${textareaRef}\"\n :rows=\"${() => props.rows.value ?? 1}\"\n :name=\"${() => props.name.value ?? ''}\"\n :placeholder=\"${() => props.placeholder.value ?? 'Message…'}\"\n :maxlength=\"${() => props.maxlength.value}\"\n ?disabled=\"${isDisabled}\"\n ?readonly=\"${() => Boolean(props.readonly.value)}\"\n ?required=\"${() => Boolean(props.required.value)}\"\n :value=\"${live(tf.value)}\"\n :aria-label=\"${() => props.label.value || 'Message'}\"\n :aria-keyshortcuts=\"${composer.keyShortcutsHint}\"\n :aria-describedby=\"${tf.ariaDescribedBy}\"\n :aria-errormessage=\"${tf.ariaErrorMessage}\"\n :aria-invalid=\"${tf.ariaInvalid}\"></textarea>\n <span class=\"${counterClass}\" aria-live=\"polite\" ?hidden=\"${counterHidden}\">${counterText}</span>\n <div id=\"${tf.assistiveId}\" class=\"helper-text\" aria-live=\"polite\" part=\"helper\" ?hidden=\"${helperHidden}\">\n ${() => tf.helperText.value}\n </div>\n <div id=\"${tf.errorId}\" class=\"helper-text\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n ${() => tf.errorText.value}\n </div>\n <div class=\"toolbar\" part=\"toolbar\">\n <div class=\"toolbar-start\" part=\"toolbar-start\">\n <slot name=\"prefix\"></slot>\n </div>\n <div class=\"toolbar-end\" part=\"toolbar-end\">\n <slot name=\"suffix\"></slot>\n <slot name=\"send\"></slot>\n ${() =>\n slots.has('send').value\n ? ''\n : html`<ore-button\n class=\"send-btn\"\n part=\"send-button\"\n type=\"button\"\n icon-only\n variant=\"solid\"\n :color=\"${() => props.color.value || 'primary'}\"\n :size=\"${fCtxProps.size}\"\n :label=\"${() => props['send-label'].value || DEFAULT_SEND_LABEL}\"\n ?loading=\"${() => Boolean(props.loading.value)}\"\n ?disabled=\"${() => !composer.canSend.value}\"\n @click=\"${(e: MouseEvent) => composer.send(e)}\">\n <ore-icon name=\"${() => props['send-icon'].value || SEND_ICON}\" size=\"16\"></ore-icon>\n </ore-button>`}\n </div>\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n disabledLoadingMixin,\n forcedColorsMixin,\n forcedColorsFocusMixin('.field'),\n sizeVariantMixin(MESSAGE_COMPOSER_SIZE_PRESET),\n componentStyles,\n ],\n});\n"],"mappings":"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"}