@pilotiq/pilotiq 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +6 -2
- package/CHANGELOG.md +614 -0
- package/CLAUDE.md +6 -5
- package/dist/Column.d.ts +35 -0
- package/dist/Column.d.ts.map +1 -1
- package/dist/Column.js +41 -0
- package/dist/Column.js.map +1 -1
- package/dist/Page.d.ts +13 -4
- package/dist/Page.d.ts.map +1 -1
- package/dist/Page.js +9 -2
- package/dist/Page.js.map +1 -1
- package/dist/Pilotiq.d.ts +84 -0
- package/dist/Pilotiq.d.ts.map +1 -1
- package/dist/Pilotiq.js +66 -0
- package/dist/Pilotiq.js.map +1 -1
- package/dist/Resource.d.ts +26 -0
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +9 -0
- package/dist/Resource.js.map +1 -1
- package/dist/actions/exportFactory.js +1 -1
- package/dist/actions/exportFactory.js.map +1 -1
- package/dist/columns/SelectColumn.d.ts +32 -5
- package/dist/columns/SelectColumn.d.ts.map +1 -1
- package/dist/columns/SelectColumn.js +37 -7
- package/dist/columns/SelectColumn.js.map +1 -1
- package/dist/defaultPages.d.ts.map +1 -1
- package/dist/defaultPages.js +3 -0
- package/dist/defaultPages.js.map +1 -1
- package/dist/elements/Form.d.ts +17 -0
- package/dist/elements/Form.d.ts.map +1 -1
- package/dist/elements/Form.js +17 -0
- package/dist/elements/Form.js.map +1 -1
- package/dist/elements/Table.d.ts +26 -0
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +15 -1
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableGroup.d.ts +84 -0
- package/dist/elements/TableGroup.d.ts.map +1 -1
- package/dist/elements/TableGroup.js +103 -0
- package/dist/elements/TableGroup.js.map +1 -1
- package/dist/elements/dispatchForm.d.ts.map +1 -1
- package/dist/elements/dispatchForm.js +36 -6
- package/dist/elements/dispatchForm.js.map +1 -1
- package/dist/elements/dispatchTable.d.ts +12 -0
- package/dist/elements/dispatchTable.d.ts.map +1 -1
- package/dist/elements/dispatchTable.js +103 -28
- package/dist/elements/dispatchTable.js.map +1 -1
- package/dist/fields/Field.d.ts +7 -2
- package/dist/fields/Field.d.ts.map +1 -1
- package/dist/fields/Field.js +8 -3
- package/dist/fields/Field.js.map +1 -1
- package/dist/fields/RepeaterField.d.ts +65 -0
- package/dist/fields/RepeaterField.d.ts.map +1 -1
- package/dist/fields/RepeaterField.js +48 -0
- package/dist/fields/RepeaterField.js.map +1 -1
- package/dist/orm/modelDefaults.d.ts.map +1 -1
- package/dist/orm/modelDefaults.js +19 -0
- package/dist/orm/modelDefaults.js.map +1 -1
- package/dist/pageData.d.ts +20 -0
- package/dist/pageData.d.ts.map +1 -1
- package/dist/pageData.js +242 -34
- package/dist/pageData.js.map +1 -1
- package/dist/react/AppShell.d.ts +17 -1
- package/dist/react/AppShell.d.ts.map +1 -1
- package/dist/react/AppShell.js +34 -3
- package/dist/react/AppShell.js.map +1 -1
- package/dist/react/PendingSuggestionApplierRegistry.d.ts +34 -0
- package/dist/react/PendingSuggestionApplierRegistry.d.ts.map +1 -0
- package/dist/react/PendingSuggestionApplierRegistry.js +51 -0
- package/dist/react/PendingSuggestionApplierRegistry.js.map +1 -0
- package/dist/react/PendingSuggestionOverlayRegistry.d.ts +46 -0
- package/dist/react/PendingSuggestionOverlayRegistry.d.ts.map +1 -0
- package/dist/react/PendingSuggestionOverlayRegistry.js +16 -0
- package/dist/react/PendingSuggestionOverlayRegistry.js.map +1 -0
- package/dist/react/PendingSuggestionsContext.d.ts +153 -0
- package/dist/react/PendingSuggestionsContext.d.ts.map +1 -0
- package/dist/react/PendingSuggestionsContext.js +46 -0
- package/dist/react/PendingSuggestionsContext.js.map +1 -0
- package/dist/react/SchemaRenderer.d.ts.map +1 -1
- package/dist/react/SchemaRenderer.js +312 -39
- package/dist/react/SchemaRenderer.js.map +1 -1
- package/dist/react/cells/EditableCell.d.ts +8 -0
- package/dist/react/cells/EditableCell.d.ts.map +1 -1
- package/dist/react/cells/EditableCell.js +6 -2
- package/dist/react/cells/EditableCell.js.map +1 -1
- package/dist/react/fields/CheckboxListInput.d.ts.map +1 -1
- package/dist/react/fields/CheckboxListInput.js +29 -2
- package/dist/react/fields/CheckboxListInput.js.map +1 -1
- package/dist/react/fields/ColorInput.d.ts.map +1 -1
- package/dist/react/fields/ColorInput.js +28 -2
- package/dist/react/fields/ColorInput.js.map +1 -1
- package/dist/react/fields/DateTimeInput.d.ts.map +1 -1
- package/dist/react/fields/DateTimeInput.js +28 -2
- package/dist/react/fields/DateTimeInput.js.map +1 -1
- package/dist/react/fields/FieldShell.d.ts.map +1 -1
- package/dist/react/fields/FieldShell.js +161 -3
- package/dist/react/fields/FieldShell.js.map +1 -1
- package/dist/react/fields/FileUploadInput.d.ts.map +1 -1
- package/dist/react/fields/FileUploadInput.js +27 -2
- package/dist/react/fields/FileUploadInput.js.map +1 -1
- package/dist/react/fields/KeyValueInput.d.ts.map +1 -1
- package/dist/react/fields/KeyValueInput.js +33 -2
- package/dist/react/fields/KeyValueInput.js.map +1 -1
- package/dist/react/fields/RadioInput.d.ts.map +1 -1
- package/dist/react/fields/RadioInput.js +28 -2
- package/dist/react/fields/RadioInput.js.map +1 -1
- package/dist/react/fields/SelectFieldInput.d.ts.map +1 -1
- package/dist/react/fields/SelectFieldInput.js +31 -2
- package/dist/react/fields/SelectFieldInput.js.map +1 -1
- package/dist/react/fields/SliderInput.d.ts.map +1 -1
- package/dist/react/fields/SliderInput.js +26 -2
- package/dist/react/fields/SliderInput.js.map +1 -1
- package/dist/react/fields/TagsInput.d.ts.map +1 -1
- package/dist/react/fields/TagsInput.js +26 -2
- package/dist/react/fields/TagsInput.js.map +1 -1
- package/dist/react/fields/ToggleFieldInput.d.ts.map +1 -1
- package/dist/react/fields/ToggleFieldInput.js +29 -2
- package/dist/react/fields/ToggleFieldInput.js.map +1 -1
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +3 -0
- package/dist/react/index.js.map +1 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +55 -2
- package/dist/routes.js.map +1 -1
- package/dist/schema/Section.d.ts +16 -0
- package/dist/schema/Section.d.ts.map +1 -1
- package/dist/schema/Section.js +16 -0
- package/dist/schema/Section.js.map +1 -1
- package/dist/schema/Wizard.d.ts +45 -0
- package/dist/schema/Wizard.d.ts.map +1 -1
- package/dist/schema/Wizard.js +50 -0
- package/dist/schema/Wizard.js.map +1 -1
- package/dist/schema/resolveSchema.d.ts +8 -0
- package/dist/schema/resolveSchema.d.ts.map +1 -1
- package/dist/schema/resolveSchema.js +70 -1
- package/dist/schema/resolveSchema.js.map +1 -1
- package/dist/sessionFilters.d.ts.map +1 -1
- package/dist/sessionFilters.js +12 -1
- package/dist/sessionFilters.js.map +1 -1
- package/dist/styles/file-upload.css +13 -0
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +19 -12
- package/dist/vite.js.map +1 -1
- package/package.json +6 -4
- package/src/Column.test.ts +36 -0
- package/src/Column.ts +54 -0
- package/src/Page.ts +13 -4
- package/src/Pilotiq.ts +109 -0
- package/src/Resource.ts +29 -0
- package/src/actions/exportFactory.ts +1 -1
- package/src/columns/SelectColumn.ts +46 -8
- package/src/columns/editableColumns.test.ts +45 -0
- package/src/defaultPages.ts +3 -0
- package/src/elements/Form.ts +19 -0
- package/src/elements/Table.ts +35 -1
- package/src/elements/TableGroup.test.ts +111 -0
- package/src/elements/TableGroup.ts +135 -0
- package/src/elements/dispatchForm.ts +34 -7
- package/src/elements/dispatchTable.test.ts +267 -0
- package/src/elements/dispatchTable.ts +111 -32
- package/src/fields/Field.test.ts +15 -0
- package/src/fields/Field.ts +8 -3
- package/src/fields/RepeaterField.ts +104 -0
- package/src/fields/RepeaterRelationship.test.ts +173 -0
- package/src/nestedRelationManagerData.test.ts +21 -0
- package/src/orm/modelDefaults.ts +21 -0
- package/src/pageData.ts +267 -47
- package/src/react/AppShell.tsx +55 -4
- package/src/react/PendingSuggestionApplierRegistry.ts +80 -0
- package/src/react/PendingSuggestionOverlayRegistry.ts +54 -0
- package/src/react/PendingSuggestionsContext.tsx +172 -0
- package/src/react/SchemaRenderer.tsx +504 -95
- package/src/react/cells/EditableCell.tsx +11 -2
- package/src/react/fields/CheckboxListInput.tsx +23 -2
- package/src/react/fields/ColorInput.tsx +22 -2
- package/src/react/fields/DateTimeInput.tsx +22 -2
- package/src/react/fields/FieldShell.tsx +167 -3
- package/src/react/fields/FileUploadInput.tsx +21 -2
- package/src/react/fields/KeyValueInput.tsx +32 -2
- package/src/react/fields/RadioInput.tsx +23 -2
- package/src/react/fields/SelectFieldInput.tsx +25 -2
- package/src/react/fields/SliderInput.tsx +20 -2
- package/src/react/fields/TagsInput.tsx +20 -2
- package/src/react/fields/ToggleFieldInput.tsx +23 -2
- package/src/react/index.ts +18 -0
- package/src/relationManagerData.test.ts +451 -2
- package/src/routes.ts +58 -2
- package/src/schema/Section.ts +17 -0
- package/src/schema/Wizard.ts +67 -0
- package/src/schema/containers.test.ts +90 -0
- package/src/schema/resolveSchema.test.ts +50 -0
- package/src/schema/resolveSchema.ts +79 -1
- package/src/sessionFilters.test.ts +23 -0
- package/src/sessionFilters.ts +11 -1
- package/src/styles/file-upload.css +13 -0
- package/src/vite.ts +19 -12
package/dist/react/AppShell.d.ts
CHANGED
|
@@ -30,6 +30,11 @@ export interface AppShellProps {
|
|
|
30
30
|
* `panelInfo()` server-side. */
|
|
31
31
|
renderHooks?: RenderHookMap;
|
|
32
32
|
themeEditor?: boolean;
|
|
33
|
+
/** AI suggestion mode — absent means `'auto'` (the default). When
|
|
34
|
+
* set to `'review'`, AI plugins read this and stage writes as
|
|
35
|
+
* `PendingSuggestion`s for user approval instead of applying
|
|
36
|
+
* immediately. Plan: `docs/plans/ai-review-mode.md`. */
|
|
37
|
+
aiSuggestionsMode?: 'auto' | 'review';
|
|
33
38
|
};
|
|
34
39
|
basePath: string;
|
|
35
40
|
/** Pathname used to compute active-link state in the sidebar/topbar. */
|
|
@@ -52,7 +57,18 @@ export interface AppShellProps {
|
|
|
52
57
|
* chrome simply doesn't mount.
|
|
53
58
|
*/
|
|
54
59
|
rightPanelRegistry?: RightPanelRegistry;
|
|
60
|
+
/**
|
|
61
|
+
* Build-time layout-provider registry from the Vite plugin. Each entry
|
|
62
|
+
* is a React component that wraps the panel's layout tree at the
|
|
63
|
+
* root. Plugins register via `Pilotiq.layoutProvider(C)`; the Vite
|
|
64
|
+
* plugin harvests refs into this array. Empty `[]` is the no-op
|
|
65
|
+
* default — chrome renders without any extra wrapping.
|
|
66
|
+
*/
|
|
67
|
+
layoutProviderRegistry?: ReadonlyArray<React.ComponentType<{
|
|
68
|
+
children: React.ReactNode;
|
|
69
|
+
basePath?: string;
|
|
70
|
+
}>>;
|
|
55
71
|
children: React.ReactNode;
|
|
56
72
|
}
|
|
57
|
-
export declare function AppShell({ layout, notifications, componentRegistry, rightPanelRegistry, ...props }: AppShellProps):
|
|
73
|
+
export declare function AppShell({ layout, notifications, componentRegistry, rightPanelRegistry, layoutProviderRegistry, ...props }: AppShellProps): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
|
|
58
74
|
//# sourceMappingURL=AppShell.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppShell.d.ts","sourceRoot":"","sources":["../../src/react/AppShell.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"AppShell.d.ts","sourceRoot":"","sources":["../../src/react/AppShell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAKlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAKnE,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACxG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAGrD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QAC3C,oEAAoE;QACpE,UAAU,CAAC,EAAE,OAAO,EAAE,CAAA;QACtB;sEAC8D;QAC9D,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;QAC9B;;qEAE6D;QAC7D,qBAAqB,CAAC,EAAE,yBAAyB,CAAA;QACjD;;yEAEiE;QACjE,YAAY,CAAC,EAAE,gBAAgB,CAAA;QAC/B;;;yCAGiC;QACjC,WAAW,CAAC,EAAE,aAAa,CAAA;QAC3B,WAAW,CAAC,EAAE,OAAO,CAAA;QACrB;;;iEAGyD;QACzD,iBAAiB,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;KACtC,CAAA;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC7B;8CAC0C;IAC1C,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAClC;;;;wCAIoC;IACpC,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC;QAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;IAC7G,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,wBAAgB,QAAQ,CAAC,EAAE,MAAkB,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,0EA0ErJ"}
|
package/dist/react/AppShell.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
3
|
import { SidebarLayout } from './layouts/SidebarLayout.js';
|
|
4
4
|
import { TopbarLayout } from './layouts/TopbarLayout.js';
|
|
5
5
|
import { ToasterProvider } from './Toaster.js';
|
|
@@ -10,10 +10,20 @@ import { RightSidebarProvider, useRightSidebarOptional } from './RightSidebarCon
|
|
|
10
10
|
import { RightSidebar } from './RightSidebar.js';
|
|
11
11
|
import { useIsMobile } from './hooks/use-mobile.js';
|
|
12
12
|
import { RenderHookSlot } from './RenderHookSlot.js';
|
|
13
|
-
export function AppShell({ layout = 'sidebar', notifications, componentRegistry, rightPanelRegistry, ...props }) {
|
|
13
|
+
export function AppShell({ layout = 'sidebar', notifications, componentRegistry, rightPanelRegistry, layoutProviderRegistry, ...props }) {
|
|
14
14
|
const Layout = layout === 'topbar' ? TopbarLayout : SidebarLayout;
|
|
15
15
|
// exactOptionalPropertyTypes: only spread `initialNotifications` when set.
|
|
16
16
|
const toasterProps = notifications ? { initialNotifications: notifications } : {};
|
|
17
|
+
// Stamp the panel-wide AI suggestion mode on a window global so the
|
|
18
|
+
// AI plugin's `update_form_state` client-tool handler can read it
|
|
19
|
+
// without context plumbing. Singleton flag — doesn't change between
|
|
20
|
+
// pages within the same panel. Plan: `docs/plans/ai-review-mode.md`.
|
|
21
|
+
const aiSuggestionsMode = props.panel.aiSuggestionsMode ?? 'auto';
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (typeof window === 'undefined')
|
|
24
|
+
return;
|
|
25
|
+
window.__pilotiqAiSuggestionsMode = aiSuggestionsMode;
|
|
26
|
+
}, [aiSuggestionsMode]);
|
|
17
27
|
// Plan #12 — palette open state lives at AppShell so the trigger pill
|
|
18
28
|
// (rendered inside the layout's header) and the palette dialog both
|
|
19
29
|
// observe the same flag via context.
|
|
@@ -28,7 +38,28 @@ export function AppShell({ layout = 'sidebar', notifications, componentRegistry,
|
|
|
28
38
|
const hooks = props.panel.renderHooks;
|
|
29
39
|
const rightSidebarMeta = props.panel.rightSidebar;
|
|
30
40
|
const inner = (_jsx(ToasterProvider, { ...toasterProps, children: _jsxs(CommandPaletteProvider, { setOpen: setPaletteOpen, children: [_jsx(RenderHookSlot, { name: "panels::body.start", hooks: hooks }), _jsx(RightSidebarLayoutFrame, { children: _jsx(Layout, { ...props }) }), _jsx(RenderHookSlot, { name: "panels::body.end", hooks: hooks }), _jsx(CommandPalette, { ...paletteProps }), rightSidebarMeta && (_jsx(RightSidebar, { basePath: props.basePath, ...(props.currentPath !== undefined ? { currentPath: props.currentPath } : {}) }))] }) }));
|
|
31
|
-
|
|
41
|
+
// Plugin-registered layout providers (e.g. AI chat queue, tenant
|
|
42
|
+
// theme switcher). Wraps in registration order: the FIRST registered
|
|
43
|
+
// provider sits OUTERMOST (closest to the layout root); LAST sits
|
|
44
|
+
// INNERMOST (closest to the page tree). Empty / unset → no wrap.
|
|
45
|
+
const wrapped = wrapInLayoutProviders(_jsx(ComponentRegistryProvider, { value: componentRegistry, children: _jsx(RightPanelRegistryProvider, { value: rightPanelRegistry, children: rightSidebarMeta ? (_jsx(RightSidebarProvider, { meta: rightSidebarMeta, basePath: props.basePath, children: inner })) : (inner) }) }), layoutProviderRegistry, props.basePath);
|
|
46
|
+
return wrapped;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Fold registered layout providers around `tree` from last to first so
|
|
50
|
+
* the first-registered provider ends up outermost in the React tree
|
|
51
|
+
* (closest to the layout root) — matches the registration-order
|
|
52
|
+
* intuition documented on `Pilotiq.layoutProvider`.
|
|
53
|
+
*/
|
|
54
|
+
function wrapInLayoutProviders(tree, registry, basePath) {
|
|
55
|
+
if (!registry || registry.length === 0)
|
|
56
|
+
return tree;
|
|
57
|
+
let acc = tree;
|
|
58
|
+
for (let i = registry.length - 1; i >= 0; i--) {
|
|
59
|
+
const Provider = registry[i];
|
|
60
|
+
acc = _jsx(Provider, { basePath: basePath, children: acc });
|
|
61
|
+
}
|
|
62
|
+
return acc;
|
|
32
63
|
}
|
|
33
64
|
/**
|
|
34
65
|
* Padding shim that compresses host content when the right sidebar is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppShell.js","sourceRoot":"","sources":["../../src/react/AppShell.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"AppShell.js","sourceRoot":"","sources":["../../src/react/AppShell.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { PendingSuggestion } from './PendingSuggestionsContext.js';
|
|
2
|
+
/**
|
|
3
|
+
* A function that applies a `PendingSuggestion` to its target field —
|
|
4
|
+
* registered by the field renderer (or editor adapter) on mount, looked
|
|
5
|
+
* up by aggregate consumers (e.g. a chat-sidebar pending-pill's
|
|
6
|
+
* "Approve all" button) that live outside the form's React tree.
|
|
7
|
+
*
|
|
8
|
+
* The applier is responsible for the apply *only*. Dismissing the
|
|
9
|
+
* suggestion from the queue is the caller's job — the apply path is
|
|
10
|
+
* decoupled from the queue-side bookkeeping so a future Phase that
|
|
11
|
+
* mirrors approvals to a server can do both via different code paths.
|
|
12
|
+
*/
|
|
13
|
+
export type PendingSuggestionApplier = (suggestion: PendingSuggestion) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Register an applier for `(formId, fieldName)`. Returns an unregister
|
|
16
|
+
* function for `useEffect` cleanup. Re-registering with the same key
|
|
17
|
+
* replaces the previous entry — the most recently mounted renderer
|
|
18
|
+
* wins (typical in multi-instance form scenarios where an old form
|
|
19
|
+
* unmounts after a new one mounts during navigation).
|
|
20
|
+
*/
|
|
21
|
+
export declare function registerPendingSuggestionApplier(formId: string | undefined, fieldName: string, apply: PendingSuggestionApplier): () => void;
|
|
22
|
+
/**
|
|
23
|
+
* Look up an applier for `(formId, fieldName)`. Tries the form-scoped
|
|
24
|
+
* key first; falls back to the wildcard form ('*') so a producer that
|
|
25
|
+
* pushed a suggestion without `formId` still resolves an applier from
|
|
26
|
+
* a single-form page.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getPendingSuggestionApplier(formId: string | undefined, fieldName: string): PendingSuggestionApplier | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Test seam — clear the registry between tests. Not part of the public
|
|
31
|
+
* API.
|
|
32
|
+
*/
|
|
33
|
+
export declare function _clearAppliersForTests(): void;
|
|
34
|
+
//# sourceMappingURL=PendingSuggestionApplierRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PendingSuggestionApplierRegistry.d.ts","sourceRoot":"","sources":["../../src/react/PendingSuggestionApplierRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEvE;;;;;;;;;;GAUG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,UAAU,EAAE,iBAAiB,KAAK,IAAI,CAAA;AAoB9E;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,MAAM,EAAK,MAAM,GAAG,SAAS,EAC7B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAM,wBAAwB,GAClC,MAAM,IAAI,CASZ;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAK,MAAM,GAAG,SAAS,EAC7B,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,SAAS,CAOtC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const _entries = new Map();
|
|
2
|
+
/**
|
|
3
|
+
* Compose the registry key. `formId` defaults to `'*'` (global form
|
|
4
|
+
* scope) so renderers in non-multi-form pages don't have to thread an
|
|
5
|
+
* id. Form-scoped registrations always win over the wildcard when both
|
|
6
|
+
* exist for the same field name.
|
|
7
|
+
*/
|
|
8
|
+
function keyFor(formId, fieldName) {
|
|
9
|
+
return `${formId ?? '*'}::${fieldName}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Register an applier for `(formId, fieldName)`. Returns an unregister
|
|
13
|
+
* function for `useEffect` cleanup. Re-registering with the same key
|
|
14
|
+
* replaces the previous entry — the most recently mounted renderer
|
|
15
|
+
* wins (typical in multi-instance form scenarios where an old form
|
|
16
|
+
* unmounts after a new one mounts during navigation).
|
|
17
|
+
*/
|
|
18
|
+
export function registerPendingSuggestionApplier(formId, fieldName, apply) {
|
|
19
|
+
const key = keyFor(formId, fieldName);
|
|
20
|
+
const entry = { formId, fieldName, apply };
|
|
21
|
+
_entries.set(key, entry);
|
|
22
|
+
return () => {
|
|
23
|
+
// Only delete if this entry is still the one we registered — a
|
|
24
|
+
// re-register from another instance may have replaced us.
|
|
25
|
+
if (_entries.get(key) === entry)
|
|
26
|
+
_entries.delete(key);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Look up an applier for `(formId, fieldName)`. Tries the form-scoped
|
|
31
|
+
* key first; falls back to the wildcard form ('*') so a producer that
|
|
32
|
+
* pushed a suggestion without `formId` still resolves an applier from
|
|
33
|
+
* a single-form page.
|
|
34
|
+
*/
|
|
35
|
+
export function getPendingSuggestionApplier(formId, fieldName) {
|
|
36
|
+
if (formId !== undefined) {
|
|
37
|
+
const scoped = _entries.get(keyFor(formId, fieldName));
|
|
38
|
+
if (scoped)
|
|
39
|
+
return scoped.apply;
|
|
40
|
+
}
|
|
41
|
+
const wild = _entries.get(keyFor(undefined, fieldName));
|
|
42
|
+
return wild?.apply;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Test seam — clear the registry between tests. Not part of the public
|
|
46
|
+
* API.
|
|
47
|
+
*/
|
|
48
|
+
export function _clearAppliersForTests() {
|
|
49
|
+
_entries.clear();
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=PendingSuggestionApplierRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PendingSuggestionApplierRegistry.js","sourceRoot":"","sources":["../../src/react/PendingSuggestionApplierRegistry.ts"],"names":[],"mappings":"AAqBA,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAA;AAEjD;;;;;GAKG;AACH,SAAS,MAAM,CAAC,MAA0B,EAAE,SAAiB;IAC3D,OAAO,GAAG,MAAM,IAAI,GAAG,KAAK,SAAS,EAAE,CAAA;AACzC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gCAAgC,CAC9C,MAA6B,EAC7B,SAAiB,EACjB,KAAmC;IAEnC,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACrC,MAAM,KAAK,GAAkB,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;IACzD,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACxB,OAAO,GAAG,EAAE;QACV,+DAA+D;QAC/D,0DAA0D;QAC1D,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK;YAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACvD,CAAC,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CACzC,MAA6B,EAC7B,SAAiB;IAEjB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;QACtD,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC,KAAK,CAAA;IACjC,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAA;IACvD,OAAO,IAAI,EAAE,KAAK,CAAA;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,QAAQ,CAAC,KAAK,EAAE,CAAA;AAClB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import type { PendingSuggestion } from './PendingSuggestionsContext.js';
|
|
3
|
+
import type { ElementMeta } from '../schema/Element.js';
|
|
4
|
+
/**
|
|
5
|
+
* Props the per-field overlay component receives from `FieldShell` when
|
|
6
|
+
* one or more pending suggestions target the field.
|
|
7
|
+
*
|
|
8
|
+
* The overlay is responsible for both rendering AND applying the
|
|
9
|
+
* suggestion. On Approve, call `onApprove()` (which dismisses the
|
|
10
|
+
* suggestion from the queue) AFTER mutating the form's field value to
|
|
11
|
+
* `suggestion.suggestedValue` — the queue is just a notification surface,
|
|
12
|
+
* applying is the renderer's job.
|
|
13
|
+
*
|
|
14
|
+
* The Tiptap `RichTextField` renderer skips this slot entirely — it
|
|
15
|
+
* mirrors suggestions into the editor's inline AiSuggestion extension
|
|
16
|
+
* instead. Other field types (Text / Textarea / Select / Number / …)
|
|
17
|
+
* render the registered overlay below their input.
|
|
18
|
+
*/
|
|
19
|
+
export interface PendingSuggestionOverlayProps {
|
|
20
|
+
/** First suggestion targeting this field. Aggregate UIs handle stacks. */
|
|
21
|
+
suggestion: PendingSuggestion;
|
|
22
|
+
/** Drop from queue (callable after applying). */
|
|
23
|
+
onApprove: () => void;
|
|
24
|
+
/** Drop from queue without applying. */
|
|
25
|
+
onReject: () => void;
|
|
26
|
+
/** Field type string (`text` / `select` / `toggle` / `slider` / `color` /
|
|
27
|
+
* …) so per-fieldType overlay renderers can branch. Sparse — older
|
|
28
|
+
* hosts may omit. Phase C of ai-review-mode. */
|
|
29
|
+
fieldType?: string;
|
|
30
|
+
/** Resolved field meta — gives the overlay access to per-field config
|
|
31
|
+
* (`options` for Select, `min/max` for Slider, etc.) needed to render
|
|
32
|
+
* human-friendly comparisons rather than raw values. Sparse — older
|
|
33
|
+
* hosts may omit. */
|
|
34
|
+
el?: ElementMeta;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Register a component to render below any `FieldShell` whose field has at
|
|
38
|
+
* least one matching pending suggestion in the
|
|
39
|
+
* `<PendingSuggestionsContext>` queue. Called once at boot by a plugin
|
|
40
|
+
* (e.g. `@pilotiq-pro/ai`). No-op when no plugin registers — `FieldShell`
|
|
41
|
+
* skips the overlay slot.
|
|
42
|
+
*/
|
|
43
|
+
export declare function registerPendingSuggestionOverlay(C: ComponentType<PendingSuggestionOverlayProps>): void;
|
|
44
|
+
/** Returns the registered overlay component, or `null`. */
|
|
45
|
+
export declare function getPendingSuggestionOverlay(): ComponentType<PendingSuggestionOverlayProps> | null;
|
|
46
|
+
//# sourceMappingURL=PendingSuggestionOverlayRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PendingSuggestionOverlayRegistry.d.ts","sourceRoot":"","sources":["../../src/react/PendingSuggestionOverlayRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEvD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,6BAA6B;IAC5C,0EAA0E;IAC1E,UAAU,EAAE,iBAAiB,CAAA;IAC7B,iDAAiD;IACjD,SAAS,EAAG,MAAM,IAAI,CAAA;IACtB,wCAAwC;IACxC,QAAQ,EAAI,MAAM,IAAI,CAAA;IACtB;;qDAEiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;0BAGsB;IACtB,EAAE,CAAC,EAAS,WAAW,CAAA;CACxB;AAID;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAAC,CAAC,EAAE,aAAa,CAAC,6BAA6B,CAAC,GAAG,IAAI,CAEtG;AAED,2DAA2D;AAC3D,wBAAgB,2BAA2B,IAAI,aAAa,CAAC,6BAA6B,CAAC,GAAG,IAAI,CAEjG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
let _component = null;
|
|
2
|
+
/**
|
|
3
|
+
* Register a component to render below any `FieldShell` whose field has at
|
|
4
|
+
* least one matching pending suggestion in the
|
|
5
|
+
* `<PendingSuggestionsContext>` queue. Called once at boot by a plugin
|
|
6
|
+
* (e.g. `@pilotiq-pro/ai`). No-op when no plugin registers — `FieldShell`
|
|
7
|
+
* skips the overlay slot.
|
|
8
|
+
*/
|
|
9
|
+
export function registerPendingSuggestionOverlay(C) {
|
|
10
|
+
_component = C;
|
|
11
|
+
}
|
|
12
|
+
/** Returns the registered overlay component, or `null`. */
|
|
13
|
+
export function getPendingSuggestionOverlay() {
|
|
14
|
+
return _component;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=PendingSuggestionOverlayRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PendingSuggestionOverlayRegistry.js","sourceRoot":"","sources":["../../src/react/PendingSuggestionOverlayRegistry.ts"],"names":[],"mappings":"AAqCA,IAAI,UAAU,GAAwD,IAAI,CAAA;AAE1E;;;;;;GAMG;AACH,MAAM,UAAU,gCAAgC,CAAC,CAA+C;IAC9F,UAAU,GAAG,CAAC,CAAA;AAChB,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,2BAA2B;IACzC,OAAO,UAAU,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* One AI- (or extension-) sourced suggested field-value change. Sits in a
|
|
4
|
+
* unified queue read by:
|
|
5
|
+
*
|
|
6
|
+
* - the Tiptap `RichTextField` renderer — for `richtext` fields, the
|
|
7
|
+
* suggestion is mirrored into the editor's `AiSuggestion` extension as
|
|
8
|
+
* an inline diff with per-hunk Approve/Reject chips
|
|
9
|
+
* - `FieldShell`'s overlay slot — for any other field type, a registered
|
|
10
|
+
* overlay component renders a `currentValue` vs `suggestedValue` diff
|
|
11
|
+
* card below the input
|
|
12
|
+
* - aggregate "Pending suggestions" pills (e.g. in a chat sidebar) — read
|
|
13
|
+
* the full list to show counts + bulk approve / reject affordances
|
|
14
|
+
*
|
|
15
|
+
* The shape is intentionally generic — the `meta` bag carries field-type-
|
|
16
|
+
* specific extras (e.g. `editorRange: { from, to }` for `richtext`).
|
|
17
|
+
*
|
|
18
|
+
* Pilotiq core does NOT push or apply suggestions itself. The provider
|
|
19
|
+
* implementation + push paths live in plugin packages (e.g.
|
|
20
|
+
* `@pilotiq-pro/ai`); core just owns the type, context, and hooks so any
|
|
21
|
+
* field renderer can subscribe through one open-core seam.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Where a suggestion came from. Lets aggregate consumers (pill UIs)
|
|
25
|
+
* filter the shared queue by surface — e.g. a popover-chat scoped pill
|
|
26
|
+
* shows only suggestions produced by its own session, while the
|
|
27
|
+
* sidebar pill shows everything. Sparse on push; consumers treat
|
|
28
|
+
* absence as "unknown origin, include in unfiltered views".
|
|
29
|
+
*/
|
|
30
|
+
export interface PendingSuggestionOrigin {
|
|
31
|
+
/**
|
|
32
|
+
* Which UI surface initiated the agent run that produced this
|
|
33
|
+
* suggestion. `'field-action'` covers the `✦` per-field dropdown.
|
|
34
|
+
*/
|
|
35
|
+
surface: 'sidebar' | 'popover' | 'field-action';
|
|
36
|
+
/**
|
|
37
|
+
* Stable id of the agent run / chat turn that produced this
|
|
38
|
+
* suggestion. Popover pills filter on this so they only see their
|
|
39
|
+
* own session's output even when the panel-wide queue holds many.
|
|
40
|
+
*/
|
|
41
|
+
runId?: string;
|
|
42
|
+
/** Slug of the agent whose tool call produced the suggestion. */
|
|
43
|
+
agentSlug?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface PendingSuggestion {
|
|
46
|
+
/** Stable id; the producer is responsible for uniqueness. */
|
|
47
|
+
id: string;
|
|
48
|
+
/** Field name this suggestion targets. Matched verbatim in the renderer. */
|
|
49
|
+
fieldName: string;
|
|
50
|
+
/**
|
|
51
|
+
* Form scope. Multi-form pages (Plan #5 reactive fields) stamp the form's
|
|
52
|
+
* id here so a renderer in form A doesn't pick up a suggestion meant for
|
|
53
|
+
* form B. Optional — when both producer and consumer omit it, suggestions
|
|
54
|
+
* are global.
|
|
55
|
+
*/
|
|
56
|
+
formId?: string;
|
|
57
|
+
/** Snapshot of the field's value at the time the suggestion was produced. */
|
|
58
|
+
currentValue: unknown;
|
|
59
|
+
/** Proposed replacement. */
|
|
60
|
+
suggestedValue: unknown;
|
|
61
|
+
/** Optional attribution surfaced on the diff overlay / inline chip. */
|
|
62
|
+
source?: {
|
|
63
|
+
agentSlug?: string;
|
|
64
|
+
agentLabel?: string;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Provenance hint for cross-surface filtering. Sparse — pushed when
|
|
68
|
+
* the producer knows which agent run / chat surface it's running
|
|
69
|
+
* inside (e.g. the popover-chat tagging its turn id so its scoped
|
|
70
|
+
* pill can filter the shared queue). Aggregate consumers that don't
|
|
71
|
+
* care just leave the field unread.
|
|
72
|
+
*/
|
|
73
|
+
origin?: PendingSuggestionOrigin;
|
|
74
|
+
/** Wallclock ms when produced. Producers fill this in on `push`. */
|
|
75
|
+
createdAt: number;
|
|
76
|
+
/** Field-type-specific extras (e.g. `editorRange: { from, to }`). Sparse. */
|
|
77
|
+
meta?: Record<string, unknown>;
|
|
78
|
+
}
|
|
79
|
+
export interface PendingSuggestionsApi {
|
|
80
|
+
/** Full list across every field + form. Aggregate consumers read this. */
|
|
81
|
+
list: readonly PendingSuggestion[];
|
|
82
|
+
/** Add a suggestion to the queue. Returns the (possibly producer-supplied) id. */
|
|
83
|
+
push: (suggestion: Omit<PendingSuggestion, 'createdAt'> & {
|
|
84
|
+
createdAt?: number;
|
|
85
|
+
}) => string;
|
|
86
|
+
/**
|
|
87
|
+
* Drop the suggestion from the queue. Used by both inline approval
|
|
88
|
+
* paths (where the renderer applies directly and just notifies the
|
|
89
|
+
* queue) AND by Reject. For aggregate consumers (e.g. a chat-pill
|
|
90
|
+
* "Approve all" button) that live outside the form's React tree, see
|
|
91
|
+
* `approve` below — it looks up a registered applier and calls it
|
|
92
|
+
* before dismissing.
|
|
93
|
+
*/
|
|
94
|
+
dismiss: (id: string) => void;
|
|
95
|
+
/**
|
|
96
|
+
* Apply + dismiss. Resolves the suggestion's `(formId, fieldName)`
|
|
97
|
+
* pair against `PendingSuggestionApplierRegistry`; if an applier is
|
|
98
|
+
* registered (FieldShell + Tiptap bridge auto-register on mount),
|
|
99
|
+
* runs it and then dismisses. If no applier is registered (or the
|
|
100
|
+
* applier throws), falls through to a plain `dismiss` so the queue
|
|
101
|
+
* still clears — never strands an entry.
|
|
102
|
+
*
|
|
103
|
+
* Use this from cross-tree surfaces (chat-sidebar pending-pill).
|
|
104
|
+
* Inline surfaces (FieldShell overlay, Tiptap chip) apply via their
|
|
105
|
+
* own React-tree-local mutators and call `dismiss` directly.
|
|
106
|
+
*/
|
|
107
|
+
approve: (id: string) => void;
|
|
108
|
+
/**
|
|
109
|
+
* Drop every suggestion matching the optional filter. With no filter,
|
|
110
|
+
* empties the entire queue.
|
|
111
|
+
*/
|
|
112
|
+
dismissAll: (filter?: {
|
|
113
|
+
fieldName?: string;
|
|
114
|
+
formId?: string;
|
|
115
|
+
}) => void;
|
|
116
|
+
/**
|
|
117
|
+
* Apply + dismiss every suggestion matching the optional filter.
|
|
118
|
+
* Calls `approve(id)` per entry — same fall-through semantics if an
|
|
119
|
+
* applier is missing or throws.
|
|
120
|
+
*/
|
|
121
|
+
approveAll: (filter?: {
|
|
122
|
+
fieldName?: string;
|
|
123
|
+
formId?: string;
|
|
124
|
+
}) => void;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Context default is a no-op API — fields that subscribe in trees without a
|
|
128
|
+
* real provider mounted (e.g. the marketing site's preview, headless tests)
|
|
129
|
+
* see an empty list and no-op approval methods. Never throws.
|
|
130
|
+
*/
|
|
131
|
+
export declare const PendingSuggestionsContext: React.Context<PendingSuggestionsApi>;
|
|
132
|
+
/** Read the full queue + producer methods. Used by aggregate UIs. */
|
|
133
|
+
export declare function usePendingSuggestions(): PendingSuggestionsApi;
|
|
134
|
+
/**
|
|
135
|
+
* Subscribe a single field-renderer to its slice of the queue. Returns
|
|
136
|
+
* `list` already filtered + a `dismiss` callback that the renderer wires
|
|
137
|
+
* to its Approve / Reject buttons.
|
|
138
|
+
*
|
|
139
|
+
* Matching rules:
|
|
140
|
+
* - `s.fieldName === fieldName` (verbatim)
|
|
141
|
+
* - if both `formId` args are non-`undefined`, they must match; otherwise
|
|
142
|
+
* the entry passes (so global suggestions reach scoped readers and
|
|
143
|
+
* vice-versa)
|
|
144
|
+
*
|
|
145
|
+
* The list reference is stable across renders unless the underlying
|
|
146
|
+
* filtered slice actually changes — useful for `useEffect` dependencies
|
|
147
|
+
* in renderers that mirror suggestions into their own state.
|
|
148
|
+
*/
|
|
149
|
+
export declare function usePendingSuggestionsForField(fieldName: string, formId?: string): {
|
|
150
|
+
list: readonly PendingSuggestion[];
|
|
151
|
+
dismiss: (id: string) => void;
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=PendingSuggestionsContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PendingSuggestionsContext.d.ts","sourceRoot":"","sources":["../../src/react/PendingSuggestionsContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAA;AAEjE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,OAAO,EAAK,SAAS,GAAG,SAAS,GAAG,cAAc,CAAA;IAClD;;;;OAIG;IACH,KAAK,CAAC,EAAM,MAAM,CAAA;IAClB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,6DAA6D;IAC7D,EAAE,EAAe,MAAM,CAAA;IACvB,4EAA4E;IAC5E,SAAS,EAAQ,MAAM,CAAA;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAU,MAAM,CAAA;IACvB,6EAA6E;IAC7E,YAAY,EAAK,OAAO,CAAA;IACxB,4BAA4B;IAC5B,cAAc,EAAG,OAAO,CAAA;IACxB,uEAAuE;IACvE,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAG,MAAM,CAAA;QACnB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IACD;;;;;;OAMG;IACH,MAAM,CAAC,EAAU,uBAAuB,CAAA;IACxC,oEAAoE;IACpE,SAAS,EAAQ,MAAM,CAAA;IACvB,6EAA6E;IAC7E,IAAI,CAAC,EAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACzC;AAED,MAAM,WAAW,qBAAqB;IACpC,0EAA0E;IAC1E,IAAI,EAAS,SAAS,iBAAiB,EAAE,CAAA;IACzC,kFAAkF;IAClF,IAAI,EAAS,CAAC,UAAU,EAAE,IAAI,CAAC,iBAAiB,EAAE,WAAW,CAAC,GAAG;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;IAClG;;;;;;;OAOG;IACH,OAAO,EAAM,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC;;;;;;;;;;;OAWG;IACH,OAAO,EAAM,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC;;;OAGG;IACH,UAAU,EAAG,CAAC,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IACvE;;;;OAIG;IACH,UAAU,EAAG,CAAC,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACxE;AAWD;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,sCAAiD,CAAA;AAEvF,qEAAqE;AACrE,wBAAgB,qBAAqB,IAAI,qBAAqB,CAE7D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAI,MAAM,GAChB;IACD,IAAI,EAAK,SAAS,iBAAiB,EAAE,CAAA;IACrC,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9B,CAQA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createContext, useContext, useMemo } from 'react';
|
|
2
|
+
const NOOP_API = Object.freeze({
|
|
3
|
+
list: Object.freeze([]),
|
|
4
|
+
push: () => '',
|
|
5
|
+
dismiss: () => { },
|
|
6
|
+
approve: () => { },
|
|
7
|
+
dismissAll: () => { },
|
|
8
|
+
approveAll: () => { },
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Context default is a no-op API — fields that subscribe in trees without a
|
|
12
|
+
* real provider mounted (e.g. the marketing site's preview, headless tests)
|
|
13
|
+
* see an empty list and no-op approval methods. Never throws.
|
|
14
|
+
*/
|
|
15
|
+
export const PendingSuggestionsContext = createContext(NOOP_API);
|
|
16
|
+
/** Read the full queue + producer methods. Used by aggregate UIs. */
|
|
17
|
+
export function usePendingSuggestions() {
|
|
18
|
+
return useContext(PendingSuggestionsContext);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Subscribe a single field-renderer to its slice of the queue. Returns
|
|
22
|
+
* `list` already filtered + a `dismiss` callback that the renderer wires
|
|
23
|
+
* to its Approve / Reject buttons.
|
|
24
|
+
*
|
|
25
|
+
* Matching rules:
|
|
26
|
+
* - `s.fieldName === fieldName` (verbatim)
|
|
27
|
+
* - if both `formId` args are non-`undefined`, they must match; otherwise
|
|
28
|
+
* the entry passes (so global suggestions reach scoped readers and
|
|
29
|
+
* vice-versa)
|
|
30
|
+
*
|
|
31
|
+
* The list reference is stable across renders unless the underlying
|
|
32
|
+
* filtered slice actually changes — useful for `useEffect` dependencies
|
|
33
|
+
* in renderers that mirror suggestions into their own state.
|
|
34
|
+
*/
|
|
35
|
+
export function usePendingSuggestionsForField(fieldName, formId) {
|
|
36
|
+
const api = useContext(PendingSuggestionsContext);
|
|
37
|
+
const list = useMemo(() => api.list.filter(s => {
|
|
38
|
+
if (s.fieldName !== fieldName)
|
|
39
|
+
return false;
|
|
40
|
+
if (formId === undefined || s.formId === undefined)
|
|
41
|
+
return true;
|
|
42
|
+
return s.formId === formId;
|
|
43
|
+
}), [api.list, fieldName, formId]);
|
|
44
|
+
return { list, dismiss: api.dismiss };
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=PendingSuggestionsContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PendingSuggestionsContext.js","sourceRoot":"","sources":["../../src/react/PendingSuggestionsContext.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAyHjE,MAAM,QAAQ,GAA0B,MAAM,CAAC,MAAM,CAAC;IACpD,IAAI,EAAQ,MAAM,CAAC,MAAM,CAAC,EAAE,CAAiC;IAC7D,IAAI,EAAQ,GAAG,EAAE,CAAC,EAAE;IACpB,OAAO,EAAK,GAAG,EAAE,GAAE,CAAC;IACpB,OAAO,EAAK,GAAG,EAAE,GAAE,CAAC;IACpB,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC;IACpB,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC;CACrB,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,aAAa,CAAwB,QAAQ,CAAC,CAAA;AAEvF,qEAAqE;AACrE,MAAM,UAAU,qBAAqB;IACnC,OAAO,UAAU,CAAC,yBAAyB,CAAC,CAAA;AAC9C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,6BAA6B,CAC3C,SAAiB,EACjB,MAAiB;IAKjB,MAAM,GAAG,GAAG,UAAU,CAAC,yBAAyB,CAAC,CAAA;IACjD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QAC7C,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS;YAAE,OAAO,KAAK,CAAA;QAC3C,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,IAAI,CAAA;QAC/D,OAAO,CAAC,CAAC,MAAM,KAAK,MAAM,CAAA;IAC5B,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAA;IAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAA;AACvC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SchemaRenderer.d.ts","sourceRoot":"","sources":["../../src/react/SchemaRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"SchemaRenderer.d.ts","sourceRoot":"","sources":["../../src/react/SchemaRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AA8HvD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAG,WAAW,EAAE,CAAA;IACxB,MAAM,CAAC,EAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,eAAe,GAAG,KAAK,CAAC,YAAY,CAapF;AAieD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AAExE,KAAK,MAAM,GAAM,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,KAAK,IAAI,CAAA;AAC7E,KAAK,QAAQ,GAAI,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;AAkDtC;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAO,MAAM,EAChB,GAAG,EAAO,MAAM,EAAE,EAClB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAI,MAAM,EAChB,MAAM,GAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACrC,YAAY,CAAC,EAAE,QAAQ,GACtB,OAAO,CAAC,IAAI,CAAC,CAoCf;AAqvFD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAC/B,KAAK,CAAC,SAAS,CAejB;AAsnGD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,WAAW,EAAE,CAAA;IACvB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACrC;AAED,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,mBAAmB,kDAW3E"}
|