@sangwonl/pocato-react 0.3.0 → 0.4.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.
package/dist/index.d.ts CHANGED
@@ -2,6 +2,24 @@ import * as react from 'react';
2
2
  import { ReactNode, CSSProperties } from 'react';
3
3
  import { LayerSource } from '@sangwonl/pocato-core';
4
4
 
5
+ interface PocaCardConfig {
6
+ cardSize?: {
7
+ width: number;
8
+ height: number;
9
+ preset?: string;
10
+ };
11
+ front: Omit<FaceProps, 'content'>;
12
+ back?: Omit<FaceProps, 'content'>;
13
+ flippable?: boolean;
14
+ initialFlipped?: boolean;
15
+ flipSpeed?: number;
16
+ }
17
+ interface PublishedConfigResponse {
18
+ cardId: string;
19
+ releaseId: string;
20
+ config: PocaCardConfig;
21
+ }
22
+
5
23
  interface PocaCardHandle {
6
24
  flip(): void;
7
25
  wiggle(): void;
@@ -12,18 +30,43 @@ interface FaceProps {
12
30
  layers: LayerSource[];
13
31
  content?: ReactNode;
14
32
  }
15
- interface PocaCardProps {
16
- front: FaceProps;
17
- back?: FaceProps;
33
+ interface CommonPocaCardProps {
18
34
  flippable?: boolean;
19
35
  initialFlipped?: boolean;
20
36
  flipSpeed?: number;
21
37
  onFlip?: (flipped: boolean) => void;
22
38
  onReady?: () => void;
23
39
  onError?: (error: Error) => void;
40
+ loadingFallback?: ReactNode;
41
+ errorFallback?: ReactNode | ((error: Error) => ReactNode);
24
42
  style?: CSSProperties;
25
43
  className?: string;
26
44
  }
45
+ interface DirectPocaCardProps extends CommonPocaCardProps {
46
+ front: FaceProps;
47
+ back?: FaceProps;
48
+ config?: never;
49
+ cardId?: never;
50
+ publishableKey?: never;
51
+ apiBaseUrl?: never;
52
+ }
53
+ interface ConfigPocaCardProps extends CommonPocaCardProps {
54
+ config: PocaCardConfig;
55
+ front?: Partial<FaceProps>;
56
+ back?: Partial<FaceProps>;
57
+ cardId?: never;
58
+ publishableKey?: never;
59
+ apiBaseUrl?: never;
60
+ }
61
+ interface ConnectedPocaCardProps extends CommonPocaCardProps {
62
+ cardId: string;
63
+ publishableKey: string;
64
+ apiBaseUrl?: string;
65
+ front?: Partial<FaceProps>;
66
+ back?: Partial<FaceProps>;
67
+ config?: never;
68
+ }
69
+ type PocaCardProps = DirectPocaCardProps | ConfigPocaCardProps | ConnectedPocaCardProps;
27
70
  declare const PocaCard: react.ForwardRefExoticComponent<PocaCardProps & react.RefAttributes<PocaCardHandle>>;
28
71
 
29
- export { type FaceProps, PocaCard, type PocaCardHandle, type PocaCardProps };
72
+ export { type FaceProps, PocaCard, type PocaCardConfig, type PocaCardHandle, type PocaCardProps, type PublishedConfigResponse };
package/dist/index.js CHANGED
@@ -1,91 +1,246 @@
1
1
  // src/PocaCard.tsx
2
2
  import {
3
3
  forwardRef,
4
- useEffect,
4
+ useEffect as useEffect2,
5
5
  useImperativeHandle,
6
6
  useRef,
7
- useState
7
+ useState as useState2
8
8
  } from "react";
9
9
  import { createPortal } from "react-dom";
10
10
  import {
11
11
  PocaCard as CorePocaCard
12
12
  } from "@sangwonl/pocato-core";
13
- import { jsxs } from "react/jsx-runtime";
14
- var PocaCard = forwardRef(
15
- (props, ref) => {
16
- const containerRef = useRef(null);
17
- const cardRef = useRef(null);
18
- const [portalTargets, setPortalTargets] = useState({ front: null, back: null });
19
- useEffect(() => {
20
- if (!containerRef.current) return;
21
- const card = new CorePocaCard(containerRef.current, {
22
- front: { shader: props.front.shader, layers: props.front.layers },
23
- back: props.back ? { shader: props.back.shader, layers: props.back.layers } : void 0,
24
- flippable: props.flippable,
25
- initialFlipped: props.initialFlipped,
26
- flipSpeed: props.flipSpeed
27
- });
28
- cardRef.current = card;
29
- setPortalTargets({
30
- front: card.getFrontContentEl(),
31
- back: card.getBackContentEl()
32
- });
33
- return () => {
34
- card.destroy();
35
- cardRef.current = null;
36
- setPortalTargets({ front: null, back: null });
37
- };
38
- }, [props.front.shader, props.back?.shader]);
39
- const frontLayersKey = JSON.stringify(props.front.layers);
40
- const backLayersKey = JSON.stringify(props.back?.layers);
41
- const layersMounted = useRef(false);
42
- useEffect(() => {
43
- if (!layersMounted.current) {
44
- layersMounted.current = true;
45
- return;
13
+
14
+ // src/pocato-client.ts
15
+ var DEFAULT_API_BASE_URL = "https://pocato-api.gamzabaw.workers.dev";
16
+ function getApiBaseUrl(apiBaseUrl) {
17
+ return apiBaseUrl ?? DEFAULT_API_BASE_URL;
18
+ }
19
+ async function fetchPublishedConfig(cardId, options) {
20
+ const baseUrl = getApiBaseUrl(options.apiBaseUrl);
21
+ const res = await fetch(`${baseUrl}/api/v1/public/cards/${cardId}/config`, {
22
+ headers: {
23
+ "X-Pocato-Key": options.publishableKey
24
+ }
25
+ });
26
+ if (!res.ok) {
27
+ throw new Error(`Failed to load Pocato card config: ${res.status}`);
28
+ }
29
+ return res.json();
30
+ }
31
+ async function trackCardEvent(cardId, options) {
32
+ const baseUrl = getApiBaseUrl(options.apiBaseUrl);
33
+ await fetch(`${baseUrl}/api/v1/public/cards/${cardId}/events`, {
34
+ method: "POST",
35
+ headers: {
36
+ "Content-Type": "application/json",
37
+ "X-Pocato-Key": options.publishableKey
38
+ },
39
+ body: JSON.stringify({ eventType: options.eventType }),
40
+ keepalive: true
41
+ }).catch(() => {
42
+ });
43
+ }
44
+
45
+ // src/use-pocato-config.ts
46
+ import { useEffect, useState } from "react";
47
+ var cache = /* @__PURE__ */ new Map();
48
+ function getPocatoConfigCacheKey(apiBaseUrl, publishableKey, cardId) {
49
+ return `${apiBaseUrl ?? ""}:${publishableKey}:${cardId}`;
50
+ }
51
+ function usePocatoConfig(input) {
52
+ const [config, setConfig] = useState(() => {
53
+ return cache.get(getPocatoConfigCacheKey(input.apiBaseUrl, input.publishableKey, input.cardId)) ?? null;
54
+ });
55
+ const [loading, setLoading] = useState(!config);
56
+ const [error, setError] = useState(null);
57
+ useEffect(() => {
58
+ let cancelled = false;
59
+ const cacheKey = getPocatoConfigCacheKey(input.apiBaseUrl, input.publishableKey, input.cardId);
60
+ const cached = cache.get(cacheKey);
61
+ if (cached) {
62
+ setConfig(cached);
63
+ setLoading(false);
64
+ setError(null);
65
+ return;
66
+ }
67
+ setLoading(true);
68
+ setError(null);
69
+ fetchPublishedConfig(input.cardId, {
70
+ apiBaseUrl: input.apiBaseUrl,
71
+ publishableKey: input.publishableKey
72
+ }).then((response) => {
73
+ if (cancelled) return;
74
+ cache.set(cacheKey, response.config);
75
+ setConfig(response.config);
76
+ setLoading(false);
77
+ }).catch((err) => {
78
+ if (cancelled) return;
79
+ setError(err instanceof Error ? err : new Error("Failed to load Pocato config"));
80
+ setLoading(false);
81
+ });
82
+ return () => {
83
+ cancelled = true;
84
+ };
85
+ }, [input.apiBaseUrl, input.publishableKey, input.cardId]);
86
+ return { config, loading, error };
87
+ }
88
+
89
+ // src/PocaCard.tsx
90
+ import { jsx, jsxs } from "react/jsx-runtime";
91
+ function isConnectedProps(props) {
92
+ return typeof props.cardId === "string" && typeof props.publishableKey === "string";
93
+ }
94
+ function isConfigProps(props) {
95
+ return "config" in props && props.config != null;
96
+ }
97
+ function resolveConfigProps(config, props) {
98
+ return {
99
+ ...props,
100
+ front: {
101
+ ...config.front,
102
+ content: props.front?.content
103
+ },
104
+ back: config.back ? {
105
+ ...config.back,
106
+ content: props.back?.content
107
+ } : props.back?.layers ? props.back : void 0,
108
+ flippable: props.flippable ?? config.flippable,
109
+ initialFlipped: props.initialFlipped ?? config.initialFlipped,
110
+ flipSpeed: props.flipSpeed ?? config.flipSpeed
111
+ };
112
+ }
113
+ function renderErrorFallback(errorFallback, error) {
114
+ if (typeof errorFallback === "function") return errorFallback(error);
115
+ return errorFallback ?? null;
116
+ }
117
+ function ConnectedPocaCard(props, ref) {
118
+ const { config, loading, error } = usePocatoConfig({
119
+ cardId: props.cardId,
120
+ publishableKey: props.publishableKey,
121
+ apiBaseUrl: props.apiBaseUrl
122
+ });
123
+ const readyTracked = useRef(false);
124
+ useEffect2(() => {
125
+ if (error && !props.errorFallback) {
126
+ props.onError?.(error);
127
+ }
128
+ }, [error, props.errorFallback, props.onError]);
129
+ if (error) {
130
+ return renderErrorFallback(props.errorFallback, error);
131
+ }
132
+ if (loading || !config) {
133
+ return props.loadingFallback ?? null;
134
+ }
135
+ const resolved = resolveConfigProps(config, {
136
+ ...props,
137
+ onReady: () => {
138
+ if (!readyTracked.current) {
139
+ readyTracked.current = true;
140
+ void trackCardEvent(props.cardId, {
141
+ apiBaseUrl: props.apiBaseUrl,
142
+ publishableKey: props.publishableKey,
143
+ eventType: "card_ready"
144
+ });
46
145
  }
47
- cardRef.current?.updateOptions({
48
- front: { layers: props.front.layers },
49
- back: props.back ? { layers: props.back.layers } : void 0
146
+ props.onReady?.();
147
+ },
148
+ onError: (runtimeError) => {
149
+ void trackCardEvent(props.cardId, {
150
+ apiBaseUrl: props.apiBaseUrl,
151
+ publishableKey: props.publishableKey,
152
+ eventType: "render_error"
50
153
  });
51
- }, [frontLayersKey, backLayersKey]);
52
- useEffect(() => {
53
- if (props.flipSpeed != null) {
54
- cardRef.current?.updateOptions({ flipSpeed: props.flipSpeed });
55
- }
56
- }, [props.flipSpeed]);
57
- useEffect(() => {
58
- const card = cardRef.current;
59
- if (!card) return;
60
- const onFlip = props.onFlip;
61
- const onReady = props.onReady;
62
- const onError = props.onError;
63
- if (onFlip) card.on("flip", onFlip);
64
- if (onReady) card.on("ready", onReady);
65
- if (onError) card.on("error", onError);
66
- return () => {
67
- if (onFlip) card.off("flip", onFlip);
68
- if (onReady) card.off("ready", onReady);
69
- if (onError) card.off("error", onError);
70
- };
71
- }, [props.onFlip, props.onReady, props.onError]);
72
- useImperativeHandle(ref, () => ({
73
- flip: () => cardRef.current?.flip(),
74
- wiggle: () => cardRef.current?.wiggle(),
75
- reset: () => cardRef.current?.reset()
76
- }));
77
- return /* @__PURE__ */ jsxs(
78
- "div",
79
- {
80
- ref: containerRef,
81
- style: props.style,
82
- className: props.className,
83
- children: [
84
- portalTargets.front && props.front.content && createPortal(props.front.content, portalTargets.front),
85
- portalTargets.back && props.back?.content && createPortal(props.back.content, portalTargets.back)
86
- ]
87
- }
88
- );
154
+ props.onError?.(runtimeError);
155
+ }
156
+ });
157
+ return /* @__PURE__ */ jsx(PocaCardRenderer, { props: resolved, refHandle: ref });
158
+ }
159
+ function PocaCardRenderer({
160
+ props,
161
+ refHandle
162
+ }) {
163
+ const containerRef = useRef(null);
164
+ const cardRef = useRef(null);
165
+ const [portalTargets, setPortalTargets] = useState2({ front: null, back: null });
166
+ useEffect2(() => {
167
+ if (!containerRef.current) return;
168
+ const card = new CorePocaCard(containerRef.current, {
169
+ front: { shader: props.front.shader, layers: props.front.layers },
170
+ back: props.back ? { shader: props.back.shader, layers: props.back.layers } : void 0,
171
+ flippable: props.flippable,
172
+ initialFlipped: props.initialFlipped,
173
+ flipSpeed: props.flipSpeed
174
+ });
175
+ cardRef.current = card;
176
+ setPortalTargets({
177
+ front: card.getFrontContentEl(),
178
+ back: card.getBackContentEl()
179
+ });
180
+ return () => {
181
+ card.destroy();
182
+ cardRef.current = null;
183
+ setPortalTargets({ front: null, back: null });
184
+ };
185
+ }, [props.front.shader, props.back?.shader]);
186
+ const frontLayersKey = JSON.stringify(props.front.layers);
187
+ const backLayersKey = JSON.stringify(props.back?.layers);
188
+ const layersMounted = useRef(false);
189
+ useEffect2(() => {
190
+ if (!layersMounted.current) {
191
+ layersMounted.current = true;
192
+ return;
193
+ }
194
+ cardRef.current?.updateOptions({
195
+ front: { layers: props.front.layers },
196
+ back: props.back ? { layers: props.back.layers } : void 0
197
+ });
198
+ }, [frontLayersKey, backLayersKey]);
199
+ useEffect2(() => {
200
+ if (props.flipSpeed != null) {
201
+ cardRef.current?.updateOptions({ flipSpeed: props.flipSpeed });
202
+ }
203
+ }, [props.flipSpeed]);
204
+ useEffect2(() => {
205
+ const card = cardRef.current;
206
+ if (!card) return;
207
+ const onFlip = props.onFlip;
208
+ const onReady = props.onReady;
209
+ const onError = props.onError;
210
+ if (onFlip) card.on("flip", onFlip);
211
+ if (onReady) card.on("ready", onReady);
212
+ if (onError) card.on("error", onError);
213
+ return () => {
214
+ if (onFlip) card.off("flip", onFlip);
215
+ if (onReady) card.off("ready", onReady);
216
+ if (onError) card.off("error", onError);
217
+ };
218
+ }, [props.onFlip, props.onReady, props.onError]);
219
+ useImperativeHandle(refHandle, () => ({
220
+ flip: () => cardRef.current?.flip(),
221
+ wiggle: () => cardRef.current?.wiggle(),
222
+ reset: () => cardRef.current?.reset()
223
+ }));
224
+ return /* @__PURE__ */ jsxs(
225
+ "div",
226
+ {
227
+ ref: containerRef,
228
+ style: props.style,
229
+ className: props.className,
230
+ children: [
231
+ portalTargets.front && props.front.content && createPortal(props.front.content, portalTargets.front),
232
+ portalTargets.back && props.back?.content && createPortal(props.back.content, portalTargets.back)
233
+ ]
234
+ }
235
+ );
236
+ }
237
+ var PocaCard = forwardRef(
238
+ (props, ref) => {
239
+ if (isConnectedProps(props)) {
240
+ return ConnectedPocaCard(props, ref);
241
+ }
242
+ const resolved = isConfigProps(props) ? resolveConfigProps(props.config, props) : props;
243
+ return /* @__PURE__ */ jsx(PocaCardRenderer, { props: resolved, refHandle: ref });
89
244
  }
90
245
  );
91
246
  PocaCard.displayName = "PocaCard";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/PocaCard.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport {\n PocaCard as CorePocaCard,\n type PocaCardOptions,\n type LayerSource,\n} from '@sangwonl/pocato-core'\n\nexport interface PocaCardHandle {\n flip(): void\n wiggle(): void\n reset(): void\n}\n\nexport interface FaceProps {\n shader?: string\n layers: LayerSource[]\n content?: ReactNode\n}\n\nexport interface PocaCardProps {\n front: FaceProps\n back?: FaceProps\n flippable?: boolean\n initialFlipped?: boolean\n flipSpeed?: number\n onFlip?: (flipped: boolean) => void\n onReady?: () => void\n onError?: (error: Error) => void\n style?: CSSProperties\n className?: string\n}\n\nexport const PocaCard = forwardRef<PocaCardHandle, PocaCardProps>(\n (props, ref) => {\n const containerRef = useRef<HTMLDivElement>(null)\n const cardRef = useRef<CorePocaCard | null>(null)\n const [portalTargets, setPortalTargets] = useState<{\n front: HTMLElement | null\n back: HTMLElement | null\n }>({ front: null, back: null })\n\n // Create/destroy core instance\n useEffect(() => {\n if (!containerRef.current) return\n\n const card = new CorePocaCard(containerRef.current, {\n front: { shader: props.front.shader, layers: props.front.layers },\n back: props.back ? { shader: props.back.shader, layers: props.back.layers } : undefined,\n flippable: props.flippable,\n initialFlipped: props.initialFlipped,\n flipSpeed: props.flipSpeed,\n })\n\n cardRef.current = card\n setPortalTargets({\n front: card.getFrontContentEl(),\n back: card.getBackContentEl(),\n })\n\n return () => {\n card.destroy()\n cardRef.current = null\n setPortalTargets({ front: null, back: null })\n }\n // Re-create when shader config changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [props.front.shader, props.back?.shader])\n\n // Sync layers (JSON.stringify for shallow comparison of small plain objects)\n // Skip initial mount — constructor already loads layers\n const frontLayersKey = JSON.stringify(props.front.layers)\n const backLayersKey = JSON.stringify(props.back?.layers)\n const layersMounted = useRef(false)\n useEffect(() => {\n if (!layersMounted.current) {\n layersMounted.current = true\n return\n }\n cardRef.current?.updateOptions({\n front: { layers: props.front.layers },\n back: props.back ? { layers: props.back.layers } : undefined,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [frontLayersKey, backLayersKey])\n\n // Sync flipSpeed\n useEffect(() => {\n if (props.flipSpeed != null) {\n cardRef.current?.updateOptions({ flipSpeed: props.flipSpeed })\n }\n }, [props.flipSpeed])\n\n // Bind events\n useEffect(() => {\n const card = cardRef.current\n if (!card) return\n\n const onFlip = props.onFlip\n const onReady = props.onReady\n const onError = props.onError\n\n if (onFlip) card.on('flip', onFlip)\n if (onReady) card.on('ready', onReady)\n if (onError) card.on('error', onError)\n\n return () => {\n if (onFlip) card.off('flip', onFlip)\n if (onReady) card.off('ready', onReady)\n if (onError) card.off('error', onError)\n }\n }, [props.onFlip, props.onReady, props.onError])\n\n // Expose imperative handle\n useImperativeHandle(ref, () => ({\n flip: () => cardRef.current?.flip(),\n wiggle: () => cardRef.current?.wiggle(),\n reset: () => cardRef.current?.reset(),\n }))\n\n return (\n <div\n ref={containerRef}\n style={props.style}\n className={props.className}\n >\n {portalTargets.front && props.front.content && createPortal(props.front.content, portalTargets.front)}\n {portalTargets.back && props.back?.content && createPortal(props.back.content, portalTargets.back)}\n </div>\n )\n },\n)\n\nPocaCard.displayName = 'PocaCard'\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/PocaCard.tsx","../src/pocato-client.ts","../src/use-pocato-config.ts"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type ForwardedRef,\n type ReactNode,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport {\n PocaCard as CorePocaCard,\n type LayerSource,\n} from '@sangwonl/pocato-core'\nimport { trackCardEvent, type PocaCardConfig } from './pocato-client'\nimport { usePocatoConfig } from './use-pocato-config'\n\nexport interface PocaCardHandle {\n flip(): void\n wiggle(): void\n reset(): void\n}\n\nexport interface FaceProps {\n shader?: string\n layers: LayerSource[]\n content?: ReactNode\n}\n\ninterface CommonPocaCardProps {\n flippable?: boolean\n initialFlipped?: boolean\n flipSpeed?: number\n onFlip?: (flipped: boolean) => void\n onReady?: () => void\n onError?: (error: Error) => void\n loadingFallback?: ReactNode\n errorFallback?: ReactNode | ((error: Error) => ReactNode)\n style?: CSSProperties\n className?: string\n}\n\ninterface DirectPocaCardProps extends CommonPocaCardProps {\n front: FaceProps\n back?: FaceProps\n config?: never\n cardId?: never\n publishableKey?: never\n apiBaseUrl?: never\n}\n\ninterface ConfigPocaCardProps extends CommonPocaCardProps {\n config: PocaCardConfig\n front?: Partial<FaceProps>\n back?: Partial<FaceProps>\n cardId?: never\n publishableKey?: never\n apiBaseUrl?: never\n}\n\ninterface ConnectedPocaCardProps extends CommonPocaCardProps {\n cardId: string\n publishableKey: string\n apiBaseUrl?: string\n front?: Partial<FaceProps>\n back?: Partial<FaceProps>\n config?: never\n}\n\nexport type PocaCardProps = DirectPocaCardProps | ConfigPocaCardProps | ConnectedPocaCardProps\n\ninterface ResolvedPocaCardProps extends CommonPocaCardProps {\n front: FaceProps\n back?: FaceProps\n}\n\nfunction isConnectedProps(props: PocaCardProps): props is ConnectedPocaCardProps {\n return typeof props.cardId === 'string' && typeof props.publishableKey === 'string'\n}\n\nfunction isConfigProps(props: PocaCardProps): props is ConfigPocaCardProps {\n return 'config' in props && props.config != null\n}\n\nfunction resolveConfigProps(\n config: PocaCardConfig,\n props: ConfigPocaCardProps | ConnectedPocaCardProps,\n): ResolvedPocaCardProps {\n return {\n ...props,\n front: {\n ...config.front,\n content: props.front?.content,\n },\n back: config.back\n ? {\n ...config.back,\n content: props.back?.content,\n }\n : props.back?.layers\n ? props.back as FaceProps\n : undefined,\n flippable: props.flippable ?? config.flippable,\n initialFlipped: props.initialFlipped ?? config.initialFlipped,\n flipSpeed: props.flipSpeed ?? config.flipSpeed,\n }\n}\n\nfunction renderErrorFallback(errorFallback: CommonPocaCardProps['errorFallback'], error: Error) {\n if (typeof errorFallback === 'function') return errorFallback(error)\n return errorFallback ?? null\n}\n\nfunction ConnectedPocaCard(\n props: ConnectedPocaCardProps,\n ref: ForwardedRef<PocaCardHandle>,\n) {\n const { config, loading, error } = usePocatoConfig({\n cardId: props.cardId,\n publishableKey: props.publishableKey,\n apiBaseUrl: props.apiBaseUrl,\n })\n const readyTracked = useRef(false)\n\n useEffect(() => {\n if (error && !props.errorFallback) {\n props.onError?.(error)\n }\n }, [error, props.errorFallback, props.onError])\n\n if (error) {\n return renderErrorFallback(props.errorFallback, error)\n }\n\n if (loading || !config) {\n return props.loadingFallback ?? null\n }\n\n const resolved = resolveConfigProps(config, {\n ...props,\n onReady: () => {\n if (!readyTracked.current) {\n readyTracked.current = true\n void trackCardEvent(props.cardId, {\n apiBaseUrl: props.apiBaseUrl,\n publishableKey: props.publishableKey,\n eventType: 'card_ready',\n })\n }\n props.onReady?.()\n },\n onError: (runtimeError) => {\n void trackCardEvent(props.cardId, {\n apiBaseUrl: props.apiBaseUrl,\n publishableKey: props.publishableKey,\n eventType: 'render_error',\n })\n props.onError?.(runtimeError)\n },\n })\n\n return <PocaCardRenderer props={resolved} refHandle={ref} />\n}\n\nfunction PocaCardRenderer({\n props,\n refHandle,\n}: {\n props: ResolvedPocaCardProps\n refHandle: ForwardedRef<PocaCardHandle>\n}) {\n const containerRef = useRef<HTMLDivElement>(null)\n const cardRef = useRef<CorePocaCard | null>(null)\n const [portalTargets, setPortalTargets] = useState<{\n front: HTMLElement | null\n back: HTMLElement | null\n }>({ front: null, back: null })\n\n useEffect(() => {\n if (!containerRef.current) return\n\n const card = new CorePocaCard(containerRef.current, {\n front: { shader: props.front.shader, layers: props.front.layers },\n back: props.back ? { shader: props.back.shader, layers: props.back.layers } : undefined,\n flippable: props.flippable,\n initialFlipped: props.initialFlipped,\n flipSpeed: props.flipSpeed,\n })\n\n cardRef.current = card\n setPortalTargets({\n front: card.getFrontContentEl(),\n back: card.getBackContentEl(),\n })\n\n return () => {\n card.destroy()\n cardRef.current = null\n setPortalTargets({ front: null, back: null })\n }\n // Re-create when shader config changes\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [props.front.shader, props.back?.shader])\n\n const frontLayersKey = JSON.stringify(props.front.layers)\n const backLayersKey = JSON.stringify(props.back?.layers)\n const layersMounted = useRef(false)\n useEffect(() => {\n if (!layersMounted.current) {\n layersMounted.current = true\n return\n }\n cardRef.current?.updateOptions({\n front: { layers: props.front.layers },\n back: props.back ? { layers: props.back.layers } : undefined,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [frontLayersKey, backLayersKey])\n\n useEffect(() => {\n if (props.flipSpeed != null) {\n cardRef.current?.updateOptions({ flipSpeed: props.flipSpeed })\n }\n }, [props.flipSpeed])\n\n useEffect(() => {\n const card = cardRef.current\n if (!card) return\n\n const onFlip = props.onFlip\n const onReady = props.onReady\n const onError = props.onError\n\n if (onFlip) card.on('flip', onFlip)\n if (onReady) card.on('ready', onReady)\n if (onError) card.on('error', onError)\n\n return () => {\n if (onFlip) card.off('flip', onFlip)\n if (onReady) card.off('ready', onReady)\n if (onError) card.off('error', onError)\n }\n }, [props.onFlip, props.onReady, props.onError])\n\n useImperativeHandle(refHandle, () => ({\n flip: () => cardRef.current?.flip(),\n wiggle: () => cardRef.current?.wiggle(),\n reset: () => cardRef.current?.reset(),\n }))\n\n return (\n <div\n ref={containerRef}\n style={props.style}\n className={props.className}\n >\n {portalTargets.front && props.front.content && createPortal(props.front.content, portalTargets.front)}\n {portalTargets.back && props.back?.content && createPortal(props.back.content, portalTargets.back)}\n </div>\n )\n}\n\nexport const PocaCard = forwardRef<PocaCardHandle, PocaCardProps>(\n (props, ref) => {\n if (isConnectedProps(props)) {\n return ConnectedPocaCard(props, ref)\n }\n\n const resolved = isConfigProps(props) ? resolveConfigProps(props.config, props) : props\n return <PocaCardRenderer props={resolved} refHandle={ref} />\n },\n)\n\nPocaCard.displayName = 'PocaCard'\n","import type { FaceProps } from './PocaCard'\n\nconst DEFAULT_API_BASE_URL = 'https://pocato-api.gamzabaw.workers.dev'\n\nexport interface PocaCardConfig {\n cardSize?: {\n width: number\n height: number\n preset?: string\n }\n front: Omit<FaceProps, 'content'>\n back?: Omit<FaceProps, 'content'>\n flippable?: boolean\n initialFlipped?: boolean\n flipSpeed?: number\n}\n\nexport interface PublishedConfigResponse {\n cardId: string\n releaseId: string\n config: PocaCardConfig\n}\n\nexport interface PocatoClientOptions {\n apiBaseUrl?: string\n publishableKey: string\n}\n\nfunction getApiBaseUrl(apiBaseUrl?: string): string {\n return apiBaseUrl ?? DEFAULT_API_BASE_URL\n}\n\nexport async function fetchPublishedConfig(\n cardId: string,\n options: PocatoClientOptions,\n): Promise<PublishedConfigResponse> {\n const baseUrl = getApiBaseUrl(options.apiBaseUrl)\n const res = await fetch(`${baseUrl}/api/v1/public/cards/${cardId}/config`, {\n headers: {\n 'X-Pocato-Key': options.publishableKey,\n },\n })\n\n if (!res.ok) {\n throw new Error(`Failed to load Pocato card config: ${res.status}`)\n }\n\n return res.json()\n}\n\nexport async function trackCardEvent(\n cardId: string,\n options: PocatoClientOptions & { eventType: 'card_ready' | 'render_error' },\n): Promise<void> {\n const baseUrl = getApiBaseUrl(options.apiBaseUrl)\n await fetch(`${baseUrl}/api/v1/public/cards/${cardId}/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Pocato-Key': options.publishableKey,\n },\n body: JSON.stringify({ eventType: options.eventType }),\n keepalive: true,\n }).catch(() => {\n // Usage metering must not break customer rendering.\n })\n}\n","import { useEffect, useState } from 'react'\nimport { fetchPublishedConfig, type PocaCardConfig } from './pocato-client'\n\nconst cache = new Map<string, PocaCardConfig>()\n\nexport function getPocatoConfigCacheKey(\n apiBaseUrl: string | undefined,\n publishableKey: string,\n cardId: string,\n): string {\n return `${apiBaseUrl ?? ''}:${publishableKey}:${cardId}`\n}\n\nexport function usePocatoConfig(input: {\n cardId: string\n publishableKey: string\n apiBaseUrl?: string\n}) {\n const [config, setConfig] = useState<PocaCardConfig | null>(() => {\n return cache.get(getPocatoConfigCacheKey(input.apiBaseUrl, input.publishableKey, input.cardId)) ?? null\n })\n const [loading, setLoading] = useState(!config)\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n let cancelled = false\n const cacheKey = getPocatoConfigCacheKey(input.apiBaseUrl, input.publishableKey, input.cardId)\n const cached = cache.get(cacheKey)\n\n if (cached) {\n setConfig(cached)\n setLoading(false)\n setError(null)\n return\n }\n\n setLoading(true)\n setError(null)\n\n fetchPublishedConfig(input.cardId, {\n apiBaseUrl: input.apiBaseUrl,\n publishableKey: input.publishableKey,\n })\n .then((response) => {\n if (cancelled) return\n cache.set(cacheKey, response.config)\n setConfig(response.config)\n setLoading(false)\n })\n .catch((err) => {\n if (cancelled) return\n setError(err instanceof Error ? err : new Error('Failed to load Pocato config'))\n setLoading(false)\n })\n\n return () => {\n cancelled = true\n }\n }, [input.apiBaseUrl, input.publishableKey, input.cardId])\n\n return { config, loading, error }\n}\n"],"mappings":"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","names":["useEffect","useState","useEffect","useState"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sangwonl/pocato-react",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "author": "Sangwon Lee <gamzabaw@gmail.com>",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -25,7 +25,7 @@
25
25
  "dev": "tsup --watch"
26
26
  },
27
27
  "dependencies": {
28
- "@sangwonl/pocato-core": "0.3.0"
28
+ "@sangwonl/pocato-core": "0.4.0"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "react": "^18.0.0 || ^19.0.0",