diff --git a/.changeset/fresh-readme-demo.md b/.changeset/fresh-readme-demo.md new file mode 100644 index 0000000..393e725 --- /dev/null +++ b/.changeset/fresh-readme-demo.md @@ -0,0 +1,5 @@ +--- +'@react-native-motion-kit/swipe-deck': patch +--- + +Update the README and docs quick start links for the published docs site and Expo Snack demo. diff --git a/README.ko.md b/README.ko.md index aaf6a03..73ea9f0 100644 --- a/README.ko.md +++ b/README.ko.md @@ -35,6 +35,7 @@ Reanimated, Worklets, Gesture Handler를 기반으로 card stack, like/pass butt ### 예제 & 데모 - [📁 예제 프로젝트](https://github.com/react-native-motion-kit/react-native-swipe-deck/tree/main/example) - 다양한 use case를 담은 실제 구현 코드입니다 +- [🤖 Expo Snack](https://snack.expo.dev/@harang/react-native-swipe-deck) - Expo Snack에서 바로 체험할 수 있습니다 ### 🤖 AI diff --git a/README.md b/README.md index 1179f2d..f47f74e 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Full documentation is available at: ### Examples & Demo - [📁 Example Project](https://github.com/react-native-motion-kit/react-native-swipe-deck/tree/main/example) - Real implementation code with various use cases +- [🤖 Expo Snack](https://snack.expo.dev/@harang/react-native-swipe-deck) - Try it instantly on Expo Snack ### 🤖 AI diff --git a/docs/components/ExpoSnackEmbed.tsx b/docs/components/ExpoSnackEmbed.tsx new file mode 100644 index 0000000..267d100 --- /dev/null +++ b/docs/components/ExpoSnackEmbed.tsx @@ -0,0 +1,100 @@ +import { useEffect, useRef } from 'react'; + +const SNACK_EMBED_SCRIPT_SRC = 'https://snack.expo.dev/embed.js'; + +let snackEmbedScriptPromise: Promise | undefined; + +type Props = { + snackId: string; + platform?: 'web' | 'ios' | 'android'; + preview?: boolean; + height?: number | `${number}px`; +}; + +function loadSnackEmbedScript() { + if (window.ExpoSnack) { + return Promise.resolve(); + } + + if (snackEmbedScriptPromise) { + return snackEmbedScriptPromise; + } + + snackEmbedScriptPromise = new Promise((resolve, reject) => { + const existingScript = document.querySelector( + `script[src="${SNACK_EMBED_SCRIPT_SRC}"]`, + ); + const script = existingScript ?? document.createElement('script'); + + const handleLoad = () => resolve(); + const handleError = () => { + snackEmbedScriptPromise = undefined; + reject(new Error('Failed to load Expo Snack embed script.')); + }; + + script.addEventListener('load', handleLoad, { once: true }); + script.addEventListener('error', handleError, { once: true }); + + if (!existingScript) { + script.src = SNACK_EMBED_SCRIPT_SRC; + script.async = true; + document.head.appendChild(script); + } + }); + + return snackEmbedScriptPromise; +} + +export function ExpoSnackEmbed({ + snackId, + platform = 'web', + preview = true, + height = '505px', +}: Props) { + const containerRef = useRef(null); + + useEffect(() => { + const container = containerRef.current; + let isDisposed = false; + + const initializeEmbed = async () => { + await loadSnackEmbedScript(); + + if (isDisposed || !container) { + return; + } + + window.ExpoSnack?.remove?.(container); + window.ExpoSnack?.append?.(container); + }; + + initializeEmbed().catch((error) => { + console.error('Failed to initialize Expo Snack embed:', error); + }); + + return () => { + isDisposed = true; + + if (container) { + window.ExpoSnack?.remove?.(container); + } + }; + }, [platform, preview, snackId]); + + return ( +
+ ); +} diff --git a/docs/docs/1.x/en/guide/getting-started/quick-start.mdx b/docs/docs/1.x/en/guide/getting-started/quick-start.mdx index 7f0c327..7e7c2b9 100644 --- a/docs/docs/1.x/en/guide/getting-started/quick-start.mdx +++ b/docs/docs/1.x/en/guide/getting-started/quick-start.mdx @@ -1,3 +1,5 @@ +import { ExpoSnackEmbed } from '../../../../../components/ExpoSnackEmbed'; + # Quick Start Create one typed deck family for your item type. `Root`, `Card`, hooks, actions, @@ -5,8 +7,12 @@ and events from that factory share the same registry namespace. ## Examples & Demo -[📁 Example Project](https://github.com/react-native-motion-kit/react-native-swipe-deck/tree/main/example) - -Real implementation code with various use cases. +- [📁 Example Project](https://github.com/react-native-motion-kit/react-native-swipe-deck/tree/main/example) - + Real implementation code with various use cases. +- [🤖 Expo Snack](https://snack.expo.dev/@harang/react-native-swipe-deck) - + Try it instantly on Expo Snack. + + ```tsx import { Text, View } from 'react-native'; diff --git a/docs/docs/1.x/ko/guide/getting-started/quick-start.mdx b/docs/docs/1.x/ko/guide/getting-started/quick-start.mdx index 5ffc522..62352d6 100644 --- a/docs/docs/1.x/ko/guide/getting-started/quick-start.mdx +++ b/docs/docs/1.x/ko/guide/getting-started/quick-start.mdx @@ -1,3 +1,5 @@ +import { ExpoSnackEmbed } from '../../../../../components/ExpoSnackEmbed'; + # 빠른 시작 Item type에 맞는 typed deck family를 하나 만드세요. 같은 factory의 `Root`, `Card`, @@ -5,8 +7,12 @@ hook, action, event가 같은 registry namespace를 공유합니다. ## 예제 & 데모 -[📁 예제 프로젝트](https://github.com/react-native-motion-kit/react-native-swipe-deck/tree/main/example) - -다양한 use case를 담은 실제 구현 코드입니다. +- [📁 예제 프로젝트](https://github.com/react-native-motion-kit/react-native-swipe-deck/tree/main/example) - + 다양한 use case를 담은 실제 구현 코드입니다. +- [🤖 Expo Snack](https://snack.expo.dev/@harang/react-native-swipe-deck) - + Expo Snack에서 바로 체험할 수 있습니다. + + ```tsx import { Text, View } from 'react-native'; diff --git a/docs/expo-snack.d.ts b/docs/expo-snack.d.ts new file mode 100644 index 0000000..fdf419b --- /dev/null +++ b/docs/expo-snack.d.ts @@ -0,0 +1,7 @@ +interface Window { + ExpoSnack?: { + append?: (element: HTMLElement) => void; + initialize?: () => void; + remove?: (element: HTMLElement) => void; + }; +} diff --git a/docs/tsconfig.json b/docs/tsconfig.json index fa4849d..2ce14f9 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -13,10 +13,11 @@ "useDefineForClassFields": true, "allowImportingTsExtensions": true, "paths": { + "@components": ["./components"], "@theme": ["./theme"] } }, - "include": ["docs/**/*", "theme/**/*", "rspress.config.ts"], + "include": ["docs/**/*", "theme/**/*", "rspress.config.ts", "components/**/*", "expo-snack.d.ts"], "mdx": { "checkMdx": true } diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..3d14b48 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,26 @@ +const reactNativePackages = [ + '(jest-)?react-native', + '@react-native(-community)?', + 'react-native-gesture-handler', + 'react-native-reanimated', + 'react-native-worklets', +]; + +const pnpmReactNativePackages = [ + '(jest-)?react-native', + 'react-native-gesture-handler', + 'react-native-reanimated', + 'react-native-worklets', +]; + +module.exports = { + modulePathIgnorePatterns: ['/example/node_modules', '/lib/'], + preset: '@react-native/jest-preset', + resolver: 'react-native-worklets/jest/resolver', + setupFiles: ['react-native-gesture-handler/jestSetup.js'], + setupFilesAfterEnv: ['/jest-setup.js'], + transformIgnorePatterns: [ + `node_modules/(?!(${reactNativePackages.join('|')}|\\.pnpm)/)`, + `node_modules/.pnpm/(?!(${pnpmReactNativePackages.join('|')})@|@react-native\\+|@react-native-community\\+)`, + ], +}; diff --git a/package.json b/package.json index 0f3dfdc..764484f 100644 --- a/package.json +++ b/package.json @@ -120,23 +120,6 @@ "@commitlint/config-conventional" ] }, - "jest": { - "modulePathIgnorePatterns": [ - "/example/node_modules", - "/lib/" - ], - "preset": "@react-native/jest-preset", - "resolver": "react-native-worklets/jest/resolver", - "setupFiles": [ - "react-native-gesture-handler/jestSetup.js" - ], - "setupFilesAfterEnv": [ - "/jest-setup.js" - ], - "transformIgnorePatterns": [ - "node_modules/(?!((jest-)?react-native|@react-native(-community)?|react-native-gesture-handler|react-native-reanimated|react-native-worklets)/)" - ] - }, "packageManager": "pnpm@11.7.0", "create-react-native-library": { "type": "library", diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 23a34d6..182d1fd 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,7 +2,6 @@ packages: - . - example - docs -nodeLinker: hoisted autoInstallPeers: true allowBuilds: lefthook: true