@pillar-ai/react 0.1.3 → 0.1.7
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/README.md +22 -3
- package/dist/PillarProvider.d.ts +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +32 -18
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +32 -18
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/HelpButton.d.ts +0 -62
- package/dist/Tooltip.d.ts +0 -39
package/README.md
CHANGED
|
@@ -35,15 +35,34 @@ The root provider that initializes the SDK and provides context to child compone
|
|
|
35
35
|
helpCenter="your-help-center"
|
|
36
36
|
publicKey="pk_live_xxx"
|
|
37
37
|
config={{
|
|
38
|
-
panel: { position: 'right' },
|
|
39
|
-
|
|
40
|
-
theme: { mode: '
|
|
38
|
+
panel: { position: 'right', mode: 'push' },
|
|
39
|
+
edgeTrigger: { enabled: true },
|
|
40
|
+
theme: { mode: 'auto' },
|
|
41
41
|
}}
|
|
42
42
|
>
|
|
43
43
|
{children}
|
|
44
44
|
</PillarProvider>
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
### Custom Trigger Button
|
|
48
|
+
|
|
49
|
+
To use your own button instead of the built-in edge trigger:
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
<PillarProvider
|
|
53
|
+
helpCenter="your-help-center"
|
|
54
|
+
publicKey="pk_live_xxx"
|
|
55
|
+
config={{ edgeTrigger: { enabled: false } }}
|
|
56
|
+
>
|
|
57
|
+
<MyApp />
|
|
58
|
+
</PillarProvider>
|
|
59
|
+
|
|
60
|
+
function HelpButton() {
|
|
61
|
+
const { toggle } = useHelpPanel();
|
|
62
|
+
return <button onClick={toggle}>Get Help</button>;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
47
66
|
### Tooltip
|
|
48
67
|
|
|
49
68
|
Attach contextual tooltips to any element:
|
package/dist/PillarProvider.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* PillarProvider
|
|
3
3
|
* Context provider that initializes and manages the Pillar SDK
|
|
4
4
|
*/
|
|
5
|
-
import { Pillar, type PillarConfig, type PillarEvents, type PillarState, type TaskExecutePayload, type ThemeConfig } from
|
|
6
|
-
import React, { type
|
|
5
|
+
import { Pillar, type PillarConfig, type PillarEvents, type PillarState, type TaskExecutePayload, type ThemeConfig } from "@pillar-ai/sdk";
|
|
6
|
+
import React, { type ComponentType, type ReactNode } from "react";
|
|
7
7
|
/**
|
|
8
8
|
* Props passed to custom card components.
|
|
9
9
|
*/
|
|
@@ -15,7 +15,7 @@ export interface CardComponentProps<T = Record<string, unknown>> {
|
|
|
15
15
|
/** Called when user cancels the action */
|
|
16
16
|
onCancel: () => void;
|
|
17
17
|
/** Called to report state changes (loading, success, error) */
|
|
18
|
-
onStateChange?: (state:
|
|
18
|
+
onStateChange?: (state: "loading" | "success" | "error", message?: string) => void;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* A React component that can be used as a custom card renderer.
|
|
@@ -68,7 +68,7 @@ export interface PillarProviderProps {
|
|
|
68
68
|
* - `panel.useShadowDOM`: Whether to isolate styles in Shadow DOM (default: false).
|
|
69
69
|
* Set to false to let custom cards inherit your app's CSS (Tailwind, etc.)
|
|
70
70
|
*/
|
|
71
|
-
config?: Omit<PillarConfig,
|
|
71
|
+
config?: Omit<PillarConfig, "helpCenter" | "publicKey">;
|
|
72
72
|
/**
|
|
73
73
|
* Handler called when a task action is triggered from the chat.
|
|
74
74
|
* Use this to handle AI-suggested actions like opening modals, navigating, etc.
|
package/dist/index.d.ts
CHANGED
|
@@ -46,4 +46,4 @@ export { PillarProvider, usePillarContext, type PillarContextValue, type PillarP
|
|
|
46
46
|
export { PillarPanel, type PillarPanelProps } from './PillarPanel';
|
|
47
47
|
export { useHelpPanel, type UseHelpPanelResult } from './hooks/useHelpPanel';
|
|
48
48
|
export { usePillar, type UsePillarResult, type TypedUsePillarResult } from './hooks/usePillar';
|
|
49
|
-
export type {
|
|
49
|
+
export type { EdgeTriggerConfig, PanelConfig, PillarConfig, PillarEvents, PillarState, ResolvedConfig, ResolvedThemeConfig, TaskExecutePayload, TextSelectionConfig, ThemeColors, ThemeConfig, ThemeMode, CardCallbacks, CardRenderer, SidebarTabConfig, ActionDefinitions, SyncActionDefinitions, ActionDataType, ActionNames, } from '@pillar-ai/sdk';
|
package/dist/index.esm.js
CHANGED
|
@@ -12,7 +12,7 @@ const PillarContext = createContext(null);
|
|
|
12
12
|
// ============================================================================
|
|
13
13
|
function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children, }) {
|
|
14
14
|
const [pillar, setPillar] = useState(null);
|
|
15
|
-
const [state, setState] = useState(
|
|
15
|
+
const [state, setState] = useState("uninitialized");
|
|
16
16
|
const [isPanelOpen, setIsPanelOpen] = useState(false);
|
|
17
17
|
// Keep a ref to the latest onTask callback to avoid re-subscribing
|
|
18
18
|
const onTaskRef = useRef(onTask);
|
|
@@ -33,10 +33,10 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
33
33
|
setPillar(existingInstance);
|
|
34
34
|
setState(existingInstance.state);
|
|
35
35
|
// Re-subscribe to events
|
|
36
|
-
existingInstance.on(
|
|
36
|
+
existingInstance.on("panel:open", () => {
|
|
37
37
|
setIsPanelOpen(true);
|
|
38
38
|
});
|
|
39
|
-
existingInstance.on(
|
|
39
|
+
existingInstance.on("panel:close", () => {
|
|
40
40
|
setIsPanelOpen(false);
|
|
41
41
|
});
|
|
42
42
|
}
|
|
@@ -52,18 +52,18 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
52
52
|
setPillar(instance);
|
|
53
53
|
setState(instance.state);
|
|
54
54
|
// Listen for panel open/close
|
|
55
|
-
instance.on(
|
|
55
|
+
instance.on("panel:open", () => {
|
|
56
56
|
setIsPanelOpen(true);
|
|
57
57
|
});
|
|
58
|
-
instance.on(
|
|
58
|
+
instance.on("panel:close", () => {
|
|
59
59
|
setIsPanelOpen(false);
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
64
|
-
console.error(
|
|
64
|
+
console.error("[Pillar React] Failed to initialize:", error);
|
|
65
65
|
if (mounted) {
|
|
66
|
-
setState(
|
|
66
|
+
setState("error");
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
};
|
|
@@ -80,11 +80,11 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
80
80
|
// Update state when SDK state changes
|
|
81
81
|
useEffect(() => {
|
|
82
82
|
if (pillar) {
|
|
83
|
-
const unsubscribe = pillar.on(
|
|
84
|
-
setState(
|
|
83
|
+
const unsubscribe = pillar.on("ready", () => {
|
|
84
|
+
setState("ready");
|
|
85
85
|
});
|
|
86
|
-
const unsubscribeError = pillar.on(
|
|
87
|
-
setState(
|
|
86
|
+
const unsubscribeError = pillar.on("error", () => {
|
|
87
|
+
setState("error");
|
|
88
88
|
});
|
|
89
89
|
return () => {
|
|
90
90
|
unsubscribe();
|
|
@@ -95,7 +95,7 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
95
95
|
// Register task handler
|
|
96
96
|
useEffect(() => {
|
|
97
97
|
if (pillar) {
|
|
98
|
-
const unsubscribe = pillar.on(
|
|
98
|
+
const unsubscribe = pillar.on("task:execute", (task) => {
|
|
99
99
|
onTaskRef.current?.(task);
|
|
100
100
|
});
|
|
101
101
|
return unsubscribe;
|
|
@@ -128,9 +128,9 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
128
128
|
});
|
|
129
129
|
return () => {
|
|
130
130
|
// Cleanup all registrations
|
|
131
|
-
unsubscribers.forEach(unsub => unsub());
|
|
131
|
+
unsubscribers.forEach((unsub) => unsub());
|
|
132
132
|
// Unmount all React roots
|
|
133
|
-
roots.forEach(root => root.unmount());
|
|
133
|
+
roots.forEach((root) => root.unmount());
|
|
134
134
|
roots.clear();
|
|
135
135
|
};
|
|
136
136
|
}, [pillar, cards]);
|
|
@@ -148,7 +148,7 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
148
148
|
pillar?.open({ article: slug });
|
|
149
149
|
}, [pillar]);
|
|
150
150
|
const openCategory = useCallback(async (slug) => {
|
|
151
|
-
pillar?.navigate(
|
|
151
|
+
pillar?.navigate("category", { slug });
|
|
152
152
|
}, [pillar]);
|
|
153
153
|
const search = useCallback((query) => {
|
|
154
154
|
pillar?.open({ search: query });
|
|
@@ -169,7 +169,7 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
169
169
|
const value = useMemo(() => ({
|
|
170
170
|
pillar,
|
|
171
171
|
state,
|
|
172
|
-
isReady: state ===
|
|
172
|
+
isReady: state === "ready",
|
|
173
173
|
isPanelOpen,
|
|
174
174
|
open,
|
|
175
175
|
close,
|
|
@@ -181,7 +181,21 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
181
181
|
setTheme,
|
|
182
182
|
setTextSelectionEnabled,
|
|
183
183
|
on,
|
|
184
|
-
}), [
|
|
184
|
+
}), [
|
|
185
|
+
pillar,
|
|
186
|
+
state,
|
|
187
|
+
isPanelOpen,
|
|
188
|
+
open,
|
|
189
|
+
close,
|
|
190
|
+
toggle,
|
|
191
|
+
openArticle,
|
|
192
|
+
openCategory,
|
|
193
|
+
search,
|
|
194
|
+
navigate,
|
|
195
|
+
setTheme,
|
|
196
|
+
setTextSelectionEnabled,
|
|
197
|
+
on,
|
|
198
|
+
]);
|
|
185
199
|
return (jsx(PillarContext.Provider, { value: value, children: children }));
|
|
186
200
|
}
|
|
187
201
|
// ============================================================================
|
|
@@ -190,7 +204,7 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
190
204
|
function usePillarContext() {
|
|
191
205
|
const context = useContext(PillarContext);
|
|
192
206
|
if (!context) {
|
|
193
|
-
throw new Error(
|
|
207
|
+
throw new Error("usePillarContext must be used within a PillarProvider");
|
|
194
208
|
}
|
|
195
209
|
return context;
|
|
196
210
|
}
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/PillarProvider.tsx","../src/PillarPanel.tsx","../src/hooks/useHelpPanel.ts","../src/hooks/usePillar.ts"],"sourcesContent":["/**\n * PillarProvider\n * Context provider that initializes and manages the Pillar SDK\n */\n\nimport {\n Pillar,\n type PillarConfig,\n type PillarEvents,\n type PillarState,\n type TaskExecutePayload,\n type ThemeConfig,\n type CardCallbacks,\n} from '@pillar-ai/sdk';\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n type ComponentType,\n} from 'react';\nimport { createRoot, type Root } from 'react-dom/client';\n\n// ============================================================================\n// Card Types\n// ============================================================================\n\n/**\n * Props passed to custom card components.\n */\nexport interface CardComponentProps<T = Record<string, unknown>> {\n /** Data extracted by the AI for this action */\n data: T;\n /** Called when user confirms the action */\n onConfirm: (modifiedData?: Record<string, unknown>) => void;\n /** Called when user cancels the action */\n onCancel: () => void;\n /** Called to report state changes (loading, success, error) */\n onStateChange?: (state: 'loading' | 'success' | 'error', message?: string) => void;\n}\n\n/**\n * A React component that can be used as a custom card renderer.\n */\nexport type CardComponent<T = Record<string, unknown>> = ComponentType<CardComponentProps<T>>;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PillarContextValue {\n /** The Pillar SDK instance */\n pillar: Pillar | null;\n \n /** Current SDK state */\n state: PillarState;\n \n /** Whether the SDK is ready */\n isReady: boolean;\n \n /** Whether the panel is currently open */\n isPanelOpen: boolean;\n \n /** Open the help panel */\n open: (options?: { view?: string; article?: string; search?: string; focusInput?: boolean }) => void;\n \n /** Close the help panel */\n close: () => void;\n \n /** Toggle the help panel */\n toggle: () => void;\n \n /** Open a specific article */\n openArticle: (slug: string) => void;\n \n /** Open a specific category */\n openCategory: (slug: string) => Promise<void>;\n \n /** Perform a search */\n search: (query: string) => void;\n \n /** Navigate to a specific view */\n navigate: (view: string, params?: Record<string, string>) => void;\n \n /** Update the panel theme at runtime */\n setTheme: (theme: Partial<ThemeConfig>) => void;\n \n /** Enable or disable the text selection \"Ask AI\" popover */\n setTextSelectionEnabled: (enabled: boolean) => void;\n \n /** Subscribe to SDK events */\n on: <K extends keyof PillarEvents>(\n event: K,\n callback: (data: PillarEvents[K]) => void\n ) => () => void;\n}\n\nexport interface PillarProviderProps {\n /** Help center subdomain or identifier */\n helpCenter: string;\n \n /** Public API key */\n publicKey: string;\n \n /** \n * Additional SDK configuration\n * \n * Notable options:\n * - `panel.useShadowDOM`: Whether to isolate styles in Shadow DOM (default: false).\n * Set to false to let custom cards inherit your app's CSS (Tailwind, etc.)\n */\n config?: Omit<PillarConfig, 'helpCenter' | 'publicKey'>;\n \n /**\n * Handler called when a task action is triggered from the chat.\n * Use this to handle AI-suggested actions like opening modals, navigating, etc.\n * \n * @example\n * ```tsx\n * <PillarProvider\n * helpCenter=\"my-app\"\n * publicKey=\"pk_...\"\n * onTask={(task) => {\n * switch (task.name) {\n * case 'invite_team_member':\n * openInviteModal(task.data);\n * break;\n * case 'open_settings':\n * router.push('/settings');\n * break;\n * }\n * }}\n * >\n * ```\n */\n onTask?: (task: TaskExecutePayload) => void;\n \n /**\n * Custom card components to render for inline_ui type actions.\n * Map card type names to React components that will render the inline UI.\n * \n * @example\n * ```tsx\n * import { InviteMembersCard } from './cards/InviteMembersCard';\n * \n * <PillarProvider\n * helpCenter=\"my-app\"\n * publicKey=\"pk_...\"\n * cards={{\n * invite_members: InviteMembersCard,\n * confirm_delete: ConfirmDeleteCard,\n * }}\n * >\n * ```\n */\n cards?: Record<string, CardComponent>;\n \n /** Children components */\n children: ReactNode;\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst PillarContext = createContext<PillarContextValue | null>(null);\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\nexport function PillarProvider({\n helpCenter,\n publicKey,\n config,\n onTask,\n cards,\n children,\n}: PillarProviderProps): React.ReactElement {\n const [pillar, setPillar] = useState<Pillar | null>(null);\n const [state, setState] = useState<PillarState>('uninitialized');\n const [isPanelOpen, setIsPanelOpen] = useState(false);\n \n // Keep a ref to the latest onTask callback to avoid re-subscribing\n const onTaskRef = useRef(onTask);\n onTaskRef.current = onTask;\n \n // Keep a ref to cards to access latest versions\n const cardsRef = useRef(cards);\n cardsRef.current = cards;\n\n // Initialize SDK\n useEffect(() => {\n let mounted = true;\n\n const initPillar = async () => {\n try {\n // Pillar is a singleton - check if already initialized\n const existingInstance = Pillar.getInstance();\n if (existingInstance) {\n // Reuse existing instance (preserves chat history, panel state, etc.)\n if (mounted) {\n setPillar(existingInstance);\n setState(existingInstance.state);\n \n // Re-subscribe to events\n existingInstance.on('panel:open', () => {\n setIsPanelOpen(true);\n });\n \n existingInstance.on('panel:close', () => {\n setIsPanelOpen(false);\n });\n }\n return;\n }\n \n // Initialize new instance\n const instance = await Pillar.init({\n helpCenter,\n publicKey,\n ...config,\n });\n\n if (mounted) {\n setPillar(instance);\n setState(instance.state);\n\n // Listen for panel open/close\n instance.on('panel:open', () => {\n setIsPanelOpen(true);\n });\n \n instance.on('panel:close', () => {\n setIsPanelOpen(false);\n });\n }\n } catch (error) {\n console.error('[Pillar React] Failed to initialize:', error);\n if (mounted) {\n setState('error');\n }\n }\n };\n\n initPillar();\n\n // Cleanup - DON'T destroy the singleton on unmount\n // This preserves conversation history and panel state across navigation\n // Pillar.destroy() should only be called explicitly when the app unmounts completely\n return () => {\n mounted = false;\n // Note: We intentionally don't call Pillar.destroy() here\n // The singleton persists to maintain state across route changes\n };\n }, [helpCenter, publicKey]); // Re-initialize if credentials change\n\n // Update state when SDK state changes\n useEffect(() => {\n if (pillar) {\n const unsubscribe = pillar.on('ready', () => {\n setState('ready');\n });\n \n const unsubscribeError = pillar.on('error', () => {\n setState('error');\n });\n\n return () => {\n unsubscribe();\n unsubscribeError();\n };\n }\n }, [pillar]);\n\n // Register task handler\n useEffect(() => {\n if (pillar) {\n const unsubscribe = pillar.on('task:execute', (task) => {\n onTaskRef.current?.(task);\n });\n\n return unsubscribe;\n }\n }, [pillar]);\n\n // Register custom card renderers\n useEffect(() => {\n if (!pillar || !cards) return;\n \n const unsubscribers: Array<() => void> = [];\n const roots: Map<HTMLElement, Root> = new Map();\n \n // Register each card component as a vanilla renderer\n Object.entries(cards).forEach(([cardType, Component]) => {\n const unsubscribe = pillar.registerCard(cardType, (container, data, callbacks: CardCallbacks) => {\n // Create a React root for this container\n const root = createRoot(container);\n roots.set(container, root);\n \n // Render the React component\n root.render(\n <Component\n data={data}\n onConfirm={callbacks.onConfirm}\n onCancel={callbacks.onCancel}\n onStateChange={callbacks.onStateChange}\n />\n );\n \n // Return cleanup function\n return () => {\n const existingRoot = roots.get(container);\n if (existingRoot) {\n existingRoot.unmount();\n roots.delete(container);\n }\n };\n });\n \n unsubscribers.push(unsubscribe);\n });\n \n return () => {\n // Cleanup all registrations\n unsubscribers.forEach(unsub => unsub());\n // Unmount all React roots\n roots.forEach(root => root.unmount());\n roots.clear();\n };\n }, [pillar, cards]);\n\n // Actions\n const open = useCallback(\n (options?: { view?: string; article?: string; search?: string; focusInput?: boolean }) => {\n pillar?.open(options);\n },\n [pillar]\n );\n\n const close = useCallback(() => {\n pillar?.close();\n }, [pillar]);\n\n const toggle = useCallback(() => {\n pillar?.toggle();\n }, [pillar]);\n\n const openArticle = useCallback(\n (slug: string) => {\n pillar?.open({ article: slug });\n },\n [pillar]\n );\n\n const openCategory = useCallback(\n async (slug: string) => {\n pillar?.navigate('category', { slug });\n },\n [pillar]\n );\n\n const search = useCallback(\n (query: string) => {\n pillar?.open({ search: query });\n },\n [pillar]\n );\n\n const navigate = useCallback(\n (view: string, params?: Record<string, string>) => {\n pillar?.navigate(view, params);\n },\n [pillar]\n );\n\n const setTheme = useCallback(\n (theme: Partial<ThemeConfig>) => {\n pillar?.setTheme(theme);\n },\n [pillar]\n );\n\n const setTextSelectionEnabled = useCallback(\n (enabled: boolean) => {\n pillar?.setTextSelectionEnabled(enabled);\n },\n [pillar]\n );\n\n const on = useCallback(\n <K extends keyof PillarEvents>(\n event: K,\n callback: (data: PillarEvents[K]) => void\n ) => {\n return pillar?.on(event, callback) ?? (() => {});\n },\n [pillar]\n );\n\n // Context value\n const value = useMemo<PillarContextValue>(\n () => ({\n pillar,\n state,\n isReady: state === 'ready',\n isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n search,\n navigate,\n setTheme,\n setTextSelectionEnabled,\n on,\n }),\n [pillar, state, isPanelOpen, open, close, toggle, openArticle, openCategory, search, navigate, setTheme, setTextSelectionEnabled, on]\n );\n\n return (\n <PillarContext.Provider value={value}>\n {children}\n </PillarContext.Provider>\n );\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function usePillarContext(): PillarContextValue {\n const context = useContext(PillarContext);\n \n if (!context) {\n throw new Error('usePillarContext must be used within a PillarProvider');\n }\n \n return context;\n}\n\n","/**\n * PillarPanel Component\n * Renders the Pillar help panel at a custom location in the DOM\n */\n\nimport React, { useRef, useEffect, type CSSProperties, type HTMLAttributes } from 'react';\nimport { usePillarContext } from './PillarProvider';\n\nexport interface PillarPanelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name for the container */\n className?: string;\n \n /** Custom inline styles for the container */\n style?: CSSProperties;\n}\n\n/**\n * Renders the Pillar help panel at a custom location in the DOM.\n * Use this when you want to control where the panel is rendered instead of\n * having it automatically appended to document.body.\n * \n * **Important**: When using this component, set `panel.container: 'manual'` in your\n * PillarProvider config to prevent automatic mounting.\n * \n * @example\n * ```tsx\n * <PillarProvider \n * helpCenter=\"my-help\" \n * publicKey=\"pk_xxx\"\n * config={{ panel: { container: 'manual' } }}\n * >\n * <div className=\"my-layout\">\n * <Sidebar />\n * <PillarPanel className=\"help-panel-container\" />\n * <MainContent />\n * </div>\n * </PillarProvider>\n * ```\n */\nexport function PillarPanel({ \n className, \n style,\n ...props \n}: PillarPanelProps): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null);\n const { pillar, isReady } = usePillarContext();\n const hasMounted = useRef(false);\n\n useEffect(() => {\n // Only mount once when SDK is ready and we have a container\n if (!isReady || !pillar || !containerRef.current || hasMounted.current) {\n return;\n }\n\n // Mount the panel into our container\n pillar.mountPanelTo(containerRef.current);\n hasMounted.current = true;\n\n // Cleanup is handled by Pillar.destroy() in the provider\n }, [isReady, pillar]);\n\n return (\n <div \n ref={containerRef} \n className={className}\n style={style}\n data-pillar-panel-container=\"\"\n {...props}\n />\n );\n}\n\n","/**\n * useHelpPanel Hook\n * Panel-specific controls and state\n */\n\nimport { useCallback } from 'react';\nimport { usePillarContext } from '../PillarProvider';\n\nexport interface UseHelpPanelResult {\n /** Whether the panel is currently open */\n isOpen: boolean;\n \n /** Open the panel */\n open: (options?: { view?: string; article?: string; search?: string }) => void;\n \n /** Close the panel */\n close: () => void;\n \n /** Toggle the panel */\n toggle: () => void;\n \n /** Open a specific article in the panel */\n openArticle: (slug: string) => void;\n \n /** Open a specific category in the panel */\n openCategory: (slug: string) => Promise<void>;\n \n /** Open search with a query */\n openSearch: (query?: string) => void;\n \n /** Open the AI chat */\n openChat: () => void;\n}\n\n/**\n * Hook for panel-specific controls\n * \n * @example\n * ```tsx\n * function HelpButton() {\n * const { isOpen, toggle, openChat } = useHelpPanel();\n * \n * return (\n * <div>\n * <button onClick={toggle}>\n * {isOpen ? 'Close' : 'Help'}\n * </button>\n * <button onClick={openChat}>\n * Ask AI\n * </button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useHelpPanel(): UseHelpPanelResult {\n const { isPanelOpen, open, close, toggle, openArticle, openCategory, search, navigate } = usePillarContext();\n\n const openSearch = useCallback(\n (query?: string) => {\n if (query) {\n search(query);\n } else {\n open({ view: 'search' });\n }\n },\n [search, open]\n );\n\n const openChat = useCallback(() => {\n navigate('chat');\n }, [navigate]);\n\n return {\n isOpen: isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n openSearch,\n openChat,\n };\n}\n\n","/**\n * usePillar Hook\n * Access Pillar SDK instance and state with optional type-safe onTask\n */\n\nimport type {\n SyncActionDefinitions,\n ActionDefinitions,\n ActionDataType,\n ActionNames,\n} from '@pillar-ai/sdk';\nimport { useCallback } from 'react';\nimport { usePillarContext, type PillarContextValue } from '../PillarProvider';\n\nexport type UsePillarResult = PillarContextValue;\n\n/**\n * Extended result with type-safe onTask method.\n *\n * @template TActions - The action definitions for type inference\n */\nexport interface TypedUsePillarResult<\n TActions extends SyncActionDefinitions | ActionDefinitions,\n> extends Omit<PillarContextValue, 'pillar'> {\n pillar: PillarContextValue['pillar'];\n /**\n * Type-safe task handler registration.\n *\n * @param taskName - The action name (autocompleted from your actions)\n * @param handler - Handler function with typed data parameter\n * @returns Unsubscribe function\n */\n onTask: <TName extends ActionNames<TActions>>(\n taskName: TName,\n handler: (data: ActionDataType<TActions, TName>) => void\n ) => () => void;\n}\n\n/**\n * Hook to access the Pillar SDK instance and state\n *\n * @example Basic usage (untyped)\n * ```tsx\n * function MyComponent() {\n * const { isReady, open, close, isPanelOpen } = usePillar();\n *\n * if (!isReady) return <div>Loading...</div>;\n *\n * return (\n * <button onClick={() => open()}>\n * {isPanelOpen ? 'Close Help' : 'Get Help'}\n * </button>\n * );\n * }\n * ```\n *\n * @example Type-safe onTask with action definitions\n * ```tsx\n * import { actions } from '@/lib/pillar/actions';\n *\n * function MyComponent() {\n * const { pillar, onTask } = usePillar<typeof actions>();\n *\n * useEffect(() => {\n * // TypeScript knows data has { type, url, name }\n * const unsub = onTask('add_new_source', (data) => {\n * console.log(data.url); // ✓ Typed!\n * });\n * return unsub;\n * }, [onTask]);\n * }\n * ```\n */\nexport function usePillar<\n TActions extends SyncActionDefinitions | ActionDefinitions = SyncActionDefinitions,\n>(): TypedUsePillarResult<TActions> {\n const context = usePillarContext();\n\n // Create a type-safe wrapper around pillar.onTask\n const onTask = useCallback(\n <TName extends ActionNames<TActions>>(\n taskName: TName,\n handler: (data: ActionDataType<TActions, TName>) => void\n ): (() => void) => {\n if (!context.pillar) {\n // Return no-op if pillar not ready\n return () => {};\n }\n // Cast handler to match the SDK's expected type\n // The runtime behavior is the same, this is just for type narrowing\n return context.pillar.onTask(\n taskName as string,\n handler as (data: Record<string, unknown>) => void\n );\n },\n [context.pillar]\n );\n\n return {\n ...context,\n onTask,\n };\n}\n\n"],"names":["_jsx"],"mappings":";;;;;AAqKA;AACA;AACA;AAEA,MAAM,aAAa,GAAG,aAAa,CAA4B,IAAI,CAAC;AAEpE;AACA;AACA;AAEM,SAAU,cAAc,CAAC,EAC7B,UAAU,EACV,SAAS,EACT,MAAM,EACN,MAAM,EACN,KAAK,EACL,QAAQ,GACY,EAAA;IACpB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC;IACzD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAc,eAAe,CAAC;IAChE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;;AAGrD,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;AAChC,IAAA,SAAS,CAAC,OAAO,GAAG,MAAM;;AAG1B,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;AAC9B,IAAA,QAAQ,CAAC,OAAO,GAAG,KAAK;;IAGxB,SAAS,CAAC,MAAK;QACb,IAAI,OAAO,GAAG,IAAI;AAElB,QAAA,MAAM,UAAU,GAAG,YAAW;AAC5B,YAAA,IAAI;;AAEF,gBAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,EAAE;gBAC7C,IAAI,gBAAgB,EAAE;;oBAEpB,IAAI,OAAO,EAAE;wBACX,SAAS,CAAC,gBAAgB,CAAC;AAC3B,wBAAA,QAAQ,CAAC,gBAAgB,CAAC,KAAK,CAAC;;AAGhC,wBAAA,gBAAgB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAK;4BACrC,cAAc,CAAC,IAAI,CAAC;AACtB,wBAAA,CAAC,CAAC;AAEF,wBAAA,gBAAgB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAK;4BACtC,cAAc,CAAC,KAAK,CAAC;AACvB,wBAAA,CAAC,CAAC;oBACJ;oBACA;gBACF;;AAGA,gBAAA,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;oBACjC,UAAU;oBACV,SAAS;AACT,oBAAA,GAAG,MAAM;AACV,iBAAA,CAAC;gBAEF,IAAI,OAAO,EAAE;oBACX,SAAS,CAAC,QAAQ,CAAC;AACnB,oBAAA,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;;AAGxB,oBAAA,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAK;wBAC7B,cAAc,CAAC,IAAI,CAAC;AACtB,oBAAA,CAAC,CAAC;AAEF,oBAAA,QAAQ,CAAC,EAAE,CAAC,aAAa,EAAE,MAAK;wBAC9B,cAAc,CAAC,KAAK,CAAC;AACvB,oBAAA,CAAC,CAAC;gBACJ;YACF;YAAE,OAAO,KAAK,EAAE;AACd,gBAAA,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC;gBAC5D,IAAI,OAAO,EAAE;oBACX,QAAQ,CAAC,OAAO,CAAC;gBACnB;YACF;AACF,QAAA,CAAC;AAED,QAAA,UAAU,EAAE;;;;AAKZ,QAAA,OAAO,MAAK;YACV,OAAO,GAAG,KAAK;;;AAGjB,QAAA,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;;IAG5B,SAAS,CAAC,MAAK;QACb,IAAI,MAAM,EAAE;YACV,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAK;gBAC1C,QAAQ,CAAC,OAAO,CAAC;AACnB,YAAA,CAAC,CAAC;YAEF,MAAM,gBAAgB,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAK;gBAC/C,QAAQ,CAAC,OAAO,CAAC;AACnB,YAAA,CAAC,CAAC;AAEF,YAAA,OAAO,MAAK;AACV,gBAAA,WAAW,EAAE;AACb,gBAAA,gBAAgB,EAAE;AACpB,YAAA,CAAC;QACH;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;;IAGZ,SAAS,CAAC,MAAK;QACb,IAAI,MAAM,EAAE;YACV,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,IAAI,KAAI;AACrD,gBAAA,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;AAC3B,YAAA,CAAC,CAAC;AAEF,YAAA,OAAO,WAAW;QACpB;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;;IAGZ,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK;YAAE;QAEvB,MAAM,aAAa,GAAsB,EAAE;AAC3C,QAAA,MAAM,KAAK,GAA2B,IAAI,GAAG,EAAE;;AAG/C,QAAA,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAI;AACtD,YAAA,MAAM,WAAW,GAAG,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,SAAwB,KAAI;;AAE9F,gBAAA,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC;AAClC,gBAAA,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC;;AAG1B,gBAAA,IAAI,CAAC,MAAM,CACTA,GAAA,CAAC,SAAS,EAAA,EACR,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,CAAC,SAAS,EAC9B,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAC5B,aAAa,EAAE,SAAS,CAAC,aAAa,EAAA,CACtC,CACH;;AAGD,gBAAA,OAAO,MAAK;oBACV,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;oBACzC,IAAI,YAAY,EAAE;wBAChB,YAAY,CAAC,OAAO,EAAE;AACtB,wBAAA,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;oBACzB;AACF,gBAAA,CAAC;AACH,YAAA,CAAC,CAAC;AAEF,YAAA,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC;AACjC,QAAA,CAAC,CAAC;AAEF,QAAA,OAAO,MAAK;;YAEV,aAAa,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC;;AAEvC,YAAA,KAAK,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACrC,KAAK,CAAC,KAAK,EAAE;AACf,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;;AAGnB,IAAA,MAAM,IAAI,GAAG,WAAW,CACtB,CAAC,OAAoF,KAAI;AACvF,QAAA,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC;AACvB,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;AAED,IAAA,MAAM,KAAK,GAAG,WAAW,CAAC,MAAK;QAC7B,MAAM,EAAE,KAAK,EAAE;AACjB,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;AAEZ,IAAA,MAAM,MAAM,GAAG,WAAW,CAAC,MAAK;QAC9B,MAAM,EAAE,MAAM,EAAE;AAClB,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;AAEZ,IAAA,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,IAAY,KAAI;QACf,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACjC,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;IAED,MAAM,YAAY,GAAG,WAAW,CAC9B,OAAO,IAAY,KAAI;QACrB,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC;AACxC,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;AAED,IAAA,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,KAAa,KAAI;QAChB,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACjC,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;IAED,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,IAAY,EAAE,MAA+B,KAAI;AAChD,QAAA,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;AAChC,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;AAED,IAAA,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,KAA2B,KAAI;AAC9B,QAAA,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC;AACzB,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;AAED,IAAA,MAAM,uBAAuB,GAAG,WAAW,CACzC,CAAC,OAAgB,KAAI;AACnB,QAAA,MAAM,EAAE,uBAAuB,CAAC,OAAO,CAAC;AAC1C,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;IAED,MAAM,EAAE,GAAG,WAAW,CACpB,CACE,KAAQ,EACR,QAAyC,KACvC;AACF,QAAA,OAAO,MAAM,EAAE,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,MAAK,EAAE,CAAC,CAAC;AAClD,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;;AAGD,IAAA,MAAM,KAAK,GAAG,OAAO,CACnB,OAAO;QACL,MAAM;QACN,KAAK;QACL,OAAO,EAAE,KAAK,KAAK,OAAO;QAC1B,WAAW;QACX,IAAI;QACJ,KAAK;QACL,MAAM;QACN,WAAW;QACX,YAAY;QACZ,MAAM;QACN,QAAQ;QACR,QAAQ;QACR,uBAAuB;QACvB,EAAE;AACH,KAAA,CAAC,EACF,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,uBAAuB,EAAE,EAAE,CAAC,CACtI;AAED,IAAA,QACEA,GAAA,CAAC,aAAa,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,KAAK,EAAA,QAAA,EACjC,QAAQ,EAAA,CACc;AAE7B;AAEA;AACA;AACA;SAEgB,gBAAgB,GAAA;AAC9B,IAAA,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC;IAEzC,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC;IAC1E;AAEA,IAAA,OAAO,OAAO;AAChB;;AC5aA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACG,SAAU,WAAW,CAAC,EAC1B,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACS,EAAA;AACjB,IAAA,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC;IACjD,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,EAAE;AAC9C,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC;IAEhC,SAAS,CAAC,MAAK;;AAEb,QAAA,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,UAAU,CAAC,OAAO,EAAE;YACtE;QACF;;AAGA,QAAA,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,OAAO,CAAC;AACzC,QAAA,UAAU,CAAC,OAAO,GAAG,IAAI;;AAG3B,IAAA,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAErB,IAAA,QACEA,GAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EAAA,6BAAA,EACgB,EAAE,KAC1B,KAAK,EAAA,CACT;AAEN;;ACtEA;;;AAGG;AA+BH;;;;;;;;;;;;;;;;;;;;AAoBG;SACa,YAAY,GAAA;IAC1B,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,gBAAgB,EAAE;AAE5G,IAAA,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,KAAc,KAAI;QACjB,IAAI,KAAK,EAAE;YACT,MAAM,CAAC,KAAK,CAAC;QACf;aAAO;AACL,YAAA,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC1B;AACF,IAAA,CAAC,EACD,CAAC,MAAM,EAAE,IAAI,CAAC,CACf;AAED,IAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAK;QAChC,QAAQ,CAAC,MAAM,CAAC;AAClB,IAAA,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAEd,OAAO;AACL,QAAA,MAAM,EAAE,WAAW;QACnB,IAAI;QACJ,KAAK;QACL,MAAM;QACN,WAAW;QACX,YAAY;QACZ,UAAU;QACV,QAAQ;KACT;AACH;;ACnFA;;;AAGG;AAmCH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;SACa,SAAS,GAAA;AAGvB,IAAA,MAAM,OAAO,GAAG,gBAAgB,EAAE;;IAGlC,MAAM,MAAM,GAAG,WAAW,CACxB,CACE,QAAe,EACf,OAAwD,KACxC;AAChB,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;;AAEnB,YAAA,OAAO,MAAK,EAAE,CAAC;QACjB;;;QAGA,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,CAC1B,QAAkB,EAClB,OAAkD,CACnD;AACH,IAAA,CAAC,EACD,CAAC,OAAO,CAAC,MAAM,CAAC,CACjB;IAED,OAAO;AACL,QAAA,GAAG,OAAO;QACV,MAAM;KACP;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/PillarProvider.tsx","../src/PillarPanel.tsx","../src/hooks/useHelpPanel.ts","../src/hooks/usePillar.ts"],"sourcesContent":["/**\n * PillarProvider\n * Context provider that initializes and manages the Pillar SDK\n */\n\nimport {\n Pillar,\n type CardCallbacks,\n type PillarConfig,\n type PillarEvents,\n type PillarState,\n type TaskExecutePayload,\n type ThemeConfig,\n} from \"@pillar-ai/sdk\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\n\n// ============================================================================\n// Card Types\n// ============================================================================\n\n/**\n * Props passed to custom card components.\n */\nexport interface CardComponentProps<T = Record<string, unknown>> {\n /** Data extracted by the AI for this action */\n data: T;\n /** Called when user confirms the action */\n onConfirm: (modifiedData?: Record<string, unknown>) => void;\n /** Called when user cancels the action */\n onCancel: () => void;\n /** Called to report state changes (loading, success, error) */\n onStateChange?: (\n state: \"loading\" | \"success\" | \"error\",\n message?: string\n ) => void;\n}\n\n/**\n * A React component that can be used as a custom card renderer.\n */\nexport type CardComponent<T = Record<string, unknown>> = ComponentType<\n CardComponentProps<T>\n>;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PillarContextValue {\n /** The Pillar SDK instance */\n pillar: Pillar | null;\n\n /** Current SDK state */\n state: PillarState;\n\n /** Whether the SDK is ready */\n isReady: boolean;\n\n /** Whether the panel is currently open */\n isPanelOpen: boolean;\n\n /** Open the help panel */\n open: (options?: {\n view?: string;\n article?: string;\n search?: string;\n focusInput?: boolean;\n }) => void;\n\n /** Close the help panel */\n close: () => void;\n\n /** Toggle the help panel */\n toggle: () => void;\n\n /** Open a specific article */\n openArticle: (slug: string) => void;\n\n /** Open a specific category */\n openCategory: (slug: string) => Promise<void>;\n\n /** Perform a search */\n search: (query: string) => void;\n\n /** Navigate to a specific view */\n navigate: (view: string, params?: Record<string, string>) => void;\n\n /** Update the panel theme at runtime */\n setTheme: (theme: Partial<ThemeConfig>) => void;\n\n /** Enable or disable the text selection \"Ask AI\" popover */\n setTextSelectionEnabled: (enabled: boolean) => void;\n\n /** Subscribe to SDK events */\n on: <K extends keyof PillarEvents>(\n event: K,\n callback: (data: PillarEvents[K]) => void\n ) => () => void;\n}\n\nexport interface PillarProviderProps {\n /** Help center subdomain or identifier */\n helpCenter: string;\n\n /** Public API key */\n publicKey: string;\n\n /**\n * Additional SDK configuration\n *\n * Notable options:\n * - `panel.useShadowDOM`: Whether to isolate styles in Shadow DOM (default: false).\n * Set to false to let custom cards inherit your app's CSS (Tailwind, etc.)\n */\n config?: Omit<PillarConfig, \"helpCenter\" | \"publicKey\">;\n\n /**\n * Handler called when a task action is triggered from the chat.\n * Use this to handle AI-suggested actions like opening modals, navigating, etc.\n *\n * @example\n * ```tsx\n * <PillarProvider\n * helpCenter=\"my-app\"\n * publicKey=\"pk_...\"\n * onTask={(task) => {\n * switch (task.name) {\n * case 'invite_team_member':\n * openInviteModal(task.data);\n * break;\n * case 'open_settings':\n * router.push('/settings');\n * break;\n * }\n * }}\n * >\n * ```\n */\n onTask?: (task: TaskExecutePayload) => void;\n\n /**\n * Custom card components to render for inline_ui type actions.\n * Map card type names to React components that will render the inline UI.\n *\n * @example\n * ```tsx\n * import { InviteMembersCard } from './cards/InviteMembersCard';\n *\n * <PillarProvider\n * helpCenter=\"my-app\"\n * publicKey=\"pk_...\"\n * cards={{\n * invite_members: InviteMembersCard,\n * confirm_delete: ConfirmDeleteCard,\n * }}\n * >\n * ```\n */\n cards?: Record<string, CardComponent>;\n\n /** Children components */\n children: ReactNode;\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst PillarContext = createContext<PillarContextValue | null>(null);\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\nexport function PillarProvider({\n helpCenter,\n publicKey,\n config,\n onTask,\n cards,\n children,\n}: PillarProviderProps): React.ReactElement {\n const [pillar, setPillar] = useState<Pillar | null>(null);\n const [state, setState] = useState<PillarState>(\"uninitialized\");\n const [isPanelOpen, setIsPanelOpen] = useState(false);\n\n // Keep a ref to the latest onTask callback to avoid re-subscribing\n const onTaskRef = useRef(onTask);\n onTaskRef.current = onTask;\n\n // Keep a ref to cards to access latest versions\n const cardsRef = useRef(cards);\n cardsRef.current = cards;\n\n // Initialize SDK\n useEffect(() => {\n let mounted = true;\n\n const initPillar = async () => {\n try {\n // Pillar is a singleton - check if already initialized\n const existingInstance = Pillar.getInstance();\n if (existingInstance) {\n // Reuse existing instance (preserves chat history, panel state, etc.)\n if (mounted) {\n setPillar(existingInstance);\n setState(existingInstance.state);\n\n // Re-subscribe to events\n existingInstance.on(\"panel:open\", () => {\n setIsPanelOpen(true);\n });\n\n existingInstance.on(\"panel:close\", () => {\n setIsPanelOpen(false);\n });\n }\n return;\n }\n\n // Initialize new instance\n const instance = await Pillar.init({\n helpCenter,\n publicKey,\n ...config,\n });\n\n if (mounted) {\n setPillar(instance);\n setState(instance.state);\n\n // Listen for panel open/close\n instance.on(\"panel:open\", () => {\n setIsPanelOpen(true);\n });\n\n instance.on(\"panel:close\", () => {\n setIsPanelOpen(false);\n });\n }\n } catch (error) {\n console.error(\"[Pillar React] Failed to initialize:\", error);\n if (mounted) {\n setState(\"error\");\n }\n }\n };\n\n initPillar();\n\n // Cleanup - DON'T destroy the singleton on unmount\n // This preserves conversation history and panel state across navigation\n // Pillar.destroy() should only be called explicitly when the app unmounts completely\n return () => {\n mounted = false;\n // Note: We intentionally don't call Pillar.destroy() here\n // The singleton persists to maintain state across route changes\n };\n }, [helpCenter, publicKey]); // Re-initialize if credentials change\n\n // Update state when SDK state changes\n useEffect(() => {\n if (pillar) {\n const unsubscribe = pillar.on(\"ready\", () => {\n setState(\"ready\");\n });\n\n const unsubscribeError = pillar.on(\"error\", () => {\n setState(\"error\");\n });\n\n return () => {\n unsubscribe();\n unsubscribeError();\n };\n }\n }, [pillar]);\n\n // Register task handler\n useEffect(() => {\n if (pillar) {\n const unsubscribe = pillar.on(\"task:execute\", (task) => {\n onTaskRef.current?.(task);\n });\n\n return unsubscribe;\n }\n }, [pillar]);\n\n // Register custom card renderers\n useEffect(() => {\n if (!pillar || !cards) return;\n\n const unsubscribers: Array<() => void> = [];\n const roots: Map<HTMLElement, Root> = new Map();\n\n // Register each card component as a vanilla renderer\n Object.entries(cards).forEach(([cardType, Component]) => {\n const unsubscribe = pillar.registerCard(\n cardType,\n (container, data, callbacks: CardCallbacks) => {\n // Create a React root for this container\n const root = createRoot(container);\n roots.set(container, root);\n\n // Render the React component\n root.render(\n <Component\n data={data}\n onConfirm={callbacks.onConfirm}\n onCancel={callbacks.onCancel}\n onStateChange={callbacks.onStateChange}\n />\n );\n\n // Return cleanup function\n return () => {\n const existingRoot = roots.get(container);\n if (existingRoot) {\n existingRoot.unmount();\n roots.delete(container);\n }\n };\n }\n );\n\n unsubscribers.push(unsubscribe);\n });\n\n return () => {\n // Cleanup all registrations\n unsubscribers.forEach((unsub) => unsub());\n // Unmount all React roots\n roots.forEach((root) => root.unmount());\n roots.clear();\n };\n }, [pillar, cards]);\n\n // Actions\n const open = useCallback(\n (options?: {\n view?: string;\n article?: string;\n search?: string;\n focusInput?: boolean;\n }) => {\n pillar?.open(options);\n },\n [pillar]\n );\n\n const close = useCallback(() => {\n pillar?.close();\n }, [pillar]);\n\n const toggle = useCallback(() => {\n pillar?.toggle();\n }, [pillar]);\n\n const openArticle = useCallback(\n (slug: string) => {\n pillar?.open({ article: slug });\n },\n [pillar]\n );\n\n const openCategory = useCallback(\n async (slug: string) => {\n pillar?.navigate(\"category\", { slug });\n },\n [pillar]\n );\n\n const search = useCallback(\n (query: string) => {\n pillar?.open({ search: query });\n },\n [pillar]\n );\n\n const navigate = useCallback(\n (view: string, params?: Record<string, string>) => {\n pillar?.navigate(view, params);\n },\n [pillar]\n );\n\n const setTheme = useCallback(\n (theme: Partial<ThemeConfig>) => {\n pillar?.setTheme(theme);\n },\n [pillar]\n );\n\n const setTextSelectionEnabled = useCallback(\n (enabled: boolean) => {\n pillar?.setTextSelectionEnabled(enabled);\n },\n [pillar]\n );\n\n const on = useCallback(\n <K extends keyof PillarEvents>(\n event: K,\n callback: (data: PillarEvents[K]) => void\n ) => {\n return pillar?.on(event, callback) ?? (() => {});\n },\n [pillar]\n );\n\n // Context value\n const value = useMemo<PillarContextValue>(\n () => ({\n pillar,\n state,\n isReady: state === \"ready\",\n isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n search,\n navigate,\n setTheme,\n setTextSelectionEnabled,\n on,\n }),\n [\n pillar,\n state,\n isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n search,\n navigate,\n setTheme,\n setTextSelectionEnabled,\n on,\n ]\n );\n\n return (\n <PillarContext.Provider value={value}>{children}</PillarContext.Provider>\n );\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function usePillarContext(): PillarContextValue {\n const context = useContext(PillarContext);\n\n if (!context) {\n throw new Error(\"usePillarContext must be used within a PillarProvider\");\n }\n\n return context;\n}\n","/**\n * PillarPanel Component\n * Renders the Pillar help panel at a custom location in the DOM\n */\n\nimport React, { useRef, useEffect, type CSSProperties, type HTMLAttributes } from 'react';\nimport { usePillarContext } from './PillarProvider';\n\nexport interface PillarPanelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name for the container */\n className?: string;\n \n /** Custom inline styles for the container */\n style?: CSSProperties;\n}\n\n/**\n * Renders the Pillar help panel at a custom location in the DOM.\n * Use this when you want to control where the panel is rendered instead of\n * having it automatically appended to document.body.\n * \n * **Important**: When using this component, set `panel.container: 'manual'` in your\n * PillarProvider config to prevent automatic mounting.\n * \n * @example\n * ```tsx\n * <PillarProvider \n * helpCenter=\"my-help\" \n * publicKey=\"pk_xxx\"\n * config={{ panel: { container: 'manual' } }}\n * >\n * <div className=\"my-layout\">\n * <Sidebar />\n * <PillarPanel className=\"help-panel-container\" />\n * <MainContent />\n * </div>\n * </PillarProvider>\n * ```\n */\nexport function PillarPanel({ \n className, \n style,\n ...props \n}: PillarPanelProps): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null);\n const { pillar, isReady } = usePillarContext();\n const hasMounted = useRef(false);\n\n useEffect(() => {\n // Only mount once when SDK is ready and we have a container\n if (!isReady || !pillar || !containerRef.current || hasMounted.current) {\n return;\n }\n\n // Mount the panel into our container\n pillar.mountPanelTo(containerRef.current);\n hasMounted.current = true;\n\n // Cleanup is handled by Pillar.destroy() in the provider\n }, [isReady, pillar]);\n\n return (\n <div \n ref={containerRef} \n className={className}\n style={style}\n data-pillar-panel-container=\"\"\n {...props}\n />\n );\n}\n\n","/**\n * useHelpPanel Hook\n * Panel-specific controls and state\n */\n\nimport { useCallback } from 'react';\nimport { usePillarContext } from '../PillarProvider';\n\nexport interface UseHelpPanelResult {\n /** Whether the panel is currently open */\n isOpen: boolean;\n \n /** Open the panel */\n open: (options?: { view?: string; article?: string; search?: string }) => void;\n \n /** Close the panel */\n close: () => void;\n \n /** Toggle the panel */\n toggle: () => void;\n \n /** Open a specific article in the panel */\n openArticle: (slug: string) => void;\n \n /** Open a specific category in the panel */\n openCategory: (slug: string) => Promise<void>;\n \n /** Open search with a query */\n openSearch: (query?: string) => void;\n \n /** Open the AI chat */\n openChat: () => void;\n}\n\n/**\n * Hook for panel-specific controls\n * \n * @example\n * ```tsx\n * function HelpButton() {\n * const { isOpen, toggle, openChat } = useHelpPanel();\n * \n * return (\n * <div>\n * <button onClick={toggle}>\n * {isOpen ? 'Close' : 'Help'}\n * </button>\n * <button onClick={openChat}>\n * Ask AI\n * </button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useHelpPanel(): UseHelpPanelResult {\n const { isPanelOpen, open, close, toggle, openArticle, openCategory, search, navigate } = usePillarContext();\n\n const openSearch = useCallback(\n (query?: string) => {\n if (query) {\n search(query);\n } else {\n open({ view: 'search' });\n }\n },\n [search, open]\n );\n\n const openChat = useCallback(() => {\n navigate('chat');\n }, [navigate]);\n\n return {\n isOpen: isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n openSearch,\n openChat,\n };\n}\n\n","/**\n * usePillar Hook\n * Access Pillar SDK instance and state with optional type-safe onTask\n */\n\nimport type {\n SyncActionDefinitions,\n ActionDefinitions,\n ActionDataType,\n ActionNames,\n} from '@pillar-ai/sdk';\nimport { useCallback } from 'react';\nimport { usePillarContext, type PillarContextValue } from '../PillarProvider';\n\nexport type UsePillarResult = PillarContextValue;\n\n/**\n * Extended result with type-safe onTask method.\n *\n * @template TActions - The action definitions for type inference\n */\nexport interface TypedUsePillarResult<\n TActions extends SyncActionDefinitions | ActionDefinitions,\n> extends Omit<PillarContextValue, 'pillar'> {\n pillar: PillarContextValue['pillar'];\n /**\n * Type-safe task handler registration.\n *\n * @param taskName - The action name (autocompleted from your actions)\n * @param handler - Handler function with typed data parameter\n * @returns Unsubscribe function\n */\n onTask: <TName extends ActionNames<TActions>>(\n taskName: TName,\n handler: (data: ActionDataType<TActions, TName>) => void\n ) => () => void;\n}\n\n/**\n * Hook to access the Pillar SDK instance and state\n *\n * @example Basic usage (untyped)\n * ```tsx\n * function MyComponent() {\n * const { isReady, open, close, isPanelOpen } = usePillar();\n *\n * if (!isReady) return <div>Loading...</div>;\n *\n * return (\n * <button onClick={() => open()}>\n * {isPanelOpen ? 'Close Help' : 'Get Help'}\n * </button>\n * );\n * }\n * ```\n *\n * @example Type-safe onTask with action definitions\n * ```tsx\n * import { actions } from '@/lib/pillar/actions';\n *\n * function MyComponent() {\n * const { pillar, onTask } = usePillar<typeof actions>();\n *\n * useEffect(() => {\n * // TypeScript knows data has { type, url, name }\n * const unsub = onTask('add_new_source', (data) => {\n * console.log(data.url); // ✓ Typed!\n * });\n * return unsub;\n * }, [onTask]);\n * }\n * ```\n */\nexport function usePillar<\n TActions extends SyncActionDefinitions | ActionDefinitions = SyncActionDefinitions,\n>(): TypedUsePillarResult<TActions> {\n const context = usePillarContext();\n\n // Create a type-safe wrapper around pillar.onTask\n const onTask = useCallback(\n <TName extends ActionNames<TActions>>(\n taskName: TName,\n handler: (data: ActionDataType<TActions, TName>) => void\n ): (() => void) => {\n if (!context.pillar) {\n // Return no-op if pillar not ready\n return () => {};\n }\n // Cast handler to match the SDK's expected type\n // The runtime behavior is the same, this is just for type narrowing\n return context.pillar.onTask(\n taskName as string,\n handler as (data: Record<string, unknown>) => void\n );\n },\n [context.pillar]\n );\n\n return {\n ...context,\n onTask,\n };\n}\n\n"],"names":["_jsx"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ const PillarContext = react.createContext(null);
|
|
|
14
14
|
// ============================================================================
|
|
15
15
|
function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children, }) {
|
|
16
16
|
const [pillar, setPillar] = react.useState(null);
|
|
17
|
-
const [state, setState] = react.useState(
|
|
17
|
+
const [state, setState] = react.useState("uninitialized");
|
|
18
18
|
const [isPanelOpen, setIsPanelOpen] = react.useState(false);
|
|
19
19
|
// Keep a ref to the latest onTask callback to avoid re-subscribing
|
|
20
20
|
const onTaskRef = react.useRef(onTask);
|
|
@@ -35,10 +35,10 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
35
35
|
setPillar(existingInstance);
|
|
36
36
|
setState(existingInstance.state);
|
|
37
37
|
// Re-subscribe to events
|
|
38
|
-
existingInstance.on(
|
|
38
|
+
existingInstance.on("panel:open", () => {
|
|
39
39
|
setIsPanelOpen(true);
|
|
40
40
|
});
|
|
41
|
-
existingInstance.on(
|
|
41
|
+
existingInstance.on("panel:close", () => {
|
|
42
42
|
setIsPanelOpen(false);
|
|
43
43
|
});
|
|
44
44
|
}
|
|
@@ -54,18 +54,18 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
54
54
|
setPillar(instance);
|
|
55
55
|
setState(instance.state);
|
|
56
56
|
// Listen for panel open/close
|
|
57
|
-
instance.on(
|
|
57
|
+
instance.on("panel:open", () => {
|
|
58
58
|
setIsPanelOpen(true);
|
|
59
59
|
});
|
|
60
|
-
instance.on(
|
|
60
|
+
instance.on("panel:close", () => {
|
|
61
61
|
setIsPanelOpen(false);
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
catch (error) {
|
|
66
|
-
console.error(
|
|
66
|
+
console.error("[Pillar React] Failed to initialize:", error);
|
|
67
67
|
if (mounted) {
|
|
68
|
-
setState(
|
|
68
|
+
setState("error");
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
};
|
|
@@ -82,11 +82,11 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
82
82
|
// Update state when SDK state changes
|
|
83
83
|
react.useEffect(() => {
|
|
84
84
|
if (pillar) {
|
|
85
|
-
const unsubscribe = pillar.on(
|
|
86
|
-
setState(
|
|
85
|
+
const unsubscribe = pillar.on("ready", () => {
|
|
86
|
+
setState("ready");
|
|
87
87
|
});
|
|
88
|
-
const unsubscribeError = pillar.on(
|
|
89
|
-
setState(
|
|
88
|
+
const unsubscribeError = pillar.on("error", () => {
|
|
89
|
+
setState("error");
|
|
90
90
|
});
|
|
91
91
|
return () => {
|
|
92
92
|
unsubscribe();
|
|
@@ -97,7 +97,7 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
97
97
|
// Register task handler
|
|
98
98
|
react.useEffect(() => {
|
|
99
99
|
if (pillar) {
|
|
100
|
-
const unsubscribe = pillar.on(
|
|
100
|
+
const unsubscribe = pillar.on("task:execute", (task) => {
|
|
101
101
|
onTaskRef.current?.(task);
|
|
102
102
|
});
|
|
103
103
|
return unsubscribe;
|
|
@@ -130,9 +130,9 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
130
130
|
});
|
|
131
131
|
return () => {
|
|
132
132
|
// Cleanup all registrations
|
|
133
|
-
unsubscribers.forEach(unsub => unsub());
|
|
133
|
+
unsubscribers.forEach((unsub) => unsub());
|
|
134
134
|
// Unmount all React roots
|
|
135
|
-
roots.forEach(root => root.unmount());
|
|
135
|
+
roots.forEach((root) => root.unmount());
|
|
136
136
|
roots.clear();
|
|
137
137
|
};
|
|
138
138
|
}, [pillar, cards]);
|
|
@@ -150,7 +150,7 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
150
150
|
pillar?.open({ article: slug });
|
|
151
151
|
}, [pillar]);
|
|
152
152
|
const openCategory = react.useCallback(async (slug) => {
|
|
153
|
-
pillar?.navigate(
|
|
153
|
+
pillar?.navigate("category", { slug });
|
|
154
154
|
}, [pillar]);
|
|
155
155
|
const search = react.useCallback((query) => {
|
|
156
156
|
pillar?.open({ search: query });
|
|
@@ -171,7 +171,7 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
171
171
|
const value = react.useMemo(() => ({
|
|
172
172
|
pillar,
|
|
173
173
|
state,
|
|
174
|
-
isReady: state ===
|
|
174
|
+
isReady: state === "ready",
|
|
175
175
|
isPanelOpen,
|
|
176
176
|
open,
|
|
177
177
|
close,
|
|
@@ -183,7 +183,21 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
183
183
|
setTheme,
|
|
184
184
|
setTextSelectionEnabled,
|
|
185
185
|
on,
|
|
186
|
-
}), [
|
|
186
|
+
}), [
|
|
187
|
+
pillar,
|
|
188
|
+
state,
|
|
189
|
+
isPanelOpen,
|
|
190
|
+
open,
|
|
191
|
+
close,
|
|
192
|
+
toggle,
|
|
193
|
+
openArticle,
|
|
194
|
+
openCategory,
|
|
195
|
+
search,
|
|
196
|
+
navigate,
|
|
197
|
+
setTheme,
|
|
198
|
+
setTextSelectionEnabled,
|
|
199
|
+
on,
|
|
200
|
+
]);
|
|
187
201
|
return (jsxRuntime.jsx(PillarContext.Provider, { value: value, children: children }));
|
|
188
202
|
}
|
|
189
203
|
// ============================================================================
|
|
@@ -192,7 +206,7 @@ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children
|
|
|
192
206
|
function usePillarContext() {
|
|
193
207
|
const context = react.useContext(PillarContext);
|
|
194
208
|
if (!context) {
|
|
195
|
-
throw new Error(
|
|
209
|
+
throw new Error("usePillarContext must be used within a PillarProvider");
|
|
196
210
|
}
|
|
197
211
|
return context;
|
|
198
212
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/PillarProvider.tsx","../src/PillarPanel.tsx","../src/hooks/useHelpPanel.ts","../src/hooks/usePillar.ts"],"sourcesContent":["/**\n * PillarProvider\n * Context provider that initializes and manages the Pillar SDK\n */\n\nimport {\n Pillar,\n type PillarConfig,\n type PillarEvents,\n type PillarState,\n type TaskExecutePayload,\n type ThemeConfig,\n type CardCallbacks,\n} from '@pillar-ai/sdk';\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n type ComponentType,\n} from 'react';\nimport { createRoot, type Root } from 'react-dom/client';\n\n// ============================================================================\n// Card Types\n// ============================================================================\n\n/**\n * Props passed to custom card components.\n */\nexport interface CardComponentProps<T = Record<string, unknown>> {\n /** Data extracted by the AI for this action */\n data: T;\n /** Called when user confirms the action */\n onConfirm: (modifiedData?: Record<string, unknown>) => void;\n /** Called when user cancels the action */\n onCancel: () => void;\n /** Called to report state changes (loading, success, error) */\n onStateChange?: (state: 'loading' | 'success' | 'error', message?: string) => void;\n}\n\n/**\n * A React component that can be used as a custom card renderer.\n */\nexport type CardComponent<T = Record<string, unknown>> = ComponentType<CardComponentProps<T>>;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PillarContextValue {\n /** The Pillar SDK instance */\n pillar: Pillar | null;\n \n /** Current SDK state */\n state: PillarState;\n \n /** Whether the SDK is ready */\n isReady: boolean;\n \n /** Whether the panel is currently open */\n isPanelOpen: boolean;\n \n /** Open the help panel */\n open: (options?: { view?: string; article?: string; search?: string; focusInput?: boolean }) => void;\n \n /** Close the help panel */\n close: () => void;\n \n /** Toggle the help panel */\n toggle: () => void;\n \n /** Open a specific article */\n openArticle: (slug: string) => void;\n \n /** Open a specific category */\n openCategory: (slug: string) => Promise<void>;\n \n /** Perform a search */\n search: (query: string) => void;\n \n /** Navigate to a specific view */\n navigate: (view: string, params?: Record<string, string>) => void;\n \n /** Update the panel theme at runtime */\n setTheme: (theme: Partial<ThemeConfig>) => void;\n \n /** Enable or disable the text selection \"Ask AI\" popover */\n setTextSelectionEnabled: (enabled: boolean) => void;\n \n /** Subscribe to SDK events */\n on: <K extends keyof PillarEvents>(\n event: K,\n callback: (data: PillarEvents[K]) => void\n ) => () => void;\n}\n\nexport interface PillarProviderProps {\n /** Help center subdomain or identifier */\n helpCenter: string;\n \n /** Public API key */\n publicKey: string;\n \n /** \n * Additional SDK configuration\n * \n * Notable options:\n * - `panel.useShadowDOM`: Whether to isolate styles in Shadow DOM (default: false).\n * Set to false to let custom cards inherit your app's CSS (Tailwind, etc.)\n */\n config?: Omit<PillarConfig, 'helpCenter' | 'publicKey'>;\n \n /**\n * Handler called when a task action is triggered from the chat.\n * Use this to handle AI-suggested actions like opening modals, navigating, etc.\n * \n * @example\n * ```tsx\n * <PillarProvider\n * helpCenter=\"my-app\"\n * publicKey=\"pk_...\"\n * onTask={(task) => {\n * switch (task.name) {\n * case 'invite_team_member':\n * openInviteModal(task.data);\n * break;\n * case 'open_settings':\n * router.push('/settings');\n * break;\n * }\n * }}\n * >\n * ```\n */\n onTask?: (task: TaskExecutePayload) => void;\n \n /**\n * Custom card components to render for inline_ui type actions.\n * Map card type names to React components that will render the inline UI.\n * \n * @example\n * ```tsx\n * import { InviteMembersCard } from './cards/InviteMembersCard';\n * \n * <PillarProvider\n * helpCenter=\"my-app\"\n * publicKey=\"pk_...\"\n * cards={{\n * invite_members: InviteMembersCard,\n * confirm_delete: ConfirmDeleteCard,\n * }}\n * >\n * ```\n */\n cards?: Record<string, CardComponent>;\n \n /** Children components */\n children: ReactNode;\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst PillarContext = createContext<PillarContextValue | null>(null);\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\nexport function PillarProvider({\n helpCenter,\n publicKey,\n config,\n onTask,\n cards,\n children,\n}: PillarProviderProps): React.ReactElement {\n const [pillar, setPillar] = useState<Pillar | null>(null);\n const [state, setState] = useState<PillarState>('uninitialized');\n const [isPanelOpen, setIsPanelOpen] = useState(false);\n \n // Keep a ref to the latest onTask callback to avoid re-subscribing\n const onTaskRef = useRef(onTask);\n onTaskRef.current = onTask;\n \n // Keep a ref to cards to access latest versions\n const cardsRef = useRef(cards);\n cardsRef.current = cards;\n\n // Initialize SDK\n useEffect(() => {\n let mounted = true;\n\n const initPillar = async () => {\n try {\n // Pillar is a singleton - check if already initialized\n const existingInstance = Pillar.getInstance();\n if (existingInstance) {\n // Reuse existing instance (preserves chat history, panel state, etc.)\n if (mounted) {\n setPillar(existingInstance);\n setState(existingInstance.state);\n \n // Re-subscribe to events\n existingInstance.on('panel:open', () => {\n setIsPanelOpen(true);\n });\n \n existingInstance.on('panel:close', () => {\n setIsPanelOpen(false);\n });\n }\n return;\n }\n \n // Initialize new instance\n const instance = await Pillar.init({\n helpCenter,\n publicKey,\n ...config,\n });\n\n if (mounted) {\n setPillar(instance);\n setState(instance.state);\n\n // Listen for panel open/close\n instance.on('panel:open', () => {\n setIsPanelOpen(true);\n });\n \n instance.on('panel:close', () => {\n setIsPanelOpen(false);\n });\n }\n } catch (error) {\n console.error('[Pillar React] Failed to initialize:', error);\n if (mounted) {\n setState('error');\n }\n }\n };\n\n initPillar();\n\n // Cleanup - DON'T destroy the singleton on unmount\n // This preserves conversation history and panel state across navigation\n // Pillar.destroy() should only be called explicitly when the app unmounts completely\n return () => {\n mounted = false;\n // Note: We intentionally don't call Pillar.destroy() here\n // The singleton persists to maintain state across route changes\n };\n }, [helpCenter, publicKey]); // Re-initialize if credentials change\n\n // Update state when SDK state changes\n useEffect(() => {\n if (pillar) {\n const unsubscribe = pillar.on('ready', () => {\n setState('ready');\n });\n \n const unsubscribeError = pillar.on('error', () => {\n setState('error');\n });\n\n return () => {\n unsubscribe();\n unsubscribeError();\n };\n }\n }, [pillar]);\n\n // Register task handler\n useEffect(() => {\n if (pillar) {\n const unsubscribe = pillar.on('task:execute', (task) => {\n onTaskRef.current?.(task);\n });\n\n return unsubscribe;\n }\n }, [pillar]);\n\n // Register custom card renderers\n useEffect(() => {\n if (!pillar || !cards) return;\n \n const unsubscribers: Array<() => void> = [];\n const roots: Map<HTMLElement, Root> = new Map();\n \n // Register each card component as a vanilla renderer\n Object.entries(cards).forEach(([cardType, Component]) => {\n const unsubscribe = pillar.registerCard(cardType, (container, data, callbacks: CardCallbacks) => {\n // Create a React root for this container\n const root = createRoot(container);\n roots.set(container, root);\n \n // Render the React component\n root.render(\n <Component\n data={data}\n onConfirm={callbacks.onConfirm}\n onCancel={callbacks.onCancel}\n onStateChange={callbacks.onStateChange}\n />\n );\n \n // Return cleanup function\n return () => {\n const existingRoot = roots.get(container);\n if (existingRoot) {\n existingRoot.unmount();\n roots.delete(container);\n }\n };\n });\n \n unsubscribers.push(unsubscribe);\n });\n \n return () => {\n // Cleanup all registrations\n unsubscribers.forEach(unsub => unsub());\n // Unmount all React roots\n roots.forEach(root => root.unmount());\n roots.clear();\n };\n }, [pillar, cards]);\n\n // Actions\n const open = useCallback(\n (options?: { view?: string; article?: string; search?: string; focusInput?: boolean }) => {\n pillar?.open(options);\n },\n [pillar]\n );\n\n const close = useCallback(() => {\n pillar?.close();\n }, [pillar]);\n\n const toggle = useCallback(() => {\n pillar?.toggle();\n }, [pillar]);\n\n const openArticle = useCallback(\n (slug: string) => {\n pillar?.open({ article: slug });\n },\n [pillar]\n );\n\n const openCategory = useCallback(\n async (slug: string) => {\n pillar?.navigate('category', { slug });\n },\n [pillar]\n );\n\n const search = useCallback(\n (query: string) => {\n pillar?.open({ search: query });\n },\n [pillar]\n );\n\n const navigate = useCallback(\n (view: string, params?: Record<string, string>) => {\n pillar?.navigate(view, params);\n },\n [pillar]\n );\n\n const setTheme = useCallback(\n (theme: Partial<ThemeConfig>) => {\n pillar?.setTheme(theme);\n },\n [pillar]\n );\n\n const setTextSelectionEnabled = useCallback(\n (enabled: boolean) => {\n pillar?.setTextSelectionEnabled(enabled);\n },\n [pillar]\n );\n\n const on = useCallback(\n <K extends keyof PillarEvents>(\n event: K,\n callback: (data: PillarEvents[K]) => void\n ) => {\n return pillar?.on(event, callback) ?? (() => {});\n },\n [pillar]\n );\n\n // Context value\n const value = useMemo<PillarContextValue>(\n () => ({\n pillar,\n state,\n isReady: state === 'ready',\n isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n search,\n navigate,\n setTheme,\n setTextSelectionEnabled,\n on,\n }),\n [pillar, state, isPanelOpen, open, close, toggle, openArticle, openCategory, search, navigate, setTheme, setTextSelectionEnabled, on]\n );\n\n return (\n <PillarContext.Provider value={value}>\n {children}\n </PillarContext.Provider>\n );\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function usePillarContext(): PillarContextValue {\n const context = useContext(PillarContext);\n \n if (!context) {\n throw new Error('usePillarContext must be used within a PillarProvider');\n }\n \n return context;\n}\n\n","/**\n * PillarPanel Component\n * Renders the Pillar help panel at a custom location in the DOM\n */\n\nimport React, { useRef, useEffect, type CSSProperties, type HTMLAttributes } from 'react';\nimport { usePillarContext } from './PillarProvider';\n\nexport interface PillarPanelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name for the container */\n className?: string;\n \n /** Custom inline styles for the container */\n style?: CSSProperties;\n}\n\n/**\n * Renders the Pillar help panel at a custom location in the DOM.\n * Use this when you want to control where the panel is rendered instead of\n * having it automatically appended to document.body.\n * \n * **Important**: When using this component, set `panel.container: 'manual'` in your\n * PillarProvider config to prevent automatic mounting.\n * \n * @example\n * ```tsx\n * <PillarProvider \n * helpCenter=\"my-help\" \n * publicKey=\"pk_xxx\"\n * config={{ panel: { container: 'manual' } }}\n * >\n * <div className=\"my-layout\">\n * <Sidebar />\n * <PillarPanel className=\"help-panel-container\" />\n * <MainContent />\n * </div>\n * </PillarProvider>\n * ```\n */\nexport function PillarPanel({ \n className, \n style,\n ...props \n}: PillarPanelProps): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null);\n const { pillar, isReady } = usePillarContext();\n const hasMounted = useRef(false);\n\n useEffect(() => {\n // Only mount once when SDK is ready and we have a container\n if (!isReady || !pillar || !containerRef.current || hasMounted.current) {\n return;\n }\n\n // Mount the panel into our container\n pillar.mountPanelTo(containerRef.current);\n hasMounted.current = true;\n\n // Cleanup is handled by Pillar.destroy() in the provider\n }, [isReady, pillar]);\n\n return (\n <div \n ref={containerRef} \n className={className}\n style={style}\n data-pillar-panel-container=\"\"\n {...props}\n />\n );\n}\n\n","/**\n * useHelpPanel Hook\n * Panel-specific controls and state\n */\n\nimport { useCallback } from 'react';\nimport { usePillarContext } from '../PillarProvider';\n\nexport interface UseHelpPanelResult {\n /** Whether the panel is currently open */\n isOpen: boolean;\n \n /** Open the panel */\n open: (options?: { view?: string; article?: string; search?: string }) => void;\n \n /** Close the panel */\n close: () => void;\n \n /** Toggle the panel */\n toggle: () => void;\n \n /** Open a specific article in the panel */\n openArticle: (slug: string) => void;\n \n /** Open a specific category in the panel */\n openCategory: (slug: string) => Promise<void>;\n \n /** Open search with a query */\n openSearch: (query?: string) => void;\n \n /** Open the AI chat */\n openChat: () => void;\n}\n\n/**\n * Hook for panel-specific controls\n * \n * @example\n * ```tsx\n * function HelpButton() {\n * const { isOpen, toggle, openChat } = useHelpPanel();\n * \n * return (\n * <div>\n * <button onClick={toggle}>\n * {isOpen ? 'Close' : 'Help'}\n * </button>\n * <button onClick={openChat}>\n * Ask AI\n * </button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useHelpPanel(): UseHelpPanelResult {\n const { isPanelOpen, open, close, toggle, openArticle, openCategory, search, navigate } = usePillarContext();\n\n const openSearch = useCallback(\n (query?: string) => {\n if (query) {\n search(query);\n } else {\n open({ view: 'search' });\n }\n },\n [search, open]\n );\n\n const openChat = useCallback(() => {\n navigate('chat');\n }, [navigate]);\n\n return {\n isOpen: isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n openSearch,\n openChat,\n };\n}\n\n","/**\n * usePillar Hook\n * Access Pillar SDK instance and state with optional type-safe onTask\n */\n\nimport type {\n SyncActionDefinitions,\n ActionDefinitions,\n ActionDataType,\n ActionNames,\n} from '@pillar-ai/sdk';\nimport { useCallback } from 'react';\nimport { usePillarContext, type PillarContextValue } from '../PillarProvider';\n\nexport type UsePillarResult = PillarContextValue;\n\n/**\n * Extended result with type-safe onTask method.\n *\n * @template TActions - The action definitions for type inference\n */\nexport interface TypedUsePillarResult<\n TActions extends SyncActionDefinitions | ActionDefinitions,\n> extends Omit<PillarContextValue, 'pillar'> {\n pillar: PillarContextValue['pillar'];\n /**\n * Type-safe task handler registration.\n *\n * @param taskName - The action name (autocompleted from your actions)\n * @param handler - Handler function with typed data parameter\n * @returns Unsubscribe function\n */\n onTask: <TName extends ActionNames<TActions>>(\n taskName: TName,\n handler: (data: ActionDataType<TActions, TName>) => void\n ) => () => void;\n}\n\n/**\n * Hook to access the Pillar SDK instance and state\n *\n * @example Basic usage (untyped)\n * ```tsx\n * function MyComponent() {\n * const { isReady, open, close, isPanelOpen } = usePillar();\n *\n * if (!isReady) return <div>Loading...</div>;\n *\n * return (\n * <button onClick={() => open()}>\n * {isPanelOpen ? 'Close Help' : 'Get Help'}\n * </button>\n * );\n * }\n * ```\n *\n * @example Type-safe onTask with action definitions\n * ```tsx\n * import { actions } from '@/lib/pillar/actions';\n *\n * function MyComponent() {\n * const { pillar, onTask } = usePillar<typeof actions>();\n *\n * useEffect(() => {\n * // TypeScript knows data has { type, url, name }\n * const unsub = onTask('add_new_source', (data) => {\n * console.log(data.url); // ✓ Typed!\n * });\n * return unsub;\n * }, [onTask]);\n * }\n * ```\n */\nexport function usePillar<\n TActions extends SyncActionDefinitions | ActionDefinitions = SyncActionDefinitions,\n>(): TypedUsePillarResult<TActions> {\n const context = usePillarContext();\n\n // Create a type-safe wrapper around pillar.onTask\n const onTask = useCallback(\n <TName extends ActionNames<TActions>>(\n taskName: TName,\n handler: (data: ActionDataType<TActions, TName>) => void\n ): (() => void) => {\n if (!context.pillar) {\n // Return no-op if pillar not ready\n return () => {};\n }\n // Cast handler to match the SDK's expected type\n // The runtime behavior is the same, this is just for type narrowing\n return context.pillar.onTask(\n taskName as string,\n handler as (data: Record<string, unknown>) => void\n );\n },\n [context.pillar]\n );\n\n return {\n ...context,\n onTask,\n };\n}\n\n"],"names":["createContext","useState","useRef","useEffect","Pillar","createRoot","_jsx","useCallback","useMemo","useContext"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/PillarProvider.tsx","../src/PillarPanel.tsx","../src/hooks/useHelpPanel.ts","../src/hooks/usePillar.ts"],"sourcesContent":["/**\n * PillarProvider\n * Context provider that initializes and manages the Pillar SDK\n */\n\nimport {\n Pillar,\n type CardCallbacks,\n type PillarConfig,\n type PillarEvents,\n type PillarState,\n type TaskExecutePayload,\n type ThemeConfig,\n} from \"@pillar-ai/sdk\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\n\n// ============================================================================\n// Card Types\n// ============================================================================\n\n/**\n * Props passed to custom card components.\n */\nexport interface CardComponentProps<T = Record<string, unknown>> {\n /** Data extracted by the AI for this action */\n data: T;\n /** Called when user confirms the action */\n onConfirm: (modifiedData?: Record<string, unknown>) => void;\n /** Called when user cancels the action */\n onCancel: () => void;\n /** Called to report state changes (loading, success, error) */\n onStateChange?: (\n state: \"loading\" | \"success\" | \"error\",\n message?: string\n ) => void;\n}\n\n/**\n * A React component that can be used as a custom card renderer.\n */\nexport type CardComponent<T = Record<string, unknown>> = ComponentType<\n CardComponentProps<T>\n>;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PillarContextValue {\n /** The Pillar SDK instance */\n pillar: Pillar | null;\n\n /** Current SDK state */\n state: PillarState;\n\n /** Whether the SDK is ready */\n isReady: boolean;\n\n /** Whether the panel is currently open */\n isPanelOpen: boolean;\n\n /** Open the help panel */\n open: (options?: {\n view?: string;\n article?: string;\n search?: string;\n focusInput?: boolean;\n }) => void;\n\n /** Close the help panel */\n close: () => void;\n\n /** Toggle the help panel */\n toggle: () => void;\n\n /** Open a specific article */\n openArticle: (slug: string) => void;\n\n /** Open a specific category */\n openCategory: (slug: string) => Promise<void>;\n\n /** Perform a search */\n search: (query: string) => void;\n\n /** Navigate to a specific view */\n navigate: (view: string, params?: Record<string, string>) => void;\n\n /** Update the panel theme at runtime */\n setTheme: (theme: Partial<ThemeConfig>) => void;\n\n /** Enable or disable the text selection \"Ask AI\" popover */\n setTextSelectionEnabled: (enabled: boolean) => void;\n\n /** Subscribe to SDK events */\n on: <K extends keyof PillarEvents>(\n event: K,\n callback: (data: PillarEvents[K]) => void\n ) => () => void;\n}\n\nexport interface PillarProviderProps {\n /** Help center subdomain or identifier */\n helpCenter: string;\n\n /** Public API key */\n publicKey: string;\n\n /**\n * Additional SDK configuration\n *\n * Notable options:\n * - `panel.useShadowDOM`: Whether to isolate styles in Shadow DOM (default: false).\n * Set to false to let custom cards inherit your app's CSS (Tailwind, etc.)\n */\n config?: Omit<PillarConfig, \"helpCenter\" | \"publicKey\">;\n\n /**\n * Handler called when a task action is triggered from the chat.\n * Use this to handle AI-suggested actions like opening modals, navigating, etc.\n *\n * @example\n * ```tsx\n * <PillarProvider\n * helpCenter=\"my-app\"\n * publicKey=\"pk_...\"\n * onTask={(task) => {\n * switch (task.name) {\n * case 'invite_team_member':\n * openInviteModal(task.data);\n * break;\n * case 'open_settings':\n * router.push('/settings');\n * break;\n * }\n * }}\n * >\n * ```\n */\n onTask?: (task: TaskExecutePayload) => void;\n\n /**\n * Custom card components to render for inline_ui type actions.\n * Map card type names to React components that will render the inline UI.\n *\n * @example\n * ```tsx\n * import { InviteMembersCard } from './cards/InviteMembersCard';\n *\n * <PillarProvider\n * helpCenter=\"my-app\"\n * publicKey=\"pk_...\"\n * cards={{\n * invite_members: InviteMembersCard,\n * confirm_delete: ConfirmDeleteCard,\n * }}\n * >\n * ```\n */\n cards?: Record<string, CardComponent>;\n\n /** Children components */\n children: ReactNode;\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst PillarContext = createContext<PillarContextValue | null>(null);\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\nexport function PillarProvider({\n helpCenter,\n publicKey,\n config,\n onTask,\n cards,\n children,\n}: PillarProviderProps): React.ReactElement {\n const [pillar, setPillar] = useState<Pillar | null>(null);\n const [state, setState] = useState<PillarState>(\"uninitialized\");\n const [isPanelOpen, setIsPanelOpen] = useState(false);\n\n // Keep a ref to the latest onTask callback to avoid re-subscribing\n const onTaskRef = useRef(onTask);\n onTaskRef.current = onTask;\n\n // Keep a ref to cards to access latest versions\n const cardsRef = useRef(cards);\n cardsRef.current = cards;\n\n // Initialize SDK\n useEffect(() => {\n let mounted = true;\n\n const initPillar = async () => {\n try {\n // Pillar is a singleton - check if already initialized\n const existingInstance = Pillar.getInstance();\n if (existingInstance) {\n // Reuse existing instance (preserves chat history, panel state, etc.)\n if (mounted) {\n setPillar(existingInstance);\n setState(existingInstance.state);\n\n // Re-subscribe to events\n existingInstance.on(\"panel:open\", () => {\n setIsPanelOpen(true);\n });\n\n existingInstance.on(\"panel:close\", () => {\n setIsPanelOpen(false);\n });\n }\n return;\n }\n\n // Initialize new instance\n const instance = await Pillar.init({\n helpCenter,\n publicKey,\n ...config,\n });\n\n if (mounted) {\n setPillar(instance);\n setState(instance.state);\n\n // Listen for panel open/close\n instance.on(\"panel:open\", () => {\n setIsPanelOpen(true);\n });\n\n instance.on(\"panel:close\", () => {\n setIsPanelOpen(false);\n });\n }\n } catch (error) {\n console.error(\"[Pillar React] Failed to initialize:\", error);\n if (mounted) {\n setState(\"error\");\n }\n }\n };\n\n initPillar();\n\n // Cleanup - DON'T destroy the singleton on unmount\n // This preserves conversation history and panel state across navigation\n // Pillar.destroy() should only be called explicitly when the app unmounts completely\n return () => {\n mounted = false;\n // Note: We intentionally don't call Pillar.destroy() here\n // The singleton persists to maintain state across route changes\n };\n }, [helpCenter, publicKey]); // Re-initialize if credentials change\n\n // Update state when SDK state changes\n useEffect(() => {\n if (pillar) {\n const unsubscribe = pillar.on(\"ready\", () => {\n setState(\"ready\");\n });\n\n const unsubscribeError = pillar.on(\"error\", () => {\n setState(\"error\");\n });\n\n return () => {\n unsubscribe();\n unsubscribeError();\n };\n }\n }, [pillar]);\n\n // Register task handler\n useEffect(() => {\n if (pillar) {\n const unsubscribe = pillar.on(\"task:execute\", (task) => {\n onTaskRef.current?.(task);\n });\n\n return unsubscribe;\n }\n }, [pillar]);\n\n // Register custom card renderers\n useEffect(() => {\n if (!pillar || !cards) return;\n\n const unsubscribers: Array<() => void> = [];\n const roots: Map<HTMLElement, Root> = new Map();\n\n // Register each card component as a vanilla renderer\n Object.entries(cards).forEach(([cardType, Component]) => {\n const unsubscribe = pillar.registerCard(\n cardType,\n (container, data, callbacks: CardCallbacks) => {\n // Create a React root for this container\n const root = createRoot(container);\n roots.set(container, root);\n\n // Render the React component\n root.render(\n <Component\n data={data}\n onConfirm={callbacks.onConfirm}\n onCancel={callbacks.onCancel}\n onStateChange={callbacks.onStateChange}\n />\n );\n\n // Return cleanup function\n return () => {\n const existingRoot = roots.get(container);\n if (existingRoot) {\n existingRoot.unmount();\n roots.delete(container);\n }\n };\n }\n );\n\n unsubscribers.push(unsubscribe);\n });\n\n return () => {\n // Cleanup all registrations\n unsubscribers.forEach((unsub) => unsub());\n // Unmount all React roots\n roots.forEach((root) => root.unmount());\n roots.clear();\n };\n }, [pillar, cards]);\n\n // Actions\n const open = useCallback(\n (options?: {\n view?: string;\n article?: string;\n search?: string;\n focusInput?: boolean;\n }) => {\n pillar?.open(options);\n },\n [pillar]\n );\n\n const close = useCallback(() => {\n pillar?.close();\n }, [pillar]);\n\n const toggle = useCallback(() => {\n pillar?.toggle();\n }, [pillar]);\n\n const openArticle = useCallback(\n (slug: string) => {\n pillar?.open({ article: slug });\n },\n [pillar]\n );\n\n const openCategory = useCallback(\n async (slug: string) => {\n pillar?.navigate(\"category\", { slug });\n },\n [pillar]\n );\n\n const search = useCallback(\n (query: string) => {\n pillar?.open({ search: query });\n },\n [pillar]\n );\n\n const navigate = useCallback(\n (view: string, params?: Record<string, string>) => {\n pillar?.navigate(view, params);\n },\n [pillar]\n );\n\n const setTheme = useCallback(\n (theme: Partial<ThemeConfig>) => {\n pillar?.setTheme(theme);\n },\n [pillar]\n );\n\n const setTextSelectionEnabled = useCallback(\n (enabled: boolean) => {\n pillar?.setTextSelectionEnabled(enabled);\n },\n [pillar]\n );\n\n const on = useCallback(\n <K extends keyof PillarEvents>(\n event: K,\n callback: (data: PillarEvents[K]) => void\n ) => {\n return pillar?.on(event, callback) ?? (() => {});\n },\n [pillar]\n );\n\n // Context value\n const value = useMemo<PillarContextValue>(\n () => ({\n pillar,\n state,\n isReady: state === \"ready\",\n isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n search,\n navigate,\n setTheme,\n setTextSelectionEnabled,\n on,\n }),\n [\n pillar,\n state,\n isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n search,\n navigate,\n setTheme,\n setTextSelectionEnabled,\n on,\n ]\n );\n\n return (\n <PillarContext.Provider value={value}>{children}</PillarContext.Provider>\n );\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function usePillarContext(): PillarContextValue {\n const context = useContext(PillarContext);\n\n if (!context) {\n throw new Error(\"usePillarContext must be used within a PillarProvider\");\n }\n\n return context;\n}\n","/**\n * PillarPanel Component\n * Renders the Pillar help panel at a custom location in the DOM\n */\n\nimport React, { useRef, useEffect, type CSSProperties, type HTMLAttributes } from 'react';\nimport { usePillarContext } from './PillarProvider';\n\nexport interface PillarPanelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name for the container */\n className?: string;\n \n /** Custom inline styles for the container */\n style?: CSSProperties;\n}\n\n/**\n * Renders the Pillar help panel at a custom location in the DOM.\n * Use this when you want to control where the panel is rendered instead of\n * having it automatically appended to document.body.\n * \n * **Important**: When using this component, set `panel.container: 'manual'` in your\n * PillarProvider config to prevent automatic mounting.\n * \n * @example\n * ```tsx\n * <PillarProvider \n * helpCenter=\"my-help\" \n * publicKey=\"pk_xxx\"\n * config={{ panel: { container: 'manual' } }}\n * >\n * <div className=\"my-layout\">\n * <Sidebar />\n * <PillarPanel className=\"help-panel-container\" />\n * <MainContent />\n * </div>\n * </PillarProvider>\n * ```\n */\nexport function PillarPanel({ \n className, \n style,\n ...props \n}: PillarPanelProps): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null);\n const { pillar, isReady } = usePillarContext();\n const hasMounted = useRef(false);\n\n useEffect(() => {\n // Only mount once when SDK is ready and we have a container\n if (!isReady || !pillar || !containerRef.current || hasMounted.current) {\n return;\n }\n\n // Mount the panel into our container\n pillar.mountPanelTo(containerRef.current);\n hasMounted.current = true;\n\n // Cleanup is handled by Pillar.destroy() in the provider\n }, [isReady, pillar]);\n\n return (\n <div \n ref={containerRef} \n className={className}\n style={style}\n data-pillar-panel-container=\"\"\n {...props}\n />\n );\n}\n\n","/**\n * useHelpPanel Hook\n * Panel-specific controls and state\n */\n\nimport { useCallback } from 'react';\nimport { usePillarContext } from '../PillarProvider';\n\nexport interface UseHelpPanelResult {\n /** Whether the panel is currently open */\n isOpen: boolean;\n \n /** Open the panel */\n open: (options?: { view?: string; article?: string; search?: string }) => void;\n \n /** Close the panel */\n close: () => void;\n \n /** Toggle the panel */\n toggle: () => void;\n \n /** Open a specific article in the panel */\n openArticle: (slug: string) => void;\n \n /** Open a specific category in the panel */\n openCategory: (slug: string) => Promise<void>;\n \n /** Open search with a query */\n openSearch: (query?: string) => void;\n \n /** Open the AI chat */\n openChat: () => void;\n}\n\n/**\n * Hook for panel-specific controls\n * \n * @example\n * ```tsx\n * function HelpButton() {\n * const { isOpen, toggle, openChat } = useHelpPanel();\n * \n * return (\n * <div>\n * <button onClick={toggle}>\n * {isOpen ? 'Close' : 'Help'}\n * </button>\n * <button onClick={openChat}>\n * Ask AI\n * </button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useHelpPanel(): UseHelpPanelResult {\n const { isPanelOpen, open, close, toggle, openArticle, openCategory, search, navigate } = usePillarContext();\n\n const openSearch = useCallback(\n (query?: string) => {\n if (query) {\n search(query);\n } else {\n open({ view: 'search' });\n }\n },\n [search, open]\n );\n\n const openChat = useCallback(() => {\n navigate('chat');\n }, [navigate]);\n\n return {\n isOpen: isPanelOpen,\n open,\n close,\n toggle,\n openArticle,\n openCategory,\n openSearch,\n openChat,\n };\n}\n\n","/**\n * usePillar Hook\n * Access Pillar SDK instance and state with optional type-safe onTask\n */\n\nimport type {\n SyncActionDefinitions,\n ActionDefinitions,\n ActionDataType,\n ActionNames,\n} from '@pillar-ai/sdk';\nimport { useCallback } from 'react';\nimport { usePillarContext, type PillarContextValue } from '../PillarProvider';\n\nexport type UsePillarResult = PillarContextValue;\n\n/**\n * Extended result with type-safe onTask method.\n *\n * @template TActions - The action definitions for type inference\n */\nexport interface TypedUsePillarResult<\n TActions extends SyncActionDefinitions | ActionDefinitions,\n> extends Omit<PillarContextValue, 'pillar'> {\n pillar: PillarContextValue['pillar'];\n /**\n * Type-safe task handler registration.\n *\n * @param taskName - The action name (autocompleted from your actions)\n * @param handler - Handler function with typed data parameter\n * @returns Unsubscribe function\n */\n onTask: <TName extends ActionNames<TActions>>(\n taskName: TName,\n handler: (data: ActionDataType<TActions, TName>) => void\n ) => () => void;\n}\n\n/**\n * Hook to access the Pillar SDK instance and state\n *\n * @example Basic usage (untyped)\n * ```tsx\n * function MyComponent() {\n * const { isReady, open, close, isPanelOpen } = usePillar();\n *\n * if (!isReady) return <div>Loading...</div>;\n *\n * return (\n * <button onClick={() => open()}>\n * {isPanelOpen ? 'Close Help' : 'Get Help'}\n * </button>\n * );\n * }\n * ```\n *\n * @example Type-safe onTask with action definitions\n * ```tsx\n * import { actions } from '@/lib/pillar/actions';\n *\n * function MyComponent() {\n * const { pillar, onTask } = usePillar<typeof actions>();\n *\n * useEffect(() => {\n * // TypeScript knows data has { type, url, name }\n * const unsub = onTask('add_new_source', (data) => {\n * console.log(data.url); // ✓ Typed!\n * });\n * return unsub;\n * }, [onTask]);\n * }\n * ```\n */\nexport function usePillar<\n TActions extends SyncActionDefinitions | ActionDefinitions = SyncActionDefinitions,\n>(): TypedUsePillarResult<TActions> {\n const context = usePillarContext();\n\n // Create a type-safe wrapper around pillar.onTask\n const onTask = useCallback(\n <TName extends ActionNames<TActions>>(\n taskName: TName,\n handler: (data: ActionDataType<TActions, TName>) => void\n ): (() => void) => {\n if (!context.pillar) {\n // Return no-op if pillar not ready\n return () => {};\n }\n // Cast handler to match the SDK's expected type\n // The runtime behavior is the same, this is just for type narrowing\n return context.pillar.onTask(\n taskName as string,\n handler as (data: Record<string, unknown>) => void\n );\n },\n [context.pillar]\n );\n\n return {\n ...context,\n onTask,\n };\n}\n\n"],"names":["createContext","useState","useRef","useEffect","Pillar","createRoot","_jsx","useCallback","useMemo","useContext"],"mappings":";;;;;;;AA+KA;AACA;AACA;AAEA,MAAM,aAAa,GAAGA,mBAAa,CAA4B,IAAI,CAAC;AAEpE;AACA;AACA;AAEM,SAAU,cAAc,CAAC,EAC7B,UAAU,EACV,SAAS,EACT,MAAM,EACN,MAAM,EACN,KAAK,EACL,QAAQ,GACY,EAAA;IACpB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAGC,cAAQ,CAAgB,IAAI,CAAC;IACzD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAGA,cAAQ,CAAc,eAAe,CAAC;IAChE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAGA,cAAQ,CAAC,KAAK,CAAC;;AAGrD,IAAA,MAAM,SAAS,GAAGC,YAAM,CAAC,MAAM,CAAC;AAChC,IAAA,SAAS,CAAC,OAAO,GAAG,MAAM;;AAG1B,IAAA,MAAM,QAAQ,GAAGA,YAAM,CAAC,KAAK,CAAC;AAC9B,IAAA,QAAQ,CAAC,OAAO,GAAG,KAAK;;IAGxBC,eAAS,CAAC,MAAK;QACb,IAAI,OAAO,GAAG,IAAI;AAElB,QAAA,MAAM,UAAU,GAAG,YAAW;AAC5B,YAAA,IAAI;;AAEF,gBAAA,MAAM,gBAAgB,GAAGC,UAAM,CAAC,WAAW,EAAE;gBAC7C,IAAI,gBAAgB,EAAE;;oBAEpB,IAAI,OAAO,EAAE;wBACX,SAAS,CAAC,gBAAgB,CAAC;AAC3B,wBAAA,QAAQ,CAAC,gBAAgB,CAAC,KAAK,CAAC;;AAGhC,wBAAA,gBAAgB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAK;4BACrC,cAAc,CAAC,IAAI,CAAC;AACtB,wBAAA,CAAC,CAAC;AAEF,wBAAA,gBAAgB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAK;4BACtC,cAAc,CAAC,KAAK,CAAC;AACvB,wBAAA,CAAC,CAAC;oBACJ;oBACA;gBACF;;AAGA,gBAAA,MAAM,QAAQ,GAAG,MAAMA,UAAM,CAAC,IAAI,CAAC;oBACjC,UAAU;oBACV,SAAS;AACT,oBAAA,GAAG,MAAM;AACV,iBAAA,CAAC;gBAEF,IAAI,OAAO,EAAE;oBACX,SAAS,CAAC,QAAQ,CAAC;AACnB,oBAAA,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;;AAGxB,oBAAA,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAK;wBAC7B,cAAc,CAAC,IAAI,CAAC;AACtB,oBAAA,CAAC,CAAC;AAEF,oBAAA,QAAQ,CAAC,EAAE,CAAC,aAAa,EAAE,MAAK;wBAC9B,cAAc,CAAC,KAAK,CAAC;AACvB,oBAAA,CAAC,CAAC;gBACJ;YACF;YAAE,OAAO,KAAK,EAAE;AACd,gBAAA,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC;gBAC5D,IAAI,OAAO,EAAE;oBACX,QAAQ,CAAC,OAAO,CAAC;gBACnB;YACF;AACF,QAAA,CAAC;AAED,QAAA,UAAU,EAAE;;;;AAKZ,QAAA,OAAO,MAAK;YACV,OAAO,GAAG,KAAK;;;AAGjB,QAAA,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;;IAG5BD,eAAS,CAAC,MAAK;QACb,IAAI,MAAM,EAAE;YACV,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAK;gBAC1C,QAAQ,CAAC,OAAO,CAAC;AACnB,YAAA,CAAC,CAAC;YAEF,MAAM,gBAAgB,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAK;gBAC/C,QAAQ,CAAC,OAAO,CAAC;AACnB,YAAA,CAAC,CAAC;AAEF,YAAA,OAAO,MAAK;AACV,gBAAA,WAAW,EAAE;AACb,gBAAA,gBAAgB,EAAE;AACpB,YAAA,CAAC;QACH;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;;IAGZA,eAAS,CAAC,MAAK;QACb,IAAI,MAAM,EAAE;YACV,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,IAAI,KAAI;AACrD,gBAAA,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;AAC3B,YAAA,CAAC,CAAC;AAEF,YAAA,OAAO,WAAW;QACpB;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;;IAGZA,eAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK;YAAE;QAEvB,MAAM,aAAa,GAAsB,EAAE;AAC3C,QAAA,MAAM,KAAK,GAA2B,IAAI,GAAG,EAAE;;AAG/C,QAAA,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAI;AACtD,YAAA,MAAM,WAAW,GAAG,MAAM,CAAC,YAAY,CACrC,QAAQ,EACR,CAAC,SAAS,EAAE,IAAI,EAAE,SAAwB,KAAI;;AAE5C,gBAAA,MAAM,IAAI,GAAGE,iBAAU,CAAC,SAAS,CAAC;AAClC,gBAAA,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC;;AAG1B,gBAAA,IAAI,CAAC,MAAM,CACTC,cAAA,CAAC,SAAS,EAAA,EACR,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,CAAC,SAAS,EAC9B,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAC5B,aAAa,EAAE,SAAS,CAAC,aAAa,EAAA,CACtC,CACH;;AAGD,gBAAA,OAAO,MAAK;oBACV,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;oBACzC,IAAI,YAAY,EAAE;wBAChB,YAAY,CAAC,OAAO,EAAE;AACtB,wBAAA,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;oBACzB;AACF,gBAAA,CAAC;AACH,YAAA,CAAC,CACF;AAED,YAAA,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC;AACjC,QAAA,CAAC,CAAC;AAEF,QAAA,OAAO,MAAK;;YAEV,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;;AAEzC,YAAA,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;YACvC,KAAK,CAAC,KAAK,EAAE;AACf,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;;AAGnB,IAAA,MAAM,IAAI,GAAGC,iBAAW,CACtB,CAAC,OAKA,KAAI;AACH,QAAA,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC;AACvB,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;AAED,IAAA,MAAM,KAAK,GAAGA,iBAAW,CAAC,MAAK;QAC7B,MAAM,EAAE,KAAK,EAAE;AACjB,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;AAEZ,IAAA,MAAM,MAAM,GAAGA,iBAAW,CAAC,MAAK;QAC9B,MAAM,EAAE,MAAM,EAAE;AAClB,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;AAEZ,IAAA,MAAM,WAAW,GAAGA,iBAAW,CAC7B,CAAC,IAAY,KAAI;QACf,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACjC,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;IAED,MAAM,YAAY,GAAGA,iBAAW,CAC9B,OAAO,IAAY,KAAI;QACrB,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC;AACxC,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;AAED,IAAA,MAAM,MAAM,GAAGA,iBAAW,CACxB,CAAC,KAAa,KAAI;QAChB,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACjC,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;IAED,MAAM,QAAQ,GAAGA,iBAAW,CAC1B,CAAC,IAAY,EAAE,MAA+B,KAAI;AAChD,QAAA,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;AAChC,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;AAED,IAAA,MAAM,QAAQ,GAAGA,iBAAW,CAC1B,CAAC,KAA2B,KAAI;AAC9B,QAAA,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC;AACzB,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;AAED,IAAA,MAAM,uBAAuB,GAAGA,iBAAW,CACzC,CAAC,OAAgB,KAAI;AACnB,QAAA,MAAM,EAAE,uBAAuB,CAAC,OAAO,CAAC;AAC1C,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;IAED,MAAM,EAAE,GAAGA,iBAAW,CACpB,CACE,KAAQ,EACR,QAAyC,KACvC;AACF,QAAA,OAAO,MAAM,EAAE,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,MAAK,EAAE,CAAC,CAAC;AAClD,IAAA,CAAC,EACD,CAAC,MAAM,CAAC,CACT;;AAGD,IAAA,MAAM,KAAK,GAAGC,aAAO,CACnB,OAAO;QACL,MAAM;QACN,KAAK;QACL,OAAO,EAAE,KAAK,KAAK,OAAO;QAC1B,WAAW;QACX,IAAI;QACJ,KAAK;QACL,MAAM;QACN,WAAW;QACX,YAAY;QACZ,MAAM;QACN,QAAQ;QACR,QAAQ;QACR,uBAAuB;QACvB,EAAE;AACH,KAAA,CAAC,EACF;QACE,MAAM;QACN,KAAK;QACL,WAAW;QACX,IAAI;QACJ,KAAK;QACL,MAAM;QACN,WAAW;QACX,YAAY;QACZ,MAAM;QACN,QAAQ;QACR,QAAQ;QACR,uBAAuB;QACvB,EAAE;AACH,KAAA,CACF;AAED,IAAA,QACEF,cAAA,CAAC,aAAa,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,KAAK,EAAA,QAAA,EAAG,QAAQ,EAAA,CAA0B;AAE7E;AAEA;AACA;AACA;SAEgB,gBAAgB,GAAA;AAC9B,IAAA,MAAM,OAAO,GAAGG,gBAAU,CAAC,aAAa,CAAC;IAEzC,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC;IAC1E;AAEA,IAAA,OAAO,OAAO;AAChB;;AC1cA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACG,SAAU,WAAW,CAAC,EAC1B,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACS,EAAA;AACjB,IAAA,MAAM,YAAY,GAAGP,YAAM,CAAiB,IAAI,CAAC;IACjD,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,EAAE;AAC9C,IAAA,MAAM,UAAU,GAAGA,YAAM,CAAC,KAAK,CAAC;IAEhCC,eAAS,CAAC,MAAK;;AAEb,QAAA,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,UAAU,CAAC,OAAO,EAAE;YACtE;QACF;;AAGA,QAAA,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,OAAO,CAAC;AACzC,QAAA,UAAU,CAAC,OAAO,GAAG,IAAI;;AAG3B,IAAA,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAErB,IAAA,QACEG,cAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EAAA,6BAAA,EACgB,EAAE,KAC1B,KAAK,EAAA,CACT;AAEN;;ACtEA;;;AAGG;AA+BH;;;;;;;;;;;;;;;;;;;;AAoBG;SACa,YAAY,GAAA;IAC1B,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,gBAAgB,EAAE;AAE5G,IAAA,MAAM,UAAU,GAAGC,iBAAW,CAC5B,CAAC,KAAc,KAAI;QACjB,IAAI,KAAK,EAAE;YACT,MAAM,CAAC,KAAK,CAAC;QACf;aAAO;AACL,YAAA,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC1B;AACF,IAAA,CAAC,EACD,CAAC,MAAM,EAAE,IAAI,CAAC,CACf;AAED,IAAA,MAAM,QAAQ,GAAGA,iBAAW,CAAC,MAAK;QAChC,QAAQ,CAAC,MAAM,CAAC;AAClB,IAAA,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAEd,OAAO;AACL,QAAA,MAAM,EAAE,WAAW;QACnB,IAAI;QACJ,KAAK;QACL,MAAM;QACN,WAAW;QACX,YAAY;QACZ,UAAU;QACV,QAAQ;KACT;AACH;;ACnFA;;;AAGG;AAmCH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;SACa,SAAS,GAAA;AAGvB,IAAA,MAAM,OAAO,GAAG,gBAAgB,EAAE;;IAGlC,MAAM,MAAM,GAAGA,iBAAW,CACxB,CACE,QAAe,EACf,OAAwD,KACxC;AAChB,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;;AAEnB,YAAA,OAAO,MAAK,EAAE,CAAC;QACjB;;;QAGA,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,CAC1B,QAAkB,EAClB,OAAkD,CACnD;AACH,IAAA,CAAC,EACD,CAAC,OAAO,CAAC,MAAM,CAAC,CACjB;IAED,OAAO;AACL,QAAA,GAAG,OAAO;QACV,MAAM;KACP;AACH;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pillar-ai/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "React bindings for Pillar Embedded Help SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.esm.js",
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"license": "MIT",
|
|
38
38
|
"repository": {
|
|
39
39
|
"type": "git",
|
|
40
|
-
"url": "https://github.com/
|
|
40
|
+
"url": "https://github.com/pillarhq/sdk-react",
|
|
41
41
|
"directory": "packages/sdk-react"
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://trypillar.com",
|
|
44
44
|
"bugs": {
|
|
45
|
-
"url": "https://github.com/
|
|
45
|
+
"url": "https://github.com/pillarhq/sdk-react/issues"
|
|
46
46
|
},
|
|
47
47
|
"publishConfig": {
|
|
48
48
|
"access": "public"
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"react-dom": ">=17.0.0 || >=19.0.0"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@pillar-ai/sdk": "^0.1.
|
|
55
|
+
"@pillar-ai/sdk": "^0.1.7"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@rollup/plugin-commonjs": "^25.0.7",
|
package/dist/HelpButton.d.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HelpButton Component
|
|
3
|
-
* Pre-styled button to open the help panel
|
|
4
|
-
*
|
|
5
|
-
* Styling follows the dual-class pattern:
|
|
6
|
-
* - Internal class (_pillar-help-btn): Contains default styles
|
|
7
|
-
* - Public class (pillar-help-btn): Empty by default, for user overrides
|
|
8
|
-
*
|
|
9
|
-
* Supports CSS variable customization:
|
|
10
|
-
* - --pillar-btn-primary-bg
|
|
11
|
-
* - --pillar-btn-primary-color
|
|
12
|
-
* - --pillar-btn-secondary-bg
|
|
13
|
-
* - --pillar-btn-secondary-color
|
|
14
|
-
* - --pillar-btn-ghost-color
|
|
15
|
-
* - --pillar-btn-radius
|
|
16
|
-
* - --pillar-btn-font-family
|
|
17
|
-
*/
|
|
18
|
-
import { type ButtonHTMLAttributes, type ReactNode } from 'react';
|
|
19
|
-
export interface HelpButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> {
|
|
20
|
-
/** Button content - defaults to "Help" */
|
|
21
|
-
children?: ReactNode;
|
|
22
|
-
/** What to open when clicked */
|
|
23
|
-
action?: 'toggle' | 'open' | 'chat' | 'search';
|
|
24
|
-
/** Initial search query (when action is 'search') */
|
|
25
|
-
searchQuery?: string;
|
|
26
|
-
/** Article slug to open (when action is 'open') */
|
|
27
|
-
articleSlug?: string;
|
|
28
|
-
/** Custom click handler (overrides action) */
|
|
29
|
-
onClick?: () => void;
|
|
30
|
-
/** Visual variant */
|
|
31
|
-
variant?: 'primary' | 'secondary' | 'ghost';
|
|
32
|
-
/** Button size */
|
|
33
|
-
size?: 'sm' | 'md' | 'lg';
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Pre-styled help button that integrates with Pillar
|
|
37
|
-
*
|
|
38
|
-
* Uses CSS classes for styling with CSS variable support:
|
|
39
|
-
* - Internal classes (_pillar-help-btn-*): Default styles
|
|
40
|
-
* - Public classes (pillar-help-btn-*): For user overrides
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```tsx
|
|
44
|
-
* // Basic usage
|
|
45
|
-
* <HelpButton>Get Help</HelpButton>
|
|
46
|
-
*
|
|
47
|
-
* // Open chat directly
|
|
48
|
-
* <HelpButton action="chat">Ask AI</HelpButton>
|
|
49
|
-
*
|
|
50
|
-
* // Search with query
|
|
51
|
-
* <HelpButton action="search" searchQuery="getting started">
|
|
52
|
-
* Search Help
|
|
53
|
-
* </HelpButton>
|
|
54
|
-
*
|
|
55
|
-
* // Customize via CSS variables
|
|
56
|
-
* // :root { --pillar-btn-primary-bg: #8b5cf6; }
|
|
57
|
-
*
|
|
58
|
-
* // Or via public class overrides
|
|
59
|
-
* // .pillar-help-btn--primary { background: #8b5cf6; }
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
|
-
export declare function HelpButton({ children, action, searchQuery, articleSlug, onClick: customOnClick, variant, size, style, disabled, className, ...props }: HelpButtonProps): JSX.Element;
|
package/dist/Tooltip.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tooltip Component
|
|
3
|
-
* Wrapper component that adds tooltip functionality to children
|
|
4
|
-
*/
|
|
5
|
-
import React, { type ReactNode, type CSSProperties } from 'react';
|
|
6
|
-
export interface TooltipProps {
|
|
7
|
-
/** Unique tooltip ID that matches a tooltip in your Pillar dashboard */
|
|
8
|
-
tooltipId: string;
|
|
9
|
-
/** Trigger behavior: hover, click, focus, or icon (shows info icon) */
|
|
10
|
-
trigger?: 'hover' | 'click' | 'focus' | 'icon';
|
|
11
|
-
/** Tooltip position relative to the target */
|
|
12
|
-
position?: 'top' | 'bottom' | 'left' | 'right' | 'auto';
|
|
13
|
-
/** Children elements to attach the tooltip to */
|
|
14
|
-
children: ReactNode;
|
|
15
|
-
/** Additional class name for the wrapper */
|
|
16
|
-
className?: string;
|
|
17
|
-
/** Additional inline styles for the wrapper */
|
|
18
|
-
style?: CSSProperties;
|
|
19
|
-
/** Whether the wrapper should be a span (inline) or div (block) */
|
|
20
|
-
inline?: boolean;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Tooltip wrapper component that adds Pillar tooltip functionality to children
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```tsx
|
|
27
|
-
* <Tooltip tooltipId="feature-explanation" trigger="hover">
|
|
28
|
-
* <button>Learn More</button>
|
|
29
|
-
* </Tooltip>
|
|
30
|
-
* ```
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* ```tsx
|
|
34
|
-
* <Tooltip tooltipId="input-help" trigger="icon">
|
|
35
|
-
* <label>Email Address</label>
|
|
36
|
-
* </Tooltip>
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export declare function Tooltip({ tooltipId, trigger, position, children, className, style, inline, }: TooltipProps): React.ReactElement;
|