@jini-ai/admin 0.1.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.
Files changed (235) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +138 -0
  3. package/dist/browser/index.d.ts +8 -0
  4. package/dist/browser/index.d.ts.map +1 -0
  5. package/dist/browser/index.js +8 -0
  6. package/dist/browser/index.js.map +1 -0
  7. package/dist/browser/navigation.d.ts +39 -0
  8. package/dist/browser/navigation.d.ts.map +1 -0
  9. package/dist/browser/navigation.js +113 -0
  10. package/dist/browser/navigation.js.map +1 -0
  11. package/dist/core/gated/types.d.ts +87 -0
  12. package/dist/core/gated/types.d.ts.map +1 -0
  13. package/dist/core/gated/types.js +37 -0
  14. package/dist/core/gated/types.js.map +1 -0
  15. package/dist/core/index.d.ts +20 -0
  16. package/dist/core/index.d.ts.map +1 -0
  17. package/dist/core/index.js +15 -0
  18. package/dist/core/index.js.map +1 -0
  19. package/dist/core/manifest/rules.d.ts +84 -0
  20. package/dist/core/manifest/rules.d.ts.map +1 -0
  21. package/dist/core/manifest/rules.js +130 -0
  22. package/dist/core/manifest/rules.js.map +1 -0
  23. package/dist/core/manifest/types.d.ts +154 -0
  24. package/dist/core/manifest/types.d.ts.map +1 -0
  25. package/dist/core/manifest/types.js +31 -0
  26. package/dist/core/manifest/types.js.map +1 -0
  27. package/dist/core/permissions/rules.d.ts +32 -0
  28. package/dist/core/permissions/rules.d.ts.map +1 -0
  29. package/dist/core/permissions/rules.js +34 -0
  30. package/dist/core/permissions/rules.js.map +1 -0
  31. package/dist/core/ports/analytics.d.ts +35 -0
  32. package/dist/core/ports/analytics.d.ts.map +1 -0
  33. package/dist/core/ports/analytics.js +14 -0
  34. package/dist/core/ports/analytics.js.map +1 -0
  35. package/dist/core/ports/auth.d.ts +49 -0
  36. package/dist/core/ports/auth.d.ts.map +1 -0
  37. package/dist/core/ports/auth.js +19 -0
  38. package/dist/core/ports/auth.js.map +1 -0
  39. package/dist/core/ports/comments.d.ts +90 -0
  40. package/dist/core/ports/comments.d.ts.map +1 -0
  41. package/dist/core/ports/comments.js +24 -0
  42. package/dist/core/ports/comments.js.map +1 -0
  43. package/dist/core/ports/database.d.ts +101 -0
  44. package/dist/core/ports/database.d.ts.map +1 -0
  45. package/dist/core/ports/database.js +2 -0
  46. package/dist/core/ports/database.js.map +1 -0
  47. package/dist/core/ports/forms.d.ts +130 -0
  48. package/dist/core/ports/forms.d.ts.map +1 -0
  49. package/dist/core/ports/forms.js +62 -0
  50. package/dist/core/ports/forms.js.map +1 -0
  51. package/dist/core/ports/identity.d.ts +114 -0
  52. package/dist/core/ports/identity.d.ts.map +1 -0
  53. package/dist/core/ports/identity.js +28 -0
  54. package/dist/core/ports/identity.js.map +1 -0
  55. package/dist/core/ports/index.d.ts +21 -0
  56. package/dist/core/ports/index.d.ts.map +1 -0
  57. package/dist/core/ports/index.js +6 -0
  58. package/dist/core/ports/index.js.map +1 -0
  59. package/dist/core/ports/integrations.d.ts +81 -0
  60. package/dist/core/ports/integrations.d.ts.map +1 -0
  61. package/dist/core/ports/integrations.js +21 -0
  62. package/dist/core/ports/integrations.js.map +1 -0
  63. package/dist/core/ports/media.d.ts +74 -0
  64. package/dist/core/ports/media.d.ts.map +1 -0
  65. package/dist/core/ports/media.js +28 -0
  66. package/dist/core/ports/media.js.map +1 -0
  67. package/dist/core/ports/members.d.ts +50 -0
  68. package/dist/core/ports/members.d.ts.map +1 -0
  69. package/dist/core/ports/members.js +17 -0
  70. package/dist/core/ports/members.js.map +1 -0
  71. package/dist/core/ports/menus.d.ts +179 -0
  72. package/dist/core/ports/menus.d.ts.map +1 -0
  73. package/dist/core/ports/menus.js +70 -0
  74. package/dist/core/ports/menus.js.map +1 -0
  75. package/dist/core/ports/plugins.d.ts +68 -0
  76. package/dist/core/ports/plugins.d.ts.map +1 -0
  77. package/dist/core/ports/plugins.js +27 -0
  78. package/dist/core/ports/plugins.js.map +1 -0
  79. package/dist/core/ports/recovery.d.ts +171 -0
  80. package/dist/core/ports/recovery.d.ts.map +1 -0
  81. package/dist/core/ports/recovery.js +2 -0
  82. package/dist/core/ports/recovery.js.map +1 -0
  83. package/dist/core/ports/redirects.d.ts +139 -0
  84. package/dist/core/ports/redirects.d.ts.map +1 -0
  85. package/dist/core/ports/redirects.js +55 -0
  86. package/dist/core/ports/redirects.js.map +1 -0
  87. package/dist/core/ports/seo.d.ts +147 -0
  88. package/dist/core/ports/seo.d.ts.map +1 -0
  89. package/dist/core/ports/seo.js +39 -0
  90. package/dist/core/ports/seo.js.map +1 -0
  91. package/dist/core/ports/settings.d.ts +87 -0
  92. package/dist/core/ports/settings.d.ts.map +1 -0
  93. package/dist/core/ports/settings.js +23 -0
  94. package/dist/core/ports/settings.js.map +1 -0
  95. package/dist/core/ports/workspace.d.ts +44 -0
  96. package/dist/core/ports/workspace.d.ts.map +1 -0
  97. package/dist/core/ports/workspace.js +29 -0
  98. package/dist/core/ports/workspace.js.map +1 -0
  99. package/dist/core/routing/rules.d.ts +54 -0
  100. package/dist/core/routing/rules.d.ts.map +1 -0
  101. package/dist/core/routing/rules.js +113 -0
  102. package/dist/core/routing/rules.js.map +1 -0
  103. package/dist/core/routing/types.d.ts +36 -0
  104. package/dist/core/routing/types.d.ts.map +1 -0
  105. package/dist/core/routing/types.js +17 -0
  106. package/dist/core/routing/types.js.map +1 -0
  107. package/dist/core/transport/errors.d.ts +53 -0
  108. package/dist/core/transport/errors.d.ts.map +1 -0
  109. package/dist/core/transport/errors.js +63 -0
  110. package/dist/core/transport/errors.js.map +1 -0
  111. package/dist/core/transport/http.d.ts +63 -0
  112. package/dist/core/transport/http.d.ts.map +1 -0
  113. package/dist/core/transport/http.js +63 -0
  114. package/dist/core/transport/http.js.map +1 -0
  115. package/dist/core/transport/index.d.ts +5 -0
  116. package/dist/core/transport/index.d.ts.map +1 -0
  117. package/dist/core/transport/index.js +3 -0
  118. package/dist/core/transport/index.js.map +1 -0
  119. package/dist/core/transport/types.d.ts +81 -0
  120. package/dist/core/transport/types.d.ts.map +1 -0
  121. package/dist/core/transport/types.js +43 -0
  122. package/dist/core/transport/types.js.map +1 -0
  123. package/dist/react/components/ConfirmButton/ConfirmButton.d.ts +40 -0
  124. package/dist/react/components/ConfirmButton/ConfirmButton.d.ts.map +1 -0
  125. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts +22 -0
  126. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts.map +1 -0
  127. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js +59 -0
  128. package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js.map +1 -0
  129. package/dist/react/components/ConfirmButton/ConfirmButton.js +40 -0
  130. package/dist/react/components/ConfirmButton/ConfirmButton.js.map +1 -0
  131. package/dist/react/components/ConfirmButton.d.ts +39 -0
  132. package/dist/react/components/ConfirmButton.d.ts.map +1 -0
  133. package/dist/react/components/ConfirmButton.js +79 -0
  134. package/dist/react/components/ConfirmButton.js.map +1 -0
  135. package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts +90 -0
  136. package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts.map +1 -0
  137. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts +49 -0
  138. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts.map +1 -0
  139. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js +81 -0
  140. package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js.map +1 -0
  141. package/dist/react/components/ConfirmDialog/ConfirmDialog.js +92 -0
  142. package/dist/react/components/ConfirmDialog/ConfirmDialog.js.map +1 -0
  143. package/dist/react/components/ConfirmDialog.d.ts +57 -0
  144. package/dist/react/components/ConfirmDialog.d.ts.map +1 -0
  145. package/dist/react/components/ConfirmDialog.js +85 -0
  146. package/dist/react/components/ConfirmDialog.js.map +1 -0
  147. package/dist/react/components/DataTable.d.ts +97 -0
  148. package/dist/react/components/DataTable.d.ts.map +1 -0
  149. package/dist/react/components/DataTable.js +20 -0
  150. package/dist/react/components/DataTable.js.map +1 -0
  151. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts +25 -0
  152. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts.map +1 -0
  153. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js +148 -0
  154. package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js.map +1 -0
  155. package/dist/react/components/RowMenu/RowMenu.d.ts +77 -0
  156. package/dist/react/components/RowMenu/RowMenu.d.ts.map +1 -0
  157. package/dist/react/components/RowMenu/RowMenu.hooks.d.ts +30 -0
  158. package/dist/react/components/RowMenu/RowMenu.hooks.d.ts.map +1 -0
  159. package/dist/react/components/RowMenu/RowMenu.hooks.js +154 -0
  160. package/dist/react/components/RowMenu/RowMenu.hooks.js.map +1 -0
  161. package/dist/react/components/RowMenu/RowMenu.js +46 -0
  162. package/dist/react/components/RowMenu/RowMenu.js.map +1 -0
  163. package/dist/react/components/RowMenu.d.ts +44 -0
  164. package/dist/react/components/RowMenu.d.ts.map +1 -0
  165. package/dist/react/components/RowMenu.js +149 -0
  166. package/dist/react/components/RowMenu.js.map +1 -0
  167. package/dist/react/components/Sidebar.d.ts +128 -0
  168. package/dist/react/components/Sidebar.d.ts.map +1 -0
  169. package/dist/react/components/Sidebar.js +168 -0
  170. package/dist/react/components/Sidebar.js.map +1 -0
  171. package/dist/react/hooks/use-nav-sections.d.ts +50 -0
  172. package/dist/react/hooks/use-nav-sections.d.ts.map +1 -0
  173. package/dist/react/hooks/use-nav-sections.js +112 -0
  174. package/dist/react/hooks/use-nav-sections.js.map +1 -0
  175. package/dist/react/hooks/use-sidebar-rail.d.ts +39 -0
  176. package/dist/react/hooks/use-sidebar-rail.d.ts.map +1 -0
  177. package/dist/react/hooks/use-sidebar-rail.js +93 -0
  178. package/dist/react/hooks/use-sidebar-rail.js.map +1 -0
  179. package/dist/react/index.d.ts +53 -0
  180. package/dist/react/index.d.ts.map +1 -0
  181. package/dist/react/index.js +53 -0
  182. package/dist/react/index.js.map +1 -0
  183. package/dist/react/types.d.ts +28 -0
  184. package/dist/react/types.d.ts.map +1 -0
  185. package/dist/react/types.js +23 -0
  186. package/dist/react/types.js.map +1 -0
  187. package/dist/server/composio/bounded-data.d.ts +36 -0
  188. package/dist/server/composio/bounded-data.d.ts.map +1 -0
  189. package/dist/server/composio/bounded-data.js +181 -0
  190. package/dist/server/composio/bounded-data.js.map +1 -0
  191. package/dist/server/composio/catalog.d.ts +147 -0
  192. package/dist/server/composio/catalog.d.ts.map +1 -0
  193. package/dist/server/composio/catalog.js +126 -0
  194. package/dist/server/composio/catalog.js.map +1 -0
  195. package/dist/server/composio/composio-config.d.ts +42 -0
  196. package/dist/server/composio/composio-config.d.ts.map +1 -0
  197. package/dist/server/composio/composio-config.js +145 -0
  198. package/dist/server/composio/composio-config.js.map +1 -0
  199. package/dist/server/composio/composio-descriptions.d.ts +16 -0
  200. package/dist/server/composio/composio-descriptions.d.ts.map +1 -0
  201. package/dist/server/composio/composio-descriptions.js +766 -0
  202. package/dist/server/composio/composio-descriptions.js.map +1 -0
  203. package/dist/server/composio/composio.d.ts +364 -0
  204. package/dist/server/composio/composio.d.ts.map +1 -0
  205. package/dist/server/composio/composio.js +1902 -0
  206. package/dist/server/composio/composio.js.map +1 -0
  207. package/dist/server/composio/errors.d.ts +15 -0
  208. package/dist/server/composio/errors.d.ts.map +1 -0
  209. package/dist/server/composio/errors.js +16 -0
  210. package/dist/server/composio/errors.js.map +1 -0
  211. package/dist/server/composio/file-lock.d.ts +13 -0
  212. package/dist/server/composio/file-lock.d.ts.map +1 -0
  213. package/dist/server/composio/file-lock.js +92 -0
  214. package/dist/server/composio/file-lock.js.map +1 -0
  215. package/dist/server/composio/index.d.ts +18 -0
  216. package/dist/server/composio/index.d.ts.map +1 -0
  217. package/dist/server/composio/index.js +7 -0
  218. package/dist/server/composio/index.js.map +1 -0
  219. package/dist/server/composio/json-schema.d.ts +93 -0
  220. package/dist/server/composio/json-schema.d.ts.map +1 -0
  221. package/dist/server/composio/json-schema.js +498 -0
  222. package/dist/server/composio/json-schema.js.map +1 -0
  223. package/dist/server/composio/output-protection.d.ts +32 -0
  224. package/dist/server/composio/output-protection.d.ts.map +1 -0
  225. package/dist/server/composio/output-protection.js +105 -0
  226. package/dist/server/composio/output-protection.js.map +1 -0
  227. package/dist/server/composio/service.d.ts +181 -0
  228. package/dist/server/composio/service.d.ts.map +1 -0
  229. package/dist/server/composio/service.js +758 -0
  230. package/dist/server/composio/service.js.map +1 -0
  231. package/dist/server/index.d.ts +15 -0
  232. package/dist/server/index.d.ts.map +1 -0
  233. package/dist/server/index.js +15 -0
  234. package/dist/server/index.js.map +1 -0
  235. package/package.json +92 -0
@@ -0,0 +1,92 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import {} from 'react';
3
+ import { agentHandle } from '@jini-ai/agentic';
4
+ import { resolveTone, toneClassName } from '../../types.js';
5
+ import { useConfirmDialog } from './ConfirmDialog.hooks.js';
6
+ const DEFAULT_CANCEL_LABEL = 'Cancel';
7
+ /** Sub-handle segments appended to the caller's base — literals this component chooses itself,
8
+ * never host data (see this file's "Agent handles" doc comment for why that means neither needs
9
+ * sanitizing, unlike `RowMenu`'s per-item keys). */
10
+ const CONFIRM_HANDLE_ACTION = 'confirm';
11
+ const CANCEL_HANDLE_ACTION = 'cancel';
12
+ /**
13
+ * Plain-language phrase for what confirming actually changes, keyed off the dialog's own
14
+ * three-tier `ConfirmTone` vocabulary (`"default"` / `"warning"` / `"danger"`, documented in
15
+ * `../../types.js`) rather than reparsed from `title` or `body` — see this file's doc comment for
16
+ * why those cannot be safely folded into agent-facing text.
17
+ *
18
+ * @param tone - The dialog's resolved tone (see `resolveTone`).
19
+ * @returns The tier's consequence phrase, or `undefined` for `"default"`, which declares no tier.
20
+ * @complexity O(1).
21
+ */
22
+ function confirmDialogConsequencePhrase(tone) {
23
+ if (tone === 'danger')
24
+ return 'cannot be undone';
25
+ if (tone === 'warning')
26
+ return 'changes access, but is reversible';
27
+ return undefined;
28
+ }
29
+ /**
30
+ * The confirm action's agent-facing label: what it does (`confirmLabel`), what it applies to
31
+ * (`title`), and — when the tone declares one — its consequence tier.
32
+ *
33
+ * @param confirmLabel - The button's own visible text, e.g. `"Delete"`.
34
+ * @param title - The dialog's title, e.g. `"Delete role?"`.
35
+ * @param tone - The dialog's resolved tone.
36
+ * @returns A label an agent can use to judge whether confirming is safe, without having read
37
+ * `body` (which this function never receives — see this file's doc comment for why).
38
+ * @complexity O(1).
39
+ */
40
+ function confirmDialogConfirmLabel(confirmLabel, title, tone) {
41
+ const consequence = confirmDialogConsequencePhrase(tone);
42
+ return consequence === undefined ? `${confirmLabel} — ${title}` : `${confirmLabel} — ${title}; ${consequence}`;
43
+ }
44
+ /**
45
+ * The cancel action's agent-facing label. Unlike {@link confirmDialogConfirmLabel}, its consequence
46
+ * is a guarantee of this component's own contract (cancelling never calls `onConfirm`) rather than
47
+ * something read off `tone`, so it needs no tone input at all.
48
+ *
49
+ * @param cancelLabel - The button's own visible text, already defaulted by the caller.
50
+ * @param title - The dialog's title, e.g. `"Delete role?"`.
51
+ * @returns A label stating that this action leaves the titled action unconfirmed.
52
+ * @complexity O(1).
53
+ */
54
+ function confirmDialogCancelLabel(cancelLabel, title) {
55
+ return `${cancelLabel} — leaves "${title}" unconfirmed; no action taken`;
56
+ }
57
+ /**
58
+ * Builds the `data-agent-*` attribute props for one of this dialog's two actions, or nothing at
59
+ * all when the dialog published no base handle — same shape as `RowMenu.tsx`'s local
60
+ * `rowMenuAgentProps`, kept local and unexported here since only this one component needs it.
61
+ *
62
+ * @param base - The dialog's own handle from the caller, or `undefined` when it published none.
63
+ * @param action - Which action this is — see {@link CONFIRM_HANDLE_ACTION}/{@link CANCEL_HANDLE_ACTION}.
64
+ * @param options - Role and this action's already-composed label.
65
+ * @returns Spreadable attribute props, or `{}` when `base` is `undefined`.
66
+ * @complexity O(1).
67
+ */
68
+ function confirmDialogAgentProps(base, action, options) {
69
+ return base === undefined ? {} : agentHandle(`${base}-${action}`, options);
70
+ }
71
+ /**
72
+ * Controlled modal confirm — renders the `<dialog>` markup and delegates its open/close and focus
73
+ * lifecycle to {@link useConfirmDialog} (injectable via the `useDialog` prop, defaulted to the real
74
+ * implementation, so a test can supply a fake without mocking modules).
75
+ *
76
+ * Both actions are plain `type="button"` (no `<form method="dialog">`, no `type="submit"`), so there
77
+ * is no browser-assigned "default button" for Enter to reach for at all; confirm can only ever fire
78
+ * from an explicit click or explicit Tab-then-Enter onto it.
79
+ */
80
+ export function ConfirmDialog({ useDialog = useConfirmDialog, agentHandle: baseHandle, ...props }) {
81
+ const { titleId, dialogRef, cancelRef, handleNativeCancel, handleBackdropClick } = useDialog(props.open, props.pending, props.onCancel);
82
+ const tone = resolveTone(props);
83
+ const cancelLabel = props.cancelLabel ?? DEFAULT_CANCEL_LABEL;
84
+ return (_jsxs("dialog", { ref: dialogRef, className: "confirm-dialog", "aria-labelledby": titleId, onCancel: handleNativeCancel, onClick: handleBackdropClick, children: [_jsx("h2", { id: titleId, children: props.title }), _jsx("div", { className: "confirm-dialog-body", children: props.body }), _jsxs("div", { className: "confirm-dialog-actions", children: [_jsx("button", { ref: cancelRef, type: "button", className: "btn-secondary", disabled: props.pending, onClick: props.onCancel, ...confirmDialogAgentProps(baseHandle, CANCEL_HANDLE_ACTION, {
85
+ role: 'button',
86
+ label: confirmDialogCancelLabel(cancelLabel, props.title),
87
+ }), children: cancelLabel }), _jsx("button", { type: "button", className: toneClassName(tone), disabled: props.pending, onClick: props.onConfirm, ...confirmDialogAgentProps(baseHandle, CONFIRM_HANDLE_ACTION, {
88
+ role: 'button',
89
+ label: confirmDialogConfirmLabel(props.confirmLabel, props.title, tone),
90
+ }), children: props.confirmLabel })] })] }));
91
+ }
92
+ //# sourceMappingURL=ConfirmDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmDialog.js","sourceRoot":"","sources":["../../../../src/react/components/ConfirmDialog/ConfirmDialog.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type ConfirmTone } from '../types.js';
3
+ /**
4
+ * @file Shared modal confirmation primitive — the replacement for `window.confirm`, which blocks
5
+ * the whole tab, cannot carry destructive-vs-neutral styling, and reads as a browser artifact
6
+ * rather than part of the product.
7
+ *
8
+ * Built on the native `<dialog>` element (`showModal()`/`close()`) rather than a plain-`<div>`
9
+ * overlay + backdrop idiom: that shape hand-rolls focus trapping, Escape handling, and a backdrop
10
+ * element, all of which the browser's own top layer gives a real `<dialog>` for free, including
11
+ * correct stacking above everything else on the page without a chosen `z-index`.
12
+ *
13
+ * `dialog.showModal()`/`dialog.close()` are guarded by a `typeof` check rather than called
14
+ * unconditionally: jsdom (this package's React test environment, verified directly rather than
15
+ * assumed) does not implement either method at all — calling them throws `TypeError`. The fallback
16
+ * branch below toggles the plain `open` attribute instead, which no browser shipping a real
17
+ * `<dialog>` ever takes (the `showModal`/`close` branch always wins there), so this only changes
18
+ * behavior under jsdom, where it keeps the dialog mountable and its content queryable.
19
+ *
20
+ * Unstyled, like everything in this layer: the `.confirm-dialog` / `.btn-secondary` /
21
+ * `.btn-danger` / `.btn-warning` class names are emitted for the host stylesheet to define.
22
+ */
23
+ export interface ConfirmDialogProps {
24
+ open: boolean;
25
+ title: string;
26
+ body: ReactNode;
27
+ confirmLabel: string;
28
+ /** @default "Cancel" */
29
+ cancelLabel?: string;
30
+ /** Applies `.btn-warning`/`.btn-danger` to the confirm action. Defaults to `"default"` (no class,
31
+ * the plain primary button). Wins over `destructive` below when both are passed. */
32
+ tone?: ConfirmTone;
33
+ /** @deprecated Use `tone: "danger"` instead — this only ever expressed the danger tier, and the
34
+ * vocabulary has a second one (`"warning"`) this boolean cannot reach. Kept working (mapped to
35
+ * `tone: "danger"` when `tone` is not set) for existing callers rather than a breaking rename. */
36
+ destructive?: boolean;
37
+ /** External in-flight flag. Disables both actions and blocks Escape/backdrop dismissal so a
38
+ * request already underway cannot be raced by a second dismiss. */
39
+ pending?: boolean;
40
+ onConfirm: () => void;
41
+ onCancel: () => void;
42
+ }
43
+ /**
44
+ * Controlled modal confirm. The caller keeps this mounted and toggles `open` — it is never
45
+ * conditionally rendered by its parent — so the effect below has a stable `<dialog>` element to
46
+ * call `showModal()`/`close()` on and to restore focus through when it closes.
47
+ *
48
+ * Focus moves to the *cancel* action on open, not confirm — an operator whose first keystroke after
49
+ * a slow read-through is Enter should land on the safe action, not the destructive one. Both
50
+ * actions are plain `type="button"` (no `<form method="dialog">`, no `type="submit"`), so there is
51
+ * no browser-assigned "default button" for Enter to reach for at all; confirm can only ever fire
52
+ * from an explicit click or explicit Tab-then-Enter onto it.
53
+ *
54
+ * @complexity O(1) per open/close transition — one `showModal`/`close` call and one focus move.
55
+ */
56
+ export declare function ConfirmDialog(props: ConfirmDialogProps): import("react").JSX.Element;
57
+ //# sourceMappingURL=ConfirmDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmDialog.d.ts","sourceRoot":"","sources":["../../../src/react/components/ConfirmDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,SAAS,EAAuB,MAAM,OAAO,CAAC;AACvG,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;yFACqF;IACrF,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;uGAEmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;wEACoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,+BA0FtD"}
@@ -0,0 +1,85 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef } from 'react';
3
+ import { resolveTone, toneClassName } from '../types.js';
4
+ const DEFAULT_CANCEL_LABEL = 'Cancel';
5
+ /**
6
+ * Controlled modal confirm. The caller keeps this mounted and toggles `open` — it is never
7
+ * conditionally rendered by its parent — so the effect below has a stable `<dialog>` element to
8
+ * call `showModal()`/`close()` on and to restore focus through when it closes.
9
+ *
10
+ * Focus moves to the *cancel* action on open, not confirm — an operator whose first keystroke after
11
+ * a slow read-through is Enter should land on the safe action, not the destructive one. Both
12
+ * actions are plain `type="button"` (no `<form method="dialog">`, no `type="submit"`), so there is
13
+ * no browser-assigned "default button" for Enter to reach for at all; confirm can only ever fire
14
+ * from an explicit click or explicit Tab-then-Enter onto it.
15
+ *
16
+ * @complexity O(1) per open/close transition — one `showModal`/`close` call and one focus move.
17
+ */
18
+ export function ConfirmDialog(props) {
19
+ // `useId()`, not a string literal — a hardcoded id breaks the moment a screen mounts two
20
+ // `ConfirmDialog`s at once (a delete-role and a delete-policy confirm on one page, both
21
+ // stay-mounted/toggle-`open` per this component's own doc comment above): two `<h2>`s share one
22
+ // id, and `aria-labelledby` resolves via `getElementById`, which always returns the FIRST match
23
+ // in document order regardless of which dialog is actually open — a screen reader announcing
24
+ // "Delete role?" while the operator is about to confirm "Delete policy?", on a destructive
25
+ // action. `useId()` gives every mounted instance its own id for free.
26
+ const titleId = useId();
27
+ const dialogRef = useRef(null);
28
+ const cancelRef = useRef(null);
29
+ // Captured at the moment `open` flips true, before focus moves into the dialog — the element that
30
+ // had focus then is, by construction, whatever triggered this dialog (a `RowMenu` item's
31
+ // "Delete", a plain trigger button, …). Restored on close rather than left wherever the browser's
32
+ // own modal-focus algorithm happened to land (its default without this is `<body>`, which drops a
33
+ // keyboard user back to the top of the page).
34
+ const triggerRef = useRef(null);
35
+ useEffect(() => {
36
+ const dialog = dialogRef.current;
37
+ if (!dialog)
38
+ return;
39
+ if (props.open) {
40
+ triggerRef.current = document.activeElement;
41
+ if (typeof dialog.showModal === 'function') {
42
+ if (!dialog.open)
43
+ dialog.showModal();
44
+ }
45
+ else {
46
+ dialog.setAttribute('open', '');
47
+ }
48
+ cancelRef.current?.focus();
49
+ }
50
+ else {
51
+ if (typeof dialog.close === 'function') {
52
+ if (dialog.open)
53
+ dialog.close();
54
+ }
55
+ else {
56
+ dialog.removeAttribute('open');
57
+ }
58
+ if (triggerRef.current instanceof HTMLElement)
59
+ triggerRef.current.focus();
60
+ }
61
+ }, [props.open]);
62
+ function handleNativeCancel(e) {
63
+ // Fires on Escape while a real `showModal()`-opened dialog has focus. Always prevented: the
64
+ // effect above is the single source of truth for open/closed (driven by `props.open`), so
65
+ // letting the browser close the element on its own would desync DOM state from React state.
66
+ // Escape still closes the dialog — it just does so by routing through `onCancel`, same as a
67
+ // Cancel-button click, so the caller's `open` state (and therefore this same effect) is what
68
+ // actually calls `dialog.close()`.
69
+ e.preventDefault();
70
+ if (props.pending)
71
+ return;
72
+ props.onCancel();
73
+ }
74
+ function handleBackdropClick(e) {
75
+ // A `<dialog>` element's own box is sized to its content, not the viewport — a click that lands
76
+ // on the `<dialog>` element itself (as opposed to one of its children) is therefore a click on
77
+ // the backdrop area outside that content box.
78
+ if (props.pending)
79
+ return;
80
+ if (e.target === dialogRef.current)
81
+ props.onCancel();
82
+ }
83
+ return (_jsxs("dialog", { ref: dialogRef, className: "confirm-dialog", "aria-labelledby": titleId, onCancel: handleNativeCancel, onClick: handleBackdropClick, children: [_jsx("h2", { id: titleId, children: props.title }), _jsx("div", { className: "confirm-dialog-body", children: props.body }), _jsxs("div", { className: "confirm-dialog-actions", children: [_jsx("button", { ref: cancelRef, type: "button", className: "btn-secondary", disabled: props.pending, onClick: props.onCancel, children: props.cancelLabel ?? DEFAULT_CANCEL_LABEL }), _jsx("button", { type: "button", className: toneClassName(resolveTone(props)), disabled: props.pending, onClick: props.onConfirm, children: props.confirmLabel })] })] }));
84
+ }
85
+ //# sourceMappingURL=ConfirmDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmDialog.js","sourceRoot":"","sources":["../../../src/react/components/ConfirmDialog.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ import type { ReactNode } from 'react';
2
+ /**
3
+ * @file The admin list table.
4
+ *
5
+ * ## Designed from the corpus, not from what a table component usually has
6
+ *
7
+ * This replaces 25 hand-rolled `<table>` blocks across one reference admin, every one of which had
8
+ * the identical skeleton — a `.table-scroll` wrapper, a `.list-table`, a `<thead>` of plain `<th>`,
9
+ * and a `<tbody>` mapping rows — wrapped in a ternary that rendered an empty state instead when
10
+ * there was nothing to show. That ternary is the single most duplicated thing in the corpus, which
11
+ * is why `empty` and `loading` are this component's concern rather than each caller's.
12
+ *
13
+ * What the corpus did **not** contain is just as load-bearing:
14
+ *
15
+ * - **No sorting.** Zero of 25.
16
+ * - **No pagination.** Zero of 25.
17
+ * - **No row selection.** Zero of 25 — the checkboxes that appear inside some of those tables are
18
+ * field controls belonging to the row's own data, not a selection model.
19
+ *
20
+ * None of the three is implemented here. A table component that ships sorting nobody asked for has
21
+ * to guess at comparator semantics, controlled-vs-uncontrolled state, and multi-column precedence,
22
+ * and every one of those guesses becomes a compatibility obligation the moment it ships. When a
23
+ * host needs sorting, it will arrive with a real requirement attached and can be added then —
24
+ * additively, since `columns` is already a descriptor list with somewhere to put it.
25
+ *
26
+ * `<tfoot>` appeared exactly once, so it is an optional prop rather than part of the core shape.
27
+ *
28
+ * ## Row actions are not a feature
29
+ *
30
+ * An overflow menu in the last column is just a column whose `cell` renders one. There is no
31
+ * `actions` prop, because there is nothing a dedicated one would do that a `cell` does not already
32
+ * do — and having one would force a second, worse decision about where actions may appear.
33
+ *
34
+ * Three of the 25 gave that column an empty `<th>` carrying only an `aria-label`, which is the
35
+ * right shape: a visible "More" heading is noise, and a nameless column header is a gap for anyone
36
+ * navigating by column. `header` is therefore optional, and `headerLabel` names a headerless one.
37
+ *
38
+ * ## Styling contract
39
+ *
40
+ * Unstyled, like everything in this layer: `.table-scroll` and `.list-table` are emitted for the
41
+ * host stylesheet to define. The wrapper is not decorative — `overflow-x: auto` on it is what makes
42
+ * a wide table scroll instead of breaking the page, and it is also why `RowMenu` portals its popup
43
+ * out to `document.body` rather than positioning inside this box.
44
+ */
45
+ export interface DataTableColumn<Row> {
46
+ /** Stable identity for this column. Not rendered — used as the React key. */
47
+ key: string;
48
+ /** Header content. Omit for a column that carries no visible heading (a row-actions column);
49
+ * supply {@link headerLabel} when you do, so the column is still named for assistive tech. */
50
+ header?: ReactNode;
51
+ /** Accessible name for a column whose `header` is omitted or purely visual. */
52
+ headerLabel?: string;
53
+ /** Renders one cell. Receives the row and its index. */
54
+ cell: (row: Row, index: number) => ReactNode;
55
+ /** Class on this column's `<th>`. */
56
+ headerClassName?: string;
57
+ /** Class on this column's `<td>`. A function receives the row, for per-row variation. */
58
+ cellClassName?: string | ((row: Row, index: number) => string | undefined);
59
+ }
60
+ export interface DataTableProps<Row> {
61
+ rows: readonly Row[];
62
+ columns: ReadonlyArray<DataTableColumn<Row>>;
63
+ /** Stable React key per row. Required rather than defaulting to the index — an index key on a
64
+ * list that can reorder or delete is a well-known source of state landing on the wrong row, and
65
+ * every table in the corpus had a real id to hand. */
66
+ rowKey: (row: Row, index: number) => string;
67
+ /**
68
+ * Rendered **instead of the table** when there are no rows and `loading` is false. Pass the
69
+ * host's own empty-state markup. Omit it to render an empty `<tbody>` — appropriate when the
70
+ * table is one part of a larger screen that explains the emptiness itself.
71
+ */
72
+ empty?: ReactNode;
73
+ /** While true, `loadingContent` is rendered instead of the table (or an empty `<tbody>` if none
74
+ * is given). Takes precedence over `empty`, so a slow first fetch never flashes "nothing here"
75
+ * before the rows arrive — the bug that pattern produces in every list screen that gets it
76
+ * backwards. */
77
+ loading?: boolean;
78
+ loadingContent?: ReactNode;
79
+ /** `<tfoot>` content. Rendered as-is: supply your own `<tr>`/`<td>`. */
80
+ footer?: ReactNode;
81
+ /** Accessible name for the table itself. Worth setting when a screen has more than one. */
82
+ label?: string;
83
+ /** `<caption>`. Visible unless the host's CSS hides it; prefer {@link label} for a name that
84
+ * should not paint. */
85
+ caption?: ReactNode;
86
+ /** Class per row, e.g. to mark a disabled or newly-created record. */
87
+ rowClassName?: (row: Row, index: number) => string | undefined;
88
+ /** Appended to `.list-table`. */
89
+ className?: string;
90
+ /** Appended to `.table-scroll`. */
91
+ scrollClassName?: string;
92
+ }
93
+ /**
94
+ * @complexity O(rows × columns) per render — one pass, no sorting or grouping work.
95
+ */
96
+ export declare function DataTable<Row>(props: DataTableProps<Row>): import("react").JSX.Element;
97
+ //# sourceMappingURL=DataTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/react/components/DataTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,MAAM,WAAW,eAAe,CAAC,GAAG;IAClC,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ;mGAC+F;IAC/F,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IAC7C,qCAAqC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC;CAC5E;AAED,MAAM,WAAW,cAAc,CAAC,GAAG;IACjC,IAAI,EAAE,SAAS,GAAG,EAAE,CAAC;IACrB,OAAO,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C;;2DAEuD;IACvD,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;qBAGiB;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,wEAAwE;IACxE,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,2FAA2F;IAC3F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;4BACwB;IACxB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,sEAAsE;IACtE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/D,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAYD;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,+BAwCxD"}
@@ -0,0 +1,20 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ function resolveCellClassName(column, row, index) {
3
+ return typeof column.cellClassName === 'function'
4
+ ? column.cellClassName(row, index)
5
+ : column.cellClassName;
6
+ }
7
+ /**
8
+ * @complexity O(rows × columns) per render — one pass, no sorting or grouping work.
9
+ */
10
+ export function DataTable(props) {
11
+ // Loading wins over empty deliberately: `rows` is legitimately `[]` during a first fetch, and
12
+ // checking emptiness first is what makes a list screen flash its empty state before the data
13
+ // lands.
14
+ if (props.loading && props.loadingContent !== undefined)
15
+ return _jsx(_Fragment, { children: props.loadingContent });
16
+ if (!props.loading && props.rows.length === 0 && props.empty !== undefined)
17
+ return _jsx(_Fragment, { children: props.empty });
18
+ return (_jsx("div", { className: ['table-scroll', props.scrollClassName].filter(Boolean).join(' '), children: _jsxs("table", { className: ['list-table', props.className].filter(Boolean).join(' '), "aria-label": props.label, children: [props.caption === undefined ? null : _jsx("caption", { children: props.caption }), _jsx("thead", { children: _jsx("tr", { children: props.columns.map((column) => (_jsx("th", { scope: "col", className: column.headerClassName, "aria-label": column.header === undefined ? column.headerLabel : undefined, children: column.header }, column.key))) }) }), _jsx("tbody", { children: props.rows.map((row, index) => (_jsx("tr", { className: props.rowClassName?.(row, index), children: props.columns.map((column) => (_jsx("td", { className: resolveCellClassName(column, row, index), children: column.cell(row, index) }, column.key))) }, props.rowKey(row, index)))) }), props.footer === undefined ? null : _jsx("tfoot", { children: props.footer })] }) }));
19
+ }
20
+ //# sourceMappingURL=DataTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataTable.js","sourceRoot":"","sources":["../../../src/react/components/DataTable.tsx"],"names":[],"mappings":";AAgGA,SAAS,oBAAoB,CAC3B,MAA4B,EAC5B,GAAQ,EACR,KAAa;IAEb,OAAO,OAAO,MAAM,CAAC,aAAa,KAAK,UAAU;QAC/C,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC;QAClC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAM,KAA0B;IACvD,8FAA8F;IAC9F,6FAA6F;IAC7F,SAAS;IACT,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS;QAAE,OAAO,4BAAG,KAAK,CAAC,cAAc,GAAI,CAAC;IAC5F,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,4BAAG,KAAK,CAAC,KAAK,GAAI,CAAC;IAEtG,OAAO,CACL,cAAK,SAAS,EAAE,CAAC,cAAc,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAC/E,iBAAO,SAAS,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAc,KAAK,CAAC,KAAK,aACjG,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,4BAAU,KAAK,CAAC,OAAO,GAAW,EACxE,0BACE,uBACG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAC7B,aAEE,KAAK,EAAC,KAAK,EACX,SAAS,EAAE,MAAM,CAAC,eAAe,gBACrB,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,YAEvE,MAAM,CAAC,MAAM,IALT,MAAM,CAAC,GAAG,CAMZ,CACN,CAAC,GACC,GACC,EACR,0BACG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CAC9B,aAAmC,SAAS,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,YAC3E,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAC7B,aAAqB,SAAS,EAAE,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,YACrE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IADjB,MAAM,CAAC,GAAG,CAEd,CACN,CAAC,IALK,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAM5B,CACN,CAAC,GACI,EACP,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,0BAAQ,KAAK,CAAC,MAAM,GAAS,IAC5D,GACJ,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { type CanvasEmbedPlaceholderDescriptor, type InteractiveHtmlEditorProps as HtmlEditorProps } from '@jini-ai/ui/html-editor';
2
+ /** True when `el` carries any embed marker attribute this convention recognizes — exported for
3
+ * direct unit-testability without mounting the editor. Uses `hasAttributeOnAnyNodeShape` because
4
+ * the `isProtectedElement` predicate is invoked from inside GrapesJS's `isComponent` callback,
5
+ * which is not always called with a real DOM `Element` — see that helper's own doc. */
6
+ export declare function isProtectedEmbedElement(el: Element): boolean;
7
+ /**
8
+ * Recognizes a `data-embed-config` marker (`Tovu/src/core/embeds/marker.ts`'s single scanner
9
+ * convention) on a live canvas element and describes it for `@jini-ai/ui/html-editor`'s
10
+ * `applyCanvasEmbedPlaceholders` — see that function's own file header for what it does with the
11
+ * result. Exported for direct unit-testability without mounting the editor, same convention
12
+ * `isProtectedEmbedElement` above already documents.
13
+ *
14
+ * A marker whose `data-embed-config` fails to parse, isn't an object, or has no `type` returns
15
+ * `undefined` — "not a marker this function can describe," the identical degrade-quietly contract
16
+ * `scanEmbedMarkers` (the server-side scanner this mirrors) uses for a rejected marker at render time;
17
+ * this function does not warn or log, since it runs on every keystroke-adjacent canvas re-render, not
18
+ * at a write chokepoint where a loud rejection matters.
19
+ *
20
+ * @complexity O(1) — one attribute read, one `JSON.parse` of a small config object, one table lookup.
21
+ */
22
+ export declare function describeEmbedPlaceholder(el: Element): CanvasEmbedPlaceholderDescriptor | undefined;
23
+ export type InteractiveHtmlEditorProps = Omit<HtmlEditorProps, 'isProtectedElement' | 'describeEmbedPlaceholder'>;
24
+ export declare function InteractiveHtmlEditor(props: InteractiveHtmlEditorProps): import("react").JSX.Element;
25
+ //# sourceMappingURL=InteractiveHtmlEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InteractiveHtmlEditor.d.ts","sourceRoot":"","sources":["../../../../src/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gCAAgC,EACrC,KAAK,0BAA0B,IAAI,eAAe,EACnD,MAAM,yBAAyB,CAAC;AAkCjC;;;wFAGwF;AACxF,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAE5D;AA2ED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,OAAO,GAAG,gCAAgC,GAAG,SAAS,CAelG;AAED,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAAC,eAAe,EAAE,oBAAoB,GAAG,0BAA0B,CAAC,CAAC;AAElH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,+BAQtE"}
@@ -0,0 +1,148 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { InteractiveHtmlEditor as HtmlEditor, hasAttributeOnAnyNodeShape, } from '@jini-ai/ui/html-editor';
3
+ /**
4
+ * @file Tovu-specific composition of `@jini-ai/ui/html-editor`'s generic `InteractiveHtmlEditor`: a
5
+ * Page's `body_html` (the first caller — see `Tovu/apps/admin/src/features/pages/PageEditor.tsx`)
6
+ * can carry `<div data-embed-type="…" data-embed-id="…"></div>` placeholders (and the legacy
7
+ * `data-widget-embed`/`data-form-embed` attributes on migration-era rows) that a separate scanner
8
+ * (`Tovu/src/widgets/html-embeds.ts`) resolves at render time — that scanner requires the div to
9
+ * stay exactly empty and self-closing, and degrades silently, with no error, the moment anything is
10
+ * written inside one. The CURRENT convention has since moved to a single `data-embed-config`
11
+ * attribute carrying a JSON payload (`Tovu/src/core/embeds/marker.ts`); `isProtectedEmbedElement`
12
+ * below has not been updated to recognize it (tracked separately — see that function's own doc), but
13
+ * `describeEmbedPlaceholder` below IS built against the current convention, since it only needs to
14
+ * read the marker, not police edits to it.
15
+ *
16
+ * The generic `@jini-ai/ui` primitive has zero knowledge of either convention; this file is the thin
17
+ * adapter that supplies them as an `isProtectedElement` predicate and a `describeEmbedPlaceholder`
18
+ * labeler, so `PageEditor.tsx` can keep importing `InteractiveHtmlEditor` from `@jini-ai/admin/react`
19
+ * unchanged.
20
+ */
21
+ /** The attribute either the current (`data-embed-type`) or legacy (`data-widget-embed`,
22
+ * `data-form-embed`) convention uses to mark a Page HTML embed placeholder div — see
23
+ * `Tovu/src/widgets/html-embeds.ts`'s file header for the convention this protects.
24
+ *
25
+ * **Does NOT include `data-embed-config`, the CURRENT marker attribute** (`Tovu/src/core/embeds/
26
+ * marker.ts`) — a known, separately-tracked gap: an embed marker written the current way is still
27
+ * editable/draggable/removable in this editor today. Left alone here deliberately (out of scope for
28
+ * the placeholder-card feature this file's `describeEmbedPlaceholder` was added for); widening this
29
+ * list to close that gap is a one-line fix (`'data-embed-config'` added below) but changes real
30
+ * interaction behavior (an operator who could previously drag/delete a `data-embed-config` marker no
31
+ * longer could), which deserves its own change, not a side effect of an unrelated card feature. */
32
+ const EMBED_MARKER_ATTRIBUTES = ['data-embed-type', 'data-widget-embed', 'data-form-embed'];
33
+ /** True when `el` carries any embed marker attribute this convention recognizes — exported for
34
+ * direct unit-testability without mounting the editor. Uses `hasAttributeOnAnyNodeShape` because
35
+ * the `isProtectedElement` predicate is invoked from inside GrapesJS's `isComponent` callback,
36
+ * which is not always called with a real DOM `Element` — see that helper's own doc. */
37
+ export function isProtectedEmbedElement(el) {
38
+ return EMBED_MARKER_ATTRIBUTES.some((attr) => hasAttributeOnAnyNodeShape(el, attr));
39
+ }
40
+ /**
41
+ * Friendly card headings for every embed `type` value this codebase names anywhere, split into two
42
+ * groups (traced against `Tovu/src/server/http/site/render.ts`'s `renderHtmlPageBody`/`isPageEmbedType`
43
+ * at the owner's own request, 2026-08-25 — authoritative, not re-derived):
44
+ *
45
+ * - **`media`, `widget`, `post`, `content`** — the ONLY four types `isPageEmbedType` (gating
46
+ * `renderHtmlPageBody`, `render.ts:1238`) accepts, i.e. the complete set a Page's `body_html` — what
47
+ * this editor edits — can ever actually contain. These are the types an operator can realistically
48
+ * hit in the Interactive tab.
49
+ * - **`partial`, `menu`** — `Tovu/src/widgets/resolver-service.ts`'s `THEME_OWNED_MARKER_TYPES`. NOT
50
+ * reachable inside a Page body — they live in THEME TEMPLATES (site header/nav/footer), authored
51
+ * outside this editor entirely, so this component should not grow UI affordances assuming one can
52
+ * appear here. Labeled anyway (rather than left to the generic fallback below) purely so the ONE
53
+ * defensive case — a future change routes theme markup through this same editor, or a marketplace
54
+ * theme's template gets opened here by mistake — still reads as a real word instead of a raw string.
55
+ *
56
+ * **`media` covers BOTH images and video — one type, one label, by design.** `resolveMediaTypeEmbeds`
57
+ * (`resolver-service.ts`) resolves a `media` marker to either a bare `<img>` or `<video>` tag depending
58
+ * on the asset's own kind, but that distinction lives entirely server-side in the resolved OUTPUT, not
59
+ * in the marker's `data-embed-config` this function reads. Telling them apart here would need either a
60
+ * new server endpoint (out of scope — see `identityLabel`'s doc on the identical media-title tradeoff)
61
+ * or guessing from the id string, which is not a real signal and would be actively misleading if wrong.
62
+ * "Media" stays correct for both until a cheap, real signal exists.
63
+ *
64
+ * Matched lower-cased — see `identityLabel`'s doc and `core/embeds/marker.ts`'s own `toEmbedRef` for
65
+ * why the server-side scanner lower-cases `type` the same way. An unregistered type is not an error
66
+ * here (unlike a rejected/unparseable marker) — `type` is deliberately a free string end-to-end (see
67
+ * `Tovu/src/widgets/html-embeds.ts`'s file header) precisely so a new one (a marketplace theme
68
+ * introducing its own, say) never requires a matching change on this list AND never renders nothing —
69
+ * `titleCase` below covers it with a still-legible generic card instead of a blank/thrown result.
70
+ */
71
+ const EMBED_KIND_LABELS = {
72
+ media: 'Media',
73
+ widget: 'Widget',
74
+ post: 'Post',
75
+ content: 'Content',
76
+ partial: 'Partial',
77
+ menu: 'Menu',
78
+ };
79
+ /** Upper-cases just the first character — `EMBED_KIND_LABELS`'s fallback for a `type` this table
80
+ * doesn't (yet) name, so the card still reads as a word rather than a raw lower-case config value. */
81
+ function titleCase(value) {
82
+ return value.charAt(0).toUpperCase() + value.slice(1);
83
+ }
84
+ /** How much of a bare id to show when no friendlier identity (`name`) is available on the marker's
85
+ * own config — long enough to tell two real ids apart at a glance, short enough the card stays a
86
+ * small chip instead of a wall of digits. */
87
+ const ID_PREVIEW_LENGTH = 8;
88
+ /**
89
+ * The card's identity line: the marker's own `name` when its config carries one (free — no fetch),
90
+ * otherwise a truncated `id`, otherwise an explicit "nothing was set" note rather than a blank line.
91
+ *
92
+ * **Deliberately does not fetch a human title for a `media` marker.** There is no cheap existing admin
93
+ * route for a single media asset's title by id — `AdminAPI.listMedia()` (`apps/admin/src/lib/api.ts`)
94
+ * is the only read, and it returns the ENTIRE workspace's media library, active and trashed, with no
95
+ * id filter or pagination, just to answer one id's `title`. Adding a `GET /media/:id` route is out of
96
+ * this feature's scope (an editor-chrome label is not worth a new server endpoint), and reusing
97
+ * `listMedia()` here would mean an async network call — with its own loading/error/unmount-race
98
+ * handling — inside what is otherwise a synchronous, purely-descriptive function called from a
99
+ * GrapesJS `load` handler. `name`, when authored, covers the common case for free; an id-only marker
100
+ * shows its id.
101
+ */
102
+ function identityLabel(config) {
103
+ const name = typeof config.name === 'string' && config.name.length > 0 ? config.name : null;
104
+ if (name)
105
+ return name;
106
+ const id = typeof config.id === 'string' && config.id.length > 0 ? config.id : null;
107
+ if (!id)
108
+ return 'no id set';
109
+ return id.length > ID_PREVIEW_LENGTH ? `id ${id.slice(0, ID_PREVIEW_LENGTH)}…` : `id ${id}`;
110
+ }
111
+ /**
112
+ * Recognizes a `data-embed-config` marker (`Tovu/src/core/embeds/marker.ts`'s single scanner
113
+ * convention) on a live canvas element and describes it for `@jini-ai/ui/html-editor`'s
114
+ * `applyCanvasEmbedPlaceholders` — see that function's own file header for what it does with the
115
+ * result. Exported for direct unit-testability without mounting the editor, same convention
116
+ * `isProtectedEmbedElement` above already documents.
117
+ *
118
+ * A marker whose `data-embed-config` fails to parse, isn't an object, or has no `type` returns
119
+ * `undefined` — "not a marker this function can describe," the identical degrade-quietly contract
120
+ * `scanEmbedMarkers` (the server-side scanner this mirrors) uses for a rejected marker at render time;
121
+ * this function does not warn or log, since it runs on every keystroke-adjacent canvas re-render, not
122
+ * at a write chokepoint where a loud rejection matters.
123
+ *
124
+ * @complexity O(1) — one attribute read, one `JSON.parse` of a small config object, one table lookup.
125
+ */
126
+ export function describeEmbedPlaceholder(el) {
127
+ const raw = el.getAttribute('data-embed-config');
128
+ if (!raw)
129
+ return undefined;
130
+ let parsed;
131
+ try {
132
+ parsed = JSON.parse(raw);
133
+ }
134
+ catch {
135
+ return undefined;
136
+ }
137
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
138
+ return undefined;
139
+ const config = parsed;
140
+ if (typeof config.type !== 'string' || config.type === '')
141
+ return undefined;
142
+ const type = config.type.toLowerCase();
143
+ return { kindLabel: EMBED_KIND_LABELS[type] ?? titleCase(type), identityLabel: identityLabel(config) };
144
+ }
145
+ export function InteractiveHtmlEditor(props) {
146
+ return (_jsx(HtmlEditor, { ...props, isProtectedElement: isProtectedEmbedElement, describeEmbedPlaceholder: describeEmbedPlaceholder }));
147
+ }
148
+ //# sourceMappingURL=InteractiveHtmlEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InteractiveHtmlEditor.js","sourceRoot":"","sources":["../../../../src/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.tsx"],"names":[],"mappings":"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"}