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.
Files changed (65) hide show
  1. package/dist/directives/index.d.ts +2 -0
  2. package/dist/directives/index.js +2 -0
  3. package/dist/directives/popover.directive.d.ts +29 -0
  4. package/dist/directives/popover.directive.js +45 -0
  5. package/dist/directives/tooltip.directive.d.ts +60 -0
  6. package/dist/directives/tooltip.directive.js +99 -0
  7. package/dist/elements/color/vira-color-picker.element.d.ts +1 -1
  8. package/dist/elements/color/vira-color-picker.element.js +17 -15
  9. package/dist/elements/index.d.ts +5 -5
  10. package/dist/elements/index.js +5 -5
  11. package/dist/elements/{pop-up → popover}/vira-menu-item.element.d.ts +4 -4
  12. package/dist/elements/{pop-up → popover}/vira-menu-item.element.js +3 -3
  13. package/dist/elements/popover/vira-menu-trigger.element.d.ts +56 -0
  14. package/dist/elements/{pop-up → popover}/vira-menu-trigger.element.js +19 -30
  15. package/dist/elements/popover/vira-menu.element.d.ts +35 -0
  16. package/dist/elements/popover/vira-menu.element.js +262 -0
  17. package/dist/elements/popover/vira-popover-trigger.element.d.ts +49 -0
  18. package/dist/elements/popover/vira-popover-trigger.element.js +301 -0
  19. package/dist/elements/popover/vira-tooltip.element.d.ts +10 -0
  20. package/dist/elements/popover/vira-tooltip.element.js +176 -0
  21. package/dist/elements/vira-checkbox.element.d.ts +3 -3
  22. package/dist/elements/vira-checkbox.element.js +4 -3
  23. package/dist/elements/vira-date-input.element.d.ts +2 -1
  24. package/dist/elements/vira-date-input.element.js +3 -2
  25. package/dist/elements/vira-drawer.element.js +1 -1
  26. package/dist/elements/vira-dropdown.element.d.ts +29 -12
  27. package/dist/elements/vira-dropdown.element.js +173 -60
  28. package/dist/elements/vira-form.element.js +13 -22
  29. package/dist/elements/vira-input.element.d.ts +2 -1
  30. package/dist/elements/vira-input.element.js +2 -2
  31. package/dist/elements/vira-json-form.element.js +40 -36
  32. package/dist/elements/vira-modal.element.js +1 -1
  33. package/dist/elements/vira-tabs.element.d.ts +3 -9
  34. package/dist/elements/vira-tabs.element.js +5 -6
  35. package/dist/elements/vira-text-area.element.d.ts +2 -1
  36. package/dist/elements/vira-text-area.element.js +3 -2
  37. package/dist/elements/vira-theme-switcher.element.js +3 -3
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.js +1 -0
  40. package/dist/util/anchored-popover.d.ts +40 -0
  41. package/dist/util/anchored-popover.js +70 -0
  42. package/dist/util/index.d.ts +4 -3
  43. package/dist/util/index.js +4 -3
  44. package/dist/util/{pop-up-helpers.d.ts → menu-helpers.d.ts} +4 -18
  45. package/dist/util/{pop-up-helpers.js → menu-helpers.js} +2 -17
  46. package/dist/util/popover-manager.d.ts +123 -0
  47. package/dist/util/popover-manager.js +412 -0
  48. package/dist/util/vira-dropdown-option.d.ts +30 -0
  49. package/dist/util/vira-dropdown-option.js +8 -0
  50. package/dist/util/vira-form-fields.d.ts +5 -10
  51. package/dist/util/vira-form-fields.js +15 -11
  52. package/dist/util/vira-theme-client.d.ts +1 -1
  53. package/dist/util/vira-theme-client.js +3 -3
  54. package/package.json +2 -1
  55. package/dist/elements/pop-up/vira-menu-trigger.element.d.ts +0 -45
  56. package/dist/elements/pop-up/vira-menu.element.d.ts +0 -36
  57. package/dist/elements/pop-up/vira-menu.element.js +0 -88
  58. package/dist/elements/pop-up/vira-pop-up-trigger.element.d.ts +0 -109
  59. package/dist/elements/pop-up/vira-pop-up-trigger.element.js +0 -408
  60. package/dist/elements/vira-select.element.d.ts +0 -44
  61. package/dist/elements/vira-select.element.js +0 -418
  62. package/dist/util/pop-up-manager.d.ts +0 -200
  63. package/dist/util/pop-up-manager.js +0 -258
  64. package/dist/util/vira-select-option.d.ts +0 -31
  65. 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/pop-up-helpers.js';
10
- import { ViraMenuItem } from './pop-up/vira-menu-item.element.js';
11
- import { ViraMenu, ViraMenuPopUpDirection } from './pop-up/vira-menu.element.js';
12
- import { HorizontalAnchor, ViraPopUpTrigger, } from './pop-up/vira-pop-up-trigger.element.js';
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 pop-up menus.
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: 256px;
34
+ width: 224px;
33
35
  position: relative;
34
36
  max-width: 100%;
35
37
  }
36
38
 
37
- ${ViraPopUpTrigger} {
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
- & .trigger-icon {
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
- padding: 3px;
88
- padding-left: 10px;
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
- /** `undefined` means the pop up is not currently showing. */
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 selectedOptions = filterMap(inputs.selected, (selectedValue) => inputs.options.find((option) => option.value === selectedValue), check.isTruthy);
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
- direction: state.showPopUpResult?.popDown
171
- ? ViraMenuPopUpDirection.Downwards
172
- : ViraMenuPopUpDirection.Upwards,
268
+ cornerStyle: ViraMenuCornerStyle.Round,
269
+ hoverScrollSpeed: inputs.menuHoverScrollSpeed,
173
270
  })}
174
- slot=${ViraPopUpTrigger.slotNames['vira-pop-up-trigger-pop-up']}
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 option = menuItem
183
- ? inputs.options[Array.from(extractEventTarget(event, ViraMenu).querySelectorAll(ViraMenuItem.tagName)).indexOf(menuItem)]
279
+ const menuItemAction = menuItem
280
+ ? menuItemActions[Array.from(extractEventTarget(event, ViraMenu).querySelectorAll(ViraMenuItem.tagName)).indexOf(menuItem)]
184
281
  : undefined;
185
- if (check.isDefined(option) && !option.disabled) {
186
- selectOption(option);
187
- }
282
+ menuItemAction?.();
188
283
  }
189
284
  })}
190
285
  >
191
- ${renderMenuItemEntries(inputs.options.map((option) => {
192
- return {
193
- content: option.label,
194
- onClick() {
195
- selectOption(option);
196
- },
197
- disabled: option.disabled,
198
- selected: selectedOptions.includes(option),
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
- <${ViraPopUpTrigger.assign({
300
+ <${ViraPopoverTrigger.assign({
205
301
  ...inputs,
206
302
  keepOpenAfterInteraction: inputs.isMultiSelect,
207
303
  focusOnClose: true,
208
- popUpOffset: {
304
+ popoverOffset: {
209
305
  vertical: -1,
210
306
  right: 24,
211
307
  },
212
- horizontalAnchor: inputs.horizontalAnchor || HorizontalAnchor.Both,
213
308
  })}
214
- ${listen(ViraPopUpTrigger.events.openChange, (event) => {
215
- if (!!state.showPopUpResult !== !!event.detail) {
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
- showPopUpResult: event.detail,
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: !!state.showPopUpResult,
235
- 'open-upwards': !state.showPopUpResult?.popDown,
329
+ open: state.isOpen,
236
330
  })}"
237
- slot=${ViraPopUpTrigger.slotNames['vira-pop-up-trigger-trigger']}
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.showPopUpResult) {
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
- ${state.showPopUpResult ? menuTemplate : nothing}
268
- </${ViraPopUpTrigger}>
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 for=${state.randomId}>
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
- ${triggerTemplate}
379
+ ${contentTemplate}
275
380
  </label>
276
381
  `;
277
382
  }
278
383
  else {
279
- return triggerTemplate;
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
- > ${ViraInput},
73
+ > ${ViraDropdown},
73
74
  &
74
- > ${ViraSelect},
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
- <${ViraSelect.assign({
162
+ <${ViraDropdown.assign({
166
163
  options: field.options,
167
- value: field.value,
164
+ selected: field.value ? [field.value] : [],
168
165
  placeholder: field.placeholder,
169
- disabled: isDisabled,
166
+ isDisabled,
170
167
  isReadonly: inputs.isReadonly,
171
168
  label: childLabel,
172
169
  hasError: field.hasError,
173
170
  icon: field.icon,
174
- ...(inputs.useHorizontalLabels && label
175
- ? {
176
- attributePassthrough: {
177
- select: horizontalLabelAttributes,
178
- },
179
- }
180
- : {}),
171
+ attributePassthrough: horizontalLabelAttributes,
181
172
  })}
182
173
  ${field.testId ? testId(field.testId) : nothing}
183
- ${listen(ViraSelect.events.valueChange, (event) => {
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
- ></${ViraSelect}>
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 > ${ViraSelect} {
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 ${ViraSelect} {
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
- <${ViraSelect.assign({
316
+ <${ViraDropdown.assign({
314
317
  options,
315
- value: isPrimitive ? jsonPrimitiveToString(value) : undefined,
316
- disabled: isDisabled,
318
+ selected: toSelectedValues(isPrimitive ? jsonPrimitiveToString(value) : undefined),
319
+ isDisabled,
317
320
  })}
318
- ${listen(ViraSelect.events.valueChange, (event) => {
319
- const selected = enumValues.find((entry) => jsonPrimitiveToString(entry) === event.detail);
320
- emitReplaceAt(path, selected ?? event.detail);
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
- ></${ViraSelect}>
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
- <${ViraSelect.assign({
470
+ <${ViraDropdown.assign({
467
471
  options,
468
- value: selectedType,
472
+ selected: toSelectedValues(selectedType),
469
473
  })}
470
- ${listen(ViraSelect.events.valueChange, (event) => {
471
- setPendingType(pathKey, event.detail);
474
+ ${listen(ViraDropdown.events.selectedValuesChange, (event) => {
475
+ setPendingType(pathKey, assertWrap.isDefined(event.detail[0]));
472
476
  })}
473
- ></${ViraSelect}>
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
- <${ViraSelect.assign({
534
+ <${ViraDropdown.assign({
531
535
  options,
532
- value: selectedType,
536
+ selected: toSelectedValues(selectedType),
533
537
  })}
534
- ${listen(ViraSelect.events.valueChange, (event) => {
535
- setPendingType(pathKey, event.detail);
538
+ ${listen(ViraDropdown.events.selectedValuesChange, (event) => {
539
+ setPendingType(pathKey, assertWrap.isDefined(event.detail[0]));
536
540
  })}
537
- ></${ViraSelect}>
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
- <${ViraSelect.assign({
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
- value: enumValues.includes(value) ? value : undefined,
809
- disabled: isDisabled,
812
+ selected: toSelectedValues(enumValues.includes(value) ? value : undefined),
813
+ isDisabled,
810
814
  })}
811
- ${listen(ViraSelect.events.valueChange, (event) => {
812
- emitReplaceAt(path, event.detail);
815
+ ${listen(ViraDropdown.events.selectedValuesChange, (event) => {
816
+ emitReplaceAt(path, assertWrap.isDefined(event.detail[0]));
813
817
  })}
814
- ></${ViraSelect}>
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
- <${ViraSelect.assign({
846
+ <${ViraDropdown.assign({
843
847
  options: modeOptions,
844
- value: mode,
848
+ selected: toSelectedValues(mode),
845
849
  })}
846
850
  title="Choose from options or enter a custom value"
847
- ${listen(ViraSelect.events.valueChange, (event) => {
848
- setStringMode(pathKey, event.detail);
851
+ ${listen(ViraDropdown.events.selectedValuesChange, (event) => {
852
+ setStringMode(pathKey, assertWrap.isDefined(event.detail[0]));
849
853
  })}
850
- ></${ViraSelect}>
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
- <${ViraSelect.assign({
901
+ <${ViraDropdown.assign({
898
902
  options: switcherOptions,
899
- value: switcherSelected,
903
+ selected: toSelectedValues(switcherSelected),
900
904
  })}
901
905
  title="Change type"
902
- ${listen(ViraSelect.events.valueChange, (event) => {
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
- ></${ViraSelect}>
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/pop-up-manager.js';
12
+ import { isMouseEventOnScrollbar } from '../util/popover-manager.js';
13
13
  import { ViraIcon } from './vira-icon.element.js';
14
14
  const globalEventsToCloseModalOn = [
15
15
  'pagehide',