vira 28.3.0 → 28.5.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.
@@ -12,6 +12,7 @@ export * from './vira-card.element.js';
12
12
  export * from './vira-checkbox.element.js';
13
13
  export * from './vira-collapsible-wrapper.element.js';
14
14
  export * from './vira-dropdown.element.js';
15
+ export * from './vira-error.element.js';
15
16
  export * from './vira-icon.element.js';
16
17
  export * from './vira-image.element.js';
17
18
  export * from './vira-input.element.js';
@@ -12,6 +12,7 @@ export * from './vira-card.element.js';
12
12
  export * from './vira-checkbox.element.js';
13
13
  export * from './vira-collapsible-wrapper.element.js';
14
14
  export * from './vira-dropdown.element.js';
15
+ export * from './vira-error.element.js';
15
16
  export * from './vira-icon.element.js';
16
17
  export * from './vira-image.element.js';
17
18
  export * from './vira-input.element.js';
@@ -15,4 +15,4 @@ export declare enum ViraCardState {
15
15
  */
16
16
  export declare const ViraCard: import("element-vir").DeclarativeElementDefinition<"vira-card", {
17
17
  cardState?: ViraCardState | undefined;
18
- }, {}, {}, "vira-card-error" | "vira-card-success", "vira-card-border" | "vira-card-border-radius" | "vira-card-error-color" | "vira-card-success-color" | "vira-card-padding", readonly [], readonly []>;
18
+ }, {}, {}, "vira-card-error" | "vira-card-success", "vira-card-border" | "vira-card-border-radius" | "vira-card-padding", readonly [], readonly []>;
@@ -1,4 +1,5 @@
1
1
  import { css, html } from 'element-vir';
2
+ import { viraFormCssVars } from '../styles/form-styles.js';
2
3
  import { defineViraElement } from './define-vira-element.js';
3
4
  /**
4
5
  * State options for {@link ViraCard}.
@@ -25,8 +26,6 @@ export const ViraCard = defineViraElement()({
25
26
  cssVars: {
26
27
  'vira-card-border': '1px solid #d3d3d3',
27
28
  'vira-card-border-radius': '16px',
28
- 'vira-card-error-color': 'red',
29
- 'vira-card-success-color': 'green',
30
29
  'vira-card-padding': '16px',
31
30
  },
32
31
  styles: ({ hostClasses, cssVars }) => css `
@@ -38,10 +37,10 @@ export const ViraCard = defineViraElement()({
38
37
  }
39
38
 
40
39
  ${hostClasses['vira-card-error'].selector} {
41
- border-color: ${cssVars['vira-card-error-color'].value};
40
+ border-color: ${viraFormCssVars['vira-form-error-foreground-color'].value};
42
41
  }
43
42
  ${hostClasses['vira-card-success'].selector} {
44
- border-color: ${cssVars['vira-card-success-color'].value};
43
+ border-color: ${viraFormCssVars['vira-form-success-foreground-color'].value};
45
44
  }
46
45
  `,
47
46
  render() {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * An error wrapper that applies error coloring (red, by default).
3
+ *
4
+ * @category Elements
5
+ * @see https://electrovir.github.io/vira/book/elements/vira-error
6
+ */
7
+ export declare const ViraError: import("element-vir").DeclarativeElementDefinition<"vira-error", {}, {}, {}, "vira-error-", "vira-error-font-weight", readonly [], readonly []>;
@@ -0,0 +1,26 @@
1
+ import { css, html } from 'element-vir';
2
+ import { viraFormCssVars } from '../styles/form-styles.js';
3
+ import { defineViraElement } from './define-vira-element.js';
4
+ /**
5
+ * An error wrapper that applies error coloring (red, by default).
6
+ *
7
+ * @category Elements
8
+ * @see https://electrovir.github.io/vira/book/elements/vira-error
9
+ */
10
+ export const ViraError = defineViraElement()({
11
+ tagName: 'vira-error',
12
+ cssVars: {
13
+ 'vira-error-font-weight': 'bold',
14
+ },
15
+ styles: ({ cssVars }) => css `
16
+ :host {
17
+ color: ${viraFormCssVars['vira-form-error-foreground-color'].value};
18
+ font-weight: ${cssVars['vira-error-font-weight'].value};
19
+ }
20
+ `,
21
+ render() {
22
+ return html `
23
+ <slot></slot>
24
+ `;
25
+ },
26
+ });
@@ -1,3 +1,4 @@
1
+ import { type PartialWithUndefined } from '@augment-vir/common';
1
2
  import { type ViraIconSvg } from '../icons/index.js';
2
3
  import { type SharedTextInputElementInputs } from './shared-text-input-logic.js';
3
4
  export * from './shared-text-input-logic.js';
@@ -19,15 +20,24 @@ export declare enum ViraInputType {
19
20
  * @category Elements
20
21
  * @see https://electrovir.github.io/vira/book/elements/vira-input
21
22
  */
22
- export declare const ViraInput: import("element-vir").DeclarativeElementDefinition<"vira-input", {
23
- icon?: undefined | Pick<ViraIconSvg, "svgTemplate">;
24
- /** A suffix that, if provided, is shown following the user input field. */
25
- suffix?: string | undefined;
26
- showClearButton?: boolean | undefined;
27
- type?: ViraInputType;
28
- } & SharedTextInputElementInputs, {
23
+ export declare const ViraInput: import("element-vir").DeclarativeElementDefinition<"vira-input", Readonly<PartialWithUndefined<{
24
+ icon: Pick<ViraIconSvg, "svgTemplate">;
25
+ /** A suffix that, if provided, is shown following the input field. */
26
+ suffix: string;
27
+ /** A label that is shown above the input, if provided. */
28
+ label: string;
29
+ /** If true, applies error styling. */
30
+ hasError: boolean;
31
+ showClearButton: boolean;
32
+ type: ViraInputType;
33
+ }> & SharedTextInputElementInputs>, {
29
34
  forcedInputWidth: number;
30
35
  showPassword: boolean;
36
+ /**
37
+ * Used to couple the label and input together. This is not applied if no label is
38
+ * provided.
39
+ */
40
+ randomId: string;
31
41
  }, {
32
42
  /**
33
43
  * Fires whenever a user input created a new value. Does not fire if all input letters are
@@ -40,4 +50,4 @@ export declare const ViraInput: import("element-vir").DeclarativeElementDefiniti
40
50
  * that was blocked out of programmatic "value" property assignments.
41
51
  */
42
52
  inputBlocked: import("element-vir").DefineEvent<string>;
43
- }, "vira-input-disabled" | "vira-input-fit-text" | "vira-input-clear-button-shown", "vira-input-background-color" | "vira-input-placeholder-color" | "vira-input-text-color" | "vira-input-border-color" | "vira-input-text-selection-color" | "vira-input-action-button-color" | "vira-input-clear-button-hover-color" | "vira-input-clear-button-active-color" | "vira-input-show-password-button-hover-color" | "vira-input-show-password-button-active-color" | "vira-input-padding-horizontal" | "vira-input-padding-vertical", readonly [], readonly []>;
53
+ }, "vira-input-disabled" | "vira-input-fit-text" | "vira-input-clear-button-shown" | "vira-input-error", "vira-input-background-color" | "vira-input-placeholder-color" | "vira-input-text-color" | "vira-input-border-color" | "vira-input-text-selection-color" | "vira-input-action-button-color" | "vira-input-clear-button-hover-color" | "vira-input-clear-button-active-color" | "vira-input-show-password-button-hover-color" | "vira-input-show-password-button-active-color" | "vira-input-padding-horizontal" | "vira-input-padding-vertical", readonly [], readonly []>;
@@ -1,9 +1,11 @@
1
1
  import { assertWrap } from '@augment-vir/assert';
2
+ import { randomString } from '@augment-vir/common';
2
3
  import { extractEventTarget } from '@augment-vir/web';
3
4
  import { attributes, css, defineElementEvent, html, ifDefined, listen, nothing, onResize, renderIf, } from 'element-vir';
4
5
  import { CloseX24Icon } from '../icons/icon-svgs/close-x-24.icon.js';
5
6
  import { EyeClosed24Icon, EyeOpen24Icon } from '../icons/index.js';
6
7
  import { createFocusStyles } from '../styles/focus.js';
8
+ import { viraFormCssVars } from '../styles/form-styles.js';
7
9
  import { noUserSelect, viraAnimationDurations, viraBorders, viraDisabledStyles, } from '../styles/index.js';
8
10
  import { noNativeFormStyles } from '../styles/native-styles.js';
9
11
  import { defineViraElement } from './define-vira-element.js';
@@ -57,6 +59,15 @@ export const ViraInput = defineViraElement()({
57
59
  color: ${cssVars['vira-input-text-color'].value};
58
60
  }
59
61
 
62
+ label {
63
+ display: flex;
64
+ flex-direction: column;
65
+ justify-content: flex-start;
66
+ gap: 2px;
67
+ width: 100%;
68
+ max-width: 100%;
69
+ }
70
+
60
71
  ${hostClasses['vira-input-disabled'].selector} {
61
72
  ${viraDisabledStyles};
62
73
  }
@@ -226,6 +237,12 @@ export const ViraInput = defineViraElement()({
226
237
  .show-password-button:active {
227
238
  color: ${cssVars['vira-input-show-password-button-active-color'].value};
228
239
  }
240
+
241
+ ${hostClasses['vira-input-error'].selector} {
242
+ & .wrapper-border {
243
+ border-color: ${viraFormCssVars['vira-form-error-foreground-color'].value};
244
+ }
245
+ }
229
246
  `;
230
247
  },
231
248
  events: {
@@ -245,12 +262,18 @@ export const ViraInput = defineViraElement()({
245
262
  return {
246
263
  forcedInputWidth: 0,
247
264
  showPassword: false,
265
+ /**
266
+ * Used to couple the label and input together. This is not applied if no label is
267
+ * provided.
268
+ */
269
+ randomId: randomString(32),
248
270
  };
249
271
  },
250
272
  hostClasses: {
251
273
  'vira-input-disabled': ({ inputs }) => !!inputs.disabled,
252
274
  'vira-input-fit-text': ({ inputs }) => !!inputs.fitText,
253
275
  'vira-input-clear-button-shown': ({ inputs }) => !!inputs.showClearButton,
276
+ 'vira-input-error': ({ inputs }) => !!inputs.hasError,
254
277
  },
255
278
  render: ({ inputs, dispatch, state, updateState, events, host }) => {
256
279
  const { filtered: filteredValue } = filterTextInputValue({
@@ -274,11 +297,7 @@ export const ViraInput = defineViraElement()({
274
297
  * spellchecking).
275
298
  */
276
299
  inputs.type === ViraInputType.Password;
277
- /**
278
- * Don't use a wrapping `<label>` element here because it will mess with browser and
279
- * password manager autocomplete for passwords and usernames.
280
- */
281
- return html `
300
+ const inputTemplate = html `
282
301
  <span
283
302
  class="input-wrapper"
284
303
  ${listen('mousedown', (event) => {
@@ -305,6 +324,8 @@ export const ViraInput = defineViraElement()({
305
324
  `)}
306
325
 
307
326
  <input
327
+ id=${ifDefined(inputs.label ? state.randomId : undefined)}
328
+ aria-label=${ifDefined(inputs.label || undefined)}
308
329
  type=${calculateEffectiveInputType(inputs.type, state.showPassword)}
309
330
  style=${forcedInputWidthStyles}
310
331
  autocomplete=${ifDefined(shouldBlockBrowserHelps ? 'off' : undefined)}
@@ -377,6 +398,17 @@ export const ViraInput = defineViraElement()({
377
398
  <div class="border-style wrapper-border"></div>
378
399
  </span>
379
400
  `;
401
+ if (inputs.label) {
402
+ return html `
403
+ <label for=${state.randomId}>
404
+ <span class="input-label">${inputs.label}</span>
405
+ ${inputTemplate}
406
+ </label>
407
+ `;
408
+ }
409
+ else {
410
+ return inputTemplate;
411
+ }
380
412
  },
381
413
  });
382
414
  function calculateEffectiveInputType(type, showPassword) {
@@ -12,4 +12,6 @@ export declare const viraFormCssVars: import("lit-css-vars").CssVarDefinitions<{
12
12
  readonly 'vira-form-selection-hover-foreground-color': "black";
13
13
  readonly 'vira-form-selection-active-background-color': "#d2eaff";
14
14
  readonly 'vira-form-selection-active-foreground-color': "black";
15
+ readonly 'vira-form-error-foreground-color': "red";
16
+ readonly 'vira-form-success-foreground-color': "green";
15
17
  }>;
@@ -13,4 +13,6 @@ export const viraFormCssVars = defineCssVars({
13
13
  'vira-form-selection-hover-foreground-color': 'black',
14
14
  'vira-form-selection-active-background-color': '#d2eaff',
15
15
  'vira-form-selection-active-foreground-color': 'black',
16
+ 'vira-form-error-foreground-color': 'red',
17
+ 'vira-form-success-foreground-color': 'green',
16
18
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vira",
3
- "version": "28.3.0",
3
+ "version": "28.5.0",
4
4
  "description": "A simple and highly versatile design system using element-vir.",
5
5
  "keywords": [
6
6
  "design",