vueless 0.0.603 → 0.0.604
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/composables/useUI.ts +57 -27
- package/directives/tooltip/vTooltip.ts +0 -1
- package/package.json +1 -1
- package/ui.container-modal-confirm/UModalConfirm.vue +3 -1
- package/ui.data-list/UDataList.vue +1 -1
- package/ui.data-table/UTable.vue +1 -1
- package/ui.data-table/config.ts +1 -9
- package/ui.data-table/storybook/stories.ts +4 -4
- package/ui.data-table/types.ts +1 -10
- package/ui.dropdown-list/UDropdownList.vue +1 -1
- package/ui.form-calendar/UCalendar.vue +1 -1
- package/ui.form-date-picker/UDatePicker.vue +2 -2
- package/ui.form-date-picker-range/UDatePickerRange.vue +1 -1
- package/ui.form-date-picker-range/useLocale.ts +3 -1
- package/ui.form-input-file/UInputFile.vue +1 -1
- package/ui.form-select/USelect.vue +1 -1
- package/ui.form-switch/USwitch.vue +1 -1
- package/ui.loader-progress/ULoaderProgress.vue +1 -1
- package/ui.loader-progress/types.ts +5 -0
- package/ui.text-money/config.ts +0 -1
- package/ui.text-notify/UNotify.vue +1 -1
- package/utils/node/loaderIcon.js +1 -1
- package/utils/ui.ts +4 -4
- package/web-types.json +10 -1
package/composables/useUI.ts
CHANGED
|
@@ -93,6 +93,8 @@ export default function useUI<T>(
|
|
|
93
93
|
classes = cx([classes, attrs.class]);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
classes = classes.replaceAll(EXTENDS_PATTERN_REG_EXP, "");
|
|
97
|
+
|
|
96
98
|
return color ? setColor(classes, color) : classes;
|
|
97
99
|
});
|
|
98
100
|
}
|
|
@@ -118,12 +120,12 @@ export default function useUI<T>(
|
|
|
118
120
|
* Get an element attributes for a given key.
|
|
119
121
|
*/
|
|
120
122
|
function getAttrs(configKey: string, classes: ComputedRef<string>) {
|
|
121
|
-
const
|
|
123
|
+
const vuelessAttrs = ref({});
|
|
122
124
|
|
|
123
125
|
const attrs = useAttrs() as KeyAttrs;
|
|
124
126
|
const isDev = isCSR && import.meta.env?.DEV;
|
|
125
|
-
const vuelessAttrs = ref({});
|
|
126
127
|
const isTopLevelKey = (topLevelClassKey || firstClassKey) === configKey;
|
|
128
|
+
const nestedComponent = getNestedComponent(config.value[configKey] || "");
|
|
127
129
|
|
|
128
130
|
const commonAttrs: KeyAttrs = {
|
|
129
131
|
...(isTopLevelKey ? attrs : {}),
|
|
@@ -139,32 +141,25 @@ export default function useUI<T>(
|
|
|
139
141
|
|
|
140
142
|
watch(config, updateVuelessAttrs, { immediate: true });
|
|
141
143
|
watch(props, updateVuelessAttrs);
|
|
144
|
+
watch(classes, updateVuelessAttrs);
|
|
142
145
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Updating Vueless attributes.
|
|
148
|
+
*/
|
|
147
149
|
function updateVuelessAttrs() {
|
|
148
150
|
let configAttr: NestedComponent = {};
|
|
149
|
-
let extendsConfigAttr: NestedComponent = {};
|
|
150
|
-
let extendsClasses: string[] = [];
|
|
151
|
-
|
|
152
|
-
const baseClasses = getBaseClasses(config.value[configKey]);
|
|
153
|
-
const extendsKeys = getExtendsKeys(baseClasses);
|
|
154
151
|
|
|
155
152
|
if (typeof config.value[configKey] === "object") {
|
|
156
153
|
configAttr = config.value[configKey] as NestedComponent;
|
|
157
154
|
}
|
|
158
155
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
extendsConfigAttr = getExtendsConfig(extendsKeys);
|
|
162
|
-
}
|
|
156
|
+
const extendsClasses = getExtendsClasses(configKey);
|
|
157
|
+
const extendsConfigAttr = getExtendsConfigAttr(configKey);
|
|
163
158
|
|
|
164
159
|
vuelessAttrs.value = {
|
|
165
160
|
...commonAttrs,
|
|
166
|
-
class: cx([...extendsClasses, toValue(classes)
|
|
167
|
-
config: merge(configAttr, extendsConfigAttr),
|
|
161
|
+
class: cx([...extendsClasses, toValue(classes)]),
|
|
162
|
+
config: merge({}, configAttr, extendsConfigAttr),
|
|
168
163
|
...getDefaults({
|
|
169
164
|
...(configAttr.defaults || {}),
|
|
170
165
|
...(extendsConfigAttr.defaults || {}),
|
|
@@ -172,21 +167,51 @@ export default function useUI<T>(
|
|
|
172
167
|
};
|
|
173
168
|
}
|
|
174
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Recursively get extends classes.
|
|
172
|
+
*/
|
|
173
|
+
function getExtendsClasses(configKey: string) {
|
|
174
|
+
let extendsClasses: string[] = [];
|
|
175
|
+
|
|
176
|
+
const extendsKeys = getExtendsKeys(config.value[configKey]);
|
|
177
|
+
|
|
178
|
+
if (extendsKeys.length) {
|
|
179
|
+
extendsKeys.forEach((key) => {
|
|
180
|
+
extendsClasses = [
|
|
181
|
+
...extendsClasses,
|
|
182
|
+
...getExtendsClasses(key),
|
|
183
|
+
toValue(getClasses(key, mutatedProps)),
|
|
184
|
+
];
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return extendsClasses;
|
|
189
|
+
}
|
|
190
|
+
|
|
175
191
|
/**
|
|
176
192
|
* Merge extends nested component configs.
|
|
177
193
|
* TODO: Add ability to merge multiple keys in one (now works for merging only 1 first key).
|
|
178
194
|
*/
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
195
|
+
function getExtendsConfigAttr(configKey: string) {
|
|
196
|
+
let extendsConfigAttr: NestedComponent = {};
|
|
197
|
+
|
|
198
|
+
const extendsKeys = getExtendsKeys(config.value[configKey]);
|
|
199
|
+
|
|
200
|
+
if (extendsKeys.length) {
|
|
201
|
+
const [firstKey] = extendsKeys;
|
|
202
|
+
|
|
203
|
+
extendsConfigAttr = getMergedConfig({
|
|
204
|
+
defaultConfig: config.value[firstKey],
|
|
205
|
+
globalConfig: globalConfig[firstKey],
|
|
206
|
+
propsConfig: propsConfig[firstKey],
|
|
207
|
+
}) as NestedComponent;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return extendsConfigAttr;
|
|
187
211
|
}
|
|
188
212
|
|
|
189
213
|
/**
|
|
214
|
+
* Get component prop default value.
|
|
190
215
|
* Conditionally set props default value for nested components based on parent component prop value.
|
|
191
216
|
* For example, set icon size for the nested component based on the size of the parent component.
|
|
192
217
|
* Use an object where key = parent component prop value, value = nested component prop value.
|
|
@@ -221,7 +246,8 @@ function getBaseClasses(value: string | CVA | undefined) {
|
|
|
221
246
|
* Retrieves extends keys from patterns:
|
|
222
247
|
* Example: `{>someKey} {>someOtherKey}` >>> `["someKey", "someOtherKey"]`.
|
|
223
248
|
*/
|
|
224
|
-
function getExtendsKeys(
|
|
249
|
+
function getExtendsKeys(configItemValue?: CVA | string): string[] {
|
|
250
|
+
const values = getBaseClasses(configItemValue);
|
|
225
251
|
const matches = values.match(EXTENDS_PATTERN_REG_EXP);
|
|
226
252
|
|
|
227
253
|
return matches ? matches?.map((pattern) => pattern.slice(2, -1)) : [];
|
|
@@ -249,7 +275,11 @@ function isSystemKey(key: string): boolean {
|
|
|
249
275
|
/**
|
|
250
276
|
* Check is config contains default CVA keys.
|
|
251
277
|
*/
|
|
252
|
-
function isCVA(config
|
|
278
|
+
function isCVA(config?: UnknownObject | string): boolean {
|
|
279
|
+
if (typeof config !== "object") {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
|
|
253
283
|
return Object.values(CVA_CONFIG_KEY).some((value) =>
|
|
254
284
|
Object.keys(config).some((key) => key === value),
|
|
255
285
|
);
|
package/package.json
CHANGED
|
@@ -49,7 +49,9 @@ const isShownModal = computed({
|
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
const i18nGlobal = tm(UModalConfirm);
|
|
52
|
-
const currentLocale = computed(() =>
|
|
52
|
+
const currentLocale = computed(() =>
|
|
53
|
+
merge({}, defaultConfig.i18n, i18nGlobal, props?.config?.i18n),
|
|
54
|
+
);
|
|
53
55
|
|
|
54
56
|
function closeModal() {
|
|
55
57
|
isShownModal.value = false;
|
|
@@ -48,7 +48,7 @@ const emit = defineEmits([
|
|
|
48
48
|
const { tm } = useLocale();
|
|
49
49
|
|
|
50
50
|
const i18nGlobal = tm(UDataListName);
|
|
51
|
-
const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
51
|
+
const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
52
52
|
|
|
53
53
|
const iconSize = computed(() => {
|
|
54
54
|
const sizes = {
|
package/ui.data-table/UTable.vue
CHANGED
|
@@ -96,7 +96,7 @@ const stickyActionHeaderRowRef = useTemplateRef<HTMLDivElement>("sticky-action-h
|
|
|
96
96
|
const actionHeaderRowRef = useTemplateRef<HTMLDivElement>("action-header-row");
|
|
97
97
|
|
|
98
98
|
const i18nGlobal = tm(UTable);
|
|
99
|
-
const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
99
|
+
const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
100
100
|
|
|
101
101
|
const sortedRows: ComputedRef<Row[]> = computed(() => {
|
|
102
102
|
const headerKeys = props.columns.map((column) =>
|
package/ui.data-table/config.ts
CHANGED
|
@@ -40,14 +40,7 @@ export default /*tw*/ {
|
|
|
40
40
|
},
|
|
41
41
|
headerCellCheckbox: "{>headerCellBase} w-10 pr-2",
|
|
42
42
|
headerCheckbox: "{UCheckbox}",
|
|
43
|
-
headerCounter: {
|
|
44
|
-
base: "{>headerCounterBase} absolute top-4 mt-px left-11 ml-px",
|
|
45
|
-
variants: {
|
|
46
|
-
compact: {
|
|
47
|
-
true: "top-3",
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
},
|
|
43
|
+
headerCounter: "{>stickyHeaderCounter} mt-px ml-px",
|
|
51
44
|
headerLoader: "{ULoaderProgress} absolute !top-auto",
|
|
52
45
|
body: "group/body divide-none",
|
|
53
46
|
bodyRow: "hover:bg-gray-50",
|
|
@@ -108,7 +101,6 @@ export default /*tw*/ {
|
|
|
108
101
|
},
|
|
109
102
|
defaults: {
|
|
110
103
|
emptyCellLabel: "—",
|
|
111
|
-
nesting: false,
|
|
112
104
|
compact: false,
|
|
113
105
|
selectable: false,
|
|
114
106
|
dateDivider: false,
|
|
@@ -39,12 +39,12 @@ export default {
|
|
|
39
39
|
argTypes: {
|
|
40
40
|
...getArgTypes(UTable.__name),
|
|
41
41
|
row: {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
table: {
|
|
43
|
+
disable: true,
|
|
44
|
+
},
|
|
44
45
|
},
|
|
45
46
|
numberOfRows: {
|
|
46
|
-
description:
|
|
47
|
-
"The number of table rows. It's not a prop (it created for ease of work with storybook).",
|
|
47
|
+
description: "The number of table rows (not a component prop).",
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
50
|
args: {
|
package/ui.data-table/types.ts
CHANGED
|
@@ -5,16 +5,7 @@ import type { ComponentConfig, UnknownObject } from "../types.ts";
|
|
|
5
5
|
|
|
6
6
|
export type Config = typeof defaultConfig;
|
|
7
7
|
|
|
8
|
-
type RowKeys =
|
|
9
|
-
| number
|
|
10
|
-
| string
|
|
11
|
-
| boolean
|
|
12
|
-
| undefined
|
|
13
|
-
| Date
|
|
14
|
-
| Row
|
|
15
|
-
| Row[]
|
|
16
|
-
| string
|
|
17
|
-
| ((row: Row) => string);
|
|
8
|
+
type RowKeys = number | string | boolean | undefined | Date | Row | Row[] | ((row: Row) => string);
|
|
18
9
|
|
|
19
10
|
export interface CellObject {
|
|
20
11
|
contentClasses?: string | ((value: unknown | string, row: Row) => string);
|
|
@@ -54,7 +54,7 @@ const elementId = props.id || useId();
|
|
|
54
54
|
const { tm } = useLocale();
|
|
55
55
|
|
|
56
56
|
const i18nGlobal = tm(UDropdownList);
|
|
57
|
-
const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
57
|
+
const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
58
58
|
|
|
59
59
|
const addOptionKeyCombination = computed(() => {
|
|
60
60
|
return isMac ? "(⌘ + Enter)" : "(Ctrl + Enter)";
|
|
@@ -129,7 +129,7 @@ const isCurrentView = computed(() => ({
|
|
|
129
129
|
const i18nGlobal = tm<DefaultLocale>(UCalendar);
|
|
130
130
|
|
|
131
131
|
const currentLocale: ComputedRef<Locale> = computed(() =>
|
|
132
|
-
merge(defaultConfig.i18n, i18nGlobal, props.config?.i18n),
|
|
132
|
+
merge({}, defaultConfig.i18n, i18nGlobal, props.config?.i18n),
|
|
133
133
|
);
|
|
134
134
|
|
|
135
135
|
const locale = computed(() => {
|
|
@@ -82,7 +82,7 @@ const localValue = computed({
|
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
const currentLocale: ComputedRef<Locale> = computed(() =>
|
|
85
|
-
merge(defaultConfig.i18n, i18nGlobal, props.config.i18n),
|
|
85
|
+
merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n),
|
|
86
86
|
);
|
|
87
87
|
|
|
88
88
|
const clickOutsideOptions = computed(() => ({ ignore: [datepickerInputRef.value?.inputRef] }));
|
|
@@ -268,7 +268,7 @@ watchEffect(() => {
|
|
|
268
268
|
const calendarConfig = datepickerCalendarAttrs.value.config as unknown as UCalendarConfig;
|
|
269
269
|
|
|
270
270
|
if (!calendarConfig?.i18n || props.config?.i18n) {
|
|
271
|
-
calendarConfig.i18n = merge(calendarConfig.i18n, config.value.i18n);
|
|
271
|
+
calendarConfig.i18n = merge({}, calendarConfig.i18n, config.value.i18n);
|
|
272
272
|
}
|
|
273
273
|
});
|
|
274
274
|
</script>
|
|
@@ -573,7 +573,7 @@ watchEffect(() => {
|
|
|
573
573
|
const calendarConfig = datepickerCalendarAttrs.value.config as unknown as UCalendarConfig;
|
|
574
574
|
|
|
575
575
|
if (!calendarConfig.i18n || props.config?.i18n) {
|
|
576
|
-
calendarConfig.i18n = merge(calendarConfig.i18n, config.value.i18n);
|
|
576
|
+
calendarConfig.i18n = merge({}, calendarConfig.i18n, config.value.i18n);
|
|
577
577
|
}
|
|
578
578
|
});
|
|
579
579
|
</script>
|
|
@@ -15,7 +15,9 @@ export function useLocale(props: UDatePickerRangeProps<unknown>) {
|
|
|
15
15
|
|
|
16
16
|
const i18nGlobal = tm<Locale>(UDatePickerRange);
|
|
17
17
|
|
|
18
|
-
const currentLocale = computed(() =>
|
|
18
|
+
const currentLocale = computed(() =>
|
|
19
|
+
merge({}, defaultConfig.i18n, i18nGlobal, props.config?.i18n),
|
|
20
|
+
);
|
|
19
21
|
|
|
20
22
|
const locale = computed(() => {
|
|
21
23
|
const { months, weekdays } = currentLocale.value;
|
|
@@ -50,7 +50,7 @@ const fileInputRef = ref<HTMLInputElement | null>(null);
|
|
|
50
50
|
const elementId = props.id || useId();
|
|
51
51
|
|
|
52
52
|
const i18nGlobal = tm(UInputFile);
|
|
53
|
-
const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
53
|
+
const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
54
54
|
|
|
55
55
|
const currentFiles = computed<File | File[] | null>({
|
|
56
56
|
get: () => props.modelValue,
|
|
@@ -97,7 +97,7 @@ const innerWrapperRef = ref<HTMLDivElement | null>(null);
|
|
|
97
97
|
const elementId = props.id || useId();
|
|
98
98
|
|
|
99
99
|
const i18nGlobal = tm(USelect);
|
|
100
|
-
const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
100
|
+
const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
101
101
|
|
|
102
102
|
const isTop = computed(() => {
|
|
103
103
|
if (props.openDirection === DIRECTION.top) return true;
|
|
@@ -33,7 +33,7 @@ const emit = defineEmits([
|
|
|
33
33
|
const { tm } = useLocale();
|
|
34
34
|
|
|
35
35
|
const i18nGlobal = tm(USwitch);
|
|
36
|
-
const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config?.i18n));
|
|
36
|
+
const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config?.i18n));
|
|
37
37
|
|
|
38
38
|
const checkedValue = computed({
|
|
39
39
|
get: () => props.modelValue,
|
|
@@ -213,6 +213,6 @@ const { stripeAttrs } = useUI<Config>(defaultConfig);
|
|
|
213
213
|
|
|
214
214
|
<template>
|
|
215
215
|
<Transition :css="false" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
|
|
216
|
-
<div v-if="show" v-bind="stripeAttrs" :style="barStyle" />
|
|
216
|
+
<div v-if="show" v-bind="stripeAttrs" :data-test="dataTest" :style="barStyle" />
|
|
217
217
|
</Transition>
|
|
218
218
|
</template>
|
package/ui.text-money/config.ts
CHANGED
|
@@ -27,7 +27,7 @@ const notifyPositionStyles = ref({});
|
|
|
27
27
|
const notificationsWrapperRef = ref<NotificationsWrapperRef | null>(null);
|
|
28
28
|
|
|
29
29
|
const i18nGlobal = tm(UNotify);
|
|
30
|
-
const currentLocale = computed(() => merge(defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
30
|
+
const currentLocale = computed(() => merge({}, defaultConfig.i18n, i18nGlobal, props.config.i18n));
|
|
31
31
|
|
|
32
32
|
onMounted(() => {
|
|
33
33
|
window.addEventListener("resize", setPosition, { passive: true });
|
package/utils/node/loaderIcon.js
CHANGED
|
@@ -311,5 +311,5 @@ async function getDefaults() {
|
|
|
311
311
|
const defaultConfigPath = path.join(cwd, defaultIconsDir, COMPONENTS[U_ICON], "config.ts");
|
|
312
312
|
const uIconDefaultConfig = await getComponentDefaultConfig(U_ICON, defaultConfigPath);
|
|
313
313
|
|
|
314
|
-
return merge(uIconDefaultConfig?.defaults, vuelessConfig?.component?.[U_ICON]?.defaults);
|
|
314
|
+
return merge({}, uIconDefaultConfig?.defaults, vuelessConfig?.component?.[U_ICON]?.defaults);
|
|
315
315
|
}
|
package/utils/ui.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { merge } from "lodash-es";
|
|
2
2
|
import { defineConfig } from "cva";
|
|
3
3
|
import { extendTailwindMerge } from "tailwind-merge";
|
|
4
|
-
import {
|
|
4
|
+
import { isCSR, isSSR } from "./helper.ts";
|
|
5
5
|
import { createGetMergedConfig } from "./node/mergeConfigs.js";
|
|
6
6
|
import { UIcon } from "../ui.image-icon/constants.ts";
|
|
7
7
|
import {
|
|
@@ -99,10 +99,10 @@ export const cva = ({ base = "", variants = {}, compoundVariants = [], defaultVa
|
|
|
99
99
|
* Return default values for component props, icons, etc..
|
|
100
100
|
*/
|
|
101
101
|
export function getDefaults<Props, Config>(defaultConfig: Config, name: ComponentNames) {
|
|
102
|
-
const componentDefaults =
|
|
103
|
-
const globalDefaults =
|
|
102
|
+
const componentDefaults = (defaultConfig as UnknownObject).defaults || {};
|
|
103
|
+
const globalDefaults = vuelessConfig.component?.[name]?.defaults || {};
|
|
104
104
|
|
|
105
|
-
const defaults = merge(componentDefaults, globalDefaults) as Props & Defaults;
|
|
105
|
+
const defaults = merge({}, componentDefaults, globalDefaults) as Props & Defaults;
|
|
106
106
|
|
|
107
107
|
if (defaults.color) {
|
|
108
108
|
defaults.color = getColor(defaults.color as BrandColors);
|
package/web-types.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"framework": "vue",
|
|
3
3
|
"name": "vueless",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.604",
|
|
5
5
|
"contributions": {
|
|
6
6
|
"html": {
|
|
7
7
|
"description-markup": "markdown",
|
|
@@ -7858,6 +7858,15 @@
|
|
|
7858
7858
|
"kind": "expression",
|
|
7859
7859
|
"type": "ComponentConfig"
|
|
7860
7860
|
}
|
|
7861
|
+
},
|
|
7862
|
+
{
|
|
7863
|
+
"name": "dataTest",
|
|
7864
|
+
"required": false,
|
|
7865
|
+
"description": "Data-test attribute for automated testing.",
|
|
7866
|
+
"value": {
|
|
7867
|
+
"kind": "expression",
|
|
7868
|
+
"type": "string"
|
|
7869
|
+
}
|
|
7861
7870
|
}
|
|
7862
7871
|
],
|
|
7863
7872
|
"source": {
|