prime-ui-kit 0.7.7 → 0.7.9
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/index.css +203 -0
- package/dist/components/index.css.map +3 -3
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +318 -13
- package/dist/components/index.js.map +3 -3
- package/dist/components/popover/Popover.d.ts +6 -1
- package/dist/components/popover/Popover.d.ts.map +1 -1
- package/dist/components/tag-select/TagSelect.d.ts +18 -1
- package/dist/components/tag-select/TagSelect.d.ts.map +1 -1
- package/dist/components/tag-select/examples/pattern-canonical.d.ts +4 -1
- package/dist/components/tag-select/examples/pattern-canonical.d.ts.map +1 -1
- package/dist/components/tag-select/examples/pattern-features.d.ts +1 -1
- package/dist/components/tag-select/examples/pattern-features.d.ts.map +1 -1
- package/dist/index.css +203 -0
- package/dist/index.css.map +3 -3
- package/dist/index.js +318 -13
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
- package/src/components/tag-select/COMPONENT.md +58 -12
- package/src/components/tag-select/examples/pattern-canonical.tsx +51 -10
- package/src/components/tag-select/examples/pattern-features.tsx +44 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prime-ui-kit",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.9",
|
|
4
4
|
"description": "React 19 UI kit: CSS Modules, semantic design tokens (--prime-sys-*), composable components — forms, modals, selects, tables, navigation, overlays. TypeScript, ESM, a11y-oriented.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -19,28 +19,63 @@ A multi-select field: selected values appear as removable chips (styled like [Ta
|
|
|
19
19
|
|
|
20
20
|
## Composition
|
|
21
21
|
|
|
22
|
-
- **`TagSelect.Root`** — owns **`options`**, **`value`** / **`defaultValue`**, **`onValueChange`**, **`creatable`**, **`onCreated`**, **`placeholder`**, **`hint`**, **`size`** (same [`Select`](../select) size axis as **`Select.Root`**), **`disabled`**, **`hasError`**, **`aria-label`** / **`aria-labelledby`**. Renders the chip row + input, a portaled listbox when open, and optional **`ScrollContainer`** for the option list.
|
|
22
|
+
- **`TagSelect.Root`** — owns **`options`**, **`value`** / **`defaultValue`**, **`onValueChange`**, **`creatable`**, **`onCreated`**, **`optionManagement`** (опционально: меню «⋯» у строки — переименование, палитра цветов, удаление из справочника), **`placeholder`**, **`hint`**, **`size`** (same [`Select`](../select) size axis as **`Select.Root`**), **`disabled`**, **`hasError`**, **`aria-label`** / **`aria-labelledby`**. Renders the chip row + input, a portaled listbox when open, and optional **`ScrollContainer`** for the option list.
|
|
23
23
|
|
|
24
24
|
### Canonical example
|
|
25
25
|
|
|
26
|
+
Controlled **`options`**, **`creatable`**, and **`optionManagement`**: keep **`options`** in React state; in **`onUpdate`**, append a row when **`tagValue`** is not found (covers tags created in-session before the parent list includes them).
|
|
27
|
+
|
|
26
28
|
```tsx
|
|
27
29
|
import * as React from "react";
|
|
30
|
+
import type { TagSelectOption } from "prime-ui-kit";
|
|
28
31
|
import { TagSelect } from "prime-ui-kit";
|
|
29
32
|
|
|
33
|
+
const initialOptions: TagSelectOption[] = [
|
|
34
|
+
{ value: "telegram", label: "Telegram", color: "blue" },
|
|
35
|
+
{ value: "whatsapp", label: "WhatsApp", color: "green" },
|
|
36
|
+
];
|
|
37
|
+
|
|
30
38
|
export function Example() {
|
|
31
|
-
const [value, setValue] = React.useState<string[]>([
|
|
39
|
+
const [value, setValue] = React.useState<string[]>([]);
|
|
40
|
+
const [options, setOptions] = React.useState<TagSelectOption[]>(initialOptions);
|
|
32
41
|
|
|
33
42
|
return (
|
|
34
43
|
<TagSelect.Root
|
|
35
|
-
options={
|
|
36
|
-
{ value: "eng", label: "Engineering", color: "blue" },
|
|
37
|
-
{ value: "design", label: "Design", color: "purple" },
|
|
38
|
-
{ value: "sales", label: "Sales", color: "green" },
|
|
39
|
-
]}
|
|
44
|
+
options={options}
|
|
40
45
|
value={value}
|
|
41
46
|
onValueChange={setValue}
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
creatable
|
|
48
|
+
optionManagement={{
|
|
49
|
+
onUpdate: (tagValue, updates) => {
|
|
50
|
+
setOptions((prev) => {
|
|
51
|
+
const i = prev.findIndex((o) => o.value === tagValue);
|
|
52
|
+
if (i === -1) {
|
|
53
|
+
return [
|
|
54
|
+
...prev,
|
|
55
|
+
{
|
|
56
|
+
value: tagValue,
|
|
57
|
+
label: updates.label ?? tagValue,
|
|
58
|
+
color: updates.color ?? "gray",
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
return prev.map((o) =>
|
|
63
|
+
o.value === tagValue
|
|
64
|
+
? {
|
|
65
|
+
...o,
|
|
66
|
+
...(updates.label !== undefined ? { label: updates.label } : {}),
|
|
67
|
+
...(updates.color !== undefined ? { color: updates.color } : {}),
|
|
68
|
+
}
|
|
69
|
+
: o,
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
onDelete: (tagValue) => {
|
|
74
|
+
setOptions((prev) => prev.filter((o) => o.value !== tagValue));
|
|
75
|
+
},
|
|
76
|
+
}}
|
|
77
|
+
placeholder="Channel…"
|
|
78
|
+
aria-label="Contact channels"
|
|
44
79
|
/>
|
|
45
80
|
);
|
|
46
81
|
}
|
|
@@ -50,12 +85,12 @@ export function Example() {
|
|
|
50
85
|
|
|
51
86
|
| File | Intent |
|
|
52
87
|
|------|--------|
|
|
53
|
-
| [`examples/pattern-canonical.tsx`](./examples/pattern-canonical.tsx) |
|
|
54
|
-
| [`examples/pattern-features.tsx`](./examples/pattern-features.tsx) |
|
|
88
|
+
| [`examples/pattern-canonical.tsx`](./examples/pattern-canonical.tsx) | Full stack: **`creatable`**, **`optionManagement`** (⋯), controlled **`options`**; **`prime-ui-kit`** import. |
|
|
89
|
+
| [`examples/pattern-features.tsx`](./examples/pattern-features.tsx) | Same as canonical with **`@/`** imports; mirrors [`playground/snippets/tag-select/features.tsx`](../../../playground/snippets/tag-select/features.tsx). |
|
|
55
90
|
|
|
56
91
|
### Playground
|
|
57
92
|
|
|
58
|
-
Live demo: **`playground/sections/TagSelectSection.tsx`** — snippet **`playground/snippets/tag-select/features.tsx
|
|
93
|
+
Live demo: **`playground/sections/TagSelectSection.tsx`** — snippet **`playground/snippets/tag-select/features.tsx`** (same behavior as the canonical example).
|
|
59
94
|
|
|
60
95
|
**LLM note:** Prefer runnable files under **`./examples/*.tsx`** for prop combinations; this page keeps the contract (rules + API) authoritative.
|
|
61
96
|
|
|
@@ -86,6 +121,7 @@ Live demo: **`playground/sections/TagSelectSection.tsx`** — snippet **`playgro
|
|
|
86
121
|
| placeholder | `string` | `""` | No | Input placeholder |
|
|
87
122
|
| hasError | `boolean` | `false` | No | Error styling |
|
|
88
123
|
| size | `SelectSize` | `"m"` | No | Same size axis as **`Select.Root`** |
|
|
124
|
+
| optionManagement | `TagSelectOptionManagement` | — | No | Меню редактирования опции в списке (⋯): **`onUpdate`**, **`onDelete`**, опционально подписи |
|
|
89
125
|
| id | `string` | — | No | Root id (listbox and input ids are derived) |
|
|
90
126
|
| className | `string` | — | No | Extra class on the root |
|
|
91
127
|
| aria-label | `string` | — | No | Accessible name |
|
|
@@ -100,6 +136,16 @@ Live demo: **`playground/sections/TagSelectSection.tsx`** — snippet **`playgro
|
|
|
100
136
|
| color | `BadgeColor` | No | **`Badge`** **`filled`** color in the list |
|
|
101
137
|
| disabled | `boolean` | No | Option not selectable |
|
|
102
138
|
|
|
139
|
+
### TagSelectOptionManagement
|
|
140
|
+
|
|
141
|
+
| Field | Type | Required | Description |
|
|
142
|
+
|-------|------|----------|-------------|
|
|
143
|
+
| onUpdate | `(value: string, updates: { label?: string; color?: BadgeColor }) => void` | Yes | Обновить подпись и/или цвет; **`value`** опции не меняется |
|
|
144
|
+
| onDelete | `(value: string) => void` | Yes | Удалить опцию из справочника; выбранные значения с этим **`value`** снимаются |
|
|
145
|
+
| colorsSectionLabel | `string` | No | Заголовок блока цветов (по умолчанию «Colors») |
|
|
146
|
+
| deleteLabel | `string` | No | Подпись кнопки удаления (по умолчанию «Delete») |
|
|
147
|
+
| editMenuAriaLabelPrefix | `string` | No | Префикс **`aria-label`** кнопки ⋯ (по умолчанию «Edit tag») |
|
|
148
|
+
|
|
103
149
|
## Related
|
|
104
150
|
|
|
105
151
|
- [Select](../select/COMPONENT.md)
|
|
@@ -1,27 +1,68 @@
|
|
|
1
|
+
import type { TagSelectOption } from "prime-ui-kit";
|
|
1
2
|
import { TagSelect, Typography } from "prime-ui-kit";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
|
|
4
5
|
import styles from "./examples.module.css";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
const initialOptions: TagSelectOption[] = [
|
|
8
|
+
{ value: "telegram", label: "Telegram", color: "blue" },
|
|
9
|
+
{ value: "whatsapp", label: "WhatsApp", color: "green" },
|
|
10
|
+
{ value: "facebook", label: "Facebook", color: "purple" },
|
|
11
|
+
{ value: "viber", label: "Viber", color: "pink" },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Full surface: controlled **`options`**, **`creatable`**, **`optionManagement`** (⋯ rename, colors, delete).
|
|
16
|
+
* New tags stay in the list until refresh; **`onUpdate`** must append when **`value`** is not yet in **`options`**.
|
|
17
|
+
*/
|
|
7
18
|
export default function TagSelectPatternCanonicalExample() {
|
|
8
|
-
const [value, setValue] = React.useState<string[]>([
|
|
19
|
+
const [value, setValue] = React.useState<string[]>([]);
|
|
20
|
+
const [options, setOptions] = React.useState<TagSelectOption[]>(initialOptions);
|
|
9
21
|
|
|
10
22
|
return (
|
|
11
23
|
<div className={`${styles.stack} ${styles.stackNarrow}`}>
|
|
12
24
|
<TagSelect.Root
|
|
13
|
-
options={
|
|
14
|
-
{ value: "eng", label: "Engineering", color: "blue" },
|
|
15
|
-
{ value: "design", label: "Design", color: "purple" },
|
|
16
|
-
{ value: "sales", label: "Sales", color: "green" },
|
|
17
|
-
]}
|
|
25
|
+
options={options}
|
|
18
26
|
value={value}
|
|
19
27
|
onValueChange={setValue}
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
creatable
|
|
29
|
+
optionManagement={{
|
|
30
|
+
onUpdate: (tagValue, updates) => {
|
|
31
|
+
setOptions((prev) => {
|
|
32
|
+
const i = prev.findIndex((o) => o.value === tagValue);
|
|
33
|
+
if (i === -1) {
|
|
34
|
+
return [
|
|
35
|
+
...prev,
|
|
36
|
+
{
|
|
37
|
+
value: tagValue,
|
|
38
|
+
label: updates.label ?? tagValue,
|
|
39
|
+
color: updates.color ?? "gray",
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
return prev.map((o) =>
|
|
44
|
+
o.value === tagValue
|
|
45
|
+
? {
|
|
46
|
+
...o,
|
|
47
|
+
...(updates.label !== undefined ? { label: updates.label } : {}),
|
|
48
|
+
...(updates.color !== undefined ? { color: updates.color } : {}),
|
|
49
|
+
}
|
|
50
|
+
: o,
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
onDelete: (tagValue) => {
|
|
55
|
+
setOptions((prev) => prev.filter((o) => o.value !== tagValue));
|
|
56
|
+
},
|
|
57
|
+
colorsSectionLabel: "Colors",
|
|
58
|
+
deleteLabel: "Delete",
|
|
59
|
+
}}
|
|
60
|
+
placeholder="Channel…"
|
|
61
|
+
aria-label="Contact channels"
|
|
22
62
|
/>
|
|
23
63
|
<Typography.Root as="p" variant="caption" tone="muted" className={styles.caption}>
|
|
24
|
-
|
|
64
|
+
Filter, create tags, use ⋯ to rename, pick a color, or remove from the list. Selected:{" "}
|
|
65
|
+
<code>{value.join(", ") || "—"}</code>
|
|
25
66
|
</Typography.Root>
|
|
26
67
|
</div>
|
|
27
68
|
);
|
|
@@ -1,31 +1,67 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
+
import type { TagSelectOption } from "@/components/tag-select/TagSelect";
|
|
3
4
|
import { TagSelect } from "@/components/tag-select/TagSelect";
|
|
4
5
|
import { Typography } from "@/components/typography/Typography";
|
|
5
6
|
|
|
6
7
|
import styles from "./examples.module.css";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
const initialOptions: TagSelectOption[] = [
|
|
10
|
+
{ value: "telegram", label: "Telegram", color: "blue" },
|
|
11
|
+
{ value: "whatsapp", label: "WhatsApp", color: "green" },
|
|
12
|
+
{ value: "facebook", label: "Facebook", color: "purple" },
|
|
13
|
+
{ value: "viber", label: "Viber", color: "pink" },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
/** Same as `pattern-canonical.tsx` but `@/` imports; mirrors `playground/snippets/tag-select/features.tsx`. */
|
|
9
17
|
export default function TagSelectPatternFeaturesExample() {
|
|
10
18
|
const [value, setValue] = React.useState<string[]>([]);
|
|
19
|
+
const [options, setOptions] = React.useState<TagSelectOption[]>(initialOptions);
|
|
11
20
|
|
|
12
21
|
return (
|
|
13
22
|
<div className={`${styles.stack} ${styles.stackNarrow}`}>
|
|
14
23
|
<TagSelect.Root
|
|
15
|
-
options={
|
|
16
|
-
{ value: "telegram", label: "telegram", color: "blue" },
|
|
17
|
-
{ value: "whatsapp", label: "whatsapp", color: "green" },
|
|
18
|
-
{ value: "facebook", label: "facebook", color: "purple" },
|
|
19
|
-
{ value: "viber", label: "viber", color: "pink" },
|
|
20
|
-
]}
|
|
24
|
+
options={options}
|
|
21
25
|
value={value}
|
|
22
26
|
onValueChange={setValue}
|
|
23
27
|
creatable
|
|
28
|
+
optionManagement={{
|
|
29
|
+
onUpdate: (tagValue, updates) => {
|
|
30
|
+
setOptions((prev) => {
|
|
31
|
+
const i = prev.findIndex((o) => o.value === tagValue);
|
|
32
|
+
if (i === -1) {
|
|
33
|
+
return [
|
|
34
|
+
...prev,
|
|
35
|
+
{
|
|
36
|
+
value: tagValue,
|
|
37
|
+
label: updates.label ?? tagValue,
|
|
38
|
+
color: updates.color ?? "gray",
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
return prev.map((o) =>
|
|
43
|
+
o.value === tagValue
|
|
44
|
+
? {
|
|
45
|
+
...o,
|
|
46
|
+
...(updates.label !== undefined ? { label: updates.label } : {}),
|
|
47
|
+
...(updates.color !== undefined ? { color: updates.color } : {}),
|
|
48
|
+
}
|
|
49
|
+
: o,
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
onDelete: (tagValue) => {
|
|
54
|
+
setOptions((prev) => prev.filter((o) => o.value !== tagValue));
|
|
55
|
+
},
|
|
56
|
+
colorsSectionLabel: "Colors",
|
|
57
|
+
deleteLabel: "Delete",
|
|
58
|
+
}}
|
|
24
59
|
placeholder="Channel…"
|
|
25
60
|
aria-label="Contact channels"
|
|
26
61
|
/>
|
|
27
62
|
<Typography.Root as="p" variant="caption" tone="muted" className={styles.caption}>
|
|
28
|
-
|
|
63
|
+
Filter, create tags, use ⋯ to rename, pick a color, or remove from the list. Selected:{" "}
|
|
64
|
+
<code>{value.join(", ") || "—"}</code>
|
|
29
65
|
</Typography.Root>
|
|
30
66
|
</div>
|
|
31
67
|
);
|