@jini-ai/admin 0.4.3 → 0.4.4

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/comments/comments.module.d.ts +4 -4
  3. package/dist/comments/messages.en.d.ts +4 -4
  4. package/dist/comments/messages.en.js +4 -4
  5. package/dist/comments/react/components/QueueSection.js +1 -1
  6. package/dist/comments/react/index.d.ts +16 -16
  7. package/dist/forms/forms.module.d.ts +3 -2
  8. package/dist/forms/html-rules.d.ts +14 -0
  9. package/dist/forms/html-rules.js +10 -0
  10. package/dist/forms/messages.en.d.ts +3 -2
  11. package/dist/forms/messages.en.js +4 -3
  12. package/dist/forms/react/components/FormEditorHeaderText.js +2 -2
  13. package/dist/forms/react/components/FormSubmissionDetail.d.ts +3 -1
  14. package/dist/forms/react/components/FormSubmissionDetail.js +3 -2
  15. package/dist/forms/react/components/FormSubmissions.js +1 -1
  16. package/dist/forms/react/hooks/forms-view.hooks.d.ts +1 -6
  17. package/dist/forms/react/hooks/forms-view.hooks.js +3 -4
  18. package/dist/forms/react/index.d.ts +9 -6
  19. package/dist/forms/react/pages/FormsList.js +2 -7
  20. package/dist/react/components/RowMenu/RowMenu.hooks.js +14 -3
  21. package/dist/redirects/messages.en.d.ts +9 -7
  22. package/dist/redirects/messages.en.js +14 -9
  23. package/dist/redirects/react/hooks/RedirectsPage.hooks.js +2 -2
  24. package/dist/redirects/react/index.d.ts +36 -28
  25. package/dist/redirects/react/pages/RedirectsPage.js +1 -1
  26. package/dist/redirects/redirects.module.d.ts +9 -7
  27. package/dist/seo/messages.en.d.ts +5 -4
  28. package/dist/seo/messages.en.js +6 -5
  29. package/dist/seo/react/components/MediaRefField.d.ts +4 -0
  30. package/dist/seo/react/components/MediaRefField.js +2 -2
  31. package/dist/seo/react/components/SitemapModal.js +4 -2
  32. package/dist/seo/react/hooks/MediaRefField.hooks.d.ts +4 -1
  33. package/dist/seo/react/hooks/MediaRefField.hooks.js +3 -3
  34. package/dist/seo/react/index.d.ts +15 -12
  35. package/dist/seo/react/options.d.ts +7 -0
  36. package/dist/seo/react/pages/SeoPage.js +23 -23
  37. package/dist/seo/rules.d.ts +6 -0
  38. package/dist/seo/rules.js +8 -0
  39. package/dist/seo/seo.module.d.ts +5 -4
  40. package/dist/widgets/react/pages/WidgetRegionEditor.js +1 -1
  41. package/package.json +5 -5
@@ -24,8 +24,7 @@ export declare function redirects(_required: Record<string, never>, options?: Re
24
24
  readonly Import: "Import";
25
25
  readonly Marketing: "Marketing";
26
26
  readonly Redirects: "Redirects";
27
- readonly "Manual URL redirect rules. Rules created automatically from a slug change (source": "Manual URL redirect rules. Rules created automatically from a slug change (source";
28
- readonly ") also show up here.": ") also show up here.";
27
+ readonly "Manage URL redirects, including those created automatically when a page's address changes.": "Manage URL redirects, including those created automatically when a page's address changes.";
29
28
  readonly "Match type": "Match type";
30
29
  readonly "From path": "From path";
31
30
  readonly "To target": "To target";
@@ -46,9 +45,9 @@ export declare function redirects(_required: Record<string, never>, options?: Re
46
45
  readonly "Loading redirects\u2026": "Loading redirects…";
47
46
  readonly "Not valid JSON.": "Not valid JSON.";
48
47
  readonly "Must be a JSON array of rule objects.": "Must be a JSON array of rule objects.";
49
- readonly exact: "exact";
50
- readonly prefix: "prefix";
51
- readonly wildcard: "wildcard";
48
+ readonly exact: "Exact match";
49
+ readonly prefix: "Starts with";
50
+ readonly wildcard: "Wildcard";
52
51
  readonly Status: "Status";
53
52
  readonly More: "More";
54
53
  readonly Delete: "Delete";
@@ -56,8 +55,8 @@ export declare function redirects(_required: Record<string, never>, options?: Re
56
55
  readonly Enable: "Enable";
57
56
  readonly "Saving\u2026": "Saving…";
58
57
  readonly Created: "Created";
59
- readonly active: "active";
60
- readonly disabled: "disabled";
58
+ readonly active: "Active";
59
+ readonly disabled: "Disabled";
61
60
  readonly "{created} created, {failed} failed.": "{created} created, {failed} failed.";
62
61
  readonly "Item {index} ({code})": "Item {index} ({code})";
63
62
  readonly "Actions for redirect rule from \"{fromPattern}\"": "Actions for redirect rule from \"{fromPattern}\"";
@@ -65,6 +64,9 @@ export declare function redirects(_required: Record<string, never>, options?: Re
65
64
  readonly " rule objects (1-500 items)": " rule objects (1-500 items)";
66
65
  readonly "Delete the redirect rule from \"": "Delete the redirect rule from \"";
67
66
  readonly "\"?": "\"?";
67
+ readonly manual: "Manual";
68
+ readonly auto_slug_change: "URL change";
69
+ readonly import: "Imported";
68
70
  };
69
71
  pages: {
70
72
  readonly list: {
@@ -101,8 +103,7 @@ export declare function redirects(_required: Record<string, never>, options?: Re
101
103
  readonly Import: "Import";
102
104
  readonly Marketing: "Marketing";
103
105
  readonly Redirects: "Redirects";
104
- readonly "Manual URL redirect rules. Rules created automatically from a slug change (source": "Manual URL redirect rules. Rules created automatically from a slug change (source";
105
- readonly ") also show up here.": ") also show up here.";
106
+ readonly "Manage URL redirects, including those created automatically when a page's address changes.": "Manage URL redirects, including those created automatically when a page's address changes.";
106
107
  readonly "Match type": "Match type";
107
108
  readonly "From path": "From path";
108
109
  readonly "To target": "To target";
@@ -123,9 +124,9 @@ export declare function redirects(_required: Record<string, never>, options?: Re
123
124
  readonly "Loading redirects\u2026": "Loading redirects…";
124
125
  readonly "Not valid JSON.": "Not valid JSON.";
125
126
  readonly "Must be a JSON array of rule objects.": "Must be a JSON array of rule objects.";
126
- readonly exact: "exact";
127
- readonly prefix: "prefix";
128
- readonly wildcard: "wildcard";
127
+ readonly exact: "Exact match";
128
+ readonly prefix: "Starts with";
129
+ readonly wildcard: "Wildcard";
129
130
  readonly Status: "Status";
130
131
  readonly More: "More";
131
132
  readonly Delete: "Delete";
@@ -133,8 +134,8 @@ export declare function redirects(_required: Record<string, never>, options?: Re
133
134
  readonly Enable: "Enable";
134
135
  readonly "Saving\u2026": "Saving…";
135
136
  readonly Created: "Created";
136
- readonly active: "active";
137
- readonly disabled: "disabled";
137
+ readonly active: "Active";
138
+ readonly disabled: "Disabled";
138
139
  readonly "{created} created, {failed} failed.": "{created} created, {failed} failed.";
139
140
  readonly "Item {index} ({code})": "Item {index} ({code})";
140
141
  readonly "Actions for redirect rule from \"{fromPattern}\"": "Actions for redirect rule from \"{fromPattern}\"";
@@ -142,6 +143,9 @@ export declare function redirects(_required: Record<string, never>, options?: Re
142
143
  readonly " rule objects (1-500 items)": " rule objects (1-500 items)";
143
144
  readonly "Delete the redirect rule from \"": "Delete the redirect rule from \"";
144
145
  readonly "\"?": "\"?";
146
+ readonly manual: "Manual";
147
+ readonly auto_slug_change: "URL change";
148
+ readonly import: "Imported";
145
149
  };
146
150
  readonly pages: {
147
151
  readonly list: {
@@ -176,8 +180,7 @@ export declare function redirects(_required: Record<string, never>, options?: Re
176
180
  readonly Import: "Import";
177
181
  readonly Marketing: "Marketing";
178
182
  readonly Redirects: "Redirects";
179
- readonly "Manual URL redirect rules. Rules created automatically from a slug change (source": "Manual URL redirect rules. Rules created automatically from a slug change (source";
180
- readonly ") also show up here.": ") also show up here.";
183
+ readonly "Manage URL redirects, including those created automatically when a page's address changes.": "Manage URL redirects, including those created automatically when a page's address changes.";
181
184
  readonly "Match type": "Match type";
182
185
  readonly "From path": "From path";
183
186
  readonly "To target": "To target";
@@ -198,9 +201,9 @@ export declare function redirects(_required: Record<string, never>, options?: Re
198
201
  readonly "Loading redirects\u2026": "Loading redirects…";
199
202
  readonly "Not valid JSON.": "Not valid JSON.";
200
203
  readonly "Must be a JSON array of rule objects.": "Must be a JSON array of rule objects.";
201
- readonly exact: "exact";
202
- readonly prefix: "prefix";
203
- readonly wildcard: "wildcard";
204
+ readonly exact: "Exact match";
205
+ readonly prefix: "Starts with";
206
+ readonly wildcard: "Wildcard";
204
207
  readonly Status: "Status";
205
208
  readonly More: "More";
206
209
  readonly Delete: "Delete";
@@ -208,8 +211,8 @@ export declare function redirects(_required: Record<string, never>, options?: Re
208
211
  readonly Enable: "Enable";
209
212
  readonly "Saving\u2026": "Saving…";
210
213
  readonly Created: "Created";
211
- readonly active: "active";
212
- readonly disabled: "disabled";
214
+ readonly active: "Active";
215
+ readonly disabled: "Disabled";
213
216
  readonly "{created} created, {failed} failed.": "{created} created, {failed} failed.";
214
217
  readonly "Item {index} ({code})": "Item {index} ({code})";
215
218
  readonly "Actions for redirect rule from \"{fromPattern}\"": "Actions for redirect rule from \"{fromPattern}\"";
@@ -217,6 +220,9 @@ export declare function redirects(_required: Record<string, never>, options?: Re
217
220
  readonly " rule objects (1-500 items)": " rule objects (1-500 items)";
218
221
  readonly "Delete the redirect rule from \"": "Delete the redirect rule from \"";
219
222
  readonly "\"?": "\"?";
223
+ readonly manual: "Manual";
224
+ readonly auto_slug_change: "URL change";
225
+ readonly import: "Imported";
220
226
  };
221
227
  readonly pages: {
222
228
  readonly list: {
@@ -255,8 +261,7 @@ export declare function redirects(_required: Record<string, never>, options?: Re
255
261
  readonly Import: "Import";
256
262
  readonly Marketing: "Marketing";
257
263
  readonly Redirects: "Redirects";
258
- readonly "Manual URL redirect rules. Rules created automatically from a slug change (source": "Manual URL redirect rules. Rules created automatically from a slug change (source";
259
- readonly ") also show up here.": ") also show up here.";
264
+ readonly "Manage URL redirects, including those created automatically when a page's address changes.": "Manage URL redirects, including those created automatically when a page's address changes.";
260
265
  readonly "Match type": "Match type";
261
266
  readonly "From path": "From path";
262
267
  readonly "To target": "To target";
@@ -277,9 +282,9 @@ export declare function redirects(_required: Record<string, never>, options?: Re
277
282
  readonly "Loading redirects\u2026": "Loading redirects…";
278
283
  readonly "Not valid JSON.": "Not valid JSON.";
279
284
  readonly "Must be a JSON array of rule objects.": "Must be a JSON array of rule objects.";
280
- readonly exact: "exact";
281
- readonly prefix: "prefix";
282
- readonly wildcard: "wildcard";
285
+ readonly exact: "Exact match";
286
+ readonly prefix: "Starts with";
287
+ readonly wildcard: "Wildcard";
283
288
  readonly Status: "Status";
284
289
  readonly More: "More";
285
290
  readonly Delete: "Delete";
@@ -287,8 +292,8 @@ export declare function redirects(_required: Record<string, never>, options?: Re
287
292
  readonly Enable: "Enable";
288
293
  readonly "Saving\u2026": "Saving…";
289
294
  readonly Created: "Created";
290
- readonly active: "active";
291
- readonly disabled: "disabled";
295
+ readonly active: "Active";
296
+ readonly disabled: "Disabled";
292
297
  readonly "{created} created, {failed} failed.": "{created} created, {failed} failed.";
293
298
  readonly "Item {index} ({code})": "Item {index} ({code})";
294
299
  readonly "Actions for redirect rule from \"{fromPattern}\"": "Actions for redirect rule from \"{fromPattern}\"";
@@ -296,6 +301,9 @@ export declare function redirects(_required: Record<string, never>, options?: Re
296
301
  readonly " rule objects (1-500 items)": " rule objects (1-500 items)";
297
302
  readonly "Delete the redirect rule from \"": "Delete the redirect rule from \"";
298
303
  readonly "\"?": "\"?";
304
+ readonly manual: "Manual";
305
+ readonly auto_slug_change: "URL change";
306
+ readonly import: "Imported";
299
307
  };
300
308
  readonly pages: {
301
309
  readonly list: {
@@ -15,6 +15,6 @@ export function RedirectsPage({ useRedirectsHook = useWiredRedirects } = {}) {
15
15
  }
16
16
  if (!redirects)
17
17
  return _jsx("div", { className: "notice", children: t("Loading redirects…") });
18
- return (_jsxs("div", { className: "page", children: [_jsxs("div", { className: "page-header", children: [_jsxs("div", { className: "page-header-text", children: [_jsx("p", { className: "page-kicker", children: t("Marketing") }), _jsx("h1", { className: "page-title", children: t("Redirects") }), _jsxs("p", { className: "page-description", children: [t("Manual URL redirect rules. Rules created automatically from a slug change (source"), _jsx("code", { children: " auto_slug_change" }), t(") also show up here.")] })] }), _jsx("div", { className: "page-actions", children: headerActions })] }), error ? _jsx("div", { className: "notice error", children: describeApiError({ e: error, fallback: "request failed" }) }) : null, _jsxs("form", { className: "card form-measure", onSubmit: submitCreate, children: [_jsx("div", { className: "field-group", children: _jsxs("div", { className: "field-row", children: [_jsxs("div", { className: "field", children: [_jsx("label", { className: "field-label", htmlFor: "redirect-match-type", children: t("Match type") }), _jsxs("select", { id: "redirect-match-type", name: "matchType", defaultValue: "exact", ...agentHandle({ handle: "redirects-create-match-type" }, { role: "field", label: "New redirect's match type" }), children: [_jsx("option", { value: "exact", children: t("exact") }), _jsx("option", { value: "prefix", children: t("prefix") }), _jsx("option", { value: "wildcard", children: t("wildcard") })] })] }), _jsxs("div", { className: "field", children: [_jsx("label", { className: "field-label", htmlFor: "redirect-from-pattern", children: t("From path") }), _jsx("input", { id: "redirect-from-pattern", name: "fromPattern", placeholder: "/old-path", required: true, ...agentHandle({ handle: "redirects-create-from-pattern" }, { role: "field", label: "New redirect's source path or pattern" }) })] }), _jsxs("div", { className: "field", children: [_jsx("label", { className: "field-label", htmlFor: "redirect-to-target", children: t("To target") }), _jsx("input", { id: "redirect-to-target", name: "toTarget", placeholder: "/new-path or https://example.com/...", required: true, ...agentHandle({ handle: "redirects-create-to-target" }, { role: "field", label: "New redirect's destination path or URL" }) })] }), _jsxs("div", { className: "field", children: [_jsx("label", { className: "field-label", htmlFor: "redirect-status-code", children: t("Status code") }), _jsxs("select", { id: "redirect-status-code", name: "statusCode", defaultValue: "301", ...agentHandle({ handle: "redirects-create-status-code" }, { role: "field", label: "New redirect's HTTP status code" }), children: [_jsx("option", { value: "301", children: t("301 (permanent)") }), _jsx("option", { value: "302", children: t("302 (temporary)") }), _jsx("option", { value: "307", children: t("307 (temporary, method-preserving)") }), _jsx("option", { value: "308", children: t("308 (permanent, method-preserving)") })] })] })] }) }), _jsx("div", { className: "editor-actions form-actions", children: _jsx("button", { type: "submit", disabled: saving, ...agentHandle({ handle: "redirects-create-submit" }, { role: "button", label: "Add this redirect rule" }), children: saving ? t("Saving…") : t("Add redirect") }) })] }), _jsx(ImportRedirectsForm, { t: t, locale: locale }), _jsx(DataTable, { rows: redirects, rowKey: (rule) => rule.id, empty: _jsx("div", { className: "card", children: _jsx("div", { className: "empty-state", children: _jsx("p", { children: t("No redirect rules yet.") }) }) }), columns: columns }), _jsx(ConfirmDialog, { open: pendingDelete !== null, agentHandle: "redirects-delete", title: t("Delete redirect rule?"), body: deleteBody, confirmLabel: t("Delete"), destructive: true, pending: deletePending, onConfirm: confirmDelete, onCancel: cancelDelete })] }));
18
+ return (_jsxs("div", { className: "page", children: [_jsxs("div", { className: "page-header", children: [_jsxs("div", { className: "page-header-text", children: [_jsx("p", { className: "page-kicker", children: t("Marketing") }), _jsx("h1", { className: "page-title", children: t("Redirects") }), _jsx("p", { className: "page-description", children: t("Manage URL redirects, including those created automatically when a page's address changes.") })] }), _jsx("div", { className: "page-actions", children: headerActions })] }), error ? _jsx("div", { className: "notice error", children: describeApiError({ e: error, fallback: "request failed" }) }) : null, _jsxs("form", { className: "card form-measure", onSubmit: submitCreate, children: [_jsx("div", { className: "field-group", children: _jsxs("div", { className: "field-row", children: [_jsxs("div", { className: "field", children: [_jsx("label", { className: "field-label", htmlFor: "redirect-match-type", children: t("Match type") }), _jsxs("select", { id: "redirect-match-type", name: "matchType", defaultValue: "exact", ...agentHandle({ handle: "redirects-create-match-type" }, { role: "field", label: "New redirect's match type" }), children: [_jsx("option", { value: "exact", children: t("exact", { serverLabel: "exact" }) }), _jsx("option", { value: "prefix", children: t("prefix", { serverLabel: "prefix" }) }), _jsx("option", { value: "wildcard", children: t("wildcard", { serverLabel: "wildcard" }) })] })] }), _jsxs("div", { className: "field", children: [_jsx("label", { className: "field-label", htmlFor: "redirect-from-pattern", children: t("From path") }), _jsx("input", { id: "redirect-from-pattern", name: "fromPattern", placeholder: "/old-path", required: true, ...agentHandle({ handle: "redirects-create-from-pattern" }, { role: "field", label: "New redirect's source path or pattern" }) })] }), _jsxs("div", { className: "field", children: [_jsx("label", { className: "field-label", htmlFor: "redirect-to-target", children: t("To target") }), _jsx("input", { id: "redirect-to-target", name: "toTarget", placeholder: "/new-path or https://example.com/...", required: true, ...agentHandle({ handle: "redirects-create-to-target" }, { role: "field", label: "New redirect's destination path or URL" }) })] }), _jsxs("div", { className: "field", children: [_jsx("label", { className: "field-label", htmlFor: "redirect-status-code", children: t("Status code") }), _jsxs("select", { id: "redirect-status-code", name: "statusCode", defaultValue: "301", ...agentHandle({ handle: "redirects-create-status-code" }, { role: "field", label: "New redirect's HTTP status code" }), children: [_jsx("option", { value: "301", children: t("301 (permanent)") }), _jsx("option", { value: "302", children: t("302 (temporary)") }), _jsx("option", { value: "307", children: t("307 (temporary, method-preserving)") }), _jsx("option", { value: "308", children: t("308 (permanent, method-preserving)") })] })] })] }) }), _jsx("div", { className: "editor-actions form-actions", children: _jsx("button", { type: "submit", disabled: saving, ...agentHandle({ handle: "redirects-create-submit" }, { role: "button", label: "Add this redirect rule" }), children: saving ? t("Saving…") : t("Add redirect") }) })] }), _jsx(ImportRedirectsForm, { t: t, locale: locale }), _jsx(DataTable, { rows: redirects, rowKey: (rule) => rule.id, empty: _jsx("div", { className: "card", children: _jsx("div", { className: "empty-state", children: _jsx("p", { children: t("No redirect rules yet.") }) }) }), columns: columns }), _jsx(ConfirmDialog, { open: pendingDelete !== null, agentHandle: "redirects-delete", title: t("Delete redirect rule?"), body: deleteBody, confirmLabel: t("Delete"), destructive: true, pending: deletePending, onConfirm: confirmDelete, onCancel: cancelDelete })] }));
19
19
  }
20
20
  //# sourceMappingURL=RedirectsPage.js.map
@@ -16,8 +16,7 @@ export declare const redirectsModule: {
16
16
  readonly Import: "Import";
17
17
  readonly Marketing: "Marketing";
18
18
  readonly Redirects: "Redirects";
19
- readonly "Manual URL redirect rules. Rules created automatically from a slug change (source": "Manual URL redirect rules. Rules created automatically from a slug change (source";
20
- readonly ") also show up here.": ") also show up here.";
19
+ readonly "Manage URL redirects, including those created automatically when a page's address changes.": "Manage URL redirects, including those created automatically when a page's address changes.";
21
20
  readonly "Match type": "Match type";
22
21
  readonly "From path": "From path";
23
22
  readonly "To target": "To target";
@@ -38,9 +37,9 @@ export declare const redirectsModule: {
38
37
  readonly "Loading redirects\u2026": "Loading redirects…";
39
38
  readonly "Not valid JSON.": "Not valid JSON.";
40
39
  readonly "Must be a JSON array of rule objects.": "Must be a JSON array of rule objects.";
41
- readonly exact: "exact";
42
- readonly prefix: "prefix";
43
- readonly wildcard: "wildcard";
40
+ readonly exact: "Exact match";
41
+ readonly prefix: "Starts with";
42
+ readonly wildcard: "Wildcard";
44
43
  readonly Status: "Status";
45
44
  readonly More: "More";
46
45
  readonly Delete: "Delete";
@@ -48,8 +47,8 @@ export declare const redirectsModule: {
48
47
  readonly Enable: "Enable";
49
48
  readonly "Saving\u2026": "Saving…";
50
49
  readonly Created: "Created";
51
- readonly active: "active";
52
- readonly disabled: "disabled";
50
+ readonly active: "Active";
51
+ readonly disabled: "Disabled";
53
52
  readonly "{created} created, {failed} failed.": "{created} created, {failed} failed.";
54
53
  readonly "Item {index} ({code})": "Item {index} ({code})";
55
54
  readonly "Actions for redirect rule from \"{fromPattern}\"": "Actions for redirect rule from \"{fromPattern}\"";
@@ -57,6 +56,9 @@ export declare const redirectsModule: {
57
56
  readonly " rule objects (1-500 items)": " rule objects (1-500 items)";
58
57
  readonly "Delete the redirect rule from \"": "Delete the redirect rule from \"";
59
58
  readonly "\"?": "\"?";
59
+ readonly manual: "Manual";
60
+ readonly auto_slug_change: "URL change";
61
+ readonly import: "Imported";
60
62
  };
61
63
  readonly pages: {
62
64
  readonly list: {
@@ -22,10 +22,10 @@ export declare const seoMessagesEn: {
22
22
  readonly Nofollow: "Nofollow";
23
23
  readonly "OG title": "OG title";
24
24
  readonly "OG description": "OG description";
25
- readonly "OG image (media ref or URL)": "OG image (media ref or URL)";
25
+ readonly "OG image": "OG image";
26
26
  readonly "Twitter title": "Twitter title";
27
27
  readonly "Twitter description": "Twitter description";
28
- readonly "Twitter image (media ref or URL)": "Twitter image (media ref or URL)";
28
+ readonly "Twitter image": "Twitter image";
29
29
  readonly "Saving\u2026": "Saving…";
30
30
  readonly "Save overrides": "Save overrides";
31
31
  readonly "Per-entry SEO": "Per-entry SEO";
@@ -33,7 +33,7 @@ export declare const seoMessagesEn: {
33
33
  readonly "Title template (must contain %s)": "Title template (must contain %s)";
34
34
  readonly "Default meta description": "Default meta description";
35
35
  readonly "Social sharing": "Social sharing";
36
- readonly "Default Open Graph / Twitter image (media ref)": "Default Open Graph / Twitter image (media ref)";
36
+ readonly "Default Open Graph / Twitter image": "Default Open Graph / Twitter image";
37
37
  readonly "Twitter @site handle": "Twitter @site handle";
38
38
  readonly Crawling: "Crawling";
39
39
  readonly "Default noindex": "Default noindex";
@@ -41,7 +41,7 @@ export declare const seoMessagesEn: {
41
41
  readonly "Sitemap enabled": "Sitemap enabled";
42
42
  readonly "Save settings": "Save settings";
43
43
  readonly "Cached sitemap": "Cached sitemap";
44
- readonly "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.": "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.";
44
+ readonly "Rebuild the sitemap now to include the latest published content.": "Rebuild the sitemap now to include the latest published content.";
45
45
  readonly "Working\u2026": "Working…";
46
46
  readonly "Regenerate sitemap": "Regenerate sitemap";
47
47
  readonly "View sitemap": "View sitemap";
@@ -74,5 +74,6 @@ export declare const seoMessagesEn: {
74
74
  readonly "failed to regenerate sitemap": "failed to regenerate sitemap";
75
75
  readonly "failed to load the sitemap": "failed to load the sitemap";
76
76
  readonly "Could not load the sitemap (HTTP {status}).": "Could not load the sitemap (HTTP {status}).";
77
+ readonly "Selected image": "Selected image";
77
78
  };
78
79
  //# sourceMappingURL=messages.en.d.ts.map
@@ -22,10 +22,10 @@ export const seoMessagesEn = {
22
22
  "Nofollow": "Nofollow",
23
23
  "OG title": "OG title",
24
24
  "OG description": "OG description",
25
- "OG image (media ref or URL)": "OG image (media ref or URL)",
25
+ "OG image": "OG image",
26
26
  "Twitter title": "Twitter title",
27
27
  "Twitter description": "Twitter description",
28
- "Twitter image (media ref or URL)": "Twitter image (media ref or URL)",
28
+ "Twitter image": "Twitter image",
29
29
  "Saving…": "Saving…",
30
30
  "Save overrides": "Save overrides",
31
31
  "Per-entry SEO": "Per-entry SEO",
@@ -33,7 +33,7 @@ export const seoMessagesEn = {
33
33
  "Title template (must contain %s)": "Title template (must contain %s)",
34
34
  "Default meta description": "Default meta description",
35
35
  "Social sharing": "Social sharing",
36
- "Default Open Graph / Twitter image (media ref)": "Default Open Graph / Twitter image (media ref)",
36
+ "Default Open Graph / Twitter image": "Default Open Graph / Twitter image",
37
37
  "Twitter @site handle": "Twitter @site handle",
38
38
  "Crawling": "Crawling",
39
39
  "Default noindex": "Default noindex",
@@ -41,7 +41,7 @@ export const seoMessagesEn = {
41
41
  "Sitemap enabled": "Sitemap enabled",
42
42
  "Save settings": "Save settings",
43
43
  "Cached sitemap": "Cached sitemap",
44
- "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.": "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.",
44
+ "Rebuild the sitemap now to include the latest published content.": "Rebuild the sitemap now to include the latest published content.",
45
45
  "Working…": "Working…",
46
46
  "Regenerate sitemap": "Regenerate sitemap",
47
47
  "View sitemap": "View sitemap",
@@ -73,6 +73,7 @@ export const seoMessagesEn = {
73
73
  "Sitemap regeneration accepted.": "Sitemap regeneration accepted.",
74
74
  "failed to regenerate sitemap": "failed to regenerate sitemap",
75
75
  "failed to load the sitemap": "failed to load the sitemap",
76
- "Could not load the sitemap (HTTP {status}).": "Could not load the sitemap (HTTP {status})."
76
+ "Could not load the sitemap (HTTP {status}).": "Could not load the sitemap (HTTP {status}).",
77
+ "Selected image": "Selected image",
77
78
  };
78
79
  //# sourceMappingURL=messages.en.js.map
@@ -12,6 +12,10 @@ import { useWiredMediaRefField } from "../hooks/MediaRefField.hooks.js";
12
12
  * `react/hooks/MediaRefField.hooks.ts`, split out the same way `MediaPickerDialog`/`MediaPickerDialog.hooks
13
13
  * .tsx` does; this file stays props-and-JSX only. `MediaPickerDialog` itself is reused unchanged
14
14
  * (`components/MediaPickerDialog/MediaPickerDialog.tsx`) — no fork, no new picker UI.
15
+ *
16
+ * 2026-10-08 polish: the original editable-input rationale above still applies to pasted URLs
17
+ * and empty fields. A selected library reference now shows plain copy with its preview; Remove
18
+ * returns to manual entry. A hidden input preserves the exact FormData value on defaults saves.
15
19
  */
16
20
  export interface MediaRefFieldProps {
17
21
  locale: string;
@@ -5,8 +5,8 @@ import { useSeoCopy } from "../hooks/SeoPorts.hooks.js";
5
5
  import { useWiredMediaRefField, useMediaRefPresentation, handleSpread } from "../hooks/MediaRefField.hooks.js";
6
6
  export function MediaRefField({ locale, id, name, label, value, onChange, agentHandle: base, useField = useWiredMediaRefField, }, _optional = {}) {
7
7
  const t = useSeoCopy();
8
- const { Picker = MediaPickerBridge } = useMediaRefPresentation();
8
+ const { Picker = MediaPickerBridge, storedReference } = useMediaRefPresentation({ value });
9
9
  const { pickerOpen, openPicker, closePicker, handleSelect, clear, previewUrl, accept } = useField({ value, onChange });
10
- return (_jsxs("div", { className: "field media-ref-field", children: [_jsx("label", { className: "field-label", htmlFor: id, children: label }), _jsxs("div", { className: "media-ref-field-row", children: [_jsx("input", { id: id, name: name, value: value, onChange: (e) => onChange(e.target.value), ...(base ? agentHandle({ handle: base }, { role: "field", label }) : {}) }), _jsx("button", { type: "button", className: "btn-secondary", onClick: openPicker, ...handleSpread({ ...(base === undefined ? {} : { base }), suffix: "choose", label: `Choose an image for: ${label}` }), children: t({ locale: locale, key: "Choose image" }) }), value ? (_jsx("button", { type: "button", className: "btn-secondary", onClick: clear, ...handleSpread({ ...(base === undefined ? {} : { base }), suffix: "clear", label: `Remove the selected image for: ${label}` }), children: t({ locale: locale, key: "Remove" }) })) : null] }), previewUrl ? _jsx("img", { className: "media-ref-field-preview", src: previewUrl, alt: `${label} preview` }) : null, pickerOpen ? (_jsx(Picker, { onSelect: handleSelect, onCancel: closePicker, accept: accept, agentHandle: base ? `${base}-dialog` : undefined })) : null] }));
10
+ return (_jsxs("div", { className: "jini-field jini-media-ref-field", children: [_jsx("label", { className: "jini-field-label", htmlFor: id, children: label }), _jsxs("div", { className: "jini-media-ref-field-row", children: [_jsx("input", { className: "jini-input", id: id, name: storedReference ? undefined : name, value: storedReference ? t({ locale, key: "Selected image" }) : value, readOnly: storedReference, onChange: (e) => onChange(e.target.value), ...(base ? agentHandle({ handle: base }, { role: "field", label }) : {}) }), storedReference && name ? _jsx("input", { type: "hidden", name: name, value: value }) : null, _jsx("button", { type: "button", className: "jini-btn jini-btn-secondary", onClick: openPicker, ...handleSpread({ ...(base === undefined ? {} : { base }), suffix: "choose", label: `Choose an image for: ${label}` }), children: t({ locale: locale, key: "Choose image" }) }), value ? (_jsx("button", { type: "button", className: "jini-btn jini-btn-secondary", onClick: clear, ...handleSpread({ ...(base === undefined ? {} : { base }), suffix: "clear", label: `Remove the selected image for: ${label}` }), children: t({ locale: locale, key: "Remove" }) })) : null] }), previewUrl ? _jsx("img", { className: "jini-media-ref-field-preview", src: previewUrl, alt: `${label} preview` }) : null, pickerOpen ? (_jsx(Picker, { onSelect: handleSelect, onCancel: closePicker, accept: accept, agentHandle: base ? `${base}-dialog` : undefined })) : null] }));
11
11
  }
12
12
  //# sourceMappingURL=MediaRefField.js.map
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { agentHandle } from "@jini-ai/agentic";
3
3
  import { Dialog } from "@jini-ai/ui-kit/react";
4
- import { useSeoCopy } from "../hooks/SeoPorts.hooks.js";
4
+ import { formatTimestamp } from "@jini-ai/ui/panel-kit";
5
+ import { useSeoCopy, useSeoOptions } from "../hooks/SeoPorts.hooks.js";
5
6
  import { actionLabel } from "../../rules.js";
6
7
  import { useWiredSitemapModal } from "../hooks/use-sitemap-modal.hooks.js";
7
8
  import { useSitemapModalRegenerate, useSitemapPresentation, useSitemapTable, useSitemapViewToggle } from "../hooks/SitemapModal.hooks.js";
@@ -30,13 +31,14 @@ function SitemapModalHeaderActions({ locale, modal }) {
30
31
  * `useSitemapModal` (memoized there), this only maps them to JSX. */
31
32
  function SitemapModalTable({ locale, modal }) {
32
33
  const t = useSeoCopy();
34
+ const { formatDate = formatTimestamp } = useSeoOptions();
33
35
  const { rowHandles } = useSitemapTable({ modal });
34
36
  if (modal.entries.length === 0)
35
37
  return _jsx("div", { className: "notice", children: t({ locale: locale, key: "The sitemap has no URLs yet." }) });
36
38
  return (_jsxs(_Fragment, { children: [_jsx("input", { type: "search", className: "sitemap-modal-filter", "aria-label": t({ locale: locale, key: "Filter sitemap URLs" }), placeholder: t({ locale: locale, key: "Filter by URL…" }), value: modal.filter, onChange: (e) => modal.setFilter(e.target.value), ...agentHandle({ handle: "seo-sitemap-filter" }, {
37
39
  role: "field",
38
40
  label: "Narrow the sitemap table by a substring match on the URL",
39
- }) }), modal.filteredEntries.length === 0 ? (_jsx("p", { className: "muted-cell", children: t({ locale: locale, key: "No URLs match this filter." }) })) : (_jsx("div", { className: "table-scroll", children: _jsxs("table", { className: "list-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: t({ locale: locale, key: "URL" }) }), _jsx("th", { children: t({ locale: locale, key: "Last modified" }) })] }) }), _jsx("tbody", { children: modal.filteredEntries.map((entry, index) => (_jsxs("tr", { children: [_jsx("td", { children: _jsx("a", { href: entry.loc, target: "_blank", rel: "noreferrer", ...agentHandle({ handle: rowHandles[index] }, { role: "link", label: "Open this URL on the live site" }), children: entry.loc }) }), _jsx("td", { children: entry.lastmod ?? _jsx("span", { className: "muted-cell", children: t({ locale: locale, key: "—" }) }) })] }, entry.loc))) })] }) }))] }));
41
+ }) }), modal.filteredEntries.length === 0 ? (_jsx("p", { className: "muted-cell", children: t({ locale: locale, key: "No URLs match this filter." }) })) : (_jsx("div", { className: "table-scroll", children: _jsxs("table", { className: "list-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: t({ locale: locale, key: "URL" }) }), _jsx("th", { children: t({ locale: locale, key: "Last modified" }) })] }) }), _jsx("tbody", { children: modal.filteredEntries.map((entry, index) => (_jsxs("tr", { children: [_jsx("td", { children: _jsx("a", { href: entry.loc, target: "_blank", rel: "noreferrer", ...agentHandle({ handle: rowHandles[index] }, { role: "link", label: "Open this URL on the live site" }), children: entry.loc }) }), _jsx("td", { children: entry.lastmod === null ? _jsx("span", { className: "muted-cell", children: t({ locale: locale, key: "—" }) }) : formatDate({ iso: entry.lastmod }) })] }, entry.loc))) })] }) }))] }));
40
42
  }
41
43
  /** The body's content-status switch (REQ 8/9: disabled, loading, error, then raw-vs-table) — kept
42
44
  * as its own flat sequence of guards rather than a nested ternary inline in {@link SitemapModal}.
@@ -11,8 +11,11 @@ export declare function useWiredMediaRefField({ value, onChange }: {
11
11
  onChange: (value: string) => void;
12
12
  }, _optional?: Record<string, never>): MediaRefFieldController;
13
13
  /** Slot or existing promise picker; no picker implementation is forked into SEO. */
14
- export declare function useMediaRefPresentation(_required?: Record<string, never>, _optional?: Record<string, never>): {
14
+ export declare function useMediaRefPresentation({ value }: {
15
+ value: string;
16
+ }, _optional?: Record<string, never>): {
15
17
  Picker: import("react").ComponentType<import("../options.js").SeoMediaPickerSlotProps> | undefined;
18
+ storedReference: boolean;
16
19
  };
17
20
  export declare function handleSpread({ base, suffix, label }: {
18
21
  base?: string;
@@ -2,7 +2,7 @@ import { useRef } from 'react';
2
2
  import { agentHandle } from '@jini-ai/agentic';
3
3
  import { useController } from '../../../core/react/use-controller.js';
4
4
  import { createMediaRefController } from '../../controllers/media-ref.controller.js';
5
- import { resolveMediaRefPreviewUrl } from '../../rules.js';
5
+ import { isStoredMediaRef, resolveMediaRefPreviewUrl } from '../../rules.js';
6
6
  import { useSeoPorts, useSeoOptions } from './SeoPorts.hooks.js';
7
7
  export function useMediaRefField({ value, onChange, api }, _optional = {}) {
8
8
  const change = useRef(onChange);
@@ -20,9 +20,9 @@ export function useWiredMediaRefField({ value, onChange }, _optional = {}) {
20
20
  return useMediaRefField({ value, onChange, api });
21
21
  }
22
22
  /** Slot or existing promise picker; no picker implementation is forked into SEO. */
23
- export function useMediaRefPresentation(_required = {}, _optional = {}) {
23
+ export function useMediaRefPresentation({ value }, _optional = {}) {
24
24
  const { slots } = useSeoOptions();
25
- return { Picker: slots?.MediaPickerDialog };
25
+ return { Picker: slots?.MediaPickerDialog, storedReference: isStoredMediaRef({ value }) };
26
26
  }
27
27
  export function handleSpread({ base, suffix, label }, _optional = {}) {
28
28
  return base ? agentHandle({ handle: `${base}-${suffix}` }, { role: 'button', label }) : {};
@@ -38,10 +38,10 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
38
38
  readonly Nofollow: "Nofollow";
39
39
  readonly "OG title": "OG title";
40
40
  readonly "OG description": "OG description";
41
- readonly "OG image (media ref or URL)": "OG image (media ref or URL)";
41
+ readonly "OG image": "OG image";
42
42
  readonly "Twitter title": "Twitter title";
43
43
  readonly "Twitter description": "Twitter description";
44
- readonly "Twitter image (media ref or URL)": "Twitter image (media ref or URL)";
44
+ readonly "Twitter image": "Twitter image";
45
45
  readonly "Saving\u2026": "Saving…";
46
46
  readonly "Save overrides": "Save overrides";
47
47
  readonly "Per-entry SEO": "Per-entry SEO";
@@ -49,7 +49,7 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
49
49
  readonly "Title template (must contain %s)": "Title template (must contain %s)";
50
50
  readonly "Default meta description": "Default meta description";
51
51
  readonly "Social sharing": "Social sharing";
52
- readonly "Default Open Graph / Twitter image (media ref)": "Default Open Graph / Twitter image (media ref)";
52
+ readonly "Default Open Graph / Twitter image": "Default Open Graph / Twitter image";
53
53
  readonly "Twitter @site handle": "Twitter @site handle";
54
54
  readonly Crawling: "Crawling";
55
55
  readonly "Default noindex": "Default noindex";
@@ -57,7 +57,7 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
57
57
  readonly "Sitemap enabled": "Sitemap enabled";
58
58
  readonly "Save settings": "Save settings";
59
59
  readonly "Cached sitemap": "Cached sitemap";
60
- readonly "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.": "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.";
60
+ readonly "Rebuild the sitemap now to include the latest published content.": "Rebuild the sitemap now to include the latest published content.";
61
61
  readonly "Working\u2026": "Working…";
62
62
  readonly "Regenerate sitemap": "Regenerate sitemap";
63
63
  readonly "View sitemap": "View sitemap";
@@ -90,6 +90,7 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
90
90
  readonly "failed to regenerate sitemap": "failed to regenerate sitemap";
91
91
  readonly "failed to load the sitemap": "failed to load the sitemap";
92
92
  readonly "Could not load the sitemap (HTTP {status}).": "Could not load the sitemap (HTTP {status}).";
93
+ readonly "Selected image": "Selected image";
93
94
  };
94
95
  pages: {
95
96
  readonly settings: {
@@ -159,10 +160,10 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
159
160
  readonly Nofollow: "Nofollow";
160
161
  readonly "OG title": "OG title";
161
162
  readonly "OG description": "OG description";
162
- readonly "OG image (media ref or URL)": "OG image (media ref or URL)";
163
+ readonly "OG image": "OG image";
163
164
  readonly "Twitter title": "Twitter title";
164
165
  readonly "Twitter description": "Twitter description";
165
- readonly "Twitter image (media ref or URL)": "Twitter image (media ref or URL)";
166
+ readonly "Twitter image": "Twitter image";
166
167
  readonly "Saving\u2026": "Saving…";
167
168
  readonly "Save overrides": "Save overrides";
168
169
  readonly "Per-entry SEO": "Per-entry SEO";
@@ -170,7 +171,7 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
170
171
  readonly "Title template (must contain %s)": "Title template (must contain %s)";
171
172
  readonly "Default meta description": "Default meta description";
172
173
  readonly "Social sharing": "Social sharing";
173
- readonly "Default Open Graph / Twitter image (media ref)": "Default Open Graph / Twitter image (media ref)";
174
+ readonly "Default Open Graph / Twitter image": "Default Open Graph / Twitter image";
174
175
  readonly "Twitter @site handle": "Twitter @site handle";
175
176
  readonly Crawling: "Crawling";
176
177
  readonly "Default noindex": "Default noindex";
@@ -178,7 +179,7 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
178
179
  readonly "Sitemap enabled": "Sitemap enabled";
179
180
  readonly "Save settings": "Save settings";
180
181
  readonly "Cached sitemap": "Cached sitemap";
181
- readonly "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.": "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.";
182
+ readonly "Rebuild the sitemap now to include the latest published content.": "Rebuild the sitemap now to include the latest published content.";
182
183
  readonly "Working\u2026": "Working…";
183
184
  readonly "Regenerate sitemap": "Regenerate sitemap";
184
185
  readonly "View sitemap": "View sitemap";
@@ -211,6 +212,7 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
211
212
  readonly "failed to regenerate sitemap": "failed to regenerate sitemap";
212
213
  readonly "failed to load the sitemap": "failed to load the sitemap";
213
214
  readonly "Could not load the sitemap (HTTP {status}).": "Could not load the sitemap (HTTP {status}).";
215
+ readonly "Selected image": "Selected image";
214
216
  };
215
217
  readonly pages: {
216
218
  readonly settings: {
@@ -281,10 +283,10 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
281
283
  readonly Nofollow: "Nofollow";
282
284
  readonly "OG title": "OG title";
283
285
  readonly "OG description": "OG description";
284
- readonly "OG image (media ref or URL)": "OG image (media ref or URL)";
286
+ readonly "OG image": "OG image";
285
287
  readonly "Twitter title": "Twitter title";
286
288
  readonly "Twitter description": "Twitter description";
287
- readonly "Twitter image (media ref or URL)": "Twitter image (media ref or URL)";
289
+ readonly "Twitter image": "Twitter image";
288
290
  readonly "Saving\u2026": "Saving…";
289
291
  readonly "Save overrides": "Save overrides";
290
292
  readonly "Per-entry SEO": "Per-entry SEO";
@@ -292,7 +294,7 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
292
294
  readonly "Title template (must contain %s)": "Title template (must contain %s)";
293
295
  readonly "Default meta description": "Default meta description";
294
296
  readonly "Social sharing": "Social sharing";
295
- readonly "Default Open Graph / Twitter image (media ref)": "Default Open Graph / Twitter image (media ref)";
297
+ readonly "Default Open Graph / Twitter image": "Default Open Graph / Twitter image";
296
298
  readonly "Twitter @site handle": "Twitter @site handle";
297
299
  readonly Crawling: "Crawling";
298
300
  readonly "Default noindex": "Default noindex";
@@ -300,7 +302,7 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
300
302
  readonly "Sitemap enabled": "Sitemap enabled";
301
303
  readonly "Save settings": "Save settings";
302
304
  readonly "Cached sitemap": "Cached sitemap";
303
- readonly "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.": "Force-rebuild the cached sitemap now, bypassing the normal cache-hit path.";
305
+ readonly "Rebuild the sitemap now to include the latest published content.": "Rebuild the sitemap now to include the latest published content.";
304
306
  readonly "Working\u2026": "Working…";
305
307
  readonly "Regenerate sitemap": "Regenerate sitemap";
306
308
  readonly "View sitemap": "View sitemap";
@@ -333,6 +335,7 @@ export declare function seo({ siteUrl }: Pick<SeoReactOptions, 'siteUrl'>, optio
333
335
  readonly "failed to regenerate sitemap": "failed to regenerate sitemap";
334
336
  readonly "failed to load the sitemap": "failed to load the sitemap";
335
337
  readonly "Could not load the sitemap (HTTP {status}).": "Could not load the sitemap (HTTP {status}).";
338
+ readonly "Selected image": "Selected image";
336
339
  };
337
340
  readonly pages: {
338
341
  readonly settings: {
@@ -11,6 +11,13 @@ export interface SeoReactOptions {
11
11
  siteUrl: () => string;
12
12
  t?: SeoTranslator | undefined;
13
13
  describeError?: SeoErrorFormatter | undefined;
14
+ /** Format parsed lastmod values in the host's live locale/timezone; raw XML remains untouched.
15
+ * Omit to use the shared compact ISO timestamp display.
16
+ * @example ({ iso }) => formDateDisplay({ iso, locale }).text
17
+ */
18
+ formatDate?: ((required: {
19
+ iso: string;
20
+ }, optional?: Record<string, never>) => string) | undefined;
14
21
  headerActions?: ReactNode;
15
22
  slots?: {
16
23
  MediaPickerDialog?: ComponentType<SeoMediaPickerSlotProps>;