@rotki/ui-library 2.25.0 → 2.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +2 -0
  2. package/dist/components/date-time-picker/RuiDateTimePicker.js.map +1 -1
  3. package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js +25 -7
  4. package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  5. package/dist/components/date-time-picker/date-time-picker-styles.d.ts +6 -0
  6. package/dist/components/date-time-picker/segment-utils.d.ts +16 -1
  7. package/dist/components/date-time-picker/segment-utils.js +71 -14
  8. package/dist/components/date-time-picker/segment-utils.js.map +1 -1
  9. package/dist/components/date-time-picker/use-keyboard-handler.d.ts +2 -0
  10. package/dist/components/date-time-picker/use-keyboard-handler.js +10 -3
  11. package/dist/components/date-time-picker/use-keyboard-handler.js.map +1 -1
  12. package/dist/components/forms/auto-complete/RuiAutoComplete.js.map +1 -1
  13. package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js +1 -0
  14. package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
  15. package/dist/components/forms/auto-complete/auto-complete-styles.d.ts +6 -0
  16. package/dist/components/forms/category-picker/category-picker-styles.d.ts +6 -0
  17. package/dist/components/forms/select/RuiMenuSelect.js.map +1 -1
  18. package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js +1 -0
  19. package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  20. package/dist/components/forms/select/menu-select-styles.d.ts +6 -0
  21. package/dist/components/forms/text-input-styles.d.ts +3 -0
  22. package/dist/components/forms/text-input-styles.js +3 -1
  23. package/dist/components/forms/text-input-styles.js.map +1 -1
  24. package/dist/components/index.js +1 -1
  25. package/dist/components/tables/RuiDataTable.js.map +1 -1
  26. package/dist/components/tables/RuiDataTable.vue.d.ts +12 -1
  27. package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js +71 -14
  28. package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  29. package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js +1 -1
  30. package/dist/components/tables/RuiTableHead.js.map +1 -1
  31. package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js +38 -13
  32. package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js.map +1 -1
  33. package/dist/components/tables/RuiTablePagination.js.map +1 -1
  34. package/dist/components/tables/RuiTablePagination.vue.d.ts +3 -3
  35. package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js +65 -14
  36. package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  37. package/dist/components/tables/data-table/RuiDataTableBody.js.map +1 -1
  38. package/dist/components/tables/data-table/RuiDataTableBody.vue.d.ts +7 -1
  39. package/dist/components/tables/data-table/RuiDataTableBody.vue_vue_type_script_setup_true_lang.js +45 -9
  40. package/dist/components/tables/data-table/RuiDataTableBody.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/components/tables/data-table/RuiDataTableCell.js.map +1 -1
  42. package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js +13 -2
  43. package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  44. package/dist/components/tables/data-table/RuiDataTableErrorRow.js +7 -0
  45. package/dist/components/tables/data-table/RuiDataTableErrorRow.js.map +1 -0
  46. package/dist/components/tables/data-table/RuiDataTableErrorRow.vue.d.ts +21 -0
  47. package/dist/components/tables/data-table/RuiDataTableErrorRow.vue_vue_type_script_setup_true_lang.js +40 -0
  48. package/dist/components/tables/data-table/RuiDataTableErrorRow.vue_vue_type_script_setup_true_lang.js.map +1 -0
  49. package/dist/components/tables/data-table/RuiDataTableExpandedRow.js.map +1 -1
  50. package/dist/components/tables/data-table/RuiDataTableExpandedRow.vue_vue_type_script_setup_true_lang.js +12 -1
  51. package/dist/components/tables/data-table/RuiDataTableExpandedRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  52. package/dist/components/tables/data-table/RuiDataTableGroupRow.js.map +1 -1
  53. package/dist/components/tables/data-table/RuiDataTableGroupRow.vue_vue_type_script_setup_true_lang.js +52 -20
  54. package/dist/components/tables/data-table/RuiDataTableGroupRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  55. package/dist/components/tables/data-table/RuiDataTableRow.js.map +1 -1
  56. package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js +29 -14
  57. package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  58. package/dist/components/tables/data-table/context.d.ts +10 -0
  59. package/dist/components/tables/data-table/context.js +2 -0
  60. package/dist/components/tables/data-table/context.js.map +1 -1
  61. package/dist/components/tables/data-table-styles.d.ts +15 -9
  62. package/dist/components/tables/data-table-styles.js +28 -5
  63. package/dist/components/tables/data-table-styles.js.map +1 -1
  64. package/dist/components/tables/table-props.d.ts +1 -2
  65. package/dist/components/tables/table-props.js +2 -10
  66. package/dist/components/tables/table-props.js.map +1 -1
  67. package/dist/components/tables/use-pagination-navigation.js +1 -1
  68. package/dist/components/tables/use-pagination-navigation.js.map +1 -1
  69. package/dist/i18n/keys.d.ts +1 -0
  70. package/dist/i18n/keys.js +1 -0
  71. package/dist/i18n/keys.js.map +1 -1
  72. package/dist/index.js +1 -1
  73. package/dist/library-icons.json +1 -1
  74. package/dist/style.css +120 -38
  75. package/dist/web-types.json +139 -3
  76. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"RuiMenuSelect.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../../src/components/forms/select/RuiMenuSelect.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 { menuSelectStyles, type MenuSelectVariant } from '@/components/forms/select/menu-select-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 { type KeyOfType, useDropdownMenu } from '@/composables/dropdown-menu';\nimport { type FloatingOptions, Placement } from '@/composables/floating';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs } from '@/utils/helpers';\nimport { cn } from '@/utils/tv';\n\nexport interface RuiMenuSelectClassNames {\n root?: VueClassValue;\n label?: VueClassValue;\n menu?: VueClassValue;\n option?: VueClassValue;\n}\n\nexport interface MenuSelectProps<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?: RuiMenuSelectClassNames;\n /** @deprecated Use `classNames.label` instead */\n labelClass?: string;\n /** @deprecated Use `classNames.menu` instead */\n menuClass?: string;\n /** @deprecated Use `classNames.option` instead */\n optionClass?: string;\n prependWidth?: number;\n appendWidth?: number;\n itemHeight?: number;\n variant?: MenuSelectVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n autoSelectFirst?: boolean;\n hideNoData?: boolean;\n noDataText?: string;\n required?: boolean;\n}\n\ndefineOptions({\n name: 'RuiMenuSelect',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<TValue | undefined>({ required: true });\n\nconst {\n options,\n disabled = false,\n loading = false,\n readOnly = false,\n dense = false,\n clearable = false,\n hideDetails = false,\n label = 'Select',\n menuOptions,\n classNames,\n labelClass,\n menuClass,\n variant = 'default',\n hint,\n keyAttr,\n textAttr,\n itemHeight,\n prependWidth,\n appendWidth,\n errorMessages = [],\n successMessages = [],\n autoSelectFirst = false,\n hideNoData = false,\n noDataText = 'No data available',\n required = false,\n} = defineProps<MenuSelectProps<TValue, TItem>>();\n\ndefineSlots<{\n 'activator'?: (props: {\n disabled: boolean;\n value: TItem | undefined;\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 | undefined }) => any;\n 'selection.prepend'?: (props: { item: TItem }) => any;\n 'selection'?: (props: { item: TItem }) => 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 menuRef = useTemplateRef<HTMLDivElement>('menuRef');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst { focused } = useFocus(activator);\nconst isHovered = ref<boolean>(false);\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst value = computed<TItem | undefined>({\n get: () => {\n const value = get(modelValue);\n if (keyAttr)\n return options.find(option => option[keyAttr] === value);\n return value as unknown as TItem;\n },\n set: (selected?: TItem) => {\n const selection = keyAttr && selected ? selected[keyAttr] : selected;\n set(modelValue, selection as TValue);\n },\n});\n\nfunction setValue(val: TItem): void {\n set(value, val);\n set(focused, true);\n}\n\nconst {\n containerProps,\n wrapperProps,\n renderedData,\n isOpen,\n menuWidth,\n getText,\n getIdentifier,\n isActiveItem,\n modelHighlightedIndex,\n moveHighlight,\n applyHighlighted,\n valueKey,\n} = useDropdownMenu<TValue, TItem>({\n itemHeight: itemHeight ?? (dense ? 30 : 48),\n keyAttr,\n textAttr,\n options: () => options,\n dense: () => dense,\n value,\n menuRef,\n disabled: () => disabled,\n autoSelectFirst,\n setValue,\n prependWidth,\n appendWidth,\n});\n\nconst outlined = computed<boolean>(() => variant === 'outlined');\nconst float = computed<boolean>(() => (get(isOpen) || !!get(value)) && 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 menuSelectStyles>>(() => menuSelectStyles({\n filled: variant === 'filled',\n outlined: get(outlined),\n float: get(float),\n opened: get(isOpen),\n hovered: get(isHovered),\n dense,\n disabled,\n readonly: readOnly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst highlightedClass = menuSelectStyles({}).highlighted();\n\nfunction clear(): void {\n set(modelValue, undefined);\n}\n\nconst menuFloatingOptions = computed<FloatingOptions>(() => ({\n placement: Placement.bottomStart,\n ...menuOptions?.options,\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 :options=\"menuFloatingOptions\"\n close-on-content-click\n full-width\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 <button\n ref=\"activator\"\n :disabled=\"disabled\"\n :aria-disabled=\"disabled\"\n :aria-expanded=\"isOpen\"\n :aria-readonly=\"readOnly || undefined\"\n :aria-required=\"required || undefined\"\n :aria-busy=\"loading || undefined\"\n type=\"button\"\n :tabindex=\"disabled || readOnly ? -1 : 0\"\n :class=\"ui.activator({ class: cn(classNames?.label) ?? labelClass })\"\n v-bind=\"{\n ...getNonRootAttrs($attrs),\n ...(readOnly ? {} : attrs),\n }\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n @mouseenter=\"isHovered = true\"\n @mouseleave=\"isHovered = false\"\n @keydown.up.prevent=\"moveHighlight(true)\"\n @keydown.down.prevent=\"moveHighlight(false)\"\n @keydown.enter.prevent=\"applyHighlighted()\"\n @keydown.space.prevent=\"applyHighlighted()\"\n @keydown.home.prevent=\"modelHighlightedIndex = 0\"\n @keydown.end.prevent=\"modelHighlightedIndex = options.length - 1\"\n >\n <span\n v-if=\"outlined || !value\"\n :class=\"[\n ui.label(),\n { 'pr-2': !value && !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 <span\n v-if=\"value\"\n :class=\"ui.value()\"\n >\n <slot\n name=\"selection.prepend\"\n v-bind=\"{ item: value }\"\n />\n <slot\n name=\"selection\"\n v-bind=\"{ item: value }\"\n >\n {{ getText(value) }}\n </slot>\n </span>\n\n <span\n v-if=\"clearable && value && !disabled\"\n data-id=\"clear\"\n :class=\"[ui.clear(), focused && '!visible', { 'mr-2': !dense }]\"\n @click.stop.prevent=\"clear()\"\n >\n <RuiIcon\n color=\"error\"\n name=\"lu-x\"\n size=\"18\"\n />\n </span>\n\n <span :class=\"ui.iconWrapper()\">\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 </button>\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 <input\n :value=\"valueKey\"\n class=\"hidden\"\n type=\"hidden\"\n />\n </template>\n <template #default=\"{ width }\">\n <div\n v-if=\"options.length > 0\"\n :ref=\"containerProps.ref\"\n :class=\"ui.menu({ class: cn(classNames?.menu) ?? menuClass })\"\n :style=\"[containerProps.style, { width: `${width}px`, minWidth: menuWidth }]\"\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)\"\n :active=\"isActiveItem(item)\"\n :aria-selected=\"isActiveItem(item)\"\n :size=\"dense ? 'sm' : undefined\"\n variant=\"list\"\n :data-highlighted=\"modelHighlightedIndex === _index\"\n :class=\"{\n [highlightedClass]: !isActiveItem(item) && modelHighlightedIndex === _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 data-id=\"no-data\"\n :style=\"{ width: `${width}px`, minWidth: menuWidth }\"\n :class=\"classNames?.menu ?? menuClass\"\n >\n <slot name=\"no-data\">\n <div class=\"p-4\">\n {{ noDataText }}\n </div>\n </slot>\n </div>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"RuiMenuSelect.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../../src/components/forms/select/RuiMenuSelect.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 { menuSelectStyles, type MenuSelectVariant } from '@/components/forms/select/menu-select-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 { type KeyOfType, useDropdownMenu } from '@/composables/dropdown-menu';\nimport { type FloatingOptions, Placement } from '@/composables/floating';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs } from '@/utils/helpers';\nimport { cn } from '@/utils/tv';\n\nexport interface RuiMenuSelectClassNames {\n root?: VueClassValue;\n label?: VueClassValue;\n menu?: VueClassValue;\n option?: VueClassValue;\n}\n\nexport interface MenuSelectProps<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?: RuiMenuSelectClassNames;\n /** @deprecated Use `classNames.label` instead */\n labelClass?: string;\n /** @deprecated Use `classNames.menu` instead */\n menuClass?: string;\n /** @deprecated Use `classNames.option` instead */\n optionClass?: string;\n prependWidth?: number;\n appendWidth?: number;\n itemHeight?: number;\n variant?: MenuSelectVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n autoSelectFirst?: boolean;\n hideNoData?: boolean;\n noDataText?: string;\n required?: boolean;\n}\n\ndefineOptions({\n name: 'RuiMenuSelect',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<TValue | undefined>({ required: true });\n\nconst {\n options,\n disabled = false,\n loading = false,\n readOnly = false,\n dense = false,\n clearable = false,\n hideDetails = false,\n label = 'Select',\n menuOptions,\n classNames,\n labelClass,\n menuClass,\n variant = 'default',\n hint,\n keyAttr,\n textAttr,\n itemHeight,\n prependWidth,\n appendWidth,\n errorMessages = [],\n successMessages = [],\n autoSelectFirst = false,\n hideNoData = false,\n noDataText = 'No data available',\n required = false,\n} = defineProps<MenuSelectProps<TValue, TItem>>();\n\ndefineSlots<{\n 'activator'?: (props: {\n disabled: boolean;\n value: TItem | undefined;\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 | undefined }) => any;\n 'selection.prepend'?: (props: { item: TItem }) => any;\n 'selection'?: (props: { item: TItem }) => 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 menuRef = useTemplateRef<HTMLDivElement>('menuRef');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst { focused } = useFocus(activator);\nconst isHovered = ref<boolean>(false);\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst value = computed<TItem | undefined>({\n get: () => {\n const value = get(modelValue);\n if (keyAttr)\n return options.find(option => option[keyAttr] === value);\n return value as unknown as TItem;\n },\n set: (selected?: TItem) => {\n const selection = keyAttr && selected ? selected[keyAttr] : selected;\n set(modelValue, selection as TValue);\n },\n});\n\nfunction setValue(val: TItem): void {\n set(value, val);\n set(focused, true);\n}\n\nconst {\n containerProps,\n wrapperProps,\n renderedData,\n isOpen,\n menuWidth,\n getText,\n getIdentifier,\n isActiveItem,\n modelHighlightedIndex,\n moveHighlight,\n applyHighlighted,\n valueKey,\n} = useDropdownMenu<TValue, TItem>({\n itemHeight: itemHeight ?? (dense ? 30 : 48),\n keyAttr,\n textAttr,\n options: () => options,\n dense: () => dense,\n value,\n menuRef,\n disabled: () => disabled,\n autoSelectFirst,\n setValue,\n prependWidth,\n appendWidth,\n});\n\nconst outlined = computed<boolean>(() => variant === 'outlined');\nconst float = computed<boolean>(() => (get(isOpen) || !!get(value)) && 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 menuSelectStyles>>(() => menuSelectStyles({\n filled: variant === 'filled',\n outlined: get(outlined),\n float: get(float),\n showLabel: !!get(legendText),\n opened: get(isOpen),\n hovered: get(isHovered),\n dense,\n disabled,\n readonly: readOnly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst highlightedClass = menuSelectStyles({}).highlighted();\n\nfunction clear(): void {\n set(modelValue, undefined);\n}\n\nconst menuFloatingOptions = computed<FloatingOptions>(() => ({\n placement: Placement.bottomStart,\n ...menuOptions?.options,\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 :options=\"menuFloatingOptions\"\n close-on-content-click\n full-width\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 <button\n ref=\"activator\"\n :disabled=\"disabled\"\n :aria-disabled=\"disabled\"\n :aria-expanded=\"isOpen\"\n :aria-readonly=\"readOnly || undefined\"\n :aria-required=\"required || undefined\"\n :aria-busy=\"loading || undefined\"\n type=\"button\"\n :tabindex=\"disabled || readOnly ? -1 : 0\"\n :class=\"ui.activator({ class: cn(classNames?.label) ?? labelClass })\"\n v-bind=\"{\n ...getNonRootAttrs($attrs),\n ...(readOnly ? {} : attrs),\n }\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n @mouseenter=\"isHovered = true\"\n @mouseleave=\"isHovered = false\"\n @keydown.up.prevent=\"moveHighlight(true)\"\n @keydown.down.prevent=\"moveHighlight(false)\"\n @keydown.enter.prevent=\"applyHighlighted()\"\n @keydown.space.prevent=\"applyHighlighted()\"\n @keydown.home.prevent=\"modelHighlightedIndex = 0\"\n @keydown.end.prevent=\"modelHighlightedIndex = options.length - 1\"\n >\n <span\n v-if=\"outlined || !value\"\n :class=\"[\n ui.label(),\n { 'pr-2': !value && !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 <span\n v-if=\"value\"\n :class=\"ui.value()\"\n >\n <slot\n name=\"selection.prepend\"\n v-bind=\"{ item: value }\"\n />\n <slot\n name=\"selection\"\n v-bind=\"{ item: value }\"\n >\n {{ getText(value) }}\n </slot>\n </span>\n\n <span\n v-if=\"clearable && value && !disabled\"\n data-id=\"clear\"\n :class=\"[ui.clear(), focused && '!visible', { 'mr-2': !dense }]\"\n @click.stop.prevent=\"clear()\"\n >\n <RuiIcon\n color=\"error\"\n name=\"lu-x\"\n size=\"18\"\n />\n </span>\n\n <span :class=\"ui.iconWrapper()\">\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 </button>\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 <input\n :value=\"valueKey\"\n class=\"hidden\"\n type=\"hidden\"\n />\n </template>\n <template #default=\"{ width }\">\n <div\n v-if=\"options.length > 0\"\n :ref=\"containerProps.ref\"\n :class=\"ui.menu({ class: cn(classNames?.menu) ?? menuClass })\"\n :style=\"[containerProps.style, { width: `${width}px`, minWidth: menuWidth }]\"\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)\"\n :active=\"isActiveItem(item)\"\n :aria-selected=\"isActiveItem(item)\"\n :size=\"dense ? 'sm' : undefined\"\n variant=\"list\"\n :data-highlighted=\"modelHighlightedIndex === _index\"\n :class=\"{\n [highlightedClass]: !isActiveItem(item) && modelHighlightedIndex === _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 data-id=\"no-data\"\n :style=\"{ width: `${width}px`, minWidth: menuWidth }\"\n :class=\"classNames?.menu ?? menuClass\"\n >\n <slot name=\"no-data\">\n <div class=\"p-4\">\n {{ noDataText }}\n </div>\n </slot>\n </div>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":"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"}
@@ -59,6 +59,9 @@ export declare const menuSelectStyles: import("tailwind-variants").TVReturnType<
59
59
  hovered: {
60
60
  true: {};
61
61
  };
62
+ showLabel: {
63
+ true: {};
64
+ };
62
65
  } & {
63
66
  focused: {
64
67
  true: {
@@ -173,6 +176,9 @@ export declare const menuSelectStyles: import("tailwind-variants").TVReturnType<
173
176
  hovered: {
174
177
  true: {};
175
178
  };
179
+ showLabel: {
180
+ true: {};
181
+ };
176
182
  }, {
177
183
  fieldset: string;
178
184
  legend: string;
@@ -243,6 +243,9 @@ export declare const activatorStyles: import("tailwind-variants").TVReturnType<{
243
243
  hovered: {
244
244
  true: {};
245
245
  };
246
+ showLabel: {
247
+ true: {};
248
+ };
246
249
  }, {
247
250
  fieldset: string;
248
251
  legend: string;
@@ -179,11 +179,13 @@ var activatorStyles = tv({
179
179
  active: { true: { highlighted: "!bg-rui-grey-300 dark:!bg-rui-grey-700" } },
180
180
  hasError: { true: {} },
181
181
  hasSuccess: { true: {} },
182
- hovered: { true: {} }
182
+ hovered: { true: {} },
183
+ showLabel: { true: {} }
183
184
  },
184
185
  compoundVariants: [
185
186
  {
186
187
  float: true,
188
+ showLabel: true,
187
189
  class: { legend: "px-2" }
188
190
  },
189
191
  {
@@ -1 +1 @@
1
- {"version":3,"file":"text-input-styles.js","names":[],"sources":["../../../src/components/forms/text-input-styles.ts"],"sourcesContent":["import { tv } from '@/utils/tv';\n\nexport const TextInputVariant = {\n default: 'default',\n filled: 'filled',\n outlined: 'outlined',\n} as const;\n\nexport type TextInputVariant = (typeof TextInputVariant)[keyof typeof TextInputVariant];\n\n/**\n * Shared underline pseudo-element classes for default and filled variants.\n * Used by TextField and TextArea label slots.\n */\nexport const underlinePseudo = [\n 'border-b border-black/[0.42] dark:border-white/[0.42]',\n 'after:content-[\\'\\'] after:absolute after:bottom-0 after:left-0 after:block after:w-full',\n 'after:scale-x-0 after:border-b-2 after:mb-[-1px] after:transition-transform after:duration-300',\n 'after:border-black dark:after:border-white',\n].join(' ');\n\n/**\n * Shared base tv() for all text-input-family components.\n * Extended by: TextField, TextArea, MenuSelect, AutoComplete, DateTimePicker.\n *\n * Provides the common core: floating label, fieldset/legend (outlined),\n * validation colors, disabled state, dark mode, and focus color.\n *\n * ## State approach (JS-driven for all 5 components)\n *\n * - `focused`: from useFocus (Group A) or computed from isOpen (Group B)\n * - `active`: focused || hasValue — drives label float\n * - `hovered`: mouseenter/mouseleave ref\n *\n * ## Legend content\n *\n * The legend's `after:content` uses CSS variable `--rui-legend`.\n * Bind via `:style=\"\\{ '--rui-legend': labelWithQuote \\}\"` on the legend element.\n *\n * ## Compositing\n *\n * The fieldset is forced onto its own GPU layer so the focused border is\n * rasterized on integer pixel boundaries. Without it, at fractional\n * y-coordinates with a non-integer device pixel ratio such as 1.25, Chromium\n * anti-aliases the 1.6-2px focus border across two physical pixel rows behind\n * the floated label, which shows up as two thin lines crossing it.\n */\nexport const textInputBase = tv({\n slots: {\n label: 'text-rui-text-secondary transition-all duration-75',\n fieldset: [\n 'absolute w-full min-w-0 h-[calc(100%+0.5rem)] top-0 left-0',\n 'rounded pointer-events-none px-2 transition-all -mt-2',\n 'border border-black/[0.23]',\n 'dark:border-white/[0.23]',\n // translateZ(0) promotes this to its own layer, whose raster snaps to integer pixels\n 'transform-gpu',\n ].join(' '),\n legend: 'invisible text-[0.75rem] truncate [max-width:calc(100%-1rem)] leading-[0]',\n },\n variants: {\n focused: {\n true: {\n fieldset: '!border-2',\n },\n },\n hovered: {\n true: {\n fieldset: 'border-black dark:border-white',\n },\n },\n disabled: {\n true: {\n fieldset: '!border-dotted !border-black/[0.23] dark:!border-white/[0.23]',\n label: 'text-rui-text-disabled',\n },\n },\n active: {\n true: {},\n },\n showLabel: {\n true: {},\n },\n validation: {\n error: {\n fieldset: '!border-rui-error',\n label: '!text-rui-error',\n },\n success: {\n fieldset: '!border-rui-success',\n label: '!text-rui-success',\n },\n },\n color: {\n primary: {},\n secondary: {},\n error: {},\n warning: {},\n info: {},\n success: {},\n },\n },\n compoundVariants: [\n // Legend padding only when label is floated (active + has label)\n { showLabel: true, active: true, class: { legend: 'px-2' } },\n // Focused + color → fieldset border takes the color\n { focused: true, color: 'primary', class: { fieldset: '!border-rui-primary' } },\n { focused: true, color: 'secondary', class: { fieldset: '!border-rui-secondary' } },\n { focused: true, color: 'error', class: { fieldset: '!border-rui-error' } },\n { focused: true, color: 'warning', class: { fieldset: '!border-rui-warning' } },\n { focused: true, color: 'info', class: { fieldset: '!border-rui-info' } },\n { focused: true, color: 'success', class: { fieldset: '!border-rui-success' } },\n ],\n defaultVariants: {\n color: 'primary',\n },\n});\n\n/**\n * Shared tv() styles for the activator-based components (Group B):\n * MenuSelect, AutoComplete, DateTimePicker.\n *\n * IMPORTANT: tv() extend does NOT deduplicate conflicting Tailwind classes.\n * Never put a class in the base slot that a variant needs to override.\n *\n * State-driven via JS refs: `outlined`, `float` (open || hasValue),\n * `opened`, `disabled`, `readonly`, `dense`.\n *\n * The wrapper is `w-full inline-flex flex-col` so an activator fills its\n * parent whatever the context. A consumer's own width utility would normally\n * collide with `w-full` on the same element and lose to cascade order, so\n * RuiAutoComplete, RuiMenuSelect and RuiDateTimePicker route consumer classes\n * through `ui.wrapper(\\{ class \\})`, where twMerge deduplicates them and the\n * consumer's width wins.\n */\nexport const activatorStyles = tv({\n extend: textInputBase,\n slots: {\n // Re-declare base slots for type inference\n fieldset: '',\n legend: '',\n wrapper: 'w-full inline-flex flex-col',\n activator: [\n 'group relative inline-flex items-center w-full',\n 'outline-none focus:outline-none focus-within:outline-none cursor-pointer',\n 'min-h-14 pl-4 py-2 pr-8 rounded',\n 'm-0 transition-all text-body-1 text-left',\n 'dark:text-rui-text',\n ].join(' '),\n label: [\n 'text-rui-text-secondary [max-width:calc(100%-2.5rem)]',\n 'block truncate transition-all duration-75',\n ].join(' '),\n value: 'w-full block truncate transition-all duration-75',\n clear: 'ml-auto shrink-0 invisible group-hover:!visible',\n menu: 'overflow-y-auto max-h-60 min-w-[2.5rem]',\n highlighted: '!bg-rui-grey-200 dark:!bg-rui-grey-800',\n progress: 'absolute left-0 bottom-0 w-full',\n icon: 'text-rui-text transition',\n iconWrapper: 'flex items-center justify-end absolute right-3 top-px bottom-0',\n required: 'text-rui-error',\n },\n variants: {\n dense: {\n true: {\n activator: 'py-1.5 min-h-10',\n },\n },\n disabled: {\n true: {\n activator: 'opacity-65 text-rui-text-disabled active:text-rui-text-disabled cursor-default pointer-events-none',\n },\n },\n readonly: {\n true: {\n activator: 'opacity-80 pointer-events-none cursor-default bg-gray-50 dark:bg-white/10',\n },\n },\n filled: {\n true: {\n activator: [\n '!rounded-t !rounded-b-none !bg-black/[0.06]',\n '!hover:bg-black/[0.09] !focus-within:bg-black/[0.09]',\n 'dark:!bg-white/[0.09]',\n 'dark:!hover:bg-white/[0.13] dark:!focus-within:bg-white/[0.13]',\n underlinePseudo,\n ].join(' '),\n },\n },\n outlined: {\n true: {\n activator: 'bg-white dark:bg-transparent border-none hover:border-none',\n label: 'absolute',\n fieldset: '!mt-0 !h-full',\n },\n false: {\n activator: `!rounded-none ${underlinePseudo}`,\n },\n },\n float: {\n true: {\n label: '-translate-y-2 top-0 text-[0.75rem] leading-4',\n },\n },\n opened: {\n true: {\n icon: 'rotate-180',\n },\n },\n active: {\n true: {\n highlighted: '!bg-rui-grey-300 dark:!bg-rui-grey-700',\n },\n },\n hasError: {\n true: {},\n },\n hasSuccess: {\n true: {},\n },\n // Re-declare for type inference — actual styles are in textInputBase\n hovered: { true: {} },\n },\n compoundVariants: [\n // Legend padding when label is floated\n { float: true, class: { legend: 'px-2' } },\n\n // Non-outlined + opened → underline scales up\n { outlined: false, opened: true, class: { activator: 'after:scale-x-100 after:border-rui-primary' } },\n\n // Non-outlined + error → underline color\n { outlined: false, hasError: true, class: { activator: 'after:scale-x-100 after:!border-rui-error' } },\n\n // Non-outlined + success → underline color\n { outlined: false, hasSuccess: true, class: { activator: 'after:scale-x-100 after:!border-rui-success' } },\n\n // Non-outlined + disabled in dark mode\n { outlined: false, disabled: true, class: { activator: 'dark:bg-white/10' } },\n\n // Filled + disabled\n { filled: true, disabled: true, class: { activator: 'bg-black/[0.03] dark:bg-white/[0.05]' } },\n\n // Outlined + hovered → fieldset border\n { outlined: true, hovered: true, class: { fieldset: 'border-black dark:border-white' } },\n\n // Outlined + opened/focused → primary border\n { outlined: true, opened: true, class: {\n fieldset: '!border-rui-primary !border-2',\n label: 'text-rui-primary',\n } },\n\n // Outlined + error → fieldset + label\n { outlined: true, hasError: true, class: {\n fieldset: '!border-rui-error',\n label: '!text-rui-error',\n } },\n // Outlined + success → fieldset + label\n { outlined: true, hasSuccess: true, class: {\n fieldset: '!border-rui-success',\n label: '!text-rui-success',\n } },\n\n // Outlined + disabled → dotted fieldset\n { outlined: true, disabled: true, class: {\n fieldset: '!border-dotted !border-black/[0.23] dark:!border-white/[0.23]',\n } },\n\n // Float + opened → label color\n { float: true, opened: true, class: { label: 'text-rui-primary' } },\n ],\n defaultVariants: {\n filled: false,\n outlined: false,\n dense: false,\n disabled: false,\n readonly: false,\n float: false,\n opened: false,\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"text-input-styles.js","names":[],"sources":["../../../src/components/forms/text-input-styles.ts"],"sourcesContent":["import { tv } from '@/utils/tv';\n\nexport const TextInputVariant = {\n default: 'default',\n filled: 'filled',\n outlined: 'outlined',\n} as const;\n\nexport type TextInputVariant = (typeof TextInputVariant)[keyof typeof TextInputVariant];\n\n/**\n * Shared underline pseudo-element classes for default and filled variants.\n * Used by TextField and TextArea label slots.\n */\nexport const underlinePseudo = [\n 'border-b border-black/[0.42] dark:border-white/[0.42]',\n 'after:content-[\\'\\'] after:absolute after:bottom-0 after:left-0 after:block after:w-full',\n 'after:scale-x-0 after:border-b-2 after:mb-[-1px] after:transition-transform after:duration-300',\n 'after:border-black dark:after:border-white',\n].join(' ');\n\n/**\n * Shared base tv() for all text-input-family components.\n * Extended by: TextField, TextArea, MenuSelect, AutoComplete, DateTimePicker.\n *\n * Provides the common core: floating label, fieldset/legend (outlined),\n * validation colors, disabled state, dark mode, and focus color.\n *\n * ## State approach (JS-driven for all 5 components)\n *\n * - `focused`: from useFocus (Group A) or computed from isOpen (Group B)\n * - `active`: focused || hasValue — drives label float\n * - `hovered`: mouseenter/mouseleave ref\n *\n * ## Legend content\n *\n * The legend's `after:content` uses CSS variable `--rui-legend`.\n * Bind via `:style=\"\\{ '--rui-legend': labelWithQuote \\}\"` on the legend element.\n *\n * ## Compositing\n *\n * The fieldset is forced onto its own GPU layer so the focused border is\n * rasterized on integer pixel boundaries. Without it, at fractional\n * y-coordinates with a non-integer device pixel ratio such as 1.25, Chromium\n * anti-aliases the 1.6-2px focus border across two physical pixel rows behind\n * the floated label, which shows up as two thin lines crossing it.\n */\nexport const textInputBase = tv({\n slots: {\n label: 'text-rui-text-secondary transition-all duration-75',\n fieldset: [\n 'absolute w-full min-w-0 h-[calc(100%+0.5rem)] top-0 left-0',\n 'rounded pointer-events-none px-2 transition-all -mt-2',\n 'border border-black/[0.23]',\n 'dark:border-white/[0.23]',\n // translateZ(0) promotes this to its own layer, whose raster snaps to integer pixels\n 'transform-gpu',\n ].join(' '),\n legend: 'invisible text-[0.75rem] truncate [max-width:calc(100%-1rem)] leading-[0]',\n },\n variants: {\n focused: {\n true: {\n fieldset: '!border-2',\n },\n },\n hovered: {\n true: {\n fieldset: 'border-black dark:border-white',\n },\n },\n disabled: {\n true: {\n fieldset: '!border-dotted !border-black/[0.23] dark:!border-white/[0.23]',\n label: 'text-rui-text-disabled',\n },\n },\n active: {\n true: {},\n },\n showLabel: {\n true: {},\n },\n validation: {\n error: {\n fieldset: '!border-rui-error',\n label: '!text-rui-error',\n },\n success: {\n fieldset: '!border-rui-success',\n label: '!text-rui-success',\n },\n },\n color: {\n primary: {},\n secondary: {},\n error: {},\n warning: {},\n info: {},\n success: {},\n },\n },\n compoundVariants: [\n // Legend padding only when label is floated (active + has label)\n { showLabel: true, active: true, class: { legend: 'px-2' } },\n // Focused + color → fieldset border takes the color\n { focused: true, color: 'primary', class: { fieldset: '!border-rui-primary' } },\n { focused: true, color: 'secondary', class: { fieldset: '!border-rui-secondary' } },\n { focused: true, color: 'error', class: { fieldset: '!border-rui-error' } },\n { focused: true, color: 'warning', class: { fieldset: '!border-rui-warning' } },\n { focused: true, color: 'info', class: { fieldset: '!border-rui-info' } },\n { focused: true, color: 'success', class: { fieldset: '!border-rui-success' } },\n ],\n defaultVariants: {\n color: 'primary',\n },\n});\n\n/**\n * Shared tv() styles for the activator-based components (Group B):\n * MenuSelect, AutoComplete, DateTimePicker.\n *\n * IMPORTANT: tv() extend does NOT deduplicate conflicting Tailwind classes.\n * Never put a class in the base slot that a variant needs to override.\n *\n * State-driven via JS refs: `outlined`, `float` (open || hasValue),\n * `opened`, `disabled`, `readonly`, `dense`.\n *\n * The wrapper is `w-full inline-flex flex-col` so an activator fills its\n * parent whatever the context. A consumer's own width utility would normally\n * collide with `w-full` on the same element and lose to cascade order, so\n * RuiAutoComplete, RuiMenuSelect and RuiDateTimePicker route consumer classes\n * through `ui.wrapper(\\{ class \\})`, where twMerge deduplicates them and the\n * consumer's width wins.\n */\nexport const activatorStyles = tv({\n extend: textInputBase,\n slots: {\n // Re-declare base slots for type inference\n fieldset: '',\n legend: '',\n wrapper: 'w-full inline-flex flex-col',\n activator: [\n 'group relative inline-flex items-center w-full',\n 'outline-none focus:outline-none focus-within:outline-none cursor-pointer',\n 'min-h-14 pl-4 py-2 pr-8 rounded',\n 'm-0 transition-all text-body-1 text-left',\n 'dark:text-rui-text',\n ].join(' '),\n label: [\n 'text-rui-text-secondary [max-width:calc(100%-2.5rem)]',\n 'block truncate transition-all duration-75',\n ].join(' '),\n value: 'w-full block truncate transition-all duration-75',\n clear: 'ml-auto shrink-0 invisible group-hover:!visible',\n menu: 'overflow-y-auto max-h-60 min-w-[2.5rem]',\n highlighted: '!bg-rui-grey-200 dark:!bg-rui-grey-800',\n progress: 'absolute left-0 bottom-0 w-full',\n icon: 'text-rui-text transition',\n iconWrapper: 'flex items-center justify-end absolute right-3 top-px bottom-0',\n required: 'text-rui-error',\n },\n variants: {\n dense: {\n true: {\n activator: 'py-1.5 min-h-10',\n },\n },\n disabled: {\n true: {\n activator: 'opacity-65 text-rui-text-disabled active:text-rui-text-disabled cursor-default pointer-events-none',\n },\n },\n readonly: {\n true: {\n activator: 'opacity-80 pointer-events-none cursor-default bg-gray-50 dark:bg-white/10',\n },\n },\n filled: {\n true: {\n activator: [\n '!rounded-t !rounded-b-none !bg-black/[0.06]',\n '!hover:bg-black/[0.09] !focus-within:bg-black/[0.09]',\n 'dark:!bg-white/[0.09]',\n 'dark:!hover:bg-white/[0.13] dark:!focus-within:bg-white/[0.13]',\n underlinePseudo,\n ].join(' '),\n },\n },\n outlined: {\n true: {\n activator: 'bg-white dark:bg-transparent border-none hover:border-none',\n label: 'absolute',\n fieldset: '!mt-0 !h-full',\n },\n false: {\n activator: `!rounded-none ${underlinePseudo}`,\n },\n },\n float: {\n true: {\n label: '-translate-y-2 top-0 text-[0.75rem] leading-4',\n },\n },\n opened: {\n true: {\n icon: 'rotate-180',\n },\n },\n active: {\n true: {\n highlighted: '!bg-rui-grey-300 dark:!bg-rui-grey-700',\n },\n },\n hasError: {\n true: {},\n },\n hasSuccess: {\n true: {},\n },\n // Re-declare for type inference — actual styles are in textInputBase\n hovered: { true: {} },\n showLabel: { true: {} },\n },\n compoundVariants: [\n // Legend padding when a label is floated; without text it would cut an empty notch\n { float: true, showLabel: true, class: { legend: 'px-2' } },\n\n // Non-outlined + opened → underline scales up\n { outlined: false, opened: true, class: { activator: 'after:scale-x-100 after:border-rui-primary' } },\n\n // Non-outlined + error → underline color\n { outlined: false, hasError: true, class: { activator: 'after:scale-x-100 after:!border-rui-error' } },\n\n // Non-outlined + success → underline color\n { outlined: false, hasSuccess: true, class: { activator: 'after:scale-x-100 after:!border-rui-success' } },\n\n // Non-outlined + disabled in dark mode\n { outlined: false, disabled: true, class: { activator: 'dark:bg-white/10' } },\n\n // Filled + disabled\n { filled: true, disabled: true, class: { activator: 'bg-black/[0.03] dark:bg-white/[0.05]' } },\n\n // Outlined + hovered → fieldset border\n { outlined: true, hovered: true, class: { fieldset: 'border-black dark:border-white' } },\n\n // Outlined + opened/focused → primary border\n { outlined: true, opened: true, class: {\n fieldset: '!border-rui-primary !border-2',\n label: 'text-rui-primary',\n } },\n\n // Outlined + error → fieldset + label\n { outlined: true, hasError: true, class: {\n fieldset: '!border-rui-error',\n label: '!text-rui-error',\n } },\n // Outlined + success → fieldset + label\n { outlined: true, hasSuccess: true, class: {\n fieldset: '!border-rui-success',\n label: '!text-rui-success',\n } },\n\n // Outlined + disabled → dotted fieldset\n { outlined: true, disabled: true, class: {\n fieldset: '!border-dotted !border-black/[0.23] dark:!border-white/[0.23]',\n } },\n\n // Float + opened → label color\n { float: true, opened: true, class: { label: 'text-rui-primary' } },\n ],\n defaultVariants: {\n filled: false,\n outlined: false,\n dense: false,\n disabled: false,\n readonly: false,\n float: false,\n opened: false,\n },\n});\n"],"mappings":"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"}
@@ -42,11 +42,11 @@ import RuiNotification_default from "./overlays/notification/RuiNotification.js"
42
42
  import RuiFooterStepper_default from "./steppers/RuiFooterStepper.js";
43
43
  import RuiStepper_default from "./steppers/RuiStepper.js";
44
44
  import RuiTableEmptyState_default from "./tables/RuiTableEmptyState.js";
45
+ import RuiTableErrorState_default from "./tables/RuiTableErrorState.js";
45
46
  import RuiExpandButton_default from "./tables/RuiExpandButton.js";
46
47
  import RuiTableLoadingState_default from "./tables/RuiTableLoadingState.js";
47
48
  import RuiTablePagination_default from "./tables/RuiTablePagination.js";
48
49
  import RuiDataTable_default from "./tables/RuiDataTable.js";
49
- import RuiTableErrorState_default from "./tables/RuiTableErrorState.js";
50
50
  import RuiTable_default from "./tables/RuiTable.js";
51
51
  import RuiTabItem_default from "./tabs/tab-item/RuiTabItem.js";
52
52
  import RuiTabItems_default from "./tabs/tab-items/RuiTabItems.js";
@@ -1 +1 @@
1
- {"version":3,"file":"RuiDataTable.js","names":[],"sources":["../../../src/components/tables/RuiDataTable.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object, IdType extends keyof T = keyof T\">\nimport type { GroupHeader } from '@/composables/tables/data-table/types';\nimport { dataTableStyles } from '@/components/tables/data-table-styles';\nimport { type DataTableClasses, provideDataTableContext, provideDataTableNested, useDataTableNested } from '@/components/tables/data-table/context';\nimport RuiDataTableBody from '@/components/tables/data-table/RuiDataTableBody.vue';\nimport RuiDataTableMobileSort from '@/components/tables/data-table/RuiDataTableMobileSort.vue';\nimport RuiTableHead, {\n type GroupData,\n type TableColumn,\n type TableRowKeyData,\n type TableSortData,\n} from '@/components/tables/RuiTableHead.vue';\nimport RuiTablePagination, {\n type TablePaginationData,\n} from '@/components/tables/RuiTablePagination.vue';\nimport { GroupExpandButtonPosition } from '@/components/tables/table-props';\nimport { useTable } from '@/composables/defaults/table';\nimport { useStickyTableHeader } from '@/composables/sticky-header';\nimport { useTableColumns } from '@/composables/tables/data-table/columns';\nimport { useTableExpansion } from '@/composables/tables/data-table/expansion';\nimport { useTableGrouping } from '@/composables/tables/data-table/grouping';\nimport { useTablePagination } from '@/composables/tables/data-table/pagination';\nimport { useTableSelection } from '@/composables/tables/data-table/selection';\nimport { useTableSort } from '@/composables/tables/data-table/sort';\n\nexport type { GroupedTableRow, GroupHeader, TableOptions } from '@/composables/tables/data-table/types';\n\nexport interface Props<T, K extends keyof T> {\n /**\n * list of items for each row\n */\n rows: readonly T[];\n /**\n * the attribute used to identify each row uniquely for selection, usually `id`\n */\n rowAttr: K;\n /**\n * model for internal searching\n */\n search?: string;\n /**\n * model for items per page\n * will be used if the `pagination` model isn't specified\n */\n itemsPerPage?: number;\n /**\n * list of column definitions\n */\n cols?: TableColumn<T>[];\n /**\n * attribute to use from column definitions to display column titles\n */\n columnAttr?: keyof TableColumn<T>;\n /**\n * flag to show a more or less spacious table\n */\n dense?: boolean;\n /**\n * flag to outline the flag with a border\n */\n outlined?: boolean;\n /**\n * should add zebra-striping to the table row\n */\n striped?: boolean;\n /**\n * flag to show loading state of the table\n * triggers indefinite progress at the bottom of the table header\n */\n loading?: boolean;\n disablePerPage?: boolean;\n /**\n * Maximum number of pages before the jump-to-page dropdown is replaced with\n * a numeric input. Defaults to `500`. Forwarded to `RuiTablePagination`.\n */\n rangesThreshold?: number;\n /**\n * The text and icon shown when there are no rows, e.g.\n * `:empty=\"\\{ icon: 'transactions-line', label: 'No transactions found' \\}\"`\n */\n empty?: {\n label?: string;\n description?: string;\n };\n /**\n * should hide the header navigation\n */\n hideDefaultHeader?: boolean;\n /**\n * should hide the footer navigation\n */\n hideDefaultFooter?: boolean;\n\n rounded?: 'sm' | 'md' | 'lg';\n /**\n * make expansion work like accordion\n */\n singleExpand?: boolean;\n /**\n * make table head stick to top on scroll\n */\n stickyHeader?: boolean;\n stickyOffset?: number;\n /**\n * Affects how the items per page work across the app.\n * When true, changing the items per page setting in one table will affect other tables.\n */\n globalItemsPerPage?: boolean;\n groupExpandButtonPosition?: GroupExpandButtonPosition;\n disabledRows?: readonly T[];\n multiPageSelect?: boolean;\n itemClass?: ((item: T) => string) | string;\n /**\n * Render each row as a stacked card instead of a table row once the measured\n * width is narrower than this width (in pixels). Columns flagged with\n * `mobileHidden` are dropped in this layout. Falls back to the global\n * `mobileBreakpoint` table default; leave both unset to keep the default table\n * layout at every width.\n */\n mobileBreakpoint?: number;\n /**\n * What the `mobileBreakpoint` is measured against: the browser `viewport`\n * (default) or this table's own `container` width. Use `container` when the\n * table lives in a narrow region of a wider window. Falls back to the global\n * `mobileBreakpointBasis` table default.\n */\n mobileBreakpointBasis?: 'viewport' | 'container';\n /**\n * Force the stacked mobile card layout on (`true`) or off (`false`),\n * regardless of `mobileBreakpoint`. Leave unset to derive it from the width.\n */\n mobile?: boolean;\n}\n\ndefineOptions({\n name: 'RuiDataTable',\n});\n\nconst selectedData = defineModel<T[IdType][]>();\n\nconst expanded = defineModel<T[]>('expanded');\n\nconst [pagination, paginationModifiers] = defineModel<TablePaginationData, 'external'>('pagination');\n\nconst [sort, sortModifiers] = defineModel<TableSortData<T>, 'external'>('sort');\n\nconst group = defineModel<TableRowKeyData<T>>('group');\n\nconst collapsed = defineModel<T[]>('collapsed');\n\nconst {\n rows,\n rowAttr,\n search = '',\n itemsPerPage = 10,\n cols,\n columnAttr = 'label',\n dense = false,\n outlined = false,\n striped = false,\n loading = false,\n disablePerPage = false,\n rangesThreshold = 500,\n empty = { label: 'No item found' },\n hideDefaultHeader = false,\n hideDefaultFooter = false,\n rounded = 'md',\n singleExpand = false,\n stickyHeader = false,\n stickyOffset,\n globalItemsPerPage = undefined,\n groupExpandButtonPosition = GroupExpandButtonPosition.start,\n disabledRows,\n multiPageSelect = false,\n itemClass = '',\n mobileBreakpoint,\n mobileBreakpointBasis,\n mobile,\n} = defineProps<Props<T, IdType>>();\n\nconst emit = defineEmits<{\n 'update:options': [value: { pagination?: TablePaginationData; sort?: TableSortData<T> }];\n 'copy:group': [value: GroupData<T>];\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`header.${string}`, (props: { column: TableColumn<T> }) => any> &\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend': (props: { colspan: number }) => any;\n 'body.append': (props: { colspan: number }) => any;\n 'group.header': (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content': (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item': (props: { row: T; index: number }) => any;\n 'no-data': () => any;\n 'empty-description': () => any;\n 'tfoot': () => any;\n }\n>>();\n\nconst tableDefaults = useTable();\n\nconst tableWrapper = useTemplateRef<HTMLElement>('tableWrapper');\nconst { width: windowWidth } = useWindowSize();\nconst { width: containerWidth } = useElementSize(tableWrapper);\n\n// Per-table props win, then the global table defaults.\nconst resolvedMobileBreakpoint = computed<number | undefined>(() => {\n if (mobileBreakpoint !== undefined)\n return mobileBreakpoint;\n const globalBreakpoint = tableDefaults.mobileBreakpoint;\n return globalBreakpoint === undefined ? undefined : get(globalBreakpoint);\n});\nconst resolvedMobileBasis = computed<'viewport' | 'container'>(() => {\n if (mobileBreakpointBasis !== undefined)\n return mobileBreakpointBasis;\n const globalBasis = tableDefaults.mobileBreakpointBasis;\n return globalBasis === undefined ? 'viewport' : get(globalBasis);\n});\n\n/**\n * Whether the stacked card layout is showing.\n *\n * Vue coerces an absent Boolean prop to `false`, so `mobile` cannot say\n * \"unset\": with no breakpoint configured it is the manual switch, defaulting\n * to desktop, and with one configured the breakpoint drives the layout while\n * `mobile === true` can still force the stacked layout on.\n */\nconst isMobile = computed<boolean>(() => {\n const breakpoint = get(resolvedMobileBreakpoint);\n if (breakpoint === undefined)\n return mobile;\n if (mobile)\n return true;\n // `containerWidth` is 0 until measured; the viewport keeps the first paint off mobile\n const width = get(resolvedMobileBasis) === 'container'\n ? (get(containerWidth) || get(windowWidth))\n : get(windowWidth);\n return width < breakpoint;\n});\n\nconst stickyHeaderOffset = computed<number | undefined>(() =>\n stickyOffset !== undefined ? stickyOffset : get(tableDefaults.stickyOffset),\n);\n\n/**\n * A table rendered inside an expanded row must not pin its own toolbar: only\n * the outermost table sticks, otherwise the bars stack and collide.\n */\nconst isNestedTable = useDataTableNested();\nprovideDataTableNested();\n\n/**\n * On mobile there is no column header to pin, so `stickyHeader` pins the\n * pagination and sort toolbar instead while the card list scrolls.\n */\nconst stickyMobileToolbar = computed<boolean>(() => stickyHeader && get(isMobile) && !isNestedTable);\n\nconst table = useTemplateRef<HTMLTableElement>('table');\nconst tableScroller = useTemplateRef<HTMLElement>('tableScroller');\n\nconst { stick } = useStickyTableHeader(\n () => stickyHeader,\n stickyHeaderOffset,\n { table, tableScroller },\n);\n\nconst { expandable, isExpanded, onToggleExpand } = useTableExpansion<T, IdType>(\n { rowAttr, singleExpand },\n { expanded },\n);\n\nfunction emitUpdateOptions(opts: { sort?: TableSortData<T>; pagination?: TablePaginationData }): void {\n emit('update:options', opts);\n}\n\nconst {\n sortData,\n sortedMap,\n sorted,\n onSort: applySort,\n} = useTableSort<T>(\n { rows: () => rows, search: () => search, sortModifiersExternal: sortModifiers.external },\n {\n sort,\n pagination,\n emitUpdateOptions,\n },\n);\n\nconst {\n groupKeys,\n groupKey,\n grouped,\n isExpandedGroup,\n isHiddenRow,\n onToggleExpandGroup,\n onUngroup,\n} = useTableGrouping<T, IdType>(\n { rowAttr },\n {\n group,\n collapsed,\n sorted,\n },\n);\n\nconst {\n paginationData,\n filtered,\n setInternalTotal,\n resetPagination,\n} = useTablePagination<T>(\n {\n itemsPerPage,\n paginationModifiersExternal: paginationModifiers.external,\n globalItemsPerPage,\n },\n {\n pagination,\n grouped,\n isHiddenRow,\n sort,\n emitUpdateOptions,\n tableDefaults,\n },\n);\n\nconst noData = computed<boolean>(() => get(filtered).length === 0);\n\nconst ui = computed<ReturnType<typeof dataTableStyles>>(() => dataTableStyles({\n outlined,\n rounded,\n dense,\n striped,\n mobile: get(isMobile),\n}));\n\nconst { columns, colspan, headerSlots, cellValue } = useTableColumns<T, IdType>({\n cols: () => cols,\n columnAttr,\n rows: () => rows,\n expandable,\n groupKeys,\n selectedData,\n slots,\n isMobile,\n tdResolver: options => get(ui).td(options),\n});\n\nconst showMobileSort = computed<boolean>(() =>\n get(isMobile) && !!get(sortData) && get(columns).some(column => column.sortable),\n);\n\nconst ITEM_SLOT_PREFIX = 'item.';\n\n// Slot keys are static for the component lifetime — no reactivity needed\nconst itemSlotKeys: Set<string> = new Set(\n Object.keys(slots)\n .filter((key): key is `item.${string}` => key.startsWith(ITEM_SLOT_PREFIX))\n .map(key => key.slice(ITEM_SLOT_PREFIX.length)),\n);\n\nconst {\n isAllSelected,\n indeterminate,\n isSelected,\n isDisabledRow,\n onToggleAll,\n onSelect,\n onCheckboxClick,\n deselectRemovedRows,\n resetCheckboxShiftState,\n} = useTableSelection<T, IdType>(\n { rowAttr, multiPageSelect, disabledRows: () => disabledRows },\n { selectedData, filtered },\n);\n\n/**\n * Sorting clears the selection. That lives here rather than in either\n * composable, which would make sort and selection depend on each other.\n */\nfunction onSort(payload: Parameters<typeof applySort>[0]): void {\n applySort(payload);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n}\n\nfunction onPaginate(): void {\n if ((get(expanded)?.length ?? 0) > 0)\n set(expanded, []);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n}\n\n// Reset pagination page to 1 on search query change\nwatch(() => search, () => {\n resetPagination();\n onToggleAll(false);\n resetCheckboxShiftState();\n});\n\nwatch(sorted, (items) => {\n if (!multiPageSelect)\n deselectRemovedRows();\n setInternalTotal(items);\n});\n\nonMounted(() => {\n setInternalTotal(get(sorted));\n});\n\nconst classes = computed<DataTableClasses>(() => {\n const s = get(ui);\n return {\n td: s.td(),\n tr: s.tr(),\n trSelected: s.tr({ rowVariant: 'selected' }),\n trExpandable: s.tr({ rowVariant: 'expandable' }),\n trGroup: s.tr({ rowVariant: 'group' }),\n trEmpty: s.tr({ rowVariant: 'empty' }),\n checkbox: s.checkbox(),\n tbody: s.tbody(),\n tbodyLoader: s.tbodyLoader(),\n };\n});\n\nprovideDataTableContext<T, IdType>({\n // Reactive (ComputedRef/Ref) — destructuring preserves reactivity via Vue template auto-unwrap\n classes,\n columns,\n colspan,\n expandable,\n groupKey,\n isMobile,\n selectedData,\n // Static values\n cellValue,\n columnAttr,\n dense,\n getRowId: (row: T) => row[rowAttr],\n itemSlotKeys,\n groupExpandButtonPosition,\n isDisabledRow,\n isExpanded,\n isExpandedGroup,\n isSelected,\n itemClass,\n onCheckboxClick,\n onCopyGroup: (header: GroupHeader<T>) => emit('copy:group', { key: get(groupKey) ?? '', value: header.group }),\n onSelect,\n onToggleExpand,\n onToggleExpandGroup,\n onUngroup,\n});\n</script>\n\n<template>\n <div\n ref=\"tableWrapper\"\n :class=\"ui.wrapper()\"\n data-id=\"table-wrapper\"\n >\n <div\n :class=\"stickyMobileToolbar ? 'sticky z-10 bg-white dark:bg-[#121212] pt-2' : 'contents'\"\n :style=\"stickyMobileToolbar ? { top: `${stickyHeaderOffset ?? 0}px` } : undefined\"\n data-id=\"table-mobile-toolbar-sticky\"\n >\n <RuiTablePagination\n v-if=\"paginationData && !hideDefaultHeader\"\n v-model=\"paginationData\"\n :dense=\"dense\"\n :loading=\"loading\"\n :mobile=\"isMobile\"\n :disable-per-page=\"disablePerPage\"\n :ranges-threshold=\"rangesThreshold\"\n data-id=\"table-pagination\"\n @update:model-value=\"onPaginate()\"\n />\n <div\n v-if=\"showMobileSort\"\n class=\"flex justify-end p-2\"\n data-id=\"table-mobile-toolbar\"\n >\n <RuiDataTableMobileSort\n :columns=\"columns\"\n :column-attr=\"columnAttr\"\n :sorted-map=\"sortedMap\"\n :dense=\"dense\"\n @sort=\"onSort($event)\"\n />\n </div>\n </div>\n <div\n ref=\"tableScroller\"\n :class=\"[ui.scroller(), isMobile && !showMobileSort ? 'pt-2' : '']\"\n data-id=\"table-scroller\"\n >\n <table\n ref=\"table\"\n :class=\"ui.table()\"\n :aria-busy=\"loading\"\n >\n <RuiTableHead\n v-if=\"!isMobile\"\n :loading=\"loading\"\n :indeterminate=\"indeterminate\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :disable-check-all=\"!filtered?.length\"\n :is-all-selected=\"isAllSelected\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n :stick=\"stick\"\n :sticky-header=\"stickyHeader\"\n @sort=\"onSort($event)\"\n @select:all=\"onToggleAll($event)\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiTableHead\n v-if=\"stickyHeader && !isMobile\"\n :loading=\"loading\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n data-id=\"head-clone\"\n class=\"opacity-0 invisible\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiDataTableBody\n :filtered=\"filtered\"\n :loading=\"loading\"\n :no-data=\"noData\"\n :empty=\"empty\"\n >\n <template\n v-if=\"slots['body.prepend']\"\n #body.prepend=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.prepend\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header']\"\n #group.header=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header.content']\"\n #group.header.content=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header.content\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-for=\"key in itemSlotKeys\"\n #[`item.${key}`]=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n :name=\"`item.${key}`\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['no-data']\"\n #no-data\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"no-data\" />\n </template>\n <template\n v-if=\"slots['empty-description']\"\n #empty-description\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"empty-description\" />\n </template>\n <template\n v-if=\"slots['body.append']\"\n #body.append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableBody>\n <tfoot>\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"tfoot\" />\n </tfoot>\n </table>\n </div>\n <RuiTablePagination\n v-if=\"paginationData && !hideDefaultFooter\"\n v-model=\"paginationData\"\n :dense=\"dense\"\n :loading=\"loading\"\n :mobile=\"isMobile\"\n :disable-per-page=\"disablePerPage\"\n :ranges-threshold=\"rangesThreshold\"\n data-id=\"table-pagination\"\n @update:model-value=\"onPaginate()\"\n />\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RuiDataTable.js","names":[],"sources":["../../../src/components/tables/RuiDataTable.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object, IdType extends keyof T = keyof T\">\nimport type { GroupHeader } from '@/composables/tables/data-table/types';\nimport { dataTableStyles } from '@/components/tables/data-table-styles';\nimport { type DataTableClasses, type DataTableGroupLabel, provideDataTableContext, provideDataTableNested, useDataTableNested } from '@/components/tables/data-table/context';\nimport RuiDataTableBody from '@/components/tables/data-table/RuiDataTableBody.vue';\nimport RuiDataTableMobileSort from '@/components/tables/data-table/RuiDataTableMobileSort.vue';\nimport RuiTableHead, {\n type GroupData,\n type TableColumn,\n type TableRowKeyData,\n type TableSortData,\n} from '@/components/tables/RuiTableHead.vue';\nimport RuiTablePagination, {\n type TablePaginationData,\n} from '@/components/tables/RuiTablePagination.vue';\nimport { GroupExpandButtonPosition } from '@/components/tables/table-props';\nimport { useTable } from '@/composables/defaults/table';\nimport { useStickyTableHeader } from '@/composables/sticky-header';\nimport { useTableColumns } from '@/composables/tables/data-table/columns';\nimport { useTableExpansion } from '@/composables/tables/data-table/expansion';\nimport { useTableGrouping } from '@/composables/tables/data-table/grouping';\nimport { useTablePagination } from '@/composables/tables/data-table/pagination';\nimport { useTableSelection } from '@/composables/tables/data-table/selection';\nimport { useTableSort } from '@/composables/tables/data-table/sort';\n\nexport type { GroupedTableRow, GroupHeader, TableOptions } from '@/composables/tables/data-table/types';\n\nexport interface Props<T, K extends keyof T> {\n /**\n * list of items for each row\n */\n rows: readonly T[];\n /**\n * the attribute used to identify each row uniquely for selection, usually `id`\n */\n rowAttr: K;\n /**\n * model for internal searching\n */\n search?: string;\n /**\n * model for items per page\n * will be used if the `pagination` model isn't specified\n */\n itemsPerPage?: number;\n /**\n * list of column definitions\n */\n cols?: TableColumn<T>[];\n /**\n * attribute to use from column definitions to display column titles\n */\n columnAttr?: keyof TableColumn<T>;\n /**\n * flag to show a more or less spacious table\n */\n dense?: boolean;\n /**\n * flag to outline the flag with a border\n */\n outlined?: boolean;\n /**\n * should add zebra-striping to the table row\n */\n striped?: boolean;\n /**\n * flag to show loading state of the table\n * triggers indefinite progress at the bottom of the table header\n */\n loading?: boolean;\n disablePerPage?: boolean;\n /**\n * Maximum number of pages before the jump-to-page dropdown is replaced with\n * a numeric input. Defaults to `500`. Forwarded to `RuiTablePagination`.\n */\n rangesThreshold?: number;\n /**\n * The text and icon shown when there are no rows, e.g.\n * `:empty=\"\\{ icon: 'transactions-line', label: 'No transactions found' \\}\"`\n */\n empty?: {\n label?: string;\n description?: string;\n };\n /**\n * Why the last read failed. Shown above any rows kept from an earlier read,\n * or in place of the empty state; `loading` still takes precedence.\n */\n error?: string;\n /** Heading for that failure. */\n errorTitle?: string;\n /** Label for the retry control; without one, no control is offered. */\n retryText?: string;\n /**\n * should hide the header navigation\n */\n hideDefaultHeader?: boolean;\n /**\n * should hide the footer navigation\n */\n hideDefaultFooter?: boolean;\n\n rounded?: 'sm' | 'md' | 'lg';\n /**\n * make expansion work like accordion\n */\n singleExpand?: boolean;\n /**\n * make table head stick to top on scroll\n */\n stickyHeader?: boolean;\n stickyOffset?: number;\n /**\n * Affects how the items per page work across the app.\n * When true, changing the items per page setting in one table will affect other tables.\n */\n globalItemsPerPage?: boolean;\n groupExpandButtonPosition?: GroupExpandButtonPosition;\n disabledRows?: readonly T[];\n multiPageSelect?: boolean;\n itemClass?: ((item: T) => string) | string;\n /**\n * Render each row as a stacked card instead of a table row once the measured\n * width is narrower than this width (in pixels). Columns flagged with\n * `mobileHidden` are dropped in this layout. Falls back to the global\n * `mobileBreakpoint` table default; leave both unset to keep the default table\n * layout at every width.\n */\n mobileBreakpoint?: number;\n /**\n * What the `mobileBreakpoint` is measured against: the browser `viewport`\n * (default) or this table's own `container` width. Use `container` when the\n * table lives in a narrow region of a wider window. Falls back to the global\n * `mobileBreakpointBasis` table default.\n */\n mobileBreakpointBasis?: 'viewport' | 'container';\n /**\n * Force the stacked mobile card layout on (`true`) or off (`false`),\n * regardless of `mobileBreakpoint`. Leave unset to derive it from the width.\n */\n mobile?: boolean;\n}\n\ndefineOptions({\n name: 'RuiDataTable',\n});\n\nconst selectedData = defineModel<T[IdType][]>();\n\nconst expanded = defineModel<T[]>('expanded');\n\nconst [pagination, paginationModifiers] = defineModel<TablePaginationData, 'external'>('pagination');\n\nconst [sort, sortModifiers] = defineModel<TableSortData<T>, 'external'>('sort');\n\nconst group = defineModel<TableRowKeyData<T>>('group');\n\nconst collapsed = defineModel<T[]>('collapsed');\n\nconst {\n rows,\n rowAttr,\n search = '',\n itemsPerPage = 10,\n cols,\n columnAttr = 'label',\n dense = false,\n outlined = false,\n striped = false,\n loading = false,\n disablePerPage = false,\n rangesThreshold = 500,\n empty = { label: 'No item found' },\n error = '',\n errorTitle = '',\n retryText = '',\n hideDefaultHeader = false,\n hideDefaultFooter = false,\n rounded = 'md',\n singleExpand = false,\n stickyHeader = false,\n stickyOffset,\n globalItemsPerPage = undefined,\n groupExpandButtonPosition = GroupExpandButtonPosition.start,\n disabledRows,\n multiPageSelect = false,\n itemClass = '',\n mobileBreakpoint,\n mobileBreakpointBasis,\n mobile,\n} = defineProps<Props<T, IdType>>();\n\nconst emit = defineEmits<{\n 'update:options': [value: { pagination?: TablePaginationData; sort?: TableSortData<T> }];\n 'copy:group': [value: GroupData<T>];\n 'retry': [];\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`header.${string}`, (props: { column: TableColumn<T> }) => any> &\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'body.prepend': (props: { colspan: number }) => any;\n 'body.append': (props: { colspan: number }) => any;\n 'group.header': (props: {\n colspan: number;\n header: GroupHeader<T>;\n isOpen: boolean;\n toggle: () => void;\n }) => any;\n 'group.header.content': (props: { header: GroupHeader<T>; groupKey: string }) => any;\n 'expanded-item': (props: { row: T; index: number }) => any;\n 'no-data': () => any;\n 'empty-description': () => any;\n 'error': () => any;\n 'tfoot': () => any;\n }\n>>();\n\nconst tableDefaults = useTable();\n\nconst tableWrapper = useTemplateRef<HTMLElement>('tableWrapper');\nconst { width: windowWidth } = useWindowSize();\nconst { width: containerWidth } = useElementSize(tableWrapper);\n\n// Per-table props win, then the global table defaults.\nconst resolvedMobileBreakpoint = computed<number | undefined>(() => {\n if (mobileBreakpoint !== undefined)\n return mobileBreakpoint;\n const globalBreakpoint = tableDefaults.mobileBreakpoint;\n return globalBreakpoint === undefined ? undefined : get(globalBreakpoint);\n});\nconst resolvedMobileBasis = computed<'viewport' | 'container'>(() => {\n if (mobileBreakpointBasis !== undefined)\n return mobileBreakpointBasis;\n const globalBasis = tableDefaults.mobileBreakpointBasis;\n return globalBasis === undefined ? 'viewport' : get(globalBasis);\n});\n\n/**\n * Whether the stacked card layout is showing.\n *\n * Vue coerces an absent Boolean prop to `false`, so `mobile` cannot say\n * \"unset\": with no breakpoint configured it is the manual switch, defaulting\n * to desktop, and with one configured the breakpoint drives the layout while\n * `mobile === true` can still force the stacked layout on.\n */\nconst isMobile = computed<boolean>(() => {\n const breakpoint = get(resolvedMobileBreakpoint);\n if (breakpoint === undefined)\n return mobile;\n if (mobile)\n return true;\n // `containerWidth` is 0 until measured; the viewport keeps the first paint off mobile\n const width = get(resolvedMobileBasis) === 'container'\n ? (get(containerWidth) || get(windowWidth))\n : get(windowWidth);\n return width < breakpoint;\n});\n\nconst stickyHeaderOffset = computed<number | undefined>(() =>\n stickyOffset !== undefined ? stickyOffset : get(tableDefaults.stickyOffset),\n);\n\n/**\n * A table rendered inside an expanded row must not pin its own toolbar: only\n * the outermost table sticks, otherwise the bars stack and collide.\n */\nconst isNestedTable = useDataTableNested();\nprovideDataTableNested();\n\n/**\n * On mobile there is no column header to pin, so `stickyHeader` pins the\n * pagination and sort toolbar instead while the card list scrolls.\n */\nconst stickyMobileToolbar = computed<boolean>(() => stickyHeader && get(isMobile) && !isNestedTable);\n\nconst table = useTemplateRef<HTMLTableElement>('table');\nconst tableScroller = useTemplateRef<HTMLElement>('tableScroller');\n\nconst { stick } = useStickyTableHeader(\n () => stickyHeader,\n stickyHeaderOffset,\n { table, tableScroller },\n);\n\nconst { width: scrollerWidth } = useElementSize(tableScroller);\n\n/**\n * The visible width of the table, which an expanded row caps its content to.\n * Without the cap a wide panel, such as a nested table, sets the minimum width\n * of the whole table and pushes every column past the scroller. `initial`\n * resets the variable, so a nested table never inherits its parent's width.\n */\nconst viewportStyle = computed<Record<string, string>>(() => {\n const width = get(scrollerWidth);\n return { '--rui-table-viewport': width > 0 && !get(isMobile) ? `${width}px` : 'initial' };\n});\n\nconst { expandable, isExpanded, onToggleExpand } = useTableExpansion<T, IdType>(\n { rowAttr, singleExpand },\n { expanded },\n);\n\nfunction emitUpdateOptions(opts: { sort?: TableSortData<T>; pagination?: TablePaginationData }): void {\n emit('update:options', opts);\n}\n\nconst {\n sortData,\n sortedMap,\n sorted,\n onSort: applySort,\n} = useTableSort<T>(\n { rows: () => rows, search: () => search, sortModifiersExternal: sortModifiers.external },\n {\n sort,\n pagination,\n emitUpdateOptions,\n },\n);\n\nconst {\n groupKeys,\n groupKey,\n grouped,\n mappedGroups,\n isExpandedGroup,\n isHiddenRow,\n onToggleExpandGroup,\n onUngroup,\n} = useTableGrouping<T, IdType>(\n { rowAttr },\n {\n group,\n collapsed,\n sorted,\n },\n);\n\nconst {\n paginationData,\n filtered,\n setInternalTotal,\n resetPagination,\n} = useTablePagination<T>(\n {\n itemsPerPage,\n paginationModifiersExternal: paginationModifiers.external,\n globalItemsPerPage,\n },\n {\n pagination,\n grouped,\n isHiddenRow,\n sort,\n emitUpdateOptions,\n tableDefaults,\n },\n);\n\nconst noData = computed<boolean>(() => get(filtered).length === 0);\n\n/**\n * With the header bar showing, an empty table drops its footer bar: two rows\n * of disabled controls around an empty state only add noise.\n */\nconst showFooter = computed<boolean>(() => {\n const data = get(paginationData);\n if (!data || hideDefaultFooter)\n return false;\n return data.total > 0 || hideDefaultHeader;\n});\n\n/**\n * Grouped columns leave the column list, so their labels come from `cols`.\n */\nconst groupLabels = computed<DataTableGroupLabel[]>(() => get(groupKeys).map((key) => {\n const label = cols?.find(column => column.key === key)?.[columnAttr];\n return {\n key: String(key),\n label: label === undefined || label === null ? String(key) : String(label),\n };\n}));\n\n/** Each group's list starts with its header entry, which is not a row. */\nfunction getGroupSize(identifier: string): number {\n return Math.max((get(mappedGroups)[identifier]?.length ?? 0) - 1, 0);\n}\n\nconst ui = computed<ReturnType<typeof dataTableStyles>>(() => dataTableStyles({\n outlined,\n rounded,\n dense,\n striped,\n mobile: get(isMobile),\n}));\n\nconst { columns, colspan, headerSlots, cellValue } = useTableColumns<T, IdType>({\n cols: () => cols,\n columnAttr,\n rows: () => rows,\n expandable,\n groupKeys,\n selectedData,\n slots,\n isMobile,\n tdResolver: options => get(ui).td(options),\n});\n\nconst showMobileSort = computed<boolean>(() =>\n get(isMobile) && !!get(sortData) && get(columns).some(column => column.sortable),\n);\n\nconst ITEM_SLOT_PREFIX = 'item.';\n\n// Slot keys are static for the component lifetime — no reactivity needed\nconst itemSlotKeys: Set<string> = new Set(\n Object.keys(slots)\n .filter((key): key is `item.${string}` => key.startsWith(ITEM_SLOT_PREFIX))\n .map(key => key.slice(ITEM_SLOT_PREFIX.length)),\n);\n\nconst {\n isAllSelected,\n indeterminate,\n isSelected,\n isDisabledRow,\n onToggleAll,\n onSelect,\n onCheckboxClick,\n deselectRemovedRows,\n resetCheckboxShiftState,\n} = useTableSelection<T, IdType>(\n { rowAttr, multiPageSelect, disabledRows: () => disabledRows },\n { selectedData, filtered },\n);\n\n/**\n * Sorting clears the selection. That lives here rather than in either\n * composable, which would make sort and selection depend on each other.\n */\nfunction onSort(payload: Parameters<typeof applySort>[0]): void {\n applySort(payload);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n}\n\nfunction onPaginate(): void {\n if ((get(expanded)?.length ?? 0) > 0)\n set(expanded, []);\n if (!multiPageSelect)\n onToggleAll(false);\n resetCheckboxShiftState();\n}\n\n// Reset pagination page to 1 on search query change\nwatch(() => search, () => {\n resetPagination();\n onToggleAll(false);\n resetCheckboxShiftState();\n});\n\nwatch(sorted, (items) => {\n if (!multiPageSelect)\n deselectRemovedRows();\n setInternalTotal(items);\n});\n\nonMounted(() => {\n setInternalTotal(get(sorted));\n});\n\nconst classes = computed<DataTableClasses>(() => {\n const s = get(ui);\n return {\n td: s.td(),\n tr: s.tr(),\n trSelected: s.tr({ rowVariant: 'selected' }),\n trExpandable: s.tr({ rowVariant: 'expandable' }),\n trExpandedParent: s.tr({ rowVariant: 'expandedParent' }),\n trGroup: s.tr({ rowVariant: 'group' }),\n trEmpty: s.tr({ rowVariant: 'empty' }),\n checkbox: s.checkbox(),\n tbody: s.tbody(),\n tbodyLoader: s.tbodyLoader(),\n };\n});\n\nprovideDataTableContext<T, IdType>({\n // Reactive (ComputedRef/Ref) — destructuring preserves reactivity via Vue template auto-unwrap\n classes,\n columns,\n colspan,\n expandable,\n groupKey,\n groupLabels,\n isMobile,\n selectedData,\n // Static values\n cellValue,\n columnAttr,\n dense,\n getGroupSize,\n getRowId: (row: T) => row[rowAttr],\n itemSlotKeys,\n groupExpandButtonPosition,\n isDisabledRow,\n isExpanded,\n isExpandedGroup,\n isSelected,\n itemClass,\n onCheckboxClick,\n onCopyGroup: (header: GroupHeader<T>) => emit('copy:group', { key: get(groupKey) ?? '', value: header.group }),\n onSelect,\n onToggleExpand,\n onToggleExpandGroup,\n onUngroup,\n});\n</script>\n\n<template>\n <div\n ref=\"tableWrapper\"\n :class=\"ui.wrapper()\"\n data-id=\"table-wrapper\"\n >\n <div\n :class=\"stickyMobileToolbar ? 'sticky z-10 bg-white dark:bg-[#121212] pt-2' : 'contents'\"\n :style=\"stickyMobileToolbar ? { top: `${stickyHeaderOffset ?? 0}px` } : undefined\"\n data-id=\"table-mobile-toolbar-sticky\"\n >\n <RuiTablePagination\n v-if=\"paginationData && !hideDefaultHeader\"\n v-model=\"paginationData\"\n :dense=\"dense\"\n :loading=\"loading\"\n :mobile=\"isMobile\"\n :disable-per-page=\"disablePerPage\"\n :ranges-threshold=\"rangesThreshold\"\n data-id=\"table-pagination\"\n @update:model-value=\"onPaginate()\"\n />\n <div\n v-if=\"showMobileSort\"\n class=\"flex justify-end p-2\"\n data-id=\"table-mobile-toolbar\"\n >\n <RuiDataTableMobileSort\n :columns=\"columns\"\n :column-attr=\"columnAttr\"\n :sorted-map=\"sortedMap\"\n :dense=\"dense\"\n @sort=\"onSort($event)\"\n />\n </div>\n </div>\n <div\n ref=\"tableScroller\"\n :class=\"[ui.scroller(), isMobile && !showMobileSort ? 'pt-2' : '']\"\n data-id=\"table-scroller\"\n >\n <table\n ref=\"table\"\n :class=\"ui.table()\"\n :style=\"viewportStyle\"\n :aria-busy=\"loading\"\n >\n <RuiTableHead\n v-if=\"!isMobile\"\n :loading=\"loading\"\n :indeterminate=\"indeterminate\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :disable-check-all=\"!filtered?.length\"\n :is-all-selected=\"isAllSelected\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n :stick=\"stick\"\n :sticky-header=\"stickyHeader\"\n @sort=\"onSort($event)\"\n @select:all=\"onToggleAll($event)\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiTableHead\n v-if=\"stickyHeader && !isMobile\"\n :loading=\"loading\"\n :capitalize-headers=\"!cols\"\n :colspan=\"colspan\"\n :column-attr=\"columnAttr\"\n :columns=\"columns\"\n :dense=\"dense\"\n :selectable=\"!!selectedData\"\n :sort-data=\"sortData\"\n :sorted-map=\"sortedMap\"\n data-id=\"head-clone\"\n class=\"opacity-0 invisible\"\n >\n <template\n v-for=\"headerSlot in headerSlots\"\n #[headerSlot]=\"slotData\"\n >\n <slot\n :name=\"headerSlot\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiTableHead>\n <RuiDataTableBody\n :filtered=\"filtered\"\n :loading=\"loading\"\n :no-data=\"noData\"\n :empty=\"empty\"\n :error=\"error\"\n :error-title=\"errorTitle\"\n :retry-text=\"retryText\"\n @retry=\"emit('retry')\"\n >\n <template\n v-if=\"slots.error\"\n #error\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"error\" />\n </template>\n <template\n v-if=\"slots['body.prepend']\"\n #body.prepend=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.prepend\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header']\"\n #group.header=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['group.header.content']\"\n #group.header.content=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"group.header.content\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-for=\"key in itemSlotKeys\"\n #[`item.${key}`]=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n :name=\"`item.${key}`\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['expanded-item']\"\n #expanded-item=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"expanded-item\"\n v-bind=\"slotData\"\n />\n </template>\n <template\n v-if=\"slots['no-data']\"\n #no-data\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"no-data\" />\n </template>\n <template\n v-if=\"slots['empty-description']\"\n #empty-description\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"empty-description\" />\n </template>\n <template\n v-if=\"slots['body.append']\"\n #body.append=\"slotData\"\n >\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"body.append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableBody>\n <tfoot>\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot name=\"tfoot\" />\n </tfoot>\n </table>\n </div>\n <RuiTablePagination\n v-if=\"paginationData && showFooter\"\n v-model=\"paginationData\"\n :dense=\"dense\"\n :loading=\"loading\"\n :mobile=\"isMobile\"\n :disable-per-page=\"disablePerPage\"\n :ranges-threshold=\"rangesThreshold\"\n data-id=\"table-pagination\"\n @update:model-value=\"onPaginate()\"\n />\n </div>\n</template>\n"],"mappings":""}
@@ -60,6 +60,15 @@ export interface Props<T, K extends keyof T> {
60
60
  label?: string;
61
61
  description?: string;
62
62
  };
63
+ /**
64
+ * Why the last read failed. Shown above any rows kept from an earlier read,
65
+ * or in place of the empty state; `loading` still takes precedence.
66
+ */
67
+ error?: string;
68
+ /** Heading for that failure. */
69
+ errorTitle?: string;
70
+ /** Label for the retry control; without one, no control is offered. */
71
+ retryText?: string;
63
72
  /**
64
73
  * should hide the header navigation
65
74
  */
@@ -120,6 +129,7 @@ declare const __VLS_export: <T extends object, IdType extends keyof T = keyof T>
120
129
  collapsed?: T[];
121
130
  }) & {
122
131
  "onUpdate:modelValue"?: ((value: T[IdType][] | undefined) => any) | undefined;
132
+ onRetry?: (() => any) | undefined;
123
133
  "onUpdate:options"?: ((value: {
124
134
  pagination?: TablePaginationData;
125
135
  sort?: TableSortData<T>;
@@ -164,9 +174,10 @@ declare const __VLS_export: <T extends object, IdType extends keyof T = keyof T>
164
174
  }) => any;
165
175
  'no-data': () => any;
166
176
  'empty-description': () => any;
177
+ error: () => any;
167
178
  tfoot: () => any;
168
179
  }>;
169
- emit: (((evt: "update:options", value: {
180
+ emit: (((evt: "retry") => void) & ((evt: "update:options", value: {
170
181
  pagination?: TablePaginationData;
171
182
  sort?: TableSortData<T>;
172
183
  }) => void) & ((evt: "copy:group", value: GroupData<T>) => void)) & (((event: "update:modelValue", value: T[IdType][] | undefined) => void) & ((event: "update:expanded", value: T[] | undefined) => void) & ((event: "update:pagination", value: TablePaginationData | undefined) => void) & ((event: "update:sort", value: TableSortData<T>) => void) & ((event: "update:group", value: TableRowKeyData<T>) => void) & ((event: "update:collapsed", value: T[] | undefined) => void));
@@ -56,6 +56,9 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
56
56
  },
57
57
  rangesThreshold: { default: 500 },
58
58
  empty: { default: () => ({ label: "No item found" }) },
59
+ error: { default: "" },
60
+ errorTitle: { default: "" },
61
+ retryText: { default: "" },
59
62
  hideDefaultHeader: {
60
63
  type: Boolean,
61
64
  default: false
@@ -105,7 +108,11 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
105
108
  "collapsed": {},
106
109
  "collapsedModifiers": {}
107
110
  }),
108
- emits: /*@__PURE__*/ mergeModels(["update:options", "copy:group"], [
111
+ emits: /*@__PURE__*/ mergeModels([
112
+ "update:options",
113
+ "copy:group",
114
+ "retry"
115
+ ], [
109
116
  "update:modelValue",
110
117
  "update:expanded",
111
118
  "update:pagination",
@@ -168,6 +175,17 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
168
175
  table,
169
176
  tableScroller
170
177
  });
178
+ const { width: scrollerWidth } = useElementSize(tableScroller);
179
+ /**
180
+ * The visible width of the table, which an expanded row caps its content to.
181
+ * Without the cap a wide panel, such as a nested table, sets the minimum width
182
+ * of the whole table and pushes every column past the scroller. `initial`
183
+ * resets the variable, so a nested table never inherits its parent's width.
184
+ */
185
+ const viewportStyle = computed(() => {
186
+ const width = get$1(scrollerWidth);
187
+ return { "--rui-table-viewport": width > 0 && !get$1(isMobile) ? `${width}px` : "initial" };
188
+ });
171
189
  const { expandable, isExpanded, onToggleExpand } = useTableExpansion({
172
190
  rowAttr: __props.rowAttr,
173
191
  singleExpand: __props.singleExpand
@@ -184,7 +202,7 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
184
202
  pagination,
185
203
  emitUpdateOptions
186
204
  });
187
- const { groupKeys, groupKey, grouped, isExpandedGroup, isHiddenRow, onToggleExpandGroup, onUngroup } = useTableGrouping({ rowAttr: __props.rowAttr }, {
205
+ const { groupKeys, groupKey, grouped, mappedGroups, isExpandedGroup, isHiddenRow, onToggleExpandGroup, onUngroup } = useTableGrouping({ rowAttr: __props.rowAttr }, {
188
206
  group,
189
207
  collapsed,
190
208
  sorted
@@ -202,6 +220,29 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
202
220
  tableDefaults
203
221
  });
204
222
  const noData = computed(() => get$1(filtered).length === 0);
223
+ /**
224
+ * With the header bar showing, an empty table drops its footer bar: two rows
225
+ * of disabled controls around an empty state only add noise.
226
+ */
227
+ const showFooter = computed(() => {
228
+ const data = get$1(paginationData);
229
+ if (!data || __props.hideDefaultFooter) return false;
230
+ return data.total > 0 || __props.hideDefaultHeader;
231
+ });
232
+ /**
233
+ * Grouped columns leave the column list, so their labels come from `cols`.
234
+ */
235
+ const groupLabels = computed(() => get$1(groupKeys).map((key) => {
236
+ const label = __props.cols?.find((column) => column.key === key)?.[__props.columnAttr];
237
+ return {
238
+ key: String(key),
239
+ label: label === void 0 || label === null ? String(key) : String(label)
240
+ };
241
+ }));
242
+ /** Each group's list starts with its header entry, which is not a row. */
243
+ function getGroupSize(identifier) {
244
+ return Math.max((get$1(mappedGroups)[identifier]?.length ?? 0) - 1, 0);
245
+ }
205
246
  const ui = computed(() => dataTableStyles({
206
247
  outlined: __props.outlined,
207
248
  rounded: __props.rounded,
@@ -263,6 +304,7 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
263
304
  tr: s.tr(),
264
305
  trSelected: s.tr({ rowVariant: "selected" }),
265
306
  trExpandable: s.tr({ rowVariant: "expandable" }),
307
+ trExpandedParent: s.tr({ rowVariant: "expandedParent" }),
266
308
  trGroup: s.tr({ rowVariant: "group" }),
267
309
  trEmpty: s.tr({ rowVariant: "empty" }),
268
310
  checkbox: s.checkbox(),
@@ -276,11 +318,13 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
276
318
  colspan,
277
319
  expandable,
278
320
  groupKey,
321
+ groupLabels,
279
322
  isMobile,
280
323
  selectedData,
281
324
  cellValue,
282
325
  columnAttr: __props.columnAttr,
283
326
  dense: __props.dense,
327
+ getGroupSize,
284
328
  getRowId: (row) => row[__props.rowAttr],
285
329
  itemSlotKeys,
286
330
  groupExpandButtonPosition: __props.groupExpandButtonPosition,
@@ -348,6 +392,7 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
348
392
  ref_key: "table",
349
393
  ref: table,
350
394
  class: normalizeClass(unref(ui).table()),
395
+ style: normalizeStyle(unref(viewportStyle)),
351
396
  "aria-busy": __props.loading
352
397
  }, [
353
398
  !unref(isMobile) ? (openBlock(), createBlock(RuiTableHead_default, {
@@ -422,22 +467,31 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
422
467
  filtered: unref(filtered),
423
468
  loading: __props.loading,
424
469
  "no-data": unref(noData),
425
- empty: __props.empty
470
+ empty: __props.empty,
471
+ error: __props.error,
472
+ "error-title": __props.errorTitle,
473
+ "retry-text": __props.retryText,
474
+ onRetry: _cache[5] || (_cache[5] = ($event) => emit("retry"))
426
475
  }, createSlots({ _: 2 }, [
476
+ slots.error ? {
477
+ name: "error",
478
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "error")]),
479
+ key: "0"
480
+ } : void 0,
427
481
  slots["body.prepend"] ? {
428
482
  name: "body.prepend",
429
483
  fn: withCtx((slotData) => [renderSlot(_ctx.$slots, "body.prepend", normalizeProps(guardReactiveProps(slotData)))]),
430
- key: "0"
484
+ key: "1"
431
485
  } : void 0,
432
486
  slots["group.header"] ? {
433
487
  name: "group.header",
434
488
  fn: withCtx((slotData) => [renderSlot(_ctx.$slots, "group.header", normalizeProps(guardReactiveProps(slotData)))]),
435
- key: "1"
489
+ key: "2"
436
490
  } : void 0,
437
491
  slots["group.header.content"] ? {
438
492
  name: "group.header.content",
439
493
  fn: withCtx((slotData) => [renderSlot(_ctx.$slots, "group.header.content", normalizeProps(guardReactiveProps(slotData)))]),
440
- key: "2"
494
+ key: "3"
441
495
  } : void 0,
442
496
  renderList(unref(itemSlotKeys), (key) => {
443
497
  return {
@@ -448,35 +502,38 @@ var RuiDataTable_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
448
502
  slots["expanded-item"] ? {
449
503
  name: "expanded-item",
450
504
  fn: withCtx((slotData) => [renderSlot(_ctx.$slots, "expanded-item", normalizeProps(guardReactiveProps(slotData)))]),
451
- key: "3"
505
+ key: "4"
452
506
  } : void 0,
453
507
  slots["no-data"] ? {
454
508
  name: "no-data",
455
509
  fn: withCtx(() => [renderSlot(_ctx.$slots, "no-data")]),
456
- key: "4"
510
+ key: "5"
457
511
  } : void 0,
458
512
  slots["empty-description"] ? {
459
513
  name: "empty-description",
460
514
  fn: withCtx(() => [renderSlot(_ctx.$slots, "empty-description")]),
461
- key: "5"
515
+ key: "6"
462
516
  } : void 0,
463
517
  slots["body.append"] ? {
464
518
  name: "body.append",
465
519
  fn: withCtx((slotData) => [renderSlot(_ctx.$slots, "body.append", normalizeProps(guardReactiveProps(slotData)))]),
466
- key: "6"
520
+ key: "7"
467
521
  } : void 0
468
522
  ]), 1032, [
469
523
  "filtered",
470
524
  "loading",
471
525
  "no-data",
472
- "empty"
526
+ "empty",
527
+ "error",
528
+ "error-title",
529
+ "retry-text"
473
530
  ]),
474
531
  createElementVNode("tfoot", null, [renderSlot(_ctx.$slots, "tfoot")])
475
- ], 10, _hoisted_2)], 2),
476
- unref(paginationData) && !__props.hideDefaultFooter ? (openBlock(), createBlock(RuiTablePagination_default, {
532
+ ], 14, _hoisted_2)], 2),
533
+ unref(paginationData) && unref(showFooter) ? (openBlock(), createBlock(RuiTablePagination_default, {
477
534
  key: 0,
478
535
  modelValue: unref(paginationData),
479
- "onUpdate:modelValue": [_cache[5] || (_cache[5] = ($event) => isRef(paginationData) ? paginationData.value = $event : null), _cache[6] || (_cache[6] = ($event) => onPaginate())],
536
+ "onUpdate:modelValue": [_cache[6] || (_cache[6] = ($event) => isRef(paginationData) ? paginationData.value = $event : null), _cache[7] || (_cache[7] = ($event) => onPaginate())],
480
537
  dense: __props.dense,
481
538
  loading: __props.loading,
482
539
  mobile: unref(isMobile),