@colixsystems/widget-sdk 0.246.0 → 0.248.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/README.md +76 -6
- package/dist/board-auto-scroll.js +59 -0
- package/dist/board-view.js +327 -0
- package/dist/chart-logic.js +575 -0
- package/dist/chart-tokens.js +131 -0
- package/dist/chart-view.js +262 -0
- package/dist/chart.js +21 -0
- package/dist/chart.native.js +10 -0
- package/dist/contract.cjs +119 -7
- package/dist/contract.js +119 -7
- package/dist/data-table-logic.js +179 -0
- package/dist/data-table-view.js +388 -0
- package/dist/data-table.js +22 -0
- package/dist/data-table.native.js +14 -0
- package/dist/drag-kit-view.js +310 -0
- package/dist/file-upload-view.js +13 -2
- package/dist/filter-bar-logic.js +143 -0
- package/dist/filter-bar-view.js +381 -0
- package/dist/filter-bar.js +15 -0
- package/dist/filter-bar.native.js +13 -0
- package/dist/form-control-logic.js +20 -3
- package/dist/form-control-view.js +18 -0
- package/dist/form-layout-logic.js +92 -0
- package/dist/form-view.js +268 -0
- package/dist/form.js +15 -0
- package/dist/form.native.js +9 -0
- package/dist/grid-logic.js +222 -0
- package/dist/grid-view.js +109 -0
- package/dist/grid.js +7 -0
- package/dist/grid.native.js +7 -0
- package/dist/host.d.ts +6 -0
- package/dist/host.js +2 -0
- package/dist/index.d.ts +606 -7
- package/dist/index.js +15 -0
- package/dist/index.native.js +15 -0
- package/dist/menu-view.js +5 -2
- package/dist/people-picker-logic.js +203 -0
- package/dist/people-picker-view.js +250 -0
- package/dist/people-picker.js +11 -0
- package/dist/people-picker.native.js +9 -0
- package/dist/radio-group-view.js +7 -3
- package/dist/select-search-logic.js +150 -0
- package/dist/select-view.js +251 -18
- package/dist/select.js +6 -2
- package/dist/select.native.js +5 -3
- package/dist/sortable-list-view.js +228 -0
- package/dist/sortable-logic.js +273 -0
- package/dist/sortable-tokens.js +120 -0
- package/dist/sortable-view.js +24 -0
- package/dist/sortable.js +39 -0
- package/dist/sortable.native.js +30 -0
- package/dist/text-field-view.js +7 -2
- package/package.json +1 -1
- package/src/contract.js +119 -7
package/dist/index.d.ts
CHANGED
|
@@ -2406,6 +2406,160 @@ export const WIDE_WIDTH_PX: number;
|
|
|
2406
2406
|
*/
|
|
2407
2407
|
export function widthTier(width: number): "narrow" | "medium" | "wide";
|
|
2408
2408
|
|
|
2409
|
+
/** How a `<Grid>` splits its cells into lines. */
|
|
2410
|
+
export type GridBalance = "cards" | "tiles";
|
|
2411
|
+
|
|
2412
|
+
/** A theme spacing name, or a number of pixels. */
|
|
2413
|
+
export type GridGap = "xs" | "sm" | "md" | "lg" | "xl" | number;
|
|
2414
|
+
|
|
2415
|
+
/**
|
|
2416
|
+
* Lays its children out in balanced lines of cells, sized from the grid's own
|
|
2417
|
+
* measured width, on the web Player and the native export alike. It measures
|
|
2418
|
+
* an inner box with no padding, so a `style` padding is not counted twice.
|
|
2419
|
+
*
|
|
2420
|
+
* - `balance="cards"` (default): as many cells per line as fit at
|
|
2421
|
+
* `minCellWidth` (240 when unset); every line but the last is full, and the
|
|
2422
|
+
* last is padded with empty cells so its cards keep the width of the lines
|
|
2423
|
+
* above. 6 that fit 5 are 3 + 3.
|
|
2424
|
+
* - `balance="tiles"`: the remainder spreads over every line and each line
|
|
2425
|
+
* stretches, so 5 tiles at 4 per line are 3 + 2, never 4 + 1. The per-line
|
|
2426
|
+
* ceiling is `maxColumns`, or what fits at `minCellWidth`, or else 4 / 3 / 2
|
|
2427
|
+
* for the wide / medium / narrow width tier.
|
|
2428
|
+
* - `columns`: exactly that many cells per line, the last line padded.
|
|
2429
|
+
* - `cell={{ min, max }}`: definite-size cells (calendar days, seats,
|
|
2430
|
+
* swatches) as large as fit up to `max`, never below `min` (32 when unset),
|
|
2431
|
+
* in a block centred in the grid (a block whose `min` cells cannot fit
|
|
2432
|
+
* starts at the leading edge, so only its far end is cut off); with
|
|
2433
|
+
* `columns` a fixed count per line. `square` makes each cell as tall as it
|
|
2434
|
+
* is wide.
|
|
2435
|
+
*
|
|
2436
|
+
* Each child is one cell and keeps its own look; a child with `flex: 1` fills
|
|
2437
|
+
* its cell's height, so a line of cards ends level. Nothing is drawn until the
|
|
2438
|
+
* width is measured when the layout depends on it. In a row, give the grid
|
|
2439
|
+
* `style={{ flex: 1, minWidth: 0 }}` so it has a width to measure.
|
|
2440
|
+
*
|
|
2441
|
+
* @example
|
|
2442
|
+
* <Grid minCellWidth={240}>{items.map((item) => <Card key={item.id}>…</Card>)}</Grid>
|
|
2443
|
+
* <Grid columns={7} cell={{ min: 32, max: 64 }} square gap="xs">{days}</Grid>
|
|
2444
|
+
*/
|
|
2445
|
+
export const Grid: (props: {
|
|
2446
|
+
children?: ReactNode;
|
|
2447
|
+
balance?: GridBalance;
|
|
2448
|
+
/** The narrowest a cell may be; the per-line count is derived from it. */
|
|
2449
|
+
minCellWidth?: number;
|
|
2450
|
+
maxColumns?: number;
|
|
2451
|
+
columns?: number;
|
|
2452
|
+
cell?: { min?: number; max: number };
|
|
2453
|
+
square?: boolean;
|
|
2454
|
+
/** Space between cells and lines; `"md"` when unset. */
|
|
2455
|
+
gap?: GridGap;
|
|
2456
|
+
/** The grid's outer box; padding here stays out of the measured width. */
|
|
2457
|
+
style?: any;
|
|
2458
|
+
testID?: string;
|
|
2459
|
+
/** Names the grid as one group to a screen reader. */
|
|
2460
|
+
accessibilityLabel?: string;
|
|
2461
|
+
}) => any;
|
|
2462
|
+
|
|
2463
|
+
/**
|
|
2464
|
+
* `required` on a control that frames its own label (`<TextField>`,
|
|
2465
|
+
* `<Select>`, `<RadioGroup>`, `<PeoplePicker>`, `<FileUpload>`, `<FormField>`).
|
|
2466
|
+
*/
|
|
2467
|
+
export interface FieldRequiredProps {
|
|
2468
|
+
/**
|
|
2469
|
+
* Draws a mark after a text label and adds the app's "Required" to the
|
|
2470
|
+
* control's spoken name. It does not validate: pass `error` yourself.
|
|
2471
|
+
*/
|
|
2472
|
+
required?: boolean;
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
/**
|
|
2476
|
+
* A form laid out in width tiers from its own measured width, capped near
|
|
2477
|
+
* 1000px and centred: its fields one to a line when narrow, two at medium and
|
|
2478
|
+
* `columns` (three for `"auto"`) when wide. A `<FormField>` or a control that
|
|
2479
|
+
* frames its own label (`<TextField>`, `<Select>`, `<RadioGroup>`,
|
|
2480
|
+
* `<PeoplePicker>`, `<FileUpload>`) is one field; a multiline field, a `<FormField span="full">`,
|
|
2481
|
+
* a `<FieldRow>`, a `<FormSection>`, a `<FormActions>` and anything else take
|
|
2482
|
+
* the whole line. Children are read directly, not through a fragment.
|
|
2483
|
+
*
|
|
2484
|
+
* @example
|
|
2485
|
+
* <Form>
|
|
2486
|
+
* <FormSection title="Your details">
|
|
2487
|
+
* <FieldRow>
|
|
2488
|
+
* <TextField label="First name" value={first} onChangeText={setFirst} />
|
|
2489
|
+
* <TextField label="Last name" value={last} onChangeText={setLast} />
|
|
2490
|
+
* </FieldRow>
|
|
2491
|
+
* <TextField label="Email" required value={email} onChangeText={setEmail} />
|
|
2492
|
+
* <FormField label="Colour"><SwatchPicker value={colour} onChange={setColour} /></FormField>
|
|
2493
|
+
* <TextField label="Notes" multiline value={notes} onChangeText={setNotes} />
|
|
2494
|
+
* </FormSection>
|
|
2495
|
+
* <FormActions>
|
|
2496
|
+
* <Button variant="secondary" title="Cancel" onPress={cancel} />
|
|
2497
|
+
* <Button title="Save" onPress={save} />
|
|
2498
|
+
* </FormActions>
|
|
2499
|
+
* </Form>
|
|
2500
|
+
*/
|
|
2501
|
+
export const Form: (props: {
|
|
2502
|
+
children?: ReactNode;
|
|
2503
|
+
/** The most fields to a line when wide, 1–3. Default "auto" (three). */
|
|
2504
|
+
columns?: "auto" | 1 | 2 | 3;
|
|
2505
|
+
/** The cap the form centres within. Default 1000; `null` for none. */
|
|
2506
|
+
maxWidth?: number | null;
|
|
2507
|
+
/** Between fields and lines; `"md"` when unset. */
|
|
2508
|
+
gap?: GridGap;
|
|
2509
|
+
/** The form's outer box; padding here stays out of the measured width. */
|
|
2510
|
+
style?: any;
|
|
2511
|
+
testID?: string;
|
|
2512
|
+
/** Names the form as one group to a screen reader. */
|
|
2513
|
+
accessibilityLabel?: string;
|
|
2514
|
+
}) => any;
|
|
2515
|
+
|
|
2516
|
+
/** Short related fields on one line (up to three); stacked when narrow. */
|
|
2517
|
+
export const FieldRow: (props: {
|
|
2518
|
+
children?: ReactNode;
|
|
2519
|
+
gap?: GridGap;
|
|
2520
|
+
style?: any;
|
|
2521
|
+
testID?: string;
|
|
2522
|
+
}) => any;
|
|
2523
|
+
|
|
2524
|
+
/** A titled group of fields, laid out in the same columns as its form. */
|
|
2525
|
+
export const FormSection: (props: {
|
|
2526
|
+
/** A heading for screen readers too. */
|
|
2527
|
+
title?: ReactNode;
|
|
2528
|
+
description?: ReactNode;
|
|
2529
|
+
children?: ReactNode;
|
|
2530
|
+
gap?: GridGap;
|
|
2531
|
+
style?: any;
|
|
2532
|
+
testID?: string;
|
|
2533
|
+
}) => any;
|
|
2534
|
+
|
|
2535
|
+
/**
|
|
2536
|
+
* The form's buttons in normal flow after its fields: the secondary first,
|
|
2537
|
+
* the primary last. A row at the trailing edge at medium and wide; a
|
|
2538
|
+
* full-width stack in the same order when narrow.
|
|
2539
|
+
*/
|
|
2540
|
+
export const FormActions: (props: {
|
|
2541
|
+
children?: ReactNode;
|
|
2542
|
+
style?: any;
|
|
2543
|
+
testID?: string;
|
|
2544
|
+
}) => any;
|
|
2545
|
+
|
|
2546
|
+
/**
|
|
2547
|
+
* A label, required mark, helper and error round any control. A control that
|
|
2548
|
+
* frames its own label is handed them instead (a prop it sets itself wins,
|
|
2549
|
+
* `disabled={false}` included), so one label is drawn; `testID` goes to that
|
|
2550
|
+
* control, or to a wrapper round it when it has its own. Any other child is
|
|
2551
|
+
* framed here: on the web it is named as a group described by the note; on a
|
|
2552
|
+
* device the one child takes the label (with "Required") as its name and the
|
|
2553
|
+
* note as its hint, unless it names itself.
|
|
2554
|
+
*/
|
|
2555
|
+
export const FormField: (props: FormControlProps & FieldRequiredProps & {
|
|
2556
|
+
children?: ReactNode;
|
|
2557
|
+
/** Take the form's whole line. */
|
|
2558
|
+
span?: "full";
|
|
2559
|
+
/** The frame round the control. */
|
|
2560
|
+
style?: any;
|
|
2561
|
+
}) => any;
|
|
2562
|
+
|
|
2409
2563
|
/** Pass-through options for `useGeolocation().getCurrentPosition(...)`. */
|
|
2410
2564
|
export interface GeolocationOptions {
|
|
2411
2565
|
enableHighAccuracy?: boolean;
|
|
@@ -3140,6 +3294,8 @@ export interface AppUserGroupRow {
|
|
|
3140
3294
|
|
|
3141
3295
|
export interface GroupsQuery {
|
|
3142
3296
|
q?: string;
|
|
3297
|
+
/** Only these groups (1 to 100 ids): name the groups behind ids you hold. */
|
|
3298
|
+
ids?: string[];
|
|
3143
3299
|
limit?: number;
|
|
3144
3300
|
offset?: number;
|
|
3145
3301
|
}
|
|
@@ -3843,6 +3999,97 @@ export const EmptyState: (props: {
|
|
|
3843
3999
|
children?: ReactNode;
|
|
3844
4000
|
}) => any;
|
|
3845
4001
|
|
|
4002
|
+
/** One column of a `<DataTable>`. */
|
|
4003
|
+
export interface DataTableColumn<Row = Record<string, any>> {
|
|
4004
|
+
/** The record field the column shows, and the key its sort names. */
|
|
4005
|
+
key: string;
|
|
4006
|
+
/** The header label, and the label beside the value in the card layouts. Defaults to `key`. */
|
|
4007
|
+
label?: ReactNode;
|
|
4008
|
+
/** The column's share of the row width; the header uses the same. Defaults to 1. */
|
|
4009
|
+
flex?: number;
|
|
4010
|
+
align?: "left" | "center" | "right";
|
|
4011
|
+
/** The narrowest the column may get, in pixels. Defaults to 0. */
|
|
4012
|
+
minWidth?: number;
|
|
4013
|
+
/** Makes the header a sort button. */
|
|
4014
|
+
sortable?: boolean;
|
|
4015
|
+
/** The cell's content; a string or number is drawn as the cell's text. Return `undefined` for the default. */
|
|
4016
|
+
render?: (row: Row, column: DataTableColumn<Row>) => ReactNode;
|
|
4017
|
+
}
|
|
4018
|
+
|
|
4019
|
+
/** The order a `<DataTable>` shows: one column, ascending or descending. */
|
|
4020
|
+
export interface DataTableSort {
|
|
4021
|
+
key: string;
|
|
4022
|
+
direction: "asc" | "desc";
|
|
4023
|
+
}
|
|
4024
|
+
|
|
4025
|
+
/**
|
|
4026
|
+
* A list of records laid out for its own measured width, on the web Player and
|
|
4027
|
+
* the native export alike: stacked label/value cards when narrow, one card per
|
|
4028
|
+
* row at medium (the first column as the title, the rest on one line), and
|
|
4029
|
+
* aligned columns under a sticky header when wide. Its rows are `<List>` /
|
|
4030
|
+
* `<ListRow>` and its header `<ListHeader>`, styled by the theme's Lists
|
|
4031
|
+
* settings (and Cards for the card layouts); it adds no theme scope.
|
|
4032
|
+
*
|
|
4033
|
+
* Sorting: a sortable header is a 44px button named by its column and
|
|
4034
|
+
* described by its sort, and a change of sort is announced once, on both
|
|
4035
|
+
* hosts. With `onSortChange` the widget orders the rows itself (a server
|
|
4036
|
+
* sort: re-query with the new sort) and the table draws `rows` as given;
|
|
4037
|
+
* without it the table sorts them, a `Date` value as a date. `sort` makes the
|
|
4038
|
+
* order controlled, `defaultSort` sets where an uncontrolled table starts; a
|
|
4039
|
+
* controlled `sort` without `onSortChange` is display-only, its headers plain
|
|
4040
|
+
* labels. The card layouts offer the same sort from a menu above the cards.
|
|
4041
|
+
* The sticky header is filled with the rows' Lists background, else the
|
|
4042
|
+
* theme surface.
|
|
4043
|
+
*
|
|
4044
|
+
* @example
|
|
4045
|
+
* const [sort, setSort] = useState({ key: "name", direction: "asc" });
|
|
4046
|
+
* const query = useStableQuery(() => ({ sort: { field: sort.key, dir: sort.direction } }));
|
|
4047
|
+
* const { data, loading } = useDatastoreQuery(tableId, query);
|
|
4048
|
+
* <DataTable
|
|
4049
|
+
* columns={[
|
|
4050
|
+
* { key: "name", label: "Name", flex: 2, sortable: true },
|
|
4051
|
+
* { key: "status", label: "Status", render: (row) => <Badge label={row.status} /> },
|
|
4052
|
+
* { key: "total", label: "Total", align: "right", sortable: true },
|
|
4053
|
+
* ]}
|
|
4054
|
+
* rows={data}
|
|
4055
|
+
* loading={loading}
|
|
4056
|
+
* sort={sort}
|
|
4057
|
+
* onSortChange={setSort}
|
|
4058
|
+
* onRowPress={(row) => open(row.id)}
|
|
4059
|
+
* />
|
|
4060
|
+
*/
|
|
4061
|
+
export const DataTable: <Row = Record<string, any>>(
|
|
4062
|
+
props: ListRowTokens & {
|
|
4063
|
+
columns: Array<DataTableColumn<Row> | string>;
|
|
4064
|
+
rows: Row[];
|
|
4065
|
+
/** The field that keys each row. Defaults to "id". */
|
|
4066
|
+
keyField?: string;
|
|
4067
|
+
/** Every cell's content where its column has no `render`; return `undefined` for the default. */
|
|
4068
|
+
renderCell?: (row: Row, column: DataTableColumn<Row>) => ReactNode;
|
|
4069
|
+
/** Makes every row a button. */
|
|
4070
|
+
onRowPress?: (row: Row) => void;
|
|
4071
|
+
/** The order shown, controlled. */
|
|
4072
|
+
sort?: DataTableSort | null;
|
|
4073
|
+
/** Where an uncontrolled table's order starts. */
|
|
4074
|
+
defaultSort?: DataTableSort;
|
|
4075
|
+
/** Called with the new order; the widget then orders `rows` itself. */
|
|
4076
|
+
onSortChange?: (sort: DataTableSort) => void;
|
|
4077
|
+
/** The rows' scroll box height, in pixels. Defaults to 480. */
|
|
4078
|
+
maxHeight?: number;
|
|
4079
|
+
/** Placeholder rows while `rows` is still empty. */
|
|
4080
|
+
loading?: boolean;
|
|
4081
|
+
/** The empty state's title and message; the message defaults to "No results". */
|
|
4082
|
+
emptyTitle?: ReactNode;
|
|
4083
|
+
emptyMessage?: ReactNode;
|
|
4084
|
+
/** The words a sort is spoken with, in the widget's language. */
|
|
4085
|
+
sortLabels?: { sort?: string; ascending?: string; descending?: string };
|
|
4086
|
+
/** The table's outer box; padding here stays out of the measured width. */
|
|
4087
|
+
style?: any;
|
|
4088
|
+
testID?: string;
|
|
4089
|
+
accessibilityLabel?: string;
|
|
4090
|
+
},
|
|
4091
|
+
) => any;
|
|
4092
|
+
|
|
3846
4093
|
/**
|
|
3847
4094
|
* Themed status pill: a record's state (Active, Paid, Overdue) beside the
|
|
3848
4095
|
* thing it describes. The label always renders; the tone only tints it.
|
|
@@ -4136,7 +4383,7 @@ export interface FormFieldOverrides {
|
|
|
4136
4383
|
* @example
|
|
4137
4384
|
* <TextField label="Name" value={name} onChangeText={setName} placeholder="Your name" />
|
|
4138
4385
|
*/
|
|
4139
|
-
export const TextField: (props: FormControlProps & FormFieldOverrides & {
|
|
4386
|
+
export const TextField: (props: FormControlProps & FieldRequiredProps & FormFieldOverrides & {
|
|
4140
4387
|
multiline?: boolean;
|
|
4141
4388
|
style?: any;
|
|
4142
4389
|
/** The box around a labelled field. */
|
|
@@ -4187,12 +4434,54 @@ export interface SelectOption<V extends string | number = string | number> {
|
|
|
4187
4434
|
label: string;
|
|
4188
4435
|
disabled?: boolean;
|
|
4189
4436
|
testID?: string;
|
|
4437
|
+
/** Drawn before the label in the sheet: an `<Avatar>`, an icon. */
|
|
4438
|
+
leading?: ReactNode;
|
|
4439
|
+
}
|
|
4440
|
+
|
|
4441
|
+
/**
|
|
4442
|
+
* The searchable mode of `<Select>`: a `<SearchField>` heads the sheet. Turn
|
|
4443
|
+
* it on with `searchable` (the options are filtered where they are held),
|
|
4444
|
+
* `onSearch` (you fetch per query) or async `options` (Select fetches).
|
|
4445
|
+
*/
|
|
4446
|
+
export interface SelectSearchProps<V extends string | number = string | number> {
|
|
4447
|
+
/** Filter the given `options` by label as the person types. */
|
|
4448
|
+
searchable?: boolean;
|
|
4449
|
+
/**
|
|
4450
|
+
* Called with the trimmed query when the sheet opens ("") and once typing
|
|
4451
|
+
* pauses; answer by passing new `options` (and `loading` meanwhile).
|
|
4452
|
+
*/
|
|
4453
|
+
onSearch?: (query: string) => void;
|
|
4454
|
+
/** The pause, in ms, before a typed query is sent. Default 250. */
|
|
4455
|
+
searchDebounceMs?: number;
|
|
4456
|
+
/** The options for the last query are on their way. */
|
|
4457
|
+
loading?: boolean;
|
|
4458
|
+
/** The last query failed; a string replaces `loadErrorText`. */
|
|
4459
|
+
optionsError?: boolean | string;
|
|
4460
|
+
/**
|
|
4461
|
+
* The options behind picked values the current `options` may not hold (a
|
|
4462
|
+
* saved choice outside the first page), so the trigger names them.
|
|
4463
|
+
*/
|
|
4464
|
+
selectedOptions?: Array<SelectOption<V>>;
|
|
4465
|
+
/** Default "Search". */
|
|
4466
|
+
searchPlaceholder?: string;
|
|
4467
|
+
/** Shown when a query finds nothing. Default "No results". */
|
|
4468
|
+
noResultsText?: string;
|
|
4469
|
+
/** Default "Loading…". */
|
|
4470
|
+
loadingText?: string;
|
|
4471
|
+
/** Default "Could not load the options". */
|
|
4472
|
+
loadErrorText?: string;
|
|
4190
4473
|
}
|
|
4191
4474
|
|
|
4192
4475
|
/** What every `<Select>` takes, in either mode. */
|
|
4193
4476
|
export type SelectBaseProps<V extends string | number = string | number> = FormControlProps &
|
|
4194
|
-
|
|
4195
|
-
|
|
4477
|
+
FieldRequiredProps &
|
|
4478
|
+
FormFieldOverrides &
|
|
4479
|
+
SelectSearchProps<V> & {
|
|
4480
|
+
/**
|
|
4481
|
+
* The options, or a function Select calls with each query (searchable
|
|
4482
|
+
* mode) that resolves to them; only its latest answer is shown.
|
|
4483
|
+
*/
|
|
4484
|
+
options: Array<SelectOption<V>> | ((query: string) => Promise<Array<SelectOption<V>>>);
|
|
4196
4485
|
/** Shown while nothing is chosen. Default "Select". */
|
|
4197
4486
|
placeholder?: string;
|
|
4198
4487
|
/** The sheet's heading. Defaults to a text `label`. */
|
|
@@ -4220,6 +4509,11 @@ export type SelectBaseProps<V extends string | number = string | number> = FormC
|
|
|
4220
4509
|
* trigger shows the picked labels as small chips while they fit on its line,
|
|
4221
4510
|
* else "N selected".
|
|
4222
4511
|
*
|
|
4512
|
+
* Searchable (`searchable`, `onSearch` or async `options`), the sheet leads
|
|
4513
|
+
* with a `<SearchField>`, says when it is loading and when nothing matches,
|
|
4514
|
+
* and keeps the label of every option it has shown; its rows take the theme's
|
|
4515
|
+
* Lists row height and padding when they are set.
|
|
4516
|
+
*
|
|
4223
4517
|
* @example
|
|
4224
4518
|
* <Select label="Status" value={status} onValueChange={setStatus}
|
|
4225
4519
|
* options={[{ value: "open", label: "Open" }, { value: "done", label: "Done" }]} />
|
|
@@ -4246,6 +4540,136 @@ export const Select: <V extends string | number = string | number>(
|
|
|
4246
4540
|
}),
|
|
4247
4541
|
) => any;
|
|
4248
4542
|
|
|
4543
|
+
/** Where `<PeoplePicker>` reads its options. */
|
|
4544
|
+
export type PeoplePickerSource = "users" | "groups" | "records";
|
|
4545
|
+
|
|
4546
|
+
/**
|
|
4547
|
+
* A searchable `<Select>` of the workspace's users (`useDirectory`, scope
|
|
4548
|
+
* `directory.read:users`), its groups (`useGroups`, `groups.read:*`) or one
|
|
4549
|
+
* table's records (`useDatastoreQuery`, the table's `datastore.read` scope).
|
|
4550
|
+
* Nothing loads until the sheet opens; each pause in typing searches on the
|
|
4551
|
+
* server. A saved value the page does not hold is looked up once by id, so the
|
|
4552
|
+
* trigger shows its name, `loadingText` meanwhile, or `unknownText` when it is
|
|
4553
|
+
* gone, never the id. Every other `<Select>` prop works.
|
|
4554
|
+
*
|
|
4555
|
+
* @example
|
|
4556
|
+
* <PeoplePicker label="Assignee" value={assignee} onValueChange={setAssignee} />
|
|
4557
|
+
* <PeoplePicker source="groups" multiple label="Teams" values={teams} onValuesChange={setTeams} />
|
|
4558
|
+
* <PeoplePicker source="records" table={tableId} label="Customer" value={customerId}
|
|
4559
|
+
* onValueChange={setCustomerId} />
|
|
4560
|
+
*/
|
|
4561
|
+
export const PeoplePicker: (
|
|
4562
|
+
props: Omit<SelectBaseProps<string>, "options" | "onSearch" | "selectedOptions" | "searchable"> & {
|
|
4563
|
+
/** Default "users". */
|
|
4564
|
+
source?: PeoplePickerSource;
|
|
4565
|
+
/** `source="records"`: the table id. */
|
|
4566
|
+
table?: string;
|
|
4567
|
+
/** `source="records"`: the column that names a record. Default the identification column. */
|
|
4568
|
+
labelColumn?: string;
|
|
4569
|
+
/** `source="records"`: a FILE column drawn as each row's avatar. */
|
|
4570
|
+
avatarColumn?: string;
|
|
4571
|
+
/** `source="users"`: only members of this group (a `useGroups()` row id). */
|
|
4572
|
+
groupId?: string;
|
|
4573
|
+
/** `source="records"`: narrows the rows, as `useDatastoreQuery`'s `filter`. */
|
|
4574
|
+
filter?: Query["filter"];
|
|
4575
|
+
/** Ids never offered (already members, the signed-in user). */
|
|
4576
|
+
excludeIds?: string[];
|
|
4577
|
+
/** Rows per search. Default 50, at most 200. */
|
|
4578
|
+
pageSize?: number;
|
|
4579
|
+
/** Draw an avatar before each user or group. Default true. */
|
|
4580
|
+
showAvatars?: boolean;
|
|
4581
|
+
/** A saved value whose row is gone, or a row with no name. Default "Unknown". */
|
|
4582
|
+
unknownText?: string;
|
|
4583
|
+
} & (
|
|
4584
|
+
| {
|
|
4585
|
+
multiple?: false;
|
|
4586
|
+
value?: string | null;
|
|
4587
|
+
onValueChange?: (value: string, option: SelectOption<string>) => void;
|
|
4588
|
+
}
|
|
4589
|
+
| {
|
|
4590
|
+
multiple: true;
|
|
4591
|
+
values?: string[] | null;
|
|
4592
|
+
onValuesChange?: (values: string[], options: Array<SelectOption<string>>) => void;
|
|
4593
|
+
selectedCountText?: (count: number) => string;
|
|
4594
|
+
doneText?: string;
|
|
4595
|
+
}
|
|
4596
|
+
),
|
|
4597
|
+
) => any;
|
|
4598
|
+
|
|
4599
|
+
/** One `<FilterBar>` facet: a dropdown of `options` under `key` in the value. */
|
|
4600
|
+
export interface FilterBarFacet<V extends string | number = string | number> {
|
|
4601
|
+
key: string;
|
|
4602
|
+
label: string;
|
|
4603
|
+
options: Array<SelectOption<V>>;
|
|
4604
|
+
/** Several values at once; the facet's value is then a list. */
|
|
4605
|
+
multiple?: boolean;
|
|
4606
|
+
/** Type to narrow the options, as `<Select searchable>`. */
|
|
4607
|
+
searchable?: boolean;
|
|
4608
|
+
}
|
|
4609
|
+
|
|
4610
|
+
/** The applied filters: each facet's value, or a list for a `multiple` one. */
|
|
4611
|
+
export type FilterBarValue = Record<string, string | number | Array<string | number>>;
|
|
4612
|
+
|
|
4613
|
+
/**
|
|
4614
|
+
* Search plus facet filters that lay themselves out for their own measured
|
|
4615
|
+
* width. Medium and wide: one toolbar row of a `<SearchField>`, a compact
|
|
4616
|
+
* `<Select>` per facet ("Status: Any") and the sort. Narrow, or a row whose
|
|
4617
|
+
* dropdowns do not fit: the search field and one "Filters · n" button opening
|
|
4618
|
+
* the facets in a `<Modal>` sheet, where nothing applies until Apply. At every
|
|
4619
|
+
* width each applied facet is a removable `<Chip>` beneath, with a "Clear all".
|
|
4620
|
+
*
|
|
4621
|
+
* `onChange` gets the whole next value once per edit, with a cleared facet's
|
|
4622
|
+
* key removed; `onQueryChange` gets the trimmed query once typing pauses
|
|
4623
|
+
* (`queryDebounceMs`, default 250) and at once on clear or submit. Both are
|
|
4624
|
+
* controlled, so seed `query` and `value` from route params or
|
|
4625
|
+
* `useWidgetRoute`. "Clear all" resets the facets and the query. The search
|
|
4626
|
+
* field shows only with `onQueryChange`. Copy props default to English.
|
|
4627
|
+
*
|
|
4628
|
+
* @example
|
|
4629
|
+
* <FilterBar query={q} onQueryChange={setQ} value={filters} onChange={setFilters}
|
|
4630
|
+
* facets={[{ key: "status", label: "Status", options: [{ value: "open", label: "Open" }] }]}
|
|
4631
|
+
* sort={{ options: [{ value: "new", label: "Newest" }], value: sortBy, onChange: setSortBy }} />
|
|
4632
|
+
*/
|
|
4633
|
+
export const FilterBar: (props: {
|
|
4634
|
+
query?: string;
|
|
4635
|
+
onQueryChange?: (query: string) => void;
|
|
4636
|
+
/** The pause, in ms, before typed text is reported. Default 250. */
|
|
4637
|
+
queryDebounceMs?: number;
|
|
4638
|
+
facets: FilterBarFacet[];
|
|
4639
|
+
value?: FilterBarValue | null;
|
|
4640
|
+
onChange?: (next: FilterBarValue) => void;
|
|
4641
|
+
/** One more dropdown; sorting is never shown as a chip. */
|
|
4642
|
+
sort?: {
|
|
4643
|
+
options: Array<SelectOption>;
|
|
4644
|
+
value?: string | number | null;
|
|
4645
|
+
onChange: (value: string | number) => void;
|
|
4646
|
+
/** Default "Sort". */
|
|
4647
|
+
label?: string;
|
|
4648
|
+
};
|
|
4649
|
+
/** Default "Search". */
|
|
4650
|
+
searchPlaceholder?: string;
|
|
4651
|
+
/** A facet with nothing picked. Default "Any". */
|
|
4652
|
+
anyText?: string;
|
|
4653
|
+
/** The narrow button and the sheet's title. Default "Filters". */
|
|
4654
|
+
filtersText?: string;
|
|
4655
|
+
/** Spoken after the button's name; `{count}` is the number applied. Default "{count} active". */
|
|
4656
|
+
activeCountText?: string | ((count: number) => string);
|
|
4657
|
+
/** Default "Clear all". */
|
|
4658
|
+
clearAllText?: string;
|
|
4659
|
+
/** Default "Apply". */
|
|
4660
|
+
applyText?: string;
|
|
4661
|
+
/** Empties the sheet's facets and puts its sort on the first option. Default "Clear". */
|
|
4662
|
+
clearText?: string;
|
|
4663
|
+
/** Names the chip group. Default "Active filters". */
|
|
4664
|
+
activeFiltersText?: string;
|
|
4665
|
+
/** A chip's remove control; `{label}` is the chip. Default "Remove {label}". */
|
|
4666
|
+
removeText?: string | ((label: string) => string);
|
|
4667
|
+
closeAccessibilityLabel?: string;
|
|
4668
|
+
/** The outer box; its padding is not counted into the measured width. */
|
|
4669
|
+
style?: any;
|
|
4670
|
+
testID?: string;
|
|
4671
|
+
}) => any;
|
|
4672
|
+
|
|
4249
4673
|
/**
|
|
4250
4674
|
* Space-key activation for a control whose role is not a button: on the web a
|
|
4251
4675
|
* `Pressable` answers Space only for a button. Native ignores `onKeyDown`.
|
|
@@ -4318,7 +4742,7 @@ export interface RadioOption<V extends string | number = string | number> {
|
|
|
4318
4742
|
* options={[{ value: "standard", label: "Standard" }, { value: "express", label: "Express" }]} />
|
|
4319
4743
|
*/
|
|
4320
4744
|
export const RadioGroup: <V extends string | number = string | number>(
|
|
4321
|
-
props: FormControlProps & {
|
|
4745
|
+
props: FormControlProps & FieldRequiredProps & {
|
|
4322
4746
|
options: Array<RadioOption<V>>;
|
|
4323
4747
|
value?: V | null;
|
|
4324
4748
|
/** Called when a different option is picked. */
|
|
@@ -4462,6 +4886,80 @@ export const ChipGroup: (props: {
|
|
|
4462
4886
|
testID?: string;
|
|
4463
4887
|
}) => any;
|
|
4464
4888
|
|
|
4889
|
+
export type ChartType = "bar" | "hbar" | "line" | "area" | "donut" | "sparkline";
|
|
4890
|
+
export type ChartValueFormat = "number" | "compact" | "percent" | ((value: number) => string);
|
|
4891
|
+
|
|
4892
|
+
/** One series of a multi-series `<Chart>`: the key each `data` item carries its value under. */
|
|
4893
|
+
export interface ChartSeries {
|
|
4894
|
+
key: string;
|
|
4895
|
+
label: string;
|
|
4896
|
+
/** A colour of the series' own; leave unset so the theme's chart look applies. */
|
|
4897
|
+
color?: string;
|
|
4898
|
+
}
|
|
4899
|
+
|
|
4900
|
+
/**
|
|
4901
|
+
* Themed chart drawn with react-native-svg. Its series colours, axis and label
|
|
4902
|
+
* colour, gridline colour and bar corners come from the theme's `chart` scope
|
|
4903
|
+
* (falling back to the theme's colours), so every chart in the app matches. It
|
|
4904
|
+
* measures its own width, shows a `<Skeleton>` while `loading` and an
|
|
4905
|
+
* `<EmptyState>` when there is nothing to plot, draws a legend for a donut and
|
|
4906
|
+
* for several series, and gives a screen reader a summary and the values.
|
|
4907
|
+
*
|
|
4908
|
+
* @example
|
|
4909
|
+
* const { groups, loading } = useDatastoreAggregate(tableId, { groupBy: "city", sumColumn: "visits" });
|
|
4910
|
+
* <Chart type="bar" loading={loading}
|
|
4911
|
+
* data={groups.map((g) => ({ label: String(g.group), value: Number(g.sum) || 0 }))} />
|
|
4912
|
+
*/
|
|
4913
|
+
export const Chart: (props: {
|
|
4914
|
+
/** Default "bar". "hbar" is horizontal bars; "sparkline" a small line with no axes. */
|
|
4915
|
+
type?: ChartType;
|
|
4916
|
+
/** `[{ label, value }]`, or with `series` one number per series key. */
|
|
4917
|
+
data: Array<{ label: string | number | { label: string }; [key: string]: unknown }>;
|
|
4918
|
+
/** Several series sharing `data`. A donut and a sparkline draw the first. */
|
|
4919
|
+
series?: ChartSeries[];
|
|
4920
|
+
/**
|
|
4921
|
+
* How values read on the axis, the legend and to a screen reader, grouped
|
|
4922
|
+
* for the app's language. Default "number". "percent" appends "%" to values
|
|
4923
|
+
* already in percent (42 reads "42%"); it does not multiply by 100.
|
|
4924
|
+
*/
|
|
4925
|
+
valueFormat?: ChartValueFormat;
|
|
4926
|
+
/** The plot's height in px. Default 220, or 48 for a sparkline. */
|
|
4927
|
+
height?: number;
|
|
4928
|
+
loading?: boolean;
|
|
4929
|
+
/** Defaults to the shared "No results" text. */
|
|
4930
|
+
emptyTitle?: string;
|
|
4931
|
+
emptyMessage?: string;
|
|
4932
|
+
/** Replaces the spoken summary sentence; the values are still read after it. */
|
|
4933
|
+
accessibilityLabel?: string;
|
|
4934
|
+
/** The tail of a spoken value list cut short; default `(count) => \`and ${count} more\``. */
|
|
4935
|
+
moreText?: (count: number) => string;
|
|
4936
|
+
/** For hosts rendering outside a widget context; widgets omit it. */
|
|
4937
|
+
theme?: any;
|
|
4938
|
+
style?: any;
|
|
4939
|
+
testID?: string;
|
|
4940
|
+
}) => any;
|
|
4941
|
+
|
|
4942
|
+
/**
|
|
4943
|
+
* The colours `<Chart>` paints with, for a chart a widget draws itself (a
|
|
4944
|
+
* scatter plot, a timeline) so it matches Design > Components > Charts.
|
|
4945
|
+
*
|
|
4946
|
+
* @example
|
|
4947
|
+
* const colors = chartColors(useTheme());
|
|
4948
|
+
* <Circle fill={colors.series(0)} fillOpacity={colors.seriesOpacity(0)} />
|
|
4949
|
+
*/
|
|
4950
|
+
export function chartColors(theme: any): {
|
|
4951
|
+
/** The six series colours, in order. */
|
|
4952
|
+
palette: string[];
|
|
4953
|
+
/** Axis line and label colour. */
|
|
4954
|
+
axis: string;
|
|
4955
|
+
/** Gridline colour. */
|
|
4956
|
+
grid: string;
|
|
4957
|
+
/** Series `index`'s colour; a seventh and later one is lighter. */
|
|
4958
|
+
series(index: number): string;
|
|
4959
|
+
/** Series `index`'s opacity: 1, below 1 for a repeat of a colour that cannot be lightened. */
|
|
4960
|
+
seriesOpacity(index: number): number;
|
|
4961
|
+
};
|
|
4962
|
+
|
|
4465
4963
|
/**
|
|
4466
4964
|
* A file as `<FilePicker>` and `<FileUpload>` hand it over: the browser's
|
|
4467
4965
|
* `File` on the web, expo-file-system's `File` on the Expo export. Pass it to
|
|
@@ -4499,8 +4997,8 @@ export const FilePicker: ((props: {
|
|
|
4499
4997
|
/**
|
|
4500
4998
|
* Themed file chooser on `<FilePicker>`: a button (the `button` scope) in the
|
|
4501
4999
|
* input field (the `muted` scope), the chosen files with their size and a
|
|
4502
|
-
* remove control, and the form controls' `label` / `
|
|
4503
|
-
* `disabled`. On the web a file can also be dropped onto the field; native
|
|
5000
|
+
* remove control, and the form controls' `label` / `required` / `helper` /
|
|
5001
|
+
* `error` / `disabled`. On the web a file can also be dropped onto the field; native
|
|
4504
5002
|
* has no file drop, so the button is the control there. A file `accept` rules
|
|
4505
5003
|
* out is not added and shows an error. It uploads nothing: upload in
|
|
4506
5004
|
* `onPick` with `useFilestoreUpload` and pass `uploading` while it runs, which
|
|
@@ -4513,7 +5011,7 @@ export const FilePicker: ((props: {
|
|
|
4513
5011
|
* files={photos} onFilesChange={setPhotos}
|
|
4514
5012
|
* onPick={(picked) => Promise.all(picked.map((f) => upload(f))).then(() => setPhotos([]))} />
|
|
4515
5013
|
*/
|
|
4516
|
-
export const FileUpload: (props: FormControlProps & {
|
|
5014
|
+
export const FileUpload: (props: FormControlProps & FieldRequiredProps & {
|
|
4517
5015
|
accept?: string;
|
|
4518
5016
|
/** A new pick joins the list instead of replacing the file. Default false. */
|
|
4519
5017
|
multiple?: boolean;
|
|
@@ -4658,6 +5156,107 @@ export const Tooltip: (props: {
|
|
|
4658
5156
|
children: ReactNode;
|
|
4659
5157
|
}) => any;
|
|
4660
5158
|
|
|
5159
|
+
/**
|
|
5160
|
+
* The words `<SortableList>` and `<Board>` show and announce. `{item}`,
|
|
5161
|
+
* `{position}`, `{total}` and `{column}` are filled in; a blank entry keeps
|
|
5162
|
+
* the English default.
|
|
5163
|
+
*/
|
|
5164
|
+
export interface SortableLabels {
|
|
5165
|
+
/** The handle's name and its options' title. Default "Move {item}". */
|
|
5166
|
+
handle?: string;
|
|
5167
|
+
hint?: string;
|
|
5168
|
+
moveUp?: string;
|
|
5169
|
+
moveDown?: string;
|
|
5170
|
+
moveToTop?: string;
|
|
5171
|
+
moveToBottom?: string;
|
|
5172
|
+
/** Default "Move to {column}". */
|
|
5173
|
+
moveToColumn?: string;
|
|
5174
|
+
/** Default "{item} moved to position {position} of {total}". */
|
|
5175
|
+
moved?: string;
|
|
5176
|
+
/** Default "{item} moved to {column}, position {position}". */
|
|
5177
|
+
movedToColumn?: string;
|
|
5178
|
+
}
|
|
5179
|
+
|
|
5180
|
+
/**
|
|
5181
|
+
* A list the user reorders by dragging a row's grip handle, on both hosts.
|
|
5182
|
+
* The rows are `<ListRow>`s in the theme's `list` scope. A tap or Enter on
|
|
5183
|
+
* the handle opens its move options, the arrow keys move a focused handle on
|
|
5184
|
+
* the web, and a screen reader is offered the same moves as actions.
|
|
5185
|
+
* `onReorder` runs once per real change; a drag that changes nothing springs
|
|
5186
|
+
* back and calls nothing.
|
|
5187
|
+
*
|
|
5188
|
+
* @example
|
|
5189
|
+
* <SortableList
|
|
5190
|
+
* items={steps}
|
|
5191
|
+
* onReorder={(next) => setSteps(next)}
|
|
5192
|
+
* renderItem={({ item }) => <Text>{item.title}</Text>}
|
|
5193
|
+
* />
|
|
5194
|
+
*/
|
|
5195
|
+
export function SortableList<T>(props: {
|
|
5196
|
+
items: T[];
|
|
5197
|
+
onReorder?: (nextItems: T[], move: { from: number; to: number; item: T }) => void;
|
|
5198
|
+
/** A row's content; with none the item's title, name or label shows. */
|
|
5199
|
+
renderItem?: (row: { item: T; index: number; dragging: boolean }) => ReactNode;
|
|
5200
|
+
/** Default: the item's `id`, then `key`, then its position. */
|
|
5201
|
+
keyExtractor?: (item: T, index: number) => string | number;
|
|
5202
|
+
/** The name a move announces. Default: its `title`, `name` or `label`. */
|
|
5203
|
+
getItemLabel?: (item: T) => string;
|
|
5204
|
+
/** Read on every render; a row it refuses shows no handle. Default true. */
|
|
5205
|
+
canDrag?: boolean | ((item: T) => boolean);
|
|
5206
|
+
/** "card" draws each row as the app's card. Default "plain". */
|
|
5207
|
+
variant?: "plain" | "card";
|
|
5208
|
+
labels?: SortableLabels;
|
|
5209
|
+
style?: any;
|
|
5210
|
+
testID?: string;
|
|
5211
|
+
accessibilityLabel?: string;
|
|
5212
|
+
}): any;
|
|
5213
|
+
|
|
5214
|
+
/** One `<Board>` column: the key `getColumn` returns, and its heading. */
|
|
5215
|
+
export interface BoardColumn {
|
|
5216
|
+
key: string | number;
|
|
5217
|
+
title: string;
|
|
5218
|
+
}
|
|
5219
|
+
|
|
5220
|
+
/**
|
|
5221
|
+
* Cards the user moves between columns (a kanban, a pipeline) by dragging a
|
|
5222
|
+
* card's grip handle, on both hosts. Each card is the app's `<Card>`. The one
|
|
5223
|
+
* column a held card is over takes the theme's soft primary, with a line
|
|
5224
|
+
* where it will land; a narrow board scrolls its columns sideways, and by
|
|
5225
|
+
* itself while a card is held at its edge. Move options, arrow keys and
|
|
5226
|
+
* screen-reader actions move a card without dragging.
|
|
5227
|
+
*
|
|
5228
|
+
* @example
|
|
5229
|
+
* <Board
|
|
5230
|
+
* columns={[{ key: "todo", title: "To do" }, { key: "done", title: "Done" }]}
|
|
5231
|
+
* items={rows}
|
|
5232
|
+
* getColumn={(row) => row.status}
|
|
5233
|
+
* onMove={(row, { toColumn }) => move(row, toColumn)}
|
|
5234
|
+
* renderCard={({ item }) => <Text>{item.title}</Text>}
|
|
5235
|
+
* />
|
|
5236
|
+
*/
|
|
5237
|
+
export function Board<T>(props: {
|
|
5238
|
+
columns: BoardColumn[];
|
|
5239
|
+
items: T[];
|
|
5240
|
+
/** The key of the column an item belongs in; an unknown key hides it. */
|
|
5241
|
+
getColumn: (item: T) => string | number;
|
|
5242
|
+
/** `index` is its place in the target column. */
|
|
5243
|
+
onMove?: (item: T, move: { fromColumn: string | number; toColumn: string | number; index: number }) => void;
|
|
5244
|
+
/** A card's content; with none the item's title, name or label shows. */
|
|
5245
|
+
renderCard?: (card: { item: T; index: number; column: string | number; dragging: boolean }) => ReactNode;
|
|
5246
|
+
keyExtractor?: (item: T, index: number) => string | number;
|
|
5247
|
+
getItemLabel?: (item: T) => string;
|
|
5248
|
+
/** Read on every render; a card it refuses shows no handle. Default true. */
|
|
5249
|
+
canDrag?: boolean | ((item: T) => boolean);
|
|
5250
|
+
/** False when cards keep no order of their own. Default true. */
|
|
5251
|
+
reorderInColumn?: boolean;
|
|
5252
|
+
/** A column's width when a narrow board scrolls sideways. Default 280. */
|
|
5253
|
+
columnWidth?: number;
|
|
5254
|
+
labels?: SortableLabels;
|
|
5255
|
+
style?: any;
|
|
5256
|
+
testID?: string;
|
|
5257
|
+
accessibilityLabel?: string;
|
|
5258
|
+
}): any;
|
|
5259
|
+
|
|
4661
5260
|
/**
|
|
4662
5261
|
* Themed collapsible sections. The surface comes from the theme's `card`
|
|
4663
5262
|
* scope and the headers and dividers from its `list` scope, so every
|