@foxpixel/react 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode, ComponentType } from 'react';
2
+ import React, { ReactNode, ComponentType } from 'react';
3
+ import { QueryClient } from '@tanstack/react-query';
3
4
  import { AxiosInstance, AxiosRequestConfig } from 'axios';
4
5
 
5
6
  /**
@@ -137,10 +138,14 @@ declare class FoxPixelHttpClient {
137
138
  interface FoxPixelContextValue {
138
139
  client: FoxPixelHttpClient;
139
140
  config: FoxPixelConfig;
141
+ /** Optional: pass QueryClient so edit-mode messaging can invalidate cache without requiring useQueryClient() in SDK (avoids "No QueryClient set" in iframe). */
142
+ queryClient?: QueryClient | null;
140
143
  }
141
144
  interface FoxPixelProviderProps {
142
145
  children: ReactNode;
143
146
  config?: FoxPixelConfig;
147
+ /** Pass the app's QueryClient so edit-mode (iframe) can update cache on FOXPIXEL_CONTENT_UPDATED. Required for visual editor preview to refresh. */
148
+ queryClient?: QueryClient | null;
144
149
  }
145
150
  /**
146
151
  * FoxPixelProvider - Wraps your app and provides SDK functionality
@@ -163,7 +168,7 @@ interface FoxPixelProviderProps {
163
168
  * }
164
169
  * ```
165
170
  */
166
- declare function FoxPixelProvider({ children, config }: FoxPixelProviderProps): react_jsx_runtime.JSX.Element;
171
+ declare function FoxPixelProvider({ children, config, queryClient }: FoxPixelProviderProps): react_jsx_runtime.JSX.Element;
167
172
  /**
168
173
  * Hook to access FoxPixel context
169
174
  * @throws Error if used outside FoxPixelProvider
@@ -188,6 +193,8 @@ interface AuthContextValue {
188
193
  phone?: string;
189
194
  }) => Promise<void>;
190
195
  refetch: () => Promise<void>;
196
+ /** Stub: returns true when user is logged in and permission is site:content:update. */
197
+ hasPermission: (permission: string) => boolean;
191
198
  }
192
199
  interface AuthProviderProps {
193
200
  children: ReactNode;
@@ -261,6 +268,55 @@ interface WithAuthOptions {
261
268
  }
262
269
  declare function withAuth<P extends object>(Component: ComponentType<P>, options?: WithAuthOptions): (props: P) => string | number | true | Iterable<ReactNode> | react_jsx_runtime.JSX.Element | null;
263
270
 
271
+ interface EditableProps {
272
+ contentKey: string;
273
+ defaultValue: string;
274
+ as?: keyof JSX.IntrinsicElements;
275
+ multiline?: boolean;
276
+ className?: string;
277
+ }
278
+ declare function Editable({ contentKey, defaultValue, as, multiline, className, }: EditableProps): React.ReactElement<{
279
+ className: string;
280
+ 'aria-busy': boolean;
281
+ 'aria-label': string;
282
+ }, string | React.JSXElementConstructor<any>> | React.DetailedReactHTMLElement<{
283
+ onMouseEnter: () => void;
284
+ onMouseLeave: () => void;
285
+ style: React.CSSProperties;
286
+ } | {
287
+ onMouseEnter?: undefined;
288
+ onMouseLeave?: undefined;
289
+ style: React.CSSProperties;
290
+ }, HTMLElement>;
291
+ /**
292
+ * Renders rich HTML content from the CMS. Content is sanitized before rendering.
293
+ */
294
+ declare function EditableHTML({ contentKey, defaultValue, as, className, }: Omit<EditableProps, 'multiline'>): React.ReactElement<{
295
+ className: string;
296
+ 'aria-busy': boolean;
297
+ }, string | React.JSXElementConstructor<any>> | React.DetailedReactHTMLElement<{
298
+ onMouseEnter: () => void;
299
+ onMouseLeave: () => void;
300
+ style: React.CSSProperties;
301
+ } | {
302
+ onMouseEnter?: undefined;
303
+ onMouseLeave?: undefined;
304
+ style: React.CSSProperties;
305
+ }, HTMLElement>;
306
+ interface EditableImageProps {
307
+ contentKey: string;
308
+ defaultValue: string;
309
+ alt: string;
310
+ className?: string;
311
+ width?: number;
312
+ height?: number;
313
+ priority?: boolean;
314
+ }
315
+ /**
316
+ * Renders an image from a CMS-managed URL. Uses native img (no Next.js Image in SDK).
317
+ */
318
+ declare function EditableImage({ contentKey, defaultValue, alt, className, width, height, priority, }: EditableImageProps): react_jsx_runtime.JSX.Element;
319
+
264
320
  /**
265
321
  * Hook to fetch and manage services (Projects module)
266
322
  */
@@ -405,6 +461,254 @@ interface UseContactCaptureReturn {
405
461
  */
406
462
  declare function useContactCapture(): UseContactCaptureReturn;
407
463
 
464
+ /**
465
+ * Hook for managing editable site content (CMS Visual)
466
+ *
467
+ * Allows non-developers to edit text content directly on the site.
468
+ */
469
+
470
+ interface SiteContent {
471
+ id: string;
472
+ contentKey: string;
473
+ value: string | null;
474
+ contentType: string;
475
+ defaultValue: string | null;
476
+ description: string | null;
477
+ section: string | null;
478
+ sortOrder: number;
479
+ isActive: boolean;
480
+ updatedAt: string | null;
481
+ }
482
+ interface UseSiteContentOptions {
483
+ /**
484
+ * Default value to use if content is not found
485
+ */
486
+ defaultValue?: string;
487
+ /**
488
+ * Whether to fetch on mount (default: true)
489
+ */
490
+ fetchOnMount?: boolean;
491
+ }
492
+ interface UseSiteContentReturn {
493
+ /**
494
+ * The content object (null if not found or loading)
495
+ */
496
+ data: SiteContent | null;
497
+ /**
498
+ * The content value (or defaultValue if not found)
499
+ */
500
+ value: string;
501
+ /**
502
+ * Whether content is being loaded
503
+ */
504
+ isLoading: boolean;
505
+ /**
506
+ * Error if request failed
507
+ */
508
+ error: ApiError$1 | null;
509
+ /**
510
+ * Whether the current user can edit this content
511
+ */
512
+ canEdit: boolean;
513
+ /**
514
+ * Update the content value
515
+ */
516
+ update: (newValue: string) => Promise<void>;
517
+ /**
518
+ * Refetch the content
519
+ */
520
+ refetch: () => Promise<void>;
521
+ }
522
+ /**
523
+ * Hook for managing a single site content key.
524
+ *
525
+ * @example
526
+ * ```tsx
527
+ * function HeroSection() {
528
+ * const { value, canEdit, update } = useSiteContent('hero.title', {
529
+ * defaultValue: 'Welcome to our site'
530
+ * });
531
+ *
532
+ * const [isEditing, setIsEditing] = useState(false);
533
+ * const [editValue, setEditValue] = useState(value);
534
+ *
535
+ * const handleSave = async () => {
536
+ * await update(editValue);
537
+ * setIsEditing(false);
538
+ * };
539
+ *
540
+ * if (canEdit && isEditing) {
541
+ * return (
542
+ * <input
543
+ * value={editValue}
544
+ * onChange={(e) => setEditValue(e.target.value)}
545
+ * onBlur={handleSave}
546
+ * />
547
+ * );
548
+ * }
549
+ *
550
+ * return (
551
+ * <h1 onClick={() => canEdit && setIsEditing(true)}>
552
+ * {value}
553
+ * </h1>
554
+ * );
555
+ * }
556
+ * ```
557
+ */
558
+ declare function useSiteContent(contentKey: string, options?: UseSiteContentOptions): UseSiteContentReturn;
559
+ interface UseSiteContentsOptions {
560
+ /**
561
+ * Default values map
562
+ */
563
+ defaults?: Record<string, string>;
564
+ }
565
+ interface UseSiteContentsReturn {
566
+ /**
567
+ * Map of content key to content object
568
+ */
569
+ data: Record<string, SiteContent>;
570
+ /**
571
+ * Get value by key (with default fallback)
572
+ */
573
+ getValue: (key: string, defaultValue?: string) => string;
574
+ /**
575
+ * Whether contents are being loaded
576
+ */
577
+ isLoading: boolean;
578
+ /**
579
+ * Error if request failed
580
+ */
581
+ error: ApiError$1 | null;
582
+ /**
583
+ * Refetch all contents
584
+ */
585
+ refetch: () => Promise<void>;
586
+ }
587
+ /**
588
+ * Hook for fetching multiple site content keys at once.
589
+ * More efficient than calling useSiteContent multiple times.
590
+ *
591
+ * @example
592
+ * ```tsx
593
+ * function Footer() {
594
+ * const { getValue, isLoading } = useSiteContents(
595
+ * ['footer.copyright', 'footer.address', 'footer.phone'],
596
+ * { defaults: { 'footer.copyright': '© 2024' } }
597
+ * );
598
+ *
599
+ * if (isLoading) return null;
600
+ *
601
+ * return (
602
+ * <footer>
603
+ * <p>{getValue('footer.copyright')}</p>
604
+ * <p>{getValue('footer.address')}</p>
605
+ * <p>{getValue('footer.phone')}</p>
606
+ * </footer>
607
+ * );
608
+ * }
609
+ * ```
610
+ */
611
+ declare function useSiteContents(contentKeys: string[], options?: UseSiteContentsOptions): UseSiteContentsReturn;
612
+ interface UseSiteContentSectionReturn {
613
+ /**
614
+ * List of contents in the section
615
+ */
616
+ contents: SiteContent[];
617
+ /**
618
+ * Whether contents are being loaded
619
+ */
620
+ isLoading: boolean;
621
+ /**
622
+ * Error if request failed
623
+ */
624
+ error: ApiError$1 | null;
625
+ /**
626
+ * Refetch section contents
627
+ */
628
+ refetch: () => Promise<void>;
629
+ }
630
+ /**
631
+ * Hook for fetching all content in a section.
632
+ *
633
+ * @example
634
+ * ```tsx
635
+ * function HeroSection() {
636
+ * const { contents, isLoading } = useSiteContentSection('hero');
637
+ *
638
+ * if (isLoading) return <div>Loading...</div>;
639
+ *
640
+ * return (
641
+ * <div>
642
+ * {contents.map(content => (
643
+ * <div key={content.contentKey}>{content.value}</div>
644
+ * ))}
645
+ * </div>
646
+ * );
647
+ * }
648
+ * ```
649
+ */
650
+ declare function useSiteContentSection(section: string): UseSiteContentSectionReturn;
651
+
652
+ /**
653
+ * Edit-mode hooks for CMS Visual (iframe communication with Tenant Admin).
654
+ * When edit-mode=true is in the URL, the site enters edit mode and communicates
655
+ * with the parent iframe via postMessage.
656
+ */
657
+ /** Query key used for site content; must match useSiteContentQuery. */
658
+ declare const SITE_CONTENT_QUERY_KEY: "siteContent";
659
+ /**
660
+ * Returns true when the page is in edit mode (URL has edit-mode=true).
661
+ * Used to show edit affordances and enable postMessage communication.
662
+ */
663
+ declare function useEditMode(): boolean;
664
+ /**
665
+ * Sets up edit-mode messaging: notifies parent when ready and listens for
666
+ * FOXPIXEL_CONTENT_UPDATED. Uses queryClient from FoxPixelContext (pass it to
667
+ * FoxPixelProvider) so we don't require useQueryClient() and avoid "No QueryClient set" in iframe.
668
+ */
669
+ declare function useEditModeMessaging(): boolean;
670
+ /**
671
+ * Returns a callback to send an edit request to the parent iframe.
672
+ * Only has effect when in edit mode.
673
+ */
674
+ declare function useSendEditRequest(): (contentKey: string, currentValue: string, contentType?: string, section?: string, description?: string) => void;
675
+
676
+ /**
677
+ * Site content hook for Editable components.
678
+ * Uses the QueryClient passed via FoxPixelProvider (no useQuery) so it never
679
+ * depends on QueryClientProvider context — avoids "No QueryClient set" in iframe/SSR.
680
+ */
681
+ interface UseSiteContentQueryOptions {
682
+ defaultValue: string;
683
+ }
684
+ interface UseSiteContentQueryReturn {
685
+ value: string;
686
+ isLoading: boolean;
687
+ contentType: string;
688
+ }
689
+ /**
690
+ * Fetches a single site content by key. Uses the queryClient from FoxPixelContext
691
+ * (passed by the host) so it never calls useQuery() and never throws "No QueryClient set".
692
+ */
693
+ declare function useSiteContentQuery(contentKey: string, options: UseSiteContentQueryOptions): UseSiteContentQueryReturn;
694
+
695
+ /**
696
+ * Prefetch site content for Next.js getStaticProps (SSG).
697
+ * Fetches content keys and fills the QueryClient so HydrationBoundary can hydrate the app.
698
+ */
699
+
700
+ interface PrefetchSiteContentOptions {
701
+ apiUrl: string;
702
+ apiKey?: string;
703
+ tenantId?: string;
704
+ contentKeys: string[];
705
+ }
706
+ /**
707
+ * Prefetch site content keys and set them on the given QueryClient.
708
+ * Call this in getStaticProps, then pass the dehydrated state to HydrationBoundary in _app.
709
+ */
710
+ declare function prefetchSiteContent(queryClient: QueryClient, options: PrefetchSiteContentOptions): Promise<void>;
711
+
408
712
  /**
409
713
  * Blog module types for FoxPixel SDK
410
714
  * Aligned with backend BlogPostResponse, BlogCategoryResponse, BlogTagResponse
@@ -675,6 +979,8 @@ interface UseNewsletterSubscribeReturn {
675
979
  declare function useNewsletterSubscribe(): UseNewsletterSubscribeReturn;
676
980
  interface UseNewsletterUnsubscribeReturn {
677
981
  unsubscribe: (email: string) => Promise<boolean>;
982
+ /** Cancelar inscrição pelo token (link no email de confirmação). */
983
+ unsubscribeByToken: (token: string) => Promise<boolean>;
678
984
  isSubmitting: boolean;
679
985
  error: ApiError$1 | null;
680
986
  success: boolean;
@@ -861,4 +1167,4 @@ interface BlogPostSchemaLdOptions {
861
1167
  */
862
1168
  declare function getBlogPostSchemaLd(post: BlogPost, options: BlogPostSchemaLdOptions): Record<string, unknown>;
863
1169
 
864
- export { type ApiError$1 as ApiError, AuthProvider, type BlogAnalyticsSummary, type BlogAuthor, type BlogCategory, type BlogComment, type BlogCommentAdmin, type BlogCommentPage, type BlogPost, type BlogPostPage, type BlogPostSchemaLdOptions, type BlogPostStatus, type BlogSettings, type BlogTag, type CreateBlogCommentPayload, type CreateBlogPostPayload, type CreateCategoryPayload, type CreateLeadRequest, type CreateTagPayload, type EndUser, type EndUserLoginRequest, type FoxPixelConfig, FoxPixelHttpClient, FoxPixelProvider, GuestOnlyRoute, type Lead, type NewsletterFrequency, type NewsletterStats, type NewsletterStatus, type NewsletterSubscriber, type NewsletterSubscriberPage, type PostAnalyticsRow, ProtectedRoute, type Service, type ServiceCatalogResponse, type SubscribeNewsletterPayload, type UpdateBlogPostPayload, type UseAdminBlogAnalyticsReturn, type UseAdminBlogCategoriesReturn, type UseAdminBlogCommentsOptions, type UseAdminBlogCommentsReturn, type UseAdminBlogPostMutationsReturn, type UseAdminBlogPostReturn, type UseAdminBlogPostsOptions, type UseAdminBlogPostsReturn, type UseAdminBlogSettingsReturn, type UseAdminBlogTagsReturn, type UseAdminNewsletterStatsReturn, type UseAdminNewsletterSubscribersOptions, type UseAdminNewsletterSubscribersReturn, type UseBlogCategoriesReturn, type UseBlogCommentSubmitReturn, type UseBlogCommentsReturn, type UseBlogFeaturedPostsReturn, type UseBlogPostReturn, type UseBlogPostsOptions, type UseBlogPostsReturn, type UseBlogTagsReturn, type UseNewsletterSubscribeReturn, type UseNewsletterUnsubscribeReturn, getBlogPostSchemaLd, useAdminBlogAnalytics, useAdminBlogCategories, useAdminBlogComments, useAdminBlogPost, useAdminBlogPostMutations, useAdminBlogPosts, useAdminBlogSettings, useAdminBlogTags, useAdminNewsletterStats, useAdminNewsletterSubscribers, useAuth, useBlogCategories, useBlogCommentSubmit, useBlogComments, useBlogFeaturedPosts, useBlogPost, useBlogPosts, useBlogTags, useContactCapture, useFoxPixelContext, useLeadCapture, useNewsletterSubscribe, useNewsletterUnsubscribe, useServices, withAuth };
1170
+ export { type ApiError$1 as ApiError, AuthProvider, type BlogAnalyticsSummary, type BlogAuthor, type BlogCategory, type BlogComment, type BlogCommentAdmin, type BlogCommentPage, type BlogPost, type BlogPostPage, type BlogPostSchemaLdOptions, type BlogPostStatus, type BlogSettings, type BlogTag, type CreateBlogCommentPayload, type CreateBlogPostPayload, type CreateCategoryPayload, type CreateLeadRequest, type CreateTagPayload, Editable, EditableHTML, EditableImage, type EditableImageProps, type EditableProps, type EndUser, type EndUserLoginRequest, type FoxPixelConfig, FoxPixelHttpClient, FoxPixelProvider, GuestOnlyRoute, type Lead, type NewsletterFrequency, type NewsletterStats, type NewsletterStatus, type NewsletterSubscriber, type NewsletterSubscriberPage, type PostAnalyticsRow, type PrefetchSiteContentOptions, ProtectedRoute, SITE_CONTENT_QUERY_KEY, type Service, type ServiceCatalogResponse, type SiteContent, type SubscribeNewsletterPayload, type UpdateBlogPostPayload, type UseAdminBlogAnalyticsReturn, type UseAdminBlogCategoriesReturn, type UseAdminBlogCommentsOptions, type UseAdminBlogCommentsReturn, type UseAdminBlogPostMutationsReturn, type UseAdminBlogPostReturn, type UseAdminBlogPostsOptions, type UseAdminBlogPostsReturn, type UseAdminBlogSettingsReturn, type UseAdminBlogTagsReturn, type UseAdminNewsletterStatsReturn, type UseAdminNewsletterSubscribersOptions, type UseAdminNewsletterSubscribersReturn, type UseBlogCategoriesReturn, type UseBlogCommentSubmitReturn, type UseBlogCommentsReturn, type UseBlogFeaturedPostsReturn, type UseBlogPostReturn, type UseBlogPostsOptions, type UseBlogPostsReturn, type UseBlogTagsReturn, type UseNewsletterSubscribeReturn, type UseNewsletterUnsubscribeReturn, type UseSiteContentOptions, type UseSiteContentQueryOptions, type UseSiteContentQueryReturn, type UseSiteContentReturn, type UseSiteContentSectionReturn, type UseSiteContentsOptions, type UseSiteContentsReturn, getBlogPostSchemaLd, prefetchSiteContent, useAdminBlogAnalytics, useAdminBlogCategories, useAdminBlogComments, useAdminBlogPost, useAdminBlogPostMutations, useAdminBlogPosts, useAdminBlogSettings, useAdminBlogTags, useAdminNewsletterStats, useAdminNewsletterSubscribers, useAuth, useBlogCategories, useBlogCommentSubmit, useBlogComments, useBlogFeaturedPosts, useBlogPost, useBlogPosts, useBlogTags, useContactCapture, useEditMode, useEditModeMessaging, useFoxPixelContext, useLeadCapture, useNewsletterSubscribe, useNewsletterUnsubscribe, useSendEditRequest, useServices, useSiteContent, useSiteContentQuery, useSiteContentSection, useSiteContents, withAuth };