nuance-ui 0.1.27 → 0.1.29

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/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^4.0.0"
6
6
  },
7
- "version": "0.1.27",
7
+ "version": "0.1.29",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
@@ -1,6 +1,11 @@
1
1
  import type { Updater } from '@tanstack/vue-table';
2
2
  import type { Ref } from 'vue';
3
- import type { TableColumn, TableData } from './model.js';
3
+ import type { TableColumn, TableData, TableProps, TableRow } from './model.js';
4
4
  export declare function processColumns<T extends TableData>(columns: TableColumn<T>[]): TableColumn<T>[];
5
5
  export declare function valueUpdater<T extends Updater<any>>(updaterOrValue: T, ref: Ref): void;
6
6
  export declare function resolveValue<T, A = undefined>(prop: T | ((arg: A) => T), arg?: A): T | undefined;
7
+ export declare function createRowHandlers<T extends TableData>(props: TableProps<T>): {
8
+ onRowSelect: (e: Event, row: TableRow<T>) => void;
9
+ onRowHover: (e: Event, row: TableRow<T> | null) => void;
10
+ onRowContextmenu: (e: Event, row: TableRow<T>) => void;
11
+ };
@@ -22,3 +22,34 @@ export function resolveValue(prop, arg) {
22
22
  return prop(arg);
23
23
  return prop;
24
24
  }
25
+ export function createRowHandlers(props) {
26
+ function onRowSelect(e, row) {
27
+ if (!props?.onSelect)
28
+ return;
29
+ const target = e.target;
30
+ const isInteractive = target.closest("button") || target.closest("a");
31
+ if (isInteractive)
32
+ return;
33
+ e.preventDefault();
34
+ e.stopPropagation();
35
+ props.onSelect(e, row);
36
+ }
37
+ function onRowHover(e, row) {
38
+ if (!props?.onHover)
39
+ return;
40
+ props.onHover(e, row);
41
+ }
42
+ function onRowContextmenu(e, row) {
43
+ if (!props?.onContextmenu)
44
+ return;
45
+ if (Array.isArray(props.onContextmenu))
46
+ props.onContextmenu.forEach((fn) => fn(e, row));
47
+ else
48
+ props.onContextmenu(e, row);
49
+ }
50
+ return {
51
+ onRowSelect,
52
+ onRowHover,
53
+ onRowContextmenu
54
+ };
55
+ }
@@ -1,11 +1,11 @@
1
1
  import type { RowData, TableMeta } from '@tanstack/table-core';
2
2
  import type { CellContext, ColumnDef, ColumnFiltersOptions, ColumnPinningOptions, ColumnSizingOptions, CoreOptions, ExpandedOptions, FacetedOptions, GlobalFilterOptions, GroupingOptions, HeaderContext, PaginationOptions, Row, RowPinningOptions, RowSelectionOptions, SortingOptions, VisibilityOptions } from '@tanstack/vue-table';
3
3
  import type { VirtualizerOptions } from '@tanstack/vue-virtual';
4
- import type { TableHTMLAttributes, WatchOptions } from 'vue';
4
+ import type { CSSProperties, TableHTMLAttributes, WatchOptions } from 'vue';
5
5
  import type { NuanceColor } from '../../types/index.js';
6
6
  export type TableRow<T> = Row<T>;
7
7
  export type TableData = RowData;
8
- export type TableColumn<T extends TableData, D = unknown> = ColumnDef<T, D>;
8
+ export type TableColumn<T extends TableData, D = any> = ColumnDef<T, D>;
9
9
  export interface TableOptions<T extends TableData = TableData> extends Omit<CoreOptions<T>, 'data' | 'columns' | 'getCoreRowModel' | 'state' | 'onStateChange' | 'renderFallbackValue'> {
10
10
  state?: CoreOptions<T>['state'];
11
11
  onStateChange?: CoreOptions<T>['onStateChange'];
@@ -63,6 +63,7 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
63
63
  * @defaultValue 'primary'
64
64
  */
65
65
  loadingColor?: NuanceColor | string;
66
+ verticalAlign?: CSSProperties['verticalAlign'];
66
67
  onSelect?: (e: Event, row: TableRow<T>) => void;
67
68
  onHover?: (e: Event, row: TableRow<T> | null) => void;
68
69
  onContextmenu?: ((e: Event, row: TableRow<T>) => void) | Array<((e: Event, row: TableRow<T>) => void)>;
@@ -71,6 +72,7 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
71
72
  table?: string;
72
73
  thead?: string;
73
74
  th?: string;
75
+ td?: string;
74
76
  tr?: string;
75
77
  tbody?: string;
76
78
  tfoot?: string;
@@ -1,14 +1,18 @@
1
1
  <script setup>
2
- import { FlexRender, getCoreRowModel, getExpandedRowModel, getFilteredRowModel, getSortedRowModel, useVueTable } from "@tanstack/vue-table";
3
- import { useVirtualizer } from "@tanstack/vue-virtual";
2
+ import {
3
+ FlexRender,
4
+ getCoreRowModel,
5
+ getExpandedRowModel,
6
+ getFilteredRowModel,
7
+ getSortedRowModel,
8
+ useVueTable
9
+ } from "@tanstack/vue-table";
4
10
  import { reactivePick, unrefElement } from "@vueuse/core";
5
11
  import { useStyleResolver } from "#imports";
6
- import defu from "defu";
7
- import { computed, ref, toRef, useTemplateRef, watch } from "vue";
12
+ import { computed, ref, useTemplateRef, watch } from "vue";
8
13
  import { getThemeColor } from "../../utils";
9
14
  import Box from "../box.vue";
10
- import TableRow from "./_ui/table-row.vue";
11
- import { processColumns, resolveValue, valueUpdater } from "./lib";
15
+ import { createRowHandlers, processColumns, resolveValue, valueUpdater } from "./lib";
12
16
  defineOptions({ inheritAttrs: false });
13
17
  const props = defineProps({
14
18
  data: { type: Array, required: false },
@@ -20,6 +24,7 @@ const props = defineProps({
20
24
  sticky: { type: [Boolean, String], required: false },
21
25
  loading: { type: Boolean, required: false },
22
26
  loadingColor: { type: null, required: false },
27
+ verticalAlign: { type: null, required: false },
23
28
  onSelect: { type: Function, required: false },
24
29
  onHover: { type: Function, required: false },
25
30
  onContextmenu: { type: [Function, Array], required: false },
@@ -196,32 +201,11 @@ const rows = computed(() => table.getRowModel().rows);
196
201
  watch(() => props.data, () => {
197
202
  data.value = props.data ? [...props.data] : [];
198
203
  }, props.watchOptions);
199
- const virtualizerProps = toRef(() => defu(typeof props.virtualize === "boolean" ? {} : props.virtualize, {
200
- estimateSize: 65,
201
- overscan: 12
202
- }));
203
- const virtualizer = !!props.virtualize && useVirtualizer({
204
- ...virtualizerProps.value,
205
- get count() {
206
- return rows.value.length;
207
- },
208
- getScrollElement: () => unrefElement(rootRef),
209
- estimateSize: (index) => {
210
- const estimate = virtualizerProps.value.estimateSize;
211
- return typeof estimate === "function" ? estimate(index) : estimate;
212
- }
213
- });
214
- const renderedSize = computed(() => {
215
- if (!virtualizer)
216
- return 0;
217
- const virtualItems = virtualizer.value.getVirtualItems();
218
- if (!virtualItems?.length)
219
- return 0;
220
- return virtualItems.reduce((sum, item) => sum + item.size, 0);
221
- });
222
204
  const style = computed(() => useStyleResolver((theme) => ({
223
- "--table-loader-color": props.loadingColor ? getThemeColor(props.loadingColor, theme) : void 0
205
+ "--table-loader-color": props.loadingColor ? getThemeColor(props.loadingColor, theme) : void 0,
206
+ "--vertical-align": props.verticalAlign
224
207
  })));
208
+ const { onRowContextmenu, onRowHover, onRowSelect } = createRowHandlers(props);
225
209
  defineExpose({
226
210
  get $el() {
227
211
  return unrefElement(rootRef);
@@ -232,15 +216,7 @@ defineExpose({
232
216
  </script>
233
217
 
234
218
  <template>
235
- <Box
236
- ref='rootRef'
237
- :class='[$style.root, props.classes?.root]'
238
- :style='[
239
- virtualizer ? { height: `${virtualizer.getTotalSize()}px` } : void 0,
240
- style
241
- ]'
242
- :mod='{ virtualize: !!virtualizer }'
243
- >
219
+ <Box ref='rootRef' :class='[$style.root, props.classes?.root]' :style>
244
220
  <table ref='tableRef' :class='[$style.table, props.classes?.table]'>
245
221
  <caption v-if='caption || $slots.caption' :class='props.classes?.caption'>
246
222
  <slot name='caption'>
@@ -265,8 +241,15 @@ defineExpose({
265
241
  :scope="header.colSpan > 1 ? 'colgroup' : 'col'"
266
242
  :colspan='header.colSpan > 1 ? header.colSpan : void 0'
267
243
  :rowspan='header.rowSpan > 1 ? header.rowSpan : void 0'
268
- :class='[$style.th, props.classes?.th, resolveValue(header.column.columnDef.meta?.class?.th, header)]'
269
- :style='resolveValue(header.column.columnDef.meta?.style?.th, header)'
244
+ :class='[
245
+ $style.th,
246
+ props.classes?.th,
247
+ resolveValue(header.column.columnDef.meta?.class?.th, header)
248
+ ]'
249
+ :style='[
250
+ { width: header.getSize() !== 150 ? `${header.getSize()}px` : void 0 },
251
+ resolveValue(header.column.columnDef.meta?.style?.th, header)
252
+ ]'
270
253
  >
271
254
  <slot :name='`${header.id}-header`' v-bind='header.getContext()'>
272
255
  <FlexRender
@@ -285,36 +268,47 @@ defineExpose({
285
268
  <slot name='body-top' />
286
269
 
287
270
  <template v-if='rows.length'>
288
- <template v-if='virtualizer'>
289
- <template v-for='(virtualRow, index) in virtualizer.getVirtualItems()' :key='rows[virtualRow.index]?.id'>
290
- <TableRow
291
- :row='rows[virtualRow.index]'
292
- :class='[$style.tr, props.classes?.tr, resolveValue(table.options.meta?.class?.tr, virtualRow)]'
293
- :style='[
294
- {
295
- height: `${virtualRow.size}px`,
296
- transform: `translateY(${virtualRow.start - index * virtualRow.size}px)`
297
- },
298
- resolveValue(table.options.meta?.style?.tr, virtualRow)
299
- ]'
300
- :on-select='props?.onSelect'
301
- :on-hover='props?.onHover'
302
- :on-contextmenu='props?.onContextmenu'
303
- />
304
- </template>
305
- </template>
306
-
307
- <template v-else>
308
- <TableRow
309
- v-for='row in rows'
310
- :key='row.id'
311
- :row='row'
271
+ <template v-for='row in rows' :key='row.id'>
272
+ <Box
273
+ is='tr'
274
+ :mod='{
275
+ selected: row.getIsSelected(),
276
+ expanded: row.getIsExpanded(),
277
+ selectable: !!onSelect || !!onHover || !!onContextmenu
278
+ }'
279
+ :role="onSelect ? 'button' : void 0"
280
+ :tabindex='onSelect ? 0 : void 0'
312
281
  :class='[$style.tr, props.classes?.tr, resolveValue(table.options.meta?.class?.tr, row)]'
313
282
  :style='resolveValue(table.options.meta?.style?.tr, row)'
314
- :on-select='props?.onSelect'
315
- :on-hover='props?.onHover'
316
- :on-contextmenu='props?.onContextmenu'
317
- />
283
+ @click='onRowSelect($event, row)'
284
+ @pointerenter='onRowHover($event, row)'
285
+ @pointerleave='onRowHover($event, null)'
286
+ @contextmenu='onRowContextmenu($event, row)'
287
+ >
288
+ <Box
289
+ is='td'
290
+ v-for='cell in row.getVisibleCells()'
291
+ :key='cell.id'
292
+ :mod='{ pinned: cell.column.getIsPinned() }'
293
+ :colspan='resolveValue(cell.column.columnDef.meta?.colspan?.td, cell)'
294
+ :rowspan='resolveValue(cell.column.columnDef.meta?.rowspan?.td, cell)'
295
+ :class='resolveValue(cell.column.columnDef.meta?.class?.td, cell)'
296
+ :style='[
297
+ { width: cell.column.getSize() !== 150 ? `${cell.column.getSize()}px` : void 0 },
298
+ resolveValue(cell.column.columnDef.meta?.style?.td, cell)
299
+ ]'
300
+ >
301
+ <slot :name='`${cell.column.id}-cell`' v-bind='cell.getContext()'>
302
+ <FlexRender :render='cell.column.columnDef.cell' :props='cell.getContext()' />
303
+ </slot>
304
+ </Box>
305
+ </Box>
306
+
307
+ <tr v-if='row.getIsExpanded()'>
308
+ <td :colspan='row.getAllCells().length'>
309
+ <slot name='expanded' :row='row' />
310
+ </td>
311
+ </tr>
318
312
  </template>
319
313
  </template>
320
314
 
@@ -339,7 +333,6 @@ defineExpose({
339
333
  is='tfoot'
340
334
  v-if='hasFooter'
341
335
  :class='[$style.tfoot, props.classes?.tfoot]'
342
- :style='virtualizer ? { transform: `translateY(${virtualizer.getTotalSize() - renderedSize}px)` } : void 0'
343
336
  :mod='{ sticky: props.sticky === "footer" || props.sticky === true }'
344
337
  >
345
338
  <tr :class='[$style.separator, props.classes?.separator]' />
@@ -374,6 +367,9 @@ defineExpose({
374
367
  --table-color: var(--color-primary-4);
375
368
  --table-loader-color: var(--table-color);
376
369
  --table-loader-animation: carousel 2s ease-in-out infinite;
370
+ --table-padding-x: .5rem;
371
+ --table-padding-y: .5rem;
372
+ --vertical-align: baseline;
377
373
 
378
374
  @mixin where-light {
379
375
  --table-active-bg: alpha(var(--color-slate-1), .5);
@@ -431,10 +427,11 @@ defineExpose({
431
427
 
432
428
  .th {
433
429
  font-weight: 600;
434
- padding-block: .75rem;
435
- padding-inline: 1rem;
430
+ padding-block: var(--table-padding-y);
431
+ padding-inline: var(--table-padding-x);
436
432
  text-align: left;
437
433
  color: var(--table-c);
434
+ vertical-align: var(--vertical-align);
438
435
 
439
436
  &:has([role='checkbox']) {
440
437
  padding-inline-end: 0;
@@ -482,8 +479,10 @@ defineExpose({
482
479
 
483
480
  td {
484
481
  white-space: nowrap;
485
- padding: 1rem;
482
+ padding-block: var(--table-padding-y);
483
+ padding-inline: var(--table-padding-x);
486
484
  color: var(--table-c);
485
+ vertical-align: var(--vertical-align);
487
486
 
488
487
  &:has([role='checkbox']) {
489
488
  padding-inline-end: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuance-ui",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "description": "A UI Library for Modern Web Apps, powered by Vue.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,35 +0,0 @@
1
- import type { Row } from '@tanstack/vue-table';
2
- import type { TableData, TableRow } from '../model.js';
3
- export interface TableRowProps<T extends TableData> {
4
- row: Row<T>;
5
- onSelect?: (e: Event, row: TableRow<T>) => void;
6
- onHover?: (e: Event, row: TableRow<T> | null) => void;
7
- onContextmenu?: ((e: Event, row: TableRow<T>) => void) | Array<((e: Event, row: TableRow<T>) => void)>;
8
- }
9
- declare const __VLS_export: <T extends TableData>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
10
- props: __VLS_PrettifyLocal<TableRowProps<T>> & import("vue").PublicProps;
11
- expose: (exposed: {}) => void;
12
- attrs: any;
13
- slots: {
14
- [x: `${string}-cell`]: ((props: {
15
- cell: import("@tanstack/table-core").Cell<T, unknown>;
16
- column: import("@tanstack/table-core").Column<T, unknown>;
17
- getValue: import("@tanstack/table-core").Getter<unknown>;
18
- renderValue: import("@tanstack/table-core").Getter<unknown>;
19
- row: Row<T>;
20
- table: import("@tanstack/table-core").Table<T>;
21
- }) => any) | undefined;
22
- } & {
23
- expanded?: (props: {
24
- row: Row<T>;
25
- }) => any;
26
- };
27
- emit: {};
28
- }>) => import("vue").VNode & {
29
- __ctx?: Awaited<typeof __VLS_setup>;
30
- };
31
- declare const _default: typeof __VLS_export;
32
- export default _default;
33
- type __VLS_PrettifyLocal<T> = {
34
- [K in keyof T as K]: T[K];
35
- } & {};
@@ -1,74 +0,0 @@
1
- <script setup>
2
- import { FlexRender } from "@tanstack/vue-table";
3
- import Box from "../../box.vue";
4
- import { resolveValue } from "../lib";
5
- const { row, onSelect, onHover, onContextmenu } = defineProps({
6
- row: { type: Object, required: true },
7
- onSelect: { type: Function, required: false },
8
- onHover: { type: Function, required: false },
9
- onContextmenu: { type: [Function, Array], required: false }
10
- });
11
- function onRowSelect(e, row2) {
12
- if (!onSelect)
13
- return;
14
- const target = e.target;
15
- const isInteractive = target.closest("button") || target.closest("a");
16
- if (isInteractive)
17
- return;
18
- e.preventDefault();
19
- e.stopPropagation();
20
- onSelect(e, row2);
21
- }
22
- function onRowHover(e, row2) {
23
- if (!onHover)
24
- return;
25
- onHover(e, row2);
26
- }
27
- function onRowContextmenu(e, row2) {
28
- if (!onContextmenu)
29
- return;
30
- if (Array.isArray(onContextmenu))
31
- onContextmenu.forEach((fn) => fn(e, row2));
32
- else
33
- onContextmenu(e, row2);
34
- }
35
- </script>
36
-
37
- <template>
38
- <Box
39
- is='tr'
40
- v-bind='$attrs'
41
- :mod='{
42
- selected: row.getIsSelected(),
43
- expanded: row.getIsExpanded(),
44
- selectable: !!onSelect || !!onHover || !!onContextmenu
45
- }'
46
- :role="onSelect ? 'button' : void 0"
47
- :tabindex='onSelect ? 0 : void 0'
48
- @click='onRowSelect($event, row)'
49
- @pointerenter='onRowHover($event, row)'
50
- @pointerleave='onRowHover($event, null)'
51
- @contextmenu='onRowContextmenu($event, row)'
52
- >
53
- <Box
54
- is='td'
55
- v-for='cell in row.getVisibleCells()'
56
- :key='cell.id'
57
- :mod='{ pinned: cell.column.getIsPinned() }'
58
- :colspan='resolveValue(cell.column.columnDef.meta?.colspan?.td, cell)'
59
- :rowspan='resolveValue(cell.column.columnDef.meta?.rowspan?.td, cell)'
60
- :class='resolveValue(cell.column.columnDef.meta?.class?.td, cell)'
61
- :style='resolveValue(cell.column.columnDef.meta?.style?.td, cell)'
62
- >
63
- <slot :name='`${cell.column.id}-cell`' v-bind='cell.getContext()'>
64
- <FlexRender :render='cell.column.columnDef.cell' :props='cell.getContext()' />
65
- </slot>
66
- </Box>
67
- </Box>
68
-
69
- <tr v-if='row.getIsExpanded()'>
70
- <td :colspan='row.getAllCells().length'>
71
- <slot name='expanded' :row='row' />
72
- </td>
73
- </tr>
74
- </template>
@@ -1,35 +0,0 @@
1
- import type { Row } from '@tanstack/vue-table';
2
- import type { TableData, TableRow } from '../model.js';
3
- export interface TableRowProps<T extends TableData> {
4
- row: Row<T>;
5
- onSelect?: (e: Event, row: TableRow<T>) => void;
6
- onHover?: (e: Event, row: TableRow<T> | null) => void;
7
- onContextmenu?: ((e: Event, row: TableRow<T>) => void) | Array<((e: Event, row: TableRow<T>) => void)>;
8
- }
9
- declare const __VLS_export: <T extends TableData>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
10
- props: __VLS_PrettifyLocal<TableRowProps<T>> & import("vue").PublicProps;
11
- expose: (exposed: {}) => void;
12
- attrs: any;
13
- slots: {
14
- [x: `${string}-cell`]: ((props: {
15
- cell: import("@tanstack/table-core").Cell<T, unknown>;
16
- column: import("@tanstack/table-core").Column<T, unknown>;
17
- getValue: import("@tanstack/table-core").Getter<unknown>;
18
- renderValue: import("@tanstack/table-core").Getter<unknown>;
19
- row: Row<T>;
20
- table: import("@tanstack/table-core").Table<T>;
21
- }) => any) | undefined;
22
- } & {
23
- expanded?: (props: {
24
- row: Row<T>;
25
- }) => any;
26
- };
27
- emit: {};
28
- }>) => import("vue").VNode & {
29
- __ctx?: Awaited<typeof __VLS_setup>;
30
- };
31
- declare const _default: typeof __VLS_export;
32
- export default _default;
33
- type __VLS_PrettifyLocal<T> = {
34
- [K in keyof T as K]: T[K];
35
- } & {};