vira 31.25.0 → 31.26.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.
- package/dist/elements/pop-up/vira-menu-item.element.d.ts +6 -0
- package/dist/elements/pop-up/vira-menu-item.element.js +32 -30
- package/dist/elements/vira-absolute-time.element.d.ts +8 -0
- package/dist/elements/vira-absolute-time.element.js +5 -2
- package/dist/elements/vira-bold-text.element.js +2 -1
- package/dist/elements/vira-collapsible-card.element.js +2 -1
- package/dist/elements/vira-date-input.element.js +1 -0
- package/dist/elements/vira-error.element.js +2 -1
- package/dist/elements/vira-input.element.js +2 -1
- package/dist/elements/vira-json-form.element.d.ts +12 -0
- package/dist/elements/vira-json-form.element.js +104 -3
- package/dist/elements/vira-link.element.js +3 -3
- package/dist/elements/vira-relative-time.element.d.ts +7 -0
- package/dist/elements/vira-relative-time.element.js +8 -1
- package/dist/elements/vira-tabs.element.d.ts +29 -2
- package/dist/elements/vira-tabs.element.js +463 -162
- package/dist/elements/vira-tag.element.js +1 -1
- package/dist/styles/font.d.ts +3 -0
- package/dist/styles/font.js +3 -0
- package/dist/styles/form-styles.d.ts +1 -1
- package/dist/styles/form-styles.js +2 -1
- package/dist/util/vira-json-schema.d.ts +18 -1
- package/dist/util/vira-json-schema.js +37 -1
- package/package.json +1 -1
|
@@ -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);
|
|
@@ -119,6 +119,20 @@ export const ViraMenuItem = defineViraElement()({
|
|
|
119
119
|
event.stopPropagation();
|
|
120
120
|
return;
|
|
121
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Only forward `click`. Slotted content is activated by a single forwarded click, so
|
|
124
|
+
* forwarding `mousedown` as well would double-trigger interactions: a `<select>`, for
|
|
125
|
+
* example, opens its picker via `showPicker()` on both `mousedown` and `click`, and the
|
|
126
|
+
* first call consumes the transient user activation so the second throws
|
|
127
|
+
* `NotAllowedError`. `mousedown` still reaches this handler so disabled items can block
|
|
128
|
+
* it above.
|
|
129
|
+
*/
|
|
130
|
+
if (event.type !== 'click') {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (inputs.keepOpenAfterInteraction) {
|
|
134
|
+
event.stopPropagation();
|
|
135
|
+
}
|
|
122
136
|
const slotElement = assertWrap.instanceOf(host.shadowRoot.querySelector('slot'), HTMLSlotElement);
|
|
123
137
|
slotElement
|
|
124
138
|
.assignedElements({
|
|
@@ -129,29 +143,23 @@ export const ViraMenuItem = defineViraElement()({
|
|
|
129
143
|
event.preventDefault();
|
|
130
144
|
event.stopPropagation();
|
|
131
145
|
propagating[event.type] = true;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
}
|
|
146
|
+
const hasModifiers = event instanceof MouseEvent &&
|
|
147
|
+
(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey);
|
|
148
|
+
if (hasModifiers) {
|
|
149
|
+
/**
|
|
150
|
+
* If modifier keys are present, dispatch a synthetic MouseEvent so that
|
|
151
|
+
* the modifier keys are preserved. This is needed so that cmd+click
|
|
152
|
+
* opens links in a new tab.
|
|
153
|
+
*/
|
|
154
|
+
element.dispatchEvent(new MouseEvent('click', event));
|
|
152
155
|
}
|
|
153
156
|
else {
|
|
154
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Use `.click()` instead of dispatching a synthetic MouseEvent so that
|
|
159
|
+
* the resulting event carries user activation. This is required for
|
|
160
|
+
* APIs like `showPicker()` on `<select>` elements.
|
|
161
|
+
*/
|
|
162
|
+
element.click();
|
|
155
163
|
}
|
|
156
164
|
delete propagating[event.type];
|
|
157
165
|
}
|
|
@@ -160,16 +168,10 @@ export const ViraMenuItem = defineViraElement()({
|
|
|
160
168
|
const listenerRemovers = [
|
|
161
169
|
listenTo(host, 'click', propagateMouseEvent),
|
|
162
170
|
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
171
|
listenTo(host, 'click', (event) => {
|
|
172
|
-
if (propagating[event.type] ||
|
|
172
|
+
if (propagating[event.type] ||
|
|
173
|
+
inputs.disabled ||
|
|
174
|
+
inputs.keepOpenAfterInteraction) {
|
|
173
175
|
return;
|
|
174
176
|
}
|
|
175
177
|
dispatch(new events.activate(undefined));
|
|
@@ -17,6 +17,13 @@ export declare const ViraAbsoluteTime: import("element-vir").DeclarativeElementD
|
|
|
17
17
|
* time of day would be meaningless noise.
|
|
18
18
|
*/
|
|
19
19
|
dateOnly: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Timezone the value is displayed in. Defaults to the user's timezone. Set this for values
|
|
22
|
+
* that are conceptually anchored to a specific timezone (e.g. a date-only value stored at
|
|
23
|
+
* midnight UTC), where converting to the user's timezone would shift the displayed
|
|
24
|
+
* date/time.
|
|
25
|
+
*/
|
|
26
|
+
timezone: string;
|
|
20
27
|
}>, {}, {}, "vira-absolute-time-", "vira-absolute-time-", readonly [], readonly []>;
|
|
21
28
|
/**
|
|
22
29
|
* Formats a `FullDate` into the same absolute string rendered by {@link ViraAbsoluteTime}.
|
|
@@ -25,4 +32,5 @@ export declare const ViraAbsoluteTime: import("element-vir").DeclarativeElementD
|
|
|
25
32
|
*/
|
|
26
33
|
export declare function formatAbsoluteTime(time: Readonly<FullDate>, options?: Readonly<PartialWithUndefined<{
|
|
27
34
|
dateOnly: boolean;
|
|
35
|
+
timezone: string;
|
|
28
36
|
}>>): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createFullDateInUserTimezone, toFormattedString } from 'date-vir';
|
|
1
|
+
import { createFullDate, createFullDateInUserTimezone, toFormattedString, } from 'date-vir';
|
|
2
2
|
import { css } from 'element-vir';
|
|
3
3
|
import { defineViraElement } from '../util/define-vira-element.js';
|
|
4
4
|
/**
|
|
@@ -19,6 +19,7 @@ export const ViraAbsoluteTime = defineViraElement()({
|
|
|
19
19
|
render({ inputs }) {
|
|
20
20
|
return formatAbsoluteTime(inputs.time, {
|
|
21
21
|
dateOnly: inputs.dateOnly,
|
|
22
|
+
timezone: inputs.timezone,
|
|
22
23
|
});
|
|
23
24
|
},
|
|
24
25
|
});
|
|
@@ -28,5 +29,7 @@ export const ViraAbsoluteTime = defineViraElement()({
|
|
|
28
29
|
* @category Time
|
|
29
30
|
*/
|
|
30
31
|
export function formatAbsoluteTime(time, options) {
|
|
31
|
-
return toFormattedString(
|
|
32
|
+
return toFormattedString(options?.timezone
|
|
33
|
+
? createFullDate(time, options.timezone)
|
|
34
|
+
: createFullDateInUserTimezone(time), options?.dateOnly ? 'MMM d, yyyy' : 'MMM d, yyyy HH:mm ZZZZ');
|
|
32
35
|
}
|
|
@@ -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,
|
|
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 =
|
|
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 {
|
|
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: ${
|
|
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: ${
|
|
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
|
|
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
|
-
|
|
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-
|
|
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 []>;
|