@ultraviolet/ui 1.82.0 → 1.82.2

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 (38) hide show
  1. package/dist/components/Checkbox/index.cjs +14 -20
  2. package/dist/components/Checkbox/index.d.ts +1 -1
  3. package/dist/components/Checkbox/index.js +15 -21
  4. package/dist/components/Chip/index.d.ts +1 -1
  5. package/dist/components/Dialog/index.cjs +3 -3
  6. package/dist/components/Dialog/index.js +3 -3
  7. package/dist/components/List/Cell.cjs +1 -1
  8. package/dist/components/List/Cell.js +1 -1
  9. package/dist/components/List/HeaderRow.cjs +4 -5
  10. package/dist/components/List/HeaderRow.js +4 -5
  11. package/dist/components/List/ListContext.cjs +105 -104
  12. package/dist/components/List/ListContext.d.ts +14 -11
  13. package/dist/components/List/ListContext.js +105 -104
  14. package/dist/components/List/Row.cjs +33 -26
  15. package/dist/components/List/Row.js +33 -26
  16. package/dist/components/List/index.cjs +2 -2
  17. package/dist/components/List/index.d.ts +1 -22
  18. package/dist/components/List/index.js +2 -2
  19. package/dist/components/Radio/index.cjs +11 -11
  20. package/dist/components/Radio/index.d.ts +1 -2
  21. package/dist/components/Radio/index.js +11 -11
  22. package/dist/components/SearchInput/index.cjs +2 -2
  23. package/dist/components/SearchInput/index.js +2 -2
  24. package/dist/components/SelectInput/index.cjs +8 -8
  25. package/dist/components/SelectInput/index.js +8 -8
  26. package/dist/components/SwitchButton/index.cjs +3 -3
  27. package/dist/components/SwitchButton/index.js +3 -3
  28. package/dist/components/Table/HeaderRow.cjs +2 -3
  29. package/dist/components/Table/HeaderRow.js +2 -3
  30. package/dist/components/Table/Row.cjs +29 -22
  31. package/dist/components/Table/Row.js +29 -22
  32. package/dist/components/Table/TableContext.cjs +19 -157
  33. package/dist/components/Table/TableContext.d.ts +5 -30
  34. package/dist/components/Table/TableContext.js +20 -158
  35. package/dist/components/Table/index.cjs +2 -2
  36. package/dist/components/Table/index.d.ts +26 -33
  37. package/dist/components/Table/index.js +2 -2
  38. package/package.json +4 -4
@@ -1,8 +1,9 @@
1
- import type { ComponentProps, Dispatch, ReactNode, RefObject, SetStateAction } from 'react';
1
+ import type { ChangeEvent, ComponentProps, Dispatch, ReactNode, SetStateAction } from 'react';
2
2
  import type { Checkbox } from '../Checkbox';
3
3
  import type { ColumnProps } from './types';
4
- type RowState = Record<string, boolean>;
5
- type ListContextValue = {
4
+ type RowState = Record<string | number, boolean>;
5
+ type MapCheckbox = Map<string | number, HTMLInputElement>;
6
+ export type ListContextValue = {
6
7
  /**
7
8
  * @returns an unregister function
8
9
  * */
@@ -15,18 +16,20 @@ type ListContextValue = {
15
16
  * @returns an unregister function
16
17
  * */
17
18
  registerSelectableRow: (rowId: string) => () => void;
18
- selectedRowIds: RowState;
19
- selectRow: (rowId: string) => void;
20
- unselectRow: (rowId: string) => void;
21
- selectable: boolean;
22
19
  allRowSelectValue: ComponentProps<typeof Checkbox>['checked'];
20
+ selectAllHandler: (event: ChangeEvent<HTMLInputElement>) => void;
21
+ subscribeHandler: () => void;
22
+ columns: ColumnProps[];
23
+ inRange: Set<number | string>;
24
+ mapCheckbox: MapCheckbox;
25
+ selectable: boolean;
23
26
  selectAll: () => void;
27
+ selectedRowIds: RowState;
28
+ selectRow: (rowId: string) => void;
24
29
  unselectAll: () => void;
25
- refList: RefObject<HTMLInputElement[]>;
26
- inRange: string[];
27
- columns: ColumnProps[];
30
+ unselectRow: (rowId: string) => void;
28
31
  };
29
- type ListProviderProps = {
32
+ export type ListProviderProps = {
30
33
  children: ReactNode;
31
34
  autoCollapse: boolean;
32
35
  selectable: boolean;
@@ -1,6 +1,17 @@
1
1
  import { jsx } from "@emotion/react/jsx-runtime";
2
2
  import { createContext, useState, useRef, useCallback, useMemo, useEffect, useContext } from "react";
3
3
  const ListContext = createContext(void 0);
4
+ const checkStateOfCheckboxs = (ids) => {
5
+ const selectableRowCount = Object.keys(ids).length;
6
+ const selectableValuesCount = new Set(Object.values(ids));
7
+ if (!selectableRowCount) {
8
+ return false;
9
+ }
10
+ if (selectableValuesCount.size === 1) {
11
+ return [...selectableValuesCount][0];
12
+ }
13
+ return "indeterminate";
14
+ };
4
15
  const ListProvider = ({
5
16
  children,
6
17
  autoCollapse,
@@ -11,7 +22,9 @@ const ListProvider = ({
11
22
  }) => {
12
23
  const [expandedRowIds, setExpandedRowIds] = useState({});
13
24
  const [selectedRowIds, setSelectedRowIds] = useState({});
14
- const refList = useRef([]);
25
+ const [lastCheckedIndex, setLastCheckedIndex] = useState(null);
26
+ const [inRange, setInRange] = useState(/* @__PURE__ */ new Set([]));
27
+ const refList = useRef(/* @__PURE__ */ new Map());
15
28
  const registerExpandableRow = useCallback((rowId, expanded = false) => {
16
29
  setExpandedRowIds((current) => ({
17
30
  ...current,
@@ -54,142 +67,130 @@ const ListProvider = ({
54
67
  [rowId]: false
55
68
  }));
56
69
  }, []);
57
- const allRowSelectValue = useMemo(() => {
58
- const selectableRowCount = Object.keys(selectedRowIds).length;
59
- if (!selectableRowCount) {
60
- return false;
61
- }
62
- const selectedRowCount = Object.values(selectedRowIds).reduce((acc, isSelected) => acc + (isSelected ? 1 : 0), 0);
63
- if (selectedRowCount === 0) {
64
- return false;
65
- }
66
- if (selectableRowCount === selectedRowCount) {
67
- return true;
68
- }
69
- return "indeterminate";
70
- }, [selectedRowIds]);
71
- const selectAll = useCallback(() => {
72
- const newSelectedRowIds = Object.keys(selectedRowIds).reduce((acc, rowId) => ({
70
+ const allRowSelectValue = useMemo(() => checkStateOfCheckboxs(selectedRowIds), [selectedRowIds]);
71
+ const selectRows = useCallback((rowIds, state) => {
72
+ const newSelectedRowIds = rowIds.reduce((acc, rowId) => ({
73
73
  ...acc,
74
- [rowId]: true
75
- }), {});
74
+ [rowId]: state
75
+ }), selectedRowIds);
76
76
  setSelectedRowIds(newSelectedRowIds);
77
77
  if (onSelectedChange) {
78
78
  onSelectedChange(Object.keys(newSelectedRowIds).filter((row) => newSelectedRowIds[row]));
79
79
  }
80
80
  }, [onSelectedChange, selectedRowIds]);
81
+ const selectAll = useCallback(() => {
82
+ selectRows(Object.keys(selectedRowIds), true);
83
+ }, [selectRows, selectedRowIds]);
81
84
  const unselectAll = useCallback(() => {
82
- const newSelectedRowIds = Object.keys(selectedRowIds).reduce((acc, rowId) => ({
83
- ...acc,
84
- [rowId]: false
85
- }), {});
86
- setSelectedRowIds(newSelectedRowIds);
87
- if (onSelectedChange) {
88
- onSelectedChange(Object.keys(newSelectedRowIds).filter((row) => newSelectedRowIds[row]));
89
- }
90
- }, [onSelectedChange, selectedRowIds]);
85
+ selectRows(Object.keys(selectedRowIds), false);
86
+ }, [selectRows, selectedRowIds]);
91
87
  const selectRow = useCallback((rowId) => {
92
- const newSelectedRowIds = {
93
- ...selectedRowIds,
94
- [rowId]: true
95
- };
96
- setSelectedRowIds(newSelectedRowIds);
97
- if (onSelectedChange) {
98
- onSelectedChange(Object.keys(newSelectedRowIds).filter((row) => newSelectedRowIds[row]));
99
- }
100
- }, [onSelectedChange, selectedRowIds]);
88
+ selectRows([rowId], true);
89
+ }, [selectRows]);
101
90
  const unselectRow = useCallback((rowId) => {
102
- const newSelectedRowIds = {
103
- ...selectedRowIds,
104
- [rowId]: false
105
- };
106
- setSelectedRowIds(newSelectedRowIds);
107
- if (onSelectedChange) {
108
- onSelectedChange(Object.keys(newSelectedRowIds).filter((row) => newSelectedRowIds[row]));
91
+ selectRows([rowId], false);
92
+ }, [selectRows]);
93
+ const selectAllHandler = useCallback(() => {
94
+ if (allRowSelectValue && [true, "indeterminate"].includes(allRowSelectValue)) {
95
+ unselectAll();
109
96
  }
110
- }, [onSelectedChange, selectedRowIds]);
111
- const [lastCheckedIndex, setLastCheckedIndex] = useState(null);
112
- const [inRange, setInRange] = useState([]);
113
- useEffect(() => {
97
+ if (allRowSelectValue === false) {
98
+ selectAll();
99
+ }
100
+ }, [allRowSelectValue, unselectAll, selectAll]);
101
+ const subscribeHandler = useCallback(() => {
114
102
  const handlers = [];
115
103
  if (refList.current) {
116
- const handleClick = (index, isShiftPressed, checked) => {
117
- if (index !== 0) {
118
- setLastCheckedIndex(index);
119
- if (isShiftPressed && lastCheckedIndex !== null) {
120
- const start = Math.min(lastCheckedIndex, index);
121
- const end = Math.max(lastCheckedIndex, index);
122
- const newSelectedRowIds = {
123
- ...selectedRowIds
124
- };
125
- for (let i = start; i <= end; i += 1) {
126
- const checkbox = refList.current[i];
127
- const checkboxValue = checkbox.value;
128
- if (!checkbox.disabled) {
129
- if (checked) {
130
- newSelectedRowIds[checkboxValue] = false;
131
- } else {
132
- newSelectedRowIds[checkboxValue] = true;
133
- }
134
- }
135
- }
136
- setSelectedRowIds(newSelectedRowIds);
137
- if (onSelectedChange) {
138
- onSelectedChange(Object.keys(newSelectedRowIds).filter((row) => newSelectedRowIds[row]));
139
- }
140
- }
141
- } else setLastCheckedIndex(null);
104
+ const handleHover = (checkbox, event) => {
105
+ const isShiftPressed = event.shiftKey;
106
+ const isHoverActive = isShiftPressed && lastCheckedIndex !== null && !checkbox.disabled;
107
+ if (isHoverActive) {
108
+ setInRange((prev) => /* @__PURE__ */ new Set([...prev, checkbox.value]));
109
+ }
110
+ if (!lastCheckedIndex && !checkbox.disabled) {
111
+ setLastCheckedIndex(checkbox.value);
112
+ }
142
113
  };
143
- const handleHover = (index, isShiftPressed, leaving) => {
144
- const newRange = [];
145
- if (isShiftPressed && lastCheckedIndex !== null) {
146
- const start = Math.min(lastCheckedIndex, index);
147
- const end = Math.max(lastCheckedIndex, index);
148
- for (let i = start; i < end; i += 1) {
149
- const checkbox = refList.current[i];
150
- if (!checkbox.disabled && !leaving) {
151
- newRange.push(checkbox.value);
114
+ const handleClickRange = (checkbox) => {
115
+ const shouldShiftEvent = inRange.size > 0;
116
+ const isClickInsideRange = inRange.has(checkbox.value);
117
+ if (shouldShiftEvent && isClickInsideRange) {
118
+ let checkboxRows = {};
119
+ refList.current.forEach((value2, key) => {
120
+ if (inRange.has(key)) {
121
+ checkboxRows = {
122
+ ...checkboxRows,
123
+ // handle the conflict event ( click and onChange in the same time on the last checkbox click)
124
+ [key]: key === checkbox.value ? !value2.checked : value2.checked
125
+ };
152
126
  }
127
+ });
128
+ const state = checkStateOfCheckboxs(checkboxRows);
129
+ const checkboxIds = Object.keys(checkboxRows);
130
+ if (state === true) {
131
+ selectRows(checkboxIds, false);
132
+ }
133
+ if ([false, "indeterminate"].includes(state)) {
134
+ selectRows(checkboxIds, true);
153
135
  }
154
136
  }
155
- setInRange(newRange);
137
+ setTimeout(() => {
138
+ setInRange(/* @__PURE__ */ new Set([]));
139
+ setLastCheckedIndex(checkbox.value);
140
+ }, 1);
141
+ };
142
+ const handleOnChange = (checkbox) => {
143
+ const shouldHandleEvent = inRange.size === 0;
144
+ if (shouldHandleEvent) {
145
+ selectRows([checkbox.value], !checkbox.checked);
146
+ }
147
+ setLastCheckedIndex(checkbox.value);
156
148
  };
157
- refList.current.forEach((checkbox, index) => {
158
- const clickHandler = (event) => handleClick(index, event.shiftKey, selectedRowIds[event.target.value]);
159
- const hoverEnteringHandler = (event) => handleHover(index, event.shiftKey, false);
160
- const hoverLeavingHandler = (event) => handleHover(index, event.shiftKey, true);
149
+ refList.current.forEach((checkbox) => {
150
+ function clickHandler() {
151
+ handleClickRange(this);
152
+ }
153
+ function hoverHandler(event) {
154
+ handleHover(this, event);
155
+ }
156
+ function changeHandler() {
157
+ handleOnChange(this);
158
+ }
159
+ checkbox.addEventListener("change", changeHandler);
161
160
  checkbox.addEventListener("click", clickHandler);
162
- checkbox.addEventListener("mousemove", hoverEnteringHandler);
163
- checkbox.addEventListener("mouseout", hoverLeavingHandler);
161
+ checkbox.addEventListener("mouseover", hoverHandler);
164
162
  handlers.push(() => {
163
+ checkbox.removeEventListener("change", changeHandler);
165
164
  checkbox.removeEventListener("click", clickHandler);
166
- checkbox.removeEventListener("mouseout", hoverEnteringHandler);
167
- checkbox.removeEventListener("mousemove", hoverLeavingHandler);
165
+ checkbox.removeEventListener("mouseover", hoverHandler);
168
166
  });
169
167
  });
170
168
  }
171
169
  return () => {
172
170
  handlers.forEach((cleanup) => cleanup());
173
171
  };
174
- }, [lastCheckedIndex, onSelectedChange, selectedRowIds, unselectRow]);
172
+ }, [inRange, lastCheckedIndex, selectRows]);
173
+ useEffect(subscribeHandler, [subscribeHandler]);
175
174
  const value = useMemo(() => ({
176
- registerExpandableRow,
175
+ allRowSelectValue,
176
+ selectAllHandler,
177
+ subscribeHandler,
178
+ collapseRow,
179
+ columns,
180
+ expandButton,
177
181
  expandedRowIds,
178
182
  expandRow,
179
- collapseRow,
183
+ inRange,
184
+ mapCheckbox: refList.current,
185
+ registerExpandableRow,
180
186
  registerSelectableRow,
181
- selectedRowIds,
182
- selectRow,
183
- unselectRow,
184
187
  selectable,
185
188
  selectAll,
189
+ selectedRowIds,
190
+ selectRow,
186
191
  unselectAll,
187
- allRowSelectValue,
188
- expandButton,
189
- refList,
190
- inRange,
191
- columns
192
- }), [registerExpandableRow, expandedRowIds, expandRow, collapseRow, registerSelectableRow, selectedRowIds, selectRow, unselectRow, selectable, selectAll, unselectAll, allRowSelectValue, expandButton, refList, inRange, columns]);
192
+ unselectRow
193
+ }), [allRowSelectValue, selectAllHandler, subscribeHandler, collapseRow, columns, expandButton, expandedRowIds, expandRow, inRange, refList, registerExpandableRow, registerSelectableRow, selectable, selectAll, selectedRowIds, selectRow, unselectAll, unselectRow]);
193
194
  return /* @__PURE__ */ jsx(ListContext.Provider, { value, children });
194
195
  };
195
196
  const useListContext = () => {