vira 31.26.0 → 31.28.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 +1 -1
- package/dist/elements/pop-up/vira-menu-item.element.js +6 -2
- package/dist/elements/vira-absolute-time.element.d.ts +6 -7
- package/dist/elements/vira-absolute-time.element.js +10 -2
- package/dist/elements/vira-button.element.js +21 -5
- package/dist/elements/vira-date-input.element.d.ts +4 -0
- package/dist/elements/vira-date-input.element.js +2 -1
- package/dist/elements/vira-json-form.element.js +16 -5
- package/dist/elements/vira-tag.element.js +21 -5
- package/dist/icons/lucide-icons.js +6 -2
- package/dist/util/define-table.d.ts +6 -1
- package/dist/util/define-table.js +1 -1
- package/dist/util/pop-up-manager.d.ts +10 -5
- package/dist/util/pop-up-manager.js +5 -0
- package/dist/util/vira-json-schema.d.ts +5 -1
- package/dist/util/vira-json-schema.js +74 -16
- package/package.json +18 -18
|
@@ -35,4 +35,4 @@ export declare const ViraMenuItem: import("element-vir").DeclarativeElementDefin
|
|
|
35
35
|
* gated by `keepOpenAfterInteraction`.
|
|
36
36
|
*/
|
|
37
37
|
activate: import("element-vir").DefineEvent<undefined>;
|
|
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-", 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
|
-
|
|
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:
|
|
49
|
+
gap: ${cssVars['vira-menu-item-icon-gap'].value};
|
|
46
50
|
overflow: hidden;
|
|
47
51
|
padding: 8px 3px;
|
|
48
52
|
padding-right: 16px;
|
|
@@ -11,12 +11,10 @@ import { type FullDate } from 'date-vir';
|
|
|
11
11
|
export declare const ViraAbsoluteTime: import("element-vir").DeclarativeElementDefinition<"vira-absolute-time", {
|
|
12
12
|
time: Readonly<FullDate>;
|
|
13
13
|
} & PartialWithUndefined<{
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*/
|
|
19
|
-
dateOnly: boolean;
|
|
14
|
+
/** Show only the date part (`Jun 3, 2026`), omitting the time of day and timezone. */
|
|
15
|
+
showDateOnly: boolean;
|
|
16
|
+
/** Show only the time part (`14:30 PDT`), omitting the date. */
|
|
17
|
+
showTimeOnly: boolean;
|
|
20
18
|
/**
|
|
21
19
|
* Timezone the value is displayed in. Defaults to the user's timezone. Set this for values
|
|
22
20
|
* that are conceptually anchored to a specific timezone (e.g. a date-only value stored at
|
|
@@ -31,6 +29,7 @@ export declare const ViraAbsoluteTime: import("element-vir").DeclarativeElementD
|
|
|
31
29
|
* @category Time
|
|
32
30
|
*/
|
|
33
31
|
export declare function formatAbsoluteTime(time: Readonly<FullDate>, options?: Readonly<PartialWithUndefined<{
|
|
34
|
-
|
|
32
|
+
showDateOnly: boolean;
|
|
33
|
+
showTimeOnly: boolean;
|
|
35
34
|
timezone: string;
|
|
36
35
|
}>>): string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { check } from '@augment-vir/assert';
|
|
1
2
|
import { createFullDate, createFullDateInUserTimezone, toFormattedString, } from 'date-vir';
|
|
2
3
|
import { css } from 'element-vir';
|
|
3
4
|
import { defineViraElement } from '../util/define-vira-element.js';
|
|
@@ -18,7 +19,8 @@ export const ViraAbsoluteTime = defineViraElement()({
|
|
|
18
19
|
`,
|
|
19
20
|
render({ inputs }) {
|
|
20
21
|
return formatAbsoluteTime(inputs.time, {
|
|
21
|
-
|
|
22
|
+
showDateOnly: inputs.showDateOnly,
|
|
23
|
+
showTimeOnly: inputs.showTimeOnly,
|
|
22
24
|
timezone: inputs.timezone,
|
|
23
25
|
});
|
|
24
26
|
},
|
|
@@ -29,7 +31,13 @@ export const ViraAbsoluteTime = defineViraElement()({
|
|
|
29
31
|
* @category Time
|
|
30
32
|
*/
|
|
31
33
|
export function formatAbsoluteTime(time, options) {
|
|
34
|
+
const dateFormat = [
|
|
35
|
+
!options?.showTimeOnly && 'MMM d, yyyy',
|
|
36
|
+
!options?.showDateOnly && 'HH:mm ZZZZ',
|
|
37
|
+
]
|
|
38
|
+
.filter(check.isTruthy)
|
|
39
|
+
.join(' ');
|
|
32
40
|
return toFormattedString(options?.timezone
|
|
33
41
|
? createFullDate(time, options.timezone)
|
|
34
|
-
: createFullDateInUserTimezone(time),
|
|
42
|
+
: createFullDateInUserTimezone(time), dateFormat);
|
|
35
43
|
}
|
|
@@ -170,7 +170,7 @@ export const ViraButton = defineViraElement()({
|
|
|
170
170
|
'vira-button-border-radius': viraFormCssVars['vira-form-radius'].value,
|
|
171
171
|
},
|
|
172
172
|
styles: ({ hostClasses, cssVars }) => {
|
|
173
|
-
function buildVariantCssRule(variantSelector, emphasisSelector, colors) {
|
|
173
|
+
function buildVariantCssRule({ variantSelector, emphasisSelector, colors, }) {
|
|
174
174
|
return css `
|
|
175
175
|
${variantSelector}${emphasisSelector} {
|
|
176
176
|
${cssVars['vira-button-background-color'].name}: ${colors.idle.backgroundColor
|
|
@@ -201,14 +201,30 @@ export const ViraButton = defineViraElement()({
|
|
|
201
201
|
const colorKey = viraColorVariantToHostClassKey[colorVariant];
|
|
202
202
|
const colors = buildThemedButtonColors(colorKey)[emphasis];
|
|
203
203
|
const variantSelector = hostClasses[`vira-button-color-${colorKey}`].selector;
|
|
204
|
-
return buildVariantCssRule(
|
|
204
|
+
return buildVariantCssRule({
|
|
205
|
+
variantSelector,
|
|
206
|
+
emphasisSelector,
|
|
207
|
+
colors,
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
const plainStyle = buildVariantCssRule({
|
|
211
|
+
variantSelector: hostClasses['vira-button-color-plain'].selector,
|
|
212
|
+
emphasisSelector,
|
|
213
|
+
colors: plainButtonColors[emphasis],
|
|
214
|
+
});
|
|
215
|
+
const neutralStyle = buildVariantCssRule({
|
|
216
|
+
variantSelector: hostClasses['vira-button-color-neutral'].selector,
|
|
217
|
+
emphasisSelector,
|
|
218
|
+
colors: neutralButtonColors[emphasis],
|
|
205
219
|
});
|
|
206
|
-
const plainStyle = buildVariantCssRule(hostClasses['vira-button-color-plain'].selector, emphasisSelector, plainButtonColors[emphasis]);
|
|
207
|
-
const neutralStyle = buildVariantCssRule(hostClasses['vira-button-color-neutral'].selector, emphasisSelector, neutralButtonColors[emphasis]);
|
|
208
220
|
const standaloneStyles = standaloneThemeColorNames.map((colorName) => {
|
|
209
221
|
const colors = buildThemedButtonColors(colorName)[emphasis];
|
|
210
222
|
const variantSelector = hostClasses[`vira-button-color-${colorName}`].selector;
|
|
211
|
-
return buildVariantCssRule(
|
|
223
|
+
return buildVariantCssRule({
|
|
224
|
+
variantSelector,
|
|
225
|
+
emphasisSelector,
|
|
226
|
+
colors,
|
|
227
|
+
});
|
|
212
228
|
});
|
|
213
229
|
return [
|
|
214
230
|
...themedStyles,
|
|
@@ -25,6 +25,10 @@ export declare const ViraDateInput: import("element-vir").DeclarativeElementDefi
|
|
|
25
25
|
isReadonly: boolean;
|
|
26
26
|
/** Timezone used to interpret the selected date. Defaults to the user's timezone. */
|
|
27
27
|
timezone: string;
|
|
28
|
+
/** Only show the date part of the selected date when in readonly mode. */
|
|
29
|
+
showDateOnly: boolean;
|
|
30
|
+
/** Only show the time part of the selected date when in readonly mode. */
|
|
31
|
+
showTimeOnly: boolean;
|
|
28
32
|
}>, {
|
|
29
33
|
/** Used to couple the label and input together. Not applied when no label is provided. */
|
|
30
34
|
randomId: string;
|
|
@@ -78,7 +78,8 @@ export const ViraDateInput = defineViraElement()({
|
|
|
78
78
|
? html `
|
|
79
79
|
<${ViraAbsoluteTime.assign({
|
|
80
80
|
time: inputs.value,
|
|
81
|
-
|
|
81
|
+
showDateOnly: inputs.showDateOnly,
|
|
82
|
+
showTimeOnly: inputs.showTimeOnly,
|
|
82
83
|
timezone: inputs.timezone,
|
|
83
84
|
})}></${ViraAbsoluteTime}>
|
|
84
85
|
`
|
|
@@ -211,7 +211,11 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
211
211
|
dispatch(new events.valueChange(newRoot));
|
|
212
212
|
}
|
|
213
213
|
function emitReplaceAt(path, newValue) {
|
|
214
|
-
emitRoot(setValueAtPath(
|
|
214
|
+
emitRoot(setValueAtPath({
|
|
215
|
+
root: inputs.value,
|
|
216
|
+
path,
|
|
217
|
+
newValue,
|
|
218
|
+
}));
|
|
215
219
|
}
|
|
216
220
|
function emitDeleteAt(path) {
|
|
217
221
|
emitRoot(deleteValueAtPath(inputs.value, path));
|
|
@@ -231,7 +235,7 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
231
235
|
},
|
|
232
236
|
});
|
|
233
237
|
}
|
|
234
|
-
function setPendingKey(pathKey, key) {
|
|
238
|
+
function setPendingKey({ pathKey, key }) {
|
|
235
239
|
updateState({
|
|
236
240
|
pendingKeys: {
|
|
237
241
|
...state.pendingKeys,
|
|
@@ -251,7 +255,7 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
251
255
|
},
|
|
252
256
|
});
|
|
253
257
|
}
|
|
254
|
-
function getStringMode(pathKey, value, enumValues) {
|
|
258
|
+
function getStringMode({ pathKey, value, enumValues, }) {
|
|
255
259
|
const stored = state.stringModes[pathKey];
|
|
256
260
|
if (stored) {
|
|
257
261
|
return stored;
|
|
@@ -628,7 +632,10 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
628
632
|
placeholder: 'new field name',
|
|
629
633
|
})}
|
|
630
634
|
${listen(ViraInput.events.valueChange, (event) => {
|
|
631
|
-
setPendingKey(
|
|
635
|
+
setPendingKey({
|
|
636
|
+
pathKey,
|
|
637
|
+
key: event.detail,
|
|
638
|
+
});
|
|
632
639
|
})}
|
|
633
640
|
></${ViraInput}>
|
|
634
641
|
${renderObjectAddControl({
|
|
@@ -766,7 +773,11 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
766
773
|
}
|
|
767
774
|
function renderStringEnumOrRaw(path, value, enumValues) {
|
|
768
775
|
const pathKey = pathToKey(path);
|
|
769
|
-
const mode = getStringMode(
|
|
776
|
+
const mode = getStringMode({
|
|
777
|
+
pathKey,
|
|
778
|
+
value,
|
|
779
|
+
enumValues,
|
|
780
|
+
});
|
|
770
781
|
const editor = mode === ViraJsonStringMode.Options
|
|
771
782
|
? html `
|
|
772
783
|
<${ViraSelect.assign({
|
|
@@ -197,7 +197,7 @@ export const ViraTag = defineViraElement()({
|
|
|
197
197
|
}),
|
|
198
198
|
},
|
|
199
199
|
styles: ({ cssVars, hostClasses }) => {
|
|
200
|
-
function buildVariantCssRule(variantSelector, emphasisSelector, colors) {
|
|
200
|
+
function buildVariantCssRule({ variantSelector, emphasisSelector, colors, }) {
|
|
201
201
|
return css `
|
|
202
202
|
${variantSelector}${emphasisSelector} {
|
|
203
203
|
${cssVars['vira-tag-background-color'].name}: ${colors.idle.backgroundColor
|
|
@@ -226,14 +226,30 @@ export const ViraTag = defineViraElement()({
|
|
|
226
226
|
const colorKey = viraColorVariantToHostClassKey[colorVariant];
|
|
227
227
|
const colors = buildThemedTagColors(colorKey)[emphasis];
|
|
228
228
|
const variantSelector = hostClasses[`vira-tag-color-${colorKey}`].selector;
|
|
229
|
-
return buildVariantCssRule(
|
|
229
|
+
return buildVariantCssRule({
|
|
230
|
+
variantSelector,
|
|
231
|
+
emphasisSelector,
|
|
232
|
+
colors,
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
const plainStyle = buildVariantCssRule({
|
|
236
|
+
variantSelector: hostClasses['vira-tag-color-plain'].selector,
|
|
237
|
+
emphasisSelector,
|
|
238
|
+
colors: plainTagColors[emphasis],
|
|
239
|
+
});
|
|
240
|
+
const neutralStyle = buildVariantCssRule({
|
|
241
|
+
variantSelector: hostClasses['vira-tag-color-neutral'].selector,
|
|
242
|
+
emphasisSelector,
|
|
243
|
+
colors: buildThemedTagColors(ViraThemeColorName.grey)[emphasis],
|
|
230
244
|
});
|
|
231
|
-
const plainStyle = buildVariantCssRule(hostClasses['vira-tag-color-plain'].selector, emphasisSelector, plainTagColors[emphasis]);
|
|
232
|
-
const neutralStyle = buildVariantCssRule(hostClasses['vira-tag-color-neutral'].selector, emphasisSelector, buildThemedTagColors(ViraThemeColorName.grey)[emphasis]);
|
|
233
245
|
const standaloneStyles = standaloneThemeColorNames.map((colorName) => {
|
|
234
246
|
const colors = buildThemedTagColors(colorName)[emphasis];
|
|
235
247
|
const variantSelector = hostClasses[`vira-tag-color-${colorName}`].selector;
|
|
236
|
-
return buildVariantCssRule(
|
|
248
|
+
return buildVariantCssRule({
|
|
249
|
+
variantSelector,
|
|
250
|
+
emphasisSelector,
|
|
251
|
+
colors,
|
|
252
|
+
});
|
|
237
253
|
});
|
|
238
254
|
return [
|
|
239
255
|
...themedStyles,
|
|
@@ -6,7 +6,7 @@ const defaultLucideAttributes = {
|
|
|
6
6
|
stroke: String(viraIconCssVars['vira-icon-stroke-color'].value),
|
|
7
7
|
'stroke-width': String(viraIconCssVars['vira-icon-stroke-width'].value),
|
|
8
8
|
};
|
|
9
|
-
function setSvgAttribute(svgString, attributeName, value) {
|
|
9
|
+
function setSvgAttribute({ svgString, attributeName, value, }) {
|
|
10
10
|
const escapedName = attributeName.replace(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`);
|
|
11
11
|
const regex = new RegExp(String.raw `(\s)${escapedName}="[^"]*"`);
|
|
12
12
|
return regex.test(svgString)
|
|
@@ -14,7 +14,11 @@ function setSvgAttribute(svgString, attributeName, value) {
|
|
|
14
14
|
: svgString.replace(/<svg\b/, `<svg ${attributeName}="${value}"`);
|
|
15
15
|
}
|
|
16
16
|
function applySvgAttributes(svgString, attributes) {
|
|
17
|
-
return Object.entries(attributes).reduce((result, [key, value,]) => setSvgAttribute(
|
|
17
|
+
return Object.entries(attributes).reduce((result, [key, value,]) => setSvgAttribute({
|
|
18
|
+
svgString: result,
|
|
19
|
+
attributeName: key,
|
|
20
|
+
value,
|
|
21
|
+
}), svgString);
|
|
18
22
|
}
|
|
19
23
|
function isLucideIconKey(key) {
|
|
20
24
|
return key in lucideStaticImport;
|
|
@@ -107,4 +107,9 @@ export type ViraTableOptions<Orientation extends ViraTableOrientation = ViraTabl
|
|
|
107
107
|
*/
|
|
108
108
|
export declare function defineTable<const Headers extends ViraTableHeaders, OriginalData extends ReadonlyArray<any>, const Orientation extends ViraTableOrientation = ViraTableOrientation.Vertical>(
|
|
109
109
|
/** The order of these keys determines the order that they render in. */
|
|
110
|
-
headers
|
|
110
|
+
{ headers, originalData, dataMap, options, }: Readonly<{
|
|
111
|
+
headers: Readonly<Headers>;
|
|
112
|
+
originalData: OriginalData;
|
|
113
|
+
dataMap: (entry: ArrayElement<OriginalData>, entryIndex: number) => ViraTableEntry<Headers> | undefined;
|
|
114
|
+
options?: ViraTableOptions<Orientation>;
|
|
115
|
+
}>): ViraTable<Headers, Orientation, OriginalData>;
|
|
@@ -29,7 +29,7 @@ export var ViraTableOrientation;
|
|
|
29
29
|
*/
|
|
30
30
|
export function defineTable(
|
|
31
31
|
/** The order of these keys determines the order that they render in. */
|
|
32
|
-
headers, originalData, dataMap, options = {}) {
|
|
32
|
+
{ headers, originalData, dataMap, options = {}, }) {
|
|
33
33
|
const mappedData = originalData.map((dataRow, rowIndex) => {
|
|
34
34
|
return {
|
|
35
35
|
cells: dataMap(dataRow, rowIndex),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type MaybePromise } from '@augment-vir/common';
|
|
2
2
|
import { type Coords, type NavController } from 'device-navigation';
|
|
3
|
-
import { type ExtractEventByType, type ExtractEventTypes, type ListenOptions, type RemoveListenerCallback } from 'typed-event-target';
|
|
3
|
+
import { type ExtractEventByType, type ExtractEventTypes, type ListenOptions, ListenTarget, type RemoveListenerCallback } from 'typed-event-target';
|
|
4
4
|
/**
|
|
5
5
|
* Used to prevent pop-ups from closing when a text input is active.
|
|
6
6
|
*
|
|
@@ -161,12 +161,17 @@ export type PopUpManagerEvents = HidePopUpEvent | NavSelectEvent;
|
|
|
161
161
|
*/
|
|
162
162
|
export declare class PopUpManager {
|
|
163
163
|
readonly navController: NavController;
|
|
164
|
-
|
|
164
|
+
protected listenTarget: ListenTarget<PopUpManagerEvents>;
|
|
165
165
|
options: PopUpManagerOptions;
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
/** Callbacks that remove the global listeners attached while a pop up is shown. */
|
|
167
|
+
protected cleanupCallbacks: (() => void)[];
|
|
168
|
+
protected lastRootElement: HTMLElement | undefined;
|
|
168
169
|
constructor(navController: NavController, options?: Partial<PopUpManagerOptions> | undefined);
|
|
169
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Attaches the global listeners (page activation, navigation, mousedown, and keydown) that
|
|
172
|
+
* control the currently shown pop up.
|
|
173
|
+
*/
|
|
174
|
+
protected attachGlobalListeners(): void;
|
|
170
175
|
/** Listen to events emitted from a {@link PopUpManager} instance. */
|
|
171
176
|
listen<const EventDefinition extends Readonly<{
|
|
172
177
|
type: ExtractEventTypes<PopUpManagerEvents>;
|
|
@@ -62,6 +62,7 @@ export class PopUpManager {
|
|
|
62
62
|
horizontalDiffThreshold: 100,
|
|
63
63
|
supportNavigation: true,
|
|
64
64
|
};
|
|
65
|
+
/** Callbacks that remove the global listeners attached while a pop up is shown. */
|
|
65
66
|
cleanupCallbacks = [];
|
|
66
67
|
lastRootElement;
|
|
67
68
|
constructor(navController, options) {
|
|
@@ -71,6 +72,10 @@ export class PopUpManager {
|
|
|
71
72
|
...options,
|
|
72
73
|
};
|
|
73
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Attaches the global listeners (page activation, navigation, mousedown, and keydown) that
|
|
77
|
+
* control the currently shown pop up.
|
|
78
|
+
*/
|
|
74
79
|
attachGlobalListeners() {
|
|
75
80
|
this.cleanupCallbacks = [
|
|
76
81
|
listenToPageActivation(false, (isPageActive) => {
|
|
@@ -192,7 +192,11 @@ export declare function pathToKey(path: ViraJsonPath): string;
|
|
|
192
192
|
*
|
|
193
193
|
* @category Internal
|
|
194
194
|
*/
|
|
195
|
-
export declare function setValueAtPath(root
|
|
195
|
+
export declare function setValueAtPath({ root, path, newValue, }: Readonly<{
|
|
196
|
+
root: JsonValue;
|
|
197
|
+
path: ViraJsonPath;
|
|
198
|
+
newValue: JsonValue;
|
|
199
|
+
}>): JsonValue;
|
|
196
200
|
/**
|
|
197
201
|
* Returns a new JSON value where the value at `path` has been removed. If `path` targets an object
|
|
198
202
|
* key, the key is deleted; if it targets an array index, the item is spliced out.
|
|
@@ -476,10 +476,16 @@ export function validateAgainstSchema(value, schema) {
|
|
|
476
476
|
}
|
|
477
477
|
const context = createResolveContext(schema);
|
|
478
478
|
const errors = [];
|
|
479
|
-
validateRecursive(
|
|
479
|
+
validateRecursive({
|
|
480
|
+
value,
|
|
481
|
+
schema,
|
|
482
|
+
path: [],
|
|
483
|
+
context,
|
|
484
|
+
errors,
|
|
485
|
+
});
|
|
480
486
|
return errors;
|
|
481
487
|
}
|
|
482
|
-
function validateRecursive(value, schema, path, context, errors) {
|
|
488
|
+
function validateRecursive({ value, schema, path, context, errors, }) {
|
|
483
489
|
const branches = expandSchemaBranches(schema, context);
|
|
484
490
|
if (branches.length === 0) {
|
|
485
491
|
return;
|
|
@@ -487,7 +493,13 @@ function validateRecursive(value, schema, path, context, errors) {
|
|
|
487
493
|
const branchErrorSets = [];
|
|
488
494
|
for (const branch of branches) {
|
|
489
495
|
const branchErrors = [];
|
|
490
|
-
validateBranch(
|
|
496
|
+
validateBranch({
|
|
497
|
+
value,
|
|
498
|
+
branch,
|
|
499
|
+
path,
|
|
500
|
+
context,
|
|
501
|
+
errors: branchErrors,
|
|
502
|
+
});
|
|
491
503
|
if (branchErrors.length === 0) {
|
|
492
504
|
return;
|
|
493
505
|
}
|
|
@@ -500,7 +512,7 @@ function validateRecursive(value, schema, path, context, errors) {
|
|
|
500
512
|
errors.push(`${formatPathLabel(path)} did not match any allowed schema branch (anyOf/oneOf).`);
|
|
501
513
|
}
|
|
502
514
|
}
|
|
503
|
-
function validateBranch(value, branch, path, context, errors) {
|
|
515
|
+
function validateBranch({ value, branch, path, context, errors, }) {
|
|
504
516
|
const allowedTypes = getAllowedJsonTypes(branch, context);
|
|
505
517
|
const concreteType = getJsonType(value);
|
|
506
518
|
if (allowedTypes.length > 0) {
|
|
@@ -513,12 +525,19 @@ function validateBranch(value, branch, path, context, errors) {
|
|
|
513
525
|
return;
|
|
514
526
|
}
|
|
515
527
|
}
|
|
516
|
-
if ('const' in branch &&
|
|
528
|
+
if ('const' in branch &&
|
|
529
|
+
!deepEqualsJson({
|
|
530
|
+
a: value,
|
|
531
|
+
b: branch.const,
|
|
532
|
+
})) {
|
|
517
533
|
errors.push(`${formatPathLabel(path)} must equal const value.`);
|
|
518
534
|
return;
|
|
519
535
|
}
|
|
520
536
|
if ('enum' in branch && check.isArray(branch.enum)) {
|
|
521
|
-
const matched = branch.enum.some((entry) => deepEqualsJson(
|
|
537
|
+
const matched = branch.enum.some((entry) => deepEqualsJson({
|
|
538
|
+
a: value,
|
|
539
|
+
b: entry,
|
|
540
|
+
}));
|
|
522
541
|
if (!matched) {
|
|
523
542
|
errors.push(`${formatPathLabel(path)} must be one of the enum values.`);
|
|
524
543
|
return;
|
|
@@ -540,13 +559,25 @@ function validateBranch(value, branch, path, context, errors) {
|
|
|
540
559
|
];
|
|
541
560
|
const propSchema = branch.properties?.[propKey];
|
|
542
561
|
if (propSchema !== undefined) {
|
|
543
|
-
validateRecursive(
|
|
562
|
+
validateRecursive({
|
|
563
|
+
value: propValue,
|
|
564
|
+
schema: propSchema,
|
|
565
|
+
path: propPath,
|
|
566
|
+
context,
|
|
567
|
+
errors,
|
|
568
|
+
});
|
|
544
569
|
}
|
|
545
570
|
else if (additional === false) {
|
|
546
571
|
errors.push(`${formatPathLabel(propPath)} is not allowed (additionalProperties is false).`);
|
|
547
572
|
}
|
|
548
573
|
else if (check.isObject(additional)) {
|
|
549
|
-
validateRecursive(
|
|
574
|
+
validateRecursive({
|
|
575
|
+
value: propValue,
|
|
576
|
+
schema: additional,
|
|
577
|
+
path: propPath,
|
|
578
|
+
context,
|
|
579
|
+
errors,
|
|
580
|
+
});
|
|
550
581
|
}
|
|
551
582
|
else if (additional === undefined && definedKeys.size > 0) {
|
|
552
583
|
continue;
|
|
@@ -563,21 +594,37 @@ function validateBranch(value, branch, path, context, errors) {
|
|
|
563
594
|
if (check.isArray(items)) {
|
|
564
595
|
const tupleSchema = items[index] ?? branch.additionalItems;
|
|
565
596
|
if (tupleSchema !== undefined) {
|
|
566
|
-
validateRecursive(
|
|
597
|
+
validateRecursive({
|
|
598
|
+
value: item,
|
|
599
|
+
schema: tupleSchema,
|
|
600
|
+
path: itemPath,
|
|
601
|
+
context,
|
|
602
|
+
errors,
|
|
603
|
+
});
|
|
567
604
|
}
|
|
568
605
|
}
|
|
569
606
|
else if (items !== undefined) {
|
|
570
|
-
validateRecursive(
|
|
607
|
+
validateRecursive({
|
|
608
|
+
value: item,
|
|
609
|
+
schema: items,
|
|
610
|
+
path: itemPath,
|
|
611
|
+
context,
|
|
612
|
+
errors,
|
|
613
|
+
});
|
|
571
614
|
}
|
|
572
615
|
});
|
|
573
616
|
}
|
|
574
617
|
}
|
|
575
|
-
function deepEqualsJson(a, b) {
|
|
618
|
+
function deepEqualsJson({ a, b }) {
|
|
576
619
|
if (a === b) {
|
|
577
620
|
return true;
|
|
578
621
|
}
|
|
579
622
|
else if (check.isArray(a) && check.isArray(b)) {
|
|
580
|
-
return a.length === b.length &&
|
|
623
|
+
return (a.length === b.length &&
|
|
624
|
+
a.every((entry, i) => deepEqualsJson({
|
|
625
|
+
a: entry,
|
|
626
|
+
b: b[i] ?? null,
|
|
627
|
+
})));
|
|
581
628
|
}
|
|
582
629
|
else if (check.isObject(a) && check.isObject(b)) {
|
|
583
630
|
const aKeys = Object.keys(a);
|
|
@@ -585,7 +632,10 @@ function deepEqualsJson(a, b) {
|
|
|
585
632
|
if (aKeys.length !== bKeys.length) {
|
|
586
633
|
return false;
|
|
587
634
|
}
|
|
588
|
-
return aKeys.every((key) => deepEqualsJson(
|
|
635
|
+
return aKeys.every((key) => deepEqualsJson({
|
|
636
|
+
a: a[key] ?? null,
|
|
637
|
+
b: b[key] ?? null,
|
|
638
|
+
}));
|
|
589
639
|
}
|
|
590
640
|
return false;
|
|
591
641
|
}
|
|
@@ -598,7 +648,7 @@ export function pathToKey(path) {
|
|
|
598
648
|
*
|
|
599
649
|
* @category Internal
|
|
600
650
|
*/
|
|
601
|
-
export function setValueAtPath(root, path, newValue) {
|
|
651
|
+
export function setValueAtPath({ root, path, newValue, }) {
|
|
602
652
|
if (path.length === 0) {
|
|
603
653
|
return newValue;
|
|
604
654
|
}
|
|
@@ -607,7 +657,11 @@ export function setValueAtPath(root, path, newValue) {
|
|
|
607
657
|
if (typeof head === 'number') {
|
|
608
658
|
const array = check.isArray(root) ? root : [];
|
|
609
659
|
const existing = array[head] ?? null;
|
|
610
|
-
const replaced = setValueAtPath(
|
|
660
|
+
const replaced = setValueAtPath({
|
|
661
|
+
root: existing,
|
|
662
|
+
path: rest,
|
|
663
|
+
newValue,
|
|
664
|
+
});
|
|
611
665
|
if (head >= array.length) {
|
|
612
666
|
const extended = [...array];
|
|
613
667
|
while (extended.length < head) {
|
|
@@ -623,7 +677,11 @@ export function setValueAtPath(root, path, newValue) {
|
|
|
623
677
|
const existing = object[head] ?? null;
|
|
624
678
|
return {
|
|
625
679
|
...object,
|
|
626
|
-
[head]: setValueAtPath(
|
|
680
|
+
[head]: setValueAtPath({
|
|
681
|
+
root: existing,
|
|
682
|
+
path: rest,
|
|
683
|
+
newValue,
|
|
684
|
+
}),
|
|
627
685
|
};
|
|
628
686
|
}
|
|
629
687
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vira",
|
|
3
|
-
"version": "31.
|
|
3
|
+
"version": "31.28.0",
|
|
4
4
|
"description": "A simple and highly versatile design system using element-vir.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design",
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
"test:docs": "virmator docs check"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@augment-vir/assert": "^
|
|
42
|
-
"@augment-vir/common": "^
|
|
43
|
-
"@augment-vir/web": "^
|
|
41
|
+
"@augment-vir/assert": "^32.1.0",
|
|
42
|
+
"@augment-vir/common": "^32.1.0",
|
|
43
|
+
"@augment-vir/web": "^32.1.0",
|
|
44
44
|
"@electrovir/color": "^1.7.10",
|
|
45
45
|
"@electrovir/local-storage-client": "^0.1.0",
|
|
46
|
-
"date-vir": "^8.6.
|
|
46
|
+
"date-vir": "^8.6.2",
|
|
47
47
|
"device-navigation": "^4.7.2",
|
|
48
48
|
"json-schema-to-ts": "^3.1.1",
|
|
49
49
|
"lit-css-vars": "^3.6.2",
|
|
@@ -51,24 +51,24 @@
|
|
|
51
51
|
"observavir": "^2.3.2",
|
|
52
52
|
"page-active": "^1.0.3",
|
|
53
53
|
"spa-router-vir": "^6.6.0",
|
|
54
|
-
"type-fest": "^5.
|
|
55
|
-
"typed-event-target": "^4.3.
|
|
54
|
+
"type-fest": "^5.8.0",
|
|
55
|
+
"typed-event-target": "^4.3.2"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@augment-vir/test": "^
|
|
59
|
-
"@web/dev-server-esbuild": "^
|
|
60
|
-
"@web/test-runner": "^0.
|
|
61
|
-
"@web/test-runner-commands": "^0.
|
|
62
|
-
"@web/test-runner-playwright": "^0.
|
|
63
|
-
"@web/test-runner-visual-regression": "^0.
|
|
58
|
+
"@augment-vir/test": "^32.1.0",
|
|
59
|
+
"@web/dev-server-esbuild": "^2.0.0",
|
|
60
|
+
"@web/test-runner": "^1.0.0",
|
|
61
|
+
"@web/test-runner-commands": "^1.0.0",
|
|
62
|
+
"@web/test-runner-playwright": "^1.0.0",
|
|
63
|
+
"@web/test-runner-visual-regression": "^1.0.0",
|
|
64
64
|
"esbuild": "^0.28.1",
|
|
65
65
|
"istanbul-smart-text-reporter": "^1.1.5",
|
|
66
|
-
"lucide-static": "^1.
|
|
67
|
-
"markdown-code-example-inserter": "^3.0.
|
|
66
|
+
"lucide-static": "^1.23.0",
|
|
67
|
+
"markdown-code-example-inserter": "^3.0.6",
|
|
68
68
|
"theme-vir": "^28.25.0",
|
|
69
|
-
"typedoc": "^0.28.
|
|
70
|
-
"typescript": "6.0.3",
|
|
71
|
-
"vite": "^8.
|
|
69
|
+
"typedoc": "^0.28.20",
|
|
70
|
+
"typescript": "^6.0.3",
|
|
71
|
+
"vite": "^8.1.3",
|
|
72
72
|
"vite-tsconfig-paths": "^6.1.1"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|