@vielzeug/refine 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/button.cjs +1 -1
- package/dist/button.cjs.map +1 -1
- package/dist/button.js +3 -3
- package/dist/button.js.map +1 -1
- package/dist/checkbox-group.cjs +7 -7
- package/dist/checkbox-group.cjs.map +1 -1
- package/dist/checkbox-group.js +35 -26
- package/dist/checkbox-group.js.map +1 -1
- package/dist/checkbox.cjs +3 -3
- package/dist/checkbox.cjs.map +1 -1
- package/dist/checkbox.js +24 -19
- package/dist/checkbox.js.map +1 -1
- package/dist/combobox.cjs +24 -24
- package/dist/combobox.cjs.map +1 -1
- package/dist/combobox.js +133 -129
- package/dist/combobox.js.map +1 -1
- package/dist/content/card/card.css.cjs +1 -1
- package/dist/content/card/card.css.cjs.map +1 -1
- package/dist/content/card/card.css.js +1 -1
- package/dist/content/card/card.css.js.map +1 -1
- package/dist/content/icon/icon.css.cjs +1 -1
- package/dist/content/icon/icon.css.cjs.map +1 -1
- package/dist/content/icon/icon.css.js +1 -1
- package/dist/content/icon/icon.css.js.map +1 -1
- package/dist/custom-elements.json +4711 -4209
- package/dist/feedback/toast/toast.css.cjs +1 -1
- package/dist/feedback/toast/toast.css.cjs.map +1 -1
- package/dist/feedback/toast/toast.css.js +1 -1
- package/dist/feedback/toast/toast.css.js.map +1 -1
- package/dist/headless/auto-resize.cjs +2 -0
- package/dist/headless/auto-resize.cjs.map +1 -0
- package/dist/headless/auto-resize.d.ts +29 -0
- package/dist/headless/auto-resize.d.ts.map +1 -0
- package/dist/headless/auto-resize.js +16 -0
- package/dist/headless/auto-resize.js.map +1 -0
- package/dist/headless/checkable.cjs +1 -1
- package/dist/headless/checkable.cjs.map +1 -1
- package/dist/headless/checkable.d.ts +25 -7
- package/dist/headless/checkable.d.ts.map +1 -1
- package/dist/headless/checkable.js +19 -14
- package/dist/headless/checkable.js.map +1 -1
- package/dist/headless/choice-field.cjs +1 -1
- package/dist/headless/choice-field.cjs.map +1 -1
- package/dist/headless/choice-field.d.ts +21 -0
- package/dist/headless/choice-field.d.ts.map +1 -1
- package/dist/headless/choice-field.js +27 -19
- package/dist/headless/choice-field.js.map +1 -1
- package/dist/headless/composer.cjs +2 -0
- package/dist/headless/composer.cjs.map +1 -0
- package/dist/headless/composer.d.ts +44 -0
- package/dist/headless/composer.d.ts.map +1 -0
- package/dist/headless/composer.js +21 -0
- package/dist/headless/composer.js.map +1 -0
- package/dist/headless/field-base.cjs +1 -1
- package/dist/headless/field-base.cjs.map +1 -1
- package/dist/headless/field-base.d.ts +97 -84
- package/dist/headless/field-base.d.ts.map +1 -1
- package/dist/headless/field-base.js +43 -32
- package/dist/headless/field-base.js.map +1 -1
- package/dist/headless/index.d.ts +3 -1
- package/dist/headless/index.d.ts.map +1 -1
- package/dist/headless/text-field.cjs +1 -1
- package/dist/headless/text-field.cjs.map +1 -1
- package/dist/headless/text-field.d.ts +40 -0
- package/dist/headless/text-field.d.ts.map +1 -1
- package/dist/headless/text-field.js +30 -25
- package/dist/headless/text-field.js.map +1 -1
- package/dist/headless.cjs +1 -1
- package/dist/headless.js +27 -25
- package/dist/index.cjs +1 -1
- package/dist/index.js +61 -60
- package/dist/input.cjs +9 -9
- package/dist/input.cjs.map +1 -1
- package/dist/input.js +49 -44
- package/dist/input.js.map +1 -1
- package/dist/inputs/button/button.css.cjs +1 -1
- package/dist/inputs/button/button.css.cjs.map +1 -1
- package/dist/inputs/button/button.css.js +1 -1
- package/dist/inputs/button/button.css.js.map +1 -1
- package/dist/inputs/checkbox/checkbox.css.cjs +1 -1
- package/dist/inputs/checkbox/checkbox.css.cjs.map +1 -1
- package/dist/inputs/checkbox/checkbox.css.js +1 -1
- package/dist/inputs/checkbox/checkbox.css.js.map +1 -1
- package/dist/inputs/checkbox/checkbox.d.ts +3 -0
- package/dist/inputs/checkbox/checkbox.d.ts.map +1 -1
- package/dist/inputs/checkbox-group/checkbox-group.css.cjs +1 -1
- package/dist/inputs/checkbox-group/checkbox-group.css.cjs.map +1 -1
- package/dist/inputs/checkbox-group/checkbox-group.css.js +1 -1
- package/dist/inputs/checkbox-group/checkbox-group.css.js.map +1 -1
- package/dist/inputs/combobox/combobox.d.ts +1 -0
- package/dist/inputs/combobox/combobox.d.ts.map +1 -1
- package/dist/inputs/combobox/combobox.types.d.ts +2 -0
- package/dist/inputs/combobox/combobox.types.d.ts.map +1 -1
- package/dist/inputs/file-input/file-input.css.cjs +1 -1
- package/dist/inputs/file-input/file-input.css.cjs.map +1 -1
- package/dist/inputs/file-input/file-input.css.js +1 -1
- package/dist/inputs/file-input/file-input.css.js.map +1 -1
- package/dist/inputs/index.d.ts +2 -0
- package/dist/inputs/index.d.ts.map +1 -1
- package/dist/inputs/input/input.css.cjs +1 -1
- package/dist/inputs/input/input.css.cjs.map +1 -1
- package/dist/inputs/input/input.css.js +1 -1
- package/dist/inputs/input/input.css.js.map +1 -1
- package/dist/inputs/input/input.d.ts.map +1 -1
- package/dist/inputs/message-composer/message-composer.css.cjs +2 -0
- package/dist/inputs/message-composer/message-composer.css.cjs.map +1 -0
- package/dist/inputs/message-composer/message-composer.css.js +6 -0
- package/dist/inputs/message-composer/message-composer.css.js.map +1 -0
- package/dist/inputs/message-composer/message-composer.d.ts +139 -0
- package/dist/inputs/message-composer/message-composer.d.ts.map +1 -0
- package/dist/inputs/otp-input/otp-input.css.cjs +1 -1
- package/dist/inputs/otp-input/otp-input.css.cjs.map +1 -1
- package/dist/inputs/otp-input/otp-input.css.js +1 -1
- package/dist/inputs/otp-input/otp-input.css.js.map +1 -1
- package/dist/inputs/radio/radio.css.cjs +1 -1
- package/dist/inputs/radio/radio.css.cjs.map +1 -1
- package/dist/inputs/radio/radio.css.js +1 -1
- package/dist/inputs/radio/radio.css.js.map +1 -1
- package/dist/inputs/radio-group/radio-group.css.cjs +1 -1
- package/dist/inputs/radio-group/radio-group.css.cjs.map +1 -1
- package/dist/inputs/radio-group/radio-group.css.js +1 -1
- package/dist/inputs/radio-group/radio-group.css.js.map +1 -1
- package/dist/inputs/rating/rating.css.cjs +1 -1
- package/dist/inputs/rating/rating.css.cjs.map +1 -1
- package/dist/inputs/rating/rating.css.js +1 -1
- package/dist/inputs/rating/rating.css.js.map +1 -1
- package/dist/inputs/shared/field-binding.cjs +1 -1
- package/dist/inputs/shared/field-binding.cjs.map +1 -1
- package/dist/inputs/shared/field-binding.d.ts +15 -0
- package/dist/inputs/shared/field-binding.d.ts.map +1 -1
- package/dist/inputs/shared/field-binding.js +4 -3
- package/dist/inputs/shared/field-binding.js.map +1 -1
- package/dist/inputs/shared/form-context.cjs.map +1 -1
- package/dist/inputs/shared/form-context.d.ts +6 -0
- package/dist/inputs/shared/form-context.d.ts.map +1 -1
- package/dist/inputs/shared/form-context.js.map +1 -1
- package/dist/inputs/slider/slider.css.cjs +1 -1
- package/dist/inputs/slider/slider.css.cjs.map +1 -1
- package/dist/inputs/slider/slider.css.js +1 -1
- package/dist/inputs/slider/slider.css.js.map +1 -1
- package/dist/inputs/switch/switch.css.cjs +1 -1
- package/dist/inputs/switch/switch.css.cjs.map +1 -1
- package/dist/inputs/switch/switch.css.js +1 -1
- package/dist/inputs/switch/switch.css.js.map +1 -1
- package/dist/inputs/textarea/textarea.css.cjs +1 -1
- package/dist/inputs/textarea/textarea.css.cjs.map +1 -1
- package/dist/inputs/textarea/textarea.css.js +1 -1
- package/dist/inputs/textarea/textarea.css.js.map +1 -1
- package/dist/inputs/textarea/textarea.d.ts.map +1 -1
- package/dist/layout/navbar/navbar.css.cjs +1 -1
- package/dist/layout/navbar/navbar.css.cjs.map +1 -1
- package/dist/layout/navbar/navbar.css.js +1 -1
- package/dist/layout/navbar/navbar.css.js.map +1 -1
- package/dist/layout/sidebar/sidebar.css.cjs +1 -1
- package/dist/layout/sidebar/sidebar.css.cjs.map +1 -1
- package/dist/layout/sidebar/sidebar.css.js +1 -1
- package/dist/layout/sidebar/sidebar.css.js.map +1 -1
- package/dist/message-composer.cjs +52 -0
- package/dist/message-composer.cjs.map +1 -0
- package/dist/message-composer.js +168 -0
- package/dist/message-composer.js.map +1 -0
- package/dist/ore/dist/base-element.cjs +1 -1
- package/dist/ore/dist/base-element.cjs.map +1 -1
- package/dist/ore/dist/base-element.js +13 -3
- package/dist/ore/dist/base-element.js.map +1 -1
- package/dist/ore/dist/forms/field.cjs +1 -1
- package/dist/ore/dist/forms/field.cjs.map +1 -1
- package/dist/ore/dist/forms/field.js +29 -22
- package/dist/ore/dist/forms/field.js.map +1 -1
- package/dist/ore/dist/runtime.cjs +1 -1
- package/dist/ore/dist/runtime.cjs.map +1 -1
- package/dist/ore/dist/runtime.js +3 -1
- package/dist/ore/dist/runtime.js.map +1 -1
- package/dist/overlay/menu/menu.css.cjs +1 -1
- package/dist/overlay/menu/menu.css.cjs.map +1 -1
- package/dist/overlay/menu/menu.css.js +1 -1
- package/dist/overlay/menu/menu.css.js.map +1 -1
- package/dist/radio-group.cjs +9 -9
- package/dist/radio-group.cjs.map +1 -1
- package/dist/radio-group.js +44 -38
- package/dist/radio-group.js.map +1 -1
- package/dist/radio.cjs +3 -3
- package/dist/radio.cjs.map +1 -1
- package/dist/radio.js +23 -24
- package/dist/radio.js.map +1 -1
- package/dist/refine.cjs +228 -181
- package/dist/refine.cjs.map +1 -1
- package/dist/refine.iife.js +228 -181
- package/dist/refine.iife.js.map +1 -1
- package/dist/refine.js +251 -204
- package/dist/refine.js.map +1 -1
- package/dist/select.cjs +31 -31
- package/dist/select.cjs.map +1 -1
- package/dist/select.js +125 -122
- package/dist/select.js.map +1 -1
- package/dist/shared/size-presets.cjs +1 -1
- package/dist/shared/size-presets.cjs.map +1 -1
- package/dist/shared/size-presets.d.ts +23 -0
- package/dist/shared/size-presets.d.ts.map +1 -1
- package/dist/shared/size-presets.js +17 -1
- package/dist/shared/size-presets.js.map +1 -1
- package/dist/styles/mixins/animation.css.cjs +0 -3
- package/dist/styles/mixins/animation.css.cjs.map +1 -1
- package/dist/styles/mixins/animation.css.d.ts +12 -4
- package/dist/styles/mixins/animation.css.d.ts.map +1 -1
- package/dist/styles/mixins/animation.css.js +0 -3
- package/dist/styles/mixins/animation.css.js.map +1 -1
- package/dist/styles/mixins/variants.css.cjs.map +1 -1
- package/dist/styles/mixins/variants.css.d.ts +7 -2
- package/dist/styles/mixins/variants.css.d.ts.map +1 -1
- package/dist/styles/mixins/variants.css.js.map +1 -1
- package/dist/styles/theme.css +341 -132
- package/dist/switch.cjs +3 -3
- package/dist/switch.cjs.map +1 -1
- package/dist/switch.js +17 -18
- package/dist/switch.js.map +1 -1
- package/dist/textarea.cjs +15 -15
- package/dist/textarea.cjs.map +1 -1
- package/dist/textarea.js +64 -60
- package/dist/textarea.js.map +1 -1
- package/package.json +21 -9
package/dist/switch.js
CHANGED
|
@@ -27,44 +27,43 @@ g(S, {
|
|
|
27
27
|
value: b.string("on")
|
|
28
28
|
},
|
|
29
29
|
setup(e) {
|
|
30
|
-
let t = x(), n = v(f), r = p(e, n), i =
|
|
30
|
+
let t = x(), n = v(f), r = p(e, n), i = l({
|
|
31
31
|
checked: e.checked,
|
|
32
32
|
clearIndeterminateFirst: !1,
|
|
33
33
|
disabled: r.disabled,
|
|
34
34
|
error: e.error,
|
|
35
|
-
getFormField: () => i,
|
|
36
35
|
helper: e.helper,
|
|
37
36
|
onToggle: (e) => {
|
|
38
|
-
|
|
37
|
+
i.triggerValidation("change"), t("change", e);
|
|
39
38
|
},
|
|
40
39
|
prefix: "switch",
|
|
41
40
|
signal: c(y),
|
|
42
41
|
validateOn: n?.validateOn,
|
|
43
42
|
value: e.value
|
|
44
43
|
});
|
|
45
|
-
i
|
|
46
|
-
disabled:
|
|
44
|
+
i.attachFormField(u({
|
|
45
|
+
disabled: i.disabled,
|
|
47
46
|
toFormValue: (e) => e,
|
|
48
|
-
value:
|
|
49
|
-
});
|
|
50
|
-
let { assistiveId:
|
|
47
|
+
value: i.checkableFormValue
|
|
48
|
+
}));
|
|
49
|
+
let { assistiveId: a, checked: o, disabled: s, errorText: h, handleClick: g, handleKeydown: b, helperText: S, labelId: C } = i;
|
|
51
50
|
return d(r.size, {
|
|
52
|
-
assistiveId:
|
|
53
|
-
checked:
|
|
54
|
-
disabled:
|
|
55
|
-
errorText:
|
|
56
|
-
handleClick:
|
|
57
|
-
handleKeydown:
|
|
58
|
-
helperText:
|
|
59
|
-
labelId:
|
|
51
|
+
assistiveId: a,
|
|
52
|
+
checked: o,
|
|
53
|
+
disabled: s,
|
|
54
|
+
errorText: h,
|
|
55
|
+
handleClick: g,
|
|
56
|
+
handleKeydown: b,
|
|
57
|
+
helperText: S,
|
|
58
|
+
labelId: C
|
|
60
59
|
}, "switch"), _`
|
|
61
60
|
<div class="switch-wrapper" part="switch">
|
|
62
61
|
<div class="switch-track" part="track">
|
|
63
62
|
<div class="switch-thumb" part="thumb"></div>
|
|
64
63
|
</div>
|
|
65
64
|
</div>
|
|
66
|
-
<span class="label" part="label" id="${
|
|
67
|
-
${m(
|
|
65
|
+
<span class="label" part="label" id="${C}"><slot></slot></span>
|
|
66
|
+
${m(a, h, S)}
|
|
68
67
|
`;
|
|
69
68
|
},
|
|
70
69
|
styles: [
|
package/dist/switch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"switch.js","names":[],"sources":["../src/inputs/switch/switch.ts"],"sourcesContent":["import { define, html, inject, prop, onCleanup, useEmit } from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore/forms';\n\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\n\nimport { type CheckableChangePayload, lifecycleSignal, createCheckable } from '../../headless';\nimport { disablableBundle, sizableBundle, SWITCH_SIZE_PRESET, themableBundle } from '../../shared';\nimport { colorThemeMixin, disabledStateMixin, forcedColorsFormControlMixin, sizeVariantMixin } from '../../styles';\nimport { applyCheckableBinding } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './switch.css?inline';\n\nexport type OreSwitchEvents = {\n change: CheckableChangePayload;\n};\n\nexport type OreSwitchProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the switch */\n helper?: string;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A toggle switch component for binary on/off states.\n *\n * @element ore-switch\n *\n * @attr {boolean} checked - Checked/on state\n * @attr {boolean} disabled - Disable switch interaction\n * @attr {string} value - Field value\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Switch size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the switch\n *\n * @fires change - Emitted when switch is toggled. detail: { checked: boolean, value: string, originalEvent?: Event }\n *\n * @slot - Switch label text\n *\n * @cssprop --switch-width - Track width\n * @cssprop --switch-height - Track height\n * @cssprop --switch-track-bg - Inactive track background color\n * @cssprop --switch-checked-bg - Active/checked track background color\n * @cssprop --switch-thumb-bg - Thumb background color\n * @cssprop --switch-font-size - Label font size\n * @part switch - The switch wrapper element\n * @part track - The switch track element\n * @part thumb - The switch thumb element\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-switch name=\"notifications\" checked color=\"primary\">Enable notifications</ore-switch>\n * <ore-switch name=\"darkMode\" size=\"sm\">Dark mode</ore-switch>\n * <ore-switch disabled helper=\"Contact admin to change\">Admin only</ore-switch>\n * ```\n */\nexport const SWITCH_TAG = 'ore-switch' as const;\ndefine<OreSwitchProps>(SWITCH_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n name: prop.string(),\n value: prop.string('on'),\n },\n setup(props) {\n const emit = useEmit<OreSwitchEvents>();\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n
|
|
1
|
+
{"version":3,"file":"switch.js","names":[],"sources":["../src/inputs/switch/switch.ts"],"sourcesContent":["import { define, html, inject, prop, onCleanup, useEmit } from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore/forms';\n\nimport type { CheckableProps, ComponentSize, ThemeColor } from '../../types';\n\nimport { type CheckableChangePayload, lifecycleSignal, createCheckable } from '../../headless';\nimport { disablableBundle, sizableBundle, SWITCH_SIZE_PRESET, themableBundle } from '../../shared';\nimport { colorThemeMixin, disabledStateMixin, forcedColorsFormControlMixin, sizeVariantMixin } from '../../styles';\nimport { applyCheckableBinding } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport { renderHelperRegion } from '../shared/templates';\nimport componentStyles from './switch.css?inline';\n\nexport type OreSwitchEvents = {\n change: CheckableChangePayload;\n};\n\nexport type OreSwitchProps = CheckableProps & {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Error message (marks field as invalid) */\n error?: string;\n /** Helper text displayed below the switch */\n helper?: string;\n /** Component size */\n size?: ComponentSize;\n};\n\n/**\n * A toggle switch component for binary on/off states.\n *\n * @element ore-switch\n *\n * @attr {boolean} checked - Checked/on state\n * @attr {boolean} disabled - Disable switch interaction\n * @attr {string} value - Field value\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Switch size: 'sm' | 'md' | 'lg'\n * @attr {string} error - Error message (marks field as invalid)\n * @attr {string} helper - Helper text displayed below the switch\n *\n * @fires change - Emitted when switch is toggled. detail: { checked: boolean, value: string, originalEvent?: Event }\n *\n * @slot - Switch label text\n *\n * @cssprop --switch-width - Track width\n * @cssprop --switch-height - Track height\n * @cssprop --switch-track-bg - Inactive track background color\n * @cssprop --switch-checked-bg - Active/checked track background color\n * @cssprop --switch-thumb-bg - Thumb background color\n * @cssprop --switch-font-size - Label font size\n * @part switch - The switch wrapper element\n * @part track - The switch track element\n * @part thumb - The switch thumb element\n * @part label - The label element\n * @part helper-text - The helper/error text element\n *\n * @example\n * ```html\n * <ore-switch name=\"notifications\" checked color=\"primary\">Enable notifications</ore-switch>\n * <ore-switch name=\"darkMode\" size=\"sm\">Dark mode</ore-switch>\n * <ore-switch disabled helper=\"Contact admin to change\">Admin only</ore-switch>\n * ```\n */\nexport const SWITCH_TAG = 'ore-switch' as const;\ndefine<OreSwitchProps>(SWITCH_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n checked: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n name: prop.string(),\n value: prop.string('on'),\n },\n setup(props) {\n const emit = useEmit<OreSwitchEvents>();\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const checkable = createCheckable({\n checked: props.checked,\n clearIndeterminateFirst: false,\n disabled: fCtxProps.disabled,\n error: props.error,\n helper: props.helper,\n onToggle: (payload) => {\n checkable.triggerValidation('change');\n emit('change', payload);\n },\n prefix: 'switch',\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n checkable.attachFormField(\n useField<string | null>({\n disabled: checkable.disabled,\n toFormValue: (v) => v,\n value: checkable.checkableFormValue,\n }),\n );\n\n const { assistiveId, checked, disabled, errorText, handleClick, handleKeydown, helperText, labelId } = checkable;\n\n applyCheckableBinding(\n fCtxProps.size,\n { assistiveId, checked, disabled, errorText, handleClick, handleKeydown, helperText, labelId },\n 'switch',\n );\n\n return html`\n <div class=\"switch-wrapper\" part=\"switch\">\n <div class=\"switch-track\" part=\"track\">\n <div class=\"switch-thumb\" part=\"thumb\"></div>\n </div>\n </div>\n <span class=\"label\" part=\"label\" id=\"${labelId}\"><slot></slot></span>\n ${renderHelperRegion(assistiveId, errorText, helperText)}\n `;\n },\n styles: [\n colorThemeMixin,\n forcedColorsFormControlMixin,\n disabledStateMixin,\n sizeVariantMixin(SWITCH_SIZE_PRESET),\n componentStyles,\n ],\n});\n"],"mappings":";;;;;;;;;;;;;;;AAmEA,IAAa,IAAa;AAC1B,EAAuB,GAAY;CACjC,gBAAgB;CAChB,OAAO;EACL,GAAG;EACH,GAAG;EACH,GAAG;EACH,SAAS,EAAK,KAAK,EAAK;EACxB,OAAO,EAAK,OAAO;EACnB,QAAQ,EAAK,OAAO;EACpB,MAAM,EAAK,OAAO;EAClB,OAAO,EAAK,OAAO,IAAI;CACzB;CACA,MAAM,GAAO;EACX,IAAM,IAAO,EAAyB,GAEhC,IAAU,EAAO,CAAQ,GACzB,IAAY,EAAe,GAAO,CAAO,GAEzC,IAAY,EAAgB;GAChC,SAAS,EAAM;GACf,yBAAyB;GACzB,UAAU,EAAU;GACpB,OAAO,EAAM;GACb,QAAQ,EAAM;GACd,WAAW,MAAY;IAErB,AADA,EAAU,kBAAkB,QAAQ,GACpC,EAAK,UAAU,CAAO;GACxB;GACA,QAAQ;GACR,QAAQ,EAAgB,CAAS;GACjC,YAAY,GAAS;GACrB,OAAO,EAAM;EACf,CAAC;EAED,EAAU,gBACR,EAAwB;GACtB,UAAU,EAAU;GACpB,cAAc,MAAM;GACpB,OAAO,EAAU;EACnB,CAAC,CACH;EAEA,IAAM,EAAE,gBAAa,YAAS,aAAU,cAAW,gBAAa,kBAAe,eAAY,eAAY;EAQvG,OANA,EACE,EAAU,MACV;GAAE;GAAa;GAAS;GAAU;GAAW;GAAa;GAAe;GAAY;EAAQ,GAC7F,QACF,GAEO,CAAI;;;;;;6CAM8B,EAAQ;QAC7C,EAAmB,GAAa,GAAW,CAAU,EAAE;;CAE7D;CACA,QAAQ;EACN;EACA;EACA;EACA,EAAiB,CAAkB;EACnC;CACF;AACF,CAAC"}
|
package/dist/textarea.cjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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"),
|
|
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/auto-resize.cjs"),c=require("./headless/field-base.cjs"),l=require("./headless/text-field.cjs"),u=require("./ore/dist/forms/field.cjs");require("./ore/dist/forms.cjs");const d=require("./inputs/shared/field-binding.cjs"),f=require("./inputs/shared/form-context.cjs"),p=require("./inputs/textarea/textarea.css.cjs");let m=require("@vielzeug/ore"),h=require("@vielzeug/ripple");var g=`ore-textarea`;(0,m.define)(g,{formAssociated:!0,props:{...i.themableBundle,...i.sizableBundle,...i.disablableBundle,...i.roundableBundle,"auto-resize":m.prop.bool(!1),error:m.prop.string(),fullwidth:m.prop.bool(!1),helper:m.prop.string(),label:m.prop.string(),"label-placement":m.prop.oneOf([`inset`,`outside`],`inset`),maxlength:m.prop.json(void 0),name:m.prop.string(),"no-resize":m.prop.bool(!1),placeholder:m.prop.string(),readonly:m.prop.bool(!1),ref:m.prop.json(void 0),required:m.prop.bool(!1),resize:m.prop.string(),rows:m.prop.json(void 0),value:m.prop.string(),variant:m.prop.string()},setup(t){let n=(0,m.useEmit)(),r=m.watchEffect,i=(0,m.inject)(f.FORM_CTX),a=f.useFormContext(t,i),p=(0,m.ref)(),g=s.createAutoResize({enabled:t[`auto-resize`]}),_=o.lifecycleSignal(m.onCleanup),v=l.createTextField({disabled:a.disabled,error:t.error,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:`textarea`,readonly:t.readonly,required:t.required,signal:_,validateOn:i?.validateOn,value:t.value});v.attachFormField(u.useField({disabled:v.disabled,onReset:()=>{v.reset(),requestAnimationFrame(()=>g.recompute())},toFormValue:e=>e,validationMessage:v.validationMessage,validity:v.validity,value:v.value}));let{ariaDescribedBy:y,ariaErrorMessage:b,ariaInvalid:x,ariaLabelledBy:S,assistiveId:C,counter:w,errorId:T,errorText:E,fieldId:D,helperText:O,labelId:k,labelVisible:A}=v;return(0,m.onElement)(p,e=>{let n=v.wire(e),i=g.wire(e);t.ref.value?.(e);let a=(0,h.watch)(t.ref,t=>{t?.(e)}),o=r(()=>{e.style.resize=t[`auto-resize`].value||t[`no-resize`].value?`none`:t.resize.value||`vertical`,requestAnimationFrame(()=>g.recompute())});return()=>{a.dispose(),t.ref.value?.(null),n(),i(),o()}}),(0,m.bind)({attr:{error:d.errorAttr(E),size:a.size,variant:a.variant}}),m.html`
|
|
2
2
|
<div class="textarea-wrapper" part="wrapper">
|
|
3
|
-
<label class="label" part="label" for="${
|
|
3
|
+
<label class="label" part="label" for="${D}" id="${k}" ?hidden="${()=>!A.value}"
|
|
4
4
|
>${t.label}</label
|
|
5
5
|
>
|
|
6
6
|
<div class="field" part="field">
|
|
7
7
|
<textarea
|
|
8
8
|
part="textarea"
|
|
9
|
-
ref="${
|
|
10
|
-
id="${
|
|
9
|
+
ref="${p}"
|
|
10
|
+
id="${D}"
|
|
11
11
|
:name="${t.name}"
|
|
12
12
|
:placeholder="${t.placeholder}"
|
|
13
13
|
:rows="${t.rows}"
|
|
@@ -15,19 +15,19 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
15
15
|
?disabled="${t.disabled}"
|
|
16
16
|
?readonly="${t.readonly}"
|
|
17
17
|
?required="${t.required}"
|
|
18
|
-
:value="${e.live(
|
|
19
|
-
:aria-describedby="${
|
|
20
|
-
:aria-errormessage="${
|
|
21
|
-
:aria-invalid="${
|
|
22
|
-
:aria-labelledby="${
|
|
18
|
+
:value="${e.live(v.value)}"
|
|
19
|
+
:aria-describedby="${y}"
|
|
20
|
+
:aria-errormessage="${b}"
|
|
21
|
+
:aria-invalid="${x}"
|
|
22
|
+
:aria-labelledby="${S}"></textarea>
|
|
23
23
|
</div>
|
|
24
|
-
<span class="${()=>
|
|
25
|
-
<div id="${
|
|
26
|
-
${()=>
|
|
24
|
+
<span class="${()=>c.counterClassName(w?.value)}" aria-live="polite" ?hidden="${()=>!w}">${()=>w?.value.counterText.replace(` / `,`/`)??``}</span>
|
|
25
|
+
<div id="${C}" class="helper-text" aria-live="polite" part="helper" ?hidden="${()=>!!E.value||!O.value}">
|
|
26
|
+
${()=>O.value}
|
|
27
27
|
</div>
|
|
28
|
-
<div id="${
|
|
29
|
-
${()=>
|
|
28
|
+
<div id="${T}" class="helper-text" role="alert" part="error" ?hidden="${()=>!E.value}">
|
|
29
|
+
${()=>E.value}
|
|
30
30
|
</div>
|
|
31
31
|
</div>
|
|
32
|
-
`},shadow:{delegatesFocus:!0},styles:[...r.fieldMixins,t.sizeVariantMixin(a.TEXTAREA_SIZE_PRESET),n.forcedColorsFocusMixin(`textarea`),
|
|
32
|
+
`},shadow:{delegatesFocus:!0},styles:[...r.fieldMixins,t.sizeVariantMixin(a.TEXTAREA_SIZE_PRESET),n.forcedColorsFocusMixin(`textarea`),p.default]}),exports.TEXTAREA_TAG=g;
|
|
33
33
|
//# sourceMappingURL=textarea.cjs.map
|
package/dist/textarea.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.cjs","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import { define, html, inject, prop, ref, bind, onCleanup, onElement, useEmit, watchEffect } from '@vielzeug/ore';\nimport { live } from '@vielzeug/ore/directives';\nimport { useField } from '@vielzeug/ore/forms';\nimport { watch as rippleWatch } from '@vielzeug/ripple';\n\nimport type { TextFieldProps } from '../../shared';\nimport type { VisualVariant } from '../../types';\n\nimport { lifecycleSignal, createTextField } from '../../headless';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport { fieldMixins, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './textarea.css?inline';\n\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: { originalEvent: Event; value: string };\n input: { originalEvent: Event; value: string };\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /** Maximum character count; shows a counter when set */\n maxlength?: number;\n /** Disable a manual resize handle */\n 'no-resize'?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw element.\n * Set as a JS property: `bitTextarea.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Resize direction override */\n resize?: 'none' | 'horizontal' | 'both' | 'vertical';\n /** Number of visible text rows */\n rows?: number;\n};\n\n/**\n * A multi-line text input with label, helper text, character counter, and auto-resize.\n *\n * @element ore-textarea\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {number} rows - Visible row count\n * @attr {number} maxlength - Max character count (shows counter)\n * @attr {string} helper - Helper text below the textarea\n * @attr {string} error - Error message\n * @attr {boolean} disabled - Disable interaction\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Required field\n * @attr {boolean} no-resize - Disable manual resize\n * @attr {boolean} auto-resize - Grow with content\n * @attr {string} resize - Resize direction: 'none' | 'horizontal' | 'both' | 'vertical'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Fired on every keystroke with current value. detail: { value: string; originalEvent: Event }\n * @fires change - Fired on blur with changed value. detail: { value: string; originalEvent: Event }\n *\n * @slot helper - Complex helper content\n *\n * @cssprop --textarea-bg - Background color\n * @cssprop --textarea-border-color - Border color\n * @cssprop --textarea-placeholder-color - Placeholder text color\n * @cssprop --textarea-radius - Border radius\n * @cssprop --textarea-padding - Inner padding (block inline)\n * @cssprop --textarea-gap - Gap between label and field\n * @cssprop --textarea-font-size - Font size\n * @cssprop --textarea-min-height - Minimum field height\n * @cssprop --textarea-max-height - Maximum field height (none = unlimited)\n * @cssprop --textarea-resize - CSS resize direction ('vertical' | 'horizontal' | 'both' | 'none')\n * @cssprop --textarea-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --textarea-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --textarea-focus-bg - Field background when focused (flat variant)\n * @cssprop --textarea-focus-border-color - Field border when focused (flat variant)\n *\n * @part wrapper - Outer wrapper element.\n * @part label - Label element.\n * @part field - Field container.\n * @part textarea - The native `<textarea>` element.\n * @part helper - The helper text element.\n * @part error - The error text element (`role=\"alert\"`).\n *\n * @example\n * ```html\n * <ore-textarea></ore-textarea>\n * ```\n */\nexport const TEXTAREA_TAG = 'ore-textarea' as const;\ndefine<OreTextareaProps>(TEXTAREA_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n 'auto-resize': prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n 'no-resize': prop.bool(false),\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 resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const emit = useEmit<OreTextareaEvents>();\n const watch = watchEffect;\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const textareaRef = ref<HTMLTextAreaElement>();\n\n const autoGrow = () => {\n if (!props['auto-resize'].value || !textareaRef.value) return;\n\n const textareaEl = textareaRef.value;\n\n textareaEl.style.height = 'auto';\n textareaEl.style.height = `${textareaEl.scrollHeight}px`;\n };\n\n const abortSignal = lifecycleSignal(onCleanup);\n let _formField: { reportValidity(): void } | null = null;\n const tf = createTextField({\n disabled: fCtxProps.disabled,\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onBeforeInput: autoGrow,\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: 'textarea',\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string>({ disabled: tf.disabled, toFormValue: (v) => v, value: tf.value });\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n counter,\n errorId,\n errorText,\n fieldId: textareaId,\n helperText,\n labelId,\n labelVisible,\n } = tf;\n\n onElement(textareaRef, (textareaEl) => {\n const unwireEl = tf.wire(textareaEl);\n\n props.ref.value?.(textareaEl);\n\n const sub = rippleWatch(props.ref, (cb) => {\n cb?.(textareaEl);\n });\n\n const stopLayoutEffect = watch(() => {\n textareaEl.style.resize =\n props['auto-resize'].value || props['no-resize'].value ? 'none' : props.resize.value || 'vertical';\n\n if (props['auto-resize'].value) {\n requestAnimationFrame(autoGrow);\n }\n });\n\n return () => {\n sub.dispose();\n props.ref.value?.(null);\n unwireEl();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: () => errorText.value || undefined,\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const counterClass = () =>\n counter?.value.counterAtLimit\n ? 'counter at-limit'\n : counter?.value.counterNearLimit\n ? 'counter near-limit'\n : 'counter';\n const counterHidden = () => !counter;\n const counterText = () => counter?.value.counterText.replace(' / ', '/') ?? '';\n const helperHidden = () => !!errorText.value || !helperText.value;\n const errorHidden = () => !errorText.value;\n\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <label class=\"label\" part=\"label\" for=\"${textareaId}\" id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\"\n >${props.label}</label\n >\n <div class=\"field\" part=\"field\">\n <textarea\n part=\"textarea\"\n ref=\"${textareaRef}\"\n id=\"${textareaId}\"\n :name=\"${props.name}\"\n :placeholder=\"${props.placeholder}\"\n :rows=\"${props.rows}\"\n :maxlength=\"${props.maxlength}\"\n ?disabled=\"${props.disabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n :value=\"${live(tf.value)}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n :aria-errormessage=\"${ariaErrorMessage}\"\n :aria-invalid=\"${ariaInvalid}\"\n :aria-labelledby=\"${ariaLabelledBy}\"></textarea>\n </div>\n <span class=\"${counterClass}\" aria-live=\"polite\" ?hidden=\"${counterHidden}\">${counterText}</span>\n <div id=\"${assistiveId}\" class=\"helper-text\" aria-live=\"polite\" part=\"helper\" ?hidden=\"${helperHidden}\">\n ${() => helperText.value}\n </div>\n <div id=\"${errorId}\" class=\"helper-text\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n ${() => errorText.value}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [...fieldMixins, sizeVariantMixin(TEXTAREA_SIZE_PRESET), forcedColorsFocusMixin('textarea'), componentStyles],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textarea.cjs","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import { define, html, inject, prop, ref, bind, onCleanup, onElement, useEmit, watchEffect } from '@vielzeug/ore';\nimport { live } from '@vielzeug/ore/directives';\nimport { useField } from '@vielzeug/ore/forms';\nimport { watch as rippleWatch } from '@vielzeug/ripple';\n\nimport type { TextFieldProps } from '../../shared';\nimport type { VisualVariant } from '../../types';\n\nimport { counterClassName, createAutoResize, lifecycleSignal, createTextField } from '../../headless';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport { fieldMixins, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { errorAttr } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './textarea.css?inline';\n\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: { originalEvent: Event; value: string };\n input: { originalEvent: Event; value: string };\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /** Maximum character count; shows a counter when set */\n maxlength?: number;\n /** Disable a manual resize handle */\n 'no-resize'?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw element.\n * Set as a JS property: `bitTextarea.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Resize direction override */\n resize?: 'none' | 'horizontal' | 'both' | 'vertical';\n /** Number of visible text rows */\n rows?: number;\n};\n\n/**\n * A multi-line text input with label, helper text, character counter, and auto-resize.\n *\n * @element ore-textarea\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {number} rows - Visible row count\n * @attr {number} maxlength - Max character count (shows counter)\n * @attr {string} helper - Helper text below the textarea\n * @attr {string} error - Error message\n * @attr {boolean} disabled - Disable interaction\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Required field\n * @attr {boolean} no-resize - Disable manual resize\n * @attr {boolean} auto-resize - Grow with content\n * @attr {string} resize - Resize direction: 'none' | 'horizontal' | 'both' | 'vertical'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Fired on every keystroke with current value. detail: { value: string; originalEvent: Event }\n * @fires change - Fired on blur with changed value. detail: { value: string; originalEvent: Event }\n *\n * @slot helper - Complex helper content\n *\n * @cssprop --textarea-bg - Background color\n * @cssprop --textarea-border-color - Border color\n * @cssprop --textarea-placeholder-color - Placeholder text color\n * @cssprop --textarea-radius - Border radius\n * @cssprop --textarea-padding - Inner padding (block inline)\n * @cssprop --textarea-gap - Gap between label and field\n * @cssprop --textarea-font-size - Font size\n * @cssprop --textarea-min-height - Minimum field height\n * @cssprop --textarea-max-height - Maximum field height (none = unlimited)\n * @cssprop --textarea-resize - CSS resize direction ('vertical' | 'horizontal' | 'both' | 'none')\n * @cssprop --textarea-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --textarea-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --textarea-focus-bg - Field background when focused (flat variant)\n * @cssprop --textarea-focus-border-color - Field border when focused (flat variant)\n *\n * @part wrapper - Outer wrapper element.\n * @part label - Label element.\n * @part field - Field container.\n * @part textarea - The native `<textarea>` element.\n * @part helper - The helper text element.\n * @part error - The error text element (`role=\"alert\"`).\n *\n * @example\n * ```html\n * <ore-textarea></ore-textarea>\n * ```\n */\nexport const TEXTAREA_TAG = 'ore-textarea' as const;\ndefine<OreTextareaProps>(TEXTAREA_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n 'auto-resize': prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n 'no-resize': prop.bool(false),\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 resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const emit = useEmit<OreTextareaEvents>();\n const watch = watchEffect;\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: fCtxProps.disabled,\n error: props.error,\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: 'textarea',\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: () => {\n tf.reset();\n requestAnimationFrame(() => autoResize.recompute());\n },\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 counter,\n errorId,\n errorText,\n fieldId: textareaId,\n helperText,\n labelId,\n labelVisible,\n } = tf;\n\n onElement(textareaRef, (textareaEl) => {\n const unwireEl = tf.wire(textareaEl);\n const unwireAutoResize = autoResize.wire(textareaEl);\n\n props.ref.value?.(textareaEl);\n\n const sub = rippleWatch(props.ref, (cb) => {\n cb?.(textareaEl);\n });\n\n const stopLayoutEffect = watch(() => {\n textareaEl.style.resize =\n props['auto-resize'].value || props['no-resize'].value ? 'none' : props.resize.value || 'vertical';\n\n // Deferred a frame: on mount (or right after `auto-resize` flips true) the browser\n // hasn't necessarily finished laying out the textarea yet, so `scrollHeight` read\n // synchronously here could be stale.\n requestAnimationFrame(() => autoResize.recompute());\n });\n\n return () => {\n sub.dispose();\n props.ref.value?.(null);\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const counterClass = () => counterClassName(counter?.value);\n const counterHidden = () => !counter;\n const counterText = () => counter?.value.counterText.replace(' / ', '/') ?? '';\n const helperHidden = () => !!errorText.value || !helperText.value;\n const errorHidden = () => !errorText.value;\n\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <label class=\"label\" part=\"label\" for=\"${textareaId}\" id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\"\n >${props.label}</label\n >\n <div class=\"field\" part=\"field\">\n <textarea\n part=\"textarea\"\n ref=\"${textareaRef}\"\n id=\"${textareaId}\"\n :name=\"${props.name}\"\n :placeholder=\"${props.placeholder}\"\n :rows=\"${props.rows}\"\n :maxlength=\"${props.maxlength}\"\n ?disabled=\"${props.disabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n :value=\"${live(tf.value)}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n :aria-errormessage=\"${ariaErrorMessage}\"\n :aria-invalid=\"${ariaInvalid}\"\n :aria-labelledby=\"${ariaLabelledBy}\"></textarea>\n </div>\n <span class=\"${counterClass}\" aria-live=\"polite\" ?hidden=\"${counterHidden}\">${counterText}</span>\n <div id=\"${assistiveId}\" class=\"helper-text\" aria-live=\"polite\" part=\"helper\" ?hidden=\"${helperHidden}\">\n ${() => helperText.value}\n </div>\n <div id=\"${errorId}\" class=\"helper-text\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n ${() => errorText.value}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [...fieldMixins, sizeVariantMixin(TEXTAREA_SIZE_PRESET), forcedColorsFocusMixin('textarea'), componentStyles],\n});\n"],"mappings":"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"}
|
package/dist/textarea.js
CHANGED
|
@@ -6,54 +6,51 @@ import { fieldMixins as r } from "./styles/index.js";
|
|
|
6
6
|
import { disablableBundle as i, roundableBundle as a, sizableBundle as o, themableBundle as s } from "./shared/prop-bundles.js";
|
|
7
7
|
import { TEXTAREA_SIZE_PRESET as c } from "./shared/size-presets.js";
|
|
8
8
|
import { lifecycleSignal as l } from "./headless/ore.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { createAutoResize as u } from "./headless/auto-resize.js";
|
|
10
|
+
import { counterClassName as d } from "./headless/field-base.js";
|
|
11
|
+
import { createTextField as f } from "./headless/text-field.js";
|
|
12
|
+
import { useField as p } from "./ore/dist/forms/field.js";
|
|
11
13
|
import "./ore/dist/forms.js";
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import {
|
|
14
|
+
import { errorAttr as m } from "./inputs/shared/field-binding.js";
|
|
15
|
+
import { FORM_CTX as h, useFormContext as g } from "./inputs/shared/form-context.js";
|
|
16
|
+
import _ from "./inputs/textarea/textarea.css.js";
|
|
17
|
+
import { bind as v, define as y, html as b, inject as x, onCleanup as S, onElement as C, prop as w, ref as T, useEmit as E, watchEffect as D } from "@vielzeug/ore";
|
|
18
|
+
import { watch as O } from "@vielzeug/ripple";
|
|
16
19
|
//#region src/inputs/textarea/textarea.ts
|
|
17
|
-
var
|
|
18
|
-
|
|
20
|
+
var k = "ore-textarea";
|
|
21
|
+
y(k, {
|
|
19
22
|
formAssociated: !0,
|
|
20
23
|
props: {
|
|
21
24
|
...s,
|
|
22
25
|
...o,
|
|
23
26
|
...i,
|
|
24
27
|
...a,
|
|
25
|
-
"auto-resize":
|
|
26
|
-
error:
|
|
27
|
-
fullwidth:
|
|
28
|
-
helper:
|
|
29
|
-
label:
|
|
30
|
-
"label-placement":
|
|
31
|
-
maxlength:
|
|
32
|
-
name:
|
|
33
|
-
"no-resize":
|
|
34
|
-
placeholder:
|
|
35
|
-
readonly:
|
|
36
|
-
ref:
|
|
37
|
-
required:
|
|
38
|
-
resize:
|
|
39
|
-
rows:
|
|
40
|
-
value:
|
|
41
|
-
variant:
|
|
28
|
+
"auto-resize": w.bool(!1),
|
|
29
|
+
error: w.string(),
|
|
30
|
+
fullwidth: w.bool(!1),
|
|
31
|
+
helper: w.string(),
|
|
32
|
+
label: w.string(),
|
|
33
|
+
"label-placement": w.oneOf(["inset", "outside"], "inset"),
|
|
34
|
+
maxlength: w.json(void 0),
|
|
35
|
+
name: w.string(),
|
|
36
|
+
"no-resize": w.bool(!1),
|
|
37
|
+
placeholder: w.string(),
|
|
38
|
+
readonly: w.bool(!1),
|
|
39
|
+
ref: w.json(void 0),
|
|
40
|
+
required: w.bool(!1),
|
|
41
|
+
resize: w.string(),
|
|
42
|
+
rows: w.json(void 0),
|
|
43
|
+
value: w.string(),
|
|
44
|
+
variant: w.string()
|
|
42
45
|
},
|
|
43
46
|
setup(t) {
|
|
44
|
-
let n =
|
|
45
|
-
if (!t["auto-resize"].value || !o.value) return;
|
|
46
|
-
let e = o.value;
|
|
47
|
-
e.style.height = "auto", e.style.height = `${e.scrollHeight}px`;
|
|
48
|
-
}, c = l(y), m = null, g = u({
|
|
47
|
+
let n = E(), r = D, i = x(h), a = g(t, i), o = T(), s = u({ enabled: t["auto-resize"] }), c = l(S), _ = f({
|
|
49
48
|
disabled: a.disabled,
|
|
50
49
|
error: t.error,
|
|
51
|
-
getFormField: () => m,
|
|
52
50
|
helper: t.helper,
|
|
53
51
|
label: t.label,
|
|
54
52
|
labelPlacement: t["label-placement"],
|
|
55
53
|
maxLength: t.maxlength,
|
|
56
|
-
onBeforeInput: s,
|
|
57
54
|
onChange: (e, t) => {
|
|
58
55
|
n("change", {
|
|
59
56
|
originalEvent: e,
|
|
@@ -67,41 +64,48 @@ g(E, {
|
|
|
67
64
|
});
|
|
68
65
|
},
|
|
69
66
|
prefix: "textarea",
|
|
67
|
+
readonly: t.readonly,
|
|
68
|
+
required: t.required,
|
|
70
69
|
signal: c,
|
|
71
70
|
validateOn: i?.validateOn,
|
|
72
71
|
value: t.value
|
|
73
72
|
});
|
|
74
|
-
|
|
75
|
-
disabled:
|
|
73
|
+
_.attachFormField(p({
|
|
74
|
+
disabled: _.disabled,
|
|
75
|
+
onReset: () => {
|
|
76
|
+
_.reset(), requestAnimationFrame(() => s.recompute());
|
|
77
|
+
},
|
|
76
78
|
toFormValue: (e) => e,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
validationMessage: _.validationMessage,
|
|
80
|
+
validity: _.validity,
|
|
81
|
+
value: _.value
|
|
82
|
+
}));
|
|
83
|
+
let { ariaDescribedBy: y, ariaErrorMessage: w, ariaInvalid: k, ariaLabelledBy: A, assistiveId: j, counter: M, errorId: N, errorText: P, fieldId: F, helperText: I, labelId: L, labelVisible: R } = _;
|
|
84
|
+
return C(o, (e) => {
|
|
85
|
+
let n = _.wire(e), i = s.wire(e);
|
|
82
86
|
t.ref.value?.(e);
|
|
83
|
-
let
|
|
87
|
+
let a = O(t.ref, (t) => {
|
|
84
88
|
t?.(e);
|
|
85
|
-
}),
|
|
86
|
-
e.style.resize = t["auto-resize"].value || t["no-resize"].value ? "none" : t.resize.value || "vertical",
|
|
89
|
+
}), o = r(() => {
|
|
90
|
+
e.style.resize = t["auto-resize"].value || t["no-resize"].value ? "none" : t.resize.value || "vertical", requestAnimationFrame(() => s.recompute());
|
|
87
91
|
});
|
|
88
92
|
return () => {
|
|
89
|
-
|
|
93
|
+
a.dispose(), t.ref.value?.(null), n(), i(), o();
|
|
90
94
|
};
|
|
91
|
-
}),
|
|
92
|
-
error: ()
|
|
95
|
+
}), v({ attr: {
|
|
96
|
+
error: m(P),
|
|
93
97
|
size: a.size,
|
|
94
98
|
variant: a.variant
|
|
95
|
-
} }),
|
|
99
|
+
} }), b`
|
|
96
100
|
<div class="textarea-wrapper" part="wrapper">
|
|
97
|
-
<label class="label" part="label" for="${
|
|
101
|
+
<label class="label" part="label" for="${F}" id="${L}" ?hidden="${() => !R.value}"
|
|
98
102
|
>${t.label}</label
|
|
99
103
|
>
|
|
100
104
|
<div class="field" part="field">
|
|
101
105
|
<textarea
|
|
102
106
|
part="textarea"
|
|
103
107
|
ref="${o}"
|
|
104
|
-
id="${
|
|
108
|
+
id="${F}"
|
|
105
109
|
:name="${t.name}"
|
|
106
110
|
:placeholder="${t.placeholder}"
|
|
107
111
|
:rows="${t.rows}"
|
|
@@ -109,18 +113,18 @@ g(E, {
|
|
|
109
113
|
?disabled="${t.disabled}"
|
|
110
114
|
?readonly="${t.readonly}"
|
|
111
115
|
?required="${t.required}"
|
|
112
|
-
:value="${e(
|
|
113
|
-
:aria-describedby="${
|
|
114
|
-
:aria-errormessage="${
|
|
115
|
-
:aria-invalid="${
|
|
116
|
-
:aria-labelledby="${
|
|
116
|
+
:value="${e(_.value)}"
|
|
117
|
+
:aria-describedby="${y}"
|
|
118
|
+
:aria-errormessage="${w}"
|
|
119
|
+
:aria-invalid="${k}"
|
|
120
|
+
:aria-labelledby="${A}"></textarea>
|
|
117
121
|
</div>
|
|
118
|
-
<span class="${() =>
|
|
119
|
-
<div id="${
|
|
120
|
-
${() =>
|
|
122
|
+
<span class="${() => d(M?.value)}" aria-live="polite" ?hidden="${() => !M}">${() => M?.value.counterText.replace(" / ", "/") ?? ""}</span>
|
|
123
|
+
<div id="${j}" class="helper-text" aria-live="polite" part="helper" ?hidden="${() => !!P.value || !I.value}">
|
|
124
|
+
${() => I.value}
|
|
121
125
|
</div>
|
|
122
|
-
<div id="${
|
|
123
|
-
${() =>
|
|
126
|
+
<div id="${N}" class="helper-text" role="alert" part="error" ?hidden="${() => !P.value}">
|
|
127
|
+
${() => P.value}
|
|
124
128
|
</div>
|
|
125
129
|
</div>
|
|
126
130
|
`;
|
|
@@ -130,10 +134,10 @@ g(E, {
|
|
|
130
134
|
...r,
|
|
131
135
|
t(c),
|
|
132
136
|
n("textarea"),
|
|
133
|
-
|
|
137
|
+
_
|
|
134
138
|
]
|
|
135
139
|
});
|
|
136
140
|
//#endregion
|
|
137
|
-
export {
|
|
141
|
+
export { k as TEXTAREA_TAG };
|
|
138
142
|
|
|
139
143
|
//# sourceMappingURL=textarea.js.map
|
package/dist/textarea.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.js","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import { define, html, inject, prop, ref, bind, onCleanup, onElement, useEmit, watchEffect } from '@vielzeug/ore';\nimport { live } from '@vielzeug/ore/directives';\nimport { useField } from '@vielzeug/ore/forms';\nimport { watch as rippleWatch } from '@vielzeug/ripple';\n\nimport type { TextFieldProps } from '../../shared';\nimport type { VisualVariant } from '../../types';\n\nimport { lifecycleSignal, createTextField } from '../../headless';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport { fieldMixins, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './textarea.css?inline';\n\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: { originalEvent: Event; value: string };\n input: { originalEvent: Event; value: string };\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /** Maximum character count; shows a counter when set */\n maxlength?: number;\n /** Disable a manual resize handle */\n 'no-resize'?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw element.\n * Set as a JS property: `bitTextarea.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Resize direction override */\n resize?: 'none' | 'horizontal' | 'both' | 'vertical';\n /** Number of visible text rows */\n rows?: number;\n};\n\n/**\n * A multi-line text input with label, helper text, character counter, and auto-resize.\n *\n * @element ore-textarea\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {number} rows - Visible row count\n * @attr {number} maxlength - Max character count (shows counter)\n * @attr {string} helper - Helper text below the textarea\n * @attr {string} error - Error message\n * @attr {boolean} disabled - Disable interaction\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Required field\n * @attr {boolean} no-resize - Disable manual resize\n * @attr {boolean} auto-resize - Grow with content\n * @attr {string} resize - Resize direction: 'none' | 'horizontal' | 'both' | 'vertical'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Fired on every keystroke with current value. detail: { value: string; originalEvent: Event }\n * @fires change - Fired on blur with changed value. detail: { value: string; originalEvent: Event }\n *\n * @slot helper - Complex helper content\n *\n * @cssprop --textarea-bg - Background color\n * @cssprop --textarea-border-color - Border color\n * @cssprop --textarea-placeholder-color - Placeholder text color\n * @cssprop --textarea-radius - Border radius\n * @cssprop --textarea-padding - Inner padding (block inline)\n * @cssprop --textarea-gap - Gap between label and field\n * @cssprop --textarea-font-size - Font size\n * @cssprop --textarea-min-height - Minimum field height\n * @cssprop --textarea-max-height - Maximum field height (none = unlimited)\n * @cssprop --textarea-resize - CSS resize direction ('vertical' | 'horizontal' | 'both' | 'none')\n * @cssprop --textarea-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --textarea-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --textarea-focus-bg - Field background when focused (flat variant)\n * @cssprop --textarea-focus-border-color - Field border when focused (flat variant)\n *\n * @part wrapper - Outer wrapper element.\n * @part label - Label element.\n * @part field - Field container.\n * @part textarea - The native `<textarea>` element.\n * @part helper - The helper text element.\n * @part error - The error text element (`role=\"alert\"`).\n *\n * @example\n * ```html\n * <ore-textarea></ore-textarea>\n * ```\n */\nexport const TEXTAREA_TAG = 'ore-textarea' as const;\ndefine<OreTextareaProps>(TEXTAREA_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n 'auto-resize': prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n 'no-resize': prop.bool(false),\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 resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const emit = useEmit<OreTextareaEvents>();\n const watch = watchEffect;\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const textareaRef = ref<HTMLTextAreaElement>();\n\n const autoGrow = () => {\n if (!props['auto-resize'].value || !textareaRef.value) return;\n\n const textareaEl = textareaRef.value;\n\n textareaEl.style.height = 'auto';\n textareaEl.style.height = `${textareaEl.scrollHeight}px`;\n };\n\n const abortSignal = lifecycleSignal(onCleanup);\n let _formField: { reportValidity(): void } | null = null;\n const tf = createTextField({\n disabled: fCtxProps.disabled,\n error: props.error,\n getFormField: () => _formField,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onBeforeInput: autoGrow,\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: 'textarea',\n signal: abortSignal,\n validateOn: formCtx?.validateOn,\n value: props.value,\n });\n\n _formField = useField<string>({ disabled: tf.disabled, toFormValue: (v) => v, value: tf.value });\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n counter,\n errorId,\n errorText,\n fieldId: textareaId,\n helperText,\n labelId,\n labelVisible,\n } = tf;\n\n onElement(textareaRef, (textareaEl) => {\n const unwireEl = tf.wire(textareaEl);\n\n props.ref.value?.(textareaEl);\n\n const sub = rippleWatch(props.ref, (cb) => {\n cb?.(textareaEl);\n });\n\n const stopLayoutEffect = watch(() => {\n textareaEl.style.resize =\n props['auto-resize'].value || props['no-resize'].value ? 'none' : props.resize.value || 'vertical';\n\n if (props['auto-resize'].value) {\n requestAnimationFrame(autoGrow);\n }\n });\n\n return () => {\n sub.dispose();\n props.ref.value?.(null);\n unwireEl();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: () => errorText.value || undefined,\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const counterClass = () =>\n counter?.value.counterAtLimit\n ? 'counter at-limit'\n : counter?.value.counterNearLimit\n ? 'counter near-limit'\n : 'counter';\n const counterHidden = () => !counter;\n const counterText = () => counter?.value.counterText.replace(' / ', '/') ?? '';\n const helperHidden = () => !!errorText.value || !helperText.value;\n const errorHidden = () => !errorText.value;\n\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <label class=\"label\" part=\"label\" for=\"${textareaId}\" id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\"\n >${props.label}</label\n >\n <div class=\"field\" part=\"field\">\n <textarea\n part=\"textarea\"\n ref=\"${textareaRef}\"\n id=\"${textareaId}\"\n :name=\"${props.name}\"\n :placeholder=\"${props.placeholder}\"\n :rows=\"${props.rows}\"\n :maxlength=\"${props.maxlength}\"\n ?disabled=\"${props.disabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n :value=\"${live(tf.value)}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n :aria-errormessage=\"${ariaErrorMessage}\"\n :aria-invalid=\"${ariaInvalid}\"\n :aria-labelledby=\"${ariaLabelledBy}\"></textarea>\n </div>\n <span class=\"${counterClass}\" aria-live=\"polite\" ?hidden=\"${counterHidden}\">${counterText}</span>\n <div id=\"${assistiveId}\" class=\"helper-text\" aria-live=\"polite\" part=\"helper\" ?hidden=\"${helperHidden}\">\n ${() => helperText.value}\n </div>\n <div id=\"${errorId}\" class=\"helper-text\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n ${() => errorText.value}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [...fieldMixins, sizeVariantMixin(TEXTAREA_SIZE_PRESET), forcedColorsFocusMixin('textarea'), componentStyles],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textarea.js","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import { define, html, inject, prop, ref, bind, onCleanup, onElement, useEmit, watchEffect } from '@vielzeug/ore';\nimport { live } from '@vielzeug/ore/directives';\nimport { useField } from '@vielzeug/ore/forms';\nimport { watch as rippleWatch } from '@vielzeug/ripple';\n\nimport type { TextFieldProps } from '../../shared';\nimport type { VisualVariant } from '../../types';\n\nimport { counterClassName, createAutoResize, lifecycleSignal, createTextField } from '../../headless';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport { fieldMixins, forcedColorsFocusMixin, sizeVariantMixin } from '../../styles';\nimport { errorAttr } from '../shared/field-binding';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './textarea.css?inline';\n\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: { originalEvent: Event; value: string };\n input: { originalEvent: Event; value: string };\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /** Maximum character count; shows a counter when set */\n maxlength?: number;\n /** Disable a manual resize handle */\n 'no-resize'?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw element.\n * Set as a JS property: `bitTextarea.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Resize direction override */\n resize?: 'none' | 'horizontal' | 'both' | 'vertical';\n /** Number of visible text rows */\n rows?: number;\n};\n\n/**\n * A multi-line text input with label, helper text, character counter, and auto-resize.\n *\n * @element ore-textarea\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {number} rows - Visible row count\n * @attr {number} maxlength - Max character count (shows counter)\n * @attr {string} helper - Helper text below the textarea\n * @attr {string} error - Error message\n * @attr {boolean} disabled - Disable interaction\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Required field\n * @attr {boolean} no-resize - Disable manual resize\n * @attr {boolean} auto-resize - Grow with content\n * @attr {string} resize - Resize direction: 'none' | 'horizontal' | 'both' | 'vertical'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Fired on every keystroke with current value. detail: { value: string; originalEvent: Event }\n * @fires change - Fired on blur with changed value. detail: { value: string; originalEvent: Event }\n *\n * @slot helper - Complex helper content\n *\n * @cssprop --textarea-bg - Background color\n * @cssprop --textarea-border-color - Border color\n * @cssprop --textarea-placeholder-color - Placeholder text color\n * @cssprop --textarea-radius - Border radius\n * @cssprop --textarea-padding - Inner padding (block inline)\n * @cssprop --textarea-gap - Gap between label and field\n * @cssprop --textarea-font-size - Font size\n * @cssprop --textarea-min-height - Minimum field height\n * @cssprop --textarea-max-height - Maximum field height (none = unlimited)\n * @cssprop --textarea-resize - CSS resize direction ('vertical' | 'horizontal' | 'both' | 'none')\n * @cssprop --textarea-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --textarea-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --textarea-focus-bg - Field background when focused (flat variant)\n * @cssprop --textarea-focus-border-color - Field border when focused (flat variant)\n *\n * @part wrapper - Outer wrapper element.\n * @part label - Label element.\n * @part field - Field container.\n * @part textarea - The native `<textarea>` element.\n * @part helper - The helper text element.\n * @part error - The error text element (`role=\"alert\"`).\n *\n * @example\n * ```html\n * <ore-textarea></ore-textarea>\n * ```\n */\nexport const TEXTAREA_TAG = 'ore-textarea' as const;\ndefine<OreTextareaProps>(TEXTAREA_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n 'auto-resize': prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n 'no-resize': prop.bool(false),\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 resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const emit = useEmit<OreTextareaEvents>();\n const watch = watchEffect;\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: fCtxProps.disabled,\n error: props.error,\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: 'textarea',\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: () => {\n tf.reset();\n requestAnimationFrame(() => autoResize.recompute());\n },\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 counter,\n errorId,\n errorText,\n fieldId: textareaId,\n helperText,\n labelId,\n labelVisible,\n } = tf;\n\n onElement(textareaRef, (textareaEl) => {\n const unwireEl = tf.wire(textareaEl);\n const unwireAutoResize = autoResize.wire(textareaEl);\n\n props.ref.value?.(textareaEl);\n\n const sub = rippleWatch(props.ref, (cb) => {\n cb?.(textareaEl);\n });\n\n const stopLayoutEffect = watch(() => {\n textareaEl.style.resize =\n props['auto-resize'].value || props['no-resize'].value ? 'none' : props.resize.value || 'vertical';\n\n // Deferred a frame: on mount (or right after `auto-resize` flips true) the browser\n // hasn't necessarily finished laying out the textarea yet, so `scrollHeight` read\n // synchronously here could be stale.\n requestAnimationFrame(() => autoResize.recompute());\n });\n\n return () => {\n sub.dispose();\n props.ref.value?.(null);\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: fCtxProps.size,\n variant: fCtxProps.variant,\n },\n });\n\n const counterClass = () => counterClassName(counter?.value);\n const counterHidden = () => !counter;\n const counterText = () => counter?.value.counterText.replace(' / ', '/') ?? '';\n const helperHidden = () => !!errorText.value || !helperText.value;\n const errorHidden = () => !errorText.value;\n\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <label class=\"label\" part=\"label\" for=\"${textareaId}\" id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\"\n >${props.label}</label\n >\n <div class=\"field\" part=\"field\">\n <textarea\n part=\"textarea\"\n ref=\"${textareaRef}\"\n id=\"${textareaId}\"\n :name=\"${props.name}\"\n :placeholder=\"${props.placeholder}\"\n :rows=\"${props.rows}\"\n :maxlength=\"${props.maxlength}\"\n ?disabled=\"${props.disabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n :value=\"${live(tf.value)}\"\n :aria-describedby=\"${ariaDescribedBy}\"\n :aria-errormessage=\"${ariaErrorMessage}\"\n :aria-invalid=\"${ariaInvalid}\"\n :aria-labelledby=\"${ariaLabelledBy}\"></textarea>\n </div>\n <span class=\"${counterClass}\" aria-live=\"polite\" ?hidden=\"${counterHidden}\">${counterText}</span>\n <div id=\"${assistiveId}\" class=\"helper-text\" aria-live=\"polite\" part=\"helper\" ?hidden=\"${helperHidden}\">\n ${() => helperText.value}\n </div>\n <div id=\"${errorId}\" class=\"helper-text\" role=\"alert\" part=\"error\" ?hidden=\"${errorHidden}\">\n ${() => errorText.value}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [...fieldMixins, sizeVariantMixin(TEXTAREA_SIZE_PRESET), forcedColorsFocusMixin('textarea'), componentStyles],\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmGA,IAAa,IAAe;AAC5B,EAAyB,GAAc;CACrC,gBAAgB;CAChB,OAAO;EACL,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;EACH,eAAe,EAAK,KAAK,EAAK;EAC9B,OAAO,EAAK,OAAO;EACnB,WAAW,EAAK,KAAK,EAAK;EAC1B,QAAQ,EAAK,OAAO;EACpB,OAAO,EAAK,OAAO;EACnB,mBAAmB,EAAK,MAAM,CAAC,SAAS,SAAS,GAAY,OAAO;EACpE,WAAW,EAAK,KAAK,KAAA,CAA+B;EACpD,MAAM,EAAK,OAAO;EAClB,aAAa,EAAK,KAAK,EAAK;EAC5B,aAAa,EAAK,OAAO;EACzB,UAAU,EAAK,KAAK,EAAK;EACzB,KAAK,EAAK,KAAK,KAAA,CAA0E;EACzF,UAAU,EAAK,KAAK,EAAK;EACzB,QAAQ,EAAK,OAAoD;EACjE,MAAM,EAAK,KAAK,KAAA,CAA+B;EAC/C,OAAO,EAAK,OAAO;EACnB,SAAS,EAAK,OAA4D;CAC5E;CACA,MAAM,GAAO;EACX,IAAM,IAAO,EAA2B,GAClC,IAAQ,GAER,IAAU,EAAO,CAAQ,GACzB,IAAY,EAAe,GAAO,CAAO,GAEzC,IAAc,EAAyB,GACvC,IAAa,EAAiB,EAAE,SAAS,EAAM,eAAe,CAAC,GAE/D,IAAc,EAAgB,CAAS,GACvC,IAAK,EAAgB;GACzB,UAAU,EAAU;GACpB,OAAO,EAAM;GACb,QAAQ,EAAM;GACd,OAAO,EAAM;GACb,gBAAgB,EAAM;GACtB,WAAW,EAAM;GACjB,WAAW,GAAc,MAAkB;IACzC,EAAK,UAAU;KAAE,eAAe;KAAO;IAAM,CAAC;GAChD;GACA,UAAU,GAAc,MAAkB;IACxC,EAAK,SAAS;KAAE,eAAe;KAAO;IAAM,CAAC;GAC/C;GACA,QAAQ;GACR,UAAU,EAAM;GAChB,UAAU,EAAM;GAChB,QAAQ;GACR,YAAY,GAAS;GACrB,OAAO,EAAM;EACf,CAAC;EAED,EAAG,gBACD,EAAiB;GACf,UAAU,EAAG;GACb,eAAe;IAEb,AADA,EAAG,MAAM,GACT,4BAA4B,EAAW,UAAU,CAAC;GACpD;GACA,cAAc,MAAM;GACpB,mBAAmB,EAAG;GACtB,UAAU,EAAG;GACb,OAAO,EAAG;EACZ,CAAC,CACH;EAEA,IAAM,EACJ,oBACA,qBACA,gBACA,mBACA,gBACA,YACA,YACA,cACA,SAAS,GACT,eACA,YACA,oBACE;EA6CJ,OA3CA,EAAU,IAAc,MAAe;GACrC,IAAM,IAAW,EAAG,KAAK,CAAU,GAC7B,IAAmB,EAAW,KAAK,CAAU;GAEnD,EAAM,IAAI,QAAQ,CAAU;GAE5B,IAAM,IAAM,EAAY,EAAM,MAAM,MAAO;IACzC,IAAK,CAAU;GACjB,CAAC,GAEK,IAAmB,QAAY;IAOnC,AANA,EAAW,MAAM,SACf,EAAM,cAAc,CAAC,SAAS,EAAM,YAAY,CAAC,QAAQ,SAAS,EAAM,OAAO,SAAS,YAK1F,4BAA4B,EAAW,UAAU,CAAC;GACpD,CAAC;GAED,aAAa;IAKX,AAJA,EAAI,QAAQ,GACZ,EAAM,IAAI,QAAQ,IAAI,GACtB,EAAS,GACT,EAAiB,GACjB,EAAiB;GACnB;EACF,CAAC,GAED,EAAK,EACH,MAAM;GACJ,OAAO,EAAU,CAAS;GAC1B,MAAM,EAAU;GAChB,SAAS,EAAU;EACrB,EACF,CAAC,GAQM,CAAI;;iDAEkC,EAAW,QAAQ,EAAQ,mBAAmB,CAAC,EAAa,MAAM;aACtG,EAAM,MAAM;;;;;mBAKN,EAAY;kBACb,EAAW;qBACR,EAAM,KAAK;4BACJ,EAAM,YAAY;qBACzB,EAAM,KAAK;0BACN,EAAM,UAAU;yBACjB,EAAM,SAAS;yBACf,EAAM,SAAS;yBACf,EAAM,SAAS;sBAClB,EAAK,EAAG,KAAK,EAAE;iCACJ,EAAgB;kCACf,EAAiB;6BACtB,EAAY;gCACT,EAAe;;6BA3BhB,EAAiB,GAAS,KAAK,EA6B1B,sCA5BJ,CAAC,EA4BiD,UA3BpD,GAAS,MAAM,YAAY,QAAQ,OAAO,GAAG,KAAK,GA2BkB;mBAC/E,EAAY,wEA3BA,CAAC,CAAC,EAAU,SAAS,CAAC,EAAW,MA2B8C;kBAC5F,EAAW,MAAM;;mBAEhB,EAAQ,iEA7BG,CAAC,EAAU,MA6ByD;kBAChF,EAAU,MAAM;;;;CAIhC;CACA,QAAQ,EAAE,gBAAgB,GAAK;CAC/B,QAAQ;EAAC,GAAG;EAAa,EAAiB,CAAoB;EAAG,EAAuB,UAAU;EAAG;CAAe;AACtH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielzeug/refine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Accessible, themeable web components built on Ore custom element primitives",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"web-components",
|
|
@@ -291,6 +291,12 @@
|
|
|
291
291
|
"require": "./dist/menu.cjs",
|
|
292
292
|
"types": "./dist/overlay/menu/menu.d.ts"
|
|
293
293
|
},
|
|
294
|
+
"./message-composer": {
|
|
295
|
+
"source": "./src/inputs/message-composer/message-composer.ts",
|
|
296
|
+
"import": "./dist/message-composer.js",
|
|
297
|
+
"require": "./dist/message-composer.cjs",
|
|
298
|
+
"types": "./dist/inputs/message-composer/message-composer.d.ts"
|
|
299
|
+
},
|
|
294
300
|
"./navbar": {
|
|
295
301
|
"source": "./src/layout/navbar/navbar.ts",
|
|
296
302
|
"import": "./dist/navbar.js",
|
|
@@ -443,35 +449,41 @@
|
|
|
443
449
|
}
|
|
444
450
|
},
|
|
445
451
|
"scripts": {
|
|
446
|
-
"analyze": "custom-elements-manifest analyze --config refine-manifest.mjs",
|
|
447
|
-
"build": "pnpm run sync:exports && pnpm run check:manifest && vite build && pnpm run build:bundle && cp -r src/styles/*.css dist/styles && pnpm run build:types && pnpm run analyze",
|
|
452
|
+
"analyze": "custom-elements-manifest analyze --config scripts/refine-manifest.mjs",
|
|
453
|
+
"build": "pnpm run sync:theme && pnpm run check:theme && pnpm run sync:exports && pnpm run check:manifest && vite build && pnpm run build:bundle && cp -r src/styles/*.css dist/styles && pnpm run build:types && pnpm run analyze",
|
|
448
454
|
"build:types": "tsc -p tsconfig.declarations.json",
|
|
449
|
-
"check:manifest": "node ./refine-manifest.mjs check-exports",
|
|
455
|
+
"check:manifest": "node ./scripts/refine-manifest.mjs check-exports",
|
|
456
|
+
"check:theme": "node ./scripts/theme-tokens.mjs check",
|
|
450
457
|
"dev": "vite",
|
|
451
458
|
"fix": "eslint --fix src",
|
|
452
459
|
"lint": "eslint src",
|
|
453
460
|
"preview": "vite preview",
|
|
454
|
-
"sync:exports": "node ./refine-manifest.mjs sync-exports",
|
|
461
|
+
"sync:exports": "node ./scripts/refine-manifest.mjs sync-exports",
|
|
462
|
+
"sync:theme": "node ./scripts/theme-tokens.mjs sync",
|
|
455
463
|
"test": "vitest",
|
|
456
464
|
"build:bundle": "vite build --config vite.bundle.config.ts",
|
|
457
465
|
"build:bundle:watch": "vite build --watch --config vite.bundle.config.ts"
|
|
458
466
|
},
|
|
459
467
|
"dependencies": {
|
|
460
|
-
"@vielzeug/
|
|
468
|
+
"@vielzeug/arsenal": "workspace:*",
|
|
461
469
|
"@vielzeug/dnd": "workspace:*",
|
|
462
470
|
"@vielzeug/keymap": "workspace:*",
|
|
463
471
|
"@vielzeug/orbit": "workspace:*",
|
|
472
|
+
"@vielzeug/ore": "workspace:*",
|
|
464
473
|
"@vielzeug/ripple": "workspace:*",
|
|
465
|
-
"@vielzeug/arsenal": "workspace:*",
|
|
466
474
|
"@vielzeug/tempo": "workspace:*",
|
|
467
475
|
"lucide": "^1.23.0"
|
|
468
476
|
},
|
|
469
477
|
"devDependencies": {
|
|
470
478
|
"@custom-elements-manifest/analyzer": "^0.11.0",
|
|
479
|
+
"@types/culori": "^4.0.1",
|
|
471
480
|
"axe-core": "^4.12.1",
|
|
472
|
-
"browserslist": "^4.28.
|
|
481
|
+
"browserslist": "^4.28.5",
|
|
482
|
+
"culori": "^4.0.2",
|
|
473
483
|
"lightningcss": "^1.32.0",
|
|
474
|
-
"
|
|
484
|
+
"prettier": "^3.9.5",
|
|
485
|
+
"stylelint": "^17.14.0",
|
|
486
|
+
"typescript": "^6.0.3",
|
|
475
487
|
"vite": "^8.1.3",
|
|
476
488
|
"vitest": "^4.1.10"
|
|
477
489
|
},
|