three-slicer-viewer 0.3.0 → 0.3.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.
- package/README.md +4 -4
- package/TOOLPATH_SPEC.md +2 -2
- package/VIEWER.md +66 -1
- package/dist/components.js +102 -111
- package/dist/gcode_parse.js +190 -146
- package/dist/index.js +5060 -4324
- package/dist/model_loaders-DxlFNFOu.js +196 -0
- package/dist/model_loaders.js +15 -181
- package/dist/parse_3mf-BZISF3eW.js +327 -0
- package/dist/parse_3mf.worker.js +1 -1
- package/dist/shadow_host-CQ3LirzD.js +16 -0
- package/dist/sl1_encode.worker.js +1 -1
- package/dist/{sl1_write-CvrNejbW.js → sl1_write-BovHbg3k.js} +66 -65
- package/dist/sla_reconstruct-CRZ3TrI1.js +178 -0
- package/dist/sla_reconstruct.worker.js +1 -1
- package/dist/sla_slice.worker.js +22 -21
- package/dist/theme-2oyfMuvf.js +97 -0
- package/dist/toolpath.js +138 -213
- package/dist/toolpath_encoding-BuYs95qZ.js +23 -0
- package/dist/toolpath_palette-B8xEl-qa.js +89 -0
- package/dist/viewer_defaults-B7UUZ582.js +28 -0
- package/package.json +30 -5
- package/src/settings/index.js +2 -0
- package/src/settings/kernel_defaults.js +144 -0
- package/src/settings/settings_core.js +114 -131
- package/types/gcode.d.ts +27 -1
- package/types/settings.d.ts +12 -0
- package/types/viewer.d.ts +3 -1
- package/dist/parse_3mf-CQ5rAX6P.js +0 -299
- package/dist/sla_reconstruct-CXkYhux2.js +0 -176
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ exports; it does not slice. Slicing is plugged in through two props — `slicer`
|
|
|
9
9
|
`catalog` (vendor presets) — which `three-slicer/viewer` supplies. Install `three-slicer` for that, and note that
|
|
10
10
|
doing so puts your application under AGPL.
|
|
11
11
|
|
|
12
|
-
Developed in the [`
|
|
12
|
+
Developed in the [`Three_Slicer`](https://github.com/kimgh06/Three_Slicer) monorepo (`viewer-package/`), where it
|
|
13
13
|
is built and tested beside the kernel; this repository is that folder's history, pushed on every release. Issues and
|
|
14
14
|
pull requests are welcome here — a change lands upstream and comes back with the next sync.
|
|
15
15
|
|
|
@@ -70,12 +70,12 @@ handle.setColors(computeColors(data, 'speed', ctx).color) // recolour without a
|
|
|
70
70
|
## Licensing
|
|
71
71
|
|
|
72
72
|
MIT. It depends on nothing AGPL, which a check in this repository enforces rather than documents
|
|
73
|
-
(`packages/viewer/test_license_boundary.mjs`).
|
|
73
|
+
(`packages/viewer/tests/test_license_boundary.mjs`).
|
|
74
74
|
|
|
75
75
|
The implementation was written from [`TOOLPATH_SPEC.md`](./TOOLPATH_SPEC.md), a functional contract, rather
|
|
76
76
|
than derived from any upstream slicer. The reasoning and evidence are in
|
|
77
|
-
[
|
|
78
|
-
[
|
|
77
|
+
[`PROVENANCE.md`](https://github.com/kimgh06/Three_Slicer/blob/main/packages/PROVENANCE.md); the plan it came from is
|
|
78
|
+
[`RELICENSE.md`](https://github.com/kimgh06/Three_Slicer/blob/main/packages/RELICENSE.md).
|
|
79
79
|
|
|
80
80
|
Published as a locked pair with `three-slicer`: both carry the same version, and `three-slicer` pins this
|
|
81
81
|
package exactly, so a combination that was never built together cannot be resolved.
|
package/TOOLPATH_SPEC.md
CHANGED
|
@@ -163,10 +163,10 @@ Constraints:
|
|
|
163
163
|
|
|
164
164
|
## 8. How to know it works
|
|
165
165
|
|
|
166
|
-
1. `node
|
|
166
|
+
1. `node viewer-package/tests/test_toolpath_contract.mjs` — the contract, plus a printed snapshot to diff against
|
|
167
167
|
the recorded run. Exact float equality is **not** expected; counts, strides, encodings, ranges and length
|
|
168
168
|
accounting are.
|
|
169
|
-
2. `node
|
|
169
|
+
2. `node viewer-package/tests/test_move_scrub.mjs` — the scrub queries.
|
|
170
170
|
3. `npm run test:viewer` — everything, including the license boundary check.
|
|
171
171
|
4. **Look at it.** Build the three demos that consume this API
|
|
172
172
|
(`examples/{instant-quote,cad-embed,farm-dashboard}`) and open them. A static check cannot tell you a
|
package/VIEWER.md
CHANGED
|
@@ -95,7 +95,8 @@ Every panel can be switched off, and the values the component owns can be seeded
|
|
|
95
95
|
resin masks on a filament bed. The one number it cannot supply is the display's PHYSICAL size: millimetres
|
|
96
96
|
appear nowhere in an SL1, so the preview is scaled by the printer set in the viewer and the import notice says
|
|
97
97
|
so. Export hands an imported archive back byte-identical rather than re-rasterizing empty geometry.
|
|
98
|
-
- **`gcode`** — G-code text drawn on the selected plate instead of a slice result
|
|
98
|
+
- **`gcode`** — G-code text drawn on the selected plate instead of a slice result, or a `{ plateIndex: text }` map
|
|
99
|
+
drawn plate by plate (what an opened `.gcode.3mf` becomes; the viewer is preview-only while one is shown). `parseGcode` recovers roles from
|
|
99
100
|
`;TYPE:` (OrcaSlicer/PrusaSlicer/Cura), from `;_EXTRUSION_ROLE:` tags and from this kernel's own feature comments;
|
|
100
101
|
bead width comes from `;WIDTH:` or, absent that, from E. What the file never states cannot be recovered: an
|
|
101
102
|
unmarked run reads as wall, and there is no print-time estimate (that needs the machine's acceleration limits).
|
|
@@ -394,6 +395,70 @@ for 143MB) against a 4GB pool budget, which gives 2 for that model and does not
|
|
|
394
395
|
manual count is capped the same way. What the browser has NOT measured yet is
|
|
395
396
|
the arachne + tree-support preset, where the harness gains were largest.
|
|
396
397
|
|
|
398
|
+
## Theming
|
|
399
|
+
|
|
400
|
+
Both shadow roots (the viewer and `<SettingsPanel/>`) paint their chrome from one palette, `UI_TOKENS` in
|
|
401
|
+
`src/core/theme.js`. Each entry is a custom property a host can set on any ancestor of the component — custom
|
|
402
|
+
properties are the one thing that inherits across a shadow boundary, so this is the only styling hook the isolation
|
|
403
|
+
leaves open:
|
|
404
|
+
|
|
405
|
+
```css
|
|
406
|
+
.my-slicer-page { --vp-accent: #0a84ff; --vp-light-bg: #f4f4f6; }
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
An unset property falls back to the default below. Four of them are also used as translucent fill, and CSS cannot
|
|
410
|
+
take the alpha off a hex — those carry an `-rgb` twin (`--vp-accent-rgb: 0, 174, 66`) that a host overriding the
|
|
411
|
+
colour must set as well. The 3D scene (the selection tint, plate borders, grid, SLA preview
|
|
412
|
+
colours) is drawn by three.js from `THEME` in the same file and does not read these properties.
|
|
413
|
+
|
|
414
|
+
| Property | Default |
|
|
415
|
+
|---|---|
|
|
416
|
+
| `--vp-accent` | `#00ae42` |
|
|
417
|
+
| `--vp-accent-hover` | `#06c04d` |
|
|
418
|
+
| `--vp-accent-deep` | `#23402c` |
|
|
419
|
+
| `--vp-accent-ink` | `#167a3a` |
|
|
420
|
+
| `--vp-accent-on-dark` | `#9fe3bd` |
|
|
421
|
+
| `--vp-accent-soft` | `#e3f6ea` |
|
|
422
|
+
| `--vp-accent-soft-border` | `#9adfb6` |
|
|
423
|
+
| `--vp-on-accent` | `#ffffff` |
|
|
424
|
+
| `--vp-dark-base` | `#0e1216` |
|
|
425
|
+
| `--vp-dark-surface` | `#161b21` |
|
|
426
|
+
| `--vp-dark-control` | `#1a2027` |
|
|
427
|
+
| `--vp-dark-control-hover` | `#28313a` |
|
|
428
|
+
| `--vp-dark-border` | `#2c353d` |
|
|
429
|
+
| `--vp-dark-border-strong` | `#3a4550` |
|
|
430
|
+
| `--vp-dark-text` | `#cdd6dd` |
|
|
431
|
+
| `--vp-dark-text-muted` | `#aebcc6` |
|
|
432
|
+
| `--vp-dark-text-faint` | `#8b98a2` |
|
|
433
|
+
| `--vp-dark-text-disabled` | `#5a6570` |
|
|
434
|
+
| `--vp-light-bg` | `#eef0f2` |
|
|
435
|
+
| `--vp-light-surface` | `#ffffff` |
|
|
436
|
+
| `--vp-light-subtle` | `#f6f7f8` |
|
|
437
|
+
| `--vp-light-control` | `#dfe6ea` |
|
|
438
|
+
| `--vp-light-control-hover` | `#d3dee4` |
|
|
439
|
+
| `--vp-light-border` | `#d5d8dd` |
|
|
440
|
+
| `--vp-light-divider` | `#e3e6ea` |
|
|
441
|
+
| `--vp-light-text` | `#24282e` |
|
|
442
|
+
| `--vp-light-text-muted` | `#5a6069` |
|
|
443
|
+
| `--vp-light-text-faint` | `#8a9099` |
|
|
444
|
+
| `--vp-info` | `#2b6cff` |
|
|
445
|
+
| `--vp-info-ink` | `#2563eb` |
|
|
446
|
+
| `--vp-info-soft` | `#e6efff` |
|
|
447
|
+
| `--vp-tech-badge` | `#6d7ce0` |
|
|
448
|
+
| `--vp-danger` | `#e23b3b` |
|
|
449
|
+
| `--vp-danger-ink` | `#a33b37` |
|
|
450
|
+
| `--vp-danger-soft` | `#fbeaea` |
|
|
451
|
+
| `--vp-danger-on-dark` | `#ff8b8b` |
|
|
452
|
+
| `--vp-danger-deep` | `#4a2229` |
|
|
453
|
+
| `--vp-warn` | `#f0a542` |
|
|
454
|
+
| `--vp-warn-ink` | `#a86a12` |
|
|
455
|
+
| `--vp-warn-soft` | `#fdf4e3` |
|
|
456
|
+
| `--vp-warn-soft-hover` | `#f3e2cb` |
|
|
457
|
+
| `--vp-warn-border` | `#d8b48a` |
|
|
458
|
+
| `--vp-warn-on-dark` | `#f0c060` |
|
|
459
|
+
| `--vp-warn-deep` | `#3a2a10` |
|
|
460
|
+
| `--vp-warn-deep-border` | `#7a5a1e` |
|
|
461
|
+
|
|
397
462
|
## Bundler notes
|
|
398
463
|
|
|
399
464
|
- **Vite:** two config lines (worker code-splitting + top-level await in the mt glue; Chrome 89+/Safari 15+):
|
package/dist/components.js
CHANGED
|
@@ -1,125 +1,116 @@
|
|
|
1
|
-
import e, {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import e, { useState as y, useEffect as P, useMemo as j } from "react";
|
|
2
|
+
import { leanSchema as R, uiTreeKeys as U } from "three-slicer-viewer/data";
|
|
3
|
+
import { printerTechnology as W, settingRaw as I } from "three-slicer-viewer/settings";
|
|
4
|
+
import { disabledKeys as $, makeCfg as G } from "three-slicer-viewer/toggle";
|
|
5
|
+
import { U as H } from "./viewer_defaults-B7UUZ582.js";
|
|
6
|
+
import { a as Q } from "./theme-2oyfMuvf.js";
|
|
7
|
+
import { S as X } from "./shadow_host-CQ3LirzD.js";
|
|
8
|
+
const Y = ':host{display:contents}*{box-sizing:border-box}.row{display:grid;grid-template-columns:260px 220px 70px 1fr;gap:8px;align-items:center;padding:3px 0;border-bottom:1px dashed var(--_light-divider)}.row .lbl{color:var(--_light-text);text-decoration:none}.row .lbl:hover{color:var(--_accent-ink);text-decoration:underline}.row .key{font-size:11px;color:var(--_light-text-faint);overflow:hidden;text-overflow:ellipsis}.row input[type=text],.row input:not([type]),.row select,.row textarea{width:100%;max-width:260px;padding:2px 6px}.inputwrap{display:inline-flex;align-items:center;gap:4px}.unit{color:var(--_light-text-faint);font-size:12px;white-space:nowrap}.pts{font-size:11px;color:var(--_light-text-muted)}.badge{font-size:10px;padding:1px 6px;border-radius:8px;color:var(--_on-accent);text-align:center}.mode-simple{background:var(--_accent-ink)}.mode-advanced{background:var(--_info-ink)}.mode-expert{background:var(--_warn)}.mode-develop{background:var(--_danger)}.mode-none,.mode-undefined{background:var(--_light-text-faint)}.muted{color:var(--_light-text-faint);font-weight:400;font-size:12px}.row.custom{grid-template-columns:1fr}.row.disabled{opacity:.42}.row.disabled input,.row.disabled select,.row.disabled textarea{cursor:not-allowed;background:var(--_light-subtle)}.lbl-cell{display:inline-flex;align-items:center;gap:5px;min-width:0}.lbl-cell .lbl{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dirty-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--_warn);box-shadow:0 0 0 2px var(--_warn-soft)}.override-dot{flex:0 0 auto;width:9px;height:9px;border-radius:50%;background:var(--_warn);border:0;padding:0;cursor:pointer;box-shadow:0 0 0 2px var(--_warn-soft)}.override-dot:hover{background:var(--_warn-ink)}.widget-cell{display:inline-flex;align-items:center;gap:6px;min-width:0}.reset-btn{flex:0 0 auto;border:1px solid var(--_warn-border);background:var(--_warn-soft);color:var(--_warn-ink);border-radius:5px;cursor:pointer;font-size:13px;line-height:1;padding:1px 5px}.reset-btn:hover{background:var(--_warn-soft-hover)}.settings-panel{flex:0 0 400px;width:400px;border-left:1px solid var(--_light-divider);display:flex;flex-direction:column;min-height:0;background:var(--_light-surface);color:var(--_light-text);font:14px/1.5 -apple-system,Segoe UI,sans-serif}.settings-panel .sp-top{padding:10px 12px 8px;border-bottom:1px solid var(--_light-divider)}.sp-builder{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--_light-text-muted)}.sp-builder select{flex:1;padding:4px 6px}.sp-pages{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}.sp-pages button{border:1px solid var(--_light-border);background:var(--_light-subtle);border-radius:6px;padding:4px 8px;font-size:12px;cursor:pointer}.sp-pages button.on{background:var(--_accent-soft);color:var(--_accent-ink);border-color:var(--_accent-soft-border);font-weight:700}.sp-modes{display:flex;gap:4px;margin-top:8px}.sp-modes button{border:0;background:none;font-size:11px;color:var(--_light-text-faint);padding:2px 6px;border-radius:6px;cursor:pointer}.sp-modes button.on{background:var(--_accent-soft);color:var(--_accent-ink);font-weight:700}.settings-panel .sp-body{flex:1 1 auto;overflow-y:auto;padding:8px 14px 24px}.settings-panel .sp-body h2{font-size:16px}.settings-panel .row{grid-template-columns:1fr auto;grid-template-areas:"lbl badge" "key widget";row-gap:2px;padding:6px 0}.settings-panel .row .lbl{grid-area:lbl;font-weight:600}.settings-panel .row .badge{grid-area:badge;justify-self:end}.settings-panel .row .key{grid-area:key}.settings-panel .row .inputwrap,.settings-panel .row>select,.settings-panel .row>input,.settings-panel .row>textarea,.settings-panel .row>.pts,.settings-panel .row>.muted{grid-area:widget;justify-self:end}.settings-panel .row input:not([type=checkbox]):not([type=color]),.settings-panel .row select,.settings-panel .row textarea{max-width:200px}.settings-panel .row.custom{grid-template-columns:1fr;grid-template-areas:"lbl"}.sp-search{width:100%;box-sizing:border-box;padding:6px 9px;border:1px solid var(--_light-border);border-radius:6px;font-size:13px;margin-bottom:8px}:host(.sp-embedded) .settings-panel{position:static;width:auto;flex:none;border:0;height:auto}:host(.sp-embedded) .sp-body{padding:4px 2px 8px;max-height:460px}.bse{display:flex;flex-direction:column;gap:6px;min-width:0;max-width:220px}.bse-modes{display:flex;gap:4px}.bse-modes button{border:1px solid var(--_light-border);background:var(--_light-subtle);border-radius:6px;padding:2px 8px;font-size:11px;cursor:pointer}.bse-modes button.on{background:var(--_accent-soft);color:var(--_accent-ink);border-color:var(--_accent-soft-border);font-weight:700}.bse-grid{display:grid;grid-template-columns:1fr 1fr;gap:4px 8px}.bse-grid label{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--_light-text-muted);white-space:nowrap}.bse-grid input{width:56px;padding:2px 4px;font-size:12px}.bse-json{width:100%;font:11px ui-monospace,monospace;padding:4px 6px;border:1px solid var(--_light-border);border-radius:6px;box-sizing:border-box}.bse-json.err{border-color:var(--_danger);background:var(--_danger-soft)}', q = (t, a, r, o) => [[r, o], [t + r, o], [t + r, a + o], [r, a + o]], L = R.printable_area.default, V = (t) => {
|
|
9
|
+
const a = t / 2, r = 32;
|
|
10
|
+
return Array.from({ length: r }, (o, i) => {
|
|
11
|
+
const u = 2 * Math.PI * i / r;
|
|
12
|
+
return [+(a + a * Math.cos(u)).toFixed(2), +(a + a * Math.sin(u)).toFixed(2)];
|
|
10
13
|
});
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
i || (i = document.createElement("style"), i.setAttribute("data-ts-css", ""), d.append(i)), i.textContent = t, d.contains(l) || d.append(l);
|
|
15
|
-
}, [t, l]), /* @__PURE__ */ e.createElement("div", { ref: r, className: a }, W(n, l));
|
|
16
|
-
}
|
|
17
|
-
const Y = ':host{display:contents}*{box-sizing:border-box}.row{display:grid;grid-template-columns:260px 220px 70px 1fr;gap:8px;align-items:center;padding:3px 0;border-bottom:1px dashed #f0f0f0}.row .lbl{color:#222;text-decoration:none}.row .lbl:hover{color:#0a7d4f;text-decoration:underline}.row .key{font-size:11px;color:#999;overflow:hidden;text-overflow:ellipsis}.row input[type=text],.row input:not([type]),.row select,.row textarea{width:100%;max-width:260px;padding:2px 6px}.inputwrap{display:inline-flex;align-items:center;gap:4px}.unit{color:#888;font-size:12px;white-space:nowrap}.pts{font-size:11px;color:#666}.badge{font-size:10px;padding:1px 6px;border-radius:8px;color:#fff;text-align:center}.mode-simple{background:#2e9e5b}.mode-advanced{background:#3673c3}.mode-expert{background:#d9822b}.mode-develop{background:#c0392b}.mode-none,.mode-undefined{background:#aaa}.muted{color:#999;font-weight:400;font-size:12px}.row.custom{grid-template-columns:1fr}.row.disabled{opacity:.42}.row.disabled input,.row.disabled select,.row.disabled textarea{cursor:not-allowed;background:#f2f2f2}.lbl-cell{display:inline-flex;align-items:center;gap:5px;min-width:0}.lbl-cell .lbl{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dirty-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:#e8873a;box-shadow:0 0 0 2px #fff3e6}.override-dot{flex:0 0 auto;width:9px;height:9px;border-radius:50%;background:#f0a542;border:0;padding:0;cursor:pointer;box-shadow:0 0 0 2px #fdf1dd}.override-dot:hover{background:#d98c26}.widget-cell{display:inline-flex;align-items:center;gap:6px;min-width:0}.reset-btn{flex:0 0 auto;border:1px solid #d8b48a;background:#fbf1e4;color:#b5701f;border-radius:5px;cursor:pointer;font-size:13px;line-height:1;padding:1px 5px}.reset-btn:hover{background:#f3e2cb}.settings-panel{flex:0 0 400px;width:400px;border-left:1px solid #e2e2e2;display:flex;flex-direction:column;min-height:0;background:#fff;color:#222;font:14px/1.5 -apple-system,Segoe UI,sans-serif}.settings-panel .sp-top{padding:10px 12px 8px;border-bottom:1px solid #eee}.sp-builder{display:flex;align-items:center;gap:8px;font-size:12px;color:#666}.sp-builder select{flex:1;padding:4px 6px}.sp-pages{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}.sp-pages button{border:1px solid #e0e0e0;background:#fafafa;border-radius:6px;padding:4px 8px;font-size:12px;cursor:pointer}.sp-pages button.on{background:#e6f5ee;color:#0a7d4f;border-color:#b7e2cd;font-weight:700}.sp-modes{display:flex;gap:4px;margin-top:8px}.sp-modes button{border:0;background:none;font-size:11px;color:#888;padding:2px 6px;border-radius:6px;cursor:pointer}.sp-modes button.on{background:#eef2f0;color:#0a7d4f;font-weight:700}.settings-panel .sp-body{flex:1 1 auto;overflow-y:auto;padding:8px 14px 24px}.settings-panel .sp-body h2{font-size:16px}.settings-panel .row{grid-template-columns:1fr auto;grid-template-areas:"lbl badge" "key widget";row-gap:2px;padding:6px 0}.settings-panel .row .lbl{grid-area:lbl;font-weight:600}.settings-panel .row .badge{grid-area:badge;justify-self:end}.settings-panel .row .key{grid-area:key}.settings-panel .row .inputwrap,.settings-panel .row>select,.settings-panel .row>input,.settings-panel .row>textarea,.settings-panel .row>.pts,.settings-panel .row>.muted{grid-area:widget;justify-self:end}.settings-panel .row input:not([type=checkbox]):not([type=color]),.settings-panel .row select,.settings-panel .row textarea{max-width:200px}.settings-panel .row.custom{grid-template-columns:1fr;grid-template-areas:"lbl"}.sp-search{width:100%;box-sizing:border-box;padding:6px 9px;border:1px solid #d6d6d6;border-radius:6px;font-size:13px;margin-bottom:8px}:host(.sp-embedded) .settings-panel{position:static;width:auto;flex:none;border:0;height:auto}:host(.sp-embedded) .sp-body{padding:4px 2px 8px;max-height:460px}.bse{display:flex;flex-direction:column;gap:6px;min-width:0;max-width:220px}.bse-modes{display:flex;gap:4px}.bse-modes button{border:1px solid #e0e0e0;background:#fafafa;border-radius:6px;padding:2px 8px;font-size:11px;cursor:pointer}.bse-modes button.on{background:#e6f5ee;color:#0a7d4f;border-color:#b7e2cd;font-weight:700}.bse-grid{display:grid;grid-template-columns:1fr 1fr;gap:4px 8px}.bse-grid label{display:flex;align-items:center;gap:4px;font-size:11px;color:#666;white-space:nowrap}.bse-grid input{width:56px;padding:2px 4px;font-size:12px}.bse-json{width:100%;font:11px ui-monospace,monospace;padding:4px 6px;border:1px solid #d6d6d6;border-radius:6px;box-sizing:border-box}.bse-json.err{border-color:#d0435a;background:#fdf3f4}', R = (t, a, n, r) => [[n, r], [t + n, r], [t + n, a + r], [n, a + r]], V = (t) => {
|
|
18
|
-
const a = t / 2, n = 32;
|
|
19
|
-
return Array.from({ length: n }, (r, l) => {
|
|
20
|
-
const p = 2 * Math.PI * l / n;
|
|
21
|
-
return [+(a + a * Math.cos(p)).toFixed(2), +(a + a * Math.sin(p)).toFixed(2)];
|
|
22
|
-
});
|
|
23
|
-
}, L = (t) => {
|
|
24
|
-
const a = t.map((r) => r[0]), n = t.map((r) => r[1]);
|
|
25
|
-
return { x0: Math.min(...a), y0: Math.min(...n), w: Math.max(...a) - Math.min(...a), d: Math.max(...n) - Math.min(...n) };
|
|
14
|
+
}, T = (t) => {
|
|
15
|
+
const a = t.map((o) => o[0]), r = t.map((o) => o[1]);
|
|
16
|
+
return { x0: Math.min(...a), y0: Math.min(...r), w: Math.max(...a) - Math.min(...a), d: Math.max(...r) - Math.min(...r) };
|
|
26
17
|
};
|
|
27
|
-
function Z({ value: t, onChange: a, disabled:
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
18
|
+
function Z({ value: t, onChange: a, disabled: r }) {
|
|
19
|
+
const o = Array.isArray(t) && t.length >= 3 ? t : L, i = T(o), [u, d] = y(o.length === 4 ? "rect" : o.length >= 12 ? "circle" : "custom"), [c, p] = y({ w: i.w, d: i.d, ox: i.x0, oy: i.y0 }), [x, g] = y(Math.round(i.w)), [l, b] = y(JSON.stringify(o)), [k, w] = y(!1);
|
|
20
|
+
P(() => {
|
|
21
|
+
const n = T(o);
|
|
22
|
+
p({ w: n.w, d: n.d, ox: n.x0, oy: n.y0 }), g(Math.round(n.w)), b(JSON.stringify(o)), w(!1);
|
|
32
23
|
}, [JSON.stringify(t)]);
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
const { w: m, d:
|
|
36
|
-
m > 0 &&
|
|
37
|
-
},
|
|
38
|
-
g(
|
|
39
|
-
},
|
|
40
|
-
b(
|
|
24
|
+
const v = (n) => {
|
|
25
|
+
p(n);
|
|
26
|
+
const { w: m, d: f, ox: S, oy: M } = n;
|
|
27
|
+
m > 0 && f > 0 && a(q(m, f, S, M));
|
|
28
|
+
}, _ = (n) => {
|
|
29
|
+
g(n), n > 0 && a(V(n));
|
|
30
|
+
}, z = (n) => {
|
|
31
|
+
b(n);
|
|
41
32
|
try {
|
|
42
|
-
const m = JSON.parse(
|
|
43
|
-
if (!Array.isArray(m) || m.length < 3 || !m.every((
|
|
44
|
-
|
|
33
|
+
const m = JSON.parse(n);
|
|
34
|
+
if (!Array.isArray(m) || m.length < 3 || !m.every((f) => Array.isArray(f) && f.length === 2 && f.every(Number.isFinite))) throw 0;
|
|
35
|
+
w(!1), a(m);
|
|
45
36
|
} catch {
|
|
46
|
-
|
|
37
|
+
w(!0);
|
|
47
38
|
}
|
|
48
|
-
},
|
|
49
|
-
const m = parseFloat(
|
|
39
|
+
}, E = (n) => {
|
|
40
|
+
const m = parseFloat(n);
|
|
50
41
|
return Number.isFinite(m) ? m : 0;
|
|
51
42
|
};
|
|
52
|
-
return /* @__PURE__ */ e.createElement("div", { className: "bse", "data-testid": "bed-shape-editor" }, /* @__PURE__ */ e.createElement("div", { className: "bse-modes" }, [["rect", "Rectangular"], ["circle", "Circular"], ["custom", "Custom"]].map(([
|
|
43
|
+
return /* @__PURE__ */ e.createElement("div", { className: "bse", "data-testid": "bed-shape-editor" }, /* @__PURE__ */ e.createElement("div", { className: "bse-modes" }, [["rect", "Rectangular"], ["circle", "Circular"], ["custom", "Custom"]].map(([n, m]) => /* @__PURE__ */ e.createElement("button", { key: n, type: "button", className: u === n ? "on" : "", disabled: r, onClick: () => d(n) }, m))), u === "rect" && /* @__PURE__ */ e.createElement("div", { className: "bse-grid" }, /* @__PURE__ */ e.createElement("label", null, "Width ", /* @__PURE__ */ e.createElement(
|
|
53
44
|
"input",
|
|
54
45
|
{
|
|
55
46
|
type: "number",
|
|
56
47
|
min: "1",
|
|
57
|
-
value:
|
|
58
|
-
disabled:
|
|
48
|
+
value: c.w,
|
|
49
|
+
disabled: r,
|
|
59
50
|
"data-testid": "bed-w",
|
|
60
|
-
onChange: (
|
|
51
|
+
onChange: (n) => v({ ...c, w: E(n.target.value) })
|
|
61
52
|
}
|
|
62
53
|
), " mm"), /* @__PURE__ */ e.createElement("label", null, "Depth ", /* @__PURE__ */ e.createElement(
|
|
63
54
|
"input",
|
|
64
55
|
{
|
|
65
56
|
type: "number",
|
|
66
57
|
min: "1",
|
|
67
|
-
value:
|
|
68
|
-
disabled:
|
|
58
|
+
value: c.d,
|
|
59
|
+
disabled: r,
|
|
69
60
|
"data-testid": "bed-d",
|
|
70
|
-
onChange: (
|
|
61
|
+
onChange: (n) => v({ ...c, d: E(n.target.value) })
|
|
71
62
|
}
|
|
72
63
|
), " mm"), /* @__PURE__ */ e.createElement("label", null, "Origin X ", /* @__PURE__ */ e.createElement(
|
|
73
64
|
"input",
|
|
74
65
|
{
|
|
75
66
|
type: "number",
|
|
76
|
-
value:
|
|
77
|
-
disabled:
|
|
78
|
-
onChange: (
|
|
67
|
+
value: c.ox,
|
|
68
|
+
disabled: r,
|
|
69
|
+
onChange: (n) => v({ ...c, ox: E(n.target.value) })
|
|
79
70
|
}
|
|
80
71
|
)), /* @__PURE__ */ e.createElement("label", null, "Origin Y ", /* @__PURE__ */ e.createElement(
|
|
81
72
|
"input",
|
|
82
73
|
{
|
|
83
74
|
type: "number",
|
|
84
|
-
value:
|
|
85
|
-
disabled:
|
|
86
|
-
onChange: (
|
|
75
|
+
value: c.oy,
|
|
76
|
+
disabled: r,
|
|
77
|
+
onChange: (n) => v({ ...c, oy: E(n.target.value) })
|
|
87
78
|
}
|
|
88
|
-
))),
|
|
79
|
+
))), u === "circle" && /* @__PURE__ */ e.createElement("div", { className: "bse-grid" }, /* @__PURE__ */ e.createElement("label", null, "Diameter ", /* @__PURE__ */ e.createElement(
|
|
89
80
|
"input",
|
|
90
81
|
{
|
|
91
82
|
type: "number",
|
|
92
83
|
min: "1",
|
|
93
84
|
value: x,
|
|
94
|
-
disabled:
|
|
85
|
+
disabled: r,
|
|
95
86
|
"data-testid": "bed-dia",
|
|
96
|
-
onChange: (
|
|
87
|
+
onChange: (n) => _(E(n.target.value))
|
|
97
88
|
}
|
|
98
|
-
), " mm")),
|
|
89
|
+
), " mm")), u === "custom" && /* @__PURE__ */ e.createElement(
|
|
99
90
|
"textarea",
|
|
100
91
|
{
|
|
101
|
-
className: "bse-json" + (
|
|
92
|
+
className: "bse-json" + (k ? " err" : ""),
|
|
102
93
|
rows: 3,
|
|
103
|
-
value:
|
|
104
|
-
disabled:
|
|
94
|
+
value: l,
|
|
95
|
+
disabled: r,
|
|
105
96
|
"data-testid": "bed-json",
|
|
106
|
-
onChange: (
|
|
107
|
-
placeholder:
|
|
97
|
+
onChange: (n) => z(n.target.value),
|
|
98
|
+
placeholder: JSON.stringify(L)
|
|
108
99
|
}
|
|
109
100
|
));
|
|
110
101
|
}
|
|
111
102
|
const K = {
|
|
112
103
|
printable_area: Z
|
|
113
|
-
}, ee = ["all", "simple", "advanced", "expert", "develop"], B = (t) => t.replace("::build", "").replace("Tab", "").replace("_sla", " (SLA)"), te = (t) => /SLA|build_sla\b/.test(t) ? "SLA" : "FFF", ae = Object.fromEntries(Object.entries(
|
|
114
|
-
function oe(t, a,
|
|
115
|
-
if (!a || !(
|
|
116
|
-
const
|
|
117
|
-
return String(a[
|
|
104
|
+
}, ee = ["all", "simple", "advanced", "expert", "develop"], B = (t) => t.replace("::build", "").replace("Tab", "").replace("_sla", " (SLA)"), te = (t) => /SLA|build_sla\b/.test(t) ? "SLA" : "FFF", ae = Object.fromEntries(Object.entries(U).map(([t, a]) => [t, a.length ? [{ page: "Settings", groups: [{ group: B(t), options: a }] }] : []])), re = { makeCfg: G, disabledKeys: $ }, ne = (t) => Object.keys(t).filter((a) => t[a].length > 0);
|
|
105
|
+
function oe(t, a, r) {
|
|
106
|
+
if (!a || !(r in a)) return !1;
|
|
107
|
+
const o = t[r]?.default, i = Array.isArray(o) ? o[0] : o;
|
|
108
|
+
return String(a[r]) !== String(i ?? "");
|
|
118
109
|
}
|
|
119
|
-
function se(t, a,
|
|
120
|
-
if (
|
|
121
|
-
const
|
|
122
|
-
return
|
|
110
|
+
function se(t, a, r) {
|
|
111
|
+
if (r === "all" || a.startsWith("<")) return !0;
|
|
112
|
+
const o = t[a]?.mode;
|
|
113
|
+
return r === "simple" ? o === "simple" : r === "advanced" ? o === "simple" || o === "advanced" : !0;
|
|
123
114
|
}
|
|
124
115
|
function le(t) {
|
|
125
116
|
return t ? t.gui_type === "color" ? "color" : t.enum_values ? "select" : t.type === "coBool" || t.type === "coBools" ? "checkbox" : t.multiline || t.is_code ? "textarea" : t.type === "coPoints" || t.type === "coPoint" ? "points" : "input" : "unknown";
|
|
@@ -127,80 +118,80 @@ function le(t) {
|
|
|
127
118
|
function ie({ mode: t }) {
|
|
128
119
|
return /* @__PURE__ */ e.createElement("span", { className: `badge mode-${t ?? "none"}` }, t ?? "—");
|
|
129
120
|
}
|
|
130
|
-
function ce({ def: t, optKey: a, settings:
|
|
131
|
-
const d =
|
|
132
|
-
if (
|
|
121
|
+
function ce({ def: t, optKey: a, settings: r, setSettings: o, disabled: i, customWidgets: u }) {
|
|
122
|
+
const d = I(r, a), c = (l) => o((b) => ({ ...b, [a]: l })), p = u?.[a] ?? K[a];
|
|
123
|
+
if (p) return /* @__PURE__ */ e.createElement(p, { def: t, value: d, onChange: c, disabled: i });
|
|
133
124
|
const x = le(t), g = Array.isArray(d) ? d[0] : d;
|
|
134
125
|
switch (x) {
|
|
135
126
|
case "select":
|
|
136
|
-
return /* @__PURE__ */ e.createElement("select", { value: g ?? "", onChange: (
|
|
127
|
+
return /* @__PURE__ */ e.createElement("select", { value: g ?? "", onChange: (l) => c(l.target.value), disabled: i }, t.enum_values.map((l, b) => /* @__PURE__ */ e.createElement("option", { key: l, value: l }, t.enum_labels?.[b] ?? l)));
|
|
137
128
|
case "checkbox":
|
|
138
|
-
return /* @__PURE__ */ e.createElement("input", { type: "checkbox", checked: Array.isArray(d) ? !!d[0] : !!d, onChange: (
|
|
129
|
+
return /* @__PURE__ */ e.createElement("input", { type: "checkbox", checked: Array.isArray(d) ? !!d[0] : !!d, onChange: (l) => c(l.target.checked), disabled: i });
|
|
139
130
|
case "color":
|
|
140
|
-
return /* @__PURE__ */ e.createElement("input", { type: "color", value: typeof g == "string" && g.startsWith("#") ? g :
|
|
131
|
+
return /* @__PURE__ */ e.createElement("input", { type: "color", value: typeof g == "string" && g.startsWith("#") ? g : H, onChange: (l) => c(l.target.value), disabled: i });
|
|
141
132
|
case "textarea":
|
|
142
133
|
return /* @__PURE__ */ e.createElement("textarea", { rows: 2, value: Array.isArray(d) ? d.join(`
|
|
143
|
-
`) : d ?? "", onChange: (
|
|
134
|
+
`) : d ?? "", onChange: (l) => c(l.target.value), disabled: i });
|
|
144
135
|
case "points":
|
|
145
136
|
return /* @__PURE__ */ e.createElement("code", { className: "pts" }, JSON.stringify(d ?? []));
|
|
146
137
|
case "unknown":
|
|
147
138
|
return /* @__PURE__ */ e.createElement("span", { className: "muted" }, "No schema");
|
|
148
139
|
default:
|
|
149
|
-
return /* @__PURE__ */ e.createElement("span", { className: "inputwrap" }, /* @__PURE__ */ e.createElement("input", { value: g ?? "", onChange: (
|
|
140
|
+
return /* @__PURE__ */ e.createElement("span", { className: "inputwrap" }, /* @__PURE__ */ e.createElement("input", { value: g ?? "", onChange: (l) => c(l.target.value), disabled: i }), t.sidetext && /* @__PURE__ */ e.createElement("span", { className: "unit" }, t.sidetext));
|
|
150
141
|
}
|
|
151
142
|
}
|
|
152
|
-
function de({ schema: t, optKey: a, settings:
|
|
143
|
+
function de({ schema: t, optKey: a, settings: r, setSettings: o, disabled: i, onOptionOpen: u, customWidgets: d, overridden: c, onRevertKey: p }) {
|
|
153
144
|
if (a.startsWith("<")) return /* @__PURE__ */ e.createElement("div", { className: "row custom" }, /* @__PURE__ */ e.createElement("span", { className: "muted" }, "⚙ Custom widget ", a));
|
|
154
|
-
const x = t[a], g =
|
|
155
|
-
const
|
|
156
|
-
return delete
|
|
157
|
-
}),
|
|
158
|
-
return /* @__PURE__ */ e.createElement("div", { className: "row" + (
|
|
145
|
+
const x = t[a], g = i ? i[a] : void 0, l = g != null, b = oe(t, r, a), k = () => o((v) => {
|
|
146
|
+
const _ = { ...v };
|
|
147
|
+
return delete _[a], _;
|
|
148
|
+
}), w = x?.label || x?.full_label || a;
|
|
149
|
+
return /* @__PURE__ */ e.createElement("div", { className: "row" + (l ? " disabled" : ""), title: l ? `Disabled when: ${g}` : x?.tooltip ?? "", "data-testid": `row-${a}` }, /* @__PURE__ */ e.createElement("span", { className: "lbl-cell" }, c && /* @__PURE__ */ e.createElement(
|
|
159
150
|
"button",
|
|
160
151
|
{
|
|
161
152
|
type: "button",
|
|
162
153
|
className: "override-dot",
|
|
163
|
-
onClick: () =>
|
|
154
|
+
onClick: () => p?.(a),
|
|
164
155
|
title: "This plate's override — click to follow the global value again",
|
|
165
156
|
"data-testid": `override-${a}`
|
|
166
157
|
}
|
|
167
|
-
), b && /* @__PURE__ */ e.createElement("span", { className: "dirty-dot", title: "Changed from default", "data-testid": `dirty-${a}` }),
|
|
158
|
+
), b && /* @__PURE__ */ e.createElement("span", { className: "dirty-dot", title: "Changed from default", "data-testid": `dirty-${a}` }), u ? /* @__PURE__ */ e.createElement("button", { type: "button", className: "lbl lbl-link", onClick: () => u(a), title: "Details" }, w) : /* @__PURE__ */ e.createElement("span", { className: "lbl" }, w)), /* @__PURE__ */ e.createElement("code", { className: "key" }, a), /* @__PURE__ */ e.createElement(ie, { mode: x?.mode }), /* @__PURE__ */ e.createElement("span", { className: "widget-cell" }, /* @__PURE__ */ e.createElement(ce, { def: x, optKey: a, settings: r, setSettings: o, disabled: l, customWidgets: d }), b && /* @__PURE__ */ e.createElement("button", { className: "reset-btn", onClick: k, title: "Reset to default", "data-testid": `reset-${a}` }, "↺")));
|
|
168
159
|
}
|
|
169
|
-
function
|
|
170
|
-
schema: t =
|
|
160
|
+
function fe({
|
|
161
|
+
schema: t = R,
|
|
171
162
|
uiTree: a = ae,
|
|
172
|
-
toggle:
|
|
173
|
-
settings:
|
|
174
|
-
setSettings:
|
|
175
|
-
onOptionOpen:
|
|
163
|
+
toggle: r = re,
|
|
164
|
+
settings: o,
|
|
165
|
+
setSettings: i,
|
|
166
|
+
onOptionOpen: u,
|
|
176
167
|
embedded: d = !1,
|
|
177
|
-
customWidgets:
|
|
178
|
-
only:
|
|
168
|
+
customWidgets: c,
|
|
169
|
+
only: p,
|
|
179
170
|
overriddenKeys: x,
|
|
180
171
|
onRevertKey: g
|
|
181
172
|
}) {
|
|
182
|
-
const
|
|
173
|
+
const l = j(() => ne(a), [a]), [b, k] = y(p?.builder ?? l[0] ?? ""), [w, v] = y(0), [_, z] = y("all"), [E, n] = y(""), m = W(o), f = l.filter((s) => te(s) === m), S = p?.builder ?? (f.includes(b) ? b : f[0] ?? ""), M = a[p?.builder ?? S] ?? [], A = p?.page ? M.filter((s) => s.page === p.page) : M, O = A[Math.min(w, A.length - 1)], J = j(() => r.disabledKeys(r.makeCfg(o)), [o, r]), N = E.trim().toLowerCase(), C = j(() => N ? Object.entries(t).filter(([s, h]) => s.includes(N) || h.label?.toLowerCase().includes(N) || h.full_label?.toLowerCase().includes(N)).slice(0, 60).map(([s]) => s) : [], [N]), D = (s, h) => /* @__PURE__ */ e.createElement(
|
|
183
174
|
de,
|
|
184
175
|
{
|
|
185
176
|
schema: t,
|
|
186
|
-
key: s +
|
|
177
|
+
key: s + h,
|
|
187
178
|
optKey: s,
|
|
188
|
-
settings:
|
|
189
|
-
setSettings:
|
|
190
|
-
disabled:
|
|
191
|
-
onOptionOpen:
|
|
192
|
-
customWidgets:
|
|
179
|
+
settings: o,
|
|
180
|
+
setSettings: i,
|
|
181
|
+
disabled: J,
|
|
182
|
+
onOptionOpen: u,
|
|
183
|
+
customWidgets: c,
|
|
193
184
|
overridden: x?.includes(s),
|
|
194
185
|
onRevertKey: g
|
|
195
186
|
}
|
|
196
187
|
);
|
|
197
|
-
return /* @__PURE__ */ e.createElement(X, { css: Y, className: d ? "sp-embedded" : void 0 }, /* @__PURE__ */ e.createElement("div", { className: "settings-panel" }, !
|
|
198
|
-
|
|
199
|
-
} },
|
|
200
|
-
const
|
|
201
|
-
return
|
|
188
|
+
return /* @__PURE__ */ e.createElement(X, { css: Q + Y, className: d ? "sp-embedded" : void 0 }, /* @__PURE__ */ e.createElement("div", { className: "settings-panel" }, !p && /* @__PURE__ */ e.createElement("div", { className: "sp-top" }, /* @__PURE__ */ e.createElement("input", { className: "sp-search", placeholder: `Search options (${Object.keys(t).length})…`, value: E, onChange: (s) => n(s.target.value), "data-testid": "opt-search" }), !N && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("label", { className: "sp-builder" }, /* @__PURE__ */ e.createElement("span", null, "Settings group"), /* @__PURE__ */ e.createElement("select", { value: S, onChange: (s) => {
|
|
189
|
+
k(s.target.value), v(0);
|
|
190
|
+
} }, f.map((s) => /* @__PURE__ */ e.createElement("option", { key: s, value: s }, B(s))))), /* @__PURE__ */ e.createElement("div", { className: "sp-pages" }, A.map((s, h) => /* @__PURE__ */ e.createElement("button", { key: s.page + h, className: h === Math.min(w, A.length - 1) ? "on" : "", onClick: () => v(h) }, s.page))), /* @__PURE__ */ e.createElement("div", { className: "sp-modes" }, ee.map((s) => /* @__PURE__ */ e.createElement("button", { key: s, className: _ === s ? "on" : "", onClick: () => z(s) }, s))))), /* @__PURE__ */ e.createElement("div", { className: "sp-body" }, N ? /* @__PURE__ */ e.createElement("section", { "data-testid": "search-results" }, /* @__PURE__ */ e.createElement("h3", null, "Search: “", E, "” — ", C.length, " hit", C.length === 1 ? "" : "s", C.length === 60 ? "+" : ""), C.map(D), !C.length && /* @__PURE__ */ e.createElement("p", { className: "muted" }, "No matches")) : O ? /* @__PURE__ */ e.createElement(e.Fragment, null, !p && /* @__PURE__ */ e.createElement("h2", null, O.page, " ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, "Tab.cpp:", O.line)), O.groups.map((s) => {
|
|
191
|
+
const h = s.options.filter((F) => se(t, F, _) && !(p && F.startsWith("<")));
|
|
192
|
+
return h.length ? /* @__PURE__ */ e.createElement("section", { key: s.group + s.line }, /* @__PURE__ */ e.createElement("h3", null, s.group || "(untitled group)", " ", /* @__PURE__ */ e.createElement("span", { className: "muted" }, ":", s.line)), h.map(D)) : null;
|
|
202
193
|
})) : /* @__PURE__ */ e.createElement("p", { className: "muted" }, "No builder"))));
|
|
203
194
|
}
|
|
204
195
|
export {
|
|
205
|
-
|
|
196
|
+
fe as default
|
|
206
197
|
};
|