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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 suleymangulle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # rich-react-component
2
+
3
+ Repository: [github.com/suleymangulle/rich-react-component](https://github.com/suleymangulle/rich-react-component) (private) · [npm](https://www.npmjs.com/package/rich-react-component)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/rich-react-component.svg)](https://www.npmjs.com/package/rich-react-component)
6
+
7
+ Enterprise React + TypeScript component library built on **Bootstrap + Metronic** conventions, organized into three capability layers:
8
+
9
+ ```text
10
+ Base — pure UI behavior, no HTTP, no backend knowledge
11
+ Remote — adds remote-data fetching to Base components by composing them
12
+ Smart — metadata-driven configuration layer (Phases 1-5 complete)
13
+ ```
14
+
15
+ Each layer **reuses** the one below it instead of reimplementing it — `RemoteComboBox` composes `ComboBox`, it does not contain a second combobox implementation. See [`react-components-initial.md`](./react-components-initial.md) for the original architecture brief this library follows.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install rich-react-component bootstrap react react-dom
21
+ ```
22
+
23
+ `bootstrap`, `react`, and `react-dom` are peer dependencies — the library ships no CSS of its own beyond what Bootstrap classes provide.
24
+
25
+ ```tsx
26
+ import "bootstrap/dist/css/bootstrap.min.css";
27
+ ```
28
+
29
+ ## Quick example
30
+
31
+ ```tsx
32
+ import { ComboBox, SmartField } from "rich-react-component";
33
+ import { RemoteComboBox } from "rich-react-component";
34
+
35
+ // Base — you own the data
36
+ <ComboBox
37
+ options={[{ value: "tr", label: "Turkey" }]}
38
+ value={countryId}
39
+ onChange={setCountryId}
40
+ />
41
+
42
+ // Remote — the component owns fetching, cancellation, and stale-response
43
+ // protection; you only describe the endpoint and the field mapping
44
+ <RemoteComboBox
45
+ url="/api/countries"
46
+ valueMember="id"
47
+ displayMember="name"
48
+ value={countryId}
49
+ onChange={setCountryId}
50
+ />
51
+
52
+ // Smart — the server describes the field, SmartField resolves it onto
53
+ // RemoteComboBox for you; visible/readOnly/required/validation all come
54
+ // from metadata instead of being written by hand at every call site
55
+ <SmartField
56
+ metadata={{
57
+ name: "countryId", component: "ComboBox",
58
+ valueMember: "id", displayMember: "name",
59
+ dataSource: { id: "Countries" },
60
+ }}
61
+ ctx={ctx} // { values, onFieldChange, registry, dataSources, actions }
62
+ />
63
+ ```
64
+
65
+ ## What's in each layer
66
+
67
+ **Base** (49 components) — form fields (`Input`, `NumberInput`, `PasswordInput`, `FileInput`, `CheckBox`, `Switch`, `RadioGroup`, `Select`, `MultiSelect`, `DatePicker`, `TimePicker`, `DateTimePicker`, `ComboBox`, `AutoComplete`, `FormField`), feedback (`Modal`, `Toast`, `Confirm`, `Alert`, `Spinner`, `Badge`, `Skeleton`), data display (`DataGrid`, `Pagination`, `Avatar`, `Tag`, `Rating`, `ProgressBar`), navigation (`Breadcrumb`, `Menu`, `Stepper`, `Tabs`, `Navbar`, `Sidebar`, `PageHeader`), layout (`Card`, `Divider`, `Stack`, `Container`, `Row`, `Col`), and more (`Button`, `Tooltip`, `Popover`, `Accordion`, `Icon`).
68
+
69
+ **Remote** — `RemoteComboBox`, `RemoteAutoComplete`, `RemoteSelect`, `RemoteMultiSelect`, `RemoteDataGrid`, backed by a shared `HttpClient` abstraction and a `useRemoteData` hook that handles request cancellation, stale-response protection, and a consistent `idle/loading/success/empty/error` state model.
70
+
71
+ **Smart** — *Phases 1-5 complete, the full approved plan.* A metadata-driven layer: the server describes a field or action, Smart resolves that description onto the exact Base/Remote component that already exists — it never reimplements one.
72
+
73
+ - **Metadata contract** — a discriminated union per component type (`InputMetadata | ComboBoxMetadata | DatePickerMetadata | DataGridMetadata`), plus `SmartActionMetadata` for buttons. Declarative only: no expressions, no serialized functions.
74
+ - **Registries** — `SmartComponentRegistry` (keyed by the `component` discriminant, not a switch), `SmartDataSourceRegistry` and `SmartActionRegistry` (id-based indirection — metadata never carries a raw URL or a function).
75
+ - **Built-in resolvers** — Input, ComboBox, DatePicker, and DataGrid, registered via `registerBuiltInResolvers()` through the exact same call a custom application component would use. DataGrid's column metadata (`format: "text" | "date" | "currency" | "boolean"`) maps to a small, Smart-owned set of formatters — the server requests a formatter, never ships one.
76
+ - **Headless engine** — `useSmartField` / `useSmartAction` resolve one field/action's metadata (visibility, validation, localized label, resolved request params); `useSmartDependencies` tracks `dependsOn` and reports which field needs fresh metadata when a value it depends on changes.
77
+ - **Components** — `SmartField` / `SmartAction` resolve one piece of metadata into UI; `SmartForm` / `SmartActions` are thin iteration helpers over a whole `SmartFormMetadata` — no field-value ownership, no business-rule evaluation, no layout decisions.
78
+
79
+ ## Demo pages
80
+
81
+ Two dev-only pages exercise the library live — not part of the published package:
82
+
83
+ ```bash
84
+ npm run dev
85
+ ```
86
+
87
+ - `/index.html` — every Base/Remote component in one manual-test page
88
+ - `/smart-demo.html` — the full Phase 1-5 Smart engine end to end: a cascading Country/City form and server-driven field visibility/validation rendered through one `<SmartForm>` call, a paginated DataGrid through one `<SmartField>` call, `<SmartActions>` with a real fail-safe-disabled button, a dependency-refresh log, and EN/TR localization (including the DataGrid's boolean formatter) — with in-page documentation popups
89
+
90
+ ## Scripts
91
+
92
+ | Command | Description |
93
+ | --- | --- |
94
+ | `npm run dev` | Start the demo pages with Vite |
95
+ | `npm run build` | Type-check + build the library to `dist/` (ESM, CJS, `.d.ts`) |
96
+ | `npm test` | Run the test suite once (Vitest) |
97
+ | `npm run test:watch` | Run tests in watch mode |
98
+ | `npm run typecheck` | Type-check the whole project without emitting |
99
+
100
+ ## Project structure
101
+
102
+ ```text
103
+ src/
104
+ ├── base/ # Base layer — no dependency on remote/ or smart/
105
+ ├── remote/ # Remote layer — may depend on base/, not on smart/
106
+ ├── smart/ # Smart layer (Phases 1-5) — may depend on base/ and remote/
107
+ └── index.ts # public entry point
108
+
109
+ demo/ # dev-only manual-test pages (not published)
110
+ ```
111
+
112
+ ## Testing
113
+
114
+ Behavioral tests over snapshots. Every capability layer is tested against its own contract — Base components never call `fetch`, Remote components reuse (not duplicate) their Base counterpart's UI, dependency-driven param changes reload correctly without stale-response races, and the Smart registry falls back safely for an unresolved component type instead of rendering the wrong thing.
115
+
116
+ ## License
117
+
118
+ [MIT](./LICENSE) © suleymangulle
@@ -0,0 +1,17 @@
1
+ import { ReactNode } from 'react';
2
+ export interface AccordionItem {
3
+ key: string;
4
+ header: string;
5
+ content: ReactNode;
6
+ disabled?: boolean;
7
+ }
8
+ export interface AccordionProps {
9
+ items: AccordionItem[];
10
+ /** false (default) = single-open (classic accordion); true = multiple sections can be open at once. */
11
+ multiple?: boolean;
12
+ openKeys?: string[];
13
+ defaultOpenKeys?: string[];
14
+ onChange?: (openKeys: string[]) => void;
15
+ className?: string;
16
+ }
17
+ export declare function Accordion({ items, multiple, openKeys, defaultOpenKeys, onChange, className }: AccordionProps): import("react").JSX.Element;
@@ -0,0 +1,15 @@
1
+ import { ReactNode } from 'react';
2
+ export type AlertVariant = "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark";
3
+ export interface AlertProps {
4
+ variant?: AlertVariant;
5
+ dismissible?: boolean;
6
+ onDismiss?: () => void;
7
+ className?: string;
8
+ children: ReactNode;
9
+ }
10
+ /**
11
+ * Presentation only (doc section 15) — deliberately not a toast
12
+ * service/notification bus/error-management system. A consumer owns when
13
+ * an Alert mounts/unmounts and what triggers it.
14
+ */
15
+ export declare function Alert({ variant, dismissible, onDismiss, className, children }: AlertProps): import("react").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { FieldIdentity, FieldPresentation, FieldState, SelectOption } from './shared/fieldTypes';
2
+ export interface AutoCompleteProps<TValue extends string | number = string> extends FieldIdentity, FieldState, FieldPresentation {
3
+ options: SelectOption<TValue>[];
4
+ value?: TValue | null;
5
+ defaultValue?: TValue | null;
6
+ onChange?: (value: TValue | null) => void;
7
+ /** Controlled search text, independent from the selected `value`. */
8
+ inputValue?: string;
9
+ onInputValueChange?: (text: string) => void;
10
+ /** Presentational-only loading flag — see ComboBox's `loading` prop. */
11
+ loading?: boolean;
12
+ emptyText?: string;
13
+ /**
14
+ * Local filter predicate. Defaults to a case-insensitive substring match.
15
+ * RemoteAutoComplete overrides this with `() => true` because the server
16
+ * already filtered the results — Base must never re-filter server output.
17
+ */
18
+ filter?: (option: SelectOption<TValue>, query: string) => boolean;
19
+ }
20
+ export declare function AutoComplete<TValue extends string | number = string>({ options, value, defaultValue, onChange, inputValue, onInputValueChange, loading, emptyText, filter, id, name, disabled, readOnly, required, className, label, placeholder, helpText, error, }: AutoCompleteProps<TValue>): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ export interface AvatarProps {
2
+ src?: string;
3
+ /** Used both for the image's alt text and for the initials fallback when there's no `src`. */
4
+ name?: string;
5
+ size?: "sm" | "md" | "lg";
6
+ className?: string;
7
+ }
8
+ export declare function Avatar({ src, name, size, className }: AvatarProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ export type BadgeVariant = "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark";
3
+ export interface BadgeProps {
4
+ variant?: BadgeVariant;
5
+ pill?: boolean;
6
+ className?: string;
7
+ children: ReactNode;
8
+ }
9
+ export declare function Badge({ variant, pill, className, children }: BadgeProps): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ export interface BreadcrumbItem {
2
+ label: string;
3
+ href?: string;
4
+ onClick?: () => void;
5
+ }
6
+ export interface BreadcrumbProps {
7
+ items: BreadcrumbItem[];
8
+ className?: string;
9
+ }
10
+ export declare function Breadcrumb({ items, className }: BreadcrumbProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { ButtonHTMLAttributes, ReactNode } from 'react';
2
+ export type ButtonVariant = "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark" | "link" | "outline-primary" | "outline-secondary";
3
+ export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "className" | "type" | "disabled"> {
4
+ variant?: ButtonVariant;
5
+ size?: "sm" | "lg";
6
+ disabled?: boolean;
7
+ loading?: boolean;
8
+ type?: "button" | "submit" | "reset";
9
+ className?: string;
10
+ children?: ReactNode;
11
+ }
12
+ /** Reuses Spinner for the loading indicator (doc section 13) instead of a bespoke inline spinner. */
13
+ export declare function Button({ variant, size, disabled, loading, type, className, children, onClick, ...rest }: ButtonProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ export interface CardProps {
3
+ header?: ReactNode;
4
+ footer?: ReactNode;
5
+ className?: string;
6
+ children?: ReactNode;
7
+ }
8
+ /** Generic content container — the most basic layout primitive, used to group everything else. */
9
+ export declare function Card({ header, footer, className, children }: CardProps): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { FieldIdentity, FieldState } from './shared/fieldTypes';
2
+ export interface CheckBoxProps extends FieldIdentity, FieldState {
3
+ className?: string;
4
+ label?: string;
5
+ helpText?: string;
6
+ error?: string;
7
+ checked?: boolean;
8
+ defaultChecked?: boolean;
9
+ onChange?: (checked: boolean) => void;
10
+ }
11
+ /**
12
+ * Deliberately doesn't use FieldShell — a checkbox's label sits beside the
13
+ * control, not above it, so the layout genuinely differs (doc section 13:
14
+ * shared contracts only where a real semantic relationship exists). Shares
15
+ * its actual rendering with Switch via BooleanFieldControl.
16
+ */
17
+ export declare function CheckBox(props: CheckBoxProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from 'react';
2
+ export interface ColProps {
3
+ /** Column width at the default breakpoint (1-12). Omit for `col` (auto-width). */
4
+ span?: number;
5
+ sm?: number;
6
+ md?: number;
7
+ lg?: number;
8
+ xl?: number;
9
+ className?: string;
10
+ children?: ReactNode;
11
+ }
12
+ export declare function Col({ span, sm, md, lg, xl, className, children }: ColProps): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { FieldIdentity, FieldPresentation, FieldState, SelectOption } from './shared/fieldTypes';
2
+ export type { SelectOption };
3
+ export interface ComboBoxProps<TValue extends string | number = string> extends FieldIdentity, FieldState, FieldPresentation {
4
+ options: SelectOption<TValue>[];
5
+ value?: TValue | null;
6
+ defaultValue?: TValue | null;
7
+ onChange?: (value: TValue | null) => void;
8
+ /**
9
+ * Presentational-only loading flag. ComboBox has no idea *why* it's
10
+ * loading (doc section 8: don't pollute Base with HTTP concepts) — this
11
+ * is set by RemoteComboBox, but could equally be driven by any other
12
+ * async source.
13
+ */
14
+ loading?: boolean;
15
+ emptyText?: string;
16
+ }
17
+ export declare function ComboBox<TValue extends string | number = string>({ options, value, defaultValue, onChange, loading, emptyText, id, name, disabled, readOnly, required, className, label, placeholder, helpText, error, }: ComboBoxProps<TValue>): import("react").JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { ReactNode } from 'react';
2
+ import { ButtonVariant } from './Button';
3
+ export interface ConfirmOptions {
4
+ title?: string;
5
+ message: ReactNode;
6
+ confirmLabel?: string;
7
+ cancelLabel?: string;
8
+ confirmVariant?: ButtonVariant;
9
+ }
10
+ export type ConfirmFn = (options: ConfirmOptions) => Promise<boolean>;
11
+ /**
12
+ * Imperative yes/no dialog. Built on Modal + Button (doc section 20: reuse,
13
+ * don't reimplement) instead of every screen wiring its own "are you sure"
14
+ * modal-open state and footer buttons by hand.
15
+ *
16
+ * Known limitation: a second confirm() call while one is still pending
17
+ * replaces it — the first promise never settles. Acceptable for v1 (doc
18
+ * section 6: avoid speculative infrastructure); a queue can be added if a
19
+ * real screen needs overlapping confirms.
20
+ */
21
+ export declare function ConfirmProvider({ children }: {
22
+ children: ReactNode;
23
+ }): import("react").JSX.Element;
24
+ /** Throws outside ConfirmProvider — same fail-fast contract as other context-backed hooks in this library. */
25
+ export declare function useConfirm(): ConfirmFn;
@@ -0,0 +1,7 @@
1
+ import { ReactNode } from 'react';
2
+ export interface ContainerProps {
3
+ fluid?: boolean;
4
+ className?: string;
5
+ children?: ReactNode;
6
+ }
7
+ export declare function Container({ fluid, className, children }: ContainerProps): import("react").JSX.Element;
@@ -0,0 +1,43 @@
1
+ import { ReactNode } from 'react';
2
+ export interface DataGridColumn<TRow> {
3
+ key: string;
4
+ header: string;
5
+ render?: (row: TRow) => ReactNode;
6
+ sortable?: boolean;
7
+ width?: string;
8
+ }
9
+ export type DataGridSort = {
10
+ key: string;
11
+ direction: "asc" | "desc";
12
+ };
13
+ export interface DataGridProps<TRow> {
14
+ columns: DataGridColumn<TRow>[];
15
+ rows: TRow[];
16
+ rowKey: (row: TRow) => string | number;
17
+ loading?: boolean;
18
+ error?: string;
19
+ emptyText?: string;
20
+ className?: string;
21
+ /** Selection is a generic UI concern — Base doesn't know how selection maps to anything remote. */
22
+ selectedRowKeys?: Array<string | number>;
23
+ onSelectionChange?: (keys: Array<string | number>) => void;
24
+ /**
25
+ * Sort UI only. Base renders sort indicators and calls back on header
26
+ * click — it has no idea whether sorting happens client-side or via a
27
+ * server request (doc section 10).
28
+ */
29
+ sort?: DataGridSort | null;
30
+ onSortChange?: (sort: DataGridSort | null) => void;
31
+ /** Pagination UI only, fully controlled from outside — same principle as sort. */
32
+ page?: number;
33
+ pageSize?: number;
34
+ totalCount?: number;
35
+ onPageChange?: (page: number) => void;
36
+ }
37
+ /**
38
+ * Intentionally focused first iteration (doc section 10/18): columns, rows,
39
+ * selection, sort UI, pagination UI, loading/empty/error presentation.
40
+ * No built-in filtering UI, column resize/reorder, or virtualization yet —
41
+ * those are future extensions, not implemented speculatively.
42
+ */
43
+ export declare function DataGrid<TRow>({ columns, rows, rowKey, loading, error, emptyText, className, selectedRowKeys, onSelectionChange, sort, onSortChange, page, pageSize, totalCount, onPageChange, }: DataGridProps<TRow>): import("react").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { FieldIdentity, FieldPresentation, FieldState } from './shared/fieldTypes';
2
+ export interface DatePickerProps extends FieldIdentity, FieldState, FieldPresentation {
3
+ value?: Date | null;
4
+ defaultValue?: Date | null;
5
+ onChange?: (value: Date | null) => void;
6
+ min?: Date;
7
+ max?: Date;
8
+ }
9
+ /**
10
+ * Exported so TimePicker/DateTimePicker can compose the exact same
11
+ * date-part parsing/formatting instead of reimplementing it (doc section
12
+ * 12 — a coherent Date/Time value strategy across the whole family).
13
+ */
14
+ export declare function toDateInputValue(date: Date | null | undefined): string;
15
+ export declare function fromDateInputValue(raw: string): Date | null;
16
+ /**
17
+ * Intentionally minimal: reuses Input + the native date picker UI rather
18
+ * than building a calendar widget (doc section 10/18 — don't overbuild the
19
+ * first iteration). value/onChange work in terms of `Date`, so a richer
20
+ * Popup-based calendar can replace the native input later without breaking
21
+ * this public contract. See "Known Limitations" in the final report.
22
+ */
23
+ export declare function DatePicker({ value, defaultValue, onChange, min, max, ...rest }: DatePickerProps): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { FieldIdentity, FieldPresentation, FieldState } from './shared/fieldTypes';
2
+ export interface DateTimePickerProps extends FieldIdentity, FieldState, FieldPresentation {
3
+ value?: Date | null;
4
+ defaultValue?: Date | null;
5
+ onChange?: (value: Date | null) => void;
6
+ min?: Date;
7
+ max?: Date;
8
+ }
9
+ /**
10
+ * Reuses DatePicker's/TimePicker's exported date-part/time-part parsing so
11
+ * the whole family shares one coherent `Date` value strategy (doc section
12
+ * 12) — this is the actual "behavior reuse" the doc asks for. Renders two
13
+ * plain native inputs rather than nesting two <Input>s: Input always wraps
14
+ * itself in FieldShell, and nesting it twice here would produce two labels
15
+ * for one field. A single FieldShell wraps both inputs as one field group.
16
+ */
17
+ export declare function DateTimePicker({ value, defaultValue, onChange, min, max, id, name, disabled, readOnly, required, className, label, helpText, error, }: DateTimePickerProps): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { ReactNode } from 'react';
2
+ export interface DividerProps {
3
+ className?: string;
4
+ vertical?: boolean;
5
+ /** Optional centered label (e.g. "OR") — renders a labeled horizontal divider instead of a plain line. */
6
+ label?: ReactNode;
7
+ }
8
+ export declare function Divider({ className, vertical, label }: DividerProps): import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { FieldIdentity, FieldPresentation } from './shared/fieldTypes';
2
+ export interface FileInputProps extends FieldIdentity, FieldPresentation {
3
+ disabled?: boolean;
4
+ required?: boolean;
5
+ accept?: string;
6
+ multiple?: boolean;
7
+ onChange?: (files: FileList | null) => void;
8
+ }
9
+ /**
10
+ * File selection only — no upload/API/cloud-storage/chunking (doc section
11
+ * 11; that belongs to a future Remote-layer concern, not Base).
12
+ *
13
+ * Intentionally uncontrolled-only: browsers do not allow programmatically
14
+ * setting `<input type="file">`'s value for security reasons, so this is a
15
+ * documented, deliberate exception to the library's controlled/uncontrolled
16
+ * policy rather than an inconsistency — there is no `value`/`defaultValue`
17
+ * to be controlled.
18
+ */
19
+ export declare function FileInput({ id, name, disabled, required, className, label, helpText, error, accept, multiple, onChange }: FileInputProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { FieldShellProps } from './shared/FieldShell';
2
+ export type FormFieldProps = FieldShellProps;
3
+ /**
4
+ * Public composition of Label + control + ValidationMessage for consumers
5
+ * who need our field chrome around a *custom* control (e.g. a group of
6
+ * RadioButtons, a Switch, a third-party widget) rather than one of our own
7
+ * field components. Deliberately a thin re-export of FieldShell — the two
8
+ * names serve different audiences (FieldShell: internal plumbing for our
9
+ * own fields; FormField: the same behavior, public), not two
10
+ * implementations (doc section 9 — no form-framework infrastructure here).
11
+ */
12
+ export declare function FormField(props: FormFieldProps): import("react").JSX.Element;
@@ -0,0 +1,15 @@
1
+ export interface IconProps {
2
+ /**
3
+ * Full icon class name(s) — e.g. "bi bi-trash" (Bootstrap Icons) or
4
+ * "ki-outline ki-trash" (Metronic Keenicons). Icon-set agnostic by design:
5
+ * this component bundles no icon font of its own (doc section 15 — stay
6
+ * on Bootstrap/Metronic, don't introduce another framework or a
7
+ * duplicate asset), it only standardizes sizing and accessibility.
8
+ */
9
+ name: string;
10
+ size?: "sm" | "lg" | "xl";
11
+ className?: string;
12
+ /** Accessible label. Omit for a purely decorative icon (default: aria-hidden). */
13
+ label?: string;
14
+ }
15
+ export declare function Icon({ name, size, className, label }: IconProps): import("react").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { FocusEventHandler, InputHTMLAttributes, ReactNode } from 'react';
2
+ import { FieldIdentity, FieldPresentation, FieldState } from './shared/fieldTypes';
3
+ type NativePassthroughProps = Omit<InputHTMLAttributes<HTMLInputElement>, "id" | "name" | "value" | "defaultValue" | "onChange" | "onBlur" | "className" | "disabled" | "readOnly" | "required" | "placeholder">;
4
+ export interface InputProps extends FieldIdentity, FieldState, FieldPresentation {
5
+ value?: string;
6
+ defaultValue?: string;
7
+ onChange?: (value: string) => void;
8
+ onBlur?: FocusEventHandler<HTMLInputElement>;
9
+ type?: "text" | "email" | "password" | "tel" | "url" | "search";
10
+ maxLength?: number;
11
+ autoFocus?: boolean;
12
+ /**
13
+ * Escape hatch for native attributes that don't deserve a first-class prop
14
+ * on every text-like field (e.g. `inputMode`, `min`/`max`/`step`, `type`
15
+ * override). Keeps the primary prop surface small (doc section 13) while
16
+ * still letting NumberInput/DatePicker compose Input instead of
17
+ * reimplementing it.
18
+ */
19
+ inputProps?: NativePassthroughProps;
20
+ /**
21
+ * Generic trailing slot rendered inside a Bootstrap `input-group` (e.g. a
22
+ * visibility-toggle button, a unit suffix, a clear button). Not
23
+ * password-specific — PasswordInput is just its first consumer, reusing
24
+ * Input's full controlled-state/markup instead of reimplementing a
25
+ * parallel text field (doc section 4/19).
26
+ */
27
+ endAdornment?: ReactNode;
28
+ }
29
+ export declare function Input(props: InputProps): import("react").JSX.Element;
30
+ export {};
@@ -0,0 +1,21 @@
1
+ import { ReactNode } from 'react';
2
+ export interface MenuItem {
3
+ key: string;
4
+ label: ReactNode;
5
+ disabled?: boolean;
6
+ danger?: boolean;
7
+ onSelect?: () => void;
8
+ }
9
+ export interface MenuProps {
10
+ items: MenuItem[];
11
+ children: ReactNode;
12
+ placement?: "start" | "end";
13
+ className?: string;
14
+ }
15
+ /**
16
+ * A generic click-triggered action menu (e.g. a "..." row action button) —
17
+ * distinct from Select/ComboBox, which pick a *value*. Reuses Popup +
18
+ * useListNavigation, the same headless pair ComboBox/AutoComplete/
19
+ * MultiSelect already share (doc's reuse mandate).
20
+ */
21
+ export declare function Menu({ items, children, placement, className }: MenuProps): import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { ReactNode } from 'react';
2
+ export interface ModalProps {
3
+ open: boolean;
4
+ onClose: () => void;
5
+ title?: string;
6
+ children: ReactNode;
7
+ footer?: ReactNode;
8
+ className?: string;
9
+ }
10
+ /**
11
+ * Centered/backdrop dialog overlay — a different interaction model from
12
+ * Popup's anchored dropdown, so it's a separate component, but shares the
13
+ * escape-to-close behavior via useEscapeKey.
14
+ *
15
+ * Known limitation: not rendered through a portal yet (renders in place).
16
+ * Can be swapped to `createPortal(..., document.body)` later without
17
+ * changing this component's props.
18
+ */
19
+ export declare function Modal({ open, onClose, title, children, footer, className }: ModalProps): import("react").JSX.Element | null;
@@ -0,0 +1,25 @@
1
+ import { FieldIdentity, FieldPresentation, FieldState, SelectOption } from './shared/fieldTypes';
2
+ export interface MultiSelectProps<TValue extends string | number = string> extends FieldIdentity, FieldState, FieldPresentation {
3
+ options: SelectOption<TValue>[];
4
+ values?: TValue[];
5
+ defaultValues?: TValue[];
6
+ onChange?: (values: TValue[]) => void;
7
+ loading?: boolean;
8
+ emptyText?: string;
9
+ }
10
+ /**
11
+ * Follows ComboBox's established `options: SelectOption<TValue>[]` /
12
+ * FieldShell / Popup / useListNavigation conventions rather than the raw
13
+ * `items`+`valueMember`+`displayMember` shape shown as a *conceptual*
14
+ * example in the source spec — that mapping-by-key convention belongs to
15
+ * the Remote layer (where raw API objects need mapping); Base MultiSelect
16
+ * receives already-typed `SelectOption`s, consistent with Base ComboBox.
17
+ * (Documented in the final report as a deliberate reconciliation of the
18
+ * spec's own two instructions: "follow this example" vs. "follow ComboBox's
19
+ * existing, good convention" — the latter wins per the spec's own priority.)
20
+ *
21
+ * Reuses Popup + useListNavigation from ComboBox/AutoComplete; the only
22
+ * real behavioral difference is that selecting an option toggles it in a
23
+ * `values` array and leaves the popup open instead of closing it.
24
+ */
25
+ export declare function MultiSelect<TValue extends string | number = string>({ options, values, defaultValues, onChange, loading, emptyText, id, name, disabled, readOnly, required, className, label, placeholder, helpText, error, }: MultiSelectProps<TValue>): import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { ReactNode } from 'react';
2
+ export interface NavbarProps {
3
+ brand?: ReactNode;
4
+ /** Left-aligned slot, e.g. primary nav links. */
5
+ start?: ReactNode;
6
+ /** Right-aligned slot, e.g. search, notifications, user menu. */
7
+ end?: ReactNode;
8
+ variant?: "light" | "dark";
9
+ className?: string;
10
+ }
11
+ /**
12
+ * Top app bar shell. Brand/start/end are plain slots — actual nav links,
13
+ * routing, and auth/user menus belong to the consuming app (doc section 22:
14
+ * Base must not touch routing or auth), not to this component.
15
+ */
16
+ export declare function Navbar({ brand, start, end, variant, className }: NavbarProps): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { FocusEventHandler } from 'react';
2
+ import { FieldIdentity, FieldPresentation, FieldState } from './shared/fieldTypes';
3
+ export interface NumberInputProps extends FieldIdentity, FieldState, FieldPresentation {
4
+ value?: number | null;
5
+ defaultValue?: number | null;
6
+ onChange?: (value: number | null) => void;
7
+ onBlur?: FocusEventHandler<HTMLInputElement>;
8
+ min?: number;
9
+ max?: number;
10
+ step?: number;
11
+ }
12
+ /**
13
+ * Composes Input (the "Input foundation" from doc section 19) instead of
14
+ * reimplementing field markup/controlled-state logic — only the numeric
15
+ * value coercion is unique to NumberInput.
16
+ */
17
+ export declare function NumberInput({ value, defaultValue, onChange, min, max, step, ...rest }: NumberInputProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { ReactNode } from 'react';
2
+ import { BreadcrumbItem } from './Breadcrumb';
3
+ export interface PageHeaderProps {
4
+ title: ReactNode;
5
+ description?: ReactNode;
6
+ breadcrumbItems?: BreadcrumbItem[];
7
+ /** Right-aligned slot, typically page-level Buttons. */
8
+ actions?: ReactNode;
9
+ className?: string;
10
+ }
11
+ /** Composes Breadcrumb (doc section 20 — reuse, don't re-derive trail markup) for the standard title/breadcrumb/actions row atop a page. */
12
+ export declare function PageHeader({ title, description, breadcrumbItems, actions, className }: PageHeaderProps): import("react").JSX.Element;