@vielzeug/refine 26.10.7 → 26.10.10
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/README.md +6 -0
- package/dist/accordion-item.cjs +2 -2
- package/dist/accordion-item.cjs.map +1 -1
- package/dist/accordion-item.js +6 -6
- package/dist/accordion-item.js.map +1 -1
- package/dist/accordion.cjs +2 -2
- package/dist/accordion.cjs.map +1 -1
- package/dist/accordion.js +2 -2
- package/dist/accordion.js.map +1 -1
- package/dist/alert.cjs +2 -2
- package/dist/alert.cjs.map +1 -1
- package/dist/alert.js +2 -2
- package/dist/alert.js.map +1 -1
- package/dist/avatar.cjs +3 -3
- package/dist/avatar.cjs.map +1 -1
- package/dist/avatar.js +2 -2
- package/dist/avatar.js.map +1 -1
- package/dist/badge.cjs +2 -2
- package/dist/badge.cjs.map +1 -1
- package/dist/badge.js +2 -2
- package/dist/badge.js.map +1 -1
- package/dist/box.cjs +2 -2
- package/dist/box.cjs.map +1 -1
- package/dist/box.js +2 -2
- package/dist/box.js.map +1 -1
- package/dist/button-group.cjs +2 -2
- package/dist/button-group.cjs.map +1 -1
- package/dist/button-group.js +2 -2
- package/dist/button-group.js.map +1 -1
- package/dist/button.cjs +9 -9
- package/dist/button.cjs.map +1 -1
- package/dist/button.js +8 -8
- package/dist/button.js.map +1 -1
- package/dist/card.cjs +2 -2
- package/dist/card.cjs.map +1 -1
- package/dist/card.js +2 -2
- package/dist/card.js.map +1 -1
- package/dist/carousel.cjs +6 -6
- package/dist/carousel.cjs.map +1 -1
- package/dist/carousel.js +6 -6
- package/dist/carousel.js.map +1 -1
- package/dist/chat-message.cjs +4 -4
- package/dist/chat-message.cjs.map +1 -1
- package/dist/chat-message.js +4 -4
- package/dist/chat-message.js.map +1 -1
- package/dist/checkbox-group.cjs +1 -1
- package/dist/checkbox-group.cjs.map +1 -1
- package/dist/checkbox-group.js +1 -1
- package/dist/checkbox-group.js.map +1 -1
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.cjs.map +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.js.map +1 -1
- package/dist/chip.cjs +8 -8
- package/dist/chip.cjs.map +1 -1
- package/dist/chip.js +8 -8
- package/dist/chip.js.map +1 -1
- package/dist/combobox.cjs +8 -8
- package/dist/combobox.cjs.map +1 -1
- package/dist/combobox.js +11 -11
- package/dist/combobox.js.map +1 -1
- package/dist/content/avatar/avatar.d.ts +2 -1
- package/dist/content/avatar/avatar.d.ts.map +1 -1
- package/dist/content/card/card.d.ts +6 -3
- package/dist/content/card/card.d.ts.map +1 -1
- package/dist/content/carousel/carousel.d.ts +5 -3
- package/dist/content/carousel/carousel.d.ts.map +1 -1
- package/dist/content/chat-message/chat-message.d.ts +2 -1
- package/dist/content/chat-message/chat-message.d.ts.map +1 -1
- package/dist/content/copy-command/copy-command.d.ts +1 -1
- package/dist/content/copy-command/copy-command.d.ts.map +1 -1
- package/dist/content/keyboard-key/keyboard-key.d.ts +2 -1
- package/dist/content/keyboard-key/keyboard-key.d.ts.map +1 -1
- package/dist/content/list/list.d.ts +2 -1
- package/dist/content/list/list.d.ts.map +1 -1
- package/dist/content/marquee/marquee.d.ts +3 -2
- package/dist/content/marquee/marquee.d.ts.map +1 -1
- package/dist/content/pagination/pagination.d.ts +1 -1
- package/dist/content/pagination/pagination.d.ts.map +1 -1
- package/dist/content/qr-code/qr-code.d.ts +0 -41
- package/dist/content/qr-code/qr-code.d.ts.map +1 -1
- package/dist/content/separator/separator.d.ts +1 -1
- package/dist/content/separator/separator.d.ts.map +1 -1
- package/dist/content/stepper/step.d.ts +1 -1
- package/dist/content/stepper/step.d.ts.map +1 -1
- package/dist/content/table/table.d.ts +2 -1
- package/dist/content/table/table.d.ts.map +1 -1
- package/dist/content/text/text.d.ts +13 -6
- package/dist/content/text/text.d.ts.map +1 -1
- package/dist/cookie-banner.cjs +1 -1
- package/dist/cookie-banner.cjs.map +1 -1
- package/dist/cookie-banner.js +1 -1
- package/dist/cookie-banner.js.map +1 -1
- package/dist/copy-command.cjs +6 -6
- package/dist/copy-command.cjs.map +1 -1
- package/dist/copy-command.js +7 -7
- package/dist/copy-command.js.map +1 -1
- package/dist/core/checkable.cjs +1 -1
- package/dist/core/checkable.cjs.map +1 -1
- package/dist/core/checkable.d.ts +6 -7
- package/dist/core/checkable.d.ts.map +1 -1
- package/dist/core/checkable.js +1 -1
- package/dist/core/checkable.js.map +1 -1
- package/dist/core/choice-field.cjs +1 -1
- package/dist/core/choice-field.cjs.map +1 -1
- package/dist/core/choice-field.d.ts +6 -6
- package/dist/core/choice-field.d.ts.map +1 -1
- package/dist/core/choice-field.js +1 -1
- package/dist/core/choice-field.js.map +1 -1
- package/dist/core/text-field.cjs +1 -1
- package/dist/core/text-field.cjs.map +1 -1
- package/dist/core/text-field.d.ts +8 -8
- package/dist/core/text-field.d.ts.map +1 -1
- package/dist/core/text-field.js +1 -1
- package/dist/core/text-field.js.map +1 -1
- package/dist/counter.cjs +2 -2
- package/dist/counter.cjs.map +1 -1
- package/dist/counter.js +2 -2
- package/dist/counter.js.map +1 -1
- package/dist/custom-elements.json +886 -749
- package/dist/datagrid.cjs +47 -47
- package/dist/datagrid.cjs.map +1 -1
- package/dist/datagrid.js +51 -51
- package/dist/datagrid.js.map +1 -1
- package/dist/date-picker.cjs +9 -9
- package/dist/date-picker.cjs.map +1 -1
- package/dist/date-picker.js +11 -11
- package/dist/date-picker.js.map +1 -1
- package/dist/dialog.cjs +3 -3
- package/dist/dialog.cjs.map +1 -1
- package/dist/dialog.js +3 -3
- package/dist/dialog.js.map +1 -1
- package/dist/disclosure/accordion/accordion.d.ts +4 -2
- package/dist/disclosure/accordion/accordion.d.ts.map +1 -1
- package/dist/disclosure/accordion-item/accordion-item.d.ts +1 -1
- package/dist/disclosure/accordion-item/accordion-item.d.ts.map +1 -1
- package/dist/disclosure/tab-item/tab-item.d.ts +1 -1
- package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
- package/dist/disclosure/tabs/tabs.d.ts +1 -1
- package/dist/disclosure/tabs/tabs.d.ts.map +1 -1
- package/dist/drawer.cjs +4 -4
- package/dist/drawer.cjs.map +1 -1
- package/dist/drawer.js +2 -2
- package/dist/drawer.js.map +1 -1
- package/dist/feedback/alert/alert.d.ts +2 -1
- package/dist/feedback/alert/alert.d.ts.map +1 -1
- package/dist/feedback/badge/badge.d.ts +7 -4
- package/dist/feedback/badge/badge.d.ts.map +1 -1
- package/dist/feedback/chip/chip.d.ts +7 -5
- package/dist/feedback/chip/chip.d.ts.map +1 -1
- package/dist/grid-item.cjs +2 -2
- package/dist/grid-item.cjs.map +1 -1
- package/dist/grid-item.js +2 -2
- package/dist/grid-item.js.map +1 -1
- package/dist/grid.cjs +2 -2
- package/dist/grid.cjs.map +1 -1
- package/dist/grid.js +2 -2
- package/dist/grid.js.map +1 -1
- package/dist/input.cjs +7 -7
- package/dist/input.cjs.map +1 -1
- package/dist/input.js +8 -8
- package/dist/input.js.map +1 -1
- package/dist/inputs/button/button.d.ts +3 -2
- package/dist/inputs/button/button.d.ts.map +1 -1
- package/dist/inputs/button-group/button-group.d.ts +1 -37
- package/dist/inputs/button-group/button-group.d.ts.map +1 -1
- package/dist/inputs/combobox/combobox.types.d.ts +2 -2
- package/dist/inputs/combobox/combobox.types.d.ts.map +1 -1
- package/dist/inputs/counter/counter.d.ts +3 -2
- package/dist/inputs/counter/counter.d.ts.map +1 -1
- package/dist/inputs/datagrid/datagrid-model.cjs +1 -1
- package/dist/inputs/datagrid/datagrid-model.cjs.map +1 -1
- package/dist/inputs/datagrid/datagrid-model.d.ts +2 -1
- package/dist/inputs/datagrid/datagrid-model.d.ts.map +1 -1
- package/dist/inputs/datagrid/datagrid-model.js +1 -1
- package/dist/inputs/datagrid/datagrid-model.js.map +1 -1
- package/dist/inputs/datagrid/datagrid.d.ts +4 -2
- package/dist/inputs/datagrid/datagrid.d.ts.map +1 -1
- package/dist/inputs/date-picker/date-picker.d.ts +3 -2
- package/dist/inputs/date-picker/date-picker.d.ts.map +1 -1
- package/dist/inputs/input/input.d.ts +5 -3
- package/dist/inputs/input/input.d.ts.map +1 -1
- package/dist/inputs/message-composer/message-composer.d.ts +3 -2
- package/dist/inputs/message-composer/message-composer.d.ts.map +1 -1
- package/dist/inputs/number-input/number-input.d.ts +1 -1
- package/dist/inputs/number-input/number-input.d.ts.map +1 -1
- package/dist/inputs/otp-input/otp-input.d.ts +3 -2
- package/dist/inputs/otp-input/otp-input.d.ts.map +1 -1
- package/dist/inputs/query-bar/query-bar.d.ts.map +1 -1
- package/dist/inputs/select/select.d.ts +2 -2
- package/dist/inputs/select/select.d.ts.map +1 -1
- package/dist/inputs/textarea/textarea.d.ts +4 -3
- package/dist/inputs/textarea/textarea.d.ts.map +1 -1
- package/dist/inputs/time-picker/time-picker.d.ts +2 -2
- package/dist/inputs/time-picker/time-picker.d.ts.map +1 -1
- package/dist/keyboard-key.cjs +3 -3
- package/dist/keyboard-key.cjs.map +1 -1
- package/dist/keyboard-key.js +3 -3
- package/dist/keyboard-key.js.map +1 -1
- package/dist/layout/box/box.d.ts +6 -3
- package/dist/layout/box/box.d.ts.map +1 -1
- package/dist/layout/grid/grid.d.ts +11 -6
- package/dist/layout/grid/grid.d.ts.map +1 -1
- package/dist/layout/grid-item/grid-item.d.ts +8 -4
- package/dist/layout/grid-item/grid-item.d.ts.map +1 -1
- package/dist/layout/navbar/navbar.d.ts +4 -2
- package/dist/layout/navbar/navbar.d.ts.map +1 -1
- package/dist/layout/sidebar/sidebar.d.ts +2 -1
- package/dist/layout/sidebar/sidebar.d.ts.map +1 -1
- package/dist/list-item.cjs +1 -1
- package/dist/list-item.cjs.map +1 -1
- package/dist/list-item.js +1 -1
- package/dist/list-item.js.map +1 -1
- package/dist/list.cjs +2 -2
- package/dist/list.cjs.map +1 -1
- package/dist/list.js +2 -2
- package/dist/list.js.map +1 -1
- package/dist/marquee.cjs +3 -3
- package/dist/marquee.cjs.map +1 -1
- package/dist/marquee.js +3 -3
- package/dist/marquee.js.map +1 -1
- package/dist/menu.cjs +3 -3
- package/dist/menu.cjs.map +1 -1
- package/dist/menu.js +3 -3
- package/dist/menu.js.map +1 -1
- package/dist/message-composer.cjs +10 -10
- package/dist/message-composer.cjs.map +1 -1
- package/dist/message-composer.js +7 -7
- package/dist/message-composer.js.map +1 -1
- package/dist/navbar.cjs +10 -10
- package/dist/navbar.cjs.map +1 -1
- package/dist/navbar.js +13 -13
- package/dist/navbar.js.map +1 -1
- package/dist/number-input.cjs +3 -3
- package/dist/number-input.cjs.map +1 -1
- package/dist/number-input.js +4 -4
- package/dist/number-input.js.map +1 -1
- package/dist/otp-input.cjs +4 -4
- package/dist/otp-input.cjs.map +1 -1
- package/dist/otp-input.js +4 -4
- package/dist/otp-input.js.map +1 -1
- package/dist/overlay/dialog/dialog.d.ts +7 -4
- package/dist/overlay/dialog/dialog.d.ts.map +1 -1
- package/dist/overlay/drawer/drawer.d.ts +4 -2
- package/dist/overlay/drawer/drawer.d.ts.map +1 -1
- package/dist/overlay/menu/menu.d.ts +2 -1
- package/dist/overlay/menu/menu.d.ts.map +1 -1
- package/dist/pagination.cjs +9 -9
- package/dist/pagination.cjs.map +1 -1
- package/dist/pagination.js +9 -9
- package/dist/pagination.js.map +1 -1
- package/dist/qr-code.cjs +2 -2
- package/dist/qr-code.cjs.map +1 -1
- package/dist/qr-code.js +2 -2
- package/dist/qr-code.js.map +1 -1
- package/dist/query-bar.cjs +7 -7
- package/dist/query-bar.cjs.map +1 -1
- package/dist/query-bar.js +8 -8
- package/dist/query-bar.js.map +1 -1
- package/dist/radio-group.cjs +1 -1
- package/dist/radio-group.cjs.map +1 -1
- package/dist/radio-group.js +1 -1
- package/dist/radio-group.js.map +1 -1
- package/dist/refine.cjs +123 -123
- package/dist/refine.cjs.map +1 -1
- package/dist/refine.iife.js +123 -123
- package/dist/refine.iife.js.map +1 -1
- package/dist/refine.js +124 -124
- package/dist/refine.js.map +1 -1
- package/dist/select.cjs +13 -13
- package/dist/select.cjs.map +1 -1
- package/dist/select.js +15 -15
- package/dist/select.js.map +1 -1
- package/dist/separator.cjs +4 -4
- package/dist/separator.cjs.map +1 -1
- package/dist/separator.js +4 -4
- package/dist/separator.js.map +1 -1
- package/dist/shared/prop-bundles.cjs +1 -1
- package/dist/shared/prop-bundles.cjs.map +1 -1
- package/dist/shared/prop-bundles.d.ts +7 -8
- package/dist/shared/prop-bundles.d.ts.map +1 -1
- package/dist/shared/prop-bundles.js +1 -1
- package/dist/shared/prop-bundles.js.map +1 -1
- package/dist/shared/types.cjs +2 -0
- package/dist/shared/types.cjs.map +1 -0
- package/dist/shared/types.d.ts +27 -9
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +2 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/sidebar.cjs +7 -7
- package/dist/sidebar.cjs.map +1 -1
- package/dist/sidebar.js +4 -4
- package/dist/sidebar.js.map +1 -1
- package/dist/step.cjs +10 -10
- package/dist/step.cjs.map +1 -1
- package/dist/step.js +10 -10
- package/dist/step.js.map +1 -1
- package/dist/tab-item.cjs +4 -4
- package/dist/tab-item.cjs.map +1 -1
- package/dist/tab-item.js +5 -5
- package/dist/tab-item.js.map +1 -1
- package/dist/table.cjs +2 -2
- package/dist/table.cjs.map +1 -1
- package/dist/table.js +2 -2
- package/dist/table.js.map +1 -1
- package/dist/tabs.cjs +2 -2
- package/dist/tabs.cjs.map +1 -1
- package/dist/tabs.js +4 -4
- package/dist/tabs.js.map +1 -1
- package/dist/text.cjs +2 -2
- package/dist/text.cjs.map +1 -1
- package/dist/text.js +2 -2
- package/dist/text.js.map +1 -1
- package/dist/textarea.cjs +7 -7
- package/dist/textarea.cjs.map +1 -1
- package/dist/textarea.js +7 -7
- package/dist/textarea.js.map +1 -1
- package/dist/time-picker.cjs +7 -7
- package/dist/time-picker.cjs.map +1 -1
- package/dist/time-picker.js +7 -7
- package/dist/time-picker.js.map +1 -1
- package/dist/tooltip.cjs +1 -1
- package/dist/tooltip.cjs.map +1 -1
- package/dist/tooltip.js +1 -1
- package/dist/tooltip.js.map +1 -1
- package/package.json +15 -14
package/dist/textarea.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.cjs","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import {\n bind,\n define,\n getHost,\n html,\n live,\n onCleanup,\n onElement,\n prop,\n ref,\n useField,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { bindRefCallback, createAutoResize, createTextField, lifecycleSignal } from '../../core';\nimport type { TextFieldProps } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n fieldVariantMixin,\n forcedColorsFocusMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport type { VisualVariant } from '../../types';\nimport { errorAttr } from '../shared/field-binding';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport { renderFieldStatusRegion, renderStatusIcon } from '../shared/templates';\nimport componentStyles from './textarea.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: Event;\n input: InputEvent;\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /**\n * Shows an inline spinner inside the field and forces the inner `<textarea>` into\n * `disabled` for the duration: use while an async validation/submission request\n * is in flight to prevent double-submits.\n */\n loading?: 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 {boolean} loading - Show an inline spinner and force the field disabled\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\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.\n * @fires change - Fired on blur with changed value.\n *\n * @slot helper - Complex helper content\n *\n * @part status-icon - The inline error/success icon shown inside the field\n * @part spinner - The inline loading spinner shown inside the field while `loading`\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 * <ore-textarea label=\"Bio\" success></ore-textarea>\n * <ore-textarea label=\"Bio\" loading></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 loading: prop.bool(false),\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.data<((el: HTMLTextAreaElement | null) => void) | null>(),\n required: prop.bool(false),\n resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n success: prop.bool(false),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n // `loading` behaves like a temporary `disabled`: see ore-input's identical computation.\n const isDisabled = computed(() => props.disabled.value || props.loading.value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: isDisabled,\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 setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'change');\n },\n onInput: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'input');\n },\n prefix: 'textarea',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n value: props.value,\n });\n\n defineFieldValue(\n el,\n () => tf.value.value,\n (value) => {\n tf.value.value = value;\n },\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 const unwireRef = bindRefCallback(props.ref, textareaEl);\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 unwireRef();\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: props.size,\n // Reflects `success` only once `error` is confirmed empty: keeps the two host\n // attributes mutually exclusive even if a consumer sets both props at once.\n success: () => (props.success.value && !errorText.value ? true : undefined),\n variant: props.variant,\n },\n });\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}\n </label>\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=\"${isDisabled}\"\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}\"\n aria-busy=\"${() => (props.loading.value ? 'true' : null)}\"></textarea>\n ${renderStatusIcon(errorText)}\n <span class=\"field-spinner\" part=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>\n </div>\n ${renderFieldStatusRegion({ assistiveId, counter, errorId, errorText, helperText })}\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n disabledLoadingMixin,\n sizeVariantMixin(TEXTAREA_SIZE_PRESET),\n forcedColorsFocusMixin('textarea'),\n componentStyles,\n // Must come after `componentStyles`: see `ore-input`'s identical ordering note for why\n // (`@layer` precedence is fixed by which layer name is *first* referenced across this whole\n // array; `componentStyles` establishes `refine.base`, which this mixin's `refine.variants`\n // rules need to win over).\n fieldVariantMixin({ container: '.field', text: 'textarea', tokenPrefix: 'textarea' }),\n ],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textarea.cjs","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import {\n bind,\n define,\n getHost,\n html,\n model,\n onCleanup,\n onElement,\n prop,\n ref,\n useField,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { bindRefCallback, createAutoResize, createTextField, lifecycleSignal } from '../../core';\nimport type { TextFieldProps } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n fieldVariantMixin,\n forcedColorsFocusMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { FIELD_VARIANTS, type FieldVariant } from '../../types';\nimport { errorAttr } from '../shared/field-binding';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport { renderFieldStatusRegion, renderStatusIcon } from '../shared/templates';\nimport componentStyles from './textarea.css?inline';\n\nconst TEXTAREA_RESIZE = ['none', 'both', 'horizontal', 'vertical'] as const;\n\nexport { ICON_TAG } from '../../content/icon/icon';\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: Event;\n input: InputEvent;\n};\n\nexport type OreTextareaProps = TextFieldProps<FieldVariant> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /**\n * Shows an inline spinner inside the field and forces the inner `<textarea>` into\n * `disabled` for the duration: use while an async validation/submission request\n * is in flight to prevent double-submits.\n */\n loading?: 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?: (typeof TEXTAREA_RESIZE)[number];\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 {boolean} loading - Show an inline spinner and force the field disabled\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\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.\n * @fires change - Fired on blur with changed value.\n *\n * @slot helper - Complex helper content\n *\n * @part status-icon - The inline error/success icon shown inside the field\n * @part spinner - The inline loading spinner shown inside the field while `loading`\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 * <ore-textarea label=\"Bio\" success></ore-textarea>\n * <ore-textarea label=\"Bio\" loading></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 loading: prop.bool(false),\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.data<((el: HTMLTextAreaElement | null) => void) | null>(),\n required: prop.bool(false),\n resize: prop.oneOf(TEXTAREA_RESIZE),\n rows: prop.json(undefined as number | undefined),\n success: prop.bool(false),\n value: prop.string(),\n variant: prop.oneOf(FIELD_VARIANTS),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n // `loading` behaves like a temporary `disabled`: see ore-input's identical computation.\n const isDisabled = computed(() => props.disabled.value || props.loading.value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: isDisabled,\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 setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'change');\n },\n onInput: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'input');\n },\n prefix: 'textarea',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n value: props.value,\n });\n\n defineFieldValue(\n el,\n () => tf.value.value,\n (value) => {\n tf.value.value = value;\n },\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 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 const unwireRef = bindRefCallback(props.ref, textareaEl);\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 unwireRef();\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: props.size,\n // Reflects `success` only once `error` is confirmed empty: keeps the two host\n // attributes mutually exclusive even if a consumer sets both props at once.\n success: () => (props.success.value && !errorText.value ? true : undefined),\n variant: props.variant,\n },\n });\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}\n </label>\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=\"${isDisabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n value=\"${model(tf.value)}\"\n aria-describedby=\"${ariaDescribedBy}\"\n aria-errormessage=\"${ariaErrorMessage}\"\n aria-invalid=\"${ariaInvalid}\"\n aria-labelledby=\"${ariaLabelledBy}\"\n aria-busy=\"${() => (props.loading.value ? 'true' : null)}\"></textarea>\n ${renderStatusIcon(errorText)}\n <span class=\"field-spinner\" part=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>\n </div>\n ${renderFieldStatusRegion({ assistiveId, counter, errorId, errorText, helperText })}\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n disabledLoadingMixin,\n sizeVariantMixin(TEXTAREA_SIZE_PRESET),\n forcedColorsFocusMixin('textarea'),\n componentStyles,\n // Must come after `componentStyles`: see `ore-input`'s identical ordering note for why\n // (`@layer` precedence is fixed by which layer name is *first* referenced across this whole\n // array; `componentStyles` establishes `refine.base`, which this mixin's `refine.variants`\n // rules need to win over).\n fieldVariantMixin({ container: '.field', text: 'textarea', tokenPrefix: 'textarea' }),\n ],\n});\n"],"mappings":"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"}
|
package/dist/textarea.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import{defineFieldValue as e,dispatchNativeFieldEvent as t,setFieldValue as n}from"./inputs/shared/native-field-event.js";import{coarsePointerMixin as r,reducedMotionMixin as i}from"./styles/mixins/accessibility.css.js";import{fieldVariantMixin as a}from"./styles/mixins/field-variants.css.js";import{roundedVariantMixin as o,sizeVariantMixin as s}from"./styles/mixins/shape.css.js";import{disabledLoadingMixin as c}from"./styles/mixins/states.css.js";import{colorThemeMixin as l,forcedColorsFocusMixin as u}from"./styles/mixins/theme.css.js";import{createAutoResize as d}from"./core/auto-resize.js";import{lifecycleSignal as f}from"./core/ore.js";import{bindRefCallback as p}from"./core/ref-callback.js";import{createTextField as m}from"./core/text-field.js";import{disablableBundle as
|
|
1
|
+
import{defineFieldValue as e,dispatchNativeFieldEvent as t,setFieldValue as n}from"./inputs/shared/native-field-event.js";import{coarsePointerMixin as r,reducedMotionMixin as i}from"./styles/mixins/accessibility.css.js";import{fieldVariantMixin as a}from"./styles/mixins/field-variants.css.js";import{roundedVariantMixin as o,sizeVariantMixin as s}from"./styles/mixins/shape.css.js";import{disabledLoadingMixin as c}from"./styles/mixins/states.css.js";import{colorThemeMixin as l,forcedColorsFocusMixin as u}from"./styles/mixins/theme.css.js";import{createAutoResize as d}from"./core/auto-resize.js";import{lifecycleSignal as f}from"./core/ore.js";import{bindRefCallback as p}from"./core/ref-callback.js";import{createTextField as m}from"./core/text-field.js";import{FIELD_VARIANTS as h}from"./shared/types.js";import{disablableBundle as g,roundableBundle as _,sizableBundle as v,themableBundle as y}from"./shared/prop-bundles.js";import{TEXTAREA_SIZE_PRESET as b}from"./shared/size-presets.js";import{ICON_TAG as x}from"./icon.js";import{errorAttr as S}from"./inputs/shared/field-binding.js";import{renderFieldStatusRegion as C,renderStatusIcon as w}from"./inputs/shared/templates.js";import T from"./inputs/textarea/textarea.css.js";import{computed as E}from"@vielzeug/ripple";import{bind as D,define as O,getHost as k,html as A,model as j,onCleanup as M,onElement as N,prop as P,ref as F,useField as I,watchEffect as L}from"@vielzeug/ore";var R=[`none`,`both`,`horizontal`,`vertical`],z=`ore-textarea`;O(z,{formAssociated:!0,props:{...y,...v,...g,..._,"auto-resize":P.bool(!1),error:P.string(),fullwidth:P.bool(!1),helper:P.string(),label:P.string(),"label-placement":P.oneOf([`inset`,`outside`],`inset`),loading:P.bool(!1),maxlength:P.json(void 0),name:P.string(),"no-resize":P.bool(!1),placeholder:P.string(),readonly:P.bool(!1),ref:P.data(),required:P.bool(!1),resize:P.oneOf(R),rows:P.json(void 0),success:P.bool(!1),value:P.string(),variant:P.oneOf(h)},setup(r){let i=k(),a=L,o=F(),s=d({enabled:r[`auto-resize`]}),c=E(()=>r.disabled.value||r.loading.value),l=f(M),u=m({disabled:c,error:r.error,helper:r.helper,label:r.label,labelPlacement:r[`label-placement`],maxLength:r.maxlength,onChange:(e,r)=>{n(i,r),t(i,`change`)},onInput:(e,r)=>{n(i,r),t(i,`input`)},prefix:`textarea`,readonly:r.readonly,required:r.required,signal:l,value:r.value});e(i,()=>u.value.value,e=>{u.value.value=e}),u.attachFormField(I({disabled:u.disabled,onReset:()=>{u.reset(),requestAnimationFrame(()=>s.recompute())},toFormValue:e=>e,validity:u.validity,value:u.value}));let{ariaDescribedBy:h,ariaErrorMessage:g,ariaInvalid:_,ariaLabelledBy:v,assistiveId:y,counter:b,errorId:x,errorText:T,fieldId:O,helperText:P,labelId:R,labelVisible:z}=u;return N(o,e=>{let t=u.wire(e),n=s.wire(e),i=p(r.ref,e),o=a(()=>{e.style.resize=r[`auto-resize`].value||r[`no-resize`].value?`none`:r.resize.value||`vertical`,requestAnimationFrame(()=>s.recompute())});return()=>{i(),t(),n(),o()}}),D({attr:{error:S(T),size:r.size,success:()=>r.success.value&&!T.value?!0:void 0,variant:r.variant}}),A`
|
|
2
2
|
<div class="textarea-wrapper" part="wrapper">
|
|
3
|
-
<label class="label" part="label" for="${
|
|
3
|
+
<label class="label" part="label" for="${O}" id="${R}" ?hidden="${()=>!z.value}">
|
|
4
4
|
${r.label}
|
|
5
5
|
</label>
|
|
6
6
|
<div class="field" part="field">
|
|
7
7
|
<textarea
|
|
8
8
|
part="textarea"
|
|
9
9
|
ref="${o}"
|
|
10
|
-
id="${
|
|
10
|
+
id="${O}"
|
|
11
11
|
name="${r.name}"
|
|
12
12
|
placeholder="${r.placeholder}"
|
|
13
13
|
rows="${r.rows}"
|
|
@@ -15,16 +15,16 @@ import{defineFieldValue as e,dispatchNativeFieldEvent as t,setFieldValue as n}fr
|
|
|
15
15
|
?disabled="${c}"
|
|
16
16
|
?readonly="${r.readonly}"
|
|
17
17
|
?required="${r.required}"
|
|
18
|
-
value="${
|
|
18
|
+
value="${j(u.value)}"
|
|
19
19
|
aria-describedby="${h}"
|
|
20
20
|
aria-errormessage="${g}"
|
|
21
21
|
aria-invalid="${_}"
|
|
22
22
|
aria-labelledby="${v}"
|
|
23
23
|
aria-busy="${()=>r.loading.value?`true`:null}"></textarea>
|
|
24
|
-
${
|
|
24
|
+
${w(T)}
|
|
25
25
|
<span class="field-spinner" part="spinner" role="status" aria-label="Loading"></span>
|
|
26
26
|
</div>
|
|
27
|
-
${
|
|
27
|
+
${C({assistiveId:y,counter:b,errorId:x,errorText:T,helperText:P})}
|
|
28
28
|
</div>
|
|
29
|
-
`},shadow:{delegatesFocus:!0},styles:[l,r,i,o,c,s(
|
|
29
|
+
`},shadow:{delegatesFocus:!0},styles:[l,r,i,o,c,s(b),u(`textarea`),T,a({container:`.field`,text:`textarea`,tokenPrefix:`textarea`})]});export{x as ICON_TAG,z as TEXTAREA_TAG};
|
|
30
30
|
//# 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 {\n bind,\n define,\n getHost,\n html,\n live,\n onCleanup,\n onElement,\n prop,\n ref,\n useField,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { bindRefCallback, createAutoResize, createTextField, lifecycleSignal } from '../../core';\nimport type { TextFieldProps } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n fieldVariantMixin,\n forcedColorsFocusMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport type { VisualVariant } from '../../types';\nimport { errorAttr } from '../shared/field-binding';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport { renderFieldStatusRegion, renderStatusIcon } from '../shared/templates';\nimport componentStyles from './textarea.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: Event;\n input: InputEvent;\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /**\n * Shows an inline spinner inside the field and forces the inner `<textarea>` into\n * `disabled` for the duration: use while an async validation/submission request\n * is in flight to prevent double-submits.\n */\n loading?: 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 {boolean} loading - Show an inline spinner and force the field disabled\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\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.\n * @fires change - Fired on blur with changed value.\n *\n * @slot helper - Complex helper content\n *\n * @part status-icon - The inline error/success icon shown inside the field\n * @part spinner - The inline loading spinner shown inside the field while `loading`\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 * <ore-textarea label=\"Bio\" success></ore-textarea>\n * <ore-textarea label=\"Bio\" loading></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 loading: prop.bool(false),\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.data<((el: HTMLTextAreaElement | null) => void) | null>(),\n required: prop.bool(false),\n resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n success: prop.bool(false),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n // `loading` behaves like a temporary `disabled`: see ore-input's identical computation.\n const isDisabled = computed(() => props.disabled.value || props.loading.value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: isDisabled,\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 setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'change');\n },\n onInput: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'input');\n },\n prefix: 'textarea',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n value: props.value,\n });\n\n defineFieldValue(\n el,\n () => tf.value.value,\n (value) => {\n tf.value.value = value;\n },\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 const unwireRef = bindRefCallback(props.ref, textareaEl);\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 unwireRef();\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: props.size,\n // Reflects `success` only once `error` is confirmed empty: keeps the two host\n // attributes mutually exclusive even if a consumer sets both props at once.\n success: () => (props.success.value && !errorText.value ? true : undefined),\n variant: props.variant,\n },\n });\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}\n </label>\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=\"${isDisabled}\"\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}\"\n aria-busy=\"${() => (props.loading.value ? 'true' : null)}\"></textarea>\n ${renderStatusIcon(errorText)}\n <span class=\"field-spinner\" part=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>\n </div>\n ${renderFieldStatusRegion({ assistiveId, counter, errorId, errorText, helperText })}\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n disabledLoadingMixin,\n sizeVariantMixin(TEXTAREA_SIZE_PRESET),\n forcedColorsFocusMixin('textarea'),\n componentStyles,\n // Must come after `componentStyles`: see `ore-input`'s identical ordering note for why\n // (`@layer` precedence is fixed by which layer name is *first* referenced across this whole\n // array; `componentStyles` establishes `refine.base`, which this mixin's `refine.variants`\n // rules need to win over).\n fieldVariantMixin({ container: '.field', text: 'textarea', tokenPrefix: 'textarea' }),\n ],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textarea.js","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import {\n bind,\n define,\n getHost,\n html,\n model,\n onCleanup,\n onElement,\n prop,\n ref,\n useField,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { bindRefCallback, createAutoResize, createTextField, lifecycleSignal } from '../../core';\nimport type { TextFieldProps } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n fieldVariantMixin,\n forcedColorsFocusMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport { FIELD_VARIANTS, type FieldVariant } from '../../types';\nimport { errorAttr } from '../shared/field-binding';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport { renderFieldStatusRegion, renderStatusIcon } from '../shared/templates';\nimport componentStyles from './textarea.css?inline';\n\nconst TEXTAREA_RESIZE = ['none', 'both', 'horizontal', 'vertical'] as const;\n\nexport { ICON_TAG } from '../../content/icon/icon';\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: Event;\n input: InputEvent;\n};\n\nexport type OreTextareaProps = TextFieldProps<FieldVariant> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /**\n * Shows an inline spinner inside the field and forces the inner `<textarea>` into\n * `disabled` for the duration: use while an async validation/submission request\n * is in flight to prevent double-submits.\n */\n loading?: 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?: (typeof TEXTAREA_RESIZE)[number];\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 {boolean} loading - Show an inline spinner and force the field disabled\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\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.\n * @fires change - Fired on blur with changed value.\n *\n * @slot helper - Complex helper content\n *\n * @part status-icon - The inline error/success icon shown inside the field\n * @part spinner - The inline loading spinner shown inside the field while `loading`\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 * <ore-textarea label=\"Bio\" success></ore-textarea>\n * <ore-textarea label=\"Bio\" loading></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 loading: prop.bool(false),\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.data<((el: HTMLTextAreaElement | null) => void) | null>(),\n required: prop.bool(false),\n resize: prop.oneOf(TEXTAREA_RESIZE),\n rows: prop.json(undefined as number | undefined),\n success: prop.bool(false),\n value: prop.string(),\n variant: prop.oneOf(FIELD_VARIANTS),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n // `loading` behaves like a temporary `disabled`: see ore-input's identical computation.\n const isDisabled = computed(() => props.disabled.value || props.loading.value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: isDisabled,\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 setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'change');\n },\n onInput: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'input');\n },\n prefix: 'textarea',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n value: props.value,\n });\n\n defineFieldValue(\n el,\n () => tf.value.value,\n (value) => {\n tf.value.value = value;\n },\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 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 const unwireRef = bindRefCallback(props.ref, textareaEl);\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 unwireRef();\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: props.size,\n // Reflects `success` only once `error` is confirmed empty: keeps the two host\n // attributes mutually exclusive even if a consumer sets both props at once.\n success: () => (props.success.value && !errorText.value ? true : undefined),\n variant: props.variant,\n },\n });\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}\n </label>\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=\"${isDisabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n value=\"${model(tf.value)}\"\n aria-describedby=\"${ariaDescribedBy}\"\n aria-errormessage=\"${ariaErrorMessage}\"\n aria-invalid=\"${ariaInvalid}\"\n aria-labelledby=\"${ariaLabelledBy}\"\n aria-busy=\"${() => (props.loading.value ? 'true' : null)}\"></textarea>\n ${renderStatusIcon(errorText)}\n <span class=\"field-spinner\" part=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>\n </div>\n ${renderFieldStatusRegion({ assistiveId, counter, errorId, errorText, helperText })}\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n disabledLoadingMixin,\n sizeVariantMixin(TEXTAREA_SIZE_PRESET),\n forcedColorsFocusMixin('textarea'),\n componentStyles,\n // Must come after `componentStyles`: see `ore-input`'s identical ordering note for why\n // (`@layer` precedence is fixed by which layer name is *first* referenced across this whole\n // array; `componentStyles` establishes `refine.base`, which this mixin's `refine.variants`\n // rules need to win over).\n fieldVariantMixin({ container: '.field', text: 'textarea', tokenPrefix: 'textarea' }),\n ],\n});\n"],"mappings":"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"}
|
package/dist/time-picker.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./inputs/shared/native-field-event.cjs"),t=require("./styles/mixins/accessibility.css.cjs"),n=require("./styles/mixins/theme.css.cjs"),r=require("./core/positioner.cjs"),i=require("./shared/prop-bundles.cjs"),
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./inputs/shared/native-field-event.cjs"),t=require("./styles/mixins/accessibility.css.cjs"),n=require("./styles/mixins/theme.css.cjs"),r=require("./core/positioner.cjs"),i=require("./shared/types.cjs"),a=require("./shared/prop-bundles.cjs"),o=require("./icon.cjs"),s=require("./input.cjs"),c=require("./inputs/time-picker/time-picker.css.cjs");let l=require("@vielzeug/ripple"),u=require("@vielzeug/ore");function parseTime(e){if(!e)return null;let t=/^(\d{1,2}):(\d{2})$/.exec(e.trim());if(!t)return null;let n=Number(t[1]),r=Number(t[2]);return n<0||n>23||r<0||r>59?null:{hours:n,minutes:r}}function formatTime(e,t){return`${String(e).padStart(2,`0`)}:${String(t).padStart(2,`0`)}`}function formatDisplay(e,t,n){if(n===`12`){let n=e>=12?`PM`:`AM`,r=e%12==0?12:e%12;return`${String(r).padStart(2,`0`)}:${String(t).padStart(2,`0`)} ${n}`}return formatTime(e,t)}function clampTime(e,t,n,r){let i=e*60+t,a=parseTime(n),o=parseTime(r),s=a?a.hours*60+a.minutes:0,c=o?o.hours*60+o.minutes:1439,l=Math.min(Math.max(i,s),c);return{hours:Math.floor(l/60),minutes:l%60}}var d=`ore-time-picker`;(0,u.define)(d,{formAssociated:!0,props:{...a.themableBundle,...a.sizableBundle,...a.disablableBundle,...a.roundableBundle,error:u.prop.string(),fullwidth:u.prop.bool(!1),helper:u.prop.string(),label:u.prop.string(),"label-placement":u.prop.oneOf([`inset`,`outside`],`inset`),max:u.prop.string(),min:u.prop.string(),"minute-step":u.prop.number(5),name:u.prop.string(),placeholder:u.prop.string(),required:u.prop.bool(!1),success:u.prop.bool(!1),"time-format":u.prop.oneOf([`12`,`24`],`24`),value:u.prop.string(),variant:u.prop.oneOf(i.FIELD_VARIANTS)},setup(t){let n=(0,u.getHost)(),i=(0,l.signal)(!1),a=(0,l.signal)(parseTime(t.value.value));e.defineFieldValue(n,()=>{let e=a.value;return e?formatTime(e.hours,e.minutes):``},e=>{a.value=parseTime(e)});let o=(0,u.ref)(),s=(0,u.ref)(),c=r.createDropdownPositioner({getFloating:()=>s.value??null,getOffsetPx:()=>4,getReference:()=>o.value??null,matchWidth:!1}),d=null,f=(0,l.computed)(()=>!!t.disabled.value);(0,u.useField)({disabled:f,toFormValue:e=>e||null,value:(0,l.computed)(()=>{let e=a.value;return e?formatTime(e.hours,e.minutes):``})});let p=(0,l.computed)(()=>t[`time-format`].value??`24`),m=(0,l.computed)(()=>Math.max(1,Math.min(59,t[`minute-step`].value??5))),h=(0,l.computed)(()=>a.value?formatDisplay(a.value.hours,a.value.minutes,p.value):t.placeholder.value||``),g=(0,l.computed)(()=>p.value===`12`?Array.from({length:12},(e,t)=>t+1):Array.from({length:24},(e,t)=>t)),_=(0,l.computed)(()=>{let e=m.value,t=[];for(let n=0;n<60;n+=e)t.push(n);return t}),v=`time-picker-${Math.random().toString(36).slice(2,9)}-dropdown`;function toDisplayHour(e){if(p.value===`24`)return e;let t=e%12;return t===0?12:t}function to24Hour(e,t){return p.value===`24`?e:t===`AM`?e===12?0:e:e===12?12:e+12}function isTimeDisabled(e,n){let r=e*60+n,i=parseTime(t.min.value),a=parseTime(t.max.value);return!!(i&&r<i.hours*60+i.minutes||a&&r>a.hours*60+a.minutes)}let y=(0,l.signal)(a.value?.hours??0),b=(0,l.signal)(a.value?.minutes??0),x=(0,l.signal)((a.value?.hours??0)>=12?`PM`:`AM`),S=t.value.value;(0,u.onMounted)(()=>{let e=setInterval(()=>{let e=t.value.value;if(e!==S){S=e;let t=parseTime(e);a.value=t,t&&(y.value=t.hours,b.value=t.minutes,x.value=t.hours>=12?`PM`:`AM`)}},50);return()=>clearInterval(e)});function commit(r,i){let o=clampTime(r,i,t.min.value,t.max.value),s=Math.round(o.minutes/m.value)*m.value,c=Math.min(s,59);a.value={hours:o.hours,minutes:c},e.setFieldValue(n,formatTime(o.hours,c)),e.dispatchNativeFieldEvent(n,`input`),e.dispatchNativeFieldEvent(n,`change`)}function commitFromMinute(e){let t=p.value===`12`?to24Hour(y.value,x.value):y.value;b.value=e,commit(t,e),closePicker()}function openPicker(){if(f.value)return;let e=a.value;e?(y.value=p.value===`12`?toDisplayHour(e.hours):e.hours,b.value=e.minutes,x.value=e.hours>=12?`PM`:`AM`):(y.value=p.value===`12`?12:0,b.value=0,x.value=`AM`),i.value=!0,c.update(),d=c.startAutoUpdate?.()??null}function closePicker(){i.value=!1,d?.(),d=null}function handleTriggerClick(){i.value?closePicker():openPicker()}function handleOutsideClick(e){i.value&&(e.composedPath().includes(n)||closePicker())}(0,u.onMounted)(()=>(document.addEventListener(`pointerdown`,handleOutsideClick,{capture:!0}),()=>{document.removeEventListener(`pointerdown`,handleOutsideClick,{capture:!0}),d?.(),d=null}));function handleTriggerKeydown(e){f.value||(e.key===`Enter`||e.key===` `?(e.preventDefault(),handleTriggerClick()):e.key===`Escape`&&i.value?(e.preventDefault(),closePicker()):(e.key===`ArrowDown`||e.key===`ArrowUp`)&&!i.value&&(e.preventDefault(),openPicker()))}function handleDropdownKeydown(e){e.key===`Escape`&&(e.preventDefault(),closePicker())}function handleHourKeydown(e){let t=g.value,n=t.indexOf(y.value);e.key===`ArrowUp`?(e.preventDefault(),y.value=t[(n-1+t.length)%t.length]):e.key===`ArrowDown`&&(e.preventDefault(),y.value=t[(n+1)%t.length])}function handleMinuteKeydown(e){let t=_.value,n=t.indexOf(b.value);e.key===`ArrowUp`?(e.preventDefault(),b.value=t[(n-1+t.length)%t.length]):e.key===`ArrowDown`&&(e.preventDefault(),b.value=t[(n+1)%t.length])}function handlePeriodKeydown(e){(e.key===`ArrowUp`||e.key===`ArrowDown`)&&(e.preventDefault(),x.value=x.value===`AM`?`PM`:`AM`)}(0,u.bind)({attr:{open:()=>i.value?!0:void 0}});let inputValue=()=>h.value,inputLabel=()=>t.label.value??``,inputPlaceholder=()=>t.placeholder.value??``,inputLabelPlacement=()=>t[`label-placement`].value??`inset`,inputColor=()=>t.color?.value??void 0,inputSize=()=>t.size?.value??void 0,inputVariant=()=>t.variant?.value??void 0,inputRounded=()=>t.rounded?.value??void 0,inputHelper=()=>t.helper.value??``,inputError=()=>t.error.value??``,inputDisabled=()=>f.value?!0:void 0,inputRequired=()=>t.required.value?!0:void 0,inputFullwidth=()=>t.fullwidth.value?!0:void 0;return u.html`
|
|
2
2
|
<!-- Trigger -->
|
|
3
3
|
<ore-input
|
|
4
4
|
class="trigger"
|
|
@@ -43,7 +43,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
43
43
|
<div class="col" part="column" role="group" aria-label="Hours">
|
|
44
44
|
<div class="col-label" aria-hidden="true">HH</div>
|
|
45
45
|
<div class="col-scroll">
|
|
46
|
-
${()=>g.value.map(e=>{let t=isTimeDisabled(p.value===`12`?to24Hour(e,x.value):e,b.value);return
|
|
46
|
+
${()=>g.value.map(e=>{let t=isTimeDisabled(p.value===`12`?to24Hour(e,x.value):e,b.value);return u.html`
|
|
47
47
|
<div
|
|
48
48
|
class="option"
|
|
49
49
|
part="option"
|
|
@@ -66,7 +66,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
66
66
|
<div class="col" part="column" role="group" aria-label="Minutes">
|
|
67
67
|
<div class="col-label" aria-hidden="true">MM</div>
|
|
68
68
|
<div class="col-scroll">
|
|
69
|
-
${()=>_.value.map(e=>{let t=isTimeDisabled(p.value===`12`?to24Hour(y.value,x.value):y.value,e);return
|
|
69
|
+
${()=>_.value.map(e=>{let t=isTimeDisabled(p.value===`12`?to24Hour(y.value,x.value):y.value,e);return u.html`
|
|
70
70
|
<div
|
|
71
71
|
class="option"
|
|
72
72
|
part="option"
|
|
@@ -84,11 +84,11 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
84
84
|
</div>
|
|
85
85
|
|
|
86
86
|
<!-- AM/PM column (12h mode only) -->
|
|
87
|
-
${()=>p.value===`12`?
|
|
87
|
+
${()=>p.value===`12`?u.html`
|
|
88
88
|
<div class="col col-period" part="column" role="group" aria-label="Period">
|
|
89
89
|
<div class="col-label" aria-hidden="true">AM/PM</div>
|
|
90
90
|
<div class="col-scroll">
|
|
91
|
-
${[`AM`,`PM`].map(e=>
|
|
91
|
+
${[`AM`,`PM`].map(e=>u.html`
|
|
92
92
|
<div
|
|
93
93
|
class="option"
|
|
94
94
|
part="option"
|
|
@@ -102,8 +102,8 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
102
102
|
`)}
|
|
103
103
|
</div>
|
|
104
104
|
</div>
|
|
105
|
-
`:
|
|
105
|
+
`:u.html``}
|
|
106
106
|
</div>
|
|
107
107
|
</div>
|
|
108
|
-
`},shadow:{delegatesFocus:!0},styles:[n.colorThemeMixin,t.reducedMotionMixin,
|
|
108
|
+
`},shadow:{delegatesFocus:!0},styles:[n.colorThemeMixin,t.reducedMotionMixin,c.default]}),exports.ICON_TAG=o.ICON_TAG,exports.INPUT_TAG=s.INPUT_TAG,exports.TIME_PICKER_TAG=d;
|
|
109
109
|
//# sourceMappingURL=time-picker.cjs.map
|
package/dist/time-picker.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-picker.cjs","names":[],"sources":["../src/inputs/time-picker/time-picker.ts"],"sourcesContent":["import { bind, define, getHost, html, onMounted, prop, ref, useField } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { createDropdownPositioner } from '../../core';\nimport type { VisualVariant } from '../../shared';\n\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport componentStyles from './time-picker.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { INPUT_TAG } from '../input/input';\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreTimePickerEvents = {\n change: Event;\n input: Event;\n};\n\nexport type OreTimePickerProps = {\n /** Theme color */\n color?: string;\n /** Disable the picker */\n disabled?: boolean;\n /** Validation error message */\n error?: string;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Helper text below the field */\n helper?: string;\n /** Visible label */\n label?: string;\n /** Label placement */\n 'label-placement'?: 'inset' | 'outside';\n /** Maximum selectable time in HH:MM format (24-hour) */\n max?: string;\n /** Minimum selectable time in HH:MM format (24-hour) */\n min?: string;\n /** Minute step interval (1–59) */\n 'minute-step'?: number;\n /** Form field name */\n name?: string;\n /** Placeholder shown in the trigger */\n placeholder?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius */\n rounded?: string;\n /** Component size */\n size?: string;\n /**\n * Shows an inline green check icon inside the field to confirm the value has\n * passed validation. Ignored while `error` is set: an error always wins.\n */\n success?: boolean;\n /** Display format: '12' for AM/PM, '24' for 24-hour (default: '24') */\n 'time-format'?: '12' | '24';\n /** Selected time in HH:MM format (24-hour) */\n value?: string;\n /** Visual variant */\n variant?: Exclude<VisualVariant, 'text' | 'frost'>;\n};\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\n/** Parse \"HH:MM\" → { hours: 0-23, minutes: 0-59 } | null */\nfunction parseTime(val: string | undefined | null): { hours: number; minutes: number } | null {\n if (!val) return null;\n\n const match = /^(\\d{1,2}):(\\d{2})$/.exec(val.trim());\n\n if (!match) return null;\n\n const h = Number(match[1]);\n const m = Number(match[2]);\n\n if (h < 0 || h > 23 || m < 0 || m > 59) return null;\n\n return { hours: h, minutes: m };\n}\n\n/** Format { hours, minutes } → \"HH:MM\" (24-hour, zero-padded) */\nfunction formatTime(h: number, m: number): string {\n return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;\n}\n\n/** Format for display label (respects 12/24 mode) */\nfunction formatDisplay(h: number, m: number, format: '12' | '24'): string {\n if (format === '12') {\n const period = h >= 12 ? 'PM' : 'AM';\n const displayH = h % 12 === 0 ? 12 : h % 12;\n\n return `${String(displayH).padStart(2, '0')}:${String(m).padStart(2, '0')} ${period}`;\n }\n\n return formatTime(h, m);\n}\n\n/** Clamp value to [min, max] in total minutes */\nfunction clampTime(\n h: number,\n m: number,\n minVal: string | undefined | null,\n maxVal: string | undefined | null,\n): { hours: number; minutes: number } {\n const total = h * 60 + m;\n const minParsed = parseTime(minVal);\n const maxParsed = parseTime(maxVal);\n const minMins = minParsed ? minParsed.hours * 60 + minParsed.minutes : 0;\n const maxMins = maxParsed ? maxParsed.hours * 60 + maxParsed.minutes : 23 * 60 + 59;\n const clamped = Math.min(Math.max(total, minMins), maxMins);\n\n return { hours: Math.floor(clamped / 60), minutes: clamped % 60 };\n}\n\n/**\n * An accessible time picker with a scrollable clock dropdown.\n * Supports 12/24-hour display formats, min/max bounds, minute steps, and form association.\n *\n * @element ore-time-picker\n *\n * @attr {string} value - Selected time in HH:MM (24-hour) format\n * @attr {string} min - Minimum selectable time (HH:MM)\n * @attr {string} max - Maximum selectable time (HH:MM)\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} placeholder - Trigger placeholder\n * @attr {boolean} disabled - Disable the picker\n * @attr {boolean} required - Required field\n * @attr {string} name - Form field name\n * @attr {string} error - Error message\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\n * @attr {string} helper - Helper text\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} time-format - '12' or '24' (default: '24')\n * @attr {number} minute-step - Minute increment (default: 5)\n *\n * @fires input - Fired when a time is selected.\n * @fires change - Fired when a time is selected.\n *\n * @slot label - Custom label for the trigger field\n * @slot prefix - Content before the trigger text (e.g. icon)\n * @slot helper - Custom helper text\n * @slot error - Custom error content\n *\n * @cssprop --time-picker-bg - Dropdown background\n * @cssprop --time-picker-border-color - Dropdown border color\n * @cssprop --time-picker-radius - Dropdown border radius\n * @cssprop --time-picker-shadow - Dropdown shadow\n * @cssprop --time-picker-selected-bg - Selected option background\n * @cssprop --time-picker-option-hover-bg - Option hover background\n *\n * @part field - The trigger field\n * @part dropdown - The floating time dropdown\n * @part column - A scrollable column (hours / minutes / period)\n * @part option - An individual time option cell\n *\n * @example\n * ```html\n * <!-- 24-hour clock, 15-minute steps -->\n * <ore-time-picker label=\"Meeting time\" value=\"09:30\" minute-step=\"15\" color=\"primary\"></ore-time-picker>\n *\n * <!-- 12-hour AM/PM format -->\n * <ore-time-picker label=\"Appointment\" time-format=\"12\" minute-step=\"30\"></ore-time-picker>\n *\n * <!-- Outside label, bordered variant -->\n * <ore-time-picker label=\"Start time\" label-placement=\"outside\" variant=\"bordered\"></ore-time-picker>\n * ```\n */\nexport const TIME_PICKER_TAG = 'ore-time-picker' as const;\n\ndefine<OreTimePickerProps>(TIME_PICKER_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\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 max: prop.string(),\n min: prop.string(),\n 'minute-step': prop.number(5),\n name: prop.string(),\n placeholder: prop.string(),\n required: prop.bool(false),\n success: prop.bool(false),\n 'time-format': prop.oneOf(['12', '24'] as const, '24'),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n\n setup(props) {\n const el = getHost();\n\n // ── Signals ──────────────────────────────────────────────────────────────\n\n const isOpen = signal(false);\n const selectedTime = signal<{ hours: number; minutes: number } | null>(parseTime(props.value.value));\n\n defineFieldValue(\n el,\n () => {\n const value = selectedTime.value;\n\n return value ? formatTime(value.hours, value.minutes) : '';\n },\n (value) => {\n selectedTime.value = parseTime(value);\n },\n );\n\n // ── Floating position ────────────────────────────────────────────────────\n // Same Orbit-powered positioner ore-date-picker's `.calendar` popup uses (see its own\n // comment for the full rationale): `fixed` + computed `top`/`left` instead of a static\n // `position: absolute; top: 100%`, so the dropdown flips/shifts to stay within the nearest\n // clipping ancestor instead of silently overflowing it.\n const triggerRef = ref<HTMLElement>();\n const dropdownRef = ref<HTMLElement>();\n\n const positioner = createDropdownPositioner({\n getFloating: () => dropdownRef.value ?? null,\n getOffsetPx: () => 4,\n getReference: () => triggerRef.value ?? null,\n matchWidth: false,\n });\n\n let stopAutoUpdate: (() => void) | null = null;\n\n const isDisabled = computed(() => Boolean(props.disabled.value));\n\n // ── Form value ────────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => {\n const t = selectedTime.value;\n\n return t ? formatTime(t.hours, t.minutes) : '';\n }),\n });\n\n // ── Computed helpers ──────────────────────────────────────────────────────\n\n const fmt = computed(() => props['time-format'].value ?? '24');\n const minuteStep = computed(() => Math.max(1, Math.min(59, props['minute-step'].value ?? 5)));\n\n const triggerText = computed(() => {\n if (!selectedTime.value) return props.placeholder.value || '';\n\n return formatDisplay(selectedTime.value.hours, selectedTime.value.minutes, fmt.value as '12' | '24');\n });\n\n /** All hour options for the column (0-23 in 24h; 1-12 in 12h) */\n const hourOptions = computed<number[]>(() => {\n if (fmt.value === '12') {\n return Array.from({ length: 12 }, (_, i) => i + 1);\n }\n\n return Array.from({ length: 24 }, (_, i) => i);\n });\n\n /** All minute options for the column, stepped */\n const minuteOptions = computed<number[]>(() => {\n const step = minuteStep.value;\n const opts: number[] = [];\n\n for (let m = 0; m < 60; m += step) opts.push(m);\n\n return opts;\n });\n\n const dialogId = `time-picker-${Math.random().toString(36).slice(2, 9)}-dropdown`;\n\n /** Convert 24h hour to display hour in current format */\n function toDisplayHour(h24: number): number {\n if (fmt.value === '24') return h24;\n\n const h12 = h24 % 12;\n\n return h12 === 0 ? 12 : h12;\n }\n\n /** Convert display hour + period → 24h hour */\n function to24Hour(displayHour: number, period: 'AM' | 'PM'): number {\n if (fmt.value === '24') return displayHour;\n\n if (period === 'AM') return displayHour === 12 ? 0 : displayHour;\n\n return displayHour === 12 ? 12 : displayHour + 12;\n }\n\n /** Whether a given HH:MM is out of [min, max] */\n function isTimeDisabled(h: number, m: number): boolean {\n const total = h * 60 + m;\n const minParsed = parseTime(props.min.value);\n const maxParsed = parseTime(props.max.value);\n\n if (minParsed && total < minParsed.hours * 60 + minParsed.minutes) return true;\n\n if (maxParsed && total > maxParsed.hours * 60 + maxParsed.minutes) return true;\n\n return false;\n }\n\n // ── State for focused/pending selection ───────────────────────────────────\n\n /** Pending hour (24h) while user is navigating columns */\n const pendingHour = signal<number>(selectedTime.value?.hours ?? 0);\n /** Pending minute */\n const pendingMinute = signal<number>(selectedTime.value?.minutes ?? 0);\n /** Pending period (12h mode) */\n const pendingPeriod = signal<'AM' | 'PM'>((selectedTime.value?.hours ?? 0) >= 12 ? 'PM' : 'AM');\n\n // ── Sync value prop externally ────────────────────────────────────────────\n\n let lastValueProp = props.value.value;\n\n onMounted(() => {\n const interval = setInterval(() => {\n const current = props.value.value;\n\n if (current !== lastValueProp) {\n lastValueProp = current;\n\n const parsed = parseTime(current);\n\n selectedTime.value = parsed;\n\n if (parsed) {\n pendingHour.value = parsed.hours;\n pendingMinute.value = parsed.minutes;\n pendingPeriod.value = parsed.hours >= 12 ? 'PM' : 'AM';\n }\n }\n }, 50);\n\n return () => clearInterval(interval);\n });\n\n // ── Commit ────────────────────────────────────────────────────────────────\n\n function commit(h24: number, m: number): void {\n const clamped = clampTime(h24, m, props.min.value, props.max.value);\n const snapped = Math.round(clamped.minutes / minuteStep.value) * minuteStep.value;\n const snappedMin = Math.min(snapped, 59);\n\n selectedTime.value = { hours: clamped.hours, minutes: snappedMin };\n setFieldValue(el, formatTime(clamped.hours, snappedMin));\n dispatchNativeFieldEvent(el, 'input');\n dispatchNativeFieldEvent(el, 'change');\n }\n\n function commitFromMinute(m: number): void {\n const h24 = fmt.value === '12' ? to24Hour(pendingHour.value, pendingPeriod.value) : pendingHour.value;\n\n pendingMinute.value = m;\n commit(h24, m);\n closePicker();\n }\n\n // ── Open / close ──────────────────────────────────────────────────────────\n\n function openPicker(): void {\n if (isDisabled.value) return;\n\n const current = selectedTime.value;\n\n if (current) {\n pendingHour.value = fmt.value === '12' ? toDisplayHour(current.hours) : current.hours;\n pendingMinute.value = current.minutes;\n pendingPeriod.value = current.hours >= 12 ? 'PM' : 'AM';\n } else {\n pendingHour.value = fmt.value === '12' ? 12 : 0;\n pendingMinute.value = 0;\n pendingPeriod.value = 'AM';\n }\n\n isOpen.value = true;\n positioner.update();\n stopAutoUpdate = positioner.startAutoUpdate?.() ?? null;\n }\n\n function closePicker(): void {\n isOpen.value = false;\n stopAutoUpdate?.();\n stopAutoUpdate = null;\n }\n\n function handleTriggerClick(): void {\n if (isOpen.value) closePicker();\n else openPicker();\n }\n\n // ── Outside click ─────────────────────────────────────────────────────────\n\n function handleOutsideClick(e: PointerEvent | MouseEvent): void {\n if (!isOpen.value) return;\n\n if (!e.composedPath().includes(el)) closePicker();\n }\n\n onMounted(() => {\n document.addEventListener('pointerdown', handleOutsideClick, { capture: true });\n\n return () => {\n document.removeEventListener('pointerdown', handleOutsideClick, { capture: true });\n stopAutoUpdate?.();\n stopAutoUpdate = null;\n };\n });\n\n // ── Keyboard ──────────────────────────────────────────────────────────────\n\n function handleTriggerKeydown(e: KeyboardEvent): void {\n if (isDisabled.value) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleTriggerClick();\n } else if (e.key === 'Escape' && isOpen.value) {\n e.preventDefault();\n closePicker();\n } else if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && !isOpen.value) {\n e.preventDefault();\n openPicker();\n }\n }\n\n function handleDropdownKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n closePicker();\n }\n }\n\n function handleHourKeydown(e: KeyboardEvent): void {\n const opts = hourOptions.value;\n const idx = opts.indexOf(pendingHour.value);\n\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n pendingHour.value = opts[(idx - 1 + opts.length) % opts.length];\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n pendingHour.value = opts[(idx + 1) % opts.length];\n }\n }\n\n function handleMinuteKeydown(e: KeyboardEvent): void {\n const opts = minuteOptions.value;\n const idx = opts.indexOf(pendingMinute.value);\n\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n pendingMinute.value = opts[(idx - 1 + opts.length) % opts.length];\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n pendingMinute.value = opts[(idx + 1) % opts.length];\n }\n }\n\n function handlePeriodKeydown(e: KeyboardEvent): void {\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault();\n pendingPeriod.value = pendingPeriod.value === 'AM' ? 'PM' : 'AM';\n }\n }\n\n // ── Host bindings ─────────────────────────────────────────────────────────\n\n bind({\n attr: {\n open: () => (isOpen.value ? true : undefined),\n },\n });\n\n // ── ore-input prop helpers ────────────────────────────────────────────────\n\n const inputValue = () => triggerText.value;\n const inputLabel = () => props.label.value ?? '';\n const inputPlaceholder = () => props.placeholder.value ?? '';\n const inputLabelPlacement = () => props['label-placement'].value ?? 'inset';\n const inputColor = () => props.color?.value ?? undefined;\n const inputSize = () => props.size?.value ?? undefined;\n const inputVariant = () => props.variant?.value ?? undefined;\n const inputRounded = () => props.rounded?.value ?? undefined;\n const inputHelper = () => props.helper.value ?? '';\n const inputError = () => props.error.value ?? '';\n const inputDisabled = () => (isDisabled.value ? true : undefined);\n const inputRequired = () => (props.required.value ? true : undefined);\n const inputFullwidth = () => (props.fullwidth.value ? true : undefined);\n\n return html`\n <!-- Trigger -->\n <ore-input\n class=\"trigger\"\n ref=\"${triggerRef}\"\n readonly\n tabindex=\"0\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-controls=\"${dialogId}\"\n aria-expanded=\"${() => String(isOpen.value)}\"\n aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\"\n value=\"${inputValue}\"\n label=\"${inputLabel}\"\n placeholder=\"${inputPlaceholder}\"\n label-placement=\"${inputLabelPlacement}\"\n color=\"${inputColor}\"\n size=\"${inputSize}\"\n variant=\"${inputVariant}\"\n rounded=\"${inputRounded}\"\n helper=\"${inputHelper}\"\n error=\"${inputError}\"\n ?disabled=\"${inputDisabled}\"\n ?required=\"${inputRequired}\"\n ?fullwidth=\"${inputFullwidth}\"\n ?success=\"${() => props.success.value}\"\n @click=\"${handleTriggerClick}\"\n @keydown=\"${handleTriggerKeydown}\">\n <ore-icon slot=\"suffix\" name=\"clock\" size=\"16\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-input>\n\n <!-- Dropdown -->\n <div\n class=\"dropdown\"\n ref=\"${dropdownRef}\"\n id=\"${dialogId}\"\n role=\"listbox\"\n aria-label=\"${() => (props.label.value ? `${props.label.value}: select time` : 'Select time')}\"\n ?data-open=\"${isOpen}\"\n @keydown=\"${handleDropdownKeydown}\">\n <div class=\"cols-row\">\n <!-- Hours column -->\n <div class=\"col\" part=\"column\" role=\"group\" aria-label=\"Hours\">\n <div class=\"col-label\" aria-hidden=\"true\">HH</div>\n <div class=\"col-scroll\">\n ${() =>\n hourOptions.value.map((h) => {\n const h24 = fmt.value === '12' ? to24Hour(h, pendingPeriod.value) : h;\n const disabled = isTimeDisabled(h24, pendingMinute.value);\n\n return html`\n <div\n class=\"option\"\n part=\"option\"\n role=\"option\"\n tabindex=\"${() => (pendingHour.value === h && !disabled ? '0' : '-1')}\"\n aria-selected=\"${() => String(pendingHour.value === h)}\"\n aria-disabled=\"${() => String(disabled)}\"\n ?data-disabled=\"${() => disabled}\"\n @click=\"${() => {\n if (!disabled) pendingHour.value = h;\n }}\"\n @keydown=\"${handleHourKeydown}\">\n ${String(h).padStart(2, '0')}\n </div>\n `;\n })}\n </div>\n </div>\n\n <div class=\"col-sep\" aria-hidden=\"true\">:</div>\n\n <!-- Minutes column -->\n <div class=\"col\" part=\"column\" role=\"group\" aria-label=\"Minutes\">\n <div class=\"col-label\" aria-hidden=\"true\">MM</div>\n <div class=\"col-scroll\">\n ${() =>\n minuteOptions.value.map((m) => {\n const h24 = fmt.value === '12' ? to24Hour(pendingHour.value, pendingPeriod.value) : pendingHour.value;\n const disabled = isTimeDisabled(h24, m);\n\n return html`\n <div\n class=\"option\"\n part=\"option\"\n role=\"option\"\n tabindex=\"${() => (pendingMinute.value === m && !disabled ? '0' : '-1')}\"\n aria-selected=\"${() => String(pendingMinute.value === m)}\"\n aria-disabled=\"${() => String(disabled)}\"\n ?data-disabled=\"${() => disabled}\"\n @click=\"${() => {\n if (!disabled) commitFromMinute(m);\n }}\"\n @keydown=\"${handleMinuteKeydown}\">\n ${String(m).padStart(2, '0')}\n </div>\n `;\n })}\n </div>\n </div>\n\n <!-- AM/PM column (12h mode only) -->\n ${() =>\n fmt.value === '12'\n ? html`\n <div class=\"col col-period\" part=\"column\" role=\"group\" aria-label=\"Period\">\n <div class=\"col-label\" aria-hidden=\"true\">AM/PM</div>\n <div class=\"col-scroll\">\n ${(['AM', 'PM'] as const).map(\n (p) => html`\n <div\n class=\"option\"\n part=\"option\"\n role=\"option\"\n tabindex=\"${() => (pendingPeriod.value === p ? '0' : '-1')}\"\n aria-selected=\"${() => String(pendingPeriod.value === p)}\"\n @click=\"${() => {\n pendingPeriod.value = p;\n }}\"\n @keydown=\"${handlePeriodKeydown}\">\n ${p}\n </div>\n `,\n )}\n </div>\n </div>\n `\n : html``}\n </div>\n </div>\n `;\n },\n\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"time-picker.cjs","names":[],"sources":["../src/inputs/time-picker/time-picker.ts"],"sourcesContent":["import { bind, define, getHost, html, onMounted, prop, ref, useField } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { createDropdownPositioner } from '../../core';\nimport {\n disablableBundle,\n FIELD_VARIANTS,\n type FieldVariant,\n roundableBundle,\n sizableBundle,\n themableBundle,\n} from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport componentStyles from './time-picker.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { INPUT_TAG } from '../input/input';\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreTimePickerEvents = {\n change: Event;\n input: Event;\n};\n\nexport type OreTimePickerProps = {\n /** Theme color */\n color?: string;\n /** Disable the picker */\n disabled?: boolean;\n /** Validation error message */\n error?: string;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Helper text below the field */\n helper?: string;\n /** Visible label */\n label?: string;\n /** Label placement */\n 'label-placement'?: 'inset' | 'outside';\n /** Maximum selectable time in HH:MM format (24-hour) */\n max?: string;\n /** Minimum selectable time in HH:MM format (24-hour) */\n min?: string;\n /** Minute step interval (1–59) */\n 'minute-step'?: number;\n /** Form field name */\n name?: string;\n /** Placeholder shown in the trigger */\n placeholder?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius */\n rounded?: string;\n /** Component size */\n size?: string;\n /**\n * Shows an inline green check icon inside the field to confirm the value has\n * passed validation. Ignored while `error` is set: an error always wins.\n */\n success?: boolean;\n /** Display format: '12' for AM/PM, '24' for 24-hour (default: '24') */\n 'time-format'?: '12' | '24';\n /** Selected time in HH:MM format (24-hour) */\n value?: string;\n /** Visual variant */\n variant?: FieldVariant;\n};\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\n/** Parse \"HH:MM\" → { hours: 0-23, minutes: 0-59 } | null */\nfunction parseTime(val: string | undefined | null): { hours: number; minutes: number } | null {\n if (!val) return null;\n\n const match = /^(\\d{1,2}):(\\d{2})$/.exec(val.trim());\n\n if (!match) return null;\n\n const h = Number(match[1]);\n const m = Number(match[2]);\n\n if (h < 0 || h > 23 || m < 0 || m > 59) return null;\n\n return { hours: h, minutes: m };\n}\n\n/** Format { hours, minutes } → \"HH:MM\" (24-hour, zero-padded) */\nfunction formatTime(h: number, m: number): string {\n return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;\n}\n\n/** Format for display label (respects 12/24 mode) */\nfunction formatDisplay(h: number, m: number, format: '12' | '24'): string {\n if (format === '12') {\n const period = h >= 12 ? 'PM' : 'AM';\n const displayH = h % 12 === 0 ? 12 : h % 12;\n\n return `${String(displayH).padStart(2, '0')}:${String(m).padStart(2, '0')} ${period}`;\n }\n\n return formatTime(h, m);\n}\n\n/** Clamp value to [min, max] in total minutes */\nfunction clampTime(\n h: number,\n m: number,\n minVal: string | undefined | null,\n maxVal: string | undefined | null,\n): { hours: number; minutes: number } {\n const total = h * 60 + m;\n const minParsed = parseTime(minVal);\n const maxParsed = parseTime(maxVal);\n const minMins = minParsed ? minParsed.hours * 60 + minParsed.minutes : 0;\n const maxMins = maxParsed ? maxParsed.hours * 60 + maxParsed.minutes : 23 * 60 + 59;\n const clamped = Math.min(Math.max(total, minMins), maxMins);\n\n return { hours: Math.floor(clamped / 60), minutes: clamped % 60 };\n}\n\n/**\n * An accessible time picker with a scrollable clock dropdown.\n * Supports 12/24-hour display formats, min/max bounds, minute steps, and form association.\n *\n * @element ore-time-picker\n *\n * @attr {string} value - Selected time in HH:MM (24-hour) format\n * @attr {string} min - Minimum selectable time (HH:MM)\n * @attr {string} max - Maximum selectable time (HH:MM)\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} placeholder - Trigger placeholder\n * @attr {boolean} disabled - Disable the picker\n * @attr {boolean} required - Required field\n * @attr {string} name - Form field name\n * @attr {string} error - Error message\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\n * @attr {string} helper - Helper text\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} time-format - '12' or '24' (default: '24')\n * @attr {number} minute-step - Minute increment (default: 5)\n *\n * @fires input - Fired when a time is selected.\n * @fires change - Fired when a time is selected.\n *\n * @slot label - Custom label for the trigger field\n * @slot prefix - Content before the trigger text (e.g. icon)\n * @slot helper - Custom helper text\n * @slot error - Custom error content\n *\n * @cssprop --time-picker-bg - Dropdown background\n * @cssprop --time-picker-border-color - Dropdown border color\n * @cssprop --time-picker-radius - Dropdown border radius\n * @cssprop --time-picker-shadow - Dropdown shadow\n * @cssprop --time-picker-selected-bg - Selected option background\n * @cssprop --time-picker-option-hover-bg - Option hover background\n *\n * @part field - The trigger field\n * @part dropdown - The floating time dropdown\n * @part column - A scrollable column (hours / minutes / period)\n * @part option - An individual time option cell\n *\n * @example\n * ```html\n * <!-- 24-hour clock, 15-minute steps -->\n * <ore-time-picker label=\"Meeting time\" value=\"09:30\" minute-step=\"15\" color=\"primary\"></ore-time-picker>\n *\n * <!-- 12-hour AM/PM format -->\n * <ore-time-picker label=\"Appointment\" time-format=\"12\" minute-step=\"30\"></ore-time-picker>\n *\n * <!-- Outside label, bordered variant -->\n * <ore-time-picker label=\"Start time\" label-placement=\"outside\" variant=\"bordered\"></ore-time-picker>\n * ```\n */\nexport const TIME_PICKER_TAG = 'ore-time-picker' as const;\n\ndefine<OreTimePickerProps>(TIME_PICKER_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\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 max: prop.string(),\n min: prop.string(),\n 'minute-step': prop.number(5),\n name: prop.string(),\n placeholder: prop.string(),\n required: prop.bool(false),\n success: prop.bool(false),\n 'time-format': prop.oneOf(['12', '24'] as const, '24'),\n value: prop.string(),\n variant: prop.oneOf(FIELD_VARIANTS),\n },\n\n setup(props) {\n const el = getHost();\n\n // ── Signals ──────────────────────────────────────────────────────────────\n\n const isOpen = signal(false);\n const selectedTime = signal<{ hours: number; minutes: number } | null>(parseTime(props.value.value));\n\n defineFieldValue(\n el,\n () => {\n const value = selectedTime.value;\n\n return value ? formatTime(value.hours, value.minutes) : '';\n },\n (value) => {\n selectedTime.value = parseTime(value);\n },\n );\n\n // ── Floating position ────────────────────────────────────────────────────\n // Same Orbit-powered positioner ore-date-picker's `.calendar` popup uses (see its own\n // comment for the full rationale): `fixed` + computed `top`/`left` instead of a static\n // `position: absolute; top: 100%`, so the dropdown flips/shifts to stay within the nearest\n // clipping ancestor instead of silently overflowing it.\n const triggerRef = ref<HTMLElement>();\n const dropdownRef = ref<HTMLElement>();\n\n const positioner = createDropdownPositioner({\n getFloating: () => dropdownRef.value ?? null,\n getOffsetPx: () => 4,\n getReference: () => triggerRef.value ?? null,\n matchWidth: false,\n });\n\n let stopAutoUpdate: (() => void) | null = null;\n\n const isDisabled = computed(() => Boolean(props.disabled.value));\n\n // ── Form value ────────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => {\n const t = selectedTime.value;\n\n return t ? formatTime(t.hours, t.minutes) : '';\n }),\n });\n\n // ── Computed helpers ──────────────────────────────────────────────────────\n\n const fmt = computed(() => props['time-format'].value ?? '24');\n const minuteStep = computed(() => Math.max(1, Math.min(59, props['minute-step'].value ?? 5)));\n\n const triggerText = computed(() => {\n if (!selectedTime.value) return props.placeholder.value || '';\n\n return formatDisplay(selectedTime.value.hours, selectedTime.value.minutes, fmt.value as '12' | '24');\n });\n\n /** All hour options for the column (0-23 in 24h; 1-12 in 12h) */\n const hourOptions = computed<number[]>(() => {\n if (fmt.value === '12') {\n return Array.from({ length: 12 }, (_, i) => i + 1);\n }\n\n return Array.from({ length: 24 }, (_, i) => i);\n });\n\n /** All minute options for the column, stepped */\n const minuteOptions = computed<number[]>(() => {\n const step = minuteStep.value;\n const opts: number[] = [];\n\n for (let m = 0; m < 60; m += step) opts.push(m);\n\n return opts;\n });\n\n const dialogId = `time-picker-${Math.random().toString(36).slice(2, 9)}-dropdown`;\n\n /** Convert 24h hour to display hour in current format */\n function toDisplayHour(h24: number): number {\n if (fmt.value === '24') return h24;\n\n const h12 = h24 % 12;\n\n return h12 === 0 ? 12 : h12;\n }\n\n /** Convert display hour + period → 24h hour */\n function to24Hour(displayHour: number, period: 'AM' | 'PM'): number {\n if (fmt.value === '24') return displayHour;\n\n if (period === 'AM') return displayHour === 12 ? 0 : displayHour;\n\n return displayHour === 12 ? 12 : displayHour + 12;\n }\n\n /** Whether a given HH:MM is out of [min, max] */\n function isTimeDisabled(h: number, m: number): boolean {\n const total = h * 60 + m;\n const minParsed = parseTime(props.min.value);\n const maxParsed = parseTime(props.max.value);\n\n if (minParsed && total < minParsed.hours * 60 + minParsed.minutes) return true;\n\n if (maxParsed && total > maxParsed.hours * 60 + maxParsed.minutes) return true;\n\n return false;\n }\n\n // ── State for focused/pending selection ───────────────────────────────────\n\n /** Pending hour (24h) while user is navigating columns */\n const pendingHour = signal<number>(selectedTime.value?.hours ?? 0);\n /** Pending minute */\n const pendingMinute = signal<number>(selectedTime.value?.minutes ?? 0);\n /** Pending period (12h mode) */\n const pendingPeriod = signal<'AM' | 'PM'>((selectedTime.value?.hours ?? 0) >= 12 ? 'PM' : 'AM');\n\n // ── Sync value prop externally ────────────────────────────────────────────\n\n let lastValueProp = props.value.value;\n\n onMounted(() => {\n const interval = setInterval(() => {\n const current = props.value.value;\n\n if (current !== lastValueProp) {\n lastValueProp = current;\n\n const parsed = parseTime(current);\n\n selectedTime.value = parsed;\n\n if (parsed) {\n pendingHour.value = parsed.hours;\n pendingMinute.value = parsed.minutes;\n pendingPeriod.value = parsed.hours >= 12 ? 'PM' : 'AM';\n }\n }\n }, 50);\n\n return () => clearInterval(interval);\n });\n\n // ── Commit ────────────────────────────────────────────────────────────────\n\n function commit(h24: number, m: number): void {\n const clamped = clampTime(h24, m, props.min.value, props.max.value);\n const snapped = Math.round(clamped.minutes / minuteStep.value) * minuteStep.value;\n const snappedMin = Math.min(snapped, 59);\n\n selectedTime.value = { hours: clamped.hours, minutes: snappedMin };\n setFieldValue(el, formatTime(clamped.hours, snappedMin));\n dispatchNativeFieldEvent(el, 'input');\n dispatchNativeFieldEvent(el, 'change');\n }\n\n function commitFromMinute(m: number): void {\n const h24 = fmt.value === '12' ? to24Hour(pendingHour.value, pendingPeriod.value) : pendingHour.value;\n\n pendingMinute.value = m;\n commit(h24, m);\n closePicker();\n }\n\n // ── Open / close ──────────────────────────────────────────────────────────\n\n function openPicker(): void {\n if (isDisabled.value) return;\n\n const current = selectedTime.value;\n\n if (current) {\n pendingHour.value = fmt.value === '12' ? toDisplayHour(current.hours) : current.hours;\n pendingMinute.value = current.minutes;\n pendingPeriod.value = current.hours >= 12 ? 'PM' : 'AM';\n } else {\n pendingHour.value = fmt.value === '12' ? 12 : 0;\n pendingMinute.value = 0;\n pendingPeriod.value = 'AM';\n }\n\n isOpen.value = true;\n positioner.update();\n stopAutoUpdate = positioner.startAutoUpdate?.() ?? null;\n }\n\n function closePicker(): void {\n isOpen.value = false;\n stopAutoUpdate?.();\n stopAutoUpdate = null;\n }\n\n function handleTriggerClick(): void {\n if (isOpen.value) closePicker();\n else openPicker();\n }\n\n // ── Outside click ─────────────────────────────────────────────────────────\n\n function handleOutsideClick(e: PointerEvent | MouseEvent): void {\n if (!isOpen.value) return;\n\n if (!e.composedPath().includes(el)) closePicker();\n }\n\n onMounted(() => {\n document.addEventListener('pointerdown', handleOutsideClick, { capture: true });\n\n return () => {\n document.removeEventListener('pointerdown', handleOutsideClick, { capture: true });\n stopAutoUpdate?.();\n stopAutoUpdate = null;\n };\n });\n\n // ── Keyboard ──────────────────────────────────────────────────────────────\n\n function handleTriggerKeydown(e: KeyboardEvent): void {\n if (isDisabled.value) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleTriggerClick();\n } else if (e.key === 'Escape' && isOpen.value) {\n e.preventDefault();\n closePicker();\n } else if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && !isOpen.value) {\n e.preventDefault();\n openPicker();\n }\n }\n\n function handleDropdownKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n closePicker();\n }\n }\n\n function handleHourKeydown(e: KeyboardEvent): void {\n const opts = hourOptions.value;\n const idx = opts.indexOf(pendingHour.value);\n\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n pendingHour.value = opts[(idx - 1 + opts.length) % opts.length];\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n pendingHour.value = opts[(idx + 1) % opts.length];\n }\n }\n\n function handleMinuteKeydown(e: KeyboardEvent): void {\n const opts = minuteOptions.value;\n const idx = opts.indexOf(pendingMinute.value);\n\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n pendingMinute.value = opts[(idx - 1 + opts.length) % opts.length];\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n pendingMinute.value = opts[(idx + 1) % opts.length];\n }\n }\n\n function handlePeriodKeydown(e: KeyboardEvent): void {\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault();\n pendingPeriod.value = pendingPeriod.value === 'AM' ? 'PM' : 'AM';\n }\n }\n\n // ── Host bindings ─────────────────────────────────────────────────────────\n\n bind({\n attr: {\n open: () => (isOpen.value ? true : undefined),\n },\n });\n\n // ── ore-input prop helpers ────────────────────────────────────────────────\n\n const inputValue = () => triggerText.value;\n const inputLabel = () => props.label.value ?? '';\n const inputPlaceholder = () => props.placeholder.value ?? '';\n const inputLabelPlacement = () => props['label-placement'].value ?? 'inset';\n const inputColor = () => props.color?.value ?? undefined;\n const inputSize = () => props.size?.value ?? undefined;\n const inputVariant = () => props.variant?.value ?? undefined;\n const inputRounded = () => props.rounded?.value ?? undefined;\n const inputHelper = () => props.helper.value ?? '';\n const inputError = () => props.error.value ?? '';\n const inputDisabled = () => (isDisabled.value ? true : undefined);\n const inputRequired = () => (props.required.value ? true : undefined);\n const inputFullwidth = () => (props.fullwidth.value ? true : undefined);\n\n return html`\n <!-- Trigger -->\n <ore-input\n class=\"trigger\"\n ref=\"${triggerRef}\"\n readonly\n tabindex=\"0\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-controls=\"${dialogId}\"\n aria-expanded=\"${() => String(isOpen.value)}\"\n aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\"\n value=\"${inputValue}\"\n label=\"${inputLabel}\"\n placeholder=\"${inputPlaceholder}\"\n label-placement=\"${inputLabelPlacement}\"\n color=\"${inputColor}\"\n size=\"${inputSize}\"\n variant=\"${inputVariant}\"\n rounded=\"${inputRounded}\"\n helper=\"${inputHelper}\"\n error=\"${inputError}\"\n ?disabled=\"${inputDisabled}\"\n ?required=\"${inputRequired}\"\n ?fullwidth=\"${inputFullwidth}\"\n ?success=\"${() => props.success.value}\"\n @click=\"${handleTriggerClick}\"\n @keydown=\"${handleTriggerKeydown}\">\n <ore-icon slot=\"suffix\" name=\"clock\" size=\"16\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-input>\n\n <!-- Dropdown -->\n <div\n class=\"dropdown\"\n ref=\"${dropdownRef}\"\n id=\"${dialogId}\"\n role=\"listbox\"\n aria-label=\"${() => (props.label.value ? `${props.label.value}: select time` : 'Select time')}\"\n ?data-open=\"${isOpen}\"\n @keydown=\"${handleDropdownKeydown}\">\n <div class=\"cols-row\">\n <!-- Hours column -->\n <div class=\"col\" part=\"column\" role=\"group\" aria-label=\"Hours\">\n <div class=\"col-label\" aria-hidden=\"true\">HH</div>\n <div class=\"col-scroll\">\n ${() =>\n hourOptions.value.map((h) => {\n const h24 = fmt.value === '12' ? to24Hour(h, pendingPeriod.value) : h;\n const disabled = isTimeDisabled(h24, pendingMinute.value);\n\n return html`\n <div\n class=\"option\"\n part=\"option\"\n role=\"option\"\n tabindex=\"${() => (pendingHour.value === h && !disabled ? '0' : '-1')}\"\n aria-selected=\"${() => String(pendingHour.value === h)}\"\n aria-disabled=\"${() => String(disabled)}\"\n ?data-disabled=\"${() => disabled}\"\n @click=\"${() => {\n if (!disabled) pendingHour.value = h;\n }}\"\n @keydown=\"${handleHourKeydown}\">\n ${String(h).padStart(2, '0')}\n </div>\n `;\n })}\n </div>\n </div>\n\n <div class=\"col-sep\" aria-hidden=\"true\">:</div>\n\n <!-- Minutes column -->\n <div class=\"col\" part=\"column\" role=\"group\" aria-label=\"Minutes\">\n <div class=\"col-label\" aria-hidden=\"true\">MM</div>\n <div class=\"col-scroll\">\n ${() =>\n minuteOptions.value.map((m) => {\n const h24 = fmt.value === '12' ? to24Hour(pendingHour.value, pendingPeriod.value) : pendingHour.value;\n const disabled = isTimeDisabled(h24, m);\n\n return html`\n <div\n class=\"option\"\n part=\"option\"\n role=\"option\"\n tabindex=\"${() => (pendingMinute.value === m && !disabled ? '0' : '-1')}\"\n aria-selected=\"${() => String(pendingMinute.value === m)}\"\n aria-disabled=\"${() => String(disabled)}\"\n ?data-disabled=\"${() => disabled}\"\n @click=\"${() => {\n if (!disabled) commitFromMinute(m);\n }}\"\n @keydown=\"${handleMinuteKeydown}\">\n ${String(m).padStart(2, '0')}\n </div>\n `;\n })}\n </div>\n </div>\n\n <!-- AM/PM column (12h mode only) -->\n ${() =>\n fmt.value === '12'\n ? html`\n <div class=\"col col-period\" part=\"column\" role=\"group\" aria-label=\"Period\">\n <div class=\"col-label\" aria-hidden=\"true\">AM/PM</div>\n <div class=\"col-scroll\">\n ${(['AM', 'PM'] as const).map(\n (p) => html`\n <div\n class=\"option\"\n part=\"option\"\n role=\"option\"\n tabindex=\"${() => (pendingPeriod.value === p ? '0' : '-1')}\"\n aria-selected=\"${() => String(pendingPeriod.value === p)}\"\n @click=\"${() => {\n pendingPeriod.value = p;\n }}\"\n @keydown=\"${handlePeriodKeydown}\">\n ${p}\n </div>\n `,\n )}\n </div>\n </div>\n `\n : html``}\n </div>\n </div>\n `;\n },\n\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
|
package/dist/time-picker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{defineFieldValue as e,dispatchNativeFieldEvent as t,setFieldValue as n}from"./inputs/shared/native-field-event.js";import{reducedMotionMixin as r}from"./styles/mixins/accessibility.css.js";import{colorThemeMixin as i}from"./styles/mixins/theme.css.js";import{createDropdownPositioner as a}from"./core/positioner.js";import{disablableBundle as
|
|
1
|
+
import{defineFieldValue as e,dispatchNativeFieldEvent as t,setFieldValue as n}from"./inputs/shared/native-field-event.js";import{reducedMotionMixin as r}from"./styles/mixins/accessibility.css.js";import{colorThemeMixin as i}from"./styles/mixins/theme.css.js";import{createDropdownPositioner as a}from"./core/positioner.js";import{FIELD_VARIANTS as o}from"./shared/types.js";import{disablableBundle as s,roundableBundle as c,sizableBundle as l,themableBundle as u}from"./shared/prop-bundles.js";import{ICON_TAG as d}from"./icon.js";import{INPUT_TAG as f}from"./input.js";import p from"./inputs/time-picker/time-picker.css.js";import{computed as m,signal as h}from"@vielzeug/ripple";import{bind as g,define as _,getHost as v,html as y,onMounted as b,prop as x,ref as S,useField as C}from"@vielzeug/ore";function parseTime(e){if(!e)return null;let t=/^(\d{1,2}):(\d{2})$/.exec(e.trim());if(!t)return null;let n=Number(t[1]),r=Number(t[2]);return n<0||n>23||r<0||r>59?null:{hours:n,minutes:r}}function formatTime(e,t){return`${String(e).padStart(2,`0`)}:${String(t).padStart(2,`0`)}`}function formatDisplay(e,t,n){if(n===`12`){let n=e>=12?`PM`:`AM`,r=e%12==0?12:e%12;return`${String(r).padStart(2,`0`)}:${String(t).padStart(2,`0`)} ${n}`}return formatTime(e,t)}function clampTime(e,t,n,r){let i=e*60+t,a=parseTime(n),o=parseTime(r),s=a?a.hours*60+a.minutes:0,c=o?o.hours*60+o.minutes:1439,l=Math.min(Math.max(i,s),c);return{hours:Math.floor(l/60),minutes:l%60}}var w=`ore-time-picker`;_(w,{formAssociated:!0,props:{...u,...l,...s,...c,error:x.string(),fullwidth:x.bool(!1),helper:x.string(),label:x.string(),"label-placement":x.oneOf([`inset`,`outside`],`inset`),max:x.string(),min:x.string(),"minute-step":x.number(5),name:x.string(),placeholder:x.string(),required:x.bool(!1),success:x.bool(!1),"time-format":x.oneOf([`12`,`24`],`24`),value:x.string(),variant:x.oneOf(o)},setup(r){let i=v(),o=h(!1),s=h(parseTime(r.value.value));e(i,()=>{let e=s.value;return e?formatTime(e.hours,e.minutes):``},e=>{s.value=parseTime(e)});let c=S(),l=S(),u=a({getFloating:()=>l.value??null,getOffsetPx:()=>4,getReference:()=>c.value??null,matchWidth:!1}),d=null,f=m(()=>!!r.disabled.value);C({disabled:f,toFormValue:e=>e||null,value:m(()=>{let e=s.value;return e?formatTime(e.hours,e.minutes):``})});let p=m(()=>r[`time-format`].value??`24`),_=m(()=>Math.max(1,Math.min(59,r[`minute-step`].value??5))),x=m(()=>s.value?formatDisplay(s.value.hours,s.value.minutes,p.value):r.placeholder.value||``),w=m(()=>p.value===`12`?Array.from({length:12},(e,t)=>t+1):Array.from({length:24},(e,t)=>t)),T=m(()=>{let e=_.value,t=[];for(let n=0;n<60;n+=e)t.push(n);return t}),E=`time-picker-${Math.random().toString(36).slice(2,9)}-dropdown`;function toDisplayHour(e){if(p.value===`24`)return e;let t=e%12;return t===0?12:t}function to24Hour(e,t){return p.value===`24`?e:t===`AM`?e===12?0:e:e===12?12:e+12}function isTimeDisabled(e,t){let n=e*60+t,i=parseTime(r.min.value),a=parseTime(r.max.value);return!!(i&&n<i.hours*60+i.minutes||a&&n>a.hours*60+a.minutes)}let D=h(s.value?.hours??0),O=h(s.value?.minutes??0),k=h((s.value?.hours??0)>=12?`PM`:`AM`),A=r.value.value;b(()=>{let e=setInterval(()=>{let e=r.value.value;if(e!==A){A=e;let t=parseTime(e);s.value=t,t&&(D.value=t.hours,O.value=t.minutes,k.value=t.hours>=12?`PM`:`AM`)}},50);return()=>clearInterval(e)});function commit(e,a){let o=clampTime(e,a,r.min.value,r.max.value),c=Math.round(o.minutes/_.value)*_.value,l=Math.min(c,59);s.value={hours:o.hours,minutes:l},n(i,formatTime(o.hours,l)),t(i,`input`),t(i,`change`)}function commitFromMinute(e){let t=p.value===`12`?to24Hour(D.value,k.value):D.value;O.value=e,commit(t,e),closePicker()}function openPicker(){if(f.value)return;let e=s.value;e?(D.value=p.value===`12`?toDisplayHour(e.hours):e.hours,O.value=e.minutes,k.value=e.hours>=12?`PM`:`AM`):(D.value=p.value===`12`?12:0,O.value=0,k.value=`AM`),o.value=!0,u.update(),d=u.startAutoUpdate?.()??null}function closePicker(){o.value=!1,d?.(),d=null}function handleTriggerClick(){o.value?closePicker():openPicker()}function handleOutsideClick(e){o.value&&(e.composedPath().includes(i)||closePicker())}b(()=>(document.addEventListener(`pointerdown`,handleOutsideClick,{capture:!0}),()=>{document.removeEventListener(`pointerdown`,handleOutsideClick,{capture:!0}),d?.(),d=null}));function handleTriggerKeydown(e){f.value||(e.key===`Enter`||e.key===` `?(e.preventDefault(),handleTriggerClick()):e.key===`Escape`&&o.value?(e.preventDefault(),closePicker()):(e.key===`ArrowDown`||e.key===`ArrowUp`)&&!o.value&&(e.preventDefault(),openPicker()))}function handleDropdownKeydown(e){e.key===`Escape`&&(e.preventDefault(),closePicker())}function handleHourKeydown(e){let t=w.value,n=t.indexOf(D.value);e.key===`ArrowUp`?(e.preventDefault(),D.value=t[(n-1+t.length)%t.length]):e.key===`ArrowDown`&&(e.preventDefault(),D.value=t[(n+1)%t.length])}function handleMinuteKeydown(e){let t=T.value,n=t.indexOf(O.value);e.key===`ArrowUp`?(e.preventDefault(),O.value=t[(n-1+t.length)%t.length]):e.key===`ArrowDown`&&(e.preventDefault(),O.value=t[(n+1)%t.length])}function handlePeriodKeydown(e){(e.key===`ArrowUp`||e.key===`ArrowDown`)&&(e.preventDefault(),k.value=k.value===`AM`?`PM`:`AM`)}g({attr:{open:()=>o.value?!0:void 0}});let inputValue=()=>x.value,inputLabel=()=>r.label.value??``,inputPlaceholder=()=>r.placeholder.value??``,inputLabelPlacement=()=>r[`label-placement`].value??`inset`,inputColor=()=>r.color?.value??void 0,inputSize=()=>r.size?.value??void 0,inputVariant=()=>r.variant?.value??void 0,inputRounded=()=>r.rounded?.value??void 0,inputHelper=()=>r.helper.value??``,inputError=()=>r.error.value??``,inputDisabled=()=>f.value?!0:void 0,inputRequired=()=>r.required.value?!0:void 0,inputFullwidth=()=>r.fullwidth.value?!0:void 0;return y`
|
|
2
2
|
<!-- Trigger -->
|
|
3
3
|
<ore-input
|
|
4
4
|
class="trigger"
|
|
@@ -43,7 +43,7 @@ import{defineFieldValue as e,dispatchNativeFieldEvent as t,setFieldValue as n}fr
|
|
|
43
43
|
<div class="col" part="column" role="group" aria-label="Hours">
|
|
44
44
|
<div class="col-label" aria-hidden="true">HH</div>
|
|
45
45
|
<div class="col-scroll">
|
|
46
|
-
${()=>w.value.map(e=>{let t=isTimeDisabled(
|
|
46
|
+
${()=>w.value.map(e=>{let t=isTimeDisabled(p.value===`12`?to24Hour(e,k.value):e,O.value);return y`
|
|
47
47
|
<div
|
|
48
48
|
class="option"
|
|
49
49
|
part="option"
|
|
@@ -66,7 +66,7 @@ import{defineFieldValue as e,dispatchNativeFieldEvent as t,setFieldValue as n}fr
|
|
|
66
66
|
<div class="col" part="column" role="group" aria-label="Minutes">
|
|
67
67
|
<div class="col-label" aria-hidden="true">MM</div>
|
|
68
68
|
<div class="col-scroll">
|
|
69
|
-
${()=>T.value.map(e=>{let t=isTimeDisabled(
|
|
69
|
+
${()=>T.value.map(e=>{let t=isTimeDisabled(p.value===`12`?to24Hour(D.value,k.value):D.value,e);return y`
|
|
70
70
|
<div
|
|
71
71
|
class="option"
|
|
72
72
|
part="option"
|
|
@@ -84,11 +84,11 @@ import{defineFieldValue as e,dispatchNativeFieldEvent as t,setFieldValue as n}fr
|
|
|
84
84
|
</div>
|
|
85
85
|
|
|
86
86
|
<!-- AM/PM column (12h mode only) -->
|
|
87
|
-
${()=>
|
|
87
|
+
${()=>p.value===`12`?y`
|
|
88
88
|
<div class="col col-period" part="column" role="group" aria-label="Period">
|
|
89
89
|
<div class="col-label" aria-hidden="true">AM/PM</div>
|
|
90
90
|
<div class="col-scroll">
|
|
91
|
-
${[`AM`,`PM`].map(e=>
|
|
91
|
+
${[`AM`,`PM`].map(e=>y`
|
|
92
92
|
<div
|
|
93
93
|
class="option"
|
|
94
94
|
part="option"
|
|
@@ -102,8 +102,8 @@ import{defineFieldValue as e,dispatchNativeFieldEvent as t,setFieldValue as n}fr
|
|
|
102
102
|
`)}
|
|
103
103
|
</div>
|
|
104
104
|
</div>
|
|
105
|
-
`:
|
|
105
|
+
`:y``}
|
|
106
106
|
</div>
|
|
107
107
|
</div>
|
|
108
|
-
`},shadow:{delegatesFocus:!0},styles:[i,r,
|
|
108
|
+
`},shadow:{delegatesFocus:!0},styles:[i,r,p]});export{d as ICON_TAG,f as INPUT_TAG,w as TIME_PICKER_TAG};
|
|
109
109
|
//# sourceMappingURL=time-picker.js.map
|