partforge 0.117.1 → 0.118.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.
@@ -1060,12 +1060,41 @@ export function tilePicker(host) {
1060
1060
  listener you attach yourself with `addEventListener`, rather than through `host.h`,
1061
1061
  is **not** guarded — wire listeners through `host.h`, or wrap your own in try/catch.
1062
1062
 
1063
- **Looking native.** The slot inherits the rail's font, colours and light/dark theme.
1064
- Bare `<button>`, `<input>` and `<select>` elements pick up the built-in looks
1065
- automatically; the built-in classes are available by name for the exact thing:
1063
+ **Looking native.** The slot inherits the rail's font and text colour, and the
1064
+ built-in looks come for free: bare `<button>`, `<input>` and `<select>` elements
1065
+ are already styled, the built-in classes are there by name for the exact thing
1066
1066
  `row`, `seg` (a segmented row of buttons), `action`, `ghost`, `num`, `text-input`,
1067
- `select-input`; and for SVG, `pf-hit` (clickable, with a `selected` state) and
1068
- `pf-drag`. Sub-controls mounted through `host.controls` *are* the built-in widgets.
1067
+ `select-input` and sub-controls mounted through `host.controls` *are* the
1068
+ built-in widgets. For SVG there are two classes: `pf-hit` (a clickable region,
1069
+ with a `selected` state) and `pf-drag`.
1070
+
1071
+ **Colour only with the rail's tokens.** Inheriting the rail's colours covers the
1072
+ text you did not style; it does not cover anything you colour yourself. For that,
1073
+ use a `--pf-*` custom property and never a hex literal or a named colour — the
1074
+ tokens flip with the light/dark theme and a literal cannot, so a `#333` border is
1075
+ a widget that is unreadable in one of the two themes. The ones worth knowing:
1076
+ `var(--pf-text)` and `var(--pf-text-2)` for text, `var(--pf-muted)` for a
1077
+ secondary label, `var(--pf-border)` for a rule or an outline,
1078
+ `var(--pf-surface-2)` for a filled chip, `var(--pf-accent)` with
1079
+ `var(--pf-on-accent)` for the selected or primary thing, and `var(--pf-err)` for
1080
+ a problem. That palette is the whole palette: the accent blue for the one thing
1081
+ that is chosen or primary, the surface and border greys for everything else. A
1082
+ widget that reaches past it for a red or a green is a widget that has stopped
1083
+ looking like the rest of the panel.
1084
+
1085
+ **Nest a region's label inside the region.** The common case then needs no colour
1086
+ from you at all: an SVG shape you leave unfilled inherits `var(--pf-text-2)`
1087
+ rather than SVG's own black, a `pf-hit` region is filled and outlined at rest,
1088
+ and a `<text>` *inside* that region stays readable through all three states —
1089
+ the rail gives it `var(--pf-text-2)` at rest and `var(--pf-on-accent)` once the
1090
+ region is selected and has gone solid accent underneath it, and clears the
1091
+ stroke it would otherwise inherit from the region's outline (SVG paints that
1092
+ around every glyph, which at label sizes leaves a pale ghost of the number).
1093
+ Draw the label as a sibling instead and none of that reaches it: a dark number
1094
+ sitting on the selected blue is the result, and you have to colour it yourself.
1095
+ To colour a
1096
+ region from your own data, set an inline `style` — a `fill="…"` attribute loses
1097
+ to the rail's rule.
1069
1098
 
1070
1099
  **Reading the part's own files.** Artwork can live beside the code (the tree is text,
1071
1100
  so an SVG, a `partforge-vector` JSON document or a JSON data file — not a PNG).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "partforge",
3
- "version": "0.117.1",
3
+ "version": "0.118.0",
4
4
  "description": "Turn a declarative part definition into a parametric-CAD web app (three.js + Manifold/Replicad). Requires a Vite-based consumer.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -387,10 +387,10 @@ button.action:disabled { opacity: .5; cursor: default; }
387
387
  /* Custom controls (type: "custom"): a part-authored widget in the rail. The
388
388
  slot inherits the rail's cascade (font, colours, --pf-* tokens); these rules
389
389
  give BARE elements the built-in controls' look so a widget written with
390
- plain <button>/<input>/<select> still reads as native, and provide two
391
- opt-in classes for SVG: .pf-hit (a clickable region) and .pf-drag (a
392
- dragged one — touch-action: none is what lets a finger drag it on a phone
393
- instead of scrolling the sheet). */
390
+ plain <button>/<input>/<select> still reads as native, supply a themed
391
+ floor for hand-drawn SVG, and provide two opt-in classes for SVG: .pf-hit
392
+ (a clickable region) and .pf-drag (a dragged one — touch-action: none is
393
+ what lets a finger drag it on a phone instead of scrolling the sheet). */
394
394
  .pf-custom { margin: 9px 0; }
395
395
  .pf-custom.hidden { display: none; }
396
396
  .pf-custom-slot { display: flow-root; }
@@ -400,7 +400,12 @@ button.action:disabled { opacity: .5; cursor: default; }
400
400
  like .text-input (0,1,0) or .row .num (0,2,0). At true zero specificity,
401
401
  any class rule wins, so a named built-in class (.seg button, .text-input,
402
402
  select.select-input, …) always beats these bare-element defaults. */
403
- :where(.pf-custom) :where(svg) { display: block; max-width: 100%; height: auto; }
403
+ /* `fill` inherits in SVG, so this is the floor for everything the widget draws
404
+ and did not colour — including <text>. SVG's own initial fill is BLACK, which
405
+ is invisible on the dark theme, and that is what an author gets for free
406
+ unless the rail supplies a token. Inherited rather than matched, so a child
407
+ carrying its own fill="…" attribute still wins. */
408
+ :where(.pf-custom) :where(svg) { display: block; max-width: 100%; height: auto; fill: var(--pf-text-2); }
404
409
  :where(.pf-custom) :where(button) {
405
410
  font: inherit; font-size: 12px; padding: 5px 9px; cursor: pointer;
406
411
  background: transparent; border: 1px solid var(--pf-border); color: var(--pf-text-2);
@@ -417,9 +422,29 @@ button.action:disabled { opacity: .5; cursor: default; }
417
422
  outline: none; border-color: var(--pf-accent);
418
423
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--pf-accent) 35%, transparent);
419
424
  }
420
- .pf-custom .pf-hit { cursor: pointer; }
425
+ /* A region the reader clicks. The RESTING fill and stroke are what make it read
426
+ as a control: without them a .pf-hit polygon is a black slab with no border
427
+ until it is hovered or selected. Zero specificity, so a widget that colours
428
+ regions from its own data still wins — with an inline `style`, since a
429
+ `fill="…"` attribute loses to any rule that matches the element, even this
430
+ one. Hover and selected below keep their own (0,2,x) weight. */
431
+ :where(.pf-custom) :where(.pf-hit) { cursor: pointer; fill: var(--pf-surface-2); stroke: var(--pf-border); }
421
432
  .pf-custom .pf-hit:hover { fill: color-mix(in oklab, var(--pf-accent) 25%, transparent); }
422
- .pf-custom .pf-hit.selected { fill: color-mix(in oklab, var(--pf-accent) 45%, transparent); stroke: var(--pf-accent); }
433
+ /* Selected is the SOLID accent, not a wash of it. A translucent accent lands on a
434
+ different value in each theme — pale over the light background, dark over the
435
+ dark one — so no single label colour is readable on both. Solid accent is one
436
+ colour in both, which is what makes --pf-on-accent below a rule rather than a
437
+ guess. A widget that would rather tint its own region overrides with `style`. */
438
+ .pf-custom .pf-hit.selected { fill: var(--pf-accent); stroke: var(--pf-accent); }
439
+ /* A label NESTED inside the region — the structure to recommend, because it is the
440
+ only one where the rail can keep the text readable as the region changes colour
441
+ underneath it. `fill` inherits, so without these the label takes the region's OWN
442
+ fill: grey on grey at rest, and accent on accent once selected. `stroke` inherits
443
+ too, and that one is worse than it looks: the region's outline colour gets painted
444
+ around every glyph, which at label sizes is most of the glyph — pale ghosts of the
445
+ numbers at rest, blue ones when selected. Hence stroke: none, not just a fill. */
446
+ :where(.pf-custom) :where(.pf-hit) text { fill: var(--pf-text-2); stroke: none; }
447
+ .pf-custom .pf-hit.selected text { fill: var(--pf-on-accent); }
423
448
  .pf-custom .pf-drag { touch-action: none; }
424
449
  .pf-custom-error {
425
450
  margin: 4px 0; padding: 6px 8px; border: 1px solid var(--pf-err); border-radius: var(--pf-radius-control);