wenay-react2 1.0.47 → 1.0.49
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 +14 -14
- package/doc/EXAMPLE_USAGE.md +969 -969
- package/doc/PROJECT_FUNCTIONALITY.md +403 -403
- package/doc/PROJECT_RULES.md +27 -27
- package/doc/WENAY_REACT2_RENAMES.md +170 -170
- package/doc/changes/v1.0.35.md +18 -18
- package/doc/changes/v1.0.38.md +37 -37
- package/doc/changes/v1.0.39.md +23 -23
- package/doc/changes/v1.0.40.md +14 -14
- package/doc/changes/v1.0.41.md +35 -35
- package/doc/changes/v1.0.42.md +26 -26
- package/doc/changes/v1.0.43.md +10 -10
- package/doc/changes/v1.0.44.md +14 -14
- package/doc/changes/v1.0.45.md +8 -8
- package/doc/changes/v1.0.46.md +11 -11
- package/doc/changes/v1.0.47.md +9 -9
- package/doc/changes/v1.0.48.md +8 -0
- package/doc/changes/v1.0.49.md +7 -0
- package/doc/examples/README.md +5 -4
- package/doc/examples/conference-client.html +34 -0
- package/doc/examples/conference-client.ts +212 -0
- package/doc/examples/conference-server.mjs +150 -0
- package/doc/examples/peer-call-media.tsx +7 -7
- package/doc/examples/stand.tsx +5 -5
- package/doc/native.md +37 -37
- package/doc/progress/README.md +13 -13
- package/doc/progress/architecture-fix-queue.md +74 -74
- package/doc/progress/column-state-present-gate.md +28 -28
- package/doc/progress/common2-adoption-1.0.73.md +28 -28
- package/doc/progress/common2-adoption-1.0.74.md +24 -24
- package/doc/progress/hook-controller-opportunities.md +363 -363
- package/doc/progress/hook-extraction-audit.md +195 -195
- package/doc/progress/public-surface-normalization.md +351 -351
- package/doc/progress/qa-stand-walkthrough-2026-07-12.md +62 -0
- package/doc/progress/stand-as-examples-audit.md +20 -20
- package/doc/progress/style-system-normalization.md +121 -121
- package/doc/target/README.md +32 -32
- package/doc/target/my.md +134 -124
- package/doc/wenay-react2-rare.md +807 -807
- package/doc/wenay-react2.md +543 -541
- package/lib/common/demo/fakeRtcLoopback.d.ts +17 -0
- package/lib/common/demo/fakeRtcLoopback.js +108 -0
- package/lib/common/demo/peerConference.d.ts +449 -0
- package/lib/common/demo/peerConference.js +372 -0
- package/lib/common/demo/peerMedia.js +6 -1
- package/lib/common/src/hooks/index.d.ts +1 -0
- package/lib/common/src/hooks/index.js +1 -0
- package/lib/common/src/hooks/useRoute.d.ts +28 -0
- package/lib/common/src/hooks/useRoute.js +30 -0
- package/lib/common/src/logs/logsController.js +2 -2
- package/lib/common/testUseReact/qa.js +4 -3
- package/lib/style/menuRight.css +19 -19
- package/lib/style/style.css +23 -23
- package/lib/style/tokens.css +184 -184
- package/package.json +2 -1
- package/doc/wenay-react2-1.0.8.tgz +0 -0
|
@@ -1,405 +1,405 @@
|
|
|
1
|
-
# wenay-react2 Project Functionality
|
|
2
|
-
|
|
3
|
-
This document describes what this project provides and why each area exists.
|
|
4
|
-
It is not a README and not a full API reference.
|
|
5
|
-
|
|
6
|
-
Read this together with:
|
|
7
|
-
|
|
8
|
-
- `doc/wenay-react2.md` for everyday signatures.
|
|
9
|
-
- `doc/wenay-react2-rare.md` for low-level details and edge cases.
|
|
10
|
-
- `doc/EXAMPLE_USAGE.md` for usage standards and examples.
|
|
11
|
-
- `src/common/testUseReact/qa.tsx` for the live QA stand.
|
|
12
|
-
|
|
13
|
-
## Project Role
|
|
14
|
-
|
|
15
|
-
`wenay-react2` is a shared React UI/controller package for wenay apps.
|
|
16
|
-
Its main job is to package recurring UI infrastructure so products do not keep
|
|
17
|
-
rebuilding table buffers, floating windows, context menus, settings editors,
|
|
18
|
-
toolbar persistence, React subscriptions, and replay/store adapters.
|
|
19
|
-
|
|
20
|
-
The package should stay generic. It may know lifecycle, rendering,
|
|
21
|
-
persistence mechanics, and UI contracts. It must not know product business
|
|
22
|
-
terms such as exchange names, portfolio rules, strategy policy, domain column
|
|
23
|
-
groups, account behavior, or screen-specific layout decisions.
|
|
24
|
-
|
|
25
|
-
## Core Design Contract
|
|
26
|
-
|
|
27
|
-
New shared functionality should follow these rules:
|
|
28
|
-
|
|
29
|
-
- A primitive owns one generic problem.
|
|
30
|
-
- App policy belongs in an app wrapper above the primitive.
|
|
31
|
-
- Shared behavior starts as a headless hook/controller whenever it has lifecycle, state, persistence, subscription, selection, or user interaction rules.
|
|
32
|
-
- React hooks own subscription/lifecycle wiring and may return a small API, not only plain X/Y data.
|
|
33
|
-
- Controllers expose a small imperative API when state must outlive a render.
|
|
34
|
-
- Serializable UI config is stored through `memoryGetOrCreate` and announced
|
|
35
|
-
through `memoryCache`, but the app decides when to write storage.
|
|
36
|
-
- Visual components and QA stand layers should be thin renderers over the hook/controller surface.
|
|
37
|
-
- Demos should prove the primitive's contract, not hide product policy inside
|
|
38
|
-
the library.
|
|
39
|
-
|
|
40
|
-
Canonical controller vocabulary:
|
|
41
|
-
|
|
42
|
-
```ts
|
|
43
|
-
open / close / set / replace // modal-like state
|
|
44
|
-
update / remove / clean / sync // buffered data state
|
|
45
|
-
fit / flush // ag-grid lifecycle
|
|
46
|
-
props / bind // spreadable DOM props
|
|
47
|
-
get / set / reset / cancel // local controller state
|
|
48
|
-
on -> off // subscriptions
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Public Entry
|
|
52
|
-
|
|
53
|
-
Consumers import from the package root:
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
import { createToolbar, useAgGrid, createColumnState } from "wenay-react2"
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
`src/common/api.tsx` is the root export aggregator. It also exports `kit` for
|
|
60
|
-
large files that prefer grouped namespaces:
|
|
61
|
-
|
|
62
|
-
```ts
|
|
63
|
-
import { kit } from "wenay-react2"
|
|
64
|
-
|
|
65
|
-
kit.grid
|
|
66
|
-
kit.modal
|
|
67
|
-
kit.menu
|
|
68
|
-
kit.logs
|
|
69
|
-
kit.updateBy
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Compatibility Policy
|
|
73
|
-
|
|
74
|
-
New hook/controller surfaces should prefer migration without breaking old public APIs, but compatibility is not absolute. An aggressive migration is allowed only as an explicit migration cut: separate task, changelog, migration notes, and a clear list of changed imports/behavior. Default visual styles have a stricter rule: do not remove a default class/style contract unless the replacement class/token path already exists and is documented.
|
|
75
|
-
|
|
76
|
-
For diagnostics, the library may expose local counters/listeners, but it must not send hidden analytics. Apps decide whether to read, persist, or report those counters.
|
|
77
|
-
|
|
78
|
-
## Functional Areas
|
|
79
|
-
|
|
80
|
-
### Render Memory
|
|
81
|
-
|
|
82
|
-
Purpose: bridge external mutable objects into React renders.
|
|
83
|
-
|
|
84
|
-
Main APIs:
|
|
85
|
-
|
|
86
|
-
- `updateBy`, `useUpdateBy`, `renderBy`, `renderByRevers`, `renderByLast`
|
|
87
|
-
- `createUpdateApi`, `useUpdateByApi`
|
|
88
|
-
- `memoryGetOrCreate`, `memoryUpdate`, `memoryMarkDirty`, `memoryCache`
|
|
89
|
-
|
|
90
|
-
Use this when a module-level controller or persisted config needs React views
|
|
91
|
-
to refresh without moving all state into component-local `useState`.
|
|
92
|
-
|
|
93
|
-
Do not use this as a default replacement for normal React state. If a state is
|
|
94
|
-
local to one component and has no external lifecycle, `useState` is simpler.
|
|
95
|
-
|
|
96
|
-
### Persistence And Memory Cache
|
|
97
|
-
|
|
98
|
-
Purpose: centralize process/browser memory maps used by shared UI surfaces.
|
|
99
|
-
|
|
100
|
-
Shared primitives can mark config as dirty. They do not choose a write policy.
|
|
101
|
-
The application should call `memoryCache.load()` on startup and decide whether
|
|
102
|
-
to save on debounce, route leave, visibility change, pagehide, or explicit user
|
|
103
|
-
action.
|
|
104
|
-
|
|
105
|
-
This matters because toolbar layout, UI slot placement, column state, floating
|
|
106
|
-
window geometry, and resize maps are all user-facing preferences. The library
|
|
107
|
-
should not silently write storage at surprising times.
|
|
108
|
-
|
|
109
|
-
### Outside Click, Buttons, And Floating UI
|
|
110
|
-
|
|
111
|
-
Purpose: reusable interaction wrappers for menus, popups, and floating panels.
|
|
112
|
-
|
|
113
|
-
Main APIs:
|
|
114
|
-
|
|
115
|
-
- `useOutside`, `OutsideClickArea`
|
|
116
|
-
- `Button`, `OutsideButton`, `HoverButton`, `AbsoluteButton`
|
|
117
|
-
- `FloatingWindow`, `useFloatingWindowController`
|
|
118
|
-
- `useDraggableApi`, `useReorder`, `useReorderBoard`
|
|
119
|
-
|
|
120
|
-
Use these when the UI problem is generic: outside-click closing, draggable
|
|
121
|
-
position, ordered drag-and-drop, or a persistent floating window. Use `useFloatingWindowController` only for custom chrome around the same geometry/stack/resize behavior.
|
|
122
|
-
|
|
123
|
-
Do not hide business flow inside these components. For example, a trade ticket
|
|
124
|
-
window is an app component that may use `FloatingWindow`, not a library
|
|
125
|
-
primitive.
|
|
126
|
-
|
|
127
|
-
### Modal And Input Helpers
|
|
128
|
-
|
|
129
|
-
Purpose: common modal lifecycle and simple text/file input flows.
|
|
130
|
-
|
|
131
|
-
Main APIs:
|
|
132
|
-
|
|
133
|
-
- `ModalProvider`, `useModal`
|
|
134
|
-
- `FreeModal`, `TextInputModal`, `FileInputModal`
|
|
135
|
-
- `inputModal`, `confirmModal` for low-level compatibility paths
|
|
136
|
-
|
|
137
|
-
Use `ModalProvider` + `useModal` for new code. Low-level JSX stores exist for
|
|
138
|
-
compatibility and rare cases.
|
|
139
|
-
|
|
140
|
-
### Settings Dialog, UI Slot, And Toolbar
|
|
141
|
-
|
|
142
|
-
Purpose: configurable product chrome without each app inventing its own
|
|
143
|
-
settings registry, placement switcher, and toolbar editor.
|
|
144
|
-
|
|
145
|
-
Main APIs:
|
|
146
|
-
|
|
147
|
-
- `SettingsDialog`, `useSettingsDialogController`, `registerSettingsSection`
|
|
148
|
-
- `createUiSlot`
|
|
149
|
-
- `createToolbar`, `registerToolbarDensity`, `toolbarItemIcon`
|
|
150
|
-
|
|
151
|
-
Use `SettingsDialog` when the app has multiple settings sections or needs a
|
|
152
|
-
searchable settings tree. Use `useSettingsDialogController` when custom settings
|
|
153
|
-
chrome needs the same open/search/tree/history/resize behavior.
|
|
154
|
-
|
|
155
|
-
Use `createUiSlot` when the same UI fragment may live in several places and
|
|
156
|
-
the user can choose the placement.
|
|
157
|
-
|
|
158
|
-
Use `createToolbar` when a command strip needs:
|
|
159
|
-
|
|
160
|
-
- persistent item order and visibility;
|
|
161
|
-
- density modes such as icon-only or icon+label;
|
|
162
|
-
- a reusable settings editor;
|
|
163
|
-
- optional source-owned order/visibility via `UiListSource`.
|
|
164
|
-
|
|
165
|
-
`createToolbar({source})` is important: it lets the toolbar become a view over
|
|
166
|
-
another config. The main example is `columnState.api.listSource`, where grid,
|
|
167
|
-
column menu, and toolbar should all mirror one column order/visibility source.
|
|
168
|
-
|
|
169
|
-
### Menus
|
|
170
|
-
|
|
171
|
-
Purpose: generic menu rendering and context-menu coordination.
|
|
172
|
-
|
|
173
|
-
Main APIs:
|
|
174
|
-
|
|
175
|
-
- `Menu`
|
|
176
|
-
- `contextMenu.Layer`
|
|
177
|
-
- `contextMenu.openAt(event, items)`
|
|
178
|
-
- `DropdownMenu`
|
|
179
|
-
- `useRightMenuController`
|
|
180
|
-
|
|
181
|
-
Use `contextMenu.openAt(e, items)` for new right-click integrations. It opens
|
|
182
|
-
one current menu from a concrete event/point. Older queued/global paths remain
|
|
183
|
-
for compatibility through `1.x` but should not be taught in new examples.
|
|
184
|
-
|
|
185
|
-
`DropdownMenu` is a floating action menu with caller-owned trigger/content
|
|
186
|
-
styling. It is not the main right-click primitive. `useRightMenuController`
|
|
187
|
-
keeps open/fixed/select/submenu/drag state reusable for custom floating-menu views.
|
|
188
|
-
|
|
189
|
-
Menu diagnostics should start from the right-click surface: count `openAt` vs legacy queued opens, sources/layers, close reasons, item clicks by explicit stable keys, submenu opens, and async menu errors. These counters should be local/opt-in, not hidden analytics.
|
|
190
|
-
|
|
191
|
-
### agGrid4
|
|
192
|
-
|
|
193
|
-
Purpose: shared ag-grid lifecycle, row buffering, dynamic columns, and common
|
|
194
|
-
grid defaults.
|
|
195
|
-
|
|
196
|
-
Main APIs:
|
|
197
|
-
|
|
198
|
-
- `createGridBuffer`
|
|
199
|
-
- `useAgGrid`
|
|
200
|
-
- `AgGridTable`
|
|
201
|
-
- `createColumnBuffer`
|
|
202
|
-
- `useAgGridTheme`, `buildAgTheme`
|
|
203
|
-
- `numericComparator`, `colDefCentered`, `colDefWrap`
|
|
204
|
-
|
|
205
|
-
Use plain `AgGridTable` for declarative `rowData`.
|
|
206
|
-
|
|
207
|
-
Use `useAgGrid` or `createGridBuffer` when row updates arrive as patches,
|
|
208
|
-
streams, or imperative transactions.
|
|
209
|
-
|
|
210
|
-
Use overlay mode when React-owned `rowData` owns the row set and external
|
|
211
|
-
patches should update only already-present rows.
|
|
212
|
-
|
|
213
|
-
Use `createColumnBuffer` for generic dynamic column-name lifecycle. The shared
|
|
214
|
-
buffer stores names and replays them; the app wrapper decides target group,
|
|
215
|
-
column shape, `colId`, labels, and domain rules.
|
|
216
|
-
|
|
217
|
-
Low-level `applyGridRows` exists, but it is not the preferred path for new
|
|
218
|
-
React examples. Prefer the controller path because it owns attach/detach/sync
|
|
219
|
-
and reduces race conditions around grid readiness.
|
|
220
|
-
|
|
221
|
-
### Column State
|
|
222
|
-
|
|
223
|
-
Purpose: one persisted column config that can drive desktop grids, icon menus,
|
|
224
|
-
toolbars, and mobile card views.
|
|
225
|
-
|
|
226
|
-
Main APIs:
|
|
227
|
-
|
|
228
|
-
- `createColumnGrid`, `useColumnGrid`
|
|
229
|
-
- `createColumnState`
|
|
230
|
-
- `ColumnsMenu`, `MenuStrip`
|
|
231
|
-
- `ColumnDots`
|
|
232
|
-
- `CardList`
|
|
233
|
-
- `columnState.grid.attach(api)` and `detach()`
|
|
234
|
-
- `columnState.api.listSource`
|
|
235
|
-
|
|
236
|
-
Use `createColumnGrid` by default when a normal ag-grid table should get the standard dots overlay, menu, toolbar settings, cards, and table/card `View` without custom wiring. It accepts default `data`/`getId`, and can optionally fit columns when the visible column count changes. Use raw `createColumnState` when the product needs custom grouped modes, runtime presence gates, or a bespoke toolbar skin.
|
|
237
|
-
|
|
238
|
-
Use this area when the user can change column order, visibility, width, sort,
|
|
239
|
-
filter, or mobile field selection.
|
|
240
|
-
|
|
241
|
-
Key idea: column config is independent from ag-grid. ag-grid is one adapter
|
|
242
|
-
over it. Mobile cards and toolbar buttons read the same config without needing
|
|
243
|
-
ag-grid at all.
|
|
244
|
-
|
|
245
|
-
Runtime presence (`setPresent`, `setPresentGate`) is not persisted. It is for
|
|
246
|
-
modes where some stable schema columns are currently unavailable.
|
|
247
|
-
|
|
248
|
-
### Observe React Adapter
|
|
249
|
-
|
|
250
|
-
Purpose: React hooks around `wenay-common2` Observe stores and listen objects.
|
|
251
|
-
|
|
252
|
-
Main APIs:
|
|
253
|
-
|
|
254
|
-
- `useStoreNode`, `useStoreKeys`, `useStoreSelect`
|
|
255
|
-
- `useStoreMirror`
|
|
256
|
-
- `useStoreEach`
|
|
257
|
-
- `useListenEffect`, `useListenValue`, `useListenArgs`
|
|
258
|
-
|
|
259
|
-
Use these when React needs to subscribe to external stores or listens. Network
|
|
260
|
-
sync stays explicit through `useStoreMirror`; merely reading a node should not
|
|
261
|
-
start hidden transport work.
|
|
262
|
-
|
|
263
|
-
### Replay React Adapter
|
|
264
|
-
|
|
265
|
-
Purpose: React-side lifecycle over `wenay-common2` Replay lines, store replay,
|
|
266
|
-
route hand-off, pull frames, and archive playback.
|
|
267
|
-
|
|
268
|
-
Main APIs:
|
|
269
|
-
|
|
270
|
-
- `useReplaySubscribe`
|
|
271
|
-
- `useReplayRouteSubscribe`
|
|
272
|
-
- `useStoreReplaySync`, `useStoreReplayMirror`
|
|
273
|
-
- `useStoreReplayRouteSync`, `useStoreReplayRouteMirror`
|
|
274
|
-
- `useStoreReplayEach`
|
|
275
|
-
- `useReplayFrame`
|
|
276
|
-
- `useReplayHistory`
|
|
277
|
-
|
|
278
|
-
Use these for high-frequency event lines, state sync from a replay source, and
|
|
279
|
-
route hand-off between relay/direct transports.
|
|
280
|
-
|
|
281
|
-
Avoid storing every frame in React state. High-frequency lines should fold into
|
|
282
|
-
canvas, refs, external stores, or grid controllers. The controller exposes
|
|
283
|
-
`seq()` and related getters so consumers can observe position without
|
|
284
|
-
rerendering on every event.
|
|
285
|
-
|
|
286
|
-
### Logs
|
|
287
|
-
|
|
288
|
-
Purpose: shared logging UI and notification/table chrome.
|
|
289
|
-
|
|
290
|
-
Main APIs:
|
|
291
|
-
|
|
292
|
-
- `logsApi`
|
|
293
|
-
- `getLogsApi`
|
|
294
|
-
- `createLogsController`
|
|
295
|
-
- `logsApi.React.Message`, `PageLogs`, `Setting`
|
|
296
|
-
- context logger hooks/components in the rare surface (`useLogsTableController`, `useLogsNotificationsController`)
|
|
297
|
-
|
|
298
|
-
Use `logsApi` for quick global logging. Use `createLogsController` when an app needs headless append/limit/settings state without the shared UI. Use context logger components when an app needs a larger logger surface.
|
|
299
|
-
|
|
300
|
-
### Params
|
|
301
|
-
|
|
302
|
-
Purpose: editable parameter UIs over `wenay-common2` Params structures and
|
|
303
|
-
simple row/section editors.
|
|
304
|
-
|
|
305
|
-
Main APIs:
|
|
306
|
-
|
|
307
|
-
- `ParamsEditor`
|
|
308
|
-
- `useParamsEditorController`
|
|
309
|
-
- `ParamsEdit`
|
|
310
|
-
- `ParamRow`
|
|
1
|
+
# wenay-react2 Project Functionality
|
|
2
|
+
|
|
3
|
+
This document describes what this project provides and why each area exists.
|
|
4
|
+
It is not a README and not a full API reference.
|
|
5
|
+
|
|
6
|
+
Read this together with:
|
|
7
|
+
|
|
8
|
+
- `doc/wenay-react2.md` for everyday signatures.
|
|
9
|
+
- `doc/wenay-react2-rare.md` for low-level details and edge cases.
|
|
10
|
+
- `doc/EXAMPLE_USAGE.md` for usage standards and examples.
|
|
11
|
+
- `src/common/testUseReact/qa.tsx` for the live QA stand.
|
|
12
|
+
|
|
13
|
+
## Project Role
|
|
14
|
+
|
|
15
|
+
`wenay-react2` is a shared React UI/controller package for wenay apps.
|
|
16
|
+
Its main job is to package recurring UI infrastructure so products do not keep
|
|
17
|
+
rebuilding table buffers, floating windows, context menus, settings editors,
|
|
18
|
+
toolbar persistence, React subscriptions, and replay/store adapters.
|
|
19
|
+
|
|
20
|
+
The package should stay generic. It may know lifecycle, rendering,
|
|
21
|
+
persistence mechanics, and UI contracts. It must not know product business
|
|
22
|
+
terms such as exchange names, portfolio rules, strategy policy, domain column
|
|
23
|
+
groups, account behavior, or screen-specific layout decisions.
|
|
24
|
+
|
|
25
|
+
## Core Design Contract
|
|
26
|
+
|
|
27
|
+
New shared functionality should follow these rules:
|
|
28
|
+
|
|
29
|
+
- A primitive owns one generic problem.
|
|
30
|
+
- App policy belongs in an app wrapper above the primitive.
|
|
31
|
+
- Shared behavior starts as a headless hook/controller whenever it has lifecycle, state, persistence, subscription, selection, or user interaction rules.
|
|
32
|
+
- React hooks own subscription/lifecycle wiring and may return a small API, not only plain X/Y data.
|
|
33
|
+
- Controllers expose a small imperative API when state must outlive a render.
|
|
34
|
+
- Serializable UI config is stored through `memoryGetOrCreate` and announced
|
|
35
|
+
through `memoryCache`, but the app decides when to write storage.
|
|
36
|
+
- Visual components and QA stand layers should be thin renderers over the hook/controller surface.
|
|
37
|
+
- Demos should prove the primitive's contract, not hide product policy inside
|
|
38
|
+
the library.
|
|
39
|
+
|
|
40
|
+
Canonical controller vocabulary:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
open / close / set / replace // modal-like state
|
|
44
|
+
update / remove / clean / sync // buffered data state
|
|
45
|
+
fit / flush // ag-grid lifecycle
|
|
46
|
+
props / bind // spreadable DOM props
|
|
47
|
+
get / set / reset / cancel // local controller state
|
|
48
|
+
on -> off // subscriptions
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Public Entry
|
|
52
|
+
|
|
53
|
+
Consumers import from the package root:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { createToolbar, useAgGrid, createColumnState } from "wenay-react2"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`src/common/api.tsx` is the root export aggregator. It also exports `kit` for
|
|
60
|
+
large files that prefer grouped namespaces:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { kit } from "wenay-react2"
|
|
64
|
+
|
|
65
|
+
kit.grid
|
|
66
|
+
kit.modal
|
|
67
|
+
kit.menu
|
|
68
|
+
kit.logs
|
|
69
|
+
kit.updateBy
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Compatibility Policy
|
|
73
|
+
|
|
74
|
+
New hook/controller surfaces should prefer migration without breaking old public APIs, but compatibility is not absolute. An aggressive migration is allowed only as an explicit migration cut: separate task, changelog, migration notes, and a clear list of changed imports/behavior. Default visual styles have a stricter rule: do not remove a default class/style contract unless the replacement class/token path already exists and is documented.
|
|
75
|
+
|
|
76
|
+
For diagnostics, the library may expose local counters/listeners, but it must not send hidden analytics. Apps decide whether to read, persist, or report those counters.
|
|
77
|
+
|
|
78
|
+
## Functional Areas
|
|
79
|
+
|
|
80
|
+
### Render Memory
|
|
81
|
+
|
|
82
|
+
Purpose: bridge external mutable objects into React renders.
|
|
83
|
+
|
|
84
|
+
Main APIs:
|
|
85
|
+
|
|
86
|
+
- `updateBy`, `useUpdateBy`, `renderBy`, `renderByRevers`, `renderByLast`
|
|
87
|
+
- `createUpdateApi`, `useUpdateByApi`
|
|
88
|
+
- `memoryGetOrCreate`, `memoryUpdate`, `memoryMarkDirty`, `memoryCache`
|
|
89
|
+
|
|
90
|
+
Use this when a module-level controller or persisted config needs React views
|
|
91
|
+
to refresh without moving all state into component-local `useState`.
|
|
92
|
+
|
|
93
|
+
Do not use this as a default replacement for normal React state. If a state is
|
|
94
|
+
local to one component and has no external lifecycle, `useState` is simpler.
|
|
95
|
+
|
|
96
|
+
### Persistence And Memory Cache
|
|
97
|
+
|
|
98
|
+
Purpose: centralize process/browser memory maps used by shared UI surfaces.
|
|
99
|
+
|
|
100
|
+
Shared primitives can mark config as dirty. They do not choose a write policy.
|
|
101
|
+
The application should call `memoryCache.load()` on startup and decide whether
|
|
102
|
+
to save on debounce, route leave, visibility change, pagehide, or explicit user
|
|
103
|
+
action.
|
|
104
|
+
|
|
105
|
+
This matters because toolbar layout, UI slot placement, column state, floating
|
|
106
|
+
window geometry, and resize maps are all user-facing preferences. The library
|
|
107
|
+
should not silently write storage at surprising times.
|
|
108
|
+
|
|
109
|
+
### Outside Click, Buttons, And Floating UI
|
|
110
|
+
|
|
111
|
+
Purpose: reusable interaction wrappers for menus, popups, and floating panels.
|
|
112
|
+
|
|
113
|
+
Main APIs:
|
|
114
|
+
|
|
115
|
+
- `useOutside`, `OutsideClickArea`
|
|
116
|
+
- `Button`, `OutsideButton`, `HoverButton`, `AbsoluteButton`
|
|
117
|
+
- `FloatingWindow`, `useFloatingWindowController`
|
|
118
|
+
- `useDraggableApi`, `useReorder`, `useReorderBoard`
|
|
119
|
+
|
|
120
|
+
Use these when the UI problem is generic: outside-click closing, draggable
|
|
121
|
+
position, ordered drag-and-drop, or a persistent floating window. Use `useFloatingWindowController` only for custom chrome around the same geometry/stack/resize behavior.
|
|
122
|
+
|
|
123
|
+
Do not hide business flow inside these components. For example, a trade ticket
|
|
124
|
+
window is an app component that may use `FloatingWindow`, not a library
|
|
125
|
+
primitive.
|
|
126
|
+
|
|
127
|
+
### Modal And Input Helpers
|
|
128
|
+
|
|
129
|
+
Purpose: common modal lifecycle and simple text/file input flows.
|
|
130
|
+
|
|
131
|
+
Main APIs:
|
|
132
|
+
|
|
133
|
+
- `ModalProvider`, `useModal`
|
|
134
|
+
- `FreeModal`, `TextInputModal`, `FileInputModal`
|
|
135
|
+
- `inputModal`, `confirmModal` for low-level compatibility paths
|
|
136
|
+
|
|
137
|
+
Use `ModalProvider` + `useModal` for new code. Low-level JSX stores exist for
|
|
138
|
+
compatibility and rare cases.
|
|
139
|
+
|
|
140
|
+
### Settings Dialog, UI Slot, And Toolbar
|
|
141
|
+
|
|
142
|
+
Purpose: configurable product chrome without each app inventing its own
|
|
143
|
+
settings registry, placement switcher, and toolbar editor.
|
|
144
|
+
|
|
145
|
+
Main APIs:
|
|
146
|
+
|
|
147
|
+
- `SettingsDialog`, `useSettingsDialogController`, `registerSettingsSection`
|
|
148
|
+
- `createUiSlot`
|
|
149
|
+
- `createToolbar`, `registerToolbarDensity`, `toolbarItemIcon`
|
|
150
|
+
|
|
151
|
+
Use `SettingsDialog` when the app has multiple settings sections or needs a
|
|
152
|
+
searchable settings tree. Use `useSettingsDialogController` when custom settings
|
|
153
|
+
chrome needs the same open/search/tree/history/resize behavior.
|
|
154
|
+
|
|
155
|
+
Use `createUiSlot` when the same UI fragment may live in several places and
|
|
156
|
+
the user can choose the placement.
|
|
157
|
+
|
|
158
|
+
Use `createToolbar` when a command strip needs:
|
|
159
|
+
|
|
160
|
+
- persistent item order and visibility;
|
|
161
|
+
- density modes such as icon-only or icon+label;
|
|
162
|
+
- a reusable settings editor;
|
|
163
|
+
- optional source-owned order/visibility via `UiListSource`.
|
|
164
|
+
|
|
165
|
+
`createToolbar({source})` is important: it lets the toolbar become a view over
|
|
166
|
+
another config. The main example is `columnState.api.listSource`, where grid,
|
|
167
|
+
column menu, and toolbar should all mirror one column order/visibility source.
|
|
168
|
+
|
|
169
|
+
### Menus
|
|
170
|
+
|
|
171
|
+
Purpose: generic menu rendering and context-menu coordination.
|
|
172
|
+
|
|
173
|
+
Main APIs:
|
|
174
|
+
|
|
175
|
+
- `Menu`
|
|
176
|
+
- `contextMenu.Layer`
|
|
177
|
+
- `contextMenu.openAt(event, items)`
|
|
178
|
+
- `DropdownMenu`
|
|
179
|
+
- `useRightMenuController`
|
|
180
|
+
|
|
181
|
+
Use `contextMenu.openAt(e, items)` for new right-click integrations. It opens
|
|
182
|
+
one current menu from a concrete event/point. Older queued/global paths remain
|
|
183
|
+
for compatibility through `1.x` but should not be taught in new examples.
|
|
184
|
+
|
|
185
|
+
`DropdownMenu` is a floating action menu with caller-owned trigger/content
|
|
186
|
+
styling. It is not the main right-click primitive. `useRightMenuController`
|
|
187
|
+
keeps open/fixed/select/submenu/drag state reusable for custom floating-menu views.
|
|
188
|
+
|
|
189
|
+
Menu diagnostics should start from the right-click surface: count `openAt` vs legacy queued opens, sources/layers, close reasons, item clicks by explicit stable keys, submenu opens, and async menu errors. These counters should be local/opt-in, not hidden analytics.
|
|
190
|
+
|
|
191
|
+
### agGrid4
|
|
192
|
+
|
|
193
|
+
Purpose: shared ag-grid lifecycle, row buffering, dynamic columns, and common
|
|
194
|
+
grid defaults.
|
|
195
|
+
|
|
196
|
+
Main APIs:
|
|
197
|
+
|
|
198
|
+
- `createGridBuffer`
|
|
199
|
+
- `useAgGrid`
|
|
200
|
+
- `AgGridTable`
|
|
201
|
+
- `createColumnBuffer`
|
|
202
|
+
- `useAgGridTheme`, `buildAgTheme`
|
|
203
|
+
- `numericComparator`, `colDefCentered`, `colDefWrap`
|
|
204
|
+
|
|
205
|
+
Use plain `AgGridTable` for declarative `rowData`.
|
|
206
|
+
|
|
207
|
+
Use `useAgGrid` or `createGridBuffer` when row updates arrive as patches,
|
|
208
|
+
streams, or imperative transactions.
|
|
209
|
+
|
|
210
|
+
Use overlay mode when React-owned `rowData` owns the row set and external
|
|
211
|
+
patches should update only already-present rows.
|
|
212
|
+
|
|
213
|
+
Use `createColumnBuffer` for generic dynamic column-name lifecycle. The shared
|
|
214
|
+
buffer stores names and replays them; the app wrapper decides target group,
|
|
215
|
+
column shape, `colId`, labels, and domain rules.
|
|
216
|
+
|
|
217
|
+
Low-level `applyGridRows` exists, but it is not the preferred path for new
|
|
218
|
+
React examples. Prefer the controller path because it owns attach/detach/sync
|
|
219
|
+
and reduces race conditions around grid readiness.
|
|
220
|
+
|
|
221
|
+
### Column State
|
|
222
|
+
|
|
223
|
+
Purpose: one persisted column config that can drive desktop grids, icon menus,
|
|
224
|
+
toolbars, and mobile card views.
|
|
225
|
+
|
|
226
|
+
Main APIs:
|
|
227
|
+
|
|
228
|
+
- `createColumnGrid`, `useColumnGrid`
|
|
229
|
+
- `createColumnState`
|
|
230
|
+
- `ColumnsMenu`, `MenuStrip`
|
|
231
|
+
- `ColumnDots`
|
|
232
|
+
- `CardList`
|
|
233
|
+
- `columnState.grid.attach(api)` and `detach()`
|
|
234
|
+
- `columnState.api.listSource`
|
|
235
|
+
|
|
236
|
+
Use `createColumnGrid` by default when a normal ag-grid table should get the standard dots overlay, menu, toolbar settings, cards, and table/card `View` without custom wiring. It accepts default `data`/`getId`, and can optionally fit columns when the visible column count changes. Use raw `createColumnState` when the product needs custom grouped modes, runtime presence gates, or a bespoke toolbar skin.
|
|
237
|
+
|
|
238
|
+
Use this area when the user can change column order, visibility, width, sort,
|
|
239
|
+
filter, or mobile field selection.
|
|
240
|
+
|
|
241
|
+
Key idea: column config is independent from ag-grid. ag-grid is one adapter
|
|
242
|
+
over it. Mobile cards and toolbar buttons read the same config without needing
|
|
243
|
+
ag-grid at all.
|
|
244
|
+
|
|
245
|
+
Runtime presence (`setPresent`, `setPresentGate`) is not persisted. It is for
|
|
246
|
+
modes where some stable schema columns are currently unavailable.
|
|
247
|
+
|
|
248
|
+
### Observe React Adapter
|
|
249
|
+
|
|
250
|
+
Purpose: React hooks around `wenay-common2` Observe stores and listen objects.
|
|
251
|
+
|
|
252
|
+
Main APIs:
|
|
253
|
+
|
|
254
|
+
- `useStoreNode`, `useStoreKeys`, `useStoreSelect`
|
|
255
|
+
- `useStoreMirror`
|
|
256
|
+
- `useStoreEach`
|
|
257
|
+
- `useListenEffect`, `useListenValue`, `useListenArgs`
|
|
258
|
+
|
|
259
|
+
Use these when React needs to subscribe to external stores or listens. Network
|
|
260
|
+
sync stays explicit through `useStoreMirror`; merely reading a node should not
|
|
261
|
+
start hidden transport work.
|
|
262
|
+
|
|
263
|
+
### Replay React Adapter
|
|
264
|
+
|
|
265
|
+
Purpose: React-side lifecycle over `wenay-common2` Replay lines, store replay,
|
|
266
|
+
route hand-off, pull frames, and archive playback.
|
|
267
|
+
|
|
268
|
+
Main APIs:
|
|
269
|
+
|
|
270
|
+
- `useReplaySubscribe`
|
|
271
|
+
- `useReplayRouteSubscribe`
|
|
272
|
+
- `useStoreReplaySync`, `useStoreReplayMirror`
|
|
273
|
+
- `useStoreReplayRouteSync`, `useStoreReplayRouteMirror`
|
|
274
|
+
- `useStoreReplayEach`
|
|
275
|
+
- `useReplayFrame`
|
|
276
|
+
- `useReplayHistory`
|
|
277
|
+
|
|
278
|
+
Use these for high-frequency event lines, state sync from a replay source, and
|
|
279
|
+
route hand-off between relay/direct transports.
|
|
280
|
+
|
|
281
|
+
Avoid storing every frame in React state. High-frequency lines should fold into
|
|
282
|
+
canvas, refs, external stores, or grid controllers. The controller exposes
|
|
283
|
+
`seq()` and related getters so consumers can observe position without
|
|
284
|
+
rerendering on every event.
|
|
285
|
+
|
|
286
|
+
### Logs
|
|
287
|
+
|
|
288
|
+
Purpose: shared logging UI and notification/table chrome.
|
|
289
|
+
|
|
290
|
+
Main APIs:
|
|
291
|
+
|
|
292
|
+
- `logsApi`
|
|
293
|
+
- `getLogsApi`
|
|
294
|
+
- `createLogsController`
|
|
295
|
+
- `logsApi.React.Message`, `PageLogs`, `Setting`
|
|
296
|
+
- context logger hooks/components in the rare surface (`useLogsTableController`, `useLogsNotificationsController`)
|
|
297
|
+
|
|
298
|
+
Use `logsApi` for quick global logging. Use `createLogsController` when an app needs headless append/limit/settings state without the shared UI. Use context logger components when an app needs a larger logger surface.
|
|
299
|
+
|
|
300
|
+
### Params
|
|
301
|
+
|
|
302
|
+
Purpose: editable parameter UIs over `wenay-common2` Params structures and
|
|
303
|
+
simple row/section editors.
|
|
304
|
+
|
|
305
|
+
Main APIs:
|
|
306
|
+
|
|
307
|
+
- `ParamsEditor`
|
|
308
|
+
- `useParamsEditorController`
|
|
309
|
+
- `ParamsEdit`
|
|
310
|
+
- `ParamRow`
|
|
311
311
|
- `useTextInputPanel`, `useFileInputPanel`
|
|
312
|
-
- `TextInputPanel`, `FileInputPanel`
|
|
313
|
-
|
|
314
|
-
Use these for generic param editing. `useParamsEditorController` owns the draft clone,
|
|
315
|
-
immediate/delayed change notification, expand callback, and cleanup for custom renderers.
|
|
316
|
-
Product-specific validation and save policy stay in the app.
|
|
317
|
-
|
|
318
|
-
### Styles And Theme
|
|
319
|
-
|
|
320
|
-
Purpose: shared visual tokens and theme hooks for library primitives.
|
|
321
|
-
|
|
322
|
-
Main files:
|
|
323
|
-
|
|
324
|
-
- `src/style/tokens.css`
|
|
325
|
-
- `src/common/src/styles/tokens.ts`
|
|
326
|
-
- `src/style/style.css`
|
|
327
|
-
- `src/style/menuRight.css`
|
|
328
|
-
- `src/common/src/styles/styleGrid.ts`
|
|
329
|
-
- `src/common/src/grid/agGrid4/theme.ts`
|
|
330
|
-
|
|
331
|
-
New shared UI should try existing tokens first. Add tokens when the value is
|
|
332
|
-
part of a reusable primitive or expected to be themed by apps. One-off QA or
|
|
333
|
-
app styles should stay in the app/demo wrapper.
|
|
334
|
-
|
|
335
|
-
Default styles are part of the public usability contract. A primitive should remain usable after importing the package CSS; apps may override variables, but should not need to copy internal CSS just to avoid a broken surface. Runtime geometry can stay inline when it is computed from state; colors, spacing, borders, shadows, typography, and hover/active states should move to classes and CSS variables.
|
|
336
|
-
|
|
337
|
-
### Charts
|
|
338
|
-
|
|
339
|
-
Purpose: low-level chart engine and React chart demo surface.
|
|
340
|
-
|
|
341
|
-
Main APIs:
|
|
342
|
-
|
|
343
|
-
- `MyChartEngine`
|
|
344
|
-
- `createChartCanvas`
|
|
345
|
-
- chart engine internals exported through the rare surface
|
|
346
|
-
|
|
347
|
-
The chart engine is intentionally low-level. Product apps should wrap it before
|
|
348
|
-
using it as a domain chart.
|
|
349
|
-
|
|
350
|
-
## QA Stand
|
|
351
|
-
|
|
352
|
-
The live stand is `src/common/testUseReact/qa.tsx`.
|
|
353
|
-
|
|
354
|
-
Run:
|
|
355
|
-
|
|
356
|
-
```sh
|
|
357
|
-
npm run testReact
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
The stand has active cards and an archive. Use active cards as the strongest
|
|
361
|
-
signal for current behavior. Archive cards are regression checks and may show
|
|
362
|
-
older or lower-level API paths.
|
|
363
|
-
|
|
364
|
-
Important current cards:
|
|
365
|
-
|
|
366
|
-
- 23-26: Replay hooks, store sync, per-key feed, route hand-off.
|
|
367
|
-
- 28: `createColumnState` with ag-grid adapter.
|
|
368
|
-
- 29: mobile `ColumnDots` + `CardList`.
|
|
369
|
-
- 30: grouped sub-column mode above toolbar/columnState.
|
|
370
|
-
- 31: `createToolbar` over `columnState.api.listSource`.
|
|
371
|
-
- 32: `createColumnGrid` wrapper with built-in dots overlay driving table/cards.
|
|
372
|
-
|
|
373
|
-
Known audit note: archive card 5 and `src/common/testUseReact/useGrid.tsx`
|
|
374
|
-
still demonstrate direct `applyGridRows`. That is useful as a regression
|
|
375
|
-
check for the low-level helper, but new examples should teach `useAgGrid`,
|
|
376
|
-
`AgGridTable`, or `createGridBuffer` first.
|
|
377
|
-
|
|
378
|
-
## Adding A New Feature
|
|
379
|
-
|
|
380
|
-
Before adding a shared primitive:
|
|
381
|
-
|
|
382
|
-
1. Check whether an existing primitive already owns the problem.
|
|
383
|
-
2. Decide the generic boundary: what belongs in the library, what belongs in
|
|
384
|
-
the product wrapper.
|
|
385
|
-
3. Add an everyday example to `doc/wenay-react2.md` only if it is a public
|
|
386
|
-
everyday API.
|
|
312
|
+
- `TextInputPanel`, `FileInputPanel`
|
|
313
|
+
|
|
314
|
+
Use these for generic param editing. `useParamsEditorController` owns the draft clone,
|
|
315
|
+
immediate/delayed change notification, expand callback, and cleanup for custom renderers.
|
|
316
|
+
Product-specific validation and save policy stay in the app.
|
|
317
|
+
|
|
318
|
+
### Styles And Theme
|
|
319
|
+
|
|
320
|
+
Purpose: shared visual tokens and theme hooks for library primitives.
|
|
321
|
+
|
|
322
|
+
Main files:
|
|
323
|
+
|
|
324
|
+
- `src/style/tokens.css`
|
|
325
|
+
- `src/common/src/styles/tokens.ts`
|
|
326
|
+
- `src/style/style.css`
|
|
327
|
+
- `src/style/menuRight.css`
|
|
328
|
+
- `src/common/src/styles/styleGrid.ts`
|
|
329
|
+
- `src/common/src/grid/agGrid4/theme.ts`
|
|
330
|
+
|
|
331
|
+
New shared UI should try existing tokens first. Add tokens when the value is
|
|
332
|
+
part of a reusable primitive or expected to be themed by apps. One-off QA or
|
|
333
|
+
app styles should stay in the app/demo wrapper.
|
|
334
|
+
|
|
335
|
+
Default styles are part of the public usability contract. A primitive should remain usable after importing the package CSS; apps may override variables, but should not need to copy internal CSS just to avoid a broken surface. Runtime geometry can stay inline when it is computed from state; colors, spacing, borders, shadows, typography, and hover/active states should move to classes and CSS variables.
|
|
336
|
+
|
|
337
|
+
### Charts
|
|
338
|
+
|
|
339
|
+
Purpose: low-level chart engine and React chart demo surface.
|
|
340
|
+
|
|
341
|
+
Main APIs:
|
|
342
|
+
|
|
343
|
+
- `MyChartEngine`
|
|
344
|
+
- `createChartCanvas`
|
|
345
|
+
- chart engine internals exported through the rare surface
|
|
346
|
+
|
|
347
|
+
The chart engine is intentionally low-level. Product apps should wrap it before
|
|
348
|
+
using it as a domain chart.
|
|
349
|
+
|
|
350
|
+
## QA Stand
|
|
351
|
+
|
|
352
|
+
The live stand is `src/common/testUseReact/qa.tsx`.
|
|
353
|
+
|
|
354
|
+
Run:
|
|
355
|
+
|
|
356
|
+
```sh
|
|
357
|
+
npm run testReact
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
The stand has active cards and an archive. Use active cards as the strongest
|
|
361
|
+
signal for current behavior. Archive cards are regression checks and may show
|
|
362
|
+
older or lower-level API paths.
|
|
363
|
+
|
|
364
|
+
Important current cards:
|
|
365
|
+
|
|
366
|
+
- 23-26: Replay hooks, store sync, per-key feed, route hand-off.
|
|
367
|
+
- 28: `createColumnState` with ag-grid adapter.
|
|
368
|
+
- 29: mobile `ColumnDots` + `CardList`.
|
|
369
|
+
- 30: grouped sub-column mode above toolbar/columnState.
|
|
370
|
+
- 31: `createToolbar` over `columnState.api.listSource`.
|
|
371
|
+
- 32: `createColumnGrid` wrapper with built-in dots overlay driving table/cards.
|
|
372
|
+
|
|
373
|
+
Known audit note: archive card 5 and `src/common/testUseReact/useGrid.tsx`
|
|
374
|
+
still demonstrate direct `applyGridRows`. That is useful as a regression
|
|
375
|
+
check for the low-level helper, but new examples should teach `useAgGrid`,
|
|
376
|
+
`AgGridTable`, or `createGridBuffer` first.
|
|
377
|
+
|
|
378
|
+
## Adding A New Feature
|
|
379
|
+
|
|
380
|
+
Before adding a shared primitive:
|
|
381
|
+
|
|
382
|
+
1. Check whether an existing primitive already owns the problem.
|
|
383
|
+
2. Decide the generic boundary: what belongs in the library, what belongs in
|
|
384
|
+
the product wrapper.
|
|
385
|
+
3. Add an everyday example to `doc/wenay-react2.md` only if it is a public
|
|
386
|
+
everyday API.
|
|
387
387
|
4. Prefer a `use*` hook or `create*` controller as the public behavior surface; add a visual component only as a layer over it.
|
|
388
|
-
5. Add edge-case details to `doc/wenay-react2-rare.md`.
|
|
389
|
-
6. Add or update a QA stand card when behavior is visual, interactive, or hard
|
|
390
|
-
to prove through unit tests alone.
|
|
391
|
-
7. Add a changelog entry under `doc/changes/`.
|
|
392
|
-
|
|
393
|
-
## Non-Goals
|
|
394
|
-
|
|
395
|
-
`wenay-react2` should not become:
|
|
396
|
-
|
|
397
|
-
- a product shell;
|
|
398
|
-
- a business-domain library;
|
|
399
|
-
- a hidden persistence service;
|
|
400
|
-
- a transport selector;
|
|
401
|
-
- a replacement for normal React local state;
|
|
402
|
-
- a place for one-off app styling.
|
|
403
|
-
|
|
404
|
-
The package should provide strong generic tools. Apps compose those tools into
|
|
405
|
-
business behavior.
|
|
388
|
+
5. Add edge-case details to `doc/wenay-react2-rare.md`.
|
|
389
|
+
6. Add or update a QA stand card when behavior is visual, interactive, or hard
|
|
390
|
+
to prove through unit tests alone.
|
|
391
|
+
7. Add a changelog entry under `doc/changes/`.
|
|
392
|
+
|
|
393
|
+
## Non-Goals
|
|
394
|
+
|
|
395
|
+
`wenay-react2` should not become:
|
|
396
|
+
|
|
397
|
+
- a product shell;
|
|
398
|
+
- a business-domain library;
|
|
399
|
+
- a hidden persistence service;
|
|
400
|
+
- a transport selector;
|
|
401
|
+
- a replacement for normal React local state;
|
|
402
|
+
- a place for one-off app styling.
|
|
403
|
+
|
|
404
|
+
The package should provide strong generic tools. Apps compose those tools into
|
|
405
|
+
business behavior.
|