vira 31.25.1 → 31.27.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,6 +19,12 @@ export declare const ViraMenuItem: import("element-vir").DeclarativeElementDefin
19
19
  * _always_ be shown, even if `selected` is set to `false`.
20
20
  */
21
21
  iconOverride: ViraIconSvg;
22
+ /**
23
+ * When `true`, activating this item will _not_ close the containing pop-up.
24
+ *
25
+ * @default false
26
+ */
27
+ keepOpenAfterInteraction: boolean;
22
28
  }>, {
23
29
  /** Removes event listeners registered during init. */
24
30
  cleanupListeners: undefined | (() => void);
@@ -29,4 +35,4 @@ export declare const ViraMenuItem: import("element-vir").DeclarativeElementDefin
29
35
  * gated by `keepOpenAfterInteraction`.
30
36
  */
31
37
  activate: import("element-vir").DefineEvent<undefined>;
32
- }, "vira-menu-item-selected" | "vira-menu-item-disabled" | "vira-menu-item-enabled" | "vira-menu-item-default-icon" | "vira-menu-item-default-styles", "vira-menu-item-", readonly [], readonly []>;
38
+ }, "vira-menu-item-selected" | "vira-menu-item-disabled" | "vira-menu-item-enabled" | "vira-menu-item-default-icon" | "vira-menu-item-default-styles", "vira-menu-item-icon-gap", readonly [], readonly []>;
@@ -35,14 +35,18 @@ export const ViraMenuItem = defineViraElement()({
35
35
  'vira-menu-item-default-icon': ({ inputs }) => !inputs.iconOverride,
36
36
  'vira-menu-item-default-styles': ({ inputs }) => !inputs.disablePointerStyles,
37
37
  },
38
- styles: ({ hostClasses }) => css `
38
+ cssVars: {
39
+ /** Horizontal gap between a menu item's icon and its label. */
40
+ 'vira-menu-item-icon-gap': '3px',
41
+ },
42
+ styles: ({ hostClasses, cssVars }) => css `
39
43
  :host {
40
44
  display: flex;
41
45
  flex-shrink: 0;
42
46
  ${noUserSelect};
43
47
  box-sizing: border-box;
44
48
  max-width: 100%;
45
- gap: 1px;
49
+ gap: ${cssVars['vira-menu-item-icon-gap'].value};
46
50
  overflow: hidden;
47
51
  padding: 8px 3px;
48
52
  padding-right: 16px;
@@ -119,6 +123,20 @@ export const ViraMenuItem = defineViraElement()({
119
123
  event.stopPropagation();
120
124
  return;
121
125
  }
126
+ /**
127
+ * Only forward `click`. Slotted content is activated by a single forwarded click, so
128
+ * forwarding `mousedown` as well would double-trigger interactions: a `<select>`, for
129
+ * example, opens its picker via `showPicker()` on both `mousedown` and `click`, and the
130
+ * first call consumes the transient user activation so the second throws
131
+ * `NotAllowedError`. `mousedown` still reaches this handler so disabled items can block
132
+ * it above.
133
+ */
134
+ if (event.type !== 'click') {
135
+ return;
136
+ }
137
+ if (inputs.keepOpenAfterInteraction) {
138
+ event.stopPropagation();
139
+ }
122
140
  const slotElement = assertWrap.instanceOf(host.shadowRoot.querySelector('slot'), HTMLSlotElement);
123
141
  slotElement
124
142
  .assignedElements({
@@ -129,29 +147,23 @@ export const ViraMenuItem = defineViraElement()({
129
147
  event.preventDefault();
130
148
  event.stopPropagation();
131
149
  propagating[event.type] = true;
132
- if (event.type === 'click') {
133
- const hasModifiers = event instanceof MouseEvent &&
134
- (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey);
135
- if (hasModifiers) {
136
- /**
137
- * If modifier keys are present, dispatch a synthetic MouseEvent so
138
- * that the modifier keys are preserved. This is needed so that
139
- * cmd+click opens links in a new tab.
140
- */
141
- element.dispatchEvent(new MouseEvent('click', event));
142
- }
143
- else {
144
- /**
145
- * Use `.click()` instead of dispatching a synthetic MouseEvent so
146
- * that the resulting event is trusted and carries user activation.
147
- * This is required for APIs like `showPicker()` on `<select>`
148
- * elements.
149
- */
150
- element.click();
151
- }
150
+ const hasModifiers = event instanceof MouseEvent &&
151
+ (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey);
152
+ if (hasModifiers) {
153
+ /**
154
+ * If modifier keys are present, dispatch a synthetic MouseEvent so that
155
+ * the modifier keys are preserved. This is needed so that cmd+click
156
+ * opens links in a new tab.
157
+ */
158
+ element.dispatchEvent(new MouseEvent('click', event));
152
159
  }
153
160
  else {
154
- element.dispatchEvent(new MouseEvent(event.type, event));
161
+ /**
162
+ * Use `.click()` instead of dispatching a synthetic MouseEvent so that
163
+ * the resulting event carries user activation. This is required for
164
+ * APIs like `showPicker()` on `<select>` elements.
165
+ */
166
+ element.click();
155
167
  }
156
168
  delete propagating[event.type];
157
169
  }
@@ -160,16 +172,10 @@ export const ViraMenuItem = defineViraElement()({
160
172
  const listenerRemovers = [
161
173
  listenTo(host, 'click', propagateMouseEvent),
162
174
  listenTo(host, 'mousedown', propagateMouseEvent),
163
- /**
164
- * Emit `select` on a non-disabled activation so the containing pop-up can close. This
165
- * uses the _capture_ phase because interactive slotted content can stop the click from
166
- * bubbling back up to this host (which would prevent a bubble-phase listener from ever
167
- * running). The `propagating` guard skips the synthetic click that
168
- * `propagateMouseEvent` re-dispatches onto slotted content, so `select` fires exactly
169
- * once per activation.
170
- */
171
175
  listenTo(host, 'click', (event) => {
172
- if (propagating[event.type] || inputs.disabled) {
176
+ if (propagating[event.type] ||
177
+ inputs.disabled ||
178
+ inputs.keepOpenAfterInteraction) {
173
179
  return;
174
180
  }
175
181
  dispatch(new events.activate(undefined));
@@ -1,4 +1,5 @@
1
1
  import { css, html } from 'element-vir';
2
+ import { viraFontCssVars } from '../styles/font.js';
2
3
  import { defineViraElement } from '../util/define-vira-element.js';
3
4
  /**
4
5
  * Use this element to reserve space for bolded text, even if it isn't bold yet.
@@ -8,7 +9,7 @@ import { defineViraElement } from '../util/define-vira-element.js';
8
9
  export const ViraBoldText = defineViraElement()({
9
10
  tagName: 'vira-bold',
10
11
  cssVars: {
11
- 'vira-bold-bold-weight': 'bold',
12
+ 'vira-bold-bold-weight': viraFontCssVars['vira-font-weight-bold'].value,
12
13
  },
13
14
  hostClasses: {
14
15
  'vira-bold-bold': ({ inputs }) => inputs.bold,
@@ -1,5 +1,6 @@
1
1
  import { css, defineElementEvent, html, listen, nothing, testId } from 'element-vir';
2
2
  import { ChevronUp16Icon } from '../icons/index.js';
3
+ import { viraFontCssVars } from '../styles/font.js';
3
4
  import { viraFormCssVars } from '../styles/form-styles.js';
4
5
  import { defineViraElement } from '../util/define-vira-element.js';
5
6
  import { ViraCollapsibleWrapper } from './vira-collapsible-wrapper.element.js';
@@ -70,7 +71,7 @@ export const ViraCollapsibleCard = defineViraElement()({
70
71
  }
71
72
 
72
73
  .card-header {
73
- font-weight: bold;
74
+ font-weight: ${viraFontCssVars['vira-font-weight-bold'].value};
74
75
  display: flex;
75
76
  align-items: center;
76
77
  justify-content: space-between;
@@ -1,4 +1,5 @@
1
1
  import { css, html } from 'element-vir';
2
+ import { viraFontCssVars } from '../styles/font.js';
2
3
  import { viraFormCssVars } from '../styles/form-styles.js';
3
4
  import { defineViraElement } from '../util/define-vira-element.js';
4
5
  /**
@@ -10,7 +11,7 @@ import { defineViraElement } from '../util/define-vira-element.js';
10
11
  export const ViraError = defineViraElement()({
11
12
  tagName: 'vira-error',
12
13
  cssVars: {
13
- 'vira-error-font-weight': 'bold',
14
+ 'vira-error-font-weight': viraFontCssVars['vira-font-weight-bold'].value,
14
15
  },
15
16
  styles: ({ cssVars }) => css `
16
17
  :host {
@@ -5,6 +5,7 @@ import { attributes, css, defineElementEvent, html, ifDefined, listen, nothing,
5
5
  import { CloseX24Icon } from '../icons/icon-svgs/24/close-x-24.icon.js';
6
6
  import { EyeClosed24Icon, EyeOpen24Icon } from '../icons/index.js';
7
7
  import { createFocusStyles } from '../styles/focus.js';
8
+ import { viraFontCssVars } from '../styles/font.js';
8
9
  import { viraFormCssVars } from '../styles/form-styles.js';
9
10
  import { ViraSize, viraSizeHeights } from '../styles/form-variants.js';
10
11
  import { noUserSelect, viraAnimationDurations, viraDisabledStyles } from '../styles/index.js';
@@ -203,7 +204,7 @@ export const ViraInput = defineViraElement()({
203
204
  }
204
205
 
205
206
  .suffix {
206
- font-weight: bold;
207
+ font-weight: ${viraFontCssVars['vira-font-weight-bold'].value};
207
208
  ${noUserSelect};
208
209
  }
209
210
 
@@ -1,6 +1,17 @@
1
1
  import { type PartialWithUndefined } from '@augment-vir/common';
2
2
  import { type JsonValue } from 'type-fest';
3
3
  import { ViraJsonType, type ViraJsonSchema } from '../util/vira-json-schema.js';
4
+ /**
5
+ * Editing mode for a string field that offers both a fixed set of enum options and free-form text.
6
+ *
7
+ * @category Internal
8
+ */
9
+ export declare enum ViraJsonStringMode {
10
+ /** Pick from the schema's enum options via a dropdown. */
11
+ Options = "options",
12
+ /** Enter an arbitrary string via a text input. */
13
+ Custom = "custom"
14
+ }
4
15
  /**
5
16
  * An editor for arbitrary JSON values, optionally constrained by a standard JSON Schema
6
17
  * ({@link ViraJsonSchema}).
@@ -16,6 +27,7 @@ export declare const ViraJsonForm: import("element-vir").DeclarativeElementDefin
16
27
  pendingKeys: Readonly<Record<string, string>>;
17
28
  pendingTypes: Readonly<Record<string, ViraJsonType>>;
18
29
  pendingArrayValues: Readonly<Record<string, JsonValue>>;
30
+ stringModes: Readonly<Record<string, ViraJsonStringMode>>;
19
31
  showRaw: boolean;
20
32
  rawDraft: string | undefined;
21
33
  rawError: string | undefined;
@@ -6,13 +6,25 @@ import { viraFontCssVars } from '../styles/font.js';
6
6
  import { viraFormCssVars } from '../styles/form-styles.js';
7
7
  import { ViraColorVariant, ViraEmphasis, ViraSize } from '../styles/form-variants.js';
8
8
  import { defineViraElement } from '../util/define-vira-element.js';
9
- import { createDefaultForJsonType, createResolveContext, deleteValueAtPath, getAdditionalPropertiesSchema, getAllowedJsonTypes, getDefinedProperties, getEnumValues, getItemSchema, getJsonType, getNewItemSchema, getPropertySchema, getRequiredProperties, getSchemaTitle, pathToKey, pickBranchForType, setValueAtPath, validateAgainstSchema, ViraJsonType, viraJsonTypeLabels, } from '../util/vira-json-schema.js';
9
+ import { allowsFreeformString, createDefaultForJsonType, createResolveContext, deleteValueAtPath, getAdditionalPropertiesSchema, getAllowedJsonTypes, getDefinedProperties, getItemSchema, getJsonType, getNewItemSchema, getPropertySchema, getRequiredProperties, getSchemaEnumValues, getSchemaTitle, getStringEnumValues, pathToKey, pickBranchForType, setValueAtPath, validateAgainstSchema, ViraJsonType, viraJsonTypeLabels, } from '../util/vira-json-schema.js';
10
10
  import { ViraButton } from './vira-button.element.js';
11
11
  import { ViraCheckbox } from './vira-checkbox.element.js';
12
12
  import { ViraError } from './vira-error.element.js';
13
13
  import { ViraInput, ViraInputType } from './vira-input.element.js';
14
14
  import { ViraSelect } from './vira-select.element.js';
15
15
  import { ViraTextArea } from './vira-text-area.element.js';
16
+ /**
17
+ * Editing mode for a string field that offers both a fixed set of enum options and free-form text.
18
+ *
19
+ * @category Internal
20
+ */
21
+ export var ViraJsonStringMode;
22
+ (function (ViraJsonStringMode) {
23
+ /** Pick from the schema's enum options via a dropdown. */
24
+ ViraJsonStringMode["Options"] = "options";
25
+ /** Enter an arbitrary string via a text input. */
26
+ ViraJsonStringMode["Custom"] = "custom";
27
+ })(ViraJsonStringMode || (ViraJsonStringMode = {}));
16
28
  /**
17
29
  * An editor for arbitrary JSON values, optionally constrained by a standard JSON Schema
18
30
  * ({@link ViraJsonSchema}).
@@ -29,6 +41,7 @@ export const ViraJsonForm = defineViraElement()({
29
41
  pendingKeys: {},
30
42
  pendingTypes: {},
31
43
  pendingArrayValues: {},
44
+ stringModes: {},
32
45
  showRaw: false,
33
46
  rawDraft: undefined,
34
47
  rawError: undefined,
@@ -129,7 +142,7 @@ export const ViraJsonForm = defineViraElement()({
129
142
  }
130
143
 
131
144
  .json-type-tag {
132
- font-weight: normal;
145
+ font-weight: ${viraFontCssVars['vira-font-weight-normal'].value};
133
146
  color: ${viraFormCssVars['vira-form-secondary-body-foreground'].value};
134
147
  }
135
148
 
@@ -238,6 +251,23 @@ export const ViraJsonForm = defineViraElement()({
238
251
  },
239
252
  });
240
253
  }
254
+ function getStringMode(pathKey, value, enumValues) {
255
+ const stored = state.stringModes[pathKey];
256
+ if (stored) {
257
+ return stored;
258
+ }
259
+ return enumValues.includes(value)
260
+ ? ViraJsonStringMode.Options
261
+ : ViraJsonStringMode.Custom;
262
+ }
263
+ function setStringMode(pathKey, mode) {
264
+ updateState({
265
+ stringModes: {
266
+ ...state.stringModes,
267
+ [pathKey]: mode,
268
+ },
269
+ });
270
+ }
241
271
  function clearPending(pathKey) {
242
272
  updateState({
243
273
  pendingKeys: omitObjectKeys(state.pendingKeys, [pathKey]),
@@ -260,7 +290,7 @@ export const ViraJsonForm = defineViraElement()({
260
290
  }
261
291
  function renderPrimitive(path, value, schema) {
262
292
  const type = getJsonType(value);
263
- const enumValues = getEnumValues(schema, resolveContext);
293
+ const enumValues = getSchemaEnumValues(schema, resolveContext);
264
294
  if (enumValues && enumValues.length > 0) {
265
295
  const options = enumValues.map((entry) => {
266
296
  const asString = jsonPrimitiveToString(entry);
@@ -734,6 +764,64 @@ export const ViraJsonForm = defineViraElement()({
734
764
  </table>
735
765
  `;
736
766
  }
767
+ function renderStringEnumOrRaw(path, value, enumValues) {
768
+ const pathKey = pathToKey(path);
769
+ const mode = getStringMode(pathKey, value, enumValues);
770
+ const editor = mode === ViraJsonStringMode.Options
771
+ ? html `
772
+ <${ViraSelect.assign({
773
+ options: enumValues.map((entry) => {
774
+ return {
775
+ value: entry,
776
+ label: entry,
777
+ };
778
+ }),
779
+ value: enumValues.includes(value) ? value : undefined,
780
+ disabled: isDisabled,
781
+ })}
782
+ ${listen(ViraSelect.events.valueChange, (event) => {
783
+ emitReplaceAt(path, event.detail);
784
+ })}
785
+ ></${ViraSelect}>
786
+ `
787
+ : html `
788
+ <${ViraInput.assign({
789
+ value,
790
+ disabled: isDisabled,
791
+ })}
792
+ ${listen(ViraInput.events.valueChange, (event) => {
793
+ emitReplaceAt(path, event.detail);
794
+ })}
795
+ ></${ViraInput}>
796
+ `;
797
+ if (isDisabled) {
798
+ return editor;
799
+ }
800
+ const modeOptions = [
801
+ {
802
+ value: ViraJsonStringMode.Options,
803
+ label: 'Options',
804
+ },
805
+ {
806
+ value: ViraJsonStringMode.Custom,
807
+ label: 'Custom',
808
+ },
809
+ ];
810
+ return html `
811
+ <div class="json-value-with-switcher">
812
+ <span class="json-value-editor-slot">${editor}</span>
813
+ <${ViraSelect.assign({
814
+ options: modeOptions,
815
+ value: mode,
816
+ })}
817
+ title="Choose from options or enter a custom value"
818
+ ${listen(ViraSelect.events.valueChange, (event) => {
819
+ setStringMode(pathKey, event.detail);
820
+ })}
821
+ ></${ViraSelect}>
822
+ </div>
823
+ `;
824
+ }
737
825
  function renderValue(path, value, schema) {
738
826
  const concreteType = getJsonType(value);
739
827
  const allowedTypes = getAllowedJsonTypes(schema, resolveContext);
@@ -744,6 +832,19 @@ export const ViraJsonForm = defineViraElement()({
744
832
  else if (check.isObject(value)) {
745
833
  return renderObjectGroup(path, value, narrowedSchema);
746
834
  }
835
+ /**
836
+ * When a string field constrains values to an enum but also permits free-form strings,
837
+ * offer both: an options dropdown plus a switcher to toggle to raw text entry.
838
+ */
839
+ const isStringOnlyField = allowedTypes.length === 1 && allowedTypes[0] === ViraJsonType.String;
840
+ const stringEnumValues = isStringOnlyField
841
+ ? getStringEnumValues(schema, resolveContext)
842
+ : [];
843
+ if (check.isString(value) &&
844
+ stringEnumValues.length > 0 &&
845
+ allowsFreeformString(schema, resolveContext)) {
846
+ return renderStringEnumOrRaw(path, value, stringEnumValues);
847
+ }
747
848
  const editor = renderPrimitive(path, value, narrowedSchema);
748
849
  const showSwitcher = !isDisabled &&
749
850
  allowedTypes.length > 1 &&
@@ -1,7 +1,7 @@
1
1
  import { assertWrap } from '@augment-vir/assert';
2
2
  import { attributes, css, html, ifDefined, listen, } from 'element-vir';
3
3
  import { listenTo } from 'typed-event-target';
4
- import { viraFormCssVars } from '../styles/form-styles.js';
4
+ import { viraTheme } from '../styles/vira-color-theme.js';
5
5
  import { defineViraElement } from '../util/define-vira-element.js';
6
6
  /**
7
7
  * A hyperlink wrapper element that can be configured to emit route change events rather than just
@@ -41,12 +41,12 @@ export const ViraLink = defineViraElement()({
41
41
  ${hostClasses['vira-link-link-styles'].selector} {
42
42
  &:hover a,
43
43
  & a:hover {
44
- color: ${viraFormCssVars['vira-form-accent-primary-color'].value};
44
+ color: ${viraTheme.colors['vira-blue-foreground-non-body'].foreground.value};
45
45
  }
46
46
 
47
47
  &:active a,
48
48
  & a:active {
49
- color: ${viraFormCssVars['vira-form-accent-primary-active-color'].value};
49
+ color: ${viraTheme.colors['vira-blue-foreground-body'].foreground.value};
50
50
  }
51
51
  }
52
52
  `,
@@ -20,6 +20,13 @@ export declare const ViraRelativeTime: import("element-vir").DeclarativeElementD
20
20
  * @default {seconds: 5}
21
21
  */
22
22
  updateInterval: Readonly<AtLeastOneDuration>;
23
+ /**
24
+ * Timezone the absolute time is displayed in. Defaults to the user's timezone. Set this for
25
+ * values that are conceptually anchored to a specific timezone (e.g. a date-only value
26
+ * stored at midnight UTC), where converting to the user's timezone would shift the
27
+ * displayed date/time.
28
+ */
29
+ timezone: string;
23
30
  }>, {
24
31
  now: {
25
32
  hour: import("date-vir").Hour;
@@ -76,11 +76,18 @@ export const ViraRelativeTime = defineViraElement()({
76
76
  decimalCount: 0,
77
77
  });
78
78
  return html `
79
- <span title=${formatAbsoluteTime(inputs.time)}>${relativeTime}</span>
79
+ <span
80
+ title=${formatAbsoluteTime(inputs.time, {
81
+ timezone: inputs.timezone,
82
+ })}
83
+ >
84
+ ${relativeTime}
85
+ </span>
80
86
  ${inputs.showAbsoluteTime
81
87
  ? html `
82
88
  <${ViraAbsoluteTime.assign({
83
89
  time: inputs.time,
90
+ timezone: inputs.timezone,
84
91
  })}></${ViraAbsoluteTime}>
85
92
  `
86
93
  : nothing}
@@ -44,7 +44,25 @@ export type ViraTab = {
44
44
  * current route.
45
45
  */
46
46
  exactMatch: boolean;
47
+ /**
48
+ * Optional cluster label. Consecutive tabs sharing the same `group` string render together
49
+ * under that label, separated from other clusters by an inset vertical divider. Tabs with no
50
+ * `group` render standalone (no label, no divider). Grouping only affects rendering when at
51
+ * least one tab has a `group`.
52
+ */
53
+ group: string;
47
54
  }>;
55
+ /**
56
+ * Groups a flat list of tabs into clusters. Consecutive tabs sharing the same `group` string are
57
+ * merged into a single cluster; ungrouped tabs (and tabs whose `group` differs from their
58
+ * predecessor) each start a new cluster.
59
+ *
60
+ * @category Internal
61
+ */
62
+ export declare function buildClusters(tabList: ReadonlyArray<Readonly<ViraTab>>): {
63
+ group: string | undefined;
64
+ tabs: ReadonlyArray<Readonly<ViraTab>>;
65
+ }[];
48
66
  /**
49
67
  * A tab bar element that renders an array of tabs with an animated selection indicator.
50
68
  *
@@ -85,13 +103,22 @@ export declare const ViraTabs: import("element-vir").DeclarativeElementDefinitio
85
103
  menuIsDisabled: boolean;
86
104
  /** Offset for the dropdown pop-up. Only used when tabs overflow into a dropdown. */
87
105
  menuPopUpOffset: Readonly<PopUpOffset>;
106
+ /**
107
+ * Text shown on the overflow "more" trigger when the selected tab is _not_ collapsed into
108
+ * the menu. When the selected tab _is_ collapsed, the trigger shows that tab's label (with
109
+ * a checkmark) instead. Set this to a localized string; it defaults to `'More'`.
110
+ *
111
+ * @default 'More'
112
+ */
113
+ overflowLabel: string;
88
114
  /** When true, tabs and their container expand to fill all available horizontal space. */
89
115
  shouldFillWidth: boolean;
90
116
  }>, {
91
- isOverflowing: boolean;
117
+ /** How many of the visible tabs are collapsed into the overflow "more" menu. */
118
+ overflowCount: number;
92
119
  /** A callback to remove all internal observers. */
93
120
  cleanupObserver: undefined | (() => void);
94
121
  }, {
95
122
  /** Fires when a tab is clicked with the corresponding tab entry. */
96
123
  tabSelect: import("element-vir").DefineEvent<Readonly<ViraTab>>;
97
- }, "vira-tabs-bar-top" | "vira-tabs-bar-bottom" | "vira-tabs-bar-left" | "vira-tabs-bar-right" | "vira-tabs-color-red" | "vira-tabs-color-yellow" | "vira-tabs-color-green" | "vira-tabs-color-blue" | "vira-tabs-color-brand" | "vira-tabs-color-purple" | "vira-tabs-color-plain" | "vira-tabs-color-neutral" | "vira-tabs-color-teal" | "vira-tabs-color-pink" | "vira-tabs-color-grey" | "vira-tabs-icon-layout-vertical" | "vira-tabs-icon-layout-horizontal" | "vira-tabs-overflowing" | "vira-tabs-fill-width", "vira-tabs-active-color" | "vira-tabs-active-hover-color" | "vira-tabs-inactive-color" | "vira-tabs-inactive-hover-color" | "vira-tabs-bar-thickness", readonly [], readonly []>;
124
+ }, "vira-tabs-bar-top" | "vira-tabs-bar-bottom" | "vira-tabs-bar-left" | "vira-tabs-bar-right" | "vira-tabs-color-red" | "vira-tabs-color-yellow" | "vira-tabs-color-green" | "vira-tabs-color-blue" | "vira-tabs-color-brand" | "vira-tabs-color-purple" | "vira-tabs-color-plain" | "vira-tabs-color-neutral" | "vira-tabs-color-teal" | "vira-tabs-color-pink" | "vira-tabs-color-grey" | "vira-tabs-icon-layout-vertical" | "vira-tabs-icon-layout-horizontal" | "vira-tabs-fill-width", "vira-tabs-active-color" | "vira-tabs-active-hover-color" | "vira-tabs-inactive-color" | "vira-tabs-inactive-hover-color" | "vira-tabs-bar-thickness", readonly [], readonly []>;