rimelight-components 2.1.12 → 2.1.14

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/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rimelight-components",
3
- "version": "2.1.12",
3
+ "version": "2.1.14",
4
4
  "docs": "https://rimelight.com/tools/rimelight-components",
5
5
  "configKey": "rimelightComponents",
6
6
  "compatibility": {
package/dist/module.mjs CHANGED
@@ -4,7 +4,7 @@ import { readdirSync } from 'node:fs';
4
4
  import { basename } from 'node:path';
5
5
 
6
6
  const name = "rimelight-components";
7
- const version = "2.1.12";
7
+ const version = "2.1.14";
8
8
  const homepage = "https://rimelight.com/tools/rimelight-components";
9
9
 
10
10
  const defaultOptions = {
@@ -1,10 +1,13 @@
1
- import type { Page, PageSurround } from "../../types/index.js";
1
+ import { type Page, type PageSurround, type PageDefinition } from "../../types/index.js";
2
2
  interface PageEditorProps {
3
3
  isSaving: boolean;
4
4
  useSurround?: boolean;
5
5
  surround?: PageSurround | null;
6
6
  surroundStatus?: 'idle' | 'pending' | 'success' | 'error';
7
- resolvePage?: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
7
+ resolvePage: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
8
+ pageDefinitions: Record<string, PageDefinition>;
9
+ onCreatePage?: (page: Partial<Page>) => Promise<void>;
10
+ onDeletePage?: (id: string) => Promise<void>;
8
11
  }
9
12
  type __VLS_Props = PageEditorProps;
10
13
  type __VLS_ModelProps = {
@@ -1,5 +1,6 @@
1
1
  <script setup>
2
2
  import { ref, computed, useTemplateRef, provide } from "vue";
3
+ import {} from "../../types";
3
4
  import { usePageEditor, usePageRegistry } from "../../composables";
4
5
  import { getLocalizedContent } from "../../utils";
5
6
  import { useI18n } from "vue-i18n";
@@ -7,12 +8,15 @@ const { getTypeLabelKey } = usePageRegistry();
7
8
  const { t, locale } = useI18n();
8
9
  const page = defineModel({ type: null, ...{ required: true } });
9
10
  const { undo, redo, canUndo, canRedo, captureSnapshot } = usePageEditor(page);
10
- const { isSaving, useSurround = false, surroundStatus = "idle", surround = null, resolvePage } = defineProps({
11
+ const { isSaving, useSurround = false, surroundStatus = "idle", surround = null, resolvePage, onCreatePage, onDeletePage } = defineProps({
11
12
  isSaving: { type: Boolean, required: true },
12
13
  useSurround: { type: Boolean, required: false },
13
14
  surround: { type: [Object, null], required: false },
14
15
  surroundStatus: { type: String, required: false },
15
- resolvePage: { type: Function, required: false }
16
+ resolvePage: { type: Function, required: true },
17
+ pageDefinitions: { type: Object, required: true },
18
+ onCreatePage: { type: Function, required: false },
19
+ onDeletePage: { type: Function, required: false }
16
20
  });
17
21
  const emit = defineEmits(["save"]);
18
22
  const handleSave = () => {
@@ -64,6 +68,32 @@ const stopResizing = () => {
64
68
  document.body.style.cursor = "";
65
69
  document.body.style.userSelect = "";
66
70
  };
71
+ const isCreateModalOpen = ref(false);
72
+ const isCreating = ref(false);
73
+ const handleCreateConfirm = async (newPageData) => {
74
+ if (!onCreatePage) return;
75
+ try {
76
+ isCreating.value = true;
77
+ await onCreatePage(newPageData);
78
+ isCreateModalOpen.value = false;
79
+ } finally {
80
+ isCreating.value = false;
81
+ }
82
+ };
83
+ const isDeleteModalOpen = ref(false);
84
+ const isDeleting = ref(false);
85
+ const handleDeleteConfirm = async () => {
86
+ if (!onDeletePage || !page.value.id) return;
87
+ try {
88
+ isDeleting.value = true;
89
+ await onDeletePage(page.value.id);
90
+ isDeleteModalOpen.value = false;
91
+ } catch (err) {
92
+ console.error("Failed to delete page:", err);
93
+ } finally {
94
+ isDeleting.value = false;
95
+ }
96
+ };
67
97
  </script>
68
98
 
69
99
  <template>
@@ -107,6 +137,34 @@ const stopResizing = () => {
107
137
  :loading="isSaving"
108
138
  @click="handleSave"
109
139
  />
140
+ <RCCreatePageModal
141
+ :is-open="isCreateModalOpen"
142
+ :definitions="pageDefinitions"
143
+ :loading="isCreating"
144
+ @close="isCreateModalOpen = false"
145
+ @confirm="handleCreateConfirm"
146
+ >
147
+ <UButton
148
+ icon="lucide:file-plus"
149
+ label="Create Page"
150
+ color="primary"
151
+ size="xs"
152
+ />
153
+ </RCCreatePageModal>
154
+ <RCDeletePageModal
155
+ :is-open="isDeleteModalOpen"
156
+ :loading="isDeleting"
157
+ :page-title="getLocalizedContent(page.title, locale)"
158
+ @close="isDeleteModalOpen = false"
159
+ @confirm="handleDeleteConfirm"
160
+ >
161
+ <UButton
162
+ icon="lucide:file-plus"
163
+ label="Delete Page"
164
+ color="error"
165
+ size="xs"
166
+ />
167
+ </RCDeletePageModal>
110
168
  </div>
111
169
  </template>
112
170
  </UHeader>
@@ -241,7 +299,7 @@ const stopResizing = () => {
241
299
  class="h-full overflow-y-auto"
242
300
  :style="{ width: `${100 - editorWidth}%` }"
243
301
  >
244
- <RCPageRenderer v-model="page" />
302
+ <RCPageRenderer v-model="page" :resolve-page="resolvePage" />
245
303
  </div>
246
304
  </main>
247
305
  </template>
@@ -1,10 +1,13 @@
1
- import type { Page, PageSurround } from "../../types/index.js";
1
+ import { type Page, type PageSurround, type PageDefinition } from "../../types/index.js";
2
2
  interface PageEditorProps {
3
3
  isSaving: boolean;
4
4
  useSurround?: boolean;
5
5
  surround?: PageSurround | null;
6
6
  surroundStatus?: 'idle' | 'pending' | 'success' | 'error';
7
- resolvePage?: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
7
+ resolvePage: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
8
+ pageDefinitions: Record<string, PageDefinition>;
9
+ onCreatePage?: (page: Partial<Page>) => Promise<void>;
10
+ onDeletePage?: (id: string) => Promise<void>;
8
11
  }
9
12
  type __VLS_Props = PageEditorProps;
10
13
  type __VLS_ModelProps = {
@@ -155,6 +155,15 @@ const updateTextArray = (schema, vals) => {
155
155
  :placeholder="`Select ${schema.allowedPageTypes?.join('/')}`"
156
156
  class="w-full"
157
157
  />
158
+
159
+ <USelectMenu
160
+ v-else-if="schema.type === 'page-array'"
161
+ v-model="schema.value"
162
+ icon="lucide:link-2"
163
+ variant="subtle"
164
+ :placeholder="`Select ${schema.allowedPageTypes?.join('/')}`"
165
+ class="w-full"
166
+ />
158
167
  </UFormField>
159
168
  </template>
160
169
  </dl>
@@ -7,30 +7,13 @@ import {} from "@nuxt/ui/components/Tabs.vue";
7
7
  import { useI18n } from "vue-i18n";
8
8
  import { useShare, useClipboard } from "@vueuse/core";
9
9
  import {} from "../../types";
10
- const { getTypeLabelKey } = usePageRegistry();
11
10
  const page = defineModel({ type: null, ...{ required: true } });
11
+ const { getTypeLabelKey } = usePageRegistry();
12
+ const { isFieldVisible, shouldRenderGroup, getSortedFields, getSortedGroups } = useInfobox(page.value.properties);
12
13
  const { t, locale } = useI18n();
13
14
  const { share } = useShare();
14
15
  const { copy } = useClipboard();
15
16
  const toast = useToast();
16
- const shouldRenderField = (schema) => {
17
- const isVisible = !schema.visibleIf || schema.visibleIf(page.value.properties);
18
- if (!isVisible) return false;
19
- const val = schema.value;
20
- if (schema.type === "text") {
21
- return !!val?.[locale.value];
22
- }
23
- if (schema.type === "text-array") {
24
- return Array.isArray(val) && val.length > 0;
25
- }
26
- return val !== void 0 && val !== null && val !== "";
27
- };
28
- const shouldRenderGroup = (group) => {
29
- return Object.values(group.fields || {}).some((schema) => shouldRenderField(schema));
30
- };
31
- const getSortedFields = (fields) => {
32
- return Object.entries(fields).sort(([, a], [, b]) => (a.order ?? 0) - (b.order ?? 0));
33
- };
34
17
  const sharePage = async () => {
35
18
  if (!page.value) {
36
19
  return;
@@ -142,8 +125,8 @@ const imageTabs = computed(() => {
142
125
  </template>
143
126
 
144
127
  <template #default>
145
- <template v-for="(group, groupId) in page.properties" :key="groupId">
146
- <UCollapsible v-if="shouldRenderGroup(group)" :default-open="group.defaultOpen">
128
+ <template v-for="[groupId, group] in getSortedGroups(page.properties)" :key="groupId">
129
+ <UCollapsible v-if="shouldRenderGroup(group, true)" :default-open="group.defaultOpen">
147
130
  <template #default>
148
131
  <UButton
149
132
  :label="getLocalizedContent(group.label, locale)"
@@ -164,7 +147,7 @@ const imageTabs = computed(() => {
164
147
  :key="fieldKey"
165
148
  >
166
149
  <div
167
- v-if="shouldRenderField(schema)"
150
+ v-if="isFieldVisible(schema, true)"
168
151
  class="grid grid-cols-3 gap-xs items-baseline"
169
152
  >
170
153
  <dt class="text-xs font-semibold text-dimmed">
@@ -3,7 +3,7 @@ interface PageRendererProps {
3
3
  useSurround?: boolean;
4
4
  surround?: PageSurround | null;
5
5
  surroundStatus?: 'idle' | 'pending' | 'success' | 'error';
6
- resolvePage?: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
6
+ resolvePage: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
7
7
  }
8
8
  type __VLS_Props = PageRendererProps;
9
9
  type __VLS_ModelProps = {
@@ -11,7 +11,7 @@ const { useSurround = false, surroundStatus = "idle", surround = null, resolvePa
11
11
  useSurround: { type: Boolean, required: false },
12
12
  surround: { type: [Object, null], required: false },
13
13
  surroundStatus: { type: String, required: false },
14
- resolvePage: { type: Function, required: false }
14
+ resolvePage: { type: Function, required: true }
15
15
  });
16
16
  const emit = defineEmits([]);
17
17
  provide("page-resolver", resolvePage);
@@ -3,7 +3,7 @@ interface PageRendererProps {
3
3
  useSurround?: boolean;
4
4
  surround?: PageSurround | null;
5
5
  surroundStatus?: 'idle' | 'pending' | 'success' | 'error';
6
- resolvePage?: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
6
+ resolvePage: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
7
7
  }
8
8
  type __VLS_Props = PageRendererProps;
9
9
  type __VLS_ModelProps = {
@@ -0,0 +1,35 @@
1
+ import { type PageDefinition, type Page } from "../../../types/index.js";
2
+ export interface CreatePageModalProps {
3
+ isOpen: boolean;
4
+ definitions: Record<string, PageDefinition>;
5
+ loading?: boolean;
6
+ }
7
+ export interface CreatePageModalEmits {
8
+ close: [];
9
+ confirm: [page: Partial<Page>];
10
+ }
11
+ declare var __VLS_10: {};
12
+ type __VLS_Slots = {} & {
13
+ default?: (props: typeof __VLS_10) => any;
14
+ };
15
+ declare const __VLS_base: import("vue").DefineComponent<CreatePageModalProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
+ close: () => any;
17
+ confirm: (page: Partial<{
18
+ type: "Default";
19
+ properties: import("../../../types/index.js").BasePageProperties;
20
+ } & import("../../../types/index.js").BasePage>) => any;
21
+ }, string, import("vue").PublicProps, Readonly<CreatePageModalProps> & Readonly<{
22
+ onClose?: (() => any) | undefined;
23
+ onConfirm?: ((page: Partial<{
24
+ type: "Default";
25
+ properties: import("../../../types/index.js").BasePageProperties;
26
+ } & import("../../../types/index.js").BasePage>) => any) | undefined;
27
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
29
+ declare const _default: typeof __VLS_export;
30
+ export default _default;
31
+ type __VLS_WithSlots<T, S> = T & {
32
+ new (): {
33
+ $slots: S;
34
+ };
35
+ };
@@ -0,0 +1,108 @@
1
+ <script setup>
2
+ import { ref, computed, watch } from "vue";
3
+ import {} from "../../../types";
4
+ import { tv } from "tailwind-variants";
5
+ import { useI18n } from "vue-i18n";
6
+ const { t } = useI18n();
7
+ const { isOpen, loading, definitions } = defineProps({
8
+ isOpen: { type: Boolean, required: true },
9
+ definitions: { type: Object, required: true },
10
+ loading: { type: Boolean, required: false }
11
+ });
12
+ const emits = defineEmits(["close", "confirm"]);
13
+ const createPageModalStyles = tv({
14
+ slots: {
15
+ base: "flex flex-col gap-6",
16
+ group: "border border-neutral-200 rounded-lg p-4 bg-white shadow-sm",
17
+ groupTitle: "text-lg font-bold text-neutral-900 mb-4",
18
+ field: "flex flex-col gap-1.5",
19
+ label: "text-sm font-medium text-neutral-700",
20
+ input: "w-full px-3 py-2 rounded-md border border-neutral-300 focus:ring-2 focus:ring-primary-500 transition-all outline-hidden",
21
+ select: "w-full px-3 py-2 rounded-md border border-neutral-300 bg-white"
22
+ }
23
+ });
24
+ const styles = createPageModalStyles();
25
+ const selectedType = ref("");
26
+ const title = ref("");
27
+ const slug = ref("");
28
+ const typeOptions = computed(() => {
29
+ return Object.entries(definitions).map(([key, def]) => ({
30
+ label: t(def.typeLabelKey),
31
+ value: key
32
+ }));
33
+ });
34
+ watch(title, (newTitle) => {
35
+ slug.value = newTitle.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
36
+ });
37
+ const handleConfirm = () => {
38
+ if (!selectedType.value) return;
39
+ const definition = definitions[selectedType.value];
40
+ if (!definition) {
41
+ console.error(`Definition for type "${selectedType.value}" not found.`);
42
+ return;
43
+ }
44
+ const properties = {};
45
+ Object.entries(definition.properties).forEach(([groupKey, group]) => {
46
+ properties[groupKey] = {};
47
+ Object.entries(group.fields).forEach(([fieldKey, field]) => {
48
+ properties[groupKey][fieldKey] = field.value;
49
+ });
50
+ });
51
+ const newPage = {
52
+ type: selectedType.value,
53
+ title: { en: title.value },
54
+ slug: slug.value,
55
+ properties,
56
+ blocks: definition.initialBlocks ? definition.initialBlocks() : []
57
+ };
58
+ emits("confirm", newPage);
59
+ };
60
+ </script>
61
+
62
+ <template>
63
+ <UModal :model-value="isOpen" @update:model-value="emits('close')">
64
+ <slot/>
65
+ <template #content>
66
+ <UCard>
67
+ <template #header>
68
+ <div class="flex items-center justify-between">
69
+ <h3 class="text-base font-semibold leading-6">Create New Page</h3>
70
+ <UButton color="neutral" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="emits('close')" />
71
+ </div>
72
+ </template>
73
+
74
+ <div class="space-y-4 py-4">
75
+ <UFormField label="Page Template" required>
76
+ <USelect
77
+ v-model="selectedType"
78
+ :items="typeOptions"
79
+ :placeholder="t('editor.template_placeholder', 'Select a template...')"
80
+ class="w-full"
81
+ />
82
+ </UFormField>
83
+
84
+ <UFormField label="Title" required>
85
+ <UInput v-model="title" placeholder="e.g. My Awesome Movie" />
86
+ </UFormField>
87
+
88
+ <UFormField label="Slug" required>
89
+ <UInput v-model="slug" placeholder="my-awesome-movie" />
90
+ </UFormField>
91
+ </div>
92
+
93
+ <template #footer>
94
+ <div class="flex justify-end gap-2">
95
+ <UButton color="neutral" variant="ghost" label="Cancel" @click="emits('close')" />
96
+ <UButton
97
+ color="primary"
98
+ label="Create & Edit"
99
+ :loading="loading"
100
+ :disabled="!selectedType || !title"
101
+ @click="handleConfirm"
102
+ />
103
+ </div>
104
+ </template>
105
+ </UCard>
106
+ </template>
107
+ </UModal>
108
+ </template>
@@ -0,0 +1,35 @@
1
+ import { type PageDefinition, type Page } from "../../../types/index.js";
2
+ export interface CreatePageModalProps {
3
+ isOpen: boolean;
4
+ definitions: Record<string, PageDefinition>;
5
+ loading?: boolean;
6
+ }
7
+ export interface CreatePageModalEmits {
8
+ close: [];
9
+ confirm: [page: Partial<Page>];
10
+ }
11
+ declare var __VLS_10: {};
12
+ type __VLS_Slots = {} & {
13
+ default?: (props: typeof __VLS_10) => any;
14
+ };
15
+ declare const __VLS_base: import("vue").DefineComponent<CreatePageModalProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
+ close: () => any;
17
+ confirm: (page: Partial<{
18
+ type: "Default";
19
+ properties: import("../../../types/index.js").BasePageProperties;
20
+ } & import("../../../types/index.js").BasePage>) => any;
21
+ }, string, import("vue").PublicProps, Readonly<CreatePageModalProps> & Readonly<{
22
+ onClose?: (() => any) | undefined;
23
+ onConfirm?: ((page: Partial<{
24
+ type: "Default";
25
+ properties: import("../../../types/index.js").BasePageProperties;
26
+ } & import("../../../types/index.js").BasePage>) => any) | undefined;
27
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
29
+ declare const _default: typeof __VLS_export;
30
+ export default _default;
31
+ type __VLS_WithSlots<T, S> = T & {
32
+ new (): {
33
+ $slots: S;
34
+ };
35
+ };
@@ -0,0 +1,28 @@
1
+ export interface DeletePageModalProps {
2
+ isOpen: boolean;
3
+ loading?: boolean;
4
+ pageTitle: string;
5
+ }
6
+ export interface DeletePageModalEmits {
7
+ (e: 'close'): void;
8
+ (e: 'confirm'): void;
9
+ }
10
+ declare var __VLS_10: {};
11
+ type __VLS_Slots = {} & {
12
+ default?: (props: typeof __VLS_10) => any;
13
+ };
14
+ declare const __VLS_base: import("vue").DefineComponent<DeletePageModalProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
15
+ close: () => any;
16
+ confirm: () => any;
17
+ }, string, import("vue").PublicProps, Readonly<DeletePageModalProps> & Readonly<{
18
+ onClose?: (() => any) | undefined;
19
+ onConfirm?: (() => any) | undefined;
20
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
22
+ declare const _default: typeof __VLS_export;
23
+ export default _default;
24
+ type __VLS_WithSlots<T, S> = T & {
25
+ new (): {
26
+ $slots: S;
27
+ };
28
+ };
@@ -0,0 +1,84 @@
1
+ <script setup>
2
+ import { ref, watch } from "vue";
3
+ import { useI18n } from "vue-i18n";
4
+ const { isOpen, loading, pageTitle } = defineProps({
5
+ isOpen: { type: Boolean, required: true },
6
+ loading: { type: Boolean, required: false },
7
+ pageTitle: { type: String, required: true }
8
+ });
9
+ const emits = defineEmits(["close", "confirm"]);
10
+ const { t } = useI18n();
11
+ const confirmationInput = ref("");
12
+ const CONFIRMATION_TEXT = "DELETE";
13
+ watch(() => isOpen, (val) => {
14
+ if (!val) confirmationInput.value = "";
15
+ });
16
+ const handleConfirm = () => {
17
+ if (confirmationInput.value === CONFIRMATION_TEXT) {
18
+ emits("confirm");
19
+ }
20
+ };
21
+ </script>
22
+
23
+ <template>
24
+ <UModal :model-value="isOpen" @update:model-value="emits('close')">
25
+ <slot/>
26
+ <template #content>
27
+ <UCard :ui="{ body: 'space-y-4' }">
28
+ <template #header>
29
+ <div class="flex items-center justify-between">
30
+ <h3 class="text-base font-semibold leading-6 text-error-600">
31
+ {{ t("editor.delete_page_title", "Delete Page") }}
32
+ </h3>
33
+ <UButton
34
+ color="neutral"
35
+ variant="ghost"
36
+ icon="lucide:x"
37
+ class="-my-1"
38
+ @click="emits('close')"
39
+ />
40
+ </div>
41
+ </template>
42
+
43
+ <div class="text-sm text-neutral-600 dark:text-neutral-400">
44
+ <p>
45
+ Are you sure you want to delete <strong>{{ pageTitle }}</strong>?
46
+ This action is permanent and cannot be undone.
47
+ </p>
48
+ </div>
49
+
50
+ <UFormField
51
+ :label="t('editor.delete_confirm_label', `Please type ${CONFIRMATION_TEXT} to confirm`)"
52
+ required
53
+ >
54
+ <UInput
55
+ v-model="confirmationInput"
56
+ :placeholder="CONFIRMATION_TEXT"
57
+ color="error"
58
+ autocomplete="off"
59
+ @keyup.enter="handleConfirm"
60
+ />
61
+ </UFormField>
62
+
63
+ <template #footer>
64
+ <div class="flex justify-end gap-2">
65
+ <UButton
66
+ color="neutral"
67
+ variant="ghost"
68
+ :label="t('common.cancel', 'Cancel')"
69
+ @click="emits('close')"
70
+ />
71
+ <UButton
72
+ color="error"
73
+ icon="lucide:trash-2"
74
+ :label="t('editor.delete_button', 'Delete Permanently')"
75
+ :loading="loading"
76
+ :disabled="confirmationInput !== CONFIRMATION_TEXT"
77
+ @click="handleConfirm"
78
+ />
79
+ </div>
80
+ </template>
81
+ </UCard>
82
+ </template>
83
+ </UModal>
84
+ </template>
@@ -0,0 +1,28 @@
1
+ export interface DeletePageModalProps {
2
+ isOpen: boolean;
3
+ loading?: boolean;
4
+ pageTitle: string;
5
+ }
6
+ export interface DeletePageModalEmits {
7
+ (e: 'close'): void;
8
+ (e: 'confirm'): void;
9
+ }
10
+ declare var __VLS_10: {};
11
+ type __VLS_Slots = {} & {
12
+ default?: (props: typeof __VLS_10) => any;
13
+ };
14
+ declare const __VLS_base: import("vue").DefineComponent<DeletePageModalProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
15
+ close: () => any;
16
+ confirm: () => any;
17
+ }, string, import("vue").PublicProps, Readonly<DeletePageModalProps> & Readonly<{
18
+ onClose?: (() => any) | undefined;
19
+ onConfirm?: (() => any) | undefined;
20
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
22
+ declare const _default: typeof __VLS_export;
23
+ export default _default;
24
+ type __VLS_WithSlots<T, S> = T & {
25
+ new (): {
26
+ $slots: S;
27
+ };
28
+ };
@@ -1,5 +1,5 @@
1
1
  import { type MaybeRefOrGetter } from "vue";
2
- import { type Page, type Localized, type PageDefinition, type Property } from "../types/index.js";
2
+ import { type Localized, type Page, type PageDefinition, type Property } from "../types/index.js";
3
3
  export declare const getLocalizedContent: <T = string>(field: Localized<T> | undefined, currentLocale: MaybeRefOrGetter<string>) => T | string;
4
4
  type WidenProperty<T> = T extends string ? string : T extends number ? number : T extends never[] ? Localized[] : T extends object ? {
5
5
  [K in keyof T]: WidenProperty<T[K]>;
@@ -12,14 +12,17 @@ export function syncPageWithDefinition(page, definition) {
12
12
  let hasChanged = false;
13
13
  const updatedProperties = {};
14
14
  const definitionGroups = definition.properties;
15
+ const existingProperties = page.properties || {};
15
16
  for (const [groupId, definitionGroup] of Object.entries(definitionGroups)) {
16
- const existingGroup = page.properties[groupId];
17
+ const existingGroup = existingProperties[groupId];
17
18
  const updatedGroupFields = {};
18
- for (const [fieldId, definitionField] of Object.entries(definitionGroup.fields)) {
19
- if (existingGroup?.fields[fieldId]) {
19
+ const definitionFields = definitionGroup.fields || {};
20
+ for (const [fieldId, definitionField] of Object.entries(definitionFields)) {
21
+ const existingField = existingGroup?.fields ? existingGroup.fields[fieldId] : void 0;
22
+ if (existingField !== void 0) {
20
23
  updatedGroupFields[fieldId] = {
21
24
  ...definitionField,
22
- value: existingGroup.fields[fieldId].value
25
+ value: existingField.value
23
26
  };
24
27
  } else {
25
28
  updatedGroupFields[fieldId] = { ...definitionField };
@@ -34,12 +37,15 @@ export function syncPageWithDefinition(page, definition) {
34
37
  hasChanged = true;
35
38
  }
36
39
  }
37
- if (Object.keys(page.properties).length !== Object.keys(updatedProperties).length) {
40
+ const existingGroupKeys = Object.keys(existingProperties);
41
+ const updatedGroupKeys = Object.keys(updatedProperties);
42
+ if (existingGroupKeys.length !== updatedGroupKeys.length) {
38
43
  hasChanged = true;
39
44
  } else {
40
- for (const groupId in updatedProperties) {
41
- const pageGroup = page.properties[groupId];
42
- if (Object.keys(pageGroup?.fields || {}).length !== Object.keys(updatedProperties[groupId].fields).length) {
45
+ for (const groupId of updatedGroupKeys) {
46
+ const existingFields = existingProperties[groupId]?.fields || {};
47
+ const updatedFields = updatedProperties[groupId].fields;
48
+ if (Object.keys(existingFields).length !== Object.keys(updatedFields).length) {
43
49
  hasChanged = true;
44
50
  break;
45
51
  }
@@ -12,14 +12,17 @@ export function syncPageWithDefinition(page, definition) {
12
12
  let hasChanged = false;
13
13
  const updatedProperties = {};
14
14
  const definitionGroups = definition.properties;
15
+ const existingProperties = page.properties || {};
15
16
  for (const [groupId, definitionGroup] of Object.entries(definitionGroups)) {
16
- const existingGroup = page.properties[groupId];
17
+ const existingGroup = existingProperties[groupId];
17
18
  const updatedGroupFields = {};
18
- for (const [fieldId, definitionField] of Object.entries(definitionGroup.fields)) {
19
- if (existingGroup?.fields[fieldId]) {
19
+ const definitionFields = definitionGroup.fields || {};
20
+ for (const [fieldId, definitionField] of Object.entries(definitionFields)) {
21
+ const existingField = existingGroup?.fields ? existingGroup.fields[fieldId] : void 0;
22
+ if (existingField !== void 0) {
20
23
  updatedGroupFields[fieldId] = {
21
24
  ...definitionField,
22
- value: existingGroup.fields[fieldId].value
25
+ value: existingField.value
23
26
  };
24
27
  } else {
25
28
  updatedGroupFields[fieldId] = { ...definitionField };
@@ -34,12 +37,15 @@ export function syncPageWithDefinition(page, definition) {
34
37
  hasChanged = true;
35
38
  }
36
39
  }
37
- if (Object.keys(page.properties).length !== Object.keys(updatedProperties).length) {
40
+ const existingGroupKeys = Object.keys(existingProperties);
41
+ const updatedGroupKeys = Object.keys(updatedProperties);
42
+ if (existingGroupKeys.length !== updatedGroupKeys.length) {
38
43
  hasChanged = true;
39
44
  } else {
40
- for (const groupId in updatedProperties) {
41
- const pageGroup = page.properties[groupId];
42
- if (Object.keys(pageGroup?.fields || {}).length !== Object.keys(updatedProperties[groupId].fields).length) {
45
+ for (const groupId of updatedGroupKeys) {
46
+ const existingFields = existingProperties[groupId]?.fields || {};
47
+ const updatedFields = updatedProperties[groupId].fields;
48
+ if (Object.keys(existingFields).length !== Object.keys(updatedFields).length) {
43
49
  hasChanged = true;
44
50
  break;
45
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rimelight-components",
3
- "version": "2.1.12",
3
+ "version": "2.1.14",
4
4
  "description": "A component library by Rimelight Entertainment.",
5
5
  "keywords": [
6
6
  "nuxt",