tosijs-ui 1.7.0 → 1.7.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/CHANGELOG.md +56 -0
- package/dist/babylon-3d.d.ts +1 -1
- package/dist/babylon-3d.js +1 -1
- package/dist/code-editor.d.ts +1 -1
- package/dist/code-editor.js +1 -1
- package/dist/data-table.d.ts +3 -1
- package/dist/data-table.js +97 -5
- package/dist/doc-browser.js +6 -1
- package/dist/doc-system/doc-system-styles.js +11 -0
- package/dist/doc-system/site/dev-server.js +11 -1
- package/dist/hydrate/hydrate.js +77 -77
- package/dist/hydrate/hydrate.js.map +19 -18
- package/dist/iife.js +70 -70
- package/dist/iife.js.map +19 -18
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/live-example/component.js +8 -0
- package/dist/live-theme.js +98 -0
- package/dist/side-nav.d.ts +1 -1
- package/dist/side-nav.js +4 -4
- package/dist/size-break.d.ts +1 -1
- package/dist/size-break.js +3 -3
- package/dist/tab-selector.d.ts +11 -2
- package/dist/tab-selector.js +19 -6
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/value-renderer.d.ts +26 -0
- package/dist/value-renderer.js +209 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/llms.txt +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.7.1
|
|
4
|
+
|
|
5
|
+
- **Fix: components looked wrong in the doc site's dark mode** (e.g. `<tosi-table>` stayed
|
|
6
|
+
white). The doc-system theme drives the legacy `--background`/`--text-color` family and never
|
|
7
|
+
set the `--tosi-*` component palette, so components fell back to their baked-in light defaults
|
|
8
|
+
(`var(--tosi-bg, #fff)`). The doc-system now bridges `--tosi-accent`/`--tosi-bg`/`--tosi-text`/
|
|
9
|
+
`--tosi-bg-inset` onto its own colors **as references**, so every `--tosi-*` component follows
|
|
10
|
+
the site theme automatically — including dark mode (the referenced vars flip via
|
|
11
|
+
`invertLuminance`). The data-table pinned-row example now uses `var(--tosi-table-bg)` instead of
|
|
12
|
+
a hardwired `#eee`.
|
|
13
|
+
- **Data-table `type` example** demonstrating the new column types (currency, number, percent,
|
|
14
|
+
fixed, bytes, boolean) added to the docs.
|
|
15
|
+
|
|
16
|
+
- **Fix: "edit page source" showed HTML instead of source in a dev server without
|
|
17
|
+
`editableSources`.** The `/__docstore/source` endpoint was only routed when
|
|
18
|
+
`editableSources` was on; otherwise the request fell through to the SPA `index.html`
|
|
19
|
+
fallback and returned the rendered page at status 200 — so the client loaded HTML *as* the
|
|
20
|
+
source (and save read HTML). The endpoint is now handled unconditionally and answers a clean
|
|
21
|
+
`501` when editing is disabled, so `loadSource` falls back to the GitHub raw source (read-only
|
|
22
|
+
editing, matching the deployed site). Belt-and-suspenders: the client also rejects any
|
|
23
|
+
`text/html` response from that endpoint (guards SPA-rewrite hosts too). Documented the option
|
|
24
|
+
more fully in `doc-site-system.md`.
|
|
25
|
+
- **Local example save now gives feedback.** "Save changes (local)" writes a per-browser
|
|
26
|
+
scratchpad (not the file) — it used to do so silently, reading as a no-op. It now posts a
|
|
27
|
+
toast (`postNotification`): *"Saved to this browser only — use 'Save to source' to write the
|
|
28
|
+
file."*
|
|
29
|
+
|
|
30
|
+
- **`valueRenderer(type)` + declarative `<tosi-table>` column `type`.** A new exported helper
|
|
31
|
+
turns a compact type string into a reusable, locale-aware renderer with a sensible default
|
|
32
|
+
alignment: `number`, `currency`/`currency(USD)`, `fixed`/`fixed(n)` (default 2),
|
|
33
|
+
`percent`/`percent(n)` (of a fraction; default 0), `sci`, `eng`, `bytes`/`bytes(iec)` (SI ÷1000
|
|
34
|
+
or IEC ÷1024 units, right-aligned), and `boolean`/`boolean(t)`/`boolean(t,f)` (icons via the
|
|
35
|
+
`icons` proxy, centered; default `checkSquare`/`square`). Numeric cells also get a
|
|
36
|
+
`-negative` / `-zero` **state class** by value sign, so you get red negatives (etc.) from one
|
|
37
|
+
CSS rule — no custom cell renderer. Data-table columns take a `type`
|
|
38
|
+
(`ValueRendererType`) and format + align automatically — no hand-rolled `dataCell`; an explicit
|
|
39
|
+
`align`/`dataCell` still wins. Formatting follows `setLocale()`. Verified end-to-end (unit +
|
|
40
|
+
browser).
|
|
41
|
+
|
|
42
|
+
- **Deprecation cleanup: `on<Event>` component callbacks → `handle<Event>`.** tosijs reserves the
|
|
43
|
+
`on<Event>` prefix for elements-factory event-handler sugar and now warns when a component
|
|
44
|
+
*defines* such a property. Renamed the internal ones: `onResize` → `handleResize` (`size-break`,
|
|
45
|
+
`side-nav`, `code-editor`, `babylon-3d`, `tab-selector`) and `onScrollEnd` → `handleScrollEnd`
|
|
46
|
+
(`data-table`). Verified: those pages now load with zero `on<Event>` deprecation warnings.
|
|
47
|
+
(`<tosi-tabs>`'s public `onCloseTab` still uses the old name — a breaking rename deferred to a
|
|
48
|
+
deprecation-alias pass; and the `tosiValue()`/`tosiPath()` accessor deprecation is a separate,
|
|
49
|
+
larger cleanup — both tracked.)
|
|
50
|
+
|
|
51
|
+
- **CSS canary** — an inline doc-test on the `live-theme` page that smoke-tests the whole
|
|
52
|
+
styling chain in a real browser (`StyleSheet()` → the `vars` proxy → scaled-var `calc()` →
|
|
53
|
+
`createTheme`/`applyTheme` → cascade → `getComputedStyle`), plus a theme color-change
|
|
54
|
+
propagating to computed style, dark-mode luminance inversion, and `Color.inverseLuminance`.
|
|
55
|
+
Each link is silent when it breaks (happy-dom can't resolve `var()`/the cascade), so a red
|
|
56
|
+
now means a system-level CSS break, not a component quirk. Runs in the `doc-tests.pw.ts` CI
|
|
57
|
+
gate.
|
|
58
|
+
|
|
3
59
|
## 1.7.0
|
|
4
60
|
|
|
5
61
|
> ### ⚠️ BREAKING CHANGE — `<tosi-code>` moved from ACE to CodeMirror 6
|
package/dist/babylon-3d.d.ts
CHANGED
|
@@ -51,7 +51,7 @@ export declare class B3d extends WebComponent {
|
|
|
51
51
|
sceneCreated: B3dCallback;
|
|
52
52
|
update: B3dCallback;
|
|
53
53
|
private _update;
|
|
54
|
-
|
|
54
|
+
handleResize(): void;
|
|
55
55
|
loadScene: (path: string, file: string, processCallback?: MeshProcessCallback) => Promise<void>;
|
|
56
56
|
loadUI: (options: B3dUIOptions) => Promise<any>;
|
|
57
57
|
connectedCallback(): void;
|
package/dist/babylon-3d.js
CHANGED
package/dist/code-editor.d.ts
CHANGED
package/dist/code-editor.js
CHANGED
package/dist/data-table.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Component as WebComponent, ElementCreator } from 'tosijs';
|
|
2
2
|
import { SortCallback } from './make-sorter';
|
|
3
|
+
import { ValueRendererType } from './value-renderer';
|
|
3
4
|
export interface ColumnOptions {
|
|
4
5
|
name?: string;
|
|
5
6
|
prop: string;
|
|
6
7
|
width: number;
|
|
7
8
|
visible?: boolean;
|
|
8
9
|
align?: string;
|
|
10
|
+
type?: ValueRendererType;
|
|
9
11
|
pinned?: 'left' | 'right';
|
|
10
12
|
sort?: false | 'ascending' | 'descending';
|
|
11
13
|
headerCell?: (options: ColumnOptions) => HTMLElement;
|
|
@@ -201,7 +203,7 @@ export declare class TosiTable extends WebComponent {
|
|
|
201
203
|
private updateSelection;
|
|
202
204
|
private findCell;
|
|
203
205
|
private _pendingFocus;
|
|
204
|
-
private
|
|
206
|
+
private handleScrollEnd;
|
|
205
207
|
private focusCell;
|
|
206
208
|
private handleKeyNav;
|
|
207
209
|
connectedCallback(): void;
|
package/dist/data-table.js
CHANGED
|
@@ -194,6 +194,7 @@ export interface ColumnOptions {
|
|
|
194
194
|
width: number
|
|
195
195
|
visible?: boolean
|
|
196
196
|
align?: string
|
|
197
|
+
type?: string // valueRenderer type: 'currency(USD)', 'fixed(2)', 'bytes', 'boolean(check,x)', …
|
|
197
198
|
pinned?: 'left' | 'right'
|
|
198
199
|
sort?: false | 'ascending' | 'descending'
|
|
199
200
|
headerCell?: (options: ColumnOptions) => HTMLElement
|
|
@@ -201,6 +202,59 @@ export interface ColumnOptions {
|
|
|
201
202
|
}
|
|
202
203
|
```
|
|
203
204
|
|
|
205
|
+
## Column value types
|
|
206
|
+
|
|
207
|
+
Give a column a `type` and it's formatted (and aligned) automatically — no hand-rolled
|
|
208
|
+
`dataCell`. The `type` is a [`valueRenderer`](value-renderer) string:
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
[
|
|
212
|
+
{ prop: 'name', width: 160 },
|
|
213
|
+
{ prop: 'price', width: 100, type: 'currency(USD)' }, // localized $, right-aligned
|
|
214
|
+
{ prop: 'weight', width: 100, type: 'fixed(3)' }, // 3 decimals, right-aligned
|
|
215
|
+
{ prop: 'size', width: 100, type: 'bytes' }, // 1.5 MB, right-aligned
|
|
216
|
+
{ prop: 'active', width: 60, type: 'boolean' }, // checkSquare / square, centered
|
|
217
|
+
]
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Numeric types (`number`, `currency`, `fixed`, `percent`, `sci`, `eng`, `bytes`) right-align
|
|
221
|
+
by default; `boolean` centers and renders icons. An explicit `align` — or a `dataCell` —
|
|
222
|
+
always wins. Formatting follows the app locale (`setLocale()`). Numeric cells also get a
|
|
223
|
+
`-negative` or `-zero` state class by value sign, so the red "Change" values above come from
|
|
224
|
+
one CSS rule (`.-negative { color: #e44 }`), no cell renderer.
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
import { tosiTable } from 'tosijs-ui'
|
|
228
|
+
|
|
229
|
+
const rows = [
|
|
230
|
+
{ item: 'Alpha Widget', price: 12.5, qty: 1240, change: 3.25, rate: 0.075, mass: 1.23456, size: 1_536_000, active: true, flagged: false },
|
|
231
|
+
{ item: 'Beta Gadget', price: 4.99, qty: 42, change: -1.5, rate: 0.2, mass: 0.5, size: 512, active: false, flagged: true },
|
|
232
|
+
{ item: 'Gamma Sprocket', price: 199, qty: 8, change: 0, rate: 1.5, mass: 12.005, size: 2_500_000_000, active: true, flagged: true },
|
|
233
|
+
{ item: 'Delta Cog', price: 0.75, qty: 99999, change: -0.12, rate: 0.004, mass: 0.001, size: 48_200, active: false, flagged: false },
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
const table = tosiTable({ style: { display: 'block', height: '240px' } })
|
|
237
|
+
table.value = {
|
|
238
|
+
array: rows,
|
|
239
|
+
columns: [
|
|
240
|
+
{ prop: 'item', name: 'Item', width: 150 },
|
|
241
|
+
{ prop: 'price', name: 'Price', width: 110, type: 'currency(USD)' },
|
|
242
|
+
{ prop: 'change', name: 'Change', width: 100, type: 'currency(USD)' }, // red negatives via CSS
|
|
243
|
+
{ prop: 'qty', name: 'Qty', width: 90, type: 'number' },
|
|
244
|
+
{ prop: 'rate', name: 'Rate', width: 80, type: 'percent(1)' },
|
|
245
|
+
{ prop: 'mass', name: 'Mass', width: 90, type: 'fixed(2)' },
|
|
246
|
+
{ prop: 'size', name: 'Size', width: 100, type: 'bytes' },
|
|
247
|
+
{ prop: 'active', name: 'Active', width: 80, type: 'boolean' },
|
|
248
|
+
{ prop: 'flagged', name: 'Flag', width: 80, type: 'boolean(check, x)' },
|
|
249
|
+
],
|
|
250
|
+
}
|
|
251
|
+
preview.append(table)
|
|
252
|
+
```
|
|
253
|
+
```css
|
|
254
|
+
.preview .-negative { color: #e44; }
|
|
255
|
+
.preview .-zero { opacity: 0.45; }
|
|
256
|
+
```
|
|
257
|
+
|
|
204
258
|
## Pinned Columns and Rows
|
|
205
259
|
|
|
206
260
|
Set `pinned: 'left'` or `pinned: 'right'` on individual columns to pin
|
|
@@ -314,11 +368,11 @@ preview.append(table)
|
|
|
314
368
|
width: 100%;
|
|
315
369
|
}
|
|
316
370
|
.preview tosi-table .pinned-bottom {
|
|
317
|
-
background: #
|
|
371
|
+
background: var(--tosi-table-bg, var(--tosi-bg, #fff));
|
|
318
372
|
font-weight: bold;
|
|
319
373
|
}
|
|
320
374
|
.preview .row-pinned .td {
|
|
321
|
-
background: #
|
|
375
|
+
background: var(--tosi-table-bg, var(--tosi-bg, #fff));
|
|
322
376
|
}
|
|
323
377
|
.preview .num-cell {
|
|
324
378
|
font-variant-numeric: tabular-nums;
|
|
@@ -513,6 +567,7 @@ As well as any column names you want localized.
|
|
|
513
567
|
import { Component as WebComponent, elements, vars, varDefault, tosiValue, getListItem, getListBinding, tosi, } from 'tosijs';
|
|
514
568
|
import { trackDrag } from './track-drag';
|
|
515
569
|
import { icons } from './icons';
|
|
570
|
+
import { valueRenderer } from './value-renderer';
|
|
516
571
|
import { popMenu } from './menu';
|
|
517
572
|
import * as dragAndDrop from './drag-and-drop';
|
|
518
573
|
import { tosiLocalized, localize } from './localize';
|
|
@@ -545,6 +600,20 @@ function defaultWidth(array, prop, charWidth) {
|
|
|
545
600
|
}
|
|
546
601
|
const { div, span, button } = elements;
|
|
547
602
|
const passThru = (array) => array;
|
|
603
|
+
// One ValueRenderer per typed column, cached: `Intl.*Format` construction is the
|
|
604
|
+
// expensive part and a column's renderer is stable for its lifetime. Returns null
|
|
605
|
+
// when the column has no `type` or supplies its own `dataCell` (which always wins).
|
|
606
|
+
const columnRenderers = new WeakMap();
|
|
607
|
+
function columnRenderer(col) {
|
|
608
|
+
if (!col.type || col.dataCell)
|
|
609
|
+
return null;
|
|
610
|
+
let renderer = columnRenderers.get(col);
|
|
611
|
+
if (!renderer) {
|
|
612
|
+
renderer = valueRenderer(col.type);
|
|
613
|
+
columnRenderers.set(col, renderer);
|
|
614
|
+
}
|
|
615
|
+
return renderer;
|
|
616
|
+
}
|
|
548
617
|
export class TosiTable extends WebComponent {
|
|
549
618
|
static preferredTagName = 'tosi-table';
|
|
550
619
|
// Layout: a single .scroll-area inside :host is the only scroll container
|
|
@@ -968,7 +1037,9 @@ export class TosiTable extends WebComponent {
|
|
|
968
1037
|
// position: sticky lives in `.col-pinned` (added by cellClasses), so only
|
|
969
1038
|
// the per-cell offsets need to be set inline here.
|
|
970
1039
|
const style = {
|
|
971
|
-
|
|
1040
|
+
// Explicit align wins; else the column type's default (numerics right,
|
|
1041
|
+
// booleans center); else left.
|
|
1042
|
+
justifyContent: col.align || columnRenderer(col)?.align || 'left',
|
|
972
1043
|
...extra,
|
|
973
1044
|
};
|
|
974
1045
|
if (si.left != null)
|
|
@@ -993,6 +1064,27 @@ export class TosiTable extends WebComponent {
|
|
|
993
1064
|
this.applyGridCellAttrs(cell, colIndex, si, style);
|
|
994
1065
|
return cell;
|
|
995
1066
|
}
|
|
1067
|
+
// A `type` column formats through its cached ValueRenderer. The binding's toDOM
|
|
1068
|
+
// runs per stamped row, so it stays locale-reactive and works for icon cells
|
|
1069
|
+
// (which replace children) as well as text.
|
|
1070
|
+
const renderer = columnRenderer(col);
|
|
1071
|
+
if (renderer) {
|
|
1072
|
+
return span({
|
|
1073
|
+
class: this.cellClasses('td', si),
|
|
1074
|
+
role: 'gridcell',
|
|
1075
|
+
tabindex: -1,
|
|
1076
|
+
ariaColindex: String(colIndex + 1),
|
|
1077
|
+
style,
|
|
1078
|
+
bind: {
|
|
1079
|
+
value: item[col.prop],
|
|
1080
|
+
binding: {
|
|
1081
|
+
toDOM(el, val) {
|
|
1082
|
+
renderer.toDOM(el, val);
|
|
1083
|
+
},
|
|
1084
|
+
},
|
|
1085
|
+
},
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
996
1088
|
return span({
|
|
997
1089
|
class: this.cellClasses('td', si),
|
|
998
1090
|
role: 'gridcell',
|
|
@@ -1287,7 +1379,7 @@ export class TosiTable extends WebComponent {
|
|
|
1287
1379
|
return cells?.[colIndex] ?? null;
|
|
1288
1380
|
}
|
|
1289
1381
|
_pendingFocus = null;
|
|
1290
|
-
|
|
1382
|
+
handleScrollEnd = () => {
|
|
1291
1383
|
if (!this._pendingFocus)
|
|
1292
1384
|
return;
|
|
1293
1385
|
const { row, col } = this._pendingFocus;
|
|
@@ -1659,7 +1751,7 @@ export class TosiTable extends WebComponent {
|
|
|
1659
1751
|
...visibleBinding,
|
|
1660
1752
|
this._tbodyBottom,
|
|
1661
1753
|
].filter(Boolean));
|
|
1662
|
-
this._scrollArea.addEventListener('scrollend', this.
|
|
1754
|
+
this._scrollArea.addEventListener('scrollend', this.handleScrollEnd);
|
|
1663
1755
|
this.append(this._scrollArea);
|
|
1664
1756
|
this.observePinnedRowMutations();
|
|
1665
1757
|
this.tagPinnedRows();
|
package/dist/doc-browser.js
CHANGED
|
@@ -726,7 +726,12 @@ export function createDocBrowser(options) {
|
|
|
726
726
|
const loadSource = async (p) => {
|
|
727
727
|
try {
|
|
728
728
|
const r = await fetch(`/__docstore/source?file=${encodeURIComponent(p)}`);
|
|
729
|
-
|
|
729
|
+
// Accept only a genuine source response. A misconfigured dev server (no
|
|
730
|
+
// editableSources) or a SPA-rewrite host answers an unknown path with
|
|
731
|
+
// index.html at status 200 — taking that would load the PAGE as the source.
|
|
732
|
+
// Reject HTML and fall through to the GitHub raw source instead.
|
|
733
|
+
const contentType = r.headers.get('content-type') || '';
|
|
734
|
+
if (r.ok && !/text\/html/i.test(contentType))
|
|
730
735
|
return await r.text();
|
|
731
736
|
}
|
|
732
737
|
catch {
|
|
@@ -62,6 +62,17 @@ export function docSystemStyleSpec(theme = {}) {
|
|
|
62
62
|
_fontSize: '16px',
|
|
63
63
|
_codeFontSize: '14px',
|
|
64
64
|
...colors,
|
|
65
|
+
// Bridge the tosijs component palette (`--tosi-*`) onto the doc-system's color
|
|
66
|
+
// family. Defined as REFERENCES, so a component reading `var(--tosi-bg)` follows
|
|
67
|
+
// the site theme automatically — including dark mode, where `invertLuminance()`
|
|
68
|
+
// flips the referenced `--background`/`--text-color`/… in `.darkmode`. Without
|
|
69
|
+
// this the doc-system never set `--tosi-*`, so components fell back to their
|
|
70
|
+
// baked-in light defaults (e.g. `var(--tosi-bg, #fff)` → white <tosi-table> in
|
|
71
|
+
// dark mode). Colors only — component metrics keep their own defaults.
|
|
72
|
+
_tosiAccent: vars.brandColor,
|
|
73
|
+
_tosiBg: vars.background,
|
|
74
|
+
_tosiText: vars.textColor,
|
|
75
|
+
_tosiBgInset: vars.insetBg,
|
|
65
76
|
_spacing: '10px',
|
|
66
77
|
_lineHeight: 'calc(var(--font-size) * 1.6)',
|
|
67
78
|
_h1Scale: '2',
|
|
@@ -581,11 +581,21 @@ export async function devServer(config, opts = {}) {
|
|
|
581
581
|
// Source read/write for in-browser "edit page source" (opt-in, dev only).
|
|
582
582
|
// A write lands in the repo file; the chokidar watcher then rebuilds and
|
|
583
583
|
// the page refreshes — the build itself is the preview.
|
|
584
|
-
if (
|
|
584
|
+
if (reqPath === '/__docstore/source') {
|
|
585
|
+
// Handle this endpoint UNCONDITIONALLY so it never falls through to the SPA
|
|
586
|
+
// index.html fallback below. A 200-with-HTML there is silently corrupting:
|
|
587
|
+
// the client loads the PAGE as the "source" (edit-page-source shows HTML;
|
|
588
|
+
// save-to-source reads HTML). When editing isn't enabled, answer with a clean
|
|
589
|
+
// status so `loadSource` falls back to the GitHub raw source (read-only), which
|
|
590
|
+
// is what the deployed static site already does.
|
|
591
|
+
if (!config.editableSources) {
|
|
592
|
+
return new Response('editableSources is not enabled in this doc-site config (set editableSources: true to edit/save source in dev)', { status: 501, headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
|
|
593
|
+
}
|
|
585
594
|
if (request.method === 'GET')
|
|
586
595
|
return handleReadSource(request);
|
|
587
596
|
if (request.method === 'POST')
|
|
588
597
|
return handleWriteSource(request);
|
|
598
|
+
return new Response('method not allowed', { status: 405 });
|
|
589
599
|
}
|
|
590
600
|
if (reqPath === '/')
|
|
591
601
|
reqPath = '/index.html';
|