@pillar-ai/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,398 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { Pillar } from '@pillar-ai/sdk';
3
+ import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
4
+ import { createRoot } from 'react-dom/client';
5
+
6
+ // ============================================================================
7
+ // Context
8
+ // ============================================================================
9
+ const PillarContext = createContext(null);
10
+ // ============================================================================
11
+ // Provider Component
12
+ // ============================================================================
13
+ function PillarProvider({ helpCenter, publicKey, config, onTask, cards, children, }) {
14
+ const [pillar, setPillar] = useState(null);
15
+ const [state, setState] = useState('uninitialized');
16
+ const [isPanelOpen, setIsPanelOpen] = useState(false);
17
+ // Keep a ref to the latest onTask callback to avoid re-subscribing
18
+ const onTaskRef = useRef(onTask);
19
+ onTaskRef.current = onTask;
20
+ // Keep a ref to cards to access latest versions
21
+ const cardsRef = useRef(cards);
22
+ cardsRef.current = cards;
23
+ // Initialize SDK
24
+ useEffect(() => {
25
+ let mounted = true;
26
+ const initPillar = async () => {
27
+ try {
28
+ // Pillar is a singleton - check if already initialized
29
+ const existingInstance = Pillar.getInstance();
30
+ if (existingInstance) {
31
+ // Reuse existing instance (preserves chat history, panel state, etc.)
32
+ if (mounted) {
33
+ setPillar(existingInstance);
34
+ setState(existingInstance.state);
35
+ // Re-subscribe to events
36
+ existingInstance.on('panel:open', () => {
37
+ setIsPanelOpen(true);
38
+ });
39
+ existingInstance.on('panel:close', () => {
40
+ setIsPanelOpen(false);
41
+ });
42
+ }
43
+ return;
44
+ }
45
+ // Initialize new instance
46
+ const instance = await Pillar.init({
47
+ helpCenter,
48
+ publicKey,
49
+ ...config,
50
+ });
51
+ if (mounted) {
52
+ setPillar(instance);
53
+ setState(instance.state);
54
+ // Listen for panel open/close
55
+ instance.on('panel:open', () => {
56
+ setIsPanelOpen(true);
57
+ });
58
+ instance.on('panel:close', () => {
59
+ setIsPanelOpen(false);
60
+ });
61
+ }
62
+ }
63
+ catch (error) {
64
+ console.error('[Pillar React] Failed to initialize:', error);
65
+ if (mounted) {
66
+ setState('error');
67
+ }
68
+ }
69
+ };
70
+ initPillar();
71
+ // Cleanup - DON'T destroy the singleton on unmount
72
+ // This preserves conversation history and panel state across navigation
73
+ // Pillar.destroy() should only be called explicitly when the app unmounts completely
74
+ return () => {
75
+ mounted = false;
76
+ // Note: We intentionally don't call Pillar.destroy() here
77
+ // The singleton persists to maintain state across route changes
78
+ };
79
+ }, [helpCenter, publicKey]); // Re-initialize if credentials change
80
+ // Update state when SDK state changes
81
+ useEffect(() => {
82
+ if (pillar) {
83
+ const unsubscribe = pillar.on('ready', () => {
84
+ setState('ready');
85
+ });
86
+ const unsubscribeError = pillar.on('error', () => {
87
+ setState('error');
88
+ });
89
+ return () => {
90
+ unsubscribe();
91
+ unsubscribeError();
92
+ };
93
+ }
94
+ }, [pillar]);
95
+ // Register task handler
96
+ useEffect(() => {
97
+ if (pillar) {
98
+ const unsubscribe = pillar.on('task:execute', (task) => {
99
+ onTaskRef.current?.(task);
100
+ });
101
+ return unsubscribe;
102
+ }
103
+ }, [pillar]);
104
+ // Register custom card renderers
105
+ useEffect(() => {
106
+ if (!pillar || !cards)
107
+ return;
108
+ const unsubscribers = [];
109
+ const roots = new Map();
110
+ // Register each card component as a vanilla renderer
111
+ Object.entries(cards).forEach(([cardType, Component]) => {
112
+ const unsubscribe = pillar.registerCard(cardType, (container, data, callbacks) => {
113
+ // Create a React root for this container
114
+ const root = createRoot(container);
115
+ roots.set(container, root);
116
+ // Render the React component
117
+ root.render(jsx(Component, { data: data, onConfirm: callbacks.onConfirm, onCancel: callbacks.onCancel, onStateChange: callbacks.onStateChange }));
118
+ // Return cleanup function
119
+ return () => {
120
+ const existingRoot = roots.get(container);
121
+ if (existingRoot) {
122
+ existingRoot.unmount();
123
+ roots.delete(container);
124
+ }
125
+ };
126
+ });
127
+ unsubscribers.push(unsubscribe);
128
+ });
129
+ return () => {
130
+ // Cleanup all registrations
131
+ unsubscribers.forEach(unsub => unsub());
132
+ // Unmount all React roots
133
+ roots.forEach(root => root.unmount());
134
+ roots.clear();
135
+ };
136
+ }, [pillar, cards]);
137
+ // Actions
138
+ const open = useCallback((options) => {
139
+ pillar?.open(options);
140
+ }, [pillar]);
141
+ const close = useCallback(() => {
142
+ pillar?.close();
143
+ }, [pillar]);
144
+ const toggle = useCallback(() => {
145
+ pillar?.toggle();
146
+ }, [pillar]);
147
+ const openArticle = useCallback((slug) => {
148
+ pillar?.open({ article: slug });
149
+ }, [pillar]);
150
+ const openCategory = useCallback(async (slug) => {
151
+ pillar?.navigate('category', { slug });
152
+ }, [pillar]);
153
+ const search = useCallback((query) => {
154
+ pillar?.open({ search: query });
155
+ }, [pillar]);
156
+ const navigate = useCallback((view, params) => {
157
+ pillar?.navigate(view, params);
158
+ }, [pillar]);
159
+ const setTheme = useCallback((theme) => {
160
+ pillar?.setTheme(theme);
161
+ }, [pillar]);
162
+ const setTextSelectionEnabled = useCallback((enabled) => {
163
+ pillar?.setTextSelectionEnabled(enabled);
164
+ }, [pillar]);
165
+ const on = useCallback((event, callback) => {
166
+ return pillar?.on(event, callback) ?? (() => { });
167
+ }, [pillar]);
168
+ // Context value
169
+ const value = useMemo(() => ({
170
+ pillar,
171
+ state,
172
+ isReady: state === 'ready',
173
+ isPanelOpen,
174
+ open,
175
+ close,
176
+ toggle,
177
+ openArticle,
178
+ openCategory,
179
+ search,
180
+ navigate,
181
+ setTheme,
182
+ setTextSelectionEnabled,
183
+ on,
184
+ }), [pillar, state, isPanelOpen, open, close, toggle, openArticle, openCategory, search, navigate, setTheme, setTextSelectionEnabled, on]);
185
+ return (jsx(PillarContext.Provider, { value: value, children: children }));
186
+ }
187
+ // ============================================================================
188
+ // Hook
189
+ // ============================================================================
190
+ function usePillarContext() {
191
+ const context = useContext(PillarContext);
192
+ if (!context) {
193
+ throw new Error('usePillarContext must be used within a PillarProvider');
194
+ }
195
+ return context;
196
+ }
197
+
198
+ /**
199
+ * Renders the Pillar help panel at a custom location in the DOM.
200
+ * Use this when you want to control where the panel is rendered instead of
201
+ * having it automatically appended to document.body.
202
+ *
203
+ * **Important**: When using this component, set `panel.container: 'manual'` in your
204
+ * PillarProvider config to prevent automatic mounting.
205
+ *
206
+ * @example
207
+ * ```tsx
208
+ * <PillarProvider
209
+ * helpCenter="my-help"
210
+ * publicKey="pk_xxx"
211
+ * config={{ panel: { container: 'manual' } }}
212
+ * >
213
+ * <div className="my-layout">
214
+ * <Sidebar />
215
+ * <PillarPanel className="help-panel-container" />
216
+ * <MainContent />
217
+ * </div>
218
+ * </PillarProvider>
219
+ * ```
220
+ */
221
+ function PillarPanel({ className, style, ...props }) {
222
+ const containerRef = useRef(null);
223
+ const { pillar, isReady } = usePillarContext();
224
+ const hasMounted = useRef(false);
225
+ useEffect(() => {
226
+ // Only mount once when SDK is ready and we have a container
227
+ if (!isReady || !pillar || !containerRef.current || hasMounted.current) {
228
+ return;
229
+ }
230
+ // Mount the panel into our container
231
+ pillar.mountPanelTo(containerRef.current);
232
+ hasMounted.current = true;
233
+ // Cleanup is handled by Pillar.destroy() in the provider
234
+ }, [isReady, pillar]);
235
+ return (jsx("div", { ref: containerRef, className: className, style: style, "data-pillar-panel-container": "", ...props }));
236
+ }
237
+
238
+ /**
239
+ * Tooltip wrapper component that adds Pillar tooltip functionality to children
240
+ *
241
+ * @example
242
+ * ```tsx
243
+ * <Tooltip tooltipId="feature-explanation" trigger="hover">
244
+ * <button>Learn More</button>
245
+ * </Tooltip>
246
+ * ```
247
+ *
248
+ * @example
249
+ * ```tsx
250
+ * <Tooltip tooltipId="input-help" trigger="icon">
251
+ * <label>Email Address</label>
252
+ * </Tooltip>
253
+ * ```
254
+ */
255
+ function Tooltip({ tooltipId, trigger = 'hover', position = 'auto', children, className, style, inline = true, }) {
256
+ const { pillar, isReady } = usePillarContext();
257
+ const wrapperRef = useRef(null);
258
+ // Set data attributes when component mounts or props change
259
+ useEffect(() => {
260
+ if (wrapperRef.current) {
261
+ wrapperRef.current.setAttribute('data-pillar-tooltip', tooltipId);
262
+ if (trigger !== 'hover') {
263
+ wrapperRef.current.setAttribute('data-pillar-trigger', trigger);
264
+ }
265
+ else {
266
+ wrapperRef.current.removeAttribute('data-pillar-trigger');
267
+ }
268
+ if (position !== 'auto') {
269
+ wrapperRef.current.setAttribute('data-pillar-position', position);
270
+ }
271
+ else {
272
+ wrapperRef.current.removeAttribute('data-pillar-position');
273
+ }
274
+ }
275
+ }, [tooltipId, trigger, position]);
276
+ // Trigger rescan when component mounts (in case it's added dynamically)
277
+ useEffect(() => {
278
+ if (isReady && pillar) {
279
+ // Small delay to ensure DOM is ready
280
+ const timeout = setTimeout(() => {
281
+ pillar.scanTooltips();
282
+ }, 100);
283
+ return () => clearTimeout(timeout);
284
+ }
285
+ }, [isReady, pillar, tooltipId]);
286
+ const Component = inline ? 'span' : 'div';
287
+ return (jsx(Component, { ref: wrapperRef, className: className, style: style, children: children }));
288
+ }
289
+
290
+ /**
291
+ * useHelpPanel Hook
292
+ * Panel-specific controls and state
293
+ */
294
+ /**
295
+ * Hook for panel-specific controls
296
+ *
297
+ * @example
298
+ * ```tsx
299
+ * function HelpButton() {
300
+ * const { isOpen, toggle, openChat } = useHelpPanel();
301
+ *
302
+ * return (
303
+ * <div>
304
+ * <button onClick={toggle}>
305
+ * {isOpen ? 'Close' : 'Help'}
306
+ * </button>
307
+ * <button onClick={openChat}>
308
+ * Ask AI
309
+ * </button>
310
+ * </div>
311
+ * );
312
+ * }
313
+ * ```
314
+ */
315
+ function useHelpPanel() {
316
+ const { isPanelOpen, open, close, toggle, openArticle, openCategory, search, navigate } = usePillarContext();
317
+ const openSearch = useCallback((query) => {
318
+ if (query) {
319
+ search(query);
320
+ }
321
+ else {
322
+ open({ view: 'search' });
323
+ }
324
+ }, [search, open]);
325
+ const openChat = useCallback(() => {
326
+ navigate('chat');
327
+ }, [navigate]);
328
+ return {
329
+ isOpen: isPanelOpen,
330
+ open,
331
+ close,
332
+ toggle,
333
+ openArticle,
334
+ openCategory,
335
+ openSearch,
336
+ openChat,
337
+ };
338
+ }
339
+
340
+ /**
341
+ * usePillar Hook
342
+ * Access Pillar SDK instance and state with optional type-safe onTask
343
+ */
344
+ /**
345
+ * Hook to access the Pillar SDK instance and state
346
+ *
347
+ * @example Basic usage (untyped)
348
+ * ```tsx
349
+ * function MyComponent() {
350
+ * const { isReady, open, close, isPanelOpen } = usePillar();
351
+ *
352
+ * if (!isReady) return <div>Loading...</div>;
353
+ *
354
+ * return (
355
+ * <button onClick={() => open()}>
356
+ * {isPanelOpen ? 'Close Help' : 'Get Help'}
357
+ * </button>
358
+ * );
359
+ * }
360
+ * ```
361
+ *
362
+ * @example Type-safe onTask with action definitions
363
+ * ```tsx
364
+ * import { actions } from '@/lib/pillar/actions';
365
+ *
366
+ * function MyComponent() {
367
+ * const { pillar, onTask } = usePillar<typeof actions>();
368
+ *
369
+ * useEffect(() => {
370
+ * // TypeScript knows data has { type, url, name }
371
+ * const unsub = onTask('add_new_source', (data) => {
372
+ * console.log(data.url); // ✓ Typed!
373
+ * });
374
+ * return unsub;
375
+ * }, [onTask]);
376
+ * }
377
+ * ```
378
+ */
379
+ function usePillar() {
380
+ const context = usePillarContext();
381
+ // Create a type-safe wrapper around pillar.onTask
382
+ const onTask = useCallback((taskName, handler) => {
383
+ if (!context.pillar) {
384
+ // Return no-op if pillar not ready
385
+ return () => { };
386
+ }
387
+ // Cast handler to match the SDK's expected type
388
+ // The runtime behavior is the same, this is just for type narrowing
389
+ return context.pillar.onTask(taskName, handler);
390
+ }, [context.pillar]);
391
+ return {
392
+ ...context,
393
+ onTask,
394
+ };
395
+ }
396
+
397
+ export { PillarPanel, PillarProvider, Tooltip, useHelpPanel, usePillar, usePillarContext };
398
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/PillarProvider.tsx","../src/PillarPanel.tsx","../src/Tooltip.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 * Tooltip Component\n * Wrapper component that adds tooltip functionality to children\n */\n\nimport React, { useRef, useEffect, type ReactNode, type CSSProperties } from 'react';\nimport { usePillarContext } from './PillarProvider';\n\nexport interface TooltipProps {\n /** Unique tooltip ID that matches a tooltip in your Pillar dashboard */\n tooltipId: string;\n \n /** Trigger behavior: hover, click, focus, or icon (shows info icon) */\n trigger?: 'hover' | 'click' | 'focus' | 'icon';\n \n /** Tooltip position relative to the target */\n position?: 'top' | 'bottom' | 'left' | 'right' | 'auto';\n \n /** Children elements to attach the tooltip to */\n children: ReactNode;\n \n /** Additional class name for the wrapper */\n className?: string;\n \n /** Additional inline styles for the wrapper */\n style?: CSSProperties;\n \n /** Whether the wrapper should be a span (inline) or div (block) */\n inline?: boolean;\n}\n\n/**\n * Tooltip wrapper component that adds Pillar tooltip functionality to children\n * \n * @example\n * ```tsx\n * <Tooltip tooltipId=\"feature-explanation\" trigger=\"hover\">\n * <button>Learn More</button>\n * </Tooltip>\n * ```\n * \n * @example\n * ```tsx\n * <Tooltip tooltipId=\"input-help\" trigger=\"icon\">\n * <label>Email Address</label>\n * </Tooltip>\n * ```\n */\nexport function Tooltip({\n tooltipId,\n trigger = 'hover',\n position = 'auto',\n children,\n className,\n style,\n inline = true,\n}: TooltipProps): React.ReactElement {\n const { pillar, isReady } = usePillarContext();\n const wrapperRef = useRef<HTMLElement>(null);\n\n // Set data attributes when component mounts or props change\n useEffect(() => {\n if (wrapperRef.current) {\n wrapperRef.current.setAttribute('data-pillar-tooltip', tooltipId);\n \n if (trigger !== 'hover') {\n wrapperRef.current.setAttribute('data-pillar-trigger', trigger);\n } else {\n wrapperRef.current.removeAttribute('data-pillar-trigger');\n }\n \n if (position !== 'auto') {\n wrapperRef.current.setAttribute('data-pillar-position', position);\n } else {\n wrapperRef.current.removeAttribute('data-pillar-position');\n }\n }\n }, [tooltipId, trigger, position]);\n\n // Trigger rescan when component mounts (in case it's added dynamically)\n useEffect(() => {\n if (isReady && pillar) {\n // Small delay to ensure DOM is ready\n const timeout = setTimeout(() => {\n pillar.scanTooltips();\n }, 100);\n \n return () => clearTimeout(timeout);\n }\n }, [isReady, pillar, tooltipId]);\n\n const Component = inline ? 'span' : 'div';\n\n return (\n <Component\n ref={wrapperRef as React.RefObject<HTMLSpanElement & HTMLDivElement>}\n className={className}\n style={style}\n >\n {children}\n </Component>\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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"}