rich-react-component 0.1.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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +118 -0
  3. package/dist/base/Accordion.d.ts +17 -0
  4. package/dist/base/Alert.d.ts +15 -0
  5. package/dist/base/AutoComplete.d.ts +20 -0
  6. package/dist/base/Avatar.d.ts +8 -0
  7. package/dist/base/Badge.d.ts +9 -0
  8. package/dist/base/Breadcrumb.d.ts +10 -0
  9. package/dist/base/Button.d.ts +13 -0
  10. package/dist/base/Card.d.ts +9 -0
  11. package/dist/base/CheckBox.d.ts +17 -0
  12. package/dist/base/Col.d.ts +12 -0
  13. package/dist/base/ComboBox.d.ts +17 -0
  14. package/dist/base/Confirm.d.ts +25 -0
  15. package/dist/base/Container.d.ts +7 -0
  16. package/dist/base/DataGrid.d.ts +43 -0
  17. package/dist/base/DatePicker.d.ts +23 -0
  18. package/dist/base/DateTimePicker.d.ts +17 -0
  19. package/dist/base/Divider.d.ts +8 -0
  20. package/dist/base/FileInput.d.ts +19 -0
  21. package/dist/base/FormField.d.ts +12 -0
  22. package/dist/base/Icon.d.ts +15 -0
  23. package/dist/base/Input.d.ts +30 -0
  24. package/dist/base/Menu.d.ts +21 -0
  25. package/dist/base/Modal.d.ts +19 -0
  26. package/dist/base/MultiSelect.d.ts +25 -0
  27. package/dist/base/Navbar.d.ts +16 -0
  28. package/dist/base/NumberInput.d.ts +17 -0
  29. package/dist/base/PageHeader.d.ts +12 -0
  30. package/dist/base/Pagination.d.ts +15 -0
  31. package/dist/base/PasswordInput.d.ts +10 -0
  32. package/dist/base/Popover.d.ts +10 -0
  33. package/dist/base/ProgressBar.d.ts +10 -0
  34. package/dist/base/RadioButton.d.ts +18 -0
  35. package/dist/base/RadioGroup.d.ts +14 -0
  36. package/dist/base/Rating.d.ts +9 -0
  37. package/dist/base/Row.d.ts +6 -0
  38. package/dist/base/Select.d.ts +24 -0
  39. package/dist/base/Sidebar.d.ts +31 -0
  40. package/dist/base/Skeleton.d.ts +8 -0
  41. package/dist/base/Slider.d.ts +10 -0
  42. package/dist/base/Spinner.d.ts +7 -0
  43. package/dist/base/Stack.d.ts +12 -0
  44. package/dist/base/Stepper.d.ts +12 -0
  45. package/dist/base/Switch.d.ts +16 -0
  46. package/dist/base/Tabs.d.ts +16 -0
  47. package/dist/base/Tag.d.ts +14 -0
  48. package/dist/base/TextArea.d.ts +11 -0
  49. package/dist/base/TimePicker.d.ts +20 -0
  50. package/dist/base/Toast.d.ts +27 -0
  51. package/dist/base/Tooltip.d.ts +21 -0
  52. package/dist/base/index.d.ts +56 -0
  53. package/dist/base/shared/BooleanFieldControl.d.ts +22 -0
  54. package/dist/base/shared/FieldShell.d.ts +22 -0
  55. package/dist/base/shared/Label.d.ts +9 -0
  56. package/dist/base/shared/Popup.d.ts +25 -0
  57. package/dist/base/shared/ValidationMessage.d.ts +11 -0
  58. package/dist/base/shared/classNames.d.ts +1 -0
  59. package/dist/base/shared/fieldTypes.d.ts +26 -0
  60. package/dist/base/shared/index.d.ts +9 -0
  61. package/dist/base/shared/useControllableState.d.ts +16 -0
  62. package/dist/base/shared/useEscapeKey.d.ts +2 -0
  63. package/dist/base/shared/useListNavigation.d.ts +18 -0
  64. package/dist/index.cjs +2 -0
  65. package/dist/index.cjs.map +1 -0
  66. package/dist/index.d.ts +18 -0
  67. package/dist/index.js +2092 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/remote/RemoteAutoComplete.d.ts +22 -0
  70. package/dist/remote/RemoteComboBox.d.ts +21 -0
  71. package/dist/remote/RemoteDataGrid.d.ts +24 -0
  72. package/dist/remote/RemoteMultiSelect.d.ts +13 -0
  73. package/dist/remote/RemoteSelect.d.ts +17 -0
  74. package/dist/remote/hooks/useDebouncedValue.d.ts +1 -0
  75. package/dist/remote/hooks/useRemoteData.d.ts +31 -0
  76. package/dist/remote/http/HttpClient.d.ts +31 -0
  77. package/dist/remote/index.d.ts +9 -0
  78. package/dist/remote/mapping.d.ts +8 -0
  79. package/dist/smart/SmartAction.d.ts +14 -0
  80. package/dist/smart/SmartActions.d.ts +14 -0
  81. package/dist/smart/SmartField.d.ts +18 -0
  82. package/dist/smart/SmartForm.d.ts +19 -0
  83. package/dist/smart/actionRegistry.d.ts +11 -0
  84. package/dist/smart/componentRegistry.d.ts +24 -0
  85. package/dist/smart/dataSourceRegistry.d.ts +17 -0
  86. package/dist/smart/index.d.ts +26 -0
  87. package/dist/smart/resolvers/comboBoxResolver.d.ts +10 -0
  88. package/dist/smart/resolvers/dataGridResolver.d.ts +11 -0
  89. package/dist/smart/resolvers/datePickerResolver.d.ts +3 -0
  90. package/dist/smart/resolvers/index.d.ts +13 -0
  91. package/dist/smart/resolvers/inputResolver.d.ts +8 -0
  92. package/dist/smart/runtime.d.ts +26 -0
  93. package/dist/smart/types.d.ts +114 -0
  94. package/dist/smart/useSmartAction.d.ts +36 -0
  95. package/dist/smart/useSmartDependencies.d.ts +13 -0
  96. package/dist/smart/useSmartField.d.ts +47 -0
  97. package/package.json +68 -0
@@ -0,0 +1,21 @@
1
+ import { ComboBoxProps } from '../base';
2
+ import { HttpClient } from './http/HttpClient';
3
+ export interface RemoteComboBoxProps<TValue extends string | number = string, TResponse = unknown> extends Omit<ComboBoxProps<TValue>, "options" | "loading"> {
4
+ url: string;
5
+ params?: Record<string, unknown>;
6
+ /** Key read off each raw remote item to produce the option's `value` (doc section 4). */
7
+ valueMember: string;
8
+ /** Key read off each raw remote item to produce the option's `label`. */
9
+ displayMember: string;
10
+ /** Escape hatch for response envelopes beyond bare array / `{ items: [...] }` (doc section 11). */
11
+ mapResponse?: (response: TResponse) => unknown[];
12
+ client?: HttpClient;
13
+ enabled?: boolean;
14
+ }
15
+ /**
16
+ * Adds remote-loading behavior to Base ComboBox by composing it — this is
17
+ * NOT a second independent ComboBox implementation (doc section 20). All
18
+ * selection/keyboard/popup UI behavior is Base ComboBox's; this component
19
+ * only owns fetch lifecycle + raw-item -> SelectOption mapping.
20
+ */
21
+ export declare function RemoteComboBox<TValue extends string | number = string, TResponse = unknown>({ url, params, valueMember, displayMember, mapResponse, client, enabled, ...comboBoxProps }: RemoteComboBoxProps<TValue, TResponse>): import("react").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { DataGridProps } from '../base';
2
+ import { HttpClient } from './http/HttpClient';
3
+ export interface RemoteDataGridProps<TRow, TResponse = unknown> extends Omit<DataGridProps<TRow>, "rows" | "loading" | "error" | "page" | "pageSize" | "totalCount" | "onPageChange" | "sort" | "onSortChange"> {
4
+ url: string;
5
+ /** Additional filter params (e.g. `{ countryId }`) — page/pageSize/sort are managed internally. */
6
+ params?: Record<string, unknown>;
7
+ mapResponse?: (response: TResponse) => TRow[];
8
+ /**
9
+ * Extension point: read a total row count out of the raw response, when
10
+ * the backend provides one. Strongly recommended — without it, pagination
11
+ * falls back to a has-more heuristic (a full page implies "at least one
12
+ * more page exists") which cannot show an exact page count.
13
+ */
14
+ getTotalCount?: (response: TResponse) => number | undefined;
15
+ pageSize?: number;
16
+ client?: HttpClient;
17
+ }
18
+ /**
19
+ * Adds paging/sorting-against-a-server-endpoint behavior to Base DataGrid
20
+ * by composing it. All table rendering, selection, and pagination/sort UI
21
+ * remain Base DataGrid's — this component only owns request params
22
+ * (page/pageSize/sort/filters) and response mapping (doc section 10).
23
+ */
24
+ export declare function RemoteDataGrid<TRow, TResponse = unknown>({ url, params, mapResponse, getTotalCount, pageSize, client, ...dataGridProps }: RemoteDataGridProps<TRow, TResponse>): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { MultiSelectProps } from '../base';
2
+ import { HttpClient } from './http/HttpClient';
3
+ export interface RemoteMultiSelectProps<TValue extends string | number = string, TResponse = unknown> extends Omit<MultiSelectProps<TValue>, "options" | "loading"> {
4
+ url: string;
5
+ params?: Record<string, unknown>;
6
+ valueMember: string;
7
+ displayMember: string;
8
+ mapResponse?: (response: TResponse) => unknown[];
9
+ client?: HttpClient;
10
+ enabled?: boolean;
11
+ }
12
+ /** Same reuse pattern as RemoteComboBox/RemoteSelect, composing Base MultiSelect. */
13
+ export declare function RemoteMultiSelect<TValue extends string | number = string, TResponse = unknown>({ url, params, valueMember, displayMember, mapResponse, client, enabled, ...multiSelectProps }: RemoteMultiSelectProps<TValue, TResponse>): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { SelectProps } from '../base';
2
+ import { HttpClient } from './http/HttpClient';
3
+ export interface RemoteSelectProps<TValue extends string | number = string, TResponse = unknown> extends Omit<SelectProps<TValue>, "options" | "loading"> {
4
+ url: string;
5
+ params?: Record<string, unknown>;
6
+ valueMember: string;
7
+ displayMember: string;
8
+ mapResponse?: (response: TResponse) => unknown[];
9
+ client?: HttpClient;
10
+ enabled?: boolean;
11
+ }
12
+ /**
13
+ * Same reuse pattern as RemoteComboBox: composes Base Select instead of
14
+ * reimplementing it (doc section 20). Thin — only fetch lifecycle +
15
+ * valueMember/displayMember mapping belong here.
16
+ */
17
+ export declare function RemoteSelect<TValue extends string | number = string, TResponse = unknown>({ url, params, valueMember, displayMember, mapResponse, client, enabled, ...selectProps }: RemoteSelectProps<TValue, TResponse>): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function useDebouncedValue<T>(value: T, delayMs: number): T;
@@ -0,0 +1,31 @@
1
+ import { HttpClient } from '../http/HttpClient';
2
+ export type RemoteState = "idle" | "loading" | "success" | "empty" | "error";
3
+ export interface UseRemoteDataOptions<TResponse, TItem> {
4
+ client?: HttpClient;
5
+ /** `null`/`undefined` disables fetching entirely (e.g. RemoteAutoComplete below minSearchLength). */
6
+ url: string | null | undefined;
7
+ params?: Record<string, unknown>;
8
+ mapResponse: (response: TResponse) => TItem[];
9
+ enabled?: boolean;
10
+ }
11
+ export interface UseRemoteDataResult<TItem> {
12
+ state: RemoteState;
13
+ items: TItem[];
14
+ error: Error | null;
15
+ reload: () => void;
16
+ }
17
+ /**
18
+ * The one place remote/API data fetching lifecycle logic lives. Every
19
+ * Remote Component (RemoteComboBox, RemoteAutoComplete, RemoteDataGrid)
20
+ * composes this instead of writing its own fetch effect (doc section 6).
21
+ *
22
+ * Handles, per doc sections 5/7/8:
23
+ * - stable request identity: params are compared by serialized *value*,
24
+ * not object reference, so a new `{ ...params }` literal each render
25
+ * does not cause an infinite request loop.
26
+ * - request cancellation via AbortController.
27
+ * - stale-response protection via a monotonically increasing request id,
28
+ * which still guards correctness even if abort doesn't win the race.
29
+ * - a consistent idle/loading/success/empty/error state model.
30
+ */
31
+ export declare function useRemoteData<TResponse, TItem>({ client, url, params, mapResponse, enabled, }: UseRemoteDataOptions<TResponse, TItem>): UseRemoteDataResult<TItem>;
@@ -0,0 +1,31 @@
1
+ export interface HttpRequestOptions {
2
+ params?: Record<string, unknown>;
3
+ signal?: AbortSignal;
4
+ }
5
+ export interface HttpClient {
6
+ get<TResponse>(url: string, options?: HttpRequestOptions): Promise<TResponse>;
7
+ }
8
+ export declare class HttpError extends Error {
9
+ status: number;
10
+ statusText: string;
11
+ url: string;
12
+ constructor(status: number, statusText: string, url: string);
13
+ }
14
+ export interface CreateHttpClientOptions {
15
+ baseUrl?: string;
16
+ /** Injectable fetch implementation — used by tests, could also route through a wrapped/instrumented fetch. */
17
+ fetcher?: typeof fetch;
18
+ /**
19
+ * Extension point for cross-cutting concerns the doc explicitly defers
20
+ * (authorization, tenant headers, interceptors) without building them now
21
+ * (doc section 6: only establish extension points where justified).
22
+ */
23
+ buildRequestInit?: (url: string, init: RequestInit) => RequestInit;
24
+ }
25
+ /**
26
+ * The single place Remote Components go through to talk to a backend.
27
+ * Base Components never import this (enforced by dependency direction, not
28
+ * just convention — Base has no dependency on `remote/*` at all).
29
+ */
30
+ export declare function createHttpClient(options?: CreateHttpClientOptions): HttpClient;
31
+ export declare const defaultHttpClient: HttpClient;
@@ -0,0 +1,9 @@
1
+ export * from './http/HttpClient';
2
+ export * from './hooks/useRemoteData';
3
+ export * from './hooks/useDebouncedValue';
4
+ export * from './mapping';
5
+ export * from './RemoteComboBox';
6
+ export * from './RemoteAutoComplete';
7
+ export * from './RemoteDataGrid';
8
+ export * from './RemoteSelect';
9
+ export * from './RemoteMultiSelect';
@@ -0,0 +1,8 @@
1
+ import { SelectOption } from '../base';
2
+ /**
3
+ * Handles the two common response envelopes (bare array, `{ items: [...] }`)
4
+ * explicitly (doc section 11). Anything else must be handled via an
5
+ * explicit `mapResponse` — no guessing beyond these two conventions.
6
+ */
7
+ export declare function defaultArrayNormalization(response: unknown): unknown[];
8
+ export declare function toSelectOption<TValue extends string | number>(raw: unknown, valueMember: string, displayMember: string): SelectOption<TValue>;
@@ -0,0 +1,14 @@
1
+ import { SmartRuntimeContext } from './runtime';
2
+ import { SmartActionMetadata } from './types';
3
+ export interface SmartActionProps {
4
+ metadata: SmartActionMetadata;
5
+ ctx: Pick<SmartRuntimeContext, "actions" | "translate">;
6
+ }
7
+ /**
8
+ * Composes Base Button, not a second button implementation (doc §16/§20) —
9
+ * the only component-shaped thing action metadata currently resolves to.
10
+ * Unlike field metadata, an action's `component: "Button"` never needs a
11
+ * registry lookup: there is exactly one action UI shape, so there is
12
+ * nothing to resolve between.
13
+ */
14
+ export declare function SmartAction({ metadata, ctx }: SmartActionProps): import("react").JSX.Element | null;
@@ -0,0 +1,14 @@
1
+ import { SmartRuntimeContext } from './runtime';
2
+ import { SmartFormMetadata } from './types';
3
+ export interface SmartActionsProps {
4
+ metadata: SmartFormMetadata;
5
+ ctx: Pick<SmartRuntimeContext, "actions" | "translate">;
6
+ }
7
+ /**
8
+ * A thin iteration helper over SmartAction — the action-side counterpart
9
+ * of SmartForm (doc §09/§15). Maps `metadata.actions` to SmartActions and
10
+ * nothing else: no layout, no spacing, no handler logic of its own. The
11
+ * consuming screen wraps this in whatever layout (Stack, a form footer,
12
+ * a toolbar) it needs.
13
+ */
14
+ export declare function SmartActions({ metadata, ctx }: SmartActionsProps): import("react").JSX.Element | null;
@@ -0,0 +1,18 @@
1
+ import { ReactElement } from 'react';
2
+ import { SmartRuntimeContext } from './runtime';
3
+ import { SmartFieldMetadata } from './types';
4
+ export interface SmartFieldProps {
5
+ metadata: SmartFieldMetadata;
6
+ ctx: SmartRuntimeContext;
7
+ }
8
+ /**
9
+ * Given one field's metadata, resolves it into whatever Base/Remote
10
+ * component its `component` discriminant maps to (doc §09/§14) — it owns
11
+ * no UI of its own, only delegates to `ctx.registry`.
12
+ *
13
+ * Also wires the mechanical dependency tracking every metadata-driven
14
+ * field needs (doc §06): a consuming screen no longer calls
15
+ * useSmartDependencies by hand per field, SmartField does it here and
16
+ * reports which field needed the refresh, not just which value changed.
17
+ */
18
+ export declare function SmartField({ metadata, ctx }: SmartFieldProps): ReactElement | null;
@@ -0,0 +1,19 @@
1
+ import { SmartRuntimeContext } from './runtime';
2
+ import { SmartFormMetadata } from './types';
3
+ export interface SmartFormProps {
4
+ metadata: SmartFormMetadata;
5
+ ctx: SmartRuntimeContext;
6
+ }
7
+ /**
8
+ * A thin iteration helper over SmartField (doc §09/§15/§18 decision 4) —
9
+ * it owns no field values, evaluates no business rule, and decides no
10
+ * layout. Its only two responsibilities: fail the whole form closed on an
11
+ * unsupported schema version instead of rendering a partially-understood
12
+ * form (doc §12, reusing Alert rather than a bespoke error UI), and map
13
+ * each field's metadata to a SmartField.
14
+ *
15
+ * A SmartField used standalone (outside SmartForm) is responsible for its
16
+ * own schemaVersion check — this component is the only place that check
17
+ * happens automatically.
18
+ */
19
+ export declare function SmartForm({ metadata, ctx }: SmartFormProps): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ export type SmartActionHandler = () => void;
2
+ export interface SmartActionRegistry {
3
+ register(id: string, handler: SmartActionHandler): void;
4
+ resolve(id: string): SmartActionHandler | undefined;
5
+ }
6
+ /**
7
+ * Metadata carries an action id, never a function (doc §08/§11 — no
8
+ * executable code from the server, ever). The application registers the
9
+ * real handler once; Smart only looks it up by id.
10
+ */
11
+ export declare function createSmartActionRegistry(): SmartActionRegistry;
@@ -0,0 +1,24 @@
1
+ import { ReactElement } from 'react';
2
+ import { SmartFieldMetadata } from './types';
3
+ import { SmartRuntimeContext } from './runtime';
4
+ export type SmartResolver<M extends SmartFieldMetadata = SmartFieldMetadata> = (metadata: M, ctx: SmartRuntimeContext) => ReactElement | null;
5
+ export interface SmartComponentRegistry {
6
+ register<M extends SmartFieldMetadata>(component: M["component"], resolver: SmartResolver<M>): void;
7
+ resolve(metadata: SmartFieldMetadata, ctx: SmartRuntimeContext): ReactElement | null;
8
+ has(component: string): boolean;
9
+ }
10
+ /**
11
+ * Keyed by the `component` discriminant — not a switch, not a plugin
12
+ * framework (doc §04). Type safety lives at the register()/resolve()
13
+ * generic boundary; internal storage type-erases to `SmartResolver`, the
14
+ * same escape hatch any typed registry needs, isolated to this one
15
+ * function. No component type is privileged: Phase 2's built-in Input/
16
+ * ComboBox/DatePicker/DataGrid resolvers will register through this exact
17
+ * same call an application uses for a custom component.
18
+ *
19
+ * An unresolved `component` value never falls back to an unrelated
20
+ * component (doc §12) — resolve() returns null and warns once per unknown
21
+ * component name, so a field silently disappears from the form instead of
22
+ * rendering the wrong thing.
23
+ */
24
+ export declare function createSmartComponentRegistry(): SmartComponentRegistry;
@@ -0,0 +1,17 @@
1
+ import { HttpClient } from '../remote';
2
+ export interface SmartDataSourceDefinition {
3
+ url: string;
4
+ /** Defaults to Remote's own defaultHttpClient when omitted, same as RemoteComboBox etc. already do. */
5
+ client?: HttpClient;
6
+ }
7
+ export interface SmartDataSourceRegistry {
8
+ register(id: string, definition: SmartDataSourceDefinition): void;
9
+ resolve(id: string): SmartDataSourceDefinition | undefined;
10
+ }
11
+ /**
12
+ * Backs the id-based indirection decided in doc §09/§18 (decision 2):
13
+ * metadata never carries a raw URL, only an id an application registers
14
+ * once. The application owns environment/hostname/auth wiring in one
15
+ * place — Smart never needs to know it exists.
16
+ */
17
+ export declare function createSmartDataSourceRegistry(initial?: Record<string, SmartDataSourceDefinition>): SmartDataSourceRegistry;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Smart layer — Phases 1-5 complete (approved architecture, see the
3
+ * "Smart Components" design doc):
4
+ * Phase 1 — metadata types, the three registries, the headless
5
+ * useSmartField/useSmartDependencies engine.
6
+ * Phase 2 — built-in Input/ComboBox/DatePicker resolvers + SmartField.
7
+ * Phase 3 — SmartForm, a thin iteration helper over SmartField.
8
+ * Phase 4 — built-in DataGrid resolver + declarative column metadata.
9
+ * Phase 5 — useSmartAction/SmartAction/SmartActions (the action-side
10
+ * counterpart of useSmartField/SmartField/SmartForm), and
11
+ * localized boolean-column formatting in the DataGrid
12
+ * resolver.
13
+ */
14
+ export * from './types';
15
+ export * from './componentRegistry';
16
+ export * from './dataSourceRegistry';
17
+ export * from './actionRegistry';
18
+ export * from './runtime';
19
+ export * from './useSmartField';
20
+ export * from './useSmartDependencies';
21
+ export * from './useSmartAction';
22
+ export * from './resolvers';
23
+ export * from './SmartField';
24
+ export * from './SmartForm';
25
+ export * from './SmartAction';
26
+ export * from './SmartActions';
@@ -0,0 +1,10 @@
1
+ import { SmartResolver } from '../componentRegistry';
2
+ import { ComboBoxMetadata } from '../types';
3
+ /**
4
+ * Composes RemoteComboBox, not ComboBox directly (doc §04 — Base vs. Remote
5
+ * is inferred from the metadata shape: ComboBoxMetadata always carries a
6
+ * `dataSource`, so this field is always remote-backed). RemoteComboBox in
7
+ * turn composes Base ComboBox, so no selection/keyboard/popup behavior is
8
+ * duplicated anywhere in this chain.
9
+ */
10
+ export declare const comboBoxResolver: SmartResolver<ComboBoxMetadata>;
@@ -0,0 +1,11 @@
1
+ import { SmartResolver } from '../componentRegistry';
2
+ import { DataGridMetadata } from '../types';
3
+ /**
4
+ * Composes RemoteDataGrid, not Base DataGrid directly (doc §04 — inferred
5
+ * from `dataSource` the same way ComboBoxMetadata is). Column metadata is
6
+ * translated into a real `DataGridColumn<TRow>[]` and handed straight to
7
+ * the existing grid — no second grid engine, no filtering/grouping DSL
8
+ * (doc §10, matching the original library's own DataGrid scope
9
+ * restraint).
10
+ */
11
+ export declare const dataGridResolver: SmartResolver<DataGridMetadata>;
@@ -0,0 +1,3 @@
1
+ import { SmartResolver } from '../componentRegistry';
2
+ import { DatePickerMetadata } from '../types';
3
+ export declare const datePickerResolver: SmartResolver<DatePickerMetadata>;
@@ -0,0 +1,13 @@
1
+ import { SmartComponentRegistry } from '../componentRegistry';
2
+ import { comboBoxResolver } from './comboBoxResolver';
3
+ import { dataGridResolver } from './dataGridResolver';
4
+ import { datePickerResolver } from './datePickerResolver';
5
+ import { inputResolver } from './inputResolver';
6
+ export { comboBoxResolver, dataGridResolver, datePickerResolver, inputResolver };
7
+ /**
8
+ * Registers Input/ComboBox/DatePicker/DataGrid through the exact same
9
+ * `register()` call an application uses for a custom component (doc §04 —
10
+ * no privileged core; a custom "PatientSelector" resolver is registered
11
+ * the same way).
12
+ */
13
+ export declare function registerBuiltInResolvers(registry: SmartComponentRegistry): void;
@@ -0,0 +1,8 @@
1
+ import { SmartResolver } from '../componentRegistry';
2
+ import { InputMetadata } from '../types';
3
+ /**
4
+ * Composes Base Input (doc §03/§20 — reuse, not a second text-field
5
+ * implementation). The only thing this file owns is translating resolved
6
+ * metadata into Input's existing prop contract.
7
+ */
8
+ export declare const inputResolver: SmartResolver<InputMetadata>;
@@ -0,0 +1,26 @@
1
+ import { SmartActionRegistry } from './actionRegistry';
2
+ import { SmartComponentRegistry } from './componentRegistry';
3
+ import { SmartDataSourceRegistry } from './dataSourceRegistry';
4
+ /**
5
+ * What a resolver/SmartField needs to turn one piece of metadata into
6
+ * component props. Deliberately owns no canonical field values of its own
7
+ * (doc §05/§18 decision 3) — `values` is always a read-only snapshot the
8
+ * caller supplies, the same controlled shape any Base field already uses
9
+ * via `value`/`onChange`.
10
+ */
11
+ export interface SmartRuntimeContext {
12
+ values: Record<string, unknown>;
13
+ onFieldChange: (name: string, value: unknown) => void;
14
+ registry: SmartComponentRegistry;
15
+ dataSources: SmartDataSourceRegistry;
16
+ actions: SmartActionRegistry;
17
+ /** Absent = fall back to metadata's raw `label`/`helpText`/etc. strings (doc §07). */
18
+ translate?: (key: string) => string;
19
+ /**
20
+ * Mechanical signal only — "`fieldName`'s metadata needs refreshing
21
+ * because `changedField` changed." Never evaluates why; SmartField wires
22
+ * this to useSmartDependencies automatically for every field, so a
23
+ * consuming screen no longer calls the hook by hand.
24
+ */
25
+ onMetadataRefreshNeeded?: (fieldName: string, changedField: string) => void;
26
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Metadata contracts for the Smart layer (architecture proposal, approved —
3
+ * see the "Smart Components" design doc). A discriminated union, not one
4
+ * universal object — the same split Base already uses between
5
+ * FieldIdentity/FieldState/FieldPresentation, one layer up. Components
6
+ * compose only the mixins that apply to them.
7
+ *
8
+ * This module is pure data shape. It renders nothing and calls nothing —
9
+ * resolvers (src/smart/resolvers) are the only files that turn it into UI.
10
+ */
11
+ export interface SmartFieldIdentity {
12
+ /** Binding key — looked up against a runtime `values` record, never owned by Smart itself. */
13
+ name: string;
14
+ /**
15
+ * Field names whose *value* this field's configuration depends on.
16
+ * Mechanical only: it tells Smart when to ask the backend for fresh
17
+ * metadata, never what the backend's answer should be (doc §06 — business
18
+ * rules stay server-owned).
19
+ */
20
+ dependsOn?: string[];
21
+ }
22
+ export interface SmartFieldState {
23
+ visible?: boolean;
24
+ readOnly?: boolean;
25
+ disabled?: boolean;
26
+ required?: boolean;
27
+ }
28
+ export interface SmartPresentation {
29
+ label?: string;
30
+ /** Semantic key, resolved via a caller-supplied `translate`. Wins over `label` when both are present (doc §07). */
31
+ labelKey?: string;
32
+ placeholder?: string;
33
+ helpText?: string;
34
+ }
35
+ export interface SmartValidation {
36
+ validationMessage?: string;
37
+ /** Semantic key, resolved via a caller-supplied `translate`. Wins over `validationMessage` when both are present. */
38
+ validationMessageKey?: string;
39
+ }
40
+ /**
41
+ * A data-source request parameter is either a literal or a reference to
42
+ * another field's current value — never a magic string like "$CountryId"
43
+ * (doc §06/§09).
44
+ */
45
+ export type SmartParamValue = {
46
+ kind: "static";
47
+ value: unknown;
48
+ } | {
49
+ kind: "field";
50
+ field: string;
51
+ };
52
+ export interface SmartDataSourceRef {
53
+ /** Id registered in a SmartDataSourceRegistry — never a raw URL (doc §09/§11/§18 decision 2). */
54
+ id: string;
55
+ params?: Record<string, SmartParamValue>;
56
+ }
57
+ export interface InputMetadata extends SmartFieldIdentity, SmartFieldState, SmartPresentation, SmartValidation {
58
+ component: "Input";
59
+ maxLength?: number;
60
+ }
61
+ export interface ComboBoxMetadata extends SmartFieldIdentity, SmartFieldState, SmartPresentation, SmartValidation {
62
+ component: "ComboBox";
63
+ valueMember: string;
64
+ displayMember: string;
65
+ dataSource: SmartDataSourceRef;
66
+ }
67
+ export interface DatePickerMetadata extends SmartFieldIdentity, SmartFieldState, SmartPresentation, SmartValidation {
68
+ component: "DatePicker";
69
+ minDate?: string;
70
+ maxDate?: string;
71
+ }
72
+ export interface SmartDataGridColumn {
73
+ key: string;
74
+ header?: string;
75
+ headerKey?: string;
76
+ sortable?: boolean;
77
+ visible?: boolean;
78
+ format?: "text" | "date" | "currency" | "boolean";
79
+ }
80
+ export interface DataGridMetadata extends SmartFieldIdentity, SmartFieldState, SmartPresentation, SmartValidation {
81
+ component: "DataGrid";
82
+ columns: SmartDataGridColumn[];
83
+ dataSource: SmartDataSourceRef;
84
+ /** Row field each row's unique identity is read from — DataGrid always needs a stable key. */
85
+ rowKey: string;
86
+ /**
87
+ * Top-level key on the raw response holding a total row count (e.g.
88
+ * "total" for a `{ items, total }` envelope) — a declarative field-name
89
+ * reference, the same pattern as `valueMember`/`displayMember` on
90
+ * ComboBoxMetadata, never a function (doc §07/§24). Omit to fall back to
91
+ * RemoteDataGrid's has-more heuristic.
92
+ */
93
+ totalCountField?: string;
94
+ }
95
+ /**
96
+ * Add a new component type by adding a member here, not by widening an
97
+ * existing one (doc §03 — the trade for type safety is that a new component
98
+ * type needs a client-side union member before the backend can use it).
99
+ */
100
+ export type SmartFieldMetadata = InputMetadata | ComboBoxMetadata | DatePickerMetadata | DataGridMetadata;
101
+ export interface SmartActionMetadata {
102
+ id: string;
103
+ component: "Button";
104
+ visible?: boolean;
105
+ enabled?: boolean;
106
+ label?: string;
107
+ labelKey?: string;
108
+ }
109
+ export interface SmartFormMetadata {
110
+ /** Mandatory. An unsupported version fails the whole form closed (doc §12) — never a partial render. */
111
+ schemaVersion: string;
112
+ fields: SmartFieldMetadata[];
113
+ actions?: SmartActionMetadata[];
114
+ }
@@ -0,0 +1,36 @@
1
+ import { SmartActionRegistry, SmartActionHandler } from './actionRegistry';
2
+ import { SmartActionMetadata, SmartFormMetadata } from './types';
3
+ export interface UseSmartActionOptions {
4
+ actions: SmartActionRegistry;
5
+ /** Absent = fall back to metadata's raw `label` string (doc §07). */
6
+ translate?: (key: string) => string;
7
+ }
8
+ export interface ResolvedSmartAction {
9
+ metadata: SmartActionMetadata;
10
+ visible: boolean;
11
+ /**
12
+ * `metadata.enabled` ANDed with "a handler actually exists" — metadata
13
+ * saying `enabled: true` cannot make an action clickable if the
14
+ * application never registered a handler for its id (doc §12 fail-safe:
15
+ * an unregistered action renders disabled, never a no-op that looks
16
+ * clickable).
17
+ */
18
+ enabled: boolean;
19
+ label?: string;
20
+ handler?: SmartActionHandler;
21
+ }
22
+ /**
23
+ * Resolves one already-known action's metadata. Pure function, mirrors
24
+ * `resolveSmartFieldMetadata` — action metadata carries an id, never a
25
+ * function; the real handler comes from the application-owned
26
+ * `SmartActionRegistry` (doc §08/§16), looked up here by that id.
27
+ */
28
+ export declare function resolveSmartActionMetadata(metadata: SmartActionMetadata, options: UseSmartActionOptions): ResolvedSmartAction;
29
+ /**
30
+ * Looks an action up by id in `formMetadata.actions` and resolves it via
31
+ * `resolveSmartActionMetadata` — the action-side counterpart of
32
+ * `useSmartField`. Returns `undefined` when no action with that id is
33
+ * declared, the same "not present = left alone" convention `useSmartField`
34
+ * uses for fields.
35
+ */
36
+ export declare function useSmartAction(id: string, formMetadata: SmartFormMetadata | undefined, options: UseSmartActionOptions): ResolvedSmartAction | undefined;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Mechanical dependency tracking only (doc §06/§10): watches the fields a
3
+ * piece of metadata declared via `dependsOn` and calls
4
+ * `onMetadataRefreshNeeded` once per field whose value actually changed
5
+ * since the last render. It never evaluates *why* a change matters — that
6
+ * stays server-owned; this hook only decides *when to ask again*.
7
+ *
8
+ * Uses the same "stable value-based identity" strategy as useRemoteData's
9
+ * `paramsKey` (serialize, compare by value, not by object/array reference)
10
+ * to avoid the exact infinite-loop failure mode the original architecture
11
+ * doc warns against for Remote's own params.
12
+ */
13
+ export declare function useSmartDependencies(dependsOn: string[] | undefined, values: Record<string, unknown>, onMetadataRefreshNeeded?: (changedField: string) => void): void;
@@ -0,0 +1,47 @@
1
+ import { SmartFieldMetadata, SmartFormMetadata } from './types';
2
+ export interface UseSmartFieldOptions {
3
+ values: Record<string, unknown>;
4
+ /** Absent = fall back to metadata's raw `label`/`helpText`/etc. strings. */
5
+ translate?: (key: string) => string;
6
+ }
7
+ export interface ResolvedSmartField<M extends SmartFieldMetadata = SmartFieldMetadata> {
8
+ metadata: M;
9
+ visible: boolean;
10
+ readOnly: boolean;
11
+ disabled: boolean;
12
+ required: boolean;
13
+ label?: string;
14
+ placeholder?: string;
15
+ helpText?: string;
16
+ validationMessage?: string;
17
+ /**
18
+ * Only present for metadata carrying a `dataSource` (ComboBox/DataGrid).
19
+ * Resolved from `dataSource.params` + the current `values` snapshot —
20
+ * ready to pass straight through as a Remote component's `params` prop
21
+ * (doc §06). Field-name lookups that miss simply resolve to `undefined`,
22
+ * same as reading a missing key off any plain object.
23
+ */
24
+ params?: Record<string, unknown>;
25
+ }
26
+ /**
27
+ * Resolves one already-known metadata object. Pure function of its
28
+ * arguments — no React state, no effect, no fetch. Exported separately from
29
+ * `useSmartField` so a component-registry resolver that already holds a
30
+ * specific field's metadata (as `SmartResolver` hands it) can reuse this
31
+ * exact translate/params logic instead of re-deriving it (doc §04's
32
+ * resolvers and `useSmartField`'s by-name lookup are two entry points onto
33
+ * the same resolution, not two implementations).
34
+ */
35
+ export declare function resolveSmartFieldMetadata<M extends SmartFieldMetadata = SmartFieldMetadata>(metadata: M, options: UseSmartFieldOptions): ResolvedSmartField<M>;
36
+ /**
37
+ * The headless engine every Smart component composes (doc §05/§18 —
38
+ * Smart Runtime owns no canonical state). Looks a field up by name in
39
+ * `formMetadata` and resolves it via `resolveSmartFieldMetadata`. Anything
40
+ * not present in the metadata map is left alone: a field with no matching
41
+ * metadata entry returns `undefined`, meaning "not driven by metadata," not
42
+ * "hidden."
43
+ *
44
+ * A future SmartField component will call this directly, the same way
45
+ * RemoteComboBox composes useRemoteData instead of writing its own effect.
46
+ */
47
+ export declare function useSmartField<M extends SmartFieldMetadata = SmartFieldMetadata>(name: string, formMetadata: SmartFormMetadata | undefined, options: UseSmartFieldOptions): ResolvedSmartField<M> | undefined;