@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.
- package/cjs/column-list/ColumnList.js +14 -1
- package/cjs/column-list/ColumnList.js.map +1 -1
- package/cjs/column-menu/column-menu-utils.js +2 -19
- package/cjs/column-menu/column-menu-utils.js.map +1 -1
- package/cjs/column-menu/useColumnActions.js +5 -4
- package/cjs/column-menu/useColumnActions.js.map +1 -1
- package/cjs/column-picker/ColumnPicker.css.js +6 -0
- package/cjs/column-picker/ColumnPicker.css.js.map +1 -0
- package/cjs/column-picker/ColumnPicker.js +238 -0
- package/cjs/column-picker/ColumnPicker.js.map +1 -0
- package/cjs/column-picker/useColumnPicker.js +104 -0
- package/cjs/column-picker/useColumnPicker.js.map +1 -0
- package/cjs/datasource-stats/DatasourceStats.css.js +1 -1
- package/cjs/datasource-stats/DatasourceStats.js +3 -1
- package/cjs/datasource-stats/DatasourceStats.js.map +1 -1
- package/cjs/freeze-control/FreezeControl.css.js +1 -1
- package/cjs/freeze-control/FreezeControl.js +71 -10
- package/cjs/freeze-control/FreezeControl.js.map +1 -1
- package/cjs/freeze-control/FrozenBanner.css.js +6 -0
- package/cjs/freeze-control/FrozenBanner.css.js.map +1 -0
- package/cjs/freeze-control/FrozenBanner.js +55 -0
- package/cjs/freeze-control/FrozenBanner.js.map +1 -0
- package/cjs/freeze-control/useFreezeControl.js +50 -8
- package/cjs/freeze-control/useFreezeControl.js.map +1 -1
- package/cjs/index.js +6 -0
- package/cjs/index.js.map +1 -1
- package/cjs/table-column-settings/TableSettingsPanel.js +12 -1
- package/cjs/table-column-settings/TableSettingsPanel.js.map +1 -1
- package/cjs/table-column-settings/useTableAndColumnSettings.js +17 -12
- package/cjs/table-column-settings/useTableAndColumnSettings.js.map +1 -1
- package/esm/column-list/ColumnList.js +15 -2
- package/esm/column-list/ColumnList.js.map +1 -1
- package/esm/column-menu/column-menu-utils.js +2 -19
- package/esm/column-menu/column-menu-utils.js.map +1 -1
- package/esm/column-menu/useColumnActions.js +5 -4
- package/esm/column-menu/useColumnActions.js.map +1 -1
- package/esm/column-picker/ColumnPicker.css.js +4 -0
- package/esm/column-picker/ColumnPicker.css.js.map +1 -0
- package/esm/column-picker/ColumnPicker.js +235 -0
- package/esm/column-picker/ColumnPicker.js.map +1 -0
- package/esm/column-picker/useColumnPicker.js +101 -0
- package/esm/column-picker/useColumnPicker.js.map +1 -0
- package/esm/datasource-stats/DatasourceStats.css.js +1 -1
- package/esm/datasource-stats/DatasourceStats.js +3 -1
- package/esm/datasource-stats/DatasourceStats.js.map +1 -1
- package/esm/freeze-control/FreezeControl.css.js +1 -1
- package/esm/freeze-control/FreezeControl.js +73 -12
- package/esm/freeze-control/FreezeControl.js.map +1 -1
- package/esm/freeze-control/FrozenBanner.css.js +4 -0
- package/esm/freeze-control/FrozenBanner.css.js.map +1 -0
- package/esm/freeze-control/FrozenBanner.js +53 -0
- package/esm/freeze-control/FrozenBanner.js.map +1 -0
- package/esm/freeze-control/useFreezeControl.js +51 -9
- package/esm/freeze-control/useFreezeControl.js.map +1 -1
- package/esm/index.js +3 -0
- package/esm/index.js.map +1 -1
- package/esm/table-column-settings/TableSettingsPanel.js +12 -2
- package/esm/table-column-settings/TableSettingsPanel.js.map +1 -1
- package/esm/table-column-settings/useTableAndColumnSettings.js +18 -13
- package/esm/table-column-settings/useTableAndColumnSettings.js.map +1 -1
- package/package.json +11 -11
- package/types/column-menu/column-action-types.d.ts +5 -1
- package/types/column-menu/column-menu-utils.d.ts +1 -1
- package/types/column-picker/ColumnPicker.d.ts +6 -0
- package/types/column-picker/useColumnPicker.d.ts +38 -0
- package/types/datasource-stats/DatasourceStats.d.ts +3 -1
- package/types/freeze-control/FreezeControl.d.ts +6 -3
- package/types/freeze-control/FrozenBanner.d.ts +6 -0
- package/types/freeze-control/useFreezeControl.d.ts +4 -3
- package/types/index.d.ts +3 -0
- 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
|
|
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":";;;;;;;
|
|
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
|
|
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 {
|
|
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 {
|
|
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
|
|
10
|
+
const FLASH_DURATION_MS = 3e3;
|
|
10
11
|
const FreezeControl = ({
|
|
11
|
-
activeLabel = "Active",
|
|
12
12
|
dataSource,
|
|
13
13
|
className,
|
|
14
|
-
|
|
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 {
|
|
23
|
+
const { isFrozen, newRecordCount, onToggleChange } = useFreezeControl({
|
|
24
24
|
dataSource
|
|
25
25
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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 {
|
|
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":";;;;"}
|