@llmnative/react 1.22.1 → 1.24.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.
@@ -340,6 +340,12 @@ export interface ThemeConfig {
340
340
  wrapperClassName?: string;
341
341
  className?: string;
342
342
  };
343
+ Tree?: {
344
+ wrapperClassName?: string;
345
+ className?: string;
346
+ itemClassName?: string;
347
+ selectedClassName?: string;
348
+ };
343
349
  DescriptionList?: {
344
350
  wrapperClassName?: string;
345
351
  className?: string;
@@ -16,6 +16,8 @@ export { default as Alert } from './ui/Alert';
16
16
  export type { AlertProps } from './ui/Alert';
17
17
  export { default as Badge } from './ui/Badge';
18
18
  export { default as DescriptionList } from './ui/DescriptionList';
19
+ export { default as Tree, treeFromPaths } from './ui/Tree';
20
+ export type { TreeNode, TreeProps } from './ui/Tree';
19
21
  export type { DescriptionListItem, DescriptionListLayout, DescriptionListColumns, DescriptionListProps } from './ui/DescriptionList';
20
22
  export * from './ui/Badge';
21
23
  export * from './ui/Buttons';
@@ -59,7 +61,7 @@ export type { ListCardProps } from './blocks/ListCard';
59
61
  export { default as SideNav } from './blocks/SideNav';
60
62
  export type { SideNavProps, SideNavItemDef } from './blocks/SideNav';
61
63
  export { default as Form, useFormContext } from './widgets/Form';
62
- export type { FormProps, FormDeleteArgs, FormDeleteHandler, FormFinallyArgs, FormFinallyHandler, FormSaveArgs, FormSaveHandler, ChangeHandler, FieldOnChange } from './widgets/Form';
64
+ export type { FieldLabel, FormFieldProps, FormProps, FormDeleteArgs, FormDeleteHandler, FormFinallyArgs, FormFinallyHandler, FormSaveArgs, FormSaveHandler, ChangeHandler, FieldOnChange } from './widgets/Form';
63
65
  export { FormControllerContext, useFormActions, useFormController } from './widgets/form-controller';
64
66
  export type { FormActionEvent, FormController, FormControllerActions, FormControllerState, FormDraftStatus } from './widgets/form-controller';
65
67
  export { default as Grid } from './widgets/Grid';
@@ -0,0 +1,47 @@
1
+ import React from "react";
2
+ /** One node of a `<Tree>`: a leaf, or a branch with `children`. */
3
+ export interface TreeNode {
4
+ /** Unique in the tree: it is what `selectedId`, `expanded` and `onSelect` speak of. */
5
+ id: string;
6
+ label: React.ReactNode;
7
+ /** Icon name; branches default to a folder, leaves to a file. */
8
+ icon?: string;
9
+ /** Shown after the label, e.g. a count or a status. */
10
+ badge?: React.ReactNode;
11
+ /** Muted text after the label, e.g. what a file is for. */
12
+ description?: React.ReactNode;
13
+ children?: TreeNode[];
14
+ disabled?: boolean;
15
+ }
16
+ export interface TreeProps {
17
+ nodes: readonly TreeNode[];
18
+ /** Selected node (controlled). */
19
+ selectedId?: string | null;
20
+ /** Selected node at start (uncontrolled). */
21
+ defaultSelectedId?: string | null;
22
+ onSelect?: (node: TreeNode) => void;
23
+ /** Open branches (controlled). */
24
+ expanded?: readonly string[];
25
+ /** Open branches at start (uncontrolled); `true` opens them all. */
26
+ defaultExpanded?: readonly string[] | true;
27
+ onExpandedChange?: (expanded: string[]) => void;
28
+ /** Branches can be selected too, not only opened. Default `false`. */
29
+ selectableBranches?: boolean;
30
+ /** Accessible name of the tree. */
31
+ ariaLabel?: string;
32
+ wrapperClassName?: string;
33
+ className?: string;
34
+ itemClassName?: string;
35
+ selectedClassName?: string;
36
+ }
37
+ /**
38
+ * A tree of nodes (folders and files, a hierarchy), WAI-ARIA tree pattern: one tab stop, arrows to
39
+ * move, → / ← to open and close, Enter or Space to select. Branches open on click; leaves are
40
+ * selected. Expansion and selection work controlled or uncontrolled.
41
+ */
42
+ export default function Tree({ nodes, selectedId, defaultSelectedId, onSelect, expanded, defaultExpanded, onExpandedChange, selectableBranches, ariaLabel, wrapperClassName, className, itemClassName, selectedClassName, }: TreeProps): React.JSX.Element;
43
+ /**
44
+ * A tree from `a/b/c` paths: one branch per folder, one leaf per path (its id is the full path,
45
+ * folders get `path/`). Folders come before files, each sorted by name. `leaf` decorates a leaf.
46
+ */
47
+ export declare function treeFromPaths(paths: readonly string[], leaf?: (path: string) => Partial<TreeNode>): TreeNode[];
@@ -36,7 +36,7 @@ export interface CodeEditorProps extends FormFieldProps {
36
36
  * for `'fill'` to have any effect. */
37
37
  minHeight?: EditorHeight;
38
38
  maxHeight?: number;
39
- label?: string;
39
+ label?: FormFieldProps['label'];
40
40
  required?: boolean;
41
41
  disabled?: boolean;
42
42
  feedback?: string;
@@ -21,7 +21,7 @@ export interface ImageFieldProps extends FormFieldProps {
21
21
  * Example: "/content/posts/images"
22
22
  */
23
23
  uploadPath?: string;
24
- label?: string;
24
+ label?: FormFieldProps['label'];
25
25
  required?: boolean;
26
26
  disabled?: boolean;
27
27
  feedback?: string;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { UIProps } from '../../..';
3
- import { FormFieldProps, InputType } from '../../widgets/Form';
3
+ import { FieldLabel, FormFieldProps, InputType } from '../../widgets/Form';
4
4
  import type { FieldValue } from '../../../providers/data/DataProvider';
5
5
  interface BaseInputProps extends FormFieldProps {
6
6
  placeholder?: string;
@@ -19,7 +19,8 @@ interface BaseInputProps extends FormFieldProps {
19
19
  afterInset?: React.ReactNode;
20
20
  }
21
21
  interface LabelProps {
22
- label: string;
22
+ /** A text or a React node, drawn inside the `<label>` before the required mark. */
23
+ label: FieldLabel;
23
24
  required?: boolean;
24
25
  htmlFor?: string;
25
26
  className?: string;
@@ -17,7 +17,8 @@ interface UploadCSVProps extends UIProps {
17
17
  onDataLoaded: UploadCSVDataLoadedHandler;
18
18
  onClear?: () => void;
19
19
  onParseField?: UploadCSVParseFieldHandler;
20
- label?: string;
20
+ /** A text or a React node, as the label of the other fields. */
21
+ label?: React.ReactNode;
21
22
  icon?: string;
22
23
  delimiter?: string;
23
24
  normalizeKeys?: boolean;
@@ -41,9 +41,12 @@ interface FormContextResult {
41
41
  formWrapClass?: string;
42
42
  record: RecordProps;
43
43
  }
44
+ /** Label of a field: a text, or a React node (e.g. the text with an info button next to it). */
45
+ export type FieldLabel = React.ReactNode;
44
46
  export interface FormFieldProps extends UIProps {
45
47
  name: string;
46
- label?: string;
48
+ /** A text or a React node; where a text is needed (messages, `aria-label`) its text is used. */
49
+ label?: FieldLabel;
47
50
  labelMode?: LabelMode;
48
51
  value?: FieldValue;
49
52
  required?: boolean;
@@ -59,7 +62,7 @@ interface SetFormFieldsNameProps {
59
62
  }
60
63
  interface FieldValidationConstraints {
61
64
  required?: boolean;
62
- label?: string;
65
+ label?: FieldLabel;
63
66
  validator?: (value: FieldValue) => string | undefined | Promise<string | undefined>;
64
67
  }
65
68
  interface FormValidationContextValue {
@@ -50,7 +50,7 @@ type RenderAIUnavailable = (props: {
50
50
  }) => React.ReactNode;
51
51
  interface PromptFieldBase {
52
52
  name: string;
53
- label?: string;
53
+ label?: FormFieldProps["label"];
54
54
  required?: boolean;
55
55
  onChange?: FormFieldProps["onChange"];
56
56
  before?: React.ReactNode;
@@ -8,5 +8,6 @@ export * from './csv';
8
8
  export * from './utils';
9
9
  export * from './order';
10
10
  export { cn } from './cn';
11
+ export { labelText } from './labelText';
11
12
  export { useImage } from './imageBuilder';
12
13
  export type { UseImageResult, ImageBuilderConfig, SrcsetConfig, SrcsetDensityConfig, SrcsetWidthConfig, ImageParams, ImgFit } from './imageBuilder';
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ /**
3
+ * The plain text of a label that may be a React node (`FieldLabel`): the strings and numbers it
4
+ * contains, in order, with whitespace collapsed. Used where a label must be text, such as the
5
+ * "required" message of a form or an `aria-label`.
6
+ *
7
+ * ```ts
8
+ * labelText(<>Skill <InfoButton /></>) // "Skill"
9
+ * ```
10
+ */
11
+ export declare function labelText(node: React.ReactNode): string;
package/llms-full.txt CHANGED
@@ -326,6 +326,11 @@ Azioni: `save()`, `delete()`, `reset()`, `restoreDraft()`, `discardDraft()`.
326
326
 
327
327
  **NOTA**: il tipo HTML si passa con `type`. `inputType` e i sotto-componenti `Input.Number`/`Input.Email`/`Input.Date` non esistono.
328
328
 
329
+ **Label come nodo**: `label` di tutti i campi di inserimento (`Input`, `TextArea`, `Checkbox`, `Select`, `Autocomplete`, `Checklist`, `Upload*`, `ImageField`, `CodeEditor`, `RichText`, `AddressAutocomplete`, `UploadCSV`, `Prompt`) accetta una stringa o un nodo React (tipo `FieldLabel`), disegnato dentro la `<label>` prima dell'asterisco di obbligatorio. Dove serve un testo (messaggio "obbligatorio", `aria-label`) si usa il testo del nodo, ricavabile anche con `labelText(node)`.
330
+ ```tsx
331
+ <Select name="skill" required options={skills} label={<>Skill <ActionButton icon="info" ariaLabel="Apri la skill" variant="link" onClick={openSkill} /></>} />
332
+ ```
333
+
329
334
  ### Select / Autocomplete / Checklist
330
335
  ```tsx
331
336
  <Select name="role" options={[{ label: 'Admin', value: 'admin' }]} />
@@ -708,6 +713,23 @@ Coppie etichetta → valore in sola lettura (profilo, dati di un record, riepilo
708
713
  | `truncate` | `boolean` | `false`; un valore testuale diventa il suo `title` |
709
714
  | Classi | `wrapperClassName`, `className`, `itemClassName`, `labelClassName`, `valueClassName` | tema `DescriptionList` |
710
715
 
716
+ ### Tree
717
+ Albero accessibile di nodi (cartelle e file, gerarchie): pattern WAI-ARIA tree, un solo tab stop, frecce per muoversi, → / ← per aprire e chiudere, Invio o Spazio per selezionare. Le cartelle si aprono al click, le foglie si selezionano.
718
+ ```tsx
719
+ <Tree nodes={treeFromPaths(paths)} defaultExpanded selectedId={path} onSelect={(node) => setPath(node.id)} ariaLabel="File" />
720
+ <Tree nodes={[{ id: 'a', label: 'Docs', children: [{ id: 'a/1', label: 'README.md', badge: <Badge>new</Badge> }] }]} />
721
+ ```
722
+ | Prop | Tipo | Note |
723
+ |---|---|---|
724
+ | `nodes` | `TreeNode[]` — `{ id, label, icon?, badge?, description?, children?, disabled? }` | `id` unico; con `children` è una cartella |
725
+ | `selectedId` + `onSelect` / `defaultSelectedId` | `string \| null` | selezione controllata o no |
726
+ | `expanded` + `onExpandedChange` / `defaultExpanded` | `string[]`; `defaultExpanded` anche `true` (tutto aperto) | apertura controllata o no |
727
+ | `selectableBranches` | `boolean` (default `false`) | anche le cartelle si selezionano |
728
+ | `ariaLabel` | `string` | nome accessibile |
729
+ | Classi | `wrapperClassName`, `className`, `itemClassName`, `selectedClassName` | tema `Tree` |
730
+
731
+ `treeFromPaths(paths, leaf?)` costruisce l'albero da percorsi `a/b/c`: cartelle prima dei file, ordinati; l'id di un file è il percorso, quello di una cartella `percorso/`; `leaf(path)` decora le foglie (label, icona, descrizione…).
732
+
711
733
  ### Dropdown
712
734
  ```tsx
713
735
  <Dropdown trigger={<Icon name="menu" />} position="end">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llmnative/react",
3
- "version": "1.22.1",
3
+ "version": "1.24.0",
4
4
  "description": "LLM-native React framework for deterministic UI generation. Data-driven by default, schema-driven optional. Ultra-low token consumption — built for AI agents, not just humans.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/themes/cyber.ts CHANGED
@@ -446,6 +446,12 @@ export const components: Theme = {
446
446
  wrapperClassName: '',
447
447
  className: '',
448
448
  },
449
+ Tree: {
450
+ wrapperClassName: '',
451
+ className: '',
452
+ itemClassName: '',
453
+ selectedClassName: '',
454
+ },
449
455
  DescriptionList: {
450
456
  wrapperClassName: '',
451
457
  className: '',
package/themes/default.ts CHANGED
@@ -460,6 +460,12 @@ export const components: Theme = {
460
460
  wrapperClassName: '',
461
461
  className: '',
462
462
  },
463
+ Tree: {
464
+ wrapperClassName: '',
465
+ className: '',
466
+ itemClassName: '',
467
+ selectedClassName: '',
468
+ },
463
469
  DescriptionList: {
464
470
  wrapperClassName: '',
465
471
  className: '',
package/themes/flat.ts CHANGED
@@ -446,6 +446,12 @@ export const components: Theme = {
446
446
  wrapperClassName: '',
447
447
  className: '',
448
448
  },
449
+ Tree: {
450
+ wrapperClassName: '',
451
+ className: '',
452
+ itemClassName: '',
453
+ selectedClassName: '',
454
+ },
449
455
  DescriptionList: {
450
456
  wrapperClassName: '',
451
457
  className: '',