@rotki/ui-library 2.16.1 → 2.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/components/accordions/accordion/RuiAccordion.js.map +1 -1
  2. package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js +7 -2
  3. package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
  4. package/dist/components/buttons/button/RuiButton.js.map +1 -1
  5. package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js +6 -2
  6. package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/components/buttons/button/button-styles.d.ts +6 -9
  8. package/dist/components/buttons/button/button-styles.js +42 -20
  9. package/dist/components/buttons/button/button-styles.js.map +1 -1
  10. package/dist/components/cards/RuiCard.js.map +1 -1
  11. package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js +4 -1
  12. package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  13. package/dist/components/color-picker/RuiColorBoard.js.map +1 -1
  14. package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js +7 -2
  15. package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  16. package/dist/components/color-picker/RuiColorHue.js.map +1 -1
  17. package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js +7 -2
  18. package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/color-picker/RuiColorPicker.js.map +1 -1
  20. package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js +7 -2
  21. package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  22. package/dist/components/date-time-picker/RuiDateTimePicker.js.map +1 -1
  23. package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js +3 -2
  24. package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  25. package/dist/components/forms/auto-complete/RuiAutoComplete.js.map +1 -1
  26. package/dist/components/forms/auto-complete/RuiAutoComplete.vue.d.ts +1 -1
  27. package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js +6 -3
  28. package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
  29. package/dist/components/forms/select/RuiMenuSelect.js.map +1 -1
  30. package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js +2 -2
  31. package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  32. package/dist/components/forms/text-area/text-area-styles.js +2 -2
  33. package/dist/components/forms/text-area/text-area-styles.js.map +1 -1
  34. package/dist/components/forms/text-field/text-field-styles.js +3 -3
  35. package/dist/components/forms/text-field/text-field-styles.js.map +1 -1
  36. package/dist/components/forms/text-input-styles.js +2 -2
  37. package/dist/components/forms/text-input-styles.js.map +1 -1
  38. package/dist/components/loaders/RuiSkeletonLoader.js.map +1 -1
  39. package/dist/components/loaders/RuiSkeletonLoader.vue_vue_type_script_setup_true_lang.js +15 -5
  40. package/dist/components/loaders/RuiSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/components/overlays/badge/RuiBadge.js.map +1 -1
  42. package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js +2 -2
  43. package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
  44. package/dist/components/overlays/menu/RuiMenu.js.map +1 -1
  45. package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js +6 -10
  46. package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  47. package/dist/components/overlays/notification/RuiNotification.js.map +1 -1
  48. package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js +8 -3
  49. package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js.map +1 -1
  50. package/dist/components/overlays/tooltip/RuiTooltip.js.map +1 -1
  51. package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js +13 -6
  52. package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  53. package/dist/components/tables/RuiDataTable.js.map +1 -1
  54. package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js +2 -6
  55. package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  56. package/dist/components/tables/RuiTableHead.js.map +1 -1
  57. package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js +1 -1
  58. package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js.map +1 -1
  59. package/dist/components/tabs/tab/RuiTab.js.map +1 -1
  60. package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js +1 -1
  61. package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
  62. package/dist/components/tabs/tab-items/RuiTabItems.js.map +1 -1
  63. package/dist/components/tabs/tab-items/RuiTabItems.vue.d.ts +2 -2
  64. package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js +1 -1
  65. package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js.map +1 -1
  66. package/dist/components/tabs/tabs/RuiTabs.js.map +1 -1
  67. package/dist/components/tabs/tabs/RuiTabs.vue.d.ts +2 -2
  68. package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js +1 -1
  69. package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  70. package/dist/composables/forms/auto-complete/keyboard-navigation.d.ts +1 -1
  71. package/dist/composables/forms/auto-complete/keyboard-navigation.js +2 -2
  72. package/dist/composables/forms/auto-complete/keyboard-navigation.js.map +1 -1
  73. package/dist/composables/tables/data-table/expansion.d.ts +0 -1
  74. package/dist/composables/tables/data-table/expansion.js +2 -2
  75. package/dist/composables/tables/data-table/expansion.js.map +1 -1
  76. package/dist/style.css +79 -13
  77. package/dist/utils/tv.d.ts +6 -3
  78. package/dist/utils/tv.js +14 -4
  79. package/dist/utils/tv.js.map +1 -1
  80. package/dist/vite-plugin/index.js +1 -1
  81. package/dist/vite-plugin/index.js.map +1 -1
  82. package/dist/web-types.json +6 -4
  83. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
+ import { cn, tv } from "../../utils/tv.js";
1
2
  import { roundTwoDecimal, useElementDrag } from "./utils.js";
2
3
  import { computed, createElementBlock, createElementVNode, defineComponent, mergeProps, normalizeStyle, onMounted, openBlock, ref, unref, useModel, useTemplateRef, watch } from "vue";
3
4
  import { clamp, get, set } from "@vueuse/shared";
@@ -55,6 +56,7 @@ var RuiColorHue_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ de
55
56
  onMounted(() => {
56
57
  updatePosition();
57
58
  });
59
+ const rootStyle = tv({ base: "relative w-full h-3.5 rounded-full cursor-pointer bg-hue-spectrum" });
58
60
  return (_ctx, _cache) => {
59
61
  return openBlock(), createElementBlock("div", mergeProps({
60
62
  ref_key: "barElement",
@@ -65,8 +67,11 @@ var RuiColorHue_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ de
65
67
  "aria-valuemin": "0",
66
68
  "aria-valuemax": "360",
67
69
  "data-id": "color-hue",
68
- class: "relative w-full h-3.5 rounded-full cursor-pointer bg-hue-spectrum"
69
- }, _ctx.$attrs, {
70
+ class: unref(rootStyle)({ class: unref(cn)(_ctx.$attrs.class) })
71
+ }, {
72
+ ..._ctx.$attrs,
73
+ class: void 0
74
+ }, {
70
75
  onClick: _cache[0] || (_cache[0] = ($event) => unref(handleClick)($event)),
71
76
  onMousedown: _cache[1] || (_cache[1] = ($event) => unref(onMouseDown)($event)),
72
77
  onTouchstart: _cache[2] || (_cache[2] = ($event) => unref(onTouchStart)($event))
@@ -1 +1 @@
1
- {"version":3,"file":"RuiColorHue.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../src/components/color-picker/RuiColorHue.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { clamp } from '@vueuse/shared';\nimport { roundTwoDecimal, useElementDrag } from './utils';\n\ninterface Limit {\n lowerLimit: number;\n upperLimit: number;\n availableWidth: number;\n}\n\ndefineOptions({\n name: 'RuiColorHue',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<number>({ required: true });\n\nconst barElement = useTemplateRef<HTMLElement>('barElement');\n\nconst MAX_HUE = 360;\nconst CURSOR_WIDTH = 16;\nconst cursorLeft = ref<string>('');\n\nconst { handleClick, onMouseDown, onTouchStart } = useElementDrag(emitHue);\n\nconst cursorStyle = computed<{ left: string }>(() => ({\n left: get(cursorLeft),\n}));\n\nfunction getLimit(width: number): Limit {\n const lowerLimit = CURSOR_WIDTH / 2;\n const upperLimit = width - lowerLimit;\n const availableWidth = upperLimit - lowerLimit;\n\n return { lowerLimit, upperLimit, availableWidth };\n}\n\nfunction updatePosition(): void {\n set(cursorLeft, getCursorLeft());\n}\n\nfunction getCursorLeft(): string {\n const el = get(barElement);\n if (!el)\n return '0';\n\n const rect = el.getBoundingClientRect();\n const actualWidth = rect.width;\n const { lowerLimit, availableWidth } = getLimit(actualWidth);\n\n const hueVal = get(modelValue);\n const usedHue = hueVal === MAX_HUE ? MAX_HUE : hueVal % MAX_HUE;\n\n const percentage = roundTwoDecimal((usedHue / MAX_HUE) * (availableWidth / actualWidth) * 100);\n return `calc(${percentage}% + ${lowerLimit}px)`;\n}\n\nfunction emitHue(x: number): void {\n const el = get(barElement);\n if (!el)\n return;\n\n const rect = el.getBoundingClientRect();\n let calculatedX = x - rect.left;\n\n const { lowerLimit, upperLimit, availableWidth } = getLimit(rect.width);\n calculatedX = clamp(calculatedX, lowerLimit, upperLimit);\n\n set(modelValue, Math.round(((calculatedX - lowerLimit) / availableWidth) * MAX_HUE));\n}\n\nwatch(modelValue, () => {\n updatePosition();\n});\n\nonMounted(() => {\n updatePosition();\n});\n</script>\n\n<template>\n <div\n ref=\"barElement\"\n role=\"slider\"\n aria-label=\"Hue\"\n :aria-valuenow=\"modelValue\"\n aria-valuemin=\"0\"\n aria-valuemax=\"360\"\n data-id=\"color-hue\"\n class=\"relative w-full h-3.5 rounded-full cursor-pointer bg-hue-spectrum\"\n v-bind=\"$attrs\"\n @click=\"handleClick($event)\"\n @mousedown=\"onMouseDown($event)\"\n @touchstart=\"onTouchStart($event)\"\n >\n <div\n data-id=\"cursor\"\n class=\"absolute w-4 h-4 transform top-1/2 -translate-x-1/2 -translate-y-1/2 shadow-2 bg-white rounded-full\"\n :style=\"cursorStyle\"\n />\n </div>\n</template>\n"],"mappings":";;;;;AAmBA,IAAM,UAAU;AAChB,IAAM,eAAe;;;;;;;;;;;EALrB,MAAM,aAAa,SAAmB,SAAA,aAAoB;EAE1D,MAAM,aAAa,eAA4B,aAAa;EAI5D,MAAM,aAAa,IAAY,GAAG;EAElC,MAAM,EAAE,aAAa,aAAa,iBAAiB,eAAe,QAAQ;EAE1E,MAAM,cAAc,gBAAkC,EACpD,MAAM,IAAI,WAAW,EACtB,EAAE;EAEH,SAAS,SAAS,OAAsB;GACtC,MAAM,aAAa,eAAe;GAClC,MAAM,aAAa,QAAQ;AAG3B,UAAO;IAAE;IAAY;IAAY,gBAFV,aAAa;IAEa;;EAGnD,SAAS,iBAAuB;AAC9B,OAAI,YAAY,eAAe,CAAC;;EAGlC,SAAS,gBAAwB;GAC/B,MAAM,KAAK,IAAI,WAAW;AAC1B,OAAI,CAAC,GACH,QAAO;GAGT,MAAM,cADO,GAAG,uBAAuB,CACd;GACzB,MAAM,EAAE,YAAY,mBAAmB,SAAS,YAAY;GAE5D,MAAM,SAAS,IAAI,WAAW;AAI9B,UAAO,QADY,iBAFH,WAAW,UAAU,UAAU,SAAS,WAEV,WAAY,iBAAiB,eAAe,IAAI,CACpE,MAAM,WAAW;;EAG7C,SAAS,QAAQ,GAAiB;GAChC,MAAM,KAAK,IAAI,WAAW;AAC1B,OAAI,CAAC,GACH;GAEF,MAAM,OAAO,GAAG,uBAAuB;GACvC,IAAI,cAAc,IAAI,KAAK;GAE3B,MAAM,EAAE,YAAY,YAAY,mBAAmB,SAAS,KAAK,MAAM;AACvE,iBAAc,MAAM,aAAa,YAAY,WAAW;AAExD,OAAI,YAAY,KAAK,OAAQ,cAAc,cAAc,iBAAkB,QAAQ,CAAC;;AAGtF,QAAM,kBAAkB;AACtB,mBAAgB;IAChB;AAEF,kBAAgB;AACd,mBAAgB;IAChB;;uBAIA,mBAmBM,OAnBN,WAmBM;aAlBA;IAAJ,KAAI;IACJ,MAAK;IACL,cAAW;IACV,iBAAe,WAAA;IAChB,iBAAc;IACd,iBAAc;IACd,WAAQ;IACR,OAAM;MACEA,KAAAA,QAAM;IACb,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,YAAW,CAAC,OAAM;IACzB,aAAS,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,YAAW,CAAC,OAAM;IAC7B,cAAU,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,aAAY,CAAC,OAAM;QAEhC,mBAIE,OAAA;IAHA,WAAQ;IACR,OAAM;IACL,OAAK,eAAE,MAAA,YAAW,CAAA"}
1
+ {"version":3,"file":"RuiColorHue.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../src/components/color-picker/RuiColorHue.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport { clamp } from '@vueuse/shared';\nimport { cn, tv } from '@/utils/tv';\nimport { roundTwoDecimal, useElementDrag } from './utils';\n\ninterface Limit {\n lowerLimit: number;\n upperLimit: number;\n availableWidth: number;\n}\n\ndefineOptions({\n name: 'RuiColorHue',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<number>({ required: true });\n\nconst barElement = useTemplateRef<HTMLElement>('barElement');\n\nconst MAX_HUE = 360;\nconst CURSOR_WIDTH = 16;\nconst cursorLeft = ref<string>('');\n\nconst { handleClick, onMouseDown, onTouchStart } = useElementDrag(emitHue);\n\nconst cursorStyle = computed<{ left: string }>(() => ({\n left: get(cursorLeft),\n}));\n\nfunction getLimit(width: number): Limit {\n const lowerLimit = CURSOR_WIDTH / 2;\n const upperLimit = width - lowerLimit;\n const availableWidth = upperLimit - lowerLimit;\n\n return { lowerLimit, upperLimit, availableWidth };\n}\n\nfunction updatePosition(): void {\n set(cursorLeft, getCursorLeft());\n}\n\nfunction getCursorLeft(): string {\n const el = get(barElement);\n if (!el)\n return '0';\n\n const rect = el.getBoundingClientRect();\n const actualWidth = rect.width;\n const { lowerLimit, availableWidth } = getLimit(actualWidth);\n\n const hueVal = get(modelValue);\n const usedHue = hueVal === MAX_HUE ? MAX_HUE : hueVal % MAX_HUE;\n\n const percentage = roundTwoDecimal((usedHue / MAX_HUE) * (availableWidth / actualWidth) * 100);\n return `calc(${percentage}% + ${lowerLimit}px)`;\n}\n\nfunction emitHue(x: number): void {\n const el = get(barElement);\n if (!el)\n return;\n\n const rect = el.getBoundingClientRect();\n let calculatedX = x - rect.left;\n\n const { lowerLimit, upperLimit, availableWidth } = getLimit(rect.width);\n calculatedX = clamp(calculatedX, lowerLimit, upperLimit);\n\n set(modelValue, Math.round(((calculatedX - lowerLimit) / availableWidth) * MAX_HUE));\n}\n\nwatch(modelValue, () => {\n updatePosition();\n});\n\nonMounted(() => {\n updatePosition();\n});\n\nconst rootStyle = tv({ base: 'relative w-full h-3.5 rounded-full cursor-pointer bg-hue-spectrum' });\n</script>\n\n<template>\n <div\n ref=\"barElement\"\n role=\"slider\"\n aria-label=\"Hue\"\n :aria-valuenow=\"modelValue\"\n aria-valuemin=\"0\"\n aria-valuemax=\"360\"\n data-id=\"color-hue\"\n :class=\"rootStyle({ class: cn($attrs.class) })\"\n v-bind=\"{ ...$attrs, class: undefined }\"\n @click=\"handleClick($event)\"\n @mousedown=\"onMouseDown($event)\"\n @touchstart=\"onTouchStart($event)\"\n >\n <div\n data-id=\"cursor\"\n class=\"absolute w-4 h-4 transform top-1/2 -translate-x-1/2 -translate-y-1/2 shadow-2 bg-white rounded-full\"\n :style=\"cursorStyle\"\n />\n </div>\n</template>\n"],"mappings":";;;;;;AAoBA,IAAM,UAAU;AAChB,IAAM,eAAe;;;;;;;;;;;EALrB,MAAM,aAAa,SAAmB,SAAA,aAAoB;EAE1D,MAAM,aAAa,eAA4B,aAAa;EAI5D,MAAM,aAAa,IAAY,GAAG;EAElC,MAAM,EAAE,aAAa,aAAa,iBAAiB,eAAe,QAAQ;EAE1E,MAAM,cAAc,gBAAkC,EACpD,MAAM,IAAI,WAAW,EACtB,EAAE;EAEH,SAAS,SAAS,OAAsB;GACtC,MAAM,aAAa,eAAe;GAClC,MAAM,aAAa,QAAQ;AAG3B,UAAO;IAAE;IAAY;IAAY,gBAFV,aAAa;IAEa;;EAGnD,SAAS,iBAAuB;AAC9B,OAAI,YAAY,eAAe,CAAC;;EAGlC,SAAS,gBAAwB;GAC/B,MAAM,KAAK,IAAI,WAAW;AAC1B,OAAI,CAAC,GACH,QAAO;GAGT,MAAM,cADO,GAAG,uBAAuB,CACd;GACzB,MAAM,EAAE,YAAY,mBAAmB,SAAS,YAAY;GAE5D,MAAM,SAAS,IAAI,WAAW;AAI9B,UAAO,QADY,iBAFH,WAAW,UAAU,UAAU,SAAS,WAEV,WAAY,iBAAiB,eAAe,IAAI,CACpE,MAAM,WAAW;;EAG7C,SAAS,QAAQ,GAAiB;GAChC,MAAM,KAAK,IAAI,WAAW;AAC1B,OAAI,CAAC,GACH;GAEF,MAAM,OAAO,GAAG,uBAAuB;GACvC,IAAI,cAAc,IAAI,KAAK;GAE3B,MAAM,EAAE,YAAY,YAAY,mBAAmB,SAAS,KAAK,MAAM;AACvE,iBAAc,MAAM,aAAa,YAAY,WAAW;AAExD,OAAI,YAAY,KAAK,OAAQ,cAAc,cAAc,iBAAkB,QAAQ,CAAC;;AAGtF,QAAM,kBAAkB;AACtB,mBAAgB;IAChB;AAEF,kBAAgB;AACd,mBAAgB;IAChB;EAEF,MAAM,YAAY,GAAG,EAAE,MAAM,qEAAqE,CAAC;;uBAIjG,mBAmBM,OAnBN,WAmBM;aAlBA;IAAJ,KAAI;IACJ,MAAK;IACL,cAAW;IACV,iBAAe,WAAA;IAChB,iBAAc;IACd,iBAAc;IACd,WAAQ;IACP,OAAO,MAAA,UAAS,CAAA,EAAA,OAAU,MAAA,GAAE,CAACA,KAAAA,OAAO,MAAK,EAAA,CAAA;;OAC7BA,KAAAA;IAAM,OAAS,KAAA;IAAS,EAAA;IACpC,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,YAAW,CAAC,OAAM;IACzB,aAAS,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,YAAW,CAAC,OAAM;IAC7B,cAAU,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,aAAY,CAAC,OAAM;QAEhC,mBAIE,OAAA;IAHA,WAAQ;IACR,OAAM;IACL,OAAK,eAAE,MAAA,YAAW,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"RuiColorPicker.js","names":[],"sources":["../../../src/components/color-picker/RuiColorPicker.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n// Inspired by https://github.com/aesoper101/vue3-colorpicker/\nimport RuiColorBoard from '@/components/color-picker/RuiColorBoard.vue';\nimport RuiColorDisplay from '@/components/color-picker/RuiColorDisplay.vue';\nimport RuiColorHue from '@/components/color-picker/RuiColorHue.vue';\nimport RuiColorInput from '@/components/color-picker/RuiColorInput.vue';\nimport { Color } from './utils';\n\ndefineOptions({\n name: 'RuiColorPicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<string>({ default: '' });\n\nconst state = reactive({\n color: new Color(get(modelValue)),\n});\n\nfunction onBoardChange({\n saturation,\n brightness,\n}: {\n saturation: number;\n brightness: number;\n}): void {\n state.color.saturation = saturation;\n state.color.brightness = brightness;\n}\n\nwhenever(\n modelValue,\n (value: string) => {\n if (state.color.hex !== value)\n state.color = new Color(value);\n },\n);\n\nwatch(\n () => state.color.hex,\n (hex: string) => {\n set(modelValue, hex);\n },\n { immediate: true },\n);\n</script>\n\n<template>\n <div\n role=\"application\"\n aria-label=\"Color picker\"\n data-id=\"color-picker\"\n class=\"relative select-none bg-initial\"\n v-bind=\"$attrs\"\n >\n <RuiColorBoard\n :color=\"state.color\"\n @update:board=\"onBoardChange($event)\"\n />\n <div class=\"flex flex-col gap-5 p-4\">\n <div class=\"flex items-center gap-4\">\n <RuiColorDisplay :color=\"state.color.hexString\" />\n <RuiColorHue\n v-model=\"state.color.hue\"\n class=\"flex-1\"\n />\n </div>\n\n <RuiColorInput v-model=\"state.color\" />\n </div>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RuiColorPicker.js","names":[],"sources":["../../../src/components/color-picker/RuiColorPicker.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n// Inspired by https://github.com/aesoper101/vue3-colorpicker/\nimport RuiColorBoard from '@/components/color-picker/RuiColorBoard.vue';\nimport RuiColorDisplay from '@/components/color-picker/RuiColorDisplay.vue';\nimport RuiColorHue from '@/components/color-picker/RuiColorHue.vue';\nimport RuiColorInput from '@/components/color-picker/RuiColorInput.vue';\nimport { cn, tv } from '@/utils/tv';\nimport { Color } from './utils';\n\ndefineOptions({\n name: 'RuiColorPicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<string>({ default: '' });\n\nconst state = reactive({\n color: new Color(get(modelValue)),\n});\n\nfunction onBoardChange({\n saturation,\n brightness,\n}: {\n saturation: number;\n brightness: number;\n}): void {\n state.color.saturation = saturation;\n state.color.brightness = brightness;\n}\n\nwhenever(\n modelValue,\n (value: string) => {\n if (state.color.hex !== value)\n state.color = new Color(value);\n },\n);\n\nwatch(\n () => state.color.hex,\n (hex: string) => {\n set(modelValue, hex);\n },\n { immediate: true },\n);\n\nconst rootStyle = tv({ base: 'relative select-none bg-initial' });\n</script>\n\n<template>\n <div\n role=\"application\"\n aria-label=\"Color picker\"\n data-id=\"color-picker\"\n :class=\"rootStyle({ class: cn($attrs.class) })\"\n v-bind=\"{ ...$attrs, class: undefined }\"\n >\n <RuiColorBoard\n :color=\"state.color\"\n @update:board=\"onBoardChange($event)\"\n />\n <div class=\"flex flex-col gap-5 p-4\">\n <div class=\"flex items-center gap-4\">\n <RuiColorDisplay :color=\"state.color.hexString\" />\n <RuiColorHue\n v-model=\"state.color.hue\"\n class=\"flex-1\"\n />\n </div>\n\n <RuiColorInput v-model=\"state.color\" />\n </div>\n </div>\n</template>\n"],"mappings":""}
@@ -1,3 +1,4 @@
1
+ import { cn, tv } from "../../utils/tv.js";
1
2
  import { Color } from "./utils.js";
2
3
  import RuiColorBoard_default from "./RuiColorBoard.js";
3
4
  import RuiColorDisplay_default from "./RuiColorDisplay.js";
@@ -31,13 +32,17 @@ var RuiColorPicker_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */
31
32
  watch(() => state.color.hex, (hex) => {
32
33
  set$1(modelValue, hex);
33
34
  }, { immediate: true });
35
+ const rootStyle = tv({ base: "relative select-none bg-initial" });
34
36
  return (_ctx, _cache) => {
35
37
  return openBlock(), createElementBlock("div", mergeProps({
36
38
  role: "application",
37
39
  "aria-label": "Color picker",
38
40
  "data-id": "color-picker",
39
- class: "relative select-none bg-initial"
40
- }, _ctx.$attrs), [createVNode(RuiColorBoard_default, {
41
+ class: unref(rootStyle)({ class: unref(cn)(_ctx.$attrs.class) })
42
+ }, {
43
+ ..._ctx.$attrs,
44
+ class: void 0
45
+ }), [createVNode(RuiColorBoard_default, {
41
46
  color: unref(state).color,
42
47
  "onUpdate:board": _cache[0] || (_cache[0] = ($event) => onBoardChange($event))
43
48
  }, null, 8, ["color"]), createElementVNode("div", _hoisted_1, [createElementVNode("div", _hoisted_2, [createVNode(RuiColorDisplay_default, { color: unref(state).color.hexString }, null, 8, ["color"]), createVNode(RuiColorHue_default, {
@@ -1 +1 @@
1
- {"version":3,"file":"RuiColorPicker.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../src/components/color-picker/RuiColorPicker.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n// Inspired by https://github.com/aesoper101/vue3-colorpicker/\nimport RuiColorBoard from '@/components/color-picker/RuiColorBoard.vue';\nimport RuiColorDisplay from '@/components/color-picker/RuiColorDisplay.vue';\nimport RuiColorHue from '@/components/color-picker/RuiColorHue.vue';\nimport RuiColorInput from '@/components/color-picker/RuiColorInput.vue';\nimport { Color } from './utils';\n\ndefineOptions({\n name: 'RuiColorPicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<string>({ default: '' });\n\nconst state = reactive({\n color: new Color(get(modelValue)),\n});\n\nfunction onBoardChange({\n saturation,\n brightness,\n}: {\n saturation: number;\n brightness: number;\n}): void {\n state.color.saturation = saturation;\n state.color.brightness = brightness;\n}\n\nwhenever(\n modelValue,\n (value: string) => {\n if (state.color.hex !== value)\n state.color = new Color(value);\n },\n);\n\nwatch(\n () => state.color.hex,\n (hex: string) => {\n set(modelValue, hex);\n },\n { immediate: true },\n);\n</script>\n\n<template>\n <div\n role=\"application\"\n aria-label=\"Color picker\"\n data-id=\"color-picker\"\n class=\"relative select-none bg-initial\"\n v-bind=\"$attrs\"\n >\n <RuiColorBoard\n :color=\"state.color\"\n @update:board=\"onBoardChange($event)\"\n />\n <div class=\"flex flex-col gap-5 p-4\">\n <div class=\"flex items-center gap-4\">\n <RuiColorDisplay :color=\"state.color.hexString\" />\n <RuiColorHue\n v-model=\"state.color.hue\"\n class=\"flex-1\"\n />\n </div>\n\n <RuiColorInput v-model=\"state.color\" />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EAaA,MAAM,aAAa,SAAmB,SAAA,aAAiB;EAEvD,MAAM,QAAQ,SAAS,EACrB,OAAO,IAAI,MAAM,MAAI,WAAW,CAAC,EAClC,CAAC;EAEF,SAAS,cAAc,EACrB,YACA,cAIO;AACP,SAAM,MAAM,aAAa;AACzB,SAAM,MAAM,aAAa;;AAG3B,WACE,aACC,UAAkB;AACjB,OAAI,MAAM,MAAM,QAAQ,MACtB,OAAM,QAAQ,IAAI,MAAM,MAAM;IAEnC;AAED,cACQ,MAAM,MAAM,MACjB,QAAgB;AACf,SAAI,YAAY,IAAI;KAEtB,EAAE,WAAW,MAAM,CACpB;;uBAIC,mBAsBM,OAtBN,WAsBM;IArBJ,MAAK;IACL,cAAW;IACX,WAAQ;IACR,OAAM;MACEA,KAAAA,OAAM,EAAA,CAEd,YAGE,uBAAA;IAFC,OAAO,MAAA,MAAK,CAAC;IACb,kBAAY,OAAA,OAAA,OAAA,MAAA,WAAE,cAAc,OAAM;2BAErC,mBAUM,OAVN,YAUM,CATJ,mBAMM,OANN,YAMM,CALJ,YAAkD,yBAAA,EAAhC,OAAO,MAAA,MAAK,CAAC,MAAM,WAAA,EAAA,MAAA,GAAA,CAAA,QAAA,CAAA,EACrC,YAGE,qBAAA;gBAFS,MAAA,MAAK,CAAC,MAAM;uEAAZ,MAAK,CAAC,MAAM,MAAG;IACxB,OAAM;kCAIV,YAAuC,uBAAA;gBAAf,MAAA,MAAK,CAAC;uEAAN,MAAK,CAAC,QAAK"}
1
+ {"version":3,"file":"RuiColorPicker.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../src/components/color-picker/RuiColorPicker.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n// Inspired by https://github.com/aesoper101/vue3-colorpicker/\nimport RuiColorBoard from '@/components/color-picker/RuiColorBoard.vue';\nimport RuiColorDisplay from '@/components/color-picker/RuiColorDisplay.vue';\nimport RuiColorHue from '@/components/color-picker/RuiColorHue.vue';\nimport RuiColorInput from '@/components/color-picker/RuiColorInput.vue';\nimport { cn, tv } from '@/utils/tv';\nimport { Color } from './utils';\n\ndefineOptions({\n name: 'RuiColorPicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<string>({ default: '' });\n\nconst state = reactive({\n color: new Color(get(modelValue)),\n});\n\nfunction onBoardChange({\n saturation,\n brightness,\n}: {\n saturation: number;\n brightness: number;\n}): void {\n state.color.saturation = saturation;\n state.color.brightness = brightness;\n}\n\nwhenever(\n modelValue,\n (value: string) => {\n if (state.color.hex !== value)\n state.color = new Color(value);\n },\n);\n\nwatch(\n () => state.color.hex,\n (hex: string) => {\n set(modelValue, hex);\n },\n { immediate: true },\n);\n\nconst rootStyle = tv({ base: 'relative select-none bg-initial' });\n</script>\n\n<template>\n <div\n role=\"application\"\n aria-label=\"Color picker\"\n data-id=\"color-picker\"\n :class=\"rootStyle({ class: cn($attrs.class) })\"\n v-bind=\"{ ...$attrs, class: undefined }\"\n >\n <RuiColorBoard\n :color=\"state.color\"\n @update:board=\"onBoardChange($event)\"\n />\n <div class=\"flex flex-col gap-5 p-4\">\n <div class=\"flex items-center gap-4\">\n <RuiColorDisplay :color=\"state.color.hexString\" />\n <RuiColorHue\n v-model=\"state.color.hue\"\n class=\"flex-1\"\n />\n </div>\n\n <RuiColorInput v-model=\"state.color\" />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAcA,MAAM,aAAa,SAAmB,SAAA,aAAiB;EAEvD,MAAM,QAAQ,SAAS,EACrB,OAAO,IAAI,MAAM,MAAI,WAAW,CAAC,EAClC,CAAC;EAEF,SAAS,cAAc,EACrB,YACA,cAIO;AACP,SAAM,MAAM,aAAa;AACzB,SAAM,MAAM,aAAa;;AAG3B,WACE,aACC,UAAkB;AACjB,OAAI,MAAM,MAAM,QAAQ,MACtB,OAAM,QAAQ,IAAI,MAAM,MAAM;IAEnC;AAED,cACQ,MAAM,MAAM,MACjB,QAAgB;AACf,SAAI,YAAY,IAAI;KAEtB,EAAE,WAAW,MAAM,CACpB;EAED,MAAM,YAAY,GAAG,EAAE,MAAM,mCAAmC,CAAC;;uBAI/D,mBAsBM,OAtBN,WAsBM;IArBJ,MAAK;IACL,cAAW;IACX,WAAQ;IACP,OAAO,MAAA,UAAS,CAAA,EAAA,OAAU,MAAA,GAAE,CAACA,KAAAA,OAAO,MAAK,EAAA,CAAA;;OAC7BA,KAAAA;IAAM,OAAS,KAAA;IAAS,CAAA,EAAA,CAErC,YAGE,uBAAA;IAFC,OAAO,MAAA,MAAK,CAAC;IACb,kBAAY,OAAA,OAAA,OAAA,MAAA,WAAE,cAAc,OAAM;2BAErC,mBAUM,OAVN,YAUM,CATJ,mBAMM,OANN,YAMM,CALJ,YAAkD,yBAAA,EAAhC,OAAO,MAAA,MAAK,CAAC,MAAM,WAAA,EAAA,MAAA,GAAA,CAAA,QAAA,CAAA,EACrC,YAGE,qBAAA;gBAFS,MAAA,MAAK,CAAC,MAAM;uEAAZ,MAAK,CAAC,MAAM,MAAG;IACxB,OAAM;kCAIV,YAAuC,uBAAA;gBAAf,MAAA,MAAK,CAAC;uEAAN,MAAK,CAAC,QAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"RuiDateTimePicker.js","names":[],"sources":["../../../src/components/date-time-picker/RuiDateTimePicker.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type { 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 { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs } from '@/utils/helpers';\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\ndefineOptions({\n name: 'RuiDateTimePicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<ModelValueType<DateTimeModelType>>({ required: true });\n\nconst {\n disabled = false,\n readonly = false,\n allowEmpty = false,\n dense = false,\n type = 'epoch-ms',\n hideDetails = false,\n label = 'Pick a date',\n variant = 'default',\n hint,\n maxDate,\n minDate,\n format = 'day-first',\n accuracy = 'minute',\n errorMessages = [],\n successMessages = [],\n required = false,\n} = defineProps<RuiDateTimePickerProps>();\n\ndefineSlots<{\n 'menu-content': () => any;\n}>();\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 cursorPosition = ref<number>(0);\nconst currentValue = ref<number>();\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuWrapperRef = useTemplateRef<HTMLDivElement>('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 {\n clear: clearSelection,\n getDateTime,\n internalErrorMessages,\n maxAllowedDate,\n minAllowedDate,\n segmentData,\n selectedDate,\n selectedDay,\n selectedHour,\n selectedMillisecond,\n selectedMinute,\n selectedMonth,\n selectedSecond,\n selectedTime,\n selectedTimezone,\n selectedYear,\n setNow,\n valueSet,\n} = useDateTimeSelection({\n accuracy,\n allowEmpty,\n maxDate,\n minDate,\n modelValue,\n type,\n});\n\nconst { setValue, getCurrent } = useInputHandler(segmentData, currentValue);\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: clearSegment,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\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\nconst formattedDisplay = computed<string>(() => {\n let result = get(dateFormat);\n\n const replacements = [\n { pattern: 'YYYY', value: getDisplayValue(selectedYear, 4) },\n { pattern: 'MM', value: getDisplayValue(selectedMonth, 2) },\n { pattern: 'DD', value: getDisplayValue(selectedDay, 2) },\n { pattern: 'HH', value: getDisplayValue(selectedHour, 2) },\n { pattern: 'mm', value: getDisplayValue(selectedMinute, 2) },\n { pattern: 'ss', value: getDisplayValue(selectedSecond, 2) },\n { pattern: 'SSS', value: getDisplayValue(selectedMillisecond, 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\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) || !label)\n return '';\n return required ? `${label} ﹡` : label;\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 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\nfunction handleInputClick(event: MouseEvent): void {\n // Handle segment selection first, before any DOM changes from menu opening\n handleClick(event);\n // Open menu if not already open\n if (!get(isOpen)) {\n set(isOpen, true);\n }\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"getRootAttrs($attrs)\"\n :class=\"ui.wrapper()\"\n placement=\"bottom-start\"\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 :tabindex=\"disabled || readonly ? -1 : 0\"\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 {{ label }}\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 :placeholder=\"dateFormat\"\n :readonly=\"readonly\"\n :aria-invalid=\"hasError\"\n @mousedown=\"handleMouseDown($event)\"\n @focus=\"handleFocus()\"\n @blur=\"handleBlur()\"\n @select=\"handleInputSelection($event)\"\n @click.stop=\"handleInputClick($event)\"\n @keydown=\"handleKeyDown($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 tabindex=\"-1\"\n color=\"error\"\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 <span\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n @click=\"arrowClicked($event)\"\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=\"selectedHour\"\n v-model:selected-minute=\"selectedMinute\"\n v-model:selected-second=\"selectedSecond\"\n v-model:selected-millisecond=\"selectedMillisecond\"\n v-model:time-selection=\"timeSelection\"\n v-model:selected-timezone=\"selectedTimezone\"\n v-model:calendar-menu-open=\"calendarMenuOpen\"\n :accuracy=\"accuracy\"\n :max-date=\"maxAllowedDate\"\n :min-date=\"minAllowedDate\"\n @set-now=\"setNow()\"\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 { 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 { 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\ndefineOptions({\n name: 'RuiDateTimePicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<ModelValueType<DateTimeModelType>>({ required: true });\n\nconst {\n disabled = false,\n readonly = false,\n allowEmpty = false,\n dense = false,\n type = 'epoch-ms',\n hideDetails = false,\n label = 'Pick a date',\n variant = 'default',\n hint,\n maxDate,\n minDate,\n format = 'day-first',\n accuracy = 'minute',\n errorMessages = [],\n successMessages = [],\n required = false,\n} = defineProps<RuiDateTimePickerProps>();\n\ndefineSlots<{\n 'menu-content': () => any;\n}>();\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 cursorPosition = ref<number>(0);\nconst currentValue = ref<number>();\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuWrapperRef = useTemplateRef<HTMLDivElement>('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 {\n clear: clearSelection,\n getDateTime,\n internalErrorMessages,\n maxAllowedDate,\n minAllowedDate,\n segmentData,\n selectedDate,\n selectedDay,\n selectedHour,\n selectedMillisecond,\n selectedMinute,\n selectedMonth,\n selectedSecond,\n selectedTime,\n selectedTimezone,\n selectedYear,\n setNow,\n valueSet,\n} = useDateTimeSelection({\n accuracy,\n allowEmpty,\n maxDate,\n minDate,\n modelValue,\n type,\n});\n\nconst { setValue, getCurrent } = useInputHandler(segmentData, currentValue);\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: clearSegment,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\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\nconst formattedDisplay = computed<string>(() => {\n let result = get(dateFormat);\n\n const replacements = [\n { pattern: 'YYYY', value: getDisplayValue(selectedYear, 4) },\n { pattern: 'MM', value: getDisplayValue(selectedMonth, 2) },\n { pattern: 'DD', value: getDisplayValue(selectedDay, 2) },\n { pattern: 'HH', value: getDisplayValue(selectedHour, 2) },\n { pattern: 'mm', value: getDisplayValue(selectedMinute, 2) },\n { pattern: 'ss', value: getDisplayValue(selectedSecond, 2) },\n { pattern: 'SSS', value: getDisplayValue(selectedMillisecond, 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\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) || !label)\n return '';\n return required ? `${label} ﹡` : label;\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 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\nfunction handleInputClick(event: MouseEvent): void {\n // Handle segment selection first, before any DOM changes from menu opening\n handleClick(event);\n // Open menu if not already open\n if (!get(isOpen)) {\n set(isOpen, true);\n }\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\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 placement=\"bottom-start\"\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 :tabindex=\"disabled || readonly ? -1 : 0\"\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 {{ label }}\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 :placeholder=\"dateFormat\"\n :readonly=\"readonly\"\n :aria-invalid=\"hasError\"\n @mousedown=\"handleMouseDown($event)\"\n @focus=\"handleFocus()\"\n @blur=\"handleBlur()\"\n @select=\"handleInputSelection($event)\"\n @click.stop=\"handleInputClick($event)\"\n @keydown=\"handleKeyDown($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 tabindex=\"-1\"\n color=\"error\"\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 <span\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n @click=\"arrowClicked($event)\"\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=\"selectedHour\"\n v-model:selected-minute=\"selectedMinute\"\n v-model:selected-second=\"selectedSecond\"\n v-model:selected-millisecond=\"selectedMillisecond\"\n v-model:time-selection=\"timeSelection\"\n v-model:selected-timezone=\"selectedTimezone\"\n v-model:calendar-menu-open=\"calendarMenuOpen\"\n :accuracy=\"accuracy\"\n :max-date=\"maxAllowedDate\"\n :min-date=\"minAllowedDate\"\n @set-now=\"setNow()\"\n >\n <slot name=\"menu-content\" />\n </RuiDateTimePickerMenu>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":""}
@@ -1,3 +1,4 @@
1
+ import { cn } from "../../utils/tv.js";
1
2
  import RuiIcon_default from "../icons/RuiIcon.js";
2
3
  import RuiButton_default from "../buttons/button/RuiButton.js";
3
4
  import { useFormTextDetail } from "../../utils/form-text-detail.js";
@@ -212,8 +213,8 @@ var RuiDateTimePicker_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
212
213
  return openBlock(), createBlock(RuiMenu_default, mergeProps({
213
214
  modelValue: unref(isOpen),
214
215
  "onUpdate:modelValue": _cache[21] || (_cache[21] = ($event) => isRef(isOpen) ? isOpen.value = $event : null)
215
- }, unref(getRootAttrs)(_ctx.$attrs), {
216
- class: unref(ui).wrapper(),
216
+ }, unref(getRootAttrs)(_ctx.$attrs, []), {
217
+ class: unref(ui).wrapper({ class: unref(cn)(_ctx.$attrs.class) }),
217
218
  placement: "bottom-start",
218
219
  dense: __props.dense,
219
220
  hint: __props.hint,
@@ -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 { 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 { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs } from '@/utils/helpers';\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\ndefineOptions({\n name: 'RuiDateTimePicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<ModelValueType<DateTimeModelType>>({ required: true });\n\nconst {\n disabled = false,\n readonly = false,\n allowEmpty = false,\n dense = false,\n type = 'epoch-ms',\n hideDetails = false,\n label = 'Pick a date',\n variant = 'default',\n hint,\n maxDate,\n minDate,\n format = 'day-first',\n accuracy = 'minute',\n errorMessages = [],\n successMessages = [],\n required = false,\n} = defineProps<RuiDateTimePickerProps>();\n\ndefineSlots<{\n 'menu-content': () => any;\n}>();\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 cursorPosition = ref<number>(0);\nconst currentValue = ref<number>();\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuWrapperRef = useTemplateRef<HTMLDivElement>('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 {\n clear: clearSelection,\n getDateTime,\n internalErrorMessages,\n maxAllowedDate,\n minAllowedDate,\n segmentData,\n selectedDate,\n selectedDay,\n selectedHour,\n selectedMillisecond,\n selectedMinute,\n selectedMonth,\n selectedSecond,\n selectedTime,\n selectedTimezone,\n selectedYear,\n setNow,\n valueSet,\n} = useDateTimeSelection({\n accuracy,\n allowEmpty,\n maxDate,\n minDate,\n modelValue,\n type,\n});\n\nconst { setValue, getCurrent } = useInputHandler(segmentData, currentValue);\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: clearSegment,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\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\nconst formattedDisplay = computed<string>(() => {\n let result = get(dateFormat);\n\n const replacements = [\n { pattern: 'YYYY', value: getDisplayValue(selectedYear, 4) },\n { pattern: 'MM', value: getDisplayValue(selectedMonth, 2) },\n { pattern: 'DD', value: getDisplayValue(selectedDay, 2) },\n { pattern: 'HH', value: getDisplayValue(selectedHour, 2) },\n { pattern: 'mm', value: getDisplayValue(selectedMinute, 2) },\n { pattern: 'ss', value: getDisplayValue(selectedSecond, 2) },\n { pattern: 'SSS', value: getDisplayValue(selectedMillisecond, 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\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) || !label)\n return '';\n return required ? `${label} ﹡` : label;\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 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\nfunction handleInputClick(event: MouseEvent): void {\n // Handle segment selection first, before any DOM changes from menu opening\n handleClick(event);\n // Open menu if not already open\n if (!get(isOpen)) {\n set(isOpen, true);\n }\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"getRootAttrs($attrs)\"\n :class=\"ui.wrapper()\"\n placement=\"bottom-start\"\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 :tabindex=\"disabled || readonly ? -1 : 0\"\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 {{ label }}\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 :placeholder=\"dateFormat\"\n :readonly=\"readonly\"\n :aria-invalid=\"hasError\"\n @mousedown=\"handleMouseDown($event)\"\n @focus=\"handleFocus()\"\n @blur=\"handleBlur()\"\n @select=\"handleInputSelection($event)\"\n @click.stop=\"handleInputClick($event)\"\n @keydown=\"handleKeyDown($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 tabindex=\"-1\"\n color=\"error\"\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 <span\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n @click=\"arrowClicked($event)\"\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=\"selectedHour\"\n v-model:selected-minute=\"selectedMinute\"\n v-model:selected-second=\"selectedSecond\"\n v-model:selected-millisecond=\"selectedMillisecond\"\n v-model:time-selection=\"timeSelection\"\n v-model:selected-timezone=\"selectedTimezone\"\n v-model:calendar-menu-open=\"calendarMenuOpen\"\n :accuracy=\"accuracy\"\n :max-date=\"maxAllowedDate\"\n :min-date=\"minAllowedDate\"\n @set-now=\"setNow()\"\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 { 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 { 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\ndefineOptions({\n name: 'RuiDateTimePicker',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<ModelValueType<DateTimeModelType>>({ required: true });\n\nconst {\n disabled = false,\n readonly = false,\n allowEmpty = false,\n dense = false,\n type = 'epoch-ms',\n hideDetails = false,\n label = 'Pick a date',\n variant = 'default',\n hint,\n maxDate,\n minDate,\n format = 'day-first',\n accuracy = 'minute',\n errorMessages = [],\n successMessages = [],\n required = false,\n} = defineProps<RuiDateTimePickerProps>();\n\ndefineSlots<{\n 'menu-content': () => any;\n}>();\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 cursorPosition = ref<number>(0);\nconst currentValue = ref<number>();\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuWrapperRef = useTemplateRef<HTMLDivElement>('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 {\n clear: clearSelection,\n getDateTime,\n internalErrorMessages,\n maxAllowedDate,\n minAllowedDate,\n segmentData,\n selectedDate,\n selectedDay,\n selectedHour,\n selectedMillisecond,\n selectedMinute,\n selectedMonth,\n selectedSecond,\n selectedTime,\n selectedTimezone,\n selectedYear,\n setNow,\n valueSet,\n} = useDateTimeSelection({\n accuracy,\n allowEmpty,\n maxDate,\n minDate,\n modelValue,\n type,\n});\n\nconst { setValue, getCurrent } = useInputHandler(segmentData, currentValue);\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: clearSegment,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\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\nconst formattedDisplay = computed<string>(() => {\n let result = get(dateFormat);\n\n const replacements = [\n { pattern: 'YYYY', value: getDisplayValue(selectedYear, 4) },\n { pattern: 'MM', value: getDisplayValue(selectedMonth, 2) },\n { pattern: 'DD', value: getDisplayValue(selectedDay, 2) },\n { pattern: 'HH', value: getDisplayValue(selectedHour, 2) },\n { pattern: 'mm', value: getDisplayValue(selectedMinute, 2) },\n { pattern: 'ss', value: getDisplayValue(selectedSecond, 2) },\n { pattern: 'SSS', value: getDisplayValue(selectedMillisecond, 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\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) || !label)\n return '';\n return required ? `${label} ﹡` : label;\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 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\nfunction handleInputClick(event: MouseEvent): void {\n // Handle segment selection first, before any DOM changes from menu opening\n handleClick(event);\n // Open menu if not already open\n if (!get(isOpen)) {\n set(isOpen, true);\n }\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\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 placement=\"bottom-start\"\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 :tabindex=\"disabled || readonly ? -1 : 0\"\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 {{ label }}\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 :placeholder=\"dateFormat\"\n :readonly=\"readonly\"\n :aria-invalid=\"hasError\"\n @mousedown=\"handleMouseDown($event)\"\n @focus=\"handleFocus()\"\n @blur=\"handleBlur()\"\n @select=\"handleInputSelection($event)\"\n @click.stop=\"handleInputClick($event)\"\n @keydown=\"handleKeyDown($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 tabindex=\"-1\"\n color=\"error\"\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 <span\n :class=\"ui.iconWrapper()\"\n data-id=\"append\"\n @click=\"arrowClicked($event)\"\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=\"selectedHour\"\n v-model:selected-minute=\"selectedMinute\"\n v-model:selected-second=\"selectedSecond\"\n v-model:selected-millisecond=\"selectedMillisecond\"\n v-model:time-selection=\"timeSelection\"\n v-model:selected-timezone=\"selectedTimezone\"\n v-model:calendar-menu-open=\"calendarMenuOpen\"\n :accuracy=\"accuracy\"\n :max-date=\"maxAllowedDate\"\n :min-date=\"minAllowedDate\"\n @set-now=\"setNow()\"\n >\n <slot name=\"menu-content\" />\n </RuiDateTimePickerMenu>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"RuiAutoComplete.js","names":[],"sources":["../../../../src/components/forms/auto-complete/RuiAutoComplete.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"TValue, TItem\">\nimport type { VueClassValue } from '@/types/class-value';\nimport RuiButton from '@/components/buttons/button/RuiButton.vue';\nimport RuiChip from '@/components/chips/RuiChip.vue';\nimport { autoCompleteStyles, type AutoCompleteVariant } from '@/components/forms/auto-complete/auto-complete-styles';\nimport RuiIcon from '@/components/icons/RuiIcon.vue';\nimport RuiMenu, { type MenuProps } from '@/components/overlays/menu/RuiMenu.vue';\nimport RuiProgress from '@/components/progress/RuiProgress.vue';\nimport {\n type KeyOfType,\n useDropdownMenu,\n useDropdownOptionProperty,\n} from '@/composables/dropdown-menu';\nimport {\n useAutoCompleteFocus,\n useAutoCompleteKeyboardNavigation,\n useAutoCompleteSearch,\n useAutoCompleteValue,\n} from '@/composables/forms/auto-complete';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs, getTextToken } from '@/utils/helpers';\nimport { isEqual } from '@/utils/is-equal';\nimport { cn } from '@/utils/tv';\n\nexport type AutoCompleteModelValue<TValue> =\n TValue extends Array<infer U> ? U[] : TValue | undefined;\n\nexport interface RuiAutoCompleteClassNames {\n root?: VueClassValue;\n label?: VueClassValue;\n menu?: VueClassValue;\n}\n\nexport interface AutoCompleteProps<TValue, TItem> {\n options?: TItem[];\n keyAttr?: KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>;\n textAttr?: keyof TItem;\n disabled?: boolean;\n loading?: boolean;\n readOnly?: boolean;\n dense?: boolean;\n clearable?: boolean;\n label?: string;\n menuOptions?: MenuProps;\n classNames?: RuiAutoCompleteClassNames;\n /** @deprecated Use `classNames.label` instead */\n labelClass?: string;\n /** @deprecated Use `classNames.menu` instead */\n menuClass?: string;\n prependWidth?: number;\n appendWidth?: number;\n itemHeight?: number;\n variant?: AutoCompleteVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n autoSelectFirst?: boolean;\n chips?: boolean;\n noFilter?: boolean;\n hideNoData?: boolean;\n noDataText?: string;\n filter?: (item: TItem, queryText: string) => boolean;\n hideSelected?: boolean;\n placeholder?: string;\n returnObject?: boolean;\n customValue?: boolean;\n hideCustomValue?: boolean;\n required?: boolean;\n hideSearchInput?: boolean;\n hideSelectionWrapper?: boolean;\n}\n\ndefineOptions({\n name: 'RuiAutoComplete',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<AutoCompleteModelValue<TValue>>({ required: true });\n\nconst searchInputModel = defineModel<string>('searchInput', { default: '' });\n\nconst {\n options = [],\n disabled = false,\n loading = false,\n readOnly = false,\n dense = false,\n clearable = false,\n hideDetails = false,\n chips = false,\n label = 'Select',\n menuOptions,\n classNames,\n labelClass,\n menuClass,\n variant = 'default',\n hint,\n keyAttr,\n textAttr,\n itemHeight,\n errorMessages = [],\n successMessages = [],\n autoSelectFirst = false,\n noFilter = false,\n hideNoData = false,\n noDataText = 'No data available',\n filter,\n hideSelected = false,\n placeholder = '',\n returnObject = false,\n customValue = false,\n hideCustomValue = false,\n required = false,\n hideSearchInput = false,\n hideSelectionWrapper = false,\n} = defineProps<AutoCompleteProps<TValue, TItem>>();\n\nconst slots = defineSlots<{\n 'activator'?: (props: {\n disabled: boolean;\n value: TItem[];\n variant: string;\n readOnly: boolean;\n attrs: Record<string, unknown>;\n open: boolean;\n hasError: boolean;\n hasSuccess: boolean;\n }) => any;\n 'activator.label'?: (props: { value: TItem[] }) => any;\n 'selection.prepend'?: (props: { index: number; item: TItem }) => any;\n 'selection'?: (props: { index: number; item: TItem; chipAttrs?: Record<string, unknown> }) => any;\n 'item.prepend'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'item'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'item.append'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'no-data'?: () => any;\n}>();\n\nconst { getText, getIdentifier } = useDropdownOptionProperty<TValue, TItem>({\n keyAttr,\n textAttr,\n});\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuRef = useTemplateRef<HTMLDivElement>('menuRef');\nconst menuWrapperRef = useTemplateRef<HTMLDivElement>('menuWrapperRef');\n\nconst { focused: activatorFocusedWithin } = useFocusWithin(activator);\nconst { focused: menuWrapperFocusedWithin } = useFocusWithin(menuWrapperRef);\nconst { focused: searchInputFocused } = useFocus(textInput);\nconst { focused: activatorFocused } = useFocus(activator);\n\nconst {\n internalSearch,\n filteredOptions,\n justOpened,\n updateInternalSearch,\n textValueToProperValue,\n} = useAutoCompleteSearch<TItem>(\n () => options,\n searchInputModel,\n {\n keyAttr: () => keyAttr,\n textAttr: () => textAttr,\n noFilter: () => noFilter,\n filter: () => filter,\n customValue: () => customValue,\n hideCustomValue: () => hideCustomValue,\n returnObject: () => returnObject,\n },\n);\n\nconst isOpen = ref<boolean>(false);\n\n// Calculate multiple from modelValue directly to avoid circular dependency\nconst multiple = computed<boolean>(() => Array.isArray(get(modelValue)));\n\nconst shouldApplyValueAsSearch = computed<boolean>(\n () => !(slots.selection || get(multiple) || chips),\n);\n\nconst { value, setSelected } = useAutoCompleteValue<AutoCompleteModelValue<TValue>, TItem>(\n modelValue,\n () => options,\n {\n keyAttr: () => keyAttr,\n returnObject: () => returnObject,\n customValue: () => customValue,\n },\n {\n getIdentifier,\n getText,\n textValueToProperValue,\n shouldApplyValueAsSearch,\n isOpen,\n multiple,\n updateInternalSearch,\n },\n);\n\nconst resolvedItemHeight = itemHeight ?? (dense ? 30 : 48);\n\nconst {\n containerProps,\n wrapperProps,\n renderedData,\n menuWidth,\n isActiveItem,\n itemIndexInValue,\n highlightedIndex,\n moveHighlight,\n applyHighlighted,\n optionsWithSelectedHidden,\n userNavigated,\n} = useDropdownMenu<TValue, TItem>({\n itemHeight: resolvedItemHeight,\n keyAttr,\n textAttr,\n options: filteredOptions,\n dense: () => dense,\n value,\n menuRef,\n setValue,\n autoSelectFirst,\n hideSelected,\n isOpen,\n getText,\n getIdentifier,\n});\n\nconst {\n focusedValueIndex,\n moveSelectedValueHighlight,\n onEnter,\n onInputDeletePressed,\n onTab,\n setValueFocus,\n} = useAutoCompleteKeyboardNavigation<TItem>(\n {\n chips: () => chips,\n customValue: () => customValue,\n multiple,\n },\n {\n activator,\n applyHighlighted,\n clear,\n filteredOptions,\n getText,\n highlightedIndex,\n internalSearch,\n isOpen,\n removeValue: (item: TItem): void => { setValue(item); },\n searchInputFocused,\n setSearchAsValue,\n userNavigated,\n value,\n },\n);\n\nconst {\n anyFocused: focusAnyFocused,\n inputClass: focusInputClass,\n onActivatorFocused: focusOnActivatorFocused,\n onInputFocused: focusOnInputFocused,\n setInputFocus: focusSetInputFocus,\n} = useAutoCompleteFocus(\n {\n customValue: () => customValue,\n disabled: () => disabled,\n shouldApplyValueAsSearch,\n },\n {\n activatorFocused,\n activatorFocusedWithin,\n focusedValueIndex,\n internalSearch,\n isOpen,\n justOpened,\n menuWrapperFocusedWithin,\n searchInputFocused,\n setSearchAsValue,\n textInput,\n updateInternalSearch,\n },\n);\n\nconst menuMinHeight = computed<number>(\n () => Math.min(5, get(optionsWithSelectedHidden).length) * resolvedItemHeight,\n);\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst valueSet = computed<boolean>(() => get(value).length > 0);\n\nconst usedPlaceholder = computed<string>(() => {\n if (get(searchInputFocused))\n return placeholder;\n return '';\n});\n\nconst outlined = computed<boolean>(() => variant === 'outlined');\nconst float = computed<boolean>(() => (get(isOpen) || get(valueSet) || get(searchInputFocused)) && get(outlined));\n\nconst legendText = computed<string>(() => {\n if (!get(float) || !label)\n return '';\n return required ? `${label} ﹡` : label;\n});\n\nconst ui = computed<ReturnType<typeof autoCompleteStyles>>(() => autoCompleteStyles({\n filled: variant === 'filled',\n outlined: get(outlined),\n float: get(float),\n opened: get(isOpen),\n dense,\n disabled,\n readonly: readOnly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst highlightedClass = autoCompleteStyles({}).highlighted();\n\nfunction updateSearchInput(event: Event): void {\n const target = event.target;\n if (!(target instanceof HTMLInputElement))\n return;\n\n const value = target.value;\n set(isOpen, true);\n updateInternalSearch(value);\n set(justOpened, false);\n}\n\nasync function setValue(val: TItem, skipRefocused = false): Promise<void> {\n const isMultiple = get(multiple);\n\n if (isMultiple) {\n const newValue = [...get(value)];\n const indexInValue = itemIndexInValue(val);\n if (indexInValue === -1) {\n updateInternalSearch();\n newValue.push(val);\n }\n else {\n newValue.splice(indexInValue, 1);\n }\n set(value, newValue);\n }\n else {\n if (get(shouldApplyValueAsSearch))\n updateInternalSearch(getText(val));\n else updateInternalSearch();\n\n set(value, [val]);\n }\n\n if (!isMultiple) {\n if (!skipRefocused) {\n set(activatorFocused, true);\n get(activator)?.focus();\n await nextTick(() => {\n set(isOpen, false);\n });\n }\n else {\n set(isOpen, false);\n }\n }\n else if (!skipRefocused) {\n set(searchInputFocused, true);\n }\n}\n\nfunction setSearchAsValue(): void {\n const searchToBeValue = get(internalSearch);\n if (!searchToBeValue)\n return;\n\n const newValue: TItem = textValueToProperValue(searchToBeValue);\n setValue(newValue, true);\n}\n\nfunction clear(): void {\n updateInternalSearch();\n set(modelValue, (Array.isArray(get(modelValue)) ? [] : undefined) as AutoCompleteModelValue<TValue>);\n}\n\nfunction chipAttrs(item: TItem, index: number): Record<string, unknown> {\n return {\n 'data-index': index,\n 'data-value': getIdentifier(item),\n 'onKeydown': (event: KeyboardEvent): void => {\n const { key } = event;\n if (['Backspace', 'Delete'].includes(key)) {\n event.stopPropagation();\n event.preventDefault();\n setValue(item);\n }\n },\n 'onClick': (e: MouseEvent): void => {\n e.stopPropagation();\n setValueFocus(index);\n },\n 'onClick:close': (): void => {\n setValue(item);\n },\n };\n}\n\nfunction setSelectionRange(start: number, end: number): void {\n set(searchInputFocused, true);\n get(textInput)?.setSelectionRange?.(start, end);\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n\n// Optimize options watcher with shallow comparison first\nwatch(() => options, (curr, old) => {\n if (curr === old || customValue)\n return;\n\n // Only do deep comparison if reference changed\n if (isEqual(curr, old))\n return;\n\n setSelected(get(value));\n});\n\ndefineExpose({\n focus: focusSetInputFocus,\n setSelectionRange,\n});\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"{ ...getRootAttrs($attrs), ...menuOptions }\"\n :class=\"ui.wrapper()\"\n placement=\"bottom-start\"\n :close-on-content-click=\"false\"\n :full-width=\"true\"\n :persist-on-activator-click=\"true\"\n :menu-class=\"[\n { hidden: optionsWithSelectedHidden.length === 0 && customValue && !slots['no-data'] },\n menuOptions?.menuClass,\n ]\"\n :error-messages=\"errorMessages\"\n :success-messages=\"successMessages\"\n :hint=\"hint\"\n :dense=\"dense\"\n :show-details=\"!hideDetails\"\n :disabled=\"disabled\"\n disable-auto-focus\n >\n <template #activator=\"{ attrs, open, hasError: slotHasError, hasSuccess: slotHasSuccess }\">\n <slot\n name=\"activator\"\n v-bind=\"{ disabled, value, variant, readOnly, attrs, open, hasError: slotHasError, hasSuccess: slotHasSuccess }\"\n >\n <div\n ref=\"activator\"\n :class=\"ui.activator({ class: cn(classNames?.label) ?? labelClass })\"\n v-bind=\"{\n ...getNonRootAttrs($attrs, ['onClick', 'class']),\n ...(readOnly ? {} : attrs),\n }\"\n role=\"combobox\"\n :aria-expanded=\"open\"\n :aria-disabled=\"disabled || undefined\"\n :aria-readonly=\"readOnly || undefined\"\n :aria-required=\"required || undefined\"\n :aria-busy=\"loading || undefined\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n :tabindex=\"disabled || readOnly ? -1 : 0\"\n @click=\"focusSetInputFocus()\"\n @focus=\"focusOnActivatorFocused()\"\n @keydown.enter=\"onEnter($event)\"\n @keydown.tab=\"onTab($event)\"\n @keydown.left=\"moveSelectedValueHighlight($event, false)\"\n @keydown.right=\"moveSelectedValueHighlight($event, true)\"\n @keydown.up.prevent=\"moveHighlight(true)\"\n @keydown.down.prevent=\"moveHighlight(false)\"\n @keydown.home.prevent=\"highlightedIndex = 0\"\n @keydown.end.prevent=\"highlightedIndex = optionsWithSelectedHidden.length - 1\"\n >\n <span\n v-if=\"outlined || (!valueSet && !searchInputFocused)\"\n :class=\"[\n ui.label(),\n { 'pr-2': !valueSet && !open && outlined },\n ]\"\n >\n <slot\n name=\"activator.label\"\n v-bind=\"{ value }\"\n >\n {{ label }}\n </slot>\n <span\n v-if=\"required\"\n :class=\"ui.required()\"\n >\n ﹡\n </span>\n </span>\n <div\n data-id=\"value\"\n :class=\"ui.value()\"\n >\n <template\n v-for=\"(item, i) in value\"\n :key=\"getIdentifier(item)\"\n >\n <RuiChip\n v-if=\"chips\"\n :key=\"getTextToken(getIdentifier(item))\"\n tabindex=\"-1\"\n :size=\"dense ? 'sm' : 'md'\"\n closeable\n :class=\"{ 'leading-3': dense }\"\n clickable\n v-bind=\"chipAttrs(item, i)\"\n >\n <div class=\"flex\">\n <slot\n name=\"selection.prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n <slot\n :index=\"i\"\n name=\"selection\"\n v-bind=\"{ item }\"\n >\n {{ getText(item) }}\n </slot>\n </div>\n </RuiChip>\n <div\n v-else-if=\"\n multiple\n || (!searchInputFocused && (slots['selection.prepend'] || slots.selection))\n \"\n :class=\"hideSelectionWrapper ? 'contents' : 'flex'\"\n >\n <slot\n name=\"selection.prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n <slot\n v-if=\"multiple || slots.selection\"\n :index=\"i\"\n name=\"selection\"\n v-bind=\"{ item, chipAttrs: chipAttrs(item, i) }\"\n >\n {{ getText(item) }}\n </slot>\n </div>\n </template>\n <input\n ref=\"textInput\"\n :disabled=\"disabled\"\n :value=\"internalSearch\"\n class=\"bg-transparent outline-none\"\n type=\"text\"\n :placeholder=\"usedPlaceholder\"\n :class=\"[focusInputClass, { hidden: hideSearchInput }]\"\n :aria-invalid=\"hasError\"\n aria-autocomplete=\"list\"\n @keydown.delete=\"onInputDeletePressed()\"\n @input.stop=\"updateSearchInput($event)\"\n @focus=\"focusOnInputFocused()\"\n />\n </div>\n\n <RuiButton\n v-if=\"clearable && valueSet && !disabled\"\n variant=\"text\"\n icon\n size=\"sm\"\n tabindex=\"-1\"\n color=\"error\"\n data-id=\"clear\"\n :class=\"[\n ui.clear(),\n focusAnyFocused && '!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 <span\n :class=\"ui.iconWrapper()\"\n @click=\"arrowClicked($event)\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </span>\n\n <RuiProgress\n v-if=\"loading\"\n :class=\"ui.progress()\"\n color=\"primary\"\n thickness=\"3\"\n variant=\"indeterminate\"\n />\n </div>\n <fieldset\n v-if=\"outlined\"\n :class=\"ui.fieldset()\"\n >\n <legend :class=\"ui.legend()\">\n {{ legendText }}\n </legend>\n </fieldset>\n </slot>\n </template>\n <template #default=\"{ width }\">\n <div ref=\"menuWrapperRef\">\n <div\n v-if=\"optionsWithSelectedHidden.length > 0\"\n :ref=\"containerProps.ref\"\n :class=\"ui.menu({ class: cn(classNames?.menu) ?? menuClass })\"\n :style=\"[containerProps.style, { width: `${width}px`, minWidth: menuWidth, minHeight: `${menuMinHeight}px` }]\"\n @scroll=\"containerProps.onScroll\"\n @keydown.up.prevent=\"moveHighlight(true)\"\n @keydown.down.prevent=\"moveHighlight(false)\"\n >\n <div\n v-bind=\"wrapperProps\"\n ref=\"menuRef\"\n >\n <RuiButton\n v-for=\"{ item, _index } in renderedData\"\n :key=\"getIdentifier(item)?.toString()\"\n :active=\"isActiveItem(item)\"\n :aria-selected=\"isActiveItem(item)\"\n :size=\"dense ? 'sm' : undefined\"\n tabindex=\"0\"\n variant=\"list\"\n :data-highlighted=\"highlightedIndex === _index\"\n :class=\"{\n [highlightedClass]: !isActiveItem(item) && highlightedIndex === _index,\n }\"\n @click=\"setValue(item)\"\n >\n <template #prepend>\n <slot\n name=\"item.prepend\"\n v-bind=\"{ disabled, item, active: isActiveItem(item) }\"\n />\n </template>\n <slot\n name=\"item\"\n v-bind=\"{ disabled, item, active: isActiveItem(item) }\"\n >\n {{ getText(item) }}\n </slot>\n <template #append>\n <slot\n name=\"item.append\"\n v-bind=\"{ disabled, item, active: isActiveItem(item) }\"\n />\n </template>\n </RuiButton>\n </div>\n </div>\n\n <div\n v-else-if=\"!hideNoData\"\n :style=\"{ width: `${width}px`, minWidth: menuWidth }\"\n :class=\"classNames?.menu ?? menuClass\"\n >\n <slot name=\"no-data\">\n <div\n v-if=\"!customValue\"\n class=\"p-4\"\n data-id=\"no-data\"\n >\n {{ noDataText }}\n </div>\n </slot>\n </div>\n </div>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RuiAutoComplete.js","names":[],"sources":["../../../../src/components/forms/auto-complete/RuiAutoComplete.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"TValue, TItem\">\nimport type { VueClassValue } from '@/types/class-value';\nimport RuiButton from '@/components/buttons/button/RuiButton.vue';\nimport RuiChip from '@/components/chips/RuiChip.vue';\nimport { autoCompleteStyles, type AutoCompleteVariant } from '@/components/forms/auto-complete/auto-complete-styles';\nimport RuiIcon from '@/components/icons/RuiIcon.vue';\nimport RuiMenu, { type MenuProps } from '@/components/overlays/menu/RuiMenu.vue';\nimport RuiProgress from '@/components/progress/RuiProgress.vue';\nimport {\n type KeyOfType,\n useDropdownMenu,\n useDropdownOptionProperty,\n} from '@/composables/dropdown-menu';\nimport {\n useAutoCompleteFocus,\n useAutoCompleteKeyboardNavigation,\n useAutoCompleteSearch,\n useAutoCompleteValue,\n} from '@/composables/forms/auto-complete';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs, getTextToken } from '@/utils/helpers';\nimport { isEqual } from '@/utils/is-equal';\nimport { cn } from '@/utils/tv';\n\nexport type AutoCompleteModelValue<TValue> =\n TValue extends Array<infer U> ? U[] : TValue | undefined;\n\nexport interface RuiAutoCompleteClassNames {\n root?: VueClassValue;\n label?: VueClassValue;\n menu?: VueClassValue;\n}\n\nexport interface AutoCompleteProps<TValue, TItem> {\n options?: TItem[];\n keyAttr?: KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>;\n textAttr?: keyof TItem;\n disabled?: boolean;\n loading?: boolean;\n readOnly?: boolean;\n dense?: boolean;\n clearable?: boolean;\n label?: string;\n menuOptions?: MenuProps;\n classNames?: RuiAutoCompleteClassNames;\n /** @deprecated Use `classNames.label` instead */\n labelClass?: string;\n /** @deprecated Use `classNames.menu` instead */\n menuClass?: string;\n prependWidth?: number;\n appendWidth?: number;\n itemHeight?: number;\n variant?: AutoCompleteVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n autoSelectFirst?: boolean;\n chips?: boolean;\n noFilter?: boolean;\n hideNoData?: boolean;\n noDataText?: string;\n filter?: (item: TItem, queryText: string) => boolean;\n hideSelected?: boolean;\n placeholder?: string;\n returnObject?: boolean;\n customValue?: boolean;\n hideCustomValue?: boolean;\n required?: boolean;\n hideSearchInput?: boolean;\n hideSelectionWrapper?: boolean;\n}\n\ndefineOptions({\n name: 'RuiAutoComplete',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<AutoCompleteModelValue<TValue>>({ required: true });\n\nconst searchInputModel = defineModel<string>('searchInput', { default: '' });\n\nconst {\n options = [],\n disabled = false,\n loading = false,\n readOnly = false,\n dense = false,\n clearable = false,\n hideDetails = false,\n chips = false,\n label = 'Select',\n menuOptions,\n classNames,\n labelClass,\n menuClass,\n variant = 'default',\n hint,\n keyAttr,\n textAttr,\n itemHeight,\n errorMessages = [],\n successMessages = [],\n autoSelectFirst = false,\n noFilter = false,\n hideNoData = false,\n noDataText = 'No data available',\n filter,\n hideSelected = false,\n placeholder = '',\n returnObject = false,\n customValue = false,\n hideCustomValue = false,\n required = false,\n hideSearchInput = false,\n hideSelectionWrapper = false,\n} = defineProps<AutoCompleteProps<TValue, TItem>>();\n\nconst slots = defineSlots<{\n 'activator'?: (props: {\n disabled: boolean;\n value: TItem[];\n variant: string;\n readOnly: boolean;\n attrs: Record<string, unknown>;\n open: boolean;\n hasError: boolean;\n hasSuccess: boolean;\n }) => any;\n 'activator.label'?: (props: { value: TItem[] }) => any;\n 'selection.prepend'?: (props: { index: number; item: TItem }) => any;\n 'selection'?: (props: { index: number; item: TItem; chipAttrs: Record<string, unknown> }) => any;\n 'item.prepend'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'item'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'item.append'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'no-data'?: () => any;\n}>();\n\nconst { getText, getIdentifier } = useDropdownOptionProperty<TValue, TItem>({\n keyAttr,\n textAttr,\n});\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuRef = useTemplateRef<HTMLDivElement>('menuRef');\nconst menuWrapperRef = useTemplateRef<HTMLDivElement>('menuWrapperRef');\n\nconst { focused: activatorFocusedWithin } = useFocusWithin(activator);\nconst { focused: menuWrapperFocusedWithin } = useFocusWithin(menuWrapperRef);\nconst { focused: searchInputFocused } = useFocus(textInput);\nconst { focused: activatorFocused } = useFocus(activator);\n\nconst {\n internalSearch,\n filteredOptions,\n justOpened,\n updateInternalSearch,\n textValueToProperValue,\n} = useAutoCompleteSearch<TItem>(\n () => options,\n searchInputModel,\n {\n keyAttr: () => keyAttr,\n textAttr: () => textAttr,\n noFilter: () => noFilter,\n filter: () => filter,\n customValue: () => customValue,\n hideCustomValue: () => hideCustomValue,\n returnObject: () => returnObject,\n },\n);\n\nconst isOpen = ref<boolean>(false);\n\n// Calculate multiple from modelValue directly to avoid circular dependency\nconst multiple = computed<boolean>(() => Array.isArray(get(modelValue)));\n\nconst shouldApplyValueAsSearch = computed<boolean>(\n () => !(slots.selection || get(multiple) || chips),\n);\n\nconst { value, setSelected } = useAutoCompleteValue<AutoCompleteModelValue<TValue>, TItem>(\n modelValue,\n () => options,\n {\n keyAttr: () => keyAttr,\n returnObject: () => returnObject,\n customValue: () => customValue,\n },\n {\n getIdentifier,\n getText,\n textValueToProperValue,\n shouldApplyValueAsSearch,\n isOpen,\n multiple,\n updateInternalSearch,\n },\n);\n\nconst resolvedItemHeight = itemHeight ?? (dense ? 30 : 48);\n\nconst {\n containerProps,\n wrapperProps,\n renderedData,\n menuWidth,\n isActiveItem,\n itemIndexInValue,\n highlightedIndex,\n moveHighlight,\n applyHighlighted,\n optionsWithSelectedHidden,\n userNavigated,\n} = useDropdownMenu<TValue, TItem>({\n itemHeight: resolvedItemHeight,\n keyAttr,\n textAttr,\n options: filteredOptions,\n dense: () => dense,\n value,\n menuRef,\n setValue,\n autoSelectFirst,\n hideSelected,\n isOpen,\n getText,\n getIdentifier,\n});\n\nconst {\n focusedValueIndex,\n moveSelectedValueHighlight,\n onEnter,\n onInputDeletePressed,\n onTab,\n setValueFocus,\n} = useAutoCompleteKeyboardNavigation<TItem>(\n {\n chips: () => chips,\n customValue: () => customValue,\n multiple,\n },\n {\n activator,\n applyHighlighted,\n clear,\n filteredOptions,\n getText,\n highlightedIndex,\n internalSearch,\n isOpen,\n removeValue: (item: TItem): void => { setValue(item); },\n searchInputFocused,\n setSearchAsValue,\n userNavigated,\n value,\n },\n);\n\nconst {\n anyFocused: focusAnyFocused,\n inputClass: focusInputClass,\n onActivatorFocused: focusOnActivatorFocused,\n onInputFocused: focusOnInputFocused,\n setInputFocus: focusSetInputFocus,\n} = useAutoCompleteFocus(\n {\n customValue: () => customValue,\n disabled: () => disabled,\n shouldApplyValueAsSearch,\n },\n {\n activatorFocused,\n activatorFocusedWithin,\n focusedValueIndex,\n internalSearch,\n isOpen,\n justOpened,\n menuWrapperFocusedWithin,\n searchInputFocused,\n setSearchAsValue,\n textInput,\n updateInternalSearch,\n },\n);\n\nconst menuMinHeight = computed<number>(\n () => Math.min(5, get(optionsWithSelectedHidden).length) * resolvedItemHeight,\n);\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst valueSet = computed<boolean>(() => get(value).length > 0);\n\nconst usedPlaceholder = computed<string>(() => {\n if (get(searchInputFocused))\n return placeholder;\n return '';\n});\n\nconst outlined = computed<boolean>(() => variant === 'outlined');\nconst float = computed<boolean>(() => (get(isOpen) || get(valueSet) || get(searchInputFocused)) && get(outlined));\n\nconst legendText = computed<string>(() => {\n if (!get(float) || !label)\n return '';\n return required ? `${label} ﹡` : label;\n});\n\nconst ui = computed<ReturnType<typeof autoCompleteStyles>>(() => autoCompleteStyles({\n filled: variant === 'filled',\n outlined: get(outlined),\n float: get(float),\n opened: get(isOpen),\n dense,\n disabled,\n readonly: readOnly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst highlightedClass = autoCompleteStyles({}).highlighted();\n\nfunction updateSearchInput(event: Event): void {\n const target = event.target;\n if (!(target instanceof HTMLInputElement))\n return;\n\n const value = target.value;\n set(isOpen, true);\n updateInternalSearch(value);\n set(justOpened, false);\n}\n\nasync function setValue(val: TItem, skipRefocused = false): Promise<void> {\n const isMultiple = get(multiple);\n\n if (isMultiple) {\n const newValue = [...get(value)];\n const indexInValue = itemIndexInValue(val);\n if (indexInValue === -1) {\n updateInternalSearch();\n newValue.push(val);\n }\n else {\n newValue.splice(indexInValue, 1);\n }\n set(value, newValue);\n }\n else {\n if (get(shouldApplyValueAsSearch))\n updateInternalSearch(getText(val));\n else updateInternalSearch();\n\n set(value, [val]);\n }\n\n if (!isMultiple) {\n if (!skipRefocused) {\n set(activatorFocused, true);\n get(activator)?.focus();\n await nextTick(() => {\n set(isOpen, false);\n });\n }\n else {\n set(isOpen, false);\n }\n }\n else if (!skipRefocused) {\n set(searchInputFocused, true);\n }\n}\n\nfunction setSearchAsValue(): void {\n const searchToBeValue = get(internalSearch);\n if (!searchToBeValue)\n return;\n\n const newValue: TItem = textValueToProperValue(searchToBeValue);\n setValue(newValue, true);\n}\n\nfunction clear(): void {\n updateInternalSearch();\n set(modelValue, (Array.isArray(get(modelValue)) ? [] : undefined) as AutoCompleteModelValue<TValue>);\n}\n\nfunction chipAttrs(item: TItem, index: number): Record<string, unknown> {\n return {\n 'data-index': index,\n 'data-value': getIdentifier(item),\n 'onKeydown': (event: KeyboardEvent): void => {\n const { key } = event;\n if (['Backspace', 'Delete'].includes(key)) {\n event.stopPropagation();\n event.preventDefault();\n setValue(item);\n }\n },\n 'onClick': (e: MouseEvent): void => {\n e.stopPropagation();\n setValueFocus(index);\n },\n 'onClick:close': (): void => {\n setValue(item);\n },\n };\n}\n\nfunction setSelectionRange(start: number, end: number): void {\n set(searchInputFocused, true);\n get(textInput)?.setSelectionRange?.(start, end);\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n\n// Optimize options watcher with shallow comparison first\nwatch(() => options, (curr, old) => {\n if (curr === old || customValue)\n return;\n\n // Only do deep comparison if reference changed\n if (isEqual(curr, old))\n return;\n\n setSelected(get(value));\n});\n\ndefineExpose({\n focus: focusSetInputFocus,\n setSelectionRange,\n});\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"{ ...getRootAttrs($attrs, []), ...menuOptions }\"\n :class=\"ui.wrapper({ class: cn($attrs.class) })\"\n placement=\"bottom-start\"\n :close-on-content-click=\"false\"\n :full-width=\"true\"\n :persist-on-activator-click=\"true\"\n :menu-class=\"[\n { hidden: optionsWithSelectedHidden.length === 0 && customValue && !slots['no-data'] },\n menuOptions?.menuClass,\n ]\"\n :error-messages=\"errorMessages\"\n :success-messages=\"successMessages\"\n :hint=\"hint\"\n :dense=\"dense\"\n :show-details=\"!hideDetails\"\n :disabled=\"disabled\"\n disable-auto-focus\n >\n <template #activator=\"{ attrs, open, hasError: slotHasError, hasSuccess: slotHasSuccess }\">\n <slot\n name=\"activator\"\n v-bind=\"{ disabled, value, variant, readOnly, attrs, open, hasError: slotHasError, hasSuccess: slotHasSuccess }\"\n >\n <div\n ref=\"activator\"\n :class=\"ui.activator({ class: cn(classNames?.label) ?? labelClass })\"\n v-bind=\"{\n ...getNonRootAttrs($attrs, ['onClick', 'class']),\n ...(readOnly ? {} : attrs),\n }\"\n role=\"combobox\"\n :aria-expanded=\"open\"\n :aria-disabled=\"disabled || undefined\"\n :aria-readonly=\"readOnly || undefined\"\n :aria-required=\"required || undefined\"\n :aria-busy=\"loading || undefined\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n :tabindex=\"disabled || readOnly ? -1 : 0\"\n @click=\"focusSetInputFocus()\"\n @focus=\"focusOnActivatorFocused()\"\n @keydown.enter=\"onEnter($event)\"\n @keydown.tab=\"onTab($event)\"\n @keydown.left=\"moveSelectedValueHighlight($event, false)\"\n @keydown.right=\"moveSelectedValueHighlight($event, true)\"\n @keydown.up.prevent=\"moveHighlight(true)\"\n @keydown.down.prevent=\"moveHighlight(false)\"\n @keydown.home.prevent=\"highlightedIndex = 0\"\n @keydown.end.prevent=\"highlightedIndex = optionsWithSelectedHidden.length - 1\"\n >\n <span\n v-if=\"outlined || (!valueSet && !searchInputFocused)\"\n :class=\"[\n ui.label(),\n { 'pr-2': !valueSet && !open && outlined },\n ]\"\n >\n <slot\n name=\"activator.label\"\n v-bind=\"{ value }\"\n >\n {{ label }}\n </slot>\n <span\n v-if=\"required\"\n :class=\"ui.required()\"\n >\n ﹡\n </span>\n </span>\n <div\n data-id=\"value\"\n :class=\"ui.value()\"\n >\n <template\n v-for=\"(item, i) in value\"\n :key=\"getIdentifier(item)\"\n >\n <RuiChip\n v-if=\"chips\"\n :key=\"getTextToken(getIdentifier(item))\"\n tabindex=\"-1\"\n :size=\"dense ? 'sm' : 'md'\"\n closeable\n :class=\"{ 'leading-3': dense }\"\n clickable\n v-bind=\"chipAttrs(item, i)\"\n >\n <div class=\"flex\">\n <slot\n name=\"selection.prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n <slot\n :index=\"i\"\n name=\"selection\"\n v-bind=\"{ item, chipAttrs: chipAttrs(item, i) }\"\n >\n {{ getText(item) }}\n </slot>\n </div>\n </RuiChip>\n <div\n v-else-if=\"\n multiple\n || (!searchInputFocused && (slots['selection.prepend'] || slots.selection))\n \"\n :class=\"hideSelectionWrapper ? 'contents' : 'flex'\"\n >\n <slot\n name=\"selection.prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n <slot\n v-if=\"multiple || slots.selection\"\n :index=\"i\"\n name=\"selection\"\n v-bind=\"{ item, chipAttrs: chipAttrs(item, i) }\"\n >\n {{ getText(item) }}\n </slot>\n </div>\n </template>\n <input\n ref=\"textInput\"\n :disabled=\"disabled\"\n :value=\"internalSearch\"\n class=\"bg-transparent outline-none\"\n type=\"text\"\n :placeholder=\"usedPlaceholder\"\n :class=\"[focusInputClass, { hidden: hideSearchInput }]\"\n :aria-invalid=\"hasError\"\n aria-autocomplete=\"list\"\n @keydown.delete=\"onInputDeletePressed()\"\n @input.stop=\"updateSearchInput($event)\"\n @focus=\"focusOnInputFocused()\"\n />\n </div>\n\n <RuiButton\n v-if=\"clearable && valueSet && !disabled\"\n variant=\"text\"\n icon\n size=\"sm\"\n tabindex=\"-1\"\n color=\"error\"\n data-id=\"clear\"\n :class=\"[\n ui.clear(),\n focusAnyFocused && '!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 <span\n :class=\"ui.iconWrapper()\"\n @click=\"arrowClicked($event)\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </span>\n\n <RuiProgress\n v-if=\"loading\"\n :class=\"ui.progress()\"\n color=\"primary\"\n thickness=\"3\"\n variant=\"indeterminate\"\n />\n </div>\n <fieldset\n v-if=\"outlined\"\n :class=\"ui.fieldset()\"\n >\n <legend :class=\"ui.legend()\">\n {{ legendText }}\n </legend>\n </fieldset>\n </slot>\n </template>\n <template #default=\"{ width }\">\n <div ref=\"menuWrapperRef\">\n <div\n v-if=\"optionsWithSelectedHidden.length > 0\"\n :ref=\"containerProps.ref\"\n :class=\"ui.menu({ class: cn(classNames?.menu) ?? menuClass })\"\n :style=\"[containerProps.style, { width: `${width}px`, minWidth: menuWidth, minHeight: `${menuMinHeight}px` }]\"\n @scroll=\"containerProps.onScroll\"\n @keydown.up.prevent=\"moveHighlight(true)\"\n @keydown.down.prevent=\"moveHighlight(false)\"\n >\n <div\n v-bind=\"wrapperProps\"\n ref=\"menuRef\"\n >\n <RuiButton\n v-for=\"{ item, _index } in renderedData\"\n :key=\"getIdentifier(item)?.toString()\"\n :active=\"isActiveItem(item)\"\n :aria-selected=\"isActiveItem(item)\"\n :size=\"dense ? 'sm' : undefined\"\n tabindex=\"0\"\n variant=\"list\"\n :data-highlighted=\"highlightedIndex === _index\"\n :class=\"{\n [highlightedClass]: !isActiveItem(item) && highlightedIndex === _index,\n }\"\n @click=\"setValue(item)\"\n >\n <template #prepend>\n <slot\n name=\"item.prepend\"\n v-bind=\"{ disabled, item, active: isActiveItem(item) }\"\n />\n </template>\n <slot\n name=\"item\"\n v-bind=\"{ disabled, item, active: isActiveItem(item) }\"\n >\n {{ getText(item) }}\n </slot>\n <template #append>\n <slot\n name=\"item.append\"\n v-bind=\"{ disabled, item, active: isActiveItem(item) }\"\n />\n </template>\n </RuiButton>\n </div>\n </div>\n\n <div\n v-else-if=\"!hideNoData\"\n :style=\"{ width: `${width}px`, minWidth: menuWidth }\"\n :class=\"classNames?.menu ?? menuClass\"\n >\n <slot name=\"no-data\">\n <div\n v-if=\"!customValue\"\n class=\"p-4\"\n data-id=\"no-data\"\n >\n {{ noDataText }}\n </div>\n </slot>\n </div>\n </div>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":""}
@@ -83,7 +83,7 @@ declare const __VLS_export: <TValue, TItem>(__VLS_props: NonNullable<Awaited<typ
83
83
  selection?: (props: {
84
84
  index: number;
85
85
  item: TItem;
86
- chipAttrs?: Record<string, unknown>;
86
+ chipAttrs: Record<string, unknown>;
87
87
  }) => any;
88
88
  'item.prepend'?: (props: {
89
89
  disabled: boolean;
@@ -343,10 +343,10 @@ var RuiAutoComplete_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ *
343
343
  modelValue: unref(isOpen),
344
344
  "onUpdate:modelValue": _cache[18] || (_cache[18] = ($event) => isRef(isOpen) ? isOpen.value = $event : null)
345
345
  }, {
346
- ...unref(getRootAttrs)(_ctx.$attrs),
346
+ ...unref(getRootAttrs)(_ctx.$attrs, []),
347
347
  ...__props.menuOptions
348
348
  }, {
349
- class: unref(ui).wrapper(),
349
+ class: unref(ui).wrapper({ class: unref(cn)(_ctx.$attrs.class) }),
350
350
  placement: "bottom-start",
351
351
  "close-on-content-click": false,
352
352
  "full-width": true,
@@ -418,7 +418,10 @@ var RuiAutoComplete_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ *
418
418
  class: { "leading-3": __props.dense },
419
419
  clickable: ""
420
420
  }, { ref_for: true }, chipAttrs(item, i)), {
421
- default: withCtx(() => [createElementVNode("div", _hoisted_2, [renderSlot(_ctx.$slots, "selection.prepend", mergeProps({ index: i }, { ref_for: true }, { item })), renderSlot(_ctx.$slots, "selection", mergeProps({ index: i }, { ref_for: true }, { item }), () => [createTextVNode(toDisplayString(unref(getText)(item)), 1)])])]),
421
+ default: withCtx(() => [createElementVNode("div", _hoisted_2, [renderSlot(_ctx.$slots, "selection.prepend", mergeProps({ index: i }, { ref_for: true }, { item })), renderSlot(_ctx.$slots, "selection", mergeProps({ index: i }, { ref_for: true }, {
422
+ item,
423
+ chipAttrs: chipAttrs(item, i)
424
+ }), () => [createTextVNode(toDisplayString(unref(getText)(item)), 1)])])]),
422
425
  _: 2
423
426
  }, 1040, ["size", "class"])) : unref(multiple) || !unref(searchInputFocused) && (slots["selection.prepend"] || slots.selection) ? (openBlock(), createElementBlock("div", {
424
427
  key: 1,