vira 31.18.1 → 31.19.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-trigger.element.d.ts +2 -2
- package/dist/elements/pop-up/vira-menu-trigger.element.js +6 -3
- package/dist/elements/pop-up/vira-pop-up-trigger.element.d.ts +2 -2
- package/dist/elements/pop-up/vira-pop-up-trigger.element.js +4 -4
- package/dist/elements/vira-collapsible-card.element.d.ts +2 -2
- package/dist/elements/vira-collapsible-card.element.js +8 -3
- package/dist/elements/vira-collapsible-wrapper.element.d.ts +2 -2
- package/dist/elements/vira-collapsible-wrapper.element.js +2 -2
- package/dist/elements/vira-drawer.element.d.ts +2 -2
- package/dist/elements/vira-drawer.element.js +4 -2
- package/dist/elements/vira-dropdown.element.d.ts +6 -0
- package/dist/elements/vira-dropdown.element.js +38 -4
- package/dist/elements/vira-image.element.d.ts +2 -2
- package/dist/elements/vira-image.element.js +4 -4
- package/dist/elements/vira-json-form.element.js +192 -141
- package/dist/elements/vira-modal.element.d.ts +2 -2
- package/dist/elements/vira-modal.element.js +6 -2
- package/dist/elements/vira-tabs.element.js +9 -2
- package/dist/elements/vira-text-area.element.js +1 -0
- package/dist/icons/icon-svgs/16/plus-16.icon.d.ts +8 -0
- package/dist/icons/icon-svgs/{plus-24.icon.js → 16/plus-16.icon.js} +7 -7
- package/dist/icons/index.d.ts +3 -0
- package/dist/icons/index.js +4 -0
- package/dist/util/define-vira-element.js +1 -1
- package/dist/util/overflow-observer.d.ts +8 -1
- package/dist/util/overflow-observer.js +10 -2
- package/package.json +8 -8
- package/dist/icons/icon-svgs/plus-24.icon.d.ts +0 -8
|
@@ -17,7 +17,7 @@ export declare const viraMenuTriggerTestIds: {
|
|
|
17
17
|
* @category PopUp
|
|
18
18
|
* @category Elements
|
|
19
19
|
*/
|
|
20
|
-
export declare const ViraMenuTrigger: import("element-vir").DeclarativeElementDefinition
|
|
20
|
+
export declare const ViraMenuTrigger: import("element-vir").DeclarativeElementDefinition<`vira-${string}`, PartialWithUndefined<{
|
|
21
21
|
isDisabled: boolean;
|
|
22
22
|
z_debug_forceOpenState: boolean;
|
|
23
23
|
popUpOffset: PopUpOffset;
|
|
@@ -42,4 +42,4 @@ export declare const ViraMenuTrigger: import("element-vir").DeclarativeElementDe
|
|
|
42
42
|
showPopUpResult: ShowPopUpResult | undefined;
|
|
43
43
|
}, {
|
|
44
44
|
openChange: import("element-vir").DefineEvent<ShowPopUpResult | undefined>;
|
|
45
|
-
},
|
|
45
|
+
}, `vira-${string}-`, `vira-${string}-`, readonly ["vira-menu-trigger-trigger"], readonly []>;
|
|
@@ -19,7 +19,7 @@ export const viraMenuTriggerTestIds = {
|
|
|
19
19
|
export const ViraMenuTrigger = defineViraElement()({
|
|
20
20
|
tagName: 'vira-menu-trigger',
|
|
21
21
|
slotNames: [
|
|
22
|
-
'trigger',
|
|
22
|
+
'vira-menu-trigger-trigger',
|
|
23
23
|
],
|
|
24
24
|
styles: css `
|
|
25
25
|
:host {
|
|
@@ -71,7 +71,10 @@ export const ViraMenuTrigger = defineViraElement()({
|
|
|
71
71
|
});
|
|
72
72
|
})}
|
|
73
73
|
>
|
|
74
|
-
<slot
|
|
74
|
+
<slot
|
|
75
|
+
name=${slotNames['vira-menu-trigger-trigger']}
|
|
76
|
+
slot=${ViraPopUpTrigger.slotNames['vira-pop-up-trigger-trigger']}
|
|
77
|
+
></slot>
|
|
75
78
|
${state.navController && state.showPopUpResult
|
|
76
79
|
? html `
|
|
77
80
|
<${ViraMenu.assign({
|
|
@@ -80,7 +83,7 @@ export const ViraMenuTrigger = defineViraElement()({
|
|
|
80
83
|
: ViraMenuPopUpDirection.Upwards,
|
|
81
84
|
cornerStyle: inputs.menuCornerStyle,
|
|
82
85
|
})}
|
|
83
|
-
slot=${ViraPopUpTrigger.slotNames
|
|
86
|
+
slot=${ViraPopUpTrigger.slotNames['vira-pop-up-trigger-pop-up']}
|
|
84
87
|
class=${classMap({
|
|
85
88
|
'full-width-menu': inputs.horizontalAnchor === HorizontalAnchor.Both,
|
|
86
89
|
})}
|
|
@@ -79,7 +79,7 @@ export type PopUpTriggerPosition = {
|
|
|
79
79
|
* @category Elements
|
|
80
80
|
* @see https://electrovir.github.io/vira/book/elements/vira-pop-up-trigger
|
|
81
81
|
*/
|
|
82
|
-
export declare const ViraPopUpTrigger: import("element-vir").DeclarativeElementDefinition
|
|
82
|
+
export declare const ViraPopUpTrigger: import("element-vir").DeclarativeElementDefinition<`vira-${string}`, PartialWithUndefined<PopUpTriggerPosition & {
|
|
83
83
|
isDisabled: boolean;
|
|
84
84
|
/** For debugging purposes only. Very bad for actual production code use. */
|
|
85
85
|
z_debug_forceOpenState: boolean;
|
|
@@ -106,4 +106,4 @@ export declare const ViraPopUpTrigger: import("element-vir").DeclarativeElementD
|
|
|
106
106
|
navController: NavController;
|
|
107
107
|
popUpManager: PopUpManager;
|
|
108
108
|
}>;
|
|
109
|
-
}, "vira-pop-up-trigger-disabled" | "vira-pop-up-trigger-inside-focus" | "vira-pop-up-trigger-outside-focus", "vira-pop-up-trigger-",
|
|
109
|
+
}, "vira-pop-up-trigger-disabled" | "vira-pop-up-trigger-inside-focus" | "vira-pop-up-trigger-outside-focus", `vira-${string}-`, readonly ["vira-pop-up-trigger-trigger", "vira-pop-up-trigger-pop-up"], readonly []>;
|
|
@@ -53,8 +53,8 @@ export const ViraPopUpTrigger = defineViraElement()({
|
|
|
53
53
|
};
|
|
54
54
|
},
|
|
55
55
|
slotNames: [
|
|
56
|
-
'trigger',
|
|
57
|
-
'
|
|
56
|
+
'vira-pop-up-trigger-trigger',
|
|
57
|
+
'vira-pop-up-trigger-pop-up',
|
|
58
58
|
],
|
|
59
59
|
hostClasses: {
|
|
60
60
|
'vira-pop-up-trigger-disabled': ({ inputs }) => !!inputs.isDisabled,
|
|
@@ -362,7 +362,7 @@ export const ViraPopUpTrigger = defineViraElement()({
|
|
|
362
362
|
})}
|
|
363
363
|
>
|
|
364
364
|
<div class="dropdown-trigger">
|
|
365
|
-
<slot name=${slotNames
|
|
365
|
+
<slot name=${slotNames['vira-pop-up-trigger-trigger']}></slot>
|
|
366
366
|
</div>
|
|
367
367
|
|
|
368
368
|
<div
|
|
@@ -372,7 +372,7 @@ export const ViraPopUpTrigger = defineViraElement()({
|
|
|
372
372
|
style=${positionerStyles}
|
|
373
373
|
>
|
|
374
374
|
${renderIf(!!state.showPopUpResult, html `
|
|
375
|
-
<slot name=${slotNames
|
|
375
|
+
<slot name=${slotNames['vira-pop-up-trigger-pop-up']}></slot>
|
|
376
376
|
`)}
|
|
377
377
|
</div>
|
|
378
378
|
</button>
|
|
@@ -5,7 +5,7 @@ import { type PartialWithUndefined } from '@augment-vir/common';
|
|
|
5
5
|
* @category Elements
|
|
6
6
|
* @see https://electrovir.github.io/vira/book/elements/vira-checkbox
|
|
7
7
|
*/
|
|
8
|
-
export declare const ViraCollapsibleCard: import("element-vir").DeclarativeElementDefinition
|
|
8
|
+
export declare const ViraCollapsibleCard: import("element-vir").DeclarativeElementDefinition<`vira-${string}`, PartialWithUndefined<{
|
|
9
9
|
/**
|
|
10
10
|
* When set to `true`, the card styles are diminished so you can still use this element in
|
|
11
11
|
* more flexible ways.
|
|
@@ -33,4 +33,4 @@ export declare const ViraCollapsibleCard: import("element-vir").DeclarativeEleme
|
|
|
33
33
|
isExpanded: boolean;
|
|
34
34
|
}, {
|
|
35
35
|
expandToggle: import("element-vir").DefineEvent<boolean>;
|
|
36
|
-
}, "vira-collapsible-card-expanded" | "vira-collapsible-card-expansion-blocked" | "vira-collapsible-card-card-styles", "vira-collapsible-card-content-gap", readonly ["header"], readonly ["openCaret"]>;
|
|
36
|
+
}, "vira-collapsible-card-expanded" | "vira-collapsible-card-expansion-blocked" | "vira-collapsible-card-card-styles", "vira-collapsible-card-content-gap", readonly ["vira-collapsible-card-header"], readonly ["openCaret"]>;
|
|
@@ -110,7 +110,7 @@ export const ViraCollapsibleCard = defineViraElement()({
|
|
|
110
110
|
}
|
|
111
111
|
`,
|
|
112
112
|
slotNames: [
|
|
113
|
-
'header',
|
|
113
|
+
'vira-collapsible-card-header',
|
|
114
114
|
],
|
|
115
115
|
render({ inputs, slotNames, state, updateState, testIds, dispatch, events }) {
|
|
116
116
|
if (inputs.blockExpansion) {
|
|
@@ -127,7 +127,9 @@ export const ViraCollapsibleCard = defineViraElement()({
|
|
|
127
127
|
? nothing
|
|
128
128
|
: html `
|
|
129
129
|
<div class="card-header">
|
|
130
|
-
<slot name=${slotNames
|
|
130
|
+
<slot name=${slotNames['vira-collapsible-card-header']}>
|
|
131
|
+
<div class="header-filler"></div>
|
|
132
|
+
</slot>
|
|
131
133
|
|
|
132
134
|
${inputs.blockExpansion
|
|
133
135
|
? nothing
|
|
@@ -158,7 +160,10 @@ export const ViraCollapsibleCard = defineViraElement()({
|
|
|
158
160
|
dispatch(new events.expandToggle(event.detail));
|
|
159
161
|
})}
|
|
160
162
|
>
|
|
161
|
-
<div
|
|
163
|
+
<div
|
|
164
|
+
class="header-wrapper"
|
|
165
|
+
slot=${ViraCollapsibleWrapper.slotNames['vira-collapsible-wrapper-header']}
|
|
166
|
+
>
|
|
162
167
|
${wrapperHeaderTemplate}
|
|
163
168
|
</div>
|
|
164
169
|
${wrapperContentTemplate}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @category Elements
|
|
6
6
|
* @see https://electrovir.github.io/vira/book/elements/vira-collapsible-wrapper
|
|
7
7
|
*/
|
|
8
|
-
export declare const ViraCollapsibleWrapper: import("element-vir").DeclarativeElementDefinition
|
|
8
|
+
export declare const ViraCollapsibleWrapper: import("element-vir").DeclarativeElementDefinition<`vira-${string}`, {
|
|
9
9
|
expanded: boolean;
|
|
10
10
|
/** When true, forces the content to expand when printing regardless of collapsed state. */
|
|
11
11
|
expandOnPrint?: boolean;
|
|
@@ -13,4 +13,4 @@ export declare const ViraCollapsibleWrapper: import("element-vir").DeclarativeEl
|
|
|
13
13
|
contentHeight: number;
|
|
14
14
|
}, {
|
|
15
15
|
expandChange: import("element-vir").DefineEvent<boolean>;
|
|
16
|
-
}, "vira-collapsible-wrapper-expand-on-print", "vira-collapsible-wrapper-
|
|
16
|
+
}, "vira-collapsible-wrapper-expand-on-print", `vira-${string}-`, readonly ["vira-collapsible-wrapper-header"], readonly []>;
|
|
@@ -18,7 +18,7 @@ export const ViraCollapsibleWrapper = defineViraElement()({
|
|
|
18
18
|
hostClasses: {
|
|
19
19
|
'vira-collapsible-wrapper-expand-on-print': ({ inputs }) => !!inputs.expandOnPrint,
|
|
20
20
|
},
|
|
21
|
-
slotNames: ['header'],
|
|
21
|
+
slotNames: ['vira-collapsible-wrapper-header'],
|
|
22
22
|
styles: ({ hostClasses }) => css `
|
|
23
23
|
:host {
|
|
24
24
|
display: flex;
|
|
@@ -75,7 +75,7 @@ export const ViraCollapsibleWrapper = defineViraElement()({
|
|
|
75
75
|
dispatch(new events.expandChange(!inputs.expanded));
|
|
76
76
|
})}
|
|
77
77
|
>
|
|
78
|
-
<slot name=${slotNames
|
|
78
|
+
<slot name=${slotNames['vira-collapsible-wrapper-header']}>Header</slot>
|
|
79
79
|
</button>
|
|
80
80
|
|
|
81
81
|
<div
|
|
@@ -4,7 +4,7 @@ import { type PartialWithUndefined } from '@augment-vir/common';
|
|
|
4
4
|
*
|
|
5
5
|
* @category Elements
|
|
6
6
|
*/
|
|
7
|
-
export declare const ViraDrawer: import("element-vir").DeclarativeElementDefinition
|
|
7
|
+
export declare const ViraDrawer: import("element-vir").DeclarativeElementDefinition<`vira-${string}`, {
|
|
8
8
|
open: boolean;
|
|
9
9
|
} & PartialWithUndefined<{
|
|
10
10
|
/** If this isn't set, make sure to use the drawer title slot to fill it in. */
|
|
@@ -21,4 +21,4 @@ export declare const ViraDrawer: import("element-vir").DeclarativeElementDefinit
|
|
|
21
21
|
dragCurrentY: number;
|
|
22
22
|
}, {
|
|
23
23
|
drawerClose: import("element-vir").DefineEvent<void>;
|
|
24
|
-
}, "vira-drawer-dragging" | "vira-drawer-no-content-padding", "vira-drawer-backdrop-filter" | "vira-drawer-max-height", readonly ["
|
|
24
|
+
}, "vira-drawer-dragging" | "vira-drawer-no-content-padding", "vira-drawer-backdrop-filter" | "vira-drawer-max-height", readonly ["vira-drawer-drawer-title"], readonly []>;
|
|
@@ -48,7 +48,7 @@ export const ViraDrawer = defineViraElement()({
|
|
|
48
48
|
'vira-drawer-dragging': ({ state }) => state.isDragging,
|
|
49
49
|
'vira-drawer-no-content-padding': ({ inputs }) => !!inputs.noContentPadding,
|
|
50
50
|
},
|
|
51
|
-
slotNames: ['
|
|
51
|
+
slotNames: ['vira-drawer-drawer-title'],
|
|
52
52
|
cssVars: {
|
|
53
53
|
'vira-drawer-backdrop-filter': 'blur(3px)',
|
|
54
54
|
'vira-drawer-max-height': '80dvh',
|
|
@@ -275,7 +275,9 @@ export const ViraDrawer = defineViraElement()({
|
|
|
275
275
|
<div class="header">
|
|
276
276
|
<div class="header-text-wrapper">
|
|
277
277
|
<h1>
|
|
278
|
-
<slot name=${slotNames
|
|
278
|
+
<slot name=${slotNames['vira-drawer-drawer-title']}>
|
|
279
|
+
${inputs.drawerTitle}
|
|
280
|
+
</slot>
|
|
279
281
|
</h1>
|
|
280
282
|
</div>
|
|
281
283
|
<button
|
|
@@ -25,11 +25,17 @@ export declare const ViraDropdown: import("element-vir").DeclarativeElementDefin
|
|
|
25
25
|
icon: ViraIconSvg;
|
|
26
26
|
selectionPrefix: string;
|
|
27
27
|
isDisabled: boolean;
|
|
28
|
+
label: string;
|
|
28
29
|
/** For debugging purposes only. Very bad for actual production code use. */
|
|
29
30
|
z_debug_forceOpenState: boolean;
|
|
30
31
|
} & PopUpTriggerPosition>, {
|
|
31
32
|
/** `undefined` means the pop up is not currently showing. */
|
|
32
33
|
showPopUpResult: ShowPopUpResult | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Used to couple the label and trigger together. This is not applied if no label is
|
|
36
|
+
* provided.
|
|
37
|
+
*/
|
|
38
|
+
randomId: string;
|
|
33
39
|
}, {
|
|
34
40
|
selectedChange: import("element-vir").DefineEvent<string[]>;
|
|
35
41
|
openChange: import("element-vir").DefineEvent<ShowPopUpResult | undefined>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { check } from '@augment-vir/assert';
|
|
2
|
-
import { filterMap } from '@augment-vir/common';
|
|
2
|
+
import { filterMap, randomString } from '@augment-vir/common';
|
|
3
3
|
import { classMap, css, defineElementEvent, html, ifDefined, listen, nothing, testId, } from 'element-vir';
|
|
4
4
|
import { ChevronUp16Icon } from '../icons/index.js';
|
|
5
5
|
import { viraFormCssVars } from '../styles/form-styles.js';
|
|
@@ -92,6 +92,22 @@ export const ViraDropdown = defineViraElement()({
|
|
|
92
92
|
.using-placeholder {
|
|
93
93
|
opacity: 0.4;
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
label {
|
|
97
|
+
display: flex;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
justify-content: flex-start;
|
|
100
|
+
gap: 2px;
|
|
101
|
+
width: 100%;
|
|
102
|
+
max-width: 100%;
|
|
103
|
+
|
|
104
|
+
& .dropdown-label {
|
|
105
|
+
font-weight: ${viraFormCssVars['vira-form-label-font-weight'].value};
|
|
106
|
+
text-align: left;
|
|
107
|
+
flex-shrink: 0;
|
|
108
|
+
flex-wrap: wrap;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
95
111
|
`,
|
|
96
112
|
events: {
|
|
97
113
|
selectedChange: defineElementEvent(),
|
|
@@ -101,6 +117,11 @@ export const ViraDropdown = defineViraElement()({
|
|
|
101
117
|
return {
|
|
102
118
|
/** `undefined` means the pop up is not currently showing. */
|
|
103
119
|
showPopUpResult: undefined,
|
|
120
|
+
/**
|
|
121
|
+
* Used to couple the label and trigger together. This is not applied if no label is
|
|
122
|
+
* provided.
|
|
123
|
+
*/
|
|
124
|
+
randomId: randomString(32),
|
|
104
125
|
};
|
|
105
126
|
},
|
|
106
127
|
render({ state, inputs, dispatch, events, updateState, testIds }) {
|
|
@@ -133,7 +154,7 @@ export const ViraDropdown = defineViraElement()({
|
|
|
133
154
|
? ViraMenuPopUpDirection.Downwards
|
|
134
155
|
: ViraMenuPopUpDirection.Upwards,
|
|
135
156
|
})}
|
|
136
|
-
slot=${ViraPopUpTrigger.slotNames
|
|
157
|
+
slot=${ViraPopUpTrigger.slotNames['vira-pop-up-trigger-pop-up']}
|
|
137
158
|
>
|
|
138
159
|
${renderMenuItemEntries(inputs.options.map((option) => {
|
|
139
160
|
return {
|
|
@@ -147,7 +168,7 @@ export const ViraDropdown = defineViraElement()({
|
|
|
147
168
|
}))}
|
|
148
169
|
</${ViraMenu}>
|
|
149
170
|
`;
|
|
150
|
-
|
|
171
|
+
const triggerTemplate = html `
|
|
151
172
|
<${ViraPopUpTrigger.assign({
|
|
152
173
|
...inputs,
|
|
153
174
|
focusOnClose: true,
|
|
@@ -171,7 +192,9 @@ export const ViraDropdown = defineViraElement()({
|
|
|
171
192
|
open: !!state.showPopUpResult,
|
|
172
193
|
'open-upwards': !state.showPopUpResult?.popDown,
|
|
173
194
|
})}"
|
|
174
|
-
slot=${ViraPopUpTrigger.slotNames
|
|
195
|
+
slot=${ViraPopUpTrigger.slotNames['vira-pop-up-trigger-trigger']}
|
|
196
|
+
id=${ifDefined(inputs.label ? state.randomId : undefined)}
|
|
197
|
+
aria-label=${ifDefined(inputs.label || undefined)}
|
|
175
198
|
${testId(testIds.trigger)}
|
|
176
199
|
>
|
|
177
200
|
${leadingIconTemplate}
|
|
@@ -195,5 +218,16 @@ export const ViraDropdown = defineViraElement()({
|
|
|
195
218
|
${state.showPopUpResult ? menuTemplate : nothing}
|
|
196
219
|
</${ViraPopUpTrigger}>
|
|
197
220
|
`;
|
|
221
|
+
if (inputs.label) {
|
|
222
|
+
return html `
|
|
223
|
+
<label for=${state.randomId}>
|
|
224
|
+
<span class="dropdown-label">${inputs.label}</span>
|
|
225
|
+
${triggerTemplate}
|
|
226
|
+
</label>
|
|
227
|
+
`;
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
return triggerTemplate;
|
|
231
|
+
}
|
|
198
232
|
},
|
|
199
233
|
});
|
|
@@ -11,7 +11,7 @@ import { type Duration, type DurationUnit } from 'date-vir';
|
|
|
11
11
|
* @category Elements
|
|
12
12
|
* @see https://electrovir.github.io/vira/book/elements/vira-image
|
|
13
13
|
*/
|
|
14
|
-
export declare const ViraImage: import("element-vir").DeclarativeElementDefinition
|
|
14
|
+
export declare const ViraImage: import("element-vir").DeclarativeElementDefinition<`vira-${string}`, {
|
|
15
15
|
/** The URL of the image to load. This is passed directly to the `<img>` element. */
|
|
16
16
|
imageUrl: string;
|
|
17
17
|
/**
|
|
@@ -42,4 +42,4 @@ export declare const ViraImage: import("element-vir").DeclarativeElementDefiniti
|
|
|
42
42
|
}, {
|
|
43
43
|
imageLoad: import("element-vir").DefineEvent<void>;
|
|
44
44
|
imageError: import("element-vir").DefineEvent<unknown>;
|
|
45
|
-
}, "vira-image-height-constrained",
|
|
45
|
+
}, "vira-image-height-constrained", `vira-${string}-`, readonly ["vira-image-loading", "vira-image-error"], readonly []>;
|
|
@@ -34,8 +34,8 @@ export const ViraImage = defineViraElement()({
|
|
|
34
34
|
'vira-image-height-constrained': ({ inputs }) => inputs.dominantDimension === 'height',
|
|
35
35
|
},
|
|
36
36
|
slotNames: [
|
|
37
|
-
'loading',
|
|
38
|
-
'error',
|
|
37
|
+
'vira-image-loading',
|
|
38
|
+
'vira-image-error',
|
|
39
39
|
],
|
|
40
40
|
events: {
|
|
41
41
|
imageLoad: defineElementEvent(),
|
|
@@ -96,7 +96,7 @@ export const ViraImage = defineViraElement()({
|
|
|
96
96
|
const imageUrl = inputs.imageUrl;
|
|
97
97
|
const statusTemplate = state.erroredUrls[imageUrl]
|
|
98
98
|
? html `
|
|
99
|
-
<slot class="status-wrapper" name=${slotNames
|
|
99
|
+
<slot class="status-wrapper" name=${slotNames['vira-image-error']}>
|
|
100
100
|
<${ViraIcon.assign({
|
|
101
101
|
icon: StatusFailure24Icon,
|
|
102
102
|
})}
|
|
@@ -107,7 +107,7 @@ export const ViraImage = defineViraElement()({
|
|
|
107
107
|
: state.loadedUrls[imageUrl]
|
|
108
108
|
? undefined
|
|
109
109
|
: html `
|
|
110
|
-
<slot class="status-wrapper" name=${slotNames
|
|
110
|
+
<slot class="status-wrapper" name=${slotNames['vira-image-loading']}>
|
|
111
111
|
<${ViraIcon.assign({
|
|
112
112
|
icon: LoaderAnimated24Icon,
|
|
113
113
|
})}></${ViraIcon}>
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { assertWrap, check } from '@augment-vir/assert';
|
|
2
2
|
import { omitObjectKeys, wrapInTry } from '@augment-vir/common';
|
|
3
|
-
import { extractEventTarget } from '@augment-vir/web';
|
|
4
3
|
import { css, defineElementEvent, html, listen, nothing } from 'element-vir';
|
|
5
|
-
import {
|
|
4
|
+
import { Plus16Icon, X16Icon } from '../icons/index.js';
|
|
6
5
|
import { viraFontCssVars } from '../styles/font.js';
|
|
7
6
|
import { viraFormCssVars } from '../styles/form-styles.js';
|
|
8
7
|
import { ViraColorVariant, ViraEmphasis, ViraSize } from '../styles/form-variants.js';
|
|
@@ -13,6 +12,7 @@ import { ViraCheckbox } from './vira-checkbox.element.js';
|
|
|
13
12
|
import { ViraError } from './vira-error.element.js';
|
|
14
13
|
import { ViraInput, ViraInputType } from './vira-input.element.js';
|
|
15
14
|
import { ViraSelect } from './vira-select.element.js';
|
|
15
|
+
import { ViraTextArea } from './vira-text-area.element.js';
|
|
16
16
|
/**
|
|
17
17
|
* An editor for arbitrary JSON values, optionally constrained by a standard JSON Schema
|
|
18
18
|
* ({@link ViraJsonSchema}).
|
|
@@ -48,24 +48,10 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
48
48
|
justify-content: flex-end;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
.json-raw-textarea {
|
|
52
|
-
|
|
53
|
-
padding: 10px 12px;
|
|
54
|
-
border: 1px solid ${viraFormCssVars['vira-form-border-color'].value};
|
|
55
|
-
border-radius: ${viraFormCssVars['vira-form-wrapper-radius'].value};
|
|
56
|
-
background-color: ${viraFormCssVars['vira-form-background-color'].value};
|
|
57
|
-
color: ${viraFormCssVars['vira-form-foreground-color'].value};
|
|
51
|
+
${ViraTextArea}.json-raw-textarea {
|
|
52
|
+
width: 100%;
|
|
58
53
|
font-family: ${viraFontCssVars['vira-monospace'].value};
|
|
59
54
|
font-size: ${viraFormCssVars['vira-form-small-text-size'].value};
|
|
60
|
-
box-sizing: border-box;
|
|
61
|
-
width: 100%;
|
|
62
|
-
min-height: 240px;
|
|
63
|
-
resize: vertical;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.json-raw-textarea:focus {
|
|
67
|
-
outline: none;
|
|
68
|
-
border-color: ${viraFormCssVars['vira-form-focus-outline-color'].value};
|
|
69
55
|
}
|
|
70
56
|
|
|
71
57
|
.json-validation-errors {
|
|
@@ -80,68 +66,71 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
80
66
|
}
|
|
81
67
|
|
|
82
68
|
.json-group {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
padding: 10px 12px;
|
|
87
|
-
border: 1px solid ${viraFormCssVars['vira-form-border-color'].value};
|
|
88
|
-
border-radius: ${viraFormCssVars['vira-form-wrapper-radius'].value};
|
|
89
|
-
background-color: ${viraFormCssVars['vira-form-background-color'].value};
|
|
69
|
+
border-collapse: separate;
|
|
70
|
+
border-spacing: 0;
|
|
71
|
+
width: 100%;
|
|
90
72
|
box-sizing: border-box;
|
|
91
73
|
}
|
|
92
74
|
|
|
93
|
-
.json-group-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
75
|
+
.json-group-nested {
|
|
76
|
+
margin-top: 4px;
|
|
77
|
+
padding-left: 12px;
|
|
78
|
+
padding-bottom: 8px;
|
|
79
|
+
border-left: 2px solid ${viraFormCssVars['vira-form-border-color'].value};
|
|
80
|
+
border-bottom: 2px solid ${viraFormCssVars['vira-form-border-color'].value};
|
|
97
81
|
}
|
|
98
82
|
|
|
99
|
-
.json-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
color: ${viraFormCssVars['vira-form-secondary-body-foreground'].value};
|
|
103
|
-
font-size: ${viraFormCssVars['vira-form-small-text-size'].value};
|
|
83
|
+
.json-row-primitive > td {
|
|
84
|
+
padding: 4px 8px 4px 0;
|
|
85
|
+
vertical-align: middle;
|
|
104
86
|
}
|
|
105
87
|
|
|
106
|
-
.json-row {
|
|
107
|
-
|
|
108
|
-
gap: 8px;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.json-row-primitive {
|
|
112
|
-
align-items: center;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.json-row-nested {
|
|
116
|
-
flex-direction: column;
|
|
117
|
-
align-items: stretch;
|
|
118
|
-
gap: 4px;
|
|
88
|
+
.json-row-primitive > td:last-child {
|
|
89
|
+
padding-right: 0;
|
|
119
90
|
}
|
|
120
91
|
|
|
121
|
-
.json-row-label {
|
|
122
|
-
|
|
92
|
+
td.json-row-label {
|
|
93
|
+
text-align: left;
|
|
123
94
|
min-width: 80px;
|
|
95
|
+
white-space: nowrap;
|
|
124
96
|
font-weight: ${viraFormCssVars['vira-form-label-font-weight'].value};
|
|
125
|
-
word-break: break-word;
|
|
126
97
|
}
|
|
127
98
|
|
|
128
|
-
.json-row-editor {
|
|
129
|
-
|
|
130
|
-
min-width: 0;
|
|
131
|
-
display: flex;
|
|
132
|
-
flex-direction: column;
|
|
99
|
+
td.json-row-editor {
|
|
100
|
+
width: 100%;
|
|
133
101
|
}
|
|
134
102
|
|
|
135
|
-
.json-row-editor > * {
|
|
103
|
+
td.json-row-editor > * {
|
|
136
104
|
width: 100%;
|
|
137
105
|
max-width: 100%;
|
|
106
|
+
box-sizing: border-box;
|
|
138
107
|
}
|
|
139
108
|
|
|
140
|
-
.json-row-delete {
|
|
141
|
-
flex-shrink: 0;
|
|
109
|
+
td.json-row-delete {
|
|
142
110
|
width: 24px;
|
|
111
|
+
text-align: center;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.json-row-nested > td {
|
|
115
|
+
padding: 4px 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.json-row-nested-header {
|
|
143
119
|
display: flex;
|
|
144
|
-
|
|
120
|
+
align-items: center;
|
|
121
|
+
gap: 8px;
|
|
122
|
+
margin-bottom: 4px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.json-row-nested-header > .json-row-label {
|
|
126
|
+
flex-grow: 1;
|
|
127
|
+
font-weight: ${viraFormCssVars['vira-form-label-font-weight'].value};
|
|
128
|
+
word-break: break-word;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.json-type-tag {
|
|
132
|
+
font-weight: normal;
|
|
133
|
+
color: ${viraFormCssVars['vira-form-secondary-body-foreground'].value};
|
|
145
134
|
}
|
|
146
135
|
|
|
147
136
|
.json-value-with-switcher {
|
|
@@ -169,8 +158,10 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
169
158
|
.json-add-row {
|
|
170
159
|
display: flex;
|
|
171
160
|
align-items: center;
|
|
161
|
+
justify-content: flex-end;
|
|
172
162
|
gap: 6px;
|
|
173
163
|
flex-wrap: wrap;
|
|
164
|
+
padding: 8px 0;
|
|
174
165
|
}
|
|
175
166
|
|
|
176
167
|
.json-add-row ${ViraInput}, .json-add-row ${ViraSelect} {
|
|
@@ -190,6 +181,8 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
190
181
|
}
|
|
191
182
|
|
|
192
183
|
.json-empty-note {
|
|
184
|
+
display: block;
|
|
185
|
+
padding: 4px 0;
|
|
193
186
|
color: ${viraFormCssVars['vira-form-placeholder-color'].value};
|
|
194
187
|
font-style: italic;
|
|
195
188
|
font-size: ${viraFormCssVars['vira-form-small-text-size'].value};
|
|
@@ -392,8 +385,9 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
392
385
|
function renderPlusButton({ isAddDisabled, tooltip, onClick, }) {
|
|
393
386
|
return html `
|
|
394
387
|
<${ViraButton.assign({
|
|
395
|
-
icon:
|
|
396
|
-
color: ViraColorVariant.
|
|
388
|
+
icon: Plus16Icon,
|
|
389
|
+
color: ViraColorVariant.Positive,
|
|
390
|
+
buttonSize: ViraSize.Small,
|
|
397
391
|
isDisabled: isAddDisabled,
|
|
398
392
|
})}
|
|
399
393
|
title=${tooltip}
|
|
@@ -406,7 +400,7 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
406
400
|
></${ViraButton}>
|
|
407
401
|
`;
|
|
408
402
|
}
|
|
409
|
-
function renderObjectAddControl({ pathKey, allowedTypes, canAdd, onAdd, }) {
|
|
403
|
+
function renderObjectAddControl({ pathKey, allowedTypes, canAdd, disabledReason, onAdd, }) {
|
|
410
404
|
if (allowedTypes.length === 0) {
|
|
411
405
|
return nothing;
|
|
412
406
|
}
|
|
@@ -415,7 +409,7 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
415
409
|
const onlyType = assertWrap.isDefined(allowedTypes[0]);
|
|
416
410
|
return renderPlusButton({
|
|
417
411
|
isAddDisabled,
|
|
418
|
-
tooltip: `Add ${viraJsonTypeLabels[onlyType]}`,
|
|
412
|
+
tooltip: isAddDisabled ? disabledReason : `Add ${viraJsonTypeLabels[onlyType]}`,
|
|
419
413
|
onClick: () => onAdd(onlyType),
|
|
420
414
|
});
|
|
421
415
|
}
|
|
@@ -437,7 +431,9 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
437
431
|
></${ViraSelect}>
|
|
438
432
|
${renderPlusButton({
|
|
439
433
|
isAddDisabled,
|
|
440
|
-
tooltip:
|
|
434
|
+
tooltip: isAddDisabled
|
|
435
|
+
? disabledReason
|
|
436
|
+
: `Add ${viraJsonTypeLabels[selectedType]}`,
|
|
441
437
|
onClick: () => onAdd(selectedType),
|
|
442
438
|
})}
|
|
443
439
|
`;
|
|
@@ -497,8 +493,14 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
497
493
|
})}
|
|
498
494
|
`;
|
|
499
495
|
}
|
|
500
|
-
function
|
|
496
|
+
function getNestedTypeLabel(schema, value) {
|
|
497
|
+
const concreteType = getJsonType(value);
|
|
498
|
+
const narrowedSchema = pickBranchForType(schema, concreteType, resolveContext);
|
|
499
|
+
return (getSchemaTitle(narrowedSchema, resolveContext) || viraJsonTypeLabels[concreteType]);
|
|
500
|
+
}
|
|
501
|
+
function renderObjectGroup(path, value, schema) {
|
|
501
502
|
const pathKey = pathToKey(path);
|
|
503
|
+
const isRoot = path.length === 0;
|
|
502
504
|
const requiredKeys = new Set(getRequiredProperties(schema, resolveContext));
|
|
503
505
|
const definedProperties = getDefinedProperties(schema, resolveContext);
|
|
504
506
|
const definedKeys = new Set(Object.keys(definedProperties));
|
|
@@ -524,20 +526,34 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
524
526
|
}
|
|
525
527
|
}
|
|
526
528
|
: undefined;
|
|
529
|
+
if (isChildNested) {
|
|
530
|
+
return html `
|
|
531
|
+
<tr class="json-row-nested">
|
|
532
|
+
<td colspan="3">
|
|
533
|
+
<div class="json-row-nested-header">
|
|
534
|
+
<span class="json-row-label">
|
|
535
|
+
${key}${isRequired ? '*' : ''}
|
|
536
|
+
<span class="json-type-tag">
|
|
537
|
+
: ${getNestedTypeLabel(childSchema, childValue)}
|
|
538
|
+
</span>
|
|
539
|
+
</span>
|
|
540
|
+
${childOnDelete ? renderDeleteButton(childOnDelete) : nothing}
|
|
541
|
+
</div>
|
|
542
|
+
${renderValue(childPath, childValue, childSchema)}
|
|
543
|
+
</td>
|
|
544
|
+
</tr>
|
|
545
|
+
`;
|
|
546
|
+
}
|
|
527
547
|
return html `
|
|
528
|
-
<
|
|
529
|
-
class="json-row
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
? renderDeleteButton(childOnDelete)
|
|
538
|
-
: nothing}
|
|
539
|
-
</span>
|
|
540
|
-
</div>
|
|
548
|
+
<tr class="json-row-primitive">
|
|
549
|
+
<td class="json-row-label">${key}${isRequired ? '*' : ''}</td>
|
|
550
|
+
<td class="json-row-editor">
|
|
551
|
+
${renderValue(childPath, childValue, childSchema)}
|
|
552
|
+
</td>
|
|
553
|
+
<td class="json-row-delete">
|
|
554
|
+
${childOnDelete ? renderDeleteButton(childOnDelete) : nothing}
|
|
555
|
+
</td>
|
|
556
|
+
</tr>
|
|
541
557
|
`;
|
|
542
558
|
});
|
|
543
559
|
const missingDefinedKeys = [...definedKeys].filter((key) => !(key in value));
|
|
@@ -550,8 +566,9 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
550
566
|
return html `
|
|
551
567
|
<${ViraButton.assign({
|
|
552
568
|
text: `"${key}"`,
|
|
553
|
-
icon:
|
|
554
|
-
color: ViraColorVariant.
|
|
569
|
+
icon: Plus16Icon,
|
|
570
|
+
color: ViraColorVariant.Positive,
|
|
571
|
+
buttonSize: ViraSize.Small,
|
|
555
572
|
})}
|
|
556
573
|
${listen('click', () => {
|
|
557
574
|
emitReplaceAt([
|
|
@@ -568,21 +585,27 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
568
585
|
const additionalAllowedTypes = additional.allowed
|
|
569
586
|
? getAllowedJsonTypes(additional.schema, resolveContext)
|
|
570
587
|
: [];
|
|
588
|
+
const arbitraryAddDisabledReason = trimmedPendingKey
|
|
589
|
+
? `Field "${trimmedPendingKey}" already exists.`
|
|
590
|
+
: 'Enter a field name to add.';
|
|
571
591
|
const arbitraryAddRow = additional.allowed && !isDisabled
|
|
572
592
|
? html `
|
|
573
|
-
<
|
|
574
|
-
|
|
593
|
+
<tr>
|
|
594
|
+
<td colspan="3">
|
|
595
|
+
<div class="json-add-row">
|
|
596
|
+
<${ViraInput.assign({
|
|
575
597
|
value: pendingKey,
|
|
576
598
|
placeholder: 'new field name',
|
|
577
599
|
})}
|
|
578
|
-
|
|
600
|
+
${listen(ViraInput.events.valueChange, (event) => {
|
|
579
601
|
setPendingKey(pathKey, event.detail);
|
|
580
602
|
})}
|
|
581
|
-
|
|
582
|
-
|
|
603
|
+
></${ViraInput}>
|
|
604
|
+
${renderObjectAddControl({
|
|
583
605
|
pathKey,
|
|
584
606
|
allowedTypes: additionalAllowedTypes,
|
|
585
607
|
canAdd: canAddArbitraryField,
|
|
608
|
+
disabledReason: arbitraryAddDisabledReason,
|
|
586
609
|
onAdd: (type) => {
|
|
587
610
|
if (!canAddArbitraryField) {
|
|
588
611
|
return;
|
|
@@ -594,33 +617,41 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
594
617
|
clearPending(pathKey);
|
|
595
618
|
},
|
|
596
619
|
})}
|
|
597
|
-
|
|
620
|
+
</div>
|
|
621
|
+
</td>
|
|
622
|
+
</tr>
|
|
598
623
|
`
|
|
599
624
|
: nothing;
|
|
600
|
-
const title = getSchemaTitle(schema, resolveContext) || 'object';
|
|
601
625
|
return html `
|
|
602
|
-
<
|
|
603
|
-
<
|
|
604
|
-
|
|
605
|
-
${onDelete ? renderDeleteButton(onDelete) : nothing}
|
|
606
|
-
</div>
|
|
607
|
-
${rowTemplates.length === 0 && suggestedKeyButtons.length === 0
|
|
626
|
+
<table class="json-group ${isRoot ? '' : 'json-group-nested'}">
|
|
627
|
+
<tbody>
|
|
628
|
+
${rowTemplates.length === 0 && suggestedKeyButtons.length === 0
|
|
608
629
|
? html `
|
|
609
|
-
|
|
610
|
-
|
|
630
|
+
<tr>
|
|
631
|
+
<td colspan="3">
|
|
632
|
+
<span class="json-empty-note">(empty object)</span>
|
|
633
|
+
</td>
|
|
634
|
+
</tr>
|
|
635
|
+
`
|
|
611
636
|
: nothing}
|
|
612
|
-
|
|
613
|
-
|
|
637
|
+
${rowTemplates}
|
|
638
|
+
${suggestedKeyButtons.length > 0
|
|
614
639
|
? html `
|
|
615
|
-
|
|
616
|
-
|
|
640
|
+
<tr>
|
|
641
|
+
<td colspan="3">
|
|
642
|
+
<div class="json-add-row">${suggestedKeyButtons}</div>
|
|
643
|
+
</td>
|
|
644
|
+
</tr>
|
|
645
|
+
`
|
|
617
646
|
: nothing}
|
|
618
|
-
|
|
619
|
-
|
|
647
|
+
${arbitraryAddRow}
|
|
648
|
+
</tbody>
|
|
649
|
+
</table>
|
|
620
650
|
`;
|
|
621
651
|
}
|
|
622
|
-
function renderArrayGroup(path, value, schema
|
|
652
|
+
function renderArrayGroup(path, value, schema) {
|
|
623
653
|
const pathKey = pathToKey(path);
|
|
654
|
+
const isRoot = path.length === 0;
|
|
624
655
|
const newItemSchema = getNewItemSchema(schema, value.length, resolveContext);
|
|
625
656
|
const allowedItemTypes = getAllowedJsonTypes(newItemSchema, resolveContext);
|
|
626
657
|
const rowTemplates = value.map((item, index) => {
|
|
@@ -636,28 +667,43 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
636
667
|
: () => {
|
|
637
668
|
emitDeleteAt(childPath);
|
|
638
669
|
};
|
|
670
|
+
if (isChildNested) {
|
|
671
|
+
return html `
|
|
672
|
+
<tr class="json-row-nested">
|
|
673
|
+
<td colspan="3">
|
|
674
|
+
<div class="json-row-nested-header">
|
|
675
|
+
<span class="json-row-label">
|
|
676
|
+
[${index}]
|
|
677
|
+
<span class="json-type-tag">
|
|
678
|
+
: ${getNestedTypeLabel(childSchema, item)}
|
|
679
|
+
</span>
|
|
680
|
+
</span>
|
|
681
|
+
${childOnDelete ? renderDeleteButton(childOnDelete) : nothing}
|
|
682
|
+
</div>
|
|
683
|
+
${renderValue(childPath, item, childSchema)}
|
|
684
|
+
</td>
|
|
685
|
+
</tr>
|
|
686
|
+
`;
|
|
687
|
+
}
|
|
639
688
|
return html `
|
|
640
|
-
<
|
|
641
|
-
class="json-row
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
? renderDeleteButton(childOnDelete)
|
|
650
|
-
: nothing}
|
|
651
|
-
</span>
|
|
652
|
-
</div>
|
|
689
|
+
<tr class="json-row-primitive">
|
|
690
|
+
<td class="json-row-label">[${index}]</td>
|
|
691
|
+
<td class="json-row-editor">
|
|
692
|
+
${renderValue(childPath, item, childSchema)}
|
|
693
|
+
</td>
|
|
694
|
+
<td class="json-row-delete">
|
|
695
|
+
${childOnDelete ? renderDeleteButton(childOnDelete) : nothing}
|
|
696
|
+
</td>
|
|
697
|
+
</tr>
|
|
653
698
|
`;
|
|
654
699
|
});
|
|
655
|
-
const title = getSchemaTitle(schema, resolveContext) || 'array';
|
|
656
700
|
const addRow = isDisabled
|
|
657
701
|
? nothing
|
|
658
702
|
: html `
|
|
659
|
-
<
|
|
660
|
-
|
|
703
|
+
<tr>
|
|
704
|
+
<td colspan="3">
|
|
705
|
+
<div class="json-add-row">
|
|
706
|
+
${renderArrayAddControl({
|
|
661
707
|
pathKey,
|
|
662
708
|
allowedTypes: allowedItemTypes,
|
|
663
709
|
onAdd: (newValue) => {
|
|
@@ -667,32 +713,36 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
667
713
|
], newValue);
|
|
668
714
|
},
|
|
669
715
|
})}
|
|
670
|
-
|
|
716
|
+
</div>
|
|
717
|
+
</td>
|
|
718
|
+
</tr>
|
|
671
719
|
`;
|
|
672
720
|
return html `
|
|
673
|
-
<
|
|
674
|
-
<
|
|
675
|
-
|
|
676
|
-
${onDelete ? renderDeleteButton(onDelete) : nothing}
|
|
677
|
-
</div>
|
|
678
|
-
${rowTemplates.length === 0
|
|
721
|
+
<table class="json-group ${isRoot ? '' : 'json-group-nested'}">
|
|
722
|
+
<tbody>
|
|
723
|
+
${rowTemplates.length === 0
|
|
679
724
|
? html `
|
|
680
|
-
|
|
681
|
-
|
|
725
|
+
<tr>
|
|
726
|
+
<td colspan="3">
|
|
727
|
+
<span class="json-empty-note">(empty array)</span>
|
|
728
|
+
</td>
|
|
729
|
+
</tr>
|
|
730
|
+
`
|
|
682
731
|
: nothing}
|
|
683
|
-
|
|
684
|
-
|
|
732
|
+
${rowTemplates} ${addRow}
|
|
733
|
+
</tbody>
|
|
734
|
+
</table>
|
|
685
735
|
`;
|
|
686
736
|
}
|
|
687
|
-
function renderValue(path, value, schema
|
|
737
|
+
function renderValue(path, value, schema) {
|
|
688
738
|
const concreteType = getJsonType(value);
|
|
689
739
|
const allowedTypes = getAllowedJsonTypes(schema, resolveContext);
|
|
690
740
|
const narrowedSchema = pickBranchForType(schema, concreteType, resolveContext);
|
|
691
741
|
if (check.isArray(value)) {
|
|
692
|
-
return renderArrayGroup(path, value, narrowedSchema
|
|
742
|
+
return renderArrayGroup(path, value, narrowedSchema);
|
|
693
743
|
}
|
|
694
744
|
else if (check.isObject(value)) {
|
|
695
|
-
return renderObjectGroup(path, value, narrowedSchema
|
|
745
|
+
return renderObjectGroup(path, value, narrowedSchema);
|
|
696
746
|
}
|
|
697
747
|
const editor = renderPrimitive(path, value, narrowedSchema);
|
|
698
748
|
const showSwitcher = !isDisabled &&
|
|
@@ -752,14 +802,15 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
752
802
|
const rawText = state.rawDraft ?? JSON.stringify(inputs.value, undefined, 4);
|
|
753
803
|
return html `
|
|
754
804
|
${toolbarTemplate}
|
|
755
|
-
|
|
805
|
+
<${ViraTextArea.assign({
|
|
806
|
+
value: rawText,
|
|
807
|
+
disabled: isDisabled,
|
|
808
|
+
disableBrowserHelps: true,
|
|
809
|
+
rows: 12,
|
|
810
|
+
})}
|
|
756
811
|
class="json-raw-textarea"
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
.value=${rawText}
|
|
760
|
-
${listen('input', (event) => {
|
|
761
|
-
const textarea = extractEventTarget(event, HTMLTextAreaElement);
|
|
762
|
-
const text = textarea.value;
|
|
812
|
+
${listen(ViraTextArea.events.valueChange, (event) => {
|
|
813
|
+
const text = event.detail;
|
|
763
814
|
const parsed = wrapInTry(() => JSON.parse(text));
|
|
764
815
|
if (parsed instanceof Error) {
|
|
765
816
|
updateState({
|
|
@@ -775,7 +826,7 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
775
826
|
emitRoot(parsed);
|
|
776
827
|
}
|
|
777
828
|
})}
|
|
778
|
-
|
|
829
|
+
></${ViraTextArea}>
|
|
779
830
|
${state.rawError
|
|
780
831
|
? html `
|
|
781
832
|
<${ViraError}>${state.rawError}</${ViraError}>
|
|
@@ -800,7 +851,7 @@ export const ViraJsonForm = defineViraElement()({
|
|
|
800
851
|
`;
|
|
801
852
|
}
|
|
802
853
|
return html `
|
|
803
|
-
${toolbarTemplate} ${renderValue([], inputs.value, inputs.schema
|
|
854
|
+
${toolbarTemplate} ${renderValue([], inputs.value, inputs.schema)}
|
|
804
855
|
`;
|
|
805
856
|
},
|
|
806
857
|
});
|
|
@@ -5,7 +5,7 @@ import { type PartialWithUndefined } from '@augment-vir/common';
|
|
|
5
5
|
* @category Elements
|
|
6
6
|
* @see https://electrovir.github.io/vira/book/elements/vira-modal
|
|
7
7
|
*/
|
|
8
|
-
export declare const ViraModal: import("element-vir").DeclarativeElementDefinition
|
|
8
|
+
export declare const ViraModal: import("element-vir").DeclarativeElementDefinition<`vira-${string}`, {
|
|
9
9
|
open: boolean;
|
|
10
10
|
} & PartialWithUndefined<{
|
|
11
11
|
/** If this isn't set, make sure to use the modal title slot to fill it in. */
|
|
@@ -37,4 +37,4 @@ export declare const ViraModal: import("element-vir").DeclarativeElementDefiniti
|
|
|
37
37
|
cleanupListeners: undefined | (() => void);
|
|
38
38
|
}, {
|
|
39
39
|
modalClose: import("element-vir").DefineEvent<void>;
|
|
40
|
-
}, "vira-modal-phone-size" | "vira-modal-no-content-padding", "vira-modal-backdrop-filter", readonly ["
|
|
40
|
+
}, "vira-modal-phone-size" | "vira-modal-no-content-padding", "vira-modal-backdrop-filter", readonly ["vira-modal-modal-title"], readonly []>;
|
|
@@ -42,7 +42,7 @@ export const ViraModal = defineViraElement()({
|
|
|
42
42
|
'vira-modal-phone-size': ({ inputs }) => !!inputs.isMobileSize,
|
|
43
43
|
'vira-modal-no-content-padding': ({ inputs }) => !!inputs.noContentPadding,
|
|
44
44
|
},
|
|
45
|
-
slotNames: ['
|
|
45
|
+
slotNames: ['vira-modal-modal-title'],
|
|
46
46
|
cssVars: {
|
|
47
47
|
'vira-modal-backdrop-filter': 'blur(3px)',
|
|
48
48
|
},
|
|
@@ -205,7 +205,11 @@ export const ViraModal = defineViraElement()({
|
|
|
205
205
|
>
|
|
206
206
|
<div class="header">
|
|
207
207
|
<div class="header-text-wrapper">
|
|
208
|
-
<h1
|
|
208
|
+
<h1>
|
|
209
|
+
<slot name=${slotNames['vira-modal-modal-title']}>
|
|
210
|
+
${inputs.modalTitle}
|
|
211
|
+
</slot>
|
|
212
|
+
</h1>
|
|
209
213
|
${inputs.modalSubtitle
|
|
210
214
|
? html `
|
|
211
215
|
<sub>${inputs.modalSubtitle}</sub>
|
|
@@ -13,6 +13,7 @@ import { createOverflowObserver } from '../util/overflow-observer.js';
|
|
|
13
13
|
import { renderMenuItemEntries } from '../util/pop-up-helpers.js';
|
|
14
14
|
import { ViraMenuTrigger } from './pop-up/vira-menu-trigger.element.js';
|
|
15
15
|
import { ViraMenuCornerStyle } from './pop-up/vira-menu.element.js';
|
|
16
|
+
import { ViraBoldText } from './vira-bold-text.element.js';
|
|
16
17
|
import { ViraButton } from './vira-button.element.js';
|
|
17
18
|
import { ViraIcon } from './vira-icon.element.js';
|
|
18
19
|
import { ViraLink } from './vira-link.element.js';
|
|
@@ -387,7 +388,12 @@ export const ViraTabs = defineViraElement()({
|
|
|
387
388
|
})}>
|
|
388
389
|
<span class="tab-content">
|
|
389
390
|
${iconTemplate}
|
|
390
|
-
|
|
391
|
+
<${ViraBoldText.assign({
|
|
392
|
+
text: tab.label,
|
|
393
|
+
bold: isSelected,
|
|
394
|
+
})}
|
|
395
|
+
class="tab-label"
|
|
396
|
+
></${ViraBoldText}>
|
|
391
397
|
</span>
|
|
392
398
|
</${ViraLink}>
|
|
393
399
|
</li>
|
|
@@ -441,7 +447,7 @@ export const ViraTabs = defineViraElement()({
|
|
|
441
447
|
showMenuCaret: true,
|
|
442
448
|
color: ViraColorVariant.Neutral,
|
|
443
449
|
})}
|
|
444
|
-
slot=${ViraMenuTrigger.slotNames
|
|
450
|
+
slot=${ViraMenuTrigger.slotNames['vira-menu-trigger-trigger']}
|
|
445
451
|
></${ViraButton}>
|
|
446
452
|
${menuItems}
|
|
447
453
|
</${ViraMenuTrigger}>
|
|
@@ -454,6 +460,7 @@ export const ViraTabs = defineViraElement()({
|
|
|
454
460
|
cleanupObserver: createOverflowObserver({
|
|
455
461
|
element: tabsElement,
|
|
456
462
|
widthElement: host,
|
|
463
|
+
hysteresisPx: 16,
|
|
457
464
|
onChange(isOverflowing) {
|
|
458
465
|
updateState({
|
|
459
466
|
isOverflowing,
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { html } from 'element-vir';
|
|
2
|
-
import { viraIconCssVars } from '
|
|
3
|
-
import { defineIcon } from '
|
|
2
|
+
import { viraIconCssVars } from '../../icon-css-vars.js';
|
|
3
|
+
import { defineIcon } from '../../icon-svg.js';
|
|
4
4
|
/**
|
|
5
5
|
* A plus icon.
|
|
6
6
|
*
|
|
7
7
|
* @category Icon
|
|
8
8
|
* @category SVG
|
|
9
|
-
* @see https://electrovir.github.io/vira/book/icons/
|
|
9
|
+
* @see https://electrovir.github.io/vira/book/icons/plus16icon
|
|
10
10
|
*/
|
|
11
|
-
export const
|
|
12
|
-
name: '
|
|
11
|
+
export const Plus16Icon = defineIcon({
|
|
12
|
+
name: 'Plus16Icon',
|
|
13
13
|
svgTemplate: html `
|
|
14
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
14
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
|
15
15
|
<path
|
|
16
|
-
d="
|
|
16
|
+
d="M8 3v10M3 8h10"
|
|
17
17
|
fill="none"
|
|
18
18
|
stroke=${viraIconCssVars['vira-icon-stroke-color'].value}
|
|
19
19
|
stroke-width=${viraIconCssVars['vira-icon-stroke-width'].value}
|
package/dist/icons/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from './icon-svgs/16/chevron-down-16.icon.js';
|
|
|
8
8
|
export * from './icon-svgs/16/chevron-up-16.icon.js';
|
|
9
9
|
export * from './icon-svgs/16/dash-16.icon.js';
|
|
10
10
|
export * from './icon-svgs/16/element-16.icon.js';
|
|
11
|
+
export * from './icon-svgs/16/plus-16.icon.js';
|
|
11
12
|
export * from './icon-svgs/16/upload-16.icon.js';
|
|
12
13
|
export * from './icon-svgs/16/x-16.icon.js';
|
|
13
14
|
export * from './icon-svgs/24/arrow-down-24.icon.js';
|
|
@@ -100,6 +101,7 @@ export declare const allIconsByName: {
|
|
|
100
101
|
readonly Moon24Icon: import("./icon-svg.js").ViraIconSvg;
|
|
101
102
|
readonly Options24Icon: import("./icon-svg.js").ViraIconSvg;
|
|
102
103
|
readonly Pencil24Icon: import("./icon-svg.js").ViraIconSvg;
|
|
104
|
+
readonly Plus16Icon: import("./icon-svg.js").ViraIconSvg;
|
|
103
105
|
readonly Plus24Icon: import("./icon-svg.js").ViraIconSvg;
|
|
104
106
|
readonly Printer24Icon: import("./icon-svg.js").ViraIconSvg;
|
|
105
107
|
readonly Shield24Icon: import("./icon-svg.js").ViraIconSvg;
|
|
@@ -189,6 +191,7 @@ export declare const all16IconsByName: {
|
|
|
189
191
|
readonly ChevronUp16Icon: import("./icon-svg.js").ViraIconSvg;
|
|
190
192
|
readonly Dash16Icon: import("./icon-svg.js").ViraIconSvg;
|
|
191
193
|
readonly Element16Icon: import("./icon-svg.js").ViraIconSvg;
|
|
194
|
+
readonly Plus16Icon: import("./icon-svg.js").ViraIconSvg;
|
|
192
195
|
readonly Upload16Icon: import("./icon-svg.js").ViraIconSvg;
|
|
193
196
|
readonly X16Icon: import("./icon-svg.js").ViraIconSvg;
|
|
194
197
|
};
|
package/dist/icons/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { ChevronDown16Icon } from './icon-svgs/16/chevron-down-16.icon.js';
|
|
|
3
3
|
import { ChevronUp16Icon } from './icon-svgs/16/chevron-up-16.icon.js';
|
|
4
4
|
import { Dash16Icon } from './icon-svgs/16/dash-16.icon.js';
|
|
5
5
|
import { Element16Icon } from './icon-svgs/16/element-16.icon.js';
|
|
6
|
+
import { Plus16Icon } from './icon-svgs/16/plus-16.icon.js';
|
|
6
7
|
import { Upload16Icon } from './icon-svgs/16/upload-16.icon.js';
|
|
7
8
|
import { X16Icon } from './icon-svgs/16/x-16.icon.js';
|
|
8
9
|
import { ArrowDown24Icon } from './icon-svgs/24/arrow-down-24.icon.js';
|
|
@@ -64,6 +65,7 @@ export * from './icon-svgs/16/chevron-down-16.icon.js';
|
|
|
64
65
|
export * from './icon-svgs/16/chevron-up-16.icon.js';
|
|
65
66
|
export * from './icon-svgs/16/dash-16.icon.js';
|
|
66
67
|
export * from './icon-svgs/16/element-16.icon.js';
|
|
68
|
+
export * from './icon-svgs/16/plus-16.icon.js';
|
|
67
69
|
export * from './icon-svgs/16/upload-16.icon.js';
|
|
68
70
|
export * from './icon-svgs/16/x-16.icon.js';
|
|
69
71
|
export * from './icon-svgs/24/arrow-down-24.icon.js';
|
|
@@ -156,6 +158,7 @@ export const allIconsByName = {
|
|
|
156
158
|
Moon24Icon,
|
|
157
159
|
Options24Icon,
|
|
158
160
|
Pencil24Icon,
|
|
161
|
+
Plus16Icon,
|
|
159
162
|
Plus24Icon,
|
|
160
163
|
Printer24Icon,
|
|
161
164
|
Shield24Icon,
|
|
@@ -245,6 +248,7 @@ export const all16IconsByName = {
|
|
|
245
248
|
ChevronUp16Icon,
|
|
246
249
|
Dash16Icon,
|
|
247
250
|
Element16Icon,
|
|
251
|
+
Plus16Icon,
|
|
248
252
|
Upload16Icon,
|
|
249
253
|
X16Icon,
|
|
250
254
|
};
|
|
@@ -4,7 +4,7 @@ import { wrapDefineElement } from 'element-vir';
|
|
|
4
4
|
*
|
|
5
5
|
* @category Internal
|
|
6
6
|
*/
|
|
7
|
-
export const ViraTagNamePrefix =
|
|
7
|
+
export const ViraTagNamePrefix = 'vira-';
|
|
8
8
|
/**
|
|
9
9
|
* Define a vira element with custom requirements (like the `vira-` element tag prefix).
|
|
10
10
|
*
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @returns A cleanup function that disconnects all observers.
|
|
6
6
|
*/
|
|
7
|
-
export declare function createOverflowObserver({ element, widthElement, onChange, }: Readonly<{
|
|
7
|
+
export declare function createOverflowObserver({ element, widthElement, onChange, hysteresisPx, }: Readonly<{
|
|
8
8
|
/** The element whose `scrollWidth` is measured for content size. */
|
|
9
9
|
element: Element;
|
|
10
10
|
/**
|
|
@@ -14,4 +14,11 @@ export declare function createOverflowObserver({ element, widthElement, onChange
|
|
|
14
14
|
*/
|
|
15
15
|
widthElement?: Element | undefined;
|
|
16
16
|
onChange: (isOverflowing: boolean) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Pixel margin required to flip the overflow state. Once overflowing, the content must fit
|
|
19
|
+
* within `availableWidth - hysteresisPx` to flip back; once not overflowing, the content must
|
|
20
|
+
* exceed `availableWidth + hysteresisPx` to flip on. Prevents rapid toggling from minute size
|
|
21
|
+
* changes.
|
|
22
|
+
*/
|
|
23
|
+
hysteresisPx?: number | undefined;
|
|
17
24
|
}>): () => void;
|
|
@@ -4,10 +4,18 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @returns A cleanup function that disconnects all observers.
|
|
6
6
|
*/
|
|
7
|
-
export function createOverflowObserver({ element, widthElement, onChange, }) {
|
|
7
|
+
export function createOverflowObserver({ element, widthElement, onChange, hysteresisPx = 0, }) {
|
|
8
8
|
const availableWidthElement = widthElement || element;
|
|
9
|
+
let isOverflowing = false;
|
|
9
10
|
function checkOverflow() {
|
|
10
|
-
|
|
11
|
+
const contentWidth = element.scrollWidth;
|
|
12
|
+
const availableWidth = availableWidthElement.clientWidth;
|
|
13
|
+
const threshold = isOverflowing ? -hysteresisPx : hysteresisPx;
|
|
14
|
+
const nextOverflowing = contentWidth > availableWidth + threshold;
|
|
15
|
+
if (nextOverflowing !== isOverflowing) {
|
|
16
|
+
isOverflowing = nextOverflowing;
|
|
17
|
+
onChange(isOverflowing);
|
|
18
|
+
}
|
|
11
19
|
}
|
|
12
20
|
const resizeObserver = new ResizeObserver(checkOverflow);
|
|
13
21
|
resizeObserver.observe(element);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vira",
|
|
3
|
-
"version": "31.
|
|
3
|
+
"version": "31.19.0",
|
|
4
4
|
"description": "A simple and highly versatile design system using element-vir.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"test:docs": "virmator docs check"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@augment-vir/assert": "^31.
|
|
42
|
-
"@augment-vir/common": "^31.
|
|
43
|
-
"@augment-vir/web": "^31.
|
|
41
|
+
"@augment-vir/assert": "^31.70.1",
|
|
42
|
+
"@augment-vir/common": "^31.70.1",
|
|
43
|
+
"@augment-vir/web": "^31.70.1",
|
|
44
44
|
"@electrovir/color": "^1.7.9",
|
|
45
45
|
"date-vir": "^8.3.2",
|
|
46
46
|
"device-navigation": "^4.5.5",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"lit-css-vars": "^3.6.2",
|
|
49
49
|
"observavir": "^2.3.2",
|
|
50
50
|
"page-active": "^1.0.3",
|
|
51
|
-
"spa-router-vir": "^6.
|
|
51
|
+
"spa-router-vir": "^6.6.0",
|
|
52
52
|
"type-fest": "^5.6.0",
|
|
53
53
|
"typed-event-target": "^4.3.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@augment-vir/test": "^31.
|
|
56
|
+
"@augment-vir/test": "^31.70.1",
|
|
57
57
|
"@web/dev-server-esbuild": "^1.0.5",
|
|
58
58
|
"@web/test-runner": "^0.20.2",
|
|
59
59
|
"@web/test-runner-commands": "^0.9.0",
|
|
@@ -61,12 +61,12 @@
|
|
|
61
61
|
"@web/test-runner-visual-regression": "^0.10.0",
|
|
62
62
|
"esbuild": "^0.28.0",
|
|
63
63
|
"istanbul-smart-text-reporter": "^1.1.5",
|
|
64
|
-
"lucide-static": "^1.
|
|
64
|
+
"lucide-static": "^1.16.0",
|
|
65
65
|
"markdown-code-example-inserter": "^3.0.5",
|
|
66
66
|
"theme-vir": "^28.25.0",
|
|
67
67
|
"typedoc": "^0.28.19",
|
|
68
68
|
"typescript": "5.9.3",
|
|
69
|
-
"vite": "^8.0.
|
|
69
|
+
"vite": "^8.0.14",
|
|
70
70
|
"vite-tsconfig-paths": "^6.1.1"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|