vira 32.4.0 → 33.1.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 (58) 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 +12 -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 +50 -0
  18. package/dist/elements/popover/vira-popover-trigger.element.js +307 -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-drawer.element.js +1 -1
  22. package/dist/elements/vira-dropdown.element.d.ts +40 -13
  23. package/dist/elements/vira-dropdown.element.js +375 -69
  24. package/dist/elements/vira-form.element.js +10 -16
  25. package/dist/elements/vira-json-form.element.js +40 -36
  26. package/dist/elements/vira-modal.element.js +1 -1
  27. package/dist/elements/vira-tabs.element.d.ts +3 -9
  28. package/dist/elements/vira-tabs.element.js +5 -6
  29. package/dist/elements/vira-theme-switcher.element.js +3 -3
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +1 -0
  32. package/dist/util/anchored-popover.d.ts +40 -0
  33. package/dist/util/anchored-popover.js +70 -0
  34. package/dist/util/fuzzy-match.d.ts +16 -0
  35. package/dist/util/fuzzy-match.js +24 -0
  36. package/dist/util/index.d.ts +5 -3
  37. package/dist/util/index.js +5 -3
  38. package/dist/util/{pop-up-helpers.d.ts → menu-helpers.d.ts} +8 -19
  39. package/dist/util/{pop-up-helpers.js → menu-helpers.js} +12 -19
  40. package/dist/util/popover-manager.d.ts +123 -0
  41. package/dist/util/popover-manager.js +414 -0
  42. package/dist/util/vira-dropdown-option.d.ts +30 -0
  43. package/dist/util/vira-dropdown-option.js +8 -0
  44. package/dist/util/vira-form-fields.d.ts +2 -2
  45. package/dist/util/vira-theme-client.d.ts +1 -1
  46. package/dist/util/vira-theme-client.js +3 -3
  47. package/package.json +2 -1
  48. package/dist/elements/pop-up/vira-menu-trigger.element.d.ts +0 -45
  49. package/dist/elements/pop-up/vira-menu.element.d.ts +0 -36
  50. package/dist/elements/pop-up/vira-menu.element.js +0 -88
  51. package/dist/elements/pop-up/vira-pop-up-trigger.element.d.ts +0 -109
  52. package/dist/elements/pop-up/vira-pop-up-trigger.element.js +0 -408
  53. package/dist/elements/vira-select.element.d.ts +0 -44
  54. package/dist/elements/vira-select.element.js +0 -418
  55. package/dist/util/pop-up-manager.d.ts +0 -200
  56. package/dist/util/pop-up-manager.js +0 -258
  57. package/dist/util/vira-select-option.d.ts +0 -31
  58. package/dist/util/vira-select-option.js +0 -8
@@ -0,0 +1,176 @@
1
+ import { colorCss } from '@electrovir/color';
2
+ import { css, html } from 'element-vir';
3
+ import { listenTo } from 'typed-event-target';
4
+ import { viraFormCssVars } from '../../styles/form-styles.js';
5
+ import { viraTheme } from '../../styles/vira-color-theme.js';
6
+ import { createAnchoredPopoverStyles } from '../../util/anchored-popover.js';
7
+ import { defineViraElement } from '../../util/define-vira-element.js';
8
+ /**
9
+ * Centered with insets instead of `position-area`, because browsers shift a centered
10
+ * `position-area` box back onto the screen rather than moving on to the next
11
+ * `position-try-fallbacks` entry. These insets leave a space that is centered on the anchor and as
12
+ * wide as possible, and `unsafe` stops the browser from shifting the tooltip, so a tooltip wider
13
+ * than that space overflows it and moves on to an aligned fallback. Each `anchor(center)` is
14
+ * measured from the side its inset is on, so the same formula works for `left` and `right`.
15
+ */
16
+ const centeredStyles = css `
17
+ position-area: none;
18
+ top: 0;
19
+ bottom: anchor(top);
20
+ left: max(0px, 2 * anchor(center) - 100%);
21
+ right: max(0px, 2 * anchor(center) - 100%);
22
+ align-self: end;
23
+ justify-self: unsafe center;
24
+ `;
25
+ /** `unsafe` for the same reason as {@link centeredStyles}. */
26
+ const leftAlignedStyles = css `
27
+ position-area: block-start span-inline-end;
28
+ inset: auto;
29
+ align-self: normal;
30
+ justify-self: unsafe start;
31
+ `;
32
+ /** `unsafe` for the same reason as {@link centeredStyles}. */
33
+ const rightAlignedStyles = css `
34
+ position-area: block-start span-inline-start;
35
+ inset: auto;
36
+ align-self: normal;
37
+ justify-self: unsafe end;
38
+ `;
39
+ /**
40
+ * Centered but shifted to stay on the screen. For a tooltip that fits on neither side of the
41
+ * anchor.
42
+ */
43
+ const shiftedStyles = css `
44
+ position-area: block-start span-all;
45
+ inset: auto;
46
+ align-self: normal;
47
+ justify-self: anchor-center;
48
+ `;
49
+ /**
50
+ * The popover rendered by the `tooltip` directive. The element itself is the popover, centered
51
+ * above `anchor` when there's room. Its children are the tooltip contents.
52
+ *
53
+ * @category Popover
54
+ * @category Elements
55
+ */
56
+ export const ViraTooltip = defineViraElement()({
57
+ tagName: 'vira-tooltip',
58
+ styles: css `
59
+ ${createAnchoredPopoverStyles({
60
+ fallbacks: [
61
+ {
62
+ name: 'vira-tooltip-above-left-aligned',
63
+ styles: leftAlignedStyles,
64
+ },
65
+ {
66
+ name: 'vira-tooltip-above-right-aligned',
67
+ styles: rightAlignedStyles,
68
+ },
69
+ {
70
+ name: 'vira-tooltip-below-centered',
71
+ styles: centeredStyles,
72
+ flipBlock: true,
73
+ },
74
+ {
75
+ name: 'vira-tooltip-below-left-aligned',
76
+ styles: leftAlignedStyles,
77
+ flipBlock: true,
78
+ },
79
+ {
80
+ name: 'vira-tooltip-below-right-aligned',
81
+ styles: rightAlignedStyles,
82
+ flipBlock: true,
83
+ },
84
+ {
85
+ name: 'vira-tooltip-above-shifted',
86
+ styles: shiftedStyles,
87
+ },
88
+ {
89
+ name: 'vira-tooltip-below-shifted',
90
+ styles: shiftedStyles,
91
+ flipBlock: true,
92
+ },
93
+ ],
94
+ })}
95
+
96
+ :host {
97
+ anchor-name: --vira-tooltip;
98
+ ${colorCss(viraTheme.colors['vira-grey-behind-bg-highest-contrast'])};
99
+ ${centeredStyles}
100
+ margin-bottom: 7px;
101
+ padding: 4px 8px;
102
+ border-radius: 6px;
103
+ box-sizing: border-box;
104
+ width: max-content;
105
+ /*
106
+ Not 100%, which is the width of the current position-area. A tooltip limited to that
107
+ width shrinks to fit it rather than overflowing onto the next fallback.
108
+ */
109
+ max-width: min(300px, 100vw);
110
+ font-size: ${viraFormCssVars['vira-form-small-text-size'].value};
111
+ overflow-wrap: break-word;
112
+ pointer-events: none;
113
+ }
114
+
115
+ /*
116
+ Separate popovers rather than children or pseudo-elements of the tooltip, because those can't
117
+ use anchor() to reach the anchor element from inside the tooltip's top-layer box.
118
+ */
119
+ .caret {
120
+ /*
121
+ position-anchor is set explicitly because its initial value differs between browsers.
122
+ */
123
+ position-anchor: auto;
124
+ position: fixed;
125
+ inset: auto;
126
+ margin: 0;
127
+ padding: 0;
128
+ border: none;
129
+ height: auto;
130
+ width: 10px;
131
+ left: calc(anchor(center) - 5px);
132
+ background-color: ${viraTheme.colors['vira-grey-behind-bg-highest-contrast'].background
133
+ .value};
134
+ pointer-events: none;
135
+ }
136
+
137
+ /*
138
+ Each caret spans the gap between the tooltip and the anchor on its own side, so the caret
139
+ on the side without the tooltip gets a negative height, which renders as nothing. This
140
+ follows the tooltip's position-try-fallbacks choice without knowing which one won.
141
+ */
142
+ .caret-down {
143
+ top: anchor(--vira-tooltip bottom);
144
+ bottom: calc(anchor(top) + 2px);
145
+ clip-path: polygon(0 0, 100% 0, 50% 100%);
146
+ }
147
+
148
+ .caret-up {
149
+ bottom: anchor(--vira-tooltip top);
150
+ top: calc(anchor(bottom) + 2px);
151
+ clip-path: polygon(50% 0, 100% 100%, 0 100%);
152
+ }
153
+ `,
154
+ init({ host }) {
155
+ /** The carets must open after the tooltip so they can anchor to it. */
156
+ listenTo(host, 'toggle', () => {
157
+ if (!host.matches(':popover-open')) {
158
+ return;
159
+ }
160
+ host.shadowRoot.querySelectorAll('.caret').forEach((caret) => {
161
+ if (caret instanceof HTMLElement && !caret.matches(':popover-open')) {
162
+ caret.showPopover({
163
+ source: host.instanceInputs.anchor,
164
+ });
165
+ }
166
+ });
167
+ });
168
+ },
169
+ render() {
170
+ return html `
171
+ <slot></slot>
172
+ <div class="caret caret-down" popover="manual"></div>
173
+ <div class="caret caret-up" popover="manual"></div>
174
+ `;
175
+ },
176
+ });
@@ -11,7 +11,7 @@ import { viraShadows } from '../styles/shadows.js';
11
11
  import { noUserSelect } from '../styles/user-select.js';
12
12
  import { viraTheme } from '../styles/vira-color-theme.js';
13
13
  import { defineViraElement } from '../util/define-vira-element.js';
14
- import { isMouseEventOnScrollbar } from '../util/pop-up-manager.js';
14
+ import { isMouseEventOnScrollbar } from '../util/popover-manager.js';
15
15
  import { ViraIcon } from './vira-icon.element.js';
16
16
  const globalEventsToCloseDrawerOn = [
17
17
  'pagehide',
@@ -1,45 +1,72 @@
1
1
  import { type PartialWithUndefined } from '@augment-vir/common';
2
- import { type HtmlInterpolation } from 'element-vir';
2
+ import { type NavController } from 'device-navigation';
3
+ import { type AttributeValues, type HtmlInterpolation } from 'element-vir';
3
4
  import { type ViraIconSvg } from '../icons/icon-svg.js';
4
- import { type ShowPopUpResult } from '../util/pop-up-manager.js';
5
- import { type ViraSelectOption } from '../util/vira-select-option.js';
6
- import { type PopUpTriggerPosition } from './pop-up/vira-pop-up-trigger.element.js';
5
+ import { type PopoverManager } from '../util/popover-manager.js';
6
+ import { type ViraDropdownOption, type ViraDropdownOptionGroup } from '../util/vira-dropdown-option.js';
7
7
  /**
8
- * A dropdown element that uses pop-up menus.
8
+ * A dropdown element that uses popover menus.
9
9
  *
10
10
  * @category Dropdown
11
11
  * @category Elements
12
12
  * @see https://electrovir.github.io/vira/book/elements/dropdown/vira-dropdown
13
13
  */
14
14
  export declare const ViraDropdown: import("element-vir").DeclarativeElementDefinition<"vira-dropdown", {
15
- options: ReadonlyArray<Readonly<ViraSelectOption>>;
15
+ options: ReadonlyArray<Readonly<ViraDropdownOption> | Readonly<ViraDropdownOptionGroup>>;
16
16
  /** The selected id from the given options. */
17
17
  selected: ReadonlyArray<PropertyKey>;
18
18
  } & PartialWithUndefined<{
19
19
  /** Text to show if nothing is selected. */
20
20
  placeholder: string;
21
+ /**
22
+ * Text shown in the opened popover when `options` has no options. When omitted, opening a
23
+ * dropdown with no options shows no popover at all.
24
+ */
25
+ noOptionsText: string;
21
26
  /**
22
27
  * If false, this will behave like a single select dropdown, otherwise you can select
23
28
  * multiple.
24
29
  */
25
30
  isMultiSelect: boolean;
31
+ /**
32
+ * Replaces the selection text with a text input. Opening the dropdown focuses it and typing
33
+ * into it filters the options to those whose labels fuzzy match the typed text.
34
+ */
35
+ isSearchable: boolean;
26
36
  icon: ViraIconSvg;
27
37
  selectionPrefix: string;
28
38
  isDisabled: boolean;
39
+ /**
40
+ * When `true`, the currently selected options' labels are rendered as plain text with no
41
+ * trigger or menu.
42
+ */
43
+ isReadonly: boolean;
44
+ hasError: boolean;
29
45
  label: string | HtmlInterpolation;
30
- /** For debugging purposes only. Very bad for actual production code use. */
31
- z_debug_forceOpenState: boolean;
32
- } & PopUpTriggerPosition>, {
33
- /** `undefined` means the pop up is not currently showing. */
34
- showPopUpResult: ShowPopUpResult | undefined;
46
+ /** Attributes applied to the trigger element. */
47
+ attributePassthrough: Readonly<AttributeValues>;
48
+ /**
49
+ * Passed to {@link ViraMenu}'s `hoverScrollSpeed` input. How many menu items per second
50
+ * hovering a scroll arrow scrolls through.
51
+ *
52
+ * @default 24
53
+ */
54
+ menuHoverScrollSpeed: number;
55
+ }>, {
56
+ isOpen: boolean;
35
57
  shouldSelectOnMouseUp: boolean;
36
58
  /**
37
59
  * Used to couple the label and trigger together. This is not applied if no label is
38
60
  * provided.
39
61
  */
40
62
  randomId: string;
63
+ /** The text typed into the search input while the dropdown is open. */
64
+ searchText: string;
65
+ navController: undefined | NavController;
66
+ popoverManager: undefined | PopoverManager;
41
67
  }, {
42
68
  /** Emits all currently selected values. */
43
69
  selectedValuesChange: import("element-vir").DefineElementEvent<string[]>;
44
- openChange: import("element-vir").DefineElementEvent<ShowPopUpResult | undefined>;
45
- }, "vira-dropdown-", "vira-dropdown-", readonly [], readonly ["leadingIcon", "prefixText", "trigger"]>;
70
+ /** `true` when the popover just opened, `false` when it just closed. */
71
+ openChange: import("element-vir").DefineElementEvent<boolean>;
72
+ }, "vira-dropdown-", "vira-dropdown-", readonly [], readonly ["leadingIcon", "prefixText", "searchInput", "trigger"]>;