@llmnative/react 1.1.0 → 1.2.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.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/dist/index.css +3 -1
  3. package/dist/index.js +20 -23
  4. package/dist/index.mjs +18040 -17552
  5. package/dist/types/src/I18n.d.ts +3 -0
  6. package/dist/types/src/components/ErrorBoundary.d.ts +1 -1
  7. package/dist/types/src/components/blocks/Dropdown.d.ts +27 -2
  8. package/dist/types/src/components/ui/Alert.d.ts +1 -1
  9. package/dist/types/src/components/ui/Gallery.d.ts +6 -0
  10. package/dist/types/src/components/ui/Loader.d.ts +1 -1
  11. package/dist/types/src/components/ui/Modal.d.ts +18 -0
  12. package/dist/types/src/components/ui/Tab.d.ts +1 -1
  13. package/dist/types/src/components/ui/fields/CodeEditor.d.ts +6 -1
  14. package/dist/types/src/components/ui/fields/ContextMenu.d.ts +24 -0
  15. package/dist/types/src/components/ui/fields/Upload.d.ts +1 -1
  16. package/dist/types/src/components/widgets/Form.d.ts +14 -3
  17. package/dist/types/src/components/widgets/grid-core/GridCore.d.ts +1 -1
  18. package/dist/types/src/components/widgets/grid-core/GridGalleryView.d.ts +1 -1
  19. package/dist/types/src/components/widgets/grid-core/types.d.ts +79 -3
  20. package/dist/types/src/components/widgets/grid-core/useGridActions.d.ts +1 -1
  21. package/dist/types/src/index.d.ts +2 -2
  22. package/dist/types/src/libs/editorHeight.d.ts +11 -1
  23. package/dist/types/src/libs/fetch.d.ts +2 -0
  24. package/dist/types/src/providers/ai/AIProvider.d.ts +54 -1
  25. package/dist/types/src/providers/ai/index.d.ts +1 -1
  26. package/dist/types/src/providers/ai/openaiCompatible.d.ts +22 -0
  27. package/dist/types/src/providers/ai/shared.d.ts +3 -3
  28. package/dist/types/src/providers/auth/google/auth.d.ts +1 -1
  29. package/dist/types/src/providers/data/DataProvider.d.ts +8 -0
  30. package/dist/types/src/providers/data/firestore.d.ts +11 -0
  31. package/dist/vite.js +1 -1
  32. package/dist/vite.mjs +62 -53
  33. package/package.json +49 -52
  34. package/scripts/cli/setup-devtools.js +8 -7
  35. package/scripts/cli/setup-project.js +23 -19
  36. package/themes/cyber.ts +8 -7
  37. package/themes/default.ts +22 -7
  38. package/themes/flat.ts +8 -7
  39. package/dist/style.css +0 -1
  40. package/dist/types/src/providers/email/google/apis/email.d.ts +0 -7
@@ -57,6 +57,9 @@ export interface I18nDict {
57
57
  delete: string;
58
58
  cancel: string;
59
59
  close: string;
60
+ ok: string;
61
+ yes: string;
62
+ no: string;
60
63
  };
61
64
  upload: {
62
65
  clickOrDrag: string;
@@ -25,6 +25,6 @@ declare class ErrorBoundary extends React.Component<ErrorBoundaryProps, State> {
25
25
  reset: () => void;
26
26
  copy: () => void;
27
27
  sendReport: () => void;
28
- render(): string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
28
+ render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
29
29
  }
30
30
  export default ErrorBoundary;
@@ -7,7 +7,7 @@ interface DropdownTogglerProps {
7
7
  text?: string;
8
8
  title?: string;
9
9
  }
10
- interface DropdownProps extends MotionUIProps {
10
+ export interface DropdownProps extends MotionUIProps {
11
11
  children: React.ReactNode;
12
12
  /** Dropdown trigger: string (label), React element, or `DropdownTogglerProps` object. */
13
13
  trigger?: string | React.ReactNode | DropdownTogglerProps;
@@ -34,6 +34,26 @@ interface DropdownProps extends MotionUIProps {
34
34
  headerClassName?: string;
35
35
  footerClassName?: string;
36
36
  }
37
+ export type AsyncDropdownLoader<TItem> = (query: string, signal: AbortSignal) => Promise<TItem[]>;
38
+ export interface AsyncDropdownProps<TItem> extends Omit<DropdownProps, 'children' | 'header' | 'onOpenChange'> {
39
+ /** Loads results when the menu opens and whenever the query changes. */
40
+ loadItems: AsyncDropdownLoader<TItem>;
41
+ getItemId: (item: TItem) => string;
42
+ renderItem: (item: TItem) => React.ReactNode;
43
+ /** Return `false` to keep the menu open (for example after a declined confirmation). */
44
+ onSelect: (item: TItem) => void | boolean | Promise<void | boolean>;
45
+ selectedId?: string | null;
46
+ searchPlaceholder?: string;
47
+ emptyState?: React.ReactNode;
48
+ loadingState?: React.ReactNode;
49
+ errorState?: (error: unknown) => React.ReactNode;
50
+ debounceMs?: number;
51
+ closeOnSelect?: boolean;
52
+ inputClassName?: string;
53
+ selectedClassName?: string;
54
+ header?: React.ReactNode;
55
+ onOpenChange?: (open: boolean) => void;
56
+ }
37
57
  interface DropdownButtonProps extends Pick<MotionUIProps, 'motion'> {
38
58
  children: React.ReactNode;
39
59
  badge?: BadgeProps;
@@ -45,7 +65,7 @@ interface DropdownButtonProps extends Pick<MotionUIProps, 'motion'> {
45
65
  onToggle?: () => void;
46
66
  open?: boolean;
47
67
  menuId?: string;
48
- buttonRef?: React.RefObject<HTMLButtonElement>;
68
+ buttonRef?: React.RefObject<HTMLButtonElement | null>;
49
69
  }
50
70
  interface DropdownItemProps {
51
71
  /** Link URL. When set, renders as `<a>`, otherwise as `<button>`. */
@@ -64,6 +84,11 @@ interface DropdownDividerProps {
64
84
  className?: string;
65
85
  }
66
86
  export declare const Dropdown: ({ children, trigger, badge, header, footer, defaultOpen, open: controlledOpen, onOpenChange, staticOpen, position, placement, strategy, wrapperClassName, className, before, after, triggerClassName, menuClassName, badgeClassName, headerClassName, footerClassName, motion: motionConfig, }: DropdownProps) => React.JSX.Element;
87
+ /**
88
+ * Async/searchable extension of Dropdown. It owns only the interaction model; applications
89
+ * supply their own data reader and selection action (site, tenant, entity, or any resource).
90
+ */
91
+ export declare function AsyncDropdown<TItem>({ loadItems, getItemId, renderItem, onSelect, selectedId, searchPlaceholder, emptyState, loadingState, errorState, debounceMs, closeOnSelect, inputClassName, selectedClassName, header, open: controlledOpen, defaultOpen, onOpenChange, footer, headerClassName, staticOpen, ...dropdownProps }: AsyncDropdownProps<TItem>): React.JSX.Element;
67
92
  export declare const DropdownButton: ({ children, badge, display, className, badgeClassName, motion: motionConfig, title, onToggle, open, menuId, buttonRef }: DropdownButtonProps) => React.JSX.Element;
68
93
  export declare const DropdownItem: ({ children, url, onClick, icon, className }: DropdownItemProps) => React.JSX.Element;
69
94
  export declare const DropdownHeader: ({ children, className }: DropdownHeaderProps) => React.JSX.Element;
@@ -16,7 +16,7 @@ export type AlertProps = {
16
16
  */
17
17
  placement?: "inline" | "fixed" | "sticky";
18
18
  /** Required when placement="sticky": the scrollable container to anchor to. */
19
- anchorRef?: React.RefObject<HTMLElement>;
19
+ anchorRef?: React.RefObject<HTMLElement | null>;
20
20
  /** Auto-dismiss timeout in ms. */
21
21
  timeout?: number;
22
22
  /** Called when the alert is dismissed. */
@@ -26,6 +26,12 @@ export type GalleryOverlay = {
26
26
  render?: (item: GalleryRecord, index: number) => React.ReactNode;
27
27
  when?: GalleryOverlayFilter;
28
28
  className?: string;
29
+ /**
30
+ * Inline style overrides, merged on top of the position's own offset styles (and, for
31
+ * `width`/`maxWidth`, on top of the default overlay lane width — a single-line badge's
32
+ * width, too narrow for e.g. a multi-line description meant to span most of the card).
33
+ */
34
+ style?: React.CSSProperties;
29
35
  };
30
36
  export type GallerySelectionState = RecordSelectionState<GalleryRecord>;
31
37
  export type GallerySelectionChangeHandler = (selection: GallerySelectionState) => void;
@@ -9,5 +9,5 @@ interface LoaderProps extends UIProps {
9
9
  title?: string;
10
10
  description?: string;
11
11
  }
12
- declare function Loader({ children, show, icon, title, description, before, after, wrapperClassName, className }: LoaderProps): string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
12
+ declare function Loader({ children, show, icon, title, description, before, after, wrapperClassName, className }: LoaderProps): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
13
13
  export default Loader;
@@ -40,6 +40,15 @@ export interface ModalProps extends MotionUIProps {
40
40
  closeOnBackdrop?: boolean;
41
41
  /** CSS `z-index` override (useful when stacking modals). */
42
42
  zIndex?: number;
43
+ /**
44
+ * Px of screen space already reserved on the right edge (e.g. a persistent app-level
45
+ * side panel docked outside this Modal's own portal) — the backdrop/cover stop short of
46
+ * that space (so the reserved area stays undimmed and interactive) and, for
47
+ * `position="right"`, the dialog itself shifts left by the same amount instead of
48
+ * overlapping it. `0`/`undefined` = today's behaviour, flush against the real viewport
49
+ * edge.
50
+ */
51
+ rightInset?: number;
43
52
  /**
44
53
  * When `true` this modal is visually "behind" another modal stacked on top.
45
54
  * The panel becomes 10% wider (so its edge peeks out from behind the upper modal),
@@ -47,6 +56,15 @@ export interface ModalProps extends MotionUIProps {
47
56
  * modal's backdrop handles interaction blocking), and its cover becomes non-interactive.
48
57
  */
49
58
  stackedBehind?: boolean;
59
+ /**
60
+ * Replaces the default × close button with custom content, in the same header slot
61
+ * (still next to the fullscreen toggle, if any). Use this when the host app wants one
62
+ * consistent icon/action across every modal instead of the built-in × — e.g. an
63
+ * app-level "toggle side panel" icon that means the same thing whether a modal happens
64
+ * to be open or not. Backdrop click and Cancel/Save/Delete still call `onClose` as usual;
65
+ * this only swaps what's rendered in the × slot, not the close mechanics themselves.
66
+ */
67
+ closeSlot?: React.ReactNode;
50
68
  }
51
69
  /** Props for a confirm/deny modal dialog with Yes/No buttons. */
52
70
  export interface ModalYesNoProps {
@@ -41,7 +41,7 @@ interface TabProps extends MotionUIProps {
41
41
  export declare function getTabLayoutConfig(layout: TabPosition): TabLayoutConfig;
42
42
  export declare function getTabTriggerClassName(layout: TabPosition, active: boolean, className?: string): string;
43
43
  export declare function getTabPaneClassName(className?: string): string;
44
- export declare const TabLayouts: Record<TabPosition, (props: TabLayoutProps) => JSX.Element>;
44
+ export declare const TabLayouts: Record<TabPosition, (props: TabLayoutProps) => React.ReactElement>;
45
45
  export declare const TabItem: React.FC<TabItemProps>;
46
46
  declare const Tab: React.FC<TabProps>;
47
47
  export default Tab;
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { FormFieldProps } from '../../widgets/Form';
3
+ import { type EditorHeight } from '../../../libs/editorHeight';
3
4
  import type { FieldValue } from '../../../providers/data/DataProvider';
4
5
  import { type EditorCommand } from './ContextMenu';
5
6
  export type CodeEditorLanguage = 'liquid' | 'html' | 'json' | 'js' | 'ts' | 'css';
@@ -29,7 +30,11 @@ export declare const getCodeValidationResult: (code: string, language: CodeEdito
29
30
  export interface CodeEditorProps extends FormFieldProps {
30
31
  language?: CodeEditorLanguage;
31
32
  placeholder?: string;
32
- minHeight?: number;
33
+ /** A pixel value, or `'fill'` to stretch to the parent container's height (with the
34
+ * editor's own internal scroll) instead of a fixed size — see `EditorHeight`. The
35
+ * parent must actually provide a real height (e.g. a flex column with `flex-1 min-h-0`)
36
+ * for `'fill'` to have any effect. */
37
+ minHeight?: EditorHeight;
33
38
  maxHeight?: number;
34
39
  label?: string;
35
40
  required?: boolean;
@@ -4,6 +4,8 @@ export interface ContextMenuItem {
4
4
  label: string;
5
5
  value: string;
6
6
  icon?: string;
7
+ /** Secondary muted text under the label — e.g. a variable's description/type. */
8
+ description?: string;
7
9
  }
8
10
  export interface EditorContext {
9
11
  value: string;
@@ -29,6 +31,14 @@ export interface EditorCommand {
29
31
  name: string;
30
32
  description?: string;
31
33
  icon?: string;
34
+ /** Groups commands under a `ContextMenu.Heading` in menu order — commands sharing the
35
+ * same `group` string render contiguously under one heading (see CodeEditor.tsx's
36
+ * `commandMenuItems`/render logic, which does the grouping/heading-insertion). Commands
37
+ * without a `group` render ungrouped, in their original order. */
38
+ group?: string;
39
+ /** Optional auto-closed suffix to consume when replacing the active trigger. Useful when
40
+ * a command changes syntactic family, for example from `{{ ... }}` to `{% ... %}`. */
41
+ consumeSuffix?: string;
32
42
  handler?: (context: TextCommandContext) => string | Promise<string>;
33
43
  }
34
44
  export interface ContextMenuControlledState {
@@ -59,6 +69,8 @@ interface ContextMenuItemProps extends UIProps {
59
69
  label: string;
60
70
  value: string;
61
71
  icon?: string;
72
+ /** Secondary muted text under the label — e.g. a variable's description/type. */
73
+ description?: string;
62
74
  }
63
75
  interface ContextMenuHeadingProps {
64
76
  children: React.ReactNode;
@@ -81,6 +93,18 @@ type CommandTriggerMatchOptions = {
81
93
  queryPattern?: RegExp;
82
94
  requireWhitespacePrefix?: boolean;
83
95
  };
96
+ /**
97
+ * Whether `textAfterCaret` (from `TextCommandContext`/`EditorContext`) already starts with
98
+ * `closer`, optionally preceded by whitespace — typically because the editor's own
99
+ * bracket/quote auto-closing inserted it when the user typed the opening one. A command
100
+ * `handler` that would otherwise insert a closer of its own (e.g. `"{{ x }}"`) should check
101
+ * this first and omit its own closer when true, to avoid a duplicate
102
+ * (`"{{ x }}}}"` instead of the intended `"{{ x }}"`).
103
+ */
104
+ export declare const hasAutoClosedSuffix: (textAfterCaret: string, closer: string) => boolean;
105
+ /** Returns the number of characters occupied by an auto-closed suffix, including whitespace
106
+ * before it, or zero when the requested suffix is not present. */
107
+ export declare const getAutoClosedSuffixLength: (textAfterCaret: string, closer: string) => number;
84
108
  export declare const matchCommandTrigger: (value: string, caret: number, trigger: string, options?: CommandTriggerMatchOptions) => QueryMatch | null;
85
109
  export declare const buildTextCommandContext: (context: EditorContext) => TextCommandContext;
86
110
  declare const ContextMenu: ContextMenuComponent;
@@ -41,7 +41,7 @@ export interface UseFileUploadCoreOptions {
41
41
  export declare const useFileUploadCore: ({ onFilesChange, onFileReady, uploadPath, srcsetWidths, initialFiles, storageKey, storageProvider, }: UseFileUploadCoreOptions) => {
42
42
  files: FileProps[];
43
43
  setFiles: React.Dispatch<React.SetStateAction<FileProps[]>>;
44
- fileInputRef: React.MutableRefObject<HTMLInputElement | null>;
44
+ fileInputRef: React.RefObject<HTMLInputElement | null>;
45
45
  updateFile: (key: string, updates: Partial<FileProps>) => void;
46
46
  handleFiles: (selectedFiles: File[]) => void;
47
47
  handleUpload: () => void | undefined;
@@ -118,11 +118,14 @@ interface BaseFormProps {
118
118
  log?: boolean;
119
119
  /** Show the inline save/delete notice banner. Defaults to `true`. */
120
120
  showNotice?: boolean;
121
- /** Persist unsaved changes locally and offer restore/discard on re-entry. Defaults to `false`. */
122
- persistDraft?: boolean;
121
+ /**
122
+ * Stable bucket that isolates this form's local draft. Omit to disable draft persistence.
123
+ * The Form appends its own path/route identity, so one bucket safely serves many forms.
124
+ */
125
+ draftBucket?: string;
123
126
  /** When provided, the save/delete notice is rendered sticky at the top of this container
124
127
  * instead of inline in the form footer. Ideal for full-page forms outside a modal. */
125
- noticeAnchorRef?: React.RefObject<HTMLElement>;
128
+ noticeAnchorRef?: React.RefObject<HTMLElement | null>;
126
129
  /** Render a Back navigation button in the footer. */
127
130
  showBack?: boolean;
128
131
  /** CSS classes on the outermost wrapper element. */
@@ -133,6 +136,14 @@ interface BaseFormProps {
133
136
  className?: string;
134
137
  /** CSS classes on the footer container. */
135
138
  footerClassName?: string;
139
+ /**
140
+ * CSS classes on the native `<form>` element itself — distinct from `wrapperClassName`
141
+ * (the outer `Wrapper` div) and `className` ("card" appearance's body). Needed whenever
142
+ * a layout must cascade real height/flex context through the form (e.g. a full-height
143
+ * field like `CodeEditor`'s `minHeight="fill"`) instead of reaching in via an arbitrary
144
+ * `[&>form]:` child selector on `wrapperClassName`.
145
+ */
146
+ formClassName?: string;
136
147
  }
137
148
  interface FormDefaultProps extends BaseFormProps {
138
149
  children: React.ReactNode | ((fields: FormTree) => React.ReactNode) | ((args: {
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
2
  import { type RecordProps } from "../../../providers/data/DataProvider";
3
3
  import { type GridCoreProps } from "./types";
4
- declare function GridCore<TRecord extends RecordProps>({ records, recordId, sourcePath, columns, actions, form, editDeepLink, header, footer, view, sticky, wrapperClassName, loading, title, before, after, sortable, pagination, selection, onRowClick, reorderable, onReorder, groupBy, onSave, onDelete, onComplete, audit, onLoad, }: GridCoreProps<TRecord>): React.JSX.Element;
4
+ declare function GridCore<TRecord extends RecordProps>({ records, recordId, sourcePath, columns, actions, form, editDeepLink, header, footer, view, views, sticky, wrapperClassName, loading, title, before, after, sortable, pagination, selection, onRowClick, reorderable, onReorder, groupBy, onSave, onDelete, onComplete, audit, onLoad, }: GridCoreProps<TRecord>): React.JSX.Element;
5
5
  export default GridCore;
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
2
  import { type RecordProps } from "../../../providers/data/DataProvider";
3
3
  import { type GridGalleryViewProps } from "./types";
4
- declare function GridGalleryView<TRecord extends RecordProps>({ records, recordId, sortable, pagination, selection, selectedKeys, onSelectionChange, onRowClick, groupBy, wrapperClassName, before, after, }: GridGalleryViewProps<TRecord>): React.JSX.Element;
4
+ declare function GridGalleryView<TRecord extends RecordProps>({ records, recordId, sortable, pagination, selection, selectedKeys, onSelectionChange, onRowClick, groupBy, wrapperClassName, before, after, columns, overlays, }: GridGalleryViewProps<TRecord>): React.JSX.Element;
5
5
  export default GridGalleryView;
@@ -1,11 +1,70 @@
1
1
  import React from "react";
2
2
  import { type OrderConfig } from "../../../libs/order";
3
3
  import { type PaginationParams } from "../../ui/Pagination";
4
+ import { type GalleryOverlay } from "../../ui/Gallery";
4
5
  import { type DatabaseOptions, type RecordProps } from "../../../providers/data/DataProvider";
5
6
  export type GridLayout = "table" | "gallery";
6
7
  export type GridSticky = "top" | "bottom";
7
8
  export type GridSelectionMode = false | "single" | "multiple";
8
9
  export type GridRecordKey<TRecord> = keyof TRecord | ((record: TRecord) => string);
10
+ /**
11
+ * Declarative field shown as an overlay on a gallery card — distinct from `GridColumn`
12
+ * (which drives table columns): a card doesn't need the same fields as a table row,
13
+ * and has its own visibility picker (`views.gallery.fieldPicker`) separate from the
14
+ * table's `views.table.columnPicker`.
15
+ */
16
+ export type GridGalleryField<TRecord> = {
17
+ /** Record field to read. Accepts dot-notation strings for nested fields. */
18
+ key: keyof TRecord | string;
19
+ /** Label shown in the field picker (not on the card itself — the card shows the value only). */
20
+ label: string;
21
+ /** Where on the card this field's value is overlaid. Defaults to `"bottomLeft"`. */
22
+ position?: "topLeft" | "topRight" | "bottomLeft" | "bottomRight" | "middleLeft" | "middleRight";
23
+ /** Whether this field is shown by default when `fieldPicker` is enabled. Defaults to `true`. */
24
+ defaultVisible?: boolean;
25
+ /** Custom render — defaults to the raw field value as text. */
26
+ render?: (value: unknown, record: TRecord) => React.ReactNode;
27
+ };
28
+ /** Table-specific view options, grouped under `views.table`. */
29
+ export type GridTableViewConfig = {
30
+ /** Show a built-in "Columns" dropdown letting the user show/hide table columns. Default `false`. */
31
+ columnPicker?: boolean;
32
+ };
33
+ /** Gallery-specific view options, grouped under `views.gallery`. */
34
+ export type GridGalleryViewConfig<TRecord> = {
35
+ /** Cards per row — one of `1|2|3|4|6` (the only values the underlying `Gallery` component supports). */
36
+ columns?: 1 | 2 | 3 | 4 | 6;
37
+ /**
38
+ * Declarative fields overlaid on each card (see `GridGalleryField`). Generates the
39
+ * overlays automatically and, combined with `fieldPicker`, a "Fields" dropdown
40
+ * analogous to the table's "Columns" picker — but a separate one, since a card
41
+ * typically shows fewer/different fields than a table row.
42
+ */
43
+ fields?: GridGalleryField<TRecord>[];
44
+ /** Show the built-in "Fields" dropdown for `fields` above. Default `false`. */
45
+ fieldPicker?: boolean;
46
+ /**
47
+ * Escape hatch: fully custom overlay renderers (forwarded to `<Gallery overlays>`),
48
+ * for anything `fields` can't express (e.g. an action button, not just a label).
49
+ * ADDITIVE to the overlays generated from `fields` — a caller commonly needs both at
50
+ * once (e.g. a Delete button plus checkable label fields); positions shared by both
51
+ * simply stack, with the custom overlay rendered first.
52
+ */
53
+ overlays?: GalleryOverlay[];
54
+ };
55
+ /**
56
+ * Groups every Table/Gallery-view-switching concern under one input, instead of a flat
57
+ * spray of booleans on `<Grid>` — `toggle` decides whether the switch exists at all,
58
+ * `table`/`gallery` hold the options specific to each view (column picker vs. field
59
+ * picker are deliberately two different controls, since a gallery card and a table row
60
+ * don't need to show the same fields).
61
+ */
62
+ export type GridViewsConfig<TRecord> = {
63
+ /** Show the built-in Table/Gallery switch in the header, letting the user change the active view at runtime. Default `false` — `view` behaves as a fixed initial mode when omitted, same as before this existed. */
64
+ toggle?: boolean;
65
+ table?: GridTableViewConfig;
66
+ gallery?: GridGalleryViewConfig<TRecord>;
67
+ };
9
68
  export type GridFormat = "text" | "email" | "date" | "datetime" | "badge" | "image" | "boolean" | "json";
10
69
  export type GridCellContext<TRecord> = {
11
70
  record: TRecord;
@@ -30,6 +89,8 @@ export type GridColumn<TRecord> = {
30
89
  className?: string;
31
90
  /** Built-in format name or custom render function. */
32
91
  render?: GridFormat | ((ctx: GridCellContext<TRecord>) => React.ReactNode);
92
+ /** Whether this column is shown by default when `views.table.columnPicker` is enabled. Defaults to `true`. */
93
+ defaultVisible?: boolean;
33
94
  };
34
95
  export type GridSelectionState<TRecord> = {
35
96
  keys: string[];
@@ -150,9 +211,11 @@ export type GridAfterActionArgs<TRecord> = {
150
211
  };
151
212
  export type GridAfterActionHandler<TRecord> = (args: GridAfterActionArgs<TRecord>) => Promise<boolean>;
152
213
  /** Visual / layout props for `<Grid>`. */
153
- export type GridPresentation = {
154
- /** Display mode: `"table"` (default) or `"gallery"` card layout. */
214
+ export type GridPresentation<TRecord> = {
215
+ /** Display mode: `"table"` (default) or `"gallery"` card layout. Acts as the initial/default view — see `views.toggle` to let the user switch at runtime. */
155
216
  view?: GridLayout;
217
+ /** Table/Gallery switch + per-view options (column picker, gallery field picker, cards-per-row, …) — see `GridViewsConfig`. Omit entirely to keep the pre-existing fixed-`view` behavior. */
218
+ views?: GridViewsConfig<TRecord>;
156
219
  /** Stick the header (`"top"`) or footer (`"bottom"`) while scrolling. */
157
220
  sticky?: GridSticky;
158
221
  /** CSS classes on the outermost wrapper element. */
@@ -198,7 +261,7 @@ export type GridPersistence<TRecord> = {
198
261
  * Full prop surface shared by all `<Grid>` variants.
199
262
  * Combines presentation, behaviour, and persistence with a few top-level hooks.
200
263
  */
201
- export type GridBaseProps<TRecord> = GridPresentation & GridBehavior<TRecord> & GridPersistence<TRecord> & {
264
+ export type GridBaseProps<TRecord> = GridPresentation<TRecord> & GridBehavior<TRecord> & GridPersistence<TRecord> & {
202
265
  /** Transform the record array after loading (filter, sort, enrich). */
203
266
  onLoad?: (records: TRecord[]) => TRecord[] | Promise<TRecord[]>;
204
267
  /** Column definitions. Omit to auto-generate from record keys. */
@@ -222,6 +285,15 @@ export type GridCoreProps<TRecord extends RecordProps> = GridBaseProps<TRecord>
222
285
  export type GridArrayProps<TRecord extends RecordProps> = GridBaseProps<TRecord> & {
223
286
  records: TRecord[];
224
287
  recordId: GridRecordKey<TRecord>;
288
+ /**
289
+ * Base path the `records` were sourced from (e.g. `/components`) — enables the built-in
290
+ * "delete" action's `db.remove(\`${sourcePath}/${recordKey}\`)` when the caller fetched
291
+ * its own records (e.g. via `db.subscribe()`) instead of letting Grid fetch them itself
292
+ * (`GridDBProps.path` does the equivalent there). Already threaded through to `GridCore`
293
+ * — this was just missing from the public prop surface for the `records` variant.
294
+ * Omit if delete is handled entirely via a custom `actions.delete`/`onDelete`.
295
+ */
296
+ sourcePath?: string;
225
297
  };
226
298
  export type GridDBQuery = Pick<DatabaseOptions, "where" | "order" | "fieldMap">;
227
299
  export type GridDBPath = string;
@@ -273,5 +345,9 @@ export type GridGalleryViewProps<TRecord extends RecordProps> = {
273
345
  wrapperClassName?: string;
274
346
  before?: React.ReactNode;
275
347
  after?: React.ReactNode;
348
+ /** Cards per row — forwarded to `<Gallery columns>`. */
349
+ columns?: 1 | 2 | 3 | 4 | 6;
350
+ /** Overlay badges/render-props for each card — forwarded to `<Gallery overlays>`. */
351
+ overlays?: GalleryOverlay[];
276
352
  };
277
353
  export {};
@@ -31,7 +31,7 @@ declare function useGridActions<TRecord extends RecordProps>({ actions, form, ed
31
31
  normalizedActions: Record<string, GridAction<TRecord>>;
32
32
  activeAction: GridActiveAction<TRecord> | null;
33
33
  activeActionConfig: GridAction<TRecord> | undefined;
34
- activeActionBody: string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
34
+ activeActionBody: string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
35
35
  activeKey: string | null;
36
36
  runAction: (actionKey: string, record?: TRecord) => Promise<void>;
37
37
  runModalAction: (actionKey: string) => Promise<void>;
@@ -21,7 +21,7 @@ export { PromptUtils } from './libs/promptUtils';
21
21
  export type { PromptAction, PromptStatusItem, PromptRunStats } from './components/widgets/Prompt';
22
22
  export type { TableHeaderProp, TableReorderHandler, TableReorderMeta, TableSelectionChangeHandler, TableSelectionState } from './components/ui/Table';
23
23
  export type { GalleryRecord, GallerySelectionChangeHandler, GallerySelectionState } from './components/ui/Gallery';
24
- export type { GridAction, GridActions, GridAfterActionArgs, GridAfterActionHandler, GridArrayProps, GridColumn, GridCoreProps, GridDBPath, GridDBQuery, GridDBProps, GridFooterContext, GridFormContext, GridGalleryViewProps, GridHeaderContext, GridLayout, GridMutationDeleteArgs, GridMutationDeleteHandler, GridMutationSaveArgs, GridMutationSaveHandler, GridReorderHandler, GridReorderMeta, GridRecordKey, GridProps, GridSelectionChangeHandler, GridSelectionMode, GridSelectionState, GridSticky, GridTableViewProps, GridCellContext, } from './components/widgets/Grid';
24
+ export type { GridAction, GridActions, GridAfterActionArgs, GridAfterActionHandler, GridArrayProps, GridColumn, GridCoreProps, GridDBPath, GridDBQuery, GridDBProps, GridFooterContext, GridFormContext, GridGalleryField, GridGalleryViewProps, GridGalleryViewConfig, GridHeaderContext, GridLayout, GridMutationDeleteArgs, GridMutationDeleteHandler, GridMutationSaveArgs, GridMutationSaveHandler, GridReorderHandler, GridReorderMeta, GridRecordKey, GridProps, GridSelectionChangeHandler, GridSelectionMode, GridSelectionState, GridSticky, GridTableViewProps, GridTableViewConfig, GridViewsConfig, GridCellContext, } from './components/widgets/Grid';
25
25
  export type { ProviderConfigurable, ProviderConfigurationState } from './providers/ProviderConfiguration';
26
26
  export { getProviderConfigurationState } from './providers/ProviderConfiguration';
27
27
  export type { ProviderAdapterMap, ProviderService, SetProviderFn, ProviderRegistrySnapshot } from './providers/ProviderRegistryContext';
@@ -75,7 +75,7 @@ export { IconProvider, useIconProvider, useIconController } from './providers/ic
75
75
  export type { AppIconProviderConfig, IconController } from './providers/icon/IconProviderContext';
76
76
  export { useEmailProvider, EmailProvider } from './providers/email/EmailProviderContext';
77
77
  export { GmailEmailProvider } from './providers/email/google/GmailEmailProvider';
78
- export type { AIRequestOptions, AIAttachment, AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIModelCatalog, AIProviderDefinition } from './providers/ai';
78
+ export type { AIRequestOptions, AIAttachment, AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIModelCatalog, AIProviderDefinition, AICompleteRequest, AICompleteResult, AIConversationTurn, AIToolDefinition, AIToolCall, AIToolResult, } from './providers/ai';
79
79
  export { createAIProviderRegistry, getAIModelCatalog, formatAIModelRef, parseAIModelRef, AI_PROVIDER_DEFINITIONS, AI_PROVIDER_DESCRIPTORS, OPENAI_COMPATIBLE_PROVIDER_DESCRIPTOR, toProviderDescriptor } from './providers/ai';
80
80
  export type { ProviderDescriptor, ProviderCredentialField } from './providers/ProviderDescriptor';
81
81
  export { useAIProvider, useAIProviderRegistry, AIProvider } from './providers/ai/AIProviderContext';
@@ -1,9 +1,19 @@
1
+ /**
2
+ * `'fill'` means "stretch to the height of whatever parent container you're placed in,
3
+ * instead of a fixed pixel height" — the parent must actually provide a real height (e.g.
4
+ * a flex column with `flex-1 min-h-0`) for this to have any effect; on an auto-height
5
+ * parent it resolves to the same as not being there.
6
+ */
7
+ export type EditorHeight = number | 'fill';
1
8
  export interface EditorHeightOptions {
2
- minHeight?: number;
9
+ minHeight?: EditorHeight;
3
10
  maxHeight?: number;
4
11
  paddingOffset?: number;
5
12
  }
6
13
  export interface EditorHeightResult {
14
+ /** True when `minHeight === 'fill'` — the editor stretches to its parent's height with
15
+ * its own internal scroll, instead of using a fixed pixel min-height. */
16
+ fill: boolean;
7
17
  adjustedMinHeight: number;
8
18
  wrapperStyle: React.CSSProperties;
9
19
  resolvedMinHeight: number;
@@ -2,6 +2,8 @@ interface FetchOptions {
2
2
  method?: "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "PATCH";
3
3
  headers?: Record<string, string>;
4
4
  body?: Record<string, unknown> | string;
5
+ /** Lets a caller cancel an in-flight request (e.g. a "stop" button on a long AI call). */
6
+ signal?: AbortSignal;
5
7
  }
6
8
  export declare function fetchRest(url: string, options?: FetchOptions | null, fetchFn?: typeof fetch): Promise<any>;
7
9
  export declare function fetchJson(url: string, options?: FetchOptions | null, fetchFn?: typeof fetch): Promise<any>;
@@ -27,10 +27,63 @@ export interface AIRequestOptions {
27
27
  temperature?: number;
28
28
  attachments?: AIAttachment[];
29
29
  }
30
+ /** Definizione di un tool che il modello può scegliere di invocare — la SDK del provider
31
+ * riceve solo questa forma (JSON-serializzabile); l'implementazione vera resta lato
32
+ * chiamante (mai inviata al provider). Vedi AICompleteResult per come il modello segnala
33
+ * una richiesta di invocazione. */
34
+ export interface AIToolDefinition {
35
+ name: string;
36
+ description: string;
37
+ inputSchema: Record<string, unknown>;
38
+ }
39
+ /** Richiesta del modello di invocare un tool con questi argomenti — il chiamante esegue
40
+ * `name` localmente e rimanda il risultato come AIToolResult nel turno successivo. */
41
+ export interface AIToolCall {
42
+ id: string;
43
+ name: string;
44
+ input: Record<string, unknown>;
45
+ }
46
+ /** Esito dell'esecuzione locale di un tool, da rimandare al modello nel turno successivo. */
47
+ export interface AIToolResult {
48
+ toolCallId: string;
49
+ name: string;
50
+ output: unknown;
51
+ isError?: boolean;
52
+ }
53
+ /** Un turno della conversazione precedente a quello corrente — passato via
54
+ * `AICompleteRequest.history` per continuare una chat multi-turno (es. l'utente affina una
55
+ * richiesta AI già eseguita, o il modello ha invocato un tool e ne riceve il risultato). */
56
+ export type AIConversationTurn = {
57
+ role: 'user';
58
+ content: string;
59
+ } | {
60
+ role: 'assistant';
61
+ content?: string;
62
+ toolCalls?: AIToolCall[];
63
+ } | {
64
+ role: 'tool_result';
65
+ results: AIToolResult[];
66
+ };
30
67
  export interface AICompleteRequest extends AIRequestOptions {
31
68
  prompt: string;
32
69
  data?: PromptVariables;
70
+ /** Turni precedenti della conversazione — assente = primo turno (solo `prompt`). */
71
+ history?: AIConversationTurn[];
72
+ /** Tool che il modello può invocare a sua discrezione in questo turno. */
73
+ tools?: AIToolDefinition[];
74
+ /** Annulla la richiesta in corso (es. un bottone "interrompi" lato chiamante). */
75
+ signal?: AbortSignal;
33
76
  }
77
+ /** Esito di una chiamata completate — testo semplice, oppure una o più richieste di tool
78
+ * call (eventualmente accompagnate da testo, quando il modello commenta prima di invocare). */
79
+ export type AICompleteResult = {
80
+ type: 'text';
81
+ text: string;
82
+ } | {
83
+ type: 'tool_calls';
84
+ toolCalls: AIToolCall[];
85
+ text?: string;
86
+ };
34
87
  export interface AIKeyValidationResult {
35
88
  valid: boolean;
36
89
  /** Human-readable error from the provider API (e.g. "Incorrect API key provided"). */
@@ -45,7 +98,7 @@ export interface AIProviderAdapter extends ProviderConfigurable {
45
98
  /** URL to the provider's API key management page. */
46
99
  dashboardUrl?: string;
47
100
  getCapabilities(forceRefresh?: boolean): Promise<AIProviderCapabilities>;
48
- complete(request: AICompleteRequest): Promise<string | null>;
101
+ complete(request: AICompleteRequest): Promise<AICompleteResult | null>;
49
102
  /** Makes a live API call to verify the key is accepted. Never uses cache. */
50
103
  validateApiKey(): Promise<AIKeyValidationResult>;
51
104
  }
@@ -2,7 +2,7 @@ import type { AIConfig } from '../../Config';
2
2
  import type { ProviderDescriptor } from '../ProviderDescriptor';
3
3
  import type { AIProviderAdapter } from './AIProvider';
4
4
  import { type AIProviderDefinition } from './shared';
5
- export type { AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIRequestOptions, AIAttachment } from './AIProvider';
5
+ export type { AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIRequestOptions, AIAttachment, AICompleteRequest, AICompleteResult, AIConversationTurn, AIToolDefinition, AIToolCall, AIToolResult, } from './AIProvider';
6
6
  export { formatAIModelRef, parseAIModelRef } from './AIProvider';
7
7
  export type { AIModelCatalog, AIProviderDefinition } from './shared';
8
8
  export { getAIModelCatalog } from './shared';
@@ -1,4 +1,5 @@
1
1
  import type { AIProviderDefinition, BuiltInAIProviderId } from './shared';
2
+ import type { AIConversationTurn, AICompleteResult, AIToolDefinition } from './AIProvider';
2
3
  type OpenAICompatibleDefinitionOptions = {
3
4
  id: BuiltInAIProviderId;
4
5
  label: string;
@@ -15,5 +16,26 @@ type OpenAICompatibleDefinitionOptions = {
15
16
  /** Override the default validateApiKey when the models endpoint is public or uses a non-standard error format. */
16
17
  validateApiKey?: AIProviderDefinition['validateApiKey'];
17
18
  };
19
+ /** Esportate per riuso da provider "chat completions"-simili ma non costruiti tramite
20
+ * createOpenAICompatibleProviderDefinition (vedi opencode.ts) — stesso wire format OpenAI,
21
+ * niente da reinventare. */
22
+ export declare function toOpenAITool(tool: AIToolDefinition): {
23
+ type: "function";
24
+ function: {
25
+ name: string;
26
+ description: string;
27
+ parameters: Record<string, unknown>;
28
+ };
29
+ };
30
+ /** Un turno assistant con tool_calls diventa `tool_calls` sul messaggio assistant; un turno
31
+ * tool_result diventa un messaggio `role: 'tool'` per ciascun risultato — stessa forma
32
+ * richiesta dall'API Chat Completions (OpenAI e compatibili) per continuare la conversazione
33
+ * dopo una tool call. */
34
+ export declare function toOpenAIMessages(turn: AIConversationTurn): Array<Record<string, unknown>>;
35
+ export declare function parseOpenAIResponse(response: {
36
+ choices?: Array<{
37
+ message?: Record<string, unknown>;
38
+ }>;
39
+ } | null): AICompleteResult | null;
18
40
  export declare const createOpenAICompatibleProviderDefinition: ({ id, label, description, configKey, requiredConfigKeys, defaultModel, fallbackModels, baseUrl, modelsUrl, chatCompletionsUrl, dashboardUrl, credentialsHint, validateApiKey: validateApiKeyOverride, }: OpenAICompatibleDefinitionOptions) => AIProviderDefinition;
19
41
  export {};
@@ -1,6 +1,6 @@
1
1
  import { type ProviderConfigurationState } from '../ProviderConfiguration';
2
2
  import type { ProviderCredentialField } from '../ProviderDescriptor';
3
- import type { AICompleteRequest, AIKeyValidationResult, AIModelDescriptor, AIProviderAdapter, AIProviderCapabilities, AIRequestOptions } from './AIProvider';
3
+ import type { AICompleteRequest, AICompleteResult, AIKeyValidationResult, AIModelDescriptor, AIProviderAdapter, AIProviderCapabilities, AIRequestOptions } from './AIProvider';
4
4
  export type BuiltInAIProviderId = 'openai' | 'openrouter' | 'opencode' | 'openai-compatible' | 'deepseek' | 'gemini' | 'anthropic' | 'mistral' | 'glm';
5
5
  export type AIProviderDefinition = {
6
6
  id: BuiltInAIProviderId;
@@ -21,7 +21,7 @@ export type AIProviderDefinition = {
21
21
  credentialsHint?: string;
22
22
  capabilities?: Omit<AIProviderCapabilities, 'models'>;
23
23
  discoverModels: (apiKey: string) => Promise<string[]>;
24
- complete: (apiKey: string, request: Required<Pick<AICompleteRequest, 'prompt' | 'model'>> & AIRequestOptions) => Promise<string | null>;
24
+ complete: (apiKey: string, request: Required<Pick<AICompleteRequest, 'prompt' | 'model'>> & AIRequestOptions & Pick<AICompleteRequest, 'history' | 'tools' | 'signal'>) => Promise<AICompleteResult | null>;
25
25
  /**
26
26
  * Per-provider auth check. When omitted, the default implementation in
27
27
  * RuntimeAIProvider calls discoverModels() live (no cache) and treats any
@@ -50,6 +50,6 @@ export declare class RuntimeAIProvider implements AIProviderAdapter {
50
50
  isConfigured(): boolean;
51
51
  getConfigurationState(): ProviderConfigurationState;
52
52
  getCapabilities(forceRefresh?: boolean): Promise<AIProviderCapabilities>;
53
- complete(request: AICompleteRequest): Promise<string | null>;
53
+ complete(request: AICompleteRequest): Promise<AICompleteResult | null>;
54
54
  validateApiKey(): Promise<AIKeyValidationResult>;
55
55
  }
@@ -1,3 +1,3 @@
1
1
  import { GoogleConfig } from "../../../Config";
2
2
  export declare const authConfig: <K extends keyof GoogleConfig>(key: K) => GoogleConfig[K] | undefined;
3
- export declare const getGoogleCredential: () => import("firebase/auth").OAuthCredential | null;
3
+ export declare const getGoogleCredential: () => import("@firebase/auth").OAuthCredential | null;