vira 28.5.1 → 28.6.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.
@@ -19,3 +19,4 @@ export * from './vira-input.element.js';
19
19
  export * from './vira-link.element.js';
20
20
  export * from './vira-modal.element.js';
21
21
  export * from './vira-progress.element.js';
22
+ export * from './vira-select.element.js';
@@ -19,3 +19,4 @@ export * from './vira-input.element.js';
19
19
  export * from './vira-link.element.js';
20
20
  export * from './vira-modal.element.js';
21
21
  export * from './vira-progress.element.js';
22
+ export * from './vira-select.element.js';
@@ -50,4 +50,4 @@ export declare const ViraInput: import("element-vir").DeclarativeElementDefiniti
50
50
  * that was blocked out of programmatic "value" property assignments.
51
51
  */
52
52
  inputBlocked: import("element-vir").DefineEvent<string>;
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" | "vira-input-label-font-weight", readonly [], readonly []>;
53
+ }, "vira-input-disabled" | "vira-input-fit-text" | "vira-input-clear-button-shown" | "vira-input-error", "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 []>;
@@ -34,11 +34,6 @@ export var ViraInputType;
34
34
  export const ViraInput = defineViraElement()({
35
35
  tagName: 'vira-input',
36
36
  cssVars: {
37
- 'vira-input-background-color': 'white',
38
- 'vira-input-placeholder-color': '#cccccc',
39
- 'vira-input-text-color': '#000000',
40
- 'vira-input-border-color': '#cccccc',
41
- 'vira-input-text-selection-color': '#cfe9ff',
42
37
  'vira-input-action-button-color': '#aaaaaa',
43
38
  'vira-input-clear-button-hover-color': '#ff0000',
44
39
  'vira-input-clear-button-active-color': '#b30000',
@@ -48,7 +43,6 @@ export const ViraInput = defineViraElement()({
48
43
  'vira-input-show-password-button-active-color': '#0261ba',
49
44
  'vira-input-padding-horizontal': '10px',
50
45
  'vira-input-padding-vertical': '6px',
51
- 'vira-input-label-font-weight': 'bold',
52
46
  },
53
47
  styles: ({ hostClasses, cssVars }) => {
54
48
  return css `
@@ -57,7 +51,7 @@ export const ViraInput = defineViraElement()({
57
51
  display: inline-flex;
58
52
  width: 224px;
59
53
  box-sizing: border-box;
60
- color: ${cssVars['vira-input-text-color'].value};
54
+ color: ${viraFormCssVars['vira-form-foreground-color'].value};
61
55
  }
62
56
 
63
57
  label {
@@ -69,17 +63,13 @@ export const ViraInput = defineViraElement()({
69
63
  max-width: 100%;
70
64
 
71
65
  & .input-label {
72
- font-weight: ${cssVars['vira-input-label-font-weight'].value};
66
+ font-weight: ${viraFormCssVars['vira-form-label-font-weight'].value};
73
67
  text-align: left;
74
68
  flex-shrink: 0;
75
69
  flex-wrap: wrap;
76
70
  }
77
71
  }
78
72
 
79
- ${hostClasses['vira-input-disabled'].selector} {
80
- ${viraDisabledStyles};
81
- }
82
-
83
73
  ${hostClasses['vira-input-fit-text'].selector} {
84
74
  width: unset;
85
75
  }
@@ -144,9 +134,7 @@ export const ViraInput = defineViraElement()({
144
134
  .wrapper-border {
145
135
  top: -1px;
146
136
  left: -1px;
147
- border: 1px solid ${cssVars['vira-input-border-color'].value};
148
- transition: border
149
- ${viraAnimationDurations['vira-interaction-animation-duration'].value};
137
+ border: 1px solid ${viraFormCssVars['vira-form-border-color'].value};
150
138
  }
151
139
 
152
140
  .input-wrapper {
@@ -159,7 +147,7 @@ export const ViraInput = defineViraElement()({
159
147
  position: relative;
160
148
  padding: 0 ${cssVars['vira-input-padding-horizontal'].value};
161
149
  border-radius: ${viraBorders['vira-form-input-radius'].value};
162
- background-color: ${cssVars['vira-input-background-color'].value};
150
+ background-color: ${viraFormCssVars['vira-form-background-color'].value};
163
151
  /*
164
152
  Border colors are actually applied via the .wrapper-border class. However, we must
165
153
  apply a border here still so that it takes up space.
@@ -195,11 +183,11 @@ export const ViraInput = defineViraElement()({
195
183
  }
196
184
 
197
185
  ::selection {
198
- background: ${cssVars['vira-input-text-selection-color']
186
+ background: ${viraFormCssVars['vira-form-text-selection-color']
199
187
  .value}; /* WebKit/Blink Browsers */
200
188
  }
201
189
  ::-moz-selection {
202
- background: ${cssVars['vira-input-text-selection-color']
190
+ background: ${viraFormCssVars['vira-form-text-selection-color']
203
191
  .value}; /* Gecko Browsers */
204
192
  }
205
193
 
@@ -209,7 +197,7 @@ export const ViraInput = defineViraElement()({
209
197
  }
210
198
 
211
199
  input::placeholder {
212
- color: ${cssVars['vira-input-placeholder-color'].value};
200
+ color: ${viraFormCssVars['vira-form-placeholder-color'].value};
213
201
  }
214
202
 
215
203
  .suffix {
@@ -251,6 +239,25 @@ export const ViraInput = defineViraElement()({
251
239
  border-color: ${viraFormCssVars['vira-form-error-foreground-color'].value};
252
240
  }
253
241
  }
242
+
243
+ ${hostClasses['vira-input-disabled'].selector} {
244
+ cursor: not-allowed;
245
+
246
+ & label,
247
+ & .input-wrapper {
248
+ cursor: not-allowed;
249
+ }
250
+
251
+ & input,
252
+ & .wrapper-border,
253
+ & input::placeholder {
254
+ ${viraDisabledStyles};
255
+ }
256
+
257
+ & .focus-border {
258
+ display: none;
259
+ }
260
+ }
254
261
  `;
255
262
  },
256
263
  events: {
@@ -299,16 +306,7 @@ export const ViraInput = defineViraElement()({
299
306
  width: ${state.forcedInputWidth}px;
300
307
  `
301
308
  : nothing;
302
- const shouldBlockBrowserHelps = inputs.disableBrowserHelps ||
303
- /**
304
- * Some browsers leaks passwords with their browser helps (like Chrome with
305
- * spellchecking).
306
- */
307
- inputs.type === ViraInputType.Password;
308
- const inputTemplate = html `
309
- <span
310
- class="input-wrapper"
311
- ${listen('mousedown', (event) => {
309
+ const mousedownListener = listen('mousedown', (event) => {
312
310
  const eventTarget = extractEventTarget(event, HTMLElement, {
313
311
  useOriginalTarget: true,
314
312
  });
@@ -317,8 +315,15 @@ export const ViraInput = defineViraElement()({
317
315
  event.preventDefault();
318
316
  inputElement.focus();
319
317
  }
320
- })}
321
- >
318
+ });
319
+ const shouldBlockBrowserHelps = inputs.disableBrowserHelps ||
320
+ /**
321
+ * Some browsers leaks passwords with their browser helps (like Chrome with
322
+ * spellchecking).
323
+ */
324
+ inputs.type === ViraInputType.Password;
325
+ const inputTemplate = html `
326
+ <span class="input-wrapper" ${inputs.label ? nothing : mousedownListener}>
322
327
  ${iconTemplate}
323
328
  ${renderIf(!!inputs.fitText, html `
324
329
  <span
@@ -408,7 +413,7 @@ export const ViraInput = defineViraElement()({
408
413
  `;
409
414
  if (inputs.label) {
410
415
  return html `
411
- <label for=${state.randomId}>
416
+ <label for=${state.randomId} ${mousedownListener}>
412
417
  <span class="input-label">${inputs.label}</span>
413
418
  ${inputTemplate}
414
419
  </label>
@@ -0,0 +1,48 @@
1
+ import { type PartialWithUndefined } from '@augment-vir/common';
2
+ import { type AttributeValues } from 'element-vir';
3
+ import { type ViraIconSvg } from '../icons/index.js';
4
+ /**
5
+ * Options for {@link ViraSelect}.
6
+ *
7
+ * @category Dropdown
8
+ * @category Elements
9
+ * @see https://electrovir.github.io/vira/book/elements/vira-select
10
+ */
11
+ export type ViraSelectOption = {
12
+ /** A value or id, used to keep track of which option is selected. */
13
+ value: string;
14
+ label: string;
15
+ } & PartialWithUndefined<{
16
+ disabled: boolean;
17
+ }>;
18
+ /**
19
+ * Similar to {@link ViraDropdown} but is, instead, simply a wrapper for `<select>` and nothing more.
20
+ *
21
+ * @category Dropdown
22
+ * @category Elements
23
+ * @see https://electrovir.github.io/vira/book/elements/vira-select
24
+ */
25
+ export declare const ViraSelect: import("element-vir").DeclarativeElementDefinition<"vira-select", Readonly<{
26
+ options: ReadonlyArray<Readonly<ViraSelectOption>>;
27
+ /** The currently selected option value. */
28
+ value: undefined | string;
29
+ } & PartialWithUndefined<{
30
+ icon: Readonly<ViraIconSvg>;
31
+ placeholder: string;
32
+ label: string;
33
+ disabled: boolean;
34
+ attributePassthrough: Readonly<PartialWithUndefined<{
35
+ label: AttributeValues;
36
+ select: AttributeValues;
37
+ option: AttributeValues;
38
+ }>>;
39
+ hasError: boolean;
40
+ }>>, {
41
+ /**
42
+ * Used to couple the label and select together. This is not applied if no label is
43
+ * provided.
44
+ */
45
+ randomId: string;
46
+ }, {
47
+ valueChange: import("element-vir").DefineEvent<string>;
48
+ }, "vira-select-disabled" | "vira-select-error", "vira-select-padding-horizontal" | "vira-select-padding-vertical" | "vira-select-icon-padding", readonly [], readonly []>;
@@ -0,0 +1,233 @@
1
+ import { randomString } from '@augment-vir/common';
2
+ import { extractEventTarget } from '@augment-vir/web';
3
+ import { attributes, classMap, css, defineElementEvent, html, ifDefined, listen, nothing, } from 'element-vir';
4
+ import { ChevronUp24Icon } from '../icons/index.js';
5
+ import { viraDisabledStyles } from '../styles/disabled.js';
6
+ import { createFocusStyles } from '../styles/focus.js';
7
+ import { viraFormCssVars } from '../styles/form-styles.js';
8
+ import { viraAnimationDurations, viraBorders } from '../styles/index.js';
9
+ import { noNativeFormStyles } from '../styles/native-styles.js';
10
+ import { defineViraElement } from './define-vira-element.js';
11
+ import { ViraIcon } from './vira-icon.element.js';
12
+ /**
13
+ * Similar to {@link ViraDropdown} but is, instead, simply a wrapper for `<select>` and nothing more.
14
+ *
15
+ * @category Dropdown
16
+ * @category Elements
17
+ * @see https://electrovir.github.io/vira/book/elements/vira-select
18
+ */
19
+ export const ViraSelect = defineViraElement()({
20
+ tagName: 'vira-select',
21
+ state() {
22
+ return {
23
+ /**
24
+ * Used to couple the label and select together. This is not applied if no label is
25
+ * provided.
26
+ */
27
+ randomId: randomString(32),
28
+ };
29
+ },
30
+ events: {
31
+ valueChange: defineElementEvent(),
32
+ },
33
+ cssVars: {
34
+ 'vira-select-padding-horizontal': '10px',
35
+ 'vira-select-padding-vertical': '6px',
36
+ 'vira-select-icon-padding': '44px',
37
+ },
38
+ hostClasses: {
39
+ 'vira-select-disabled': ({ inputs }) => !!inputs.disabled,
40
+ 'vira-select-error': ({ inputs }) => !!inputs.hasError,
41
+ },
42
+ styles: ({ hostClasses, cssVars }) => css `
43
+ :host {
44
+ position: relative;
45
+ display: inline-flex;
46
+ width: 223px;
47
+ box-sizing: border-box;
48
+ color: ${viraFormCssVars['vira-form-foreground-color'].value};
49
+ }
50
+
51
+ .select-wrapper {
52
+ ${noNativeFormStyles};
53
+ max-width: 100%;
54
+ flex-grow: 1;
55
+ display: inline-flex;
56
+ box-sizing: border-box;
57
+ align-items: center;
58
+ position: relative;
59
+ border-radius: ${viraBorders['vira-form-input-radius'].value};
60
+ background-color: ${viraFormCssVars['vira-form-background-color'].value};
61
+ /*
62
+ Border colors are actually applied via the .wrapper-border class. However, we must
63
+ apply a border here still so that it takes up space.
64
+ */
65
+ border: 1px solid transparent;
66
+ cursor: pointer;
67
+
68
+ & select {
69
+ appearance: none;
70
+ -webkit-appearance: none;
71
+ -moz-appearance: none;
72
+ font: inherit;
73
+ outline: none;
74
+ width: 100%;
75
+ border: none;
76
+ background: none;
77
+ border-radius: inherit;
78
+ padding: ${cssVars['vira-select-padding-vertical'].value} 31px
79
+ ${cssVars['vira-select-padding-vertical'].value}
80
+ ${cssVars['vira-select-padding-horizontal'].value};
81
+ cursor: pointer;
82
+ overflow: hidden;
83
+ text-overflow: ellipsis;
84
+
85
+ &:focus:focus-visible:not([aria-disabled='true']) ~ .focus-border {
86
+ ${createFocusStyles({
87
+ elementBorderSize: 0,
88
+ noNesting: true,
89
+ })}
90
+ }
91
+
92
+ &.placeholder {
93
+ color: ${viraFormCssVars['vira-form-placeholder-color'].value};
94
+ }
95
+
96
+ &.with-icon {
97
+ padding-left: ${cssVars['vira-select-icon-padding'].value};
98
+ }
99
+ }
100
+
101
+ & ${ViraIcon} {
102
+ position: absolute;
103
+ pointer-events: none;
104
+
105
+ &.trigger-icon {
106
+ transform: rotate(180deg);
107
+ right: 3px;
108
+ }
109
+
110
+ &.input-icon {
111
+ left: 10px;
112
+ }
113
+ }
114
+
115
+ & .border-style {
116
+ position: absolute;
117
+ top: 0;
118
+ left: 0;
119
+ width: 100%;
120
+ height: 100%;
121
+ border-radius: ${viraBorders['vira-form-input-radius'].value};
122
+ z-index: 0;
123
+ pointer-events: none;
124
+ }
125
+
126
+ & .wrapper-border {
127
+ top: -1px;
128
+ left: -1px;
129
+ border: 1px solid ${viraFormCssVars['vira-form-border-color'].value};
130
+ transition: border
131
+ ${viraAnimationDurations['vira-interaction-animation-duration'].value};
132
+ }
133
+ }
134
+
135
+ label {
136
+ display: flex;
137
+ flex-direction: column;
138
+ justify-content: flex-start;
139
+ gap: 2px;
140
+ width: 100%;
141
+ max-width: 100%;
142
+
143
+ & .select-label {
144
+ font-weight: ${viraFormCssVars['vira-form-label-font-weight'].value};
145
+ text-align: left;
146
+ flex-shrink: 0;
147
+ flex-wrap: wrap;
148
+ }
149
+ }
150
+
151
+ ${hostClasses['vira-select-disabled'].selector} {
152
+ cursor: not-allowed;
153
+
154
+ & label {
155
+ cursor: not-allowed;
156
+ }
157
+
158
+ & select,
159
+ & .wrapper-border {
160
+ ${viraDisabledStyles}
161
+ }
162
+ }
163
+
164
+ ${hostClasses['vira-select-error'].selector} {
165
+ & .wrapper-border {
166
+ border-color: ${viraFormCssVars['vira-form-error-foreground-color'].value};
167
+ }
168
+ }
169
+ `,
170
+ render({ inputs, state, dispatch, events }) {
171
+ const placeholderOptionTemplate = inputs.placeholder
172
+ ? html `
173
+ <option value="" disabled ?selected=${inputs.value == undefined}>
174
+ ${inputs.placeholder}
175
+ </option>
176
+ `
177
+ : nothing;
178
+ const selectTemplate = html `
179
+ <span class="select-wrapper">
180
+ <select
181
+ class=${classMap({
182
+ placeholder: !inputs.value && !!inputs.placeholder,
183
+ 'with-icon': !!inputs.icon,
184
+ })}
185
+ tabindex=${inputs.disabled ? -1 : 0}
186
+ id=${ifDefined(inputs.label ? state.randomId : undefined)}
187
+ aria-label=${ifDefined(inputs.label || undefined)}
188
+ aria-disabled=${ifDefined(inputs.disabled ? 'true' : undefined)}
189
+ ${listen('input', (event) => {
190
+ const element = extractEventTarget(event, HTMLSelectElement);
191
+ dispatch(new events.valueChange(element.value));
192
+ })}
193
+ ${attributes(inputs.attributePassthrough?.select)}
194
+ >
195
+ ${placeholderOptionTemplate}
196
+ ${inputs.options.map((option) => {
197
+ return html `
198
+ <option
199
+ ?selected=${option.value === inputs.value}
200
+ aria-label=${option.label}
201
+ ?disabled=${option.disabled}
202
+ >
203
+ ${option.label}
204
+ </option>
205
+ `;
206
+ })}
207
+ </select>
208
+ <!--
209
+ These separate style elements are necessary so that we can select them as
210
+ siblings of the focused <select> element.
211
+ -->
212
+
213
+ <div class="border-style focus-border"></div>
214
+
215
+ <div class="border-style wrapper-border"></div>
216
+
217
+ <${ViraIcon.assign({ icon: inputs.icon })} class="input-icon"></${ViraIcon}>
218
+ <${ViraIcon.assign({ icon: ChevronUp24Icon })} class="trigger-icon"></${ViraIcon}>
219
+ </span>
220
+ `;
221
+ if (inputs.label) {
222
+ return html `
223
+ <label for=${state.randomId} ${attributes(inputs.attributePassthrough?.label)}>
224
+ <span class="select-label">${inputs.label}</span>
225
+ ${selectTemplate}
226
+ </label>
227
+ `;
228
+ }
229
+ else {
230
+ return selectTemplate;
231
+ }
232
+ },
233
+ });
@@ -6,12 +6,15 @@
6
6
  */
7
7
  export declare const viraFormCssVars: import("lit-css-vars").CssVarDefinitions<{
8
8
  readonly 'vira-form-border-color': "#cccccc";
9
+ readonly 'vira-form-placeholder-color': "#cccccc";
9
10
  readonly 'vira-form-background-color': "white";
10
11
  readonly 'vira-form-foreground-color': "black";
12
+ readonly 'vira-form-text-selection-color': "#cfe9ff";
11
13
  readonly 'vira-form-selection-hover-background-color': "#d2eaff";
12
14
  readonly 'vira-form-selection-hover-foreground-color': "black";
13
15
  readonly 'vira-form-selection-active-background-color': "#d2eaff";
14
16
  readonly 'vira-form-selection-active-foreground-color': "black";
15
17
  readonly 'vira-form-error-foreground-color': "red";
16
18
  readonly 'vira-form-success-foreground-color': "green";
19
+ readonly 'vira-form-label-font-weight': "bold";
17
20
  }>;
@@ -7,12 +7,15 @@ import { defineCssVars } from 'lit-css-vars';
7
7
  */
8
8
  export const viraFormCssVars = defineCssVars({
9
9
  'vira-form-border-color': '#cccccc',
10
+ 'vira-form-placeholder-color': '#cccccc',
10
11
  'vira-form-background-color': 'white',
11
12
  'vira-form-foreground-color': 'black',
13
+ 'vira-form-text-selection-color': '#cfe9ff',
12
14
  'vira-form-selection-hover-background-color': '#d2eaff',
13
15
  'vira-form-selection-hover-foreground-color': 'black',
14
16
  'vira-form-selection-active-background-color': '#d2eaff',
15
17
  'vira-form-selection-active-foreground-color': 'black',
16
18
  'vira-form-error-foreground-color': 'red',
17
19
  'vira-form-success-foreground-color': 'green',
20
+ 'vira-form-label-font-weight': 'bold',
18
21
  });
@@ -20,6 +20,7 @@ export const noNativeFormStyles = css `
20
20
  background: none;
21
21
  border: none;
22
22
  font: inherit;
23
+ line-height: inherit;
23
24
  color: inherit;
24
25
  text-transform: inherit;
25
26
  text-decoration: inherit;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vira",
3
- "version": "28.5.1",
3
+ "version": "28.6.0",
4
4
  "description": "A simple and highly versatile design system using element-vir.",
5
5
  "keywords": [
6
6
  "design",