@rotki/ui-library 3.0.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/accordions/accordion/RuiAccordion.js.map +1 -1
- package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js +13 -2
- package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/alerts/RuiAlert.js.map +1 -1
- package/dist/components/alerts/RuiAlert.vue.d.ts +2 -2
- package/dist/components/alerts/RuiAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/buttons/button/RuiButton.js.map +1 -1
- package/dist/components/buttons/button/RuiButton.vue.d.ts +7 -1
- package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/buttons/button/button-props.d.ts +3 -0
- package/dist/components/buttons/button/button-props.js +2 -1
- package/dist/components/buttons/button/button-props.js.map +1 -1
- package/dist/components/buttons/button/button-styles.d.ts +75 -0
- package/dist/components/buttons/button/button-styles.js +135 -4
- package/dist/components/buttons/button/button-styles.js.map +1 -1
- package/dist/components/cards/RuiCard.js.map +1 -1
- package/dist/components/cards/RuiCard.vue.d.ts +6 -0
- package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js +14 -2
- package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/chips/RuiChip.js.map +1 -1
- package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js +15 -1
- package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/chips/chip-props.d.ts +2 -0
- package/dist/components/chips/chip-props.js +3 -0
- package/dist/components/chips/chip-props.js.map +1 -1
- package/dist/components/color-picker/RuiColorInput.js.map +1 -1
- package/dist/components/color-picker/RuiColorInput.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/color-picker/RuiColorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/RuiDateTimePicker.js.map +1 -1
- package/dist/components/date-time-picker/RuiDateTimePicker.vue.d.ts +4 -0
- package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js +6 -2
- package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/RuiDateTimePickerMenu.js.map +1 -1
- package/dist/components/date-time-picker/RuiDateTimePickerMenu.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/date-time-picker/RuiDateTimePickerMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/date-time-picker/RuiTimezoneSelect.js.map +1 -1
- package/dist/components/date-time-picker/RuiTimezoneSelect.vue.d.ts +4 -0
- package/dist/components/date-time-picker/RuiTimezoneSelect.vue_vue_type_script_setup_true_lang.js +3 -2
- package/dist/components/date-time-picker/RuiTimezoneSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoComplete.js.map +1 -1
- package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js +6 -2
- package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/auto-complete/auto-complete-props.d.ts +4 -0
- package/dist/components/forms/category-picker/RuiCategoryPicker.js.map +1 -1
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue.d.ts +4 -1
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue_vue_type_script_setup_true_lang.js +7 -4
- package/dist/components/forms/category-picker/RuiCategoryPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/check-control-styles.d.ts +27 -0
- package/dist/components/forms/check-control-styles.js +26 -1
- package/dist/components/forms/check-control-styles.js.map +1 -1
- package/dist/components/forms/checkbox/RuiCheckbox.js.map +1 -1
- package/dist/components/forms/checkbox/RuiCheckbox.vue.d.ts +6 -0
- package/dist/components/forms/checkbox/RuiCheckbox.vue_vue_type_script_setup_true_lang.js +14 -4
- package/dist/components/forms/checkbox/RuiCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/checkbox/checkbox-group/RuiCheckboxGroup.js.map +1 -1
- package/dist/components/forms/checkbox/checkbox-group/RuiCheckboxGroup.vue.d.ts +4 -0
- package/dist/components/forms/checkbox/checkbox-group/RuiCheckboxGroup.vue_vue_type_script_setup_true_lang.js +7 -2
- package/dist/components/forms/checkbox/checkbox-group/RuiCheckboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/field-defaults/RuiFieldDefaults.js.map +1 -1
- package/dist/components/forms/field-defaults/RuiFieldDefaults.vue.d.ts +3 -0
- package/dist/components/forms/field-defaults/RuiFieldDefaults.vue_vue_type_script_setup_true_lang.js +8 -2
- package/dist/components/forms/field-defaults/RuiFieldDefaults.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/file-upload/RuiFileUpload.js.map +1 -1
- package/dist/components/forms/file-upload/RuiFileUpload.vue.d.ts +4 -1
- package/dist/components/forms/file-upload/RuiFileUpload.vue_vue_type_script_setup_true_lang.js +18 -6
- package/dist/components/forms/file-upload/RuiFileUpload.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/radio-button/radio/RuiRadio.js.map +1 -1
- package/dist/components/forms/radio-button/radio/RuiRadio.vue.d.ts +6 -0
- package/dist/components/forms/radio-button/radio/RuiRadio.vue_vue_type_script_setup_true_lang.js +14 -3
- package/dist/components/forms/radio-button/radio/RuiRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.js.map +1 -1
- package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.vue.d.ts +4 -0
- package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.vue_vue_type_script_setup_true_lang.js +7 -2
- package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/revealable-text-field/RuiRevealableTextField.js.map +1 -1
- package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue_vue_type_script_setup_true_lang.js +3 -2
- package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/select/RuiMenuSelect.js.map +1 -1
- package/dist/components/forms/select/RuiMenuSelect.vue.d.ts +4 -0
- package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js +6 -2
- package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/slider/RuiSlider.js.map +1 -1
- package/dist/components/forms/slider/RuiSlider.vue.d.ts +4 -0
- package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/switch/RuiSwitch.js.map +1 -1
- package/dist/components/forms/switch/RuiSwitch.vue.d.ts +6 -0
- package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js +25 -5
- package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/text-area/RuiTextArea.js.map +1 -1
- package/dist/components/forms/text-area/RuiTextArea.vue.d.ts +4 -0
- package/dist/components/forms/text-area/RuiTextArea.vue_vue_type_script_setup_true_lang.js +6 -4
- package/dist/components/forms/text-area/RuiTextArea.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/text-area/text-area-styles.d.ts +0 -1
- package/dist/components/forms/text-area/text-area-styles.js +6 -7
- package/dist/components/forms/text-area/text-area-styles.js.map +1 -1
- package/dist/components/forms/text-field/RuiTextField.js.map +1 -1
- package/dist/components/forms/text-field/RuiTextField.vue.d.ts +6 -2
- package/dist/components/forms/text-field/RuiTextField.vue_vue_type_script_setup_true_lang.js +6 -4
- package/dist/components/forms/text-field/RuiTextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/forms/text-field/text-field-styles.d.ts +0 -1
- package/dist/components/forms/text-field/text-field-styles.js +6 -7
- package/dist/components/forms/text-field/text-field-styles.js.map +1 -1
- package/dist/components/helpers/RuiFormTextDetail.js.map +1 -1
- package/dist/components/helpers/RuiFormTextDetail.vue.d.ts +14 -0
- package/dist/components/helpers/RuiFormTextDetail.vue_vue_type_script_setup_true_lang.js +41 -11
- package/dist/components/helpers/RuiFormTextDetail.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/loaders/RuiSkeletonBase.js.map +1 -1
- package/dist/components/loaders/RuiSkeletonBase.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/overlays/menu/RuiMenu.js.map +1 -1
- package/dist/components/overlays/menu/RuiMenu.vue.d.ts +3 -0
- package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js +9 -1
- package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiDataTable.js.map +1 -1
- package/dist/components/tables/RuiDataTable.vue.d.ts +4 -0
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js +7 -1
- package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiExpandButton.js.map +1 -1
- package/dist/components/tables/RuiExpandButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTableHead.js.map +1 -1
- package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/RuiTablePagination.js.map +1 -1
- package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableAppendRow.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableAppendRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableRow.js.map +1 -1
- package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/tables/data-table-styles.d.ts +8 -1
- package/dist/components/tables/data-table-styles.js +14 -5
- package/dist/components/tables/data-table-styles.js.map +1 -1
- package/dist/components/tabs/tab-items/RuiTabItems.js.map +1 -1
- package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js +9 -2
- package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/composables/clip-while-resizing.d.ts +15 -0
- package/dist/composables/clip-while-resizing.js +46 -0
- package/dist/composables/clip-while-resizing.js.map +1 -0
- package/dist/composables/defaults/field.d.ts +19 -3
- package/dist/composables/defaults/field.js +32 -6
- package/dist/composables/defaults/field.js.map +1 -1
- package/dist/composables/forms/auto-complete/keyboard-navigation.js.map +1 -1
- package/dist/composables/sticky-blocker.d.ts +20 -0
- package/dist/composables/sticky-blocker.js +62 -0
- package/dist/composables/sticky-blocker.js.map +1 -0
- package/dist/composables/tables/data-table/columns.js.map +1 -1
- package/dist/composables/tables/data-table/selection.js +23 -21
- package/dist/composables/tables/data-table/selection.js.map +1 -1
- package/dist/icons/icons_1.js.map +1 -1
- package/dist/icons/icons_2.js.map +1 -1
- package/dist/icons/icons_3.js.map +1 -1
- package/dist/icons/icons_4.js.map +1 -1
- package/dist/icons/icons_5.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js.map +1 -1
- package/dist/style.css +325 -19
- package/dist/styles/colors.css +4 -0
- package/dist/theme/theme.css +1 -1
- package/dist/theme.css +1 -1
- package/dist/utils/development.d.ts +6 -0
- package/dist/utils/development.js +17 -0
- package/dist/utils/development.js.map +1 -0
- package/dist/utils/form-text-detail.d.ts +15 -0
- package/dist/utils/form-text-detail.js +11 -1
- package/dist/utils/form-text-detail.js.map +1 -1
- package/dist/vite-plugin/types.d.ts +1 -1
- package/dist/web-types.json +232 -3
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiDataTableRow.js","names":["_sfc_main"],"sources":["../../../../src/components/tables/data-table/RuiDataTableRow.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport RuiCheckbox from '@/components/forms/checkbox/RuiCheckbox.vue';\nimport { useDataTableColumns, useDataTableExpansion, useDataTableRowIdentity, useDataTableSelection, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableAppendRow from '@/components/tables/data-table/RuiDataTableAppendRow.vue';\nimport RuiDataTableCell from '@/components/tables/data-table/RuiDataTableCell.vue';\nimport RuiDataTableExpandedRow from '@/components/tables/data-table/RuiDataTableExpandedRow.vue';\nimport RuiExpandButton from '@/components/tables/RuiExpandButton.vue';\n\nconst {\n row,\n index,\n} = defineProps<{\n row: T;\n index: number;\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n }\n>>();\n\nconst { classes, dense, isMobile } = useDataTableStyling();\nconst { cellValue, columns, itemSlotKeys } = useDataTableColumns<T>();\nconst { isDisabledRow, isSelected, onCheckboxClick, onSelect, selectedData } = useDataTableSelection<T>();\nconst { expandable, isExpanded, onToggleExpand } = useDataTableExpansion<T>();\nconst { getRowId, itemClass } = useDataTableRowIdentity<T>();\n\nconst rowId = computed<T[keyof T]>(() => getRowId(row));\nconst selected = computed<boolean>(() => isSelected(get(rowId)));\nconst disabled = computed<boolean>(() => isDisabledRow(get(rowId)));\nconst expanded = computed<boolean>(() => get(expandable) && !!slots['expanded-item'] && isExpanded(get(rowId)));\n\n/** How long a closing panel stays to fade out; matches its `duration-100`. */\nconst PANEL_LEAVE_MS = 100;\n\nconst reducedMotion = usePreferredReducedMotion();\n\n/**\n * Whether the panel is in the DOM, which outlasts `expanded` by its fade-out.\n *\n * @remarks\n * Not a `<Transition>`: test utilities stub that with an element, which lands inside the consumer's\n * `<tbody>` and shifts every `tr:nth-child` its specs count. The fade-in is CSS `@starting-style`.\n */\nconst panelShown = ref<boolean>(get(expanded));\nconst panelClosing = ref<boolean>(false);\n\nconst { start: finishClosing, stop: cancelClosing } = useTimeoutFn(() => {\n set(panelShown, false);\n set(panelClosing, false);\n}, PANEL_LEAVE_MS, { immediate: false });\n\nwatch(expanded, (open) => {\n if (open) {\n cancelClosing();\n set(panelClosing, false);\n set(panelShown, true);\n return;\n }\n if (!get(panelShown))\n return;\n if (get(reducedMotion) === 'reduce') {\n set(panelShown, false);\n return;\n }\n set(panelClosing, true);\n finishClosing();\n});\n\nconst rowClass = computed<string>(() => typeof itemClass === 'string' ? itemClass : itemClass(row));\n\n/** Selection wins over the open-panel shade, so a selected row still reads as selected. */\nconst stateClass = computed<string>(() => {\n if (get(selected))\n return get(classes).trSelected;\n if (get(expanded))\n return get(classes).trExpandedParent;\n return get(classes).tr;\n});\n\n/** Whether the row has a follow-up row, which reads as the second half of the same item. */\nconst appended = computed<boolean>(() => !!slots['row-append']);\n\n/**\n * The stripe follows the item, not the `<tr>`: counting rows would shade an item and its follow-up\n * differently, and an open panel would flip every stripe below it. The table's `striped` variant\n * shades the marked rows.\n */\nconst stripe = computed<'' | undefined>(() => (index % 2 === 1 ? '' : undefined));\n\n/**\n * The two rows of an item highlight together, whichever one the pointer is over. An open row keeps\n * its band rather than taking the hover, as it does without a follow-up.\n */\nconst pairHoverClass = computed<string>(() => {\n if (!get(appended) || get(expanded) || get(isMobile))\n return '';\n return 'has-[+[data-id=row-append]:hover]:bg-rui-neutral-950/[0.03] dark:has-[+[data-id=row-append]:hover]:bg-white/[0.04]';\n});\nconst appendHoverClass = computed<string>(() => {\n if (get(expanded) || get(isMobile))\n return '';\n return '[[data-id=row]:hover+&]:bg-rui-neutral-950/[0.03] dark:[[data-id=row]:hover+&]:bg-white/[0.04]';\n});\n\n/**\n * On mobile the follow-up is the bottom of the item's card: square on top, against the card, and\n * rounded below unless an open panel follows it.\n */\nconst mobileAppendClass = computed<string>(() => {\n const shared = 'block border-x border-b! border-rui-divider overflow-hidden';\n return get(expanded) ? shared : `${shared} rounded-b-rui-card mb-3`;\n});\n\n/**\n * A column is pinned to the mobile card header when it is flagged\n * `mobileHeader`, typically an action column, or when it is the\n * auto-generated expand column.\n */\nfunction isMobileHeaderColumn(column: TableColumn<T>): boolean {\n return !!column.mobileHeader || column.key === 'expand';\n}\n\n/**\n * A pinned column only earns a spot in the header if it renders something: the\n * expand toggle, a provided item slot, or a non-empty cell value. Without this,\n * a pinned column with no content, such as an action column whose\n * `#item.action` slot a nested table does not provide, leaves an empty header\n * bar with just its divider line.\n */\nfunction mobileHeaderColumnHasContent(column: TableColumn<T>): boolean {\n if (column.key === 'expand')\n return true;\n if (itemSlotKeys.has(column.key.toString()))\n return true;\n const value = cellValue(row, column.key);\n return value !== undefined && value !== null && value !== '';\n}\n\n/**\n * In the stacked mobile layout, header columns render in the card header row\n * instead of as a label/value pair. Everything else stacks below in the body.\n */\nconst mobileHeaderColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => isMobileHeaderColumn(column) && mobileHeaderColumnHasContent(column)) : [],\n);\nconst bodyColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => !isMobileHeaderColumn(column)) : get(columns),\n);\nconst showMobileHeader = computed<boolean>(() =>\n get(isMobile) && (!!get(selectedData) || get(mobileHeaderColumns).length > 0),\n);\n\n/**\n * Without a selection checkbox the header bar would hold only the pinned\n * actions, so they float in the card's top-right corner instead and the first\n * field row makes room for them.\n */\nconst compactMobileHeader = computed<boolean>(() =>\n get(showMobileHeader) && !get(selectedData) && get(bodyColumns).length > 0,\n);\n\n/** Room for each floating action, about one small icon button wide. */\nconst firstRowInset = computed<Record<string, string> | undefined>(() =>\n get(compactMobileHeader) ? { paddingRight: `${get(mobileHeaderColumns).length * 2 + 1}rem` } : undefined,\n);\n\n/**\n * `border-y!` defeats the `divide-y-0` on the mobile tbody, which otherwise\n * zeroes the top and bottom border on every card except the first. An expanded\n * card flattens its bottom edge so the expanded panel attaches flush beneath\n * it. A card with a follow-up row drops its bottom border too, so the\n * follow-up continues it with no line between them, as on desktop.\n *\n * These bindings do not run through the class merger, so each state picks its\n * own utilities rather than emitting conflicting ones.\n */\nconst mobileCardClass = computed<string>(() => {\n if (get(appended))\n return 'relative flex flex-col border-x border-t! border-rui-divider overflow-hidden rounded-t-rui-card mb-0';\n const shared = 'relative flex flex-col border border-y! border-rui-divider overflow-hidden';\n return get(expanded)\n ? `${shared} rounded-t-rui-card mb-0`\n : `${shared} rounded-rui-card mb-3 last:mb-0`;\n});\n</script>\n\n<template>\n <tr\n :class=\"[stateClass, rowClass, pairHoverClass, isMobile ? mobileCardClass : '']\"\n :aria-selected=\"selectedData ? selected : undefined\"\n :data-stripe=\"stripe\"\n data-id=\"row\"\n >\n <!-- Mobile card header: checkbox on the left, pinned action columns on the right -->\n <td\n v-if=\"showMobileHeader\"\n :class=\"compactMobileHeader\n ? 'absolute top-0 right-0 z-1 flex items-center gap-1 px-2 py-1'\n : 'flex items-center justify-between gap-2 px-4 py-2 border-b border-rui-divider'\"\n data-id=\"mobile-card-header\"\n >\n <RuiCheckbox\n v-if=\"selectedData\"\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n <span v-else-if=\"!compactMobileHeader\" />\n\n <div\n v-if=\"mobileHeaderColumns.length > 0\"\n class=\"flex items-center gap-1 min-w-0\"\n >\n <template\n v-for=\"(column, headerIndex) in mobileHeaderColumns\"\n :key=\"`header-${headerIndex}`\"\n >\n <slot\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n :name=\"`item.${column.key.toString()}`\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n />\n <RuiExpandButton\n v-else-if=\"column.key === 'expand'\"\n :expanded=\"isExpanded(rowId)\"\n @click=\"onToggleExpand(row)\"\n />\n <template v-else>\n {{ cellValue(row, column.key) }}\n </template>\n </template>\n </div>\n </td>\n\n <!-- Desktop checkbox cell -->\n <td\n v-else-if=\"selectedData && !isMobile\"\n :class=\"classes.checkbox\"\n colspan=\"1\"\n rowspan=\"1\"\n >\n <RuiCheckbox\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n </td>\n\n <RuiDataTableCell\n v-for=\"(column, subIndex) in bodyColumns\"\n :key=\"subIndex\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n :row-id=\"rowId\"\n :style=\"subIndex === 0 ? firstRowInset : undefined\"\n >\n <template\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n #default=\"slotData\"\n >\n <slot\n :name=\"`item.${column.key.toString()}`\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableCell>\n </tr>\n\n <!-- no divider above: with its row it is one item, sharing the row's state, stripe and hover -->\n <RuiDataTableAppendRow\n v-if=\"slots['row-append']\"\n class=\"border-t-0!\"\n :class=\"[stateClass, rowClass, appendHoverClass, isMobile ? mobileAppendClass : '']\"\n :data-stripe=\"stripe\"\n :row=\"row\"\n :index=\"index\"\n >\n <template #row-append=\"slotData\">\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableAppendRow>\n\n <!-- opacity only: the rows below move once, at once, rather than sliding with a growing height -->\n <RuiDataTableExpandedRow\n v-if=\"panelShown\"\n class=\"transition-opacity starting:opacity-0 motion-reduce:transition-none\"\n :class=\"panelClosing ? 'opacity-0 duration-100 ease-in' : 'duration-150 ease-out'\"\n :row=\"row\"\n :index=\"index\"\n >\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 </RuiDataTableExpandedRow>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RuiDataTableRow.js","names":["_sfc_main"],"sources":["../../../../src/components/tables/data-table/RuiDataTableRow.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport RuiCheckbox from '@/components/forms/checkbox/RuiCheckbox.vue';\nimport { useDataTableColumns, useDataTableExpansion, useDataTableRowIdentity, useDataTableSelection, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableAppendRow from '@/components/tables/data-table/RuiDataTableAppendRow.vue';\nimport RuiDataTableCell from '@/components/tables/data-table/RuiDataTableCell.vue';\nimport RuiDataTableExpandedRow from '@/components/tables/data-table/RuiDataTableExpandedRow.vue';\nimport RuiExpandButton from '@/components/tables/RuiExpandButton.vue';\n\nconst {\n row,\n index,\n} = defineProps<{\n row: T;\n index: number;\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n }\n>>();\n\nconst { classes, dense, isMobile } = useDataTableStyling();\nconst { cellValue, columns, itemSlotKeys } = useDataTableColumns<T>();\nconst { isDisabledRow, isSelected, onCheckboxClick, onSelect, selectedData } = useDataTableSelection<T>();\nconst { expandable, isExpanded, onToggleExpand } = useDataTableExpansion<T>();\nconst { getRowId, itemClass } = useDataTableRowIdentity<T>();\n\nconst rowId = computed<T[keyof T]>(() => getRowId(row));\nconst selected = computed<boolean>(() => isSelected(get(rowId)));\nconst disabled = computed<boolean>(() => isDisabledRow(get(rowId)));\nconst expanded = computed<boolean>(() => get(expandable) && !!slots['expanded-item'] && isExpanded(get(rowId)));\n\n/** How long a closing panel stays to fade out; matches its `duration-100`. */\nconst PANEL_LEAVE_MS = 100;\n\nconst reducedMotion = usePreferredReducedMotion();\n\n/**\n * Whether the panel is in the DOM, which outlasts `expanded` by its fade-out.\n *\n * @remarks\n * Not a `<Transition>`: test utilities stub that with an element, which lands inside the consumer's\n * `<tbody>` and shifts every `tr:nth-child` its specs count. The fade-in is CSS `@starting-style`.\n */\nconst panelShown = ref<boolean>(get(expanded));\nconst panelClosing = ref<boolean>(false);\n\nconst { start: finishClosing, stop: cancelClosing } = useTimeoutFn(() => {\n set(panelShown, false);\n set(panelClosing, false);\n}, PANEL_LEAVE_MS, { immediate: false });\n\nwatch(expanded, (open) => {\n if (open) {\n cancelClosing();\n set(panelClosing, false);\n set(panelShown, true);\n return;\n }\n if (!get(panelShown))\n return;\n if (get(reducedMotion) === 'reduce') {\n set(panelShown, false);\n return;\n }\n set(panelClosing, true);\n finishClosing();\n});\n\nconst rowClass = computed<string>(() => typeof itemClass === 'string' ? itemClass : itemClass(row));\n\n/** Selection wins over the open-panel shade, so a selected row still reads as selected. */\nconst stateClass = computed<string>(() => {\n if (get(selected))\n return get(classes).trSelected;\n if (get(expanded))\n return get(classes).trExpandedParent;\n return get(classes).tr;\n});\n\n/** Whether the row has a follow-up row, which reads as the second half of the same item. */\nconst appended = computed<boolean>(() => !!slots['row-append']);\n\n/**\n * The stripe follows the item, not the `<tr>`: counting rows would shade an item and its follow-up\n * differently, and an open panel would flip every stripe below it. The table's `striped` variant\n * shades the marked rows.\n */\nconst stripe = computed<'' | undefined>(() => (index % 2 === 1 ? '' : undefined));\n\n/**\n * The two rows of an item highlight together, whichever one the pointer is over. An open row keeps\n * its band rather than taking the hover, as it does without a follow-up.\n */\nconst pairHoverClass = computed<string>(() => {\n if (!get(appended) || get(expanded) || get(isMobile))\n return '';\n return 'has-[+[data-id=row-append]:hover]:bg-rui-neutral-950/[0.03] dark:has-[+[data-id=row-append]:hover]:bg-white/[0.04]';\n});\nconst appendHoverClass = computed<string>(() => {\n if (get(expanded) || get(isMobile))\n return '';\n return '[[data-id=row]:hover+&]:bg-rui-neutral-950/[0.03] dark:[[data-id=row]:hover+&]:bg-white/[0.04]';\n});\n\n/**\n * On mobile the follow-up is the bottom of the item's card: square on top, against the card, and\n * rounded below unless an open panel follows it.\n */\nconst mobileAppendClass = computed<string>(() => {\n const shared = 'block border-x border-b! border-rui-divider overflow-hidden';\n return get(expanded) ? shared : `${shared} rounded-b-rui-card mb-3`;\n});\n\n/**\n * A column is pinned to the mobile card header when it is flagged\n * `mobileHeader`, typically an action column, or when it is the\n * auto-generated expand column.\n */\nfunction isMobileHeaderColumn(column: TableColumn<T>): boolean {\n return !!column.mobileHeader || column.key === 'expand';\n}\n\n/**\n * A pinned column only earns a spot in the header if it renders something: the\n * expand toggle, a provided item slot, or a non-empty cell value. Without this,\n * a pinned column with no content, such as an action column whose\n * `#item.action` slot a nested table does not provide, leaves an empty header\n * bar with just its divider line.\n */\nfunction mobileHeaderColumnHasContent(column: TableColumn<T>): boolean {\n if (column.key === 'expand')\n return true;\n if (itemSlotKeys.has(column.key.toString()))\n return true;\n const value = cellValue(row, column.key);\n return value !== undefined && value !== null && value !== '';\n}\n\n/**\n * In the stacked mobile layout, header columns render in the card header row\n * instead of as a label/value pair. Everything else stacks below in the body.\n */\nconst mobileHeaderColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => isMobileHeaderColumn(column) && mobileHeaderColumnHasContent(column)) : [],\n);\nconst bodyColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => !isMobileHeaderColumn(column)) : get(columns),\n);\nconst showMobileHeader = computed<boolean>(() =>\n get(isMobile) && (!!get(selectedData) || get(mobileHeaderColumns).length > 0),\n);\n\n/**\n * Without a selection checkbox the header bar would hold only the pinned\n * actions, so they float in the card's top-right corner instead and the first\n * field row makes room for them.\n */\nconst compactMobileHeader = computed<boolean>(() =>\n get(showMobileHeader) && !get(selectedData) && get(bodyColumns).length > 0,\n);\n\n/** Room for each floating action, about one small icon button wide. */\nconst firstRowInset = computed<Record<string, string> | undefined>(() =>\n get(compactMobileHeader) ? { paddingRight: `${get(mobileHeaderColumns).length * 2 + 1}rem` } : undefined,\n);\n\n/**\n * `border-y!` defeats the `divide-y-0` on the mobile tbody, which otherwise\n * zeroes the top and bottom border on every card except the first. An expanded\n * card flattens its bottom edge so the expanded panel attaches flush beneath\n * it. A card with a follow-up row drops its bottom border too, so the\n * follow-up continues it with no line between them, as on desktop.\n *\n * These bindings do not run through the class merger, so each state picks its\n * own utilities rather than emitting conflicting ones.\n */\nconst mobileCardClass = computed<string>(() => {\n if (get(appended))\n return 'relative flex flex-col border-x border-t! border-rui-divider overflow-hidden rounded-t-rui-card mb-0';\n const shared = 'relative flex flex-col border border-y! border-rui-divider overflow-hidden';\n return get(expanded)\n ? `${shared} rounded-t-rui-card mb-0`\n : `${shared} rounded-rui-card mb-3 last:mb-0`;\n});\n</script>\n\n<template>\n <tr\n :class=\"[stateClass, rowClass, pairHoverClass, isMobile ? mobileCardClass : '']\"\n :aria-selected=\"selectedData ? selected : undefined\"\n :data-stripe=\"stripe\"\n data-id=\"row\"\n >\n <!-- Mobile card header: checkbox on the left, pinned action columns on the right -->\n <td\n v-if=\"showMobileHeader\"\n :class=\"compactMobileHeader\n ? 'absolute top-0 right-0 z-1 flex items-center gap-1 px-2 py-1'\n : 'flex items-center justify-between gap-2 px-4 py-2 border-b border-rui-divider'\"\n data-id=\"mobile-card-header\"\n >\n <RuiCheckbox\n v-if=\"selectedData\"\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n details=\"hidden\"\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n <span v-else-if=\"!compactMobileHeader\" />\n\n <div\n v-if=\"mobileHeaderColumns.length > 0\"\n class=\"flex items-center gap-1 min-w-0\"\n >\n <template\n v-for=\"(column, headerIndex) in mobileHeaderColumns\"\n :key=\"`header-${headerIndex}`\"\n >\n <slot\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n :name=\"`item.${column.key.toString()}`\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n />\n <RuiExpandButton\n v-else-if=\"column.key === 'expand'\"\n :expanded=\"isExpanded(rowId)\"\n @click=\"onToggleExpand(row)\"\n />\n <template v-else>\n {{ cellValue(row, column.key) }}\n </template>\n </template>\n </div>\n </td>\n\n <!-- Desktop checkbox cell -->\n <td\n v-else-if=\"selectedData && !isMobile\"\n :class=\"classes.checkbox\"\n colspan=\"1\"\n rowspan=\"1\"\n >\n <RuiCheckbox\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n details=\"hidden\"\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n </td>\n\n <RuiDataTableCell\n v-for=\"(column, subIndex) in bodyColumns\"\n :key=\"subIndex\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n :row-id=\"rowId\"\n :style=\"subIndex === 0 ? firstRowInset : undefined\"\n >\n <template\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n #default=\"slotData\"\n >\n <slot\n :name=\"`item.${column.key.toString()}`\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableCell>\n </tr>\n\n <!-- no divider above: with its row it is one item, sharing the row's state, stripe and hover -->\n <RuiDataTableAppendRow\n v-if=\"slots['row-append']\"\n class=\"border-t-0!\"\n :class=\"[stateClass, rowClass, appendHoverClass, isMobile ? mobileAppendClass : '']\"\n :data-stripe=\"stripe\"\n :row=\"row\"\n :index=\"index\"\n >\n <template #row-append=\"slotData\">\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableAppendRow>\n\n <!-- opacity only: the rows below move once, at once, rather than sliding with a growing height -->\n <RuiDataTableExpandedRow\n v-if=\"panelShown\"\n class=\"transition-opacity starting:opacity-0 motion-reduce:transition-none\"\n :class=\"panelClosing ? 'opacity-0 duration-100 ease-in' : 'duration-150 ease-out'\"\n :row=\"row\"\n :index=\"index\"\n >\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 </RuiDataTableExpandedRow>\n</template>\n"],"mappings":""}
|
package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -173,7 +173,7 @@ var RuiDataTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
173
173
|
size: unref(dense) ? "sm" : void 0,
|
|
174
174
|
color: "primary",
|
|
175
175
|
class: "select-none",
|
|
176
|
-
|
|
176
|
+
details: "hidden",
|
|
177
177
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => unref(onSelect)($event, unref(rowId), true)),
|
|
178
178
|
onClick: _cache[1] || (_cache[1] = ($event) => unref(onCheckboxClick)($event, unref(rowId), __props.index))
|
|
179
179
|
}, null, 8, [
|
|
@@ -204,7 +204,7 @@ var RuiDataTableRow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
204
204
|
size: unref(dense) ? "sm" : void 0,
|
|
205
205
|
color: "primary",
|
|
206
206
|
class: "select-none",
|
|
207
|
-
|
|
207
|
+
details: "hidden",
|
|
208
208
|
"onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => unref(onSelect)($event, unref(rowId), true)),
|
|
209
209
|
onClick: _cache[4] || (_cache[4] = ($event) => unref(onCheckboxClick)($event, unref(rowId), __props.index))
|
|
210
210
|
}, null, 8, [
|
package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiDataTableRow.vue_vue_type_script_setup_true_lang.js","names":["_useSlots","_openBlock","_createElementBlock","_Fragment","_createElementVNode","_normalizeClass","_unref","_createBlock","RuiCheckbox","_createCommentVNode","_renderList","_renderSlot","RuiExpandButton","_createTextVNode","_toDisplayString","_createVNode","RuiDataTableCell","_normalizeStyle","_createSlots","_withCtx","_mergeProps","RuiDataTableAppendRow","_normalizeProps","_guardReactiveProps","RuiDataTableExpandedRow"],"sources":["../../../../src/components/tables/data-table/RuiDataTableRow.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport RuiCheckbox from '@/components/forms/checkbox/RuiCheckbox.vue';\nimport { useDataTableColumns, useDataTableExpansion, useDataTableRowIdentity, useDataTableSelection, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableAppendRow from '@/components/tables/data-table/RuiDataTableAppendRow.vue';\nimport RuiDataTableCell from '@/components/tables/data-table/RuiDataTableCell.vue';\nimport RuiDataTableExpandedRow from '@/components/tables/data-table/RuiDataTableExpandedRow.vue';\nimport RuiExpandButton from '@/components/tables/RuiExpandButton.vue';\n\nconst {\n row,\n index,\n} = defineProps<{\n row: T;\n index: number;\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n }\n>>();\n\nconst { classes, dense, isMobile } = useDataTableStyling();\nconst { cellValue, columns, itemSlotKeys } = useDataTableColumns<T>();\nconst { isDisabledRow, isSelected, onCheckboxClick, onSelect, selectedData } = useDataTableSelection<T>();\nconst { expandable, isExpanded, onToggleExpand } = useDataTableExpansion<T>();\nconst { getRowId, itemClass } = useDataTableRowIdentity<T>();\n\nconst rowId = computed<T[keyof T]>(() => getRowId(row));\nconst selected = computed<boolean>(() => isSelected(get(rowId)));\nconst disabled = computed<boolean>(() => isDisabledRow(get(rowId)));\nconst expanded = computed<boolean>(() => get(expandable) && !!slots['expanded-item'] && isExpanded(get(rowId)));\n\n/** How long a closing panel stays to fade out; matches its `duration-100`. */\nconst PANEL_LEAVE_MS = 100;\n\nconst reducedMotion = usePreferredReducedMotion();\n\n/**\n * Whether the panel is in the DOM, which outlasts `expanded` by its fade-out.\n *\n * @remarks\n * Not a `<Transition>`: test utilities stub that with an element, which lands inside the consumer's\n * `<tbody>` and shifts every `tr:nth-child` its specs count. The fade-in is CSS `@starting-style`.\n */\nconst panelShown = ref<boolean>(get(expanded));\nconst panelClosing = ref<boolean>(false);\n\nconst { start: finishClosing, stop: cancelClosing } = useTimeoutFn(() => {\n set(panelShown, false);\n set(panelClosing, false);\n}, PANEL_LEAVE_MS, { immediate: false });\n\nwatch(expanded, (open) => {\n if (open) {\n cancelClosing();\n set(panelClosing, false);\n set(panelShown, true);\n return;\n }\n if (!get(panelShown))\n return;\n if (get(reducedMotion) === 'reduce') {\n set(panelShown, false);\n return;\n }\n set(panelClosing, true);\n finishClosing();\n});\n\nconst rowClass = computed<string>(() => typeof itemClass === 'string' ? itemClass : itemClass(row));\n\n/** Selection wins over the open-panel shade, so a selected row still reads as selected. */\nconst stateClass = computed<string>(() => {\n if (get(selected))\n return get(classes).trSelected;\n if (get(expanded))\n return get(classes).trExpandedParent;\n return get(classes).tr;\n});\n\n/** Whether the row has a follow-up row, which reads as the second half of the same item. */\nconst appended = computed<boolean>(() => !!slots['row-append']);\n\n/**\n * The stripe follows the item, not the `<tr>`: counting rows would shade an item and its follow-up\n * differently, and an open panel would flip every stripe below it. The table's `striped` variant\n * shades the marked rows.\n */\nconst stripe = computed<'' | undefined>(() => (index % 2 === 1 ? '' : undefined));\n\n/**\n * The two rows of an item highlight together, whichever one the pointer is over. An open row keeps\n * its band rather than taking the hover, as it does without a follow-up.\n */\nconst pairHoverClass = computed<string>(() => {\n if (!get(appended) || get(expanded) || get(isMobile))\n return '';\n return 'has-[+[data-id=row-append]:hover]:bg-rui-neutral-950/[0.03] dark:has-[+[data-id=row-append]:hover]:bg-white/[0.04]';\n});\nconst appendHoverClass = computed<string>(() => {\n if (get(expanded) || get(isMobile))\n return '';\n return '[[data-id=row]:hover+&]:bg-rui-neutral-950/[0.03] dark:[[data-id=row]:hover+&]:bg-white/[0.04]';\n});\n\n/**\n * On mobile the follow-up is the bottom of the item's card: square on top, against the card, and\n * rounded below unless an open panel follows it.\n */\nconst mobileAppendClass = computed<string>(() => {\n const shared = 'block border-x border-b! border-rui-divider overflow-hidden';\n return get(expanded) ? shared : `${shared} rounded-b-rui-card mb-3`;\n});\n\n/**\n * A column is pinned to the mobile card header when it is flagged\n * `mobileHeader`, typically an action column, or when it is the\n * auto-generated expand column.\n */\nfunction isMobileHeaderColumn(column: TableColumn<T>): boolean {\n return !!column.mobileHeader || column.key === 'expand';\n}\n\n/**\n * A pinned column only earns a spot in the header if it renders something: the\n * expand toggle, a provided item slot, or a non-empty cell value. Without this,\n * a pinned column with no content, such as an action column whose\n * `#item.action` slot a nested table does not provide, leaves an empty header\n * bar with just its divider line.\n */\nfunction mobileHeaderColumnHasContent(column: TableColumn<T>): boolean {\n if (column.key === 'expand')\n return true;\n if (itemSlotKeys.has(column.key.toString()))\n return true;\n const value = cellValue(row, column.key);\n return value !== undefined && value !== null && value !== '';\n}\n\n/**\n * In the stacked mobile layout, header columns render in the card header row\n * instead of as a label/value pair. Everything else stacks below in the body.\n */\nconst mobileHeaderColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => isMobileHeaderColumn(column) && mobileHeaderColumnHasContent(column)) : [],\n);\nconst bodyColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => !isMobileHeaderColumn(column)) : get(columns),\n);\nconst showMobileHeader = computed<boolean>(() =>\n get(isMobile) && (!!get(selectedData) || get(mobileHeaderColumns).length > 0),\n);\n\n/**\n * Without a selection checkbox the header bar would hold only the pinned\n * actions, so they float in the card's top-right corner instead and the first\n * field row makes room for them.\n */\nconst compactMobileHeader = computed<boolean>(() =>\n get(showMobileHeader) && !get(selectedData) && get(bodyColumns).length > 0,\n);\n\n/** Room for each floating action, about one small icon button wide. */\nconst firstRowInset = computed<Record<string, string> | undefined>(() =>\n get(compactMobileHeader) ? { paddingRight: `${get(mobileHeaderColumns).length * 2 + 1}rem` } : undefined,\n);\n\n/**\n * `border-y!` defeats the `divide-y-0` on the mobile tbody, which otherwise\n * zeroes the top and bottom border on every card except the first. An expanded\n * card flattens its bottom edge so the expanded panel attaches flush beneath\n * it. A card with a follow-up row drops its bottom border too, so the\n * follow-up continues it with no line between them, as on desktop.\n *\n * These bindings do not run through the class merger, so each state picks its\n * own utilities rather than emitting conflicting ones.\n */\nconst mobileCardClass = computed<string>(() => {\n if (get(appended))\n return 'relative flex flex-col border-x border-t! border-rui-divider overflow-hidden rounded-t-rui-card mb-0';\n const shared = 'relative flex flex-col border border-y! border-rui-divider overflow-hidden';\n return get(expanded)\n ? `${shared} rounded-t-rui-card mb-0`\n : `${shared} rounded-rui-card mb-3 last:mb-0`;\n});\n</script>\n\n<template>\n <tr\n :class=\"[stateClass, rowClass, pairHoverClass, isMobile ? mobileCardClass : '']\"\n :aria-selected=\"selectedData ? selected : undefined\"\n :data-stripe=\"stripe\"\n data-id=\"row\"\n >\n <!-- Mobile card header: checkbox on the left, pinned action columns on the right -->\n <td\n v-if=\"showMobileHeader\"\n :class=\"compactMobileHeader\n ? 'absolute top-0 right-0 z-1 flex items-center gap-1 px-2 py-1'\n : 'flex items-center justify-between gap-2 px-4 py-2 border-b border-rui-divider'\"\n data-id=\"mobile-card-header\"\n >\n <RuiCheckbox\n v-if=\"selectedData\"\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n <span v-else-if=\"!compactMobileHeader\" />\n\n <div\n v-if=\"mobileHeaderColumns.length > 0\"\n class=\"flex items-center gap-1 min-w-0\"\n >\n <template\n v-for=\"(column, headerIndex) in mobileHeaderColumns\"\n :key=\"`header-${headerIndex}`\"\n >\n <slot\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n :name=\"`item.${column.key.toString()}`\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n />\n <RuiExpandButton\n v-else-if=\"column.key === 'expand'\"\n :expanded=\"isExpanded(rowId)\"\n @click=\"onToggleExpand(row)\"\n />\n <template v-else>\n {{ cellValue(row, column.key) }}\n </template>\n </template>\n </div>\n </td>\n\n <!-- Desktop checkbox cell -->\n <td\n v-else-if=\"selectedData && !isMobile\"\n :class=\"classes.checkbox\"\n colspan=\"1\"\n rowspan=\"1\"\n >\n <RuiCheckbox\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n hide-details\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n </td>\n\n <RuiDataTableCell\n v-for=\"(column, subIndex) in bodyColumns\"\n :key=\"subIndex\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n :row-id=\"rowId\"\n :style=\"subIndex === 0 ? firstRowInset : undefined\"\n >\n <template\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n #default=\"slotData\"\n >\n <slot\n :name=\"`item.${column.key.toString()}`\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableCell>\n </tr>\n\n <!-- no divider above: with its row it is one item, sharing the row's state, stripe and hover -->\n <RuiDataTableAppendRow\n v-if=\"slots['row-append']\"\n class=\"border-t-0!\"\n :class=\"[stateClass, rowClass, appendHoverClass, isMobile ? mobileAppendClass : '']\"\n :data-stripe=\"stripe\"\n :row=\"row\"\n :index=\"index\"\n >\n <template #row-append=\"slotData\">\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableAppendRow>\n\n <!-- opacity only: the rows below move once, at once, rather than sliding with a growing height -->\n <RuiDataTableExpandedRow\n v-if=\"panelShown\"\n class=\"transition-opacity starting:opacity-0 motion-reduce:transition-none\"\n :class=\"panelClosing ? 'opacity-0 duration-100 ease-in' : 'duration-150 ease-out'\"\n :row=\"row\"\n :index=\"index\"\n >\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 </RuiDataTableExpandedRow>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RuiDataTableRow.vue_vue_type_script_setup_true_lang.js","names":["_useSlots","_openBlock","_createElementBlock","_Fragment","_createElementVNode","_normalizeClass","_unref","_createBlock","RuiCheckbox","_createCommentVNode","_renderList","_renderSlot","RuiExpandButton","_createTextVNode","_toDisplayString","_createVNode","RuiDataTableCell","_normalizeStyle","_createSlots","_withCtx","_mergeProps","RuiDataTableAppendRow","_normalizeProps","_guardReactiveProps","RuiDataTableExpandedRow"],"sources":["../../../../src/components/tables/data-table/RuiDataTableRow.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends object\">\nimport type { TableColumn } from '@/components/tables/RuiTableHead.vue';\nimport RuiCheckbox from '@/components/forms/checkbox/RuiCheckbox.vue';\nimport { useDataTableColumns, useDataTableExpansion, useDataTableRowIdentity, useDataTableSelection, useDataTableStyling } from '@/components/tables/data-table/context';\nimport RuiDataTableAppendRow from '@/components/tables/data-table/RuiDataTableAppendRow.vue';\nimport RuiDataTableCell from '@/components/tables/data-table/RuiDataTableCell.vue';\nimport RuiDataTableExpandedRow from '@/components/tables/data-table/RuiDataTableExpandedRow.vue';\nimport RuiExpandButton from '@/components/tables/RuiExpandButton.vue';\n\nconst {\n row,\n index,\n} = defineProps<{\n row: T;\n index: number;\n}>();\n\nconst slots = defineSlots<Partial<\n Record<`item.${string}`, (props: { column: TableColumn<T>; row: T; index: number }) => any> & {\n 'expanded-item'?: (props: { row: T; index: number }) => any;\n 'row-append'?: (props: { row: T; index: number }) => any;\n }\n>>();\n\nconst { classes, dense, isMobile } = useDataTableStyling();\nconst { cellValue, columns, itemSlotKeys } = useDataTableColumns<T>();\nconst { isDisabledRow, isSelected, onCheckboxClick, onSelect, selectedData } = useDataTableSelection<T>();\nconst { expandable, isExpanded, onToggleExpand } = useDataTableExpansion<T>();\nconst { getRowId, itemClass } = useDataTableRowIdentity<T>();\n\nconst rowId = computed<T[keyof T]>(() => getRowId(row));\nconst selected = computed<boolean>(() => isSelected(get(rowId)));\nconst disabled = computed<boolean>(() => isDisabledRow(get(rowId)));\nconst expanded = computed<boolean>(() => get(expandable) && !!slots['expanded-item'] && isExpanded(get(rowId)));\n\n/** How long a closing panel stays to fade out; matches its `duration-100`. */\nconst PANEL_LEAVE_MS = 100;\n\nconst reducedMotion = usePreferredReducedMotion();\n\n/**\n * Whether the panel is in the DOM, which outlasts `expanded` by its fade-out.\n *\n * @remarks\n * Not a `<Transition>`: test utilities stub that with an element, which lands inside the consumer's\n * `<tbody>` and shifts every `tr:nth-child` its specs count. The fade-in is CSS `@starting-style`.\n */\nconst panelShown = ref<boolean>(get(expanded));\nconst panelClosing = ref<boolean>(false);\n\nconst { start: finishClosing, stop: cancelClosing } = useTimeoutFn(() => {\n set(panelShown, false);\n set(panelClosing, false);\n}, PANEL_LEAVE_MS, { immediate: false });\n\nwatch(expanded, (open) => {\n if (open) {\n cancelClosing();\n set(panelClosing, false);\n set(panelShown, true);\n return;\n }\n if (!get(panelShown))\n return;\n if (get(reducedMotion) === 'reduce') {\n set(panelShown, false);\n return;\n }\n set(panelClosing, true);\n finishClosing();\n});\n\nconst rowClass = computed<string>(() => typeof itemClass === 'string' ? itemClass : itemClass(row));\n\n/** Selection wins over the open-panel shade, so a selected row still reads as selected. */\nconst stateClass = computed<string>(() => {\n if (get(selected))\n return get(classes).trSelected;\n if (get(expanded))\n return get(classes).trExpandedParent;\n return get(classes).tr;\n});\n\n/** Whether the row has a follow-up row, which reads as the second half of the same item. */\nconst appended = computed<boolean>(() => !!slots['row-append']);\n\n/**\n * The stripe follows the item, not the `<tr>`: counting rows would shade an item and its follow-up\n * differently, and an open panel would flip every stripe below it. The table's `striped` variant\n * shades the marked rows.\n */\nconst stripe = computed<'' | undefined>(() => (index % 2 === 1 ? '' : undefined));\n\n/**\n * The two rows of an item highlight together, whichever one the pointer is over. An open row keeps\n * its band rather than taking the hover, as it does without a follow-up.\n */\nconst pairHoverClass = computed<string>(() => {\n if (!get(appended) || get(expanded) || get(isMobile))\n return '';\n return 'has-[+[data-id=row-append]:hover]:bg-rui-neutral-950/[0.03] dark:has-[+[data-id=row-append]:hover]:bg-white/[0.04]';\n});\nconst appendHoverClass = computed<string>(() => {\n if (get(expanded) || get(isMobile))\n return '';\n return '[[data-id=row]:hover+&]:bg-rui-neutral-950/[0.03] dark:[[data-id=row]:hover+&]:bg-white/[0.04]';\n});\n\n/**\n * On mobile the follow-up is the bottom of the item's card: square on top, against the card, and\n * rounded below unless an open panel follows it.\n */\nconst mobileAppendClass = computed<string>(() => {\n const shared = 'block border-x border-b! border-rui-divider overflow-hidden';\n return get(expanded) ? shared : `${shared} rounded-b-rui-card mb-3`;\n});\n\n/**\n * A column is pinned to the mobile card header when it is flagged\n * `mobileHeader`, typically an action column, or when it is the\n * auto-generated expand column.\n */\nfunction isMobileHeaderColumn(column: TableColumn<T>): boolean {\n return !!column.mobileHeader || column.key === 'expand';\n}\n\n/**\n * A pinned column only earns a spot in the header if it renders something: the\n * expand toggle, a provided item slot, or a non-empty cell value. Without this,\n * a pinned column with no content, such as an action column whose\n * `#item.action` slot a nested table does not provide, leaves an empty header\n * bar with just its divider line.\n */\nfunction mobileHeaderColumnHasContent(column: TableColumn<T>): boolean {\n if (column.key === 'expand')\n return true;\n if (itemSlotKeys.has(column.key.toString()))\n return true;\n const value = cellValue(row, column.key);\n return value !== undefined && value !== null && value !== '';\n}\n\n/**\n * In the stacked mobile layout, header columns render in the card header row\n * instead of as a label/value pair. Everything else stacks below in the body.\n */\nconst mobileHeaderColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => isMobileHeaderColumn(column) && mobileHeaderColumnHasContent(column)) : [],\n);\nconst bodyColumns = computed<TableColumn<T>[]>(() =>\n get(isMobile) ? get(columns).filter(column => !isMobileHeaderColumn(column)) : get(columns),\n);\nconst showMobileHeader = computed<boolean>(() =>\n get(isMobile) && (!!get(selectedData) || get(mobileHeaderColumns).length > 0),\n);\n\n/**\n * Without a selection checkbox the header bar would hold only the pinned\n * actions, so they float in the card's top-right corner instead and the first\n * field row makes room for them.\n */\nconst compactMobileHeader = computed<boolean>(() =>\n get(showMobileHeader) && !get(selectedData) && get(bodyColumns).length > 0,\n);\n\n/** Room for each floating action, about one small icon button wide. */\nconst firstRowInset = computed<Record<string, string> | undefined>(() =>\n get(compactMobileHeader) ? { paddingRight: `${get(mobileHeaderColumns).length * 2 + 1}rem` } : undefined,\n);\n\n/**\n * `border-y!` defeats the `divide-y-0` on the mobile tbody, which otherwise\n * zeroes the top and bottom border on every card except the first. An expanded\n * card flattens its bottom edge so the expanded panel attaches flush beneath\n * it. A card with a follow-up row drops its bottom border too, so the\n * follow-up continues it with no line between them, as on desktop.\n *\n * These bindings do not run through the class merger, so each state picks its\n * own utilities rather than emitting conflicting ones.\n */\nconst mobileCardClass = computed<string>(() => {\n if (get(appended))\n return 'relative flex flex-col border-x border-t! border-rui-divider overflow-hidden rounded-t-rui-card mb-0';\n const shared = 'relative flex flex-col border border-y! border-rui-divider overflow-hidden';\n return get(expanded)\n ? `${shared} rounded-t-rui-card mb-0`\n : `${shared} rounded-rui-card mb-3 last:mb-0`;\n});\n</script>\n\n<template>\n <tr\n :class=\"[stateClass, rowClass, pairHoverClass, isMobile ? mobileCardClass : '']\"\n :aria-selected=\"selectedData ? selected : undefined\"\n :data-stripe=\"stripe\"\n data-id=\"row\"\n >\n <!-- Mobile card header: checkbox on the left, pinned action columns on the right -->\n <td\n v-if=\"showMobileHeader\"\n :class=\"compactMobileHeader\n ? 'absolute top-0 right-0 z-1 flex items-center gap-1 px-2 py-1'\n : 'flex items-center justify-between gap-2 px-4 py-2 border-b border-rui-divider'\"\n data-id=\"mobile-card-header\"\n >\n <RuiCheckbox\n v-if=\"selectedData\"\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n details=\"hidden\"\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n <span v-else-if=\"!compactMobileHeader\" />\n\n <div\n v-if=\"mobileHeaderColumns.length > 0\"\n class=\"flex items-center gap-1 min-w-0\"\n >\n <template\n v-for=\"(column, headerIndex) in mobileHeaderColumns\"\n :key=\"`header-${headerIndex}`\"\n >\n <slot\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n :name=\"`item.${column.key.toString()}`\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n />\n <RuiExpandButton\n v-else-if=\"column.key === 'expand'\"\n :expanded=\"isExpanded(rowId)\"\n @click=\"onToggleExpand(row)\"\n />\n <template v-else>\n {{ cellValue(row, column.key) }}\n </template>\n </template>\n </div>\n </td>\n\n <!-- Desktop checkbox cell -->\n <td\n v-else-if=\"selectedData && !isMobile\"\n :class=\"classes.checkbox\"\n colspan=\"1\"\n rowspan=\"1\"\n >\n <RuiCheckbox\n :data-id=\"`table-toggle-check-${index}`\"\n aria-label=\"Select row\"\n :model-value=\"selected\"\n :disabled=\"disabled\"\n :size=\"dense ? 'sm' : undefined\"\n color=\"primary\"\n class=\"select-none\"\n details=\"hidden\"\n @update:model-value=\"onSelect($event, rowId, true)\"\n @click=\"onCheckboxClick($event, rowId, index)\"\n />\n </td>\n\n <RuiDataTableCell\n v-for=\"(column, subIndex) in bodyColumns\"\n :key=\"subIndex\"\n :column=\"column\"\n :row=\"row\"\n :index=\"index\"\n :row-id=\"rowId\"\n :style=\"subIndex === 0 ? firstRowInset : undefined\"\n >\n <template\n v-if=\"itemSlotKeys.has(column.key.toString())\"\n #default=\"slotData\"\n >\n <slot\n :name=\"`item.${column.key.toString()}`\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableCell>\n </tr>\n\n <!-- no divider above: with its row it is one item, sharing the row's state, stripe and hover -->\n <RuiDataTableAppendRow\n v-if=\"slots['row-append']\"\n class=\"border-t-0!\"\n :class=\"[stateClass, rowClass, appendHoverClass, isMobile ? mobileAppendClass : '']\"\n :data-stripe=\"stripe\"\n :row=\"row\"\n :index=\"index\"\n >\n <template #row-append=\"slotData\">\n <!-- eslint-disable-next-line vue/require-explicit-slots -- defined via Partial<Record<...>> in defineSlots -->\n <slot\n name=\"row-append\"\n v-bind=\"slotData\"\n />\n </template>\n </RuiDataTableAppendRow>\n\n <!-- opacity only: the rows below move once, at once, rather than sliding with a growing height -->\n <RuiDataTableExpandedRow\n v-if=\"panelShown\"\n class=\"transition-opacity starting:opacity-0 motion-reduce:transition-none\"\n :class=\"panelClosing ? 'opacity-0 duration-100 ease-in' : 'duration-150 ease-out'\"\n :row=\"row\"\n :index=\"index\"\n >\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 </RuiDataTableExpandedRow>\n</template>\n"],"mappings":"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"}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Header and pagination of a nested table, stepped by depth to stand off the band around them (about
|
|
3
3
|
* 1.12:1 or more) as well as their own rows: past the lighter band one panel deep, short of the darker
|
|
4
4
|
* band two deep. Nested bars never stick, so the tint can be translucent over the table's own surface.
|
|
5
|
+
* The dark tint stops where the secondary labels on it still reach 4.5:1.
|
|
5
6
|
*/
|
|
6
|
-
export declare const NESTED_BAR = "[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.13] dark:[[data-id=row-expanded]_&]:bg-white/[0.
|
|
7
|
+
export declare const NESTED_BAR = "[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.13] dark:[[data-id=row-expanded]_&]:bg-white/[0.13] [[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.06] dark:[[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-white/[0.07]";
|
|
7
8
|
export declare const dataTableStyles: import("tailwind-variants").TVReturnType<{
|
|
8
9
|
sticky: {
|
|
9
10
|
true: {
|
|
@@ -60,6 +61,7 @@ export declare const dataTableStyles: import("tailwind-variants").TVReturnType<{
|
|
|
60
61
|
tbody: string;
|
|
61
62
|
tr: string;
|
|
62
63
|
td: string;
|
|
64
|
+
tfoot: string;
|
|
63
65
|
};
|
|
64
66
|
};
|
|
65
67
|
}, {
|
|
@@ -69,6 +71,7 @@ export declare const dataTableStyles: import("tailwind-variants").TVReturnType<{
|
|
|
69
71
|
tbody: string;
|
|
70
72
|
tr: string;
|
|
71
73
|
td: string;
|
|
74
|
+
tfoot: string;
|
|
72
75
|
checkbox: string;
|
|
73
76
|
tbodyLoader: string;
|
|
74
77
|
pagination: string;
|
|
@@ -128,6 +131,7 @@ export declare const dataTableStyles: import("tailwind-variants").TVReturnType<{
|
|
|
128
131
|
tbody: string;
|
|
129
132
|
tr: string;
|
|
130
133
|
td: string;
|
|
134
|
+
tfoot: string;
|
|
131
135
|
};
|
|
132
136
|
};
|
|
133
137
|
}, {
|
|
@@ -137,6 +141,7 @@ export declare const dataTableStyles: import("tailwind-variants").TVReturnType<{
|
|
|
137
141
|
tbody: string;
|
|
138
142
|
tr: string;
|
|
139
143
|
td: string;
|
|
144
|
+
tfoot: string;
|
|
140
145
|
checkbox: string;
|
|
141
146
|
tbodyLoader: string;
|
|
142
147
|
pagination: string;
|
|
@@ -196,6 +201,7 @@ export declare const dataTableStyles: import("tailwind-variants").TVReturnType<{
|
|
|
196
201
|
tbody: string;
|
|
197
202
|
tr: string;
|
|
198
203
|
td: string;
|
|
204
|
+
tfoot: string;
|
|
199
205
|
};
|
|
200
206
|
};
|
|
201
207
|
}, {
|
|
@@ -205,6 +211,7 @@ export declare const dataTableStyles: import("tailwind-variants").TVReturnType<{
|
|
|
205
211
|
tbody: string;
|
|
206
212
|
tr: string;
|
|
207
213
|
td: string;
|
|
214
|
+
tfoot: string;
|
|
208
215
|
checkbox: string;
|
|
209
216
|
tbodyLoader: string;
|
|
210
217
|
pagination: string;
|
|
@@ -11,8 +11,9 @@ var NESTED_BAND = "[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.11] dark:[[d
|
|
|
11
11
|
* Header and pagination of a nested table, stepped by depth to stand off the band around them (about
|
|
12
12
|
* 1.12:1 or more) as well as their own rows: past the lighter band one panel deep, short of the darker
|
|
13
13
|
* band two deep. Nested bars never stick, so the tint can be translucent over the table's own surface.
|
|
14
|
+
* The dark tint stops where the secondary labels on it still reach 4.5:1.
|
|
14
15
|
*/
|
|
15
|
-
var NESTED_BAR = "[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.13] dark:[[data-id=row-expanded]_&]:bg-white/[0.
|
|
16
|
+
var NESTED_BAR = "[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.13] dark:[[data-id=row-expanded]_&]:bg-white/[0.13] [[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.06] dark:[[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-white/[0.07]";
|
|
16
17
|
var dataTableStyles = tv({
|
|
17
18
|
slots: {
|
|
18
19
|
wrapper: "relative between:border-t between:border-b-0 between:border-rui-divider overflow-clip bg-rui-surface",
|
|
@@ -21,13 +22,14 @@ var dataTableStyles = tv({
|
|
|
21
22
|
tbody: "between:border-t between:border-b-0 between:border-rui-divider",
|
|
22
23
|
tr: "hover:bg-rui-neutral-950/[0.03] dark:hover:bg-white/[0.04]",
|
|
23
24
|
td: "[:where(&)]:px-4 text-rui-text text-body-2 tabular-nums [text-wrap:initial]",
|
|
25
|
+
tfoot: "[:where(&>tr>*)]:px-4 text-rui-text text-body-2 tabular-nums",
|
|
24
26
|
checkbox: "px-2 w-[3.625rem] max-w-[3.625rem] [&_label]:ml-0",
|
|
25
27
|
tbodyLoader: "text-center",
|
|
26
28
|
pagination: `bg-rui-surface-muted ${NESTED_BAR}`
|
|
27
29
|
},
|
|
28
30
|
variants: {
|
|
29
31
|
sticky: { true: { pagination: "sticky bottom-0 z-rui-raised" } },
|
|
30
|
-
outlined: { true: { wrapper:
|
|
32
|
+
outlined: { true: { wrapper: `border border-rui-divider [[data-id=row-expanded]_&]:bg-clip-padding [[data-id=row-expanded]_&]:border-rui-neutral-950/[0.16] dark:[[data-id=row-expanded]_&]:border-white/[0.12]` } },
|
|
31
33
|
rounded: {
|
|
32
34
|
sm: { wrapper: "rounded-rui-sm" },
|
|
33
35
|
md: { wrapper: "rounded-rui-card" },
|
|
@@ -51,7 +53,8 @@ var dataTableStyles = tv({
|
|
|
51
53
|
table: "block min-w-0 max-w-none w-full whitespace-normal between:border-t-0 border-0",
|
|
52
54
|
tbody: "block between:border-t-0",
|
|
53
55
|
tr: "block",
|
|
54
|
-
td: "block px-4 py-2"
|
|
56
|
+
td: "block px-4 py-2",
|
|
57
|
+
tfoot: "block [&>tr]:block [:where(&>tr>*)]:block [:where(&>tr>*)]:py-2"
|
|
55
58
|
} }
|
|
56
59
|
},
|
|
57
60
|
/**
|
|
@@ -63,11 +66,17 @@ var dataTableStyles = tv({
|
|
|
63
66
|
compoundVariants: [{
|
|
64
67
|
dense: false,
|
|
65
68
|
mobile: false,
|
|
66
|
-
class: {
|
|
69
|
+
class: {
|
|
70
|
+
td: "[:where(&)]:py-1 [:where(&)]:h-11",
|
|
71
|
+
tfoot: "[:where(&>tr>*)]:py-1 [:where(&>tr>*)]:h-11"
|
|
72
|
+
}
|
|
67
73
|
}, {
|
|
68
74
|
dense: true,
|
|
69
75
|
mobile: false,
|
|
70
|
-
class: {
|
|
76
|
+
class: {
|
|
77
|
+
td: "[:where(&)]:py-1 [:where(&)]:h-9",
|
|
78
|
+
tfoot: "[:where(&>tr>*)]:py-1 [:where(&>tr>*)]:h-9"
|
|
79
|
+
}
|
|
71
80
|
}],
|
|
72
81
|
defaultVariants: {
|
|
73
82
|
dense: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table-styles.js","names":[],"sources":["../../../src/components/tables/data-table-styles.ts"],"sourcesContent":["import { tv } from '@/utils/tv';\n\n/** A 2px primary rail down the left edge of an open row and its panel; out of flow, so the cell keeps its padding. */\nconst OPEN_ROW_RAIL = '[&>td:first-child]:relative [&>td:first-child]:before:absolute [&>td:first-child]:before:inset-y-0 [&>td:first-child]:before:left-0 [&>td:first-child]:before:w-0.5 [&>td:first-child]:before:bg-rui-primary';\n\n/**\n * The band of an open row inside another table's panel: a step darker than the outer band, so the two\n * levels never share a grey while the rows between them keep the plain surface.\n */\nconst NESTED_BAND = '[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.11] dark:[[data-id=row-expanded]_&]:bg-white/[0.14]';\n\n/**\n * Header and pagination of a nested table, stepped by depth to stand off the band around them (about\n * 1.12:1 or more) as well as their own rows: past the lighter band one panel deep, short of the darker\n * band two deep. Nested bars never stick, so the tint can be translucent over the table's own surface.\n */\nexport const NESTED_BAR = '[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.13] dark:[[data-id=row-expanded]_&]:bg-white/[0.
|
|
1
|
+
{"version":3,"file":"data-table-styles.js","names":[],"sources":["../../../src/components/tables/data-table-styles.ts"],"sourcesContent":["import { tv } from '@/utils/tv';\n\n/** A 2px primary rail down the left edge of an open row and its panel; out of flow, so the cell keeps its padding. */\nconst OPEN_ROW_RAIL = '[&>td:first-child]:relative [&>td:first-child]:before:absolute [&>td:first-child]:before:inset-y-0 [&>td:first-child]:before:left-0 [&>td:first-child]:before:w-0.5 [&>td:first-child]:before:bg-rui-primary';\n\n/**\n * The band of an open row inside another table's panel: a step darker than the outer band, so the two\n * levels never share a grey while the rows between them keep the plain surface.\n */\nconst NESTED_BAND = '[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.11] dark:[[data-id=row-expanded]_&]:bg-white/[0.14]';\n\n/**\n * Header and pagination of a nested table, stepped by depth to stand off the band around them (about\n * 1.12:1 or more) as well as their own rows: past the lighter band one panel deep, short of the darker\n * band two deep. Nested bars never stick, so the tint can be translucent over the table's own surface.\n * The dark tint stops where the secondary labels on it still reach 4.5:1.\n */\nexport const NESTED_BAR = '[[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.13] dark:[[data-id=row-expanded]_&]:bg-white/[0.13] [[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-rui-neutral-950/[0.06] dark:[[data-id=row-expanded]_[data-id=row-expanded]_&]:bg-white/[0.07]';\n\n/**\n * The outline of a nested table, firm enough to hold its edge on the band around it. The translucent\n * divider is clipped off the table's own surface, so it tints the band and not the white beneath it.\n */\nconst NESTED_EDGE = '[[data-id=row-expanded]_&]:bg-clip-padding [[data-id=row-expanded]_&]:border-rui-neutral-950/[0.16] dark:[[data-id=row-expanded]_&]:border-white/[0.12]';\n\nexport const dataTableStyles = tv({\n slots: {\n // `clip`, not `hidden`, which may shrink the item below its rows; its own surface reads the same anywhere\n wrapper: 'relative between:border-t between:border-b-0 between:border-rui-divider overflow-clip bg-rui-surface',\n // focusable only while it scrolls with nothing to tab to (useKeyboardScroll), ring drawn inside\n scroller: 'overflow-x-auto overflow-y-hidden [clip-path:inset(0_0_0_0)] outline-hidden focus-visible:focus-ring focus-visible:-outline-offset-2',\n table: 'min-w-full table-fixed between:border-t between:border-b-0 between:border-rui-divider whitespace-nowrap mx-auto my-0 max-w-fit relative border-rui-divider',\n tbody: 'between:border-t between:border-b-0 between:border-rui-divider',\n // its own tint, lighter than `rui-hover`, which lands on the header and pagination grey\n tr: 'hover:bg-rui-neutral-950/[0.03] dark:hover:bg-white/[0.04]',\n // numbers line up in columns; no slashed zero, which in Inter reads as a second, monospace font beside zero-free values\n td: '[:where(&)]:px-4 text-rui-text text-body-2 tabular-nums [text-wrap:initial]',\n // the `tfoot` slot's cells (a total row) take the body cells' padding, height and text, so a footer row lines up without its own classes\n tfoot: '[:where(&>tr>*)]:px-4 text-rui-text text-body-2 tabular-nums',\n checkbox: 'px-2 w-[3.625rem] max-w-[3.625rem] [&_label]:ml-0',\n tbodyLoader: 'text-center',\n // tinted like the column header, the pair framing the body; opaque, so rows scroll behind a stuck bar\n pagination: `bg-rui-surface-muted ${NESTED_BAR}`,\n },\n variants: {\n sticky: {\n true: { pagination: 'sticky bottom-0 z-rui-raised' },\n },\n outlined: {\n true: { wrapper: `border border-rui-divider ${NESTED_EDGE}` },\n },\n rounded: {\n sm: { wrapper: 'rounded-rui-sm' },\n md: { wrapper: 'rounded-rui-card' },\n lg: { wrapper: 'rounded-rui-lg' },\n },\n dense: {\n true: {},\n false: {},\n },\n // under every row state through `:where()`, per item (`data-stripe`); half the row hover, so a striped row still darkens on hover\n striped: {\n true: { tbody: '[:where(&>tr[data-stripe])]:bg-rui-neutral-950/[0.015] dark:[:where(&>tr[data-stripe])]:bg-white/[0.02]' },\n },\n rowVariant: {\n selected: { tr: 'bg-rui-primary-soft' },\n empty: { tr: 'hover:bg-transparent dark:hover:bg-transparent' },\n // a grey band darker than the header so the two never match, a step darker again inside another panel\n expandable: { tr: `bg-rui-neutral-950/[0.07] hover:bg-rui-neutral-950/[0.07] dark:bg-white/[0.09] dark:hover:bg-white/[0.09] ${NESTED_BAND} [[data-id=row-expanded]_&]:hover:bg-rui-neutral-950/[0.11] dark:[[data-id=row-expanded]_&]:hover:bg-white/[0.14] ${OPEN_ROW_RAIL} !border-t-0` },\n expandedParent: { tr: `bg-rui-neutral-950/[0.07] dark:bg-white/[0.09] ${NESTED_BAND} ${OPEN_ROW_RAIL}` },\n group: { tr: 'bg-rui-neutral-100 hover:bg-rui-neutral-100 dark:bg-white/[0.05] dark:hover:bg-white/[0.05]' },\n },\n mobile: {\n true: {\n wrapper: 'between:border-t-0 border-0 rounded-none overflow-visible',\n scroller: 'overflow-visible [clip-path:none]',\n table: 'block min-w-0 max-w-none w-full whitespace-normal between:border-t-0 border-0',\n tbody: 'block between:border-t-0',\n tr: 'block',\n td: 'block px-4 py-2',\n tfoot: 'block [&>tr]:block [:where(&>tr>*)]:block [:where(&>tr>*)]:py-2',\n },\n },\n },\n /**\n * A fixed row height keeps a row of plain text as tall as one holding an\n * icon button. Padding and floor sit in `:where()` so a consumer's `cellClass`\n * (`py-0` is common) still wins at any stylesheet order, and each density\n * sets its own because the class merger cannot dedupe these.\n */\n compoundVariants: [\n // a 4px inset under the height floor fits a 36px button in a 44px row (a 28px one in a dense 36px row)\n { dense: false, mobile: false, class: { td: '[:where(&)]:py-1 [:where(&)]:h-11', tfoot: '[:where(&>tr>*)]:py-1 [:where(&>tr>*)]:h-11' } },\n { dense: true, mobile: false, class: { td: '[:where(&)]:py-1 [:where(&)]:h-9', tfoot: '[:where(&>tr>*)]:py-1 [:where(&>tr>*)]:h-9' } },\n ],\n defaultVariants: {\n dense: false,\n mobile: false,\n },\n});\n"],"mappings":";;;AAGA,IAAM,gBAAgB;;;;;AAMtB,IAAM,cAAc;;;;;;;AAQpB,IAAa,aAAa;AAQ1B,IAAa,kBAAkB,GAAG;CAChC,OAAO;EAEL,SAAS;EAET,UAAU;EACV,OAAO;EACP,OAAO;EAEP,IAAI;EAEJ,IAAI;EAEJ,OAAO;EACP,UAAU;EACV,aAAa;EAEb,YAAY,wBAAwB;CACtC;CACA,UAAU;EACR,QAAQ,EACN,MAAM,EAAE,YAAY,+BAA+B,EACrD;EACA,UAAU,EACR,MAAM,EAAE,SAAS,oLAA2C,EAC9D;EACA,SAAS;GACP,IAAI,EAAE,SAAS,iBAAiB;GAChC,IAAI,EAAE,SAAS,mBAAmB;GAClC,IAAI,EAAE,SAAS,iBAAiB;EAClC;EACA,OAAO;GACL,MAAM,CAAC;GACP,OAAO,CAAC;EACV;EAEA,SAAS,EACP,MAAM,EAAE,OAAO,0GAA0G,EAC3H;EACA,YAAY;GACV,UAAU,EAAE,IAAI,sBAAsB;GACtC,OAAO,EAAE,IAAI,iDAAiD;GAE9D,YAAY,EAAE,IAAI,6GAA6G,YAAY,oHAAoH,cAAc,cAAc;GAC3R,gBAAgB,EAAE,IAAI,kDAAkD,YAAY,GAAG,gBAAgB;GACvG,OAAO,EAAE,IAAI,8FAA8F;EAC7G;EACA,QAAQ,EACN,MAAM;GACJ,SAAS;GACT,UAAU;GACV,OAAO;GACP,OAAO;GACP,IAAI;GACJ,IAAI;GACJ,OAAO;EACT,EACF;CACF;;;;;;;CAOA,kBAAkB,CAEhB;EAAE,OAAO;EAAO,QAAQ;EAAO,OAAO;GAAE,IAAI;GAAqC,OAAO;EAA8C;CAAE,GACxI;EAAE,OAAO;EAAM,QAAQ;EAAO,OAAO;GAAE,IAAI;GAAoC,OAAO;EAA6C;CAAE,CACvI;CACA,iBAAiB;EACf,OAAO;EACP,QAAQ;CACV;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiTabItems.js","names":["_sfc_main"],"sources":["../../../../src/components/tabs/tab-items/RuiTabItems.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends string | number\">\nimport { Fragment, isVNode } from 'vue';\n\ndefineOptions({\n name: 'RuiTabItems',\n inheritAttrs: false,\n});\n\n/**\n * The tab whose panel is showing.\n *\n * The default matches RuiTabs. Without one, binding both components to the\n * same ref that starts as `undefined` leaves this component with\n * `modelValue === undefined`, so the `active = modelValue === value` check\n * fails for every tab: the panel renders but stays at height 0, which reads as\n * an element with no content.\n */\nconst modelValue = defineModel<T>({ default: () => 0 as T });\n\nconst slots = useSlots();\n\nconst currIndex = ref<number>(-1);\nconst activeIndex = ref<number>(-1);\nconst inner = useTemplateRef<HTMLDivElement>('inner');\n\nconst { height: innerHeight } = useElementSize(inner);\n\nconst children = computed<VNode[]>(() => {\n const slotContent = slots.default?.() ?? [];\n\n const tabs = getChildrenTabs(slotContent);\n\n let anyActive = false;\n const children = tabs.map((tab, index) => {\n const value = tab.props?.value ?? index;\n const active = get(modelValue) === value;\n if (active) {\n anyActive = true;\n if (index !== get(currIndex))\n set(currIndex, index);\n }\n\n return {\n ...tab,\n props: {\n value,\n ...tab.props,\n },\n };\n });\n\n if (!anyActive)\n set(currIndex, -1);\n\n return children;\n});\n\n/**\n * Unwraps the fragments a `v-for` in the slot produces, so only tab items come\n * back.\n *\n * @param children - the slot's vnodes\n * @returns the tab items among them\n */\nfunction getChildrenTabs(children: VNode[]): VNode[] {\n return children\n .flatMap((item) => {\n if (item.type === Fragment && Array.isArray(item.children) && item.children.length > 0)\n return getChildrenTabs(item.children.filter(isVNode));\n\n return [item];\n })\n .flat();\n}\n\nwatch(currIndex, (index) => {\n nextTick(() => {\n set(activeIndex, index);\n });\n});\n</script>\n\n<template>\n <div\n class=\"grow transition-[height] duration-200 ease-out
|
|
1
|
+
{"version":3,"file":"RuiTabItems.js","names":["_sfc_main"],"sources":["../../../../src/components/tabs/tab-items/RuiTabItems.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends string | number\">\nimport { Fragment, isVNode } from 'vue';\nimport { useClipWhileResizing } from '@/composables/clip-while-resizing';\n\ndefineOptions({\n name: 'RuiTabItems',\n inheritAttrs: false,\n});\n\n/**\n * The tab whose panel is showing.\n *\n * The default matches RuiTabs. Without one, binding both components to the\n * same ref that starts as `undefined` leaves this component with\n * `modelValue === undefined`, so the `active = modelValue === value` check\n * fails for every tab: the panel renders but stays at height 0, which reads as\n * an element with no content.\n */\nconst modelValue = defineModel<T>({ default: () => 0 as T });\n\nconst slots = useSlots();\n\nconst currIndex = ref<number>(-1);\nconst activeIndex = ref<number>(-1);\nconst inner = useTemplateRef<HTMLDivElement>('inner');\nconst root = useTemplateRef<HTMLDivElement>('root');\n\nconst { height: innerHeight } = useElementSize(inner);\n\n// clip only while the height follows a panel change, so sticky content inside a panel works\nconst clipped = useClipWhileResizing(root, () => get(innerHeight));\n\nconst children = computed<VNode[]>(() => {\n const slotContent = slots.default?.() ?? [];\n\n const tabs = getChildrenTabs(slotContent);\n\n let anyActive = false;\n const children = tabs.map((tab, index) => {\n const value = tab.props?.value ?? index;\n const active = get(modelValue) === value;\n if (active) {\n anyActive = true;\n if (index !== get(currIndex))\n set(currIndex, index);\n }\n\n return {\n ...tab,\n props: {\n value,\n ...tab.props,\n },\n };\n });\n\n if (!anyActive)\n set(currIndex, -1);\n\n return children;\n});\n\n/**\n * Unwraps the fragments a `v-for` in the slot produces, so only tab items come\n * back.\n *\n * @param children - the slot's vnodes\n * @returns the tab items among them\n */\nfunction getChildrenTabs(children: VNode[]): VNode[] {\n return children\n .flatMap((item) => {\n if (item.type === Fragment && Array.isArray(item.children) && item.children.length > 0)\n return getChildrenTabs(item.children.filter(isVNode));\n\n return [item];\n })\n .flat();\n}\n\nwatch(currIndex, (index) => {\n nextTick(() => {\n set(activeIndex, index);\n });\n});\n</script>\n\n<template>\n <div\n ref=\"root\"\n class=\"grow transition-[height] duration-200 ease-out motion-reduce:transition-none\"\n :class=\"{ 'overflow-hidden': clipped }\"\n :data-clipped=\"clipped || undefined\"\n :style=\"{ height: `${innerHeight}px` }\"\n v-bind=\"$attrs\"\n >\n <div ref=\"inner\">\n <Component\n :is=\"child\"\n v-for=\"(child, i) in children\"\n :key=\"i\"\n :active=\"i === activeIndex\"\n />\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
|
|
2
2
|
import { useElementSize } from "../../../vendor/@vueuse/core/dist/index.js";
|
|
3
|
+
import { useClipWhileResizing } from "../../../composables/clip-while-resizing.js";
|
|
3
4
|
import { Fragment, computed, createBlock, createElementBlock, createElementVNode, defineComponent, isVNode, mergeProps, nextTick, openBlock, ref, renderList, resolveDynamicComponent, unref, useModel, useSlots, useTemplateRef, watch } from "vue";
|
|
4
5
|
//#region src/components/tabs/tab-items/RuiTabItems.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
+
var _hoisted_1 = ["data-clipped"];
|
|
5
7
|
var RuiTabItems_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
6
8
|
name: "RuiTabItems",
|
|
7
9
|
inheritAttrs: false,
|
|
@@ -26,7 +28,9 @@ var RuiTabItems_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
|
|
|
26
28
|
const currIndex = ref(-1);
|
|
27
29
|
const activeIndex = ref(-1);
|
|
28
30
|
const inner = useTemplateRef("inner");
|
|
31
|
+
const root = useTemplateRef("root");
|
|
29
32
|
const { height: innerHeight } = useElementSize(inner);
|
|
33
|
+
const clipped = useClipWhileResizing(root, () => get(innerHeight));
|
|
30
34
|
const children = computed(() => {
|
|
31
35
|
const tabs = getChildrenTabs(slots.default?.() ?? []);
|
|
32
36
|
let anyActive = false;
|
|
@@ -67,7 +71,10 @@ var RuiTabItems_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
|
|
|
67
71
|
});
|
|
68
72
|
return (_ctx, _cache) => {
|
|
69
73
|
return openBlock(), createElementBlock("div", mergeProps({
|
|
70
|
-
|
|
74
|
+
ref_key: "root",
|
|
75
|
+
ref: root,
|
|
76
|
+
class: ["grow transition-[height] duration-200 ease-out motion-reduce:transition-none", { "overflow-hidden": unref(clipped) }],
|
|
77
|
+
"data-clipped": unref(clipped) || void 0,
|
|
71
78
|
style: { height: `${unref(innerHeight)}px` }
|
|
72
79
|
}, _ctx.$attrs), [createElementVNode("div", {
|
|
73
80
|
ref_key: "inner",
|
|
@@ -77,7 +84,7 @@ var RuiTabItems_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
|
|
|
77
84
|
key: i,
|
|
78
85
|
active: i === unref(activeIndex)
|
|
79
86
|
}, null, 8, ["active"]);
|
|
80
|
-
}), 128))], 512)], 16);
|
|
87
|
+
}), 128))], 512)], 16, _hoisted_1);
|
|
81
88
|
};
|
|
82
89
|
}
|
|
83
90
|
});
|
package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuiTabItems.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_useModel","_openBlock","_createElementBlock","_mergeProps","_unref","_createElementVNode","_Fragment","_renderList","_createBlock","_resolveDynamicComponent"],"sources":["../../../../src/components/tabs/tab-items/RuiTabItems.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends string | number\">\nimport { Fragment, isVNode } from 'vue';\n\ndefineOptions({\n name: 'RuiTabItems',\n inheritAttrs: false,\n});\n\n/**\n * The tab whose panel is showing.\n *\n * The default matches RuiTabs. Without one, binding both components to the\n * same ref that starts as `undefined` leaves this component with\n * `modelValue === undefined`, so the `active = modelValue === value` check\n * fails for every tab: the panel renders but stays at height 0, which reads as\n * an element with no content.\n */\nconst modelValue = defineModel<T>({ default: () => 0 as T });\n\nconst slots = useSlots();\n\nconst currIndex = ref<number>(-1);\nconst activeIndex = ref<number>(-1);\nconst inner = useTemplateRef<HTMLDivElement>('inner');\n\nconst { height: innerHeight } = useElementSize(inner);\n\nconst children = computed<VNode[]>(() => {\n const slotContent = slots.default?.() ?? [];\n\n const tabs = getChildrenTabs(slotContent);\n\n let anyActive = false;\n const children = tabs.map((tab, index) => {\n const value = tab.props?.value ?? index;\n const active = get(modelValue) === value;\n if (active) {\n anyActive = true;\n if (index !== get(currIndex))\n set(currIndex, index);\n }\n\n return {\n ...tab,\n props: {\n value,\n ...tab.props,\n },\n };\n });\n\n if (!anyActive)\n set(currIndex, -1);\n\n return children;\n});\n\n/**\n * Unwraps the fragments a `v-for` in the slot produces, so only tab items come\n * back.\n *\n * @param children - the slot's vnodes\n * @returns the tab items among them\n */\nfunction getChildrenTabs(children: VNode[]): VNode[] {\n return children\n .flatMap((item) => {\n if (item.type === Fragment && Array.isArray(item.children) && item.children.length > 0)\n return getChildrenTabs(item.children.filter(isVNode));\n\n return [item];\n })\n .flat();\n}\n\nwatch(currIndex, (index) => {\n nextTick(() => {\n set(activeIndex, index);\n });\n});\n</script>\n\n<template>\n <div\n class=\"grow transition-[height] duration-200 ease-out
|
|
1
|
+
{"version":3,"file":"RuiTabItems.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_useModel","_openBlock","_createElementBlock","_mergeProps","_unref","_createElementVNode","_Fragment","_renderList","_createBlock","_resolveDynamicComponent"],"sources":["../../../../src/components/tabs/tab-items/RuiTabItems.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends string | number\">\nimport { Fragment, isVNode } from 'vue';\nimport { useClipWhileResizing } from '@/composables/clip-while-resizing';\n\ndefineOptions({\n name: 'RuiTabItems',\n inheritAttrs: false,\n});\n\n/**\n * The tab whose panel is showing.\n *\n * The default matches RuiTabs. Without one, binding both components to the\n * same ref that starts as `undefined` leaves this component with\n * `modelValue === undefined`, so the `active = modelValue === value` check\n * fails for every tab: the panel renders but stays at height 0, which reads as\n * an element with no content.\n */\nconst modelValue = defineModel<T>({ default: () => 0 as T });\n\nconst slots = useSlots();\n\nconst currIndex = ref<number>(-1);\nconst activeIndex = ref<number>(-1);\nconst inner = useTemplateRef<HTMLDivElement>('inner');\nconst root = useTemplateRef<HTMLDivElement>('root');\n\nconst { height: innerHeight } = useElementSize(inner);\n\n// clip only while the height follows a panel change, so sticky content inside a panel works\nconst clipped = useClipWhileResizing(root, () => get(innerHeight));\n\nconst children = computed<VNode[]>(() => {\n const slotContent = slots.default?.() ?? [];\n\n const tabs = getChildrenTabs(slotContent);\n\n let anyActive = false;\n const children = tabs.map((tab, index) => {\n const value = tab.props?.value ?? index;\n const active = get(modelValue) === value;\n if (active) {\n anyActive = true;\n if (index !== get(currIndex))\n set(currIndex, index);\n }\n\n return {\n ...tab,\n props: {\n value,\n ...tab.props,\n },\n };\n });\n\n if (!anyActive)\n set(currIndex, -1);\n\n return children;\n});\n\n/**\n * Unwraps the fragments a `v-for` in the slot produces, so only tab items come\n * back.\n *\n * @param children - the slot's vnodes\n * @returns the tab items among them\n */\nfunction getChildrenTabs(children: VNode[]): VNode[] {\n return children\n .flatMap((item) => {\n if (item.type === Fragment && Array.isArray(item.children) && item.children.length > 0)\n return getChildrenTabs(item.children.filter(isVNode));\n\n return [item];\n })\n .flat();\n}\n\nwatch(currIndex, (index) => {\n nextTick(() => {\n set(activeIndex, index);\n });\n});\n</script>\n\n<template>\n <div\n ref=\"root\"\n class=\"grow transition-[height] duration-200 ease-out motion-reduce:transition-none\"\n :class=\"{ 'overflow-hidden': clipped }\"\n :data-clipped=\"clipped || undefined\"\n :style=\"{ height: `${innerHeight}px` }\"\n v-bind=\"$attrs\"\n >\n <div ref=\"inner\">\n <Component\n :is=\"child\"\n v-for=\"(child, i) in children\"\n :key=\"i\"\n :active=\"i === activeIndex\"\n />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;EAkBA,MAAM,aAAaC,SAAc,SAAA,YAA0B;EAE3D,MAAM,QAAQ,SAAS;EAEvB,MAAM,YAAY,IAAY,EAAE;EAChC,MAAM,cAAc,IAAY,EAAE;EAClC,MAAM,QAAQ,eAA+B,OAAO;EACpD,MAAM,OAAO,eAA+B,MAAM;EAElD,MAAM,EAAE,QAAQ,gBAAgB,eAAe,KAAK;EAGpD,MAAM,UAAU,qBAAqB,YAAY,IAAI,WAAW,CAAC;EAEjE,MAAM,WAAW,eAAwB;GAGvC,MAAM,OAAO,gBAFO,MAAM,UAAU,KAAK,CAAC,CAEF;GAExC,IAAI,YAAY;GAChB,MAAM,WAAW,KAAK,KAAK,KAAK,UAAU;IACxC,MAAM,QAAQ,IAAI,OAAO,SAAS;IAElC,IADe,IAAI,UAAU,MAAM,OACvB;KACV,YAAY;KACZ,IAAI,UAAU,IAAI,SAAS,GACzB,IAAI,WAAW,KAAK;IACxB;IAEA,OAAO;KACL,GAAG;KACH,OAAO;MACL;MACA,GAAG,IAAI;KACT;IACF;GACF,CAAC;GAED,IAAI,CAAC,WACH,IAAI,WAAW,EAAE;GAEnB,OAAO;EACT,CAAC;;;;;;;;EASD,SAAS,gBAAgB,UAA4B;GACnD,OAAO,SACJ,SAAS,SAAS;IACjB,IAAI,KAAK,SAAS,YAAY,MAAM,QAAQ,KAAK,QAAQ,KAAK,KAAK,SAAS,SAAS,GACnF,OAAO,gBAAgB,KAAK,SAAS,OAAO,OAAO,CAAC;IAEtD,OAAO,CAAC,IAAI;GACd,CAAC,CAAA,CACA,KAAK;EACV;EAEA,MAAM,YAAY,UAAU;GAC1B,eAAe;IACb,IAAI,aAAa,KAAK;GACxB,CAAC;EACH,CAAC;;GAIC,OAAAC,UAAA,GAAAC,mBAgBM,OAhBNC,WAgBM;IAfA,SAAA;IAAJ,KAAI;IACJ,OAAK,CAAC,gFAA8E,EAAA,mBACvDC,MAAA,OAAA,EAAO,CAAA;IACnC,gBAAcA,MAAA,OAAA,KAAW,KAAA;IACzB,OAAK,EAAA,QAAA,GAAeA,MAAA,WAAA,EAAW,IAAA;GACxBL,GAAAA,KAAAA,MAAM,GAAA,CAEdM,mBAOM,OAAA;IAPG,SAAA;IAAJ,KAAI;GACPJ,GAAAA,EAAAA,UAAA,IAAA,GAAAC,mBAKEI,UAAA,MAAAC,WAHqBH,MAAA,QAAA,IAAb,OAAO,MAAC;IAFlB,OAAAH,UAAA,GAAAO,YAKEC,wBAJK,KAAK,GAAA;KAET,KAAK;KACL,QAAQ,MAAML,MAAA,WAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ComputedRef, MaybeRefOrGetter, Ref } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a box that animates its height should clip its content right now.
|
|
4
|
+
*
|
|
5
|
+
* A permanent `overflow: hidden` makes the box the scroll container of everything inside it, so a
|
|
6
|
+
* `position: sticky` child sticks to the box and never to the page. This clips only while the
|
|
7
|
+
* height changes: from the moment the height value changes until the box's `height` transition
|
|
8
|
+
* ends. The timer covers a change that runs no transition (reduced motion, a hidden box, an equal
|
|
9
|
+
* computed height), which fires no `transitionend`.
|
|
10
|
+
*
|
|
11
|
+
* @param element - the box whose `height` transitions
|
|
12
|
+
* @param height - the height the box is given; any change starts a clip
|
|
13
|
+
* @returns true while the height is changing
|
|
14
|
+
*/
|
|
15
|
+
export declare function useClipWhileResizing(element: Readonly<Ref<HTMLElement | null>>, height: MaybeRefOrGetter<string | number>): ComputedRef<boolean>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { get, set, useTimeoutFn } from "../vendor/@vueuse/shared/dist/index.js";
|
|
2
|
+
import { useEventListener } from "../vendor/@vueuse/core/dist/index.js";
|
|
3
|
+
import { computed, shallowRef, toValue, watch } from "vue";
|
|
4
|
+
//#region src/composables/clip-while-resizing.ts
|
|
5
|
+
/** A little past the 200ms height transition, for when no `transitionend` arrives. */
|
|
6
|
+
var SETTLE_FALLBACK_MS = 300;
|
|
7
|
+
/**
|
|
8
|
+
* Whether a box that animates its height should clip its content right now.
|
|
9
|
+
*
|
|
10
|
+
* A permanent `overflow: hidden` makes the box the scroll container of everything inside it, so a
|
|
11
|
+
* `position: sticky` child sticks to the box and never to the page. This clips only while the
|
|
12
|
+
* height changes: from the moment the height value changes until the box's `height` transition
|
|
13
|
+
* ends. The timer covers a change that runs no transition (reduced motion, a hidden box, an equal
|
|
14
|
+
* computed height), which fires no `transitionend`.
|
|
15
|
+
*
|
|
16
|
+
* @param element - the box whose `height` transitions
|
|
17
|
+
* @param height - the height the box is given; any change starts a clip
|
|
18
|
+
* @returns true while the height is changing
|
|
19
|
+
*/
|
|
20
|
+
function useClipWhileResizing(element, height) {
|
|
21
|
+
const resizing = shallowRef(false);
|
|
22
|
+
const { start, stop } = useTimeoutFn(() => {
|
|
23
|
+
set(resizing, false);
|
|
24
|
+
}, SETTLE_FALLBACK_MS, { immediate: false });
|
|
25
|
+
watch(() => toValue(height), () => {
|
|
26
|
+
set(resizing, true);
|
|
27
|
+
start();
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Ends the clip when the box's own height transition ends; a child's transition bubbles up too.
|
|
31
|
+
*
|
|
32
|
+
* @param event - the transition event that reached the box
|
|
33
|
+
*/
|
|
34
|
+
function settle(event) {
|
|
35
|
+
if (event.target !== get(element) || event.propertyName !== "height") return;
|
|
36
|
+
stop();
|
|
37
|
+
set(resizing, false);
|
|
38
|
+
}
|
|
39
|
+
useEventListener(element, "transitionend", settle);
|
|
40
|
+
useEventListener(element, "transitioncancel", settle);
|
|
41
|
+
return computed(() => get(resizing));
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { useClipWhileResizing };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=clip-while-resizing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clip-while-resizing.js","names":[],"sources":["../../src/composables/clip-while-resizing.ts"],"sourcesContent":["import type { ComputedRef, MaybeRefOrGetter, Ref } from 'vue';\nimport { useEventListener, useTimeoutFn } from '@vueuse/core';\n\n/** A little past the 200ms height transition, for when no `transitionend` arrives. */\nconst SETTLE_FALLBACK_MS = 300;\n\n/**\n * Whether a box that animates its height should clip its content right now.\n *\n * A permanent `overflow: hidden` makes the box the scroll container of everything inside it, so a\n * `position: sticky` child sticks to the box and never to the page. This clips only while the\n * height changes: from the moment the height value changes until the box's `height` transition\n * ends. The timer covers a change that runs no transition (reduced motion, a hidden box, an equal\n * computed height), which fires no `transitionend`.\n *\n * @param element - the box whose `height` transitions\n * @param height - the height the box is given; any change starts a clip\n * @returns true while the height is changing\n */\nexport function useClipWhileResizing(\n element: Readonly<Ref<HTMLElement | null>>,\n height: MaybeRefOrGetter<string | number>,\n): ComputedRef<boolean> {\n const resizing = shallowRef<boolean>(false);\n\n const { start, stop } = useTimeoutFn(() => {\n set(resizing, false);\n }, SETTLE_FALLBACK_MS, { immediate: false });\n\n watch(() => toValue(height), () => {\n set(resizing, true);\n start();\n });\n\n /**\n * Ends the clip when the box's own height transition ends; a child's transition bubbles up too.\n *\n * @param event - the transition event that reached the box\n */\n function settle(event: TransitionEvent): void {\n if (event.target !== get(element) || event.propertyName !== 'height')\n return;\n stop();\n set(resizing, false);\n }\n\n useEventListener(element, 'transitionend', settle);\n useEventListener(element, 'transitioncancel', settle);\n\n return computed<boolean>(() => get(resizing));\n}\n"],"mappings":";;;;;AAIA,IAAM,qBAAqB;;;;;;;;;;;;;;AAe3B,SAAgB,qBACd,SACA,QACsB;CACtB,MAAM,WAAW,WAAoB,KAAK;CAE1C,MAAM,EAAE,OAAO,SAAS,mBAAmB;EACzC,IAAI,UAAU,KAAK;CACrB,GAAG,oBAAoB,EAAE,WAAW,MAAM,CAAC;CAE3C,YAAY,QAAQ,MAAM,SAAS;EACjC,IAAI,UAAU,IAAI;EAClB,MAAM;CACR,CAAC;;;;;;CAOD,SAAS,OAAO,OAA8B;EAC5C,IAAI,MAAM,WAAW,IAAI,OAAO,KAAK,MAAM,iBAAiB,UAC1D;EACF,KAAK;EACL,IAAI,UAAU,KAAK;CACrB;CAEA,iBAAiB,SAAS,iBAAiB,MAAM;CACjD,iBAAiB,SAAS,oBAAoB,MAAM;CAEpD,OAAO,eAAwB,IAAI,QAAQ,CAAC;AAC9C"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FormDetails } from '../../utils/form-text-detail.js';
|
|
2
|
+
import { type ComputedRef, type InjectionKey, type MaybeRef, type MaybeRefOrGetter } from 'vue';
|
|
2
3
|
/**
|
|
3
4
|
* Where a field shows its label.
|
|
4
5
|
*
|
|
@@ -9,14 +10,29 @@ import type { ComputedRef, InjectionKey, MaybeRef, MaybeRefOrGetter } from 'vue'
|
|
|
9
10
|
export type LabelPlacement = 'top' | 'hidden';
|
|
10
11
|
export interface FieldOptions {
|
|
11
12
|
labelPlacement: MaybeRef<LabelPlacement>;
|
|
13
|
+
details: MaybeRef<FormDetails>;
|
|
14
|
+
}
|
|
15
|
+
/** What a `provideFieldDefaults` or `RuiFieldDefaults` scope sets; an unset key falls through to the scope above. */
|
|
16
|
+
export interface FieldScopeOptions {
|
|
17
|
+
labelPlacement?: MaybeRefOrGetter<LabelPlacement | undefined>;
|
|
18
|
+
details?: MaybeRefOrGetter<FormDetails | undefined>;
|
|
12
19
|
}
|
|
13
20
|
/** The app-wide default, set through `createRui({ defaults: { field } })`. */
|
|
14
21
|
export declare const FieldSymbol: InjectionKey<FieldOptions>;
|
|
15
22
|
export declare function createFieldDefaults(options?: Partial<FieldOptions>): FieldOptions;
|
|
16
|
-
/**
|
|
17
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Sets defaults for every field rendered below the calling component. A key left unset
|
|
25
|
+
* keeps what an enclosing scope set. Passing a placement alone is the 3.0 form.
|
|
26
|
+
*/
|
|
27
|
+
export declare function provideFieldDefaults(options: FieldScopeOptions | MaybeRefOrGetter<LabelPlacement | undefined>): void;
|
|
18
28
|
/**
|
|
19
29
|
* The placement a field uses: its own prop, then the nearest scope, then the
|
|
20
30
|
* app default, then `top`.
|
|
21
31
|
*/
|
|
22
32
|
export declare function useLabelPlacement(placement: MaybeRefOrGetter<LabelPlacement | undefined>): ComputedRef<LabelPlacement>;
|
|
33
|
+
/**
|
|
34
|
+
* The details mode the scope and app give a control that sets none itself: the nearest
|
|
35
|
+
* scope, then the app default. `undefined` when neither sets one. Outside a component
|
|
36
|
+
* setup there is nothing to inject, so it is always `undefined` there.
|
|
37
|
+
*/
|
|
38
|
+
export declare function useInheritedDetails(): () => FormDetails | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, inject, provide, toValue } from "vue";
|
|
1
|
+
import { computed, hasInjectionContext, inject, isRef, provide, toValue } from "vue";
|
|
2
2
|
//#region src/composables/defaults/field.ts
|
|
3
3
|
/** The app-wide default, set through `createRui({ defaults: { field } })`. */
|
|
4
4
|
var FieldSymbol = Symbol.for("rui:field");
|
|
@@ -7,12 +7,27 @@ var FieldScopeSymbol = Symbol.for("rui:field-scope");
|
|
|
7
7
|
function createFieldDefaults(options) {
|
|
8
8
|
return {
|
|
9
9
|
labelPlacement: "top",
|
|
10
|
+
details: "reserve",
|
|
10
11
|
...options
|
|
11
12
|
};
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
function isScopeOptions(options) {
|
|
15
|
+
return typeof options === "object" && !isRef(options);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Sets defaults for every field rendered below the calling component. A key left unset
|
|
19
|
+
* keeps what an enclosing scope set. Passing a placement alone is the 3.0 form.
|
|
20
|
+
*/
|
|
21
|
+
function provideFieldDefaults(options) {
|
|
22
|
+
const { labelPlacement, details } = isScopeOptions(options) ? options : {
|
|
23
|
+
labelPlacement: options,
|
|
24
|
+
details: void 0
|
|
25
|
+
};
|
|
26
|
+
const parent = inject(FieldScopeSymbol, void 0);
|
|
27
|
+
provide(FieldScopeSymbol, {
|
|
28
|
+
labelPlacement: () => toValue(labelPlacement) ?? parent?.labelPlacement(),
|
|
29
|
+
details: () => toValue(details) ?? parent?.details()
|
|
30
|
+
});
|
|
16
31
|
}
|
|
17
32
|
/**
|
|
18
33
|
* The placement a field uses: its own prop, then the nearest scope, then the
|
|
@@ -21,9 +36,20 @@ function provideFieldDefaults(labelPlacement) {
|
|
|
21
36
|
function useLabelPlacement(placement) {
|
|
22
37
|
const scope = inject(FieldScopeSymbol, void 0);
|
|
23
38
|
const app = inject(FieldSymbol, void 0);
|
|
24
|
-
return computed(() => toValue(placement) ??
|
|
39
|
+
return computed(() => toValue(placement) ?? scope?.labelPlacement() ?? (app ? toValue(app.labelPlacement) : void 0) ?? "top");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The details mode the scope and app give a control that sets none itself: the nearest
|
|
43
|
+
* scope, then the app default. `undefined` when neither sets one. Outside a component
|
|
44
|
+
* setup there is nothing to inject, so it is always `undefined` there.
|
|
45
|
+
*/
|
|
46
|
+
function useInheritedDetails() {
|
|
47
|
+
if (!hasInjectionContext()) return () => void 0;
|
|
48
|
+
const scope = inject(FieldScopeSymbol, void 0);
|
|
49
|
+
const app = inject(FieldSymbol, void 0);
|
|
50
|
+
return () => scope?.details() ?? (app ? toValue(app.details) : void 0);
|
|
25
51
|
}
|
|
26
52
|
//#endregion
|
|
27
|
-
export { FieldSymbol, createFieldDefaults, provideFieldDefaults, useLabelPlacement };
|
|
53
|
+
export { FieldSymbol, createFieldDefaults, provideFieldDefaults, useInheritedDetails, useLabelPlacement };
|
|
28
54
|
|
|
29
55
|
//# sourceMappingURL=field.js.map
|