vira 25.3.0 → 25.4.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.
@@ -1,5 +1,5 @@
1
- import { PopUpManager, ShowPopUpResult } from '../../util/pop-up-manager.js';
2
- import { ViraDropdownOption } from './vira-dropdown-item.element.js';
1
+ import { type PopUpManager, type ShowPopUpResult } from '../../util/pop-up-manager.js';
2
+ import { type ViraDropdownOption } from './vira-dropdown-item.element.js';
3
3
  /**
4
4
  * Filters an array of {@link ViraDropdownOption} based on the given selection.
5
5
  *
@@ -1,5 +1,5 @@
1
- import { PartialWithUndefined } from '@augment-vir/common';
2
- import { HTMLTemplateResult } from 'element-vir';
1
+ import { type PartialWithUndefined } from '@augment-vir/common';
2
+ import { type HTMLTemplateResult } from 'element-vir';
3
3
  /**
4
4
  * An individual option for ViraDropdown.
5
5
  *
@@ -1,4 +1,5 @@
1
- import { ViraDropdownOption } from './vira-dropdown-item.element.js';
1
+ import { type NavController } from 'device-navigation';
2
+ import { type ViraDropdownOption } from './vira-dropdown-item.element.js';
2
3
  /**
3
4
  * Test ids for {@link ViraDropdownOptions}.
4
5
  *
@@ -14,6 +15,7 @@ export declare const viraDropdownOptionsTestIds: {
14
15
  * @category Elements
15
16
  */
16
17
  export declare const ViraDropdownOptions: import("element-vir").DeclarativeElementDefinition<"vira-dropdown-options", Readonly<{
18
+ navController: NavController;
17
19
  /** All dropdown options to show to the user. */
18
20
  options: ReadonlyArray<Readonly<ViraDropdownOption>>;
19
21
  /**
@@ -1,5 +1,5 @@
1
- import { nav, navSelector } from 'device-navigation';
2
- import { classMap, css, defineElementEvent, html, ifDefined, listen, nothing, testId, } from 'element-vir';
1
+ import { nav, navAttribute, NavValue } from 'device-navigation';
2
+ import { classMap, css, defineElementEvent, html, ifDefined, listen, testId } from 'element-vir';
3
3
  import { viraBorders } from '../../styles/border.js';
4
4
  import { viraFormCssVars } from '../../styles/form-themes.js';
5
5
  import { viraDisabledStyles } from '../../styles/index.js';
@@ -49,7 +49,10 @@ export const ViraDropdownOptions = defineViraElement()({
49
49
  outline: none;
50
50
  }
51
51
 
52
- ${navSelector.css.selected('.dropdown-item:not(.disabled)')} {
52
+ ${navAttribute.css({
53
+ baseSelector: '.dropdown-item:not(.disabled):not(.selected)',
54
+ navValue: NavValue.Focused,
55
+ })} {
53
56
  background-color: ${viraFormCssVars['vira-form-selection-hover-background-color']
54
57
  .value};
55
58
  outline: none;
@@ -66,22 +69,24 @@ export const ViraDropdownOptions = defineViraElement()({
66
69
  `,
67
70
  render({ inputs, dispatch, events }) {
68
71
  const optionTemplates = inputs.options.map((option) => {
72
+ const selected = inputs.selectedOptions.includes(option);
69
73
  const innerTemplate = option.template ||
70
74
  html `
71
75
  <${ViraDropdownItem.assign({
72
76
  label: option.label,
73
- selected: inputs.selectedOptions.includes(option),
77
+ selected,
74
78
  })}></${ViraDropdownItem}>
75
79
  `;
76
80
  return html `
77
81
  <div
78
82
  class="dropdown-item ${classMap({
79
83
  disabled: !!option.disabled,
84
+ selected,
80
85
  })}"
81
86
  ${testId(viraDropdownOptionsTestIds.option)}
82
87
  title=${ifDefined(option.hoverText || undefined)}
83
88
  role="option"
84
- ${option.disabled ? nothing : nav()}
89
+ ${nav(inputs.navController, { disabled: option.disabled || selected })}
85
90
  ${listen('mousedown', (event) => {
86
91
  /**
87
92
  * Prevent this mousedown event from propagating to the window, which would
@@ -1,8 +1,7 @@
1
- import { PartialWithUndefined } from '@augment-vir/common';
2
- import { NavController } from 'device-navigation';
3
- import { ViraIconSvg } from '../../icons/icon-svg.js';
4
- import { PopUpManager, ShowPopUpResult } from '../../util/pop-up-manager.js';
5
- import { ViraDropdownOption } from './vira-dropdown-item.element.js';
1
+ import { type PartialWithUndefined } from '@augment-vir/common';
2
+ import { type ViraIconSvg } from '../../icons/icon-svg.js';
3
+ import { PopUpManager, type ShowPopUpResult } from '../../util/pop-up-manager.js';
4
+ import { type ViraDropdownOption } from './vira-dropdown-item.element.js';
6
5
  /**
7
6
  * Test ids for {@link ViraDropdown}.
8
7
  *
@@ -42,7 +41,6 @@ export declare const ViraDropdown: import("element-vir").DeclarativeElementDefin
42
41
  /** `undefined` means the pop up is not currently showing. */
43
42
  showPopUpResult: ShowPopUpResult | undefined;
44
43
  popUpManager: PopUpManager;
45
- navController: NavController | undefined;
46
44
  }, {
47
45
  selectedChange: import("element-vir").DefineEvent<PropertyKey[]>;
48
46
  openChange: import("element-vir").DefineEvent<boolean>;
@@ -32,12 +32,11 @@ export const viraDropdownTestIds = {
32
32
  */
33
33
  export const ViraDropdown = defineViraElement()({
34
34
  tagName: 'vira-dropdown',
35
- state() {
35
+ state({ host }) {
36
36
  return {
37
37
  /** `undefined` means the pop up is not currently showing. */
38
38
  showPopUpResult: undefined,
39
- popUpManager: new PopUpManager(),
40
- navController: undefined,
39
+ popUpManager: new PopUpManager(new NavController(host)),
41
40
  };
42
41
  },
43
42
  hostClasses: {
@@ -195,7 +194,6 @@ export const ViraDropdown = defineViraElement()({
195
194
  }
196
195
  dispatch(new events.selectedChange(createNewSelection(option.id, inputs.selected, !!inputs.isMultiSelect)));
197
196
  });
198
- updateState({ navController: new NavController(host) });
199
197
  },
200
198
  render({ dispatch, events, state, inputs, updateState, host }) {
201
199
  assertUniqueIdProps(inputs.options);
@@ -304,6 +302,7 @@ export const ViraDropdown = defineViraElement()({
304
302
  <${ViraDropdownOptions.assign({
305
303
  options: inputs.options,
306
304
  selectedOptions,
305
+ navController: state.popUpManager.navController,
307
306
  })}
308
307
  ${listen(ViraDropdownOptions.events.selectionChange, (event) => {
309
308
  /**
@@ -1,3 +1,4 @@
1
+ import { type AttributeValues } from 'element-vir';
1
2
  /**
2
3
  * Inputs shared between the multiple input elements.
3
4
  *
@@ -23,6 +24,8 @@ export type SharedTextInputElementInputs = {
23
24
  disableBrowserHelps?: boolean;
24
25
  /** Set this to true to make the whole element size to only fit the input text. */
25
26
  fitText?: boolean;
27
+ /** A set of attributes that will be applied to the inner native text element. */
28
+ attributePassthrough?: AttributeValues | undefined;
26
29
  };
27
30
  /**
28
31
  * Inputs used to check if the current input element value is allowed.
@@ -1,4 +1,4 @@
1
- import { ViraIconSvg } from '../icons/index.js';
1
+ import { type ViraIconSvg } from '../icons/index.js';
2
2
  /**
3
3
  * Button styles available for {@link ViraButton}.
4
4
  *
@@ -1,4 +1,4 @@
1
- import { ViraIconSvg } from '../icons/icon-svg.js';
1
+ import { type ViraIconSvg } from '../icons/icon-svg.js';
2
2
  /**
3
3
  * An element that renders a single {@link ViraIconSvg}.
4
4
  *
@@ -1,5 +1,5 @@
1
- import { Dimensions } from '@augment-vir/common';
2
- import { Duration, DurationUnit } from 'date-vir';
1
+ import { type Dimensions } from '@augment-vir/common';
2
+ import { type Duration, type DurationUnit } from 'date-vir';
3
3
  /**
4
4
  * An `<img>` element wrapper that handles size constraints and includes slots for loading and error
5
5
  * indicators.
@@ -1,5 +1,5 @@
1
- import { ViraIconSvg } from '../icons/index.js';
2
- import { SharedTextInputElementInputs } from './shared-text-input-logic.js';
1
+ import { type ViraIconSvg } from '../icons/index.js';
2
+ import { type SharedTextInputElementInputs } from './shared-text-input-logic.js';
3
3
  export * from './shared-text-input-logic.js';
4
4
  /**
5
5
  * Input types for {@link ViraInput}.
@@ -1,4 +1,4 @@
1
- import { css, defineElementEvent, html, listen, onResize, renderIf, } from 'element-vir';
1
+ import { attributes, css, defineElementEvent, html, listen, nothing, onResize, renderIf, } from 'element-vir';
2
2
  import { CloseX24Icon } from '../icons/icon-svgs/close-x-24.icon.js';
3
3
  import { EyeClosed24Icon, EyeOpen24Icon } from '../icons/index.js';
4
4
  import { createFocusStyles, viraFocusCssVars } from '../styles/focus.js';
@@ -311,6 +311,9 @@ export const ViraInput = defineViraElement()({
311
311
  });
312
312
  })}
313
313
  placeholder=${inputs.placeholder}
314
+ ${inputs.attributePassthrough
315
+ ? attributes(inputs.attributePassthrough)
316
+ : nothing}
314
317
  />
315
318
  ${renderIf(!!(inputs.showClearButton && inputs.value), html `
316
319
  <button
@@ -1,6 +1,5 @@
1
- import type { PartialWithUndefined } from '@augment-vir/common';
2
- import { SpaRoute, SpaRouter } from 'spa-router-vir';
3
- import { RequireExactlyOne } from 'type-fest';
1
+ import { type PartialWithUndefined } from '@augment-vir/common';
2
+ import { type SpaRoute, type SpaRouter } from 'spa-router-vir';
4
3
  /**
5
4
  * A hyperlink wrapper element that can be configured to emit route change events rather than just
6
5
  * being a raw link.
@@ -9,7 +8,7 @@ import { RequireExactlyOne } from 'type-fest';
9
8
  * @category Elements
10
9
  * @see https://electrovir.github.io/element-vir/vira/book/elements/vira-link
11
10
  */
12
- export declare const ViraLink: import("element-vir").DeclarativeElementDefinition<"vira-link", RequireExactlyOne<{
11
+ export declare const ViraLink: import("element-vir").DeclarativeElementDefinition<"vira-link", import("type-fest/source/require-exactly-one.js")._RequireExactlyOne<{
13
12
  /**
14
13
  * A full raw URL link that will navigate the current window away or open a new tab. If this
15
14
  * property is provided for the inputs, don't provide a route property.
@@ -27,7 +26,7 @@ export declare const ViraLink: import("element-vir").DeclarativeElementDefinitio
27
26
  router: Pick<SpaRouter<any, any, any>, "createRouteUrl" | "setRouteOnDirectNavigation">;
28
27
  scrollToTop?: boolean;
29
28
  };
30
- }> & PartialWithUndefined<{
29
+ }, "link" | "route"> & PartialWithUndefined<{
31
30
  aria?: {
32
31
  /**
33
32
  * This label will be attached to the inner `<a>` element's `aria-label` attribute.
@@ -1,4 +1,4 @@
1
- import { TemplateResult } from 'element-vir';
1
+ import { type TemplateResult } from 'element-vir';
2
2
  import { viraIconCssVars } from './icon-css-vars.js';
3
3
  /**
4
4
  * An individual Vira icon SVG definition.
@@ -1,5 +1,5 @@
1
- import { Format } from 'colorjs.io/types/src/space';
2
- import { ColorTypes } from '../re-exports/colorjs-io.js';
1
+ import { type Format } from 'colorjs.io/types/src/space';
2
+ import { type ColorTypes } from '../re-exports/colorjs-io.js';
3
3
  /**
4
4
  * Asserts that the given color type is valid.
5
5
  *
@@ -1,4 +1,4 @@
1
- import { CSSResult } from 'element-vir';
1
+ import { type CSSResult } from 'element-vir';
2
2
  /**
3
3
  * CSS chunks for default Vira shadow styles.
4
4
  *
@@ -1,6 +1,6 @@
1
- import { MaybePromise } from '@augment-vir/common';
2
- import { Coords } from 'device-navigation';
3
- import { ExtractEventByType, ExtractEventTypes, ListenOptions, RemoveListenerCallback } from 'typed-event-target';
1
+ import { type MaybePromise } from '@augment-vir/common';
2
+ import { type Coords, type NavController } from 'device-navigation';
3
+ import { type ExtractEventByType, type ExtractEventTypes, type ListenOptions, type RemoveListenerCallback } from 'typed-event-target';
4
4
  /**
5
5
  * A type used for representing a rectangle's position.
6
6
  *
@@ -120,11 +120,12 @@ export type PopUpManagerEvents = HidePopUpEvent | NavSelectEvent;
120
120
  * @category Pop Up
121
121
  */
122
122
  export declare class PopUpManager {
123
+ readonly navController: NavController;
123
124
  private listenTarget;
124
125
  private options;
125
126
  private cleanupCallbacks;
126
127
  private lastRootElement;
127
- constructor(options?: Partial<PopUpManagerOptions> | undefined);
128
+ constructor(navController: NavController, options?: Partial<PopUpManagerOptions> | undefined);
128
129
  private attachGlobalListeners;
129
130
  /** Listen to events emitted from a {@link PopUpManager} instance. */
130
131
  listen<const EventDefinition extends Readonly<{
@@ -1,7 +1,7 @@
1
1
  import { assert } from '@augment-vir/assert';
2
2
  import { mapObjectValues } from '@augment-vir/common';
3
3
  import { findOverflowAncestor } from '@augment-vir/web';
4
- import { NavController, NavDirection } from 'device-navigation';
4
+ import { NavDirection } from 'device-navigation';
5
5
  import { listenToPageActivation } from 'page-active';
6
6
  import { ListenTarget, defineTypedCustomEvent, defineTypedEvent, listenToGlobal, } from 'typed-event-target';
7
7
  /**
@@ -36,6 +36,7 @@ export class NavSelectEvent extends defineTypedCustomEvent()('nav-select') {
36
36
  * @category Pop Up
37
37
  */
38
38
  export class PopUpManager {
39
+ navController;
39
40
  listenTarget = new ListenTarget();
40
41
  options = {
41
42
  minDownSpace: 200,
@@ -44,11 +45,11 @@ export class PopUpManager {
44
45
  };
45
46
  cleanupCallbacks = [];
46
47
  lastRootElement;
47
- constructor(options) {
48
+ constructor(navController, options) {
49
+ this.navController = navController;
48
50
  this.options = { ...this.options, ...options };
49
51
  }
50
- attachGlobalListeners(rootElement) {
51
- const navController = new NavController(rootElement);
52
+ attachGlobalListeners() {
52
53
  this.cleanupCallbacks = [
53
54
  listenToPageActivation(false, (isPageActive) => {
54
55
  if (!isPageActive) {
@@ -72,7 +73,7 @@ export class PopUpManager {
72
73
  if (keyCode === 'ArrowDown') {
73
74
  event.stopImmediatePropagation();
74
75
  event.preventDefault();
75
- navController.navigate({
76
+ this.navController.navigate({
76
77
  direction: NavDirection.Down,
77
78
  allowWrapping: false,
78
79
  });
@@ -80,7 +81,7 @@ export class PopUpManager {
80
81
  else if (keyCode === 'ArrowUp') {
81
82
  event.stopImmediatePropagation();
82
83
  event.preventDefault();
83
- navController.navigate({
84
+ this.navController.navigate({
84
85
  direction: NavDirection.Up,
85
86
  allowWrapping: false,
86
87
  });
@@ -88,7 +89,7 @@ export class PopUpManager {
88
89
  else if (keyCode === 'ArrowLeft') {
89
90
  event.stopImmediatePropagation();
90
91
  event.preventDefault();
91
- navController.navigate({
92
+ this.navController.navigate({
92
93
  direction: NavDirection.Left,
93
94
  allowWrapping: false,
94
95
  });
@@ -96,16 +97,15 @@ export class PopUpManager {
96
97
  else if (keyCode === 'ArrowRight') {
97
98
  event.stopImmediatePropagation();
98
99
  event.preventDefault();
99
- navController.navigate({
100
+ this.navController.navigate({
100
101
  direction: NavDirection.Right,
101
102
  allowWrapping: false,
102
103
  });
103
104
  }
104
105
  else if (keyCode === 'Enter' || keyCode === 'Return') {
105
- const currentlyFocused = navController.getCurrentlyFocused();
106
- if (currentlyFocused) {
107
- navController.enterInto();
108
- this.listenTarget.dispatch(new NavSelectEvent({ detail: currentlyFocused.node.coords }));
106
+ const result = this.navController.enterInto({ fallbackToActivate: true });
107
+ if (result.success) {
108
+ this.listenTarget.dispatch(new NavSelectEvent({ detail: result.coords }));
109
109
  event.stopImmediatePropagation();
110
110
  event.preventDefault();
111
111
  }
@@ -156,7 +156,7 @@ export class PopUpManager {
156
156
  });
157
157
  const useUp = diff.top > diff.bottom + currentOptions.verticalDiffThreshold &&
158
158
  diff.bottom < currentOptions.minDownSpace;
159
- this.attachGlobalListeners(rootElement);
159
+ this.attachGlobalListeners();
160
160
  return {
161
161
  popDown: !useUp,
162
162
  positions: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vira",
3
- "version": "25.3.0",
3
+ "version": "25.4.0",
4
4
  "description": "A simple and highly versatile design system using element-vir.",
5
5
  "keywords": [
6
6
  "design",
@@ -37,36 +37,36 @@
37
37
  "test:docs": "virmator docs check"
38
38
  },
39
39
  "dependencies": {
40
- "@augment-vir/assert": "^31.11.0",
41
- "@augment-vir/common": "^31.11.0",
42
- "@augment-vir/web": "^31.11.0",
40
+ "@augment-vir/assert": "^31.18.0",
41
+ "@augment-vir/common": "^31.18.0",
42
+ "@augment-vir/web": "^31.18.0",
43
43
  "colorjs.io": "^0.5.2",
44
44
  "date-vir": "^7.3.1",
45
- "device-navigation": "^3.1.1",
45
+ "device-navigation": "^4.1.2",
46
46
  "lit-css-vars": "^3.0.11",
47
47
  "observavir": "^2.0.5",
48
48
  "page-active": "^1.0.1",
49
49
  "spa-router-vir": "^5.3.1",
50
- "type-fest": "^4.40.0",
51
- "typed-event-target": "^4.0.3"
50
+ "type-fest": "^4.41.0",
51
+ "typed-event-target": "^4.0.4"
52
52
  },
53
53
  "devDependencies": {
54
- "@augment-vir/test": "^31.11.0",
54
+ "@augment-vir/test": "^31.18.0",
55
55
  "@web/dev-server-esbuild": "^1.0.4",
56
56
  "@web/test-runner": "^0.20.1",
57
57
  "@web/test-runner-commands": "^0.9.0",
58
58
  "@web/test-runner-playwright": "^0.11.0",
59
59
  "@web/test-runner-visual-regression": "^0.10.0",
60
- "esbuild": "^0.25.2",
60
+ "esbuild": "^0.25.4",
61
61
  "istanbul-smart-text-reporter": "^1.1.5",
62
62
  "markdown-code-example-inserter": "^3.0.3",
63
- "typedoc": "^0.28.2",
63
+ "typedoc": "^0.28.4",
64
64
  "typescript": "5.8.3",
65
- "vite": "^6.2.6",
65
+ "vite": "^6.3.5",
66
66
  "vite-tsconfig-paths": "^5.1.4"
67
67
  },
68
68
  "peerDependencies": {
69
- "element-vir": "^25.3.0"
69
+ "element-vir": "^25.4.0"
70
70
  },
71
71
  "engines": {
72
72
  "node": ">=22"