@kywi-software/core 0.9.0 → 0.11.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/AGENT-PATTERNS.md +15 -13
- package/README.md +67 -0
- package/dist/admin/layout-editor/column-overlay.d.ts.map +1 -1
- package/dist/admin/layout-editor/column-overlay.js +7 -1
- package/dist/admin/layout-editor/column-overlay.js.map +1 -1
- package/dist/admin/layout-editor/drop-indicator.d.ts +18 -1
- package/dist/admin/layout-editor/drop-indicator.d.ts.map +1 -1
- package/dist/admin/layout-editor/drop-indicator.js +23 -3
- package/dist/admin/layout-editor/drop-indicator.js.map +1 -1
- package/dist/admin/layout-editor/editor-canvas.d.ts +31 -8
- package/dist/admin/layout-editor/editor-canvas.d.ts.map +1 -1
- package/dist/admin/layout-editor/editor-canvas.js +131 -48
- package/dist/admin/layout-editor/editor-canvas.js.map +1 -1
- package/dist/admin/layout-editor/editor-state.d.ts.map +1 -1
- package/dist/admin/layout-editor/editor-state.js +19 -3
- package/dist/admin/layout-editor/editor-state.js.map +1 -1
- package/dist/admin/layout-editor/editor.css +106 -8
- package/dist/admin/layout-editor/inline-text.d.ts +56 -4
- package/dist/admin/layout-editor/inline-text.d.ts.map +1 -1
- package/dist/admin/layout-editor/inline-text.js +134 -11
- package/dist/admin/layout-editor/inline-text.js.map +1 -1
- package/dist/admin/layout-editor/layout-editor.d.ts.map +1 -1
- package/dist/admin/layout-editor/layout-editor.js +1 -1
- package/dist/admin/layout-editor/layout-editor.js.map +1 -1
- package/dist/admin/layout-editor/module-overlay.d.ts +26 -13
- package/dist/admin/layout-editor/module-overlay.d.ts.map +1 -1
- package/dist/admin/layout-editor/module-overlay.js +206 -22
- package/dist/admin/layout-editor/module-overlay.js.map +1 -1
- package/dist/admin/layout-editor/overlay-shell.d.ts.map +1 -1
- package/dist/admin/layout-editor/overlay-shell.js +39 -12
- package/dist/admin/layout-editor/overlay-shell.js.map +1 -1
- package/dist/admin/layout-editor/props-panel.js +1 -1
- package/dist/admin/layout-editor/props-panel.js.map +1 -1
- package/dist/admin/layout-editor/section-overlay.d.ts +8 -1
- package/dist/admin/layout-editor/section-overlay.d.ts.map +1 -1
- package/dist/admin/layout-editor/section-overlay.js +8 -8
- package/dist/admin/layout-editor/section-overlay.js.map +1 -1
- package/dist/admin/layout-editor/section-variant-container-config.js +5 -5
- package/dist/admin/layout-editor/section-variant-container-config.js.map +1 -1
- package/dist/admin/layout-editor/use-chrome-flip.d.ts +111 -11
- package/dist/admin/layout-editor/use-chrome-flip.d.ts.map +1 -1
- package/dist/admin/layout-editor/use-chrome-flip.js +233 -33
- package/dist/admin/layout-editor/use-chrome-flip.js.map +1 -1
- package/dist/admin/layout-editor/use-editor-dnd.d.ts +44 -1
- package/dist/admin/layout-editor/use-editor-dnd.d.ts.map +1 -1
- package/dist/admin/layout-editor/use-editor-dnd.js +191 -3
- package/dist/admin/layout-editor/use-editor-dnd.js.map +1 -1
- package/dist/admin/styles/admin.css +22 -1
- package/dist/admin/surfaces/layouts/layout-editor-client.d.ts.map +1 -1
- package/dist/admin/surfaces/layouts/layout-editor-client.js +12 -1
- package/dist/admin/surfaces/layouts/layout-editor-client.js.map +1 -1
- package/dist/api/content-routes.d.ts.map +1 -1
- package/dist/api/content-routes.js +34 -7
- package/dist/api/content-routes.js.map +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +7 -73
- package/dist/api/index.js.map +1 -1
- package/dist/cache/content-invalidation.d.ts +28 -0
- package/dist/cache/content-invalidation.d.ts.map +1 -0
- package/dist/cache/content-invalidation.js +72 -0
- package/dist/cache/content-invalidation.js.map +1 -0
- package/dist/db/content-restore.d.ts +5 -1
- package/dist/db/content-restore.d.ts.map +1 -1
- package/dist/db/content-restore.js +9 -2
- package/dist/db/content-restore.js.map +1 -1
- package/dist/layout/comments-module.d.ts.map +1 -1
- package/dist/layout/comments-module.js +6 -2
- package/dist/layout/comments-module.js.map +1 -1
- package/dist/layout/module-render-context.d.ts +32 -0
- package/dist/layout/module-render-context.d.ts.map +1 -1
- package/dist/layout/module-render-context.js +32 -1
- package/dist/layout/module-render-context.js.map +1 -1
- package/dist/layout/modules-extended.d.ts.map +1 -1
- package/dist/layout/modules-extended.js +21 -11
- package/dist/layout/modules-extended.js.map +1 -1
- package/dist/layout/modules.d.ts.map +1 -1
- package/dist/layout/modules.js +15 -10
- package/dist/layout/modules.js.map +1 -1
- package/dist/scope/inline-editing.d.ts.map +1 -1
- package/dist/scope/inline-editing.js +10 -0
- package/dist/scope/inline-editing.js.map +1 -1
- package/dist/scope/sticky-offset.d.ts +185 -0
- package/dist/scope/sticky-offset.d.ts.map +1 -0
- package/dist/scope/sticky-offset.js +432 -0
- package/dist/scope/sticky-offset.js.map +1 -0
- package/dist/site/styles.css +41 -3
- package/package.json +1 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { HookRegistry } from '../hooks/registry.js';
|
|
2
|
+
import type { KywiCacheProvider } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Drop every cache entry that can answer for one content node: its id key, its
|
|
5
|
+
* slug key, and the site's feed/nav projections. A missing `slug` only skips
|
|
6
|
+
* the slug key — the rest still runs.
|
|
7
|
+
*/
|
|
8
|
+
export type ContentCacheInvalidator = (siteId?: string, id?: string, slug?: string) => Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Build the narrow content-cache invalidation used both by the hook
|
|
11
|
+
* subscribers below and by mutation routes (workflow transitions, version
|
|
12
|
+
* restore) that update content directly rather than through the content hook
|
|
13
|
+
* dispatcher.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createContentCacheInvalidator(cacheProvider: KywiCacheProvider): ContentCacheInvalidator;
|
|
16
|
+
/**
|
|
17
|
+
* Subscribe the content cache to every content mutation event, and return the
|
|
18
|
+
* invalidator so callers that bypass the hook chain can reuse it.
|
|
19
|
+
*
|
|
20
|
+
* #137: `content:afterDelete` used to clear only the id key, so the slug key
|
|
21
|
+
* kept serving the just-trashed row — delete a page, recreate the same slug,
|
|
22
|
+
* and the editor loaded the trashed row's (empty) layout. Every event that can
|
|
23
|
+
* change what a slug resolves to now clears both keys. The DB getters already
|
|
24
|
+
* filter `deleted_at IS NULL`; the cache was the only place a trashed row could
|
|
25
|
+
* still come from.
|
|
26
|
+
*/
|
|
27
|
+
export declare function wireContentCacheInvalidation(registry: HookRegistry, cacheProvider: KywiCacheProvider): ContentCacheInvalidator;
|
|
28
|
+
//# sourceMappingURL=content-invalidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-invalidation.d.ts","sourceRoot":"","sources":["../../src/cache/content-invalidation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGnD;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,CAAC,EAAE,MAAM,EACf,EAAE,CAAC,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,KACV,OAAO,CAAC,IAAI,CAAC,CAAA;AAElB;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,iBAAiB,GAC/B,uBAAuB,CAQzB;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,YAAY,EACtB,aAAa,EAAE,iBAAiB,GAC/B,uBAAuB,CAoCzB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { contentKey, contentSlugKey } from './keys.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build the narrow content-cache invalidation used both by the hook
|
|
4
|
+
* subscribers below and by mutation routes (workflow transitions, version
|
|
5
|
+
* restore) that update content directly rather than through the content hook
|
|
6
|
+
* dispatcher.
|
|
7
|
+
*/
|
|
8
|
+
export function createContentCacheInvalidator(cacheProvider) {
|
|
9
|
+
return async (siteId, id, slug) => {
|
|
10
|
+
if (!siteId || !id)
|
|
11
|
+
return;
|
|
12
|
+
await cacheProvider.delete(contentKey(siteId, id));
|
|
13
|
+
if (slug)
|
|
14
|
+
await cacheProvider.delete(contentSlugKey(siteId, slug));
|
|
15
|
+
await cacheProvider.invalidatePattern(`feed:${siteId}:*`);
|
|
16
|
+
await cacheProvider.invalidatePattern(`nav:${siteId}:*`);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function readContent(payload) {
|
|
20
|
+
const content = payload?.content ?? {};
|
|
21
|
+
return {
|
|
22
|
+
siteId: String(content.siteId ?? ''),
|
|
23
|
+
id: String(content.id ?? ''),
|
|
24
|
+
slug: content.slug ? String(content.slug) : undefined,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Subscribe the content cache to every content mutation event, and return the
|
|
29
|
+
* invalidator so callers that bypass the hook chain can reuse it.
|
|
30
|
+
*
|
|
31
|
+
* #137: `content:afterDelete` used to clear only the id key, so the slug key
|
|
32
|
+
* kept serving the just-trashed row — delete a page, recreate the same slug,
|
|
33
|
+
* and the editor loaded the trashed row's (empty) layout. Every event that can
|
|
34
|
+
* change what a slug resolves to now clears both keys. The DB getters already
|
|
35
|
+
* filter `deleted_at IS NULL`; the cache was the only place a trashed row could
|
|
36
|
+
* still come from.
|
|
37
|
+
*/
|
|
38
|
+
export function wireContentCacheInvalidation(registry, cacheProvider) {
|
|
39
|
+
const invalidate = createContentCacheInvalidator(cacheProvider);
|
|
40
|
+
const invalidateFromEvent = async (payload) => {
|
|
41
|
+
const { siteId, id, slug } = readContent(payload);
|
|
42
|
+
await invalidate(siteId, id, slug);
|
|
43
|
+
};
|
|
44
|
+
// A create can't have a stale entry of its own, but it can inherit one: a row
|
|
45
|
+
// recreated on a slug whose previous occupant was purged through a path that
|
|
46
|
+
// never invalidated (empty-trash, a direct DB write) would otherwise resolve
|
|
47
|
+
// to the old row. Clearing the keys the new row is about to own makes that
|
|
48
|
+
// self-healing. Nav is left alone — an unpublished new node isn't in it yet.
|
|
49
|
+
registry.on('content:afterCreate', async (payload) => {
|
|
50
|
+
const { siteId, id, slug } = readContent(payload);
|
|
51
|
+
if (!siteId)
|
|
52
|
+
return;
|
|
53
|
+
if (id)
|
|
54
|
+
await cacheProvider.delete(contentKey(siteId, id));
|
|
55
|
+
if (slug)
|
|
56
|
+
await cacheProvider.delete(contentSlugKey(siteId, slug));
|
|
57
|
+
await cacheProvider.invalidatePattern(`feed:${siteId}:*`);
|
|
58
|
+
});
|
|
59
|
+
registry.on('content:afterUpdate', invalidateFromEvent);
|
|
60
|
+
// Unpublish fires its own dedicated event (afterUpdate no longer fires on
|
|
61
|
+
// unpublish) — without this the public site keeps serving the just-unpublished
|
|
62
|
+
// node from stale cache.
|
|
63
|
+
registry.on('content:afterUnpublish', invalidateFromEvent);
|
|
64
|
+
registry.on('content:afterPublish', invalidateFromEvent);
|
|
65
|
+
registry.on('content:afterDelete', invalidateFromEvent);
|
|
66
|
+
// Trash transitions change what a slug resolves to just as much as a delete
|
|
67
|
+
// does: a restore puts the row back, a permanent delete removes it for good.
|
|
68
|
+
registry.on('trash:afterRestore', invalidateFromEvent);
|
|
69
|
+
registry.on('trash:afterPermanentDelete', invalidateFromEvent);
|
|
70
|
+
return invalidate;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=content-invalidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-invalidation.js","sourceRoot":"","sources":["../../src/cache/content-invalidation.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,8 +11,12 @@ export interface DeletedContentRow {
|
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Get a soft-deleted content node by ID (for hook payloads).
|
|
14
|
+
*
|
|
15
|
+
* `siteId` is an optional cross-site guard: when provided, an id belonging to
|
|
16
|
+
* another site resolves to null, so a trash route can't hand a foreign row to
|
|
17
|
+
* its hooks.
|
|
14
18
|
*/
|
|
15
|
-
export declare function getDeletedContentById(db: KywiDb, id: string): Promise<Record<string, unknown> | null>;
|
|
19
|
+
export declare function getDeletedContentById(db: KywiDb, id: string, siteId?: string): Promise<Record<string, unknown> | null>;
|
|
16
20
|
/**
|
|
17
21
|
* List soft-deleted content for a specific site, sorted by deletion date (newest first).
|
|
18
22
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-restore.d.ts","sourceRoot":"","sources":["../../src/db/content-restore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,eAAe,EAAE,MAAM,CAAA;IACvB,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED
|
|
1
|
+
{"version":3,"file":"content-restore.d.ts","sourceRoot":"","sources":["../../src/db/content-restore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,eAAe,EAAE,MAAM,CAAA;IACvB,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAUzC;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,UAAU,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5C,OAAO,CAAC;IAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA+BvD;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,MAAM,EACV,UAAU,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5C,OAAO,CAAC;IAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BvD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOlF;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAmCjB;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAA;CAAE,CAAC,CA+C3D;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYnF;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOlE"}
|
|
@@ -2,12 +2,19 @@ import { eq, and, sql, desc, count } from 'drizzle-orm';
|
|
|
2
2
|
import { kywiContent } from '../schema/base.js';
|
|
3
3
|
/**
|
|
4
4
|
* Get a soft-deleted content node by ID (for hook payloads).
|
|
5
|
+
*
|
|
6
|
+
* `siteId` is an optional cross-site guard: when provided, an id belonging to
|
|
7
|
+
* another site resolves to null, so a trash route can't hand a foreign row to
|
|
8
|
+
* its hooks.
|
|
5
9
|
*/
|
|
6
|
-
export async function getDeletedContentById(db, id) {
|
|
10
|
+
export async function getDeletedContentById(db, id, siteId) {
|
|
11
|
+
const conditions = [eq(kywiContent.id, id), sql `${kywiContent.deletedAt} IS NOT NULL`];
|
|
12
|
+
if (siteId !== undefined)
|
|
13
|
+
conditions.push(eq(kywiContent.siteId, siteId));
|
|
7
14
|
const [row] = await db
|
|
8
15
|
.select()
|
|
9
16
|
.from(kywiContent)
|
|
10
|
-
.where(and(
|
|
17
|
+
.where(and(...conditions))
|
|
11
18
|
.limit(1);
|
|
12
19
|
return row ?? null;
|
|
13
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-restore.js","sourceRoot":"","sources":["../../src/db/content-restore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAW,MAAM,aAAa,CAAA;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAc/C
|
|
1
|
+
{"version":3,"file":"content-restore.js","sourceRoot":"","sources":["../../src/db/content-restore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAW,MAAM,aAAa,CAAA;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAc/C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,EAAU,EACV,EAAU,EACV,MAAe;IAEf,MAAM,UAAU,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAA,GAAG,WAAW,CAAC,SAAS,cAAc,CAAC,CAAA;IACtF,IAAI,MAAM,KAAK,SAAS;QAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACzE,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;SACnB,MAAM,EAAE;SACR,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;SACzB,KAAK,CAAC,CAAC,CAAC,CAAA;IAEX,OAAQ,GAA+B,IAAI,IAAI,CAAA;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,EAAU,EACV,MAAc,EACd,UAA6C;IAE7C,MAAM,KAAK,GAAG,GAAG,CACf,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,GAAG,CAAA,GAAG,WAAW,CAAC,SAAS,cAAc,CAC1C,CAAA;IAED,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,EAAE;SAC3B,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;SAC1B,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CAAC,KAAK,CAAC,CAAA;IAEf,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,CAAC,CAAA;IAE7C,MAAM,IAAI,GAAG,MAAM,EAAE;SAClB,MAAM,CAAC;QACN,EAAE,EAAE,WAAW,CAAC,EAAE;QAClB,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,eAAe,EAAE,WAAW,CAAC,eAAe;QAC5C,SAAS,EAAE,WAAW,CAAC,SAAS;QAChC,SAAS,EAAE,WAAW,CAAC,SAAS;QAChC,SAAS,EAAE,WAAW,CAAC,SAAS;QAChC,QAAQ,EAAE,WAAW,CAAC,QAAQ;KAC/B,CAAC;SACD,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CAAC,KAAK,CAAC;SACZ,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;SACpC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;SACvB,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IAE5B,OAAO,EAAE,IAAI,EAAE,IAA2B,EAAE,KAAK,EAAE,CAAA;AACrD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,EAAU,EACV,UAA6C;IAE7C,MAAM,KAAK,GAAG,GAAG,CAAA,GAAG,WAAW,CAAC,SAAS,cAAc,CAAA;IAEvD,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,EAAE;SAC3B,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;SAC1B,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CAAC,KAAK,CAAC,CAAA;IAEf,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,CAAC,CAAA;IAE7C,MAAM,IAAI,GAAG,MAAM,EAAE;SAClB,MAAM,CAAC;QACN,EAAE,EAAE,WAAW,CAAC,EAAE;QAClB,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,eAAe,EAAE,WAAW,CAAC,eAAe;QAC5C,SAAS,EAAE,WAAW,CAAC,SAAS;QAChC,SAAS,EAAE,WAAW,CAAC,SAAS;QAChC,SAAS,EAAE,WAAW,CAAC,SAAS;QAChC,QAAQ,EAAE,WAAW,CAAC,QAAQ;KAC/B,CAAC;SACD,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CAAC,KAAK,CAAC;SACZ,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;SACpC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;SACvB,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IAE5B,OAAO,EAAE,IAAI,EAAE,IAA2B,EAAE,KAAK,EAAE,CAAA;AACrD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAU,EAAE,QAAgB;IAC9D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;SACnB,MAAM,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC;SAC9B,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAA,GAAG,WAAW,CAAC,SAAS,UAAU,CAAC,CAAC;SAC/E,KAAK,CAAC,CAAC,CAAC,CAAA;IACX,OAAO,GAAG,KAAK,SAAS,CAAA;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,EAAU,EACV,MAAc;IAEd,uDAAuD;IACvD,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE;SACxB,MAAM,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC;SAC9B,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,EAClC,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAClC,GAAG,CAAA,GAAG,WAAW,CAAC,QAAQ,UAAU,EACpC,GAAG,CAAA,GAAG,WAAW,CAAC,SAAS,UAAU,CACtC,CACF;SACA,KAAK,CAAC,CAAC,CAAC,CAAA;IAEX,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,EAAE,CAAA;IAEhC,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE;SACvB,MAAM,CAAC,WAAW,CAAC;SACnB,MAAM,CAAC;QACN,MAAM;QACN,KAAK,EAAE,mBAAmB;QAC1B,IAAI,EAAE,YAAY;QAClB,QAAQ,EAAE,QAAQ;QAClB,eAAe,EAAE,gBAAgB;QACjC,MAAM,EAAE,WAAW;QACnB,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,IAAI;KACT,CAAC;SACR,SAAS,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAA;IAEpC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;IACnE,OAAO,OAAO,CAAC,EAAE,CAAA;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,EAAU,EACV,EAAU,EACV,MAAe;IAEf,6EAA6E;IAC7E,+EAA+E;IAC/E,0EAA0E;IAC1E,8EAA8E;IAC9E,MAAM,KAAK,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC1E,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE;SACvB,MAAM,CAAC;QACN,EAAE,EAAE,WAAW,CAAC,EAAE;QAClB,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,QAAQ,EAAE,WAAW,CAAC,QAAQ;KAC/B,CAAC;SACD,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAA,GAAG,WAAW,CAAC,SAAS,cAAc,EAAE,GAAG,KAAK,CAAC,CAAC;SACvF,KAAK,CAAC,CAAC,CAAC,CAAA;IAEX,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAA;IAEjE,IAAI,gBAAgB,GAAG,KAAK,CAAA;IAC5B,IAAI,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAA;IAElC,yFAAyF;IACzF,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;QAC7D,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,yDAAyD;YACzD,MAAM,iBAAiB,GAAG,MAAM,2BAA2B,CAAC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;YAC/E,WAAW,GAAG,iBAAiB,CAAA;YAC/B,gBAAgB,GAAG,IAAI,CAAA;QACzB,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAA4B;QAC1C,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,IAAI,IAAI,EAAE;KACtB,CAAA;IACD,IAAI,gBAAgB,EAAE,CAAC;QACrB,UAAU,CAAC,QAAQ,GAAG,WAAW,CAAA;IACnC,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;SACnB,MAAM,CAAC,WAAW,CAAC;SACnB,GAAG,CAAC,UAAiB,CAAC;SACtB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAA,GAAG,WAAW,CAAC,SAAS,cAAc,CAAC,CAAC;SAC7E,SAAS,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAA;IAEpC,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,SAAS,EAAE,gBAAgB,EAAE,CAAA;AAC1D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAU,EAAE,MAAc;IAChE,MAAM,MAAM,GAAG,MAAM,EAAE;SACpB,MAAM,CAAC,WAAW,CAAC;SACnB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,GAAG,CAAA,GAAG,WAAW,CAAC,SAAS,cAAc,CAC1C,CACF;SACA,SAAS,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAA;IAEpC,OAAO,MAAM,CAAC,MAAM,CAAA;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EAAU;IAC/C,MAAM,MAAM,GAAG,MAAM,EAAE;SACpB,MAAM,CAAC,WAAW,CAAC;SACnB,KAAK,CAAC,GAAG,CAAA,GAAG,WAAW,CAAC,SAAS,cAAc,CAAC;SAChD,SAAS,CAAC,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAA;IAEpC,OAAO,MAAM,CAAC,MAAM,CAAA;AACtB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comments-module.d.ts","sourceRoot":"","sources":["../../src/layout/comments-module.tsx"],"names":[],"mappings":"AAKA;;;;;;;;;;GAUG;AAEH,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;
|
|
1
|
+
{"version":3,"file":"comments-module.d.ts","sourceRoot":"","sources":["../../src/layout/comments-module.tsx"],"names":[],"mappings":"AAKA;;;;;;;;;;GAUG;AAEH,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AA+OD,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAmBpD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useContext, useEffect, useRef, useState } from 'react';
|
|
4
|
-
import { ModuleEditorContext } from './module-render-context.js';
|
|
4
|
+
import { ModuleEditorContext, useInlinePropAnchor } from './module-render-context.js';
|
|
5
5
|
const COMMENTS_ENDPOINT = '/api/v1/comments';
|
|
6
6
|
const HONEYPOT_FIELD = '_kywi_hp';
|
|
7
7
|
/**
|
|
@@ -40,7 +40,11 @@ function authorLabel(c) {
|
|
|
40
40
|
}
|
|
41
41
|
// ─── Editor preview (non-interactive) ────────────────────────────────────────
|
|
42
42
|
function CommentsModulePreview({ title, submitLabel }) {
|
|
43
|
-
|
|
43
|
+
// Only the heading is anchored for inline editing (kywi-cms#145). `submitLabel`
|
|
44
|
+
// renders on a DISABLED button, which cannot take focus — anchoring it would
|
|
45
|
+
// start an edit the caret can never enter or leave. It stays a rail edit.
|
|
46
|
+
const anchor = useInlinePropAnchor();
|
|
47
|
+
return (_jsxs("div", { className: "kywi-module kywi-module-comments kywi-module-comments-preview", "aria-hidden": "true", children: [_jsx("h2", { className: "kywi-comments-title", ...anchor('title'), children: title }), _jsx("p", { className: "kywi-comments-preview-note", children: "Approved comments for this content appear here; visitors can post new ones (held for moderation)." }), _jsxs("div", { className: "kywi-comments-form kywi-comments-form-preview", children: [_jsx("input", { className: "kywi-form-input", disabled: true, placeholder: "Name (optional)" }), _jsx("textarea", { className: "kywi-form-textarea", disabled: true, placeholder: "Add a comment\u2026" }), _jsx("button", { type: "button", className: "kywi-form-submit", disabled: true, children: submitLabel })] })] }));
|
|
44
48
|
}
|
|
45
49
|
// ─── Public view (interactive) ───────────────────────────────────────────────
|
|
46
50
|
function CommentsModuleView({ title, submitLabel, allowAnonymous, explicitId, }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comments-module.js","sourceRoot":"","sources":["../../src/layout/comments-module.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAc,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"comments-module.js","sourceRoot":"","sources":["../../src/layout/comments-module.tsx"],"names":[],"mappings":"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"}
|
|
@@ -10,4 +10,36 @@
|
|
|
10
10
|
* context) always gets the real, submitting form (kywi-cms#34).
|
|
11
11
|
*/
|
|
12
12
|
export declare const ModuleEditorContext: import("react").Context<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* The attribute a renderer puts on the element that renders ONE inline-editable
|
|
15
|
+
* text prop (kywi-cms#145). Kept here rather than in the layout editor so the
|
|
16
|
+
* renderers that emit it don't have to import admin code.
|
|
17
|
+
*/
|
|
18
|
+
export declare const INLINE_PROP_ATTR = "data-kywi-prop";
|
|
19
|
+
/** What `useInlinePropAnchor()` spreads onto an element. Empty off the editor. */
|
|
20
|
+
export type InlinePropAnchor = {
|
|
21
|
+
'data-kywi-prop'?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Mark the element that renders one inline-editable text prop, so the front-of-
|
|
25
|
+
* site editor can make exactly THAT element contenteditable instead of the whole
|
|
26
|
+
* module wrapper (kywi-cms#145).
|
|
27
|
+
*
|
|
28
|
+
* Before this, inline editing bound the module's first text prop to the wrapper,
|
|
29
|
+
* which for any module rendering more than one visible text prop (card's
|
|
30
|
+
* title/body/footer, hero, cta, testimonial, …) meant a commit serialized EVERY
|
|
31
|
+
* prop's text into the one bound field — silent content corruption through the
|
|
32
|
+
* primary editing gesture.
|
|
33
|
+
*
|
|
34
|
+
* Editor-only, exactly like the #134 empty-state placeholders: outside
|
|
35
|
+
* `ModuleEditorContext` this contributes no attributes at all, so published
|
|
36
|
+
* markup is byte-identical to before (guarded by
|
|
37
|
+
* `layout/__tests__/inline-prop-anchors.test.tsx`).
|
|
38
|
+
*
|
|
39
|
+
* Only annotate an element whose text content is EXACTLY the prop's value — that
|
|
40
|
+
* equality is what makes the commit read safe. An element that also renders
|
|
41
|
+
* punctuation or a sibling value (pricing's `/{period}`) must stay unannotated;
|
|
42
|
+
* it degrades to the props-rail fallback instead of writing a mangled value.
|
|
43
|
+
*/
|
|
44
|
+
export declare function useInlinePropAnchor(): (prop: string) => InlinePropAnchor;
|
|
13
45
|
//# sourceMappingURL=module-render-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-render-context.d.ts","sourceRoot":"","sources":["../../src/layout/module-render-context.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,kCAAgC,CAAA"}
|
|
1
|
+
{"version":3,"file":"module-render-context.d.ts","sourceRoot":"","sources":["../../src/layout/module-render-context.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,kCAAgC,CAAA;AAEhE;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,mBAAmB,CAAA;AAEhD,kFAAkF;AAClF,MAAM,MAAM,gBAAgB,GAAG;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,CAGxE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { createContext } from 'react';
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
3
|
/**
|
|
4
4
|
* Signals that a module is being rendered inside the admin layout-editor canvas
|
|
5
5
|
* rather than on a public page. Interactive modules that would otherwise emit a
|
|
@@ -12,4 +12,35 @@ import { createContext } from 'react';
|
|
|
12
12
|
* context) always gets the real, submitting form (kywi-cms#34).
|
|
13
13
|
*/
|
|
14
14
|
export const ModuleEditorContext = createContext(false);
|
|
15
|
+
/**
|
|
16
|
+
* The attribute a renderer puts on the element that renders ONE inline-editable
|
|
17
|
+
* text prop (kywi-cms#145). Kept here rather than in the layout editor so the
|
|
18
|
+
* renderers that emit it don't have to import admin code.
|
|
19
|
+
*/
|
|
20
|
+
export const INLINE_PROP_ATTR = 'data-kywi-prop';
|
|
21
|
+
/**
|
|
22
|
+
* Mark the element that renders one inline-editable text prop, so the front-of-
|
|
23
|
+
* site editor can make exactly THAT element contenteditable instead of the whole
|
|
24
|
+
* module wrapper (kywi-cms#145).
|
|
25
|
+
*
|
|
26
|
+
* Before this, inline editing bound the module's first text prop to the wrapper,
|
|
27
|
+
* which for any module rendering more than one visible text prop (card's
|
|
28
|
+
* title/body/footer, hero, cta, testimonial, …) meant a commit serialized EVERY
|
|
29
|
+
* prop's text into the one bound field — silent content corruption through the
|
|
30
|
+
* primary editing gesture.
|
|
31
|
+
*
|
|
32
|
+
* Editor-only, exactly like the #134 empty-state placeholders: outside
|
|
33
|
+
* `ModuleEditorContext` this contributes no attributes at all, so published
|
|
34
|
+
* markup is byte-identical to before (guarded by
|
|
35
|
+
* `layout/__tests__/inline-prop-anchors.test.tsx`).
|
|
36
|
+
*
|
|
37
|
+
* Only annotate an element whose text content is EXACTLY the prop's value — that
|
|
38
|
+
* equality is what makes the commit read safe. An element that also renders
|
|
39
|
+
* punctuation or a sibling value (pricing's `/{period}`) must stay unannotated;
|
|
40
|
+
* it degrades to the props-rail fallback instead of writing a mangled value.
|
|
41
|
+
*/
|
|
42
|
+
export function useInlinePropAnchor() {
|
|
43
|
+
const inEditor = useContext(ModuleEditorContext);
|
|
44
|
+
return (prop) => (inEditor ? { [INLINE_PROP_ATTR]: prop } : {});
|
|
45
|
+
}
|
|
15
46
|
//# sourceMappingURL=module-render-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-render-context.js","sourceRoot":"","sources":["../../src/layout/module-render-context.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"module-render-context.js","sourceRoot":"","sources":["../../src/layout/module-render-context.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAEjD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,aAAa,CAAU,KAAK,CAAC,CAAA;AAEhE;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAA;AAKhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,QAAQ,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAA;IAChD,OAAO,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AACzE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modules-extended.d.ts","sourceRoot":"","sources":["../../src/layout/modules-extended.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0C,MAAM,OAAO,CAAA;AAQ9D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAcD,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAqBjD;AAID,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAUjD;AAID,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"modules-extended.d.ts","sourceRoot":"","sources":["../../src/layout/modules-extended.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0C,MAAM,OAAO,CAAA;AAQ9D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAcD,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAqBjD;AAID,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAUjD;AAID,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAcrD;AAID,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAwChD;AAID,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CA0BpD;AAID,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAyD/C;AAqBD,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAyBvD;AAID,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAqB/C;AAID,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CA6BhD;AAID,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAqBvD;AAID,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CA8CnD;AAID,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAkB/C;AAID,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CA2BrD;AAID,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAejD;AAID;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;IAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,WAAW,EAAE,CAAA;CACxB;AA2BD;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAA;AA0PtE,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAoBvD;AAID,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,qBAkBnD;AAID,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAiBrD;AA0LD,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAcrD;AAID,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAqCxD;AAID,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAarD;AAID,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAyBnD;AAID,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAgBtD;AAID,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAejD;AAID,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAehD;AAID,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAqBhD;AAID,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAoBpD;AAID,wBAAgB,oBAAoB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAoB1D;AAID,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAoB3D;AAID,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAqCnD;AAID,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,qBAmBtD;AAID,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAyBlD;AAID,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAoBrD;AAID,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAqBhD;AAWD,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CA2CzD;AAUD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,2CAiC5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,4CAOzC;AAID,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,CAuCvF,CAAA"}
|
|
@@ -4,7 +4,7 @@ import { useContext, useEffect, useState } from 'react';
|
|
|
4
4
|
import { sanitizeHtml } from '../util/sanitize.js';
|
|
5
5
|
import { resolveMediaRef } from './media-ref.js';
|
|
6
6
|
import { KywiForm } from '../scope/kywi-form.js';
|
|
7
|
-
import { ModuleEditorContext } from './module-render-context.js';
|
|
7
|
+
import { ModuleEditorContext, useInlinePropAnchor } from './module-render-context.js';
|
|
8
8
|
import { CommentsModule } from './comments-module.js';
|
|
9
9
|
// ─── Helper: parse JSON-or-array props ──────────────────────────────────────
|
|
10
10
|
function parseArrayProp(raw) {
|
|
@@ -38,10 +38,11 @@ export function EmbedModule({ props }) {
|
|
|
38
38
|
}
|
|
39
39
|
// ─── Accordion ────────────────────────────────────────────────────────────────
|
|
40
40
|
export function AccordionModule({ props }) {
|
|
41
|
+
const anchor = useInlinePropAnchor();
|
|
41
42
|
const title = String(props.title ?? '');
|
|
42
43
|
const content = sanitizeHtml(String(props.content ?? ''));
|
|
43
44
|
const open = props.open === true;
|
|
44
|
-
return (_jsx("div", { className: "kywi-module kywi-module-accordion", children: _jsxs("details", { open: open || undefined, children: [_jsx("summary", { children: title }), _jsx("div", { dangerouslySetInnerHTML: { __html: content } })] }) }));
|
|
45
|
+
return (_jsx("div", { className: "kywi-module kywi-module-accordion", children: _jsxs("details", { open: open || undefined, children: [_jsx("summary", { ...anchor('title'), children: title }), _jsx("div", { ...anchor('content'), dangerouslySetInnerHTML: { __html: content } })] }) }));
|
|
45
46
|
}
|
|
46
47
|
// ─── Tabs ─────────────────────────────────────────────────────────────────────
|
|
47
48
|
export function TabsModule({ props }) {
|
|
@@ -128,15 +129,17 @@ export function SocialShareModule({ props }) {
|
|
|
128
129
|
}
|
|
129
130
|
// ─── CTA ──────────────────────────────────────────────────────────────────────
|
|
130
131
|
export function CtaModule({ props }) {
|
|
132
|
+
const anchor = useInlinePropAnchor();
|
|
131
133
|
const headline = String(props.headline ?? '');
|
|
132
134
|
const subtext = String(props.subtext ?? '');
|
|
133
135
|
const buttonLabel = String(props.buttonLabel ?? 'Get Started');
|
|
134
136
|
const buttonHref = String(props.buttonHref ?? '#');
|
|
135
137
|
const buttonVariant = String(props.buttonVariant ?? 'primary');
|
|
136
|
-
return (_jsxs("section", { className: "kywi-module kywi-module-cta", children: [headline && _jsx("h2", { className: "kywi-cta-headline", children: headline }), subtext && _jsx("p", { className: "kywi-cta-subtext", children: subtext }), _jsx("a", { href: buttonHref, className: `kywi-btn kywi-btn-${buttonVariant} kywi-cta-btn`, children: buttonLabel })] }));
|
|
138
|
+
return (_jsxs("section", { className: "kywi-module kywi-module-cta", children: [headline && _jsx("h2", { className: "kywi-cta-headline", ...anchor('headline'), children: headline }), subtext && _jsx("p", { className: "kywi-cta-subtext", ...anchor('subtext'), children: subtext }), _jsx("a", { href: buttonHref, className: `kywi-btn kywi-btn-${buttonVariant} kywi-cta-btn`, ...anchor('buttonLabel'), children: buttonLabel })] }));
|
|
137
139
|
}
|
|
138
140
|
// ─── Hero ─────────────────────────────────────────────────────────────────────
|
|
139
141
|
export function HeroModule({ props }) {
|
|
142
|
+
const anchor = useInlinePropAnchor();
|
|
140
143
|
const headline = String(props.headline ?? '');
|
|
141
144
|
const subtext = String(props.subtext ?? '');
|
|
142
145
|
const backgroundImage = props.backgroundImage ? resolveMediaRef(props.backgroundImage) : undefined;
|
|
@@ -145,18 +148,20 @@ export function HeroModule({ props }) {
|
|
|
145
148
|
const style = backgroundImage
|
|
146
149
|
? { backgroundImage: `url(${backgroundImage})`, backgroundSize: 'cover', backgroundPosition: 'center' }
|
|
147
150
|
: {};
|
|
148
|
-
return (_jsx("section", { className: "kywi-module kywi-module-hero", style: style, children: _jsxs("div", { className: "kywi-hero-overlay", children: [headline && _jsx("h1", { className: "kywi-hero-headline", children: headline }), subtext && _jsx("p", { className: "kywi-hero-subtext", children: subtext }), buttonLabel && (_jsx("a", { href: buttonHref, className: "kywi-btn kywi-btn-primary kywi-hero-btn", children: buttonLabel }))] }) }));
|
|
151
|
+
return (_jsx("section", { className: "kywi-module kywi-module-hero", style: style, children: _jsxs("div", { className: "kywi-hero-overlay", children: [headline && _jsx("h1", { className: "kywi-hero-headline", ...anchor('headline'), children: headline }), subtext && _jsx("p", { className: "kywi-hero-subtext", ...anchor('subtext'), children: subtext }), buttonLabel && (_jsx("a", { href: buttonHref, className: "kywi-btn kywi-btn-primary kywi-hero-btn", ...anchor('buttonLabel'), children: buttonLabel }))] }) }));
|
|
149
152
|
}
|
|
150
153
|
// ─── Testimonial ──────────────────────────────────────────────────────────────
|
|
151
154
|
export function TestimonialModule({ props }) {
|
|
155
|
+
const anchor = useInlinePropAnchor();
|
|
152
156
|
const quote = String(props.quote ?? '');
|
|
153
157
|
const author = String(props.author ?? '');
|
|
154
158
|
const role = props.role ? String(props.role) : undefined;
|
|
155
159
|
const avatar = props.avatar ? resolveMediaRef(props.avatar) : undefined;
|
|
156
|
-
return (_jsx("div", { className: "kywi-module kywi-module-testimonial", children: _jsxs("blockquote", { className: "kywi-testimonial-quote", cite: author, children: [_jsx("p", { children: quote }), _jsxs("footer", { className: "kywi-testimonial-footer", children: [avatar && _jsx("img", { src: avatar, alt: author, className: "kywi-testimonial-avatar" }), _jsxs("cite", { children: [_jsx("span", { className: "kywi-testimonial-author", children: author }), role && _jsx("span", { className: "kywi-testimonial-role", children: role })] })] })] }) }));
|
|
160
|
+
return (_jsx("div", { className: "kywi-module kywi-module-testimonial", children: _jsxs("blockquote", { className: "kywi-testimonial-quote", cite: author, children: [_jsx("p", { ...anchor('quote'), children: quote }), _jsxs("footer", { className: "kywi-testimonial-footer", children: [avatar && _jsx("img", { src: avatar, alt: author, className: "kywi-testimonial-avatar" }), _jsxs("cite", { children: [_jsx("span", { className: "kywi-testimonial-author", ...anchor('author'), children: author }), role && _jsx("span", { className: "kywi-testimonial-role", ...anchor('role'), children: role })] })] })] }) }));
|
|
157
161
|
}
|
|
158
162
|
// ─── Pricing ──────────────────────────────────────────────────────────────────
|
|
159
163
|
export function PricingModule({ props }) {
|
|
164
|
+
const anchor = useInlinePropAnchor();
|
|
160
165
|
const planName = String(props.planName ?? '');
|
|
161
166
|
const price = String(props.price ?? '');
|
|
162
167
|
const period = String(props.period ?? 'month');
|
|
@@ -174,14 +179,15 @@ export function PricingModule({ props }) {
|
|
|
174
179
|
catch {
|
|
175
180
|
// use empty list
|
|
176
181
|
}
|
|
177
|
-
return (_jsx("div", { className: `kywi-module kywi-module-pricing${highlighted ? ' kywi-pricing-highlighted' : ''}`, children: _jsxs("div", { className: "kywi-pricing-card", children: [planName && _jsx("h3", { className: "kywi-pricing-plan", children: planName }), _jsxs("div", { className: "kywi-pricing-price", children: [_jsx("span", { className: "kywi-pricing-amount", children: price }), _jsxs("span", { className: "kywi-pricing-period", children: ["/", period] })] }), features.length > 0 && (_jsx("ul", { className: "kywi-pricing-features", children: features.map((feature, i) => (_jsx("li", { className: "kywi-pricing-feature", children: feature }, i))) })), _jsx("a", { href: buttonHref, className: "kywi-btn kywi-btn-primary kywi-pricing-btn", children: buttonLabel })] }) }));
|
|
182
|
+
return (_jsx("div", { className: `kywi-module kywi-module-pricing${highlighted ? ' kywi-pricing-highlighted' : ''}`, children: _jsxs("div", { className: "kywi-pricing-card", children: [planName && _jsx("h3", { className: "kywi-pricing-plan", ...anchor('planName'), children: planName }), _jsxs("div", { className: "kywi-pricing-price", children: [_jsx("span", { className: "kywi-pricing-amount", ...anchor('price'), children: price }), _jsxs("span", { className: "kywi-pricing-period", children: ["/", period] })] }), features.length > 0 && (_jsx("ul", { className: "kywi-pricing-features", children: features.map((feature, i) => (_jsx("li", { className: "kywi-pricing-feature", children: feature }, i))) })), _jsx("a", { href: buttonHref, className: "kywi-btn kywi-btn-primary kywi-pricing-btn", ...anchor('buttonLabel'), children: buttonLabel })] }) }));
|
|
178
183
|
}
|
|
179
184
|
// ─── FAQ ──────────────────────────────────────────────────────────────────────
|
|
180
185
|
export function FaqModule({ props }) {
|
|
186
|
+
const anchor = useInlinePropAnchor();
|
|
181
187
|
const question = String(props.question ?? '');
|
|
182
188
|
const answer = sanitizeHtml(String(props.answer ?? ''));
|
|
183
189
|
const open = props.open === true;
|
|
184
|
-
return (_jsx("div", { className: "kywi-module kywi-module-faq", children: _jsxs("details", { open: open || undefined, children: [_jsx("summary", { className: "kywi-faq-question", children: question }), _jsx("div", { className: "kywi-faq-answer", dangerouslySetInnerHTML: { __html: answer } })] }) }));
|
|
190
|
+
return (_jsx("div", { className: "kywi-module kywi-module-faq", children: _jsxs("details", { open: open || undefined, children: [_jsx("summary", { className: "kywi-faq-question", ...anchor('question'), children: question }), _jsx("div", { className: "kywi-faq-answer", ...anchor('answer'), dangerouslySetInnerHTML: { __html: answer } })] }) }));
|
|
185
191
|
}
|
|
186
192
|
// ─── Countdown ────────────────────────────────────────────────────────────────
|
|
187
193
|
export function CountdownModule({ props }) {
|
|
@@ -202,10 +208,11 @@ export function CountdownModule({ props }) {
|
|
|
202
208
|
}
|
|
203
209
|
// ─── Alert ────────────────────────────────────────────────────────────────────
|
|
204
210
|
export function AlertModule({ props }) {
|
|
211
|
+
const anchor = useInlinePropAnchor();
|
|
205
212
|
const message = String(props.message ?? '');
|
|
206
213
|
const type = String(props.type ?? 'info');
|
|
207
214
|
const dismissible = props.dismissible === true;
|
|
208
|
-
return (_jsx("div", { role: "alert", className: `kywi-module kywi-module-alert kywi-alert kywi-alert-${type}`, "data-dismissible": dismissible, children: _jsx("span", { className: "kywi-alert-message", children: message }) }));
|
|
215
|
+
return (_jsx("div", { role: "alert", className: `kywi-module kywi-module-alert kywi-alert kywi-alert-${type}`, "data-dismissible": dismissible, children: _jsx("span", { className: "kywi-alert-message", ...anchor('message'), children: message }) }));
|
|
209
216
|
}
|
|
210
217
|
function optionalString(value) {
|
|
211
218
|
return typeof value === 'string' && value !== '' ? value : undefined;
|
|
@@ -487,17 +494,19 @@ export function ColumnsModule({ props }) {
|
|
|
487
494
|
}
|
|
488
495
|
// ─── Blockquote ──────────────────────────────────────────────────────────────
|
|
489
496
|
export function BlockquoteModule({ props }) {
|
|
497
|
+
const anchor = useInlinePropAnchor();
|
|
490
498
|
const content = String(props.content ?? '');
|
|
491
499
|
const cite = props.cite ? String(props.cite) : undefined;
|
|
492
500
|
const author = props.author ? String(props.author) : undefined;
|
|
493
|
-
return (_jsxs("figure", { className: "kywi-module kywi-module-blockquote", children: [_jsx("blockquote", { cite: cite, children: _jsx("p", { children: content }) }), author && _jsx("figcaption", { className: "kywi-blockquote-author", children: author })] }));
|
|
501
|
+
return (_jsxs("figure", { className: "kywi-module kywi-module-blockquote", children: [_jsx("blockquote", { cite: cite, children: _jsx("p", { ...anchor('content'), children: content }) }), author && (_jsx("figcaption", { className: "kywi-blockquote-author", ...anchor('author'), children: author }))] }));
|
|
494
502
|
}
|
|
495
503
|
// ─── Badge ───────────────────────────────────────────────────────────────────
|
|
496
504
|
export function BadgeModule({ props }) {
|
|
505
|
+
const anchor = useInlinePropAnchor();
|
|
497
506
|
const label = String(props.label ?? '');
|
|
498
507
|
const variant = String(props.variant ?? 'default');
|
|
499
508
|
const href = props.href ? String(props.href) : undefined;
|
|
500
|
-
const inner = _jsx("span", { className: `kywi-badge kywi-badge-${variant}`, children: label });
|
|
509
|
+
const inner = (_jsx("span", { className: `kywi-badge kywi-badge-${variant}`, ...anchor('label'), children: label }));
|
|
501
510
|
return (_jsx("span", { className: "kywi-module kywi-module-badge", children: href ? _jsx("a", { href: href, children: inner }) : inner }));
|
|
502
511
|
}
|
|
503
512
|
// ─── Icon ────────────────────────────────────────────────────────────────────
|
|
@@ -510,13 +519,14 @@ export function IconModule({ props }) {
|
|
|
510
519
|
}
|
|
511
520
|
// ─── Card ────────────────────────────────────────────────────────────────────
|
|
512
521
|
export function CardModule({ props }) {
|
|
522
|
+
const anchor = useInlinePropAnchor();
|
|
513
523
|
const title = String(props.title ?? '');
|
|
514
524
|
const body = String(props.body ?? '');
|
|
515
525
|
const image = props.image ? resolveMediaRef(props.image) : undefined;
|
|
516
526
|
const imageAlt = String(props.imageAlt ?? title);
|
|
517
527
|
const href = props.href ? String(props.href) : undefined;
|
|
518
528
|
const footer = props.footer ? String(props.footer) : undefined;
|
|
519
|
-
const card = (_jsxs("div", { className: "kywi-module kywi-module-card", children: [image && _jsx("img", { src: image, alt: imageAlt, className: "kywi-card-image" }), _jsxs("div", { className: "kywi-card-body", children: [title && _jsx("h3", { className: "kywi-card-title", children: title }), body && _jsx("p", { className: "kywi-card-text", children: body })] }), footer && _jsx("div", { className: "kywi-card-footer", children: footer })] }));
|
|
529
|
+
const card = (_jsxs("div", { className: "kywi-module kywi-module-card", children: [image && _jsx("img", { src: image, alt: imageAlt, className: "kywi-card-image" }), _jsxs("div", { className: "kywi-card-body", children: [title && _jsx("h3", { className: "kywi-card-title", ...anchor('title'), children: title }), body && _jsx("p", { className: "kywi-card-text", ...anchor('body'), children: body })] }), footer && _jsx("div", { className: "kywi-card-footer", ...anchor('footer'), children: footer })] }));
|
|
520
530
|
return href ? _jsx("a", { href: href, className: "kywi-card-link", children: card }) : card;
|
|
521
531
|
}
|
|
522
532
|
// ─── Tag Cloud ───────────────────────────────────────────────────────────────
|