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.
- package/LICENSE +21 -0
- package/README.md +118 -0
- package/dist/base/Accordion.d.ts +17 -0
- package/dist/base/Alert.d.ts +15 -0
- package/dist/base/AutoComplete.d.ts +20 -0
- package/dist/base/Avatar.d.ts +8 -0
- package/dist/base/Badge.d.ts +9 -0
- package/dist/base/Breadcrumb.d.ts +10 -0
- package/dist/base/Button.d.ts +13 -0
- package/dist/base/Card.d.ts +9 -0
- package/dist/base/CheckBox.d.ts +17 -0
- package/dist/base/Col.d.ts +12 -0
- package/dist/base/ComboBox.d.ts +17 -0
- package/dist/base/Confirm.d.ts +25 -0
- package/dist/base/Container.d.ts +7 -0
- package/dist/base/DataGrid.d.ts +43 -0
- package/dist/base/DatePicker.d.ts +23 -0
- package/dist/base/DateTimePicker.d.ts +17 -0
- package/dist/base/Divider.d.ts +8 -0
- package/dist/base/FileInput.d.ts +19 -0
- package/dist/base/FormField.d.ts +12 -0
- package/dist/base/Icon.d.ts +15 -0
- package/dist/base/Input.d.ts +30 -0
- package/dist/base/Menu.d.ts +21 -0
- package/dist/base/Modal.d.ts +19 -0
- package/dist/base/MultiSelect.d.ts +25 -0
- package/dist/base/Navbar.d.ts +16 -0
- package/dist/base/NumberInput.d.ts +17 -0
- package/dist/base/PageHeader.d.ts +12 -0
- package/dist/base/Pagination.d.ts +15 -0
- package/dist/base/PasswordInput.d.ts +10 -0
- package/dist/base/Popover.d.ts +10 -0
- package/dist/base/ProgressBar.d.ts +10 -0
- package/dist/base/RadioButton.d.ts +18 -0
- package/dist/base/RadioGroup.d.ts +14 -0
- package/dist/base/Rating.d.ts +9 -0
- package/dist/base/Row.d.ts +6 -0
- package/dist/base/Select.d.ts +24 -0
- package/dist/base/Sidebar.d.ts +31 -0
- package/dist/base/Skeleton.d.ts +8 -0
- package/dist/base/Slider.d.ts +10 -0
- package/dist/base/Spinner.d.ts +7 -0
- package/dist/base/Stack.d.ts +12 -0
- package/dist/base/Stepper.d.ts +12 -0
- package/dist/base/Switch.d.ts +16 -0
- package/dist/base/Tabs.d.ts +16 -0
- package/dist/base/Tag.d.ts +14 -0
- package/dist/base/TextArea.d.ts +11 -0
- package/dist/base/TimePicker.d.ts +20 -0
- package/dist/base/Toast.d.ts +27 -0
- package/dist/base/Tooltip.d.ts +21 -0
- package/dist/base/index.d.ts +56 -0
- package/dist/base/shared/BooleanFieldControl.d.ts +22 -0
- package/dist/base/shared/FieldShell.d.ts +22 -0
- package/dist/base/shared/Label.d.ts +9 -0
- package/dist/base/shared/Popup.d.ts +25 -0
- package/dist/base/shared/ValidationMessage.d.ts +11 -0
- package/dist/base/shared/classNames.d.ts +1 -0
- package/dist/base/shared/fieldTypes.d.ts +26 -0
- package/dist/base/shared/index.d.ts +9 -0
- package/dist/base/shared/useControllableState.d.ts +16 -0
- package/dist/base/shared/useEscapeKey.d.ts +2 -0
- package/dist/base/shared/useListNavigation.d.ts +18 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +2092 -0
- package/dist/index.js.map +1 -0
- package/dist/remote/RemoteAutoComplete.d.ts +22 -0
- package/dist/remote/RemoteComboBox.d.ts +21 -0
- package/dist/remote/RemoteDataGrid.d.ts +24 -0
- package/dist/remote/RemoteMultiSelect.d.ts +13 -0
- package/dist/remote/RemoteSelect.d.ts +17 -0
- package/dist/remote/hooks/useDebouncedValue.d.ts +1 -0
- package/dist/remote/hooks/useRemoteData.d.ts +31 -0
- package/dist/remote/http/HttpClient.d.ts +31 -0
- package/dist/remote/index.d.ts +9 -0
- package/dist/remote/mapping.d.ts +8 -0
- package/dist/smart/SmartAction.d.ts +14 -0
- package/dist/smart/SmartActions.d.ts +14 -0
- package/dist/smart/SmartField.d.ts +18 -0
- package/dist/smart/SmartForm.d.ts +19 -0
- package/dist/smart/actionRegistry.d.ts +11 -0
- package/dist/smart/componentRegistry.d.ts +24 -0
- package/dist/smart/dataSourceRegistry.d.ts +17 -0
- package/dist/smart/index.d.ts +26 -0
- package/dist/smart/resolvers/comboBoxResolver.d.ts +10 -0
- package/dist/smart/resolvers/dataGridResolver.d.ts +11 -0
- package/dist/smart/resolvers/datePickerResolver.d.ts +3 -0
- package/dist/smart/resolvers/index.d.ts +13 -0
- package/dist/smart/resolvers/inputResolver.d.ts +8 -0
- package/dist/smart/runtime.d.ts +26 -0
- package/dist/smart/types.d.ts +114 -0
- package/dist/smart/useSmartAction.d.ts +36 -0
- package/dist/smart/useSmartDependencies.d.ts +13 -0
- package/dist/smart/useSmartField.d.ts +47 -0
- 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
|
+
[](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,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;
|