docblocks-react-ui 0.1.0 → 0.2.0
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/CHANGELOG.md +177 -0
- package/README.md +86 -11
- package/dist/{Editor-CiJY5R4v.mjs → Editor-YAlRhGNW.mjs} +2862 -499
- package/dist/{index-D6_ysSmQ.d.mts → index-DOKS86aH.d.mts} +85 -7
- package/dist/index.d.mts +56 -10
- package/dist/index.mjs +134 -24
- package/dist/mermaid/index.mjs +5 -4
- package/dist/pdf/index.d.mts +1 -1
- package/dist/pdf/index.mjs +8 -7
- package/dist/styles.css +14 -0
- package/package.json +4 -17
- package/dist/Editor-DT7RkRXf.d.mts +0 -32
- package/dist/Skeleton-D922Ths5.mjs +0 -13
- package/dist/motion/index.d.mts +0 -8
- package/dist/motion/index.mjs +0 -1009
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,182 @@
|
|
|
1
1
|
# docblocks-react-ui
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- bcc306e: The `Editor`'s page view is now the motion row layer (the former
|
|
8
|
+
`MotionEditor`'s merge): every page block is its own `Reorder.Item` row —
|
|
9
|
+
the drag-reorder (one drag = one range move of the dragged block's
|
|
10
|
+
derived subtree), the insert/remove's layout animation, the rendered
|
|
11
|
+
list marker per row. Consumers rendering `<Editor>` get the animated,
|
|
12
|
+
draggable page without a code change; the `view` / `formatPalette` props
|
|
13
|
+
stand. The `MotionEditor` export and the `./motion` subpath are removed
|
|
14
|
+
(the base `Editor` is the motion editor — the previous split stood the
|
|
15
|
+
base entry without any reorder path, so a consumer taking it got a
|
|
16
|
+
non-reorderable editor).
|
|
17
|
+
|
|
18
|
+
The three peers are now REQUIRED (pre-1.0 breaking): `framer-motion`
|
|
19
|
+
(the page view's row layer), `mermaid` (the `./mermaid` subpath), and
|
|
20
|
+
`pdfjs-dist` (the `./pdf` subpath) lose their `optional: true` — the
|
|
21
|
+
install must carry all of them. The `./mermaid` and `./pdf` subpaths'
|
|
22
|
+
wiring stays opt-in (the `pdfPreview` prop / the `code` block renderer);
|
|
23
|
+
the required peers guarantee availability only. The static row rendering
|
|
24
|
+
stands for the table cells and the canvas's page miniature (the
|
|
25
|
+
`BlockGroups`'s stand); the `BlockView`/`BlockNodeView` renderers are
|
|
26
|
+
unchanged.
|
|
27
|
+
- d62b662: The editor's UI strings stand localized (en + ru). The language is
|
|
28
|
+
consumer-driven: the package reads the `<html lang>` attribute (the `ru*`
|
|
29
|
+
prefix stands the Russian stand; the absent or unknown language falls
|
|
30
|
+
back to English) and follows the attribute's change at runtime. There is
|
|
31
|
+
no `locale` prop.
|
|
32
|
+
|
|
33
|
+
The package runs its own `i18next` instance over the shipped catalogs —
|
|
34
|
+
`i18next` and `react-i18next` are new runtime dependencies — under the
|
|
35
|
+
`EditorProvider`'s subtree (and the consumer-placed `DocHeader`): the
|
|
36
|
+
consumer's global `i18next` singleton stands untouched, and the editor's
|
|
37
|
+
`useTranslation` never conflicts with it. The English's values keep the
|
|
38
|
+
former's literals as-is (the zero visual diff over the English's
|
|
39
|
+
language).
|
|
40
|
+
|
|
41
|
+
Not localized (the technical stand): the code language's names, the font
|
|
42
|
+
family's and weight's names, the avatar emoji picker's accessible names,
|
|
43
|
+
and the technical glyphs. Parameterized strings use the `{param}`
|
|
44
|
+
interpolation (the single braces' stand).
|
|
45
|
+
- 0e798be: The page row's delete affordance: the hover's trash icon at the row's
|
|
46
|
+
right edge (every page type — the text rows' own wrapper, the non-text
|
|
47
|
+
rows' row-level stand over the motion view; the edit's mode only).
|
|
48
|
+
The deletion was previously discoverable only through the less obvious
|
|
49
|
+
path (the gutter's select + the Delete key). The click is a true
|
|
50
|
+
deletion (the Delete key's image special case — the in-place conversion
|
|
51
|
+
to an empty paragraph — stands for the key gesture only), the row's
|
|
52
|
+
whole blocks selection is deleted when the row is part of one (the
|
|
53
|
+
Delete key's gesture parity), and the gesture stands the document
|
|
54
|
+
root's trailing-paragraph guarantee + the focus's parking as the Delete
|
|
55
|
+
key's path (the focus never drops to the document).
|
|
56
|
+
- 74e0abd: Add the standalone's database's surface (the consumer's own page, not a
|
|
57
|
+
document block): the `DatabaseTable` component (the live grid over the
|
|
58
|
+
bridge's table id — the same `useDatabaseTable`'s data stand as the
|
|
59
|
+
document block) + the `useTableList` hook (the `listTables`'s catalog
|
|
60
|
+
read + the `createTable` / `renameTable` mutations over the fresh's
|
|
61
|
+
`operationId` per op; the catalog's auto-refresh stands over the own's
|
|
62
|
+
successful mutations + the manual's `refresh`). The `DatabaseTable`'s
|
|
63
|
+
view's settings (`filter`, the `columnOrder`, the `hiddenColumns`, the
|
|
64
|
+
`columnWidths`) stand the internal's state seeded from the optional
|
|
65
|
+
`view` prop + persisted over the `onViewChange`'s patch callback (the
|
|
66
|
+
controlled's mode stands absent — one patch per change, as the block's
|
|
67
|
+
`updateBlock` stand). The `readOnly`'s stand gates the editing's paths
|
|
68
|
+
(the block's read-only's parity). The grid's `GridBody` stands extracted
|
|
69
|
+
from the document's context (the view's attrs' write is the callback's
|
|
70
|
+
stand — the block's wrapper keeps one `updateBlock` per change, no
|
|
71
|
+
behavior's diff).
|
|
72
|
+
|
|
73
|
+
### Patch Changes
|
|
74
|
+
|
|
75
|
+
- a89733e: The external-form database's history and boundary stands:
|
|
76
|
+
|
|
77
|
+
- the undo / redo's in-flight window — a forward write that commits while
|
|
78
|
+
the undo's inverse (or the redo's forward) is in flight stands the
|
|
79
|
+
history's invariants: the undo's path consumes the undone op (popped from
|
|
80
|
+
the undo stack, not moved to the redo stack — the fresh write cleared the
|
|
81
|
+
redo side, and the re-commit over the newer entry would clobber it), and
|
|
82
|
+
the redo's path re-enters the op on the undo stack at the call's position
|
|
83
|
+
(below the window's writes, not on top — the undo order's inversion is
|
|
84
|
+
closed, the first undo reverts the newest write).
|
|
85
|
+
- the operation's rejections stand the structured `BridgeError` (the code's
|
|
86
|
+
retry / the clear's decision stands the first-class property, not the
|
|
87
|
+
`cause`'s dig): a rejection that carries no machine code stands the
|
|
88
|
+
transport-level `unavailable` (the safe recovery is the same-operationId's
|
|
89
|
+
reconciliation, not a blind new operation).
|
|
90
|
+
- the cell-value equality stands the element-wise comparison over the
|
|
91
|
+
composite value (the multi-select's array) — the identity stand committed
|
|
92
|
+
the no-op over the same content and pushed the undo entry.
|
|
93
|
+
- the enum's options catalog stands the full page set (the cursor's
|
|
94
|
+
continuation to the tail) over the single page's `limit: 200` — the
|
|
95
|
+
truncated catalog over 200 options stood the silent-ignored delete of the
|
|
96
|
+
truncated option over the commit's diff.
|
|
97
|
+
- the column form's commit failures stand the logged error + the catalog's
|
|
98
|
+
re-read (the partial stand over the move's second commit), the silent
|
|
99
|
+
catches are gone.
|
|
100
|
+
- ff90f80: The external-form database stand's hardening: the bridge tables' picker
|
|
101
|
+
guards the `listTables` rejection (the unhandled rejection stands the
|
|
102
|
+
logged error + the empty list stand), and the hook's undo / redo drops
|
|
103
|
+
the replaced entry by identity (the in-flight inverse over the history's
|
|
104
|
+
mutation no longer drops the fresh entry — the double-apply and the
|
|
105
|
+
stale restore are closed). The database JSDoc stands the actual
|
|
106
|
+
contract: the mixed paste's description is self-contained, and the lost
|
|
107
|
+
response's reconciliation is the consumer's stand over the bridge's
|
|
108
|
+
`getOperationStatus` (the UI's convergence is the rebaseline).
|
|
109
|
+
- 590f5e7: The editor root's focus-ring stand: the root is a focus park (the
|
|
110
|
+
drag's release and the gutter's delete park the focus there so the
|
|
111
|
+
keyboard's input stays scoped over the editor) and is reached
|
|
112
|
+
programmatically only (tabIndex -1) — the browser's default focus ring
|
|
113
|
+
stood the visible ring over the whole document after a drag's release.
|
|
114
|
+
The ring is suppressed (`outline: none` on the focused root); the focus
|
|
115
|
+
itself stays, and the individual controls keep their own focus styles.
|
|
116
|
+
- a1564a2: The embed and frame's render stands:
|
|
117
|
+
|
|
118
|
+
- the sync-embed's stale's dynamic stand — the ref's block removed from the
|
|
119
|
+
master over the embed's mount now stands the broken's transition (the
|
|
120
|
+
master's change re-stands the block to the render-time's check; the
|
|
121
|
+
master's undo of the removal stands the resolved's back stand).
|
|
122
|
+
- the canvas frame's window references stand memoized (the frame's drag
|
|
123
|
+
re-renders the frame on every pointermove — the fresh array / Set
|
|
124
|
+
references broke the window's copies' memo and re-rendered every copy
|
|
125
|
+
over the drag's pass; the page-frame block's window stands the same
|
|
126
|
+
stand).
|
|
127
|
+
- the pdf worker's asset stands the degradation's signal: the unreachable
|
|
128
|
+
worker's asset (the bundler's rewritten reference, the hosting's dropped
|
|
129
|
+
asset) stands the logged warning over the silent native-viewer's
|
|
130
|
+
fallback.
|
|
131
|
+
- the `docblocks-core`'s peer range stands `^0.1.0` (the required peer's
|
|
132
|
+
version stand over the `*` — the packages stand lockstep over the 0.x
|
|
133
|
+
case, the breaking core's minor stands the range's bump over the same
|
|
134
|
+
release).
|
|
135
|
+
- ecb2a91: The paste's markdown link re-gate stands the mid-string control's
|
|
136
|
+
degrade: an href with a tab / LF / CR between the scheme's letters
|
|
137
|
+
(`java<tab>script:…`) no longer passes the gate — the check runs over
|
|
138
|
+
the WHATWG URL parser's full input normalization (the control is
|
|
139
|
+
removed from any position before the scheme detection, the browser's
|
|
140
|
+
parity). The run degrades to plain text over the unsafe href (the core's
|
|
141
|
+
gate is the single stand; this package's mirror passes it through).
|
|
142
|
+
- d162a1a: The paste surface's hardening: the markdown paste's link stand re-checks
|
|
143
|
+
the href over the core's public `isSafeLinkHref` itself at both the raw
|
|
144
|
+
parse and the entity-decode pass (the trimmed form — the browser trims
|
|
145
|
+
the leading C0 controls before the scheme detection, so the parser's
|
|
146
|
+
mirror stands the writer's contract: the `<a href>` tag, the exposed
|
|
147
|
+
entity's scheme, and the entity-hidden leading C0 degrade the run to
|
|
148
|
+
plain text instead of aborting the multi-block paste over the core's
|
|
149
|
+
strict mark rejection); and the clipboard's HTML serializes the mark
|
|
150
|
+
values escaped (the hostile remote data's stand — the attribute break
|
|
151
|
+
over the third-party paste target is closed).
|
|
152
|
+
- f907ee1: The editor store and the flat page derivation stand the registry's
|
|
153
|
+
own-property lookups (the `constructor`, `toString`, ... names are
|
|
154
|
+
unknown types, not the inherited `Object.prototype` members): a hostile
|
|
155
|
+
type named by a prototype key stands absent in the page sequence (the
|
|
156
|
+
cross-minor's stand — no renderer lookup over the inherited member, no
|
|
157
|
+
render-error stand, the data preserved in the export), and the seed and
|
|
158
|
+
the diff share one reader's posture (the store's filter and the
|
|
159
|
+
`getBlock`'s own-property stand agree on the block's presence).
|
|
160
|
+
- ab836e5: The selector's escape stand: the three block-content lookups (the range
|
|
161
|
+
extend's target, the gesture's stale-restore focus, the format
|
|
162
|
+
toolbar's type-change exclude) build the `data-block-id` selector over
|
|
163
|
+
`CSS.escape` — the full parity with the package's other lookup points,
|
|
164
|
+
where a crafted block id (a quote / bracket) would otherwise stand a
|
|
165
|
+
`SyntaxError` from `querySelector` in the keyboard / gesture handlers.
|
|
166
|
+
- Updated dependencies [bf92634]
|
|
167
|
+
- Updated dependencies [b66e45e]
|
|
168
|
+
- Updated dependencies [c5a38d2]
|
|
169
|
+
- Updated dependencies [769c12a]
|
|
170
|
+
- Updated dependencies [72fdfd3]
|
|
171
|
+
- docblocks-core@0.1.2
|
|
172
|
+
|
|
173
|
+
## 0.1.1
|
|
174
|
+
|
|
175
|
+
### Patch Changes
|
|
176
|
+
|
|
177
|
+
- The README stands the `styles.css`'s import's ambient `*.css` declaration's
|
|
178
|
+
note and the `DocHeader`'s stand over the `viewer`'s level.
|
|
179
|
+
|
|
3
180
|
## 0.1.0
|
|
4
181
|
|
|
5
182
|
### Added
|
package/README.md
CHANGED
|
@@ -12,11 +12,14 @@ package renders the document and provides the editing surface
|
|
|
12
12
|
npm i docblocks-react-ui docblocks-core
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Peer dependencies: `docblocks-core`, `react` (19), `react-dom
|
|
16
|
-
peers
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
Peer dependencies: `docblocks-core`, `react` (19), `react-dom`, and the
|
|
16
|
+
required peers `framer-motion` (the Editor's page view is the motion row
|
|
17
|
+
layer — the drag-reorder + the layout animations), `mermaid` (the
|
|
18
|
+
`./mermaid` subpath's renderer), and `pdfjs-dist` (the `./pdf` subpath's
|
|
19
|
+
preview) — the install must carry all of them (npm enforces the required
|
|
20
|
+
peers). The package's own runtime dependencies (zustand, the Radix
|
|
21
|
+
primitives, the shared ui runtime set) are declared, so a plain `npm i`
|
|
22
|
+
is the whole install.
|
|
20
23
|
|
|
21
24
|
The package is ESM-only (`import`, not `require`); it stands Node
|
|
22
25
|
`^22.22.2 || ^24.15.0 || >=26.0.0` (the `engines` field).
|
|
@@ -49,6 +52,10 @@ function App() {
|
|
|
49
52
|
}
|
|
50
53
|
```
|
|
51
54
|
|
|
55
|
+
The `styles.css` side-effect import stands the standard bundler's ambient
|
|
56
|
+
`*.css` module declaration (shipped with the Vite / CRA / Next.js templates);
|
|
57
|
+
a bare `tsc`-only setup needs a one-line `declare module "*.css"` shim.
|
|
58
|
+
|
|
52
59
|
- `EditorProvider` owns the per-instance editor state (the store projection
|
|
53
60
|
of the doc, the selection view, the subscriptions). Multiple providers may
|
|
54
61
|
coexist, each with its own doc.
|
|
@@ -199,6 +206,9 @@ document data, never on the wire):
|
|
|
199
206
|
external database form's rows live in the consumer's table (they are not
|
|
200
207
|
part of the snapshot — the inline form is document data and is). A new
|
|
201
208
|
snapshot is a remount (pass it under a changing `key`).
|
|
209
|
+
- The `DocHeader` stands over the viewer's stand too: pass the snapshot as
|
|
210
|
+
its `doc` (the viewer's switcher stays off — the `accessLevel` stands no
|
|
211
|
+
`mode` stand over the `viewer` level).
|
|
202
212
|
|
|
203
213
|
### Sync and presence
|
|
204
214
|
|
|
@@ -327,6 +337,49 @@ package root: `BridgeError` (the structured error type) with
|
|
|
327
337
|
`isDatabaseBridge`, and `useDatabaseTable(bridge, tableId, filter?)` — the
|
|
328
338
|
grid controller for a consumer-owned grid over the bridge.
|
|
329
339
|
|
|
340
|
+
### Standalone database table
|
|
341
|
+
|
|
342
|
+
The database's UI stands outside any document as well — the
|
|
343
|
+
consumer-owned "tables section" (the user's tables management, not a
|
|
344
|
+
document block). The package ships the composable primitives; the
|
|
345
|
+
consumer assembles its own section (the list / the UX) over
|
|
346
|
+
`useTableList` and embeds the ready grid over the picked table:
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
import { DatabaseTable, useTableList } from "docblocks-react-ui";
|
|
350
|
+
|
|
351
|
+
function TablesSection({ bridge }: { bridge: DatabaseBridge }) {
|
|
352
|
+
const list = useTableList(bridge);
|
|
353
|
+
const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
354
|
+
return (
|
|
355
|
+
<div>
|
|
356
|
+
{list.tables?.map((table) => (
|
|
357
|
+
<button key={table.id} onClick={() => setSelectedId(table.id)}>
|
|
358
|
+
{table.name}
|
|
359
|
+
</button>
|
|
360
|
+
))}
|
|
361
|
+
{selectedId !== null && <DatabaseTable bridge={bridge} tableId={selectedId} />}
|
|
362
|
+
</div>
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
- `DatabaseTable({ bridge, tableId, readOnly?, view?, onViewChange? })` —
|
|
368
|
+
the live grid over the bridge's table id (the same data stand as the
|
|
369
|
+
document block: the schema, the rows, the live events, the optimistic
|
|
370
|
+
cell layer). The view's settings (`filter`, `columnOrder`,
|
|
371
|
+
`hiddenColumns`, `columnWidths`) stand the internal state (seeded from
|
|
372
|
+
the optional `view` prop at mount); `onViewChange(patch)` receives one
|
|
373
|
+
patch per change for the consumer's persistence (the controlled mode
|
|
374
|
+
stands absent — the state is never external). `readOnly` gates the
|
|
375
|
+
editing's paths (the read-only block's parity).
|
|
376
|
+
- `useTableList(bridge)` — `{ tables, loading, error, refresh, create,
|
|
377
|
+
rename }`: the `listTables` catalog (the system tables stand out), the
|
|
378
|
+
`createTable` / `renameTable` mutations (the fresh `operationId` per op;
|
|
379
|
+
they reject with the `BridgeError`), and the catalog's re-read —
|
|
380
|
+
automatic over the hook's own successful mutations + manual over
|
|
381
|
+
`refresh` (the contract's catalog stands no push channel).
|
|
382
|
+
|
|
330
383
|
### Sync-embed
|
|
331
384
|
|
|
332
385
|
A `sync-embed` block references another document by an opaque ref. The
|
|
@@ -375,7 +428,7 @@ const blockRenderers: BlockRendererMap = {
|
|
|
375
428
|
|
|
376
429
|
`pdfPreview` is a component that renders a `pdf`-subtype image block's
|
|
377
430
|
resolved blob as a client-side first-page preview. The `./pdf` subpath
|
|
378
|
-
provides one over `pdfjs-dist` (
|
|
431
|
+
provides one over `pdfjs-dist` (a required peer):
|
|
379
432
|
|
|
380
433
|
```tsx
|
|
381
434
|
import { PdfFirstPage } from "docblocks-react-ui/pdf";
|
|
@@ -425,6 +478,25 @@ insert menu, the drag / resize / nudge / fit / draw sessions) or
|
|
|
425
478
|
programmatically through the core's block commands. The viewport's zoom
|
|
426
479
|
and pan are view state — they never reach the document.
|
|
427
480
|
|
|
481
|
+
### Localization
|
|
482
|
+
|
|
483
|
+
The editor's UI strings ship localized (en + ru). The language is
|
|
484
|
+
consumer-driven — the package reads the `<html lang>` attribute (the `ru*`
|
|
485
|
+
prefix stands the Russian stand; the absent / unknown language falls back
|
|
486
|
+
to English) and follows the attribute's change at runtime (the editor
|
|
487
|
+
re-renders over the flip). There is no `locale` prop — the document's
|
|
488
|
+
language is the consumer's, set on `<html>`.
|
|
489
|
+
|
|
490
|
+
The package runs its **own** `i18next` instance (the shipped catalogs,
|
|
491
|
+
`i18next` + `react-i18next` are runtime dependencies) under the
|
|
492
|
+
`EditorProvider`'s subtree — a consumer's global `i18next` singleton stands
|
|
493
|
+
untouched, and the editor's `useTranslation` never leaks into (or out of)
|
|
494
|
+
the consumer's setup.
|
|
495
|
+
|
|
496
|
+
Not localized (the technical stand): the code language names, the font
|
|
497
|
+
family / weight names, the avatar emoji picker's accessible names, and the
|
|
498
|
+
technical glyphs.
|
|
499
|
+
|
|
428
500
|
### Subtree view
|
|
429
501
|
|
|
430
502
|
`rootBlockId` renders the entry list of one block instead of the document
|
|
@@ -467,8 +539,10 @@ value actually changes (the store's reference-stability contract):
|
|
|
467
539
|
| `view` | `"page"` (default) or `"canvas"` — the rendering the consumer switches |
|
|
468
540
|
| `formatPalette` | The format toolbar's color swatches (default `FORMAT_PALETTE`, exported) |
|
|
469
541
|
|
|
470
|
-
|
|
471
|
-
|
|
542
|
+
The page view renders the flat page sequence — every page block is its
|
|
543
|
+
own row (the drag-reorder's pure framer `Reorder`, the insert/remove's
|
|
544
|
+
layout animation, the rendered list marker per row) — over the required
|
|
545
|
+
`framer-motion` peer.
|
|
472
546
|
|
|
473
547
|
## Subpath exports
|
|
474
548
|
|
|
@@ -477,12 +551,13 @@ layout animations and drag-reorder (requires `framer-motion`).
|
|
|
477
551
|
| `docblocks-react-ui` | The editor, the provider, the hooks, the primitives (the entry) |
|
|
478
552
|
| `docblocks-react-ui/styles.css` | The compiled stylesheet: the utility layer + the token seed + the `--docblocks-*` mapping + the structural rules |
|
|
479
553
|
| `docblocks-react-ui/theme.css` | The pure token seed (standard tokens + the radius scale), no utility layer |
|
|
480
|
-
| `docblocks-react-ui/motion` | `MotionEditor` (layout animations, insert/remove, drag-reorder; peer: `framer-motion`) |
|
|
481
554
|
| `docblocks-react-ui/mermaid` | The `mermaid` renderer above `code { language: "mermaid" }` blocks (peer: `mermaid`) |
|
|
482
555
|
| `docblocks-react-ui/pdf` | `PdfFirstPage` (the first-page preview over `pdfjs-dist`; the worker is copied to `dist/pdf/` at build time) |
|
|
483
556
|
|
|
484
|
-
The
|
|
485
|
-
|
|
557
|
+
The `./mermaid` and `./pdf` subpaths' wiring is opt-in (the `pdfPreview`
|
|
558
|
+
prop / the `code` block renderer): a consumer who skips a subpath imports
|
|
559
|
+
nothing of its module. The peers themselves are required installs (the
|
|
560
|
+
page view's framer import included).
|
|
486
561
|
|
|
487
562
|
## Theming
|
|
488
563
|
|