@soft-stech/bootsman-ui-shadcn 1.4.36 → 1.4.37

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/index.js CHANGED
@@ -148,8 +148,8 @@ import "./BuiCalendar.vue_vue_type_style_index_0_lang-DK4yUiXC.js";
148
148
  import { _ as Bi } from "./BuiTable.vue_vue_type_script_setup_true_lang-Z45MrzQA.js";
149
149
  import { _ as fi } from "./BuiTableBody.vue_vue_type_script_setup_true_lang-BGWE-WLM.js";
150
150
  import { _ as _i } from "./BuiTableCell.vue_vue_type_script_setup_true_lang-BMPBnL81.js";
151
- import { _ as di } from "./BuiTableHead.vue_vue_type_script_setup_true_lang-Bz1T89Vm.js";
152
- import { _ as Ci } from "./BuiTableHeader.vue_vue_type_script_setup_true_lang-H9TKoH8p.js";
151
+ import { _ as di } from "./BuiTableHead.vue_vue_type_script_setup_true_lang-JNDLoSoG.js";
152
+ import { _ as Ci } from "./BuiTableHeader.vue_vue_type_script_setup_true_lang-18MBtNeo.js";
153
153
  import { _ as Fi } from "./BuiTableRow.vue_vue_type_script_setup_true_lang-f1ZCSbzt.js";
154
154
  import { _ as Si } from "./BuiTableCaption.vue_vue_type_script_setup_true_lang-C9PP4Fcx.js";
155
155
  import { _ as Ai } from "./BuiTableEmpty.vue_vue_type_script_setup_true_lang-BxUialLd.js";
@@ -0,0 +1,127 @@
1
+ export declare function useResizeColumns(): {
2
+ tableHeaderElement: import('vue').Ref<({
3
+ $: import('vue').ComponentInternalInstance;
4
+ $data: {};
5
+ $props: {
6
+ readonly class?: string | undefined;
7
+ readonly freezeHeader?: boolean | undefined;
8
+ } & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps & Readonly<{
9
+ class?: string;
10
+ freezeHeader?: boolean;
11
+ }> & Readonly<{}>;
12
+ $attrs: {
13
+ [x: string]: unknown;
14
+ };
15
+ $refs: {
16
+ [x: string]: unknown;
17
+ };
18
+ $slots: Readonly<{
19
+ [name: string]: import('vue').Slot<any> | undefined;
20
+ }>;
21
+ $root: import('vue').ComponentPublicInstance | null;
22
+ $parent: import('vue').ComponentPublicInstance | null;
23
+ $host: Element | null;
24
+ $emit: (event: string, ...args: any[]) => void;
25
+ $el: any;
26
+ $options: import('vue').ComponentOptionsBase<Readonly<{
27
+ class?: string;
28
+ freezeHeader?: boolean;
29
+ }> & Readonly<{}>, {
30
+ headRef: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
31
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, {}, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
32
+ beforeCreate?: (() => void) | (() => void)[];
33
+ created?: (() => void) | (() => void)[];
34
+ beforeMount?: (() => void) | (() => void)[];
35
+ mounted?: (() => void) | (() => void)[];
36
+ beforeUpdate?: (() => void) | (() => void)[];
37
+ updated?: (() => void) | (() => void)[];
38
+ activated?: (() => void) | (() => void)[];
39
+ deactivated?: (() => void) | (() => void)[];
40
+ beforeDestroy?: (() => void) | (() => void)[];
41
+ beforeUnmount?: (() => void) | (() => void)[];
42
+ destroyed?: (() => void) | (() => void)[];
43
+ unmounted?: (() => void) | (() => void)[];
44
+ renderTracked?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
45
+ renderTriggered?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
46
+ errorCaptured?: ((err: unknown, instance: import('vue').ComponentPublicInstance | null, info: string) => boolean | void) | ((err: unknown, instance: import('vue').ComponentPublicInstance | null, info: string) => boolean | void)[];
47
+ };
48
+ $forceUpdate: () => void;
49
+ $nextTick: typeof import('vue').nextTick;
50
+ $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
51
+ } & Readonly<{}> & Omit<Readonly<{
52
+ class?: string;
53
+ freezeHeader?: boolean;
54
+ }> & Readonly<{}>, "headRef"> & import('vue').ShallowUnwrapRef<{
55
+ headRef: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
56
+ }> & {} & import('vue').ComponentCustomProperties & {} & {
57
+ $slots: {
58
+ default?(_: {}): any;
59
+ };
60
+ }) | null, ({
61
+ $: import('vue').ComponentInternalInstance;
62
+ $data: {};
63
+ $props: {
64
+ readonly class?: string | undefined;
65
+ readonly freezeHeader?: boolean | undefined;
66
+ } & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps & Readonly<{
67
+ class?: string;
68
+ freezeHeader?: boolean;
69
+ }> & Readonly<{}>;
70
+ $attrs: {
71
+ [x: string]: unknown;
72
+ };
73
+ $refs: {
74
+ [x: string]: unknown;
75
+ };
76
+ $slots: Readonly<{
77
+ [name: string]: import('vue').Slot<any> | undefined;
78
+ }>;
79
+ $root: import('vue').ComponentPublicInstance | null;
80
+ $parent: import('vue').ComponentPublicInstance | null;
81
+ $host: Element | null;
82
+ $emit: (event: string, ...args: any[]) => void;
83
+ $el: any;
84
+ $options: import('vue').ComponentOptionsBase<Readonly<{
85
+ class?: string;
86
+ freezeHeader?: boolean;
87
+ }> & Readonly<{}>, {
88
+ headRef: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
89
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, {}, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
90
+ beforeCreate?: (() => void) | (() => void)[];
91
+ created?: (() => void) | (() => void)[];
92
+ beforeMount?: (() => void) | (() => void)[];
93
+ mounted?: (() => void) | (() => void)[];
94
+ beforeUpdate?: (() => void) | (() => void)[];
95
+ updated?: (() => void) | (() => void)[];
96
+ activated?: (() => void) | (() => void)[];
97
+ deactivated?: (() => void) | (() => void)[];
98
+ beforeDestroy?: (() => void) | (() => void)[];
99
+ beforeUnmount?: (() => void) | (() => void)[];
100
+ destroyed?: (() => void) | (() => void)[];
101
+ unmounted?: (() => void) | (() => void)[];
102
+ renderTracked?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
103
+ renderTriggered?: ((e: import('vue').DebuggerEvent) => void) | ((e: import('vue').DebuggerEvent) => void)[];
104
+ errorCaptured?: ((err: unknown, instance: import('vue').ComponentPublicInstance | null, info: string) => boolean | void) | ((err: unknown, instance: import('vue').ComponentPublicInstance | null, info: string) => boolean | void)[];
105
+ };
106
+ $forceUpdate: () => void;
107
+ $nextTick: typeof import('vue').nextTick;
108
+ $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
109
+ } & Readonly<{}> & Omit<Readonly<{
110
+ class?: string;
111
+ freezeHeader?: boolean;
112
+ }> & Readonly<{}>, "headRef"> & import('vue').ShallowUnwrapRef<{
113
+ headRef: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
114
+ }> & {} & import('vue').ComponentCustomProperties & {} & {
115
+ $slots: {
116
+ default?(_: {}): any;
117
+ };
118
+ }) | null>;
119
+ calculatedColumnSizing: import('vue').Ref<Record<string, number> | undefined, Record<string, number> | undefined>;
120
+ isResizing: import('vue').Ref<boolean, boolean>;
121
+ resizingCellId: import('vue').Ref<string, string>;
122
+ handleResizeControlMouseDown: (cellId: string, enableColumnResizing: boolean) => void;
123
+ handleResizeControlMouseUp: () => void;
124
+ resetCells: () => void;
125
+ setInitialColumnWidths: () => void;
126
+ setProvidedCellWidths: (columnSizing: Record<string, number> | undefined) => void;
127
+ };
@@ -0,0 +1,89 @@
1
+ import { ref as n } from "vue";
2
+ import "vee-validate";
3
+ import { useEventListener as R } from "@vueuse/core";
4
+ function A() {
5
+ const u = n(!1), o = n(""), r = n(""), i = n(void 0), d = n(90), m = n(void 0), a = n(null), v = n(void 0), w = (e) => {
6
+ a.value && a.value.headRef && [...a.value.headRef.querySelectorAll("th")].forEach((l) => {
7
+ const s = l.id.split("_")[0];
8
+ e && e[s] && (l.style.width = e[s] + "px");
9
+ });
10
+ }, W = () => {
11
+ if (a.value && a.value.headRef)
12
+ return [...a.value.headRef.querySelectorAll("th")].reduce((l, s) => {
13
+ const h = s.id.split("_")[0];
14
+ return {
15
+ ...l,
16
+ [h]: {
17
+ cell: s,
18
+ initialWidth: s.offsetWidth
19
+ }
20
+ };
21
+ }, {});
22
+ }, g = (e, t) => {
23
+ if (t && (u.value = !0, o.value = e, i.value)) {
24
+ const l = i.value[e].cell;
25
+ let s = l.nextElementSibling;
26
+ s || (s = l.previousElementSibling), r.value = s ? s.id.split("_")[0] : "", v.value = R(document, "mousemove", z);
27
+ }
28
+ }, x = () => {
29
+ if (u.value && (u.value = !1, o.value = "", r.value = "", v.value && v.value(), i.value)) {
30
+ const e = {};
31
+ for (let t in i.value) {
32
+ const l = i.value[t], s = l.cell.hasAttribute("can-resize") ? Math.floor(l.cell.offsetWidth) <= d.value ? d.value : l.cell.offsetWidth : l.initialWidth;
33
+ l.cell.style.width = s + "px", e[t] = s;
34
+ }
35
+ m.value = e;
36
+ }
37
+ }, y = (e) => {
38
+ if (!e.nextElementSibling) {
39
+ const t = e.querySelector(".header-cell_wrapper");
40
+ if (t)
41
+ return parseInt(window.getComputedStyle(t).paddingRight);
42
+ }
43
+ return 0;
44
+ }, c = (e, t, l) => {
45
+ if (!e || !t) {
46
+ o.value = "", r.value = "";
47
+ return;
48
+ }
49
+ const s = l.movementX, h = s < 0 ? "left" : "right", f = Math.floor(parseInt(e.style.width)) + s, p = Math.floor(parseInt(t.style.width)) - s;
50
+ if (h === "left")
51
+ if (f <= d.value || !e.hasAttribute("can-resize")) {
52
+ const C = e.previousElementSibling;
53
+ c(C, t, l);
54
+ } else
55
+ e.style.width = f + "px", t.style.width = p + "px";
56
+ else if (p <= d.value + y(t) || !t.hasAttribute("can-resize")) {
57
+ const C = t.nextElementSibling;
58
+ c(e, C, l);
59
+ } else
60
+ e.style.width = f + "px", t.style.width = p + "px";
61
+ }, z = (e) => {
62
+ if (e.preventDefault(), i.value) {
63
+ const t = i.value[o.value]?.cell, l = i.value[r.value]?.cell;
64
+ c(t, l, e);
65
+ }
66
+ };
67
+ return {
68
+ tableHeaderElement: a,
69
+ calculatedColumnSizing: m,
70
+ isResizing: u,
71
+ resizingCellId: o,
72
+ handleResizeControlMouseDown: g,
73
+ handleResizeControlMouseUp: x,
74
+ resetCells: () => {
75
+ if (i.value)
76
+ for (let e in i.value)
77
+ i.value[e].cell.style.width = i.value[e].initialWidth + "px";
78
+ },
79
+ setInitialColumnWidths: () => {
80
+ if (i.value = W(), i.value)
81
+ for (let e in i.value)
82
+ i.value[e].cell.style.width || (i.value[e].cell.style.width = i.value[e].initialWidth + "px");
83
+ },
84
+ setProvidedCellWidths: w
85
+ };
86
+ }
87
+ export {
88
+ A as useResizeColumns
89
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soft-stech/bootsman-ui-shadcn",
3
- "version": "1.4.36",
3
+ "version": "1.4.37",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -27,6 +27,7 @@
27
27
  "@vueuse/integrations": "^13.0.0",
28
28
  "class-variance-authority": "0.7.0",
29
29
  "clsx": "2.1.1",
30
+ "lodash-es": "^4.17.21",
30
31
  "lucide-vue-next": "0.441.0",
31
32
  "radix-vue": "1.9.8",
32
33
  "sortablejs": "^1",
@@ -40,6 +41,7 @@
40
41
  "@rushstack/eslint-patch": "1.10.4",
41
42
  "@tsconfig/node18": "18.2.4",
42
43
  "@types/jsdom": "21.1.7",
44
+ "@types/lodash-es": "^4.17.12",
43
45
  "@types/node": "20.12.14",
44
46
  "@vitejs/plugin-vue": "5.1.3",
45
47
  "@vitest/coverage-v8": "2.1.1",
@@ -8,7 +8,6 @@ import type {
8
8
  PaginationState,
9
9
  Row,
10
10
  RowSelectionState,
11
- ColumnSizingState,
12
11
  VisibilityState,
13
12
  ColumnOrderState
14
13
  } from '@tanstack/vue-table'
@@ -69,7 +68,8 @@ const columns: ColumnDef<Task>[] = [
69
68
  },
70
69
  {
71
70
  accessorKey: 'title',
72
- header: 'Title'
71
+ header: 'Title',
72
+ enableResizing: false
73
73
  },
74
74
  {
75
75
  accessorKey: 'status',
@@ -108,7 +108,7 @@ function updateSelection(val: RowSelectionState) {
108
108
  }
109
109
 
110
110
  const columnVisibility = ref<VisibilityState>({ hiddenColumn: false })
111
- const columnSizing = ref<ColumnSizingState>({ title: 300 })
111
+ const columnSizing = ref<Record<string, number>>({ title: 350, status: 200 })
112
112
  const columnOrder = ref<ColumnOrderState>()
113
113
 
114
114
  type GroupBy = 'none' | 'status' | 'priority'
@@ -190,8 +190,8 @@ function groupName(group: string | number) {
190
190
  :data="sortedData"
191
191
  v-model:sorting="sorting"
192
192
  v-model:pagination="pagination"
193
- v-model:column-sizing="columnSizing"
194
193
  v-model:column-visibility="columnVisibility"
194
+ v-model:column-sizing="columnSizing"
195
195
  v-model:column-order="columnOrder"
196
196
  @update:selection="updateSelection"
197
197
  :total-items="totalItems"
@@ -11,7 +11,6 @@ import type {
11
11
  Column,
12
12
  ColumnDef,
13
13
  ColumnOrderState,
14
- ColumnSizingState,
15
14
  PaginationState,
16
15
  Row,
17
16
  RowSelectionState,
@@ -25,7 +24,7 @@ import {
25
24
  getSortedRowModel,
26
25
  useVueTable
27
26
  } from '@tanstack/vue-table'
28
- import { computed, watchEffect, ref, watch } from 'vue'
27
+ import { computed, watchEffect, ref, watch, onMounted, onBeforeMount, onUnmounted } from 'vue'
29
28
  import {
30
29
  BuiTable,
31
30
  BuiTableBody,
@@ -48,7 +47,9 @@ import { BuiPopover, BuiPopoverContent, BuiPopoverTrigger } from '@/components/u
48
47
  import { BuiScrollArea } from '@/components/ui/scroll-area'
49
48
  import { BuiButton } from '@/components/ui/button'
50
49
  import { Settings2Icon } from 'lucide-vue-next'
51
- import { useElementSize } from '@vueuse/core'
50
+ import { useElementSize, useEventListener } from '@vueuse/core'
51
+ import { useResizeColumns } from '@/lib/useResizeColumns'
52
+ import { isEqual } from 'lodash-es'
52
53
 
53
54
  const NO_GROUP_KEY = '#UNDEFINED#'
54
55
 
@@ -67,6 +68,7 @@ const props = withDefaults(
67
68
  renderSubComponent?: (row: Row<TData>) => (() => any) | undefined
68
69
  freezeHeader?: boolean
69
70
  enableColumnListControl?: boolean
71
+ enableColumnResizing?: boolean
70
72
  columnSearchPlaceholder?: string
71
73
  columnSearchNotFound?: string
72
74
  columnResetVisibility?: string
@@ -84,7 +86,8 @@ const props = withDefaults(
84
86
  totalItems: 0,
85
87
  columnSearchPlaceholder: 'Column name',
86
88
  columnSearchNotFound: 'Not found',
87
- columnResetVisibility: 'Reset column visibility'
89
+ columnResetVisibility: 'Reset column visibility',
90
+ enableColumnResizing: true
88
91
  }
89
92
  )
90
93
 
@@ -92,8 +95,8 @@ const sorting = defineModel<SortingState>('sorting')
92
95
  const pagination = defineModel<PaginationState>('pagination')
93
96
  const rowSelection = defineModel<RowSelectionState>('selection')
94
97
  const columnVisibility = defineModel<VisibilityState>('columnVisibility')
95
- const columnSizing = defineModel<ColumnSizingState>('columnSizing')
96
98
  const columnOrder = defineModel<ColumnOrderState>('columnOrder')
99
+ const columnSizing = defineModel<Record<string, number>>('columnSizing')
97
100
  const computedItems = computed(() =>
98
101
  props.manualPagination ? props.totalItems : props.data.length
99
102
  )
@@ -128,18 +131,12 @@ const table = useVueTable({
128
131
  onColumnVisibilityChange: (updaterOrValue) => {
129
132
  valueUpdater(updaterOrValue, columnVisibility)
130
133
  },
131
- onColumnSizingChange: (updaterOrValue) => {
132
- valueUpdater(updaterOrValue, columnSizing)
133
- },
134
134
  onColumnOrderChange: (updaterOrValue) => {
135
135
  valueUpdater(updaterOrValue, columnOrder)
136
136
  },
137
137
  autoResetPageIndex: false,
138
138
  manualPagination: props.manualPagination, // set to false to enable client-side pagination
139
139
  manualSorting: props.manualSorting,
140
- enableColumnResizing: true,
141
- columnResizeMode: 'onChange',
142
- columnResizeDirection: 'ltr',
143
140
  state: {
144
141
  get sorting() {
145
142
  return sorting.value
@@ -153,9 +150,6 @@ const table = useVueTable({
153
150
  get columnVisibility() {
154
151
  return columnVisibility.value
155
152
  },
156
- get columnSizing() {
157
- return columnSizing.value
158
- },
159
153
  get columnOrder() {
160
154
  return columnOrder.value
161
155
  }
@@ -241,6 +235,39 @@ watch(columnsListIds, () => {
241
235
 
242
236
  const tableHeaderRef = ref<InstanceType<typeof BuiTableHeader> | null>(null)
243
237
  const { height } = useElementSize(tableHeaderRef)
238
+
239
+ const {
240
+ tableHeaderElement,
241
+ calculatedColumnSizing,
242
+ isResizing,
243
+ resizingCellId,
244
+ resetCells,
245
+ handleResizeControlMouseDown,
246
+ handleResizeControlMouseUp,
247
+ setInitialColumnWidths,
248
+ setProvidedCellWidths
249
+ } = useResizeColumns()
250
+
251
+ onBeforeMount(() => {
252
+ calculatedColumnSizing.value = columnSizing.value
253
+ })
254
+
255
+ onMounted(() => {
256
+ if (tableHeaderRef.value) {
257
+ tableHeaderElement.value = tableHeaderRef.value
258
+
259
+ setProvidedCellWidths(columnSizing.value)
260
+ setInitialColumnWidths()
261
+ }
262
+ })
263
+
264
+ watchEffect(() => {
265
+ if (!isEqual(calculatedColumnSizing.value, columnSizing.value)) {
266
+ columnSizing.value = calculatedColumnSizing.value
267
+ }
268
+ })
269
+
270
+ useEventListener(document, 'mouseup', handleResizeControlMouseUp)
244
271
  </script>
245
272
 
246
273
  <template>
@@ -272,7 +299,9 @@ const { height } = useElementSize(tableHeaderRef)
272
299
  <BuiCommandInput
273
300
  :placeholder="columnSearchPlaceholder"
274
301
  v-model="searchColumn"
275
- @input="(event) => (searchColumn = event.target.value)"
302
+ @input="
303
+ (event: InputEvent) => (searchColumn = (event.target as HTMLInputElement)?.value)
304
+ "
276
305
  />
277
306
  <BuiCommandList>
278
307
  <BuiScrollArea class="h-[300px]">
@@ -295,10 +324,14 @@ const { height } = useElementSize(tableHeaderRef)
295
324
  </template>
296
325
  <BuiTableHeader v-if="tableHeaders" :freeze-header="props.freezeHeader" ref="tableHeaderRef">
297
326
  <BuiTableHead
298
- v-for="header in tableHeaders"
327
+ v-for="(header, index) in tableHeaders"
299
328
  :key="header.id"
300
- :style="{ ...getPinningStyle(header.column), width: header.getSize() + 'px' }"
329
+ :id="`${header.id}_cell`"
330
+ :style="{
331
+ ...getPinningStyle(header.column)
332
+ }"
301
333
  :freeze-header="props.freezeHeader"
334
+ :can-resize="header.column.getCanResize() ? true : undefined"
302
335
  >
303
336
  <FlexRender
304
337
  v-if="!header.isPlaceholder"
@@ -306,12 +339,15 @@ const { height } = useElementSize(tableHeaderRef)
306
339
  :props="header.getContext()"
307
340
  />
308
341
  <div
309
- @dblclick="() => header.column.resetSize()"
310
- @mousedown="header.getResizeHandler()?.($event)"
342
+ v-if="
343
+ enableColumnResizing && index < tableHeaders.length - 1 && header.column.getCanResize()
344
+ "
345
+ @dblclick="resetCells"
346
+ @mousedown="() => handleResizeControlMouseDown(header.id, props.enableColumnResizing)"
311
347
  :className="
312
348
  cn(
313
349
  'absolute top-0 right-0 h-full w-1 bg-muted-foreground opacity-0 cursor-col-resize select-none touch-none hover:opacity-50',
314
- header.column.getIsResizing() ? 'bg-primary opacity-50' : ''
350
+ isResizing && resizingCellId === header.id ? 'bg-primary opacity-50' : ''
315
351
  )
316
352
  "
317
353
  />
@@ -11,7 +11,7 @@ const props = defineProps<{
11
11
  <th
12
12
  :class="
13
13
  cn(
14
- 'h-10 text-left align-middle text-foreground [&:has([role=checkbox])]:pr-0 ',
14
+ 'relative h-10 text-left align-middle text-foreground [&:has([role=checkbox])]:pr-0 ',
15
15
  props.class,
16
16
  props.freezeHeader ? 'bg-background p-0' : 'bg-foreground/[0.04] p-0'
17
17
  )
@@ -19,10 +19,14 @@ const props = defineProps<{
19
19
  >
20
20
  <div
21
21
  class="flex h-full items-center !border-b !border-border/[0.16]"
22
- :class="{ 'bg-foreground/[0.04]': props.freezeHeader }"
22
+ :class="{
23
+ 'bg-foreground/[0.04]': props.freezeHeader,
24
+ 'header-cell_wrapper': !props.freezeHeader
25
+ }"
23
26
  >
24
27
  <div
25
28
  class="flex h-full w-full items-center whitespace-nowrap border-r border-border/[0.16] px-2 text-sm font-semibold"
29
+ :class="{ 'header-cell_wrapper': props.freezeHeader }"
26
30
  >
27
31
  <slot />
28
32
  </div>
@@ -1,5 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import { cn } from '@/lib/utils'
3
+ import { ref } from 'vue'
4
+
5
+ const headRef = ref<HTMLElement | null>(null)
6
+
7
+ defineExpose({ headRef })
3
8
 
4
9
  const props = defineProps<{
5
10
  class?: string
@@ -9,6 +14,7 @@ const props = defineProps<{
9
14
 
10
15
  <template>
11
16
  <thead
17
+ ref="headRef"
12
18
  :class="
13
19
  cn(
14
20
  '[&_tr]:border-border/[0.16]',