@kupcad/ui 0.1.3 → 0.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kupcad/ui",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "KupCAD's UI: a three.js viewer of a model the core made, for any host (@kupcad/ui/viewer), and the Svelte panels around it (the viewer's pane, parameters, console, a language server's preview), styled by --kc-* tokens.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -36,11 +36,11 @@
36
36
  "access": "public"
37
37
  },
38
38
  "dependencies": {
39
- "@kupcad/protocol": "0.1.3",
39
+ "@kupcad/protocol": "0.1.4",
40
40
  "three": "^0.186.1"
41
41
  },
42
42
  "devDependencies": {
43
- "@kupcad/wasm": "0.1.3",
43
+ "@kupcad/wasm": "0.1.4",
44
44
  "@playwright/test": "^1.64.1",
45
45
  "@sveltejs/vite-plugin-svelte": "^7.3.1",
46
46
  "@testing-library/svelte": "^5.4.2",
@@ -2,11 +2,13 @@
2
2
  @component
3
3
  The parameters' controls, from the schema a frame (or `kupcad doc`) gives: grouped by their
4
4
  `group:`, each showing the value set in the panel, else the one the run took. `overrides` is
5
- what the panel sets (bindable), each change (and revert) given to `onchange`, which a host
6
- sends to the core; a value refused by the run is shown on its control. A bar at the top, held
7
- there as the panel scrolls, says how many values are set; while any is, its Reset all reverts
8
- them all at once, the panel's refusals with them. The button keeps its place when there is
9
- nothing to reset, so nothing under the bar moves as a first value is set or the last reverted.
5
+ what the panel sets (bindable), each change (and revert) given to `onchange` as plain values,
6
+ which a host sends to the core (to a worker, a webview's host: a list kept in state is a proxy
7
+ that a message can't copy); a value refused by the run is shown on its control. A bar at the
8
+ top, held there as the panel scrolls, says how many values are set; while any is, its Reset
9
+ all reverts them all at once, the panel's refusals with them. The button keeps its place when
10
+ there is nothing to reset, so nothing under the bar moves as a first value is set or the last
11
+ reverted.
10
12
  A value set back to the parameter's own (the one it showed before the panel set it: the run's,
11
13
  the script's or a host's preset's) is a revert, not a value set.
12
14
  -->
@@ -20,6 +22,7 @@
20
22
  withOverride,
21
23
  withoutOverride,
22
24
  } from './params.js';
25
+ import { plainValues } from './values.svelte.js';
23
26
 
24
27
  /** @import { Failure, ParamSpec, ParamValue, ParamValues, UiSchema } from '@kupcad/protocol/types' */
25
28
 
@@ -52,7 +55,7 @@
52
55
  /** @param {ParamValues} next */
53
56
  function change(next) {
54
57
  overrides = next;
55
- onchange?.(next);
58
+ onchange?.(plainValues(next));
56
59
  }
57
60
 
58
61
  /**
package/src/params.js CHANGED
@@ -60,8 +60,10 @@ export function partsOf(rule) {
60
60
  * A number control's increment: the script's `step:`, else 1 for one between a `min` and a
61
61
  * `max` (a slider moved by a hand lands on whole numbers, not on 27.41112), or, for a range
62
62
  * narrower than 1, which a step of 1 couldn't move in, the power of ten that gives it at least
63
- * ten positions; any value for a number with no range.
64
- * @param {Rule} rule
63
+ * ten positions; any value for a number with no range. Finer still where the range's ends or
64
+ * the parameter's default have more decimals: a control's steps count from its `min`, so 1.2 to
65
+ * 4 by 1 reached neither 4 nor a default of 2, which the slider showed as 2.2.
66
+ * @param {Rule | ParamSpec} rule
65
67
  * @returns {number | 'any'}
66
68
  */
67
69
  export function stepOf(rule) {
@@ -69,7 +71,32 @@ export function stepOf(rule) {
69
71
  const { min, max } = rule;
70
72
  if (min === null || max === null || !(max > min)) return 'any';
71
73
  const range = max - min;
72
- return range >= 1 ? 1 : 10 ** (Math.floor(Math.log10(range)) - 1);
74
+ const coarsest = range >= 1 ? 1 : 10 ** (Math.floor(Math.log10(range)) - 1);
75
+ const marks = [min, max];
76
+ if ('default_value' in rule && typeof rule.default_value === 'number') {
77
+ marks.push(rule.default_value);
78
+ }
79
+ const steps = marks.map(decimalStepOf);
80
+ return steps.includes(null) ? 'any' : Math.min(coarsest, .../** @type {number[]} */ (steps));
81
+ }
82
+
83
+ /** The decimal places a step may have: past them, a number is taken as having no grid. */
84
+ const MAX_PLACES = 9;
85
+
86
+ /**
87
+ * The coarsest power of ten, 1 at most, that `n` is a whole multiple of (0.1 for 1.2, 1 for 40),
88
+ * or null for a number of more than MAX_PLACES decimals.
89
+ * @param {number} n
90
+ * @returns {number | null}
91
+ */
92
+ function decimalStepOf(n) {
93
+ for (let places = 0; places <= MAX_PLACES; places += 1) {
94
+ const scaled = n * 10 ** places;
95
+ if (Math.abs(scaled - Math.round(scaled)) < 1e-9 * Math.max(1, Math.abs(scaled))) {
96
+ return 10 ** -places;
97
+ }
98
+ }
99
+ return null;
73
100
  }
74
101
 
75
102
  /**