Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/core/src/util/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ const resolveSchemaWithSegments = (
return undefined;
}

if (schema.$ref) {
// use typeof because schema can by of any type - check singleSegmentResolveSchema below
if (typeof schema.$ref === 'string') {
schema = resolveSchema(rootSchema, schema.$ref, rootSchema);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vue-vuetify/dev/components/ExampleAppBar.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { useAppStore } from '../store';
import JsonFormsLogo from '../assets/JsonFormsLogo.vue';
import { useAppStore } from '../store';
import ThemeChanger from './ThemeChanger.vue';

const appStore = useAppStore();
Expand Down
18 changes: 17 additions & 1 deletion packages/vue-vuetify/dev/components/ExampleDrawer.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import VuetifyLogo from '../assets/VuetifyLogo.vue';
import examples from '../examples';
import { useAppStore } from '../store';
Expand All @@ -8,6 +9,15 @@ const appStore = useAppStore();
const handleExampleClick = (exampleName: string) => {
appStore.exampleName = exampleName;
};
const search = ref(''); // Search term

const filteredExamples = computed(() => {
return examples.filter(
(example) =>
example.name.toLowerCase().includes(search.value.toLowerCase()) ||
example.label.toLowerCase().includes(search.value.toLowerCase()),
);
});
</script>

<template>
Expand All @@ -26,8 +36,14 @@ const handleExampleClick = (exampleName: string) => {
<v-divider></v-divider>

<v-list dense nav>
<v-text-field
v-model="search"
append-inner-icon="mdi-magnify"
density="compact"
label="Search examples"
/>
<v-list-item
v-for="example in examples"
v-for="example in filteredExamples"
:key="example.name"
:value="example.name"
link
Expand Down
4 changes: 2 additions & 2 deletions packages/vue-vuetify/dev/components/ExampleForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from '@jsonforms/vue';
import type { Ajv, ErrorObject } from 'ajv';
import * as JsonRefs from 'json-refs';
import { computed, onMounted, reactive, watch } from 'vue';
import { computed, onMounted, shallowReactive, watch } from 'vue';

export type ResolvedSchema = {
schema?: JsonSchema;
Expand Down Expand Up @@ -44,7 +44,7 @@ const props = defineProps<{
state: JsonFormsProps;
}>();

const resolvedSchema = reactive<ResolvedSchema>({
const resolvedSchema = shallowReactive<ResolvedSchema>({
schema: undefined,
resolved: false,
error: undefined,
Expand Down
31 changes: 30 additions & 1 deletion packages/vue-vuetify/dev/components/ExampleSettings.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { useAppStore } from '../store';
import { appstoreLayouts, useAppStore, type AppstoreLayouts } from '../store';

const appStore = useAppStore();

Expand Down Expand Up @@ -53,6 +53,16 @@ const iconsets = [
{ text: 'Material Design', value: 'mdi' },
{ text: 'Font Awesome', value: 'fa' },
];

const layoutMapping: Record<AppstoreLayouts, string> = {
'': 'Default',
'demo-and-data': 'Demo and Data',
};

const layouts = appstoreLayouts.map((value: AppstoreLayouts) => ({
text: layoutMapping[value] ?? value,
value: value,
}));
</script>

<template>
Expand Down Expand Up @@ -174,6 +184,25 @@ const iconsets = [

<v-divider />

<v-container>
<v-row><v-col>Demo Layout</v-col></v-row>
<v-row>
<v-col>
<v-select
outlined
persistent-hint
dense
v-model="appStore.layout"
:items="layouts"
item-title="text"
item-value="value"
></v-select>
</v-col>
</v-row>
</v-container>

<v-divider />

<v-container>
<v-row><v-col>Blueprints (need browser reload)</v-col></v-row>
<v-row>
Expand Down
103 changes: 87 additions & 16 deletions packages/vue-vuetify/dev/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import type { ValidationMode } from '@jsonforms/core';
import { reactive, ref, watch } from 'vue';
import { reactive, ref, watch, type Ref, type UnwrapRef } from 'vue';

export const appstoreLayouts = ['', 'demo-and-data'] as const;
export type AppstoreLayouts = (typeof appstoreLayouts)[number];

const appstore = reactive({
exampleName: useHistoryHash(''),
rtl: false,
formOnly: false,
layout: useLocalStorage('vuetify-example-layout', ''),
formOnly: useHistoryHashQuery('form-only', false as boolean),
activeTab: useHistoryHashQuery('active-tab', 0 as number),
dark: useLocalStorage('vuetify-example-dark', false),
theme: useLocalStorage('vuetify-example-theme', 'light'),
drawer: true,
drawer: useHistoryHashQuery('drawer', true as boolean),
settings: false,
variant: useLocalStorage('vuetify-example-variant', ''),
iconset: useLocalStorage('vuetify-example-iconset', 'mdi'),
blueprint: useLocalStorage('vuetify-example-blueprint', 'md1'),
jsonforms: {
readonly: false,
readonly: useHistoryHashQuery('read-only', false as boolean),
validationMode: 'ValidateAndShow' as ValidationMode,
config: {
restrict: true,
Expand All @@ -26,7 +31,6 @@ const appstore = reactive({
hideAvatar: false,
hideArraySummaryValidation: false,
enableFilterErrorsBeforeTouch: false,
vuetify: {},
},
locale: useLocalStorage('vuetify-example-locale', 'en'),
},
Expand All @@ -36,12 +40,13 @@ export const useAppStore = () => {
return appstore;
};

export function useHistoryHash(initialValue: string) {
function useHistoryHash(initialValue: string) {
const data = ref(initialValue);

// Function to update data based on URL hash
const updateDataFromHash = () => {
const hash = window.location.hash.slice(1);
const hashAndQuery = window.location.hash.slice(1); // Remove the leading '#'
const [hash, _] = hashAndQuery.split('?'); // Split hash and query string
if (hash) {
try {
data.value = decodeURIComponent(hash);
Expand All @@ -51,17 +56,83 @@ export function useHistoryHash(initialValue: string) {
}
};

// Update data from URL hash on component mount
// Initial update from URL hash
updateDataFromHash();

watch(
data,
(newValue) => {
const encodedData = encodeURIComponent(newValue);
window.history.replaceState(null, '', `#${encodedData}`);
},
{ deep: true },
);
watch(data, (newValue) => {
const encodedData = encodeURIComponent(newValue);

const currentHash = window.location.hash.slice(1);
const [, currentQueryString] = currentHash.split('?'); // Extract the query part after ?

window.history.replaceState(
null,
'',
`#${encodedData}${currentQueryString ? '?' + currentQueryString : ''}`, // Keep the query parameters intact
);
});

return data;
}

function useHistoryHashQuery<T extends string | boolean | number>(
queryParam: string,
initialValue: T,
) {
const data: Ref<UnwrapRef<T>> = ref<T>(initialValue);

// Function to update data based on URL hash
const updateDataFromHash = () => {
const hashAndQuery = window.location.hash.slice(1); // Remove the leading '#'
const [_, query] = hashAndQuery.split('?'); // Split hash and query string

const searchParams = new URLSearchParams(query);
if (searchParams) {
try {
const value = searchParams.has(queryParam)
? searchParams.get(queryParam)
: `${initialValue}`;

// Convert the value based on the type of initialValue
if (typeof initialValue === 'boolean') {
// Handle boolean conversion
data.value = (value === 'true') as UnwrapRef<T>;
} else if (typeof initialValue === 'number') {
data.value = (value ? parseFloat(value) : 0) as UnwrapRef<T>;
} else if (typeof initialValue === 'string') {
// Handle string conversion
data.value = value as UnwrapRef<T>;
}
} catch (error) {
console.error('Error parsing hash:', error);
}
}
};

// Initial update from URL hash
updateDataFromHash();

watch(data, (newValue) => {
const encodedData = encodeURIComponent(newValue);

const hashAndQuery = window.location.hash.slice(1); // Remove the leading '#'
const [hash, query] = hashAndQuery.split('?'); // Split hash and query string

const searchParams = new URLSearchParams(query);

if (newValue === initialValue) {
// it is the default value so no need to preserve the query paramter
searchParams.delete(queryParam);
} else {
searchParams.set(queryParam, encodedData);
}

window.history.replaceState(
null,
'',
`#${hash}${searchParams.size > 0 ? '?' + searchParams : ''}`, // Keep the query parameters intact
);
});

return data;
}
Expand Down
Loading
Loading