@ryuzaki13/react-foundation-lib 1.4.1 → 1.4.3

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 (73) hide show
  1. package/README.md +154 -100
  2. package/dist/chunks/{formatters-CBgrBeSA.js → formatters-D33Uh3si.js} +7 -8
  3. package/dist/chunks/{formatters-CBgrBeSA.js.map → formatters-D33Uh3si.js.map} +1 -1
  4. package/dist/chunks/odata-service-CWkHASdw.js +2211 -0
  5. package/dist/chunks/odata-service-CWkHASdw.js.map +1 -0
  6. package/dist/chunks/{validate-BW-7BZy_.js → validate-DyzojM0w.js} +2 -2
  7. package/dist/chunks/{validate-BW-7BZy_.js.map → validate-DyzojM0w.js.map} +1 -1
  8. package/dist/error-report/index.js +2 -2
  9. package/dist/excel/index.js +20 -21
  10. package/dist/excel/index.js.map +1 -1
  11. package/dist/formatters/index.js +4 -5
  12. package/dist/{odata → odata-service}/buildSeparatedArrays.d.ts +1 -1
  13. package/dist/odata-service/buildSeparatedArrays.d.ts.map +1 -0
  14. package/dist/{odata/types.d.ts → odata-service/collectionTypes.d.ts} +1 -1
  15. package/dist/odata-service/collectionTypes.d.ts.map +1 -0
  16. package/dist/{odata → odata-service}/dateUtils.d.ts +1 -1
  17. package/dist/odata-service/dateUtils.d.ts.map +1 -0
  18. package/dist/{odata → odata-service}/findCollectionPairs.d.ts +1 -1
  19. package/dist/odata-service/findCollectionPairs.d.ts.map +1 -0
  20. package/dist/odata-service/index.d.ts +5 -0
  21. package/dist/odata-service/index.d.ts.map +1 -1
  22. package/dist/odata-service/index.js +2 -2
  23. package/dist/{odata/store.d.ts → odata-service/odataCollectionStore.d.ts} +1 -1
  24. package/dist/odata-service/odataCollectionStore.d.ts.map +1 -0
  25. package/dist/query-client/index.js.map +1 -1
  26. package/dist/query-client/queryClient.d.ts +1 -3
  27. package/dist/query-client/queryClient.d.ts.map +1 -1
  28. package/package.json +1 -5
  29. package/src/bounded-copy-stack/README.mdx +257 -0
  30. package/src/context-menu/README.mdx +326 -0
  31. package/src/currency/README.mdx +155 -0
  32. package/src/date-segments/README.mdx +319 -0
  33. package/src/error/README.mdx +95 -0
  34. package/src/error-report/README.mdx +612 -0
  35. package/src/excel/README.mdx +449 -0
  36. package/src/fingerprint/README.mdx +100 -0
  37. package/src/form/README.mdx +101 -0
  38. package/src/foundationLib.mdx +70 -54
  39. package/src/hooks/README.mdx +988 -0
  40. package/src/http/README.mdx +126 -0
  41. package/src/media/README.mdx +1853 -0
  42. package/src/notifications/README.mdx +323 -0
  43. package/src/number-scale/README.mdx +318 -0
  44. package/src/odata-service/README.mdx +2916 -0
  45. package/src/presets/README.mdx +136 -0
  46. package/src/pwa/README.mdx +394 -0
  47. package/src/query-client/README.mdx +2500 -0
  48. package/src/range-output/README.mdx +161 -0
  49. package/src/seo/README.mdx +279 -0
  50. package/src/session-storage/README.mdx +125 -0
  51. package/src/string-comparison/README.mdx +96 -0
  52. package/src/table/README.mdx +3106 -0
  53. package/src/three-scene/README.mdx +248 -0
  54. package/src/types/README.mdx +172 -0
  55. package/src/utils/README.mdx +1724 -0
  56. package/src/validators/README.mdx +239 -0
  57. package/src/virtualizer/README.mdx +138 -0
  58. package/src/xml/README.mdx +149 -0
  59. package/dist/chunks/dateUtils-B5V5aXB-.js +0 -847
  60. package/dist/chunks/dateUtils-B5V5aXB-.js.map +0 -1
  61. package/dist/chunks/odata-service-B6TxBSLm.js +0 -1277
  62. package/dist/chunks/odata-service-B6TxBSLm.js.map +0 -1
  63. package/dist/odata/buildSeparatedArrays.d.ts.map +0 -1
  64. package/dist/odata/dateUtils.d.ts.map +0 -1
  65. package/dist/odata/findCollectionPairs.d.ts.map +0 -1
  66. package/dist/odata/index.d.ts +0 -6
  67. package/dist/odata/index.d.ts.map +0 -1
  68. package/dist/odata/index.js +0 -102
  69. package/dist/odata/index.js.map +0 -1
  70. package/dist/odata/store.d.ts.map +0 -1
  71. package/dist/odata/types.d.ts.map +0 -1
  72. package/src/pwa/README.md +0 -638
  73. package/src/query-client/README.md +0 -565
@@ -0,0 +1,326 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ <Meta title="Foundation Lib/Interaction/Context Menu State" />
4
+
5
+ # Состояние и anchors контекстного меню через `@ryuzaki13/react-foundation-lib/context-menu`
6
+
7
+ Модуль описывает открытое/закрытое состояние контекстного меню, источник открытия и два вида anchor: DOM element или экранная точка. Также он создаёт virtual anchor для Floating UI.
8
+
9
+ Модуль не содержит React hook и не рисует меню.
10
+
11
+ ## Содержание
12
+
13
+ - [Назначение и границы](#назначение-и-границы)
14
+ - [Установка и импорт](#установка-и-импорт)
15
+ - [Модель данных](#модель-данных)
16
+ - [Получение точки](#получение-точки)
17
+ - [`createVirtualAnchor`](#createvirtualanchor)
18
+ - [State helpers](#state-helpers)
19
+ - [React reducer recipe](#react-reducer-recipe)
20
+ - [Floating UI recipe](#floating-ui-recipe)
21
+ - [Доступность](#доступность)
22
+ - [Полный API и ошибки](#полный-api-и-ошибки)
23
+
24
+ ## Назначение и границы
25
+
26
+ ```text
27
+ click/contextmenu/keyboard
28
+ │
29
+ ├─ element anchor
30
+ └─ point {x,y}
31
+ │
32
+ ▼
33
+ MenuState
34
+ │
35
+ ▼
36
+ host React/Floating UI/menu component
37
+ ```
38
+
39
+ Модуль:
40
+
41
+ - не добавляет event listeners;
42
+ - не вызывает `preventDefault`;
43
+ - не хранит global state;
44
+ - не позиционирует floating element;
45
+ - не закрывает меню по Escape/outside click;
46
+ - не управляет focus/ARIA;
47
+ - не клонирует DOM elements.
48
+
49
+ Готовый visual primitive находится в `@ryuzaki13/react-foundation-ui/context-menu`.
50
+
51
+ ## Установка и импорт
52
+
53
+ ```ts
54
+ import {
55
+ closeMenu,
56
+ createVirtualAnchor,
57
+ getMenuPointFromEvent,
58
+ getMenuPointFromRect,
59
+ initialMenuState,
60
+ openMenu,
61
+ toggleMenu
62
+ } from "@ryuzaki13/react-foundation-lib/context-menu";
63
+
64
+ import type {
65
+ ElementMenuAnchor,
66
+ MenuAnchor,
67
+ MenuOpenSource,
68
+ MenuPoint,
69
+ MenuState,
70
+ OpenMenuPayload,
71
+ PointMenuAnchor
72
+ } from "@ryuzaki13/react-foundation-lib/context-menu";
73
+ ```
74
+
75
+ Functions pure, но types/anchors используют DOM `Element`/`HTMLElement`. Публичный subpath не импортирует Floating UI runtime.
76
+
77
+ ## Модель данных
78
+
79
+ ### Point
80
+
81
+ ```ts
82
+ interface MenuPoint {
83
+ x: number;
84
+ y: number;
85
+ }
86
+ ```
87
+
88
+ Координаты соответствуют viewport/client coordinates, а не page scroll coordinates.
89
+
90
+ ### Источник открытия
91
+
92
+ ```ts
93
+ type MenuOpenSource = "click" | "contextmenu" | "keyboard" | "programmatic";
94
+ ```
95
+
96
+ Source помогает UI выбирать focus/animation/recovery, но helpers сами не меняют поведение по source.
97
+
98
+ ### Anchors
99
+
100
+ ```ts
101
+ type ElementMenuAnchor = {
102
+ type: "element";
103
+ element: HTMLElement;
104
+ };
105
+
106
+ type PointMenuAnchor = {
107
+ type: "point";
108
+ point: MenuPoint;
109
+ contextElement?: Element | null;
110
+ };
111
+
112
+ type MenuAnchor = ElementMenuAnchor | PointMenuAnchor;
113
+ ```
114
+
115
+ `contextElement` помогает Floating UI определить document/layout context для virtual element.
116
+
117
+ ### State
118
+
119
+ ```ts
120
+ interface MenuState {
121
+ open: boolean;
122
+ source: MenuOpenSource | null;
123
+ anchor: MenuAnchor | null;
124
+ }
125
+ ```
126
+
127
+ Нормальное закрытое состояние:
128
+
129
+ ```ts
130
+ {
131
+ open: false,
132
+ source: null,
133
+ anchor: null
134
+ }
135
+ ```
136
+
137
+ ## Получение точки
138
+
139
+ ### `getMenuPointFromEvent`
140
+
141
+ ```ts
142
+ function onContextMenu(event: React.MouseEvent<HTMLElement>) {
143
+ event.preventDefault();
144
+
145
+ const point = getMenuPointFromEvent(event);
146
+ // { x: event.clientX, y: event.clientY }.
147
+ }
148
+ ```
149
+
150
+ Функции нужен только structural object с `clientX`/`clientY`, поэтому подходят native и React mouse events.
151
+
152
+ Она не вызывает `preventDefault` и не проверяет finite coordinates.
153
+
154
+ ### `getMenuPointFromRect`
155
+
156
+ Возвращает геометрический центр rect:
157
+
158
+ ```ts
159
+ const point = getMenuPointFromRect({
160
+ left: 10,
161
+ top: 20,
162
+ width: 80,
163
+ height: 40
164
+ });
165
+ // { x: 50, y: 40 }.
166
+ ```
167
+
168
+ Подходит для keyboard opening от центра `element.getBoundingClientRect()`:
169
+
170
+ ```ts
171
+ const point = getMenuPointFromRect(button.getBoundingClientRect());
172
+ ```
173
+
174
+ ## `createVirtualAnchor`
175
+
176
+ Создаёт object с `getBoundingClientRect`, представляющий точку нулевого размера:
177
+
178
+ ```ts
179
+ const virtualAnchor = createVirtualAnchor({ x: 120, y: 240 }, triggerElement);
180
+ ```
181
+
182
+ Возвращаемый rect:
183
+
184
+ ```ts
185
+ {
186
+ x: 120,
187
+ y: 240,
188
+ top: 240,
189
+ left: 120,
190
+ bottom: 240,
191
+ right: 120,
192
+ width: 0,
193
+ height: 0,
194
+ toJSON: () => undefined
195
+ }
196
+ ```
197
+
198
+ Если `contextElement` равен `null`/`undefined`, в результате поле становится `undefined`.
199
+
200
+ Point object читается при каждом `getBoundingClientRect`. Не мутируйте его; создайте новый anchor при изменении координат.
201
+
202
+ ## State helpers
203
+
204
+ ### `initialMenuState`
205
+
206
+ Экспортируется один module-level object. Рассматривайте его как readonly-константу и не мутируйте:
207
+
208
+ ```ts
209
+ const [state, setState] = useState<MenuState>(initialMenuState);
210
+ ```
211
+
212
+ ### `openMenu`
213
+
214
+ ```ts
215
+ const state = openMenu({
216
+ source: "contextmenu",
217
+ anchor: {
218
+ type: "point",
219
+ point: { x: 100, y: 200 }
220
+ }
221
+ });
222
+ ```
223
+
224
+ Всегда возвращает новый state `{ open: true, source, anchor }`. Anchor/element переносятся по ссылке.
225
+
226
+ ### `closeMenu`
227
+
228
+ ```ts
229
+ const closed = closeMenu(opened);
230
+ ```
231
+
232
+ Открытое состояние превращается в canonical closed state. Если `state.open === false` и `state.anchor === null`, возвращается исходная ссылка `state`, что удобно для reducer no-op.
233
+
234
+ Передавайте согласованное состояние. Если вручную создать `{ open:false, source:"click", anchor:null }`, `closeMenu` вернёт его без очистки source.
235
+
236
+ ### `toggleMenu`
237
+
238
+ ```ts
239
+ const next = toggleMenu(current, payload);
240
+ ```
241
+
242
+ - если `current.open === true`, закрывает меню и игнорирует payload;
243
+ - если меню закрыто, вызывает `openMenu(payload)`.
244
+
245
+ Toggle подходит для click button. Для `contextmenu` чаще нужен явный `openMenu`, чтобы повторный right-click перемещал anchor, а не закрывал меню.
246
+
247
+ ## React reducer recipe
248
+
249
+ ```tsx
250
+ const [menu, setMenu] = useState<MenuState>(initialMenuState);
251
+
252
+ function handleContextMenu(event: React.MouseEvent<HTMLElement>) {
253
+ event.preventDefault();
254
+
255
+ setMenu(
256
+ openMenu({
257
+ source: "contextmenu",
258
+ anchor: {
259
+ type: "point",
260
+ point: getMenuPointFromEvent(event),
261
+ contextElement: event.currentTarget
262
+ }
263
+ })
264
+ );
265
+ }
266
+
267
+ function handleClose() {
268
+ setMenu((current) => closeMenu(current));
269
+ }
270
+ ```
271
+
272
+ Не сохраняйте `MenuState` в JSON/localStorage: он может содержать `HTMLElement`.
273
+
274
+ ## Floating UI recipe
275
+
276
+ ```ts
277
+ const reference =
278
+ menu.anchor?.type === "element"
279
+ ? menu.anchor.element
280
+ : menu.anchor?.type === "point"
281
+ ? createVirtualAnchor(menu.anchor.point, menu.anchor.contextElement)
282
+ : null;
283
+ ```
284
+
285
+ Передайте `reference` в public API выбранного Floating UI wrapper. Не импортируйте private package files.
286
+
287
+ ## Доступность
288
+
289
+ Host обязан реализовать:
290
+
291
+ - открытие клавишей Context Menu/Shift+F10 или принятой командой;
292
+ - focus первого/выбранного item;
293
+ - Arrow/Home/End navigation;
294
+ - закрытие по Escape и возврат focus;
295
+ - `role="menu"`/`menuitem` только если semantics действительно menu;
296
+ - disabled items;
297
+ - outside click и focus dismissal;
298
+ - сохранение trigger element для keyboard recovery.
299
+
300
+ Для keyboard source element anchor обычно лучше point без pointer coordinates.
301
+
302
+ ## Полный API и ошибки
303
+
304
+ | Export | Назначение |
305
+ | ----------------------- | --------------------------- |
306
+ | `getMenuPointFromEvent` | Читает client coordinates |
307
+ | `getMenuPointFromRect` | Центр rect |
308
+ | `createVirtualAnchor` | Point-like DOMRect provider |
309
+ | `initialMenuState` | Canonical closed state |
310
+ | `openMenu` | Новый opened state |
311
+ | `closeMenu` | Закрывает/очищает state |
312
+ | `toggleMenu` | Toggle по `open` |
313
+ | `MenuPoint` | `{ x, y }` |
314
+ | `MenuOpenSource` | Источник открытия |
315
+ | `MenuAnchor` | Element/point union |
316
+ | `MenuState` | Полное state |
317
+ | `OpenMenuPayload` | `{ source, anchor }` |
318
+
319
+ Типичные ошибки:
320
+
321
+ - Использовать `pageX/pageY` вместо client coordinates.
322
+ - Вызывать toggle при каждом `contextmenu` и неожиданно закрывать открытое меню.
323
+ - Мутировать `initialMenuState`.
324
+ - Persist DOM element.
325
+ - Считать virtual anchor готовым positioner-ом.
326
+ - Не возвращать focus после keyboard menu.
@@ -0,0 +1,155 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ <Meta title="Foundation Lib/Data/Currency" />
4
+
5
+ # Валютные подписи через `@ryuzaki13/react-foundation-lib/currency`
6
+
7
+ Модуль связывает общий OData-параметр `p_curr` с отображаемой подписью показателя. Он определяет один из двух режимов валюты и добавляет соответствующий суффикс к label.
8
+
9
+ ## Содержание
10
+
11
+ - [Назначение](#назначение)
12
+ - [Установка и импорт](#установка-и-импорт)
13
+ - [`CurrencyMode`](#currencymode)
14
+ - [`resolveCurrencyModeFromODataParameters`](#resolvecurrencymodefromodataparameters)
15
+ - [`resolveCurrencyAwareLabel`](#resolvecurrencyawarelabel)
16
+ - [Готовый pipeline](#готовый-pipeline)
17
+ - [Ограничения и ошибки](#ограничения-и-ошибки)
18
+ - [API-справочник](#api-справочник)
19
+
20
+ ## Назначение
21
+
22
+ ```text
23
+ wrapped OData params
24
+ { p_curr: { value: true } }
25
+ │
26
+ ▼
27
+ CurrencyMode "rub"
28
+ │
29
+ ▼
30
+ "Выручка" + ["за тн", "руб/тн"]
31
+ │
32
+ ▼
33
+ "Выручка руб/тн"
34
+ ```
35
+
36
+ Модуль не форматирует денежное число, не конвертирует валюту и не строит OData query. Для чисел используйте `/formatters`, для OData params — `/odata-service`.
37
+
38
+ ## Установка и импорт
39
+
40
+ ```ts
41
+ import { resolveCurrencyAwareLabel, resolveCurrencyModeFromODataParameters } from "@ryuzaki13/react-foundation-lib/currency";
42
+
43
+ import type { CurrencyMode } from "@ryuzaki13/react-foundation-lib/currency";
44
+ ```
45
+
46
+ Модуль ESM, не требует React или browser API. Параметры должны иметь публичную wrapped-форму из `/odata-service`.
47
+
48
+ ## `CurrencyMode`
49
+
50
+ ```ts
51
+ type CurrencyMode = "internal" | "rub";
52
+ ```
53
+
54
+ - `internal` — внутренний режим;
55
+ - `rub` — рублёвый режим.
56
+
57
+ `null` используется resolver-функцией, когда режим определить нельзя.
58
+
59
+ ## `resolveCurrencyModeFromODataParameters`
60
+
61
+ ```ts
62
+ const mode = resolveCurrencyModeFromODataParameters(params);
63
+ ```
64
+
65
+ Функция читает только собственное поле `p_curr.value`:
66
+
67
+ | Вход | Результат |
68
+ | ------------------------------- | ------------ |
69
+ | параметров нет | `null` |
70
+ | поля `p_curr` нет | `null` |
71
+ | `{ p_curr: { value: false } }` | `"internal"` |
72
+ | `{ p_curr: { value: true } }` | `"rub"` |
73
+ | `{ p_curr: { value: "true" } }` | `null` |
74
+ | `{ p_curr: { value: 1 } }` | `null` |
75
+
76
+ Строка `"true"` намеренно не приводится к boolean. Нормализуйте внешний payload на OData boundary, а не внутри UI label.
77
+
78
+ Пример с helper `/odata-service`:
79
+
80
+ ```ts
81
+ import { wrapODataParams } from "@ryuzaki13/react-foundation-lib/odata-service";
82
+
83
+ const params = wrapODataParams({ p_curr: true });
84
+ const mode = resolveCurrencyModeFromODataParameters(params);
85
+ // "rub".
86
+ ```
87
+
88
+ ## `resolveCurrencyAwareLabel`
89
+
90
+ ```ts
91
+ const label = resolveCurrencyAwareLabel("Выручка", ["за тн", "руб/тн"], "rub");
92
+ // "Выручка руб/тн".
93
+ ```
94
+
95
+ Пара `currencyLabels` имеет фиксированный смысл:
96
+
97
+ ```ts
98
+ readonly[(internalLabel, rubLabel)];
99
+ ```
100
+
101
+ | Mode | Индекс суффикса |
102
+ | ---------- | --------------: |
103
+ | `internal` | 0 |
104
+ | `rub` | 1 |
105
+
106
+ Точные правила:
107
+
108
+ - без `currencyLabels` возвращается исходный `label`;
109
+ - при `null`/`undefined` mode возвращается исходный `label`;
110
+ - суффикс обрезается через `trim()`;
111
+ - пустой суффикс не добавляется;
112
+ - обычно между label и суффиксом добавляется один пробел;
113
+ - если обрезанный суффикс начинается с запятой, дополнительный пробел не добавляется.
114
+
115
+ ```ts
116
+ resolveCurrencyAwareLabel("Выручка", [", за тн", ", руб/тн"], "rub");
117
+ // "Выручка, руб/тн".
118
+
119
+ resolveCurrencyAwareLabel("Выручка", ["", " "], "rub");
120
+ // "Выручка".
121
+ ```
122
+
123
+ Исходный `label` не обрезается и не нормализуется.
124
+
125
+ ## Готовый pipeline
126
+
127
+ ```ts
128
+ function buildMetricLabel(
129
+ baseLabel: string,
130
+ currencyLabels: readonly [string, string] | undefined,
131
+ params: WrappedODataParameters | undefined
132
+ ) {
133
+ const mode = resolveCurrencyModeFromODataParameters(params);
134
+ return resolveCurrencyAwareLabel(baseLabel, currencyLabels, mode);
135
+ }
136
+ ```
137
+
138
+ Resolver чистый: одинаковый вход даёт одинаковую строку и не меняет params/labels.
139
+
140
+ ## Ограничения и ошибки
141
+
142
+ - Поддерживается только параметр с точным id `p_curr`.
143
+ - Поддерживаются только два режима; код валюты `USD`, `EUR` и exchange rate не обрабатываются.
144
+ - Функция не проверяет грамматику и единицы измерения.
145
+ - Запятая должна входить в сам суффикс, если нужна форма `"Выручка, руб"`.
146
+ - Не передавайте плоский `{ p_curr: true }`: ожидается `{ p_curr: { value: true } }`.
147
+ - Не используйте label helper для финансовых вычислений.
148
+
149
+ ## API-справочник
150
+
151
+ | Export | Результат |
152
+ | ---------------------------------------- | ----------------------- |
153
+ | `CurrencyMode` | `"internal" \| "rub"` |
154
+ | `resolveCurrencyModeFromODataParameters` | `CurrencyMode \| null` |
155
+ | `resolveCurrencyAwareLabel` | Итоговая display-строка |