tosijs-ui 1.16.12 → 1.16.13

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.16.13
4
+
5
+ Documentation only; no library code changed.
6
+
7
+ - **Better examples for the two 1.16.12 features**, in the package's doc comments and
8
+ `llms.txt` as well as on the site. The table's row detail example now opens each invoice to
9
+ a nested `<tosi-table>` of its line items with a totals line. The curated form example
10
+ starts from a valid value and has **View only** and **Every field** toggles; the
11
+ hidden-error case is a separate, smaller example.
12
+
3
13
  ## 1.16.12
4
14
 
5
15
  Two additions for task-focused screens: a table row can open to show a detail element, and a
@@ -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, table, tr, td, th, b } = elements
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
- item: ['Widget', 'Gasket', 'Sprocket', 'Flange'][(i + n) % 4],
1015
- qty: 1 + ((i + n) % 5),
1016
- price: 12.5 * (1 + ((i * 7 + n) % 9)),
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, l) => sum + l.qty * l.price, 0)
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: '320px' },
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: (row) =>
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-lines {
1058
- border-collapse: collapse;
1081
+ .preview .invoice-detail {
1082
+ max-width: 480px;
1059
1083
  }
1060
- .preview .invoice-lines :is(td, th) {
1061
- padding: 2px 16px 2px 0;
1062
- text-align: left;
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('Qty')
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)