@opencxh/ui-kit 3.136.4 → 3.137.1
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/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2254 -2160
- package/dist/index.js.map +1 -1
- package/dist/src/action/FilterChip.d.ts +18 -7
- package/dist/src/action/SegmentedToggle.d.ts +8 -1
- package/dist/src/content/PageToolbar.d.ts +21 -3
- package/dist/src/content/Table.d.ts +30 -11
- package/dist/src/forms/Form.d.ts +17 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/input/SearchField.d.ts +33 -0
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ export interface FilterChipProps {
|
|
|
9
9
|
* the resting chip; `active` still wins, because "you picked this" outranks
|
|
10
10
|
* "this is urgent".
|
|
11
11
|
*/
|
|
12
|
-
tone?: "none" | "default" | "muted" | "warning" | "danger";
|
|
12
|
+
tone?: "none" | "default" | "muted" | "outline" | "warning" | "danger";
|
|
13
13
|
/**
|
|
14
14
|
* `rect` is the filter-bar shape — the same 9px corner as a button, so a
|
|
15
15
|
* chip and a button in one toolbar line up. `pill` is for a chip that reads
|
|
@@ -22,6 +22,14 @@ export interface FilterChipProps {
|
|
|
22
22
|
active?: boolean;
|
|
23
23
|
/** Show a trailing caret (opens a menu the consumer wires with Dropdown/Popover). */
|
|
24
24
|
caret?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Menu panel for a chip that opens its own popover. Receives a `close`
|
|
27
|
+
* callback so a row can dismiss the panel after picking. Without it the chip
|
|
28
|
+
* is purely presentational and `onClick` is yours to wire.
|
|
29
|
+
*/
|
|
30
|
+
menu?: (close: () => void) => React.ReactNode;
|
|
31
|
+
/** Panel classes, when `menu` is set. */
|
|
32
|
+
menuClassName?: string;
|
|
25
33
|
/** Open a value clear affordance (✕) — only shown when `active`. */
|
|
26
34
|
onClear?: () => void;
|
|
27
35
|
/** Accessible name for the clear affordance. */
|
|
@@ -32,15 +40,18 @@ export interface FilterChipProps {
|
|
|
32
40
|
className?: string;
|
|
33
41
|
}
|
|
34
42
|
/**
|
|
35
|
-
* Filter chip — the inbox filter bar and the thread
|
|
36
|
-
* menus. Presentational
|
|
37
|
-
*
|
|
38
|
-
*
|
|
43
|
+
* Filter chip — the inbox filter bar, the table toolbar, and the thread
|
|
44
|
+
* priority/assign/inbox/tags menus. Presentational by default (the consumer
|
|
45
|
+
* wires the menu with `Dropdown`/`Popover` and `onClick`); pass `menu` and the
|
|
46
|
+
* chip opens its own popover instead, which is the only way to get a clear
|
|
47
|
+
* button on a menu chip — a `<FilterChip>` used as someone else's trigger
|
|
48
|
+
* would nest a button inside a button.
|
|
39
49
|
*
|
|
40
50
|
* @example
|
|
41
51
|
* ```tsx
|
|
42
52
|
* <FilterChip label={status ? `Status: ${status}` : "Status"} caret
|
|
43
|
-
* active={!!status}
|
|
53
|
+
* active={!!status} onClear={() => setStatus(null)}
|
|
54
|
+
* menu={(close) => <StatusList onPick={(s) => { setStatus(s); close(); }} />} />
|
|
44
55
|
* ```
|
|
45
56
|
*/
|
|
46
|
-
export declare function FilterChip({ label, icon, tone, shape, size, active, caret, onClear, clearLabel, onClick, title, className, }: FilterChipProps): React.JSX.Element;
|
|
57
|
+
export declare function FilterChip({ label, icon, tone, shape, size, active, caret, menu, menuClassName, onClear, clearLabel, onClick, title, className, }: FilterChipProps): React.JSX.Element;
|
|
@@ -9,6 +9,13 @@ export interface SegmentedToggleProps<T extends string> {
|
|
|
9
9
|
onChange: (value: T) => void;
|
|
10
10
|
/** Control height. */
|
|
11
11
|
size?: "sm" | "md";
|
|
12
|
+
/**
|
|
13
|
+
* Track fill. `sunk` reads against the white card; use `track` when the
|
|
14
|
+
* toggle itself sits on a sunk plane, where `sunk` on `sunk` is invisible.
|
|
15
|
+
*/
|
|
16
|
+
tone?: "sunk" | "track";
|
|
17
|
+
/** Fill the container and split it evenly — a toggle that heads a column. */
|
|
18
|
+
fullWidth?: boolean;
|
|
12
19
|
className?: string;
|
|
13
20
|
/** Accessible group label. */
|
|
14
21
|
"aria-label"?: string;
|
|
@@ -27,4 +34,4 @@ export interface SegmentedToggleProps<T extends string> {
|
|
|
27
34
|
* />
|
|
28
35
|
* ```
|
|
29
36
|
*/
|
|
30
|
-
export declare function SegmentedToggle<T extends string>({ options, value, onChange, size, className, "aria-label": ariaLabel, }: SegmentedToggleProps<T>): React.JSX.Element;
|
|
37
|
+
export declare function SegmentedToggle<T extends string>({ options, value, onChange, size, tone, fullWidth, className, "aria-label": ariaLabel, }: SegmentedToggleProps<T>): React.JSX.Element;
|
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
import { ButtonProps } from '../action/Button';
|
|
2
3
|
import { PageHeaderAction } from './PageHeader';
|
|
4
|
+
export interface PageToolbarActionsProps {
|
|
5
|
+
actions: PageHeaderAction[];
|
|
6
|
+
/**
|
|
7
|
+
* Variant for actions that do not name one. `secondary` (a sunk plate) suits
|
|
8
|
+
* a detail page's Cancel/Save pair; a list toolbar passes `ghost`, because
|
|
9
|
+
* there the plate would collide with the sunk search field beside it.
|
|
10
|
+
*/
|
|
11
|
+
defaultVariant?: ButtonProps["variant"];
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The action cluster shared by `PageToolbar` and the table toolbar, so a
|
|
16
|
+
* "New …" button looks the same wherever a view decides to put it.
|
|
17
|
+
*/
|
|
18
|
+
export declare const PageToolbarActions: React.FC<PageToolbarActionsProps>;
|
|
3
19
|
export interface PageToolbarProps {
|
|
4
20
|
/** Right-aligned action buttons */
|
|
5
21
|
actions?: PageHeaderAction[];
|
|
@@ -15,8 +31,10 @@ export interface PageToolbarProps {
|
|
|
15
31
|
children?: React.ReactNode;
|
|
16
32
|
}
|
|
17
33
|
/**
|
|
18
|
-
* Thin action-bar for views that already have a host header (e.g. settings
|
|
19
|
-
*
|
|
20
|
-
* the right. Use `PageHeader` when the view needs its own
|
|
34
|
+
* Thin action-bar for views that already have a host header (e.g. a settings
|
|
35
|
+
* page or a detail view). Renders an optional back button on the left and
|
|
36
|
+
* action buttons on the right. Use `PageHeader` when the view needs its own
|
|
37
|
+
* title/breadcrumbs — and for a list, put the actions on the `Table` toolbar
|
|
38
|
+
* instead, next to the search and filters they apply to.
|
|
21
39
|
*/
|
|
22
40
|
export declare const PageToolbar: React.FC<PageToolbarProps>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
import { PageHeaderAction } from './PageHeader';
|
|
2
3
|
export interface TableColumn<T = any> {
|
|
3
4
|
/** Unique column identifier */
|
|
4
5
|
id: string;
|
|
@@ -42,6 +43,8 @@ export interface TableFilter {
|
|
|
42
43
|
label: string;
|
|
43
44
|
/** Filter type */
|
|
44
45
|
type?: "select" | "date" | "dateRange";
|
|
46
|
+
/** Leading icon on the chip — what the filter is about, at a glance. */
|
|
47
|
+
icon?: React.ReactNode;
|
|
45
48
|
/** Filter options (for select type) */
|
|
46
49
|
options?: Array<{
|
|
47
50
|
value: string;
|
|
@@ -79,13 +82,26 @@ export interface TableProps<T = any> {
|
|
|
79
82
|
searchable?: boolean;
|
|
80
83
|
/** Search placeholder text */
|
|
81
84
|
searchPlaceholder?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Take over the query. Pass this pair when the page already filters its own
|
|
87
|
+
* data — across fields no column exposes, or together with filters of its
|
|
88
|
+
* own — and only wants the search plate to sit in the toolbar where the
|
|
89
|
+
* design puts it. The built-in column search then stays out of the way;
|
|
90
|
+
* without them the table owns both the box and the filtering.
|
|
91
|
+
*/
|
|
92
|
+
searchValue?: string;
|
|
93
|
+
onSearchChange?: (value: string) => void;
|
|
82
94
|
/** Table filters */
|
|
83
95
|
filters?: TableFilter[];
|
|
96
|
+
/**
|
|
97
|
+
* Buttons for the toolbar above the table — "New …", import, export. This is
|
|
98
|
+
* where a list's own actions belong: the page header names the page, the
|
|
99
|
+
* table owns what you do to it.
|
|
100
|
+
*/
|
|
101
|
+
toolbarActions?: PageHeaderAction[];
|
|
84
102
|
/** Whether table has pagination */
|
|
85
103
|
paginated?: boolean;
|
|
86
|
-
/**
|
|
87
|
-
pageSizeOptions?: number[];
|
|
88
|
-
/** Default page size */
|
|
104
|
+
/** Rows per page. Fixed — the footer is a summary and a page list, nothing to set. */
|
|
89
105
|
defaultPageSize?: number;
|
|
90
106
|
/** Row actions */
|
|
91
107
|
actions?: TableAction<T>[];
|
|
@@ -101,14 +117,16 @@ export interface TableProps<T = any> {
|
|
|
101
117
|
getRowKey?: (row: T, index: number) => string | number;
|
|
102
118
|
/** Empty state content */
|
|
103
119
|
emptyContent?: React.ReactNode;
|
|
104
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Left-hand line under the table. Defaults to the range/total count on a
|
|
122
|
+
* paginated table; pass a node to say it in the app's own words ("9 of 1,284
|
|
123
|
+
* contacts"), which also gives an unpaginated table that one line.
|
|
124
|
+
*/
|
|
125
|
+
footerSummary?: React.ReactNode;
|
|
126
|
+
/** Row density. `md` is the default data row; `sm` for a dense inline list. */
|
|
105
127
|
size?: "sm" | "md" | "lg";
|
|
106
128
|
/** Whether to show row hover */
|
|
107
129
|
hoverable?: boolean;
|
|
108
|
-
/** Whether to show row borders */
|
|
109
|
-
bordered?: boolean;
|
|
110
|
-
/** Whether to stripe rows */
|
|
111
|
-
striped?: boolean;
|
|
112
130
|
/** Additional CSS classes */
|
|
113
131
|
className?: string;
|
|
114
132
|
/** Custom row className */
|
|
@@ -119,10 +137,11 @@ export interface TableProps<T = any> {
|
|
|
119
137
|
* surface, where a second wash just muddies the edge.
|
|
120
138
|
*/
|
|
121
139
|
headerBackground?: boolean;
|
|
122
|
-
/**
|
|
140
|
+
/** Horizontal padding inside the table box. */
|
|
123
141
|
padding?: "none" | "sm" | "md" | "lg";
|
|
124
142
|
}
|
|
125
143
|
/**
|
|
126
|
-
*
|
|
144
|
+
* Data table: a bordered box with a tinted column strip, a toolbar above it
|
|
145
|
+
* (search, filters, the list's own actions) and a summary + paginator below.
|
|
127
146
|
*/
|
|
128
|
-
export declare const Table: <T extends Record<string, any>>({ data, columns, loading, searchable, searchPlaceholder, filters,
|
|
147
|
+
export declare const Table: <T extends Record<string, any>>({ data, columns, loading, searchable, searchPlaceholder, searchValue, onSearchChange, filters, toolbarActions, paginated, defaultPageSize, actions, onRowClick, selectable, selectedRows, onSelectionChange, getRowKey, emptyContent, footerSummary, size, hoverable, padding, className, rowClassName, headerBackground, }: TableProps<T>) => React.JSX.Element;
|
package/dist/src/forms/Form.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InternalSDK } from '@opencxh/domain';
|
|
2
2
|
import { default as React } from 'react';
|
|
3
|
-
export type FormFieldType = "text" | "email" | "password" | "number" | "tel" | "url" | "textarea" | "select" | "checkbox" | "radio" | "date" | "file" | "folder" | "custom" | "array";
|
|
3
|
+
export type FormFieldType = "text" | "email" | "password" | "number" | "tel" | "url" | "textarea" | "select" | "segmented" | "checkbox" | "radio" | "date" | "file" | "folder" | "custom" | "array";
|
|
4
4
|
/**
|
|
5
5
|
* `NonNullable` before the `object` test is load-bearing: form data is routinely
|
|
6
6
|
* a `Partial<T>`, which makes every property `X | undefined`, and
|
|
@@ -30,6 +30,22 @@ type NestedKeys<T> = T extends unknown ? {
|
|
|
30
30
|
* up on inferring `group.items` once it gets large enough.
|
|
31
31
|
*/
|
|
32
32
|
type FieldPath<T> = NestedKeys<T> | (keyof T & string);
|
|
33
|
+
/**
|
|
34
|
+
* One band of a page-wide form: a fixed label column with the section title and
|
|
35
|
+
* its explanation, and the fields beside it.
|
|
36
|
+
*
|
|
37
|
+
* Exported because a page often has a section that is not a `Form` field at all
|
|
38
|
+
* — a checklist, a list of linked records — and it has to line up with the bands
|
|
39
|
+
* above it. Without this those sections each re-derive the column width and the
|
|
40
|
+
* spacing, and they drift.
|
|
41
|
+
*/
|
|
42
|
+
export declare function FormSection({ title, description, className, children, }: {
|
|
43
|
+
title?: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
/** Caller owns the divider: only it knows whether it is the last band. */
|
|
46
|
+
className?: string;
|
|
47
|
+
children: React.ReactNode;
|
|
48
|
+
}): React.JSX.Element;
|
|
33
49
|
export interface FormGroupItem<T = any> {
|
|
34
50
|
/** Field name (key in form data) */
|
|
35
51
|
name: FieldPath<T>;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -13,12 +13,13 @@ export { Checkbox, type CheckboxProps } from './input/Checkbox';
|
|
|
13
13
|
export { DatePicker, type DatePickerProps } from './input/DatePicker';
|
|
14
14
|
export { FolderSelect, type FolderDestination, type FolderSelectProps } from './input/FolderSelect';
|
|
15
15
|
export { SearchableTextField, type SearchableTextFieldProps } from './input/SearchableTextField';
|
|
16
|
+
export { SearchField, type SearchFieldProps } from './input/SearchField';
|
|
16
17
|
export { Select, type SelectOption, type SelectProps } from './input/Select';
|
|
17
18
|
export { Switch, type SwitchProps } from './input/Switch';
|
|
18
19
|
export { StorageInput, type StorageInputProps } from './input/StorageInput';
|
|
19
20
|
export { TextArea, type TextAreaProps } from './input/TextArea';
|
|
20
21
|
export { TextField, type TextFieldProps } from './input/TextField';
|
|
21
|
-
export { Form, type FormButtonProps, type FormFieldType, type FormGroup, type FormGroupItem, type FormProps } from './forms/Form';
|
|
22
|
+
export { Form, FormSection, type FormButtonProps, type FormFieldType, type FormGroup, type FormGroupItem, type FormProps } from './forms/Form';
|
|
22
23
|
export { Dropdown, type DropdownOption, type DropdownProps } from './overlays/Dropdown';
|
|
23
24
|
export { ConfirmDialog, type ConfirmDialogProps } from './overlays/ConfirmDialog';
|
|
24
25
|
export { Modal, type ModalProps } from './overlays/Modal';
|
|
@@ -41,7 +42,7 @@ export { List, ListBulkAction, type ListGroup, type ListProps } from './content/
|
|
|
41
42
|
export { MessageBubble, type MessageBubbleProps } from './content/MessageBubble';
|
|
42
43
|
export { KpiCard, type KpiCardProps } from './content/KpiCard';
|
|
43
44
|
export { PageHeader, type PageHeaderAction, type PageHeaderProps } from './content/PageHeader';
|
|
44
|
-
export { PageToolbar, type PageToolbarProps } from './content/PageToolbar';
|
|
45
|
+
export { PageToolbar, PageToolbarActions, type PageToolbarActionsProps, type PageToolbarProps } from './content/PageToolbar';
|
|
45
46
|
export { RichText, type RichTextProps } from './content/RichText';
|
|
46
47
|
export { SectionDivider, type SectionDividerProps } from './content/SectionDivider';
|
|
47
48
|
export { SettingsRow, SettingsSection, type SettingsRowProps, type SettingsSectionProps } from './content/SettingsRow';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface SearchFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "value" | "onChange" | "type"> {
|
|
3
|
+
/** Current query. Controlled — this field has no internal state. */
|
|
4
|
+
value: string;
|
|
5
|
+
/** Called with the new query text (not the event). */
|
|
6
|
+
onValueChange: (value: string) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Keyboard hint shown at the trailing edge while the field is empty —
|
|
9
|
+
* `⌘K`, `⌘F`. Replaced by the clear button once there is a query.
|
|
10
|
+
*/
|
|
11
|
+
hint?: string;
|
|
12
|
+
/** `md` is the default control height; `sm` for a dense bar. */
|
|
13
|
+
size?: "sm" | "md";
|
|
14
|
+
/** Accessible name for the clear button. */
|
|
15
|
+
clearLabel?: string;
|
|
16
|
+
/** Classes for the plate around the input. */
|
|
17
|
+
containerClassName?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The sunk, frameless search plate: a magnifier, the query, and either a
|
|
21
|
+
* keyboard hint or a clear button. It is deliberately *not* a `TextField` —
|
|
22
|
+
* a bordered box would read as one more empty input in a toolbar that already
|
|
23
|
+
* has filter chips and buttons, where this is the thing you type into.
|
|
24
|
+
*
|
|
25
|
+
* Three places had grown their own copy of it (the nav search, the settings
|
|
26
|
+
* search, the table toolbar); they share this one now.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* <SearchField value={query} onValueChange={setQuery} placeholder="Zoeken" hint="⌘K" />
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare const SearchField: React.ForwardRefExoticComponent<SearchFieldProps & React.RefAttributes<HTMLInputElement>>;
|