rimelight-components 2.1.1 → 2.1.3

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.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
- export * from '../dist/runtime/types/index.js';
2
+ export * from '../dist/runtime/types/index.mjs';
3
3
 
4
4
  interface CalloutOptions {
5
5
  icon: string;
@@ -0,0 +1,69 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+ export * from '../dist/runtime/types/index.mjs';
3
+
4
+ interface CalloutOptions {
5
+ icon: string;
6
+ title: string;
7
+ tooltip: string;
8
+ }
9
+
10
+ interface ModuleOptions {
11
+ /**
12
+ * Prefix for components
13
+ * @defaultValue `RC`
14
+ */
15
+ prefix?: string;
16
+ callouts: {
17
+ info: CalloutOptions;
18
+ success: CalloutOptions;
19
+ warning: CalloutOptions;
20
+ error: CalloutOptions;
21
+ commentary: CalloutOptions;
22
+ ideation: CalloutOptions;
23
+ source: CalloutOptions;
24
+ };
25
+ }
26
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, {
27
+ enabled: boolean;
28
+ prefix: string;
29
+ callouts: {
30
+ info: {
31
+ icon: string;
32
+ title: string;
33
+ tooltip: string;
34
+ };
35
+ success: {
36
+ icon: string;
37
+ title: string;
38
+ tooltip: string;
39
+ };
40
+ warning: {
41
+ icon: string;
42
+ title: string;
43
+ tooltip: string;
44
+ };
45
+ error: {
46
+ icon: string;
47
+ title: string;
48
+ tooltip: string;
49
+ };
50
+ commentary: {
51
+ icon: string;
52
+ title: string;
53
+ tooltip: string;
54
+ };
55
+ ideation: {
56
+ icon: string;
57
+ title: string;
58
+ tooltip: string;
59
+ };
60
+ source: {
61
+ icon: string;
62
+ title: string;
63
+ tooltip: string;
64
+ };
65
+ };
66
+ }, true>;
67
+
68
+ export { _default as default };
69
+ export type { ModuleOptions };
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rimelight-components",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
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.1";
7
+ const version = "2.1.3";
8
8
  const homepage = "https://rimelight.com/tools/rimelight-components";
9
9
 
10
10
  const defaultOptions = {
@@ -194,10 +194,10 @@ const module$1 = defineNuxtModule().with({
194
194
  prefix: options.prefix ?? void 0,
195
195
  global: true
196
196
  });
197
+ nuxt.options.alias["#rimelight"] = resolve("./runtime");
197
198
  addImportsDir(resolve("./runtime/composables"));
198
199
  addImportsDir(resolve("./runtime/types"));
199
200
  addImportsDir(resolve("./runtime/utils"));
200
- addServerImportsDir(resolve("./runtime/composables"));
201
201
  addServerImportsDir(resolve("./runtime/types"));
202
202
  addServerImportsDir(resolve("./runtime/utils"));
203
203
  const blockRendererFiles = readdirSync(resolve("./runtime/components/blocks/renderer")).filter(
@@ -0,0 +1,4 @@
1
+ import { defineAppConfig } from "#imports";
2
+ export default defineAppConfig({
3
+ rimelightComponents: {}
4
+ });
@@ -0,0 +1,4 @@
1
+ export * from "./useDateRange.mjs";
2
+ export * from "./usePageEditor.mjs";
3
+ export * from "./useBlockEditor.mjs";
4
+ export * from "./usePageRegistry.mjs";
@@ -0,0 +1,150 @@
1
+ import { computed, ref, shallowRef } from "vue";
2
+ import { v7 as uuidv7 } from "uuid";
3
+ function findBlockLocation(blocks, id) {
4
+ for (let i = 0; i < blocks.length; i++) {
5
+ const block = blocks[i];
6
+ if (!block) continue;
7
+ if (block.id === id) {
8
+ return { parentArray: blocks, index: i };
9
+ }
10
+ if ("children" in block.props && Array.isArray(block.props.children)) {
11
+ const result = findBlockLocation(block.props.children, id);
12
+ if (result) return result;
13
+ }
14
+ }
15
+ return null;
16
+ }
17
+ function regenerateIds(block) {
18
+ block.id = uuidv7();
19
+ if ("children" in block.props && Array.isArray(block.props.children)) {
20
+ block.props.children.forEach((child) => regenerateIds(child));
21
+ }
22
+ }
23
+ export function useBlockEditor(initialBlocks, { maxHistorySize = 100, onMutation } = {}) {
24
+ const history = shallowRef([]);
25
+ const future = shallowRef([]);
26
+ const committedBlocks = ref(JSON.parse(JSON.stringify(initialBlocks.value)));
27
+ const captureSnapshot = () => {
28
+ const snapshot = JSON.parse(JSON.stringify(initialBlocks.value));
29
+ future.value = [];
30
+ const newHistory = [...history.value, snapshot];
31
+ if (newHistory.length > maxHistorySize) {
32
+ newHistory.shift();
33
+ }
34
+ history.value = newHistory;
35
+ };
36
+ const executeMutation = (mutationFn) => {
37
+ if (onMutation) {
38
+ onMutation();
39
+ } else {
40
+ captureSnapshot();
41
+ }
42
+ mutationFn();
43
+ };
44
+ const undo = () => {
45
+ if (history.value.length === 0) return;
46
+ const currentState = JSON.parse(JSON.stringify(initialBlocks.value));
47
+ future.value = [currentState, ...future.value];
48
+ const previousState = history.value[history.value.length - 1];
49
+ if (previousState) {
50
+ initialBlocks.value.splice(0, initialBlocks.value.length, ...previousState);
51
+ const newHistory = [...history.value];
52
+ newHistory.pop();
53
+ history.value = newHistory;
54
+ }
55
+ };
56
+ const redo = () => {
57
+ if (future.value.length === 0) return;
58
+ const currentState = JSON.parse(JSON.stringify(initialBlocks.value));
59
+ let newHistory = [...history.value, currentState];
60
+ if (newHistory.length > maxHistorySize) {
61
+ newHistory.shift();
62
+ }
63
+ history.value = newHistory;
64
+ const nextState = future.value[0];
65
+ if (nextState) {
66
+ initialBlocks.value.splice(0, initialBlocks.value.length, ...nextState);
67
+ const newFuture = [...future.value];
68
+ newFuture.shift();
69
+ future.value = newFuture;
70
+ }
71
+ };
72
+ const canUndo = computed(() => history.value.length > 0);
73
+ const canRedo = computed(() => future.value.length > 0);
74
+ const updateBlockProps = (id, newProps) => {
75
+ executeMutation(() => {
76
+ const loc = findBlockLocation(initialBlocks.value, id);
77
+ if (!loc) return;
78
+ const oldBlock = loc.parentArray[loc.index];
79
+ if (!oldBlock) return;
80
+ const newPropsObject = {
81
+ ...oldBlock.props,
82
+ ...newProps
83
+ };
84
+ const newBlock = {
85
+ id: oldBlock.id,
86
+ // Explicitly carry over the required BaseBlock properties
87
+ type: oldBlock.type,
88
+ // Explicitly carry over the required BaseBlock properties
89
+ props: newPropsObject
90
+ };
91
+ loc.parentArray.splice(loc.index, 1, newBlock);
92
+ });
93
+ };
94
+ const removeBlock = (id) => {
95
+ executeMutation(() => {
96
+ const loc = findBlockLocation(initialBlocks.value, id);
97
+ if (!loc) return;
98
+ loc.parentArray.splice(loc.index, 1);
99
+ });
100
+ };
101
+ const moveBlock = (id, direction) => {
102
+ executeMutation(() => {
103
+ const loc = findBlockLocation(initialBlocks.value, id);
104
+ if (!loc) return;
105
+ const { parentArray, index } = loc;
106
+ const newIndex = index + direction;
107
+ if (newIndex >= 0 && newIndex < parentArray.length) {
108
+ const movedBlock = parentArray.splice(index, 1)[0];
109
+ if (movedBlock) {
110
+ parentArray.splice(newIndex, 0, movedBlock);
111
+ }
112
+ }
113
+ });
114
+ };
115
+ const duplicateBlock = (id) => {
116
+ executeMutation(() => {
117
+ const loc = findBlockLocation(initialBlocks.value, id);
118
+ if (!loc) return;
119
+ const original = loc.parentArray[loc.index];
120
+ const clone = JSON.parse(JSON.stringify(original));
121
+ regenerateIds(clone);
122
+ loc.parentArray.splice(loc.index + 1, 0, clone);
123
+ });
124
+ };
125
+ const insertBlock = (newBlockType, targetId = null, position = "after") => {
126
+ executeMutation(() => {
127
+ });
128
+ };
129
+ const commitChanges = () => {
130
+ const committedSnapshot = JSON.parse(JSON.stringify(initialBlocks.value));
131
+ committedBlocks.value = committedSnapshot;
132
+ return committedSnapshot;
133
+ };
134
+ return {
135
+ // Mutations
136
+ updateBlockProps,
137
+ removeBlock,
138
+ moveBlock,
139
+ duplicateBlock,
140
+ insertBlock,
141
+ // History
142
+ undo,
143
+ redo,
144
+ canUndo,
145
+ canRedo,
146
+ // State
147
+ committedBlocks,
148
+ commitChanges
149
+ };
150
+ }
@@ -0,0 +1,55 @@
1
+ import { useState, readonly } from "#imports";
2
+ import { subDays, subMonths, subYears, startOfDay, endOfDay } from "date-fns";
3
+ export function useDateRange() {
4
+ const dateRange = useState(`feedback-date-range`, () => ({
5
+ start: subDays(/* @__PURE__ */ new Date(), 30),
6
+ end: /* @__PURE__ */ new Date()
7
+ }));
8
+ const setDateRange = (range) => {
9
+ dateRange.value = {
10
+ start: startOfDay(range.start),
11
+ end: endOfDay(range.end)
12
+ };
13
+ };
14
+ const setPresetRange = (preset) => {
15
+ const end = /* @__PURE__ */ new Date();
16
+ let start;
17
+ switch (preset) {
18
+ case `week`:
19
+ start = subDays(end, 7);
20
+ break;
21
+ case `month`:
22
+ start = subDays(end, 30);
23
+ break;
24
+ case `3months`:
25
+ start = subMonths(end, 3);
26
+ break;
27
+ case `6months`:
28
+ start = subMonths(end, 6);
29
+ break;
30
+ case `year`:
31
+ start = subYears(end, 1);
32
+ break;
33
+ default:
34
+ start = subDays(end, 30);
35
+ }
36
+ setDateRange({
37
+ start,
38
+ end
39
+ });
40
+ };
41
+ const isDateInRange = (date) => {
42
+ const checkDate = typeof date === `string` ? new Date(date) : date;
43
+ return checkDate >= dateRange.value.start && checkDate <= dateRange.value.end;
44
+ };
45
+ const filterFeedbackByDateRange = (feedback) => {
46
+ return feedback.filter((item) => isDateInRange(item.createdAt));
47
+ };
48
+ return {
49
+ dateRange: readonly(dateRange),
50
+ setDateRange,
51
+ setPresetRange,
52
+ isDateInRange,
53
+ filterFeedbackByDateRange
54
+ };
55
+ }
@@ -0,0 +1,45 @@
1
+ import { computed, shallowRef, watch } from "vue";
2
+ export function usePageEditor(page, maxHistorySize = 100) {
3
+ const history = shallowRef([]);
4
+ const future = shallowRef([]);
5
+ const captureSnapshot = () => {
6
+ const snapshot = JSON.stringify(page.value);
7
+ if (history.value.length > 0 && history.value[history.value.length - 1] === snapshot) return;
8
+ future.value = [];
9
+ const newHistory = [...history.value, snapshot];
10
+ if (newHistory.length > maxHistorySize) newHistory.shift();
11
+ history.value = newHistory;
12
+ };
13
+ const undo = () => {
14
+ if (history.value.length === 0) return;
15
+ future.value = [JSON.stringify(page.value), ...future.value];
16
+ const previous = JSON.parse(history.value.pop());
17
+ page.value = previous;
18
+ };
19
+ const redo = () => {
20
+ if (future.value.length === 0) return;
21
+ history.value = [...history.value, JSON.stringify(page.value)];
22
+ const next = JSON.parse(future.value.shift());
23
+ page.value = next;
24
+ };
25
+ const canUndo = computed(() => history.value.length > 0);
26
+ const canRedo = computed(() => future.value.length > 0);
27
+ const save = () => {
28
+ return JSON.parse(JSON.stringify(page.value));
29
+ };
30
+ watch(
31
+ () => page.value.properties,
32
+ () => {
33
+ captureSnapshot();
34
+ },
35
+ { deep: true }
36
+ );
37
+ return {
38
+ undo,
39
+ redo,
40
+ canUndo,
41
+ canRedo,
42
+ save,
43
+ captureSnapshot
44
+ };
45
+ }
@@ -0,0 +1,16 @@
1
+ import { reactive, readonly } from "vue";
2
+ const PAGE_DEFINITIONS = reactive({});
3
+ export const usePageRegistry = () => {
4
+ const registerDefinitions = (definitions) => {
5
+ Object.assign(PAGE_DEFINITIONS, definitions);
6
+ };
7
+ const getTypeLabelKey = (type) => {
8
+ const definition = PAGE_DEFINITIONS[type];
9
+ return definition?.typeLabelKey ?? `page.type.${type.toLowerCase()}`;
10
+ };
11
+ return {
12
+ registerDefinitions,
13
+ getTypeLabelKey,
14
+ definitions: readonly(PAGE_DEFINITIONS)
15
+ };
16
+ };
@@ -0,0 +1,10 @@
1
+ import { uuid, timestamp } from "drizzle-orm/pg-core";
2
+ import { sql } from "drizzle-orm";
3
+ export const id = uuid("id").default(sql`uuidv7()`).notNull();
4
+ export const timestamps = {
5
+ updated_at: timestamp("updated_at", {
6
+ withTimezone: true
7
+ }).$onUpdate(() => /* @__PURE__ */ new Date()),
8
+ created_at: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
9
+ deleted_at: timestamp("deleted_at", { withTimezone: true })
10
+ };
@@ -0,0 +1,29 @@
1
+ import { defineAsyncComponent } from "vue";
2
+ import { BLOCK_RENDERER_COMPONENT_MAP } from "#build/rimelight-block-renderer-map";
3
+ import { BLOCK_EDITOR_COMPONENT_MAP } from "#build/rimelight-block-editor-map";
4
+ export const getBlockRendererComponent = (type) => {
5
+ const componentImporter = BLOCK_RENDERER_COMPONENT_MAP[type];
6
+ if (!componentImporter) {
7
+ console.warn(
8
+ `[BlockMapper] Block component not found for type: ${type}. Please check block name.`
9
+ );
10
+ return void 0;
11
+ }
12
+ return defineAsyncComponent(async () => {
13
+ const module = await componentImporter();
14
+ return module.default;
15
+ });
16
+ };
17
+ export const getBlockEditorComponent = (type) => {
18
+ const componentImporter = BLOCK_EDITOR_COMPONENT_MAP[type];
19
+ if (!componentImporter) {
20
+ console.warn(
21
+ `[EditorBlockMapper] Editor block component not found for type: ${type}. Please check block name.`
22
+ );
23
+ return void 0;
24
+ }
25
+ return defineAsyncComponent(async () => {
26
+ const module = await componentImporter();
27
+ return module.default;
28
+ });
29
+ };
File without changes
@@ -0,0 +1,3 @@
1
+ export * from "./blocks.mjs";
2
+ export * from "./pages.mjs";
3
+ export * from "./schemas.mjs";
File without changes
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ export const LocalizedSchema = (schema) => z.record(z.string(), schema);
3
+ export const linkVariantEnum = z.enum(["solid", "outline", "subtle", "soft", "ghost", "link"]);
4
+ export const linkColorEnum = z.enum([
5
+ "primary",
6
+ "secondary",
7
+ "neutral",
8
+ "error",
9
+ "warning",
10
+ "success",
11
+ "info"
12
+ ]);
13
+ export const ImageSchema = z.object({
14
+ src: z.string().min(1, "Image source must be provided."),
15
+ alt: z.string().min(1, "Image alt text must be provided."),
16
+ width: z.number().int().positive().optional(),
17
+ height: z.number().int().positive().optional(),
18
+ name: LocalizedSchema(z.string()).optional()
19
+ });
20
+ export const LinkSchema = z.object({
21
+ label: z.string().min(1, "Link label must be provided."),
22
+ to: z.url("Link destination must be a valid URL.").min(1, "Link destination must be provided."),
23
+ icon: z.string().optional(),
24
+ trailing: z.boolean().optional(),
25
+ color: linkColorEnum.optional(),
26
+ variant: linkVariantEnum.optional()
27
+ });
@@ -1,6 +1,6 @@
1
1
  export * from "./richTextHelpers.js";
2
2
  export * from "./page.js";
3
- export * from "./database.js";
3
+ export * from "./database";
4
4
  export function slugify(text) {
5
5
  if (!text) {
6
6
  return "";
@@ -0,0 +1,9 @@
1
+ export * from "./richTextHelpers.mjs";
2
+ export * from "./page.mjs";
3
+ export * from "./database";
4
+ export function slugify(text) {
5
+ if (!text) {
6
+ return "";
7
+ }
8
+ return text.toString().normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/\s+/g, "-").replace(/[^\w-]+/g, "").replace(/--+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
9
+ }
@@ -0,0 +1,77 @@
1
+ import { toValue } from "vue";
2
+ export const getLocalizedContent = (field, currentLocale) => {
3
+ if (!field || typeof field !== "object") return "";
4
+ const locale = toValue(currentLocale);
5
+ return field[locale] ?? field["en"] ?? "";
6
+ };
7
+ export function definePageDefinition(def) {
8
+ return def;
9
+ }
10
+ export function syncPageWithDefinition(page, definition) {
11
+ if (!definition) return page;
12
+ let hasChanged = false;
13
+ const updatedProperties = {};
14
+ const definitionGroups = definition.properties;
15
+ for (const [groupId, definitionGroup] of Object.entries(definitionGroups)) {
16
+ const existingGroup = page.properties[groupId];
17
+ const updatedGroupFields = {};
18
+ for (const [fieldId, definitionField] of Object.entries(definitionGroup.fields)) {
19
+ if (existingGroup?.fields[fieldId]) {
20
+ updatedGroupFields[fieldId] = {
21
+ ...definitionField,
22
+ value: existingGroup.fields[fieldId].value
23
+ };
24
+ } else {
25
+ updatedGroupFields[fieldId] = { ...definitionField };
26
+ hasChanged = true;
27
+ }
28
+ }
29
+ updatedProperties[groupId] = {
30
+ ...definitionGroup,
31
+ fields: updatedGroupFields
32
+ };
33
+ if (!existingGroup) {
34
+ hasChanged = true;
35
+ }
36
+ }
37
+ if (Object.keys(page.properties).length !== Object.keys(updatedProperties).length) {
38
+ hasChanged = true;
39
+ } 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) {
43
+ hasChanged = true;
44
+ break;
45
+ }
46
+ }
47
+ }
48
+ page.properties = updatedProperties;
49
+ if (definition.initialBlocks) {
50
+ const idealBlocks = definition.initialBlocks();
51
+ const currentBlocks = [...page.blocks];
52
+ const idealBlocksMap = new Map(idealBlocks.map((b) => [b.id, b]));
53
+ const filteredCurrent = currentBlocks.filter((b) => {
54
+ if (!b.isTemplated) return true;
55
+ return idealBlocksMap.has(b.id);
56
+ });
57
+ if (filteredCurrent.length !== currentBlocks.length) {
58
+ hasChanged = true;
59
+ }
60
+ let lastExistingIdealIndex = -1;
61
+ for (const idealBlock of idealBlocks) {
62
+ const existingIndex = filteredCurrent.findIndex((b) => b.id === idealBlock.id);
63
+ if (existingIndex !== -1) {
64
+ lastExistingIdealIndex = existingIndex;
65
+ } else {
66
+ filteredCurrent.splice(lastExistingIdealIndex + 1, 0, { ...idealBlock });
67
+ lastExistingIdealIndex++;
68
+ hasChanged = true;
69
+ }
70
+ }
71
+ page.blocks = filteredCurrent;
72
+ }
73
+ if (hasChanged) {
74
+ page.updated_at = /* @__PURE__ */ new Date();
75
+ }
76
+ return page;
77
+ }
@@ -0,0 +1,25 @@
1
+ import { v7 as uuidv7 } from "uuid";
2
+ export function richTextToHtml(content) {
3
+ return content.map((item) => {
4
+ if (item.type === "text" || item.type === "link") {
5
+ return item.props.content;
6
+ }
7
+ if (item.type === "mention") {
8
+ return "";
9
+ }
10
+ return "";
11
+ }).join("");
12
+ }
13
+ export function parseHtmlToRichText(html) {
14
+ if (html.trim().length === 0) {
15
+ return [];
16
+ }
17
+ const newTextNode = {
18
+ id: uuidv7(),
19
+ type: "text",
20
+ props: {
21
+ content: html.trim()
22
+ }
23
+ };
24
+ return [newTextNode];
25
+ }
package/dist/types.d.mts CHANGED
@@ -2,4 +2,4 @@ export { default } from './module.mjs'
2
2
 
3
3
  export { type ModuleOptions } from './module.mjs'
4
4
 
5
- export * from '../dist/runtime/types/index.js'
5
+ export * from '../dist/runtime/types/index.mjs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rimelight-components",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "A component library by Rimelight Entertainment.",
5
5
  "keywords": [
6
6
  "nuxt",
@@ -32,6 +32,10 @@
32
32
  "./utils/*": {
33
33
  "types": "./dist/runtime/utils/*.d.mts",
34
34
  "import": "./dist/runtime/utils/*.js"
35
+ },
36
+ "./db": {
37
+ "types": "./dist/runtime/utils/db.d.ts",
38
+ "import": "./dist/runtime/utils/db.js"
35
39
  }
36
40
  },
37
41
  "typesVersions": {
File without changes