vira 26.4.1 → 26.5.1

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,4 +1,4 @@
1
- import { classMap, css, html, renderIf } from 'element-vir';
1
+ import { css, html } from 'element-vir';
2
2
  import { Check24Icon } from '../../icons/icon-svgs/check-24.icon.js';
3
3
  import { noUserSelect } from '../../styles/index.js';
4
4
  import { defineViraElement } from '../define-vira-element.js';
@@ -12,26 +12,33 @@ import { ViraIcon } from '../vira-icon.element.js';
12
12
  export const ViraMenuItem = defineViraElement()({
13
13
  tagName: 'vira-menu-item',
14
14
  hostClasses: {
15
- 'vira-menu-item-selected': ({ inputs }) => inputs.selected,
15
+ 'vira-menu-item-selected': ({ inputs }) => !inputs.hideCheckIcon && inputs.selected,
16
16
  },
17
17
  styles: ({ hostClasses }) => css `
18
18
  :host {
19
19
  display: flex;
20
20
  ${noUserSelect};
21
+ box-sizing: border-box;
22
+ max-width: 100%;
23
+ overflow: hidden;
21
24
  }
22
25
 
23
26
  .item {
24
27
  pointer-events: none;
25
28
  min-height: 24px;
26
29
  display: flex;
30
+ max-width: 100%;
27
31
  align-items: center;
28
32
  padding: 8px;
33
+ padding-right: 24px;
29
34
  padding-left: 0;
30
35
  text-align: left;
36
+ box-sizing: border-box;
31
37
  }
32
38
 
33
39
  ${hostClasses['vira-menu-item-selected'].selector} ${ViraIcon} {
34
40
  opacity: 1;
41
+ visibility: hidden;
35
42
  }
36
43
 
37
44
  /*
@@ -44,17 +51,11 @@ export const ViraMenuItem = defineViraElement()({
44
51
  margin-right: -2px;
45
52
  margin-left: 2px;
46
53
  }
47
-
48
- .include-left-spacing {
49
- padding-left: 12px;
50
- }
51
54
  `,
52
55
  render({ inputs }) {
53
56
  return html `
54
- <div class="item ${classMap({ 'include-left-spacing': !!inputs.hideCheckIcon })}">
55
- ${renderIf(!inputs.hideCheckIcon, html `
56
- <${ViraIcon.assign({ icon: Check24Icon })}></${ViraIcon}>
57
- `)}
57
+ <div class="item">
58
+ <${ViraIcon.assign({ icon: Check24Icon })}></${ViraIcon}>
58
59
  <slot>${inputs.label}</slot>
59
60
  </div>
60
61
  `;
@@ -3,7 +3,7 @@ import { type NavController } from 'device-navigation';
3
3
  import { type PopUpManager, type ShowPopUpResult } from '../../util/pop-up-manager.js';
4
4
  import { type MenuItem } from './pop-up-menu-item.js';
5
5
  import { type PopUpMenuCornerStyle } from './vira-pop-up-menu.element.js';
6
- import { type PopUpOffset } from './vira-pop-up-trigger.element.js';
6
+ import { HorizontalAnchor, type PopUpOffset } from './vira-pop-up-trigger.element.js';
7
7
  /**
8
8
  * Test ids for {@link ViraMenuTrigger}.
9
9
  *
@@ -30,6 +30,20 @@ export declare const ViraMenuTrigger: import("element-vir").DeclarativeElementDe
30
30
  /** Hide menu item check mark icons. */
31
31
  hideCheckIcons: boolean;
32
32
  menuCornerStyle: PopUpMenuCornerStyle;
33
+ /**
34
+ * - `HorizontalAnchor.Left`: pop-up is anchored to the left side of the trigger and the
35
+ * pop-up can grow to the right.
36
+ * - `HorizontalAnchor.Right`: pop-up is anchored to the right side of the trigger and the
37
+ * pop-up can grow to the left.
38
+ * - `HorizontalAnchor.Both`: pop-up is anchored on both sides of the trigger and cannot grow
39
+ * beyond it.
40
+ *
41
+ * Note that when `HorizontalAnchor.Both` is _not_ used, this anchor will cancel out any
42
+ * `popUpOffset` for the direction _opposite_ of the chosen anchor.
43
+ *
44
+ * @default HorizontalAnchor.Left
45
+ */
46
+ horizontalAnchor: HorizontalAnchor;
33
47
  }>, {
34
48
  navController: undefined | NavController;
35
49
  popUpManager: undefined | PopUpManager;
@@ -3,7 +3,7 @@ import { defineViraElement } from '../define-vira-element.js';
3
3
  import { updateSelectedItems } from './pop-up-helpers.js';
4
4
  import { ViraMenu } from './vira-menu.element.js';
5
5
  import { PopUpMenuDirection, ViraPopUpMenu, } from './vira-pop-up-menu.element.js';
6
- import { ViraPopUpTrigger } from './vira-pop-up-trigger.element.js';
6
+ import { HorizontalAnchor, ViraPopUpTrigger, } from './vira-pop-up-trigger.element.js';
7
7
  /**
8
8
  * Test ids for {@link ViraMenuTrigger}.
9
9
  *
@@ -31,6 +31,10 @@ export const ViraMenuTrigger = defineViraElement()({
31
31
  ${ViraPopUpTrigger} {
32
32
  width: 100%;
33
33
  }
34
+
35
+ .full-width-menu {
36
+ width: 100%;
37
+ }
34
38
  `,
35
39
  events: {
36
40
  itemActivate: defineElementEvent(),
@@ -51,6 +55,7 @@ export const ViraMenuTrigger = defineViraElement()({
51
55
  keepOpenAfterInteraction: true,
52
56
  z_debug_forceOpenState: inputs.z_debug_forceOpenState,
53
57
  popUpOffset: inputs.popUpOffset,
58
+ horizontalAnchor: inputs.horizontalAnchor || HorizontalAnchor.Left,
54
59
  })}
55
60
  class=${classMap({
56
61
  open: !!state.showPopUpResult,
@@ -95,6 +100,9 @@ export const ViraMenuTrigger = defineViraElement()({
95
100
  cornerStyle: inputs.menuCornerStyle,
96
101
  })}
97
102
  slot=${ViraPopUpTrigger.slotNames.popUp}
103
+ class=${classMap({
104
+ 'full-width-menu': inputs.horizontalAnchor === HorizontalAnchor.Both,
105
+ })}
98
106
  >
99
107
  <${ViraMenu.assign({
100
108
  items: inputs.items,
@@ -39,6 +39,7 @@ export const ViraMenu = defineViraElement()({
39
39
  flex-direction: column;
40
40
 
41
41
  width: 100%;
42
+ max-width: 100%;
42
43
  max-height: 100%;
43
44
  overflow-y: auto;
44
45
  z-index: 100;
@@ -43,8 +43,7 @@ export const ViraPopUpMenu = defineViraElement()({
43
43
  styles: ({ hostClasses }) => css `
44
44
  :host {
45
45
  display: flex;
46
-
47
- width: 100%;
46
+ max-width: 100%;
48
47
  max-height: 100%;
49
48
  overflow-y: auto;
50
49
  z-index: 99;
@@ -11,6 +11,29 @@ export type PopUpOffset = PartialWithUndefined<{
11
11
  right: number;
12
12
  left: number;
13
13
  }>;
14
+ /**
15
+ * Anchor options for pop-ups.
16
+ *
17
+ * @category Internal
18
+ */
19
+ export declare enum HorizontalAnchor {
20
+ /**
21
+ * The left side of the pop-up will be anchored to the left side of the trigger, allowing the
22
+ * pop-up to grow on the right side of the trigger.
23
+ */
24
+ Left = "left",
25
+ /**
26
+ * The Right side of the pop-up will be anchored to the right side of the trigger, allowing the
27
+ * pop-up to grow on the left side of the trigger.
28
+ */
29
+ Right = "right",
30
+ /**
31
+ * Restrict the pop-up on both sides.
32
+ *
33
+ * This is the default anchor for {@link ViraPopUpTrigger}.
34
+ */
35
+ Both = "both"
36
+ }
14
37
  /**
15
38
  * An element with slots for a pop-up trigger and pop-up contents.
16
39
  *
@@ -26,6 +49,20 @@ export declare const ViraPopUpTrigger: import("element-vir").DeclarativeElementD
26
49
  keepOpenAfterInteraction: boolean;
27
50
  /** All values in px. */
28
51
  popUpOffset?: PopUpOffset;
52
+ /**
53
+ * - `HorizontalAnchor.Left`: pop-up is anchored to the left side of the trigger and the
54
+ * pop-up can grow to the right.
55
+ * - `HorizontalAnchor.Right`: pop-up is anchored to the right side of the trigger and the
56
+ * pop-up can grow to the left.
57
+ * - `HorizontalAnchor.Both`: pop-up is anchored on both sides of the trigger and cannot grow
58
+ * beyond it. (This is the default experience.)
59
+ *
60
+ * Note that when `HorizontalAnchor.Both` is _not_ used, this anchor will cancel out any
61
+ * `popUpOffset` for the direction _opposite_ of the chosen anchor.
62
+ *
63
+ * @default HorizontalAnchor.Both
64
+ */
65
+ horizontalAnchor?: HorizontalAnchor;
29
66
  }>, {
30
67
  /** `undefined` means the pop up is not currently showing. */
31
68
  showPopUpResult: ShowPopUpResult | undefined;
@@ -6,6 +6,30 @@ import { noNativeFormStyles, noUserSelect, viraDisabledStyles } from '../../styl
6
6
  import { HidePopUpEvent, NavSelectEvent, PopUpManager, } from '../../util/pop-up-manager.js';
7
7
  import { defineViraElement } from '../define-vira-element.js';
8
8
  import { triggerPopUpState } from './pop-up-helpers.js';
9
+ /**
10
+ * Anchor options for pop-ups.
11
+ *
12
+ * @category Internal
13
+ */
14
+ export var HorizontalAnchor;
15
+ (function (HorizontalAnchor) {
16
+ /**
17
+ * The left side of the pop-up will be anchored to the left side of the trigger, allowing the
18
+ * pop-up to grow on the right side of the trigger.
19
+ */
20
+ HorizontalAnchor["Left"] = "left";
21
+ /**
22
+ * The Right side of the pop-up will be anchored to the right side of the trigger, allowing the
23
+ * pop-up to grow on the left side of the trigger.
24
+ */
25
+ HorizontalAnchor["Right"] = "right";
26
+ /**
27
+ * Restrict the pop-up on both sides.
28
+ *
29
+ * This is the default anchor for {@link ViraPopUpTrigger}.
30
+ */
31
+ HorizontalAnchor["Both"] = "both";
32
+ })(HorizontalAnchor || (HorizontalAnchor = {}));
9
33
  /**
10
34
  * An element with slots for a pop-up trigger and pop-up contents.
11
35
  *
@@ -72,14 +96,15 @@ export const ViraPopUpTrigger = defineViraElement()({
72
96
  pointer-events: none;
73
97
  display: flex;
74
98
  flex-direction: column;
99
+ align-items: flex-start;
100
+ overflow: hidden;
75
101
 
76
102
  /* highest possible z-index */
77
103
  z-index: 2147483647;
78
- left: 0;
79
- right: 0;
80
104
 
81
105
  & > * {
82
106
  pointer-events: auto;
107
+ max-width: 100%;
83
108
  }
84
109
  }
85
110
 
@@ -166,6 +191,24 @@ export const ViraPopUpTrigger = defineViraElement()({
166
191
  triggerPopUp({ emitEvent: false, open: true }, undefined);
167
192
  }
168
193
  }
194
+ const leftCss = inputs.horizontalAnchor === HorizontalAnchor.Right && state.showPopUpResult
195
+ ? css `
196
+ left: -${state.showPopUpResult.positions.diff.left}px;
197
+ `
198
+ : css `
199
+ left: ${inputs.popUpOffset?.left || 0}px;
200
+ `;
201
+ const rightCss = state.showPopUpResult && inputs.horizontalAnchor === HorizontalAnchor.Left
202
+ ? css `
203
+ right: -${state.showPopUpResult.positions.diff.right}px;
204
+ `
205
+ : css `
206
+ right: ${inputs.popUpOffset?.right || 0}px;
207
+ `;
208
+ const horizontalPositionStyle = css `
209
+ ${leftCss}
210
+ ${rightCss}
211
+ `;
169
212
  /**
170
213
  * These styles do _not_ account for window resizing while the menu is open. I decided this
171
214
  * was not a major enough problem to tackle. If it becomes major enough in the future,
@@ -178,15 +221,13 @@ export const ViraPopUpTrigger = defineViraElement()({
178
221
  css `
179
222
  bottom: -${state.showPopUpResult.positions.diff.bottom}px;
180
223
  top: calc(100% + ${inputs.popUpOffset?.vertical || 0}px);
181
- left: ${inputs.popUpOffset?.left || 0}px;
182
- right: ${inputs.popUpOffset?.right || 0}px;
224
+ ${horizontalPositionStyle}
183
225
  `
184
226
  : /** Dropdown going up position. */
185
227
  css `
186
228
  top: -${state.showPopUpResult.positions.diff.top}px;
187
229
  bottom: calc(100% + ${inputs.popUpOffset?.vertical || 0}px);
188
- left: ${inputs.popUpOffset?.left || 0}px;
189
- right: ${inputs.popUpOffset?.right || 0}px;
230
+ ${horizontalPositionStyle}
190
231
  `
191
232
  : undefined;
192
233
  function respondToClick(event) {
@@ -2,6 +2,7 @@ import { type PartialWithUndefined } from '@augment-vir/common';
2
2
  import { type ViraIconSvg } from '../icons/icon-svg.js';
3
3
  import { type ShowPopUpResult } from '../util/pop-up-manager.js';
4
4
  import { type MenuItem } from './pop-up/pop-up-menu-item.js';
5
+ import { HorizontalAnchor } from './pop-up/vira-pop-up-trigger.element.js';
5
6
  /**
6
7
  * Test ids for {@link ViraDropdown}.
7
8
  *
@@ -36,6 +37,17 @@ export declare const ViraDropdown: import("element-vir").DeclarativeElementDefin
36
37
  isDisabled: boolean;
37
38
  /** For debugging purposes only. Very bad for actual production code use. */
38
39
  z_debug_forceOpenState: boolean;
40
+ /**
41
+ * - `HorizontalAnchor.Left`: dropdown is anchored to the left side of the trigger and the
42
+ * dropdown can grow to the right.
43
+ * - `HorizontalAnchor.Right`: dropdown is anchored to the right side of the trigger and the
44
+ * dropdown can grow to the left.
45
+ * - `HorizontalAnchor.Both`: dropdown is anchored on both sides of the trigger and cannot
46
+ * grow beyond it. (This is the default experience.)
47
+ *
48
+ * @default HorizontalAnchor.Both
49
+ */
50
+ horizontalAnchor: HorizontalAnchor;
39
51
  }>, {
40
52
  /** `undefined` means the pop up is not currently showing. */
41
53
  showPopUpResult: ShowPopUpResult | undefined;
@@ -7,6 +7,7 @@ import { viraFormCssVars } from '../styles/form-themes.js';
7
7
  import { noUserSelect, viraAnimationDurations } from '../styles/index.js';
8
8
  import { defineViraElement } from './define-vira-element.js';
9
9
  import { ViraMenuTrigger } from './pop-up/vira-menu-trigger.element.js';
10
+ import { HorizontalAnchor } from './pop-up/vira-pop-up-trigger.element.js';
10
11
  import { ViraIcon } from './vira-icon.element.js';
11
12
  /**
12
13
  * Test ids for {@link ViraDropdown}.
@@ -140,6 +141,7 @@ export const ViraDropdown = defineViraElement()({
140
141
  vertical: -1,
141
142
  right: 24,
142
143
  },
144
+ horizontalAnchor: inputs.horizontalAnchor || HorizontalAnchor.Both,
143
145
  })}
144
146
  ${listen(ViraMenuTrigger.events.openChange, (event) => {
145
147
  updateState({ showPopUpResult: event.detail });
@@ -1,4 +1,5 @@
1
1
  import { clamp } from '@augment-vir/common';
2
+ import { applyAttributes } from 'device-navigation';
2
3
  import { css, html } from 'element-vir';
3
4
  import { defineViraElement } from './define-vira-element.js';
4
5
  /**
@@ -45,12 +46,18 @@ export const ViraProgress = defineViraElement()({
45
46
  flex-grow: 1;
46
47
  }
47
48
  `,
48
- render({ inputs }) {
49
+ render({ inputs, host }) {
49
50
  const min = inputs.min || 0;
50
51
  const max = inputs.max || 100;
51
52
  const totalRange = max - min;
52
53
  const value = inputs.value - min;
53
54
  const percentFull = clamp(Math.round((value / totalRange) * 100), { min: 0, max: 100 });
55
+ applyAttributes(host, {
56
+ 'aria-valuemin': inputs.min,
57
+ 'aria-valuemax': inputs.max,
58
+ 'aria-valuenow': inputs.value,
59
+ 'aria-role': 'progressbar',
60
+ });
54
61
  return html `
55
62
  <div
56
63
  class="progress-bar"
@@ -59,7 +59,7 @@ export type PopUpManagerOptions = {
59
59
  supportNavigation: boolean;
60
60
  };
61
61
  /**
62
- * Output type from {@link PopUpManager.showPopUp}
62
+ * Output type from `PopUpManager.showPopUp`
63
63
  *
64
64
  * @category PopUp
65
65
  */
@@ -49,8 +49,21 @@ export class PopUpManager {
49
49
  this.navController = navController;
50
50
  this.options = { ...this.options, ...options };
51
51
  }
52
- attachGlobalListeners() {
52
+ attachGlobalListeners(container) {
53
+ let firstFired = false;
54
+ const resizeObserver = new ResizeObserver(() => {
55
+ if (firstFired) {
56
+ this.removePopUp();
57
+ }
58
+ else {
59
+ firstFired = true;
60
+ }
61
+ });
62
+ resizeObserver.observe(container);
53
63
  this.cleanupCallbacks = [
64
+ () => {
65
+ resizeObserver.disconnect();
66
+ },
54
67
  listenToPageActivation(false, (isPageActive) => {
55
68
  if (!isPageActive) {
56
69
  this.removePopUp();
@@ -167,7 +180,7 @@ export class PopUpManager {
167
180
  });
168
181
  const useUp = diff.top > diff.bottom + currentOptions.verticalDiffThreshold &&
169
182
  diff.bottom < currentOptions.minDownSpace;
170
- this.attachGlobalListeners();
183
+ this.attachGlobalListeners(container);
171
184
  return {
172
185
  popDown: !useUp,
173
186
  positions: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vira",
3
- "version": "26.4.1",
3
+ "version": "26.5.1",
4
4
  "description": "A simple and highly versatile design system using element-vir.",
5
5
  "keywords": [
6
6
  "design",
@@ -38,21 +38,21 @@
38
38
  "test:docs": "virmator docs check"
39
39
  },
40
40
  "dependencies": {
41
- "@augment-vir/assert": "^31.23.3",
42
- "@augment-vir/common": "^31.23.3",
43
- "@augment-vir/web": "^31.23.3",
41
+ "@augment-vir/assert": "^31.26.0",
42
+ "@augment-vir/common": "^31.26.0",
43
+ "@augment-vir/web": "^31.26.0",
44
44
  "colorjs.io": "^0.5.2",
45
45
  "date-vir": "^7.3.1",
46
46
  "device-navigation": "^4.5.5",
47
47
  "lit-css-vars": "^3.0.11",
48
- "observavir": "^2.0.5",
48
+ "observavir": "^2.1.0",
49
49
  "page-active": "^1.0.1",
50
- "spa-router-vir": "^6.1.1",
50
+ "spa-router-vir": "^6.1.3",
51
51
  "type-fest": "^4.41.0",
52
52
  "typed-event-target": "^4.1.0"
53
53
  },
54
54
  "devDependencies": {
55
- "@augment-vir/test": "^31.23.3",
55
+ "@augment-vir/test": "^31.26.0",
56
56
  "@web/dev-server-esbuild": "^1.0.4",
57
57
  "@web/test-runner": "^0.20.2",
58
58
  "@web/test-runner-commands": "^0.9.0",
@@ -63,11 +63,11 @@
63
63
  "markdown-code-example-inserter": "^3.0.3",
64
64
  "typedoc": "^0.28.5",
65
65
  "typescript": "5.8.3",
66
- "vite": "^6.3.5",
66
+ "vite": "^7.0.0",
67
67
  "vite-tsconfig-paths": "^5.1.4"
68
68
  },
69
69
  "peerDependencies": {
70
- "element-vir": "^26.4.1"
70
+ "element-vir": "^26.5.1"
71
71
  },
72
72
  "engines": {
73
73
  "node": ">=22"