tosijs-ui 1.9.0 → 1.9.2

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.
Files changed (100) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/babylon-3d.js +2 -2
  3. package/dist/bodymovin-player.js +1 -1
  4. package/dist/carousel.js +1 -1
  5. package/dist/code-editor.d.ts +2 -2
  6. package/dist/code-editor.js +3 -3
  7. package/dist/data-table.d.ts +2 -2
  8. package/dist/data-table.js +10 -10
  9. package/dist/dialog.js +1 -1
  10. package/dist/doc-browser.d.ts +1 -1
  11. package/dist/doc-browser.js +37 -15
  12. package/dist/doc-system/book-html.d.ts +1 -1
  13. package/dist/doc-system/book-html.js +3 -3
  14. package/dist/doc-system/book-target.js +1 -1
  15. package/dist/doc-system/css-var-editor.d.ts +1 -1
  16. package/dist/doc-system/css-var-editor.js +1 -1
  17. package/dist/doc-system/doc-system-styles.js +25 -4
  18. package/dist/doc-system/doc-system.d.ts +1 -1
  19. package/dist/doc-system/doc-system.js +8 -8
  20. package/dist/doc-system/nav-tree.js +1 -1
  21. package/dist/doc-system/site/check-examples-cli.js +1 -1
  22. package/dist/doc-system/site/check-examples.d.ts +2 -2
  23. package/dist/doc-system/site/check-examples.js +1 -1
  24. package/dist/doc-system/site/dev-server.d.ts +2 -2
  25. package/dist/doc-system/site/dev-server.js +53 -68
  26. package/dist/doc-system/site/docs.js +3 -3
  27. package/dist/doc-system/site/epub-cli.js +1 -1
  28. package/dist/doc-system/site/epub.d.ts +2 -2
  29. package/dist/doc-system/site/epub.js +6 -6
  30. package/dist/doc-system/site/generate-css.d.ts +2 -2
  31. package/dist/doc-system/site/generate-css.js +2 -2
  32. package/dist/doc-system/site/generate-site.d.ts +3 -3
  33. package/dist/doc-system/site/generate-site.js +4 -4
  34. package/dist/doc-system/site/index.d.ts +16 -16
  35. package/dist/doc-system/site/index.js +9 -9
  36. package/dist/doc-system/site/make-llms-txt.js +1 -1
  37. package/dist/doc-system/site/orchestrator.d.ts +1 -1
  38. package/dist/doc-system/site/orchestrator.js +12 -12
  39. package/dist/doc-system/site/sections.js +2 -2
  40. package/dist/doc-system/site/site-config.d.ts +6 -6
  41. package/dist/editable-rect.js +2 -2
  42. package/dist/filter-builder.d.ts +1 -1
  43. package/dist/filter-builder.js +2 -2
  44. package/dist/float.js +1 -1
  45. package/dist/form.js +1 -1
  46. package/dist/header.js +2 -2
  47. package/dist/icon-svg.js +1 -1
  48. package/dist/icons/data/index.d.ts +313 -313
  49. package/dist/icons/data/index.js +313 -313
  50. package/dist/icons.d.ts +2 -2
  51. package/dist/icons.js +2 -2
  52. package/dist/iife.js +82 -82
  53. package/dist/iife.js.map +47 -47
  54. package/dist/index-iife.js +1 -1
  55. package/dist/index.d.ts +49 -49
  56. package/dist/index.js +49 -49
  57. package/dist/live-example/code-transform.d.ts +1 -1
  58. package/dist/live-example/component.d.ts +1 -1
  59. package/dist/live-example/component.js +14 -14
  60. package/dist/live-example/execution.d.ts +1 -1
  61. package/dist/live-example/execution.js +1 -1
  62. package/dist/live-example/index.d.ts +8 -8
  63. package/dist/live-example/index.js +6 -6
  64. package/dist/live-example/insert-examples.d.ts +2 -2
  65. package/dist/live-example/remote-sync.d.ts +1 -1
  66. package/dist/live-example/test-harness.d.ts +1 -1
  67. package/dist/live-example/test-harness.js +1 -1
  68. package/dist/live-example/types.d.ts +2 -2
  69. package/dist/live-example.d.ts +1 -1
  70. package/dist/live-example.js +1 -1
  71. package/dist/live-theme.js +5 -5
  72. package/dist/localize.d.ts +1 -1
  73. package/dist/localize.js +2 -2
  74. package/dist/mapbox.js +1 -1
  75. package/dist/menu.d.ts +2 -2
  76. package/dist/menu.js +5 -5
  77. package/dist/month.d.ts +2 -2
  78. package/dist/month.js +3 -3
  79. package/dist/notifications.js +2 -2
  80. package/dist/pocket-bar.d.ts +1 -1
  81. package/dist/pocket-bar.js +2 -2
  82. package/dist/pop-float.d.ts +1 -1
  83. package/dist/pop-float.js +2 -2
  84. package/dist/rating.js +1 -1
  85. package/dist/rich-text.d.ts +1 -1
  86. package/dist/rich-text.js +3 -3
  87. package/dist/segmented.js +2 -2
  88. package/dist/select.d.ts +1 -1
  89. package/dist/select.js +3 -3
  90. package/dist/sizer.js +2 -2
  91. package/dist/tab-selector.js +2 -2
  92. package/dist/tag-list.js +2 -2
  93. package/dist/theme.js +4 -4
  94. package/dist/tooltip.js +2 -2
  95. package/dist/tsconfig.tsbuildinfo +1 -1
  96. package/dist/value-renderer.js +3 -3
  97. package/dist/version.d.ts +1 -1
  98. package/dist/version.js +1 -1
  99. package/llms.txt +1 -1
  100. package/package.json +4 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,88 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.2
4
+
5
+ **Accessibility: every default color pair now meets WCAG AA.** Found by running
6
+ `hj map` (haltija 1.11) over the doc site, which reports a measured contrast ratio per
7
+ node — none of these were visible as wrong to the eye.
8
+
9
+ | pair | was | now |
10
+ | --- | --- | --- |
11
+ | test widget, running | white on `#fa0` — **1.9:1** | `#2b1a00` on `#fa0` — 8.8:1 |
12
+ | test widget, passed | white on `#0a0` — **3.1:1** | white on `#008a00` — 4.5:1 |
13
+ | `--tosi-accent` as text | `#EE257B` — **4.05:1** on white, 4.3:1 on the page | `#d92270` — 4.6:1 |
14
+ | `--tosi-accent` as a fill | white on `#EE257B` — **4.05:1** | white on `#d92270` — 4.8:1 |
15
+
16
+ **The brand pink is 9% darker** (`#EE257B` → `#d92270`). It is imperceptible side by side
17
+ and it was the only value that clears AA in *both* directions — as text on the page, and
18
+ as a fill carrying white text. Override `--tosi-accent` if you want the original.
19
+
20
+ Two more, found by sweeping wider — both in **example code we publish**, which matters
21
+ more than a component default because people copy it: the `.-negative { color: #e44 }` we
22
+ document for negative numbers in tables sat at **3.63:1** (now `#d32f2f`, 4.77:1), and
23
+ `#007AFF` — the accent in every theming example in our docs — was **4.02:1** under white
24
+ text (now `#0064d2`, 5.59:1).
25
+
26
+ Also fixed: the doc-site brand bar's text was a hand-tuned warm off-white
27
+ (`brandColor.rotate(30).brighten(0.9)` → `#fbeae9`) sitting at **4.09:1** on the brand —
28
+ under AA for the normal-size nav links in it. Every brighten value short of pure white
29
+ also misses, so it now uses `contrasting()`, which picks the readable extreme for whatever
30
+ the brand currently is and cannot drift when the brand moves. Three stale `#EE257B` /
31
+ `#007AFF` fallbacks were still live in `header.ts` and `doc-browser.ts` and now match.
32
+
33
+ Verified across 8 pages in both themes on haltija 1.11.2: **0 failures, 0 uncertain**.
34
+
35
+ **The browser-test lane now runs its own private haltija.** It used to reuse any running
36
+ instance and otherwise spawn with `-f`, which reclaims haltija's shared default port and
37
+ kills whatever held it. Both halves were wrong: adopting meant inheriting the *desktop
38
+ app's* window, whose visibility depends on whatever else is on screen — and `hj` rightly
39
+ refuses to drive a hidden tab, since a backgrounded tab throttles `requestAnimationFrame`
40
+ and would produce plausible-but-wrong results. The lane failed roughly two runs in three
41
+ with no programmatic way out. It now takes an isolated instance on an ephemeral port:
42
+ **4/4 runs green**, and a concurrent haltija belonging to someone else survives untouched
43
+ (verified both). Closes #18 and #21.
44
+
45
+ The test widget's text color is now **paired** with its background rather than hardcoded
46
+ to white. Amber is a genuinely light color: darkening it enough for white text turns it
47
+ brown and stops reading as "in progress", so it keeps its hue and takes dark text, which
48
+ is the conventional warning-badge treatment. New `--tosi-test-text-color-{pass,fail,running}`
49
+ variables if you theme these.
50
+
51
+ In dark mode the brand color is **brightened** rather than reused: `invertLuminance` flips
52
+ the neutrals but leaves a saturated hue roughly where it was, so a pink dark enough for a
53
+ near-white page landed at 4.4:1 on a near-black one. The hue is the brand; the luminance
54
+ belongs to whatever it sits on.
55
+
56
+ ## 1.9.1
57
+
58
+ **`tosijs-ui` did not import under Node.** Shipped `dist/` used extensionless relative
59
+ imports (`from './site-config'`), which bun resolves and Node ESM does not — so a Node
60
+ consumer got `Cannot find module` on entry points that had nothing to do with bun. Every
61
+ entry point is affected, and this goes back well before 1.8.0.
62
+
63
+ Everything shipped now uses explicit `.js` specifiers, which Node requires and every
64
+ bundler accepts. **If you are on Node, upgrade; 1.9.0 and earlier will not resolve.**
65
+
66
+ Two runtime requirements are unchanged, and are now documented rather than implied — they
67
+ are honest constraints, not bugs, but the failure messages named symptoms rather than
68
+ causes:
69
+
70
+ | entry point | runtime |
71
+ | --- | --- |
72
+ | `tosijs-ui/site` | **bun** — it shells out, builds and spawns |
73
+ | `tosijs-ui`, `tosijs-ui/<component>` | a **browser** or a bundler targeting one |
74
+ | `tosijs-ui/icon-svg` | anything — deliberately DOM-free |
75
+
76
+ `engines` now declares bun, and `doc-site-system.md` has a "Runtimes — what runs where"
77
+ section.
78
+
79
+ **Why four test lanes missed it:** all four run under bun. `test-consumer` packs the real
80
+ tarball, installs it and builds from a foreign cwd — but with bun, so it proved the
81
+ package works for people exactly like us. It now imports every entry point through **Node**
82
+ and asserts the absence of module-resolution errors specifically, separating "packaging is
83
+ broken" from "this needs a DOM / needs bun". Verified against the published 1.9.0: all
84
+ three checks fail on it.
85
+
3
86
  ## 1.9.0
4
87
 
5
88
  Consumer repairs, remote access, and **authoring: many books from one corpus**.
@@ -207,8 +207,8 @@ be used to load `.glb` files. Setting `src` calls this for you on connect.
207
207
  */
208
208
  /*{ "parent": "Components" }*/
209
209
  import { Component as WebComponent, elements } from 'tosijs';
210
- import { scriptTag } from './via-tag';
211
- import { icons, svg2DataUrl } from './icons';
210
+ import { scriptTag } from './via-tag.js';
211
+ import { icons, svg2DataUrl } from './icons.js';
212
212
  const noop = () => {
213
213
  /* do not care */
214
214
  };
@@ -103,7 +103,7 @@ Also see the [documentation for advanced interactions](https://lottiefiles.githu
103
103
  */
104
104
  /*{ "parent": "Components" }*/
105
105
  import { Component as WebComponent } from 'tosijs';
106
- import { scriptTag } from './via-tag';
106
+ import { scriptTag } from './via-tag.js';
107
107
  export class BodymovinPlayer extends WebComponent {
108
108
  static preferredTagName = 'tosi-lottie';
109
109
  static initAttributes = {
package/dist/carousel.js CHANGED
@@ -57,7 +57,7 @@ This is a minimalist carousel component that supports the usual stuff.
57
57
  */
58
58
  /*{ "parent": "Components" }*/
59
59
  import { Component as WebComponent, elements, vars, } from 'tosijs';
60
- import { icons } from './icons';
60
+ import { icons } from './icons.js';
61
61
  const { button, slot, div } = elements;
62
62
  export class TosiCarousel extends WebComponent {
63
63
  static preferredTagName = 'tosi-carousel';
@@ -1,6 +1,6 @@
1
1
  import { Component as WebComponent, ElementCreator, PartsMap } from 'tosijs';
2
- import type { CmHandle, TjsAutocompleteConfig } from './code-editor-cm';
3
- export type { TjsAutocompleteConfig } from './code-editor-cm';
2
+ import type { CmHandle, TjsAutocompleteConfig } from './code-editor-cm.js';
3
+ export type { TjsAutocompleteConfig } from './code-editor-cm.js';
4
4
  interface CodeEditorParts extends PartsMap {
5
5
  host: HTMLDivElement;
6
6
  diffHost: HTMLDivElement;
@@ -65,7 +65,7 @@ won't catch this one.
65
65
  */
66
66
  /*{ "parent": "Components" }*/
67
67
  import { Component as WebComponent, elements, varDefault, } from 'tosijs';
68
- import { tosiDiff } from './diff';
68
+ import { tosiDiff } from './diff.js';
69
69
  const { div } = elements;
70
70
  // Warn once per removed member, not once per access — a live-example page holds
71
71
  // dozens of editors and a render-loop read would otherwise flood the console.
@@ -286,7 +286,7 @@ export class CodeEditor extends WebComponent {
286
286
  if (this._loadPromise === undefined) {
287
287
  // Lazy chunk — CodeMirror only enters the bundle here, on first editor use.
288
288
  const generation = ++this._loadGeneration;
289
- this._loadPromise = import('./code-editor-cm').then(({ createCmEditor }) => {
289
+ this._loadPromise = import('./code-editor-cm.js').then(({ createCmEditor }) => {
290
290
  // The chunk fetch is async, and the pre-load window is WIDE on a cold fetch —
291
291
  // doc-browser navigation and closeEditor() both remove editors mid-flight. If we
292
292
  // mounted regardless:
@@ -346,7 +346,7 @@ export class CodeEditor extends WebComponent {
346
346
  const handle = this._handle;
347
347
  if (!handle || !this.isTjsMode())
348
348
  return;
349
- import('./code-editor-cm')
349
+ import('./code-editor-cm.js')
350
350
  .then(({ loadTjsExtension }) => loadTjsExtension(this._tjsAutocomplete ?? {}))
351
351
  .then((ext) => {
352
352
  if (ext && this._handle === handle && this.isTjsMode()) {
@@ -1,6 +1,6 @@
1
1
  import { Component as WebComponent, ElementCreator } from 'tosijs';
2
- import { SortCallback } from './make-sorter';
3
- import { ValueRendererType } from './value-renderer';
2
+ import { SortCallback } from './make-sorter.js';
3
+ import { ValueRendererType } from './value-renderer.js';
4
4
  export interface ColumnOptions {
5
5
  name?: string;
6
6
  prop: string;
@@ -221,7 +221,7 @@ Numeric types (`number`, `currency`, `fixed`, `percent`, `sci`, `eng`, `bytes`)
221
221
  by default; `boolean` centers and renders icons. An explicit `align` — or a `dataCell` —
222
222
  always wins. Formatting follows the app locale (`setLocale()`). Numeric cells also get a
223
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.
224
+ one CSS rule (`.-negative { color: #d32f2f }`), no cell renderer.
225
225
 
226
226
  ```js
227
227
  import { tosiTable } from 'tosijs-ui'
@@ -251,7 +251,7 @@ table.value = {
251
251
  preview.append(table)
252
252
  ```
253
253
  ```css
254
- .preview .-negative { color: #e44; }
254
+ .preview .-negative { color: #d32f2f; }
255
255
  .preview .-zero { opacity: 0.45; }
256
256
  ```
257
257
 
@@ -565,12 +565,12 @@ As well as any column names you want localized.
565
565
  */
566
566
  /*{ "parent": "Components" }*/
567
567
  import { Component as WebComponent, elements, vars, varDefault, tosiValue, getListItem, getListBinding, tosi, } from 'tosijs';
568
- import { trackDrag } from './track-drag';
569
- import { icons } from './icons';
570
- import { valueRenderer } from './value-renderer';
571
- import { popMenu } from './menu';
572
- import * as dragAndDrop from './drag-and-drop';
573
- import { tosiLocalized, localize } from './localize';
568
+ import { trackDrag } from './track-drag.js';
569
+ import { icons } from './icons.js';
570
+ import { valueRenderer } from './value-renderer.js';
571
+ import { popMenu } from './menu.js';
572
+ import * as dragAndDrop from './drag-and-drop.js';
573
+ import { tosiLocalized, localize } from './localize.js';
574
574
  function defaultWidth(array, prop, charWidth) {
575
575
  const example = array.find((item) => item[prop] !== undefined && item[prop] !== null);
576
576
  if (example !== undefined) {
@@ -687,10 +687,10 @@ export class TosiTable extends WebComponent {
687
687
  background: varDefault.tosiTableHeaderBg(varDefault.tosiTableBg('var(--tosi-bg, #fff)')),
688
688
  },
689
689
  ':host .tr[aria-selected] .td': {
690
- background: varDefault.tosiTableSelectedBg('var(--tosi-accent, #007AFF22)'),
690
+ background: varDefault.tosiTableSelectedBg('var(--tosi-accent, #0064d222)'),
691
691
  },
692
692
  ':host .td:focus, :host .th:focus': {
693
- outline: '2px solid var(--tosi-accent, #007AFF)',
693
+ outline: '2px solid var(--tosi-accent, #0064d2)',
694
694
  outlineOffset: '-2px',
695
695
  zIndex: '1',
696
696
  },
package/dist/dialog.js CHANGED
@@ -119,7 +119,7 @@ preview.append(
119
119
  */
120
120
  /*{ "parent": "Components" }*/
121
121
  import { Component, elements, on, vars, varDefault } from 'tosijs';
122
- import { findHighestZ } from './track-drag';
122
+ import { findHighestZ } from './track-drag.js';
123
123
  const { dialog, button, header, footer, tosiSlot, h3, p, label, input, div } = elements;
124
124
  export class TosiDialog extends Component {
125
125
  static preferredTagName = 'tosi-dialog';
@@ -1,4 +1,4 @@
1
- import { TestResults } from './live-example/test-harness';
1
+ import { TestResults } from './live-example/test-harness.js';
2
2
  export interface PageTestResults {
3
3
  passed: boolean;
4
4
  tests: TestResults['tests'];
@@ -152,24 +152,41 @@ The `tosijs-ui` demo is a complete working example. See:
152
152
  */
153
153
  /*{"pin":"bottom","parent":"Appendices"}*/
154
154
  import { elements, vars, varDefault, bindings, touch, getListItem, debounce, tosi, StyleSheet, } from 'tosijs';
155
- import { buildSlugMap, pathForSlug, filenameForPath, } from './doc-system/routing';
156
- import { buildNavTree } from './doc-system/nav-tree';
157
- import { renderDocMarkdown } from './doc-system/render';
158
- import { pageTitle } from './doc-system/doc-title';
159
- import { LiveExample, testManager } from './live-example';
160
- import { tosiSidenav, TosiSidenav } from './side-nav';
161
- import { icons } from './icons';
162
- import { tosiLocalized } from './localize';
163
- import { popMenu } from './menu';
164
- import { codeEditor } from './code-editor';
165
- import { tosiDiff } from './diff';
155
+ import { buildSlugMap, pathForSlug, filenameForPath, } from './doc-system/routing.js';
156
+ import { buildNavTree } from './doc-system/nav-tree.js';
157
+ import { renderDocMarkdown } from './doc-system/render.js';
158
+ import { pageTitle } from './doc-system/doc-title.js';
159
+ import { LiveExample, testManager } from './live-example.js';
160
+ import { tosiSidenav, TosiSidenav } from './side-nav.js';
161
+ import { icons } from './icons.js';
162
+ import { tosiLocalized } from './localize.js';
163
+ import { popMenu } from './menu.js';
164
+ import { codeEditor } from './code-editor.js';
165
+ import { tosiDiff } from './diff.js';
166
166
  const { div, span, a, header, button, template, input, h2, img, details, summary, ul, li, } = elements;
167
- // Test colors
167
+ /*
168
+ Test colors, and the text color that goes ON each — because contrast is a PAIR.
169
+
170
+ The widget used one hardcoded `color: white` and swapped only the background, so the
171
+ amber running state rendered white-on-#fa0 at **1.9:1** and the green pass state at
172
+ **3.1:1**, both well under WCAG AA's 4.5:1. (Found by `hj map`, which reports a
173
+ `contrast` ratio per node — invisible to the eye until measured.)
174
+
175
+ Amber is a genuinely light color: darkening it far enough for white text turns it brown
176
+ (63% brightness) and stops reading as "in progress". So it keeps its hue and takes dark
177
+ text at 11:1, which is the conventional warning-badge treatment. Green only needed a
178
+ nudge (81% brightness) to carry white.
179
+ */
168
180
  const testColor = {
169
- pass: varDefault.testColorPass('#0a0'),
181
+ pass: varDefault.testColorPass('#008a00'),
170
182
  fail: varDefault.testColorFail('#c00'),
171
183
  running: varDefault.testColorRunning('#fa0'),
172
184
  };
185
+ const testTextColor = {
186
+ pass: varDefault.testTextColorPass('#fff'),
187
+ fail: varDefault.testTextColorFail('#fff'),
188
+ running: varDefault.testTextColorRunning('#2b1a00'),
189
+ };
173
190
  // Test indicator styles - widget inherits button styles from base stylesheet
174
191
  const testIndicatorStyleSpec = {
175
192
  '.view-source': { opacity: '0.9' },
@@ -215,25 +232,30 @@ const testIndicatorStyleSpec = {
215
232
  // was overlaying this.
216
233
  '.test-widget': {
217
234
  _testBg: testColor.running,
235
+ _testFg: testTextColor.running,
218
236
  position: 'fixed',
219
237
  bottom: vars.spacing,
220
238
  left: vars.spacing,
221
239
  zIndex: '1000',
222
240
  background: vars.testBg,
223
- color: 'white',
241
+ // Paired with the background, not fixed to white — see testTextColor above.
242
+ color: vars.testFg,
224
243
  gap: vars.spacing50,
225
244
  },
226
245
  '.test-widget[hidden]': { display: 'none' },
227
246
  '.test-widget.-running': {
228
247
  _testBg: testColor.running,
248
+ _testFg: testTextColor.running,
229
249
  animation: 'test-appear 0.3s ease-out, test-pulse 2s ease-in-out 0.3s infinite',
230
250
  },
231
251
  '.test-widget.-passed': {
232
252
  _testBg: testColor.pass,
253
+ _testFg: testTextColor.pass,
233
254
  animation: 'test-fade 3s ease-out forwards',
234
255
  },
235
256
  '.test-widget.-failed': {
236
257
  _testBg: testColor.fail,
258
+ _testFg: testTextColor.fail,
237
259
  animation: 'test-pulse 2s ease-in-out infinite',
238
260
  },
239
261
  // Count badge
@@ -250,7 +272,7 @@ const testIndicatorStyleSpec = {
250
272
  },
251
273
  // Deep-linked example (e.g. arriving at /slug/#example-2): brief highlight pulse
252
274
  '@keyframes example-target-pulse': {
253
- from: { boxShadow: `0 0 0 3px ${varDefault.accent('#007aff')}` },
275
+ from: { boxShadow: `0 0 0 3px ${varDefault.accent('#0064d2')}` },
254
276
  to: { boxShadow: '0 0 0 3px transparent' },
255
277
  },
256
278
  '.example-target': {
@@ -1,4 +1,4 @@
1
- import { NavNode, NavDoc } from './nav-tree';
1
+ import { NavNode, NavDoc } from './nav-tree.js';
2
2
  export interface BookDoc {
3
3
  filename: string;
4
4
  title: string;
@@ -6,9 +6,9 @@ doc-browser (the user's browser prints it to PDF). Pure rendering — no fs, no
6
6
  Node-only APIs — so it bundles into the iife. Live examples are pretty-printed,
7
7
  force-wrapped code listings, not executed.
8
8
  */
9
- import { renderDocMarkdown } from './render';
10
- import { buildSlugMap } from './routing';
11
- import { buildNavTree } from './nav-tree';
9
+ import { renderDocMarkdown } from './render.js';
10
+ import { buildSlugMap } from './routing.js';
11
+ import { buildNavTree } from './nav-tree.js';
12
12
  // Clean book typography; force-wraps code so listings never overflow a page.
13
13
  export const DEFAULT_BOOK_CSS = `/* doc-system book stylesheet */
14
14
  html { font-size: 100%; }
@@ -19,7 +19,7 @@ exactly what it means everywhere else (filename, slug, or slugified title).
19
19
  Cycles are survivable by construction: `parent` is author-written and nav-tree already
20
20
  guards against loops, so this walks with a seen-set rather than trusting the data.
21
21
  */
22
- import { resolveParent } from './routing';
22
+ import { resolveParent } from './routing.js';
23
23
  /** The main book's internal key — what a doc with no `book` lands in. */
24
24
  export const DEFAULT_BOOK = '';
25
25
  /** `book: "none"` — on the site, in no book. */
@@ -1,5 +1,5 @@
1
1
  import { Component as WebComponent, ElementCreator } from 'tosijs';
2
- import { TosiForm } from '../form';
2
+ import { TosiForm } from '../form.js';
3
3
  declare class TosiCssVarEditor extends WebComponent {
4
4
  static preferredTagName: string;
5
5
  static initAttributes: {
@@ -7,7 +7,7 @@ can drop `<tosi-css-var-editor element-selector="tosi-widget">` under an example
7
7
  deliberately not exported from `tosijs-ui`.
8
8
  */
9
9
  import { Component as WebComponent, elements, Color, } from 'tosijs';
10
- import { tosiForm, tosiField } from '../form';
10
+ import { tosiForm, tosiField } from '../form.js';
11
11
  const { h2, code } = elements;
12
12
  // A value is a color if it's a hex literal or an rgb()/hsl() (with or without alpha)
13
13
  // functional notation — the forms getComputedStyle / getPropertyValue return. The old
@@ -11,7 +11,7 @@ palette can eventually be driven entirely by a few attributes on the element
11
11
  (accent/background/text) — most of the palette is derived from `accent`.
12
12
  */
13
13
  import { vars, Color, invertLuminance, } from 'tosijs';
14
- import { icons, svg2DataUrl } from '../icons';
14
+ import { icons, svg2DataUrl } from '../icons.js';
15
15
  // The sidebar's geometry, shared by the hydrated layout and the pre-hydration one.
16
16
  // These mirror what <tosi-sidenav> is given by doc-browser (navSize / minSize): the
17
17
  // sidebar is `SIDEBAR_WIDTH` wide and collapses behind a toggle below
@@ -20,7 +20,7 @@ export const SIDEBAR_WIDTH = 200;
20
20
  export const SIDEBAR_BREAKPOINT = 600;
21
21
  /** Compute the full set of `:root` color variables from a few base colors. */
22
22
  export function docSystemColors(theme = {}) {
23
- const brandColor = Color.fromCss(theme.accent ?? '#EE257B');
23
+ const brandColor = Color.fromCss(theme.accent ?? '#d92270');
24
24
  return {
25
25
  _textColor: theme.text ?? '#222',
26
26
  _brandColor: brandColor,
@@ -32,7 +32,18 @@ export function docSystemColors(theme = {}) {
32
32
  _barColor: brandColor.opacity(0.4),
33
33
  _focusColor: brandColor.opacity(0.7),
34
34
  _placeholderColor: brandColor.opacity(0.4),
35
- _brandTextColor: brandColor.rotate(30).brighten(0.9),
35
+ /*
36
+ `contrasting()` rather than a hand-tuned tint.
37
+
38
+ `brandColor.rotate(30).brighten(0.9)` produced a warm off-white (#fbeae9) that sat at
39
+ **4.09:1** on the brand bar — under AA for the normal-size nav links in it. Every
40
+ brighten value short of pure white also misses (0.96 lands at 4.49), so the tint had
41
+ to go; it was imperceptible anyway. `contrasting()` picks the readable extreme for
42
+ whatever the brand currently is, so this cannot drift the next time the brand moves.
43
+ Dark mode is unaffected: invertLuminance flips this to near-black on the brightened
44
+ bar, which is already high-contrast.
45
+ */
46
+ _brandTextColor: brandColor.contrasting(),
36
47
  _insetBg: brandColor.rotate(45).brighten(0.8),
37
48
  // Neutral off-white (not brand-tinted); dark mode inverts its luminance to
38
49
  // off-black, so the editor surface stays a clean neutral in both themes.
@@ -55,7 +66,7 @@ export function docSystemColors(theme = {}) {
55
66
  /** Build the full doc-system stylesheet for a given base theme. */
56
67
  export function docSystemStyleSpec(theme = {}) {
57
68
  const colors = docSystemColors(theme);
58
- const brandColor = Color.fromCss(theme.accent ?? '#EE257B');
69
+ const brandColor = Color.fromCss(theme.accent ?? '#d92270');
59
70
  return {
60
71
  '@import': 'https://fonts.googleapis.com/css2?family=Aleo:ital,wght@0,100..900;1,100..900&famiSpline+Sans+Mono:ital,wght@0,300..700;1,300..700&display=swap',
61
72
  ':root': {
@@ -89,6 +100,16 @@ export function docSystemStyleSpec(theme = {}) {
89
100
  },
90
101
  '.darkmode': {
91
102
  ...invertLuminance(colors),
103
+ /*
104
+ Lift the brand color for dark backgrounds.
105
+
106
+ `invertLuminance` flips the neutrals but leaves a saturated brand hue roughly where
107
+ it was, so one accent has to serve both a near-white and a near-black page — and a
108
+ pink dark enough to clear AA on `#fafafa` (4.56:1) lands at 4.4:1 on `#050505`,
109
+ just under. Brightening it in dark mode is the standard resolution: the hue is the
110
+ brand, the luminance belongs to the background it sits on.
111
+ */
112
+ _brandColor: brandColor.brighten(0.18),
92
113
  _shadowColor: brandColor.opacity(0.5),
93
114
  _menuShadow: `0 0 0 2px ${brandColor.opacity(0.75)}`,
94
115
  _menuSeparatorColor: brandColor.opacity(0.5),
@@ -1,5 +1,5 @@
1
1
  import { Component, ElementCreator } from 'tosijs';
2
- import './css-var-editor';
2
+ import './css-var-editor.js';
3
3
  export declare class TosiDocSystem extends Component {
4
4
  static preferredTagName: string;
5
5
  static initAttributes: {
@@ -57,16 +57,16 @@ A self-contained, controllable embed (e.g. docs in a floating panel):
57
57
  */
58
58
  /*{ "parent": "Appendices" }*/
59
59
  import { Component, StyleSheet, elements, tosi, vars, } from 'tosijs';
60
- import { createDocBrowser } from '../doc-browser';
61
- import { buildSlugMap, legacyQueryPath } from './routing';
62
- import { buildBookHtml, slugify } from './book-html';
63
- import { docSystemStyleSpec } from './doc-system-styles';
64
- import { icons } from '../icons';
65
- import { popMenu } from '../menu';
66
- import { i18n, setLocale, initLocalization } from '../localize';
60
+ import { createDocBrowser } from '../doc-browser.js';
61
+ import { buildSlugMap, legacyQueryPath } from './routing.js';
62
+ import { buildBookHtml, slugify } from './book-html.js';
63
+ import { docSystemStyleSpec } from './doc-system-styles.js';
64
+ import { icons } from '../icons.js';
65
+ import { popMenu } from '../menu.js';
66
+ import { i18n, setLocale, initLocalization } from '../localize.js';
67
67
  // Side-effect: register <tosi-css-var-editor> so doc pages can drop the live CSS-var
68
68
  // tweaker under an example. Part of the doc-system, NOT re-exported from tosijs-ui.
69
- import './css-var-editor';
69
+ import './css-var-editor.js';
70
70
  const { button, div } = elements;
71
71
  const PREFS_KEY = 'tosi-doc-system-prefs';
72
72
  export class TosiDocSystem extends Component {
@@ -11,7 +11,7 @@ parent form a nav section, nested arbitrarily deep. Parents are expected to
11
11
  exist as real docs by the time the tree is built (the build auto-creates any
12
12
  missing section docs first), so this module never synthesizes.
13
13
  */
14
- import { resolveParent } from './routing';
14
+ import { resolveParent } from './routing.js';
15
15
  /** Pin buckets sort top < none < bottom. */
16
16
  function pinRank(doc) {
17
17
  return doc.pin === 'top' ? 0 : doc.pin === 'bottom' ? 2 : 1;
@@ -26,7 +26,7 @@ orchestrator.ts.
26
26
 
27
27
  Build-time only. Never import this from browser code.
28
28
  */
29
- import { checkExamples } from './check-examples';
29
+ import { checkExamples } from './check-examples.js';
30
30
  const docsJson = process.argv[2];
31
31
  if (!docsJson) {
32
32
  console.error('check-examples-cli: expected a docs.json path');
@@ -1,5 +1,5 @@
1
- import type { Doc } from './docs';
2
- import type { ExampleBakes } from '../render';
1
+ import type { Doc } from './docs.js';
2
+ import type { ExampleBakes } from '../render.js';
3
3
  export interface ExampleProblem {
4
4
  filename: string;
5
5
  title: string;
@@ -22,7 +22,7 @@ executed, so they're skipped.
22
22
  Build-time only (bun). Never import from browser code.
23
23
  */
24
24
  import { marked } from 'marked';
25
- import { rewriteImports, AsyncFunction, loadTransform, UnsupportedImportError, } from '../../live-example/code-transform';
25
+ import { rewriteImports, AsyncFunction, loadTransform, UnsupportedImportError, } from '../../live-example/code-transform.js';
26
26
  // The default live-example context (matches the IIFE globals the pages provide).
27
27
  // A project that sets a custom `context` on its <tosi-doc-system> can pass its
28
28
  // own keys; these are the tosijs-ui defaults.
@@ -1,5 +1,5 @@
1
- import type { SiteConfig } from './site-config';
2
- import { isLoopbackAddressForAuth as isLoopbackAddress } from './dev-auth';
1
+ import type { SiteConfig } from './site-config.js';
2
+ import { isLoopbackAddressForAuth as isLoopbackAddress } from './dev-auth.js';
3
3
  declare global {
4
4
  var Bun: any;
5
5
  }