@andreyfedkovich/cozy-ui 0.7.7 → 0.9.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 +13 -0
- package/README.md +132 -15
- package/dist-lib/index.d.ts +70 -24
- package/dist-lib/styles.modules.css +1 -0
- package/dist-lib/styles.tailwind.css +2 -0
- package/dist-lib/ui-library.cjs.js +12 -12
- package/dist-lib/ui-library.cjs.js.map +1 -1
- package/dist-lib/ui-library.es.js +3872 -3689
- package/dist-lib/ui-library.es.js.map +1 -1
- package/package.json +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
Формат основан на [Keep a Changelog](https://keepachangelog.com/).
|
|
4
4
|
Версии соответствуют [Semantic Versioning](https://semver.org/) и git-тегам `v*`.
|
|
5
5
|
|
|
6
|
+
## 0.9.0 - 2026-06-04
|
|
7
|
+
|
|
8
|
+
- **feat:** Единый контракт валидации полей — headless API: `FieldMeta`, `ShowErrorPolicy`, `resolveShowError`, `resolveFieldError`, `resolveFieldMessage`, `useFieldState`, `resolveValueChangeHandler`.
|
|
9
|
+
- **feat:** `Input`, `Textarea`, `Checkbox`, `Select`, `DialogSelect`, `TreeDialogSelect`, `Calendar` — пропсы `fieldMeta` и `showErrorPolicy`; явный `error` по-прежнему переопределяет meta. Дефолтная политика: `invalid && (touched || submitted || hasValue)`.
|
|
10
|
+
- **feat:** Общий A11y для полей — `aria-invalid`, `aria-describedby`, стабильные `id` через `useId()`, сообщение об ошибке с `role="alert"`.
|
|
11
|
+
- **feat:** Value picker’ы (`Select`, `DialogSelect`, `TreeDialogSelect`, `Calendar`) — канонический колбэк `onValueChange`; `onChange` оставлен как deprecated alias. На trigger добавлены `onBlur` / `onFocus` для интеграции с формами.
|
|
12
|
+
- **docs:** README — раздел Field validation, две семьи колбэков (native `onChange` vs picker `onValueChange`).
|
|
13
|
+
|
|
14
|
+
## 0.8.0 - 2026-06-02
|
|
15
|
+
|
|
16
|
+
- **feat:** Split published CSS into three entry points for Tailwind v3 host compatibility: `styles.css` (full bundle), `styles.modules.css` (SCSS modules only), and `styles.tailwind.css` (Tailwind v4 utilities). Existing `import "@andreyfedkovich/cozy-ui/styles.css"` is unchanged.
|
|
17
|
+
- **build:** `build:lib` now publishes all three files; `verify-lib-styles.mjs` validates each file and the structural bundle concat.
|
|
18
|
+
|
|
6
19
|
## 0.7.0 - 2026-05-26
|
|
7
20
|
|
|
8
21
|
- **feat:** `SettingsView` — composition-first layout for settings pages (`SettingsView.Section`, `.Group`, `.Item`, `.Divider`), declarative `sections`, variants `classic` / `elevated`, densities `comfortable` / `compact`, collapsible sections, left icon badges, row badges (e.g. New/Beta), link rows (`href`, `external`), danger styling, and `render` for full row customization.
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ npm i @andreyfedkovich/cozy-ui
|
|
|
31
31
|
- [Design tokens](#design-tokens)
|
|
32
32
|
- [Component API](#component-api)
|
|
33
33
|
- [Layout & content](#layout--content) — `BaseBlock`, `Card`, `CollapsableBlock`, `Collapse`, `Carousel`, `EmptyComponent`, `Spinner`
|
|
34
|
-
- [Inputs & forms](#inputs--forms) — `Button`, `RadioGroupButton`, `Input`, `Textarea`, `Calendar`, `Checkbox`, `Select`, `DialogSelect`, `TreeDialogSelect`, `InputCaption`, `Label`
|
|
34
|
+
- [Inputs & forms](#inputs--forms) — field validation helpers, `Button`, `RadioGroupButton`, `Input`, `Textarea`, `Calendar`, `Checkbox`, `Select`, `DialogSelect`, `TreeDialogSelect`, `InputCaption`, `Label`
|
|
35
35
|
- [Navigation](#navigation) — `Tabs`, `TabsRounded`, `Stepper`
|
|
36
36
|
- [Overlays](#overlays) — `Popover`, `TooltipDark`, `TooltipLight`
|
|
37
37
|
- [Utility](#utility) — `Tag`, `CopyTextTrigger`
|
|
@@ -78,7 +78,7 @@ yarn add @andreyfedkovich/cozy-ui
|
|
|
78
78
|
|
|
79
79
|
Peer dependencies: **React ≥ 18** and **react-dom ≥ 18** (React 19 supported).
|
|
80
80
|
|
|
81
|
-
Import the stylesheet **once** at your app root
|
|
81
|
+
Import the stylesheet **once** at your app root. Which file depends on your host setup — see [Styling in host apps](#styling-in-host-apps) below.
|
|
82
82
|
|
|
83
83
|
```ts
|
|
84
84
|
import "@andreyfedkovich/cozy-ui/styles.css";
|
|
@@ -86,6 +86,46 @@ import "@andreyfedkovich/cozy-ui/styles.css";
|
|
|
86
86
|
|
|
87
87
|
Sizing uses CSS `rem` against the browser’s default root font size (commonly **16px**). You **do not** need to set `html { font-size: … }` for components to match the library demo.
|
|
88
88
|
|
|
89
|
+
### Styling in host apps
|
|
90
|
+
|
|
91
|
+
The library publishes three CSS entry points:
|
|
92
|
+
|
|
93
|
+
| Import | Contents |
|
|
94
|
+
|--------|----------|
|
|
95
|
+
| `@andreyfedkovich/cozy-ui/styles.css` | Full bundle (SCSS modules + Tailwind v4 utilities) |
|
|
96
|
+
| `@andreyfedkovich/cozy-ui/styles.modules.css` | SCSS modules only — safe alongside Tailwind v3 |
|
|
97
|
+
| `@andreyfedkovich/cozy-ui/styles.tailwind.css` | Tailwind v4 utilities and shadcn design tokens |
|
|
98
|
+
|
|
99
|
+
**A. Host without Tailwind** (greenfield, demo apps):
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import "@andreyfedkovich/cozy-ui/styles.css";
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**B. Host with Tailwind v3 + shadcn** (e.g. existing product apps):
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
// App entry (main.tsx / _app.tsx) — NOT inside your @tailwind index.css
|
|
109
|
+
import "@andreyfedkovich/cozy-ui/styles.modules.css";
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Covers SCSS-native components: `SettingsView`, `Switch`, `SideNav`, `Input`, `Select`, `Stepper`, and most other “cozy-native” UI. The modules bundle does not include Tailwind v4 preflight and will not override your host’s Tailwind reset.
|
|
113
|
+
|
|
114
|
+
**C. You also need Tailwind-based cozy components** (`Calendar`, shadcn wrappers):
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import "@andreyfedkovich/cozy-ui/styles.modules.css";
|
|
118
|
+
import "@andreyfedkovich/cozy-ui/styles.tailwind.css"; // intentional — may conflict with Tailwind v3
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Use this only when you need components that rely on prebuilt Tailwind utilities. **Do not** import `styles.css` or `styles.tailwind.css` in a Tailwind v3 host unless you accept the risk of duplicate preflight and utility conflicts.
|
|
122
|
+
|
|
123
|
+
**Notes:**
|
|
124
|
+
|
|
125
|
+
- Several public components combine SCSS with shadcn primitives — `Button`, `Label`, `Calendar`, `Popover`, and dialog-based components (`DialogSelect`, `ApprovalRoute`, …). In scenario B your host shadcn setup may already style them; if classes or tokens differ, use scenario C.
|
|
126
|
+
- shadcn CSS variables (`--primary`, `--background`, …) live in `styles.tailwind.css`, not in `styles.modules.css`. Tailwind v3 + shadcn hosts usually already define these in `:root`.
|
|
127
|
+
- Import cozy styles at your **app entry**, not inside your Tailwind `@tailwind` CSS file.
|
|
128
|
+
|
|
89
129
|
### Typography (host application)
|
|
90
130
|
|
|
91
131
|
Cozy UI **does not ship font files** and **does not hardcode** a brand typeface. Text components inherit the font from your app (`font-family: inherit` / `var(--cozy-font-family, inherit)`).
|
|
@@ -117,16 +157,18 @@ The library demo uses the system / Inter stack from your app shell — that is e
|
|
|
117
157
|
|
|
118
158
|
### Tailwind-powered components
|
|
119
159
|
|
|
120
|
-
Most Cozy UI styles come from SCSS modules bundled into `styles.css`. Components built on shadcn use Tailwind class names in JS; those utilities are **prebuilt into
|
|
160
|
+
Most Cozy UI styles come from SCSS modules bundled into `styles.modules.css`. Components built on shadcn use Tailwind class names in JS; those utilities are **prebuilt into** `styles.tailwind.css` (and included in the full `styles.css` bundle). You do **not** need Tailwind CSS in your application unless you choose scenario B above.
|
|
161
|
+
|
|
162
|
+
If your app already uses **Tailwind v4** and you prefer to generate utilities yourself, you may add `@source` pointing at the library bundle — optional, not required.
|
|
121
163
|
|
|
122
|
-
If your app
|
|
164
|
+
If your app uses **Tailwind v3**, import `styles.modules.css` only (scenario B) or add `styles.tailwind.css` when needed (scenario C). Do not import the full `styles.css` bundle — it includes Tailwind v4 preflight that conflicts with v3 hosts.
|
|
123
165
|
|
|
124
166
|
### Adding a new Tailwind-based component (library authors)
|
|
125
167
|
|
|
126
168
|
1. Primitive in `src/components/ui/<name>.tsx` (Tailwind + Radix as needed).
|
|
127
169
|
2. Public API in `src/lib/components/<Name>/` (field label, errors, value; SCSS optional for the trigger shell).
|
|
128
170
|
3. Ensure paths are covered by `@source` in `src/lib/tailwind.css` (`../lib/**/*`, `../components/ui/**/*`).
|
|
129
|
-
4. Run `npm run build:lib` before publish; verify `dist-lib/styles.css`
|
|
171
|
+
4. Run `npm run build:lib` before publish; verify `dist-lib/styles.css` (and split files) include the new classes.
|
|
130
172
|
|
|
131
173
|
---
|
|
132
174
|
|
|
@@ -354,6 +396,59 @@ const [view, setView] = useState<"grid" | "list">("grid");
|
|
|
354
396
|
/>;
|
|
355
397
|
```
|
|
356
398
|
|
|
399
|
+
#### Field validation (headless)
|
|
400
|
+
|
|
401
|
+
Form state stays in your app (React Hook Form, TanStack Form, or `useState`). Cozy UI provides a shared **`FieldMeta`** contract and **`showErrorPolicy`** so all fields resolve “when to show the error” the same way.
|
|
402
|
+
|
|
403
|
+
| Export | Description |
|
|
404
|
+
| ------ | ----------- |
|
|
405
|
+
| `FieldMeta` | `touched`, `dirty`, `submitted`, `hasValue`, `invalid`, `errorMessage` |
|
|
406
|
+
| `ShowErrorPolicy` | `"default"` \| `"onBlur"` \| `"onSubmit"` \| `"always"` \| custom `(meta) => boolean` |
|
|
407
|
+
| `resolveShowError`, `resolveFieldError`, `resolveFieldMessage` | Pure functions (SSR-safe) |
|
|
408
|
+
| `useFieldState` | React hook wrapping the resolvers |
|
|
409
|
+
|
|
410
|
+
**Default policy:** `invalid && (touched || submitted || hasValue)`.
|
|
411
|
+
|
|
412
|
+
**Props on fields:** `error` (explicit override), `fieldMeta`, `showErrorPolicy`.
|
|
413
|
+
|
|
414
|
+
**Callback families:**
|
|
415
|
+
|
|
416
|
+
| Family | Components | Value callback | Focus |
|
|
417
|
+
| ------ | ---------- | -------------- | ----- |
|
|
418
|
+
| Native text | `Input`, `Textarea`, `Checkbox` | `onChange(event)` — DOM | `onBlur` / `onFocus` via `...rest` |
|
|
419
|
+
| Value picker | `Select`, `DialogSelect`, `TreeDialogSelect`, `Calendar` | **`onValueChange(value)`** (canonical); `onChange` deprecated alias | `onBlur` / `onFocus` on trigger |
|
|
420
|
+
|
|
421
|
+
```tsx
|
|
422
|
+
import { Input, resolveFieldError } from "@andreyfedkovich/cozy-ui";
|
|
423
|
+
import { useState } from "react";
|
|
424
|
+
|
|
425
|
+
const [email, setEmail] = useState("");
|
|
426
|
+
const [touched, setTouched] = useState(false);
|
|
427
|
+
const [submitted, setSubmitted] = useState(false);
|
|
428
|
+
|
|
429
|
+
const meta = {
|
|
430
|
+
touched,
|
|
431
|
+
submitted,
|
|
432
|
+
hasValue: email.trim().length > 0,
|
|
433
|
+
invalid: !email.includes("@"),
|
|
434
|
+
errorMessage: "Enter a valid email.",
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// Optional: resolve message before render
|
|
438
|
+
resolveFieldError(meta, "default");
|
|
439
|
+
|
|
440
|
+
<Input
|
|
441
|
+
label="Email"
|
|
442
|
+
value={email}
|
|
443
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
444
|
+
onBlur={() => setTouched(true)}
|
|
445
|
+
fieldMeta={meta}
|
|
446
|
+
showErrorPolicy="default"
|
|
447
|
+
/>;
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**React Hook Form (recipe):** use `register` on `Input`; use `Controller` on `Select` with `onValueChange={(opt) => field.onChange(opt)}`.
|
|
451
|
+
|
|
357
452
|
#### `Input`
|
|
358
453
|
|
|
359
454
|
Accessible text field with optional label and validation message for product forms.
|
|
@@ -363,7 +458,9 @@ Accessible text field with optional label and validation message for product for
|
|
|
363
458
|
| `label` | `ReactNode` | — | Field label above the input. |
|
|
364
459
|
| `tooltipContent` | `ReactNode` | — | Help tooltip on the «?» icon next to the label. |
|
|
365
460
|
| `tooltipPopperClassName` | `string` | — | Extra class for the tooltip popper. |
|
|
366
|
-
| `error` | `string \| null` | — | Validation message
|
|
461
|
+
| `error` | `string \| null` | — | Validation message (overrides `fieldMeta`). |
|
|
462
|
+
| `fieldMeta` | `FieldMeta` | — | Form meta for policy-based error display. |
|
|
463
|
+
| `showErrorPolicy` | `ShowErrorPolicy`| `"default"` | When to show `fieldMeta.errorMessage`. |
|
|
367
464
|
| `disabled` | `boolean` | `false` | Disabled state. |
|
|
368
465
|
| `className` | `string` | — | Wrapper class. |
|
|
369
466
|
| `inputClassName` | `string` | — | Native `<input>` class. |
|
|
@@ -435,9 +532,13 @@ Date picker field for forms. Value is stored as `yyyy-MM-dd` (or `null`); the tr
|
|
|
435
532
|
| `label` | `string` | — | Field label. |
|
|
436
533
|
| `required` | `boolean` | `false` | Appends ` *` to the label. |
|
|
437
534
|
| `value` | `string \| null` | — | Selected date as `yyyy-MM-dd`. |
|
|
438
|
-
| `
|
|
535
|
+
| `onValueChange` | `(value: string \| null) => void` | — | Called when the user picks or clears a date. |
|
|
536
|
+
| `onChange` | `(value: string \| null) => void` | — | **Deprecated.** Use `onValueChange`. |
|
|
537
|
+
| `onBlur` / `onFocus` | focus handlers | — | Forwarded to the trigger button. |
|
|
439
538
|
| `minDate` | `Date` | — | Earliest selectable day (inclusive, local calendar). |
|
|
440
|
-
| `error` | `string \| null` | — | Validation message
|
|
539
|
+
| `error` | `string \| null` | — | Validation message (overrides `fieldMeta`). |
|
|
540
|
+
| `fieldMeta` | `FieldMeta` | — | Form meta for policy-based error display. |
|
|
541
|
+
| `showErrorPolicy` | `ShowErrorPolicy` | `"default"` | When to show `fieldMeta.errorMessage`. |
|
|
441
542
|
| `disabled` | `boolean` | `false` | Disables the trigger. |
|
|
442
543
|
| `tooltipContent` | `ReactNode` | — | Help tooltip on the «i» icon next to the label. |
|
|
443
544
|
| `tooltipPopperClassName` | `string` | — | Extra class for the tooltip popper. |
|
|
@@ -458,14 +559,14 @@ const [startDate, setStartDate] = useState<string | null>(null);
|
|
|
458
559
|
label="Дата начала"
|
|
459
560
|
required
|
|
460
561
|
value={startDate}
|
|
461
|
-
|
|
562
|
+
onValueChange={setStartDate}
|
|
462
563
|
minDate={todayLocalDay()}
|
|
463
564
|
/>;
|
|
464
565
|
|
|
465
566
|
<Calendar
|
|
466
567
|
label="Дедлайн"
|
|
467
568
|
value={startDate}
|
|
468
|
-
|
|
569
|
+
onValueChange={setStartDate}
|
|
469
570
|
error="Укажите дату."
|
|
470
571
|
tooltipContent="Дата должна быть не раньше сегодня."
|
|
471
572
|
/>;
|
|
@@ -515,7 +616,10 @@ Powerful, virtualized-friendly select with `single` and `multiple` modes, search
|
|
|
515
616
|
| `mode` | `"single" \| "multiple"` | — | Selection mode. |
|
|
516
617
|
| `value` | `CustomOption \| CustomOption[]` | — | Current value. |
|
|
517
618
|
| `options` | `CustomOption[]` | — | Available options. |
|
|
518
|
-
| `
|
|
619
|
+
| `onValueChange` | `(option) => void` | — | Selection callback (canonical). |
|
|
620
|
+
| `onChange` | `(option) => void` | — | **Deprecated.** Use `onValueChange`. |
|
|
621
|
+
| `onBlur` / `onFocus` | focus handlers on trigger | — | For `touched` tracking. |
|
|
622
|
+
| `fieldMeta` / `showErrorPolicy` | see Field validation | — | Policy-based error display. |
|
|
519
623
|
| `onSearch` | `(value: string) => void` | — | Async search hook. |
|
|
520
624
|
| `template` | `"list" \| "table"` | `"list"` | Dropdown layout. |
|
|
521
625
|
| `columns` | `SelectColumn[]` | — | Required when `template="table"`. |
|
|
@@ -542,7 +646,7 @@ const [value, setValue] = useState<CustomOption<unknown, string> | null>(null);
|
|
|
542
646
|
placeholder="Pick one"
|
|
543
647
|
value={value}
|
|
544
648
|
options={options}
|
|
545
|
-
|
|
649
|
+
onValueChange={setValue}
|
|
546
650
|
/>;
|
|
547
651
|
```
|
|
548
652
|
|
|
@@ -567,7 +671,7 @@ import { DialogSelect } from "@andreyfedkovich/cozy-ui";
|
|
|
567
671
|
const { items, total } = await res.json();
|
|
568
672
|
return { options: items.map((p) => ({ value: p.id, label: p.name })), total };
|
|
569
673
|
}}
|
|
570
|
-
|
|
674
|
+
onValueChange={(opt) => console.log(opt)}
|
|
571
675
|
/>;
|
|
572
676
|
```
|
|
573
677
|
|
|
@@ -592,7 +696,7 @@ import { TreeDialogSelect } from "@andreyfedkovich/cozy-ui";
|
|
|
592
696
|
})}
|
|
593
697
|
searchNodes={async (search) => ({ matches: await searchTreeWithPath(search) })}
|
|
594
698
|
leafConfirmOnly
|
|
595
|
-
|
|
699
|
+
onValueChange={(node) => console.log(node)}
|
|
596
700
|
/>;
|
|
597
701
|
```
|
|
598
702
|
|
|
@@ -1058,6 +1162,19 @@ const [layout, setLayout] = useState<"agent" | "editor">("agent");
|
|
|
1058
1162
|
|
|
1059
1163
|
## Hooks & helpers
|
|
1060
1164
|
|
|
1165
|
+
### Field validation
|
|
1166
|
+
|
|
1167
|
+
```ts
|
|
1168
|
+
import {
|
|
1169
|
+
type FieldMeta,
|
|
1170
|
+
type ShowErrorPolicy,
|
|
1171
|
+
resolveFieldError,
|
|
1172
|
+
resolveFieldMessage,
|
|
1173
|
+
resolveShowError,
|
|
1174
|
+
useFieldState,
|
|
1175
|
+
} from "@andreyfedkovich/cozy-ui";
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1061
1178
|
### `useMeasureElement`
|
|
1062
1179
|
|
|
1063
1180
|
Tracks the size of a DOM element via `ResizeObserver`.
|
|
@@ -1151,7 +1268,7 @@ For per-component overrides, every component accepts a `className` prop and uses
|
|
|
1151
1268
|
```bash
|
|
1152
1269
|
bun install
|
|
1153
1270
|
bun run dev # demo playground at http://localhost:5173
|
|
1154
|
-
bun run build:lib # dist-lib/ (ESM + CJS + .d.ts + styles.css
|
|
1271
|
+
bun run build:lib # dist-lib/ (ESM + CJS + .d.ts + styles.css / styles.modules.css / styles.tailwind.css)
|
|
1155
1272
|
bun run lint
|
|
1156
1273
|
bun run format
|
|
1157
1274
|
```
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { default as FeedbackIcon } from './feedback.svg?react';
|
|
|
25
25
|
import { default as FileReloadIcon } from './fileReload.svg?react';
|
|
26
26
|
import { default as FileSync } from './fileSync.svg?react';
|
|
27
27
|
import { default as FilterIcon } from './filter.svg?react';
|
|
28
|
+
import { FocusEventHandler } from 'react';
|
|
28
29
|
import { default as FolderEditIcon } from './folderEdit.svg?react';
|
|
29
30
|
import { ForwardRefExoticComponent } from 'react';
|
|
30
31
|
import { default as GraduateIcon } from './graduate.svg?react';
|
|
@@ -137,17 +138,17 @@ declare type ButtonSize = "small" | "medium" | "large";
|
|
|
137
138
|
|
|
138
139
|
declare type ButtonVariant = "default" | "primary" | "secondary" | "text" | "link" | "danger";
|
|
139
140
|
|
|
140
|
-
export declare const Calendar: ({ label, required, value, onChange, minDate, error, disabled, tooltipContent, tooltipPopperClassName, className, }: CalendarProps) => JSX.Element;
|
|
141
|
+
export declare const Calendar: ({ label, required, value, onValueChange, onChange, minDate, error, fieldMeta, showErrorPolicy, disabled, onBlur, onFocus, tooltipContent, tooltipPopperClassName, className, }: CalendarProps) => JSX.Element;
|
|
141
142
|
|
|
142
|
-
export declare interface CalendarProps {
|
|
143
|
+
export declare interface CalendarProps extends ValueFieldCallbacks<string | null>, FieldValidationProps {
|
|
143
144
|
label: string;
|
|
144
145
|
required?: boolean;
|
|
145
146
|
value?: string | null;
|
|
146
|
-
onChange: (value: string | null) => void;
|
|
147
147
|
/** Нижняя граница выбора (включительно), локальный календарный день */
|
|
148
148
|
minDate?: Date;
|
|
149
|
-
error?: string | null;
|
|
150
149
|
disabled?: boolean;
|
|
150
|
+
onBlur?: FocusEventHandler<HTMLButtonElement>;
|
|
151
|
+
onFocus?: FocusEventHandler<HTMLButtonElement>;
|
|
151
152
|
/** Подсказка по наведению на иконку «?» справа от подписи */
|
|
152
153
|
tooltipContent?: ReactNode;
|
|
153
154
|
tooltipPopperClassName?: string;
|
|
@@ -203,9 +204,8 @@ export { ChatIcon }
|
|
|
203
204
|
|
|
204
205
|
export declare const Checkbox: ForwardRefExoticComponent<CheckboxProps & RefAttributes<HTMLInputElement>>;
|
|
205
206
|
|
|
206
|
-
export declare interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type"
|
|
207
|
+
export declare interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type">, FieldValidationProps {
|
|
207
208
|
label?: ReactNode;
|
|
208
|
-
error?: string | null;
|
|
209
209
|
checkboxClassName?: string;
|
|
210
210
|
/** Подсказка по наведению на иконку «?» справа от подписи */
|
|
211
211
|
tooltipContent?: ReactNode;
|
|
@@ -387,8 +387,7 @@ export declare interface CustomOption<T, S = string> {
|
|
|
387
387
|
meta?: T;
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
-
declare type CustomSelectProps<T, S> = {
|
|
391
|
-
onChange?: (option: CustomOption<T, S>) => void;
|
|
390
|
+
declare type CustomSelectProps<T, S> = ValueFieldCallbacks<CustomOption<T, S>> & FieldValidationProps & {
|
|
392
391
|
options?: CustomOption<T, S>[];
|
|
393
392
|
placeholder: string;
|
|
394
393
|
dropdownRender?: (menu: ReactNode) => ReactNode;
|
|
@@ -416,7 +415,8 @@ declare type CustomSelectProps<T, S> = {
|
|
|
416
415
|
disabled?: boolean;
|
|
417
416
|
onClose?: () => void;
|
|
418
417
|
portalTarget?: Element;
|
|
419
|
-
|
|
418
|
+
onBlur?: default_2.FocusEventHandler<HTMLDivElement>;
|
|
419
|
+
onFocus?: default_2.FocusEventHandler<HTMLDivElement>;
|
|
420
420
|
template?: "list" | "table";
|
|
421
421
|
columns?: SelectColumn<T, S>[];
|
|
422
422
|
total?: number;
|
|
@@ -483,7 +483,7 @@ export declare interface DetailViewProps {
|
|
|
483
483
|
id?: string;
|
|
484
484
|
}
|
|
485
485
|
|
|
486
|
-
export declare const DialogSelect: <T, S extends string | number>({ value, placeholder, loadOptions, onChange, onClear, columns, label, tooltipContent, tooltipPopperClassName, title, searchPlaceholder, selectButtonText, closeButtonText, manualButtonText, onManualAdd, pageSize, debounceMs, disabled, error, className, inputClassName, selectedOptionRender, }: DialogSelectProps<T, S>) => JSX.Element;
|
|
486
|
+
export declare const DialogSelect: <T, S extends string | number>({ value, placeholder, loadOptions, onValueChange, onChange, onBlur, onFocus, onClear, columns, label, tooltipContent, tooltipPopperClassName, title, searchPlaceholder, selectButtonText, closeButtonText, manualButtonText, onManualAdd, pageSize, debounceMs, disabled, error, fieldMeta, showErrorPolicy, className, inputClassName, selectedOptionRender, }: DialogSelectProps<T, S>) => JSX.Element;
|
|
487
487
|
|
|
488
488
|
export declare type DialogSelectColumn<T, S extends string | number> = {
|
|
489
489
|
key: string;
|
|
@@ -492,12 +492,13 @@ export declare type DialogSelectColumn<T, S extends string | number> = {
|
|
|
492
492
|
render: (option: CustomOption<T, S>) => ReactNode;
|
|
493
493
|
};
|
|
494
494
|
|
|
495
|
-
export declare interface DialogSelectProps<T, S extends string | number> {
|
|
495
|
+
export declare interface DialogSelectProps<T, S extends string | number> extends ValueFieldCallbacks<CustomOption<T, S>>, FieldValidationProps {
|
|
496
496
|
value?: CustomOption<T, S> | null;
|
|
497
497
|
placeholder: string;
|
|
498
498
|
loadOptions: (params: LoadOptionsParams) => Promise<LoadOptionsResult<T, S>>;
|
|
499
|
-
onChange?: (option: CustomOption<T, S>) => void;
|
|
500
499
|
onClear?: () => void;
|
|
500
|
+
onBlur?: default_2.FocusEventHandler<HTMLDivElement>;
|
|
501
|
+
onFocus?: default_2.FocusEventHandler<HTMLDivElement>;
|
|
501
502
|
columns?: DialogSelectColumn<T, S>[];
|
|
502
503
|
label?: ReactNode;
|
|
503
504
|
/** Подсказка по наведению на иконку «?» справа от подписи */
|
|
@@ -512,7 +513,6 @@ export declare interface DialogSelectProps<T, S extends string | number> {
|
|
|
512
513
|
pageSize?: number;
|
|
513
514
|
debounceMs?: number;
|
|
514
515
|
disabled?: boolean;
|
|
515
|
-
error?: string | null;
|
|
516
516
|
className?: string;
|
|
517
517
|
inputClassName?: string;
|
|
518
518
|
selectedOptionRender?: (option: CustomOption<T, S>) => ReactNode;
|
|
@@ -562,8 +562,24 @@ declare interface FieldComponentProps extends Omit<DetailField, "value"> {
|
|
|
562
562
|
className?: string;
|
|
563
563
|
}
|
|
564
564
|
|
|
565
|
+
export declare type FieldMeta = {
|
|
566
|
+
touched?: boolean;
|
|
567
|
+
dirty?: boolean;
|
|
568
|
+
submitted?: boolean;
|
|
569
|
+
hasValue?: boolean;
|
|
570
|
+
invalid?: boolean;
|
|
571
|
+
errorMessage?: string | null;
|
|
572
|
+
};
|
|
573
|
+
|
|
565
574
|
declare const FieldRow: FC<FieldComponentProps>;
|
|
566
575
|
|
|
576
|
+
export declare type FieldValidationProps = {
|
|
577
|
+
/** Explicit error overrides {@link fieldMeta} + policy when set. */
|
|
578
|
+
error?: string | null;
|
|
579
|
+
fieldMeta?: FieldMeta;
|
|
580
|
+
showErrorPolicy?: ShowErrorPolicy;
|
|
581
|
+
};
|
|
582
|
+
|
|
567
583
|
export { FileReloadIcon }
|
|
568
584
|
|
|
569
585
|
export { FileSync }
|
|
@@ -610,7 +626,7 @@ export declare const Input: ForwardRefExoticComponent<InputProps & RefAttributes
|
|
|
610
626
|
|
|
611
627
|
export declare const InputCaption: React_2.FC<PropsWithChildren<InputCaptionProps>>;
|
|
612
628
|
|
|
613
|
-
declare interface InputCaptionProps {
|
|
629
|
+
declare interface InputCaptionProps extends React_2.HTMLAttributes<HTMLParagraphElement> {
|
|
614
630
|
isFullWidth?: boolean;
|
|
615
631
|
/** Visual tone. Defaults to `error` for backwards compatibility with validation messages. */
|
|
616
632
|
variant?: InputCaptionVariant;
|
|
@@ -620,15 +636,16 @@ declare interface InputCaptionProps {
|
|
|
620
636
|
|
|
621
637
|
export declare type InputCaptionVariant = "neutral" | "error" | "success";
|
|
622
638
|
|
|
623
|
-
export declare interface InputProps extends InputHTMLAttributes<HTMLInputElement
|
|
639
|
+
export declare interface InputProps extends InputHTMLAttributes<HTMLInputElement>, FieldValidationProps {
|
|
624
640
|
label?: ReactNode;
|
|
625
|
-
error?: string | null;
|
|
626
641
|
inputClassName?: string;
|
|
627
642
|
/** Подсказка по наведению на иконку «?» справа от подписи */
|
|
628
643
|
tooltipContent?: ReactNode;
|
|
629
644
|
tooltipPopperClassName?: string;
|
|
630
645
|
}
|
|
631
646
|
|
|
647
|
+
export declare function isFieldInvalid(meta: FieldMeta): boolean;
|
|
648
|
+
|
|
632
649
|
export { IslandIcon }
|
|
633
650
|
|
|
634
651
|
declare interface ItemComponentProps extends SettingsItem {
|
|
@@ -782,6 +799,21 @@ declare interface RadioGroupButtonProps<T extends string | number> {
|
|
|
782
799
|
|
|
783
800
|
export { ReloadIcon }
|
|
784
801
|
|
|
802
|
+
export declare function resolveFieldError(meta: FieldMeta | undefined, policy?: ShowErrorPolicy): string | null;
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Resolves the error message to display: explicit `error` wins over fieldMeta + policy.
|
|
806
|
+
*/
|
|
807
|
+
export declare function resolveFieldMessage(options: {
|
|
808
|
+
error?: string | null;
|
|
809
|
+
fieldMeta?: FieldMeta;
|
|
810
|
+
showErrorPolicy?: ShowErrorPolicy;
|
|
811
|
+
}): string | null;
|
|
812
|
+
|
|
813
|
+
export declare function resolveShowError(meta: FieldMeta | undefined, policy?: ShowErrorPolicy): boolean;
|
|
814
|
+
|
|
815
|
+
export declare function resolveValueChangeHandler<T>(callbacks: ValueFieldCallbacks<T>): ((value: T) => void) | undefined;
|
|
816
|
+
|
|
785
817
|
export { SchoolIcon }
|
|
786
818
|
|
|
787
819
|
export { SearchIcon }
|
|
@@ -798,7 +830,7 @@ declare interface SectionComponentProps extends Omit<DetailSection, "fields"> {
|
|
|
798
830
|
declare interface SectionProps extends SideNavSection {
|
|
799
831
|
}
|
|
800
832
|
|
|
801
|
-
export declare const Select: <T, S extends string | number>({ options, value, mode, placeholder, onChange, dropdownRender, optionRender, selectedOptionRender, dropdownIcon, tagRender, dropDownClassName, optionClassName, inputClassName, deleteIconClassName, onDelete, onClear, label, tooltipContent, tooltipPopperClassName, onSearch, searchClassName, searchPlaceholder, isLoading, disabled, onClose, portalTarget, error, template, columns, total, }: CustomSelectProps<T, S>) => JSX.Element;
|
|
833
|
+
export declare const Select: <T, S extends string | number>({ options, value, mode, placeholder, onValueChange, onChange, onBlur, onFocus, dropdownRender, optionRender, selectedOptionRender, dropdownIcon, tagRender, dropDownClassName, optionClassName, inputClassName, deleteIconClassName, onDelete, onClear, label, tooltipContent, tooltipPopperClassName, onSearch, searchClassName, searchPlaceholder, isLoading, disabled, onClose, portalTarget, error, fieldMeta, showErrorPolicy, template, columns, total, }: CustomSelectProps<T, S>) => JSX.Element;
|
|
802
834
|
|
|
803
835
|
export declare type SelectColumn<T, S> = {
|
|
804
836
|
key: string;
|
|
@@ -878,6 +910,8 @@ export declare interface SettingsViewProps {
|
|
|
878
910
|
id?: string;
|
|
879
911
|
}
|
|
880
912
|
|
|
913
|
+
export declare type ShowErrorPolicy = "default" | "onBlur" | "onSubmit" | "always" | ((meta: FieldMeta) => boolean);
|
|
914
|
+
|
|
881
915
|
export declare const SideNav: SideNavComponent;
|
|
882
916
|
|
|
883
917
|
declare type SideNavComponent = FC<SideNavProps> & {
|
|
@@ -1036,10 +1070,9 @@ export { TaskListIcon }
|
|
|
1036
1070
|
|
|
1037
1071
|
export declare const Textarea: ForwardRefExoticComponent<TextareaProps & RefAttributes<HTMLTextAreaElement>>;
|
|
1038
1072
|
|
|
1039
|
-
export declare interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement
|
|
1073
|
+
export declare interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, FieldValidationProps {
|
|
1040
1074
|
label?: ReactNode;
|
|
1041
|
-
error
|
|
1042
|
-
/** Neutral helper text under the textarea (hidden when `error` is set). */
|
|
1075
|
+
/** Neutral helper text under the textarea (hidden when error is shown). */
|
|
1043
1076
|
hint?: ReactNode;
|
|
1044
1077
|
hintVariant?: InputCaptionVariant;
|
|
1045
1078
|
textareaClassName?: string;
|
|
@@ -1098,7 +1131,7 @@ export declare type TooltipTrigger = "hover" | "click";
|
|
|
1098
1131
|
/** `yyyy-MM-dd` for API / form state */
|
|
1099
1132
|
export declare const toYmdString: (d: Date) => string;
|
|
1100
1133
|
|
|
1101
|
-
export declare const TreeDialogSelect: <T, S extends string | number>({ value, placeholder, loadChildren: loadChildrenProp, loadNodes, searchNodes, onChange, onClear, label, tooltipContent, tooltipPopperClassName, title, searchPlaceholder, selectButtonText, closeButtonText, confirmButtonText, debounceMs, disabled, error, className, inputClassName, selectedOptionRender, nodeRender, leafConfirmOnly, }: TreeDialogSelectProps<T, S>) => JSX.Element;
|
|
1134
|
+
export declare const TreeDialogSelect: <T, S extends string | number>({ value, placeholder, loadChildren: loadChildrenProp, loadNodes, searchNodes, onValueChange, onChange, onBlur, onFocus, onClear, label, tooltipContent, tooltipPopperClassName, title, searchPlaceholder, selectButtonText, closeButtonText, confirmButtonText, debounceMs, disabled, error, fieldMeta, showErrorPolicy, className, inputClassName, selectedOptionRender, nodeRender, leafConfirmOnly, }: TreeDialogSelectProps<T, S>) => JSX.Element;
|
|
1102
1135
|
|
|
1103
1136
|
/** Pass either {@link loadNodes} or {@link loadChildren} (deprecated alias). */
|
|
1104
1137
|
export declare type TreeDialogSelectProps<T, S extends string | number> = TreeDialogSelectShared<T, S> & ({
|
|
@@ -1109,12 +1142,13 @@ export declare type TreeDialogSelectProps<T, S extends string | number> = TreeDi
|
|
|
1109
1142
|
loadNodes?: TreeLoader<T, S>;
|
|
1110
1143
|
});
|
|
1111
1144
|
|
|
1112
|
-
declare interface TreeDialogSelectShared<T, S extends string | number> {
|
|
1145
|
+
declare interface TreeDialogSelectShared<T, S extends string | number> extends ValueFieldCallbacks<TreeNode<T, S>>, FieldValidationProps {
|
|
1113
1146
|
value?: TreeNode<T, S> | null;
|
|
1114
1147
|
placeholder: string;
|
|
1115
1148
|
searchNodes?: (search: string) => Promise<TreeSearchResult<T, S>>;
|
|
1116
|
-
onChange?: (node: TreeNode<T, S>) => void;
|
|
1117
1149
|
onClear?: () => void;
|
|
1150
|
+
onBlur?: default_2.FocusEventHandler<HTMLDivElement>;
|
|
1151
|
+
onFocus?: default_2.FocusEventHandler<HTMLDivElement>;
|
|
1118
1152
|
label?: ReactNode;
|
|
1119
1153
|
/** Подсказка по наведению на иконку «?» справа от подписи */
|
|
1120
1154
|
tooltipContent?: ReactNode;
|
|
@@ -1126,7 +1160,6 @@ declare interface TreeDialogSelectShared<T, S extends string | number> {
|
|
|
1126
1160
|
confirmButtonText?: string;
|
|
1127
1161
|
debounceMs?: number;
|
|
1128
1162
|
disabled?: boolean;
|
|
1129
|
-
error?: string | null;
|
|
1130
1163
|
className?: string;
|
|
1131
1164
|
inputClassName?: string;
|
|
1132
1165
|
selectedOptionRender?: (node: TreeNode<T, S>) => ReactNode;
|
|
@@ -1176,6 +1209,12 @@ declare interface UseDropdownPositionProps {
|
|
|
1176
1209
|
onAnchorFrame?: (placement: DropdownPosition) => void;
|
|
1177
1210
|
}
|
|
1178
1211
|
|
|
1212
|
+
export declare function useFieldState(fieldMeta: FieldMeta | undefined, policy?: ShowErrorPolicy, explicitError?: string | null): {
|
|
1213
|
+
showError: boolean;
|
|
1214
|
+
errorMessage: string | null;
|
|
1215
|
+
showErrorByPolicy: boolean;
|
|
1216
|
+
};
|
|
1217
|
+
|
|
1179
1218
|
export declare const useMeasureElement: (element?: HTMLElement | null) => {
|
|
1180
1219
|
height: number;
|
|
1181
1220
|
width: number;
|
|
@@ -1183,6 +1222,13 @@ export declare const useMeasureElement: (element?: HTMLElement | null) => {
|
|
|
1183
1222
|
|
|
1184
1223
|
export { UserSwitchIcon }
|
|
1185
1224
|
|
|
1225
|
+
/** Picker controls: canonical value callback + deprecated alias. */
|
|
1226
|
+
export declare type ValueFieldCallbacks<T> = {
|
|
1227
|
+
onValueChange?: (value: T) => void;
|
|
1228
|
+
/** @deprecated Use {@link onValueChange}. Removed in next major. */
|
|
1229
|
+
onChange?: (value: T) => void;
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1186
1232
|
export { WalletIcon }
|
|
1187
1233
|
|
|
1188
1234
|
export { WarnIcon }
|