@operato/property-editor 10.29.9 → 10.29.12

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 CHANGED
@@ -3,6 +3,29 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ### [10.29.12](https://github.com/hatiolab/operato/compare/v10.29.11...v10.29.12) (2026-10-06)
7
+
8
+ **Note:** Version bump only for package @operato/property-editor
9
+
10
+
11
+
12
+
13
+
14
+ ### [10.29.11](https://github.com/hatiolab/operato/compare/v10.29.10...v10.29.11) (2026-10-06)
15
+
16
+
17
+ ### :rocket: New Features
18
+
19
+ * **property-editor:** number-map rows are compact and aligned, with a slider for a ranged value ([97f145e](https://github.com/hatiolab/operato/commit/97f145e732cddb4340d162321a3ab88185e23795))
20
+ * **property-editor:** thinner number-map rows, and a slider drag applies as it moves ([75ef024](https://github.com/hatiolab/operato/commit/75ef024d217bbfab74a0d96c61ac770594159ab4))
21
+
22
+
23
+ ### :bug: Bug Fix
24
+
25
+ * **property-editor:** number-map value field wide enough for a signed decimal ([7b4d851](https://github.com/hatiolab/operato/commit/7b4d8515d73e7a01cad53582c7f876d9953118ac))
26
+
27
+
28
+
6
29
  ### [10.29.9](https://github.com/hatiolab/operato/compare/v10.29.8...v10.29.9) (2026-10-05)
7
30
 
8
31
  **Note:** Version bump only for package @operato/property-editor
@@ -30,9 +30,9 @@
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">40.65% </span>
33
+ <span class="strong">45.74% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>37/91</span>
35
+ <span class='fraction'>43/94</span>
36
36
  </div>
37
37
 
38
38
 
@@ -115,8 +115,8 @@
115
115
  </td>
116
116
  <td data-value="84.39" class="pct high">84.39%</td>
117
117
  <td data-value="410" class="abs high">346/410</td>
118
- <td data-value="42.1" class="pct low">42.1%</td>
119
- <td data-value="38" class="abs low">16/38</td>
118
+ <td data-value="53.65" class="pct medium">53.65%</td>
119
+ <td data-value="41" class="abs medium">22/41</td>
120
120
  <td data-value="56.25" class="pct medium">56.25%</td>
121
121
  <td data-value="16" class="abs medium">9/16</td>
122
122
  <td data-value="84.39" class="pct high">84.39%</td>
@@ -131,7 +131,7 @@
131
131
  <div class='footer quiet pad2 space-top1 center small'>
132
132
  Code coverage generated by
133
133
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
134
- at 2026-09-26T13:35:47.979Z
134
+ at 2026-10-06T00:52:46.443Z
135
135
  </div>
136
136
  <script src="prettify.js"></script>
137
137
  <script>
@@ -524,8 +524,8 @@ FN:56,hintOf
524
524
  FN:62,_valueChanged
525
525
  FNF:3
526
526
  FNH:3
527
- FNDA:6,editorTemplate
528
- FNDA:12,hintOf
527
+ FNDA:5,editorTemplate
528
+ FNDA:10,hintOf
529
529
  FNDA:3,_valueChanged
530
530
  DA:1,1
531
531
  DA:2,1
@@ -555,38 +555,38 @@ DA:25,1
555
555
  DA:26,1
556
556
  DA:27,1
557
557
  DA:28,1
558
- DA:29,6
559
- DA:30,6
560
- DA:31,6
561
- DA:32,6
562
- DA:33,6
563
- DA:34,6
564
- DA:35,12
565
- DA:36,12
566
- DA:37,12
567
- DA:38,12
568
- DA:39,12
569
- DA:40,12
570
- DA:41,12
571
- DA:42,12
572
- DA:43,12
573
- DA:44,12
574
- DA:45,12
575
- DA:46,12
576
- DA:47,12
577
- DA:48,12
578
- DA:49,12
579
- DA:50,12
580
- DA:51,6
581
- DA:52,6
582
- DA:53,6
583
- DA:54,6
558
+ DA:29,5
559
+ DA:30,5
560
+ DA:31,5
561
+ DA:32,5
562
+ DA:33,5
563
+ DA:34,5
564
+ DA:35,10
565
+ DA:36,10
566
+ DA:37,10
567
+ DA:38,10
568
+ DA:39,10
569
+ DA:40,10
570
+ DA:41,10
571
+ DA:42,10
572
+ DA:43,10
573
+ DA:44,10
574
+ DA:45,10
575
+ DA:46,10
576
+ DA:47,10
577
+ DA:48,10
578
+ DA:49,10
579
+ DA:50,10
580
+ DA:51,5
581
+ DA:52,5
582
+ DA:53,5
583
+ DA:54,5
584
584
  DA:55,1
585
585
  DA:56,1
586
- DA:57,12
587
- DA:58,12
588
- DA:59,12
589
- DA:60,12
586
+ DA:57,10
587
+ DA:58,10
588
+ DA:59,10
589
+ DA:60,10
590
590
  DA:61,1
591
591
  DA:62,1
592
592
  DA:63,3
@@ -598,28 +598,28 @@ DA:68,3
598
598
  DA:69,3
599
599
  DA:70,3
600
600
  DA:71,3
601
- DA:72,1
602
- DA:73,1
603
- DA:74,1
604
- DA:75,1
605
- DA:76,2
606
- DA:77,2
607
- DA:78,2
608
- DA:79,2
609
- DA:80,2
601
+ DA:72,2
602
+ DA:73,2
603
+ DA:74,2
604
+ DA:75,2
605
+ DA:76,1
606
+ DA:77,1
607
+ DA:78,1
608
+ DA:79,1
609
+ DA:80,1
610
610
  DA:81,1
611
611
  LF:81
612
612
  LH:81
613
- BRDA:28,0,0,6
613
+ BRDA:28,0,0,5
614
614
  BRDA:29,1,0,0
615
615
  BRDA:29,2,0,0
616
616
  BRDA:30,3,0,0
617
- BRDA:34,4,0,12
618
- BRDA:42,5,0,8
617
+ BRDA:34,4,0,10
618
+ BRDA:42,5,0,6
619
619
  BRDA:42,6,0,4
620
620
  BRDA:42,7,0,0
621
621
  BRDA:48,8,0,0
622
- BRDA:56,9,0,12
622
+ BRDA:56,9,0,10
623
623
  BRDA:57,10,0,0
624
624
  BRDA:58,11,0,0
625
625
  BRDA:59,12,0,0
@@ -628,16 +628,19 @@ BRDA:66,14,0,0
628
628
  BRDA:67,15,0,0
629
629
  BRDA:67,16,0,0
630
630
  BRDA:68,17,0,0
631
- BRDA:70,18,0,1
632
- BRDA:70,19,0,0
633
- BRDA:70,20,0,0
634
- BRDA:71,21,0,1
635
- BRDA:73,22,0,0
636
- BRDA:73,23,0,0
637
- BRDA:76,24,0,2
638
- BRDA:67,25,0,5
639
- BRF:26
640
- BRH:10
631
+ BRDA:70,18,0,2
632
+ BRDA:70,19,0,2
633
+ BRDA:70,20,0,2
634
+ BRDA:70,21,0,2
635
+ BRDA:71,22,0,2
636
+ BRDA:73,23,0,1
637
+ BRDA:73,24,0,1
638
+ BRDA:73,25,0,1
639
+ BRDA:73,26,0,0
640
+ BRDA:76,27,0,1
641
+ BRDA:67,28,0,5
642
+ BRF:29
643
+ BRH:16
641
644
  end_of_record
642
645
  TN:
643
646
  SF:src/ox-property-editor.ts
@@ -662,13 +665,13 @@ FNDA:0,getEditor
662
665
  FNDA:4,connectedCallback
663
666
  FNDA:0,editorTemplate
664
667
  FNDA:0,getDefaultValue
665
- FNDA:6,render
666
- FNDA:6,shouldUpdate
668
+ FNDA:5,render
669
+ FNDA:5,shouldUpdate
667
670
  FNDA:0,get valueProperty
668
- FNDA:6,makeup
671
+ FNDA:5,makeup
669
672
  FNDA:0,_computeLabelId
670
673
  FNDA:0,_valueChanged
671
- FNDA:2,observe
674
+ FNDA:1,observe
672
675
  DA:1,1
673
676
  DA:2,1
674
677
  DA:3,1
@@ -903,13 +906,13 @@ DA:231,0
903
906
  DA:232,0
904
907
  DA:233,4
905
908
  DA:234,4
906
- DA:235,6
907
- DA:236,6
908
- DA:237,6
909
- DA:238,6
910
- DA:239,6
911
- DA:240,6
912
- DA:241,6
909
+ DA:235,5
910
+ DA:236,5
911
+ DA:237,5
912
+ DA:238,5
913
+ DA:239,5
914
+ DA:240,5
915
+ DA:241,5
913
916
  DA:242,0
914
917
  DA:243,0
915
918
  DA:244,0
@@ -918,8 +921,8 @@ DA:246,0
918
921
  DA:247,0
919
922
  DA:248,0
920
923
  DA:249,0
921
- DA:250,6
922
- DA:251,6
924
+ DA:250,5
925
+ DA:251,5
923
926
  DA:252,0
924
927
  DA:253,0
925
928
  DA:254,0
@@ -935,33 +938,33 @@ DA:263,0
935
938
  DA:264,0
936
939
  DA:265,0
937
940
  DA:266,0
938
- DA:267,6
939
- DA:268,6
940
- DA:269,6
941
+ DA:267,5
942
+ DA:268,5
943
+ DA:269,5
941
944
  DA:270,4
942
945
  DA:271,4
943
946
  DA:272,4
944
947
  DA:273,4
945
- DA:274,6
948
+ DA:274,5
946
949
  DA:275,0
947
950
  DA:276,0
948
- DA:277,6
949
- DA:278,6
950
- DA:279,6
951
- DA:280,6
952
- DA:281,6
953
- DA:282,6
954
- DA:283,6
955
- DA:284,6
956
- DA:285,6
951
+ DA:277,5
952
+ DA:278,5
953
+ DA:279,5
954
+ DA:280,5
955
+ DA:281,5
956
+ DA:282,5
957
+ DA:283,5
958
+ DA:284,5
959
+ DA:285,5
957
960
  DA:286,4
958
961
  DA:287,4
959
962
  DA:288,0
960
963
  DA:289,0
961
964
  DA:290,4
962
965
  DA:291,4
963
- DA:292,6
964
- DA:293,6
966
+ DA:292,5
967
+ DA:293,5
965
968
  DA:294,4
966
969
  DA:295,4
967
970
  DA:296,0
@@ -991,25 +994,25 @@ DA:319,0
991
994
  DA:320,0
992
995
  DA:321,4
993
996
  DA:322,4
994
- DA:323,2
997
+ DA:323,1
995
998
  DA:324,0
996
999
  DA:325,0
997
1000
  DA:326,0
998
1001
  DA:327,0
999
- DA:328,2
1002
+ DA:328,1
1000
1003
  DA:329,4
1001
1004
  LF:329
1002
1005
  LH:265
1003
1006
  BRDA:9,0,0,4
1004
1007
  BRDA:220,1,0,4
1005
- BRDA:234,2,0,6
1008
+ BRDA:234,2,0,5
1006
1009
  BRDA:236,3,0,0
1007
1010
  BRDA:241,4,0,0
1008
1011
  BRDA:251,5,0,0
1009
- BRDA:273,6,0,6
1012
+ BRDA:273,6,0,5
1010
1013
  BRDA:274,7,0,0
1011
- BRDA:291,8,0,6
1012
- BRDA:322,9,0,2
1014
+ BRDA:291,8,0,5
1015
+ BRDA:322,9,0,1
1013
1016
  BRDA:323,10,0,0
1014
1017
  BRDA:323,11,0,0
1015
1018
  BRF:12
@@ -11,15 +11,24 @@ export interface NumberMapEntry {
11
11
  default?: number;
12
12
  }
13
13
  /**
14
- * Several numbers kept as one map ({ key: number }) -- a figure's design values a board sets (ADR-0096), a shelf's
15
- * spacings. Each entry is the number editor's field on a row of its own, its unit beside it, its range and default in
16
- * the placeholder. A value outside its range is not taken: the field goes back to what it was. A change sends the whole
17
- * map, so the map is the one value the component holds.
14
+ * Several numbers kept as one map ({ key: number }) -- a figure's design values and state values a board sets
15
+ * (ADR-0096), a shelf's spacings. Each entry is one compact row: its name, a slider when it has a range, the number
16
+ * field, and its unit. A value outside its range is not taken: the field goes back to what it was. A change sends the
17
+ * whole map, so the map is the one value the component holds.
18
+ *
19
+ * The slider is taken at every step of a drag, so what it drives moves with the handle.
18
20
  *
19
21
  * Built by the Figure lane after the existing editors (chief architect, 2026-09-26); open for the UX lane's review.
20
22
  */
21
23
  export declare class OxPropertyEditorNumberMap extends OxPropertyEditor {
24
+ static styles: import("lit").CSSResult[];
22
25
  editorTemplate(value: any, spec: PropertySpec): TemplateResult;
26
+ /** The slider's range, when the entry has one to slide over. */
27
+ private rangeOf;
28
+ /** How far along its range a value is, in percent, for the filled part of the track. */
29
+ private fillOf;
23
30
  private hintOf;
31
+ /** While dragging the value is taken at every step, so the figure moves with the handle. */
32
+ private onSlide;
24
33
  _valueChanged(e: Event): void;
25
34
  }
@@ -1,13 +1,15 @@
1
1
  import { __decorate } from "tslib";
2
- import { html } from 'lit';
2
+ import { css, html, nothing } from 'lit';
3
3
  import { customElement } from 'lit/decorators.js';
4
4
  import { ifDefined } from 'lit/directives/if-defined.js';
5
5
  import { OxPropertyEditor } from './ox-property-editor.js';
6
6
  /**
7
- * Several numbers kept as one map ({ key: number }) -- a figure's design values a board sets (ADR-0096), a shelf's
8
- * spacings. Each entry is the number editor's field on a row of its own, its unit beside it, its range and default in
9
- * the placeholder. A value outside its range is not taken: the field goes back to what it was. A change sends the whole
10
- * map, so the map is the one value the component holds.
7
+ * Several numbers kept as one map ({ key: number }) -- a figure's design values and state values a board sets
8
+ * (ADR-0096), a shelf's spacings. Each entry is one compact row: its name, a slider when it has a range, the number
9
+ * field, and its unit. A value outside its range is not taken: the field goes back to what it was. A change sends the
10
+ * whole map, so the map is the one value the component holds.
11
+ *
12
+ * The slider is taken at every step of a drag, so what it drives moves with the handle.
11
13
  *
12
14
  * Built by the Figure lane after the existing editors (chief architect, 2026-09-26); open for the UX lane's review.
13
15
  */
@@ -17,35 +19,65 @@ let OxPropertyEditorNumberMap = class OxPropertyEditorNumberMap extends OxProper
17
19
  const entries = (_b = (_a = spec.property) === null || _a === void 0 ? void 0 : _a.entries) !== null && _b !== void 0 ? _b : [];
18
20
  const map = value && typeof value === 'object' ? value : {};
19
21
  return html `
20
- <div fullwidth>
22
+ <div fullwidth rows>
21
23
  ${entries.map(entry => {
22
24
  var _a, _b;
25
+ const shown = (_a = map[entry.key]) !== null && _a !== void 0 ? _a : entry.default;
26
+ const ranged = this.rangeOf(entry);
23
27
  return html `
24
- <div data-key=${entry.key} style="display: flex; align-items: center; gap: var(--spacing-small, 4px)">
25
- <span style="flex: 1">${entry.label}</span>
26
- <input
27
- type="number"
28
- data-key=${entry.key}
29
- aria-label=${entry.label}
30
- style="flex: 1"
31
- .value=${String((_b = (_a = map[entry.key]) !== null && _a !== void 0 ? _a : entry.default) !== null && _b !== void 0 ? _b : '')}
32
- placeholder=${ifDefined(this.hintOf(entry))}
33
- min=${ifDefined(entry.min)}
34
- max=${ifDefined(entry.max)}
35
- ?disabled=${this.disabled}
36
- />
37
- ${entry.unit ? html `<span>${entry.unit}</span>` : ''}
38
- </div>
28
+ <span name title=${entry.label}>${entry.label}</span>
29
+ ${ranged
30
+ ? html `<input
31
+ type="range"
32
+ data-key=${entry.key}
33
+ aria-label=${entry.label}
34
+ min=${ranged.min}
35
+ max=${ranged.max}
36
+ step=${ranged.step}
37
+ .value=${String(shown !== null && shown !== void 0 ? shown : ranged.min)}
38
+ style=${`--fill: ${this.fillOf(shown !== null && shown !== void 0 ? shown : ranged.min, ranged)}%`}
39
+ ?disabled=${this.disabled}
40
+ @input=${this.onSlide}
41
+ />`
42
+ : nothing}
43
+ <input
44
+ type="number"
45
+ data-key=${entry.key}
46
+ aria-label=${entry.label}
47
+ ?wide=${!ranged}
48
+ .value=${String(shown !== null && shown !== void 0 ? shown : '')}
49
+ placeholder=${ifDefined(this.hintOf(entry))}
50
+ min=${ifDefined(entry.min)}
51
+ max=${ifDefined(entry.max)}
52
+ step="any"
53
+ ?disabled=${this.disabled}
54
+ />
55
+ <span unit>${(_b = entry.unit) !== null && _b !== void 0 ? _b : ''}</span>
39
56
  `;
40
57
  })}
41
58
  </div>
42
59
  `;
43
60
  }
61
+ /** The slider's range, when the entry has one to slide over. */
62
+ rangeOf(entry) {
63
+ const { min, max } = entry;
64
+ if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min)
65
+ return undefined;
66
+ return { min: min, max: max, step: (max - min) / 100 };
67
+ }
68
+ /** How far along its range a value is, in percent, for the filled part of the track. */
69
+ fillOf(value, range) {
70
+ return Math.min(Math.max(((value - range.min) / (range.max - range.min)) * 100, 0), 100);
71
+ }
44
72
  hintOf(entry) {
45
73
  const range = entry.min !== undefined && entry.max !== undefined ? `${entry.min}–${entry.max}` : undefined;
46
74
  const standard = entry.default !== undefined ? `(${entry.default})` : undefined;
47
75
  return [range, standard].filter(Boolean).join(' ') || undefined;
48
76
  }
77
+ /** While dragging the value is taken at every step, so the figure moves with the handle. */
78
+ onSlide(e) {
79
+ this._valueChanged(e);
80
+ }
49
81
  _valueChanged(e) {
50
82
  var _a, _b, _c, _d;
51
83
  e.stopPropagation();
@@ -62,12 +94,150 @@ let OxPropertyEditorNumberMap = class OxPropertyEditorNumberMap extends OxProper
62
94
  input.value = String((_d = (_c = map[key]) !== null && _c !== void 0 ? _c : entry === null || entry === void 0 ? void 0 : entry.default) !== null && _d !== void 0 ? _d : '');
63
95
  return;
64
96
  }
65
- map[key] = number;
97
+ map[key] = input.type === 'range' ? Math.round(number * 100) / 100 : number;
66
98
  this.value = map;
99
+ this.renderRoot.querySelectorAll(`input[data-key="${key}"]`).forEach(one => {
100
+ one.value = String(map[key]);
101
+ if (one.type === 'range')
102
+ one.style.setProperty('--fill', `${this.fillOf(map[key], { min: Number(one.min), max: Number(one.max) })}%`);
103
+ });
67
104
  this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }));
68
105
  this.observe(this.value);
69
106
  }
70
107
  };
108
+ OxPropertyEditorNumberMap.styles = [
109
+ ...OxPropertyEditor.styles,
110
+ css `
111
+ /*
112
+ * The rows take the editor's own 24 columns (subgrid), so a name sits in the label column, right-aligned like
113
+ * every other label, and the fields start where every other field starts.
114
+ */
115
+ :host > div[rows] {
116
+ display: grid;
117
+ grid-template-columns: subgrid;
118
+ grid-auto-rows: 16px;
119
+ row-gap: 3px;
120
+ align-items: center;
121
+ }
122
+
123
+ :host > div[rows] > [name] {
124
+ grid-column: 1 / var(--property-editor-label-end, 9);
125
+ text-align: right;
126
+ font: var(--property-editor-label-font, var(--label-font));
127
+ color: var(--property-editor-label-color, inherit);
128
+ overflow: hidden;
129
+ text-overflow: ellipsis;
130
+ white-space: nowrap;
131
+ }
132
+
133
+ /* A thin track filled up to the value (--fill), and a small round thumb: quieter than the fields around it. */
134
+ :host > div[rows] > input[type='range'] {
135
+ grid-column: var(--property-editor-label-end, 9) / 18;
136
+ -webkit-appearance: none;
137
+ appearance: none;
138
+ width: 100%;
139
+ min-width: 0;
140
+ height: 12px;
141
+ margin: 0;
142
+ padding: 0;
143
+ border: none;
144
+ background: transparent;
145
+ cursor: pointer;
146
+ }
147
+
148
+ :host > div[rows] > input[type='range']::-webkit-slider-runnable-track {
149
+ height: 2px;
150
+ border-radius: 1px;
151
+ background: linear-gradient(
152
+ to right,
153
+ var(--md-sys-color-primary) var(--fill, 0%),
154
+ var(--md-sys-color-outline-variant) var(--fill, 0%)
155
+ );
156
+ }
157
+
158
+ :host > div[rows] > input[type='range']::-webkit-slider-thumb {
159
+ -webkit-appearance: none;
160
+ width: 8px;
161
+ height: 8px;
162
+ margin-top: -3px;
163
+ border-radius: 50%;
164
+ background: var(--md-sys-color-primary);
165
+ transition: transform 0.12s;
166
+ }
167
+
168
+ :host > div[rows] > input[type='range']:hover::-webkit-slider-thumb,
169
+ :host > div[rows] > input[type='range']:focus-visible::-webkit-slider-thumb {
170
+ transform: scale(1.4);
171
+ }
172
+
173
+ :host > div[rows] > input[type='range']::-moz-range-track {
174
+ height: 2px;
175
+ border-radius: 1px;
176
+ background: var(--md-sys-color-outline-variant);
177
+ }
178
+
179
+ :host > div[rows] > input[type='range']::-moz-range-progress {
180
+ height: 2px;
181
+ border-radius: 1px;
182
+ background: var(--md-sys-color-primary);
183
+ }
184
+
185
+ :host > div[rows] > input[type='range']::-moz-range-thumb {
186
+ width: 8px;
187
+ height: 8px;
188
+ border: none;
189
+ border-radius: 50%;
190
+ background: var(--md-sys-color-primary);
191
+ }
192
+
193
+ :host > div[rows] > input[type='range']:disabled {
194
+ cursor: default;
195
+ opacity: 0.5;
196
+ }
197
+
198
+ :host > div[rows] > input[type='number'] {
199
+ grid-column: 18 / 22;
200
+ box-sizing: border-box;
201
+ width: 100%;
202
+ min-width: 0;
203
+ height: 16px;
204
+ min-height: 0;
205
+ padding: 0 2px;
206
+ font: 0.7rem/1 var(--theme-font, Roboto, sans-serif);
207
+ /* The value reads as text; the field shows itself only when pointed at or typed in. */
208
+ background: transparent;
209
+ border-color: transparent;
210
+ border-radius: 3px;
211
+ }
212
+
213
+ :host > div[rows] > input[type='number']:hover {
214
+ border-color: var(--md-sys-color-outline-variant);
215
+ }
216
+
217
+ :host > div[rows] > input[type='number']:focus {
218
+ border-color: var(--md-sys-color-primary);
219
+ background: var(--property-editor-background, field);
220
+ }
221
+
222
+ :host > div[rows] > input[type='number']::-webkit-inner-spin-button {
223
+ display: none;
224
+ min-width: 0;
225
+ }
226
+
227
+ /* No range, no slider: the field takes the slider's room. */
228
+ :host > div[rows] > input[type='number'][wide] {
229
+ grid-column: var(--property-editor-label-end, 9) / 22;
230
+ }
231
+
232
+ :host > div[rows] > [unit] {
233
+ grid-column: 22 / -1;
234
+ overflow: hidden;
235
+ font: 0.66rem/1 var(--theme-font, Roboto, sans-serif);
236
+ color: var(--md-sys-color-outline);
237
+ white-space: nowrap;
238
+ }
239
+ `
240
+ ];
71
241
  OxPropertyEditorNumberMap = __decorate([
72
242
  customElement('ox-property-editor-number-map')
73
243
  ], OxPropertyEditorNumberMap);
@@ -1 +1 @@
1
- {"version":3,"file":"ox-property-editor-number-map.js","sourceRoot":"","sources":["../../src/ox-property-editor-number-map.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, TemplateResult } from 'lit'\nimport { customElement } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { OxPropertyEditor } from './ox-property-editor.js'\nimport { PropertySpec } from './types.js'\n\n/** One number of the map: its key, the name shown, and what it is held to. */\nexport interface NumberMapEntry {\n key: string\n label: string\n unit?: string\n min?: number\n max?: number\n default?: number\n}\n\n/**\n * Several numbers kept as one map ({ key: number }) -- a figure's design values a board sets (ADR-0096), a shelf's\n * spacings. Each entry is the number editor's field on a row of its own, its unit beside it, its range and default in\n * the placeholder. A value outside its range is not taken: the field goes back to what it was. A change sends the whole\n * map, so the map is the one value the component holds.\n *\n * Built by the Figure lane after the existing editors (chief architect, 2026-09-26); open for the UX lane's review.\n */\n@customElement('ox-property-editor-number-map')\nexport class OxPropertyEditorNumberMap extends OxPropertyEditor {\n editorTemplate(value: any, spec: PropertySpec): TemplateResult {\n const entries: NumberMapEntry[] = spec.property?.entries ?? []\n const map: Record<string, number> = value && typeof value === 'object' ? value : {}\n return html`\n <div fullwidth>\n ${entries.map(\n entry => html`\n <div data-key=${entry.key} style=\"display: flex; align-items: center; gap: var(--spacing-small, 4px)\">\n <span style=\"flex: 1\">${entry.label}</span>\n <input\n type=\"number\"\n data-key=${entry.key}\n aria-label=${entry.label}\n style=\"flex: 1\"\n .value=${String(map[entry.key] ?? entry.default ?? '')}\n placeholder=${ifDefined(this.hintOf(entry))}\n min=${ifDefined(entry.min)}\n max=${ifDefined(entry.max)}\n ?disabled=${this.disabled}\n />\n ${entry.unit ? html`<span>${entry.unit}</span>` : ''}\n </div>\n `\n )}\n </div>\n `\n }\n\n private hintOf(entry: NumberMapEntry): string | undefined {\n const range = entry.min !== undefined && entry.max !== undefined ? `${entry.min}–${entry.max}` : undefined\n const standard = entry.default !== undefined ? `(${entry.default})` : undefined\n return [range, standard].filter(Boolean).join(' ') || undefined\n }\n\n override _valueChanged(e: Event) {\n e.stopPropagation()\n const input = e.target as HTMLInputElement\n const key = input.getAttribute('data-key')\n if (!key) return\n const entry = ((this.property?.entries ?? []) as NumberMapEntry[]).find(one => one.key === key)\n const map: Record<string, number> = this.value && typeof this.value === 'object' ? { ...this.value } : {}\n const number = input.valueAsNumber\n const outside = !Number.isFinite(number) || (entry?.min !== undefined && number < entry.min) || (entry?.max !== undefined && number > entry.max)\n if (outside) {\n /* Not taken: the field shows what the map holds. */\n input.value = String(map[key] ?? entry?.default ?? '')\n return\n }\n map[key] = number\n this.value = map\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n this.observe(this.value)\n }\n}\n"]}
1
+ {"version":3,"file":"ox-property-editor-number-map.js","sourceRoot":"","sources":["../../src/ox-property-editor-number-map.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, nothing, TemplateResult } from 'lit'\nimport { customElement } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { OxPropertyEditor } from './ox-property-editor.js'\nimport { PropertySpec } from './types.js'\n\n/** One number of the map: its key, the name shown, and what it is held to. */\nexport interface NumberMapEntry {\n key: string\n label: string\n unit?: string\n min?: number\n max?: number\n default?: number\n}\n\n/**\n * Several numbers kept as one map ({ key: number }) -- a figure's design values and state values a board sets\n * (ADR-0096), a shelf's spacings. Each entry is one compact row: its name, a slider when it has a range, the number\n * field, and its unit. A value outside its range is not taken: the field goes back to what it was. A change sends the\n * whole map, so the map is the one value the component holds.\n *\n * The slider is taken at every step of a drag, so what it drives moves with the handle.\n *\n * Built by the Figure lane after the existing editors (chief architect, 2026-09-26); open for the UX lane's review.\n */\n@customElement('ox-property-editor-number-map')\nexport class OxPropertyEditorNumberMap extends OxPropertyEditor {\n static styles = [\n ...OxPropertyEditor.styles,\n css`\n /*\n * The rows take the editor's own 24 columns (subgrid), so a name sits in the label column, right-aligned like\n * every other label, and the fields start where every other field starts.\n */\n :host > div[rows] {\n display: grid;\n grid-template-columns: subgrid;\n grid-auto-rows: 16px;\n row-gap: 3px;\n align-items: center;\n }\n\n :host > div[rows] > [name] {\n grid-column: 1 / var(--property-editor-label-end, 9);\n text-align: right;\n font: var(--property-editor-label-font, var(--label-font));\n color: var(--property-editor-label-color, inherit);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* A thin track filled up to the value (--fill), and a small round thumb: quieter than the fields around it. */\n :host > div[rows] > input[type='range'] {\n grid-column: var(--property-editor-label-end, 9) / 18;\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n min-width: 0;\n height: 12px;\n margin: 0;\n padding: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n }\n\n :host > div[rows] > input[type='range']::-webkit-slider-runnable-track {\n height: 2px;\n border-radius: 1px;\n background: linear-gradient(\n to right,\n var(--md-sys-color-primary) var(--fill, 0%),\n var(--md-sys-color-outline-variant) var(--fill, 0%)\n );\n }\n\n :host > div[rows] > input[type='range']::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 8px;\n height: 8px;\n margin-top: -3px;\n border-radius: 50%;\n background: var(--md-sys-color-primary);\n transition: transform 0.12s;\n }\n\n :host > div[rows] > input[type='range']:hover::-webkit-slider-thumb,\n :host > div[rows] > input[type='range']:focus-visible::-webkit-slider-thumb {\n transform: scale(1.4);\n }\n\n :host > div[rows] > input[type='range']::-moz-range-track {\n height: 2px;\n border-radius: 1px;\n background: var(--md-sys-color-outline-variant);\n }\n\n :host > div[rows] > input[type='range']::-moz-range-progress {\n height: 2px;\n border-radius: 1px;\n background: var(--md-sys-color-primary);\n }\n\n :host > div[rows] > input[type='range']::-moz-range-thumb {\n width: 8px;\n height: 8px;\n border: none;\n border-radius: 50%;\n background: var(--md-sys-color-primary);\n }\n\n :host > div[rows] > input[type='range']:disabled {\n cursor: default;\n opacity: 0.5;\n }\n\n :host > div[rows] > input[type='number'] {\n grid-column: 18 / 22;\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 16px;\n min-height: 0;\n padding: 0 2px;\n font: 0.7rem/1 var(--theme-font, Roboto, sans-serif);\n /* The value reads as text; the field shows itself only when pointed at or typed in. */\n background: transparent;\n border-color: transparent;\n border-radius: 3px;\n }\n\n :host > div[rows] > input[type='number']:hover {\n border-color: var(--md-sys-color-outline-variant);\n }\n\n :host > div[rows] > input[type='number']:focus {\n border-color: var(--md-sys-color-primary);\n background: var(--property-editor-background, field);\n }\n\n :host > div[rows] > input[type='number']::-webkit-inner-spin-button {\n display: none;\n min-width: 0;\n }\n\n /* No range, no slider: the field takes the slider's room. */\n :host > div[rows] > input[type='number'][wide] {\n grid-column: var(--property-editor-label-end, 9) / 22;\n }\n\n :host > div[rows] > [unit] {\n grid-column: 22 / -1;\n overflow: hidden;\n font: 0.66rem/1 var(--theme-font, Roboto, sans-serif);\n color: var(--md-sys-color-outline);\n white-space: nowrap;\n }\n `\n ]\n\n editorTemplate(value: any, spec: PropertySpec): TemplateResult {\n const entries: NumberMapEntry[] = spec.property?.entries ?? []\n const map: Record<string, number> = value && typeof value === 'object' ? value : {}\n return html`\n <div fullwidth rows>\n ${entries.map(entry => {\n const shown = map[entry.key] ?? entry.default\n const ranged = this.rangeOf(entry)\n return html`\n <span name title=${entry.label}>${entry.label}</span>\n ${ranged\n ? html`<input\n type=\"range\"\n data-key=${entry.key}\n aria-label=${entry.label}\n min=${ranged.min}\n max=${ranged.max}\n step=${ranged.step}\n .value=${String(shown ?? ranged.min)}\n style=${`--fill: ${this.fillOf(shown ?? ranged.min, ranged)}%`}\n ?disabled=${this.disabled}\n @input=${this.onSlide}\n />`\n : nothing}\n <input\n type=\"number\"\n data-key=${entry.key}\n aria-label=${entry.label}\n ?wide=${!ranged}\n .value=${String(shown ?? '')}\n placeholder=${ifDefined(this.hintOf(entry))}\n min=${ifDefined(entry.min)}\n max=${ifDefined(entry.max)}\n step=\"any\"\n ?disabled=${this.disabled}\n />\n <span unit>${entry.unit ?? ''}</span>\n `\n })}\n </div>\n `\n }\n\n /** The slider's range, when the entry has one to slide over. */\n private rangeOf(entry: NumberMapEntry): { min: number; max: number; step: number } | undefined {\n const { min, max } = entry\n if (!Number.isFinite(min) || !Number.isFinite(max) || max! <= min!) return undefined\n return { min: min!, max: max!, step: (max! - min!) / 100 }\n }\n\n /** How far along its range a value is, in percent, for the filled part of the track. */\n private fillOf(value: number, range: { min: number; max: number }): number {\n return Math.min(Math.max(((value - range.min) / (range.max - range.min)) * 100, 0), 100)\n }\n\n private hintOf(entry: NumberMapEntry): string | undefined {\n const range = entry.min !== undefined && entry.max !== undefined ? `${entry.min}–${entry.max}` : undefined\n const standard = entry.default !== undefined ? `(${entry.default})` : undefined\n return [range, standard].filter(Boolean).join(' ') || undefined\n }\n\n /** While dragging the value is taken at every step, so the figure moves with the handle. */\n private onSlide(e: Event) {\n this._valueChanged(e)\n }\n\n override _valueChanged(e: Event) {\n e.stopPropagation()\n const input = e.target as HTMLInputElement\n const key = input.getAttribute('data-key')\n if (!key) return\n const entry = ((this.property?.entries ?? []) as NumberMapEntry[]).find(one => one.key === key)\n const map: Record<string, number> = this.value && typeof this.value === 'object' ? { ...this.value } : {}\n const number = input.valueAsNumber\n const outside = !Number.isFinite(number) || (entry?.min !== undefined && number < entry.min) || (entry?.max !== undefined && number > entry.max)\n if (outside) {\n /* Not taken: the field shows what the map holds. */\n input.value = String(map[key] ?? entry?.default ?? '')\n return\n }\n map[key] = input.type === 'range' ? Math.round(number * 100) / 100 : number\n this.value = map\n this.renderRoot.querySelectorAll<HTMLInputElement>(`input[data-key=\"${key}\"]`).forEach(one => {\n one.value = String(map[key])\n if (one.type === 'range') one.style.setProperty('--fill', `${this.fillOf(map[key]!, { min: Number(one.min), max: Number(one.max) })}%`)\n })\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n this.observe(this.value)\n }\n}\n"]}