vira 32.3.0 → 33.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/directives/index.d.ts +2 -0
- package/dist/directives/index.js +2 -0
- package/dist/directives/popover.directive.d.ts +29 -0
- package/dist/directives/popover.directive.js +45 -0
- package/dist/directives/tooltip.directive.d.ts +60 -0
- package/dist/directives/tooltip.directive.js +99 -0
- package/dist/elements/color/vira-color-picker.element.d.ts +1 -1
- package/dist/elements/color/vira-color-picker.element.js +17 -15
- package/dist/elements/index.d.ts +5 -5
- package/dist/elements/index.js +5 -5
- package/dist/elements/{pop-up → popover}/vira-menu-item.element.d.ts +4 -4
- package/dist/elements/{pop-up → popover}/vira-menu-item.element.js +3 -3
- package/dist/elements/popover/vira-menu-trigger.element.d.ts +56 -0
- package/dist/elements/{pop-up → popover}/vira-menu-trigger.element.js +19 -30
- package/dist/elements/popover/vira-menu.element.d.ts +35 -0
- package/dist/elements/popover/vira-menu.element.js +262 -0
- package/dist/elements/popover/vira-popover-trigger.element.d.ts +49 -0
- package/dist/elements/popover/vira-popover-trigger.element.js +301 -0
- package/dist/elements/popover/vira-tooltip.element.d.ts +10 -0
- package/dist/elements/popover/vira-tooltip.element.js +176 -0
- package/dist/elements/vira-checkbox.element.d.ts +3 -3
- package/dist/elements/vira-checkbox.element.js +4 -3
- package/dist/elements/vira-date-input.element.d.ts +2 -1
- package/dist/elements/vira-date-input.element.js +3 -2
- package/dist/elements/vira-drawer.element.js +1 -1
- package/dist/elements/vira-dropdown.element.d.ts +29 -12
- package/dist/elements/vira-dropdown.element.js +173 -60
- package/dist/elements/vira-form.element.js +13 -22
- package/dist/elements/vira-input.element.d.ts +2 -1
- package/dist/elements/vira-input.element.js +2 -2
- package/dist/elements/vira-json-form.element.js +40 -36
- package/dist/elements/vira-modal.element.js +1 -1
- package/dist/elements/vira-tabs.element.d.ts +3 -9
- package/dist/elements/vira-tabs.element.js +5 -6
- package/dist/elements/vira-text-area.element.d.ts +2 -1
- package/dist/elements/vira-text-area.element.js +3 -2
- package/dist/elements/vira-theme-switcher.element.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/util/anchored-popover.d.ts +40 -0
- package/dist/util/anchored-popover.js +70 -0
- package/dist/util/index.d.ts +4 -3
- package/dist/util/index.js +4 -3
- package/dist/util/{pop-up-helpers.d.ts → menu-helpers.d.ts} +4 -18
- package/dist/util/{pop-up-helpers.js → menu-helpers.js} +2 -17
- package/dist/util/popover-manager.d.ts +123 -0
- package/dist/util/popover-manager.js +412 -0
- package/dist/util/vira-dropdown-option.d.ts +30 -0
- package/dist/util/vira-dropdown-option.js +8 -0
- package/dist/util/vira-form-fields.d.ts +5 -10
- package/dist/util/vira-form-fields.js +15 -11
- package/dist/util/vira-theme-client.d.ts +1 -1
- package/dist/util/vira-theme-client.js +3 -3
- package/package.json +2 -1
- package/dist/elements/pop-up/vira-menu-trigger.element.d.ts +0 -45
- package/dist/elements/pop-up/vira-menu.element.d.ts +0 -36
- package/dist/elements/pop-up/vira-menu.element.js +0 -88
- package/dist/elements/pop-up/vira-pop-up-trigger.element.d.ts +0 -109
- package/dist/elements/pop-up/vira-pop-up-trigger.element.js +0 -408
- package/dist/elements/vira-select.element.d.ts +0 -44
- package/dist/elements/vira-select.element.js +0 -418
- package/dist/util/pop-up-manager.d.ts +0 -200
- package/dist/util/pop-up-manager.js +0 -258
- package/dist/util/vira-select-option.d.ts +0 -31
- package/dist/util/vira-select-option.js +0 -8
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { check } from '@augment-vir/assert';
|
|
2
2
|
import { filterMap, randomString } from '@augment-vir/common';
|
|
3
3
|
import { extractEventTarget } from '@augment-vir/web';
|
|
4
|
-
import { classMap, css, defineElementEvent, html, ifDefined, listen, nothing, testId, } from 'element-vir';
|
|
4
|
+
import { attributes, classMap, css, defineElementEvent, html, ifDefined, listen, nothing, testId, } from 'element-vir';
|
|
5
5
|
import { ChevronUp16Icon } from '../icons/index.js';
|
|
6
6
|
import { viraFormCssVars } from '../styles/form-styles.js';
|
|
7
|
+
import { ViraSize, viraSizeHeights } from '../styles/form-variants.js';
|
|
7
8
|
import { noUserSelect, viraAnimationDurations } from '../styles/index.js';
|
|
8
9
|
import { defineViraElement } from '../util/define-vira-element.js';
|
|
9
|
-
import { renderMenuItemEntries } from '../util/
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { renderMenuItemEntries } from '../util/menu-helpers.js';
|
|
11
|
+
import { isViraDropdownOptionGroup, } from '../util/vira-dropdown-option.js';
|
|
12
|
+
import { ViraMenuItem } from './popover/vira-menu-item.element.js';
|
|
13
|
+
import { ViraMenu, ViraMenuCornerStyle } from './popover/vira-menu.element.js';
|
|
14
|
+
import { ViraPopoverTrigger } from './popover/vira-popover-trigger.element.js';
|
|
13
15
|
import { ViraIcon } from './vira-icon.element.js';
|
|
14
16
|
/**
|
|
15
|
-
* A dropdown element that uses
|
|
17
|
+
* A dropdown element that uses popover menus.
|
|
16
18
|
*
|
|
17
19
|
* @category Dropdown
|
|
18
20
|
* @category Elements
|
|
@@ -29,12 +31,12 @@ export const ViraDropdown = defineViraElement()({
|
|
|
29
31
|
:host {
|
|
30
32
|
display: inline-flex;
|
|
31
33
|
vertical-align: middle;
|
|
32
|
-
width:
|
|
34
|
+
width: 224px;
|
|
33
35
|
position: relative;
|
|
34
36
|
max-width: 100%;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
${
|
|
39
|
+
${ViraPopoverTrigger} {
|
|
38
40
|
width: 100%;
|
|
39
41
|
}
|
|
40
42
|
|
|
@@ -60,18 +62,8 @@ export const ViraDropdown = defineViraElement()({
|
|
|
60
62
|
justify-content: flex-end;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
.open {
|
|
64
|
-
|
|
65
|
-
transform: rotate(0);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
&:not(.open-upwards).dropdown-trigger {
|
|
69
|
-
border-bottom-left-radius: 0;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
&.open-upwards.dropdown-trigger {
|
|
73
|
-
border-top-left-radius: 0;
|
|
74
|
-
}
|
|
65
|
+
.open .trigger-icon {
|
|
66
|
+
transform: rotate(0);
|
|
75
67
|
}
|
|
76
68
|
|
|
77
69
|
.dropdown-trigger {
|
|
@@ -84,13 +76,50 @@ export const ViraDropdown = defineViraElement()({
|
|
|
84
76
|
gap: 8px;
|
|
85
77
|
text-align: left;
|
|
86
78
|
align-items: center;
|
|
87
|
-
|
|
88
|
-
padding
|
|
79
|
+
min-height: ${viraSizeHeights[ViraSize.Medium]}px;
|
|
80
|
+
padding: 0 3px 0 10px;
|
|
89
81
|
border-radius: ${viraFormCssVars['vira-form-radius'].value};
|
|
90
82
|
background-color: ${viraFormCssVars['vira-form-background-color'].value};
|
|
91
83
|
color: ${viraFormCssVars['vira-form-foreground-color'].value};
|
|
92
84
|
}
|
|
93
85
|
|
|
86
|
+
.dropdown-wrapper {
|
|
87
|
+
display: flex;
|
|
88
|
+
width: 100%;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.has-error .dropdown-trigger {
|
|
92
|
+
border-color: ${viraFormCssVars['vira-form-error-color'].value};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.option-group-label,
|
|
96
|
+
.no-options {
|
|
97
|
+
${noUserSelect};
|
|
98
|
+
/* Aligns with the label text of each ViraMenuItem, past its check icon. */
|
|
99
|
+
padding: 8px 12px 4px
|
|
100
|
+
calc(${ViraMenuItem.cssVars['vira-menu-item-icon-gap'].value} * 3 + 16px);
|
|
101
|
+
opacity: 0.6;
|
|
102
|
+
text-align: left;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.option-group-label {
|
|
106
|
+
font-weight: ${viraFormCssVars['vira-form-label-font-weight'].value};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.no-options {
|
|
110
|
+
cursor: default;
|
|
111
|
+
padding-bottom: 8px;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
${ViraMenuItem}.option-group-label {
|
|
115
|
+
padding: 0 0 0 calc(${ViraMenuItem.cssVars['vira-menu-item-icon-gap'].value} * 2);
|
|
116
|
+
${ViraMenuItem.cssVars['vira-menu-item-padding'].name}: 8px 12px 4px 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.readonly-value {
|
|
120
|
+
overflow-wrap: anywhere;
|
|
121
|
+
}
|
|
122
|
+
|
|
94
123
|
.using-placeholder {
|
|
95
124
|
opacity: 0.4;
|
|
96
125
|
}
|
|
@@ -114,12 +143,12 @@ export const ViraDropdown = defineViraElement()({
|
|
|
114
143
|
events: {
|
|
115
144
|
/** Emits all currently selected values. */
|
|
116
145
|
selectedValuesChange: defineElementEvent(),
|
|
146
|
+
/** `true` when the popover just opened, `false` when it just closed. */
|
|
117
147
|
openChange: defineElementEvent(),
|
|
118
148
|
},
|
|
119
149
|
state() {
|
|
120
150
|
return {
|
|
121
|
-
|
|
122
|
-
showPopUpResult: undefined,
|
|
151
|
+
isOpen: false,
|
|
123
152
|
shouldSelectOnMouseUp: false,
|
|
124
153
|
/**
|
|
125
154
|
* Used to couple the label and trigger together. This is not applied if no label is
|
|
@@ -129,7 +158,10 @@ export const ViraDropdown = defineViraElement()({
|
|
|
129
158
|
};
|
|
130
159
|
},
|
|
131
160
|
render({ state, inputs, dispatch, events, updateState, testIds }) {
|
|
132
|
-
const
|
|
161
|
+
const flatOptions = inputs.options.flatMap((entry) => {
|
|
162
|
+
return isViraDropdownOptionGroup(entry) ? entry.options : [entry];
|
|
163
|
+
});
|
|
164
|
+
const selectedOptions = filterMap(inputs.selected, (selectedValue) => flatOptions.find((option) => option.value === selectedValue), check.isTruthy);
|
|
133
165
|
const leadingIconTemplate = inputs.icon
|
|
134
166
|
? html `
|
|
135
167
|
<${ViraIcon.assign({
|
|
@@ -165,13 +197,78 @@ export const ViraDropdown = defineViraElement()({
|
|
|
165
197
|
detail: newSelectedValues,
|
|
166
198
|
}));
|
|
167
199
|
}
|
|
200
|
+
function toggleGroup(group) {
|
|
201
|
+
const enabledGroupOptions = group.options.filter((option) => !option.disabled);
|
|
202
|
+
const isGroupSelected = enabledGroupOptions.every((option) => {
|
|
203
|
+
return selectedOptions.includes(option);
|
|
204
|
+
});
|
|
205
|
+
dispatch(new events.selectedValuesChange({
|
|
206
|
+
detail: (isGroupSelected
|
|
207
|
+
? selectedOptions.filter((option) => !enabledGroupOptions.includes(option))
|
|
208
|
+
: [
|
|
209
|
+
...selectedOptions,
|
|
210
|
+
...enabledGroupOptions.filter((option) => {
|
|
211
|
+
return !selectedOptions.includes(option);
|
|
212
|
+
}),
|
|
213
|
+
]).map((option) => option.value),
|
|
214
|
+
}));
|
|
215
|
+
}
|
|
216
|
+
function renderGroupLabel(group) {
|
|
217
|
+
return inputs.isMultiSelect
|
|
218
|
+
? html `
|
|
219
|
+
<${ViraMenuItem.assign({
|
|
220
|
+
disablePointerStyles: true,
|
|
221
|
+
})}
|
|
222
|
+
class="option-group-label"
|
|
223
|
+
${listen('click', () => {
|
|
224
|
+
toggleGroup(group);
|
|
225
|
+
})}
|
|
226
|
+
>
|
|
227
|
+
${group.groupName}
|
|
228
|
+
</${ViraMenuItem}>
|
|
229
|
+
`
|
|
230
|
+
: html `
|
|
231
|
+
<div class="option-group-label">${group.groupName}</div>
|
|
232
|
+
`;
|
|
233
|
+
}
|
|
234
|
+
/** Drag-select actions in the same order as the rendered menu items. */
|
|
235
|
+
const menuItemActions = inputs.options.flatMap((entry) => {
|
|
236
|
+
const options = isViraDropdownOptionGroup(entry) ? entry.options : [entry];
|
|
237
|
+
const optionActions = options.map((option) => {
|
|
238
|
+
return option.disabled
|
|
239
|
+
? undefined
|
|
240
|
+
: () => {
|
|
241
|
+
selectOption(option);
|
|
242
|
+
};
|
|
243
|
+
});
|
|
244
|
+
return isViraDropdownOptionGroup(entry) && inputs.isMultiSelect
|
|
245
|
+
? [
|
|
246
|
+
() => {
|
|
247
|
+
toggleGroup(entry);
|
|
248
|
+
},
|
|
249
|
+
...optionActions,
|
|
250
|
+
]
|
|
251
|
+
: optionActions;
|
|
252
|
+
});
|
|
253
|
+
function renderOptionEntries(options) {
|
|
254
|
+
return renderMenuItemEntries(options.map((option) => {
|
|
255
|
+
return {
|
|
256
|
+
content: option.label,
|
|
257
|
+
onClick() {
|
|
258
|
+
selectOption(option);
|
|
259
|
+
},
|
|
260
|
+
disabled: option.disabled,
|
|
261
|
+
selected: selectedOptions.includes(option),
|
|
262
|
+
};
|
|
263
|
+
}));
|
|
264
|
+
}
|
|
265
|
+
const isMenuShown = state.isOpen && (!!flatOptions.length || !!inputs.noOptionsText);
|
|
168
266
|
const menuTemplate = html `
|
|
169
267
|
<${ViraMenu.assign({
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
: ViraMenuPopUpDirection.Upwards,
|
|
268
|
+
cornerStyle: ViraMenuCornerStyle.Round,
|
|
269
|
+
hoverScrollSpeed: inputs.menuHoverScrollSpeed,
|
|
173
270
|
})}
|
|
174
|
-
slot=${
|
|
271
|
+
slot=${ViraPopoverTrigger.slotNames['vira-popover-trigger-popover']}
|
|
175
272
|
${listen('mouseup', (event) => {
|
|
176
273
|
if (state.shouldSelectOnMouseUp) {
|
|
177
274
|
const menuItem = event
|
|
@@ -179,46 +276,44 @@ export const ViraDropdown = defineViraElement()({
|
|
|
179
276
|
.find((eventTarget) => {
|
|
180
277
|
return eventTarget instanceof ViraMenuItem;
|
|
181
278
|
});
|
|
182
|
-
const
|
|
183
|
-
?
|
|
279
|
+
const menuItemAction = menuItem
|
|
280
|
+
? menuItemActions[Array.from(extractEventTarget(event, ViraMenu).querySelectorAll(ViraMenuItem.tagName)).indexOf(menuItem)]
|
|
184
281
|
: undefined;
|
|
185
|
-
|
|
186
|
-
selectOption(option);
|
|
187
|
-
}
|
|
282
|
+
menuItemAction?.();
|
|
188
283
|
}
|
|
189
284
|
})}
|
|
190
285
|
>
|
|
191
|
-
${
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
286
|
+
${flatOptions.length
|
|
287
|
+
? inputs.options.map((entry) => {
|
|
288
|
+
return isViraDropdownOptionGroup(entry)
|
|
289
|
+
? html `
|
|
290
|
+
${renderGroupLabel(entry)} ${renderOptionEntries(entry.options)}
|
|
291
|
+
`
|
|
292
|
+
: renderOptionEntries([entry]);
|
|
293
|
+
})
|
|
294
|
+
: html `
|
|
295
|
+
<div class="no-options">${inputs.noOptionsText}</div>
|
|
296
|
+
`}
|
|
201
297
|
</${ViraMenu}>
|
|
202
298
|
`;
|
|
203
299
|
const triggerTemplate = html `
|
|
204
|
-
<${
|
|
300
|
+
<${ViraPopoverTrigger.assign({
|
|
205
301
|
...inputs,
|
|
206
302
|
keepOpenAfterInteraction: inputs.isMultiSelect,
|
|
207
303
|
focusOnClose: true,
|
|
208
|
-
|
|
304
|
+
popoverOffset: {
|
|
209
305
|
vertical: -1,
|
|
210
306
|
right: 24,
|
|
211
307
|
},
|
|
212
|
-
horizontalAnchor: inputs.horizontalAnchor || HorizontalAnchor.Both,
|
|
213
308
|
})}
|
|
214
|
-
${listen(
|
|
215
|
-
if (
|
|
309
|
+
${listen(ViraPopoverTrigger.events.openChange, (event) => {
|
|
310
|
+
if (state.isOpen !== event.detail) {
|
|
216
311
|
dispatch(new events.openChange({
|
|
217
312
|
detail: event.detail,
|
|
218
313
|
}));
|
|
219
314
|
}
|
|
220
315
|
updateState({
|
|
221
|
-
|
|
316
|
+
isOpen: event.detail,
|
|
222
317
|
});
|
|
223
318
|
})}
|
|
224
319
|
${listen('mouseup', () => {
|
|
@@ -231,15 +326,15 @@ export const ViraDropdown = defineViraElement()({
|
|
|
231
326
|
>
|
|
232
327
|
<div
|
|
233
328
|
class="dropdown-trigger ${classMap({
|
|
234
|
-
open:
|
|
235
|
-
'open-upwards': !state.showPopUpResult?.popDown,
|
|
329
|
+
open: state.isOpen,
|
|
236
330
|
})}"
|
|
237
|
-
slot=${
|
|
331
|
+
slot=${ViraPopoverTrigger.slotNames['vira-popover-trigger-trigger']}
|
|
238
332
|
id=${ifDefined(inputs.label ? state.randomId : undefined)}
|
|
239
|
-
aria-label=${ifDefined(inputs.label || undefined)}
|
|
333
|
+
aria-label=${ifDefined((check.isString(inputs.label) && inputs.label) || undefined)}
|
|
334
|
+
${attributes(inputs.attributePassthrough)}
|
|
240
335
|
${testId(testIds.trigger)}
|
|
241
336
|
${listen('mousedown', () => {
|
|
242
|
-
if (!state.
|
|
337
|
+
if (!state.isOpen) {
|
|
243
338
|
updateState({
|
|
244
339
|
shouldSelectOnMouseUp: true,
|
|
245
340
|
});
|
|
@@ -264,19 +359,37 @@ export const ViraDropdown = defineViraElement()({
|
|
|
264
359
|
></${ViraIcon}>
|
|
265
360
|
</span>
|
|
266
361
|
</div>
|
|
267
|
-
${
|
|
268
|
-
</${
|
|
362
|
+
${isMenuShown ? menuTemplate : nothing}
|
|
363
|
+
</${ViraPopoverTrigger}>
|
|
269
364
|
`;
|
|
365
|
+
const contentTemplate = inputs.isReadonly
|
|
366
|
+
? html `
|
|
367
|
+
<span class="readonly-value">${selectionDisplay}</span>
|
|
368
|
+
`
|
|
369
|
+
: triggerTemplate;
|
|
270
370
|
if (inputs.label) {
|
|
271
371
|
return html `
|
|
272
|
-
<label
|
|
372
|
+
<label
|
|
373
|
+
for=${ifDefined(inputs.isReadonly ? undefined : state.randomId)}
|
|
374
|
+
class=${classMap({
|
|
375
|
+
'has-error': !!inputs.hasError,
|
|
376
|
+
})}
|
|
377
|
+
>
|
|
273
378
|
<span class="dropdown-label">${inputs.label}</span>
|
|
274
|
-
${
|
|
379
|
+
${contentTemplate}
|
|
275
380
|
</label>
|
|
276
381
|
`;
|
|
277
382
|
}
|
|
278
383
|
else {
|
|
279
|
-
return
|
|
384
|
+
return html `
|
|
385
|
+
<span
|
|
386
|
+
class="dropdown-wrapper ${classMap({
|
|
387
|
+
'has-error': !!inputs.hasError,
|
|
388
|
+
})}"
|
|
389
|
+
>
|
|
390
|
+
${contentTemplate}
|
|
391
|
+
</span>
|
|
392
|
+
`;
|
|
280
393
|
}
|
|
281
394
|
},
|
|
282
395
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { check } from '@augment-vir/assert';
|
|
1
2
|
import { getObjectTypedEntries } from '@augment-vir/common';
|
|
2
3
|
import { css, defineElementEvent, html, listen, nothing, testId, } from 'element-vir';
|
|
3
4
|
import { viraFormCssVars } from '../styles/form-styles.js';
|
|
@@ -5,8 +6,8 @@ import { defineViraElement } from '../util/define-vira-element.js';
|
|
|
5
6
|
import { applyRequiredLabel, areFormFieldsValid, ViraFormFieldType, } from '../util/vira-form-fields.js';
|
|
6
7
|
import { ViraCheckbox } from './vira-checkbox.element.js';
|
|
7
8
|
import { ViraDateInput } from './vira-date-input.element.js';
|
|
9
|
+
import { ViraDropdown } from './vira-dropdown.element.js';
|
|
8
10
|
import { ViraInput, ViraInputType } from './vira-input.element.js';
|
|
9
|
-
import { ViraSelect } from './vira-select.element.js';
|
|
10
11
|
import { ViraTextArea } from './vira-text-area.element.js';
|
|
11
12
|
/**
|
|
12
13
|
* A form element.
|
|
@@ -69,9 +70,9 @@ export const ViraForm = defineViraElement()({
|
|
|
69
70
|
&
|
|
70
71
|
> ${ViraDateInput},
|
|
71
72
|
&
|
|
72
|
-
> ${
|
|
73
|
+
> ${ViraDropdown},
|
|
73
74
|
&
|
|
74
|
-
> ${
|
|
75
|
+
> ${ViraInput},
|
|
75
76
|
&
|
|
76
77
|
> ${ViraTextArea} {
|
|
77
78
|
width: 100%;
|
|
@@ -111,11 +112,7 @@ export const ViraForm = defineViraElement()({
|
|
|
111
112
|
return nothing;
|
|
112
113
|
}
|
|
113
114
|
else if (field.type === ViraFormFieldType.Checkbox) {
|
|
114
|
-
const checkboxLabel = showRequiredMarker
|
|
115
|
-
? html `
|
|
116
|
-
${field.label}*
|
|
117
|
-
`
|
|
118
|
-
: field.label;
|
|
115
|
+
const checkboxLabel = applyRequiredLabel(field.label, showRequiredMarker);
|
|
119
116
|
return wrapFormField({
|
|
120
117
|
label: checkboxLabel,
|
|
121
118
|
fieldTemplate: html `
|
|
@@ -153,7 +150,7 @@ export const ViraForm = defineViraElement()({
|
|
|
153
150
|
}
|
|
154
151
|
const label = applyRequiredLabel(field.label, showRequiredMarker);
|
|
155
152
|
const childLabel = inputs.useHorizontalLabels ? undefined : label;
|
|
156
|
-
const horizontalLabelAttributes = inputs.useHorizontalLabels && label
|
|
153
|
+
const horizontalLabelAttributes = inputs.useHorizontalLabels && check.isString(label) && label
|
|
157
154
|
? {
|
|
158
155
|
'aria-label': label,
|
|
159
156
|
}
|
|
@@ -162,34 +159,28 @@ export const ViraForm = defineViraElement()({
|
|
|
162
159
|
return wrapFormField({
|
|
163
160
|
label,
|
|
164
161
|
fieldTemplate: html `
|
|
165
|
-
<${
|
|
162
|
+
<${ViraDropdown.assign({
|
|
166
163
|
options: field.options,
|
|
167
|
-
|
|
164
|
+
selected: field.value ? [field.value] : [],
|
|
168
165
|
placeholder: field.placeholder,
|
|
169
|
-
|
|
166
|
+
isDisabled,
|
|
170
167
|
isReadonly: inputs.isReadonly,
|
|
171
168
|
label: childLabel,
|
|
172
169
|
hasError: field.hasError,
|
|
173
170
|
icon: field.icon,
|
|
174
|
-
|
|
175
|
-
? {
|
|
176
|
-
attributePassthrough: {
|
|
177
|
-
select: horizontalLabelAttributes,
|
|
178
|
-
},
|
|
179
|
-
}
|
|
180
|
-
: {}),
|
|
171
|
+
attributePassthrough: horizontalLabelAttributes,
|
|
181
172
|
})}
|
|
182
173
|
${field.testId ? testId(field.testId) : nothing}
|
|
183
|
-
${listen(
|
|
174
|
+
${listen(ViraDropdown.events.selectedValuesChange, (event) => {
|
|
184
175
|
dispatch(new events.valueChange({
|
|
185
176
|
detail: {
|
|
186
177
|
key,
|
|
187
178
|
...field,
|
|
188
|
-
value: event.detail,
|
|
179
|
+
value: event.detail[0],
|
|
189
180
|
},
|
|
190
181
|
}));
|
|
191
182
|
})}
|
|
192
|
-
></${
|
|
183
|
+
></${ViraDropdown}>
|
|
193
184
|
`,
|
|
194
185
|
});
|
|
195
186
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type PartialWithUndefined } from '@augment-vir/common';
|
|
2
|
+
import { type HtmlInterpolation } from 'element-vir';
|
|
2
3
|
import { type ViraIconSvg } from '../icons/index.js';
|
|
3
4
|
export * from '../util/shared-text-input-logic.js';
|
|
4
5
|
/**
|
|
@@ -25,7 +26,7 @@ export declare const ViraInput: import("element-vir").DeclarativeElementDefiniti
|
|
|
25
26
|
/** A suffix that, if provided, is shown following the input field. */
|
|
26
27
|
suffix: string;
|
|
27
28
|
/** A label that is shown above the input, if provided. */
|
|
28
|
-
label: string;
|
|
29
|
+
label: string | HtmlInterpolation;
|
|
29
30
|
/** If true, applies error styling. */
|
|
30
31
|
hasError: boolean;
|
|
31
32
|
showClearButton: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assertWrap } from '@augment-vir/assert';
|
|
1
|
+
import { assertWrap, check } from '@augment-vir/assert';
|
|
2
2
|
import { randomString } from '@augment-vir/common';
|
|
3
3
|
import { extractEventTarget } from '@augment-vir/web';
|
|
4
4
|
import { attributes, css, defineElementEvent, html, ifDefined, listen, nothing, onResize, renderIf, } from 'element-vir';
|
|
@@ -374,7 +374,7 @@ export const ViraInput = defineViraElement()({
|
|
|
374
374
|
|
|
375
375
|
<input
|
|
376
376
|
id=${ifDefined(inputs.label ? state.randomId : undefined)}
|
|
377
|
-
aria-label=${ifDefined(inputs.label || undefined)}
|
|
377
|
+
aria-label=${ifDefined((check.isString(inputs.label) && inputs.label) || undefined)}
|
|
378
378
|
type=${calculateEffectiveInputType(inputs.type, state.showPassword)}
|
|
379
379
|
style=${forcedInputWidthStyles}
|
|
380
380
|
autocomplete=${ifDefined(shouldBlockBrowserHelps ? 'off' : undefined)}
|
|
@@ -9,9 +9,9 @@ import { defineViraElement } from '../util/define-vira-element.js';
|
|
|
9
9
|
import { allowsFreeformString, createDefaultForJsonType, createResolveContext, deleteValueAtPath, getAdditionalPropertiesSchema, getAllowedJsonTypes, getDefinedProperties, getItemSchema, getJsonType, getNewItemSchema, getPropertySchema, getRequiredProperties, getSchemaEnumValues, getSchemaTitle, getStringEnumValues, pathToKey, pickBranchForType, setValueAtPath, validateAgainstSchema, ViraJsonType, viraJsonTypeLabels, } from '../util/vira-json-schema.js';
|
|
10
10
|
import { ViraButton } from './vira-button.element.js';
|
|
11
11
|
import { ViraCheckbox } from './vira-checkbox.element.js';
|
|
12
|
+
import { ViraDropdown } from './vira-dropdown.element.js';
|
|
12
13
|
import { ViraError } from './vira-error.element.js';
|
|
13
14
|
import { ViraInput, ViraInputType } from './vira-input.element.js';
|
|
14
|
-
import { ViraSelect } from './vira-select.element.js';
|
|
15
15
|
import { ViraTextArea } from './vira-text-area.element.js';
|
|
16
16
|
/**
|
|
17
17
|
* Editing mode for a string field that offers both a fixed set of enum options and free-form text.
|
|
@@ -25,6 +25,9 @@ export var ViraJsonStringMode;
|
|
|
25
25
|
/** Enter an arbitrary string via a text input. */
|
|
26
26
|
ViraJsonStringMode["Custom"] = "custom";
|
|
27
27
|
})(ViraJsonStringMode || (ViraJsonStringMode = {}));
|
|
28
|
+
function toSelectedValues(value) {
|
|
29
|
+
return value == undefined ? [] : [value];
|
|
30
|
+
}
|
|
28
31
|
/**
|
|
29
32
|
* An editor for arbitrary JSON values, optionally constrained by a standard JSON Schema
|
|
30
33
|
* ({@link ViraJsonSchema}).
|
|
@@ -163,7 +166,7 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
163
166
|
min-width: 0;
|
|
164
167
|
}
|
|
165
168
|
|
|
166
|
-
.json-value-with-switcher > ${
|
|
169
|
+
.json-value-with-switcher > ${ViraDropdown} {
|
|
167
170
|
flex-shrink: 0;
|
|
168
171
|
width: 130px;
|
|
169
172
|
}
|
|
@@ -177,7 +180,7 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
177
180
|
padding: 8px 0;
|
|
178
181
|
}
|
|
179
182
|
|
|
180
|
-
.json-add-row ${ViraInput}, .json-add-row ${
|
|
183
|
+
.json-add-row ${ViraInput}, .json-add-row ${ViraDropdown} {
|
|
181
184
|
width: 160px;
|
|
182
185
|
}
|
|
183
186
|
|
|
@@ -310,16 +313,17 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
310
313
|
check.isNumber(value) ||
|
|
311
314
|
check.isBoolean(value);
|
|
312
315
|
return html `
|
|
313
|
-
<${
|
|
316
|
+
<${ViraDropdown.assign({
|
|
314
317
|
options,
|
|
315
|
-
|
|
316
|
-
|
|
318
|
+
selected: toSelectedValues(isPrimitive ? jsonPrimitiveToString(value) : undefined),
|
|
319
|
+
isDisabled,
|
|
317
320
|
})}
|
|
318
|
-
${listen(
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
+
${listen(ViraDropdown.events.selectedValuesChange, (event) => {
|
|
322
|
+
const selectedValue = assertWrap.isDefined(event.detail[0]);
|
|
323
|
+
const selected = enumValues.find((entry) => jsonPrimitiveToString(entry) === selectedValue);
|
|
324
|
+
emitReplaceAt(path, selected ?? selectedValue);
|
|
321
325
|
})}
|
|
322
|
-
></${
|
|
326
|
+
></${ViraDropdown}>
|
|
323
327
|
`;
|
|
324
328
|
}
|
|
325
329
|
else if (type === ViraJsonType.Boolean) {
|
|
@@ -463,14 +467,14 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
463
467
|
};
|
|
464
468
|
});
|
|
465
469
|
return html `
|
|
466
|
-
<${
|
|
470
|
+
<${ViraDropdown.assign({
|
|
467
471
|
options,
|
|
468
|
-
|
|
472
|
+
selected: toSelectedValues(selectedType),
|
|
469
473
|
})}
|
|
470
|
-
${listen(
|
|
471
|
-
setPendingType(pathKey, event.detail);
|
|
474
|
+
${listen(ViraDropdown.events.selectedValuesChange, (event) => {
|
|
475
|
+
setPendingType(pathKey, assertWrap.isDefined(event.detail[0]));
|
|
472
476
|
})}
|
|
473
|
-
></${
|
|
477
|
+
></${ViraDropdown}>
|
|
474
478
|
${renderPlusButton({
|
|
475
479
|
isAddDisabled,
|
|
476
480
|
tooltip: isAddDisabled
|
|
@@ -527,14 +531,14 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
527
531
|
};
|
|
528
532
|
});
|
|
529
533
|
return html `
|
|
530
|
-
<${
|
|
534
|
+
<${ViraDropdown.assign({
|
|
531
535
|
options,
|
|
532
|
-
|
|
536
|
+
selected: toSelectedValues(selectedType),
|
|
533
537
|
})}
|
|
534
|
-
${listen(
|
|
535
|
-
setPendingType(pathKey, event.detail);
|
|
538
|
+
${listen(ViraDropdown.events.selectedValuesChange, (event) => {
|
|
539
|
+
setPendingType(pathKey, assertWrap.isDefined(event.detail[0]));
|
|
536
540
|
})}
|
|
537
|
-
></${
|
|
541
|
+
></${ViraDropdown}>
|
|
538
542
|
${renderPlusButton({
|
|
539
543
|
isAddDisabled: false,
|
|
540
544
|
tooltip: `Add ${viraJsonTypeLabels[selectedType]}`,
|
|
@@ -798,20 +802,20 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
798
802
|
});
|
|
799
803
|
const editor = mode === ViraJsonStringMode.Options
|
|
800
804
|
? html `
|
|
801
|
-
<${
|
|
805
|
+
<${ViraDropdown.assign({
|
|
802
806
|
options: enumValues.map((entry) => {
|
|
803
807
|
return {
|
|
804
808
|
value: entry,
|
|
805
809
|
label: entry,
|
|
806
810
|
};
|
|
807
811
|
}),
|
|
808
|
-
|
|
809
|
-
|
|
812
|
+
selected: toSelectedValues(enumValues.includes(value) ? value : undefined),
|
|
813
|
+
isDisabled,
|
|
810
814
|
})}
|
|
811
|
-
${listen(
|
|
812
|
-
emitReplaceAt(path, event.detail);
|
|
815
|
+
${listen(ViraDropdown.events.selectedValuesChange, (event) => {
|
|
816
|
+
emitReplaceAt(path, assertWrap.isDefined(event.detail[0]));
|
|
813
817
|
})}
|
|
814
|
-
></${
|
|
818
|
+
></${ViraDropdown}>
|
|
815
819
|
`
|
|
816
820
|
: html `
|
|
817
821
|
<${ViraInput.assign({
|
|
@@ -839,15 +843,15 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
839
843
|
return html `
|
|
840
844
|
<div class="json-value-with-switcher">
|
|
841
845
|
<span class="json-value-editor-slot">${editor}</span>
|
|
842
|
-
<${
|
|
846
|
+
<${ViraDropdown.assign({
|
|
843
847
|
options: modeOptions,
|
|
844
|
-
|
|
848
|
+
selected: toSelectedValues(mode),
|
|
845
849
|
})}
|
|
846
850
|
title="Choose from options or enter a custom value"
|
|
847
|
-
${listen(
|
|
848
|
-
setStringMode(pathKey, event.detail);
|
|
851
|
+
${listen(ViraDropdown.events.selectedValuesChange, (event) => {
|
|
852
|
+
setStringMode(pathKey, assertWrap.isDefined(event.detail[0]));
|
|
849
853
|
})}
|
|
850
|
-
></${
|
|
854
|
+
></${ViraDropdown}>
|
|
851
855
|
</div>
|
|
852
856
|
`;
|
|
853
857
|
}
|
|
@@ -894,16 +898,16 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
894
898
|
return html `
|
|
895
899
|
<div class="json-value-with-switcher">
|
|
896
900
|
<span class="json-value-editor-slot">${editor}</span>
|
|
897
|
-
<${
|
|
901
|
+
<${ViraDropdown.assign({
|
|
898
902
|
options: switcherOptions,
|
|
899
|
-
|
|
903
|
+
selected: toSelectedValues(switcherSelected),
|
|
900
904
|
})}
|
|
901
905
|
title="Change type"
|
|
902
|
-
${listen(
|
|
903
|
-
const newType = event.detail;
|
|
906
|
+
${listen(ViraDropdown.events.selectedValuesChange, (event) => {
|
|
907
|
+
const newType = assertWrap.isDefined(event.detail[0]);
|
|
904
908
|
emitReplaceAt(path, createDefaultForJsonType(newType));
|
|
905
909
|
})}
|
|
906
|
-
></${
|
|
910
|
+
></${ViraDropdown}>
|
|
907
911
|
</div>
|
|
908
912
|
`;
|
|
909
913
|
}
|
|
@@ -9,7 +9,7 @@ import { noNativeFormStyles, noNativeSpacing } from '../styles/native-styles.js'
|
|
|
9
9
|
import { viraShadows } from '../styles/shadows.js';
|
|
10
10
|
import { viraTheme } from '../styles/vira-color-theme.js';
|
|
11
11
|
import { defineViraElement } from '../util/define-vira-element.js';
|
|
12
|
-
import { isMouseEventOnScrollbar } from '../util/
|
|
12
|
+
import { isMouseEventOnScrollbar } from '../util/popover-manager.js';
|
|
13
13
|
import { ViraIcon } from './vira-icon.element.js';
|
|
14
14
|
const globalEventsToCloseModalOn = [
|
|
15
15
|
'pagehide',
|