@worknice/whiteboard 0.62.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -468,7 +468,8 @@ const CustomizableTable = ({ data, columns, csvFilename, getRowId, availableColu
468
468
  return void 0 !== tableColumn && tableColumn.getIsVisible();
469
469
  }), [
470
470
  filterableColumns,
471
- reactTable
471
+ reactTable,
472
+ columnVisibility
472
473
  ]);
473
474
  const hasFilterableColumns = filterableColumnsForModal.length > 0;
474
475
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
@@ -1,5 +1,6 @@
1
1
  import { type CSSProperties, type ReactNode } from "react";
2
2
  import { type ZodTypeAny } from "zod";
3
+ import { type RichListRowHeight } from "./helpers";
3
4
  import { type RichListBulkAction, type RichListContentSlot, type RichListMainSlot, type RichListRowAction, type RichListSlot } from "./types";
4
5
  type CommonProps<Type> = {
5
6
  data: Array<Type>;
@@ -48,9 +49,14 @@ type CommonProps<Type> = {
48
49
  */
49
50
  rowActions?: (row: Type) => Array<RichListRowAction<Type> | null>;
50
51
  /**
52
+ * Row height preset, pixel value, or breakpoint-specific values keyed to
53
+ * `compactBreakpoint` (same signal as `layoutVisibility: "whenWide"` / `"whenCompact"`).
54
+ *
55
+ * @example rowHeight="large"
56
+ * @example rowHeight={{ whenWide: "large", whenCompact: "medium" }}
51
57
  * @default `"medium"`
52
58
  */
53
- rowHeight?: number | "small" | "medium" | "large";
59
+ rowHeight?: RichListRowHeight;
54
60
  /**
55
61
  * File name for CSV export when columns with `csvExport: true` are included.
56
62
  * @default (omitted) no CSV download from the list toolbar.
@@ -149,4 +155,4 @@ type NavigationProps<Type> = {
149
155
  export type RichListProps<Type> = CommonProps<Type> & NavigationProps<Type>;
150
156
  declare const RichList: <Type>({ data, getRowId, leadingSlot, mainSlot, contentSlots, contentAlignment, trailingSlot, href, onClick, rowActions, bulkActions, secondaryBulkActions, rowHeight, csvFilename, fillContainerHeight, compactBreakpoint: compactBreakpointProp, emptyState, id, pathName, localStorageSchema, header, }: RichListProps<Type>) => import("react/jsx-runtime").JSX.Element;
151
157
  export default RichList;
152
- export type { RichListBulkAction, RichListColumnWidthMode, RichListContentSlot, RichListLayoutVisibility, RichListMainSlot, RichListRowAction, RichListSlot, RichListSlotSize, RichListTextField, } from "./types";
158
+ export type { RichListBulkAction, RichListColumnWidthMode, RichListContentSlot, RichListGrouping, RichListLayoutVisibility, RichListMainSlot, RichListRowAction, RichListSlot, RichListSlotSize, RichListTextField, } from "./types";
@@ -63,7 +63,6 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
63
63
  contentSlots
64
64
  ]);
65
65
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useLayoutEffect)(()=>{
66
- if (0 === renderableContentSlots.length) return;
67
66
  const el = listScopeRef.current;
68
67
  if (!el) return;
69
68
  const update = ()=>{
@@ -75,7 +74,6 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
75
74
  ro.observe(el);
76
75
  return ()=>ro.disconnect();
77
76
  }, [
78
- renderableContentSlots,
79
77
  compactBreakpointPx
80
78
  ]);
81
79
  const enableRowSelection = bulkActions.length + secondaryBulkActions.length > 0;
@@ -146,6 +144,9 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
146
144
  const sortableEntries = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>allEntries.filter((e)=>null !== e && e.enableSorting && void 0 !== e.value), [
147
145
  allEntries
148
146
  ]);
147
+ const groupableEntries = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>allEntries.filter((e)=>null !== e && void 0 !== e.grouping), [
148
+ allEntries
149
+ ]);
149
150
  const hasSortableEntries = sortableEntries.length > 0;
150
151
  const sortableEntryIds = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>new Set(sortableEntries.map((entry)=>entry.id)), [
151
152
  sortableEntries
@@ -155,12 +156,14 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
155
156
  const tableFilteringForEntry = (entryId)=>!(void 0 !== inlineSingleSelectExcludedFromTableColumnId && entryId === inlineSingleSelectExcludedFromTableColumnId);
156
157
  const columns = allEntries.filter((e)=>null !== e).map((entry)=>{
157
158
  const tableFiltering = !!entry.filter && tableFilteringForEntry(entry.id);
159
+ const grouping = entry.grouping;
158
160
  if (void 0 === entry.value) return columnHelper.display({
159
161
  id: entry.id,
160
162
  cell: ({ row })=>entry.render(row.original),
161
163
  enableHiding: (0, __WEBPACK_EXTERNAL_MODULE__helpers_js_87289b43__.isColumnWithVisibilityState)(entry),
162
164
  enableGlobalFilter: false,
163
- enableColumnFilter: tableFiltering
165
+ enableColumnFilter: tableFiltering,
166
+ getGroupingValue: grouping ? (row)=>grouping.fn(row) : void 0
164
167
  });
165
168
  const value = entry.value;
166
169
  return columnHelper.accessor((row)=>value(row), {
@@ -171,6 +174,7 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
171
174
  enableSorting: entry.enableSorting,
172
175
  sortingFn: entry.sortingFn ?? "auto",
173
176
  sortUndefined: 1,
177
+ getGroupingValue: grouping ? (row)=>grouping.fn(row) : void 0,
174
178
  filterFn: entry.filter && tableFiltering ? (row, _columnId, filterValue)=>{
175
179
  const filter = entry.filter;
176
180
  if (!filter) return true;
@@ -311,8 +315,11 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
311
315
  data: tableData,
312
316
  columns: columnDefs,
313
317
  getRowId,
318
+ groupedColumnMode: false,
314
319
  getCoreRowModel: (0, __WEBPACK_EXTERNAL_MODULE__tanstack_react_table_777e1b4b__.getCoreRowModel)(),
315
320
  getFilteredRowModel: (0, __WEBPACK_EXTERNAL_MODULE__tanstack_react_table_777e1b4b__.getFilteredRowModel)(),
321
+ getGroupedRowModel: (0, __WEBPACK_EXTERNAL_MODULE__tanstack_react_table_777e1b4b__.getGroupedRowModel)(),
322
+ getExpandedRowModel: (0, __WEBPACK_EXTERNAL_MODULE__tanstack_react_table_777e1b4b__.getExpandedRowModel)(),
316
323
  ...hasSortableEntries ? {
317
324
  getSortedRowModel: (0, __WEBPACK_EXTERNAL_MODULE__tanstack_react_table_777e1b4b__.getSortedRowModel)()
318
325
  } : {},
@@ -321,12 +328,15 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
321
328
  initialState: {
322
329
  columnFilters: tableColumnFiltersInitialState,
323
330
  columnVisibility: initialColumnVisibility,
331
+ expanded: true,
324
332
  globalFilter: "",
333
+ grouping: parsedLocalStorage.grouping ?? [],
325
334
  sorting: initialSorting
326
335
  },
327
336
  defaultColumn: {
328
337
  enableColumnFilter: false,
329
338
  enableGlobalFilter: false,
339
+ enableGrouping: false,
330
340
  enableSorting: false
331
341
  }
332
342
  });
@@ -363,12 +373,14 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
363
373
  if (storageKey) window.localStorage.setItem(storageKey, JSON.stringify({
364
374
  columnFilters: mergeInlineSinglePersistedColumnFilters(tableState.columnFilters, inlineSingleSelectExcludedFromTableColumnId, inlineSingleSelectOptionIdResolved),
365
375
  columnVisibility: tableState.columnVisibility,
366
- sorting: persistedSorting
376
+ sorting: persistedSorting,
377
+ grouping: tableState.grouping
367
378
  }));
368
379
  }, [
369
380
  storageKey,
370
381
  tableState.columnFilters,
371
382
  tableState.columnVisibility,
383
+ tableState.grouping,
372
384
  persistedSorting,
373
385
  inlineSingleSelectExcludedFromTableColumnId,
374
386
  inlineSingleSelectOptionIdResolved
@@ -393,13 +405,17 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
393
405
  const hasMultipleActions = allBulkActionRowCounts.length > 1;
394
406
  const allRowsCanDoAllActions = hasMultipleActions && allBulkActionRowCounts.every((count)=>count === filteredSelectedRows.rows.length);
395
407
  const showBulkActionCounts = bulkActionRowCountsDiffer || hasMultipleActions && !allRowsCanDoAllActions;
396
- const resolvedRowHeightPx = "number" == typeof rowHeight ? rowHeight : __WEBPACK_EXTERNAL_MODULE__helpers_js_87289b43__.ROW_HEIGHT_PRESETS[rowHeight];
408
+ const resolvedRowHeightValue = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>(0, __WEBPACK_EXTERNAL_MODULE__helpers_js_87289b43__.resolveRichListRowHeightValue)(rowHeight, isCompactContentSlots, "medium"), [
409
+ rowHeight,
410
+ isCompactContentSlots
411
+ ]);
412
+ const resolvedRowHeightPx = (0, __WEBPACK_EXTERNAL_MODULE__helpers_js_87289b43__.richListRowHeightToPx)(resolvedRowHeightValue);
397
413
  const listRootStyle = (0, __WEBPACK_EXTERNAL_MODULE__utils_customProperties_js_3d9c174d__["default"])({
398
414
  "--row-height": `${resolvedRowHeightPx}px`,
399
- "--richlist-padding-inline": `${(0, __WEBPACK_EXTERNAL_MODULE__helpers_js_87289b43__.richListInlinePaddingPx)(rowHeight)}px`
415
+ "--richlist-padding-inline": `${(0, __WEBPACK_EXTERNAL_MODULE__helpers_js_87289b43__.richListInlinePaddingPx)(resolvedRowHeightValue)}px`
400
416
  });
401
417
  const showDisplayForColumnVisibility = !isCompactContentSlots && toggleableContentSlots.length > 0;
402
- const showDisplayButton = hasSortableEntries || showDisplayForColumnVisibility;
418
+ const showDisplayButton = hasSortableEntries || groupableEntries.length > 0 || showDisplayForColumnVisibility;
403
419
  const defaultDisplayColumnVisibility = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>Object.fromEntries(toggleableContentSlots.map((entry)=>[
404
420
  entry.id,
405
421
  !("hiddenByDefault" in entry && entry.hiddenByDefault)
@@ -412,6 +428,12 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
412
428
  })), [
413
429
  sortableEntries
414
430
  ]);
431
+ const groupableColumnsForModal = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>groupableEntries.map((entry)=>({
432
+ id: entry.id,
433
+ label: entry.grouping.label
434
+ })), [
435
+ groupableEntries
436
+ ]);
415
437
  const displayColumnsForModal = toggleableContentSlots.map((entry)=>({
416
438
  id: entry.id,
417
439
  label: entry.label ?? entry.id,
@@ -419,7 +441,7 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
419
441
  defaultVisible: !("hiddenByDefault" in entry && entry.hiddenByDefault)
420
442
  }));
421
443
  const displayColumnsForDisplayModal = isCompactContentSlots ? [] : displayColumnsForModal;
422
- const displayActiveCount = (0, __WEBPACK_EXTERNAL_MODULE__RichListDisplayModal_js_6277e838__.getDisplayFormActiveExpanderCount)(hasSortableEntries, persistedSorting, displayColumnsForDisplayModal);
444
+ const displayActiveCount = (0, __WEBPACK_EXTERNAL_MODULE__RichListDisplayModal_js_6277e838__.getDisplayFormActiveExpanderCount)(hasSortableEntries, persistedSorting, displayColumnsForDisplayModal, groupableEntries.length > 0, tableState.grouping[0]);
423
445
  const hasToolbar = enableRowSelection || entriesWithGlobalFilter.length > 0 || entriesWithFilter.length > 0 || showDisplayButton || shouldShowCsvExport;
424
446
  const actionsByRowId = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
425
447
  const map = new Map();
@@ -530,7 +552,7 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
530
552
  tone: "muted",
531
553
  children: [
532
554
  "Showing ",
533
- table.getFilteredRowModel().flatRows.length,
555
+ table.getPreGroupedRowModel().flatRows.length,
534
556
  " of",
535
557
  " ",
536
558
  table.getPreFilteredRowModel().flatRows.length
@@ -552,9 +574,12 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
552
574
  }),
553
575
  rows.length > 0 ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("ul", {
554
576
  className: __WEBPACK_EXTERNAL_MODULE__RichList_module_js_320d4975__["default"].list,
555
- children: rows.map((row)=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__RichListRow_js_08189b13__["default"], {
577
+ children: rows.map((row)=>{
578
+ const groupEntry = groupableEntries.find((entry)=>entry.id === row.groupingColumnId);
579
+ return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__RichListRow_js_08189b13__["default"], {
556
580
  row: row,
557
581
  table: table,
582
+ groupEntry: groupEntry,
558
583
  enableRowSelection: enableRowSelection,
559
584
  href: href,
560
585
  onClick: onClick,
@@ -569,7 +594,8 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
569
594
  contentSlotsJustifyContent: contentAlignment,
570
595
  actionsForRow: actionsByRowId.get(row.id) ?? [],
571
596
  lastSelectedRowRef: lastSelectedRowRef
572
- }, row.id))
597
+ }, row.id);
598
+ })
573
599
  }) : /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
574
600
  className: __WEBPACK_EXTERNAL_MODULE__RichList_module_js_320d4975__["default"].emptyState,
575
601
  children: emptyState
@@ -588,6 +614,11 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
588
614
  sortableColumns: sortableColumnsForModal,
589
615
  currentSorting: persistedSorting,
590
616
  onApplySorting: (sorting)=>table.setSorting(sorting),
617
+ groupableColumns: groupableColumnsForModal,
618
+ currentGroupingId: tableState.grouping[0],
619
+ onApplyGrouping: (columnId)=>table.setGrouping(columnId ? [
620
+ columnId
621
+ ] : []),
591
622
  displayColumns: displayColumnsForDisplayModal,
592
623
  onApplyColumnVisibility: (vis)=>{
593
624
  table.setColumnVisibility((prev)=>{
@@ -599,6 +630,7 @@ const RichList = ({ data, getRowId, leadingSlot, mainSlot, contentSlots = EMPTY_
599
630
  });
600
631
  },
601
632
  defaultSorting: [],
633
+ defaultGroupingId: void 0,
602
634
  defaultColumnVisibility: defaultDisplayColumnVisibility
603
635
  })
604
636
  ]
@@ -1,17 +1,21 @@
1
1
  import type { SortingState } from "@tanstack/react-table";
2
2
  /**
3
3
  * How many `FilterExpander` sections in the display form are in the
4
- * highlighted (non-default) state: Sort, and/or Visible columns.
4
+ * highlighted (non-default) state: Sort, Group by, and/or Visible columns.
5
5
  */
6
6
  export declare function getDisplayFormActiveExpanderCount(hasSortForm: boolean, sorting: SortingState, displayColumnRows: Array<{
7
7
  id: string;
8
8
  visible: boolean;
9
9
  defaultVisible: boolean;
10
- }>): number;
10
+ }>, hasGroupForm: boolean, groupingId: string | undefined): number;
11
11
  type SortableColumn = {
12
12
  id: string;
13
13
  label: string;
14
14
  };
15
+ type GroupableColumn = {
16
+ id: string;
17
+ label: string;
18
+ };
15
19
  type DisplayColumn = {
16
20
  id: string;
17
21
  label: string;
@@ -24,10 +28,14 @@ type Props = {
24
28
  sortableColumns: SortableColumn[];
25
29
  currentSorting: SortingState;
26
30
  onApplySorting: (sorting: SortingState) => void;
31
+ groupableColumns: GroupableColumn[];
32
+ currentGroupingId: string | undefined;
33
+ onApplyGrouping: (columnId: string | undefined) => void;
27
34
  displayColumns: DisplayColumn[];
28
35
  onApplyColumnVisibility: (visibility: Record<string, boolean>) => void;
29
36
  defaultSorting: SortingState;
37
+ defaultGroupingId: string | undefined;
30
38
  defaultColumnVisibility: Record<string, boolean>;
31
39
  };
32
- declare const RichListDisplayModal: ({ onClose, sortableColumns, currentSorting, onApplySorting, displayColumns, onApplyColumnVisibility, defaultSorting, defaultColumnVisibility, }: Props) => import("react/jsx-runtime").JSX.Element;
40
+ declare const RichListDisplayModal: ({ onClose, sortableColumns, currentSorting, onApplySorting, groupableColumns, currentGroupingId, onApplyGrouping, displayColumns, onApplyColumnVisibility, defaultSorting, defaultGroupingId, defaultColumnVisibility, }: Props) => import("react/jsx-runtime").JSX.Element;
33
41
  export default RichListDisplayModal;
@@ -16,13 +16,15 @@ import * as __WEBPACK_EXTERNAL_MODULE__Modal_js_91697624__ from "../Modal.js";
16
16
  import * as __WEBPACK_EXTERNAL_MODULE__PlainText_js_6d36b5d5__ from "../PlainText.js";
17
17
  import * as __WEBPACK_EXTERNAL_MODULE__VStack_js_6ebc0134__ from "../VStack.js";
18
18
  const NO_SORT_ID = "__richListNoSort__";
19
- function getDisplayFormActiveExpanderCount(hasSortForm, sorting, displayColumnRows) {
19
+ const NO_GROUP_ID = "__richListNoGroup__";
20
+ function getDisplayFormActiveExpanderCount(hasSortForm, sorting, displayColumnRows, hasGroupForm, groupingId) {
20
21
  let n = 0;
21
22
  if (hasSortForm && void 0 !== sorting[0]) n += 1;
23
+ if (hasGroupForm && void 0 !== groupingId) n += 1;
22
24
  if (displayColumnRows.some((c)=>c.visible !== c.defaultVisible)) n += 1;
23
25
  return n;
24
26
  }
25
- const RichListDisplayModal = ({ onClose, sortableColumns, currentSorting, onApplySorting, displayColumns, onApplyColumnVisibility, defaultSorting, defaultColumnVisibility })=>{
27
+ const RichListDisplayModal = ({ onClose, sortableColumns, currentSorting, onApplySorting, groupableColumns, currentGroupingId, onApplyGrouping, displayColumns, onApplyColumnVisibility, defaultSorting, defaultGroupingId, defaultColumnVisibility })=>{
26
28
  const sortOptions = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>[
27
29
  {
28
30
  id: NO_SORT_ID,
@@ -32,9 +34,19 @@ const RichListDisplayModal = ({ onClose, sortableColumns, currentSorting, onAppl
32
34
  ], [
33
35
  sortableColumns
34
36
  ]);
37
+ const groupOptions = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>[
38
+ {
39
+ id: NO_GROUP_ID,
40
+ label: "No grouping"
41
+ },
42
+ ...groupableColumns
43
+ ], [
44
+ groupableColumns
45
+ ]);
35
46
  const firstSort = currentSorting[0];
36
47
  const initialSortColumnId = firstSort?.id ?? NO_SORT_ID;
37
48
  const initialSortDesc = firstSort?.desc ?? false;
49
+ const initialGroupColumnId = currentGroupingId ?? NO_GROUP_ID;
38
50
  const initialVisibility = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>Object.fromEntries(displayColumns.map((c)=>[
39
51
  c.id,
40
52
  c.visible
@@ -45,6 +57,7 @@ const RichListDisplayModal = ({ onClose, sortableColumns, currentSorting, onAppl
45
57
  initialValues: {
46
58
  sortColumnId: initialSortColumnId,
47
59
  sortDesc: initialSortDesc,
60
+ groupColumnId: initialGroupColumnId,
48
61
  visibility: initialVisibility
49
62
  },
50
63
  onSubmit: async (values)=>{
@@ -55,6 +68,7 @@ const RichListDisplayModal = ({ onClose, sortableColumns, currentSorting, onAppl
55
68
  }
56
69
  ] : [];
57
70
  onApplySorting(nextSort);
71
+ onApplyGrouping(values.groupColumnId && values.groupColumnId !== NO_GROUP_ID ? values.groupColumnId : void 0);
58
72
  onApplyColumnVisibility(values.visibility);
59
73
  }
60
74
  });
@@ -62,19 +76,27 @@ const RichListDisplayModal = ({ onClose, sortableColumns, currentSorting, onAppl
62
76
  data.sortColumnId,
63
77
  sortOptions
64
78
  ]);
79
+ const groupColumnOption = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>groupOptions.find((o)=>o.id === data.groupColumnId) ?? groupOptions[0], [
80
+ data.groupColumnId,
81
+ groupOptions
82
+ ]);
65
83
  const isSortActive = data.sortColumnId !== NO_SORT_ID;
84
+ const isGroupActive = data.groupColumnId !== NO_GROUP_ID;
66
85
  const hasSortSection = sortableColumns.length > 0;
86
+ const hasGroupSection = groupableColumns.length > 0;
67
87
  const hasDisplaySection = displayColumns.length > 0;
68
88
  const handleReset = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
69
89
  setData(()=>({
70
90
  sortColumnId: defaultSorting[0]?.id ?? NO_SORT_ID,
71
91
  sortDesc: defaultSorting[0]?.desc ?? false,
92
+ groupColumnId: defaultGroupingId ?? NO_GROUP_ID,
72
93
  visibility: {
73
94
  ...defaultColumnVisibility
74
95
  }
75
96
  }));
76
97
  }, [
77
98
  defaultColumnVisibility,
99
+ defaultGroupingId,
78
100
  defaultSorting,
79
101
  setData
80
102
  ]);
@@ -93,7 +115,7 @@ const RichListDisplayModal = ({ onClose, sortableColumns, currentSorting, onAppl
93
115
  type: "secondary",
94
116
  onClick: handleReset,
95
117
  icon: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__icons_components_Restore_js_f78ce3bd__["default"], {}),
96
- disabled: !hasSortSection && !hasDisplaySection,
118
+ disabled: !hasSortSection && !hasGroupSection && !hasDisplaySection,
97
119
  children: "Reset"
98
120
  }),
99
121
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__forms_FormButtonSet_js_786d786e__["default"], {
@@ -118,8 +140,8 @@ const RichListDisplayModal = ({ onClose, sortableColumns, currentSorting, onAppl
118
140
  children: [
119
141
  hasSortSection ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__controls_FilterModal_js_c5dcd344__.FilterExpander, {
120
142
  label: "Sort by",
121
- highlight: isSortActive,
122
- defaultOpen: !hasDisplaySection || isSortActive,
143
+ highlight: isSortActive || hasGroupSection && isGroupActive,
144
+ defaultOpen: !hasDisplaySection || isSortActive || hasGroupSection && isGroupActive,
123
145
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(__WEBPACK_EXTERNAL_MODULE__VStack_js_6ebc0134__["default"], {
124
146
  spacing: "n2",
125
147
  justifyItems: "start",
@@ -158,10 +180,41 @@ const RichListDisplayModal = ({ onClose, sortableColumns, currentSorting, onAppl
158
180
  }));
159
181
  },
160
182
  disabled: !isSortActive
161
- })
183
+ }),
184
+ hasGroupSection ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__inputs_SelectInput_js_a37c3c04__["default"], {
185
+ id: "richListDisplayGroupColumn",
186
+ options: groupOptions,
187
+ optionToId: (o)=>o.id,
188
+ optionToLabel: (o)=>o.label,
189
+ value: groupColumnOption,
190
+ onChange: (option)=>{
191
+ setData((prev)=>({
192
+ ...prev,
193
+ groupColumnId: option.id
194
+ }));
195
+ }
196
+ }) : null
162
197
  ]
163
198
  })
164
199
  }) : null,
200
+ !hasSortSection && hasGroupSection ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__controls_FilterModal_js_c5dcd344__.FilterExpander, {
201
+ label: "Group by",
202
+ highlight: isGroupActive,
203
+ defaultOpen: !hasDisplaySection || isGroupActive,
204
+ children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__inputs_SelectInput_js_a37c3c04__["default"], {
205
+ id: "richListDisplayGroupColumn",
206
+ options: groupOptions,
207
+ optionToId: (o)=>o.id,
208
+ optionToLabel: (o)=>o.label,
209
+ value: groupColumnOption,
210
+ onChange: (option)=>{
211
+ setData((prev)=>({
212
+ ...prev,
213
+ groupColumnId: option.id
214
+ }));
215
+ }
216
+ })
217
+ }) : null,
165
218
  hasDisplaySection ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__controls_FilterModal_js_c5dcd344__.FilterExpander, {
166
219
  label: "Visible columns",
167
220
  highlight: displayColumns.some((c)=>data.visibility[c.id] !== c.defaultVisible),
@@ -1,10 +1,15 @@
1
1
  import { type Row, type Table } from "@tanstack/react-table";
2
2
  import { type CSSProperties, type MutableRefObject } from "react";
3
- import { type NormalizedSlot, type NormalizedTextField } from "./types";
3
+ import { type NormalizedSlot, type NormalizedTextField, type RichListGrouping } from "./types";
4
4
  import { type RichListRowAction } from "./types";
5
+ type GroupEntry<Type> = {
6
+ id: string;
7
+ grouping: RichListGrouping<Type>;
8
+ };
5
9
  type Props<Type> = {
6
10
  row: Row<Type>;
7
11
  table: Table<Type>;
12
+ groupEntry: GroupEntry<Type> | undefined;
8
13
  /** When the list has bulk actions, rows can be selected via the checkbox lane. */
9
14
  enableRowSelection: boolean;
10
15
  href: ((row: Type) => string) | undefined;
@@ -34,5 +39,5 @@ type Props<Type> = {
34
39
  actionsForRow: Array<RichListRowAction<Type>>;
35
40
  lastSelectedRowRef: MutableRefObject<Row<Type> | undefined>;
36
41
  };
37
- declare const RichListRow: <Type>({ row, table, enableRowSelection, href, onClick, normalizedLeadingSlots, normalizedPrimary, normalizedSecondary, mainSlotMaxWidthPx, normalizedContentSlots, normalizedTrailingSlots, isCompactContentSlots, rowMainHidesContentSlotColumns, contentSlotsJustifyContent, actionsForRow, lastSelectedRowRef, }: Props<Type>) => import("react/jsx-runtime").JSX.Element;
42
+ declare const RichListRow: <Type>({ row, table, groupEntry, enableRowSelection, href, onClick, normalizedLeadingSlots, normalizedPrimary, normalizedSecondary, mainSlotMaxWidthPx, normalizedContentSlots, normalizedTrailingSlots, isCompactContentSlots, rowMainHidesContentSlotColumns, contentSlotsJustifyContent, actionsForRow, lastSelectedRowRef, }: Props<Type>) => import("react/jsx-runtime").JSX.Element;
38
43
  export default RichListRow;
@@ -20,7 +20,7 @@ function contentSlotAlignClass(align) {
20
20
  return __WEBPACK_EXTERNAL_MODULE__RichListRow_module_js_3bb1d324__["default"].contentSlotStart;
21
21
  }
22
22
  }
23
- const RichListRow = ({ row, table, enableRowSelection, href, onClick, normalizedLeadingSlots, normalizedPrimary, normalizedSecondary, mainSlotMaxWidthPx, normalizedContentSlots, normalizedTrailingSlots, isCompactContentSlots, rowMainHidesContentSlotColumns, contentSlotsJustifyContent, actionsForRow, lastSelectedRowRef })=>{
23
+ const RichListRow = ({ row, table, groupEntry, enableRowSelection, href, onClick, normalizedLeadingSlots, normalizedPrimary, normalizedSecondary, mainSlotMaxWidthPx, normalizedContentSlots, normalizedTrailingSlots, isCompactContentSlots, rowMainHidesContentSlotColumns, contentSlotsJustifyContent, actionsForRow, lastSelectedRowRef })=>{
24
24
  const { Link } = (0, __WEBPACK_EXTERNAL_MODULE__utils_useNextContext_js_c6ca8eb1__["default"])();
25
25
  const rowOriginal = row.original;
26
26
  const hrefValue = href ? href(rowOriginal) : void 0;
@@ -139,6 +139,16 @@ const RichListRow = ({ row, table, enableRowSelection, href, onClick, normalized
139
139
  },
140
140
  onChange: (value)=>row.toggleSelected(value)
141
141
  });
142
+ if (row.getIsGrouped() && groupEntry) return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("li", {
143
+ className: __WEBPACK_EXTERNAL_MODULE__RichListRow_module_js_3bb1d324__["default"].listItem,
144
+ children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
145
+ className: (0, __WEBPACK_EXTERNAL_MODULE_clsx__["default"])(__WEBPACK_EXTERNAL_MODULE__RichListRow_module_js_3bb1d324__["default"].row, __WEBPACK_EXTERNAL_MODULE__RichListRow_module_js_3bb1d324__["default"].rowGrouped),
146
+ children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
147
+ className: __WEBPACK_EXTERNAL_MODULE__RichListRow_module_js_3bb1d324__["default"].groupHeader,
148
+ children: groupEntry.grouping.header(rowOriginal)
149
+ })
150
+ })
151
+ });
142
152
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("li", {
143
153
  className: __WEBPACK_EXTERNAL_MODULE__RichListRow_module_js_3bb1d324__["default"].listItem,
144
154
  "data-selected": row.getIsSelected() ? "" : void 0,
@@ -2,6 +2,8 @@ import "./RichListRow_module.css";
2
2
  const RichListRow_module_rslib_entry_ = {
3
3
  listItem: "listItem-HfVE7t",
4
4
  row: "row-qNQike",
5
+ groupHeader: "groupHeader-XItOuo",
6
+ rowGrouped: "rowGrouped-M7DdXT",
5
7
  clickableZone: "clickableZone-KG4Ygg",
6
8
  clickableZoneActive: "clickableZoneActive-OtaDew",
7
9
  leadingLane: "leadingLane-oEnTWq",
@@ -7,6 +7,14 @@
7
7
  border-top: solid var(--size-n5) var(--color-grey-t09);
8
8
  }
9
9
 
10
+ .groupHeader-XItOuo {
11
+ flex: auto;
12
+ align-items: center;
13
+ width: 100%;
14
+ min-width: 0;
15
+ display: flex;
16
+ }
17
+
10
18
  .row-qNQike {
11
19
  --row-bg: transparent;
12
20
  --row-hover-bg: var(--color-grey-t10);
@@ -40,6 +48,20 @@
40
48
  .listItem-HfVE7t[data-selected] > .row-qNQike:hover {
41
49
  background-color: var(--color-purple-t09);
42
50
  }
51
+
52
+ .row-qNQike.rowGrouped-M7DdXT:hover {
53
+ background-color: var(--color-grey-t10);
54
+ }
55
+ }
56
+
57
+ .row-qNQike.rowGrouped-M7DdXT {
58
+ --row-bg: var(--color-grey-t10);
59
+ --row-hover-bg: var(--color-grey-t10);
60
+ background-color: var(--color-grey-t10);
61
+ height: auto;
62
+ min-height: 0;
63
+ padding: var(--size-00);
64
+ overflow: visible;
43
65
  }
44
66
 
45
67
  .clickableZone-KG4Ygg {
@@ -58,7 +80,7 @@
58
80
  cursor: pointer;
59
81
  }
60
82
 
61
- .clickableZoneActive-OtaDew :is(.leadingLane-oEnTWq, .rowMain-ekCI8x, .trailingLane-J4qLz8) a[href], .clickableZoneActive-OtaDew :is(.leadingLane-oEnTWq, .rowMain-ekCI8x, .trailingLane-J4qLz8) a[role="link"], .clickableZoneActive-OtaDew .contentSlot-xgewfJ a[href], .clickableZoneActive-OtaDew .contentSlot-xgewfJ a[role="link"] {
83
+ .clickableZoneActive-OtaDew :is(.leadingLane-oEnTWq, .rowMain-ekCI8x, .trailingLane-J4qLz8) :is(a[href], a[role="link"], button), .clickableZoneActive-OtaDew .contentSlot-xgewfJ :is(a[href], a[role="link"], button) {
62
84
  pointer-events: auto;
63
85
  z-index: 2;
64
86
  position: relative;
@@ -239,10 +261,6 @@
239
261
  display: flex;
240
262
  }
241
263
 
242
- .primaryLine-Sedy1b {
243
- font: var(--font-regular-bold);
244
- }
245
-
246
264
  .secondaryLine-iySU25 {
247
265
  color: var(--color-grey-s03);
248
266
  }
@@ -1,4 +1,5 @@
1
1
  .root-S5afi_ {
2
+ isolation: isolate;
2
3
  background: var(--color-white);
3
4
  border-radius: var(--size-n2);
4
5
  border: solid var(--size-n5) var(--color-grey-t09);
@@ -28,13 +28,29 @@ export declare const formatSlotSize: (size: RichListSlotSize) => string;
28
28
  * `data-richlist-compact` attribute that JS sets on `.richListQueryScope` from
29
29
  * `isCompactContentSlots` (driven by this prop).
30
30
  * - The Display dialog's column-visibility section is hidden (no room).
31
+ * - `rowHeight` object form picks `whenCompact` vs `whenWide` (see `RichListRowHeight`).
31
32
  */
32
33
  export declare const RICH_LIST_CONTENT_COMPACT_MAX_PX = 1024;
33
34
  export declare const ROW_HEIGHT_PRESETS: {
34
35
  readonly small: 56;
35
36
  readonly medium: 72;
36
- readonly large: 104;
37
+ readonly large: 96;
37
38
  };
39
+ export type RichListRowHeightValue = number | keyof typeof ROW_HEIGHT_PRESETS;
40
+ type AtLeastOne<T, K extends keyof T = keyof T> = K extends keyof T ? Pick<T, K> & Partial<Omit<T, K>> : never;
41
+ /** Breakpoint-specific row height; at least one of `whenWide` / `whenCompact` required. */
42
+ export type RichListRowHeightByBreakpoint = AtLeastOne<{
43
+ whenWide: RichListRowHeightValue;
44
+ whenCompact: RichListRowHeightValue;
45
+ }>;
46
+ export type RichListRowHeight = RichListRowHeightValue | RichListRowHeightByBreakpoint;
47
+ export declare const isRichListRowHeightByBreakpoint: (rowHeight: RichListRowHeight) => rowHeight is RichListRowHeightByBreakpoint;
48
+ export declare const richListRowHeightToPx: (value: RichListRowHeightValue) => number;
49
+ /**
50
+ * Picks the scalar height for the current compact state.
51
+ * Missing side falls back to `defaultValue` (RichList default: `"medium"`).
52
+ */
53
+ export declare const resolveRichListRowHeightValue: (rowHeight: RichListRowHeight | undefined, isCompact: boolean, defaultValue?: RichListRowHeightValue) => RichListRowHeightValue;
38
54
  /**
39
55
  * Horizontal padding (px) applied across the whole list (toolbar, rows, empty state)
40
56
  * at each row height preset. Forwarded as the `--richlist-padding-inline` custom
@@ -44,7 +60,7 @@ export declare const ROW_HEIGHT_PRESETS: {
44
60
  export declare const RICH_LIST_INLINE_PAD_PRESET_PX: {
45
61
  [K in keyof typeof ROW_HEIGHT_PRESETS]: number;
46
62
  };
47
- export declare const richListInlinePaddingPx: (rowHeight: number | keyof typeof ROW_HEIGHT_PRESETS) => number;
63
+ export declare const richListInlinePaddingPx: (rowHeight: RichListRowHeightValue) => number;
48
64
  export declare const SELECT_COLUMN_ID = "_richListSelect";
49
65
  export declare const normalizeTextField: <Type>(field: RichListTextField<Type>, position: "primary" | "secondary") => NormalizedTextField<Type>;
50
66
  /**
@@ -13,7 +13,15 @@ const RICH_LIST_CONTENT_COMPACT_MAX_PX = 1024;
13
13
  const ROW_HEIGHT_PRESETS = {
14
14
  small: 56,
15
15
  medium: 72,
16
- large: 104
16
+ large: 96
17
+ };
18
+ const isRichListRowHeightByBreakpoint = (rowHeight)=>"object" == typeof rowHeight && null !== rowHeight;
19
+ const richListRowHeightToPx = (value)=>"number" == typeof value ? value : ROW_HEIGHT_PRESETS[value];
20
+ const resolveRichListRowHeightValue = (rowHeight, isCompact, defaultValue = "medium")=>{
21
+ const input = rowHeight ?? defaultValue;
22
+ if (!isRichListRowHeightByBreakpoint(input)) return input;
23
+ const selected = isCompact ? input.whenCompact : input.whenWide;
24
+ return selected ?? defaultValue;
17
25
  };
18
26
  const RICH_LIST_INLINE_PAD_PRESET_PX = {
19
27
  small: 12,
@@ -51,7 +59,8 @@ const normalizeTextField = (field, position)=>{
51
59
  csvExport: field.csvExport ?? false,
52
60
  enableSorting: field.enableSorting ?? false,
53
61
  sortingFn: field.sortingFn,
54
- layoutVisibility: field.layoutVisibility ?? "always"
62
+ layoutVisibility: field.layoutVisibility ?? "always",
63
+ grouping: field.grouping
55
64
  };
56
65
  };
57
66
  const normalizeSlot = (slot, position, positionIndex)=>{
@@ -90,7 +99,8 @@ const normalizeSlot = (slot, position, positionIndex)=>{
90
99
  hiddenByDefault: slot.hiddenByDefault ?? false,
91
100
  csvExport: slot.csvExport ?? false,
92
101
  enableSorting: slot.enableSorting ?? false,
93
- sortingFn: slot.sortingFn
102
+ sortingFn: slot.sortingFn,
103
+ grouping: slot.grouping
94
104
  };
95
105
  };
96
106
  const isVisibleAtBreakpoint = (layoutVisibility, isCompactContentSlots)=>{
@@ -148,4 +158,4 @@ const richListRowActionToMenuOption = (action, row)=>{
148
158
  render: action.render
149
159
  };
150
160
  };
151
- export { RICH_LIST_CONTENT_COMPACT_MAX_PX, RICH_LIST_INLINE_PAD_PRESET_PX, ROW_HEIGHT_PRESETS, SELECT_COLUMN_ID, formatSlotSize, handleDownloadCsv, isColumnWithVisibilityState, isToggleableContentColumn, isVisibleAtBreakpoint, normalizeSlot, normalizeTextField, richListInlinePaddingPx, richListRowActionToMenuOption };
161
+ export { RICH_LIST_CONTENT_COMPACT_MAX_PX, RICH_LIST_INLINE_PAD_PRESET_PX, ROW_HEIGHT_PRESETS, SELECT_COLUMN_ID, formatSlotSize, handleDownloadCsv, isColumnWithVisibilityState, isRichListRowHeightByBreakpoint, isToggleableContentColumn, isVisibleAtBreakpoint, normalizeSlot, normalizeTextField, resolveRichListRowHeightValue, richListInlinePaddingPx, richListRowActionToMenuOption, richListRowHeightToPx };
@@ -1,6 +1,7 @@
1
1
  import type { CSSProperties } from "react";
2
+ import type { RichListRowHeight } from "../helpers";
2
3
  export type CommonProps = {
3
4
  compactBreakpoint?: number;
4
5
  contentAlignment?: NonNullable<CSSProperties["justifyContent"]>;
5
- rowHeight?: number | "large" | "medium" | "small";
6
+ rowHeight?: RichListRowHeight;
6
7
  };
@@ -2,6 +2,12 @@ import type { SortingColumnDef } from "@tanstack/react-table";
2
2
  import { type ReactNode } from "react";
3
3
  import { type Filter } from "../../controls/FilterModal";
4
4
  import { type PrimitiveValue } from "../../utils/tables";
5
+ /** Row grouping config. */
6
+ export type RichListGrouping<Type> = {
7
+ fn: (row: Type) => string;
8
+ header: (row: Type) => ReactNode;
9
+ label: string;
10
+ };
5
11
  /**
6
12
  * Column width. Use a number (pixels) or a percentage string such as `"30%"` if the
7
13
  * track should grow or shrink with the list width.
@@ -106,6 +112,8 @@ export type RichListTextField<Type> = ((row: Type) => ReactNode) | {
106
112
  * @default `"always"`
107
113
  */
108
114
  layoutVisibility?: RichListLayoutVisibility;
115
+ /** When set, this field can group rows in the list toolbar. */
116
+ grouping?: RichListGrouping<Type>;
109
117
  };
110
118
  /**
111
119
  * Primary and optional secondary lines stacked in the row’s main column (same horizontal
@@ -196,6 +204,8 @@ type RichListBaseSlotObject<Type> = {
196
204
  * @default `"always"`
197
205
  */
198
206
  layoutVisibility?: RichListLayoutVisibility;
207
+ /** When set, this column can group rows in the list toolbar. */
208
+ grouping?: RichListGrouping<Type>;
199
209
  };
200
210
  /**
201
211
  * A **leading** or **trailing** column. The row order is: leading, main slot (primary /
@@ -277,6 +287,7 @@ export type NormalizedTextField<Type> = {
277
287
  sortingFn?: SortingColumnDef<Type>["sortingFn"];
278
288
  /** @default `"always"` */
279
289
  layoutVisibility: RichListLayoutVisibility;
290
+ grouping?: RichListGrouping<Type>;
280
291
  };
281
292
  /**
282
293
  * Internal shape after `normalizeSlot` in `helpers.ts`. See `RichListSlot` and
@@ -318,6 +329,7 @@ export type NormalizedSlot<Type> = {
318
329
  enableSorting: boolean;
319
330
  /** @default `"auto"` */
320
331
  sortingFn?: SortingColumnDef<Type>["sortingFn"];
332
+ grouping?: RichListGrouping<Type>;
321
333
  };
322
334
  /**
323
335
  * One action for a row: an icon in the action strip and/or an item in the “more” menu.
@@ -5,3 +5,13 @@
5
5
  display: grid;
6
6
  }
7
7
 
8
+ .container-yc42of > header > :first-child {
9
+ min-width: 0;
10
+ }
11
+
12
+ @media (max-width: 768px) {
13
+ .container-yc42of > header {
14
+ grid-template-columns: 1fr auto;
15
+ }
16
+ }
17
+
@@ -1,6 +1,12 @@
1
1
  import { type ReactNode } from "react";
2
2
  type Props = {
3
3
  direction?: "row" | "column";
4
+ /**
5
+ * When set, at most this many tags are rendered, followed by a "+N" count
6
+ * of the remaining tags. The set becomes a button that opens a modal
7
+ * listing every tag.
8
+ */
9
+ maxVisibleTags?: number;
4
10
  tags: Array<{
5
11
  key: string;
6
12
  value: ReactNode;
@@ -11,5 +17,5 @@ type Props = {
11
17
  * nothing will be rendered. If there's not enough space, the tags will wrap
12
18
  * (using flexbox) or be truncated.
13
19
  */
14
- declare const TagSet: ({ tags, direction }: Props) => import("react/jsx-runtime").JSX.Element | null;
20
+ declare const TagSet: ({ tags, direction, maxVisibleTags }: Props) => import("react/jsx-runtime").JSX.Element | null;
15
21
  export default TagSet;
@@ -1,18 +1,81 @@
1
+ "use client";
1
2
  import * as __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__ from "react/jsx-runtime";
2
3
  import * as __WEBPACK_EXTERNAL_MODULE_clsx__ from "clsx";
3
4
  import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react";
5
+ import * as __WEBPACK_EXTERNAL_MODULE__controls_Button_js_f591ba2e__ from "../controls/Button.js";
6
+ import * as __WEBPACK_EXTERNAL_MODULE__icons_components_Close_js_7809217d__ from "../icons/components/Close.js";
7
+ import * as __WEBPACK_EXTERNAL_MODULE__Card_js_d67c086a__ from "./Card.js";
8
+ import * as __WEBPACK_EXTERNAL_MODULE__CardContent_js_20e3f6de__ from "./CardContent.js";
9
+ import * as __WEBPACK_EXTERNAL_MODULE__Modal_js_50f53bdf__ from "./Modal.js";
10
+ import * as __WEBPACK_EXTERNAL_MODULE__PlainText_js_cd0b6798__ from "./PlainText.js";
4
11
  import * as __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__ from "./TagSet.module.js";
5
- const TagSet = ({ tags, direction = "row" })=>{
12
+ const TagSet = ({ tags, direction = "row", maxVisibleTags })=>{
13
+ const [isModalOpen, setIsModalOpen] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(false);
6
14
  const nonNullTags = tags.filter((badge)=>null !== badge && void 0 !== badge.value && null !== badge.value);
7
- return nonNullTags.length > 0 ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
8
- className: (0, __WEBPACK_EXTERNAL_MODULE_clsx__["default"])([
9
- __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__["default"].container,
10
- "row" === direction ? __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__["default"].directionRow : __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__["default"].directionColumn
11
- ]),
15
+ if (0 === nonNullTags.length) return null;
16
+ const containerClassName = (0, __WEBPACK_EXTERNAL_MODULE_clsx__["default"])([
17
+ __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__["default"].container,
18
+ "row" === direction ? __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__["default"].directionRow : __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__["default"].directionColumn
19
+ ]);
20
+ const hiddenTagCount = void 0 === maxVisibleTags ? 0 : Math.max(nonNullTags.length - maxVisibleTags, 0);
21
+ if (0 === hiddenTagCount) return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
22
+ className: containerClassName,
12
23
  children: nonNullTags.map(({ key, value })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE_react__.Fragment, {
13
24
  children: value
14
25
  }, key))
15
- }) : null;
26
+ });
27
+ return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.Fragment, {
28
+ children: [
29
+ /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("button", {
30
+ "aria-label": `Show all ${nonNullTags.length} tags`,
31
+ className: (0, __WEBPACK_EXTERNAL_MODULE_clsx__["default"])(containerClassName, __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__["default"].overflowTrigger),
32
+ onClick: (event)=>{
33
+ event.stopPropagation();
34
+ setIsModalOpen(true);
35
+ },
36
+ title: `Show all ${nonNullTags.length} tags`,
37
+ type: "button",
38
+ children: [
39
+ nonNullTags.slice(0, maxVisibleTags).map(({ key, value })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE_react__.Fragment, {
40
+ children: value
41
+ }, key)),
42
+ /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(__WEBPACK_EXTERNAL_MODULE__PlainText_js_cd0b6798__["default"], {
43
+ font: "small-semibold",
44
+ children: [
45
+ "+",
46
+ hiddenTagCount
47
+ ]
48
+ })
49
+ ]
50
+ }),
51
+ isModalOpen ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__Modal_js_50f53bdf__["default"], {
52
+ onClose: ()=>setIsModalOpen(false),
53
+ size: "small",
54
+ children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__Card_js_d67c086a__["default"], {
55
+ header: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__PlainText_js_cd0b6798__["default"], {
56
+ font: "h6",
57
+ children: "Tags"
58
+ }),
59
+ actions: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__controls_Button_js_f591ba2e__["default"], {
60
+ icon: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__icons_components_Close_js_7809217d__["default"], {}),
61
+ onClick: ()=>setIsModalOpen(false),
62
+ type: "ghost"
63
+ }),
64
+ children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__CardContent_js_20e3f6de__["default"], {
65
+ children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
66
+ className: (0, __WEBPACK_EXTERNAL_MODULE_clsx__["default"])([
67
+ __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__["default"].container,
68
+ __WEBPACK_EXTERNAL_MODULE__TagSet_module_js_d14b95cb__["default"].directionRow
69
+ ]),
70
+ children: nonNullTags.map(({ key, value })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE_react__.Fragment, {
71
+ children: value
72
+ }, key))
73
+ })
74
+ })
75
+ })
76
+ }) : null
77
+ ]
78
+ });
16
79
  };
17
80
  const TagSet_rslib_entry_ = TagSet;
18
81
  export { TagSet_rslib_entry_ as default };
@@ -2,6 +2,7 @@ import "./TagSet_module.css";
2
2
  const TagSet_module_rslib_entry_ = {
3
3
  container: "container-L0HAwG",
4
4
  directionRow: "directionRow-gPULoA",
5
- directionColumn: "directionColumn-YfoXcq"
5
+ directionColumn: "directionColumn-YfoXcq",
6
+ overflowTrigger: "overflowTrigger-GgLKSJ"
6
7
  };
7
8
  export { TagSet_module_rslib_entry_ as default };
@@ -13,3 +13,13 @@
13
13
  flex-direction: column;
14
14
  }
15
15
 
16
+ .overflowTrigger-GgLKSJ {
17
+ cursor: pointer;
18
+ align-items: center;
19
+ }
20
+
21
+ .overflowTrigger-GgLKSJ:focus-visible {
22
+ border-radius: var(--size-n3);
23
+ box-shadow: 0px 0px 0px 2px var(--color-white), 0px 0px 0px 4px var(--color-purple-000);
24
+ }
25
+
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@worknice/whiteboard",
3
3
  "description": "",
4
- "version": "0.62.0",
4
+ "version": "0.63.0",
5
5
  "license": "MIT",
6
6
  "private": false,
7
7
  "files": [
@@ -39,7 +39,7 @@
39
39
  "react-markdown": "^10.1.0",
40
40
  "utf8": "^3.0.0",
41
41
  "zod": "^4.1.13",
42
- "@worknice/utils": "^0.45.0"
42
+ "@worknice/utils": "^0.46.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@anolilab/semantic-release-pnpm": "^3.2.2",