inviton-powerduck 0.0.321 → 0.0.322
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.
|
@@ -1,474 +1,474 @@
|
|
|
1
|
-
/* Styles for <DropdownNext>. Self-contained — the new dropdown emits no
|
|
2
|
-
.select2-* class aliases and is independent of select2's stylesheet.
|
|
3
|
-
The visual design (gray chips with × on the left, blue highlighted
|
|
4
|
-
options, bold group headers, form-control 38px trigger) replicates
|
|
5
|
-
select2's default theme but every rule below targets only .pd-dd-*
|
|
6
|
-
classes our TSX emits. Verified visually against select2 via
|
|
7
|
-
dev/validate-dropdown-parity.mjs. */
|
|
8
|
-
|
|
9
|
-
.pd-dd-root {
|
|
10
|
-
position: relative;
|
|
11
|
-
display: inline-block;
|
|
12
|
-
width: 100%;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/* ── Trigger (single & multi-chip, non-tags) ─────────────────────────── */
|
|
16
|
-
|
|
17
|
-
/* Outer trigger shell — keeps the project's form-control look (Bootstrap-y,
|
|
18
|
-
* #ced4da border, 38px min-height). Inner padding (8px left / 20px right)
|
|
19
|
-
* matches select2's `.select2-selection__rendered`, so text and chips sit at
|
|
20
|
-
* the same horizontal offset as in the legacy reference. */
|
|
21
|
-
.pd-dd-trigger {
|
|
22
|
-
display: flex;
|
|
23
|
-
align-items: center;
|
|
24
|
-
min-height: 38px;
|
|
25
|
-
padding: 4px 20px 4px 8px;
|
|
26
|
-
background: #fff;
|
|
27
|
-
border: 1px solid #ced4da;
|
|
28
|
-
border-radius: 4px;
|
|
29
|
-
cursor: pointer;
|
|
30
|
-
user-select: none;
|
|
31
|
-
position: relative;
|
|
32
|
-
box-sizing: border-box;
|
|
33
|
-
font-size: 14px;
|
|
34
|
-
color: #212529;
|
|
35
|
-
line-height: 1.4;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.pd-dd-trigger.pd-dd-disabled,
|
|
39
|
-
.pd-dd-trigger[aria-disabled="true"] {
|
|
40
|
-
background: #e9ecef;
|
|
41
|
-
cursor: not-allowed;
|
|
42
|
-
color: #6c757d;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.pd-dd-trigger:focus-visible {
|
|
46
|
-
outline: none;
|
|
47
|
-
border-color: #3b82f6;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.pd-dd-root.pd-dd-open .pd-dd-trigger {
|
|
51
|
-
border-bottom-left-radius: 0;
|
|
52
|
-
border-bottom-right-radius: 0;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.pd-dd-trigger-text {
|
|
56
|
-
flex: 1;
|
|
57
|
-
min-width: 0;
|
|
58
|
-
color: inherit;
|
|
59
|
-
white-space: nowrap;
|
|
60
|
-
overflow: hidden;
|
|
61
|
-
text-overflow: ellipsis;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.pd-dd-trigger-text.pd-dd-placeholder {
|
|
65
|
-
color: #999;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.pd-dd-trigger-arrow {
|
|
69
|
-
position: absolute;
|
|
70
|
-
right: 1px;
|
|
71
|
-
top: 1px;
|
|
72
|
-
bottom: 1px;
|
|
73
|
-
width: 20px;
|
|
74
|
-
display: flex;
|
|
75
|
-
align-items: center;
|
|
76
|
-
justify-content: center;
|
|
77
|
-
pointer-events: none;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.pd-dd-trigger-arrow b {
|
|
81
|
-
display: block;
|
|
82
|
-
width: 0;
|
|
83
|
-
height: 0;
|
|
84
|
-
border: 5px solid transparent;
|
|
85
|
-
border-top-color: #888;
|
|
86
|
-
border-bottom: 0;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/* Single-select clear button (× shown when placeholder is set and a value
|
|
90
|
-
* is selected; mirrors select2's allowClear behaviour). Sits on the right of
|
|
91
|
-
* the trigger text, just before the arrow — matches select2's clear-button
|
|
92
|
-
* placement. */
|
|
93
|
-
.pd-dd-trigger-clear {
|
|
94
|
-
display: inline-flex;
|
|
95
|
-
align-items: center;
|
|
96
|
-
justify-content: center;
|
|
97
|
-
margin-left: 4px;
|
|
98
|
-
color: #999;
|
|
99
|
-
cursor: pointer;
|
|
100
|
-
font-weight: 700;
|
|
101
|
-
font-size: 14px;
|
|
102
|
-
line-height: 1;
|
|
103
|
-
padding: 0 4px;
|
|
104
|
-
flex-shrink: 0;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.pd-dd-trigger-clear:hover {
|
|
108
|
-
color: #444;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/* ── Multi-chip selection inside a non-tags trigger ──────────────────── */
|
|
112
|
-
|
|
113
|
-
.pd-dd-chips {
|
|
114
|
-
display: flex;
|
|
115
|
-
flex-wrap: wrap;
|
|
116
|
-
gap: 4px;
|
|
117
|
-
flex: 1;
|
|
118
|
-
min-width: 0;
|
|
119
|
-
align-items: center;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/* Chip — replicates select2 `.select2-selection__choice` size & colours.
|
|
123
|
-
* Order inside: <text> <×> — × on the right, opposite of older select2 but
|
|
124
|
-
* matching modern select2 4.1+ and what users expect today.
|
|
125
|
-
* `min-height: 24px` + `align-items: center` keeps chip content centered
|
|
126
|
-
* vertically regardless of the typography of custom-rendered text. */
|
|
127
|
-
.pd-dd-chip {
|
|
128
|
-
display: inline-flex;
|
|
129
|
-
align-items: center;
|
|
130
|
-
background: #e4e4e4;
|
|
131
|
-
color: #212529;
|
|
132
|
-
border: 1px solid #aaa;
|
|
133
|
-
border-radius: 4px;
|
|
134
|
-
padding: 0 5px;
|
|
135
|
-
font-size: 16px;
|
|
136
|
-
line-height: 24px;
|
|
137
|
-
min-height: 24px;
|
|
138
|
-
max-width: 100%;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.pd-dd-chip-remove {
|
|
142
|
-
display: inline-flex;
|
|
143
|
-
align-items: center;
|
|
144
|
-
justify-content: center;
|
|
145
|
-
margin-left: 4px;
|
|
146
|
-
color: #999;
|
|
147
|
-
cursor: pointer;
|
|
148
|
-
font-weight: 700;
|
|
149
|
-
font-size: 14px;
|
|
150
|
-
line-height: 1;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.pd-dd-chip-remove:hover {
|
|
154
|
-
color: #444;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/* ── Panel (popup over trigger or always-visible in inline mode) ─────── */
|
|
158
|
-
|
|
159
|
-
.pd-dd-panel {
|
|
160
|
-
position: absolute;
|
|
161
|
-
top: 100%;
|
|
162
|
-
left: 0;
|
|
163
|
-
right: 0;
|
|
164
|
-
z-index: 1051;
|
|
165
|
-
background: #fff;
|
|
166
|
-
border: 1px solid #aaa;
|
|
167
|
-
border-top: none;
|
|
168
|
-
border-bottom-left-radius: 4px;
|
|
169
|
-
border-bottom-right-radius: 4px;
|
|
170
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
171
|
-
min-width: 200px;
|
|
172
|
-
box-sizing: border-box;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
.pd-dd-panel-inner {
|
|
176
|
-
display: flex;
|
|
177
|
-
flex-direction: column;
|
|
178
|
-
max-height: 320px;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
.pd-dd-search {
|
|
182
|
-
padding: 4px;
|
|
183
|
-
border-bottom: 1px solid #eee;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.pd-dd-search-input {
|
|
187
|
-
width: 100%;
|
|
188
|
-
padding: 4px;
|
|
189
|
-
font-size: 14px;
|
|
190
|
-
line-height: 1.4;
|
|
191
|
-
border: 1px solid #aaa;
|
|
192
|
-
border-radius: 0;
|
|
193
|
-
box-sizing: border-box;
|
|
194
|
-
outline: none;
|
|
195
|
-
color: #212529;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
.pd-dd-search-input:focus {
|
|
199
|
-
border-color: #5897fb;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
.pd-dd-results {
|
|
203
|
-
overflow-y: auto;
|
|
204
|
-
max-height: 240px;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
.pd-dd-results-list {
|
|
208
|
-
list-style: none;
|
|
209
|
-
margin: 0;
|
|
210
|
-
padding: 0;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/* Option row — same look across single, multi, multi-checkboxes, inline,
|
|
214
|
-
* and tags modes. Differences (checkbox prefix, etc.) are layered on top via
|
|
215
|
-
* additional classes — never via parent-mode-specific CSS. */
|
|
216
|
-
.pd-dd-option {
|
|
217
|
-
display: flex;
|
|
218
|
-
align-items: center;
|
|
219
|
-
gap: 6px;
|
|
220
|
-
padding: 6px;
|
|
221
|
-
cursor: pointer;
|
|
222
|
-
font-size: 13px;
|
|
223
|
-
line-height: 1.4;
|
|
224
|
-
color: #212529;
|
|
225
|
-
background: transparent;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.pd-dd-option--selected,
|
|
229
|
-
.pd-dd-option--focused {
|
|
230
|
-
background: #5897fb;
|
|
231
|
-
color: #fff;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
.pd-dd-option-text {
|
|
235
|
-
flex: 1;
|
|
236
|
-
min-width: 0;
|
|
237
|
-
overflow: hidden;
|
|
238
|
-
text-overflow: ellipsis;
|
|
239
|
-
white-space: nowrap;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.pd-dd-no-results,
|
|
243
|
-
.pd-dd-error {
|
|
244
|
-
padding: 6px;
|
|
245
|
-
color: #6c757d;
|
|
246
|
-
font-style: italic;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
.pd-dd-error {
|
|
250
|
-
color: #b91c1c;
|
|
251
|
-
font-style: normal;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/* `<LoadingIndicator>` brings its own overlay + min-height; the wrapping <li>
|
|
255
|
-
* just needs to be a positioned block so the absolute overlay anchors here
|
|
256
|
-
* (LoadingIndicator's ensureMinHeight already adds `position: relative`). */
|
|
257
|
-
.pd-dd-loading {
|
|
258
|
-
list-style: none;
|
|
259
|
-
margin: 0;
|
|
260
|
-
padding: 0;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/* Group header — bold, slightly indented, non-interactive */
|
|
264
|
-
.pd-dd-group-header {
|
|
265
|
-
padding: 6px;
|
|
266
|
-
font-size: 13px;
|
|
267
|
-
font-weight: 700;
|
|
268
|
-
color: #212529;
|
|
269
|
-
cursor: default;
|
|
270
|
-
pointer-events: none;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/* Multi-checkboxes mode: each option row gets a Powerduck-style `form-check`
|
|
274
|
-
* checkbox (NowUi skin, same markup as <CheckBox skin={NowUi} size={Small}>
|
|
275
|
-
* everywhere else in the app). `pointer-events: none` makes the whole
|
|
276
|
-
* checkbox visually-only — clicks pass through to the parent <li> which owns
|
|
277
|
-
* the toggle path. The checkbox's `checked` attribute mirrors the row's
|
|
278
|
-
* selection state via Vue's prop diffing on re-render. */
|
|
279
|
-
.pd-dd-cb {
|
|
280
|
-
display: inline-flex;
|
|
281
|
-
align-items: center;
|
|
282
|
-
margin: 0;
|
|
283
|
-
padding: 0;
|
|
284
|
-
pointer-events: none;
|
|
285
|
-
flex-shrink: 0;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
.pd-dd-cb .form-check-label {
|
|
289
|
-
margin: 0;
|
|
290
|
-
padding: 0;
|
|
291
|
-
min-height: 0;
|
|
292
|
-
cursor: inherit;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/* "Add: <typed>" suggestion row appears at the end of the tag-mode option list
|
|
296
|
-
* when nothing matches the typed query. Visually consistent with normal rows. */
|
|
297
|
-
.pd-dd-option-add {
|
|
298
|
-
font-style: italic;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/* ── Header (OK button for Checkboxes mode) ──────────────────────────── */
|
|
302
|
-
|
|
303
|
-
/* Mirrors select2's `.s2-cb-btn` from the s2-multi-cb plugin — single
|
|
304
|
-
* commit button anchored at the top of the panel. Used by Checkboxes mode
|
|
305
|
-
* only; multi-chip mode keeps Done/Cancel in the footer below. */
|
|
306
|
-
.pd-dd-header {
|
|
307
|
-
padding: 6px;
|
|
308
|
-
border-bottom: 1px solid #eee;
|
|
309
|
-
display: flex;
|
|
310
|
-
justify-content: flex-end;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
.pd-dd-header .btn {
|
|
314
|
-
font-size: 13px;
|
|
315
|
-
padding: 4px 12px;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/* ── Footer (Done button for chip-mode multi-select only) ────────────── */
|
|
319
|
-
|
|
320
|
-
.pd-dd-footer {
|
|
321
|
-
display: flex;
|
|
322
|
-
justify-content: flex-end;
|
|
323
|
-
gap: 6px;
|
|
324
|
-
padding: 6px;
|
|
325
|
-
border-top: 1px solid #eee;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
.pd-dd-footer .btn {
|
|
329
|
-
font-size: 13px;
|
|
330
|
-
padding: 4px 10px;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/* ── Tags mode ───────────────────────────────────────────────────────── */
|
|
334
|
-
|
|
335
|
-
.pd-dd-tags-root {
|
|
336
|
-
width: 100%;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
.pd-dd-tags-trigger {
|
|
340
|
-
min-height: 38px;
|
|
341
|
-
padding: 0;
|
|
342
|
-
background: #fff;
|
|
343
|
-
border: 1px solid #ced4da;
|
|
344
|
-
border-radius: 4px;
|
|
345
|
-
display: block;
|
|
346
|
-
box-sizing: border-box;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/* Inner UL mirrors select2's `.select2-selection__rendered`:
|
|
350
|
-
* horizontal padding 5px, no flex gap (each chip carries its own
|
|
351
|
-
* `margin: 5px 5px 0 0` so chips align to the top of the trigger). */
|
|
352
|
-
.pd-dd-tags-chips {
|
|
353
|
-
list-style: none;
|
|
354
|
-
margin: 0;
|
|
355
|
-
padding: 0 5px;
|
|
356
|
-
display: flex;
|
|
357
|
-
flex-wrap: wrap;
|
|
358
|
-
align-items: flex-start;
|
|
359
|
-
min-height: 24px;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/* Tag chip — matches select2 `.select2-selection__choice` (16px/24px font,
|
|
363
|
-
* 26px effective height, 5px top margin so chips sit just below the trigger
|
|
364
|
-
* border). The 5px top margin (plus chip border + padding) brings each chip
|
|
365
|
-
* to ~32px overall height, near-flush with the trigger's bottom edge. */
|
|
366
|
-
.pd-dd-tag-chip {
|
|
367
|
-
display: inline-flex;
|
|
368
|
-
align-items: center;
|
|
369
|
-
background: #e4e4e4;
|
|
370
|
-
color: #212529;
|
|
371
|
-
border: 1px solid #aaa;
|
|
372
|
-
border-radius: 4px;
|
|
373
|
-
padding: 0 5px;
|
|
374
|
-
margin: 5px 5px 0 0;
|
|
375
|
-
font-size: 16px;
|
|
376
|
-
line-height: 24px;
|
|
377
|
-
max-width: 100%;
|
|
378
|
-
cursor: default;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
.pd-dd-chip-action {
|
|
382
|
-
display: inline-flex;
|
|
383
|
-
align-items: center;
|
|
384
|
-
justify-content: center;
|
|
385
|
-
margin: 0 2px;
|
|
386
|
-
color: #4b5563;
|
|
387
|
-
cursor: pointer;
|
|
388
|
-
font-size: 12px;
|
|
389
|
-
padding: 0 2px;
|
|
390
|
-
border-radius: 2px;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
.pd-dd-chip-action:hover {
|
|
394
|
-
background: #d9d9d9;
|
|
395
|
-
color: #111827;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
.pd-dd-tag-input-host {
|
|
399
|
-
display: inline-flex;
|
|
400
|
-
flex: 1 1 80px;
|
|
401
|
-
min-width: 80px;
|
|
402
|
-
margin-top: 5px;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/* Inline search input that doubles as the placeholder host when the chip
|
|
406
|
-
* list is empty. Uses the same 16px/24px text size as chips so empty
|
|
407
|
-
* placeholder text and any filled value sit on the same baseline. */
|
|
408
|
-
.pd-dd-tag-input {
|
|
409
|
-
border: none;
|
|
410
|
-
outline: none;
|
|
411
|
-
background: transparent;
|
|
412
|
-
font-size: 16px;
|
|
413
|
-
line-height: 24px;
|
|
414
|
-
flex: 1;
|
|
415
|
-
min-width: 80px;
|
|
416
|
-
padding: 0;
|
|
417
|
-
margin: 0;
|
|
418
|
-
color: #212529;
|
|
419
|
-
height: 24px;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
.pd-dd-tag-input:disabled {
|
|
423
|
-
cursor: not-allowed;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
/* Placeholder colour matches `.pd-dd-trigger-text.pd-dd-placeholder` so the
|
|
427
|
-
* empty-state look in tags mode is identical to single-select. */
|
|
428
|
-
.pd-dd-tag-input::placeholder {
|
|
429
|
-
color: #999;
|
|
430
|
-
opacity: 1;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
/* Sortable.js dragging affordance */
|
|
434
|
-
.pd-dd-tag-chip.sortable-ghost {
|
|
435
|
-
opacity: 0.4;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
.pd-dd-tag-chip.sortable-chosen {
|
|
439
|
-
background: #cbd5e0;
|
|
440
|
-
border-color: #5897fb;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/* ── Inline mode ─────────────────────────────────────────────────────── */
|
|
444
|
-
|
|
445
|
-
.pd-dd-inline {
|
|
446
|
-
width: 100%;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
.pd-dd-panel-inline {
|
|
450
|
-
position: static;
|
|
451
|
-
box-shadow: none;
|
|
452
|
-
margin: 0;
|
|
453
|
-
min-width: 0;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
.pd-dd-panel-inline .pd-dd-panel-inner {
|
|
457
|
-
max-height: none;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
.pd-dd-panel-inline .pd-dd-results {
|
|
461
|
-
max-height: none;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/* Migration sentinel: MIGRATION.md tells consumers to replace the deprecated
|
|
465
|
-
* `afterBound` animation-disable hook with `cssClass="pd-dd-no-animation"`.
|
|
466
|
-
* The base component currently has no open/close transitions, so the class
|
|
467
|
-
* acts as a no-op marker today. Keep the selector here so any future
|
|
468
|
-
* animation rules can opt out via `:not(.pd-dd-no-animation)` and the
|
|
469
|
-
* promised migration target stays a real class. */
|
|
470
|
-
.pd-dd-root.pd-dd-no-animation,
|
|
471
|
-
.pd-dd-root.pd-dd-no-animation .pd-dd-panel {
|
|
472
|
-
transition: none !important;
|
|
473
|
-
animation: none !important;
|
|
474
|
-
}
|
|
1
|
+
/* Styles for <DropdownNext>. Self-contained — the new dropdown emits no
|
|
2
|
+
.select2-* class aliases and is independent of select2's stylesheet.
|
|
3
|
+
The visual design (gray chips with × on the left, blue highlighted
|
|
4
|
+
options, bold group headers, form-control 38px trigger) replicates
|
|
5
|
+
select2's default theme but every rule below targets only .pd-dd-*
|
|
6
|
+
classes our TSX emits. Verified visually against select2 via
|
|
7
|
+
dev/validate-dropdown-parity.mjs. */
|
|
8
|
+
|
|
9
|
+
.pd-dd-root {
|
|
10
|
+
position: relative;
|
|
11
|
+
display: inline-block;
|
|
12
|
+
width: 100%;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* ── Trigger (single & multi-chip, non-tags) ─────────────────────────── */
|
|
16
|
+
|
|
17
|
+
/* Outer trigger shell — keeps the project's form-control look (Bootstrap-y,
|
|
18
|
+
* #ced4da border, 38px min-height). Inner padding (8px left / 20px right)
|
|
19
|
+
* matches select2's `.select2-selection__rendered`, so text and chips sit at
|
|
20
|
+
* the same horizontal offset as in the legacy reference. */
|
|
21
|
+
.pd-dd-trigger {
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
min-height: 38px;
|
|
25
|
+
padding: 4px 20px 4px 8px;
|
|
26
|
+
background: #fff;
|
|
27
|
+
border: 1px solid #ced4da;
|
|
28
|
+
border-radius: 4px;
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
user-select: none;
|
|
31
|
+
position: relative;
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
color: #212529;
|
|
35
|
+
line-height: 1.4;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.pd-dd-trigger.pd-dd-disabled,
|
|
39
|
+
.pd-dd-trigger[aria-disabled="true"] {
|
|
40
|
+
background: #e9ecef;
|
|
41
|
+
cursor: not-allowed;
|
|
42
|
+
color: #6c757d;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.pd-dd-trigger:focus-visible {
|
|
46
|
+
outline: none;
|
|
47
|
+
border-color: #3b82f6;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.pd-dd-root.pd-dd-open .pd-dd-trigger {
|
|
51
|
+
border-bottom-left-radius: 0;
|
|
52
|
+
border-bottom-right-radius: 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.pd-dd-trigger-text {
|
|
56
|
+
flex: 1;
|
|
57
|
+
min-width: 0;
|
|
58
|
+
color: inherit;
|
|
59
|
+
white-space: nowrap;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
text-overflow: ellipsis;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.pd-dd-trigger-text.pd-dd-placeholder {
|
|
65
|
+
color: #999;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.pd-dd-trigger-arrow {
|
|
69
|
+
position: absolute;
|
|
70
|
+
right: 1px;
|
|
71
|
+
top: 1px;
|
|
72
|
+
bottom: 1px;
|
|
73
|
+
width: 20px;
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
pointer-events: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.pd-dd-trigger-arrow b {
|
|
81
|
+
display: block;
|
|
82
|
+
width: 0;
|
|
83
|
+
height: 0;
|
|
84
|
+
border: 5px solid transparent;
|
|
85
|
+
border-top-color: #888;
|
|
86
|
+
border-bottom: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Single-select clear button (× shown when placeholder is set and a value
|
|
90
|
+
* is selected; mirrors select2's allowClear behaviour). Sits on the right of
|
|
91
|
+
* the trigger text, just before the arrow — matches select2's clear-button
|
|
92
|
+
* placement. */
|
|
93
|
+
.pd-dd-trigger-clear {
|
|
94
|
+
display: inline-flex;
|
|
95
|
+
align-items: center;
|
|
96
|
+
justify-content: center;
|
|
97
|
+
margin-left: 4px;
|
|
98
|
+
color: #999;
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
font-weight: 700;
|
|
101
|
+
font-size: 14px;
|
|
102
|
+
line-height: 1;
|
|
103
|
+
padding: 0 4px;
|
|
104
|
+
flex-shrink: 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.pd-dd-trigger-clear:hover {
|
|
108
|
+
color: #444;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ── Multi-chip selection inside a non-tags trigger ──────────────────── */
|
|
112
|
+
|
|
113
|
+
.pd-dd-chips {
|
|
114
|
+
display: flex;
|
|
115
|
+
flex-wrap: wrap;
|
|
116
|
+
gap: 4px;
|
|
117
|
+
flex: 1;
|
|
118
|
+
min-width: 0;
|
|
119
|
+
align-items: center;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Chip — replicates select2 `.select2-selection__choice` size & colours.
|
|
123
|
+
* Order inside: <text> <×> — × on the right, opposite of older select2 but
|
|
124
|
+
* matching modern select2 4.1+ and what users expect today.
|
|
125
|
+
* `min-height: 24px` + `align-items: center` keeps chip content centered
|
|
126
|
+
* vertically regardless of the typography of custom-rendered text. */
|
|
127
|
+
.pd-dd-chip {
|
|
128
|
+
display: inline-flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
background: #e4e4e4;
|
|
131
|
+
color: #212529;
|
|
132
|
+
border: 1px solid #aaa;
|
|
133
|
+
border-radius: 4px;
|
|
134
|
+
padding: 0 5px;
|
|
135
|
+
font-size: 16px;
|
|
136
|
+
line-height: 24px;
|
|
137
|
+
min-height: 24px;
|
|
138
|
+
max-width: 100%;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.pd-dd-chip-remove {
|
|
142
|
+
display: inline-flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
justify-content: center;
|
|
145
|
+
margin-left: 4px;
|
|
146
|
+
color: #999;
|
|
147
|
+
cursor: pointer;
|
|
148
|
+
font-weight: 700;
|
|
149
|
+
font-size: 14px;
|
|
150
|
+
line-height: 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.pd-dd-chip-remove:hover {
|
|
154
|
+
color: #444;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* ── Panel (popup over trigger or always-visible in inline mode) ─────── */
|
|
158
|
+
|
|
159
|
+
.pd-dd-panel {
|
|
160
|
+
position: absolute;
|
|
161
|
+
top: 100%;
|
|
162
|
+
left: 0;
|
|
163
|
+
right: 0;
|
|
164
|
+
z-index: 1051;
|
|
165
|
+
background: #fff;
|
|
166
|
+
border: 1px solid #aaa;
|
|
167
|
+
border-top: none;
|
|
168
|
+
border-bottom-left-radius: 4px;
|
|
169
|
+
border-bottom-right-radius: 4px;
|
|
170
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
171
|
+
min-width: 200px;
|
|
172
|
+
box-sizing: border-box;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.pd-dd-panel-inner {
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
max-height: 320px;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.pd-dd-search {
|
|
182
|
+
padding: 4px;
|
|
183
|
+
border-bottom: 1px solid #eee;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.pd-dd-search-input {
|
|
187
|
+
width: 100%;
|
|
188
|
+
padding: 4px;
|
|
189
|
+
font-size: 14px;
|
|
190
|
+
line-height: 1.4;
|
|
191
|
+
border: 1px solid #aaa;
|
|
192
|
+
border-radius: 0;
|
|
193
|
+
box-sizing: border-box;
|
|
194
|
+
outline: none;
|
|
195
|
+
color: #212529;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.pd-dd-search-input:focus {
|
|
199
|
+
border-color: #5897fb;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.pd-dd-results {
|
|
203
|
+
overflow-y: auto;
|
|
204
|
+
max-height: 240px;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.pd-dd-results-list {
|
|
208
|
+
list-style: none;
|
|
209
|
+
margin: 0;
|
|
210
|
+
padding: 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/* Option row — same look across single, multi, multi-checkboxes, inline,
|
|
214
|
+
* and tags modes. Differences (checkbox prefix, etc.) are layered on top via
|
|
215
|
+
* additional classes — never via parent-mode-specific CSS. */
|
|
216
|
+
.pd-dd-option {
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
gap: 6px;
|
|
220
|
+
padding: 6px;
|
|
221
|
+
cursor: pointer;
|
|
222
|
+
font-size: 13px;
|
|
223
|
+
line-height: 1.4;
|
|
224
|
+
color: #212529;
|
|
225
|
+
background: transparent;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.pd-dd-option--selected,
|
|
229
|
+
.pd-dd-option--focused {
|
|
230
|
+
background: #5897fb;
|
|
231
|
+
color: #fff;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.pd-dd-option-text {
|
|
235
|
+
flex: 1;
|
|
236
|
+
min-width: 0;
|
|
237
|
+
overflow: hidden;
|
|
238
|
+
text-overflow: ellipsis;
|
|
239
|
+
white-space: nowrap;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.pd-dd-no-results,
|
|
243
|
+
.pd-dd-error {
|
|
244
|
+
padding: 6px;
|
|
245
|
+
color: #6c757d;
|
|
246
|
+
font-style: italic;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.pd-dd-error {
|
|
250
|
+
color: #b91c1c;
|
|
251
|
+
font-style: normal;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* `<LoadingIndicator>` brings its own overlay + min-height; the wrapping <li>
|
|
255
|
+
* just needs to be a positioned block so the absolute overlay anchors here
|
|
256
|
+
* (LoadingIndicator's ensureMinHeight already adds `position: relative`). */
|
|
257
|
+
.pd-dd-loading {
|
|
258
|
+
list-style: none;
|
|
259
|
+
margin: 0;
|
|
260
|
+
padding: 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* Group header — bold, slightly indented, non-interactive */
|
|
264
|
+
.pd-dd-group-header {
|
|
265
|
+
padding: 6px;
|
|
266
|
+
font-size: 13px;
|
|
267
|
+
font-weight: 700;
|
|
268
|
+
color: #212529;
|
|
269
|
+
cursor: default;
|
|
270
|
+
pointer-events: none;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* Multi-checkboxes mode: each option row gets a Powerduck-style `form-check`
|
|
274
|
+
* checkbox (NowUi skin, same markup as <CheckBox skin={NowUi} size={Small}>
|
|
275
|
+
* everywhere else in the app). `pointer-events: none` makes the whole
|
|
276
|
+
* checkbox visually-only — clicks pass through to the parent <li> which owns
|
|
277
|
+
* the toggle path. The checkbox's `checked` attribute mirrors the row's
|
|
278
|
+
* selection state via Vue's prop diffing on re-render. */
|
|
279
|
+
.pd-dd-cb {
|
|
280
|
+
display: inline-flex;
|
|
281
|
+
align-items: center;
|
|
282
|
+
margin: 0;
|
|
283
|
+
padding: 0;
|
|
284
|
+
pointer-events: none;
|
|
285
|
+
flex-shrink: 0;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.pd-dd-cb .form-check-label {
|
|
289
|
+
margin: 0;
|
|
290
|
+
padding: 0;
|
|
291
|
+
min-height: 0;
|
|
292
|
+
cursor: inherit;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* "Add: <typed>" suggestion row appears at the end of the tag-mode option list
|
|
296
|
+
* when nothing matches the typed query. Visually consistent with normal rows. */
|
|
297
|
+
.pd-dd-option-add {
|
|
298
|
+
font-style: italic;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/* ── Header (OK button for Checkboxes mode) ──────────────────────────── */
|
|
302
|
+
|
|
303
|
+
/* Mirrors select2's `.s2-cb-btn` from the s2-multi-cb plugin — single
|
|
304
|
+
* commit button anchored at the top of the panel. Used by Checkboxes mode
|
|
305
|
+
* only; multi-chip mode keeps Done/Cancel in the footer below. */
|
|
306
|
+
.pd-dd-header {
|
|
307
|
+
padding: 6px;
|
|
308
|
+
border-bottom: 1px solid #eee;
|
|
309
|
+
display: flex;
|
|
310
|
+
justify-content: flex-end;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.pd-dd-header .btn {
|
|
314
|
+
font-size: 13px;
|
|
315
|
+
padding: 4px 12px;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/* ── Footer (Done button for chip-mode multi-select only) ────────────── */
|
|
319
|
+
|
|
320
|
+
.pd-dd-footer {
|
|
321
|
+
display: flex;
|
|
322
|
+
justify-content: flex-end;
|
|
323
|
+
gap: 6px;
|
|
324
|
+
padding: 6px;
|
|
325
|
+
border-top: 1px solid #eee;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.pd-dd-footer .btn {
|
|
329
|
+
font-size: 13px;
|
|
330
|
+
padding: 4px 10px;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* ── Tags mode ───────────────────────────────────────────────────────── */
|
|
334
|
+
|
|
335
|
+
.pd-dd-tags-root {
|
|
336
|
+
width: 100%;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.pd-dd-tags-trigger {
|
|
340
|
+
min-height: 38px;
|
|
341
|
+
padding: 0;
|
|
342
|
+
background: #fff;
|
|
343
|
+
border: 1px solid #ced4da;
|
|
344
|
+
border-radius: 4px;
|
|
345
|
+
display: block;
|
|
346
|
+
box-sizing: border-box;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/* Inner UL mirrors select2's `.select2-selection__rendered`:
|
|
350
|
+
* horizontal padding 5px, no flex gap (each chip carries its own
|
|
351
|
+
* `margin: 5px 5px 0 0` so chips align to the top of the trigger). */
|
|
352
|
+
.pd-dd-tags-chips {
|
|
353
|
+
list-style: none;
|
|
354
|
+
margin: 0;
|
|
355
|
+
padding: 0 5px;
|
|
356
|
+
display: flex;
|
|
357
|
+
flex-wrap: wrap;
|
|
358
|
+
align-items: flex-start;
|
|
359
|
+
min-height: 24px;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* Tag chip — matches select2 `.select2-selection__choice` (16px/24px font,
|
|
363
|
+
* 26px effective height, 5px top margin so chips sit just below the trigger
|
|
364
|
+
* border). The 5px top margin (plus chip border + padding) brings each chip
|
|
365
|
+
* to ~32px overall height, near-flush with the trigger's bottom edge. */
|
|
366
|
+
.pd-dd-tag-chip {
|
|
367
|
+
display: inline-flex;
|
|
368
|
+
align-items: center;
|
|
369
|
+
background: #e4e4e4;
|
|
370
|
+
color: #212529;
|
|
371
|
+
border: 1px solid #aaa;
|
|
372
|
+
border-radius: 4px;
|
|
373
|
+
padding: 0 5px;
|
|
374
|
+
margin: 5px 5px 0 0;
|
|
375
|
+
font-size: 16px;
|
|
376
|
+
line-height: 24px;
|
|
377
|
+
max-width: 100%;
|
|
378
|
+
cursor: default;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.pd-dd-chip-action {
|
|
382
|
+
display: inline-flex;
|
|
383
|
+
align-items: center;
|
|
384
|
+
justify-content: center;
|
|
385
|
+
margin: 0 2px;
|
|
386
|
+
color: #4b5563;
|
|
387
|
+
cursor: pointer;
|
|
388
|
+
font-size: 12px;
|
|
389
|
+
padding: 0 2px;
|
|
390
|
+
border-radius: 2px;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.pd-dd-chip-action:hover {
|
|
394
|
+
background: #d9d9d9;
|
|
395
|
+
color: #111827;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.pd-dd-tag-input-host {
|
|
399
|
+
display: inline-flex;
|
|
400
|
+
flex: 1 1 80px;
|
|
401
|
+
min-width: 80px;
|
|
402
|
+
margin-top: 5px;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/* Inline search input that doubles as the placeholder host when the chip
|
|
406
|
+
* list is empty. Uses the same 16px/24px text size as chips so empty
|
|
407
|
+
* placeholder text and any filled value sit on the same baseline. */
|
|
408
|
+
.pd-dd-tag-input {
|
|
409
|
+
border: none;
|
|
410
|
+
outline: none;
|
|
411
|
+
background: transparent;
|
|
412
|
+
font-size: 16px;
|
|
413
|
+
line-height: 24px;
|
|
414
|
+
flex: 1;
|
|
415
|
+
min-width: 80px;
|
|
416
|
+
padding: 0;
|
|
417
|
+
margin: 0;
|
|
418
|
+
color: #212529;
|
|
419
|
+
height: 24px;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.pd-dd-tag-input:disabled {
|
|
423
|
+
cursor: not-allowed;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/* Placeholder colour matches `.pd-dd-trigger-text.pd-dd-placeholder` so the
|
|
427
|
+
* empty-state look in tags mode is identical to single-select. */
|
|
428
|
+
.pd-dd-tag-input::placeholder {
|
|
429
|
+
color: #999;
|
|
430
|
+
opacity: 1;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/* Sortable.js dragging affordance */
|
|
434
|
+
.pd-dd-tag-chip.sortable-ghost {
|
|
435
|
+
opacity: 0.4;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.pd-dd-tag-chip.sortable-chosen {
|
|
439
|
+
background: #cbd5e0;
|
|
440
|
+
border-color: #5897fb;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/* ── Inline mode ─────────────────────────────────────────────────────── */
|
|
444
|
+
|
|
445
|
+
.pd-dd-inline {
|
|
446
|
+
width: 100%;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.pd-dd-panel-inline {
|
|
450
|
+
position: static;
|
|
451
|
+
box-shadow: none;
|
|
452
|
+
margin: 0;
|
|
453
|
+
min-width: 0;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.pd-dd-panel-inline .pd-dd-panel-inner {
|
|
457
|
+
max-height: none;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.pd-dd-panel-inline .pd-dd-results {
|
|
461
|
+
max-height: none;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/* Migration sentinel: MIGRATION.md tells consumers to replace the deprecated
|
|
465
|
+
* `afterBound` animation-disable hook with `cssClass="pd-dd-no-animation"`.
|
|
466
|
+
* The base component currently has no open/close transitions, so the class
|
|
467
|
+
* acts as a no-op marker today. Keep the selector here so any future
|
|
468
|
+
* animation rules can opt out via `:not(.pd-dd-no-animation)` and the
|
|
469
|
+
* promised migration target stays a real class. */
|
|
470
|
+
.pd-dd-root.pd-dd-no-animation,
|
|
471
|
+
.pd-dd-root.pd-dd-no-animation .pd-dd-panel {
|
|
472
|
+
transition: none !important;
|
|
473
|
+
animation: none !important;
|
|
474
|
+
}
|
|
@@ -614,7 +614,10 @@ class DropdownListComponent extends TsxComponent<DropdownListArgs> implements Dr
|
|
|
614
614
|
|
|
615
615
|
this.searchQuery = '';
|
|
616
616
|
this.focusedFlatIndex = -1;
|
|
617
|
-
|
|
617
|
+
// Tags mode commits per click via toggleTagItem (emits `changed` directly).
|
|
618
|
+
// Initialising pendingMulti here would cause close()'s commit branch to
|
|
619
|
+
// re-emit the pre-toggle selection and override per-click commits — QA_GO-429 Bug A.
|
|
620
|
+
if (this.multiselect === true && this.tags !== true) {
|
|
618
621
|
this.pendingMulti = [...this.getSelectedIds()];
|
|
619
622
|
}
|
|
620
623
|
|
|
@@ -227,6 +227,18 @@ class NumericInputComponent extends TsxComponent<NumericInputArgs> implements Nu
|
|
|
227
227
|
const renderedValue = applyDecimals ? newValue.toFixed(decimals) : (newValue ?? '');
|
|
228
228
|
|
|
229
229
|
(this.$el as HTMLElement)?.querySelectorAll('input').forEach((input) => {
|
|
230
|
+
// Don't stomp the in-progress value while the user is typing. The Spinner-mode
|
|
231
|
+
// value interceptor + InputSpinner editor would otherwise re-format `input.value`
|
|
232
|
+
// to `Intl.NumberFormat(...)` then a follow-up re-render snaps it back to the
|
|
233
|
+
// stale prop — QA_GO-429 Bug B.
|
|
234
|
+
const active = (typeof document !== 'undefined' ? document.activeElement : null) as HTMLElement | null;
|
|
235
|
+
const isThisInputFocused = active === input
|
|
236
|
+
|| (active != null && active.closest('.input-spinner-wrap')?.contains(input) === true);
|
|
237
|
+
|
|
238
|
+
if (isThisInputFocused) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
230
242
|
input.value = String(renderedValue);
|
|
231
243
|
});
|
|
232
244
|
}
|
|
@@ -146,7 +146,28 @@ export class InputSpinner {
|
|
|
146
146
|
// Intercept direct writes to original.value (e.g. `input.value = '5'` from
|
|
147
147
|
// Vue updates) so the visible spinner input stays in sync without callers
|
|
148
148
|
// having to know about `setValue`.
|
|
149
|
+
//
|
|
150
|
+
// QA_GO-429 Bug B: short-circuit the callback when (a) the value the
|
|
151
|
+
// caller wrote is what the spinner already cached, OR (b) the write
|
|
152
|
+
// originated from the spinner's own `setValue()` (re-entry guard).
|
|
153
|
+
// Without these guards every `self.original.value = X` inside `setValue`
|
|
154
|
+
// re-queues another `setTimeout(setValue(X))`, an infinite setTimeout
|
|
155
|
+
// recursion that fires hundreds of times per second and clobbers the
|
|
156
|
+
// user's typed value every frame — see the Bug B trace in QA_GO-429.
|
|
149
157
|
installValueInterceptor(self.original, (newVal) => {
|
|
158
|
+
if (self.inSetValue === true) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const parsed = parseFloat(newVal);
|
|
163
|
+
if (!isNaN(parsed) && parsed === self.value) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if ((newVal === '' || newVal == null) && isNaN(self.value)) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
150
171
|
setTimeout(() => setValue(newVal));
|
|
151
172
|
});
|
|
152
173
|
|
|
@@ -231,22 +252,32 @@ export class InputSpinner {
|
|
|
231
252
|
updateInput = true;
|
|
232
253
|
}
|
|
233
254
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
255
|
+
// QA_GO-429 Bug B: mark re-entry so installValueInterceptor's callback
|
|
256
|
+
// skips the setTimeout(setValue) it would otherwise queue for every
|
|
257
|
+
// `self.original.value = ...` we do below. Without this flag the
|
|
258
|
+
// interceptor would queue an infinite setTimeout cascade that keeps
|
|
259
|
+
// firing setValue with stale values and clobbers user typing.
|
|
260
|
+
self.inSetValue = true;
|
|
261
|
+
try {
|
|
262
|
+
if (isNaN(newValue) || newValue === '') {
|
|
263
|
+
self.original.value = '';
|
|
264
|
+
if (updateInput) {
|
|
265
|
+
self.input.value = '';
|
|
266
|
+
}
|
|
239
267
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
268
|
+
self.value = NaN;
|
|
269
|
+
} else {
|
|
270
|
+
newValue = parseFloat(newValue);
|
|
271
|
+
newValue = Math.min(Math.max(newValue, self.min), self.max);
|
|
272
|
+
self.original.value = newValue;
|
|
273
|
+
if (updateInput) {
|
|
274
|
+
self.input.value = (self.original as any).inputSpinnerEditor.render(newValue);
|
|
275
|
+
}
|
|
248
276
|
|
|
249
|
-
|
|
277
|
+
self.value = newValue;
|
|
278
|
+
}
|
|
279
|
+
} finally {
|
|
280
|
+
self.inSetValue = false;
|
|
250
281
|
}
|
|
251
282
|
}
|
|
252
283
|
|