@overdoser/react-toolkit 0.0.8 → 0.0.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/llms.txt CHANGED
@@ -367,6 +367,9 @@ Props:
367
367
  - `onValueChange?: (value: string) => void` — single-mode value-only callback.
368
368
  - `onValuesChange?: (values: string[]) => void` — multi-mode callback.
369
369
  - `clearSearchOnSelect?: boolean` — default `true`. Multi-mode only.
370
+ - `allowCreate?: boolean` — default `false`. Multi-mode only. Adds a "Create '<query>'" row when the search query doesn't match an existing option. Pressing Enter (or clicking the row) pushes the trimmed query into `onValuesChange` and fires `onCreate`.
371
+ - `onCreate?: (value: string) => void` — Multi-mode only, paired with `allowCreate`. Fires with the new value; consumers typically persist it (e.g. push it back into `options`).
372
+ - `createLabel?: (query: string) => ReactNode` — Multi-mode only. Custom render for the create row. Default: `Create "<query>"`.
370
373
  - `classes?: Partial<SelectClasses>` where `SelectClasses = { wrapper, root, arrow, search, menu, item, chip, chipRemove }`
371
374
 
372
375
  Searchable example:
package/manifest.json CHANGED
@@ -253,6 +253,9 @@
253
253
  "onValueChange": { "type": "(value: string) => void", "notes": "Single-mode value-only callback." },
254
254
  "onValuesChange": { "type": "(values: string[]) => void", "notes": "Multi-mode callback." },
255
255
  "clearSearchOnSelect": { "type": "boolean", "default": true, "notes": "Multi-mode only." },
256
+ "allowCreate": { "type": "boolean", "default": false, "notes": "Multi-mode only. Adds a 'Create <query>' row when the query doesn't match an existing option; pressing Enter (or clicking it) pushes the trimmed query into onValuesChange and fires onCreate." },
257
+ "onCreate": { "type": "(value: string) => void", "notes": "Multi-mode only. Paired with allowCreate." },
258
+ "createLabel": { "type": "(query: string) => ReactNode", "notes": "Multi-mode only. Custom render for the Create row." },
256
259
  "classes": { "type": "Partial<SelectClasses>", "shape": ["wrapper", "root", "arrow", "search", "menu", "item", "chip", "chipRemove"] }
257
260
  }
258
261
  },
@@ -659,6 +662,7 @@
659
662
  "recipes/interactive-line-chart.tsx",
660
663
  "recipes/interactive-area-chart.tsx",
661
664
  "recipes/interactive-pie-chart.tsx",
662
- "recipes/trading-chart.tsx"
665
+ "recipes/trading-chart.tsx",
666
+ "recipes/tag-input.tsx"
663
667
  ]
664
668
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@overdoser/react-toolkit",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",
@@ -0,0 +1,71 @@
1
+ import { useState } from 'react';
2
+ import { useForm } from 'react-hook-form';
3
+ import { Button, Form, FormField, Select } from '@overdoser/react-toolkit';
4
+
5
+ interface TagOption {
6
+ value: string;
7
+ label: string;
8
+ }
9
+
10
+ const INITIAL_TAGS: TagOption[] = [
11
+ { value: 'react', label: 'React' },
12
+ { value: 'typescript', label: 'TypeScript' },
13
+ { value: 'rust', label: 'Rust' },
14
+ { value: 'go', label: 'Go' },
15
+ { value: 'python', label: 'Python' },
16
+ ];
17
+
18
+ /**
19
+ * Tag-input pattern using `<Select multiple allowCreate>`. Users can pick
20
+ * from existing tags or type a new one + Enter to create it. The freshly
21
+ * created value is selected immediately; the consumer persists it back into
22
+ * `options` via `onCreate` so future searches surface it.
23
+ *
24
+ * Wired through `<FormField>` to show react-hook-form integration. The
25
+ * standalone uncontrolled form (no `<Form>`) works just as well — just use
26
+ * `useState` for the selected values + the options list.
27
+ */
28
+ export function TagInputRecipe({
29
+ onSubmit,
30
+ }: {
31
+ onSubmit?: (values: { tags: string[] }) => void;
32
+ }) {
33
+ const form = useForm<{ tags: string[] }>({ defaultValues: { tags: [] } });
34
+ const [options, setOptions] = useState<TagOption[]>(INITIAL_TAGS);
35
+
36
+ return (
37
+ <Form
38
+ form={form}
39
+ onSubmit={(values) => onSubmit?.(values)}
40
+ >
41
+ <FormField
42
+ name="tags"
43
+ label="Tags"
44
+ helperText="Pick existing tags or type a new one and press Enter"
45
+ >
46
+ <Select
47
+ multiple
48
+ allowCreate
49
+ options={options}
50
+ onCreate={(value) => {
51
+ // Persist the new tag back into the option list so future searches
52
+ // find it. Avoid duplicating if a race added it elsewhere.
53
+ setOptions((prev) =>
54
+ prev.some((o) => o.value === value) ? prev : [...prev, { value, label: value }],
55
+ );
56
+ }}
57
+ placeholder="Pick or create tags…"
58
+ searchPlaceholder="Type a tag…"
59
+ createLabel={(q) => (
60
+ <>
61
+ Add tag &ldquo;<strong>{q}</strong>&rdquo;
62
+ </>
63
+ )}
64
+ />
65
+ </FormField>
66
+ <Button type="submit" variant="primary">
67
+ Save
68
+ </Button>
69
+ </Form>
70
+ );
71
+ }