@vuu-ui/vuu-table-extras 0.13.64 → 0.13.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/cjs/column-list/ColumnList.js +14 -1
  2. package/cjs/column-list/ColumnList.js.map +1 -1
  3. package/cjs/column-menu/column-menu-utils.js +2 -19
  4. package/cjs/column-menu/column-menu-utils.js.map +1 -1
  5. package/cjs/column-menu/useColumnActions.js +5 -4
  6. package/cjs/column-menu/useColumnActions.js.map +1 -1
  7. package/cjs/column-picker/ColumnPicker.css.js +6 -0
  8. package/cjs/column-picker/ColumnPicker.css.js.map +1 -0
  9. package/cjs/column-picker/ColumnPicker.js +238 -0
  10. package/cjs/column-picker/ColumnPicker.js.map +1 -0
  11. package/cjs/column-picker/useColumnPicker.js +104 -0
  12. package/cjs/column-picker/useColumnPicker.js.map +1 -0
  13. package/cjs/datasource-stats/DatasourceStats.css.js +1 -1
  14. package/cjs/datasource-stats/DatasourceStats.js +3 -1
  15. package/cjs/datasource-stats/DatasourceStats.js.map +1 -1
  16. package/cjs/freeze-control/FreezeControl.css.js +1 -1
  17. package/cjs/freeze-control/FreezeControl.js +71 -10
  18. package/cjs/freeze-control/FreezeControl.js.map +1 -1
  19. package/cjs/freeze-control/FrozenBanner.css.js +6 -0
  20. package/cjs/freeze-control/FrozenBanner.css.js.map +1 -0
  21. package/cjs/freeze-control/FrozenBanner.js +55 -0
  22. package/cjs/freeze-control/FrozenBanner.js.map +1 -0
  23. package/cjs/freeze-control/useFreezeControl.js +50 -8
  24. package/cjs/freeze-control/useFreezeControl.js.map +1 -1
  25. package/cjs/index.js +6 -0
  26. package/cjs/index.js.map +1 -1
  27. package/cjs/table-column-settings/TableSettingsPanel.js +12 -1
  28. package/cjs/table-column-settings/TableSettingsPanel.js.map +1 -1
  29. package/cjs/table-column-settings/useTableAndColumnSettings.js +17 -12
  30. package/cjs/table-column-settings/useTableAndColumnSettings.js.map +1 -1
  31. package/esm/column-list/ColumnList.js +15 -2
  32. package/esm/column-list/ColumnList.js.map +1 -1
  33. package/esm/column-menu/column-menu-utils.js +2 -19
  34. package/esm/column-menu/column-menu-utils.js.map +1 -1
  35. package/esm/column-menu/useColumnActions.js +5 -4
  36. package/esm/column-menu/useColumnActions.js.map +1 -1
  37. package/esm/column-picker/ColumnPicker.css.js +4 -0
  38. package/esm/column-picker/ColumnPicker.css.js.map +1 -0
  39. package/esm/column-picker/ColumnPicker.js +235 -0
  40. package/esm/column-picker/ColumnPicker.js.map +1 -0
  41. package/esm/column-picker/useColumnPicker.js +101 -0
  42. package/esm/column-picker/useColumnPicker.js.map +1 -0
  43. package/esm/datasource-stats/DatasourceStats.css.js +1 -1
  44. package/esm/datasource-stats/DatasourceStats.js +3 -1
  45. package/esm/datasource-stats/DatasourceStats.js.map +1 -1
  46. package/esm/freeze-control/FreezeControl.css.js +1 -1
  47. package/esm/freeze-control/FreezeControl.js +73 -12
  48. package/esm/freeze-control/FreezeControl.js.map +1 -1
  49. package/esm/freeze-control/FrozenBanner.css.js +4 -0
  50. package/esm/freeze-control/FrozenBanner.css.js.map +1 -0
  51. package/esm/freeze-control/FrozenBanner.js +53 -0
  52. package/esm/freeze-control/FrozenBanner.js.map +1 -0
  53. package/esm/freeze-control/useFreezeControl.js +51 -9
  54. package/esm/freeze-control/useFreezeControl.js.map +1 -1
  55. package/esm/index.js +3 -0
  56. package/esm/index.js.map +1 -1
  57. package/esm/table-column-settings/TableSettingsPanel.js +12 -2
  58. package/esm/table-column-settings/TableSettingsPanel.js.map +1 -1
  59. package/esm/table-column-settings/useTableAndColumnSettings.js +18 -13
  60. package/esm/table-column-settings/useTableAndColumnSettings.js.map +1 -1
  61. package/package.json +11 -11
  62. package/types/column-menu/column-action-types.d.ts +5 -1
  63. package/types/column-menu/column-menu-utils.d.ts +1 -1
  64. package/types/column-picker/ColumnPicker.d.ts +6 -0
  65. package/types/column-picker/useColumnPicker.d.ts +38 -0
  66. package/types/datasource-stats/DatasourceStats.d.ts +3 -1
  67. package/types/freeze-control/FreezeControl.d.ts +6 -3
  68. package/types/freeze-control/FrozenBanner.d.ts +6 -0
  69. package/types/freeze-control/useFreezeControl.d.ts +4 -3
  70. package/types/index.d.ts +3 -0
  71. package/types/table-column-settings/TableSettingsPanel.d.ts +2 -1
@@ -0,0 +1,235 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { forwardRef, useCallback, useRef, useMemo } from 'react';
3
+ import cx from 'clsx';
4
+ import { useComponentCssInjection } from '@salt-ds/styles';
5
+ import { useWindow } from '@salt-ds/window';
6
+ import { reorderColumnItems, DragDropProvider, getColumnLabel, useSortable } from '@vuu-ui/vuu-utils';
7
+ import columnPickerCss from './ColumnPicker.css.js';
8
+ import { Input, ListBox, Option } from '@salt-ds/core';
9
+ import { useColumnPicker, SelectedColumnChangeType } from './useColumnPicker.js';
10
+ import { IconButton } from '@vuu-ui/vuu-ui-controls';
11
+ import { useHighlighting } from '@vuu-ui/vuu-table';
12
+
13
+ const classBase = "vuuColumnPicker";
14
+ const classBaseListItem = "vuuColumnPickerListItem";
15
+ const searchIcon = /* @__PURE__ */ jsx("span", { "data-icon": "search" });
16
+ const NO_SELECTION = [];
17
+ const useSorting = (id, index) => {
18
+ const { handleRef: sortableHandleRef, ref: sortableRef } = useSortable({
19
+ id,
20
+ index
21
+ });
22
+ const [handleRef, ref] = useMemo(() => {
23
+ return [sortableHandleRef, sortableRef];
24
+ }, [sortableHandleRef, sortableRef]);
25
+ return {
26
+ handleRef,
27
+ ref
28
+ };
29
+ };
30
+ const SelectedColumnListItem = ({
31
+ className: classNameProp,
32
+ index,
33
+ column: item,
34
+ onRemove,
35
+ searchPattern = "",
36
+ ...optionProps
37
+ }) => {
38
+ const { handleRef, ref } = useSorting(item.name, index);
39
+ const value = getColumnLabel(item);
40
+ const valueWithHighlighting = useHighlighting(value, searchPattern);
41
+ return /* @__PURE__ */ jsxs(
42
+ Option,
43
+ {
44
+ ...optionProps,
45
+ className: cx(classNameProp, classBaseListItem),
46
+ "data-name": item.name,
47
+ ref,
48
+ children: [
49
+ /* @__PURE__ */ jsx(
50
+ IconButton,
51
+ {
52
+ "data-embedded": true,
53
+ appearance: "transparent",
54
+ icon: "draggable",
55
+ ref: handleRef,
56
+ size: 16
57
+ }
58
+ ),
59
+ /* @__PURE__ */ jsx("span", { className: `${classBase}-text`, children: valueWithHighlighting }),
60
+ /* @__PURE__ */ jsx(
61
+ IconButton,
62
+ {
63
+ className: `${classBaseListItem}-action`,
64
+ "data-embedded": true,
65
+ appearance: "transparent",
66
+ icon: "cross",
67
+ onClick: onRemove,
68
+ size: 16
69
+ }
70
+ )
71
+ ]
72
+ }
73
+ );
74
+ };
75
+ const AvailableColumnListItem = ({
76
+ className: classNameProp,
77
+ index,
78
+ column: item,
79
+ onAdd,
80
+ searchPattern = "",
81
+ ...optionProps
82
+ }) => {
83
+ const value = getColumnLabel(item);
84
+ const valueWithHighlighting = useHighlighting(value, searchPattern);
85
+ return /* @__PURE__ */ jsxs(
86
+ Option,
87
+ {
88
+ ...optionProps,
89
+ className: cx(classNameProp, classBaseListItem),
90
+ "data-name": item.name,
91
+ children: [
92
+ /* @__PURE__ */ jsx("span", { className: `${classBase}-text`, children: valueWithHighlighting }),
93
+ /* @__PURE__ */ jsx(
94
+ IconButton,
95
+ {
96
+ className: `${classBaseListItem}-action`,
97
+ "data-embedded": true,
98
+ appearance: "transparent",
99
+ icon: "plus",
100
+ onClick: onAdd,
101
+ size: 16
102
+ }
103
+ )
104
+ ]
105
+ }
106
+ );
107
+ };
108
+ const ColumnPicker = forwardRef(function ColumnPicker2({
109
+ availableColumns: availableColumnsProp,
110
+ className,
111
+ defaultSelectedColumns,
112
+ onChangeSelectedColumns,
113
+ selectedColumns: selectedColumnsProp,
114
+ ...htmlAttributes
115
+ }, forwardedRef) {
116
+ const targetWindow = useWindow();
117
+ useComponentCssInjection({
118
+ testId: "vuu-column-picker",
119
+ css: columnPickerCss,
120
+ window: targetWindow
121
+ });
122
+ const searchCallbackRef = useCallback((el) => {
123
+ setTimeout(() => {
124
+ el?.querySelector("input")?.focus();
125
+ }, 100);
126
+ }, []);
127
+ const {
128
+ availableColumns,
129
+ onAddItemToSelectedList,
130
+ onChangeSearchInput,
131
+ onRemoveItemFromSelectedList,
132
+ searchState,
133
+ selectedColumns
134
+ } = useColumnPicker({
135
+ availableColumns: availableColumnsProp,
136
+ defaultSelectedColumns,
137
+ onChangeSelectedColumns,
138
+ selectedColumns: selectedColumnsProp
139
+ });
140
+ const listRef = useRef(null);
141
+ const getOptionName = (option) => {
142
+ if (option) {
143
+ const { name } = option.dataset;
144
+ if (name) {
145
+ return name;
146
+ }
147
+ }
148
+ throw Error("[ColumnPicker] list option has no data-name");
149
+ };
150
+ const handleDragEnd = useCallback(() => {
151
+ setTimeout(() => {
152
+ const listItems = listRef.current?.querySelectorAll(".saltOption");
153
+ if (listItems) {
154
+ const orderedColumnNames = Array.from(listItems).map(getOptionName);
155
+ onChangeSelectedColumns?.(
156
+ reorderColumnItems(selectedColumns, orderedColumnNames),
157
+ SelectedColumnChangeType.ColumnsReordered
158
+ );
159
+ }
160
+ }, 300);
161
+ }, [onChangeSelectedColumns, selectedColumns]);
162
+ return /* @__PURE__ */ jsxs(
163
+ "div",
164
+ {
165
+ ...htmlAttributes,
166
+ className: cx(classBase, className),
167
+ ref: forwardedRef,
168
+ children: [
169
+ /* @__PURE__ */ jsx("form", { className: `${classBase}-search`, role: "search", children: /* @__PURE__ */ jsx(
170
+ Input,
171
+ {
172
+ startAdornment: searchIcon,
173
+ placeholder: "Find column",
174
+ ref: searchCallbackRef,
175
+ value: searchState.searchText,
176
+ onChange: onChangeSearchInput
177
+ }
178
+ ) }),
179
+ /* @__PURE__ */ jsxs("div", { className: `${classBase}-scrollContainer vuuScrollable`, children: [
180
+ /* @__PURE__ */ jsx("div", { className: `${classBase}-sectionHeader`, children: "Columns in view" }),
181
+ /* @__PURE__ */ jsx(DragDropProvider, { onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx(
182
+ ListBox,
183
+ {
184
+ className: `${classBase}-selectedList`,
185
+ ref: listRef,
186
+ selected: NO_SELECTION,
187
+ children: selectedColumns.map((column, index) => /* @__PURE__ */ jsx(
188
+ SelectedColumnListItem,
189
+ {
190
+ column,
191
+ index,
192
+ onRemove: onRemoveItemFromSelectedList,
193
+ searchPattern: searchState.searchText.toLowerCase(),
194
+ value: column
195
+ },
196
+ column.name
197
+ ))
198
+ }
199
+ ) }),
200
+ /* @__PURE__ */ jsx(
201
+ "div",
202
+ {
203
+ className: cx(
204
+ `${classBase}-sectionHeader`,
205
+ `${classBase}-availableHeader`
206
+ ),
207
+ children: "Available columns"
208
+ }
209
+ ),
210
+ /* @__PURE__ */ jsx(
211
+ ListBox,
212
+ {
213
+ className: `${classBase}-availableList`,
214
+ selected: NO_SELECTION,
215
+ children: availableColumns.map((column, index) => /* @__PURE__ */ jsx(
216
+ AvailableColumnListItem,
217
+ {
218
+ column,
219
+ index,
220
+ onAdd: onAddItemToSelectedList,
221
+ searchPattern: searchState.searchText.toLowerCase(),
222
+ value: column
223
+ },
224
+ column.name
225
+ ))
226
+ }
227
+ )
228
+ ] })
229
+ ]
230
+ }
231
+ );
232
+ });
233
+
234
+ export { ColumnPicker, classBaseListItem };
235
+ //# sourceMappingURL=ColumnPicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColumnPicker.js","sources":["../../../../packages/vuu-table-extras/src/column-picker/ColumnPicker.tsx"],"sourcesContent":["import { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport {\n ForwardedRef,\n forwardRef,\n HTMLAttributes,\n MouseEventHandler,\n RefCallback,\n useCallback,\n useMemo,\n useRef,\n} from \"react\";\nimport cx from \"clsx\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n DragDropProvider,\n getColumnLabel,\n reorderColumnItems,\n useSortable,\n} from \"@vuu-ui/vuu-utils\";\n\nimport columnPickerCss from \"./ColumnPicker.css\";\nimport { Input, ListBox, Option, OptionProps } from \"@salt-ds/core\";\nimport {\n ColumPickerHookProps,\n SelectedColumnChangeType,\n useColumnPicker,\n} from \"./useColumnPicker\";\nimport { IconButton } from \"@vuu-ui/vuu-ui-controls\";\nimport { useHighlighting } from \"@vuu-ui/vuu-table\";\n\nconst classBase = \"vuuColumnPicker\";\nexport const classBaseListItem = \"vuuColumnPickerListItem\";\n\nexport interface ColumnPickerProps\n extends ColumPickerHookProps,\n HTMLAttributes<HTMLDivElement> {}\n\nconst searchIcon = <span data-icon=\"search\" />;\nconst NO_SELECTION: string[] = [] as const;\n\nconst useSorting = (id: string, index: number) => {\n const { handleRef: sortableHandleRef, ref: sortableRef } = useSortable({\n id,\n index,\n });\n\n const [handleRef, ref] = useMemo(() => {\n return [sortableHandleRef, sortableRef];\n }, [sortableHandleRef, sortableRef]);\n\n return {\n handleRef,\n ref,\n };\n};\n\nconst SelectedColumnListItem = ({\n className: classNameProp,\n index,\n column: item,\n onRemove,\n searchPattern = \"\",\n ...optionProps\n}: OptionProps & {\n index: number;\n column: ColumnDescriptor;\n onRemove: MouseEventHandler<HTMLButtonElement>;\n searchPattern?: Lowercase<string>;\n}) => {\n const { handleRef, ref } = useSorting(item.name, index);\n const value = getColumnLabel(item as ColumnDescriptor);\n const valueWithHighlighting = useHighlighting(value, searchPattern);\n\n return (\n <Option\n {...optionProps}\n className={cx(classNameProp, classBaseListItem)}\n data-name={item.name}\n ref={ref}\n >\n <IconButton\n data-embedded\n appearance=\"transparent\"\n icon=\"draggable\"\n ref={handleRef}\n size={16}\n />\n <span className={`${classBase}-text`}>{valueWithHighlighting}</span>\n <IconButton\n className={`${classBaseListItem}-action`}\n data-embedded\n appearance=\"transparent\"\n icon=\"cross\"\n onClick={onRemove}\n size={16}\n />\n </Option>\n );\n};\n\nconst AvailableColumnListItem = ({\n className: classNameProp,\n index,\n column: item,\n onAdd,\n searchPattern = \"\",\n ...optionProps\n}: OptionProps & {\n index: number;\n column: ColumnDescriptor;\n onAdd: MouseEventHandler<HTMLButtonElement>;\n searchPattern?: Lowercase<string>;\n}) => {\n const value = getColumnLabel(item as ColumnDescriptor);\n const valueWithHighlighting = useHighlighting(value, searchPattern);\n\n return (\n <Option\n {...optionProps}\n className={cx(classNameProp, classBaseListItem)}\n data-name={item.name}\n >\n <span className={`${classBase}-text`}>{valueWithHighlighting}</span>\n <IconButton\n className={`${classBaseListItem}-action`}\n data-embedded\n appearance=\"transparent\"\n icon=\"plus\"\n onClick={onAdd}\n size={16}\n />\n </Option>\n );\n};\n\nexport const ColumnPicker = forwardRef(function ColumnPicker(\n {\n availableColumns: availableColumnsProp,\n className,\n defaultSelectedColumns,\n onChangeSelectedColumns,\n selectedColumns: selectedColumnsProp,\n ...htmlAttributes\n }: ColumnPickerProps,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-column-picker\",\n css: columnPickerCss,\n window: targetWindow,\n });\n\n const searchCallbackRef = useCallback<RefCallback<HTMLElement>>((el) => {\n setTimeout(() => {\n el?.querySelector(\"input\")?.focus();\n }, 100);\n }, []);\n\n const {\n availableColumns,\n onAddItemToSelectedList,\n onChangeSearchInput,\n onRemoveItemFromSelectedList,\n searchState,\n selectedColumns,\n } = useColumnPicker({\n availableColumns: availableColumnsProp,\n defaultSelectedColumns,\n onChangeSelectedColumns,\n selectedColumns: selectedColumnsProp,\n });\n const listRef = useRef<HTMLDivElement>(null);\n\n const getOptionName = (option?: HTMLElement) => {\n if (option) {\n const { name } = option.dataset;\n if (name) {\n return name;\n }\n }\n throw Error(\"[ColumnPicker] list option has no data-name\");\n };\n\n const handleDragEnd = useCallback(() => {\n setTimeout(() => {\n const listItems =\n listRef.current?.querySelectorAll<HTMLDivElement>(\".saltOption\");\n if (listItems) {\n const orderedColumnNames = Array.from(listItems).map(getOptionName);\n onChangeSelectedColumns?.(\n reorderColumnItems(selectedColumns, orderedColumnNames),\n SelectedColumnChangeType.ColumnsReordered,\n );\n }\n }, 300);\n }, [onChangeSelectedColumns, selectedColumns]);\n\n return (\n <div\n {...htmlAttributes}\n className={cx(classBase, className)}\n ref={forwardedRef}\n >\n <form className={`${classBase}-search`} role=\"search\">\n <Input\n startAdornment={searchIcon}\n placeholder=\"Find column\"\n ref={searchCallbackRef}\n value={searchState.searchText}\n onChange={onChangeSearchInput}\n />\n </form>\n\n <div className={`${classBase}-scrollContainer vuuScrollable`}>\n <div className={`${classBase}-sectionHeader`}>Columns in view</div>\n <DragDropProvider onDragEnd={handleDragEnd}>\n <ListBox\n className={`${classBase}-selectedList`}\n ref={listRef}\n selected={NO_SELECTION}\n >\n {selectedColumns.map((column, index) => (\n <SelectedColumnListItem\n column={column}\n index={index}\n key={column.name}\n onRemove={onRemoveItemFromSelectedList}\n searchPattern={\n searchState.searchText.toLowerCase() as Lowercase<string>\n }\n value={column}\n />\n ))}\n </ListBox>\n </DragDropProvider>\n\n <div\n className={cx(\n `${classBase}-sectionHeader`,\n `${classBase}-availableHeader`,\n )}\n >\n Available columns\n </div>\n <ListBox\n className={`${classBase}-availableList`}\n selected={NO_SELECTION}\n >\n {availableColumns.map((column, index) => (\n <AvailableColumnListItem\n column={column}\n index={index}\n key={column.name}\n onAdd={onAddItemToSelectedList}\n searchPattern={\n searchState.searchText.toLowerCase() as Lowercase<string>\n }\n value={column}\n />\n ))}\n </ListBox>\n </div>\n </div>\n );\n});\n"],"names":["ColumnPicker"],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import { useControlled } from '@salt-ds/core';
2
+ import { queryClosest } from '@vuu-ui/vuu-utils';
3
+ import { useState, useRef, useMemo, useCallback } from 'react';
4
+
5
+ const nonSelectedColumns = ({
6
+ availableColumns,
7
+ selectedColumns
8
+ }) => availableColumns.filter(
9
+ ({ name }) => selectedColumns.findIndex((c) => c.name === name) === -1
10
+ );
11
+ const findColumn = (target, columns) => {
12
+ const listItem = queryClosest(target, ".saltOption", true);
13
+ const { name } = listItem.dataset;
14
+ const column = columns.find((col) => col.name === name);
15
+ if (column) {
16
+ return column;
17
+ } else {
18
+ throw Error(`[useColumnPicker] column ${name} not found`);
19
+ }
20
+ };
21
+ const SelectedColumnChangeType = {
22
+ ColumnAdded: "column-added",
23
+ ColumnRemoved: "column-removed",
24
+ ColumnsReordered: "columns-reordered"
25
+ };
26
+ const useColumnPicker = ({
27
+ availableColumns,
28
+ defaultSelectedColumns,
29
+ onChangeSelectedColumns,
30
+ selectedColumns: selectedColumnsProp
31
+ }) => {
32
+ const [searchState, setSearchState] = useState({ searchText: "" });
33
+ const [selectedColumns, setSelectedColumns] = useControlled({
34
+ controlled: selectedColumnsProp,
35
+ default: defaultSelectedColumns ?? [],
36
+ name: "ColumnPicker",
37
+ state: "selectedColumns"
38
+ });
39
+ const visibleColumnsRef = useRef({ availableColumns, selectedColumns });
40
+ useMemo(() => {
41
+ const value = searchState.searchText.toLowerCase();
42
+ if (value) {
43
+ const pattern = value.toLowerCase();
44
+ visibleColumnsRef.current = {
45
+ availableColumns: availableColumns.filter(
46
+ ({ name, label = name }) => label.toLowerCase().indexOf(pattern) !== -1
47
+ ),
48
+ selectedColumns: selectedColumns.filter(
49
+ ({ name, label = name }) => label.toLowerCase().indexOf(pattern) !== -1
50
+ )
51
+ };
52
+ } else {
53
+ visibleColumnsRef.current = { availableColumns, selectedColumns };
54
+ }
55
+ }, [availableColumns, selectedColumns, searchState.searchText]);
56
+ const handleChangeSearchInput = useCallback((evt) => {
57
+ const { value } = evt.target;
58
+ setSearchState({
59
+ searchText: value
60
+ });
61
+ }, []);
62
+ const handleAddItemToSelectedList = useCallback(
63
+ ({ target }) => {
64
+ const targetColumn = findColumn(target, availableColumns);
65
+ const newColumns = selectedColumns.concat(targetColumn);
66
+ onChangeSelectedColumns(newColumns, SelectedColumnChangeType.ColumnAdded);
67
+ setSelectedColumns(newColumns);
68
+ },
69
+ [
70
+ availableColumns,
71
+ onChangeSelectedColumns,
72
+ selectedColumns,
73
+ setSelectedColumns
74
+ ]
75
+ );
76
+ const handleRemoveItemFromSelectedList = useCallback(
77
+ ({ target }) => {
78
+ const targetColumn = findColumn(target, selectedColumns);
79
+ const newColumns = selectedColumns.filter(
80
+ (col) => col.name !== targetColumn.name
81
+ );
82
+ onChangeSelectedColumns(
83
+ newColumns,
84
+ SelectedColumnChangeType.ColumnRemoved
85
+ );
86
+ setSelectedColumns(newColumns);
87
+ },
88
+ [onChangeSelectedColumns, selectedColumns, setSelectedColumns]
89
+ );
90
+ return {
91
+ availableColumns: nonSelectedColumns(visibleColumnsRef.current),
92
+ onAddItemToSelectedList: handleAddItemToSelectedList,
93
+ onRemoveItemFromSelectedList: handleRemoveItemFromSelectedList,
94
+ onChangeSearchInput: handleChangeSearchInput,
95
+ searchState,
96
+ selectedColumns: visibleColumnsRef.current.selectedColumns
97
+ };
98
+ };
99
+
100
+ export { SelectedColumnChangeType, useColumnPicker };
101
+ //# sourceMappingURL=useColumnPicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useColumnPicker.js","sources":["../../../../packages/vuu-table-extras/src/column-picker/useColumnPicker.tsx"],"sourcesContent":["import { useControlled } from \"@salt-ds/core\";\nimport { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport { queryClosest, ValueOf } from \"@vuu-ui/vuu-utils\";\nimport {\n FormEventHandler,\n MouseEventHandler,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nexport type ColumnPickerAction = (column: ColumnDescriptor) => void;\n\nconst nonSelectedColumns = ({\n availableColumns,\n selectedColumns,\n}: {\n availableColumns: ColumnDescriptor[];\n selectedColumns: ColumnDescriptor[];\n}) =>\n availableColumns.filter(\n ({ name }) => selectedColumns.findIndex((c) => c.name === name) === -1,\n );\n\nconst findColumn = (target: EventTarget, columns: ColumnDescriptor[]) => {\n const listItem = queryClosest(target, \".saltOption\", true);\n const { name } = listItem.dataset;\n const column = columns.find((col) => col.name === name);\n if (column) {\n return column;\n } else {\n throw Error(`[useColumnPicker] column ${name} not found`);\n }\n};\nexport const SelectedColumnChangeType = {\n ColumnAdded: \"column-added\",\n ColumnRemoved: \"column-removed\",\n ColumnsReordered: \"columns-reordered\",\n} as const;\nexport type SelectedColumnChangeType = ValueOf<typeof SelectedColumnChangeType>;\nexport type SelectedColumnsChangeHandler = (\n columns: ColumnDescriptor[],\n changeType: SelectedColumnChangeType,\n) => void;\n\nexport interface ColumPickerHookProps {\n /**\n * All available columns, including selected columns.\n */\n availableColumns: ColumnDescriptor[];\n /**\n * Columns already selected and rendered in Table,\n * columnPicker will be uncontrolled\n */\n defaultSelectedColumns?: ColumnDescriptor[];\n onChangeSelectedColumns: SelectedColumnsChangeHandler;\n /**\n * Columns already selected and rendered in Table.\n * columnPicker will be controlled\n */\n selectedColumns?: ColumnDescriptor[];\n}\n\nexport const useColumnPicker = ({\n availableColumns,\n defaultSelectedColumns,\n onChangeSelectedColumns,\n selectedColumns: selectedColumnsProp,\n}: ColumPickerHookProps) => {\n const [searchState, setSearchState] = useState<{\n searchText: string;\n }>({ searchText: \"\" });\n\n const [selectedColumns, setSelectedColumns] = useControlled({\n controlled: selectedColumnsProp,\n default: defaultSelectedColumns ?? [],\n name: \"ColumnPicker\",\n state: \"selectedColumns\",\n });\n\n const visibleColumnsRef = useRef({ availableColumns, selectedColumns });\n\n useMemo(() => {\n const value = searchState.searchText.toLowerCase();\n if (value) {\n const pattern = value.toLowerCase();\n visibleColumnsRef.current = {\n availableColumns: availableColumns.filter(\n ({ name, label = name }) =>\n label.toLowerCase().indexOf(pattern) !== -1,\n ),\n selectedColumns: selectedColumns.filter(\n ({ name, label = name }) =>\n label.toLowerCase().indexOf(pattern) !== -1,\n ),\n };\n } else {\n visibleColumnsRef.current = { availableColumns, selectedColumns };\n }\n }, [availableColumns, selectedColumns, searchState.searchText]);\n\n const handleChangeSearchInput = useCallback<FormEventHandler>((evt) => {\n const { value } = evt.target as HTMLInputElement;\n setSearchState({\n searchText: value,\n });\n }, []);\n\n const handleAddItemToSelectedList = useCallback<\n MouseEventHandler<HTMLButtonElement>\n >(\n ({ target }) => {\n const targetColumn = findColumn(target, availableColumns);\n const newColumns = selectedColumns.concat(targetColumn);\n onChangeSelectedColumns(newColumns, SelectedColumnChangeType.ColumnAdded);\n setSelectedColumns(newColumns);\n },\n [\n availableColumns,\n onChangeSelectedColumns,\n selectedColumns,\n setSelectedColumns,\n ],\n );\n\n const handleRemoveItemFromSelectedList = useCallback<\n MouseEventHandler<HTMLButtonElement>\n >(\n ({ target }) => {\n const targetColumn = findColumn(target, selectedColumns);\n const newColumns = selectedColumns.filter(\n (col) => col.name !== targetColumn.name,\n );\n onChangeSelectedColumns(\n newColumns,\n SelectedColumnChangeType.ColumnRemoved,\n );\n setSelectedColumns(newColumns);\n },\n [onChangeSelectedColumns, selectedColumns, setSelectedColumns],\n );\n\n return {\n availableColumns: nonSelectedColumns(visibleColumnsRef.current),\n onAddItemToSelectedList: handleAddItemToSelectedList,\n onRemoveItemFromSelectedList: handleRemoveItemFromSelectedList,\n onChangeSearchInput: handleChangeSearchInput,\n searchState,\n selectedColumns: visibleColumnsRef.current.selectedColumns,\n };\n};\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- var dataSourceStats = ".vuuDatasourceStats {\n align-items: center;\n display: grid;\n font-size: var(--vuuDatasourceStats-fontSize, 10px);\n gap: var(--vuuDatasourceStats-gap, var(--salt-spacing-100));\n grid-template-areas: \"panel-start panel-center panel-end\";\n grid-template-columns: 1fr 1fr 1fr;\n grid-template-rows: auto;\n height: var(--vuuDatasourceStats-height, 100%);\n padding: 0 var(--salt-spacing-200);\n\n .vuuDatasourceStats-statsPanel {\n align-items: center;\n display: flex;\n gap: var(--salt-spacing-100);\n width: fit-content;\n }\n\n .vuuDatasourceStats-rowStats {\n justify-self: flex-start;\n grid-area: panel-start;\n }\n .vuuDatasourceStats-freezeStatus {\n justify-self: flex-start;\n grid-area: panel-start;\n }\n .vuuDatasourceStats-selectionStats {\n justify-self: center;\n grid-area: panel-center;\n }\n\n.vuuDatasourceStats-label {\n color: var(--salt-content-secondary-foreground);\n}\n\n.vuuDatasourceStats-value {\n color: var(--salt-content-primary-foreground);\n}\n.vuuDatasourceStats-actions {\n margin: 0 var(--salt-spacing-200);\n}\n\n}\n\n";
1
+ var dataSourceStats = ".vuuDatasourceStats {\n align-items: center;\n background: var(--vuuDatasourceStats-background, var(--salt-container-secondary-background));\n display: grid;\n font-size: var(--vuuDatasourceStats-fontSize, 10px);\n gap: var(--vuuDatasourceStats-gap, var(--salt-spacing-100));\n grid-template-areas: \"panel-start panel-center panel-end\";\n grid-template-columns: 1fr 1fr 1fr;\n grid-template-rows: auto;\n height: var(--vuuDatasourceStats-height, 100%);\n padding: 0 var(--salt-spacing-200);\n\n .vuuDatasourceStats-statsPanel {\n align-items: center;\n display: flex;\n gap: var(--salt-spacing-100);\n width: fit-content;\n }\n\n .vuuDatasourceStats-rowStats {\n justify-self: flex-start;\n grid-area: panel-start;\n }\n .vuuDatasourceStats-freezeStatus {\n justify-self: flex-start;\n grid-area: panel-start;\n }\n .vuuDatasourceStats-selectionStats {\n justify-self: center;\n grid-area: panel-center;\n }\n\n .vuuDatasourceStats-label {\n color: var(--salt-content-secondary-foreground);\n }\n\n .vuuDatasourceStats-value {\n color: var(--salt-content-primary-foreground);\n }\n .vuuDatasourceStats-tooltray {\n justify-self: end;;\n margin: 0 var(--salt-spacing-200);\n grid-area: panel-end;\n }\n\n}\n\n";
2
2
 
3
3
  export { dataSourceStats as default };
4
4
  //# sourceMappingURL=DatasourceStats.css.js.map
@@ -22,6 +22,7 @@ const DataSourceStats = ({
22
22
  showFreezeStatus = true,
23
23
  showRowStats = true,
24
24
  showSelectionStats = true,
25
+ tooltrayActions,
25
26
  ...htmlAttributes
26
27
  }) => {
27
28
  const targetWindow = useWindow();
@@ -84,7 +85,8 @@ const DataSourceStats = ({
84
85
  /* @__PURE__ */ jsx("span", { className: `${classBase}-actions`, children })
85
86
  ]
86
87
  }
87
- ) : null
88
+ ) : null,
89
+ tooltrayActions ? /* @__PURE__ */ jsx("div", { className: `${classBase}-statsPanel ${classBase}-tooltray`, children: /* @__PURE__ */ jsx("span", { className: `${classBase}-actions`, children: tooltrayActions }) }) : null
88
90
  ]
89
91
  }
90
92
  );
@@ -1 +1 @@
1
- {"version":3,"file":"DatasourceStats.js","sources":["../../../../packages/vuu-table-extras/src/datasource-stats/DatasourceStats.tsx"],"sourcesContent":["import cx from \"clsx\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { HTMLAttributes, ReactNode } from \"react\";\n\nimport dataSourceStats from \"./DatasourceStats.css\";\nimport {\n DatasourceStatsHookProps,\n useDatasourceStats,\n} from \"./useDatasourceStats\";\n\nexport type ItemLabel =\n | string\n | {\n singlular: string;\n plural: string;\n };\n\nexport interface DataSourceStatsProps\n extends DatasourceStatsHookProps,\n Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * children will be displayed when selection present. Intended\n * use case is display of action button(s) that will operate on\n * selected rows.\n */\n children?: ReactNode;\n /**\n * Label will be used in display of selected row count, e.g\n * '6 trades selected', where 'trade' is the itemLabel, will\n * default to 'row'\n */\n itemLabel?: ItemLabel;\n}\n\nconst classBase = \"vuuDatasourceStats\";\n\nconst numberFormatter = new Intl.NumberFormat();\n\nconst getLabel = (label: ItemLabel, count = 1) => {\n if (count === 1) {\n return typeof label === \"string\" ? label : label.singlular;\n } else {\n return typeof label === \"string\" ? `${label}s` : label.plural;\n }\n};\n\nexport const DataSourceStats = ({\n children,\n className,\n dataSource,\n itemLabel = \"row\",\n showFreezeStatus = true,\n showRowStats = true,\n showSelectionStats = true,\n ...htmlAttributes\n}: DataSourceStatsProps) => {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-datasource-stats\",\n css: dataSourceStats,\n window: targetWindow,\n });\n\n const { freezeTime, range, selectedCount, size } = useDatasourceStats({\n dataSource,\n showFreezeStatus,\n showRowStats,\n showSelectionStats,\n });\n\n const from = numberFormatter.format(range.firstRowInViewport);\n const to = numberFormatter.format(Math.min(range.lastRowInViewport, size));\n const value = numberFormatter.format(size);\n const showSelection = showSelectionStats && selectedCount > 0;\n\n if (size === 0) {\n return (\n <div {...htmlAttributes} className={cx(classBase, className)}>\n <span className={`${classBase}-label`}>No Rows to display</span>\n </div>\n );\n } else {\n return (\n <div\n {...htmlAttributes}\n className={cx(classBase, className, {\n [`${classBase}-withSelection`]: showSelection,\n })}\n >\n {showRowStats ? (\n <div className={`${classBase}-statsPanel ${classBase}-rowStats`}>\n <span className={`${classBase}-label`}>Row count</span>\n <span className={`${classBase}-range`}>\n <span className={`${classBase}-value`}>{from}</span>\n <span className={`${classBase}-label`}>-</span>\n <span className={`${classBase}-value`}>{to}</span>\n </span>\n <span className={`${classBase}-label`}>of</span>\n <span className={`${classBase}-value`}>{value}</span>\n </div>\n ) : null}\n {showFreezeStatus && freezeTime !== undefined ? (\n <div className={`${classBase}-statsPanel ${classBase}-freezeStatus`}>\n <span\n className={`${classBase}-label`}\n >{`(frozen at ${freezeTime})`}</span>\n </div>\n ) : null}\n {showSelection ? (\n <div\n className={`${classBase}-statsPanel ${classBase}-selectionStats`}\n >\n <span className={`${classBase}-value`}>{selectedCount}</span>\n <span\n className={`${classBase}-label`}\n >{`selected ${getLabel(itemLabel, selectedCount)}`}</span>\n <span className={`${classBase}-actions`}>{children}</span>\n </div>\n ) : null}\n </div>\n );\n }\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DatasourceStats.js","sources":["../../../../packages/vuu-table-extras/src/datasource-stats/DatasourceStats.tsx"],"sourcesContent":["import cx from \"clsx\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { HTMLAttributes, ReactNode } from \"react\";\n\nimport dataSourceStats from \"./DatasourceStats.css\";\nimport {\n DatasourceStatsHookProps,\n useDatasourceStats,\n} from \"./useDatasourceStats\";\n\nexport type ItemLabel =\n | string\n | {\n singlular: string;\n plural: string;\n };\n\nexport interface DataSourceStatsProps\n extends DatasourceStatsHookProps,\n Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * children will be displayed when selection present. Intended\n * use case is display of action button(s) that will operate on\n * selected rows.\n */\n children?: ReactNode;\n /**\n * Label will be used in display of selected row count, e.g\n * '6 trades selected', where 'trade' is the itemLabel, will\n * default to 'row'\n */\n itemLabel?: ItemLabel;\n\n selectionActions?: ReactNode;\n tooltrayActions?: ReactNode;\n}\n\nconst classBase = \"vuuDatasourceStats\";\n\nconst numberFormatter = new Intl.NumberFormat();\n\nconst getLabel = (label: ItemLabel, count = 1) => {\n if (count === 1) {\n return typeof label === \"string\" ? label : label.singlular;\n } else {\n return typeof label === \"string\" ? `${label}s` : label.plural;\n }\n};\n\nexport const DataSourceStats = ({\n children,\n className,\n dataSource,\n itemLabel = \"row\",\n showFreezeStatus = true,\n showRowStats = true,\n showSelectionStats = true,\n tooltrayActions,\n ...htmlAttributes\n}: DataSourceStatsProps) => {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-datasource-stats\",\n css: dataSourceStats,\n window: targetWindow,\n });\n\n const { freezeTime, range, selectedCount, size } = useDatasourceStats({\n dataSource,\n showFreezeStatus,\n showRowStats,\n showSelectionStats,\n });\n\n const from = numberFormatter.format(range.firstRowInViewport);\n const to = numberFormatter.format(Math.min(range.lastRowInViewport, size));\n const value = numberFormatter.format(size);\n const showSelection = showSelectionStats && selectedCount > 0;\n\n if (size === 0) {\n return (\n <div {...htmlAttributes} className={cx(classBase, className)}>\n <span className={`${classBase}-label`}>No Rows to display</span>\n </div>\n );\n } else {\n return (\n <div\n {...htmlAttributes}\n className={cx(classBase, className, {\n [`${classBase}-withSelection`]: showSelection,\n })}\n >\n {showRowStats ? (\n <div className={`${classBase}-statsPanel ${classBase}-rowStats`}>\n <span className={`${classBase}-label`}>Row count</span>\n <span className={`${classBase}-range`}>\n <span className={`${classBase}-value`}>{from}</span>\n <span className={`${classBase}-label`}>-</span>\n <span className={`${classBase}-value`}>{to}</span>\n </span>\n <span className={`${classBase}-label`}>of</span>\n <span className={`${classBase}-value`}>{value}</span>\n </div>\n ) : null}\n {showFreezeStatus && freezeTime !== undefined ? (\n <div className={`${classBase}-statsPanel ${classBase}-freezeStatus`}>\n <span\n className={`${classBase}-label`}\n >{`(frozen at ${freezeTime})`}</span>\n </div>\n ) : null}\n {showSelection ? (\n <div\n className={`${classBase}-statsPanel ${classBase}-selectionStats`}\n >\n <span className={`${classBase}-value`}>{selectedCount}</span>\n <span\n className={`${classBase}-label`}\n >{`selected ${getLabel(itemLabel, selectedCount)}`}</span>\n <span className={`${classBase}-actions`}>{children}</span>\n </div>\n ) : null}\n {tooltrayActions ? (\n <div className={`${classBase}-statsPanel ${classBase}-tooltray`}>\n <span className={`${classBase}-actions`}>{tooltrayActions}</span>\n </div>\n ) : null}\n </div>\n );\n }\n};\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- var freezeControlCss = "\n\n.FreezeControl {\n align-items: center;\n background-color: var(--vuuFreezeControl-background, var(--salt-container-secondary-background));\n border-radius: 6px;\n display: inline-grid;\n grid-template-columns: 1fr auto 1fr;\n grid-template-rows: var(--salt-size-base);\n column-gap: var(--salt-spacing-200);\n padding: 0 var(--salt-spacing-200);\n\n .FreezeControl-label-active {\n grid-area: 1/1/2/2;\n }\n\n .saltSwitch {\n grid-area: 1/2/2/3;\n .saltSwitch-track {\n height: 24px;\n }\n }\n\n .FreezeControl-label-frozen {\n grid-area: 1/3/2/4;\n }\n\n}\n\n";
1
+ var freezeControlCss = ".FreezeControl {\n display: inline-flex;\n --freeze-control-flash-duration: 0.25s;\n\n .FreezeControl-buttonRow {\n background-color: var(--salt-container-secondary-background);\n border: 1px solid var(--salt-container-secondary-borderColor);\n border-radius: 50px;\n display: flex;\n height: var(--salt-size-base);\n overflow: hidden;\n }\n\n .FreezeControl-buttonWrapper {\n border-radius: 50px;\n padding: 0 var(--salt-spacing-150);\n }\n\n .FreezeControl-buttonWrapper-active {\n background-color: var(--salt-actionable-secondary-background-active);\n }\n\n .saltToggleButtonGroup.vuuStateButtonGroup\n .saltToggleButton[aria-pressed=\"true\"] {\n background-color: transparent;\n }\n\n .FreezeControl-customBadge {\n background-color: var(--salt-container-primary-background);\n border-radius: 50%;\n color: var(--salt-text-primary-foreground);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--salt-text-fontSize);\n font-weight: bold;\n height: var(--salt-size-base);\n width: var(--salt-size-base);\n min-width: var(--salt-size-base);\n margin-left: var(--salt-spacing-100);\n }\n\n .FreezeControl-newOrders {\n align-items: center;\n background-color: transparent;\n display: flex;\n font-size: var(--salt-text-fontSize);\n padding: 0 var(--salt-spacing-200);\n }\n}\n\n.FreezeControl-customBadge-flashing {\n animation: flashGreenRed var(--freeze-control-flash-duration, 0.25s)\n steps(1, end) infinite;\n}\n\n@keyframes flashGreenRed {\n 0% {\n background-color: var(--salt-status-success-background);\n }\n 50% {\n background-color: var(--salt-container-primary-background);\n }\n 100% {\n background-color: var(--salt-status-success-background);\n }\n}\n";
2
2
 
3
3
  export { freezeControlCss as default };
4
4
  //# sourceMappingURL=FreezeControl.css.js.map
@@ -1,17 +1,17 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { useComponentCssInjection } from '@salt-ds/styles';
3
3
  import { useWindow } from '@salt-ds/window';
4
- import { Switch } from '@salt-ds/core';
5
- import freezeControlCss from './FreezeControl.css.js';
4
+ import { ToggleButtonGroup, ToggleButton } from '@salt-ds/core';
6
5
  import { useFreezeControl } from './useFreezeControl.js';
6
+ import { useState, useRef, useEffect } from 'react';
7
7
  import cx from 'clsx';
8
+ import freezeControlCss from './FreezeControl.css.js';
8
9
 
9
- const classBase = "FreezeControl";
10
+ const FLASH_DURATION_MS = 3e3;
10
11
  const FreezeControl = ({
11
- activeLabel = "Active",
12
12
  dataSource,
13
13
  className,
14
- lockedLabel = "Locked",
14
+ flashDuration = 0.25,
15
15
  ...htmlAttributes
16
16
  }) => {
17
17
  const targetWindow = useWindow();
@@ -20,14 +20,75 @@ const FreezeControl = ({
20
20
  css: freezeControlCss,
21
21
  window: targetWindow
22
22
  });
23
- const { frozen, onSwitchChange } = useFreezeControl({
23
+ const { isFrozen, newRecordCount, onToggleChange } = useFreezeControl({
24
24
  dataSource
25
25
  });
26
- return /* @__PURE__ */ jsxs("div", { ...htmlAttributes, className: cx(classBase, className), children: [
27
- /* @__PURE__ */ jsx("span", { className: `${classBase}-label-active`, children: activeLabel }),
28
- /* @__PURE__ */ jsx(Switch, { checked: frozen, onChange: onSwitchChange, className: "vuuLarge" }),
29
- /* @__PURE__ */ jsx("span", { className: `${classBase}-label-frozen`, children: lockedLabel })
30
- ] });
26
+ const [isFlashing, setIsFlashing] = useState(false);
27
+ const flashTimeoutRef = useRef(null);
28
+ useEffect(() => {
29
+ if (isFrozen && newRecordCount > 0) {
30
+ setIsFlashing(true);
31
+ if (flashTimeoutRef.current) {
32
+ clearTimeout(flashTimeoutRef.current);
33
+ }
34
+ flashTimeoutRef.current = setTimeout(() => {
35
+ setIsFlashing(false);
36
+ }, FLASH_DURATION_MS);
37
+ }
38
+ }, [newRecordCount, isFrozen]);
39
+ return /* @__PURE__ */ jsx(
40
+ "div",
41
+ {
42
+ ...htmlAttributes,
43
+ className: cx("FreezeControl", className),
44
+ style: {
45
+ ...htmlAttributes.style,
46
+ "--freeze-control-flash-duration": `${flashDuration}s`
47
+ },
48
+ children: /* @__PURE__ */ jsxs("div", { className: `FreezeControl-buttonRow`, children: [
49
+ /* @__PURE__ */ jsxs(
50
+ ToggleButtonGroup,
51
+ {
52
+ className: "vuuStateButtonGroup",
53
+ onChange: onToggleChange,
54
+ value: isFrozen ? "frozen" : "live",
55
+ children: [
56
+ /* @__PURE__ */ jsx(
57
+ "div",
58
+ {
59
+ className: cx(`FreezeControl-buttonWrapper`, {
60
+ [`FreezeControl-buttonWrapper-active`]: !isFrozen
61
+ }),
62
+ children: /* @__PURE__ */ jsx(ToggleButton, { value: "live", children: "Live" })
63
+ }
64
+ ),
65
+ /* @__PURE__ */ jsx(
66
+ "div",
67
+ {
68
+ className: cx(`FreezeControl-buttonWrapper`, {
69
+ [`FreezeControl-buttonWrapper-active`]: isFrozen
70
+ }),
71
+ children: /* @__PURE__ */ jsx(ToggleButton, { value: "frozen", children: isFrozen ? "Frozen" : "Freeze" })
72
+ }
73
+ )
74
+ ]
75
+ }
76
+ ),
77
+ isFrozen && /* @__PURE__ */ jsxs("div", { className: `FreezeControl-newOrders`, children: [
78
+ "New Orders",
79
+ /* @__PURE__ */ jsx(
80
+ "div",
81
+ {
82
+ className: cx(`FreezeControl-customBadge`, {
83
+ [`FreezeControl-customBadge-flashing`]: isFlashing
84
+ }),
85
+ children: newRecordCount
86
+ }
87
+ )
88
+ ] })
89
+ ] })
90
+ }
91
+ );
31
92
  };
32
93
 
33
94
  export { FreezeControl };
@@ -1 +1 @@
1
- {"version":3,"file":"FreezeControl.js","sources":["../../../../packages/vuu-table-extras/src/freeze-control/FreezeControl.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { Switch } from \"@salt-ds/core\";\nimport freezeControlCss from \"./FreezeControl.css\";\nimport { useFreezeControl, type FreezeProps } from \"./useFreezeControl\";\nimport { HTMLAttributes } from \"react\";\nimport cx from \"clsx\";\n\nconst classBase = \"FreezeControl\";\n\nexport interface FreezeControlProps\n extends HTMLAttributes<HTMLDivElement>,\n FreezeProps {\n activeLabel?: string;\n lockedLabel?: string;\n}\n\nexport const FreezeControl = ({\n activeLabel = \"Active\",\n dataSource,\n className,\n lockedLabel = \"Locked\",\n ...htmlAttributes\n}: FreezeControlProps) => {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-freeze-control\",\n css: freezeControlCss,\n window: targetWindow,\n });\n\n const { frozen, onSwitchChange } = useFreezeControl({\n dataSource,\n });\n\n return (\n <div {...htmlAttributes} className={cx(classBase, className)}>\n <span className={`${classBase}-label-active`}>{activeLabel}</span>\n <Switch checked={frozen} onChange={onSwitchChange} className=\"vuuLarge\" />\n <span className={`${classBase}-label-frozen`}>{lockedLabel}</span>\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAQA,MAAM,SAAY,GAAA,eAAA;AASX,MAAM,gBAAgB,CAAC;AAAA,EAC5B,WAAc,GAAA,QAAA;AAAA,EACd,UAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAc,GAAA,QAAA;AAAA,EACd,GAAG;AACL,CAA0B,KAAA;AACxB,EAAA,MAAM,eAAe,SAAU,EAAA;AAC/B,EAAyB,wBAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,oBAAA;AAAA,IACR,GAAK,EAAA,gBAAA;AAAA,IACL,MAAQ,EAAA;AAAA,GACT,CAAA;AAED,EAAA,MAAM,EAAE,MAAA,EAAQ,cAAe,EAAA,GAAI,gBAAiB,CAAA;AAAA,IAClD;AAAA,GACD,CAAA;AAED,EACE,uBAAA,IAAA,CAAC,SAAK,GAAG,cAAA,EAAgB,WAAW,EAAG,CAAA,SAAA,EAAW,SAAS,CACzD,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,MAAK,EAAA,EAAA,SAAA,EAAW,CAAG,EAAA,SAAS,iBAAkB,QAAY,EAAA,WAAA,EAAA,CAAA;AAAA,wBAC1D,MAAO,EAAA,EAAA,OAAA,EAAS,QAAQ,QAAU,EAAA,cAAA,EAAgB,WAAU,UAAW,EAAA,CAAA;AAAA,wBACvE,MAAK,EAAA,EAAA,SAAA,EAAW,CAAG,EAAA,SAAS,iBAAkB,QAAY,EAAA,WAAA,EAAA;AAAA,GAC7D,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"FreezeControl.js","sources":["../../../../packages/vuu-table-extras/src/freeze-control/FreezeControl.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { ToggleButton, ToggleButtonGroup } from \"@salt-ds/core\";\nimport { useFreezeControl, type FreezeProps } from \"./useFreezeControl\";\nimport { HTMLAttributes, useEffect, useRef, useState } from \"react\";\nimport cx from \"clsx\";\n\nimport freezeControlCss from \"./FreezeControl.css\";\n\n// Duration to keep flashing after last new record (in milliseconds)\nconst FLASH_DURATION_MS = 3000;\n\nexport interface FreezeControlProps\n extends HTMLAttributes<HTMLDivElement>,\n FreezeProps {\n /**\n * Duration of the flash animation for the badge (in seconds).\n * @default 0.25\n */\n flashDuration?: number;\n}\n\nexport const FreezeControl = ({\n dataSource,\n className,\n flashDuration = 0.25,\n ...htmlAttributes\n}: FreezeControlProps) => {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-freeze-control\",\n css: freezeControlCss,\n window: targetWindow,\n });\n\n const { isFrozen, newRecordCount, onToggleChange } = useFreezeControl({\n dataSource,\n });\n\n const [isFlashing, setIsFlashing] = useState(false);\n const flashTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Check if we're frozen and have new records and set the flash with a 3 second timeout\n useEffect(() => {\n if (isFrozen && newRecordCount > 0) {\n setIsFlashing(true);\n\n if (flashTimeoutRef.current) {\n clearTimeout(flashTimeoutRef.current);\n }\n\n flashTimeoutRef.current = setTimeout(() => {\n setIsFlashing(false);\n }, FLASH_DURATION_MS);\n }\n }, [newRecordCount, isFrozen]);\n\n return (\n <div\n {...htmlAttributes}\n className={cx(\"FreezeControl\", className)}\n style={\n {\n ...htmlAttributes.style,\n \"--freeze-control-flash-duration\": `${flashDuration}s`,\n } as React.CSSProperties\n }\n >\n <div className={`FreezeControl-buttonRow`}>\n <ToggleButtonGroup\n className=\"vuuStateButtonGroup\"\n onChange={onToggleChange}\n value={isFrozen ? \"frozen\" : \"live\"}\n >\n <div\n className={cx(`FreezeControl-buttonWrapper`, {\n [`FreezeControl-buttonWrapper-active`]: !isFrozen,\n })}\n >\n <ToggleButton value=\"live\">Live</ToggleButton>\n </div>\n <div\n className={cx(`FreezeControl-buttonWrapper`, {\n [`FreezeControl-buttonWrapper-active`]: isFrozen,\n })}\n >\n <ToggleButton value=\"frozen\">\n {isFrozen ? \"Frozen\" : \"Freeze\"}\n </ToggleButton>\n </div>\n </ToggleButtonGroup>\n {isFrozen && (\n <div className={`FreezeControl-newOrders`}>\n New Orders\n <div\n className={cx(`FreezeControl-customBadge`, {\n [`FreezeControl-customBadge-flashing`]: isFlashing,\n })}\n >\n {newRecordCount}\n </div>\n </div>\n )}\n </div>\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ var frozenBannerCss = ".FrozenBanner {\n align-items: center;\n background-color: var(--salt-actionable-secondary-background-active);\n border-radius: 4px;\n color: var(--salt-actionable-secondary-foreground-active);\n display: flex;\n font-size: var(--salt-text-fontSize);\n height: var(--salt-size-base);\n padding: 0 var(--salt-spacing-200);\n}\n";
2
+
3
+ export { frozenBannerCss as default };
4
+ //# sourceMappingURL=FrozenBanner.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FrozenBanner.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}