@colixsystems/widget-sdk 0.249.0 → 0.251.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 +15 -4
- package/dist/contract.cjs +7 -2
- package/dist/contract.js +7 -2
- package/dist/data-table-view.js +25 -19
- package/dist/index.d.ts +9 -2
- package/package.json +1 -1
- package/src/contract.js +7 -2
package/README.md
CHANGED
|
@@ -84,7 +84,18 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
84
84
|
|
|
85
85
|
## Status
|
|
86
86
|
|
|
87
|
-
`v0.
|
|
87
|
+
`v0.251.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
|
|
88
|
+
|
|
89
|
+
### What's new in 0.251.0 (contract 1.205.0)
|
|
90
|
+
|
|
91
|
+
**A text property's default is real, editable text in the Studio.** The Properties panel used to show a `string` property's `default` as a grey placeholder, so authors took it for a hint and never edited the text the widget actually rendered. It now shows the default as the field's own value. It is still not written until the author edits, so an untouched field keeps following the manifest. Clearing a field that shows a default stores `""`. Your widget gets an empty string and should render it as empty, so read text props with `??`, not `||`. Two `ui` hints are now typed:
|
|
92
|
+
|
|
93
|
+
- `ui.placeholder` — a grey hint shown while the field is empty.
|
|
94
|
+
- `ui.clearRestoresDefault: true` — clearing brings the default back instead of storing `""`. Use it for a caption that must never render blank, such as a button label.
|
|
95
|
+
|
|
96
|
+
### What's new in 0.250.0 (contract 1.204.0)
|
|
97
|
+
|
|
98
|
+
**`<DataTable showHeader={false}>`** drops the wide layout's header row (and its sticky index) for a table that needs no column labels; sorting then lives only in the card layouts' sort menu. The built-in Data List now draws through `<DataTable>`, and its "Show column headers" setting maps to this prop.
|
|
88
99
|
|
|
89
100
|
### What's new in 0.249.0 (contract 1.203.0)
|
|
90
101
|
|
|
@@ -2085,7 +2096,7 @@ const style = useWidgetStyle();
|
|
|
2085
2096
|
<View style={[styles.card, style.cardBackground && { backgroundColor: style.cardBackground }]}>
|
|
2086
2097
|
```
|
|
2087
2098
|
|
|
2088
|
-
Keep `themeDefault` for a fallback that IS a theme token: it stays display-only (
|
|
2099
|
+
Keep `themeDefault` for a fallback that IS a theme token: it stays display-only (shown in the Style panel field, never written) so the field tracks the workspace theme. Use `default` for a literal constant your code genuinely falls back to — that value now reaches `props.style`, so it must match what your code applies.
|
|
2089
2100
|
|
|
2090
2101
|
### What's new in 0.117.0 (contract 1.89.0)
|
|
2091
2102
|
|
|
@@ -2605,7 +2616,7 @@ Docs-only correction of documented host behaviour: no export, type, runtime, or
|
|
|
2605
2616
|
|
|
2606
2617
|
**`themeDefault` publishes the value a style field falls back to (sc-4164).** An unset `styleSchema` field rendered as an empty box, so an author adjusting `Title size` could not see the size they were changing. `WidgetPropertyDef` now documents the key the Studio has read since sc-1807:
|
|
2607
2618
|
|
|
2608
|
-
- **`themeDefault: "<dotted path into the resolved widget theme>"`** — e.g. `"typography.sizes.lg"`, `"radii.md"`, `"colors.onSurface"`. The Studio
|
|
2619
|
+
- **`themeDefault: "<dotted path into the resolved widget theme>"`** — e.g. `"typography.sizes.lg"`, `"radii.md"`, `"colors.onSurface"`. The Studio shows it in the field, resolved against the **workspace's** theme, so the hint stays truthful after a rebrand. Prefer it over a literal `default` whenever your fallback is a theme token — which it usually is, since you style from `useTheme()`.
|
|
2609
2620
|
- **A literal `default`** still works and is the right choice for a hard-coded constant your code carries (`default: 1.4` for a line height you wrote yourself).
|
|
2610
2621
|
- **Both are DISPLAY-ONLY.** Neither is ever written into `props.style`, so a style field keeps its only-when-set contract and continues to inherit the theme. Declare the value your code actually applies — a baseline that disagrees with the render is worse than none.
|
|
2611
2622
|
- **Optional.** A field whose fallback has no fixed value (a `background` that inherits whatever the container paints) declares neither and renders blank.
|
|
@@ -3151,7 +3162,7 @@ import { defineWidget, validateManifest, useDatastoreQuery, Text, View } from "@
|
|
|
3151
3162
|
- `parseMarkdown`, `markdownToPlainText`, `parseMarkdownImage`, `formatMarkdownImage`, `stripHtmlToMarkdown`, `MARKDOWN_IMAGE_SIZES` — the same grammar as pure helpers, for content you inspect rather than render: the block list, a marker-free projection (list previews, search, a11y labels), the one-line image form read and written, a legacy-HTML row normalised to markdown on read, and the closed size list (`small` | `medium` | `large` | `full`).
|
|
3152
3163
|
- `isSafeMarkdownImageSrc`, `isHttpImageSrc`, `normaliseMarkdownImageSize`, `readMarkdownAlt` — the image half of that grammar, for a widget rendering images itself via `renderImage`. `isSafeMarkdownImageSrc` is the same allowlist the parser applies (an `http(s)` URL or a filestore id; a `javascript:` scheme is refused), so the widget and the parser cannot disagree about which src is renderable.
|
|
3153
3164
|
- `List`, `ListRow`, `ListHeader`, `EmptyState` — the themed list building blocks. `<ListRow title subtitle leading trailing onPress selected divider>` draws one record row from the theme's `list` scope (padding, height, gap, radius, background, divider); `<List>` spaces its rows and hands overrides down; `<ListHeader>` labels a table's columns on the rows' own inset; `<EmptyState icon title message>` is the "nothing here" panel. Use them by default for record rows and a table's header; build your own row when it needs what `ListRow` cannot do (a swipe-to-delete row, a row that expands in place).
|
|
3154
|
-
- `DataTable` — a list or table of records laid out for its own width, on both hosts. `<DataTable columns rows>` is stacked label/value cards when narrow, one card per row at medium and aligned columns under a sticky header when wide, built from `List` / `ListRow` / `ListHeader` and styled by the theme's `list` scope. A column is `{ key, label, flex, align, minWidth, sortable, render }`; `renderCell`, `onRowPress`, `keyField` (default `"id"`), `loading` and `emptyTitle` / `emptyMessage`,
|
|
3165
|
+
- `DataTable` — a list or table of records laid out for its own width, on both hosts. `<DataTable columns rows>` is stacked label/value cards when narrow, one card per row at medium and aligned columns under a sticky header when wide, built from `List` / `ListRow` / `ListHeader` and styled by the theme's `list` scope. A column is `{ key, label, flex, align, minWidth, sortable, render }`; `renderCell`, `onRowPress`, `keyField` (default `"id"`), `loading` and `emptyTitle` / `emptyMessage`, `maxHeight` (480) and `showHeader` (`false` drops the wide header row) complete it. A sortable header is a 44px button named by its column and described by its sort, and a change of sort is announced once; with `onSortChange` the widget orders the rows (a server sort) and the table draws them as given, otherwise it sorts them itself (a `Date` as a date). A controlled `sort` without `onSortChange` is display-only, its headers plain labels. Use it by default for records; editable cells, grouped rows, resizable columns or a pivot are yours to build from `ListHeader` + `ListRow`.
|
|
3155
3166
|
- `Badge`, `Avatar`, `Progress`, `Stat`, `Divider` — the themed status pill, person picture, completion bar or ring, headline figure and rule the built-in widgets of the same names render through. Reach for them inside a record row instead of hand-rolling a pill or a circle from `View`.
|
|
3156
3167
|
- `Grid` — balanced lines of cells sized from the grid's own measured width, on both hosts. `<Grid minCellWidth gap balance>`: `balance` `"cards"` (default) fits as many cells to a line as `minCellWidth` allows (240 when unset), fills every line but the last and pads that one with empty cells; `"tiles"` spreads the remainder and stretches each line (5 at 4 per line are 3 + 2), with `maxColumns` or the width tier (4 / 3 / 2) as the ceiling. `columns` fixes the count per line; `cell={{ min, max }}` with `square` makes definite-size cells (calendar days, seats, swatches) in a centred block. It measures an inner box with no padding, and `gap` is a theme spacing name or a number. Each child keeps its own look, and a child with `flex: 1` fills its cell's height. Use it by default for card grids, tile rows and capped cells; masonry or spanning cells are yours to lay out with `useContainerWidth()`.
|
|
3157
3168
|
- `Form`, `FieldRow`, `FormSection`, `FormActions`, `FormField` — a form laid out in width tiers from its own measured width, on both hosts: `<Form columns maxWidth gap>` puts its fields one to a line when narrow, two at medium and up to three when wide (`columns` is the wide ceiling), capped near 1000px and centred (`maxWidth={null}` for none). A `<FormField>`, or a `<TextField>`, `<Select>`, `<RadioGroup>`, `<PeoplePicker>` or `<FileUpload>` with its own label, is one field; a multiline field, `<FormField span="full">`, `<FieldRow>` (short related fields on one line, stacked when narrow), `<FormSection title description>` and `<FormActions>` (Save / Cancel in normal flow, secondary first and primary last, a trailing row or a full-width stack when narrow) take the whole line. `<FormField label required helper error>` draws the form controls' label, required mark, helper and error round any control and names it for a screen reader; a control that frames its own label is handed them instead, so one label is drawn. `required` (also on `TextField`, `Select`, `RadioGroup`, `PeoplePicker`, `FileUpload`) draws the mark and adds "Required" to the spoken name; it does not validate. Use it by default; a multi-step wizard, a form beside a live preview or fields laid over a picture are yours to lay out with `useContainerWidth()`.
|
package/dist/contract.cjs
CHANGED
|
@@ -3364,7 +3364,7 @@ const PRIMITIVES = [
|
|
|
3364
3364
|
{
|
|
3365
3365
|
name: "DataTable",
|
|
3366
3366
|
description:
|
|
3367
|
-
'A list of records laid out for its own width. `<DataTable columns={[{ key: "name", label: "Name", flex: 2, sortable: true }, { key: "status", label: "Status", render: (row) => <Badge label={row.status} /> }, { key: "total", label: "Total", align: "right" }]} rows={data} loading={loading} onRowPress={(row) => open(row.id)} />` — use it by default for a list or table of records (datastore rows): it is stacked label/value cards when narrow, one card per row at medium (the first column as the title, the rest on one line), and aligned columns under a sticky header when wide, from its own measured width, so it needs no tier code of yours. When the table needs what it cannot do (editable cells, grouped or collapsible rows, resizable columns, a pivot), build your own from `<ListHeader>` over a `<List>` of `<ListRow>`s with the same `flex` per column. Columns: `key`, `label`, `flex` (default 1, the same in the header and the rows), `align` ("left" / "center" / "right"), `minWidth`, `sortable`, `render(row, column)` (a string or number becomes the cell\'s text). Props: `columns`, `rows`, `keyField` (default "id"), `renderCell(row, column)` (every cell without its own `render`; return `undefined` for the default), `onRowPress(row)`, `sort` / `defaultSort` (`{ key, direction: "asc" | "desc" }`), `onSortChange(sort)`, `maxHeight` (the rows\' scroll box, default 480), `loading` (placeholder rows while `rows` is empty), `emptyTitle`, `emptyMessage` (an empty state, "No results" by default), `sortLabels` (`{ sort, ascending, descending }` in the widget\'s language), the Lists overrides (`rowPadding`, `gap`, …), `style`, `testID`, `accessibilityLabel`. A sortable header is a 44px button named by its column and described by its sort, and a change of sort is announced once; the card layouts offer the same sort from a menu. With `onSortChange` you order the rows (re-query with the new sort) and the table draws `rows` as given; without it the table sorts them itself (a `Date` value sorts as a date). A controlled `sort` without `onSortChange` is display-only: the rows follow it and the headers are plain labels. The sticky header is filled with the rows\' Lists background, else the theme surface. It is styled by Design > Components > Lists (and Cards for the card layouts).',
|
|
3367
|
+
'A list of records laid out for its own width. `<DataTable columns={[{ key: "name", label: "Name", flex: 2, sortable: true }, { key: "status", label: "Status", render: (row) => <Badge label={row.status} /> }, { key: "total", label: "Total", align: "right" }]} rows={data} loading={loading} onRowPress={(row) => open(row.id)} />` — use it by default for a list or table of records (datastore rows): it is stacked label/value cards when narrow, one card per row at medium (the first column as the title, the rest on one line), and aligned columns under a sticky header when wide, from its own measured width, so it needs no tier code of yours. When the table needs what it cannot do (editable cells, grouped or collapsible rows, resizable columns, a pivot), build your own from `<ListHeader>` over a `<List>` of `<ListRow>`s with the same `flex` per column. Columns: `key`, `label`, `flex` (default 1, the same in the header and the rows), `align` ("left" / "center" / "right"), `minWidth`, `sortable`, `render(row, column)` (a string or number becomes the cell\'s text). Props: `columns`, `rows`, `keyField` (default "id"), `renderCell(row, column)` (every cell without its own `render`; return `undefined` for the default), `onRowPress(row)`, `sort` / `defaultSort` (`{ key, direction: "asc" | "desc" }`), `onSortChange(sort)`, `maxHeight` (the rows\' scroll box, default 480), `showHeader` (default true; `false` drops the wide layout\'s header row), `loading` (placeholder rows while `rows` is empty), `emptyTitle`, `emptyMessage` (an empty state, "No results" by default), `sortLabels` (`{ sort, ascending, descending }` in the widget\'s language), the Lists overrides (`rowPadding`, `gap`, …), `style`, `testID`, `accessibilityLabel`. A sortable header is a 44px button named by its column and described by its sort, and a change of sort is announced once; the card layouts offer the same sort from a menu. With `onSortChange` you order the rows (re-query with the new sort) and the table draws `rows` as given; without it the table sorts them itself (a `Date` value sorts as a date). A controlled `sort` without `onSortChange` is display-only: the rows follow it and the headers are plain labels. The sticky header is filled with the rows\' Lists background, else the theme surface. It is styled by Design > Components > Lists (and Cards for the card layouts).',
|
|
3368
3368
|
rnComponent: null,
|
|
3369
3369
|
docsUrl: null,
|
|
3370
3370
|
},
|
|
@@ -6330,7 +6330,12 @@ const CONTRACT = deepFreeze({
|
|
|
6330
6330
|
// `trailingIcon`, `onTrailingPress`, `trailingAccessibilityLabel` and the
|
|
6331
6331
|
// slots' testIDs; `<SearchField>` draws through them. New warnings
|
|
6332
6332
|
// `field-in-bordered-row`, `field-trailing-press-unnamed`.
|
|
6333
|
-
|
|
6333
|
+
// 1.204.0: additive (sc-12244) — `<DataTable showHeader>` (default true);
|
|
6334
|
+
// false drops the wide layout's header row and its sticky index.
|
|
6335
|
+
// 1.205.0: additive (sc-11840) — a string property's `default` shows as the
|
|
6336
|
+
// field's editable text and clearing stores ""; `ui.placeholder` and
|
|
6337
|
+
// `ui.clearRestoresDefault` are typed.
|
|
6338
|
+
version: "1.205.0",
|
|
6334
6339
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
6335
6340
|
hooks: HOOKS,
|
|
6336
6341
|
primitives: PRIMITIVES,
|
package/dist/contract.js
CHANGED
|
@@ -3364,7 +3364,7 @@ const PRIMITIVES = [
|
|
|
3364
3364
|
{
|
|
3365
3365
|
name: "DataTable",
|
|
3366
3366
|
description:
|
|
3367
|
-
'A list of records laid out for its own width. `<DataTable columns={[{ key: "name", label: "Name", flex: 2, sortable: true }, { key: "status", label: "Status", render: (row) => <Badge label={row.status} /> }, { key: "total", label: "Total", align: "right" }]} rows={data} loading={loading} onRowPress={(row) => open(row.id)} />` — use it by default for a list or table of records (datastore rows): it is stacked label/value cards when narrow, one card per row at medium (the first column as the title, the rest on one line), and aligned columns under a sticky header when wide, from its own measured width, so it needs no tier code of yours. When the table needs what it cannot do (editable cells, grouped or collapsible rows, resizable columns, a pivot), build your own from `<ListHeader>` over a `<List>` of `<ListRow>`s with the same `flex` per column. Columns: `key`, `label`, `flex` (default 1, the same in the header and the rows), `align` ("left" / "center" / "right"), `minWidth`, `sortable`, `render(row, column)` (a string or number becomes the cell\'s text). Props: `columns`, `rows`, `keyField` (default "id"), `renderCell(row, column)` (every cell without its own `render`; return `undefined` for the default), `onRowPress(row)`, `sort` / `defaultSort` (`{ key, direction: "asc" | "desc" }`), `onSortChange(sort)`, `maxHeight` (the rows\' scroll box, default 480), `loading` (placeholder rows while `rows` is empty), `emptyTitle`, `emptyMessage` (an empty state, "No results" by default), `sortLabels` (`{ sort, ascending, descending }` in the widget\'s language), the Lists overrides (`rowPadding`, `gap`, …), `style`, `testID`, `accessibilityLabel`. A sortable header is a 44px button named by its column and described by its sort, and a change of sort is announced once; the card layouts offer the same sort from a menu. With `onSortChange` you order the rows (re-query with the new sort) and the table draws `rows` as given; without it the table sorts them itself (a `Date` value sorts as a date). A controlled `sort` without `onSortChange` is display-only: the rows follow it and the headers are plain labels. The sticky header is filled with the rows\' Lists background, else the theme surface. It is styled by Design > Components > Lists (and Cards for the card layouts).',
|
|
3367
|
+
'A list of records laid out for its own width. `<DataTable columns={[{ key: "name", label: "Name", flex: 2, sortable: true }, { key: "status", label: "Status", render: (row) => <Badge label={row.status} /> }, { key: "total", label: "Total", align: "right" }]} rows={data} loading={loading} onRowPress={(row) => open(row.id)} />` — use it by default for a list or table of records (datastore rows): it is stacked label/value cards when narrow, one card per row at medium (the first column as the title, the rest on one line), and aligned columns under a sticky header when wide, from its own measured width, so it needs no tier code of yours. When the table needs what it cannot do (editable cells, grouped or collapsible rows, resizable columns, a pivot), build your own from `<ListHeader>` over a `<List>` of `<ListRow>`s with the same `flex` per column. Columns: `key`, `label`, `flex` (default 1, the same in the header and the rows), `align` ("left" / "center" / "right"), `minWidth`, `sortable`, `render(row, column)` (a string or number becomes the cell\'s text). Props: `columns`, `rows`, `keyField` (default "id"), `renderCell(row, column)` (every cell without its own `render`; return `undefined` for the default), `onRowPress(row)`, `sort` / `defaultSort` (`{ key, direction: "asc" | "desc" }`), `onSortChange(sort)`, `maxHeight` (the rows\' scroll box, default 480), `showHeader` (default true; `false` drops the wide layout\'s header row), `loading` (placeholder rows while `rows` is empty), `emptyTitle`, `emptyMessage` (an empty state, "No results" by default), `sortLabels` (`{ sort, ascending, descending }` in the widget\'s language), the Lists overrides (`rowPadding`, `gap`, …), `style`, `testID`, `accessibilityLabel`. A sortable header is a 44px button named by its column and described by its sort, and a change of sort is announced once; the card layouts offer the same sort from a menu. With `onSortChange` you order the rows (re-query with the new sort) and the table draws `rows` as given; without it the table sorts them itself (a `Date` value sorts as a date). A controlled `sort` without `onSortChange` is display-only: the rows follow it and the headers are plain labels. The sticky header is filled with the rows\' Lists background, else the theme surface. It is styled by Design > Components > Lists (and Cards for the card layouts).',
|
|
3368
3368
|
rnComponent: null,
|
|
3369
3369
|
docsUrl: null,
|
|
3370
3370
|
},
|
|
@@ -6326,7 +6326,12 @@ const CONTRACT = deepFreeze({
|
|
|
6326
6326
|
// `trailingIcon`, `onTrailingPress`, `trailingAccessibilityLabel` and the
|
|
6327
6327
|
// slots' testIDs; `<SearchField>` draws through them. New warnings
|
|
6328
6328
|
// `field-in-bordered-row`, `field-trailing-press-unnamed`.
|
|
6329
|
-
|
|
6329
|
+
// 1.204.0: additive (sc-12244) — `<DataTable showHeader>` (default true);
|
|
6330
|
+
// false drops the wide layout's header row and its sticky index.
|
|
6331
|
+
// 1.205.0: additive (sc-11840) — a string property's `default` shows as the
|
|
6332
|
+
// field's editable text and clearing stores ""; `ui.placeholder` and
|
|
6333
|
+
// `ui.clearRestoresDefault` are typed.
|
|
6334
|
+
version: "1.205.0",
|
|
6330
6335
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
6331
6336
|
hooks: HOOKS,
|
|
6332
6337
|
primitives: PRIMITIVES,
|
package/dist/data-table-view.js
CHANGED
|
@@ -294,35 +294,40 @@ export function makeDataTable(rn, parts) {
|
|
|
294
294
|
return resolveListTokens(theme, overrides).background || theme.colors.surface;
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
+
function columnsHeader(table, theme) {
|
|
298
|
+
return h(
|
|
299
|
+
ListHeader,
|
|
300
|
+
{
|
|
301
|
+
...table.overrides,
|
|
302
|
+
style: { backgroundColor: headerFill(theme, table.overrides) },
|
|
303
|
+
testID: testId(table.testID, "header"),
|
|
304
|
+
},
|
|
305
|
+
...table.columns.map((column) =>
|
|
306
|
+
h(HeaderCell, {
|
|
307
|
+
key: column.key,
|
|
308
|
+
column,
|
|
309
|
+
sort: table.sort,
|
|
310
|
+
onSort: table.onSort,
|
|
311
|
+
labels: table.labels,
|
|
312
|
+
testID: table.testID,
|
|
313
|
+
}),
|
|
314
|
+
),
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
297
318
|
// Inside the page's scroller; Android scrolls only the outer one without it.
|
|
298
319
|
function ColumnsLayout({ table }) {
|
|
299
320
|
const theme = useTableTheme();
|
|
321
|
+
const header = table.showHeader ? columnsHeader(table, theme) : null;
|
|
300
322
|
return h(
|
|
301
323
|
ScrollView,
|
|
302
324
|
{
|
|
303
325
|
style: { maxHeight: table.maxHeight },
|
|
304
326
|
nestedScrollEnabled: true,
|
|
305
|
-
stickyHeaderIndices: [0],
|
|
327
|
+
stickyHeaderIndices: header ? [0] : undefined,
|
|
306
328
|
testID: testId(table.testID, "scroll"),
|
|
307
329
|
},
|
|
308
|
-
|
|
309
|
-
ListHeader,
|
|
310
|
-
{
|
|
311
|
-
...table.overrides,
|
|
312
|
-
style: { backgroundColor: headerFill(theme, table.overrides) },
|
|
313
|
-
testID: testId(table.testID, "header"),
|
|
314
|
-
},
|
|
315
|
-
...table.columns.map((column) =>
|
|
316
|
-
h(HeaderCell, {
|
|
317
|
-
key: column.key,
|
|
318
|
-
column,
|
|
319
|
-
sort: table.sort,
|
|
320
|
-
onSort: table.onSort,
|
|
321
|
-
labels: table.labels,
|
|
322
|
-
testID: table.testID,
|
|
323
|
-
}),
|
|
324
|
-
),
|
|
325
|
-
),
|
|
330
|
+
header,
|
|
326
331
|
bodyOf(table, "columns"),
|
|
327
332
|
);
|
|
328
333
|
}
|
|
@@ -366,6 +371,7 @@ export function makeDataTable(rn, parts) {
|
|
|
366
371
|
emptyTitle: props.emptyTitle,
|
|
367
372
|
emptyMessage: props.emptyMessage ?? (props.emptyTitle ? undefined : emptyFallback),
|
|
368
373
|
maxHeight: resolveMaxHeight(props.maxHeight),
|
|
374
|
+
showHeader: props.showHeader !== false,
|
|
369
375
|
overrides: listOverrides(props),
|
|
370
376
|
testID,
|
|
371
377
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -87,8 +87,8 @@ export interface WidgetPropertyDef {
|
|
|
87
87
|
// sc-1807 / sc-4164 — the value the widget falls back to when this field is
|
|
88
88
|
// unset, as a dotted path into the resolved widget theme
|
|
89
89
|
// (`"typography.sizes.lg"`, `"radii.md"`, `"colors.onSurface"`). The Studio
|
|
90
|
-
// shows it
|
|
91
|
-
// adjusting from; it resolves against the WORKSPACE's theme, so the hint stays
|
|
90
|
+
// shows it in the field (a greyed hint for colours) so the author can see
|
|
91
|
+
// what they are adjusting from; it resolves against the WORKSPACE's theme, so the hint stays
|
|
92
92
|
// truthful after a rebrand. DISPLAY-ONLY — never written into props.style, so
|
|
93
93
|
// a styleSchema field keeps its only-when-set contract. Prefer this over a
|
|
94
94
|
// literal `default` whenever the fallback is a theme token.
|
|
@@ -106,6 +106,11 @@ export interface WidgetPropertyDef {
|
|
|
106
106
|
// a static `default`). Today: `"tabId"` → seed a unique stable id
|
|
107
107
|
// for newly added Tab Layout tabs.
|
|
108
108
|
defaultFactory?: "tabId";
|
|
109
|
+
// string: a grey hint shown while the field is empty.
|
|
110
|
+
placeholder?: string;
|
|
111
|
+
// string: clearing restores `default` instead of storing "" — for a
|
|
112
|
+
// caption that must never render blank (a button label).
|
|
113
|
+
clearRestoresDefault?: boolean;
|
|
109
114
|
};
|
|
110
115
|
validation?: { min?: number; max?: number; pattern?: string };
|
|
111
116
|
}
|
|
@@ -4076,6 +4081,8 @@ export const DataTable: <Row = Record<string, any>>(
|
|
|
4076
4081
|
onSortChange?: (sort: DataTableSort) => void;
|
|
4077
4082
|
/** The rows' scroll box height, in pixels. Defaults to 480. */
|
|
4078
4083
|
maxHeight?: number;
|
|
4084
|
+
/** `false` drops the wide layout's header row. Defaults to true. */
|
|
4085
|
+
showHeader?: boolean;
|
|
4079
4086
|
/** Placeholder rows while `rows` is still empty. */
|
|
4080
4087
|
loading?: boolean;
|
|
4081
4088
|
/** The empty state's title and message; the message defaults to "No results". */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.251.0",
|
|
4
4
|
"description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
|
|
5
5
|
"homepage": "https://github.com/Colix-AB/AppStudio",
|
|
6
6
|
"type": "module",
|
package/src/contract.js
CHANGED
|
@@ -3364,7 +3364,7 @@ const PRIMITIVES = [
|
|
|
3364
3364
|
{
|
|
3365
3365
|
name: "DataTable",
|
|
3366
3366
|
description:
|
|
3367
|
-
'A list of records laid out for its own width. `<DataTable columns={[{ key: "name", label: "Name", flex: 2, sortable: true }, { key: "status", label: "Status", render: (row) => <Badge label={row.status} /> }, { key: "total", label: "Total", align: "right" }]} rows={data} loading={loading} onRowPress={(row) => open(row.id)} />` — use it by default for a list or table of records (datastore rows): it is stacked label/value cards when narrow, one card per row at medium (the first column as the title, the rest on one line), and aligned columns under a sticky header when wide, from its own measured width, so it needs no tier code of yours. When the table needs what it cannot do (editable cells, grouped or collapsible rows, resizable columns, a pivot), build your own from `<ListHeader>` over a `<List>` of `<ListRow>`s with the same `flex` per column. Columns: `key`, `label`, `flex` (default 1, the same in the header and the rows), `align` ("left" / "center" / "right"), `minWidth`, `sortable`, `render(row, column)` (a string or number becomes the cell\'s text). Props: `columns`, `rows`, `keyField` (default "id"), `renderCell(row, column)` (every cell without its own `render`; return `undefined` for the default), `onRowPress(row)`, `sort` / `defaultSort` (`{ key, direction: "asc" | "desc" }`), `onSortChange(sort)`, `maxHeight` (the rows\' scroll box, default 480), `loading` (placeholder rows while `rows` is empty), `emptyTitle`, `emptyMessage` (an empty state, "No results" by default), `sortLabels` (`{ sort, ascending, descending }` in the widget\'s language), the Lists overrides (`rowPadding`, `gap`, …), `style`, `testID`, `accessibilityLabel`. A sortable header is a 44px button named by its column and described by its sort, and a change of sort is announced once; the card layouts offer the same sort from a menu. With `onSortChange` you order the rows (re-query with the new sort) and the table draws `rows` as given; without it the table sorts them itself (a `Date` value sorts as a date). A controlled `sort` without `onSortChange` is display-only: the rows follow it and the headers are plain labels. The sticky header is filled with the rows\' Lists background, else the theme surface. It is styled by Design > Components > Lists (and Cards for the card layouts).',
|
|
3367
|
+
'A list of records laid out for its own width. `<DataTable columns={[{ key: "name", label: "Name", flex: 2, sortable: true }, { key: "status", label: "Status", render: (row) => <Badge label={row.status} /> }, { key: "total", label: "Total", align: "right" }]} rows={data} loading={loading} onRowPress={(row) => open(row.id)} />` — use it by default for a list or table of records (datastore rows): it is stacked label/value cards when narrow, one card per row at medium (the first column as the title, the rest on one line), and aligned columns under a sticky header when wide, from its own measured width, so it needs no tier code of yours. When the table needs what it cannot do (editable cells, grouped or collapsible rows, resizable columns, a pivot), build your own from `<ListHeader>` over a `<List>` of `<ListRow>`s with the same `flex` per column. Columns: `key`, `label`, `flex` (default 1, the same in the header and the rows), `align` ("left" / "center" / "right"), `minWidth`, `sortable`, `render(row, column)` (a string or number becomes the cell\'s text). Props: `columns`, `rows`, `keyField` (default "id"), `renderCell(row, column)` (every cell without its own `render`; return `undefined` for the default), `onRowPress(row)`, `sort` / `defaultSort` (`{ key, direction: "asc" | "desc" }`), `onSortChange(sort)`, `maxHeight` (the rows\' scroll box, default 480), `showHeader` (default true; `false` drops the wide layout\'s header row), `loading` (placeholder rows while `rows` is empty), `emptyTitle`, `emptyMessage` (an empty state, "No results" by default), `sortLabels` (`{ sort, ascending, descending }` in the widget\'s language), the Lists overrides (`rowPadding`, `gap`, …), `style`, `testID`, `accessibilityLabel`. A sortable header is a 44px button named by its column and described by its sort, and a change of sort is announced once; the card layouts offer the same sort from a menu. With `onSortChange` you order the rows (re-query with the new sort) and the table draws `rows` as given; without it the table sorts them itself (a `Date` value sorts as a date). A controlled `sort` without `onSortChange` is display-only: the rows follow it and the headers are plain labels. The sticky header is filled with the rows\' Lists background, else the theme surface. It is styled by Design > Components > Lists (and Cards for the card layouts).',
|
|
3368
3368
|
rnComponent: null,
|
|
3369
3369
|
docsUrl: null,
|
|
3370
3370
|
},
|
|
@@ -6326,7 +6326,12 @@ const CONTRACT = deepFreeze({
|
|
|
6326
6326
|
// `trailingIcon`, `onTrailingPress`, `trailingAccessibilityLabel` and the
|
|
6327
6327
|
// slots' testIDs; `<SearchField>` draws through them. New warnings
|
|
6328
6328
|
// `field-in-bordered-row`, `field-trailing-press-unnamed`.
|
|
6329
|
-
|
|
6329
|
+
// 1.204.0: additive (sc-12244) — `<DataTable showHeader>` (default true);
|
|
6330
|
+
// false drops the wide layout's header row and its sticky index.
|
|
6331
|
+
// 1.205.0: additive (sc-11840) — a string property's `default` shows as the
|
|
6332
|
+
// field's editable text and clearing stores ""; `ui.placeholder` and
|
|
6333
|
+
// `ui.clearRestoresDefault` are typed.
|
|
6334
|
+
version: "1.205.0",
|
|
6330
6335
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
6331
6336
|
hooks: HOOKS,
|
|
6332
6337
|
primitives: PRIMITIVES,
|