@rotki/ui-library 2.25.0 → 2.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +2 -0
  2. package/dist/components/date-time-picker/RuiDateTimePicker.js.map +1 -1
  3. package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js +25 -7
  4. package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  5. package/dist/components/date-time-picker/date-time-picker-styles.d.ts +6 -0
  6. package/dist/components/date-time-picker/segment-utils.d.ts +16 -1
  7. package/dist/components/date-time-picker/segment-utils.js +71 -14
  8. package/dist/components/date-time-picker/segment-utils.js.map +1 -1
  9. package/dist/components/date-time-picker/use-keyboard-handler.d.ts +2 -0
  10. package/dist/components/date-time-picker/use-keyboard-handler.js +10 -3
  11. package/dist/components/date-time-picker/use-keyboard-handler.js.map +1 -1
  12. package/dist/components/forms/auto-complete/RuiAutoComplete.js.map +1 -1
  13. package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js +1 -0
  14. package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
  15. package/dist/components/forms/auto-complete/auto-complete-styles.d.ts +6 -0
  16. package/dist/components/forms/category-picker/category-picker-styles.d.ts +6 -0
  17. package/dist/components/forms/select/RuiMenuSelect.js.map +1 -1
  18. package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js +1 -0
  19. package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  20. package/dist/components/forms/select/menu-select-styles.d.ts +6 -0
  21. package/dist/components/forms/text-input-styles.d.ts +3 -0
  22. package/dist/components/forms/text-input-styles.js +3 -1
  23. package/dist/components/forms/text-input-styles.js.map +1 -1
  24. package/dist/components/index.js +1 -1
  25. package/dist/components/tables/RuiDataTable.js.map +1 -1
  26. package/dist/components/tables/RuiDataTable.vue.d.ts +12 -1
  27. package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js +71 -14
  28. package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  29. package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js +1 -1
  30. package/dist/components/tables/RuiTableHead.js.map +1 -1
  31. package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js +38 -13
  32. package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js.map +1 -1
  33. package/dist/components/tables/RuiTablePagination.js.map +1 -1
  34. package/dist/components/tables/RuiTablePagination.vue.d.ts +3 -3
  35. package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js +65 -14
  36. package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  37. package/dist/components/tables/data-table/RuiDataTableBody.js.map +1 -1
  38. package/dist/components/tables/data-table/RuiDataTableBody.vue.d.ts +7 -1
  39. package/dist/components/tables/data-table/RuiDataTableBody.vue_vue_type_script_setup_true_lang.js +45 -9
  40. package/dist/components/tables/data-table/RuiDataTableBody.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/components/tables/data-table/RuiDataTableCell.js.map +1 -1
  42. package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js +13 -2
  43. package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  44. package/dist/components/tables/data-table/RuiDataTableErrorRow.js +7 -0
  45. package/dist/components/tables/data-table/RuiDataTableErrorRow.js.map +1 -0
  46. package/dist/components/tables/data-table/RuiDataTableErrorRow.vue.d.ts +21 -0
  47. package/dist/components/tables/data-table/RuiDataTableErrorRow.vue_vue_type_script_setup_true_lang.js +40 -0
  48. package/dist/components/tables/data-table/RuiDataTableErrorRow.vue_vue_type_script_setup_true_lang.js.map +1 -0
  49. package/dist/components/tables/data-table/RuiDataTableExpandedRow.js.map +1 -1
  50. package/dist/components/tables/data-table/RuiDataTableExpandedRow.vue_vue_type_script_setup_true_lang.js +12 -1
  51. package/dist/components/tables/data-table/RuiDataTableExpandedRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  52. package/dist/components/tables/data-table/RuiDataTableGroupRow.js.map +1 -1
  53. package/dist/components/tables/data-table/RuiDataTableGroupRow.vue_vue_type_script_setup_true_lang.js +52 -20
  54. package/dist/components/tables/data-table/RuiDataTableGroupRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  55. package/dist/components/tables/data-table/RuiDataTableRow.js.map +1 -1
  56. package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js +29 -14
  57. package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  58. package/dist/components/tables/data-table/context.d.ts +10 -0
  59. package/dist/components/tables/data-table/context.js +2 -0
  60. package/dist/components/tables/data-table/context.js.map +1 -1
  61. package/dist/components/tables/data-table-styles.d.ts +15 -9
  62. package/dist/components/tables/data-table-styles.js +28 -5
  63. package/dist/components/tables/data-table-styles.js.map +1 -1
  64. package/dist/components/tables/table-props.d.ts +1 -2
  65. package/dist/components/tables/table-props.js +2 -10
  66. package/dist/components/tables/table-props.js.map +1 -1
  67. package/dist/components/tables/use-pagination-navigation.js +1 -1
  68. package/dist/components/tables/use-pagination-navigation.js.map +1 -1
  69. package/dist/i18n/keys.d.ts +1 -0
  70. package/dist/i18n/keys.js +1 -0
  71. package/dist/i18n/keys.js.map +1 -1
  72. package/dist/index.js +1 -1
  73. package/dist/library-icons.json +1 -1
  74. package/dist/style.css +120 -38
  75. package/dist/web-types.json +139 -3
  76. package/package.json +1 -1
package/README.md CHANGED
@@ -206,6 +206,7 @@ const i18n = createI18n({
206
206
  date_after_max: 'Date cannot be after {date}',
207
207
  date_before_min: 'Date cannot be before {date}',
208
208
  date_in_future: 'The selected date cannot be in the future',
209
+ paste_unreadable: 'Could not read a date from the pasted text',
209
210
  },
210
211
  },
211
212
  },
@@ -238,6 +239,7 @@ export const RUI_I18N_KEYS = {
238
239
  dateAfterMax: 'rui.date_time_picker.date_after_max',
239
240
  dateBeforeMin: 'rui.date_time_picker.date_before_min',
240
241
  dateInFuture: 'rui.date_time_picker.date_in_future',
242
+ pasteUnreadable: 'rui.date_time_picker.paste_unreadable',
241
243
  },
242
244
  } as const;
243
245
  ```
@@ -1 +1 @@
1
- {"version":3,"file":"RuiDateTimePicker.js","names":[],"sources":["../../../src/components/date-time-picker/RuiDateTimePicker.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type { ComponentPublicInstance } from 'vue';\nimport type { DateTimePickerAction, DateTimeSegmentType } from '@/components/date-time-picker/types';\nimport type { TimePickerSelection } from '@/components/time-picker/RuiTimePicker.vue';\nimport RuiButton from '@/components/buttons/button/RuiButton.vue';\nimport { dateTimePickerStyles, type DateTimePickerVariant } from '@/components/date-time-picker/date-time-picker-styles';\nimport RuiDateTimePickerMenu from '@/components/date-time-picker/RuiDateTimePickerMenu.vue';\nimport { useDateTimeSelection } from '@/components/date-time-picker/use-date-time-selection';\nimport { useInputHandler } from '@/components/date-time-picker/use-input-handler';\nimport { useKeyboardHandler } from '@/components/date-time-picker/use-keyboard-handler';\nimport RuiIcon from '@/components/icons/RuiIcon.vue';\nimport RuiMenu from '@/components/overlays/menu/RuiMenu.vue';\nimport { type FloatingOptions, Placement } from '@/composables/floating';\nimport { useRuiI8n } from '@/composables/use-rui-i18n';\nimport { RUI_I18N_KEYS } from '@/i18n/keys';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs } from '@/utils/helpers';\nimport { cn } from '@/utils/tv';\n\ntype DateFormat = 'year-first' | 'month-first' | 'day-first';\n\ntype DateTimeModelType = 'date' | 'epoch-ms' | 'epoch';\n\ntype ModelValueType<T extends DateTimeModelType> = T extends 'date'\n ? Date | undefined\n : T extends 'epoch-ms'\n ? number | undefined\n : T extends 'epoch'\n ? number | undefined\n : Date | number | undefined;\n\nexport interface RuiDateTimePickerProps {\n minDate?: Date | number;\n maxDate?: Date | number | 'now';\n format?: DateFormat;\n type?: DateTimeModelType;\n accuracy?: 'minute' | 'second' | 'millisecond';\n disabled?: boolean;\n allowEmpty?: boolean;\n readonly?: boolean;\n dense?: boolean;\n label?: string;\n variant?: DateTimePickerVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n required?: boolean;\n /**\n * Renders the timezone selector in the menu. Off by default: the value is\n * emitted as a date or an epoch, so the picked timezone does not survive a\n * round trip and most consumers work in local time.\n */\n showTimezone?: boolean;\n /**\n * Actions rendered in the menu footer. `clear` is only rendered when the\n * picker is `allowEmpty`. Pass an empty array to drop the footer entirely.\n */\n actions?: DateTimePickerAction[];\n /**\n * Focuses the field once it is mounted. The native attribute is ignored for\n * an input inserted into an already loaded document, which is the usual case\n * for a picker revealed by an editor or a dialog.\n */\n autofocus?: boolean;\n /**\n * Accepts an entry that stops short of the full format, filling the segments\n * it never reached from one end of the day: `start` gives a bare date\n * 00:00:00.000 and `end` gives it 23:59:59.999. Meant for a range, where the\n * two bounds want opposite ends. Left unset, an entry missing its time is not\n * a value and nothing is emitted.\n *\n * The fill runs when the user is done with the field - leaving it, pressing\n * enter, or closing the calendar - and is written back into the segments, so\n * what it decided on is on screen.\n *\n * Spelled out rather than written as `PartialTimeMode`: a consumer that hands\n * this whole interface to its own `defineProps` needs every member resolvable\n * by the SFC compiler, which does not follow the type into the package.\n */\n partialTime?: 'start' | 'end';\n}\n\ndefineOptions({\n name: 'RuiDateTimePicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<ModelValueType<DateTimeModelType>>({ required: true });\nconst menuOpen = defineModel<boolean>('menuOpen', { default: false });\n\nconst {\n disabled = false,\n readonly = false,\n allowEmpty = false,\n dense = false,\n type = 'epoch-ms',\n hideDetails = false,\n label,\n variant = 'default',\n hint,\n maxDate,\n minDate,\n format = 'day-first',\n accuracy = 'minute',\n errorMessages = [],\n successMessages = [],\n required = false,\n showTimezone = false,\n actions = ['now'],\n autofocus = false,\n partialTime,\n} = defineProps<RuiDateTimePickerProps>();\n\ndefineSlots<{\n 'menu-content': () => any;\n}>();\n\nconst MENU_OPTIONS: FloatingOptions = { placement: Placement.bottomStart };\n\nconst baseFormats: Record<DateFormat, string> = {\n 'day-first': 'DD/MM/YYYY HH:mm',\n 'month-first': 'MM/DD/YYYY HH:mm',\n 'year-first': 'YYYY/MM/DD HH:mm',\n};\n\nconst isOpen = ref<boolean>(false);\nconst isHovered = ref<boolean>(false);\nconst cursorPosition = ref<number>(0);\nconst currentValue = ref<number>();\n\nconst { t } = useRuiI8n();\n\nconst keys = RUI_I18N_KEYS.dateTimePicker;\n\nconst fieldLabel = computed<string>(() => label ?? t(keys.label, 'Pick a date'));\nconst clearLabel = computed<string>(() => t(keys.clearValue, 'Clear the date'));\nconst toggleLabel = computed<string>(() => (get(isOpen)\n ? t(keys.closeCalendar, 'Close the calendar')\n : t(keys.openCalendar, 'Open the calendar')));\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuWrapperRef = useTemplateRef<ComponentPublicInstance>('menuWrapperRef');\nconst calendarMenuOpen = ref<boolean>(false);\n\nconst { focused: activatorFocusedWithin } = useFocusWithin(activator);\nconst { focused: menuWrapperFocusedWithin } = useFocusWithin(menuWrapperRef);\nconst { focused: searchInputFocused } = useFocus(textInput);\n\nconst anyFocused = computed<boolean>(() => get(activatorFocusedWithin) || get(menuWrapperFocusedWithin));\n\nconst dateFormat = computed<string>(() => {\n const fmt = baseFormats[format];\n if (accuracy === 'second') {\n return fmt.replace('HH:mm', 'HH:mm:ss');\n }\n else if (accuracy === 'millisecond') {\n return fmt.replace('HH:mm', 'HH:mm:ss.SSS');\n }\n return fmt;\n});\n\nconst {\n clear: clearSelection,\n commitPartialTime,\n getDateTime,\n internalErrorMessages,\n maxAllowedDate,\n minAllowedDate,\n segmentData,\n selectedDate,\n modelDay,\n modelHour,\n modelMillisecond,\n modelMinute,\n modelMonth,\n modelSecond,\n selectedTime,\n modelTimezone,\n modelYear,\n setNow,\n setToday,\n valueSet,\n} = useDateTimeSelection({\n accuracy,\n allowEmpty,\n dateFormat,\n maxDate,\n minDate,\n modelValue,\n partialTime,\n type,\n});\n\nconst { setValue, getCurrent } = useInputHandler(segmentData, currentValue);\n\nconst {\n clear: clearSegment,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\n selectFirstSegment,\n setSegment,\n} = useKeyboardHandler({\n accuracy,\n currentValue,\n cursorPosition,\n dateFormat,\n disabled,\n getCurrent,\n getDateTime,\n readonly,\n setValue,\n textInput,\n});\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst isOutlined = computed<boolean>(() => variant === 'outlined');\n\n/** True once any segment holds a digit, even a partially typed date. */\nconst anySegmentSet = computed<boolean>(() => [\n modelYear,\n modelMonth,\n modelDay,\n modelHour,\n modelMinute,\n modelSecond,\n modelMillisecond,\n].some(segment => isDefined(segment)));\n\n/**\n * The field's text.\n *\n * An untouched field shows its format through the placeholder rather than\n * holding the tokens as its value, where a screen reader reads them as content\n * and select-all copies them. The tokens stay while the field is focused: that\n * is when the segment machinery highlights them, and collapsing the value\n * mid-edit would blank the field under the cursor. The guard is \"no segment\n * set\" rather than `valueSet`, so blurring a half-typed date keeps what was\n * entered on screen.\n */\nconst formattedDisplay = computed<string>(() => {\n if (!get(anySegmentSet) && !get(searchInputFocused)) {\n return '';\n }\n\n let result = get(dateFormat);\n\n const replacements = [\n { pattern: 'YYYY', value: getDisplayValue(modelYear, 4) },\n { pattern: 'MM', value: getDisplayValue(modelMonth, 2) },\n { pattern: 'DD', value: getDisplayValue(modelDay, 2) },\n { pattern: 'HH', value: getDisplayValue(modelHour, 2) },\n { pattern: 'mm', value: getDisplayValue(modelMinute, 2) },\n { pattern: 'ss', value: getDisplayValue(modelSecond, 2) },\n { pattern: 'SSS', value: getDisplayValue(modelMillisecond, 3) },\n ];\n\n for (const { pattern, value } of replacements) {\n if (value !== undefined) {\n result = result.replace(pattern, value);\n }\n }\n\n return result;\n});\n\n/**\n * An untouched field holds no value until focus expands the format tokens into\n * it. That patch overwrites the input's value, and writing a value drops any\n * selection with it, so the highlight `handleFocus` just set is gone by the\n * time the tokens are on screen and the caret ends up after them. Re-select\n * the first segment once the tokens have actually landed.\n */\nwatch(formattedDisplay, (value, previous) => {\n if (previous === '' && value !== '' && get(searchInputFocused))\n selectFirstSegment();\n}, { flush: 'post' });\n\nconst timeSelection = computed<TimePickerSelection>({\n get() {\n const type = getCurrentSegment()?.type;\n\n if (type === 'mm') {\n return 'minute';\n }\n else if (type === 'ss') {\n return 'second';\n }\n else if (type === 'SSS') {\n return 'millisecond';\n }\n return 'hour';\n },\n set(value: TimePickerSelection) {\n let segmentType: DateTimeSegmentType = 'HH';\n if (value === 'minute') {\n segmentType = 'mm';\n }\n else if (value === 'second') {\n segmentType = 'ss';\n }\n else if (value === 'millisecond') {\n segmentType = 'SSS';\n }\n\n setSegment(segmentType);\n },\n});\n\nconst float = computed<boolean>(() => (get(isOpen) || get(valueSet) || get(searchInputFocused)) && get(isOutlined));\n\nconst legendText = computed<string>(() => {\n if (!get(float))\n return '';\n const resolved = get(fieldLabel);\n return required ? `${resolved} ﹡` : resolved;\n});\n\nconst ui = computed<ReturnType<typeof dateTimePickerStyles>>(() => dateTimePickerStyles({\n filled: variant === 'filled',\n outlined: get(isOutlined),\n float: get(float),\n opened: get(isOpen),\n hovered: get(isHovered),\n dense,\n disabled,\n readonly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst combinedErrorMessages = computed<string[]>(() => {\n if (!errorMessages)\n return get(internalErrorMessages);\n\n const propErrors = Array.isArray(errorMessages) ? errorMessages : [errorMessages];\n return [...propErrors, ...get(internalErrorMessages)];\n});\n\nfunction getDisplayValue(digit: Ref<number | undefined>, padding: number): string | undefined {\n return isDefined(digit) ? get(digit).toString().padStart(padding, '0') : undefined;\n}\n\nasync function setInputFocus(): Promise<void> {\n await nextTick(() => {\n set(searchInputFocused, true);\n });\n}\n\nfunction clear(segmentType?: string): void {\n if (!segmentType) {\n clearSelection();\n set(currentValue, undefined);\n return;\n }\n\n clearSegment(segmentType);\n}\n\n/**\n * An entry left incomplete is completed once the user is done with the field,\n * never while they are still filling it in: a half typed hour is not a segment\n * they left out. Leaving the field counts, unless the calendar is open, since\n * then the focus is only moving into it and the menu closing covers that.\n */\nfunction onBlur(): void {\n handleBlur();\n if (!get(isOpen))\n commitPartialTime();\n}\n\nwatch(isOpen, (open) => {\n if (!open && !get(searchInputFocused))\n commitPartialTime();\n});\n\n/**\n * Selects the clicked segment before opening the menu, so the selection is not\n * lost to the DOM changes that opening brings.\n */\nfunction handleInputClick(event: MouseEvent): void {\n handleClick(event);\n if (!get(isOpen)) {\n set(isOpen, true);\n }\n}\n\n/**\n * The menu is teleported to the body, so it never sits next to the field in\n * the tab sequence. Opening it from the keyboard therefore moves focus into\n * the calendar; opening it with the mouse leaves focus in the field, which is\n * what `disable-auto-focus` on the menu is there for.\n */\nconst focusCalendarOnOpen = ref<boolean>(false);\n\n/**\n * Asks for focus to move into the calendar. The menu is teleported and mounts\n * a frame later, so the watcher below waits for the wrapper to appear rather\n * than guessing at a number of ticks.\n */\nfunction focusCalendar(): void {\n set(focusCalendarOnOpen, true);\n}\n\nwatch(menuWrapperRef, (menu) => {\n if (!menu || !get(focusCalendarOnOpen))\n return;\n\n set(focusCalendarOnOpen, false);\n nextTick(() => {\n const el = menu.$el as HTMLElement | undefined;\n el?.querySelector<HTMLButtonElement>('[role=\"gridcell\"][tabindex=\"0\"]')?.focus({ preventScroll: true });\n });\n});\n\n/** Moves focus to the field. Exposed so a consumer can drive it from a ref. */\nfunction focus(): void {\n get(textInput)?.focus({ preventScroll: true });\n}\n\nfunction focusField(): void {\n nextTick(focus);\n}\n\nonMounted(() => {\n if (autofocus && !disabled)\n focusField();\n});\n\n/** Escape inside the calendar closes it and hands focus back to the field. */\nfunction closeFromMenu(): void {\n set(isOpen, false);\n focusField();\n}\n\n/**\n * The menu used to be mouse-only: the activator carried no key handlers, so\n * there was no way to reach the calendar from the keyboard. Alt+ArrowDown\n * opens it and Escape closes it, following the combobox convention, and the\n * append chevron is a real button for anyone who tabs to it instead.\n *\n * Enter and Escape are the other ways to be done with the field, and the keys\n * a consumer tends to close its editor on. Escape reaches that point only once\n * the calendar is already shut, and discards nothing, since the segments stay\n * on screen either way, so it commits what was entered rather than dropping it\n * when the field goes. Both write the value before the key carries on\n * bubbling, so it survives that close.\n */\nfunction onKeyDown(event: KeyboardEvent): void {\n if (disabled || readonly)\n return;\n\n if (event.altKey && event.key === 'ArrowDown') {\n event.preventDefault();\n set(isOpen, true);\n focusCalendar();\n return;\n }\n\n if (event.key === 'Escape' && get(isOpen)) {\n set(isOpen, false);\n return;\n }\n\n if (event.key === 'Enter' || event.key === 'Escape')\n commitPartialTime();\n\n handleKeyDown(event);\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n\nconst menuActions = computed<DateTimePickerAction[]>(\n () => actions.filter(action => action !== 'clear' || allowEmpty),\n);\n\nconst anyMenuOpen = computed<boolean>(() => get(isOpen) || get(calendarMenuOpen));\n\nwatch(anyMenuOpen, (value) => {\n set(menuOpen, value);\n});\n\ndefineExpose({\n focus,\n});\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"getRootAttrs($attrs, [])\"\n :class=\"ui.wrapper({ class: cn($attrs.class) })\"\n :options=\"MENU_OPTIONS\"\n :dense=\"dense\"\n :hint=\"hint\"\n :disabled=\"disabled\"\n :success-messages=\"successMessages\"\n :error-messages=\"combinedErrorMessages\"\n :close-on-content-click=\"false\"\n :show-details=\"!hideDetails\"\n :persistent=\"calendarMenuOpen\"\n full-width\n disable-auto-focus\n >\n <template #activator=\"{ attrs, open }\">\n <div\n ref=\"activator\"\n :class=\"ui.activator()\"\n v-bind=\"{\n ...getNonRootAttrs($attrs, ['onClick', 'class']),\n ...(readonly ? {} : attrs),\n }\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n @mouseenter=\"isHovered = true\"\n @mouseleave=\"isHovered = false\"\n @click=\"setInputFocus()\"\n >\n <span\n v-if=\"isOutlined && (searchInputFocused || open || valueSet)\"\n data-id=\"label\"\n :class=\"[\n ui.label(),\n { 'pr-2': !valueSet && !open && isOutlined },\n ]\"\n >\n {{ fieldLabel }}\n <span\n v-if=\"required\"\n data-id=\"required-indicator\"\n :class=\"ui.required()\"\n >\n ﹡\n </span>\n </span>\n\n <span :class=\"ui.iconPrepend()\">\n <RuiIcon\n class=\"text-rui-text-secondary transition\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-calendar-days\"\n />\n </span>\n\n <div :class=\"ui.value()\">\n <input\n ref=\"textInput\"\n :disabled=\"disabled\"\n :value=\"formattedDisplay\"\n class=\"bg-transparent outline-none flex-1 min-w-0\"\n type=\"text\"\n inputmode=\"numeric\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n autocapitalize=\"off\"\n :placeholder=\"dateFormat\"\n :readonly=\"readonly\"\n :aria-invalid=\"hasError\"\n :aria-label=\"fieldLabel\"\n :aria-required=\"required || undefined\"\n @mousedown=\"handleMouseDown($event)\"\n @focus=\"handleFocus()\"\n @blur=\"onBlur()\"\n @select=\"handleInputSelection($event)\"\n @click.stop=\"handleInputClick($event)\"\n @keydown=\"onKeyDown($event)\"\n @paste=\"handlePaste($event)\"\n @input=\"handleInput($event)\"\n />\n </div>\n\n <RuiButton\n v-if=\"allowEmpty && valueSet && !disabled\"\n variant=\"text\"\n icon\n data-id=\"clear-button\"\n size=\"sm\"\n color=\"error\"\n :aria-label=\"clearLabel\"\n :class=\"[\n ui.clear(),\n anyFocused && '!visible',\n { 'mr-2': !dense },\n ]\"\n @click.stop.prevent=\"clear()\"\n >\n <RuiIcon\n name=\"lu-x\"\n size=\"18\"\n />\n </RuiButton>\n\n <!-- Out of the tab sequence, following the combobox pattern: the button only duplicates\n Alt+ArrowDown on the field, so leaving it in cost two stops to cross one date field\n and four to cross a from/to pair, for nothing a keyboard user could not already do.\n It stays a real button, so it keeps its label and its expanded state for anyone\n reaching it by any other means. -->\n <button\n v-if=\"!disabled && !readonly\"\n type=\"button\"\n tabindex=\"-1\"\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n :aria-label=\"toggleLabel\"\n :aria-expanded=\"isOpen\"\n aria-haspopup=\"dialog\"\n @click=\"arrowClicked($event)\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </button>\n <span\n v-else\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </span>\n </div>\n <fieldset\n v-if=\"isOutlined\"\n :class=\"ui.fieldset()\"\n >\n <legend :class=\"ui.legend()\">\n {{ legendText }}\n </legend>\n </fieldset>\n </template>\n <template #default>\n <RuiDateTimePickerMenu\n ref=\"menuWrapperRef\"\n v-model:selected-date=\"selectedDate\"\n v-model:selected-time=\"selectedTime\"\n v-model:selected-hour=\"modelHour\"\n v-model:selected-minute=\"modelMinute\"\n v-model:selected-second=\"modelSecond\"\n v-model:selected-millisecond=\"modelMillisecond\"\n v-model:time-selection=\"timeSelection\"\n v-model:selected-timezone=\"modelTimezone\"\n v-model:calendar-menu-open=\"calendarMenuOpen\"\n :accuracy=\"accuracy\"\n :max-date=\"maxAllowedDate\"\n :min-date=\"minAllowedDate\"\n :show-timezone=\"showTimezone\"\n :actions=\"menuActions\"\n @keydown.escape=\"closeFromMenu()\"\n @set-now=\"setNow()\"\n @set-today=\"setToday()\"\n @clear=\"clear()\"\n >\n <slot name=\"menu-content\" />\n </RuiDateTimePickerMenu>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RuiDateTimePicker.js","names":[],"sources":["../../../src/components/date-time-picker/RuiDateTimePicker.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type { ComponentPublicInstance } from 'vue';\nimport type { DateTimePickerAction, DateTimeSegmentType } from '@/components/date-time-picker/types';\nimport type { TimePickerSelection } from '@/components/time-picker/RuiTimePicker.vue';\nimport RuiButton from '@/components/buttons/button/RuiButton.vue';\nimport { dateTimePickerStyles, type DateTimePickerVariant } from '@/components/date-time-picker/date-time-picker-styles';\nimport RuiDateTimePickerMenu from '@/components/date-time-picker/RuiDateTimePickerMenu.vue';\nimport { useDateTimeSelection } from '@/components/date-time-picker/use-date-time-selection';\nimport { useInputHandler } from '@/components/date-time-picker/use-input-handler';\nimport { useKeyboardHandler } from '@/components/date-time-picker/use-keyboard-handler';\nimport RuiIcon from '@/components/icons/RuiIcon.vue';\nimport RuiMenu from '@/components/overlays/menu/RuiMenu.vue';\nimport { type FloatingOptions, Placement } from '@/composables/floating';\nimport { useRuiI8n } from '@/composables/use-rui-i18n';\nimport { RUI_I18N_KEYS } from '@/i18n/keys';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs } from '@/utils/helpers';\nimport { cn } from '@/utils/tv';\n\ntype DateFormat = 'year-first' | 'month-first' | 'day-first';\n\ntype DateTimeModelType = 'date' | 'epoch-ms' | 'epoch';\n\ntype ModelValueType<T extends DateTimeModelType> = T extends 'date'\n ? Date | undefined\n : T extends 'epoch-ms'\n ? number | undefined\n : T extends 'epoch'\n ? number | undefined\n : Date | number | undefined;\n\nexport interface RuiDateTimePickerProps {\n minDate?: Date | number;\n maxDate?: Date | number | 'now';\n format?: DateFormat;\n type?: DateTimeModelType;\n accuracy?: 'minute' | 'second' | 'millisecond';\n disabled?: boolean;\n allowEmpty?: boolean;\n readonly?: boolean;\n dense?: boolean;\n label?: string;\n variant?: DateTimePickerVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n required?: boolean;\n /**\n * Renders the timezone selector in the menu. Off by default: the value is\n * emitted as a date or an epoch, so the picked timezone does not survive a\n * round trip and most consumers work in local time.\n */\n showTimezone?: boolean;\n /**\n * Actions rendered in the menu footer. `clear` is only rendered when the\n * picker is `allowEmpty`. Pass an empty array to drop the footer entirely.\n */\n actions?: DateTimePickerAction[];\n /**\n * Focuses the field once it is mounted. The native attribute is ignored for\n * an input inserted into an already loaded document, which is the usual case\n * for a picker revealed by an editor or a dialog.\n */\n autofocus?: boolean;\n /**\n * Accepts an entry that stops short of the full format, filling the segments\n * it never reached from one end of the day: `start` gives a bare date\n * 00:00:00.000 and `end` gives it 23:59:59.999. Meant for a range, where the\n * two bounds want opposite ends. Left unset, an entry missing its time is not\n * a value and nothing is emitted.\n *\n * The fill runs when the user is done with the field - leaving it, pressing\n * enter, or closing the calendar - and is written back into the segments, so\n * what it decided on is on screen.\n *\n * Spelled out rather than written as `PartialTimeMode`: a consumer that hands\n * this whole interface to its own `defineProps` needs every member resolvable\n * by the SFC compiler, which does not follow the type into the package.\n */\n partialTime?: 'start' | 'end';\n}\n\ndefineOptions({\n name: 'RuiDateTimePicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<ModelValueType<DateTimeModelType>>({ required: true });\nconst menuOpen = defineModel<boolean>('menuOpen', { default: false });\n\nconst {\n disabled = false,\n readonly = false,\n allowEmpty = false,\n dense = false,\n type = 'epoch-ms',\n hideDetails = false,\n label,\n variant = 'default',\n hint,\n maxDate,\n minDate,\n format = 'day-first',\n accuracy = 'minute',\n errorMessages = [],\n successMessages = [],\n required = false,\n showTimezone = false,\n actions = ['now'],\n autofocus = false,\n partialTime,\n} = defineProps<RuiDateTimePickerProps>();\n\ndefineSlots<{\n 'menu-content': () => any;\n}>();\n\nconst MENU_OPTIONS: FloatingOptions = { placement: Placement.bottomStart };\n\nconst baseFormats: Record<DateFormat, string> = {\n 'day-first': 'DD/MM/YYYY HH:mm',\n 'month-first': 'MM/DD/YYYY HH:mm',\n 'year-first': 'YYYY/MM/DD HH:mm',\n};\n\nconst isOpen = ref<boolean>(false);\nconst isHovered = ref<boolean>(false);\nconst cursorPosition = ref<number>(0);\nconst currentValue = ref<number>();\n\nconst { t } = useRuiI8n();\n\nconst keys = RUI_I18N_KEYS.dateTimePicker;\n\nconst fieldLabel = computed<string>(() => label ?? t(keys.label, 'Pick a date'));\nconst clearLabel = computed<string>(() => t(keys.clearValue, 'Clear the date'));\nconst toggleLabel = computed<string>(() => (get(isOpen)\n ? t(keys.closeCalendar, 'Close the calendar')\n : t(keys.openCalendar, 'Open the calendar')));\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuWrapperRef = useTemplateRef<ComponentPublicInstance>('menuWrapperRef');\nconst calendarMenuOpen = ref<boolean>(false);\n\nconst { focused: activatorFocusedWithin } = useFocusWithin(activator);\nconst { focused: menuWrapperFocusedWithin } = useFocusWithin(menuWrapperRef);\nconst { focused: searchInputFocused } = useFocus(textInput);\n\nconst anyFocused = computed<boolean>(() => get(activatorFocusedWithin) || get(menuWrapperFocusedWithin));\n\nconst dateFormat = computed<string>(() => {\n const fmt = baseFormats[format];\n if (accuracy === 'second') {\n return fmt.replace('HH:mm', 'HH:mm:ss');\n }\n else if (accuracy === 'millisecond') {\n return fmt.replace('HH:mm', 'HH:mm:ss.SSS');\n }\n return fmt;\n});\n\nconst {\n clear: clearSelection,\n commitPartialTime,\n getDateTime,\n internalErrorMessages,\n maxAllowedDate,\n minAllowedDate,\n segmentData,\n selectedDate,\n modelDay,\n modelHour,\n modelMillisecond,\n modelMinute,\n modelMonth,\n modelSecond,\n selectedTime,\n modelTimezone,\n modelYear,\n setNow,\n setToday,\n valueSet,\n} = useDateTimeSelection({\n accuracy,\n allowEmpty,\n dateFormat,\n maxDate,\n minDate,\n modelValue,\n partialTime,\n type,\n});\n\nconst { setValue, getCurrent } = useInputHandler(segmentData, currentValue);\n\nconst {\n clear: clearSegment,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\n pasteRejected,\n selectFirstSegment,\n setSegment,\n} = useKeyboardHandler({\n accuracy,\n currentValue,\n cursorPosition,\n dateFormat,\n disabled,\n getCurrent,\n getDateTime,\n readonly,\n setValue,\n textInput,\n timezone: modelTimezone,\n});\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst isOutlined = computed<boolean>(() => variant === 'outlined');\n\n/** True once any segment holds a digit, even a partially typed date. */\nconst anySegmentSet = computed<boolean>(() => [\n modelYear,\n modelMonth,\n modelDay,\n modelHour,\n modelMinute,\n modelSecond,\n modelMillisecond,\n].some(segment => isDefined(segment)));\n\n/**\n * The field's text.\n *\n * An untouched field shows its format through the placeholder rather than\n * holding the tokens as its value, where a screen reader reads them as content\n * and select-all copies them. The tokens stay while the field is focused: that\n * is when the segment machinery highlights them, and collapsing the value\n * mid-edit would blank the field under the cursor. The guard is \"no segment\n * set\" rather than `valueSet`, so blurring a half-typed date keeps what was\n * entered on screen.\n */\nconst formattedDisplay = computed<string>(() => {\n if (!get(anySegmentSet) && !get(searchInputFocused)) {\n return '';\n }\n\n let result = get(dateFormat);\n\n const replacements = [\n { pattern: 'YYYY', value: getDisplayValue(modelYear, 4) },\n { pattern: 'MM', value: getDisplayValue(modelMonth, 2) },\n { pattern: 'DD', value: getDisplayValue(modelDay, 2) },\n { pattern: 'HH', value: getDisplayValue(modelHour, 2) },\n { pattern: 'mm', value: getDisplayValue(modelMinute, 2) },\n { pattern: 'ss', value: getDisplayValue(modelSecond, 2) },\n { pattern: 'SSS', value: getDisplayValue(modelMillisecond, 3) },\n ];\n\n for (const { pattern, value } of replacements) {\n if (value !== undefined) {\n result = result.replace(pattern, value);\n }\n }\n\n return result;\n});\n\n/**\n * An untouched field holds no value until focus expands the format tokens into\n * it. That patch overwrites the input's value, and writing a value drops any\n * selection with it, so the highlight `handleFocus` just set is gone by the\n * time the tokens are on screen and the caret ends up after them. Re-select\n * the first segment once the tokens have actually landed.\n */\nwatch(formattedDisplay, (value, previous) => {\n if (previous === '' && value !== '' && get(searchInputFocused))\n selectFirstSegment();\n}, { flush: 'post' });\n\nconst timeSelection = computed<TimePickerSelection>({\n get() {\n const type = getCurrentSegment()?.type;\n\n if (type === 'mm') {\n return 'minute';\n }\n else if (type === 'ss') {\n return 'second';\n }\n else if (type === 'SSS') {\n return 'millisecond';\n }\n return 'hour';\n },\n set(value: TimePickerSelection) {\n let segmentType: DateTimeSegmentType = 'HH';\n if (value === 'minute') {\n segmentType = 'mm';\n }\n else if (value === 'second') {\n segmentType = 'ss';\n }\n else if (value === 'millisecond') {\n segmentType = 'SSS';\n }\n\n setSegment(segmentType);\n },\n});\n\nconst float = computed<boolean>(() => (get(isOpen) || get(valueSet) || get(searchInputFocused)) && get(isOutlined));\n\nconst legendText = computed<string>(() => {\n if (!get(float))\n return '';\n const resolved = get(fieldLabel);\n return required ? `${resolved} ﹡` : resolved;\n});\n\nconst ui = computed<ReturnType<typeof dateTimePickerStyles>>(() => dateTimePickerStyles({\n filled: variant === 'filled',\n outlined: get(isOutlined),\n float: get(float),\n showLabel: !!get(legendText),\n opened: get(isOpen),\n hovered: get(isHovered),\n dense,\n disabled,\n readonly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst pasteMessage = computed<string>(() => (get(pasteRejected)\n ? t(keys.pasteUnreadable, 'Could not read a date from the pasted text')\n : ''));\n\n/**\n * The paste message goes first: the details show one message, and it answers\n * what the user just did, which a standing validation error does not.\n */\nconst combinedErrorMessages = computed<string[]>(() => {\n const paste = get(pasteMessage) ? [get(pasteMessage)] : [];\n if (!errorMessages)\n return [...paste, ...get(internalErrorMessages)];\n\n const propErrors = Array.isArray(errorMessages) ? errorMessages : [errorMessages];\n return [...paste, ...propErrors, ...get(internalErrorMessages)];\n});\n\nfunction getDisplayValue(digit: Ref<number | undefined>, padding: number): string | undefined {\n return isDefined(digit) ? get(digit).toString().padStart(padding, '0') : undefined;\n}\n\nasync function setInputFocus(): Promise<void> {\n await nextTick(() => {\n set(searchInputFocused, true);\n });\n}\n\nfunction clear(segmentType?: string): void {\n if (!segmentType) {\n clearSelection();\n set(currentValue, undefined);\n return;\n }\n\n clearSegment(segmentType);\n}\n\n/**\n * An entry left incomplete is completed once the user is done with the field,\n * never while they are still filling it in: a half typed hour is not a segment\n * they left out. Leaving the field counts, unless the calendar is open, since\n * then the focus is only moving into it and the menu closing covers that.\n */\nfunction onBlur(): void {\n handleBlur();\n if (!get(isOpen))\n commitPartialTime();\n}\n\nwatch(isOpen, (open) => {\n if (!open && !get(searchInputFocused))\n commitPartialTime();\n});\n\n/**\n * Selects the clicked segment before opening the menu, so the selection is not\n * lost to the DOM changes that opening brings.\n */\nfunction handleInputClick(event: MouseEvent): void {\n handleClick(event);\n if (!get(isOpen)) {\n set(isOpen, true);\n }\n}\n\n/**\n * The menu is teleported to the body, so it never sits next to the field in\n * the tab sequence. Opening it from the keyboard therefore moves focus into\n * the calendar; opening it with the mouse leaves focus in the field, which is\n * what `disable-auto-focus` on the menu is there for.\n */\nconst focusCalendarOnOpen = ref<boolean>(false);\n\n/**\n * Asks for focus to move into the calendar. The menu is teleported and mounts\n * a frame later, so the watcher below waits for the wrapper to appear rather\n * than guessing at a number of ticks.\n */\nfunction focusCalendar(): void {\n set(focusCalendarOnOpen, true);\n}\n\nwatch(menuWrapperRef, (menu) => {\n if (!menu || !get(focusCalendarOnOpen))\n return;\n\n set(focusCalendarOnOpen, false);\n nextTick(() => {\n const el = menu.$el as HTMLElement | undefined;\n el?.querySelector<HTMLButtonElement>('[role=\"gridcell\"][tabindex=\"0\"]')?.focus({ preventScroll: true });\n });\n});\n\n/** Moves focus to the field. Exposed so a consumer can drive it from a ref. */\nfunction focus(): void {\n get(textInput)?.focus({ preventScroll: true });\n}\n\nfunction focusField(): void {\n nextTick(focus);\n}\n\nonMounted(() => {\n if (autofocus && !disabled)\n focusField();\n});\n\n/** Escape inside the calendar closes it and hands focus back to the field. */\nfunction closeFromMenu(): void {\n set(isOpen, false);\n focusField();\n}\n\n/**\n * The menu used to be mouse-only: the activator carried no key handlers, so\n * there was no way to reach the calendar from the keyboard. Alt+ArrowDown\n * opens it and Escape closes it, following the combobox convention, and the\n * append chevron is a real button for anyone who tabs to it instead.\n *\n * Enter and Escape are the other ways to be done with the field, and the keys\n * a consumer tends to close its editor on. Escape reaches that point only once\n * the calendar is already shut, and discards nothing, since the segments stay\n * on screen either way, so it commits what was entered rather than dropping it\n * when the field goes. Both write the value before the key carries on\n * bubbling, so it survives that close.\n */\nfunction onKeyDown(event: KeyboardEvent): void {\n if (disabled || readonly)\n return;\n\n if (event.altKey && event.key === 'ArrowDown') {\n event.preventDefault();\n set(isOpen, true);\n focusCalendar();\n return;\n }\n\n if (event.key === 'Escape' && get(isOpen)) {\n set(isOpen, false);\n return;\n }\n\n if (event.key === 'Enter' || event.key === 'Escape')\n commitPartialTime();\n\n handleKeyDown(event);\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n\nconst menuActions = computed<DateTimePickerAction[]>(\n () => actions.filter(action => action !== 'clear' || allowEmpty),\n);\n\nconst anyMenuOpen = computed<boolean>(() => get(isOpen) || get(calendarMenuOpen));\n\nwatch(anyMenuOpen, (value) => {\n set(menuOpen, value);\n});\n\ndefineExpose({\n focus,\n});\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"getRootAttrs($attrs, [])\"\n :class=\"ui.wrapper({ class: cn($attrs.class) })\"\n :options=\"MENU_OPTIONS\"\n :dense=\"dense\"\n :hint=\"hint\"\n :disabled=\"disabled\"\n :success-messages=\"successMessages\"\n :error-messages=\"combinedErrorMessages\"\n :close-on-content-click=\"false\"\n :show-details=\"!hideDetails\"\n :persistent=\"calendarMenuOpen\"\n full-width\n disable-auto-focus\n >\n <template #activator=\"{ attrs, open }\">\n <div\n ref=\"activator\"\n :class=\"ui.activator()\"\n v-bind=\"{\n ...getNonRootAttrs($attrs, ['onClick', 'class']),\n ...(readonly ? {} : attrs),\n }\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n @mouseenter=\"isHovered = true\"\n @mouseleave=\"isHovered = false\"\n @click=\"setInputFocus()\"\n >\n <span\n v-if=\"isOutlined && (searchInputFocused || open || valueSet)\"\n data-id=\"label\"\n :class=\"[\n ui.label(),\n { 'pr-2': !valueSet && !open && isOutlined },\n ]\"\n >\n {{ fieldLabel }}\n <span\n v-if=\"required\"\n data-id=\"required-indicator\"\n :class=\"ui.required()\"\n >\n ﹡\n </span>\n </span>\n\n <span :class=\"ui.iconPrepend()\">\n <RuiIcon\n class=\"text-rui-text-secondary transition\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-calendar-days\"\n />\n </span>\n\n <div :class=\"ui.value()\">\n <input\n ref=\"textInput\"\n :disabled=\"disabled\"\n :value=\"formattedDisplay\"\n class=\"bg-transparent outline-none flex-1 min-w-0\"\n type=\"text\"\n inputmode=\"numeric\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n autocapitalize=\"off\"\n :placeholder=\"dateFormat\"\n :readonly=\"readonly\"\n :aria-invalid=\"hasError\"\n :aria-label=\"fieldLabel\"\n :aria-required=\"required || undefined\"\n @mousedown=\"handleMouseDown($event)\"\n @focus=\"handleFocus()\"\n @blur=\"onBlur()\"\n @select=\"handleInputSelection($event)\"\n @click.stop=\"handleInputClick($event)\"\n @keydown=\"onKeyDown($event)\"\n @paste=\"handlePaste($event)\"\n @input=\"handleInput($event)\"\n />\n <!-- The details line is not a live region, so a rejected paste is announced from here -->\n <span\n class=\"sr-only\"\n aria-live=\"polite\"\n data-id=\"paste-status\"\n >\n {{ pasteMessage }}\n </span>\n </div>\n\n <RuiButton\n v-if=\"allowEmpty && valueSet && !disabled\"\n variant=\"text\"\n icon\n data-id=\"clear-button\"\n size=\"sm\"\n color=\"error\"\n :aria-label=\"clearLabel\"\n :class=\"[\n ui.clear(),\n anyFocused && '!visible',\n { 'mr-2': !dense },\n ]\"\n @click.stop.prevent=\"clear()\"\n >\n <RuiIcon\n name=\"lu-x\"\n size=\"18\"\n />\n </RuiButton>\n\n <!-- Out of the tab sequence, following the combobox pattern: the button only duplicates\n Alt+ArrowDown on the field, so leaving it in cost two stops to cross one date field\n and four to cross a from/to pair, for nothing a keyboard user could not already do.\n It stays a real button, so it keeps its label and its expanded state for anyone\n reaching it by any other means. -->\n <button\n v-if=\"!disabled && !readonly\"\n type=\"button\"\n tabindex=\"-1\"\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n :aria-label=\"toggleLabel\"\n :aria-expanded=\"isOpen\"\n aria-haspopup=\"dialog\"\n @click=\"arrowClicked($event)\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </button>\n <span\n v-else\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </span>\n </div>\n <fieldset\n v-if=\"isOutlined\"\n :class=\"ui.fieldset()\"\n >\n <legend :class=\"ui.legend()\">\n {{ legendText }}\n </legend>\n </fieldset>\n </template>\n <template #default>\n <RuiDateTimePickerMenu\n ref=\"menuWrapperRef\"\n v-model:selected-date=\"selectedDate\"\n v-model:selected-time=\"selectedTime\"\n v-model:selected-hour=\"modelHour\"\n v-model:selected-minute=\"modelMinute\"\n v-model:selected-second=\"modelSecond\"\n v-model:selected-millisecond=\"modelMillisecond\"\n v-model:time-selection=\"timeSelection\"\n v-model:selected-timezone=\"modelTimezone\"\n v-model:calendar-menu-open=\"calendarMenuOpen\"\n :accuracy=\"accuracy\"\n :max-date=\"maxAllowedDate\"\n :min-date=\"minAllowedDate\"\n :show-timezone=\"showTimezone\"\n :actions=\"menuActions\"\n @keydown.escape=\"closeFromMenu()\"\n @set-now=\"setNow()\"\n @set-today=\"setToday()\"\n @clear=\"clear()\"\n >\n <slot name=\"menu-content\" />\n </RuiDateTimePickerMenu>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":""}
@@ -26,7 +26,12 @@ var _hoisted_2 = [
26
26
  "aria-label",
27
27
  "aria-required"
28
28
  ];
29
- var _hoisted_3 = ["aria-label", "aria-expanded"];
29
+ var _hoisted_3 = {
30
+ class: "sr-only",
31
+ "aria-live": "polite",
32
+ "data-id": "paste-status"
33
+ };
34
+ var _hoisted_4 = ["aria-label", "aria-expanded"];
30
35
  var RuiDateTimePicker_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
31
36
  name: "RuiDateTimePicker",
32
37
  inheritAttrs: false,
@@ -129,7 +134,7 @@ var RuiDateTimePicker_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
129
134
  type: __props.type
130
135
  });
131
136
  const { setValue, getCurrent } = useInputHandler(segmentData, currentValue);
132
- const { clear: clearSegment, getCurrentSegment, handleBlur, handleClick, handleFocus, handleInput, handleInputSelection, handleKeyDown, handleMouseDown, handlePaste, selectFirstSegment, setSegment } = useKeyboardHandler({
137
+ const { clear: clearSegment, getCurrentSegment, handleBlur, handleClick, handleFocus, handleInput, handleInputSelection, handleKeyDown, handleMouseDown, handlePaste, pasteRejected, selectFirstSegment, setSegment } = useKeyboardHandler({
133
138
  accuracy: __props.accuracy,
134
139
  currentValue,
135
140
  cursorPosition,
@@ -139,7 +144,8 @@ var RuiDateTimePicker_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
139
144
  getDateTime,
140
145
  readonly: __props.readonly,
141
146
  setValue,
142
- textInput
147
+ textInput,
148
+ timezone: modelTimezone
143
149
  });
144
150
  const { hasError, hasSuccess } = useFormTextDetail(() => __props.errorMessages, () => __props.successMessages);
145
151
  const isOutlined = computed(() => __props.variant === "outlined");
@@ -236,6 +242,7 @@ var RuiDateTimePicker_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
236
242
  filled: __props.variant === "filled",
237
243
  outlined: get$1(isOutlined),
238
244
  float: get$1(float),
245
+ showLabel: !!get$1(legendText),
239
246
  opened: get$1(isOpen),
240
247
  hovered: get$1(isHovered),
241
248
  dense: __props.dense,
@@ -244,9 +251,20 @@ var RuiDateTimePicker_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
244
251
  hasError: get$1(hasError),
245
252
  hasSuccess: get$1(hasSuccess) && !get$1(hasError)
246
253
  }));
254
+ const pasteMessage = computed(() => get$1(pasteRejected) ? t(keys.pasteUnreadable, "Could not read a date from the pasted text") : "");
255
+ /**
256
+ * The paste message goes first: the details show one message, and it answers
257
+ * what the user just did, which a standing validation error does not.
258
+ */
247
259
  const combinedErrorMessages = computed(() => {
248
- if (!__props.errorMessages) return get$1(internalErrorMessages);
249
- return [...Array.isArray(__props.errorMessages) ? __props.errorMessages : [__props.errorMessages], ...get$1(internalErrorMessages)];
260
+ const paste = get$1(pasteMessage) ? [get$1(pasteMessage)] : [];
261
+ if (!__props.errorMessages) return [...paste, ...get$1(internalErrorMessages)];
262
+ const propErrors = Array.isArray(__props.errorMessages) ? __props.errorMessages : [__props.errorMessages];
263
+ return [
264
+ ...paste,
265
+ ...propErrors,
266
+ ...get$1(internalErrorMessages)
267
+ ];
250
268
  });
251
269
  function getDisplayValue(digit, padding) {
252
270
  return isDefined(digit) ? get$1(digit).toString().padStart(padding, "0") : void 0;
@@ -433,7 +451,7 @@ var RuiDateTimePicker_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
433
451
  onKeydown: _cache[5] || (_cache[5] = ($event) => onKeyDown($event)),
434
452
  onPaste: _cache[6] || (_cache[6] = ($event) => unref(handlePaste)($event)),
435
453
  onInput: _cache[7] || (_cache[7] = ($event) => unref(handleInput)($event))
436
- }, null, 40, _hoisted_2)], 2),
454
+ }, null, 40, _hoisted_2), createElementVNode("span", _hoisted_3, toDisplayString(unref(pasteMessage)), 1)], 2),
437
455
  __props.allowEmpty && unref(valueSet) && !__props.disabled ? (openBlock(), createBlock(RuiButton_default, {
438
456
  key: 1,
439
457
  variant: "text",
@@ -469,7 +487,7 @@ var RuiDateTimePicker_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
469
487
  class: normalizeClass(unref(ui).icon()),
470
488
  size: __props.dense ? 16 : 24,
471
489
  name: "lu-chevron-down"
472
- }, null, 8, ["class", "size"])], 10, _hoisted_3)) : (openBlock(), createElementBlock("span", {
490
+ }, null, 8, ["class", "size"])], 10, _hoisted_4)) : (openBlock(), createElementBlock("span", {
473
491
  key: 3,
474
492
  class: normalizeClass(unref(ui).iconWrapper()),
475
493
  "data-id": "append"
@@ -1 +1 @@
1
- {"version":3,"file":"RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../src/components/date-time-picker/RuiDateTimePicker.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type { ComponentPublicInstance } from 'vue';\nimport type { DateTimePickerAction, DateTimeSegmentType } from '@/components/date-time-picker/types';\nimport type { TimePickerSelection } from '@/components/time-picker/RuiTimePicker.vue';\nimport RuiButton from '@/components/buttons/button/RuiButton.vue';\nimport { dateTimePickerStyles, type DateTimePickerVariant } from '@/components/date-time-picker/date-time-picker-styles';\nimport RuiDateTimePickerMenu from '@/components/date-time-picker/RuiDateTimePickerMenu.vue';\nimport { useDateTimeSelection } from '@/components/date-time-picker/use-date-time-selection';\nimport { useInputHandler } from '@/components/date-time-picker/use-input-handler';\nimport { useKeyboardHandler } from '@/components/date-time-picker/use-keyboard-handler';\nimport RuiIcon from '@/components/icons/RuiIcon.vue';\nimport RuiMenu from '@/components/overlays/menu/RuiMenu.vue';\nimport { type FloatingOptions, Placement } from '@/composables/floating';\nimport { useRuiI8n } from '@/composables/use-rui-i18n';\nimport { RUI_I18N_KEYS } from '@/i18n/keys';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs } from '@/utils/helpers';\nimport { cn } from '@/utils/tv';\n\ntype DateFormat = 'year-first' | 'month-first' | 'day-first';\n\ntype DateTimeModelType = 'date' | 'epoch-ms' | 'epoch';\n\ntype ModelValueType<T extends DateTimeModelType> = T extends 'date'\n ? Date | undefined\n : T extends 'epoch-ms'\n ? number | undefined\n : T extends 'epoch'\n ? number | undefined\n : Date | number | undefined;\n\nexport interface RuiDateTimePickerProps {\n minDate?: Date | number;\n maxDate?: Date | number | 'now';\n format?: DateFormat;\n type?: DateTimeModelType;\n accuracy?: 'minute' | 'second' | 'millisecond';\n disabled?: boolean;\n allowEmpty?: boolean;\n readonly?: boolean;\n dense?: boolean;\n label?: string;\n variant?: DateTimePickerVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n required?: boolean;\n /**\n * Renders the timezone selector in the menu. Off by default: the value is\n * emitted as a date or an epoch, so the picked timezone does not survive a\n * round trip and most consumers work in local time.\n */\n showTimezone?: boolean;\n /**\n * Actions rendered in the menu footer. `clear` is only rendered when the\n * picker is `allowEmpty`. Pass an empty array to drop the footer entirely.\n */\n actions?: DateTimePickerAction[];\n /**\n * Focuses the field once it is mounted. The native attribute is ignored for\n * an input inserted into an already loaded document, which is the usual case\n * for a picker revealed by an editor or a dialog.\n */\n autofocus?: boolean;\n /**\n * Accepts an entry that stops short of the full format, filling the segments\n * it never reached from one end of the day: `start` gives a bare date\n * 00:00:00.000 and `end` gives it 23:59:59.999. Meant for a range, where the\n * two bounds want opposite ends. Left unset, an entry missing its time is not\n * a value and nothing is emitted.\n *\n * The fill runs when the user is done with the field - leaving it, pressing\n * enter, or closing the calendar - and is written back into the segments, so\n * what it decided on is on screen.\n *\n * Spelled out rather than written as `PartialTimeMode`: a consumer that hands\n * this whole interface to its own `defineProps` needs every member resolvable\n * by the SFC compiler, which does not follow the type into the package.\n */\n partialTime?: 'start' | 'end';\n}\n\ndefineOptions({\n name: 'RuiDateTimePicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<ModelValueType<DateTimeModelType>>({ required: true });\nconst menuOpen = defineModel<boolean>('menuOpen', { default: false });\n\nconst {\n disabled = false,\n readonly = false,\n allowEmpty = false,\n dense = false,\n type = 'epoch-ms',\n hideDetails = false,\n label,\n variant = 'default',\n hint,\n maxDate,\n minDate,\n format = 'day-first',\n accuracy = 'minute',\n errorMessages = [],\n successMessages = [],\n required = false,\n showTimezone = false,\n actions = ['now'],\n autofocus = false,\n partialTime,\n} = defineProps<RuiDateTimePickerProps>();\n\ndefineSlots<{\n 'menu-content': () => any;\n}>();\n\nconst MENU_OPTIONS: FloatingOptions = { placement: Placement.bottomStart };\n\nconst baseFormats: Record<DateFormat, string> = {\n 'day-first': 'DD/MM/YYYY HH:mm',\n 'month-first': 'MM/DD/YYYY HH:mm',\n 'year-first': 'YYYY/MM/DD HH:mm',\n};\n\nconst isOpen = ref<boolean>(false);\nconst isHovered = ref<boolean>(false);\nconst cursorPosition = ref<number>(0);\nconst currentValue = ref<number>();\n\nconst { t } = useRuiI8n();\n\nconst keys = RUI_I18N_KEYS.dateTimePicker;\n\nconst fieldLabel = computed<string>(() => label ?? t(keys.label, 'Pick a date'));\nconst clearLabel = computed<string>(() => t(keys.clearValue, 'Clear the date'));\nconst toggleLabel = computed<string>(() => (get(isOpen)\n ? t(keys.closeCalendar, 'Close the calendar')\n : t(keys.openCalendar, 'Open the calendar')));\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuWrapperRef = useTemplateRef<ComponentPublicInstance>('menuWrapperRef');\nconst calendarMenuOpen = ref<boolean>(false);\n\nconst { focused: activatorFocusedWithin } = useFocusWithin(activator);\nconst { focused: menuWrapperFocusedWithin } = useFocusWithin(menuWrapperRef);\nconst { focused: searchInputFocused } = useFocus(textInput);\n\nconst anyFocused = computed<boolean>(() => get(activatorFocusedWithin) || get(menuWrapperFocusedWithin));\n\nconst dateFormat = computed<string>(() => {\n const fmt = baseFormats[format];\n if (accuracy === 'second') {\n return fmt.replace('HH:mm', 'HH:mm:ss');\n }\n else if (accuracy === 'millisecond') {\n return fmt.replace('HH:mm', 'HH:mm:ss.SSS');\n }\n return fmt;\n});\n\nconst {\n clear: clearSelection,\n commitPartialTime,\n getDateTime,\n internalErrorMessages,\n maxAllowedDate,\n minAllowedDate,\n segmentData,\n selectedDate,\n modelDay,\n modelHour,\n modelMillisecond,\n modelMinute,\n modelMonth,\n modelSecond,\n selectedTime,\n modelTimezone,\n modelYear,\n setNow,\n setToday,\n valueSet,\n} = useDateTimeSelection({\n accuracy,\n allowEmpty,\n dateFormat,\n maxDate,\n minDate,\n modelValue,\n partialTime,\n type,\n});\n\nconst { setValue, getCurrent } = useInputHandler(segmentData, currentValue);\n\nconst {\n clear: clearSegment,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\n selectFirstSegment,\n setSegment,\n} = useKeyboardHandler({\n accuracy,\n currentValue,\n cursorPosition,\n dateFormat,\n disabled,\n getCurrent,\n getDateTime,\n readonly,\n setValue,\n textInput,\n});\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst isOutlined = computed<boolean>(() => variant === 'outlined');\n\n/** True once any segment holds a digit, even a partially typed date. */\nconst anySegmentSet = computed<boolean>(() => [\n modelYear,\n modelMonth,\n modelDay,\n modelHour,\n modelMinute,\n modelSecond,\n modelMillisecond,\n].some(segment => isDefined(segment)));\n\n/**\n * The field's text.\n *\n * An untouched field shows its format through the placeholder rather than\n * holding the tokens as its value, where a screen reader reads them as content\n * and select-all copies them. The tokens stay while the field is focused: that\n * is when the segment machinery highlights them, and collapsing the value\n * mid-edit would blank the field under the cursor. The guard is \"no segment\n * set\" rather than `valueSet`, so blurring a half-typed date keeps what was\n * entered on screen.\n */\nconst formattedDisplay = computed<string>(() => {\n if (!get(anySegmentSet) && !get(searchInputFocused)) {\n return '';\n }\n\n let result = get(dateFormat);\n\n const replacements = [\n { pattern: 'YYYY', value: getDisplayValue(modelYear, 4) },\n { pattern: 'MM', value: getDisplayValue(modelMonth, 2) },\n { pattern: 'DD', value: getDisplayValue(modelDay, 2) },\n { pattern: 'HH', value: getDisplayValue(modelHour, 2) },\n { pattern: 'mm', value: getDisplayValue(modelMinute, 2) },\n { pattern: 'ss', value: getDisplayValue(modelSecond, 2) },\n { pattern: 'SSS', value: getDisplayValue(modelMillisecond, 3) },\n ];\n\n for (const { pattern, value } of replacements) {\n if (value !== undefined) {\n result = result.replace(pattern, value);\n }\n }\n\n return result;\n});\n\n/**\n * An untouched field holds no value until focus expands the format tokens into\n * it. That patch overwrites the input's value, and writing a value drops any\n * selection with it, so the highlight `handleFocus` just set is gone by the\n * time the tokens are on screen and the caret ends up after them. Re-select\n * the first segment once the tokens have actually landed.\n */\nwatch(formattedDisplay, (value, previous) => {\n if (previous === '' && value !== '' && get(searchInputFocused))\n selectFirstSegment();\n}, { flush: 'post' });\n\nconst timeSelection = computed<TimePickerSelection>({\n get() {\n const type = getCurrentSegment()?.type;\n\n if (type === 'mm') {\n return 'minute';\n }\n else if (type === 'ss') {\n return 'second';\n }\n else if (type === 'SSS') {\n return 'millisecond';\n }\n return 'hour';\n },\n set(value: TimePickerSelection) {\n let segmentType: DateTimeSegmentType = 'HH';\n if (value === 'minute') {\n segmentType = 'mm';\n }\n else if (value === 'second') {\n segmentType = 'ss';\n }\n else if (value === 'millisecond') {\n segmentType = 'SSS';\n }\n\n setSegment(segmentType);\n },\n});\n\nconst float = computed<boolean>(() => (get(isOpen) || get(valueSet) || get(searchInputFocused)) && get(isOutlined));\n\nconst legendText = computed<string>(() => {\n if (!get(float))\n return '';\n const resolved = get(fieldLabel);\n return required ? `${resolved} ﹡` : resolved;\n});\n\nconst ui = computed<ReturnType<typeof dateTimePickerStyles>>(() => dateTimePickerStyles({\n filled: variant === 'filled',\n outlined: get(isOutlined),\n float: get(float),\n opened: get(isOpen),\n hovered: get(isHovered),\n dense,\n disabled,\n readonly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst combinedErrorMessages = computed<string[]>(() => {\n if (!errorMessages)\n return get(internalErrorMessages);\n\n const propErrors = Array.isArray(errorMessages) ? errorMessages : [errorMessages];\n return [...propErrors, ...get(internalErrorMessages)];\n});\n\nfunction getDisplayValue(digit: Ref<number | undefined>, padding: number): string | undefined {\n return isDefined(digit) ? get(digit).toString().padStart(padding, '0') : undefined;\n}\n\nasync function setInputFocus(): Promise<void> {\n await nextTick(() => {\n set(searchInputFocused, true);\n });\n}\n\nfunction clear(segmentType?: string): void {\n if (!segmentType) {\n clearSelection();\n set(currentValue, undefined);\n return;\n }\n\n clearSegment(segmentType);\n}\n\n/**\n * An entry left incomplete is completed once the user is done with the field,\n * never while they are still filling it in: a half typed hour is not a segment\n * they left out. Leaving the field counts, unless the calendar is open, since\n * then the focus is only moving into it and the menu closing covers that.\n */\nfunction onBlur(): void {\n handleBlur();\n if (!get(isOpen))\n commitPartialTime();\n}\n\nwatch(isOpen, (open) => {\n if (!open && !get(searchInputFocused))\n commitPartialTime();\n});\n\n/**\n * Selects the clicked segment before opening the menu, so the selection is not\n * lost to the DOM changes that opening brings.\n */\nfunction handleInputClick(event: MouseEvent): void {\n handleClick(event);\n if (!get(isOpen)) {\n set(isOpen, true);\n }\n}\n\n/**\n * The menu is teleported to the body, so it never sits next to the field in\n * the tab sequence. Opening it from the keyboard therefore moves focus into\n * the calendar; opening it with the mouse leaves focus in the field, which is\n * what `disable-auto-focus` on the menu is there for.\n */\nconst focusCalendarOnOpen = ref<boolean>(false);\n\n/**\n * Asks for focus to move into the calendar. The menu is teleported and mounts\n * a frame later, so the watcher below waits for the wrapper to appear rather\n * than guessing at a number of ticks.\n */\nfunction focusCalendar(): void {\n set(focusCalendarOnOpen, true);\n}\n\nwatch(menuWrapperRef, (menu) => {\n if (!menu || !get(focusCalendarOnOpen))\n return;\n\n set(focusCalendarOnOpen, false);\n nextTick(() => {\n const el = menu.$el as HTMLElement | undefined;\n el?.querySelector<HTMLButtonElement>('[role=\"gridcell\"][tabindex=\"0\"]')?.focus({ preventScroll: true });\n });\n});\n\n/** Moves focus to the field. Exposed so a consumer can drive it from a ref. */\nfunction focus(): void {\n get(textInput)?.focus({ preventScroll: true });\n}\n\nfunction focusField(): void {\n nextTick(focus);\n}\n\nonMounted(() => {\n if (autofocus && !disabled)\n focusField();\n});\n\n/** Escape inside the calendar closes it and hands focus back to the field. */\nfunction closeFromMenu(): void {\n set(isOpen, false);\n focusField();\n}\n\n/**\n * The menu used to be mouse-only: the activator carried no key handlers, so\n * there was no way to reach the calendar from the keyboard. Alt+ArrowDown\n * opens it and Escape closes it, following the combobox convention, and the\n * append chevron is a real button for anyone who tabs to it instead.\n *\n * Enter and Escape are the other ways to be done with the field, and the keys\n * a consumer tends to close its editor on. Escape reaches that point only once\n * the calendar is already shut, and discards nothing, since the segments stay\n * on screen either way, so it commits what was entered rather than dropping it\n * when the field goes. Both write the value before the key carries on\n * bubbling, so it survives that close.\n */\nfunction onKeyDown(event: KeyboardEvent): void {\n if (disabled || readonly)\n return;\n\n if (event.altKey && event.key === 'ArrowDown') {\n event.preventDefault();\n set(isOpen, true);\n focusCalendar();\n return;\n }\n\n if (event.key === 'Escape' && get(isOpen)) {\n set(isOpen, false);\n return;\n }\n\n if (event.key === 'Enter' || event.key === 'Escape')\n commitPartialTime();\n\n handleKeyDown(event);\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n\nconst menuActions = computed<DateTimePickerAction[]>(\n () => actions.filter(action => action !== 'clear' || allowEmpty),\n);\n\nconst anyMenuOpen = computed<boolean>(() => get(isOpen) || get(calendarMenuOpen));\n\nwatch(anyMenuOpen, (value) => {\n set(menuOpen, value);\n});\n\ndefineExpose({\n focus,\n});\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"getRootAttrs($attrs, [])\"\n :class=\"ui.wrapper({ class: cn($attrs.class) })\"\n :options=\"MENU_OPTIONS\"\n :dense=\"dense\"\n :hint=\"hint\"\n :disabled=\"disabled\"\n :success-messages=\"successMessages\"\n :error-messages=\"combinedErrorMessages\"\n :close-on-content-click=\"false\"\n :show-details=\"!hideDetails\"\n :persistent=\"calendarMenuOpen\"\n full-width\n disable-auto-focus\n >\n <template #activator=\"{ attrs, open }\">\n <div\n ref=\"activator\"\n :class=\"ui.activator()\"\n v-bind=\"{\n ...getNonRootAttrs($attrs, ['onClick', 'class']),\n ...(readonly ? {} : attrs),\n }\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n @mouseenter=\"isHovered = true\"\n @mouseleave=\"isHovered = false\"\n @click=\"setInputFocus()\"\n >\n <span\n v-if=\"isOutlined && (searchInputFocused || open || valueSet)\"\n data-id=\"label\"\n :class=\"[\n ui.label(),\n { 'pr-2': !valueSet && !open && isOutlined },\n ]\"\n >\n {{ fieldLabel }}\n <span\n v-if=\"required\"\n data-id=\"required-indicator\"\n :class=\"ui.required()\"\n >\n ﹡\n </span>\n </span>\n\n <span :class=\"ui.iconPrepend()\">\n <RuiIcon\n class=\"text-rui-text-secondary transition\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-calendar-days\"\n />\n </span>\n\n <div :class=\"ui.value()\">\n <input\n ref=\"textInput\"\n :disabled=\"disabled\"\n :value=\"formattedDisplay\"\n class=\"bg-transparent outline-none flex-1 min-w-0\"\n type=\"text\"\n inputmode=\"numeric\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n autocapitalize=\"off\"\n :placeholder=\"dateFormat\"\n :readonly=\"readonly\"\n :aria-invalid=\"hasError\"\n :aria-label=\"fieldLabel\"\n :aria-required=\"required || undefined\"\n @mousedown=\"handleMouseDown($event)\"\n @focus=\"handleFocus()\"\n @blur=\"onBlur()\"\n @select=\"handleInputSelection($event)\"\n @click.stop=\"handleInputClick($event)\"\n @keydown=\"onKeyDown($event)\"\n @paste=\"handlePaste($event)\"\n @input=\"handleInput($event)\"\n />\n </div>\n\n <RuiButton\n v-if=\"allowEmpty && valueSet && !disabled\"\n variant=\"text\"\n icon\n data-id=\"clear-button\"\n size=\"sm\"\n color=\"error\"\n :aria-label=\"clearLabel\"\n :class=\"[\n ui.clear(),\n anyFocused && '!visible',\n { 'mr-2': !dense },\n ]\"\n @click.stop.prevent=\"clear()\"\n >\n <RuiIcon\n name=\"lu-x\"\n size=\"18\"\n />\n </RuiButton>\n\n <!-- Out of the tab sequence, following the combobox pattern: the button only duplicates\n Alt+ArrowDown on the field, so leaving it in cost two stops to cross one date field\n and four to cross a from/to pair, for nothing a keyboard user could not already do.\n It stays a real button, so it keeps its label and its expanded state for anyone\n reaching it by any other means. -->\n <button\n v-if=\"!disabled && !readonly\"\n type=\"button\"\n tabindex=\"-1\"\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n :aria-label=\"toggleLabel\"\n :aria-expanded=\"isOpen\"\n aria-haspopup=\"dialog\"\n @click=\"arrowClicked($event)\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </button>\n <span\n v-else\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </span>\n </div>\n <fieldset\n v-if=\"isOutlined\"\n :class=\"ui.fieldset()\"\n >\n <legend :class=\"ui.legend()\">\n {{ legendText }}\n </legend>\n </fieldset>\n </template>\n <template #default>\n <RuiDateTimePickerMenu\n ref=\"menuWrapperRef\"\n v-model:selected-date=\"selectedDate\"\n v-model:selected-time=\"selectedTime\"\n v-model:selected-hour=\"modelHour\"\n v-model:selected-minute=\"modelMinute\"\n v-model:selected-second=\"modelSecond\"\n v-model:selected-millisecond=\"modelMillisecond\"\n v-model:time-selection=\"timeSelection\"\n v-model:selected-timezone=\"modelTimezone\"\n v-model:calendar-menu-open=\"calendarMenuOpen\"\n :accuracy=\"accuracy\"\n :max-date=\"maxAllowedDate\"\n :min-date=\"minAllowedDate\"\n :show-timezone=\"showTimezone\"\n :actions=\"menuActions\"\n @keydown.escape=\"closeFromMenu()\"\n @set-now=\"setNow()\"\n @set-today=\"setToday()\"\n @clear=\"clear()\"\n >\n <slot name=\"menu-content\" />\n </RuiDateTimePickerMenu>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../src/components/date-time-picker/RuiDateTimePicker.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type { ComponentPublicInstance } from 'vue';\nimport type { DateTimePickerAction, DateTimeSegmentType } from '@/components/date-time-picker/types';\nimport type { TimePickerSelection } from '@/components/time-picker/RuiTimePicker.vue';\nimport RuiButton from '@/components/buttons/button/RuiButton.vue';\nimport { dateTimePickerStyles, type DateTimePickerVariant } from '@/components/date-time-picker/date-time-picker-styles';\nimport RuiDateTimePickerMenu from '@/components/date-time-picker/RuiDateTimePickerMenu.vue';\nimport { useDateTimeSelection } from '@/components/date-time-picker/use-date-time-selection';\nimport { useInputHandler } from '@/components/date-time-picker/use-input-handler';\nimport { useKeyboardHandler } from '@/components/date-time-picker/use-keyboard-handler';\nimport RuiIcon from '@/components/icons/RuiIcon.vue';\nimport RuiMenu from '@/components/overlays/menu/RuiMenu.vue';\nimport { type FloatingOptions, Placement } from '@/composables/floating';\nimport { useRuiI8n } from '@/composables/use-rui-i18n';\nimport { RUI_I18N_KEYS } from '@/i18n/keys';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs } from '@/utils/helpers';\nimport { cn } from '@/utils/tv';\n\ntype DateFormat = 'year-first' | 'month-first' | 'day-first';\n\ntype DateTimeModelType = 'date' | 'epoch-ms' | 'epoch';\n\ntype ModelValueType<T extends DateTimeModelType> = T extends 'date'\n ? Date | undefined\n : T extends 'epoch-ms'\n ? number | undefined\n : T extends 'epoch'\n ? number | undefined\n : Date | number | undefined;\n\nexport interface RuiDateTimePickerProps {\n minDate?: Date | number;\n maxDate?: Date | number | 'now';\n format?: DateFormat;\n type?: DateTimeModelType;\n accuracy?: 'minute' | 'second' | 'millisecond';\n disabled?: boolean;\n allowEmpty?: boolean;\n readonly?: boolean;\n dense?: boolean;\n label?: string;\n variant?: DateTimePickerVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n required?: boolean;\n /**\n * Renders the timezone selector in the menu. Off by default: the value is\n * emitted as a date or an epoch, so the picked timezone does not survive a\n * round trip and most consumers work in local time.\n */\n showTimezone?: boolean;\n /**\n * Actions rendered in the menu footer. `clear` is only rendered when the\n * picker is `allowEmpty`. Pass an empty array to drop the footer entirely.\n */\n actions?: DateTimePickerAction[];\n /**\n * Focuses the field once it is mounted. The native attribute is ignored for\n * an input inserted into an already loaded document, which is the usual case\n * for a picker revealed by an editor or a dialog.\n */\n autofocus?: boolean;\n /**\n * Accepts an entry that stops short of the full format, filling the segments\n * it never reached from one end of the day: `start` gives a bare date\n * 00:00:00.000 and `end` gives it 23:59:59.999. Meant for a range, where the\n * two bounds want opposite ends. Left unset, an entry missing its time is not\n * a value and nothing is emitted.\n *\n * The fill runs when the user is done with the field - leaving it, pressing\n * enter, or closing the calendar - and is written back into the segments, so\n * what it decided on is on screen.\n *\n * Spelled out rather than written as `PartialTimeMode`: a consumer that hands\n * this whole interface to its own `defineProps` needs every member resolvable\n * by the SFC compiler, which does not follow the type into the package.\n */\n partialTime?: 'start' | 'end';\n}\n\ndefineOptions({\n name: 'RuiDateTimePicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<ModelValueType<DateTimeModelType>>({ required: true });\nconst menuOpen = defineModel<boolean>('menuOpen', { default: false });\n\nconst {\n disabled = false,\n readonly = false,\n allowEmpty = false,\n dense = false,\n type = 'epoch-ms',\n hideDetails = false,\n label,\n variant = 'default',\n hint,\n maxDate,\n minDate,\n format = 'day-first',\n accuracy = 'minute',\n errorMessages = [],\n successMessages = [],\n required = false,\n showTimezone = false,\n actions = ['now'],\n autofocus = false,\n partialTime,\n} = defineProps<RuiDateTimePickerProps>();\n\ndefineSlots<{\n 'menu-content': () => any;\n}>();\n\nconst MENU_OPTIONS: FloatingOptions = { placement: Placement.bottomStart };\n\nconst baseFormats: Record<DateFormat, string> = {\n 'day-first': 'DD/MM/YYYY HH:mm',\n 'month-first': 'MM/DD/YYYY HH:mm',\n 'year-first': 'YYYY/MM/DD HH:mm',\n};\n\nconst isOpen = ref<boolean>(false);\nconst isHovered = ref<boolean>(false);\nconst cursorPosition = ref<number>(0);\nconst currentValue = ref<number>();\n\nconst { t } = useRuiI8n();\n\nconst keys = RUI_I18N_KEYS.dateTimePicker;\n\nconst fieldLabel = computed<string>(() => label ?? t(keys.label, 'Pick a date'));\nconst clearLabel = computed<string>(() => t(keys.clearValue, 'Clear the date'));\nconst toggleLabel = computed<string>(() => (get(isOpen)\n ? t(keys.closeCalendar, 'Close the calendar')\n : t(keys.openCalendar, 'Open the calendar')));\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuWrapperRef = useTemplateRef<ComponentPublicInstance>('menuWrapperRef');\nconst calendarMenuOpen = ref<boolean>(false);\n\nconst { focused: activatorFocusedWithin } = useFocusWithin(activator);\nconst { focused: menuWrapperFocusedWithin } = useFocusWithin(menuWrapperRef);\nconst { focused: searchInputFocused } = useFocus(textInput);\n\nconst anyFocused = computed<boolean>(() => get(activatorFocusedWithin) || get(menuWrapperFocusedWithin));\n\nconst dateFormat = computed<string>(() => {\n const fmt = baseFormats[format];\n if (accuracy === 'second') {\n return fmt.replace('HH:mm', 'HH:mm:ss');\n }\n else if (accuracy === 'millisecond') {\n return fmt.replace('HH:mm', 'HH:mm:ss.SSS');\n }\n return fmt;\n});\n\nconst {\n clear: clearSelection,\n commitPartialTime,\n getDateTime,\n internalErrorMessages,\n maxAllowedDate,\n minAllowedDate,\n segmentData,\n selectedDate,\n modelDay,\n modelHour,\n modelMillisecond,\n modelMinute,\n modelMonth,\n modelSecond,\n selectedTime,\n modelTimezone,\n modelYear,\n setNow,\n setToday,\n valueSet,\n} = useDateTimeSelection({\n accuracy,\n allowEmpty,\n dateFormat,\n maxDate,\n minDate,\n modelValue,\n partialTime,\n type,\n});\n\nconst { setValue, getCurrent } = useInputHandler(segmentData, currentValue);\n\nconst {\n clear: clearSegment,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\n pasteRejected,\n selectFirstSegment,\n setSegment,\n} = useKeyboardHandler({\n accuracy,\n currentValue,\n cursorPosition,\n dateFormat,\n disabled,\n getCurrent,\n getDateTime,\n readonly,\n setValue,\n textInput,\n timezone: modelTimezone,\n});\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst isOutlined = computed<boolean>(() => variant === 'outlined');\n\n/** True once any segment holds a digit, even a partially typed date. */\nconst anySegmentSet = computed<boolean>(() => [\n modelYear,\n modelMonth,\n modelDay,\n modelHour,\n modelMinute,\n modelSecond,\n modelMillisecond,\n].some(segment => isDefined(segment)));\n\n/**\n * The field's text.\n *\n * An untouched field shows its format through the placeholder rather than\n * holding the tokens as its value, where a screen reader reads them as content\n * and select-all copies them. The tokens stay while the field is focused: that\n * is when the segment machinery highlights them, and collapsing the value\n * mid-edit would blank the field under the cursor. The guard is \"no segment\n * set\" rather than `valueSet`, so blurring a half-typed date keeps what was\n * entered on screen.\n */\nconst formattedDisplay = computed<string>(() => {\n if (!get(anySegmentSet) && !get(searchInputFocused)) {\n return '';\n }\n\n let result = get(dateFormat);\n\n const replacements = [\n { pattern: 'YYYY', value: getDisplayValue(modelYear, 4) },\n { pattern: 'MM', value: getDisplayValue(modelMonth, 2) },\n { pattern: 'DD', value: getDisplayValue(modelDay, 2) },\n { pattern: 'HH', value: getDisplayValue(modelHour, 2) },\n { pattern: 'mm', value: getDisplayValue(modelMinute, 2) },\n { pattern: 'ss', value: getDisplayValue(modelSecond, 2) },\n { pattern: 'SSS', value: getDisplayValue(modelMillisecond, 3) },\n ];\n\n for (const { pattern, value } of replacements) {\n if (value !== undefined) {\n result = result.replace(pattern, value);\n }\n }\n\n return result;\n});\n\n/**\n * An untouched field holds no value until focus expands the format tokens into\n * it. That patch overwrites the input's value, and writing a value drops any\n * selection with it, so the highlight `handleFocus` just set is gone by the\n * time the tokens are on screen and the caret ends up after them. Re-select\n * the first segment once the tokens have actually landed.\n */\nwatch(formattedDisplay, (value, previous) => {\n if (previous === '' && value !== '' && get(searchInputFocused))\n selectFirstSegment();\n}, { flush: 'post' });\n\nconst timeSelection = computed<TimePickerSelection>({\n get() {\n const type = getCurrentSegment()?.type;\n\n if (type === 'mm') {\n return 'minute';\n }\n else if (type === 'ss') {\n return 'second';\n }\n else if (type === 'SSS') {\n return 'millisecond';\n }\n return 'hour';\n },\n set(value: TimePickerSelection) {\n let segmentType: DateTimeSegmentType = 'HH';\n if (value === 'minute') {\n segmentType = 'mm';\n }\n else if (value === 'second') {\n segmentType = 'ss';\n }\n else if (value === 'millisecond') {\n segmentType = 'SSS';\n }\n\n setSegment(segmentType);\n },\n});\n\nconst float = computed<boolean>(() => (get(isOpen) || get(valueSet) || get(searchInputFocused)) && get(isOutlined));\n\nconst legendText = computed<string>(() => {\n if (!get(float))\n return '';\n const resolved = get(fieldLabel);\n return required ? `${resolved} ﹡` : resolved;\n});\n\nconst ui = computed<ReturnType<typeof dateTimePickerStyles>>(() => dateTimePickerStyles({\n filled: variant === 'filled',\n outlined: get(isOutlined),\n float: get(float),\n showLabel: !!get(legendText),\n opened: get(isOpen),\n hovered: get(isHovered),\n dense,\n disabled,\n readonly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst pasteMessage = computed<string>(() => (get(pasteRejected)\n ? t(keys.pasteUnreadable, 'Could not read a date from the pasted text')\n : ''));\n\n/**\n * The paste message goes first: the details show one message, and it answers\n * what the user just did, which a standing validation error does not.\n */\nconst combinedErrorMessages = computed<string[]>(() => {\n const paste = get(pasteMessage) ? [get(pasteMessage)] : [];\n if (!errorMessages)\n return [...paste, ...get(internalErrorMessages)];\n\n const propErrors = Array.isArray(errorMessages) ? errorMessages : [errorMessages];\n return [...paste, ...propErrors, ...get(internalErrorMessages)];\n});\n\nfunction getDisplayValue(digit: Ref<number | undefined>, padding: number): string | undefined {\n return isDefined(digit) ? get(digit).toString().padStart(padding, '0') : undefined;\n}\n\nasync function setInputFocus(): Promise<void> {\n await nextTick(() => {\n set(searchInputFocused, true);\n });\n}\n\nfunction clear(segmentType?: string): void {\n if (!segmentType) {\n clearSelection();\n set(currentValue, undefined);\n return;\n }\n\n clearSegment(segmentType);\n}\n\n/**\n * An entry left incomplete is completed once the user is done with the field,\n * never while they are still filling it in: a half typed hour is not a segment\n * they left out. Leaving the field counts, unless the calendar is open, since\n * then the focus is only moving into it and the menu closing covers that.\n */\nfunction onBlur(): void {\n handleBlur();\n if (!get(isOpen))\n commitPartialTime();\n}\n\nwatch(isOpen, (open) => {\n if (!open && !get(searchInputFocused))\n commitPartialTime();\n});\n\n/**\n * Selects the clicked segment before opening the menu, so the selection is not\n * lost to the DOM changes that opening brings.\n */\nfunction handleInputClick(event: MouseEvent): void {\n handleClick(event);\n if (!get(isOpen)) {\n set(isOpen, true);\n }\n}\n\n/**\n * The menu is teleported to the body, so it never sits next to the field in\n * the tab sequence. Opening it from the keyboard therefore moves focus into\n * the calendar; opening it with the mouse leaves focus in the field, which is\n * what `disable-auto-focus` on the menu is there for.\n */\nconst focusCalendarOnOpen = ref<boolean>(false);\n\n/**\n * Asks for focus to move into the calendar. The menu is teleported and mounts\n * a frame later, so the watcher below waits for the wrapper to appear rather\n * than guessing at a number of ticks.\n */\nfunction focusCalendar(): void {\n set(focusCalendarOnOpen, true);\n}\n\nwatch(menuWrapperRef, (menu) => {\n if (!menu || !get(focusCalendarOnOpen))\n return;\n\n set(focusCalendarOnOpen, false);\n nextTick(() => {\n const el = menu.$el as HTMLElement | undefined;\n el?.querySelector<HTMLButtonElement>('[role=\"gridcell\"][tabindex=\"0\"]')?.focus({ preventScroll: true });\n });\n});\n\n/** Moves focus to the field. Exposed so a consumer can drive it from a ref. */\nfunction focus(): void {\n get(textInput)?.focus({ preventScroll: true });\n}\n\nfunction focusField(): void {\n nextTick(focus);\n}\n\nonMounted(() => {\n if (autofocus && !disabled)\n focusField();\n});\n\n/** Escape inside the calendar closes it and hands focus back to the field. */\nfunction closeFromMenu(): void {\n set(isOpen, false);\n focusField();\n}\n\n/**\n * The menu used to be mouse-only: the activator carried no key handlers, so\n * there was no way to reach the calendar from the keyboard. Alt+ArrowDown\n * opens it and Escape closes it, following the combobox convention, and the\n * append chevron is a real button for anyone who tabs to it instead.\n *\n * Enter and Escape are the other ways to be done with the field, and the keys\n * a consumer tends to close its editor on. Escape reaches that point only once\n * the calendar is already shut, and discards nothing, since the segments stay\n * on screen either way, so it commits what was entered rather than dropping it\n * when the field goes. Both write the value before the key carries on\n * bubbling, so it survives that close.\n */\nfunction onKeyDown(event: KeyboardEvent): void {\n if (disabled || readonly)\n return;\n\n if (event.altKey && event.key === 'ArrowDown') {\n event.preventDefault();\n set(isOpen, true);\n focusCalendar();\n return;\n }\n\n if (event.key === 'Escape' && get(isOpen)) {\n set(isOpen, false);\n return;\n }\n\n if (event.key === 'Enter' || event.key === 'Escape')\n commitPartialTime();\n\n handleKeyDown(event);\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n\nconst menuActions = computed<DateTimePickerAction[]>(\n () => actions.filter(action => action !== 'clear' || allowEmpty),\n);\n\nconst anyMenuOpen = computed<boolean>(() => get(isOpen) || get(calendarMenuOpen));\n\nwatch(anyMenuOpen, (value) => {\n set(menuOpen, value);\n});\n\ndefineExpose({\n focus,\n});\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"getRootAttrs($attrs, [])\"\n :class=\"ui.wrapper({ class: cn($attrs.class) })\"\n :options=\"MENU_OPTIONS\"\n :dense=\"dense\"\n :hint=\"hint\"\n :disabled=\"disabled\"\n :success-messages=\"successMessages\"\n :error-messages=\"combinedErrorMessages\"\n :close-on-content-click=\"false\"\n :show-details=\"!hideDetails\"\n :persistent=\"calendarMenuOpen\"\n full-width\n disable-auto-focus\n >\n <template #activator=\"{ attrs, open }\">\n <div\n ref=\"activator\"\n :class=\"ui.activator()\"\n v-bind=\"{\n ...getNonRootAttrs($attrs, ['onClick', 'class']),\n ...(readonly ? {} : attrs),\n }\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n @mouseenter=\"isHovered = true\"\n @mouseleave=\"isHovered = false\"\n @click=\"setInputFocus()\"\n >\n <span\n v-if=\"isOutlined && (searchInputFocused || open || valueSet)\"\n data-id=\"label\"\n :class=\"[\n ui.label(),\n { 'pr-2': !valueSet && !open && isOutlined },\n ]\"\n >\n {{ fieldLabel }}\n <span\n v-if=\"required\"\n data-id=\"required-indicator\"\n :class=\"ui.required()\"\n >\n ﹡\n </span>\n </span>\n\n <span :class=\"ui.iconPrepend()\">\n <RuiIcon\n class=\"text-rui-text-secondary transition\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-calendar-days\"\n />\n </span>\n\n <div :class=\"ui.value()\">\n <input\n ref=\"textInput\"\n :disabled=\"disabled\"\n :value=\"formattedDisplay\"\n class=\"bg-transparent outline-none flex-1 min-w-0\"\n type=\"text\"\n inputmode=\"numeric\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n autocapitalize=\"off\"\n :placeholder=\"dateFormat\"\n :readonly=\"readonly\"\n :aria-invalid=\"hasError\"\n :aria-label=\"fieldLabel\"\n :aria-required=\"required || undefined\"\n @mousedown=\"handleMouseDown($event)\"\n @focus=\"handleFocus()\"\n @blur=\"onBlur()\"\n @select=\"handleInputSelection($event)\"\n @click.stop=\"handleInputClick($event)\"\n @keydown=\"onKeyDown($event)\"\n @paste=\"handlePaste($event)\"\n @input=\"handleInput($event)\"\n />\n <!-- The details line is not a live region, so a rejected paste is announced from here -->\n <span\n class=\"sr-only\"\n aria-live=\"polite\"\n data-id=\"paste-status\"\n >\n {{ pasteMessage }}\n </span>\n </div>\n\n <RuiButton\n v-if=\"allowEmpty && valueSet && !disabled\"\n variant=\"text\"\n icon\n data-id=\"clear-button\"\n size=\"sm\"\n color=\"error\"\n :aria-label=\"clearLabel\"\n :class=\"[\n ui.clear(),\n anyFocused && '!visible',\n { 'mr-2': !dense },\n ]\"\n @click.stop.prevent=\"clear()\"\n >\n <RuiIcon\n name=\"lu-x\"\n size=\"18\"\n />\n </RuiButton>\n\n <!-- Out of the tab sequence, following the combobox pattern: the button only duplicates\n Alt+ArrowDown on the field, so leaving it in cost two stops to cross one date field\n and four to cross a from/to pair, for nothing a keyboard user could not already do.\n It stays a real button, so it keeps its label and its expanded state for anyone\n reaching it by any other means. -->\n <button\n v-if=\"!disabled && !readonly\"\n type=\"button\"\n tabindex=\"-1\"\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n :aria-label=\"toggleLabel\"\n :aria-expanded=\"isOpen\"\n aria-haspopup=\"dialog\"\n @click=\"arrowClicked($event)\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </button>\n <span\n v-else\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </span>\n </div>\n <fieldset\n v-if=\"isOutlined\"\n :class=\"ui.fieldset()\"\n >\n <legend :class=\"ui.legend()\">\n {{ legendText }}\n </legend>\n </fieldset>\n </template>\n <template #default>\n <RuiDateTimePickerMenu\n ref=\"menuWrapperRef\"\n v-model:selected-date=\"selectedDate\"\n v-model:selected-time=\"selectedTime\"\n v-model:selected-hour=\"modelHour\"\n v-model:selected-minute=\"modelMinute\"\n v-model:selected-second=\"modelSecond\"\n v-model:selected-millisecond=\"modelMillisecond\"\n v-model:time-selection=\"timeSelection\"\n v-model:selected-timezone=\"modelTimezone\"\n v-model:calendar-menu-open=\"calendarMenuOpen\"\n :accuracy=\"accuracy\"\n :max-date=\"maxAllowedDate\"\n :min-date=\"minAllowedDate\"\n :show-timezone=\"showTimezone\"\n :actions=\"menuActions\"\n @keydown.escape=\"closeFromMenu()\"\n @set-now=\"setNow()\"\n @set-today=\"setToday()\"\n @clear=\"clear()\"\n >\n <slot name=\"menu-content\" />\n </RuiDateTimePickerMenu>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":"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"}
@@ -66,6 +66,9 @@ export declare const dateTimePickerStyles: import("tailwind-variants").TVReturnT
66
66
  hovered: {
67
67
  true: {};
68
68
  };
69
+ showLabel: {
70
+ true: {};
71
+ };
69
72
  } & {
70
73
  focused: {
71
74
  true: {
@@ -180,6 +183,9 @@ export declare const dateTimePickerStyles: import("tailwind-variants").TVReturnT
180
183
  hovered: {
181
184
  true: {};
182
185
  };
186
+ showLabel: {
187
+ true: {};
188
+ };
183
189
  }, {
184
190
  fieldset: string;
185
191
  legend: string;
@@ -30,4 +30,19 @@ export declare function resolveBound(bound: Date | number | undefined, epochSeco
30
30
  */
31
31
  export declare function clampToBounds(date: Dayjs, min: Date, max?: Date): Dayjs;
32
32
  export declare function getClickPosition(event: MouseEvent, input: HTMLInputElement, useCaretPosition: boolean): number;
33
- export declare function parseAndSetDateValues(pastedText: string, dateFormat: string, accuracy: TimeAccuracy, setValue: (segment: DateTimeSegmentType, value?: number) => void): void;
33
+ /**
34
+ * Reads a pasted date into the wall-clock time of the field's timezone.
35
+ *
36
+ * Accepts the field's own format and ISO dates, either cut short at any
37
+ * segment, as well as unix timestamps in seconds or milliseconds. A trailing
38
+ * `Z`, numeric offset, `UTC` or `GMT` makes the text an instant that is moved
39
+ * into the timezone. Any other zone name, such as `CEST`, cannot be resolved
40
+ * reliably and is dropped, reading the rest as wall-clock time.
41
+ *
42
+ * @param pastedText - the text from the clipboard
43
+ * @param dateFormat - the field's format
44
+ * @param timezone - the field's timezone, the local one when undefined
45
+ * @returns the date, or undefined when the text is not one
46
+ */
47
+ export declare function parsePastedDate(pastedText: string, dateFormat: string, timezone?: string): Dayjs | undefined;
48
+ export declare function parseAndSetDateValues(pastedText: string, dateFormat: string, accuracy: TimeAccuracy, setValue: (segment: DateTimeSegmentType, value?: number) => void, timezone?: string): boolean;
@@ -62,21 +62,78 @@ function getClickPosition(event, input, useCaretPosition) {
62
62
  if (caretPos) return caretPos.offset;
63
63
  return document.caretRangeFromPoint?.(event.clientX, event.clientY)?.startOffset ?? fallback;
64
64
  }
65
- function parseAndSetDateValues(pastedText, dateFormat, accuracy, setValue) {
66
- try {
67
- const parsedDate = dayjs(pastedText, dateFormat);
68
- if (!parsedDate.isValid()) return;
69
- const date = parsedDate.toDate();
70
- setValue("YYYY", date.getFullYear());
71
- setValue("MM", date.getMonth() + 1);
72
- setValue("DD", date.getDate());
73
- setValue("HH", date.getHours());
74
- setValue("mm", date.getMinutes());
75
- if (includeSeconds(accuracy)) setValue("ss", date.getSeconds());
76
- if (includeMilliseconds(accuracy)) setValue("SSS", date.getMilliseconds());
77
- } catch {}
65
+ var UNIX_SECONDS = /^\d{9,10}$/;
66
+ var UNIX_MILLISECONDS = /^\d{12,13}$/;
67
+ var UTC_OFFSET = /(?:Z|[+-]\d{2}:?\d{2})$/i;
68
+ var UTC_NAME = /\s+(?:UTC|GMT)$/i;
69
+ var ZONE_NAME = /\s+[A-Z]{2,5}$/i;
70
+ var ISO_FORMATS = ["YYYY-MM-DD[T]HH:mm:ss.SSS", "YYYY-MM-DD HH:mm:ss.SSS"];
71
+ /**
72
+ * Lists a format followed by its shorter forms, dropping the millisecond, the
73
+ * second and then the whole time, so a paste may stop short of the field's
74
+ * accuracy.
75
+ *
76
+ * @param format - the full format
77
+ * @returns the format and every shorter form of it
78
+ */
79
+ function withTruncations(format) {
80
+ const truncations = [format];
81
+ for (const suffix of [
82
+ ".SSS",
83
+ ":ss",
84
+ /[\sT[\]]+HH:mm$/
85
+ ]) {
86
+ const last = truncations.at(-1);
87
+ const shorter = last.replace(suffix, "");
88
+ if (shorter !== last) truncations.push(shorter);
89
+ }
90
+ return truncations;
91
+ }
92
+ /**
93
+ * Reads a pasted date into the wall-clock time of the field's timezone.
94
+ *
95
+ * Accepts the field's own format and ISO dates, either cut short at any
96
+ * segment, as well as unix timestamps in seconds or milliseconds. A trailing
97
+ * `Z`, numeric offset, `UTC` or `GMT` makes the text an instant that is moved
98
+ * into the timezone. Any other zone name, such as `CEST`, cannot be resolved
99
+ * reliably and is dropped, reading the rest as wall-clock time.
100
+ *
101
+ * @param pastedText - the text from the clipboard
102
+ * @param dateFormat - the field's format
103
+ * @param timezone - the field's timezone, the local one when undefined
104
+ * @returns the date, or undefined when the text is not one
105
+ */
106
+ function parsePastedDate(pastedText, dateFormat, timezone) {
107
+ const text = pastedText.trim();
108
+ if (UNIX_SECONDS.test(text)) return dayjs.unix(Number(text)).tz(timezone);
109
+ if (UNIX_MILLISECONDS.test(text)) return dayjs(Number(text)).tz(timezone);
110
+ if (UTC_OFFSET.test(text)) {
111
+ const instant = dayjs(text.replace(" ", "T"));
112
+ return instant.isValid() ? instant.tz(timezone) : void 0;
113
+ }
114
+ const formats = [dateFormat, ...ISO_FORMATS].flatMap((format) => withTruncations(format));
115
+ if (UTC_NAME.test(text)) return parseWallClock(text.replace(UTC_NAME, ""), formats, true)?.tz(timezone);
116
+ return parseWallClock(text.replace(ZONE_NAME, ""), formats, false);
117
+ }
118
+ function parseWallClock(text, formats, utc) {
119
+ for (const format of formats) {
120
+ const date = utc ? dayjs.utc(text, format, true) : dayjs(text, format, true);
121
+ if (date.isValid()) return date;
122
+ }
123
+ }
124
+ function parseAndSetDateValues(pastedText, dateFormat, accuracy, setValue, timezone) {
125
+ const date = parsePastedDate(pastedText, dateFormat, timezone);
126
+ if (!date) return false;
127
+ setValue("YYYY", date.year());
128
+ setValue("MM", date.month() + 1);
129
+ setValue("DD", date.date());
130
+ setValue("HH", date.hour());
131
+ setValue("mm", date.minute());
132
+ if (includeSeconds(accuracy)) setValue("ss", date.second());
133
+ if (includeMilliseconds(accuracy)) setValue("SSS", date.millisecond());
134
+ return true;
78
135
  }
79
136
  //#endregion
80
- export { buildDateTime, clampToBounds, getClickPosition, parseAndSetDateValues, resolveBound };
137
+ export { buildDateTime, clampToBounds, getClickPosition, parseAndSetDateValues, parsePastedDate, resolveBound };
81
138
 
82
139
  //# sourceMappingURL=segment-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"segment-utils.js","names":[],"sources":["../../../src/components/date-time-picker/segment-utils.ts"],"sourcesContent":["import type { DateTimeSegmentType } from '@/components/date-time-picker/types';\nimport type { TimeAccuracy } from '@/consts/time-accuracy';\nimport dayjs, { type Dayjs } from 'dayjs';\nimport { includeMilliseconds, includeSeconds } from '@/components/date-time-picker/utils';\n\nimport '@/components/date-time-picker/dayjs-setup';\n\nexport interface SegmentValues {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\n/**\n * Applies the entered date segments, keeping the day inside the month the year\n * and month land on.\n *\n * @param base - the date to apply them to\n * @param segments - the segments entered so far\n * @returns the date with its year, month and day set\n */\nfunction applyDateSegments(base: Dayjs, { day, month, year }: SegmentValues): Dayjs {\n let dateTime = base;\n\n if (year !== undefined)\n dateTime = dateTime.year(year);\n\n if (month !== undefined)\n dateTime = dateTime.month(month - 1);\n\n if (day !== undefined)\n dateTime = dateTime.date(Math.min(day, dateTime.daysInMonth()));\n\n return dateTime;\n}\n\n/**\n * Builds a date from the segments that have been entered so far. Segments the\n * accuracy does not expose are zeroed rather than inherited from the clock the\n * base date started at, so a value cannot pick up a stray second.\n */\nexport function buildDateTime(segments: SegmentValues, accuracy: TimeAccuracy, base: Dayjs = dayjs()): Dayjs {\n const { hour, millisecond, minute, second } = segments;\n let dateTime = applyDateSegments(base, segments);\n\n if (hour !== undefined)\n dateTime = dateTime.hour(hour);\n\n if (minute !== undefined)\n dateTime = dateTime.minute(minute);\n\n if (second !== undefined)\n dateTime = dateTime.second(second);\n else if (!includeSeconds(accuracy))\n dateTime = dateTime.second(0);\n\n if (millisecond !== undefined)\n dateTime = dateTime.millisecond(millisecond);\n else if (!includeMilliseconds(accuracy))\n dateTime = dateTime.millisecond(0);\n\n return dateTime;\n}\n\nconst MILLISECONDS = 1000;\n\n/**\n * Turns a `minDate` / `maxDate` prop into a Date. An `epoch` picker states its\n * bounds in whole seconds, so those are widened to milliseconds first.\n */\nexport function resolveBound(bound: Date | number | undefined, epochSeconds: boolean): Date | undefined {\n if (bound === undefined) {\n return undefined;\n }\n\n if (epochSeconds && typeof bound === 'number') {\n return new Date(bound * MILLISECONDS);\n }\n\n return new Date(bound);\n}\n\n/**\n * Pulls a date inside the allowed range. Used by the `now` and `today` actions,\n * which have no partial state: typed input is left to diverge and explain\n * itself through the error message instead, since clamping a keystroke would\n * rewrite a year the moment its first digit landed below the minimum.\n */\nexport function clampToBounds(date: Dayjs, min: Date, max?: Date): Dayjs {\n const lower = dayjs(min);\n if (date.isBefore(lower)) {\n return lower;\n }\n\n if (max && date.isAfter(max)) {\n return dayjs(max);\n }\n\n return date;\n}\n\nexport function getClickPosition(\n event: MouseEvent,\n input: HTMLInputElement,\n useCaretPosition: boolean,\n): number {\n const fallback = input.selectionStart ?? 0;\n if (!useCaretPosition)\n return fallback;\n const caretPos = document.caretPositionFromPoint?.(event.clientX, event.clientY);\n if (caretPos)\n return caretPos.offset;\n return document.caretRangeFromPoint?.(event.clientX, event.clientY)?.startOffset ?? fallback;\n}\n\nexport function parseAndSetDateValues(\n pastedText: string,\n dateFormat: string,\n accuracy: TimeAccuracy,\n setValue: (segment: DateTimeSegmentType, value?: number) => void,\n): void {\n try {\n const parsedDate = dayjs(pastedText, dateFormat);\n\n if (!parsedDate.isValid()) {\n return;\n }\n\n const date = parsedDate.toDate();\n setValue('YYYY', date.getFullYear());\n setValue('MM', date.getMonth() + 1);\n setValue('DD', date.getDate());\n setValue('HH', date.getHours());\n setValue('mm', date.getMinutes());\n if (includeSeconds(accuracy)) {\n setValue('ss', date.getSeconds());\n }\n if (includeMilliseconds(accuracy)) {\n setValue('SSS', date.getMilliseconds());\n }\n }\n catch {\n // Invalid format, ignore paste\n }\n}\n"],"mappings":";;;;;;;;;;;;AAyBA,SAAS,kBAAkB,MAAa,EAAE,KAAK,OAAO,QAA8B;CAClF,IAAI,WAAW;CAEf,IAAI,SAAS,KAAA,GACX,WAAW,SAAS,KAAK,IAAI;CAE/B,IAAI,UAAU,KAAA,GACZ,WAAW,SAAS,MAAM,QAAQ,CAAC;CAErC,IAAI,QAAQ,KAAA,GACV,WAAW,SAAS,KAAK,KAAK,IAAI,KAAK,SAAS,YAAY,CAAC,CAAC;CAEhE,OAAO;AACT;;;;;;AAOA,SAAgB,cAAc,UAAyB,UAAwB,OAAc,MAAM,GAAU;CAC3G,MAAM,EAAE,MAAM,aAAa,QAAQ,WAAW;CAC9C,IAAI,WAAW,kBAAkB,MAAM,QAAQ;CAE/C,IAAI,SAAS,KAAA,GACX,WAAW,SAAS,KAAK,IAAI;CAE/B,IAAI,WAAW,KAAA,GACb,WAAW,SAAS,OAAO,MAAM;CAEnC,IAAI,WAAW,KAAA,GACb,WAAW,SAAS,OAAO,MAAM;MAC9B,IAAI,CAAC,eAAe,QAAQ,GAC/B,WAAW,SAAS,OAAO,CAAC;CAE9B,IAAI,gBAAgB,KAAA,GAClB,WAAW,SAAS,YAAY,WAAW;MACxC,IAAI,CAAC,oBAAoB,QAAQ,GACpC,WAAW,SAAS,YAAY,CAAC;CAEnC,OAAO;AACT;AAEA,IAAM,eAAe;;;;;AAMrB,SAAgB,aAAa,OAAkC,cAAyC;CACtG,IAAI,UAAU,KAAA,GACZ;CAGF,IAAI,gBAAgB,OAAO,UAAU,UACnC,uBAAO,IAAI,KAAK,QAAQ,YAAY;CAGtC,OAAO,IAAI,KAAK,KAAK;AACvB;;;;;;;AAQA,SAAgB,cAAc,MAAa,KAAW,KAAmB;CACvE,MAAM,QAAQ,MAAM,GAAG;CACvB,IAAI,KAAK,SAAS,KAAK,GACrB,OAAO;CAGT,IAAI,OAAO,KAAK,QAAQ,GAAG,GACzB,OAAO,MAAM,GAAG;CAGlB,OAAO;AACT;AAEA,SAAgB,iBACd,OACA,OACA,kBACQ;CACR,MAAM,WAAW,MAAM,kBAAkB;CACzC,IAAI,CAAC,kBACH,OAAO;CACT,MAAM,WAAW,SAAS,yBAAyB,MAAM,SAAS,MAAM,OAAO;CAC/E,IAAI,UACF,OAAO,SAAS;CAClB,OAAO,SAAS,sBAAsB,MAAM,SAAS,MAAM,OAAO,CAAC,EAAE,eAAe;AACtF;AAEA,SAAgB,sBACd,YACA,YACA,UACA,UACM;CACN,IAAI;EACF,MAAM,aAAa,MAAM,YAAY,UAAU;EAE/C,IAAI,CAAC,WAAW,QAAQ,GACtB;EAGF,MAAM,OAAO,WAAW,OAAO;EAC/B,SAAS,QAAQ,KAAK,YAAY,CAAC;EACnC,SAAS,MAAM,KAAK,SAAS,IAAI,CAAC;EAClC,SAAS,MAAM,KAAK,QAAQ,CAAC;EAC7B,SAAS,MAAM,KAAK,SAAS,CAAC;EAC9B,SAAS,MAAM,KAAK,WAAW,CAAC;EAChC,IAAI,eAAe,QAAQ,GACzB,SAAS,MAAM,KAAK,WAAW,CAAC;EAElC,IAAI,oBAAoB,QAAQ,GAC9B,SAAS,OAAO,KAAK,gBAAgB,CAAC;CAE1C,QACM,CAEN;AACF"}
1
+ {"version":3,"file":"segment-utils.js","names":[],"sources":["../../../src/components/date-time-picker/segment-utils.ts"],"sourcesContent":["import type { DateTimeSegmentType } from '@/components/date-time-picker/types';\nimport type { TimeAccuracy } from '@/consts/time-accuracy';\nimport dayjs, { type Dayjs } from 'dayjs';\nimport { includeMilliseconds, includeSeconds } from '@/components/date-time-picker/utils';\n\nimport '@/components/date-time-picker/dayjs-setup';\n\nexport interface SegmentValues {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\n/**\n * Applies the entered date segments, keeping the day inside the month the year\n * and month land on.\n *\n * @param base - the date to apply them to\n * @param segments - the segments entered so far\n * @returns the date with its year, month and day set\n */\nfunction applyDateSegments(base: Dayjs, { day, month, year }: SegmentValues): Dayjs {\n let dateTime = base;\n\n if (year !== undefined)\n dateTime = dateTime.year(year);\n\n if (month !== undefined)\n dateTime = dateTime.month(month - 1);\n\n if (day !== undefined)\n dateTime = dateTime.date(Math.min(day, dateTime.daysInMonth()));\n\n return dateTime;\n}\n\n/**\n * Builds a date from the segments that have been entered so far. Segments the\n * accuracy does not expose are zeroed rather than inherited from the clock the\n * base date started at, so a value cannot pick up a stray second.\n */\nexport function buildDateTime(segments: SegmentValues, accuracy: TimeAccuracy, base: Dayjs = dayjs()): Dayjs {\n const { hour, millisecond, minute, second } = segments;\n let dateTime = applyDateSegments(base, segments);\n\n if (hour !== undefined)\n dateTime = dateTime.hour(hour);\n\n if (minute !== undefined)\n dateTime = dateTime.minute(minute);\n\n if (second !== undefined)\n dateTime = dateTime.second(second);\n else if (!includeSeconds(accuracy))\n dateTime = dateTime.second(0);\n\n if (millisecond !== undefined)\n dateTime = dateTime.millisecond(millisecond);\n else if (!includeMilliseconds(accuracy))\n dateTime = dateTime.millisecond(0);\n\n return dateTime;\n}\n\nconst MILLISECONDS = 1000;\n\n/**\n * Turns a `minDate` / `maxDate` prop into a Date. An `epoch` picker states its\n * bounds in whole seconds, so those are widened to milliseconds first.\n */\nexport function resolveBound(bound: Date | number | undefined, epochSeconds: boolean): Date | undefined {\n if (bound === undefined) {\n return undefined;\n }\n\n if (epochSeconds && typeof bound === 'number') {\n return new Date(bound * MILLISECONDS);\n }\n\n return new Date(bound);\n}\n\n/**\n * Pulls a date inside the allowed range. Used by the `now` and `today` actions,\n * which have no partial state: typed input is left to diverge and explain\n * itself through the error message instead, since clamping a keystroke would\n * rewrite a year the moment its first digit landed below the minimum.\n */\nexport function clampToBounds(date: Dayjs, min: Date, max?: Date): Dayjs {\n const lower = dayjs(min);\n if (date.isBefore(lower)) {\n return lower;\n }\n\n if (max && date.isAfter(max)) {\n return dayjs(max);\n }\n\n return date;\n}\n\nexport function getClickPosition(\n event: MouseEvent,\n input: HTMLInputElement,\n useCaretPosition: boolean,\n): number {\n const fallback = input.selectionStart ?? 0;\n if (!useCaretPosition)\n return fallback;\n const caretPos = document.caretPositionFromPoint?.(event.clientX, event.clientY);\n if (caretPos)\n return caretPos.offset;\n return document.caretRangeFromPoint?.(event.clientX, event.clientY)?.startOffset ?? fallback;\n}\n\nconst UNIX_SECONDS = /^\\d{9,10}$/;\nconst UNIX_MILLISECONDS = /^\\d{12,13}$/;\nconst UTC_OFFSET = /(?:Z|[+-]\\d{2}:?\\d{2})$/i;\nconst UTC_NAME = /\\s+(?:UTC|GMT)$/i;\nconst ZONE_NAME = /\\s+[A-Z]{2,5}$/i;\nconst ISO_FORMATS = ['YYYY-MM-DD[T]HH:mm:ss.SSS', 'YYYY-MM-DD HH:mm:ss.SSS'];\n\n/**\n * Lists a format followed by its shorter forms, dropping the millisecond, the\n * second and then the whole time, so a paste may stop short of the field's\n * accuracy.\n *\n * @param format - the full format\n * @returns the format and every shorter form of it\n */\nfunction withTruncations(format: string): string[] {\n const truncations = [format];\n for (const suffix of ['.SSS', ':ss', /[\\sT[\\]]+HH:mm$/]) {\n const last = truncations.at(-1)!;\n const shorter = last.replace(suffix, '');\n if (shorter !== last)\n truncations.push(shorter);\n }\n return truncations;\n}\n\n/**\n * Reads a pasted date into the wall-clock time of the field's timezone.\n *\n * Accepts the field's own format and ISO dates, either cut short at any\n * segment, as well as unix timestamps in seconds or milliseconds. A trailing\n * `Z`, numeric offset, `UTC` or `GMT` makes the text an instant that is moved\n * into the timezone. Any other zone name, such as `CEST`, cannot be resolved\n * reliably and is dropped, reading the rest as wall-clock time.\n *\n * @param pastedText - the text from the clipboard\n * @param dateFormat - the field's format\n * @param timezone - the field's timezone, the local one when undefined\n * @returns the date, or undefined when the text is not one\n */\nexport function parsePastedDate(pastedText: string, dateFormat: string, timezone?: string): Dayjs | undefined {\n const text = pastedText.trim();\n\n if (UNIX_SECONDS.test(text))\n return dayjs.unix(Number(text)).tz(timezone);\n if (UNIX_MILLISECONDS.test(text))\n return dayjs(Number(text)).tz(timezone);\n\n if (UTC_OFFSET.test(text)) {\n const instant = dayjs(text.replace(' ', 'T'));\n return instant.isValid() ? instant.tz(timezone) : undefined;\n }\n\n const formats = [dateFormat, ...ISO_FORMATS].flatMap(format => withTruncations(format));\n if (UTC_NAME.test(text))\n return parseWallClock(text.replace(UTC_NAME, ''), formats, true)?.tz(timezone);\n return parseWallClock(text.replace(ZONE_NAME, ''), formats, false);\n}\n\nfunction parseWallClock(text: string, formats: string[], utc: boolean): Dayjs | undefined {\n for (const format of formats) {\n const date = utc ? dayjs.utc(text, format, true) : dayjs(text, format, true);\n if (date.isValid())\n return date;\n }\n return undefined;\n}\n\nexport function parseAndSetDateValues(\n pastedText: string,\n dateFormat: string,\n accuracy: TimeAccuracy,\n setValue: (segment: DateTimeSegmentType, value?: number) => void,\n timezone?: string,\n): boolean {\n const date = parsePastedDate(pastedText, dateFormat, timezone);\n if (!date)\n return false;\n\n setValue('YYYY', date.year());\n setValue('MM', date.month() + 1);\n setValue('DD', date.date());\n setValue('HH', date.hour());\n setValue('mm', date.minute());\n if (includeSeconds(accuracy))\n setValue('ss', date.second());\n if (includeMilliseconds(accuracy))\n setValue('SSS', date.millisecond());\n return true;\n}\n"],"mappings":"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"}
@@ -14,6 +14,7 @@ interface KeyboardHandlerOptions {
14
14
  disabled: boolean;
15
15
  readonly: boolean;
16
16
  accuracy: TimeAccuracy;
17
+ timezone: Readonly<Ref<string | undefined>>;
17
18
  }
18
19
  export declare function useKeyboardHandler(options: KeyboardHandlerOptions): {
19
20
  clear: (segmentType?: string) => void;
@@ -26,6 +27,7 @@ export declare function useKeyboardHandler(options: KeyboardHandlerOptions): {
26
27
  handleKeyDown: (event: KeyboardEvent) => void;
27
28
  handleMouseDown: (event: MouseEvent) => void;
28
29
  handlePaste: (event: ClipboardEvent) => void;
30
+ pasteRejected: Readonly<ShallowRef<boolean>>;
29
31
  selectFirstSegment: () => void;
30
32
  setSegment: (segmentType: DateTimeSegmentType) => void;
31
33
  };