wenay-react2 1.0.35 → 1.0.36
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/README.md +12 -56
- package/lib/common/api.d.ts +28 -28
- package/lib/common/api.js +31 -31
- package/lib/common/src/components/Buttons/MiniButton.d.ts +1 -3
- package/lib/common/src/components/Buttons/MiniButton.js +1 -3
- package/lib/common/src/components/Dnd/{RNDFunc.d.ts → DragArea.d.ts} +1 -1
- package/lib/common/src/components/Dnd/{RNDFunc.js → DragArea.js} +1 -1
- package/lib/common/src/components/Dnd/{RNDFunc3.d.ts → FloatingWindow.d.ts} +7 -7
- package/lib/common/src/components/Dnd/{RNDFunc3.js → FloatingWindow.js} +10 -10
- package/lib/common/src/components/Dnd/OutlineDragDemo.d.ts +1 -0
- package/lib/common/src/components/Dnd/{DraggableOutlineDiv.js → OutlineDragDemo.js} +1 -2
- package/lib/common/src/components/Dnd/Resizable.js +1 -1
- package/lib/common/src/components/Dnd/index.d.ts +3 -3
- package/lib/common/src/components/Dnd/index.js +3 -3
- package/lib/common/src/components/Input.d.ts +5 -5
- package/lib/common/src/components/Input.js +10 -10
- package/lib/common/src/components/Menu/RightMenu.d.ts +25 -5
- package/lib/common/src/components/Menu/RightMenu.js +27 -19
- package/lib/common/src/components/Menu/RightMenuStore.d.ts +2 -2
- package/lib/common/src/components/Menu/RightMenuStore.js +1 -1
- package/lib/common/src/components/Modal/LeftModal.js +4 -4
- package/lib/common/src/components/Modal/Modal.d.ts +11 -17
- package/lib/common/src/components/Modal/Modal.js +15 -21
- package/lib/common/src/components/Modal/ModalContextProvider.d.ts +0 -6
- package/lib/common/src/components/Modal/ModalContextProvider.js +2 -9
- package/lib/common/src/components/Other.d.ts +2 -2
- package/lib/common/src/components/Other.js +5 -5
- package/lib/common/src/components/Parameters.d.ts +3 -3
- package/lib/common/src/components/Parameters.js +3 -3
- package/lib/common/src/components/{ParametersEngine.d.ts → ParamsEditor.d.ts} +1 -1
- package/lib/common/src/components/{ParametersEngine.js → ParamsEditor.js} +10 -10
- package/lib/common/src/components/Settings/SettingsDialog.d.ts +4 -4
- package/lib/common/src/components/Toolbar/Toolbar.d.ts +50 -37
- package/lib/common/src/components/Toolbar/Toolbar.js +60 -23
- package/lib/common/src/components/UiSlot/UiSlot.d.ts +3 -3
- package/lib/common/src/components/UiSlot/UiSlot.js +6 -6
- package/lib/common/src/grid/agGrid4/agGrid4.d.ts +4 -4
- package/lib/common/src/grid/agGrid4/agGrid4.js +6 -6
- package/lib/common/src/grid/agGrid4/index.d.ts +3 -3
- package/lib/common/src/grid/agGrid4/index.js +1 -1
- package/lib/common/src/grid/agGrid4/theme.d.ts +3 -3
- package/lib/common/src/grid/columnState/CardList.d.ts +11 -0
- package/lib/common/src/grid/columnState/CardList.js +28 -0
- package/lib/common/src/grid/columnState/ColumnDots.d.ts +9 -0
- package/lib/common/src/grid/columnState/ColumnDots.js +121 -0
- package/lib/common/src/grid/columnState/ColumnsMenu.d.ts +65 -0
- package/lib/common/src/grid/columnState/ColumnsMenu.js +123 -0
- package/lib/common/src/grid/columnState/columnState.d.ts +113 -0
- package/lib/common/src/grid/columnState/columnState.js +284 -0
- package/lib/common/src/grid/columnState/index.d.ts +4 -0
- package/lib/common/src/grid/columnState/index.js +4 -0
- package/lib/common/src/hooks/index.d.ts +1 -1
- package/lib/common/src/hooks/index.js +1 -1
- package/lib/common/src/hooks/useKeyboard.d.ts +18 -0
- package/lib/common/src/hooks/{useAddDownAnyKey.js → useKeyboard.js} +16 -24
- package/lib/common/src/hooks/useObserveStore.d.ts +12 -12
- package/lib/common/src/hooks/useObserveStore.js +2 -2
- package/lib/common/src/hooks/useOutside.d.ts +12 -19
- package/lib/common/src/hooks/useOutside.js +9 -16
- package/lib/common/src/hooks/useReorder.d.ts +4 -4
- package/lib/common/src/hooks/useReorderBoard.d.ts +15 -15
- package/lib/common/src/hooks/useReplay.d.ts +9 -9
- package/lib/common/src/hooks/useReplay.js +7 -7
- package/lib/common/src/logs/logs.d.ts +3 -3
- package/lib/common/src/logs/logs.js +11 -13
- package/lib/common/src/logs/{logs3.d.ts → logsContext.d.ts} +4 -4
- package/lib/common/src/logs/{logs3.js → logsContext.js} +4 -4
- package/lib/common/src/menu/menu.d.ts +16 -16
- package/lib/common/src/menu/menu.js +12 -11
- package/lib/common/src/menu/menuMouse.d.ts +71 -13
- package/lib/common/src/menu/menuMouse.js +189 -21
- package/lib/common/src/menu/menuR.d.ts +3 -3
- package/lib/common/src/menu/menuR.js +5 -5
- package/lib/common/src/styles/styleGrid.d.ts +1 -1
- package/lib/common/src/styles/tokens.d.ts +1 -1
- package/lib/common/src/styles/tokens.js +1 -1
- package/lib/common/src/utils/cache.d.ts +11 -11
- package/lib/common/src/utils/cache.js +0 -0
- package/lib/common/src/utils/gridRows.d.ts +37 -0
- package/lib/common/src/utils/{applyTransactionAsyncUpdate.js → gridRows.js} +6 -38
- package/lib/common/src/utils/index.d.ts +2 -2
- package/lib/common/src/utils/index.js +2 -2
- package/lib/common/src/utils/inputAutoStep.d.ts +2 -2
- package/lib/common/src/utils/inputAutoStep.js +26 -37
- package/lib/common/src/utils/{mapMemory.d.ts → memoryStore.d.ts} +13 -13
- package/lib/common/src/utils/{mapMemory.js → memoryStore.js} +32 -32
- package/lib/common/src/utils/observableMap.d.ts +5 -5
- package/lib/common/src/utils/observableMap.js +3 -3
- package/lib/common/updateBy.js +2 -2
- package/lib/style/style.css +3 -3
- package/lib/style/tokens.css +1 -1
- package/package.json +49 -49
- package/lib/common/src/components/Dnd/DraggableOutlineDiv.d.ts +0 -2
- package/lib/common/src/hooks/useAddDownAnyKey.d.ts +0 -24
- package/lib/common/src/utils/applyTransactionAsyncUpdate.d.ts +0 -53
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { listen as createListen } from 'wenay-common2';
|
|
2
|
+
import { renderBy, updateBy } from '../../../updateBy';
|
|
3
|
+
import { memoryGetOrCreate, memoryMarkDirty } from '../../utils/memoryStore';
|
|
4
|
+
const SCHEMA_V = 1;
|
|
5
|
+
/** Grid events that mean "the user changed the column layout / sort / filter". */
|
|
6
|
+
const GRID_EVENTS = ['columnMoved', 'columnResized', 'columnVisible', 'sortChanged', 'filterChanged'];
|
|
7
|
+
export function createColumnState(opts) {
|
|
8
|
+
const groupMembers = (g) => opts.columns.filter(c => c.group == g).map(c => c.key);
|
|
9
|
+
const groupKeys = [...new Set(opts.columns.map(c => c.group).filter((g) => !!g))];
|
|
10
|
+
const defConfig = () => ({
|
|
11
|
+
v: SCHEMA_V,
|
|
12
|
+
order: opts.def?.order?.slice() ?? opts.columns.map(c => c.key),
|
|
13
|
+
visible: opts.def?.visible ? { ...opts.def.visible } : Object.fromEntries(opts.columns.map(c => [c.key, c.defaultVisible != false])),
|
|
14
|
+
width: opts.def?.width ? { ...opts.def.width } : {},
|
|
15
|
+
sort: opts.def?.sort ? { ...opts.def.sort } : null,
|
|
16
|
+
filter: opts.def?.filter ? { ...opts.def.filter } : {},
|
|
17
|
+
groups: opts.def?.groups ? { ...opts.def.groups } : Object.fromEntries(groupKeys.map(g => [g, groupMembers(g)])),
|
|
18
|
+
});
|
|
19
|
+
const st = memoryGetOrCreate(opts.key, defConfig());
|
|
20
|
+
const [emitChange, onChange] = createListen();
|
|
21
|
+
/** Runtime-only, never persisted: which column keys the attached grid
|
|
22
|
+
* actually HAS right now. null = unknown / no grid = treat all as present.
|
|
23
|
+
* A column removed from the live grid (dynamic defs, "drop empty columns"
|
|
24
|
+
* standards) keeps its config entry and its menu button - the button just
|
|
25
|
+
* goes inert. The grid adapter maintains this; grid-less consumers may
|
|
26
|
+
* call setPresent themselves. */
|
|
27
|
+
const rt = { present: null };
|
|
28
|
+
function setPresent(keys) {
|
|
29
|
+
const next = keys ? Object.fromEntries(keys.map(k => [k, true])) : null;
|
|
30
|
+
if (JSON.stringify(next) == JSON.stringify(rt.present))
|
|
31
|
+
return;
|
|
32
|
+
rt.present = next;
|
|
33
|
+
renderBy(rt);
|
|
34
|
+
}
|
|
35
|
+
const getPresent = () => rt.present;
|
|
36
|
+
const isPresent = (key) => !rt.present || rt.present[key] == true;
|
|
37
|
+
function usePresent() {
|
|
38
|
+
updateBy(rt);
|
|
39
|
+
return rt.present;
|
|
40
|
+
}
|
|
41
|
+
/** The persisted state may be stale or partial (older app version, columns
|
|
42
|
+
* added/removed) - never crash, never drop user data that still applies:
|
|
43
|
+
* unknown keys are filtered out, missing columns are appended
|
|
44
|
+
* (default-visible), fixed columns are pinned back to their descriptor
|
|
45
|
+
* index. This IS the soft migration; v covers incompatible shape changes. */
|
|
46
|
+
function normalize() {
|
|
47
|
+
const known = new Set(opts.columns.map(c => c.key));
|
|
48
|
+
const byKey = new Map(opts.columns.map(c => [c.key, c]));
|
|
49
|
+
const rawOrder = Array.isArray(st.order) ? st.order : [];
|
|
50
|
+
const order = rawOrder.filter(k => known.has(k) && !byKey.get(k)?.fixed);
|
|
51
|
+
for (const c of opts.columns)
|
|
52
|
+
if (!c.fixed && order.indexOf(c.key) == -1)
|
|
53
|
+
order.push(c.key);
|
|
54
|
+
opts.columns.forEach(function pinFixed(c, i) {
|
|
55
|
+
if (c.fixed)
|
|
56
|
+
order.splice(Math.min(i, order.length), 0, c.key);
|
|
57
|
+
});
|
|
58
|
+
const rawVisible = st.visible && typeof st.visible == 'object' ? st.visible : {};
|
|
59
|
+
const visible = {};
|
|
60
|
+
for (const c of opts.columns)
|
|
61
|
+
visible[c.key] = c.fixed ? true : (rawVisible[c.key] ?? c.defaultVisible != false);
|
|
62
|
+
const rawWidth = st.width && typeof st.width == 'object' ? st.width : {};
|
|
63
|
+
const width = {};
|
|
64
|
+
for (const [k, w] of Object.entries(rawWidth))
|
|
65
|
+
if (known.has(k) && typeof w == 'number' && isFinite(w) && w > 0)
|
|
66
|
+
width[k] = w;
|
|
67
|
+
const sort = st.sort && known.has(st.sort.key) && (st.sort.dir == 'asc' || st.sort.dir == 'desc')
|
|
68
|
+
? { key: st.sort.key, dir: st.sort.dir } : null;
|
|
69
|
+
const rawFilter = st.filter && typeof st.filter == 'object' ? st.filter : {};
|
|
70
|
+
const filter = {};
|
|
71
|
+
for (const [k, f] of Object.entries(rawFilter))
|
|
72
|
+
if (known.has(k))
|
|
73
|
+
filter[k] = f;
|
|
74
|
+
const rawGroups = st.groups && typeof st.groups == 'object' ? st.groups : {};
|
|
75
|
+
const groups = {};
|
|
76
|
+
for (const g of groupKeys) {
|
|
77
|
+
const members = groupMembers(g);
|
|
78
|
+
groups[g] = Array.isArray(rawGroups[g]) ? rawGroups[g].filter(k => members.indexOf(k) != -1) : members;
|
|
79
|
+
}
|
|
80
|
+
return { v: SCHEMA_V, order, visible, width, sort, filter, groups };
|
|
81
|
+
}
|
|
82
|
+
/** Every edit funnels through here: mutate the persisted object in place
|
|
83
|
+
* (identity is the updateBy/renderBy subscription key), announce, mark the
|
|
84
|
+
* cache dirty, push to the attached grid (unless the grid IS the source),
|
|
85
|
+
* emit outward. */
|
|
86
|
+
function commit(next, fromGrid) {
|
|
87
|
+
st.v = SCHEMA_V;
|
|
88
|
+
st.order = next.order.slice();
|
|
89
|
+
st.visible = { ...next.visible };
|
|
90
|
+
st.width = { ...next.width };
|
|
91
|
+
st.sort = next.sort ? { ...next.sort } : null;
|
|
92
|
+
st.filter = { ...next.filter };
|
|
93
|
+
st.groups = Object.fromEntries(Object.entries(next.groups).map(([g, keys]) => [g, keys.slice()]));
|
|
94
|
+
renderBy(st);
|
|
95
|
+
memoryMarkDirty(opts.key);
|
|
96
|
+
if (!fromGrid)
|
|
97
|
+
applyToGrid();
|
|
98
|
+
emitChange(normalize());
|
|
99
|
+
}
|
|
100
|
+
const getConfig = () => normalize();
|
|
101
|
+
const setConfig = (next) => commit(next, false);
|
|
102
|
+
const reset = () => commit(defConfig(), false);
|
|
103
|
+
function useConfig() {
|
|
104
|
+
updateBy(st);
|
|
105
|
+
return normalize();
|
|
106
|
+
}
|
|
107
|
+
function show(key, on) {
|
|
108
|
+
const cfg = normalize();
|
|
109
|
+
commit({ ...cfg, visible: { ...cfg.visible, [key]: on } }, false);
|
|
110
|
+
}
|
|
111
|
+
function move(order) {
|
|
112
|
+
commit({ ...normalize(), order }, false);
|
|
113
|
+
}
|
|
114
|
+
function setSort(sort) {
|
|
115
|
+
commit({ ...normalize(), sort }, false);
|
|
116
|
+
}
|
|
117
|
+
/** The mobile "sort button" cycle over one column: asc -> desc -> off.
|
|
118
|
+
* A different column starts its own cycle at asc; the sticky sort of
|
|
119
|
+
* another column is simply replaced. */
|
|
120
|
+
function toggleSort(key) {
|
|
121
|
+
const cur = normalize().sort;
|
|
122
|
+
setSort(cur?.key != key ? { key, dir: 'asc' } : cur.dir == 'asc' ? { key, dir: 'desc' } : null);
|
|
123
|
+
}
|
|
124
|
+
/** The order/visibility slice of THIS config as an external list source
|
|
125
|
+
* (structurally = Toolbar's UiListSource): plug it into
|
|
126
|
+
* createToolbar({source}) or any order/visibility editor - the editor,
|
|
127
|
+
* the menu and the attached grid then all mirror one another, because
|
|
128
|
+
* they edit the SAME config. */
|
|
129
|
+
const listSource = {
|
|
130
|
+
useConfig() {
|
|
131
|
+
const c = useConfig();
|
|
132
|
+
return { order: c.order, visible: c.visible };
|
|
133
|
+
},
|
|
134
|
+
getConfig() {
|
|
135
|
+
const c = normalize();
|
|
136
|
+
return { order: c.order, visible: c.visible };
|
|
137
|
+
},
|
|
138
|
+
setConfig(next) {
|
|
139
|
+
const cfg = normalize();
|
|
140
|
+
// an editor over a SUBSET of columns must not lose the rest:
|
|
141
|
+
// unknown incoming keys are dropped by normalize, missing ones re-appended
|
|
142
|
+
commit({ ...cfg, order: next.order, visible: { ...cfg.visible, ...next.visible } }, false);
|
|
143
|
+
},
|
|
144
|
+
onChange: (cb) => onChange.on(c => cb({ order: c.order, visible: c.visible })),
|
|
145
|
+
};
|
|
146
|
+
/** Keys to render, in order. Grouped columns are additionally gated by their
|
|
147
|
+
* group's enabled set. */
|
|
148
|
+
function visibleKeys() {
|
|
149
|
+
const cfg = normalize();
|
|
150
|
+
const byKey = new Map(opts.columns.map(c => [c.key, c]));
|
|
151
|
+
return cfg.order.filter(k => {
|
|
152
|
+
if (cfg.visible[k] == false)
|
|
153
|
+
return false;
|
|
154
|
+
const g = byKey.get(k)?.group;
|
|
155
|
+
return !g || cfg.groups[g]?.indexOf(k) != -1;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/* ----- grid adapter (two-way) ----- */
|
|
159
|
+
let gridApi = null;
|
|
160
|
+
let applying = false;
|
|
161
|
+
let saveTimer;
|
|
162
|
+
function toAgState(cfg) {
|
|
163
|
+
return cfg.order.map(k => ({
|
|
164
|
+
colId: k,
|
|
165
|
+
hide: cfg.visible[k] == false,
|
|
166
|
+
width: cfg.width[k], // undefined = leave the grid's current width
|
|
167
|
+
sort: cfg.sort?.key == k ? cfg.sort.dir : null,
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
/** Store -> grid. The applying flag (plus source=='api' on events) keeps the
|
|
171
|
+
* restore from bouncing back as a save. */
|
|
172
|
+
function applyToGrid() {
|
|
173
|
+
if (!gridApi)
|
|
174
|
+
return;
|
|
175
|
+
applying = true;
|
|
176
|
+
try {
|
|
177
|
+
const cfg = normalize();
|
|
178
|
+
gridApi.applyColumnState({ state: toAgState(cfg), applyOrder: true });
|
|
179
|
+
gridApi.setFilterModel(Object.keys(cfg.filter).length ? cfg.filter : null);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
applying = false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Grid -> store: fold the live column state back into the config. Columns
|
|
186
|
+
* the grid does not know keep their stored values (a grid may mount a
|
|
187
|
+
* subset). Skipped when nothing actually changed - the residual guard
|
|
188
|
+
* against apply/save loops. */
|
|
189
|
+
function readFromGrid() {
|
|
190
|
+
if (!gridApi || gridApi.isDestroyed?.())
|
|
191
|
+
return;
|
|
192
|
+
const cfg = normalize();
|
|
193
|
+
const known = new Set(opts.columns.map(c => c.key));
|
|
194
|
+
const order = [];
|
|
195
|
+
const visible = { ...cfg.visible };
|
|
196
|
+
const width = { ...cfg.width };
|
|
197
|
+
let sort = null;
|
|
198
|
+
const gridIds = new Set();
|
|
199
|
+
for (const s of gridApi.getColumnState()) {
|
|
200
|
+
if (!s.colId)
|
|
201
|
+
continue;
|
|
202
|
+
gridIds.add(s.colId);
|
|
203
|
+
if (!known.has(s.colId))
|
|
204
|
+
continue;
|
|
205
|
+
order.push(s.colId);
|
|
206
|
+
visible[s.colId] = !s.hide;
|
|
207
|
+
if (typeof s.width == 'number' && s.width > 0)
|
|
208
|
+
width[s.colId] = s.width;
|
|
209
|
+
if (s.sort == 'asc' || s.sort == 'desc')
|
|
210
|
+
sort = { key: s.colId, dir: s.sort };
|
|
211
|
+
}
|
|
212
|
+
// the grid cannot express a sort by a column it does not currently have:
|
|
213
|
+
// keep the STICKY sort instead of folding its absence in as "off"
|
|
214
|
+
if (!sort && cfg.sort && !gridIds.has(cfg.sort.key))
|
|
215
|
+
sort = cfg.sort;
|
|
216
|
+
for (const k of cfg.order)
|
|
217
|
+
if (order.indexOf(k) == -1)
|
|
218
|
+
order.push(k);
|
|
219
|
+
const filter = (gridApi.getFilterModel() ?? {});
|
|
220
|
+
const next = { ...cfg, order, visible, width, sort, filter };
|
|
221
|
+
if (JSON.stringify(next) == JSON.stringify(cfg))
|
|
222
|
+
return;
|
|
223
|
+
commit(next, true);
|
|
224
|
+
// normalize() may have corrected the grid's move (a fixed column dragged
|
|
225
|
+
// away from its pinned index): push the corrected order back so the grid
|
|
226
|
+
// and the config never disagree
|
|
227
|
+
if (JSON.stringify(normalize().order) != JSON.stringify(next.order))
|
|
228
|
+
applyToGrid();
|
|
229
|
+
}
|
|
230
|
+
function onGridEvent(e) {
|
|
231
|
+
if (applying || e?.source == 'api')
|
|
232
|
+
return;
|
|
233
|
+
// resize/move fire per animation frame during a drag; persist the final shape only
|
|
234
|
+
if (e?.finished === false)
|
|
235
|
+
return;
|
|
236
|
+
clearTimeout(saveTimer);
|
|
237
|
+
saveTimer = setTimeout(readFromGrid, opts.saveMs ?? 300);
|
|
238
|
+
}
|
|
239
|
+
/** The grid's column SET changed (dynamic columnDefs, "drop empty columns"
|
|
240
|
+
* standards): refresh presence; when the set really changed, re-impose the
|
|
241
|
+
* config - a column that came BACK gets its stored order/width/visibility
|
|
242
|
+
* again (setting columnDefs resets order to the defs' order). No loop:
|
|
243
|
+
* applyColumnState never adds/removes columns, so it cannot re-fire this. */
|
|
244
|
+
function onGridColumns() {
|
|
245
|
+
if (!gridApi || gridApi.isDestroyed?.())
|
|
246
|
+
return;
|
|
247
|
+
const before = rt.present;
|
|
248
|
+
setPresent((gridApi.getColumns() ?? []).map(c => c.getColId()));
|
|
249
|
+
if (rt.present != before && !applying)
|
|
250
|
+
applyToGrid();
|
|
251
|
+
}
|
|
252
|
+
/** Call from onGridReady (AgGridTable forwards it on top of its own wiring) or
|
|
253
|
+
* via controller.withApi. Restores the saved state, then watches the grid. */
|
|
254
|
+
function attach(api) {
|
|
255
|
+
detach();
|
|
256
|
+
gridApi = api;
|
|
257
|
+
applyToGrid();
|
|
258
|
+
setPresent((api.getColumns() ?? []).map(c => c.getColId()));
|
|
259
|
+
for (const t of GRID_EVENTS)
|
|
260
|
+
api.addEventListener(t, onGridEvent);
|
|
261
|
+
api.addEventListener('gridColumnsChanged', onGridColumns);
|
|
262
|
+
}
|
|
263
|
+
/** Call from onGridPreDestroyed. The config survives the grid (columnBuffer
|
|
264
|
+
* pattern): remount + attach restores the same layout. */
|
|
265
|
+
function detach() {
|
|
266
|
+
clearTimeout(saveTimer);
|
|
267
|
+
saveTimer = undefined;
|
|
268
|
+
if (gridApi && !gridApi.isDestroyed?.()) {
|
|
269
|
+
for (const t of GRID_EVENTS)
|
|
270
|
+
gridApi.removeEventListener(t, onGridEvent);
|
|
271
|
+
gridApi.removeEventListener('gridColumnsChanged', onGridColumns);
|
|
272
|
+
}
|
|
273
|
+
gridApi = null;
|
|
274
|
+
setPresent(null);
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
/** The column descriptors this state was created over - UI components
|
|
278
|
+
* (dots, cards, icon menus) render from these + the config. */
|
|
279
|
+
columns: opts.columns,
|
|
280
|
+
api: { getConfig, setConfig, useConfig, onChange, reset, show, move, setSort, toggleSort, visibleKeys,
|
|
281
|
+
getPresent, usePresent, isPresent, setPresent, listSource },
|
|
282
|
+
grid: { attach, detach },
|
|
283
|
+
};
|
|
284
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const keyboardState: {
|
|
2
|
+
key: string;
|
|
3
|
+
};
|
|
4
|
+
export type KeyboardApi = {
|
|
5
|
+
readonly key: string;
|
|
6
|
+
getKey(): string;
|
|
7
|
+
get(): string;
|
|
8
|
+
clear(): void;
|
|
9
|
+
reset(): void;
|
|
10
|
+
subscribe(listener: (key: string, event?: KeyboardEvent) => void): () => void;
|
|
11
|
+
on(listener: (key: string, event?: KeyboardEvent) => void): () => void;
|
|
12
|
+
};
|
|
13
|
+
export declare const keyboard: KeyboardApi;
|
|
14
|
+
export declare function useKeyboard(options?: {
|
|
15
|
+
enabled?: boolean;
|
|
16
|
+
target?: Document | HTMLElement;
|
|
17
|
+
onKeyDown?: (key: string, event: KeyboardEvent) => void;
|
|
18
|
+
}): KeyboardApi;
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
2
|
import { renderBy } from "../../updateBy";
|
|
3
|
-
import {
|
|
4
|
-
export const
|
|
3
|
+
import { listen as createListen } from "wenay-common2";
|
|
4
|
+
export const keyboardState = {
|
|
5
5
|
key: ""
|
|
6
6
|
};
|
|
7
|
-
const [emitKeyDown,
|
|
8
|
-
export const
|
|
9
|
-
get key() { return
|
|
10
|
-
getKey() { return
|
|
11
|
-
get() { return
|
|
7
|
+
const [emitKeyDown, keyboardListen] = createListen();
|
|
8
|
+
export const keyboard = {
|
|
9
|
+
get key() { return keyboardState.key; },
|
|
10
|
+
getKey() { return keyboardState.key; },
|
|
11
|
+
get() { return keyboardState.key; },
|
|
12
12
|
clear() {
|
|
13
|
-
|
|
14
|
-
renderBy(
|
|
13
|
+
keyboardState.key = "";
|
|
14
|
+
renderBy(keyboardState);
|
|
15
15
|
emitKeyDown("", undefined);
|
|
16
16
|
},
|
|
17
17
|
reset() {
|
|
18
|
-
|
|
18
|
+
keyboard.clear();
|
|
19
19
|
},
|
|
20
20
|
subscribe(listener) {
|
|
21
|
-
return
|
|
21
|
+
return keyboardListen.on(listener);
|
|
22
22
|
},
|
|
23
23
|
on(listener) {
|
|
24
|
-
return
|
|
24
|
+
return keyboardListen.on(listener);
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
-
export function
|
|
27
|
+
export function useKeyboard(options = {}) {
|
|
28
28
|
const { enabled = true, target } = options;
|
|
29
29
|
const onKeyDownRef = useRef(options.onKeyDown);
|
|
30
30
|
onKeyDownRef.current = options.onKeyDown;
|
|
@@ -37,8 +37,8 @@ export function useAddDownAnyKey(options = {}) {
|
|
|
37
37
|
const func = (event) => {
|
|
38
38
|
if (!(event instanceof KeyboardEvent))
|
|
39
39
|
return;
|
|
40
|
-
|
|
41
|
-
renderBy(
|
|
40
|
+
keyboardState.key = event.key;
|
|
41
|
+
renderBy(keyboardState);
|
|
42
42
|
emitKeyDown(event.key, event);
|
|
43
43
|
onKeyDownRef.current?.(event.key, event);
|
|
44
44
|
};
|
|
@@ -47,13 +47,5 @@ export function useAddDownAnyKey(options = {}) {
|
|
|
47
47
|
currentTarget.removeEventListener("keydown", func);
|
|
48
48
|
};
|
|
49
49
|
}, [enabled, target]);
|
|
50
|
-
return
|
|
50
|
+
return keyboard;
|
|
51
51
|
}
|
|
52
|
-
export const useKeyDown = useAddDownAnyKey;
|
|
53
|
-
export const useAnyKey = useAddDownAnyKey;
|
|
54
|
-
/** @deprecated Use `useKeyDown(options)` or `useAnyKey(options)`. */
|
|
55
|
-
export function addDownAnyKey() {
|
|
56
|
-
return useAddDownAnyKey();
|
|
57
|
-
}
|
|
58
|
-
/** @deprecated Use `useKeyDown(options)` or `useAnyKey(options)`. */
|
|
59
|
-
export const useAddDownAnyKeyOld = useAddDownAnyKey;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type StoreChange =
|
|
3
|
-
type StoreEachCtx =
|
|
4
|
-
type StoreSubOpts =
|
|
5
|
-
type StoreSyncOpts =
|
|
6
|
-
type StoreDrain =
|
|
7
|
-
type StoreMask<T> =
|
|
8
|
-
type StorePick<T, M> =
|
|
9
|
-
type StoreNode<T> =
|
|
10
|
-
type StoreSelection<T, M> =
|
|
1
|
+
import { Observe } from "wenay-common2";
|
|
2
|
+
type StoreChange = Observe.StoreChange;
|
|
3
|
+
type StoreEachCtx = Observe.StoreEachCtx;
|
|
4
|
+
type StoreSubOpts = Observe.StoreSubOpts;
|
|
5
|
+
type StoreSyncOpts = Observe.StoreSyncOpts;
|
|
6
|
+
type StoreDrain = Observe.StoreDrain;
|
|
7
|
+
type StoreMask<T> = Observe.StoreMask<T>;
|
|
8
|
+
type StorePick<T, M> = Observe.StorePick<T, M>;
|
|
9
|
+
type StoreNode<T> = Observe.StoreNode<T>;
|
|
10
|
+
type StoreSelection<T, M> = Observe.StoreSelection<T, M>;
|
|
11
11
|
export type ListenLike<TArgs extends readonly unknown[] = readonly unknown[]> = {
|
|
12
12
|
on(cb: (...args: TArgs) => void, opts?: {
|
|
13
13
|
key?: string | symbol;
|
|
@@ -69,7 +69,7 @@ export type UseStoreEachOptions = {
|
|
|
69
69
|
* cb goes through a ref — a new identity does not resubscribe.
|
|
70
70
|
* The remote (wire) counterpart is useStoreReplayEach in useReplay.ts.
|
|
71
71
|
*/
|
|
72
|
-
export declare function useStoreEach<T extends object>(store:
|
|
72
|
+
export declare function useStoreEach<T extends object>(store: Observe.Store<T> | null | undefined, cb: (key: string, value: T[keyof T] | undefined, ctx: StoreEachCtx) => void, options?: UseStoreEachOptions): void;
|
|
73
73
|
export type RemoteStoreLike<T extends object> = {
|
|
74
74
|
get(mask?: any): T | Promise<T>;
|
|
75
75
|
changed: ListenLike<readonly []>;
|
|
@@ -80,7 +80,7 @@ export type UseStoreMirrorOptions<T extends object, M extends StoreMask<T>> = St
|
|
|
80
80
|
auto?: boolean;
|
|
81
81
|
};
|
|
82
82
|
export type StoreMirrorController<T extends object, M extends StoreMask<T>> = {
|
|
83
|
-
readonly store:
|
|
83
|
+
readonly store: Observe.Store<T> & {
|
|
84
84
|
sync(mask: M, subOpts?: StoreSyncOpts): Promise<() => void>;
|
|
85
85
|
};
|
|
86
86
|
readonly value: StorePick<T, M>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { Observe } from "wenay-common2";
|
|
3
3
|
function readNode(node, options) {
|
|
4
4
|
if (!node.has())
|
|
5
5
|
return options?.fallback;
|
|
@@ -128,7 +128,7 @@ export function useStoreMirror(remote, initial, options) {
|
|
|
128
128
|
if (!storeRef.current || storeRef.current.remote !== remote) {
|
|
129
129
|
storeRef.current = {
|
|
130
130
|
remote,
|
|
131
|
-
store:
|
|
131
|
+
store: Observe.createStoreMirror(remote, initial),
|
|
132
132
|
};
|
|
133
133
|
}
|
|
134
134
|
const store = storeRef.current.store;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { ReactElement } from "react";
|
|
2
2
|
export declare const StyleOtherRow: React.CSSProperties;
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const StyleOtherColumn: React.CSSProperties;
|
|
4
4
|
export type UseOutsideOptions<T extends HTMLElement = HTMLDivElement> = {
|
|
5
5
|
ref?: React.RefObject<T | null>;
|
|
6
6
|
outsideClick?: () => void;
|
|
@@ -24,37 +24,30 @@ export type UseOutsideApi<T extends HTMLElement = HTMLDivElement> = {
|
|
|
24
24
|
};
|
|
25
25
|
export declare function useOutsideApi<T extends HTMLElement = HTMLDivElement>(options: UseOutsideOptions<T>): UseOutsideApi<T>;
|
|
26
26
|
export declare function useOutside<T extends HTMLElement = HTMLDivElement>(options: UseOutsideOptions<T>): UseOutsideApi<T>;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
type tChildrenFunc = (api: {
|
|
27
|
+
export declare function useOutsideRef<T extends HTMLElement = HTMLDivElement>(options: UseOutsideOptions<T>): React.RefObject<T | null>;
|
|
28
|
+
type ChildrenFunc = (api: {
|
|
30
29
|
onClose: () => void;
|
|
31
30
|
}) => ReactElement | React.JSX.Element;
|
|
32
|
-
type
|
|
33
|
-
type
|
|
34
|
-
|
|
35
|
-
children: tChildren;
|
|
31
|
+
type ButtonChildren = ReactElement | React.ReactNode | ChildrenFunc;
|
|
32
|
+
type ButtonBaseProps = {
|
|
33
|
+
children: ButtonChildren;
|
|
36
34
|
button: ReactElement | ((status: boolean) => ReactElement);
|
|
37
35
|
style?: React.CSSProperties;
|
|
38
36
|
className?: string;
|
|
39
37
|
};
|
|
40
|
-
type
|
|
38
|
+
type ButtonProps = ButtonBaseProps & {
|
|
41
39
|
statusDef?: boolean;
|
|
42
40
|
keySave?: string;
|
|
43
41
|
outClick?: boolean | (() => void);
|
|
44
42
|
zIndex?: number;
|
|
45
43
|
};
|
|
46
|
-
export declare const
|
|
44
|
+
export declare const OutsideClickArea: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
47
45
|
outsideClick: () => void;
|
|
48
46
|
status?: boolean;
|
|
49
47
|
zIndex?: number;
|
|
50
48
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
51
|
-
export declare
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} & React.RefAttributes<HTMLDivElement>>;
|
|
56
|
-
export declare function Button({ keySave, statusDef, outClick, ...data }: tButton): import("react/jsx-runtime").JSX.Element;
|
|
57
|
-
export declare function ButtonHover(props: tButtonBase): import("react/jsx-runtime").JSX.Element;
|
|
58
|
-
export declare const ButtonOutClick: typeof Button;
|
|
59
|
-
export declare function ButtonAbs(props: Parameters<typeof Button>[0]): import("react/jsx-runtime").JSX.Element;
|
|
49
|
+
export declare function Button({ keySave, statusDef, outClick, ...data }: ButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
50
|
+
export declare function HoverButton(props: ButtonBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
export declare const OutsideButton: typeof Button;
|
|
52
|
+
export declare function AbsoluteButton(props: Parameters<typeof Button>[0]): import("react/jsx-runtime").JSX.Element;
|
|
60
53
|
export {};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
export const StyleOtherRow = { display: "flex", flexDirection: "row", flex: "auto 1 1" };
|
|
4
|
-
export const
|
|
4
|
+
export const StyleOtherColumn = { display: "flex", flexDirection: "column", flex: "auto 0 1" };
|
|
5
5
|
export function useOutsideApi(options) {
|
|
6
6
|
const { outsideClick, onOutside, ref, status = options.enabled ?? true } = options;
|
|
7
|
-
const internalRef = useRef(null);
|
|
7
|
+
const internalRef = useRef(null);
|
|
8
8
|
const r = ref ?? internalRef;
|
|
9
9
|
const outsideClickRef = useRef(outsideClick ?? onOutside);
|
|
10
10
|
const [enabled, setEnabled] = useState(status);
|
|
@@ -52,15 +52,12 @@ export function useOutsideApi(options) {
|
|
|
52
52
|
export function useOutside(options) {
|
|
53
53
|
return useOutsideApi(options);
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
export function useOutsideOld(options) {
|
|
55
|
+
export function useOutsideRef(options) {
|
|
57
56
|
return useOutsideApi(options).ref;
|
|
58
57
|
}
|
|
59
|
-
export const
|
|
58
|
+
export const OutsideClickArea = React.forwardRef(({ children, outsideClick, zIndex, style = {}, status = true, ...other }, forwardedRef) => {
|
|
60
59
|
const style2 = zIndex ? { ...style, zIndex } : style;
|
|
61
|
-
const internalRef = useOutside({ outsideClick
|
|
62
|
-
// Combine refs if forwardedRef is provided; stable identity, otherwise React
|
|
63
|
-
// re-runs the ref (null + node) on every render
|
|
60
|
+
const internalRef = useOutside({ outsideClick, status });
|
|
64
61
|
const combinedRef = React.useCallback((node) => {
|
|
65
62
|
internalRef.current = node;
|
|
66
63
|
if (typeof forwardedRef === 'function') {
|
|
@@ -72,15 +69,11 @@ export const DivOutsideClick = React.forwardRef(({ children, outsideClick, zInde
|
|
|
72
69
|
}, [forwardedRef, internalRef]);
|
|
73
70
|
return _jsx("div", { ref: forwardedRef ? combinedRef : internalRef, style: style2, ...other, children: children });
|
|
74
71
|
});
|
|
75
|
-
// Deprecated: Use DivOutsideClick instead
|
|
76
|
-
export const DivOutsideClick2 = DivOutsideClick;
|
|
77
72
|
function ButtonBase({ children, button, style = {}, className = "", state: [a, setA] }) {
|
|
78
73
|
return _jsxs("div", { style: { position: "relative", width: "min-content", ...style }, className: className, children: [_jsx("div", { onClick: () => setA(!a), children: typeof button == "function" ? button(a) : button }), a && (typeof children == "function" ? children({ onClose: () => setA(!a) }) : children)] });
|
|
79
74
|
}
|
|
80
75
|
const saveStatus = {};
|
|
81
76
|
export function Button({ keySave, statusDef, outClick, ...data }) {
|
|
82
|
-
// The keySave feature was dead: saveStatus was read but not written. Now status
|
|
83
|
-
// persists in memory for the session on each toggle.
|
|
84
77
|
if (keySave && saveStatus[keySave] != null)
|
|
85
78
|
statusDef = saveStatus[keySave];
|
|
86
79
|
const [status, setStatusRaw] = useState(statusDef ?? false);
|
|
@@ -98,15 +91,15 @@ export function Button({ keySave, statusDef, outClick, ...data }) {
|
|
|
98
91
|
if (typeof outClick == "function")
|
|
99
92
|
outClick();
|
|
100
93
|
};
|
|
101
|
-
return outClick ? (_jsx(
|
|
94
|
+
return outClick ? (_jsx(OutsideClickArea, { status: state[0], outsideClick: handleOutsideClick, children: _jsx(ButtonBase, { ...data, state: state }) })) : (_jsx(ButtonBase, { ...data, state: state }));
|
|
102
95
|
}
|
|
103
|
-
export function
|
|
96
|
+
export function HoverButton(props) {
|
|
104
97
|
const [hover, setHover] = useState(false);
|
|
105
98
|
return _jsxs("div", { onMouseEnter: () => setHover(true), onMouseLeave: () => setHover(false), style: { position: "relative", width: "min-content" }, children: [typeof props.button == "function" ? props.button(hover) : props.button, hover &&
|
|
106
99
|
_jsx("div", { style: { position: "absolute" }, children: typeof props.children == "function" ? props.children({ onClose: () => setHover(false) }) : props.children })] });
|
|
107
100
|
}
|
|
108
|
-
export const
|
|
109
|
-
export function
|
|
101
|
+
export const OutsideButton = ({ outClick = true, ...a }) => Button({ ...a, outClick });
|
|
102
|
+
export function AbsoluteButton(props) {
|
|
110
103
|
const children = (api) => _jsx("div", { style: { position: "relative" }, children: _jsx("div", { style: {
|
|
111
104
|
position: "absolute",
|
|
112
105
|
zIndex: props.zIndex ?? 9
|
|
@@ -7,7 +7,7 @@ import React from 'react';
|
|
|
7
7
|
* the container's children.
|
|
8
8
|
* NOT a dnd framework: no nesting, no cross-container moves, no spans or
|
|
9
9
|
* collision packing - when that day comes, take a ready-made library. */
|
|
10
|
-
export type
|
|
10
|
+
export type ReorderOptions = {
|
|
11
11
|
/** keys in render order; the container's children must correspond 1:1 */
|
|
12
12
|
order: string[];
|
|
13
13
|
/** ONE commit on drop; skipped when nothing moved */
|
|
@@ -28,7 +28,7 @@ export type tReorderOptions = {
|
|
|
28
28
|
/** hold before the drag starts (touch-friendly fields); default 0 */
|
|
29
29
|
holdMs?: number;
|
|
30
30
|
};
|
|
31
|
-
export type
|
|
31
|
+
export type ReorderItem = {
|
|
32
32
|
/** spread on the block element */
|
|
33
33
|
props: {
|
|
34
34
|
onMouseDown: React.MouseEventHandler<HTMLElement>;
|
|
@@ -41,9 +41,9 @@ export type tReorderItem = {
|
|
|
41
41
|
/** some drag is active - the consumer adds its transition class/style on non-dragged blocks */
|
|
42
42
|
active: boolean;
|
|
43
43
|
};
|
|
44
|
-
export declare function useReorder<E extends HTMLElement = HTMLDivElement>(o:
|
|
44
|
+
export declare function useReorder<E extends HTMLElement = HTMLDivElement>(o: ReorderOptions): {
|
|
45
45
|
listRef: React.RefObject<E | null>;
|
|
46
|
-
item: (key: string) =>
|
|
46
|
+
item: (key: string) => ReorderItem;
|
|
47
47
|
dragKey: string | null;
|
|
48
48
|
preview: string[] | null;
|
|
49
49
|
};
|