tosijs-ui 1.16.12 → 1.16.14
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/CHANGELOG.md +53 -0
- package/dist/data-table.js +50 -24
- package/dist/iife.js +100 -100
- package/dist/iife.js.map +7 -7
- package/dist/schema-form/curate.d.ts +49 -9
- package/dist/schema-form/curate.js +108 -34
- package/dist/schema-form/fields.d.ts +10 -0
- package/dist/schema-form/fields.js +12 -3
- package/dist/schema-form.d.ts +112 -9
- package/dist/schema-form.js +934 -97
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.16.14
|
|
4
|
+
|
|
5
|
+
More reach for curated schema forms (#221): into arrays and unions, grouped into sections,
|
|
6
|
+
and usable as a review screen. All of it is off until you ask for it.
|
|
7
|
+
|
|
8
|
+
- **A curation can reach inside arrays and unions.** Give an array's, a union's or an
|
|
9
|
+
object's entry its own `fields`, with paths relative to the property: for an array they
|
|
10
|
+
apply to every item (`thresholds: { fields: { value: 'Threshold' } }`), for a union to the
|
|
11
|
+
branch the value currently matches. Items and branches keep what is not shown, an error in
|
|
12
|
+
an item property that is not shown is listed by its real path, and a union's
|
|
13
|
+
`picker: false` hides the variant picker. One `fields` covers every branch of a union: a
|
|
14
|
+
path the active branch lacks is left out, a path no branch has says so.
|
|
15
|
+
- **Sections.** An entry `{ section: 'Advanced', fields: {...}, collapsed?: true }` groups
|
|
16
|
+
fields in a titled panel. `collapsed: true` also works on an object or array entry. A
|
|
17
|
+
section or collapsed entry is marked `-invalid`, with a red title, while a field inside it
|
|
18
|
+
is in error. **TypeScript:** `FieldCuration`'s values now include `CuratedSection`, so code
|
|
19
|
+
that walks a curation and reads `entry.caption` needs the new guard: `isSection` is exported.
|
|
20
|
+
- **Proposals, for review screens.** `form.proposals = { path: { value, reason?, source? } }`
|
|
21
|
+
shows each proposed value under its field with Accept and Reject. `value` stays the
|
|
22
|
+
current value until one is accepted; accepting fires `proposalaccept` then `change`,
|
|
23
|
+
rejecting fires `proposalreject`. `acceptProposal(path)` / `rejectProposal(path)` do it
|
|
24
|
+
from code, and `proposalView` renders a proposal your own way. A proposal can be for a
|
|
25
|
+
whole array, object or union, and an object item of an array can be proposed whole
|
|
26
|
+
(`list.0`). One for an array item follows its item when items move. `proposalView` is
|
|
27
|
+
given `ProposalContext.readOnly`, and its `accept` / `reject` do nothing while the form is
|
|
28
|
+
read-only. Works with or without a curation. New localized strings: `Proposed`, `Accept`, `Reject`,
|
|
29
|
+
`Proposed changes to fields not shown here`.
|
|
30
|
+
- For TypeScript: `isSection` is exported; `ProposalContext.readOnly` tells a custom
|
|
31
|
+
`proposalView` that the form is read-only.
|
|
32
|
+
- **Fixed: an array item with several fields laid them out in two columns**, so the second
|
|
33
|
+
field sat in the column meant for the move and remove buttons and the buttons wrapped
|
|
34
|
+
underneath. Fields now stack and the buttons sit beside the first. The form now places an
|
|
35
|
+
item's children itself (`grid-column`), so a stylesheet of your own that arranged
|
|
36
|
+
`.schema-item` children may need a look.
|
|
37
|
+
- **Fixed: setting `value` with a different number of array items left the old rows.** A
|
|
38
|
+
longer array showed only the rows it had before, and a shorter one kept controls for items
|
|
39
|
+
that no longer existed. Arrays are now re-filled when their length changes.
|
|
40
|
+
- **Fixed: a schema `title` that is not a string** was handed to the label, or to a union's
|
|
41
|
+
picker option, as element properties. Only a string is a title now, for properties and for
|
|
42
|
+
`anyOf` / `oneOf` branches; anything else falls back to the key or the branch's value.
|
|
43
|
+
- Schema `title`s were already shown as written, never humanised or localized; the docs now
|
|
44
|
+
say so and a test holds it.
|
|
45
|
+
|
|
46
|
+
## 1.16.13
|
|
47
|
+
|
|
48
|
+
Documentation only; no library code changed.
|
|
49
|
+
|
|
50
|
+
- **Better examples for the two 1.16.12 features**, in the package's doc comments and
|
|
51
|
+
`llms.txt` as well as on the site. The table's row detail example now opens each invoice to
|
|
52
|
+
a nested `<tosi-table>` of its line items with a totals line. The curated form example
|
|
53
|
+
starts from a valid value and has **View only** and **Every field** toggles; the
|
|
54
|
+
hidden-error case is a separate, smaller example.
|
|
55
|
+
|
|
3
56
|
## 1.16.12
|
|
4
57
|
|
|
5
58
|
Two additions for task-focused screens: a table row can open to show a detail element, and a
|
package/dist/data-table.js
CHANGED
|
@@ -1005,41 +1005,65 @@ target `.tr-detail`. Add `Details` to your localized strings.
|
|
|
1005
1005
|
import { tosiTable } from 'tosijs-ui'
|
|
1006
1006
|
import { elements } from 'tosijs'
|
|
1007
1007
|
|
|
1008
|
-
const { div,
|
|
1008
|
+
const { div, span, b } = elements
|
|
1009
1009
|
|
|
1010
1010
|
const invoices = Array.from({ length: 2000 }, (_, i) => ({
|
|
1011
1011
|
id: `INV-${1000 + i}`,
|
|
1012
1012
|
buyer: ['Acme', 'Globex', 'Initech', 'Umbrella'][i % 4],
|
|
1013
|
-
lines: Array.from({ length: 1 + (i % 4) }, (_, n) =>
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1013
|
+
lines: Array.from({ length: 1 + (i % 4) }, (_, n) => {
|
|
1014
|
+
const qty = 1 + ((i + n) % 5)
|
|
1015
|
+
const price = 12.5 * (1 + ((i * 7 + n) % 9))
|
|
1016
|
+
return {
|
|
1017
|
+
item: ['Widget', 'Gasket', 'Sprocket', 'Flange'][(i + n) % 4],
|
|
1018
|
+
qty,
|
|
1019
|
+
price,
|
|
1020
|
+
amount: qty * price,
|
|
1021
|
+
}
|
|
1022
|
+
}),
|
|
1018
1023
|
}))
|
|
1019
1024
|
for (const invoice of invoices) {
|
|
1020
|
-
invoice.total = invoice.lines.reduce((sum,
|
|
1025
|
+
invoice.total = invoice.lines.reduce((sum, line) => sum + line.amount, 0)
|
|
1021
1026
|
}
|
|
1022
1027
|
|
|
1028
|
+
const usd = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' })
|
|
1029
|
+
|
|
1030
|
+
// The detail is a component built from the row: here, a table of its line items.
|
|
1031
|
+
const invoiceDetail = (invoice) =>
|
|
1032
|
+
div(
|
|
1033
|
+
{ class: 'invoice-detail' },
|
|
1034
|
+
tosiTable({
|
|
1035
|
+
rowHeight: 0,
|
|
1036
|
+
nosort: true,
|
|
1037
|
+
nohide: true,
|
|
1038
|
+
noreorder: true,
|
|
1039
|
+
array: invoice.lines,
|
|
1040
|
+
columns: [
|
|
1041
|
+
{ prop: 'item', name: 'Item', width: 160 },
|
|
1042
|
+
{ prop: 'qty', name: 'Qty', width: 70, type: 'number' },
|
|
1043
|
+
{ prop: 'price', name: 'Unit price', width: 110, type: 'currency(USD)' },
|
|
1044
|
+
{ prop: 'amount', name: 'Amount', width: 110, type: 'currency(USD)' },
|
|
1045
|
+
],
|
|
1046
|
+
}),
|
|
1047
|
+
div(
|
|
1048
|
+
{ class: 'invoice-total' },
|
|
1049
|
+
span(`${invoice.lines.length} line${invoice.lines.length === 1 ? '' : 's'}, billed to ${invoice.buyer}`),
|
|
1050
|
+
b('Total ', usd.format(invoice.total))
|
|
1051
|
+
)
|
|
1052
|
+
)
|
|
1053
|
+
|
|
1023
1054
|
const invoiceTable = tosiTable({
|
|
1024
|
-
style: { height: '
|
|
1055
|
+
style: { height: '360px' },
|
|
1025
1056
|
rowHeight: 32,
|
|
1026
1057
|
select: true,
|
|
1027
1058
|
array: invoices,
|
|
1028
1059
|
columns: [
|
|
1029
1060
|
{ prop: 'detail', width: 40, expander: true },
|
|
1030
1061
|
{ prop: 'id', name: 'Invoice', width: 120 },
|
|
1031
|
-
{ prop: 'buyer', width: 160 },
|
|
1032
|
-
{ prop: 'total', width: 120, type: 'currency(USD)' },
|
|
1062
|
+
{ prop: 'buyer', name: 'Buyer', width: 160 },
|
|
1063
|
+
{ prop: 'total', name: 'Total', width: 120, type: 'currency(USD)' },
|
|
1033
1064
|
],
|
|
1034
1065
|
rowId: (row) => row.id,
|
|
1035
|
-
rowDetail:
|
|
1036
|
-
table(
|
|
1037
|
-
{ class: 'invoice-lines' },
|
|
1038
|
-
tr(th('Item'), th('Qty'), th('Price')),
|
|
1039
|
-
...row.lines.map((line) =>
|
|
1040
|
-
tr(td(line.item), td(String(line.qty)), td(line.price.toFixed(2)))
|
|
1041
|
-
)
|
|
1042
|
-
),
|
|
1066
|
+
rowDetail: invoiceDetail,
|
|
1043
1067
|
})
|
|
1044
1068
|
invoiceTable.expandedRowIds = ['INV-1001']
|
|
1045
1069
|
|
|
@@ -1054,12 +1078,13 @@ invoiceTable.addEventListener('rowcollapse', (event) => {
|
|
|
1054
1078
|
preview.append(invoiceTable, log)
|
|
1055
1079
|
```
|
|
1056
1080
|
```css
|
|
1057
|
-
.preview .invoice-
|
|
1058
|
-
|
|
1081
|
+
.preview .invoice-detail {
|
|
1082
|
+
max-width: 480px;
|
|
1059
1083
|
}
|
|
1060
|
-
.preview .invoice-
|
|
1061
|
-
|
|
1062
|
-
|
|
1084
|
+
.preview .invoice-total {
|
|
1085
|
+
display: flex;
|
|
1086
|
+
justify-content: space-between;
|
|
1087
|
+
padding: 8px 0 0;
|
|
1063
1088
|
}
|
|
1064
1089
|
.preview .detail-log {
|
|
1065
1090
|
padding: 8px 0;
|
|
@@ -1088,7 +1113,8 @@ test('a row expands to its detail and collapses again', async () => {
|
|
|
1088
1113
|
const toggle = table.getCells(row)[0].querySelector('.row-expander')
|
|
1089
1114
|
expect(toggle.getAttribute('aria-expanded')).toBe('true')
|
|
1090
1115
|
const detail = document.getElementById(toggle.getAttribute('aria-controls'))
|
|
1091
|
-
expect(detail.textContent).toContain('
|
|
1116
|
+
expect(detail.textContent).toContain('billed to Umbrella')
|
|
1117
|
+
expect(detail.querySelector('tosi-table').array).toBe(row.lines)
|
|
1092
1118
|
|
|
1093
1119
|
toggle.click()
|
|
1094
1120
|
expect(table.isRowExpanded(row)).toBe(false)
|