@nadicodeai/ui 6.0.1 → 6.1.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/dist/components/action-menu.d.ts +8 -0
- package/dist/components/action-menu.d.ts.map +1 -0
- package/dist/components/action-menu.js +8 -0
- package/dist/components/card.d.ts +1 -1
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +5 -3
- package/dist/components/chart-breakdown-table.d.ts +3 -2
- package/dist/components/chart-breakdown-table.d.ts.map +1 -1
- package/dist/components/chart-breakdown-table.js +13 -9
- package/dist/components/chart-bullet-bar.d.ts +13 -12
- package/dist/components/chart-bullet-bar.d.ts.map +1 -1
- package/dist/components/chart-bullet-bar.js +16 -36
- package/dist/components/chart-kpi-stat.d.ts +26 -15
- package/dist/components/chart-kpi-stat.d.ts.map +1 -1
- package/dist/components/chart-kpi-stat.js +28 -4
- package/dist/components/chart-time-series-layout.d.ts +6 -0
- package/dist/components/chart-time-series-layout.d.ts.map +1 -0
- package/dist/components/chart-time-series-layout.js +6 -0
- package/dist/components/chart-time-series.d.ts +6 -2
- package/dist/components/chart-time-series.d.ts.map +1 -1
- package/dist/components/chart-time-series.js +27 -9
- package/dist/components/chart.js +1 -1
- package/dist/components/collection-filters.d.ts +28 -0
- package/dist/components/collection-filters.d.ts.map +1 -0
- package/dist/components/collection-filters.js +54 -0
- package/dist/components/collection-scope.d.ts +15 -0
- package/dist/components/collection-scope.d.ts.map +1 -0
- package/dist/components/collection-scope.js +7 -0
- package/dist/components/collection-toolbar.d.ts +10 -0
- package/dist/components/collection-toolbar.d.ts.map +1 -0
- package/dist/components/collection-toolbar.js +4 -0
- package/dist/components/settings-facts.d.ts +28 -0
- package/dist/components/settings-facts.d.ts.map +1 -0
- package/dist/components/settings-facts.js +7 -0
- package/dist/components/settings-section.d.ts +5 -5
- package/dist/components/settings-section.d.ts.map +1 -1
- package/dist/components/settings-section.js +6 -11
- package/dist/components/sidebar.d.ts +4 -1
- package/dist/components/sidebar.d.ts.map +1 -1
- package/dist/components/sidebar.js +3 -3
- package/dist/components/table-layouts.d.ts +22 -0
- package/dist/components/table-layouts.d.ts.map +1 -0
- package/dist/components/table-layouts.js +20 -0
- package/dist/components/table.d.ts +15 -2
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +8 -4
- package/dist/eslint/rules/jsx-class-utility.js +44 -12
- package/dist/eslint/rules/no-resting-settings-control.js +15 -13
- package/dist/eslint/rules/no-shadcn-appearance-override.js +189 -36
- package/dist/eslint/rules/shadcn-composition.js +48 -3
- package/dist/hooks/use-confirm-action.d.ts +0 -6
- package/dist/hooks/use-confirm-action.d.ts.map +1 -1
- package/dist/hooks/use-confirm-action.js +5 -12
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/lib/use-copy-to-clipboard.d.ts +0 -41
- package/dist/lib/use-copy-to-clipboard.d.ts.map +1 -1
- package/dist/lib/use-copy-to-clipboard.js +6 -15
- package/docs/component-classification.md +3 -2
- package/docs/contract.md +79 -8
- package/docs/product-compositions.md +14 -11
- package/package.json +3 -2
|
@@ -19,8 +19,9 @@ copy, and behavior.
|
|
|
19
19
|
|
|
20
20
|
| Component | Classification | Built on | Required states | Package-owned accessibility | Fixture |
|
|
21
21
|
| --- | --- | --- | --- | --- | --- |
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
22
|
+
| `ActionMenu` | Canonical record-action composition. | shadcn `Button` and `DropdownMenu`. | closed, open, keyboard selection, focus return. | Required accessible trigger name; inherited menu mechanics. | `../src/components/action-menu.test.tsx` |
|
|
23
|
+
| `SettingsSection` | NadicodeAI product composition. | shadcn Card slots, Separator, and FieldGroup. | header, field group, and divided action footer. | Section structure; consumer owns the form transaction. | `../src/components/settings-section.test.tsx` |
|
|
24
|
+
| `SettingsField` | NadicodeAI product composition. | shadcn Field, FieldLabel, FieldDescription, and FieldError. | valid, invalid, required, and disabled field rows. | Render callback supplies the control's label and message associations in server and client components. | `../src/components/settings-section.test.tsx` |
|
|
24
25
|
| `FeedbackState` | Net-new central product state composition adapted from shadcn empty-state patterns. | shadcn `Empty` and lucide status icons. | `empty`, `loading`, `saving`, `error`, `permission`, `offline`, `no-results`, `fatal`. | `role="status"` for loading/saving; `role="alert"` for error, permission, offline, and fatal. | `../tests/guards/product-compositions.test.ts` |
|
|
25
26
|
|
|
26
27
|
## App-Owned Boundaries
|
package/docs/contract.md
CHANGED
|
@@ -27,6 +27,9 @@ Physical role, not content importance, chooses depth:
|
|
|
27
27
|
work chooses it explicitly.
|
|
28
28
|
- `Card surface="plain"` is the explicit structural/auth/website escape and
|
|
29
29
|
carries no elevation.
|
|
30
|
+
- `Card surface="outlined"` is a flat panel with a single semantic border and
|
|
31
|
+
compact corners; it carries no elevation ring or shadow. Bounded fact cells
|
|
32
|
+
use it inside resting record sections. Portal's kit keeps the resting default.
|
|
30
33
|
- Tooltip, menu, popover, select, combobox, navigation popup, hover card,
|
|
31
34
|
chart tooltip, and toast roots own `nc-elevation-floating` internally.
|
|
32
35
|
- Dialog, alert dialog, drawer, and sheet roots own `nc-elevation-modal`
|
|
@@ -64,11 +67,36 @@ transparent and unframed because the Card already owns containment.
|
|
|
64
67
|
|
|
65
68
|
### Tables
|
|
66
69
|
|
|
67
|
-
`Table` owns the native table structure, solid semantic background,
|
|
68
|
-
|
|
70
|
+
`Table` owns the native table structure, solid semantic background, an overflow
|
|
71
|
+
safety boundary, and one compact density: 36px header rows and 40px body rows. Consumers
|
|
69
72
|
compose `TableHeader`, `TableBody`, `TableRow`, `TableHead`, and `TableCell`; they
|
|
70
73
|
do not replace table layout with grid or flex, hide the header to create another
|
|
71
|
-
presentation, or reconstruct the native semantics with ARIA.
|
|
74
|
+
presentation, or reconstruct the native semantics with ARIA. Portal collections
|
|
75
|
+
must fit their available width without horizontal scrolling: preserve identity
|
|
76
|
+
and actions in columns and place supporting facts in native detail rows before
|
|
77
|
+
the full schema becomes cramped. Test the table container itself, not only the
|
|
78
|
+
document width; retaining the overflow safety boundary must not conceal a
|
|
79
|
+
layout defect.
|
|
80
|
+
|
|
81
|
+
`CollectionScope` chooses the parent of one record collection. It places the
|
|
82
|
+
scope selector and optional detail action above the collection toolbar. Empty
|
|
83
|
+
parents stay in the selector. Apps bind authorized options and URL state; clearing
|
|
84
|
+
record filters preserves the parent scope. Parent details belong on their detail
|
|
85
|
+
page, not in repeated panels surrounding identical child tables.
|
|
86
|
+
|
|
87
|
+
`BreakdownTable` owns its responsive comparison layout: identity and value stay
|
|
88
|
+
in the main row; share moves into a labeled detail row when space is tight.
|
|
89
|
+
Its caption names the table. Callers supply data and labels, not column-hiding CSS.
|
|
90
|
+
|
|
91
|
+
### Record action menus
|
|
92
|
+
|
|
93
|
+
`ActionMenu` is the shared three-dot composition of `Button` and `DropdownMenu`:
|
|
94
|
+
a ghost icon trigger, horizontal ellipsis, and end-aligned popup. It inherits the
|
|
95
|
+
menu's glass, elevation, motion, keyboard behavior, and focus return. Supply
|
|
96
|
+
`label` as a localized, record-specific accessible name; `triggerId` supports
|
|
97
|
+
focus return from an app-owned confirmation, and `children` supplies menu items.
|
|
98
|
+
Apps own action selection, permission, placement, and confirmation. Reuse this
|
|
99
|
+
composition instead of drawing another trigger or popup.
|
|
72
100
|
|
|
73
101
|
## Status Vocabulary
|
|
74
102
|
|
|
@@ -121,12 +149,15 @@ fundamental `Card` with explicit `visual`, `name`, `job`, `status`, `meta`,
|
|
|
121
149
|
and `action` slots and owns presentation only; when it is the page identity,
|
|
122
150
|
the `name` slot carries the page's `h1`. The app owns Agent data, recipe
|
|
123
151
|
assignment, status grammar, routing, and actions; it assigns a recipe
|
|
124
|
-
explicitly and never infers or randomizes one from a free-form role
|
|
125
|
-
|
|
152
|
+
explicitly and never infers or randomizes one from a free-form role.
|
|
153
|
+
When the product chooses a card presentation, use `AgentCard`; registry cells,
|
|
154
|
+
membership rows, and compact detail headers compose the shared `AgentVisual`
|
|
155
|
+
within the structure their reading task requires. An Agent's presence does not
|
|
156
|
+
by itself choose a card layout. There is no `AgentGlyph`,
|
|
126
157
|
`AgentRow`, `KpiCard`, or product-domain `agent` object prop in the shared
|
|
127
158
|
package.
|
|
128
159
|
|
|
129
|
-
- **Standard components, not app-owned product features.** This package ships primitives, standard UI components, assistant-ui compositions, brand adapters, React adapters, reusable sections, and presentational product components. It must not ship app-specific feature/use-case screens or names such as operator-login, portal activation, customer credential control, or customer management.
|
|
160
|
+
- **Standard components, not app-owned product features.** This package ships primitives, standard UI components, assistant-ui compositions, brand adapters, React adapters, reusable sections, and presentational product components. It must not ship app-specific feature/use-case screens or names such as operator-login, portal activation, customer credential control, or customer management. Domain registries, command search providers, and chart dashboards bind app data and routes in the app; that binding is not a reason to copy reusable presentation. Portal's DataTable owns its Next.js query and registry protocol once, while consuming the shared UI foundation. Product-independent compositions belong here with a real consumer. The source-backed `chart-*` package surface is the plan-approved exception per issue #166; apps select charts and bind their titles, data, and navigation. Every data-shaped chart exposes an equivalent non-visual data alternative. A component whose complete value is already available in visible text or `aria-valuetext` does not add a redundant table.
|
|
130
161
|
- **Auth routes are consumer-owned shadcn block work.** Login, signup, OTP, two-factor, magic-link, and provider-button flows start from the selected shadcn block/example in the consuming app, with app-owned Better Auth behavior. Do not ship generic auth, signup, OTP, federated-login, or provider abstractions from this package unless a later explicit boundary decision replaces the selected shadcn block.
|
|
131
162
|
- **Reusable sections and compositions live here after proof.** Bento grids, media mounts, demo surfaces, page frames, section intros, CTA bands, proof slots, benefits grids, generic shells, and homepage/use-case sections belong in `@nadicodeai/ui` when a second concrete consumer, a plan-approved shared component, or a named validation slice proves the package boundary. Website, portal, and sibling Nadia routes pass data and media children into existing compositions instead of rebuilding layout locally.
|
|
132
163
|
- **Brand renderers live here for React consumers.** Logo geometry, asset generation, and usage semantics are owned by [`packages/design-system/DESIGN.md`, "Brand media authority"](../../design-system/DESIGN.md#brand-media-authority). `BrandLockup` supplies the approved horizontal lockup. `BrandMark` serves tight spaces and `BrandWordmark` serves placements where the name must read by itself. All three render the package's public neutral geometry seam with React-scoped SVG ids, dynamic theme paint, and accessible names. Consuming routes use these adapters; they never import raw logo assets, draw brand SVG inline, mask or recolor assets, or create another lockup rule.
|
|
@@ -135,17 +166,57 @@ package.
|
|
|
135
166
|
|
|
136
167
|
## Accessibility Invariant
|
|
137
168
|
|
|
138
|
-
**Tier-1 accessibility is tested, browser-free.**
|
|
169
|
+
**Tier-1 accessibility is tested, browser-free.** Rendering component tests use the package `expectAccessible` helper to check the rendered DOM. The jsdom tier is structural: rendered contrast, landmark context, focus, and keyboard behavior belong to real-browser Playwright coverage. The shared library ESLint configuration is the executable authority for static JSX accessibility rules, and the repository quality doctrine owns their policy; this contract does not copy the rule inventory.
|
|
139
170
|
|
|
140
171
|
## Reusable Sections
|
|
141
172
|
|
|
142
173
|
The source tree, barrels, and package exports own the current reusable section vocabulary. When a page needs a variation, extend the owning source component with a small typed prop or slot; do not fork the layout in a consumer or document a second component inventory here.
|
|
143
174
|
|
|
175
|
+
`KpiStatGroup` owns the metric strip, responsive tiles, and link treatment; `KpiStat` owns its value, note, delta, and decorative trend. Apps supply metrics and bind links through `render`. Time-series charts expose `size`; their lightweight layout module also sizes deferred placeholders, so consumers never select internal chart elements.
|
|
176
|
+
|
|
177
|
+
`CollectionToolbar` owns the collection-control layout: compact filters at the
|
|
178
|
+
leading edge, a flexible search field, and trailing actions. Its slot order is
|
|
179
|
+
also the reading and focus order, including when controls wrap. Consumers supply
|
|
180
|
+
existing controls and own their query state; they do not set independent search
|
|
181
|
+
widths or align filters to table columns. `CollectionFilters` owns the controlled
|
|
182
|
+
field/value picker and applied-filter chips; callers supply options, localized
|
|
183
|
+
copy, and callbacks. The component owns discovery, edit/remove, keyboard focus,
|
|
184
|
+
and empty search results. It does not own routing or fetch state.
|
|
185
|
+
|
|
186
|
+
`SettingsFactsSection` owns a named record or settings reading section: its
|
|
187
|
+
heading and optional action, header separator, and bounded responsive fact
|
|
188
|
+
cells in two equal columns, stacked on compact screens. Consumers supply labels,
|
|
189
|
+
values, an optional contextual footer, and a Card surface; paragraph facts take a full row. The stable heading remains a programmatic focus target
|
|
190
|
+
when an editor closes. Keep fact labels, order, and cells stable when data is
|
|
191
|
+
missing: null and undefined values use the required localized
|
|
192
|
+
`missingValueLabel`, while zero remains a value. Consumers do not filter out
|
|
193
|
+
unknown facts or replace them with indefinite loading skeletons. Editable
|
|
194
|
+
controls remain in `SettingsSection`.
|
|
195
|
+
|
|
196
|
+
`SettingsSection` composes Card's named header, divider, FieldGroup body, and
|
|
197
|
+
optional divided `footer` for local save actions and feedback. The caller owns
|
|
198
|
+
the form transaction and controls; the section owns their shared geometry.
|
|
199
|
+
Header `actions` are optional supporting commands, distinct from footer submission.
|
|
200
|
+
`SettingsField` uses one render callback in server and client components. Spread
|
|
201
|
+
its `controlProps` onto the control to retain the visible label, descriptions,
|
|
202
|
+
error association, and disabled/required state; do not wire another copy by hand.
|
|
203
|
+
|
|
204
|
+
`TableDetailRow` keeps supporting collection facts readable at compact widths
|
|
205
|
+
inside a native full-width table cell. It shares the owning column labels and
|
|
206
|
+
values rather than requiring another responsive cell implementation. Identity
|
|
207
|
+
and status retain their column headers. Missing values retain their place.
|
|
208
|
+
`Table compactDetails` and `TableDetailRow layout` share `tableCompactLayouts`:
|
|
209
|
+
`standard` retains full columns at 768px of container width, `wide` at 1024px,
|
|
210
|
+
and `spacious` at 1152px for schemas with additional operational columns.
|
|
211
|
+
The same owner switches column visibility, detail visibility, and row boundaries.
|
|
212
|
+
Two supporting facts use two columns; additional facts can use three when they fit.
|
|
213
|
+
The cell renderer supplies the value, leaving the label to the detail row.
|
|
214
|
+
|
|
144
215
|
## Consumer Boundary
|
|
145
216
|
|
|
146
217
|
Consumers own routing, auth, app data, server actions, runtime construction and adapters, permission decisions, analytics, and app-specific copy. The package owns reusable React presentation and the public Agent UI dependency boundary. Agent state and behavior come through the Agents interface; non-React and TUI contracts belong to their consuming products.
|
|
147
218
|
|
|
148
|
-
App source composes layout, data, behavior, and semantic content around package components. It does not restyle an imported component root: appearance changes enter through the component's typed variant or are added to the owning package component. App `className` values on package components are
|
|
219
|
+
App source composes layout, data, behavior, and semantic content around package components. It does not restyle an imported component root: appearance changes enter through the component's typed variant or are added to the owning package component. App `className` values on package components arrange and size the component root. Descendant `data-slot` selectors are not a public styling API; internal spacing, type, and sizing belong to the shared component, enforced by `nadicodeai/no-shadcn-appearance-override`. App source uses semantic roles such as `bg-background` and `text-foreground`; canonical `nc-*` color utilities stay behind package-owned primitives such as `BrandField`. Raw Tailwind palette colors are not available to anyone: the generated theme clears the `--color-*` namespace, so `bg-red-500` produces no CSS and `better-tailwindcss/no-unknown-classes` reports it. Visible controls come from `@nadicodeai/ui`, while hidden inputs remain valid form transport. The root ESLint rules `nadicodeai/no-shadcn-appearance-override` and `nadicodeai/no-native-visible-control` enforce the rest of this boundary; each takes a `packageOwnedPrimitives` option (`"exempt"` by default, `"lint"` to hold this package's own source to the same rule).
|
|
149
220
|
|
|
150
221
|
When this package is read from an installed npm package, follow the [consumer setup guide](consuming-cross-repo.md) for setup and public import paths. The styling invariant above remains the authority for component implementation.
|
|
151
222
|
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
# Product Compositions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shared product compositions own repeatable presentation and interaction. Consumers bind routing, persistence, permissions, and product copy. See the [component contract](contract.md) for each family's ownership.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
chart cards follow this rule: use `@shadcn/data-table-demo`,
|
|
9
|
-
`@shadcn/command-dialog`, `@shadcn/chart`, or the relevant `@shadcn/chart-*`
|
|
10
|
-
block/example as the source of truth.
|
|
5
|
+
Check first-party shadcn or assistant-ui registry patterns before adding a
|
|
6
|
+
composition. Once adapted, reuse its maintained owner; do not assemble the same
|
|
7
|
+
registry example again for each page.
|
|
11
8
|
|
|
12
9
|
Import components through the wildcard component subpath after build:
|
|
13
10
|
|
|
@@ -19,12 +16,13 @@ Fixtures live in:
|
|
|
19
16
|
|
|
20
17
|
- [`../tests/guards/product-compositions.test.ts`](../tests/guards/product-compositions.test.ts)
|
|
21
18
|
- [`../tests/guards/product-compositions-ssr.test.ts`](../tests/guards/product-compositions-ssr.test.ts)
|
|
19
|
+
- [`../src/components/settings-section.test.tsx`](../src/components/settings-section.test.tsx)
|
|
22
20
|
|
|
23
21
|
## Boundaries
|
|
24
22
|
|
|
25
23
|
| Component | Package owns | Consumer owns |
|
|
26
24
|
| --- | --- | --- |
|
|
27
|
-
| `SettingsSection` / `SettingsField` |
|
|
25
|
+
| `SettingsSection` / `SettingsField` | Header, divided save footer, field layout, labels, descriptions, errors, and control associations. | Form state, validation, submission, persistence, settings taxonomy, and save/cancel behavior. |
|
|
28
26
|
| `FeedbackState` | Shared empty, loading, saving, error, permission, offline, no-results, and fatal state presentation. | Recovery actions, retry behavior, permission escalation, app-specific state language. |
|
|
29
27
|
|
|
30
28
|
## SettingsSection
|
|
@@ -35,6 +33,7 @@ Use `SettingsSection` and `SettingsField` for horizontal settings rows that need
|
|
|
35
33
|
<SettingsSection
|
|
36
34
|
title="Workspace defaults"
|
|
37
35
|
description="Shared defaults for agent work."
|
|
36
|
+
footer={<Button type="submit">Save</Button>}
|
|
38
37
|
>
|
|
39
38
|
<SettingsField
|
|
40
39
|
id="review-window"
|
|
@@ -44,7 +43,7 @@ Use `SettingsSection` and `SettingsField` for horizontal settings rows that need
|
|
|
44
43
|
invalid={Boolean(reviewWindowError)}
|
|
45
44
|
>
|
|
46
45
|
{({ controlProps }) => (
|
|
47
|
-
<
|
|
46
|
+
<Input {...controlProps} value={reviewWindow} onChange={onReviewWindowChange} />
|
|
48
47
|
)}
|
|
49
48
|
</SettingsField>
|
|
50
49
|
</SettingsSection>
|
|
@@ -53,11 +52,15 @@ Use `SettingsSection` and `SettingsField` for horizontal settings rows that need
|
|
|
53
52
|
| Prop | Purpose |
|
|
54
53
|
| --- | --- |
|
|
55
54
|
| `title` / `description` / `actions` | Section header content and right-side action slot. |
|
|
55
|
+
| `footer` | Local Save/Cancel controls and completion feedback. The owning form wraps the section. |
|
|
56
56
|
| `id` / `label` | Required field identity and accessible label. |
|
|
57
57
|
| `description` / `error` / `invalid` | Field helper text, error text, and invalid state. |
|
|
58
|
-
| `children` | A render function receives `controlProps` for the real control
|
|
58
|
+
| `children` | A render function receives `controlProps` for the real control in server and client components. |
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
Spread `controlProps` onto the real control. SettingsField invokes the callback
|
|
61
|
+
before rendered children cross any client boundary; it does not forward the
|
|
62
|
+
callback to a client component. The [contract](contract.md) owns the field's
|
|
63
|
+
accessibility and state guarantees.
|
|
61
64
|
|
|
62
65
|
## FeedbackState
|
|
63
66
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nadicodeai/ui",
|
|
3
|
-
"version": "6.0
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@assistant-ui/react": "0.15.18",
|
|
71
71
|
"@assistant-ui/react-markdown": "0.14.14",
|
|
72
72
|
"@base-ui/react": "^1.8.0",
|
|
73
|
-
"@nadicodeai/design-system": "6.0
|
|
73
|
+
"@nadicodeai/design-system": "6.1.0",
|
|
74
74
|
"@paper-design/shaders": "0.0.80",
|
|
75
75
|
"class-variance-authority": "^0.7.1",
|
|
76
76
|
"clsx": "^2.1.1",
|
|
@@ -106,6 +106,7 @@
|
|
|
106
106
|
"@stryker-mutator/vitest-runner": "10.0.0",
|
|
107
107
|
"@tailwindcss/postcss": "^4.3.3",
|
|
108
108
|
"@testing-library/react": "^16.3.3",
|
|
109
|
+
"@testing-library/user-event": "^14.6.7",
|
|
109
110
|
"@types/react": "19.2.18",
|
|
110
111
|
"@types/react-dom": "19.2.7",
|
|
111
112
|
"axe-core": "^4.13.0",
|