From bd3ddc174cef1bb9b4938872c32bc76fedfc1e89 Mon Sep 17 00:00:00 2001 From: harang Date: Fri, 26 Jun 2026 18:57:12 +0900 Subject: [PATCH 1/2] docs: establish Rspress docs as the library reference Add a v1-only Rspress documentation workspace for English and Korean guides. The npm README is now compact, while generated AI-readable markdown is exposed for agents until the public docs URL exists. Constraint: Public docs deployment URL is not available yet Constraint: Bob declaration generation must stay scoped to src Rejected: Keep README as the full reference | detailed guidance now belongs in docs site Confidence: high Scope-risk: moderate Directive: Do not let docs participate in library declaration builds Tested: yarn build Tested: yarn typecheck Tested: yarn workspace @react-native-motion-kit/swipe-deck-docs typecheck Tested: yarn workspace @react-native-motion-kit/swipe-deck-docs build Tested: yarn format:check; yarn lint; git diff --check --- .changeset/bright-docs-arrive.md | 5 + README.ko.md | 692 +---- README.md | 702 +---- docs/.gitignore | 14 + docs/docs/1.x/en/_nav.json | 7 + docs/docs/1.x/en/guide/_meta.json | 12 + .../1.x/en/guide/getting-started/_meta.json | 1 + docs/docs/1.x/en/guide/getting-started/ai.mdx | 73 + .../en/guide/getting-started/installation.mdx | 47 + .../1.x/en/guide/getting-started/overview.mdx | 65 + .../en/guide/getting-started/quick-start.mdx | 103 + docs/docs/1.x/en/guide/usage/_meta.json | 11 + .../docs/1.x/en/guide/usage/api-reference.mdx | 133 + docs/docs/1.x/en/guide/usage/basic-usage.mdx | 80 + docs/docs/1.x/en/guide/usage/deck-hooks.mdx | 100 + .../1.x/en/guide/usage/handling-events.mdx | 80 + docs/docs/1.x/en/guide/usage/motion.mdx | 139 + .../guide/usage/multi-instance-management.mdx | 58 + .../en/guide/usage/programmatic-actions.mdx | 75 + docs/docs/1.x/en/guide/usage/undo.mdx | 77 + .../en/guide/usage/visible-card-budget.mdx | 45 + docs/docs/1.x/en/index.md | 50 + docs/docs/1.x/ko/_nav.json | 7 + docs/docs/1.x/ko/guide/_meta.json | 12 + .../1.x/ko/guide/getting-started/_meta.json | 1 + docs/docs/1.x/ko/guide/getting-started/ai.mdx | 69 + .../ko/guide/getting-started/installation.mdx | 45 + .../1.x/ko/guide/getting-started/overview.mdx | 60 + .../ko/guide/getting-started/quick-start.mdx | 103 + docs/docs/1.x/ko/guide/usage/_meta.json | 11 + .../docs/1.x/ko/guide/usage/api-reference.mdx | 130 + docs/docs/1.x/ko/guide/usage/basic-usage.mdx | 78 + docs/docs/1.x/ko/guide/usage/deck-hooks.mdx | 97 + .../1.x/ko/guide/usage/handling-events.mdx | 78 + docs/docs/1.x/ko/guide/usage/motion.mdx | 133 + .../guide/usage/multi-instance-management.mdx | 56 + .../ko/guide/usage/programmatic-actions.mdx | 73 + docs/docs/1.x/ko/guide/usage/undo.mdx | 74 + .../ko/guide/usage/visible-card-budget.mdx | 44 + docs/docs/1.x/ko/index.md | 50 + docs/docs/env.d.ts | 11 + docs/docs/public/logo.png | Bin 0 -> 184611 bytes docs/package.json | 21 + docs/rspress.config.ts | 63 + docs/theme/index.css | 8 + docs/theme/index.tsx | 73 + docs/tsconfig.json | 23 + package.json | 18 +- tsconfig.build.json | 1 + tsconfig.json | 3 +- yarn.lock | 2512 ++++++++++++++++- 51 files changed, 5035 insertions(+), 1388 deletions(-) create mode 100644 .changeset/bright-docs-arrive.md create mode 100644 docs/.gitignore create mode 100644 docs/docs/1.x/en/_nav.json create mode 100644 docs/docs/1.x/en/guide/_meta.json create mode 100644 docs/docs/1.x/en/guide/getting-started/_meta.json create mode 100644 docs/docs/1.x/en/guide/getting-started/ai.mdx create mode 100644 docs/docs/1.x/en/guide/getting-started/installation.mdx create mode 100644 docs/docs/1.x/en/guide/getting-started/overview.mdx create mode 100644 docs/docs/1.x/en/guide/getting-started/quick-start.mdx create mode 100644 docs/docs/1.x/en/guide/usage/_meta.json create mode 100644 docs/docs/1.x/en/guide/usage/api-reference.mdx create mode 100644 docs/docs/1.x/en/guide/usage/basic-usage.mdx create mode 100644 docs/docs/1.x/en/guide/usage/deck-hooks.mdx create mode 100644 docs/docs/1.x/en/guide/usage/handling-events.mdx create mode 100644 docs/docs/1.x/en/guide/usage/motion.mdx create mode 100644 docs/docs/1.x/en/guide/usage/multi-instance-management.mdx create mode 100644 docs/docs/1.x/en/guide/usage/programmatic-actions.mdx create mode 100644 docs/docs/1.x/en/guide/usage/undo.mdx create mode 100644 docs/docs/1.x/en/guide/usage/visible-card-budget.mdx create mode 100644 docs/docs/1.x/en/index.md create mode 100644 docs/docs/1.x/ko/_nav.json create mode 100644 docs/docs/1.x/ko/guide/_meta.json create mode 100644 docs/docs/1.x/ko/guide/getting-started/_meta.json create mode 100644 docs/docs/1.x/ko/guide/getting-started/ai.mdx create mode 100644 docs/docs/1.x/ko/guide/getting-started/installation.mdx create mode 100644 docs/docs/1.x/ko/guide/getting-started/overview.mdx create mode 100644 docs/docs/1.x/ko/guide/getting-started/quick-start.mdx create mode 100644 docs/docs/1.x/ko/guide/usage/_meta.json create mode 100644 docs/docs/1.x/ko/guide/usage/api-reference.mdx create mode 100644 docs/docs/1.x/ko/guide/usage/basic-usage.mdx create mode 100644 docs/docs/1.x/ko/guide/usage/deck-hooks.mdx create mode 100644 docs/docs/1.x/ko/guide/usage/handling-events.mdx create mode 100644 docs/docs/1.x/ko/guide/usage/motion.mdx create mode 100644 docs/docs/1.x/ko/guide/usage/multi-instance-management.mdx create mode 100644 docs/docs/1.x/ko/guide/usage/programmatic-actions.mdx create mode 100644 docs/docs/1.x/ko/guide/usage/undo.mdx create mode 100644 docs/docs/1.x/ko/guide/usage/visible-card-budget.mdx create mode 100644 docs/docs/1.x/ko/index.md create mode 100644 docs/docs/env.d.ts create mode 100644 docs/docs/public/logo.png create mode 100644 docs/package.json create mode 100644 docs/rspress.config.ts create mode 100644 docs/theme/index.css create mode 100644 docs/theme/index.tsx create mode 100644 docs/tsconfig.json diff --git a/.changeset/bright-docs-arrive.md b/.changeset/bright-docs-arrive.md new file mode 100644 index 0000000..0b1e560 --- /dev/null +++ b/.changeset/bright-docs-arrive.md @@ -0,0 +1,5 @@ +--- +'@react-native-motion-kit/swipe-deck': patch +--- + +Add the Rspress documentation site and refresh the npm package metadata. diff --git a/README.ko.md b/README.ko.md index a87defd..797fc51 100644 --- a/README.ko.md +++ b/README.ko.md @@ -6,15 +6,16 @@ React Native Motion Kit logo -Reanimated와 Gesture Handler 기반의 고성능 React Native용 Tinder 스타일 swipe deck / swipe card 라이브러리입니다. +Reanimated, Worklets, Gesture Handler 기반의 고성능 React Native용 Tinder 스타일 +swipe deck / swipe card 라이브러리입니다. ## 특징 - **작은 render window**: 현재 카드와 bounded forward stack만 mount합니다. - **Item-keyed rendering**: promoted card가 React Native view identity를 유지합니다. - **Typed compound API**: `createSwipeDeck()`로 typed deck family를 만듭니다. -- **Motion preset**: Tinder 스타일 drag, rotation, dismiss, next-card, action motion을 조정합니다. -- **Reanimated-first**: gesture/animation 상태를 shared value와 worklet 중심으로 유지합니다. +- **Deck hooks**: state, action, event, animated overlay를 같은 factory에서 다룹니다. +- **Motion recipes**: gesture motion, programmatic action, undo restore를 따로 조정합니다. ## 설치 @@ -25,693 +26,56 @@ npm install @react-native-motion-kit/swipe-deck react-native-gesture-handler rea 사용 중인 React Native 또는 Expo 버전에 맞춰 Reanimated/Worklets 설정을 완료하세요. Babel 설정에서는 `react-native-worklets/plugin`을 마지막 Babel plugin으로 추가해야 합니다. -### 최소 지원 버전 - -| Package | Minimum | -| ------------------------------ | -------- | -| `react` | `18.0.0` | -| `react-native` | `0.75.0` | -| `react-native-gesture-handler` | `2.24.0` | -| `react-native-reanimated` | `4.0.0` | -| `react-native-worklets` | `0.5.0` | - ## 빠른 시작 -`Root`, `Card`, 외부 action, state, interaction hook이 같은 factory instance를 공유해야 한다면 item type에 맞는 typed deck family를 하나 만드세요. - ```tsx +import { Text, View } from 'react-native'; import { createSwipeDeck, SwipeDeckMotion } from '@react-native-motion-kit/swipe-deck'; -const ProfileDeck = createSwipeDeck({ - motion: SwipeDeckMotion.tinder({ - drag: { - mode: 'horizontal', - liftYFactor: 0.15, - }, - rotation: { - mode: 'grab-position', - }, - dismiss: { - threshold: ({ width }) => width * 0.3, - velocityThreshold: 800, - minDuration: 300, - maxDuration: 520, - }, - }), -}); - -function ProfileDeckEvents() { - ProfileDeck.useDeckEventListener('swipe', ({ item, direction, source }) => { - console.log(item, direction, source); - }); - ProfileDeck.useDeckEventListener('endReached', () => { - console.log('No more cards'); - }); - - return null; -} - -function ProfileDeckScreen() { - return ( - <> - - item.id} visibleCardCount={3}> - - {({ item, role, isActive }) => ( - - )} - - - - ); -} -``` - -## 핵심 개념 - -### Bounded forward window - -Deck은 전체 data set을 한 번에 렌더링하지 않습니다. - -기본적으로 active index부터 최대 **3개의 item-keyed card**를 mount합니다. - -1. current card -2. next card -3. next buffered card - -이 방식은 dismissed previous card를 다시 채우지 않으면서도 현재 카드와 들어오는 stack의 연속성을 유지합니다. - -`visibleCardCount`는 최대 예산입니다. - -- 기본값은 더 자연스러운 next-card promotion을 위해 `3`입니다. -- `1`보다 작은 값은 데이터가 충분할 때 `1`로 정규화됩니다. -- `visibleCardCount={1}`는 현재 카드만 렌더링하므로 next-card stack/promotion 시각 효과는 보이지 않습니다. -- `visibleCardCount={2}`는 현재 카드와 바로 다음 카드만 렌더링합니다. -- 실제 mount 개수는 active index부터 남은 데이터 개수를 넘지 않습니다. -- 짝수 값은 그대로 최대 예산으로 유지되며, 홀수로 올림 처리하지 않습니다. - -### 안정적인 item key - -`getKey`는 card identity 렌더링 계약의 일부이므로 필수입니다. - -Key는 다음 조건을 만족해야 합니다. - -- 같은 logical item은 swipe가 진행되어도 같은 key를 반환해야 합니다. -- 서로 다른 item은 같은 key를 공유하지 않는 것이 좋습니다. - -그래야 promoted card가 React Native view identity를 유지하고, 다른 item의 native text subtree를 재사용하지 않습니다. - -### Typed compound API - -주요 API는 compound/slot 기반입니다. - -- `Root`는 data, gesture state, deck-level option을 소유합니다. -- `Card`는 각 item의 rendering을 정의합니다. -- `createSwipeDeck()`는 typed component family를 만듭니다. - -```tsx -const ProfileDeck = createSwipeDeck(); - -function ProfileDeckScreen() { - return ( - item.id}> - {({ item }) => } - - ); -} -``` - -이렇게 하면 `Root`, `Card`, 앞으로 추가될 slot들이 JSX에서 generic을 반복하지 않고 같은 item type을 공유할 수 있습니다. - -`allowedDirections`는 하나의 Root에서 dismiss로 받아들일 방향을 제한합니다. - -```tsx - item.id} allowedDirections={['right']}> - {({ item }) => } - -``` - -- `allowedDirections`를 생략하면 양방향을 모두 허용합니다. -- `['right']` 또는 `['left']`는 해당 dismiss 방향만 허용합니다. -- `[]`는 card drag 자체는 가능하지만, 손을 놓으면 항상 snap-back되고 `swipeLeft()` / `swipeRight()`는 `false`를 반환합니다. -- `canSwipe`는 “dismiss action이 현재 받아들여질 수 있는가”를 의미합니다. 허용된 방향이 없으면 `false`가 됩니다. - -Hook과 외부 UI가 공유할 수 있는 이름 붙은 factory instance가 필요하면 이 factory pattern을 -사용하세요. - -### Deck hooks - -Factory hook은 Provider를 추가하거나 controller prop을 tree로 넘기지 않고도 deck 전체 state, -action, Reanimated interaction 값을 제공합니다. Hook은 `createSwipeDeck()`로 만든 factory -instance에 scope됩니다. - -```tsx -// profile-deck.ts -export const ProfileDeck = createSwipeDeck(); -``` - -Counter와 button처럼 React로 렌더링되는 UI에는 state/action hook을 사용하세요. - -```tsx -function ProfileDeckControls() { - const { activeIndex, count, canSwipe, canUndo, isCompleted } = ProfileDeck.useDeckState(); - const { swipeLeft, swipeRight, undo } = ProfileDeck.useDeckActions(); - const current = activeIndex >= 0 ? activeIndex + 1 : 0; - - return ( - - {isCompleted ? 'Done' : `${current} / ${count}`} - - Nope - - - Undo - - - Like - - - ); -} -``` - -Swipe 진행도에 따라 움직이는 animated UI에는 interaction shared value를 사용하세요. 이 값들은 -UI thread에서 업데이트되고 gesture의 매 frame마다 React rerender를 만들지 않습니다. - -```tsx -function SwipeReactionOverlay() { - const { signedProgress } = ProfileDeck.useDeckInteraction(); - - const likeStyle = useAnimatedStyle(() => { - const progress = Math.max(signedProgress.get(), 0); - - return { - opacity: progress, - transform: [{ scale: 0.9 + progress * 0.18 }], - }; - }); - - return ; -} -``` - -Swipe, undo, index 변경, end reached 같은 commit된 model event에는 event hook을 사용하세요. - -```tsx -function ProfileDeckEvents() { - const lastSwipe = ProfileDeck.useDeckEvent('swipe', null); - const endReached = ProfileDeck.useDeckEvent('endReached', false); - - ProfileDeck.useDeckEventListener('undo', ({ item }) => { - console.log('Restored', item); - }); - - return ( - - {endReached - ? 'Done' - : lastSwipe - ? `Last swipe: ${lastSwipe.direction} from ${lastSwipe.source}` - : 'No swipe yet'} - - ); -} -``` - -Event hook은 commit 단위의 latest-value API입니다. - -- `useDeckEvent()`는 event name별 최신 event 하나만 저장합니다. Event history가 아닙니다. -- `initialValue`는 event payload shape, `null`, `undefined`, 또는 `endReached`의 `false`로 제한됩니다. - `swipe` 같은 object event에는 `null`을 사용하세요. `{}`는 event payload 타입을 넓혀버리지 않도록 의도적으로 막습니다. -- Object initial value를 넘기면 `eventName`을 기준으로 contextual typing이 걸립니다. - 그래서 `useDeckEvent('swipe', { ... })`에서는 `item`, `index`, `direction`, `source`가 자동완성됩니다. -- Swipe event에는 `source: 'gesture' | 'programmatic'`이 포함됩니다. `gesture`는 사용자가 pan - gesture를 threshold/velocity 기준 이상으로 놓아서 commit된 경우입니다. `programmatic`은 - `actions.swipeLeft()` 또는 `actions.swipeRight()`로 commit된 경우이며, button을 뜻하지는 - 않습니다. 앱 UI에서 그 action을 button으로만 호출한다면 앱에서 button 의미로 매핑하면 됩니다. -- Initial value 없이 named deck을 읽어야 한다면 id를 두 번째 인자로 넘기면 됩니다. - `useDeckEvent('swipe', 'nearby')`처럼 사용할 수 있고, initial value도 함께 넘기는 경우에는 id가 세 번째 인자입니다. -- Root가 attach될 때와 detach될 때 event snapshot은 clear됩니다. 그래서 fresh/detached deck에서는 - hook이 `initialValue`를 반환합니다. -- `useDeckEventListener()`는 imperative 구독입니다. Mounted listener는 attach/detach를 지나도 - 같은 factory/id store에 구독된 상태를 유지하지만, active Root가 새 event를 emit할 때만 실행됩니다. -- Event는 commit path에서 emit됩니다. 같은 tick 안에서는 event payload가 해당 event의 source of truth이고, - 뒤따르는 `useDeckState()` render는 event 직후에 settle될 수 있습니다. - -그리고 같은 factory의 Root 주변에서 control을 렌더링합니다. - -```tsx -function ProfileDeckScreen() { - return ( - - item.id} undoEnabled> - - {({ item, isActive }) => ( - - - {isActive ? : null} - - )} - - - - - ); -} -``` - -- `useDeckState(id?)`는 `activeIndex`, `count`, `isCompleted`, `canSwipe`, `canUndo` 같은 React 렌더링용 deck state를 반환합니다. - 현재 item이 필요하면 deck state가 primitive하고 stable하게 유지되도록 사용자의 `data[activeIndex]`에서 직접 계산하세요. -- `useDeckActions(id?)`는 `swipeLeft()`, `swipeRight()`, `undo()` 같은 stable action을 반환합니다. - swipe action은 실행이 받아들여지면 `true`, deck이 아직 연결되지 않았거나 disabled/animating/layout 미측정/완료 상태라면 `false`를 반환합니다. - `undo()`는 deck이 완료된 뒤에도 `canUndo`가 true라면 `true`를 반환합니다. -- `useDeckInteraction(id?)`는 progress 기반 UI를 위한 Reanimated shared value를 반환합니다. - gesture progress는 UI thread에 남고, 매 frame React rerender를 만들지 않습니다. - - `interaction.phase`는 UI thread lifecycle signal입니다: - `idle | dragging | dismissing | undoing`. - - deck이 drag 중인지, dismiss 중인지, restore 중인지 알아야 하는 visual feedback에는 - `phase`를 사용하세요. swipe, undo, index change처럼 commit된 model event는 - `useDeckEvent` / `useDeckEventListener`를 사용하세요. - - `dismissing`은 dismiss가 accepted된 뒤 다음 item commit과 interaction reset이 끝날 때까지의 - lifecycle을 포함합니다. 즉, 화면 밖으로 나가는 animation frame만 의미하지는 않습니다. - - `interaction.direction`은 raw live drag/dismiss signal입니다(`-1 | 0 | 1`). - 외부 UI가 UI thread에서 accepted dismiss 방향(`left | right | null`)을 알아야 한다면 - `interaction.dismissDirection`을 사용하세요. `dismissDirection`은 lifecycle state이지, - commit된 `swipe` event payload가 아닙니다. - - programmatic springboard action은 action이 받아들여지는 즉시 `dismissing`으로 들어갑니다. - anticipation 중에는 실제 dismiss phase가 시작되기 전까지 `interaction.direction`이 neutral일 수 있지만, - `interaction.dismissDirection`에는 이미 accepted action direction이 들어있습니다. -- `useDeckEvent(eventName, initialValue?, id?)`는 React 렌더링용 최신 commit event를 반환합니다. - 첫 event 전과 deck이 detach된 뒤에는 `undefined` 또는 `initialValue`를 반환합니다. -- `useDeckEventListener(eventName, listener, id?)`는 앱 코드에서 별도 state를 만들지 않고 commit된 model event를 구독합니다. - listener hook은 unmount 시 자동으로 정리됩니다. - 성공한 swipe는 `swipe -> indexChange -> endReached` 순서로 emit됩니다. Undo는 - `undo -> indexChange` 순서로 emit됩니다. - -### Programmatic action motion - -`motion`은 손으로 drag하는 gesture 기반 deck feel을 제어합니다. `actionMotion`은 -`useDeckActions()`에서 실행하는 like/pass 버튼 같은 programmatic action만 제어합니다. -따라서 버튼으로 넘길 때의 움직임을 바꿔도 manual drag, threshold, flick 동작은 바뀌지 않습니다. - -```tsx -import { - createSwipeDeck, - SwipeDeckActionMotion, - SwipeDeckMotion, -} from '@react-native-motion-kit/swipe-deck'; +type Profile = { + id: string; + name: string; +}; const ProfileDeck = createSwipeDeck({ motion: SwipeDeckMotion.tinder(), - actionMotion: SwipeDeckActionMotion.springboard({ - anticipationDistance: ({ width }) => width * 0.04, - anticipationDuration: 80, - dismissDuration: 320, - }), -}); - -function LikeButton() { - const actions = ProfileDeck.useDeckActions(); - - return Like; -} -``` - -제공되는 recipe는 다음과 같습니다. - -- `SwipeDeckActionMotion.direct(options?)`: action 방향으로 바로 dismiss합니다. 생략한 값은 - deck에서 resolve된 dismiss duration, easing, offscreen multiplier를 재사용합니다. -- `SwipeDeckActionMotion.springboard(options?)`: 최종 방향의 반대쪽으로 살짝 움직인 뒤 화면 밖으로 - dismiss합니다. Anticipation 단계에서는 swipe progress를 중립으로 유지해 반대쪽 overlay가 - 순간적으로 보이지 않게 하며, `interaction.direction`도 dismiss phase가 시작될 때까지 - 중립으로 유지합니다. 생략한 dismiss 값은 deck에서 resolve된 dismiss duration, easing, - offscreen multiplier를 재사용합니다. - -특정 action 한 번만 override할 수도 있습니다. - -```tsx -actions.swipeLeft( - SwipeDeckActionMotion.direct({ - duration: 180, - }), -); -``` - -`actionMotion` 우선순위는 deep merge가 아니라 replacement 방식입니다. - -1. `createSwipeDeck({ actionMotion })`의 factory `actionMotion` -2. 해당 Root에서 factory default를 대체하는 `Root actionMotion` -3. `swipeLeft(recipe)` 또는 `swipeRight(recipe)`에 넘긴 per-call recipe - -Action은 callback으로 바로 넘겨도 안전합니다. React Native press event가 `swipeRight` 또는 -`swipeLeft`로 전달되면 그 event 인자는 무시하고 설정된 action motion을 사용합니다. - -### Undo / back swipe motion - -Undo는 opt-in입니다. 해당 deck에서 undo/back-swipe UX를 제공할 때 Root에 `undoEnabled`를 -추가하세요. 활성화되면 성공한 swipe마다 key/index/direction metadata entry 하나를 LIFO undo stack에 -저장합니다. Lookup은 현재 `data`에 대한 key-to-index map을 사용하고, data나 key가 바뀌면 invalid -entry를 prune합니다. 생략하면 성공한 swipe도 undo metadata를 저장하지 않고, `canUndo`는 `false`를 -유지하며, `actions.undo()`는 `false`를 반환합니다. - -Undo가 받아들여지면 deck은 main stack을 restored index 기준으로 잠시 렌더링하고, 그 실제 current -card를 카드가 원래 나갔던 방향에서 다시 중앙으로 들어오도록 animation한 뒤 restored index를 -commit합니다. - -```tsx -import { createSwipeDeck, SwipeDeckUndoMotion } from '@react-native-motion-kit/swipe-deck'; - -const ProfileDeck = createSwipeDeck({ - undoMotion: SwipeDeckUndoMotion.spring({ - springConfig: { - damping: 36, - stiffness: 300, - mass: 3, - }, - }), }); -function ProfileDeckExample() { +function ProfileCard({ profile }: { profile: Profile }) { return ( - item.id} undoEnabled> - {({ item }) => } - - ); -} - -function UndoButton() { - const state = ProfileDeck.useDeckState(); - const actions = ProfileDeck.useDeckActions(); - - return ( - - Undo - - ); -} -``` - -Undo는 기본적으로 비활성화되어 있으므로 undo control을 노출하지 않는 deck은 undo history 비용을 -내지 않습니다. `undoEnabled`를 켜면 key가 `data`에 남아 있는 동안 이전 swipe들을 LIFO 순서로 반복 -복원할 수 있습니다. 오래 실행되는 undo-enabled deck은 해당 entry가 undo되거나 data 변경으로 prune될 -때까지 accepted swipe마다 metadata entry 하나를 유지합니다. 기본 undo motion은 zero-duration -`SwipeDeckUndoMotion.timing()`을 사용하므로, 별도 motion을 설정하지 않으면 card를 즉시 복원합니다. - -제공되는 recipe는 다음과 같습니다. - -- `SwipeDeckUndoMotion.spring(options?)`: Reanimated `withSpring`으로 card를 복원합니다. -- `SwipeDeckUndoMotion.timing(options?)`: deterministic한 `withTiming`으로 card를 복원합니다. - -두 recipe는 공통으로 다음 옵션을 받습니다. - -- `from: 'auto' | 'left' | 'right'`: `auto`는 원래 swipe된 방향에서 card를 되돌립니다. -- `entryDistance`: 화면 밖 시작 거리를 number 또는 layout callback으로 지정합니다. - -`timing`은 `duration`, `easing`을 추가로 받고 기본 duration은 `0`입니다. `spring`은 `springConfig`를 받습니다. - -`undoMotion` 우선순위는 replacement 방식입니다. - -1. `createSwipeDeck({ undoMotion })`의 factory `undoMotion` -2. 해당 Root에서 factory default를 대체하는 `Root undoMotion` -3. `actions.undo(recipe)`에 넘긴 per-call recipe - -Undo도 callback으로 바로 넘겨도 안전합니다. React Native press event가 `undo`로 전달되면 그 -event 인자는 무시하고 설정된 undo motion을 사용합니다. Undo restore 중 public interaction 값 -(`progress`, `signedProgress`, `direction`, `translationX`, `translationY`)은 중립으로 유지되어, -progress 기반 swipe overlay가 순간적으로 깜빡이지 않습니다. - -같은 factory에서 여러 Root를 렌더링할 때만 `id`를 사용하세요. - -```tsx -function MultiDeckScreen() { - const nearbyState = ProfileDeck.useDeckState('nearby'); - - return ( - <> - item.id}> - {({ item }) => } - - - item.id}> - {({ item }) => } - - - {nearbyState.activeIndex + 1} - - ); -} -``` - -`id`는 item key가 아니라 factory 안에서 deck instance를 구분하는 namespace입니다. -서로 다른 factory는 둘 다 default id를 써도 충돌하지 않지만, 같은 factory와 같은 id의 Root 두 개가 동시에 mount되는 것은 잘못된 사용입니다. -id는 `"nearby"`, `"recommended"`처럼 화면/용도 단위의 안정적이고 적은 개수의 값으로 유지하세요. -Registry는 hook, action, interaction shared value의 identity를 안정적으로 유지하기 위해 factory lifetime 동안 id별 store를 유지합니다. -따라서 item id, timestamp, 매 render마다 바뀌는 값, 일회성 route 값에서 deck id를 만들지 마세요. -Factory와 id는 render path 밖에서 안정적으로 만들고 유지하세요. 동적 factory나 동적 id는 registry가 -의도적으로 안정적으로 유지하는 long-lived namespace를 계속 만들 수 있습니다. - -짧은 이름을 선호한다면 같은 factory instance에서 destructuring한 alias를 export해도 됩니다. - -```ts -const ProfileDeck = createSwipeDeck(); - -export const { - Root: ProfileDeckRoot, - Card: ProfileDeckCard, - useDeckState: useProfileDeckState, - useDeckActions: useProfileDeckActions, - useDeckInteraction: useProfileDeckInteraction, -} = ProfileDeck; -``` - -Factory는 deck family마다 한 번만 만들고 shared module에서 export하세요. Hook, action, interaction은 같은 factory instance에서 만든 Root에만 연결됩니다. item type과 id가 같아도 `createSwipeDeck()`를 다시 호출하면 별도 registry namespace가 만들어지므로, 한 factory의 hook으로 다른 factory의 Root를 제어할 수 없습니다. - -### 간단한 inline 사용 - -카드 렌더링만 필요하다면 factory instance를 만들지 않고 static API를 사용할 수 있습니다. -작은 inline deck에는 유용하지만, `useDeckState`, `useDeckActions`, `useDeckInteraction`, `useDeckEvent`, -`useDeckEventListener` 같은 factory hook은 노출하지 않습니다. -Static `Root`는 `id`를 받지 않습니다. 이름이 있는 deck state, action, interaction, model event가 필요하면 factory instance를 사용하세요. -Static `Root`와 `Card`는 factory처럼 item type을 함께 고정하지 않습니다. -따라서 card render prop에서 `item` 타입이 필요하면 `Card`에 item type을 직접 넘기세요. - -```tsx -import { SwipeDeck } from '@react-native-motion-kit/swipe-deck'; - -function InlineDeck() { - return ( - item.id}> - >{({ item }) => } - + + {profile.name} + ); } -``` - -## Motion - -### Swipe progress를 따라가는 것 - -Buffered next card는 swipe progress에 따라 애니메이션됩니다. - -- scale은 `1`에 가까워집니다. -- opacity는 `1`에 가까워집니다. -- `translateY`는 `0`에 가까워집니다. - -Swipe가 commit되면 다음 일이 일어납니다. - -- dismissed card는 화면 밖으로 나갑니다. -- promoted next card는 자신의 item identity를 유지합니다. -- 새로운 future item이 bounded window에 들어옵니다. - -이 동작은 `SwipeDeckMotion.tinder(...)` 같은 motion preset으로 조정합니다. - -### Drag mode - -`drag.mode`는 drag 중 active card가 손가락 translation을 어떻게 사용할지 제어합니다. - -| mode | Active card 움직임 | -| ------------ | ----------------------------------------------- | -| `free` | 손가락의 X/Y 이동을 모두 따라갑니다. | -| `horizontal` | 손가락의 Y 이동은 무시하고 X 이동만 반영합니다. | - -`drag.liftYFactor`는 active card를 `abs(translationX) * liftYFactor`만큼 위로 올립니다. - -```tsx -SwipeDeckMotion.tinder({ - drag: { - mode: 'horizontal', - liftYFactor: 0, - }, - rotation: { - mode: 'fixed', - origin: 'bottom-center', - }, -}); -``` - -`drag.mode: 'horizontal'`과 `rotation: { mode: 'fixed', origin: 'bottom-center' }`를 함께 쓰면 아래쪽 축을 기준으로 좌우로만 움직이는 느낌을 만들 수 있습니다. - -### Motion 우선순위 - -Motion 값은 다음 순서로 resolve됩니다. - -1. `createSwipeDeck({ motion })`의 factory motion default -2. 명시한 field만 부분 override하는 `Root motion` -3. `swipeThreshold`, `velocityThreshold` 같은 direct root prop - -Factory motion과 Root motion은 deep merge됩니다. `maxDegrees`, `inputRange` 같은 numeric rotation tuning은 Root motion에서 명시적으로 덮어쓰지 않는 한 유지되며, `rotation.mode`를 바꿔도 mode default로 reset되지 않습니다. - -### Motion preset 안정성 - -Motion preset은 module-scope constant 또는 `useMemo`로 안정적으로 유지하는 것을 권장합니다. - -안정적인 preset reference를 유지하면 Reanimated easing function이나 spring config object를 넘길 때 불필요한 gesture/worklet setup 재생성을 피할 수 있습니다. - -앱 전체 또는 deck family 단위 기본값은 render 바깥에서 정의하고 factory에 넘기세요. - -```tsx -const profileDeckMotion = SwipeDeckMotion.tinder({ - rotation: { - mode: 'fixed', - origin: 'bottom-center', - }, - dismiss: { - threshold: ({ width }) => width * 0.3, - }, -}); - -const ProfileDeck = createSwipeDeck({ - motion: profileDeckMotion, -}); -``` - -Motion이 props 또는 state에 의존한다면 call site에서 config를 memoize하세요. - -```tsx -function ProfileScreen({ slowMotion }: { slowMotion: boolean }) { - const motion = useMemo( - () => - SwipeDeckMotion.tinder({ - dismiss: { - minDuration: slowMotion ? 420 : 220, - maxDuration: slowMotion ? 700 : 420, - }, - }), - [slowMotion], - ); +export function ProfileDeckScreen({ profiles }: { profiles: Profile[] }) { return ( - item.id} motion={motion}> + item.id} visibleCardCount={3}> {({ item }) => } ); } ``` -### Rotation - -`rotation.mode`는 회전 기준점을 고정할지, gesture 시작 위치에서 계산할지 제어합니다. 기본값은 Tinder-like `mode: 'grab-position'`입니다. Rotation 설정은 swipe 인식을 바꾸지 않습니다. 다만 `dismiss.duration`을 생략하면 release target을 회전된 card geometry로 계산하기 때문에 velocity-derived dismiss timing은 달라질 수 있습니다. - -#### Fixed rotation - -기본 grab-position 동작 대신 모든 gesture가 같은 anchor를 사용해야 한다면 fixed rotation을 사용하세요. - -| origin | 느낌 | -| --------------- | --------------------------------------------------------------------------------------------------------------------------- | -| `center` | 카드 중앙을 기준으로 회전합니다. | -| `top-center` | 카드의 위쪽 중앙 edge를 기준으로 회전합니다. 위쪽은 거의 고정된 축처럼 느껴지고, 아래쪽은 더 큰 원호를 그리며 움직입니다. | -| `bottom-center` | 카드의 아래쪽 중앙 edge를 기준으로 회전합니다. 아래쪽은 거의 고정된 축처럼 느껴지고, 위쪽은 더 큰 원호를 그리며 움직입니다. | - -```tsx -SwipeDeckMotion.tinder({ - rotation: { - mode: 'fixed', - origin: 'bottom-center', - direction: 'default', - }, -}); -``` +Control, animated overlay, commit event가 필요하다면 같은 factory Root 주변에서 +`ProfileDeck.useDeckState()`, `ProfileDeck.useDeckActions()`, +`ProfileDeck.useDeckInteraction()`, `ProfileDeck.useDeckEvent()`, +`ProfileDeck.useDeckEventListener()`를 사용하세요. -같은 고정 anchor에서 회전 부호만 반대로 만들고 싶다면 `direction: 'reverse'`를 사용하세요. +## 문서 -#### Grab-position rotation - -Grab-position rotation은 기본 Tinder-like 동작입니다. `maxDegrees`, `inputRange` 같은 공통 rotation 값만 덮어쓰고 싶을 때 명시적으로 사용하세요. - -```tsx -SwipeDeckMotion.tinder({ - rotation: { - mode: 'grab-position', - direction: 'default', - maxDegrees: 25, - }, -}); -``` - -카드 위쪽에서 잡으면 top-center anchor와 default rotation sign을 사용합니다. 아래쪽에서 잡으면 bottom-center anchor와 reverse rotation sign을 사용합니다. `direction: 'reverse'`를 주면 이 mapping을 뒤집습니다. `maxDegrees`, `inputRange`는 계속 설정할 수 있지만, 이 mode에서는 고정 `origin`은 의도적으로 받지 않습니다. - -같은 `maxDegrees` 값도 edge 기반 rotation에서는 더 강하게 느껴집니다. 그래서 Tinder preset은 `maxDegrees`를 직접 지정하지 않은 경우 `top-center`, `bottom-center`, `grab-position`에 더 작은 기본 회전 각도를 사용합니다. - -### Dismiss target - -`dismiss.offscreenMultiplier`는 성공한 swipe의 release target을 제어합니다. - -- 성공한 swipe는 항상 화면 밖으로 dismiss됩니다. -- 기본값 `1.5`는 카드를 `clearDistance * 1.5` 위치로 보냅니다. -- `clearDistance`는 손을 놓는 순간의 실제 swipe direction, rotation mode, rotation direction, gesture start position으로 계산합니다. -- `1`보다 작은 값은 `1`로 정규화됩니다. -- `duration`을 생략하면 release velocity와 target까지 남은 거리로 duration을 계산합니다. - -대부분의 앱은 이 옵션을 생략하고 다음 값만 조정하면 됩니다. - -- `threshold` -- `velocityThreshold` -- `duration`, `minDuration`, `maxDuration` -- Reanimated `easing` - -`dismiss.easing`은 Reanimated `withTiming`과 같은 easing 값을 받습니다. -기본값은 `Easing.out(Easing.cubic)`입니다. - -## Visible card budget - -```tsx -function CurrentOnlyDeck() { - return ( - item.id} visibleCardCount={1}> - {/* 가장 가벼운 예산: 현재 카드만 렌더링, next-card promotion 시각 효과 없음 */} - - ); -} - -function DefaultDeck() { - return ( - item.id} visibleCardCount={3}> - {/* default budget for smoother next-card promotion */} - - ); -} - -function DeepStackDeck() { - return ( - item.id} visibleCardCount={9}> - {/* deeper stacked UI */} - - ); -} -``` +공개 사이트를 준비하는 동안 전체 가이드는 이 저장소의 `docs/` 아래에서 관리합니다. -| 입력 | Mount되는 card | -| ---------------------------------------------- | -------------------------------------------------------- | -| `visibleCardCount={1}` | 현재 카드만 | -| `visibleCardCount={2}` | 데이터가 충분할 때 최대 `2`개 | -| 남은 데이터가 10개이고 `visibleCardCount={20}` | 최대 남은 10개 | -| 짝수 값 | 최대 예산으로 그대로 유지되며, 홀수로 올림 처리하지 않음 | +- [개요](docs/docs/1.x/ko/guide/getting-started/overview.mdx) +- [빠른 시작](docs/docs/1.x/ko/guide/getting-started/quick-start.mdx) +- [API 레퍼런스](docs/docs/1.x/ko/guide/usage/api-reference.mdx) +- [AI 사용 가이드](docs/docs/1.x/ko/guide/getting-started/ai.mdx) -## 기여하기 +AI가 읽기 좋은 문서는 docs build 시 생성됩니다. -- [Development workflow](CONTRIBUTING.md#development-workflow) -- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request) -- [Code of conduct](CODE_OF_CONDUCT.md) +- [llms.txt](docs/doc_build/ko/llms.txt) +- [llms-full.txt](docs/doc_build/ko/llms-full.txt) ## 라이선스 diff --git a/README.md b/README.md index 7711ef0..a5ad9fb 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,16 @@ React Native Motion Kit logo -High-performance Tinder-style swipe deck and swipe cards for React Native, powered by Reanimated and Gesture Handler. +High-performance Tinder-style swipe deck and swipe cards for React Native, +powered by Reanimated, Worklets, and Gesture Handler. ## Highlights - **Small render window**: mounts only the active card and a bounded forward stack. - **Item-keyed rendering**: promoted cards keep their React Native view identity. - **Typed compound API**: create one typed deck family with `createSwipeDeck()`. -- **Motion presets**: tune Tinder-style drag, rotation, dismiss, next-card, and action motion. -- **Reanimated-first**: gesture and animation state stays on shared values/worklets. +- **Deck hooks**: read state, run actions, subscribe to events, and drive animated overlays. +- **Motion recipes**: tune gesture motion, programmatic actions, and undo restores separately. ## Installation @@ -25,700 +26,57 @@ npm install @react-native-motion-kit/swipe-deck react-native-gesture-handler rea Then follow the Reanimated/Worklets setup for your React Native or Expo version. Make sure `react-native-worklets/plugin` is the last Babel plugin. -### Minimum versions - -| Package | Minimum | -| ------------------------------ | -------- | -| `react` | `18.0.0` | -| `react-native` | `0.75.0` | -| `react-native-gesture-handler` | `2.24.0` | -| `react-native-reanimated` | `4.0.0` | -| `react-native-worklets` | `0.5.0` | - -## Quick start - -Create one typed deck family for your item type when you want `Root`, `Card`, external actions, state, and interaction hooks to share the same factory instance. +## Quick Start ```tsx +import { Text, View } from 'react-native'; import { createSwipeDeck, SwipeDeckMotion } from '@react-native-motion-kit/swipe-deck'; -const ProfileDeck = createSwipeDeck({ - motion: SwipeDeckMotion.tinder({ - drag: { - mode: 'horizontal', - liftYFactor: 0.15, - }, - rotation: { - mode: 'grab-position', - }, - dismiss: { - threshold: ({ width }) => width * 0.3, - velocityThreshold: 800, - minDuration: 300, - maxDuration: 520, - }, - }), -}); - -function ProfileDeckEvents() { - ProfileDeck.useDeckEventListener('swipe', ({ item, direction, source }) => { - console.log(item, direction, source); - }); - ProfileDeck.useDeckEventListener('endReached', () => { - console.log('No more cards'); - }); - - return null; -} - -function ProfileDeckScreen() { - return ( - <> - - item.id} visibleCardCount={3}> - - {({ item, role, isActive }) => ( - - )} - - - - ); -} -``` - -## Core concepts - -### Bounded forward window - -The deck never renders the whole data set. - -By default, it mounts up to **3 item-keyed cards** from the active index forward: - -1. current card -2. next card -3. next buffered card - -This keeps the active/incoming stack continuous without backfilling dismissed previous cards. - -`visibleCardCount` is a maximum budget: - -- the default is `3` for smoother next-card promotion; -- values below `1` normalize to `1` when enough data exists; -- `visibleCardCount={1}` renders only the current card, so no next-card stack/promotion visual is shown; -- `visibleCardCount={2}` renders only the current card and the immediate next card; -- the mounted count never exceeds the remaining data from the active index; -- even values are kept as-is and are not rounded up. - -### Stable item keys - -`getKey` is required because card identity is part of the rendering contract. - -A key must be: - -- stable for the same logical item across swipes; -- unique across different items. - -That lets promoted cards keep their React Native view identity instead of reusing another item's native text subtree. - -### Typed compound API - -The primary API is compound/slot based: - -- `Root` owns data, gesture state, and deck-level options. -- `Card` defines how each item is rendered. -- `createSwipeDeck()` creates a typed component family. - -```tsx -const ProfileDeck = createSwipeDeck(); - -function ProfileDeckScreen() { - return ( - item.id}> - {({ item }) => } - - ); -} -``` - -This keeps `Root`, `Card`, and future slots on the same item type without repeating generics in JSX. - -`allowedDirections` limits which directions can be accepted as a dismiss for one Root: - -```tsx - item.id} allowedDirections={['right']}> - {({ item }) => } - -``` - -- Omit `allowedDirections` to allow both directions. -- `['right']` or `['left']` allows only that dismiss direction. -- `[]` still lets the card drag, but every release snaps back and `swipeLeft()` / `swipeRight()` return `false`. -- `canSwipe` means “a dismiss action can currently be accepted”; it becomes `false` when no direction is allowed. - -Use this factory pattern when the deck needs a named instance that can be shared by hooks and external UI. - -### Deck hooks - -Factory hooks expose deck-wide state, actions, and Reanimated interaction values without adding a -Provider or passing a controller prop through your tree. They are scoped to the factory instance -created by `createSwipeDeck()`. - -```tsx -// profile-deck.ts -export const ProfileDeck = createSwipeDeck(); -``` - -Use state/actions for React-rendered UI such as counters and buttons: - -```tsx -function ProfileDeckControls() { - const { activeIndex, count, canSwipe, canUndo, isCompleted } = ProfileDeck.useDeckState(); - const { swipeLeft, swipeRight, undo } = ProfileDeck.useDeckActions(); - const current = activeIndex >= 0 ? activeIndex + 1 : 0; - - return ( - - {isCompleted ? 'Done' : `${current} / ${count}`} - - Nope - - - Undo - - - Like - - - ); -} -``` - -Use interaction shared values for progress-driven animated UI. These values update on the UI thread -and do not rerender React every gesture frame: - -```tsx -function SwipeReactionOverlay() { - const { signedProgress } = ProfileDeck.useDeckInteraction(); - - const likeStyle = useAnimatedStyle(() => { - const progress = Math.max(signedProgress.get(), 0); - - return { - opacity: progress, - transform: [{ scale: 0.9 + progress * 0.18 }], - }; - }); - - return ; -} -``` - -Use event hooks for committed model events such as swipe, undo, index changes, and end reached: - -```tsx -function ProfileDeckEvents() { - const lastSwipe = ProfileDeck.useDeckEvent('swipe', null); - const endReached = ProfileDeck.useDeckEvent('endReached', false); - - ProfileDeck.useDeckEventListener('undo', ({ item }) => { - console.log('Restored', item); - }); - - return ( - - {endReached - ? 'Done' - : lastSwipe - ? `Last swipe: ${lastSwipe.direction} from ${lastSwipe.source}` - : 'No swipe yet'} - - ); -} -``` - -Event hooks are commit-level, latest-value APIs: - -- `useDeckEvent()` stores only the latest event for each event name. It is not an event history. -- `initialValue` is restricted to the event payload shape, `null`, `undefined`, or `false` for - `endReached`. Use `null` for object events such as `swipe`; `{}` is intentionally rejected so - the event payload type is not widened away. -- If you do pass an object initial value, the object is contextually typed from `eventName`, so - `useDeckEvent('swipe', { ... })` autocompletes `item`, `index`, `direction`, and `source`. -- Swipe events include `source: 'gesture' | 'programmatic'`. `gesture` means the user committed the - swipe by releasing a pan gesture past threshold/velocity. `programmatic` means the swipe was - committed through `actions.swipeLeft()` or `actions.swipeRight()`; apps may map that to a button - only when those actions are triggered by buttons in that app. -- For a named deck without an initial value, pass the id as the second argument: - `useDeckEvent('swipe', 'nearby')`. If you also pass an initial value, the id remains the third - argument. -- Event snapshots are cleared when a Root attaches and when it detaches, so the hook returns - `initialValue` for a fresh or detached deck. -- `useDeckEventListener()` is imperative. Mounted listeners stay subscribed to the factory/id - store across attach/detach, but they only run when the active Root emits a new event. -- Events are emitted from the commit path. During the same tick, the event payload is the source of - truth for that event; a following `useDeckState()` render can settle just after the event. - -Then render those controls around the same factory Root: - -```tsx -function ProfileDeckScreen() { - return ( - - item.id} undoEnabled> - - {({ item, isActive }) => ( - - - {isActive ? : null} - - )} - - - - - ); -} -``` - -- `useDeckState(id?)` returns React-rendered deck state such as `activeIndex`, `count`, - `isCompleted`, `canSwipe`, and `canUndo`. Derive the active item from your own - `data[activeIndex]` when needed so deck state stays primitive and stable. -- `useDeckActions(id?)` returns stable actions such as `swipeLeft()`, `swipeRight()`, - and `undo()`. - Swipe actions return `true` when accepted and `false` when the deck is unattached, disabled, - animating, unmeasured, or completed. `undo()` returns `true` when `canUndo` is true, including - after the deck is completed. -- `useDeckInteraction(id?)` returns Reanimated shared values for progress-driven UI. Gesture - progress stays on the UI thread and does not rerender React every frame. - - `interaction.phase` is a UI-thread lifecycle signal: - `idle | dragging | dismissing | undoing`. - - Use `phase` for visual feedback that needs to know whether the deck is actively dragging, - dismissing, or restoring. Use `useDeckEvent` / `useDeckEventListener` for committed model - events such as swipe, undo, and index changes. - - `dismissing` covers the accepted dismiss lifecycle until the deck has committed the next item - and reset interaction values. It is intentionally broader than only the offscreen animation - frames. - - `interaction.direction` is the raw live drag/dismiss signal (`-1 | 0 | 1`). Use - `interaction.dismissDirection` when external UI needs the accepted dismiss side - (`left | right | null`) on the UI thread. `dismissDirection` is lifecycle state, not the - committed `swipe` event payload. - - Programmatic springboard actions enter `dismissing` as soon as the action is accepted. During - anticipation, `interaction.direction` can still be neutral until the real dismiss phase starts, - while `interaction.dismissDirection` already contains the accepted action direction. -- `useDeckEvent(eventName, initialValue?, id?)` returns the latest committed deck event for - React-rendered UI. It returns `undefined` or `initialValue` before the first event and after the - deck detaches. -- `useDeckEventListener(eventName, listener, id?)` subscribes to committed model events without - forcing React state into your app code. Listener hooks clean up automatically on unmount. - Successful swipe events emit in `swipe -> indexChange -> endReached` order. Undo emits - `undo -> indexChange`. - -### Programmatic action motion - -`motion` controls gesture-driven deck feel. `actionMotion` controls only programmatic actions -from `useDeckActions()`, such as a like/pass button. This keeps button-triggered motion tunable -without changing manual drag, threshold, or flick behavior. - -```tsx -import { - createSwipeDeck, - SwipeDeckActionMotion, - SwipeDeckMotion, -} from '@react-native-motion-kit/swipe-deck'; +type Profile = { + id: string; + name: string; +}; const ProfileDeck = createSwipeDeck({ motion: SwipeDeckMotion.tinder(), - actionMotion: SwipeDeckActionMotion.springboard({ - anticipationDistance: ({ width }) => width * 0.04, - anticipationDuration: 80, - dismissDuration: 320, - }), -}); - -function LikeButton() { - const actions = ProfileDeck.useDeckActions(); - - return Like; -} -``` - -Available recipes: - -- `SwipeDeckActionMotion.direct(options?)`: dismisses immediately toward the action direction. - Omitted values reuse the deck's resolved dismiss duration, easing, and offscreen multiplier. -- `SwipeDeckActionMotion.springboard(options?)`: moves a little in the opposite direction first, - then dismisses offscreen. During the anticipation phase, swipe progress stays neutral so - opposite-side overlays do not flash; `interaction.direction` also stays neutral until the - dismiss phase starts. Omitted dismiss values reuse the deck's resolved dismiss duration, easing, - and offscreen multiplier. - -You can override one action call without changing the Root or factory default: - -```tsx -actions.swipeLeft( - SwipeDeckActionMotion.direct({ - duration: 180, - }), -); -``` - -`actionMotion` precedence is replacement-based, not deep-merged: - -1. factory `actionMotion` from `createSwipeDeck({ actionMotion })`; -2. `Root actionMotion`, which replaces the factory default for that Root; -3. per-call recipe passed to `swipeLeft(recipe)` or `swipeRight(recipe)`. - -Actions are callback-safe. If a React Native press event is passed to `swipeRight` or `swipeLeft`, -the event argument is ignored and the configured action motion is used. - -### Undo / back swipe motion - -Undo is opt-in. Add `undoEnabled` to a Root when that deck exposes undo/back-swipe UX. When -enabled, each successful swipe stores one key/index/direction metadata entry in a LIFO undo stack. -Lookups use a key-to-index map for the current `data`, and invalid entries are pruned when data or -keys change. When omitted, successful swipes do not store undo metadata, `canUndo` stays `false`, -and `actions.undo()` returns `false`. - -When accepted, the deck temporarily renders the main stack from the restored index, animates that -real current card from the side it originally left, then commits the restored index. - -```tsx -import { createSwipeDeck, SwipeDeckUndoMotion } from '@react-native-motion-kit/swipe-deck'; - -const ProfileDeck = createSwipeDeck({ - undoMotion: SwipeDeckUndoMotion.spring({ - springConfig: { - damping: 36, - stiffness: 300, - mass: 3, - }, - }), }); -function ProfileDeckExample() { +function ProfileCard({ profile }: { profile: Profile }) { return ( - item.id} undoEnabled> - {({ item }) => } - - ); -} - -function UndoButton() { - const state = ProfileDeck.useDeckState(); - const actions = ProfileDeck.useDeckActions(); - - return ( - - Undo - - ); -} -``` - -Undo is disabled by default so decks that do not expose undo controls pay no undo-history cost. -With `undoEnabled`, repeated undo restores previously swiped cards in LIFO order while their keys -remain present in `data`. Long-running undo-enabled decks retain one metadata entry per accepted -swipe until that entry is undone or pruned by data changes. Undo motion uses zero-duration -`SwipeDeckUndoMotion.timing()` by default, so the card is restored immediately unless you opt into a -custom motion. - -Available recipes: - -- `SwipeDeckUndoMotion.spring(options?)`: restores the card with Reanimated `withSpring`. -- `SwipeDeckUndoMotion.timing(options?)`: restores the card with deterministic `withTiming`. - -Both recipes accept: - -- `from: 'auto' | 'left' | 'right'`: `auto` returns from the original swipe direction. -- `entryDistance`: number or layout callback for the offscreen start distance. - -`timing` also accepts `duration` and `easing`; its default duration is `0`. `spring` accepts `springConfig`. - -Undo motion precedence is replacement-based: - -1. factory `undoMotion` from `createSwipeDeck({ undoMotion })`; -2. `Root undoMotion`, which replaces the factory default for that Root; -3. per-call recipe passed to `actions.undo(recipe)`. - -Undo is callback-safe. If a React Native press event is passed to `undo`, the event argument is -ignored and the configured undo motion is used. During undo restore, public interaction values -(`progress`, `signedProgress`, `direction`, `translationX`, `translationY`) remain neutral, so -progress-driven swipe overlays do not flash. - -Use an `id` only when you render multiple roots from the same factory: - -```tsx -function MultiDeckScreen() { - const nearbyState = ProfileDeck.useDeckState('nearby'); - - return ( - <> - item.id}> - {({ item }) => } - - - item.id}> - {({ item }) => } - - - {nearbyState.activeIndex + 1} - - ); -} -``` - -`id` is a factory-scoped deck namespace, not an item key. Two different factories can both -use the default id safely, but two mounted roots from the same factory and same id are invalid. -Keep ids stable and low-cardinality, such as screen-level names (`"nearby"` or `"recommended"`). -The registry keeps one store per id for the lifetime of the factory so hooks, actions, and -interaction shared values stay stable. Do not derive ids from item ids, timestamps, values that -change per render, or one-off route values. Create factories and ids outside render paths; dynamic -factories or dynamic ids create long-lived namespaces that the registry intentionally keeps stable. - -If you prefer shorter names, destructure from the same factory instance and export aliases: - -```ts -const ProfileDeck = createSwipeDeck(); - -export const { - Root: ProfileDeckRoot, - Card: ProfileDeckCard, - useDeckState: useProfileDeckState, - useDeckActions: useProfileDeckActions, - useDeckInteraction: useProfileDeckInteraction, -} = ProfileDeck; -``` - -Create the factory once per deck family and export it from a shared module. Hooks, actions, and interactions only connect to Roots created by that same factory instance. Calling `createSwipeDeck()` again creates a separate registry namespace even if the item type and id are the same, so hooks from one factory cannot control Roots from another. - -### Simple inline usage - -If you only need card rendering, you can use the static API without creating a factory instance. -This is useful for small inline decks, but it does not expose factory hooks such as -`useDeckState`, `useDeckActions`, `useDeckInteraction`, `useDeckEvent`, or -`useDeckEventListener`. -Static `Root` does not accept `id`; use a factory instance when you need named deck state, -actions, interactions, or model events. -Because static `Root` and `Card` do not share a factory type, pass the item type to `Card` when you want typed render props. - -```tsx -import { SwipeDeck } from '@react-native-motion-kit/swipe-deck'; - -function InlineDeck() { - return ( - item.id}> - >{({ item }) => } - + + {profile.name} + ); } -``` - -## Motion - -### What follows swipe progress? - -Buffered next cards animate with swipe progress: - -- scale moves toward `1`; -- opacity moves toward `1`; -- `translateY` moves toward `0`. - -When a swipe commits: - -- the dismissed card exits offscreen; -- the promoted next card keeps its item identity; -- a new future item enters the bounded window. - -Tune this with motion presets such as `SwipeDeckMotion.tinder(...)`. - -### Drag mode - -`drag.mode` controls how the active card uses finger translation while dragging. - -| mode | Active card movement | -| ------------ | ---------------------------------------------------------------------------- | -| `free` | Follows both horizontal and vertical finger movement. | -| `horizontal` | Ignores vertical finger movement and moves from horizontal translation only. | - -`drag.liftYFactor` lifts the active card upward by `abs(translationX) * liftYFactor`. - -```tsx -SwipeDeckMotion.tinder({ - drag: { - mode: 'horizontal', - liftYFactor: 0, - }, - rotation: { - mode: 'fixed', - origin: 'bottom-center', - }, -}); -``` - -Use `drag.mode: 'horizontal'` with `rotation: { mode: 'fixed', origin: 'bottom-center' }` for a lower-anchor, left/right-only feel. - -### Motion precedence - -Motion values are resolved in this order: - -1. factory motion defaults from `createSwipeDeck({ motion })`; -2. `Root motion`, which partially overrides only the fields it specifies; -3. direct root props such as `swipeThreshold` and `velocityThreshold`. - -Factory and Root motion are deep-merged. Numeric rotation tuning such as `maxDegrees` and `inputRange` is preserved unless the Root motion explicitly overrides it; changing `rotation.mode` does not reset those values to mode defaults. - -### Motion preset stability - -Prefer keeping motion presets stable with a module-scope constant or `useMemo`. - -Stable preset references avoid unnecessary gesture/worklet setup when you pass Reanimated easing functions or spring config objects. - -For app-wide or deck-family defaults, define motion outside render and pass it to the factory: - -```tsx -const profileDeckMotion = SwipeDeckMotion.tinder({ - rotation: { - mode: 'fixed', - origin: 'bottom-center', - }, - dismiss: { - threshold: ({ width }) => width * 0.3, - }, -}); - -const ProfileDeck = createSwipeDeck({ - motion: profileDeckMotion, -}); -``` - -When motion depends on props or state, memoize the config at the call site: - -```tsx -function ProfileScreen({ slowMotion }: { slowMotion: boolean }) { - const motion = useMemo( - () => - SwipeDeckMotion.tinder({ - dismiss: { - minDuration: slowMotion ? 420 : 220, - maxDuration: slowMotion ? 700 : 420, - }, - }), - [slowMotion], - ); +export function ProfileDeckScreen({ profiles }: { profiles: Profile[] }) { return ( - item.id} motion={motion}> + item.id} visibleCardCount={3}> {({ item }) => } ); } ``` -### Rotation - -`rotation.mode` controls whether the rotation anchor is fixed or resolved from the gesture start position. The default is Tinder-like `mode: 'grab-position'`. Rotation settings do not change swipe recognition. When `dismiss.duration` is omitted, however, velocity-derived dismiss timing can change because the release target is computed from the rotated card geometry. - -#### Fixed rotation - -Use fixed rotation when every gesture should use the same anchor instead of the default grab-position behavior. - -| origin | Feel | -| --------------- | ------------------------------------------------------------------------------------------------------------------------ | -| `center` | Rotates around the card center. | -| `top-center` | Rotates around the top-center edge, so the upper part feels anchored and the bottom travels through a larger arc. | -| `bottom-center` | Rotates around the bottom-center edge, so the lower part feels almost anchored and the top travels through a larger arc. | - -```tsx -SwipeDeckMotion.tinder({ - rotation: { - mode: 'fixed', - origin: 'bottom-center', - direction: 'default', - }, -}); -``` +Use `ProfileDeck.useDeckState()`, `ProfileDeck.useDeckActions()`, +`ProfileDeck.useDeckInteraction()`, `ProfileDeck.useDeckEvent()`, and +`ProfileDeck.useDeckEventListener()` around the same factory Root when you need +controls, animated overlays, or committed model events. -Use `direction: 'reverse'` when you want the same fixed anchor but the opposite rotation sign. +## Docs -#### Grab-position rotation - -Grab-position rotation is the default Tinder-like behavior. Use it explicitly when you want to override only shared rotation values such as `maxDegrees` or `inputRange`. - -```tsx -SwipeDeckMotion.tinder({ - rotation: { - mode: 'grab-position', - direction: 'default', - maxDegrees: 25, - }, -}); -``` - -Upper-half grabs use a top-center anchor with the default rotation sign. Lower-half grabs use a bottom-center anchor with the reverse rotation sign. `direction: 'reverse'` flips that mapping. `maxDegrees` and `inputRange` are still configurable, but fixed `origin` is intentionally omitted in this mode. - -Because the same `maxDegrees` feels stronger with edge-based rotation, the Tinder preset uses a smaller default rotation angle for `top-center`, `bottom-center`, and `grab-position` unless you provide `maxDegrees` explicitly. - -### Dismiss target - -`dismiss.offscreenMultiplier` controls the successful swipe release target. - -- Successful swipes always dismiss offscreen. -- The default `1.5` sends the card to `clearDistance * 1.5`. -- `clearDistance` is resolved at release from the actual swipe direction, rotation mode, rotation direction, and gesture start position. -- Values below `1` are normalized to `1`. -- If `duration` is omitted, velocity-derived timing is computed from the remaining distance to this target. - -Most apps can skip this option and tune only: - -- `threshold` -- `velocityThreshold` -- `duration`, `minDuration`, `maxDuration` -- Reanimated `easing` - -`dismiss.easing` accepts the same easing value as Reanimated `withTiming`. -The default is `Easing.out(Easing.cubic)`. - -## Visible card budget - -```tsx -function CurrentOnlyDeck() { - return ( - item.id} visibleCardCount={1}> - {/* lightest budget: current card only, no next-card promotion visual */} - - ); -} - -function DefaultDeck() { - return ( - item.id} visibleCardCount={3}> - {/* default budget for smoother next-card promotion */} - - ); -} - -function DeepStackDeck() { - return ( - item.id} visibleCardCount={9}> - {/* deeper stacked UI */} - - ); -} -``` +Full guides are maintained in this repository under `docs/` while the public +site is being prepared. -| Input | Mounted cards | -| ----------------------------------------------- | ------------------------------------------- | -| `visibleCardCount={1}` | Only the current card. | -| `visibleCardCount={2}` | Up to `2` cards when enough data exists. | -| `visibleCardCount={20}` with 10 remaining items | At most those 10 remaining items. | -| even values | Kept as the maximum budget; not rounded up. | +- [Overview](docs/docs/1.x/en/guide/getting-started/overview.mdx) +- [Quick Start](docs/docs/1.x/en/guide/getting-started/quick-start.mdx) +- [API Reference](docs/docs/1.x/en/guide/usage/api-reference.mdx) +- [AI Usage Guide](docs/docs/1.x/en/guide/getting-started/ai.mdx) -## Contributing +AI-readable docs are generated during the docs build: -- [Development workflow](CONTRIBUTING.md#development-workflow) -- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request) -- [Code of conduct](CODE_OF_CONDUCT.md) +- [llms.txt](docs/doc_build/llms.txt) +- [llms-full.txt](docs/doc_build/llms-full.txt) ## License diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..a8be826 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,14 @@ +# Local +.DS_Store +*.local +*.log* + +# Dist +node_modules/ +dist/ +doc_build/ + +# IDE +.vscode/* +!.vscode/extensions.json +.idea/ diff --git a/docs/docs/1.x/en/_nav.json b/docs/docs/1.x/en/_nav.json new file mode 100644 index 0000000..a6c3ff0 --- /dev/null +++ b/docs/docs/1.x/en/_nav.json @@ -0,0 +1,7 @@ +[ + { + "text": "Guide", + "link": "/guide/getting-started/overview.html", + "activeMatch": "/guide/" + } +] diff --git a/docs/docs/1.x/en/guide/_meta.json b/docs/docs/1.x/en/guide/_meta.json new file mode 100644 index 0000000..169ecfc --- /dev/null +++ b/docs/docs/1.x/en/guide/_meta.json @@ -0,0 +1,12 @@ +[ + { + "type": "dir", + "name": "getting-started", + "label": "Getting Started" + }, + { + "type": "dir", + "name": "usage", + "label": "Usage" + } +] diff --git a/docs/docs/1.x/en/guide/getting-started/_meta.json b/docs/docs/1.x/en/guide/getting-started/_meta.json new file mode 100644 index 0000000..17fcb81 --- /dev/null +++ b/docs/docs/1.x/en/guide/getting-started/_meta.json @@ -0,0 +1 @@ +["overview", "installation", "quick-start", "ai"] diff --git a/docs/docs/1.x/en/guide/getting-started/ai.mdx b/docs/docs/1.x/en/guide/getting-started/ai.mdx new file mode 100644 index 0000000..ac99258 --- /dev/null +++ b/docs/docs/1.x/en/guide/getting-started/ai.mdx @@ -0,0 +1,73 @@ +# AI Usage Guide + +When generating code with an AI assistant, give it these rules. They prevent the +most common integration mistakes. + +## LLM-Readable Docs + +This site publishes Markdown files for AI tools during `rspress build`. + +- [`/llms.txt`](/llms.txt): compact documentation index with page links and + summaries. Use this when the agent should choose only the relevant pages. +- [`/llms-full.txt`](/llms-full.txt): full English documentation in one + Markdown file. Use this when the agent has enough context budget and should + understand the whole API surface. +- [`/ko/llms.txt`](/ko/llms.txt) and + [`/ko/llms-full.txt`](/ko/llms-full.txt): Korean equivalents. + +Before the public docs URL is available, build locally and read the generated +files from `docs/doc_build/`. + +## Recommended Prompt + +```md +Use @react-native-motion-kit/swipe-deck. + +- Create one createSwipeDeck() factory outside render. +- Render Root and Card from that same factory. +- Use a stable getKey(item) value, usually item.id. +- Use factory hooks from the same factory instance as the Root. +- Use useDeckState/useDeckActions for React UI. +- Use useDeckInteraction for Reanimated UI-thread overlays. +- Use useDeckEvent/useDeckEventListener for committed swipe, undo, indexChange, + and endReached events. +- Add undoEnabled only when the UI exposes undo. +- Do not derive deck id from item ids, timestamps, or values that change each render. +``` + +## Good Factory Shape + +```tsx +// profile-deck.ts +import { createSwipeDeck } from '@react-native-motion-kit/swipe-deck'; + +export type Profile = { + id: string; + name: string; +}; + +export const ProfileDeck = createSwipeDeck(); +``` + +```tsx +// ProfileDeckScreen.tsx +import { ProfileDeck } from './profile-deck'; + +export function ProfileDeckScreen({ profiles }: { profiles: Profile[] }) { + return ( + item.id}> + {({ item }) => } + + ); +} +``` + +## Common Mistakes To Avoid + +- Do not call `createSwipeDeck()` inside a component render path. +- Do not use hooks from one factory to control a Root from another factory. +- Do not use array indexes as keys when items can be inserted, removed, or + reordered. +- Do not use `useDeckInteraction` for committed business logic; use events for + committed model changes. +- Do not turn on `undoEnabled` unless the deck exposes undo controls. diff --git a/docs/docs/1.x/en/guide/getting-started/installation.mdx b/docs/docs/1.x/en/guide/getting-started/installation.mdx new file mode 100644 index 0000000..5bfa73e --- /dev/null +++ b/docs/docs/1.x/en/guide/getting-started/installation.mdx @@ -0,0 +1,47 @@ +# Installation + +Install the package and its React Native gesture/animation peer dependencies: + +```sh +npm install @react-native-motion-kit/swipe-deck react-native-gesture-handler react-native-reanimated react-native-worklets +``` + +You can use your package manager of choice. For Yarn: + +```sh +yarn add @react-native-motion-kit/swipe-deck react-native-gesture-handler react-native-reanimated react-native-worklets +``` + +## Minimum Versions + +| Package | Minimum | +| ------------------------------ | -------- | +| `react` | `18.0.0` | +| `react-native` | `0.75.0` | +| `react-native-gesture-handler` | `2.24.0` | +| `react-native-reanimated` | `4.0.0` | +| `react-native-worklets` | `0.5.0` | + +## React Native Setup + +Follow the Reanimated and Worklets setup instructions for your React Native or +Expo version. In Babel config, make sure `react-native-worklets/plugin` is the +last Babel plugin. + +```js title="babel.config.js" +module.exports = { + presets: ['module:@react-native/babel-preset'], + plugins: ['react-native-worklets/plugin'], +}; +``` + +Gesture Handler also expects your app surface to be under +`GestureHandlerRootView`. + +```tsx +import { GestureHandlerRootView } from 'react-native-gesture-handler'; + +export function AppRoot() { + return {/* app */}; +} +``` diff --git a/docs/docs/1.x/en/guide/getting-started/overview.mdx b/docs/docs/1.x/en/guide/getting-started/overview.mdx new file mode 100644 index 0000000..8db095d --- /dev/null +++ b/docs/docs/1.x/en/guide/getting-started/overview.mdx @@ -0,0 +1,65 @@ +# Overview + +`@react-native-motion-kit/swipe-deck` is a high-performance Tinder-style swipe +deck for React Native. It is built for apps that need a smooth card stack, +programmatic like/pass buttons, progress-driven overlays, and a typed API that +does not make every screen wire a controller by hand. + +## Mental Model + +The main API is a typed compound component family: + +- `createSwipeDeck()` creates one deck family for an item type. +- `Root` owns data, gesture state, motion options, actions, events, and layout. +- `Card` renders each mounted item in the bounded forward window. +- Factory hooks read state, run actions, subscribe to events, and expose + Reanimated shared values for animated UI. + +```tsx +import { createSwipeDeck } from '@react-native-motion-kit/swipe-deck'; + +type Profile = { + id: string; + name: string; +}; + +const ProfileDeck = createSwipeDeck(); +``` + +Create the factory once, export it from a shared module, and use hooks from that +same factory around a matching `Root`. + +## Why It Exists + +- The deck does not render the full data set. +- Promoted cards keep item identity through stable keys. +- Manual drag motion and programmatic action motion can be tuned separately. +- Interaction shared values update on the UI thread without rerendering React + every gesture frame. +- Events describe committed model changes such as swipes, undo, index changes, + and end reached. + +## Core Concepts + +### Bounded Forward Window + +By default, the deck mounts up to three cards from the active index forward: + +1. current card +2. next card +3. next buffered card + +This keeps the stack continuous without backfilling dismissed cards. Use +`visibleCardCount` to tune that maximum budget. + +### Stable Item Keys + +`getKey` is required. The same logical item must return the same key across +swipes, and different items should not share a key. The deck uses that key as +the React identity for each mounted card. + +### Committed Events vs Live Interaction + +Use event hooks for committed model changes. Use interaction shared values for +frame-synchronous visual feedback while a card is dragging, dismissing, or +restoring. 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 new file mode 100644 index 0000000..857c5b3 --- /dev/null +++ b/docs/docs/1.x/en/guide/getting-started/quick-start.mdx @@ -0,0 +1,103 @@ +# Quick Start + +Create one typed deck family for your item type. `Root`, `Card`, hooks, actions, +and events from that factory share the same registry namespace. + +```tsx +import { Text, View } from 'react-native'; +import { createSwipeDeck, SwipeDeckMotion } from '@react-native-motion-kit/swipe-deck'; + +type Profile = { + id: string; + name: string; + bio: string; +}; + +const ProfileDeck = createSwipeDeck({ + motion: SwipeDeckMotion.tinder({ + drag: { + mode: 'horizontal', + liftYFactor: 0.15, + }, + rotation: { + mode: 'grab-position', + }, + dismiss: { + threshold: ({ width }) => width * 0.3, + velocityThreshold: 800, + minDuration: 300, + maxDuration: 520, + }, + }), +}); + +function ProfileDeckEvents() { + ProfileDeck.useDeckEventListener('swipe', ({ item, direction, source }) => { + console.log(item.name, direction, source); + }); + + ProfileDeck.useDeckEventListener('endReached', () => { + console.log('No more cards'); + }); + + return null; +} + +function ProfileCard({ profile, active }: { profile: Profile; active: boolean }) { + return ( + + {active ? 'Now viewing' : 'Up next'} + {profile.name} + {profile.bio} + + ); +} + +export function ProfileDeckScreen({ profiles }: { profiles: Profile[] }) { + return ( + <> + + item.id} visibleCardCount={3}> + + {({ item, isActive }) => } + + + + ); +} +``` + +## Add Controls + +Use state and action hooks for React-rendered UI such as counters and buttons. + +```tsx +function ProfileDeckControls() { + const { activeIndex, count, canSwipe, canUndo, isCompleted } = ProfileDeck.useDeckState(); + const { swipeLeft, swipeRight, undo } = ProfileDeck.useDeckActions(); + const current = activeIndex >= 0 ? activeIndex + 1 : 0; + + return ( + + {isCompleted ? 'Done' : `${current} / ${count}`} + + Nope + + + Undo + + + Like + + + ); +} +``` + +Enable undo tracking only when you expose undo UX: + +```tsx + item.id} undoEnabled> + {({ item }) => } + +``` diff --git a/docs/docs/1.x/en/guide/usage/_meta.json b/docs/docs/1.x/en/guide/usage/_meta.json new file mode 100644 index 0000000..cd32246 --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/_meta.json @@ -0,0 +1,11 @@ +[ + "basic-usage", + "deck-hooks", + "handling-events", + "programmatic-actions", + "undo", + "motion", + "multi-instance-management", + "visible-card-budget", + "api-reference" +] diff --git a/docs/docs/1.x/en/guide/usage/api-reference.mdx b/docs/docs/1.x/en/guide/usage/api-reference.mdx new file mode 100644 index 0000000..461caa0 --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/api-reference.mdx @@ -0,0 +1,133 @@ +--- +description: Reference the main exports, Root and Card props, hooks, events, and built-in motion helpers. +--- + +# API Reference + +## Main Exports + +```ts +export { + SwipeDeckActionMotion, + SwipeDeckMotion, + createSwipeDeck, + SwipeDeck, + SwipeDeckUndoMotion, +} from '@react-native-motion-kit/swipe-deck'; +``` + +[Go to source](https://github.com/react-native-motion-kit/react-native-swipe-deck/blob/main/src/index.tsx) + +## `createSwipeDeck(config?)` + +Creates a typed deck family. + +```tsx +const ProfileDeck = createSwipeDeck({ + motion: SwipeDeckMotion.tinder(), +}); +``` + +The returned instance includes: + +- `Root` +- `Card` +- `useDeckState` +- `useDeckActions` +- `useDeckInteraction` +- `useDeckEvent` +- `useDeckEventListener` + +## `SwipeDeck.Root` Props + +[Go to source](https://github.com/react-native-motion-kit/react-native-swipe-deck/blob/main/src/types.ts) + +| Prop | Type | Notes | +| ------------------- | ------------------------------------ | ----------------------------------------- | +| `id` | `string` | Factory-scoped deck namespace. | +| `data` | `readonly T[]` | Ordered items rendered by the deck. | +| `getKey` | `(item: T, index: number) => string` | Required stable item key. | +| `initialIndex` | `number` | Initial active item index. | +| `disabled` | `boolean` | Disables accepted actions and gestures. | +| `allowedDirections` | `AllowedDirections` | Limits accepted dismiss directions. | +| `swipeThreshold` | `SwipeThreshold` | Root-level dismiss threshold override. | +| `velocityThreshold` | `number` | Root-level flick threshold override. | +| `motion` | `SwipeDeckMotionPreset` | Gesture-driven motion preset. | +| `actionMotion` | `SwipeDeckActionMotionRecipe` | Programmatic swipe motion recipe. | +| `undoMotion` | `SwipeDeckUndoMotionRecipe` | Programmatic undo restore motion recipe. | +| `undoEnabled` | `boolean` | Enables undo history tracking. | +| `visibleCardCount` | `number` | Maximum mounted forward card budget. | +| `containerStyle` | `StyleProp` | Style applied to the deck container. | +| `children` | `ReactNode` | Must include a matching `SwipeDeck.Card`. | + +```ts +type AllowedDirections = readonly ('left' | 'right')[]; +type SwipeThreshold = number | ((layout: SwipeDeckLayout) => number); +``` + +Static `SwipeDeck.Root` accepts the same props except `id`. + +## `SwipeDeck.Card` Props + +| Prop | Type | Notes | +| ---------- | ----------------------------------------- | --------------------------------------- | +| `style` | `StyleProp` | Style applied to the absolute card. | +| `children` | `(info: SwipeRenderInfo) => ReactNode` | Renders one item in the bounded window. | + +`SwipeRenderInfo` includes `item`, `index`, `offset`, `role`, and +`isActive`. + +## State And Actions + +```ts +type SwipeDeckState = { + activeIndex: number; + count: number; + isCompleted: boolean; + canSwipe: boolean; + canUndo: boolean; +}; + +type SwipeDeckActions = { + swipeLeft: SwipeDeckAction; + swipeRight: SwipeDeckAction; + undo: SwipeDeckUndoAction; +}; +``` + +Programmatic actions return `boolean` to tell whether the action was accepted. + +## Interaction + +```ts +type SwipeDeckInteractionPhase = 'idle' | 'dragging' | 'dismissing' | 'undoing'; +``` + +`useDeckInteraction()` returns Reanimated shared values for `progress`, +`signedProgress`, `direction`, `dismissDirection`, `translationX`, +`translationY`, `isDragging`, and `phase`. + +## Events + +```ts +type SwipeDeckEventMap = { + swipe: SwipeEvent; + undo: UndoEvent; + indexChange: { index: number }; + endReached: true; +}; +``` + +Use `useDeckEvent` for latest event snapshots and `useDeckEventListener` for +imperative subscriptions. + +## Motion Helpers + +- `SwipeDeckMotion.tinder(options?)` +- `SwipeDeckActionMotion.direct(options?)` +- `SwipeDeckActionMotion.springboard(options?)` +- `SwipeDeckUndoMotion.spring(options?)` +- `SwipeDeckUndoMotion.timing(options?)` + +For behavior details, prefer the guide pages over treating this reference as an +onboarding surface. diff --git a/docs/docs/1.x/en/guide/usage/basic-usage.mdx b/docs/docs/1.x/en/guide/usage/basic-usage.mdx new file mode 100644 index 0000000..9687430 --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/basic-usage.mdx @@ -0,0 +1,80 @@ +--- +description: Learn when to use the factory API, Card render info, allowed directions, and the static SwipeDeck API. +--- + +# Basic Usage + +## Factory API + +The factory API is the primary API. Use it when a deck needs hooks, actions, +events, interaction shared values, or multiple named instances. + +```tsx +import { createSwipeDeck } from '@react-native-motion-kit/swipe-deck'; + +const ProfileDeck = createSwipeDeck(); + +function Screen() { + return ( + item.id}> + {({ item }) => } + + ); +} +``` + +The factory keeps `Root`, `Card`, and hooks on the same item type without +repeating generics in JSX. + +## Card Render Info + +`Card` receives render info for each mounted item. + +| Field | Meaning | +| ---------- | ------------------------------------------------------- | +| `item` | The item from your `data` array. | +| `index` | The item index in `data`. | +| `offset` | The card offset from the active item. | +| `role` | `'current'` for the active card, `'next'` for buffered. | +| `isActive` | `true` only for the active card. | + +```tsx + + {({ item, role, isActive }) => } + +``` + +## Allowed Directions + +`allowedDirections` limits which directions can be accepted as a dismiss. + +```tsx + item.id} allowedDirections={['right']}> + {({ item }) => } + +``` + +- Omit `allowedDirections` to allow both directions. +- Pass `['left']` or `['right']` to allow only one dismiss direction. +- Pass `[]` to allow dragging but reject every dismiss release and + programmatic swipe action. + +## Static API + +Use the static API only when you need inline card rendering and do not need +factory hooks. + +```tsx +import { SwipeDeck } from '@react-native-motion-kit/swipe-deck'; + +function InlineDeck() { + return ( + item.id}> + >{({ item }) => } + + ); +} +``` + +Static `Root` does not accept `id`, and static `Root` / `Card` do not share a +factory type. Pass the item type to `Card` when you want typed render props. diff --git a/docs/docs/1.x/en/guide/usage/deck-hooks.mdx b/docs/docs/1.x/en/guide/usage/deck-hooks.mdx new file mode 100644 index 0000000..c0b3751 --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/deck-hooks.mdx @@ -0,0 +1,100 @@ +# Deck Hooks + +Factory hooks expose deck state, actions, and interaction values without a +provider prop or controller object. + +```tsx +const ProfileDeck = createSwipeDeck(); +``` + +## `useDeckState(id?)` + +Returns React-rendered deck state. + +| Field | Meaning | +| ------------- | --------------------------------------------------------- | +| `activeIndex` | Current active item index, or `-1` before attach. | +| `count` | Total item count in the attached deck. | +| `isCompleted` | Whether the deck has consumed all items. | +| `canSwipe` | Whether a dismiss action can currently be accepted. | +| `canUndo` | Whether the latest valid swipe can currently be restored. | + +```tsx +function Counter() { + const { activeIndex, count, isCompleted } = ProfileDeck.useDeckState(); + const current = activeIndex >= 0 ? activeIndex + 1 : 0; + + return {isCompleted ? 'Done' : `${current} / ${count}`}; +} +``` + +Derive the current item from your own `data[activeIndex]` when needed. Deck +state stays primitive and stable. + +## `useDeckActions(id?)` + +Returns stable action callbacks. + +```tsx +function Controls() { + const { canSwipe, canUndo } = ProfileDeck.useDeckState(); + const { swipeLeft, swipeRight, undo } = ProfileDeck.useDeckActions(); + + return ( + + + Nope + + + Undo + + + Like + + + ); +} +``` + +`swipeLeft()` and `swipeRight()` return `true` when accepted and `false` when the +deck is unattached, disabled, animating, unmeasured, completed, or the direction +is not allowed. `undo()` returns `true` when `canUndo` is true, including after +the deck is completed. + +## `useDeckInteraction(id?)` + +Returns Reanimated shared values for progress-driven UI. + +```tsx +function SwipeReactionOverlay() { + const { signedProgress } = ProfileDeck.useDeckInteraction(); + + const likeStyle = useAnimatedStyle(() => { + const progress = Math.max(signedProgress.get(), 0); + + return { + opacity: progress, + transform: [{ scale: 0.9 + progress * 0.18 }], + }; + }); + + return ; +} +``` + +Interaction values update on the UI thread and do not rerender React every +gesture frame. + +| Value | Meaning | +| ------------------ | ------------------------------------------------------ | +| `progress` | Absolute swipe progress from `0` to `1`. | +| `signedProgress` | Signed progress from `-1` to `1`. | +| `direction` | Raw live direction signal: `-1`, `0`, or `1`. | +| `dismissDirection` | Accepted dismiss side: `'left'`, `'right'`, or `null`. | +| `translationX` | Active card horizontal translation. | +| `translationY` | Active card vertical translation. | +| `isDragging` | Whether the deck is dragging or dismissing. | +| `phase` | `idle`, `dragging`, `dismissing`, or `undoing`. | + +Use `phase` for frame-synchronous visual feedback. Use event hooks for +committed state changes. diff --git a/docs/docs/1.x/en/guide/usage/handling-events.mdx b/docs/docs/1.x/en/guide/usage/handling-events.mdx new file mode 100644 index 0000000..0d10682 --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/handling-events.mdx @@ -0,0 +1,80 @@ +# Handling Events + +Event hooks describe committed model events. They are separate from live +interaction values. + +## Event Map + +| Event | Payload | +| ------------- | ------------------------------------ | +| `swipe` | `{ item, index, direction, source }` | +| `undo` | `{ item, index, direction }` | +| `indexChange` | `{ index }` | +| `endReached` | `true` | + +`swipe.source` is `'gesture'` when the user releases a pan gesture past the +configured threshold or velocity policy. It is `'programmatic'` when the swipe +commits through `actions.swipeLeft()` or `actions.swipeRight()`. + +## `useDeckEvent` + +`useDeckEvent(eventName, initialValue?, id?)` returns the latest committed event +snapshot for React-rendered UI. + +```tsx +function ProfileDeckStatus() { + const lastSwipe = ProfileDeck.useDeckEvent('swipe', null); + const endReached = ProfileDeck.useDeckEvent('endReached', false); + + return ( + + {endReached + ? 'Done' + : lastSwipe + ? `Last swipe: ${lastSwipe.direction} from ${lastSwipe.source}` + : 'No swipe yet'} + + ); +} +``` + +This is a latest-value API, not an event history. Event snapshots clear when a +Root attaches or detaches. + +Initial values are intentionally restricted to the event payload shape, `null`, +`undefined`, or `false` for `endReached`. Use `null` for object events such as +`swipe`. + +For a named deck without an initial value, pass the id as the second argument: + +```tsx +const lastSwipe = ProfileDeck.useDeckEvent('swipe', 'nearby'); +``` + +If you also pass an initial value, id is the third argument. + +## `useDeckEventListener` + +`useDeckEventListener(eventName, listener, id?)` subscribes imperatively without +forcing React state into your app code. + +```tsx +function ProfileDeckEvents() { + ProfileDeck.useDeckEventListener('swipe', ({ item, direction, source }) => { + console.log(item, direction, source); + }); + + ProfileDeck.useDeckEventListener('undo', ({ item }) => { + console.log('Restored', item); + }); + + ProfileDeck.useDeckEventListener('endReached', () => { + console.log('No more cards'); + }); + + return null; +} +``` + +Successful swipe events emit in `swipe -> indexChange -> endReached` order. Undo +emits `undo -> indexChange`. diff --git a/docs/docs/1.x/en/guide/usage/motion.mdx b/docs/docs/1.x/en/guide/usage/motion.mdx new file mode 100644 index 0000000..cad636f --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/motion.mdx @@ -0,0 +1,139 @@ +# Motion + +`SwipeDeckMotion.tinder()` is the built-in motion preset for Tinder-style card +stacks. + +```tsx +import { SwipeDeckMotion } from '@react-native-motion-kit/swipe-deck'; + +const motion = SwipeDeckMotion.tinder({ + drag: { + mode: 'horizontal', + liftYFactor: 0.15, + }, + rotation: { + mode: 'grab-position', + }, + dismiss: { + threshold: ({ width }) => width * 0.3, + velocityThreshold: 800, + minDuration: 300, + maxDuration: 520, + }, +}); +``` + +## What Follows Swipe Progress? + +Buffered next cards animate with swipe progress: + +- scale moves toward `1` +- opacity moves toward `1` +- `translateY` moves toward `0` + +When a swipe commits, the dismissed card exits offscreen, the promoted next card +keeps its item identity, and a new future item enters the bounded window. + +## Drag Mode + +`drag.mode` controls how the active card uses finger translation while dragging. + +| Mode | Active card movement | +| ------------ | ---------------------------------------------------------- | +| `free` | Follows both horizontal and vertical finger movement. | +| `horizontal` | Ignores vertical finger movement and uses horizontal drag. | + +`drag.liftYFactor` lifts the active card upward by +`abs(translationX) * liftYFactor`. + +## Rotation + +`rotation.mode` controls whether the rotation anchor is fixed or resolved from +the gesture start position. + +### Fixed Rotation + +Use fixed rotation when every gesture should use the same anchor. + +| Origin | Feel | +| --------------- | ------------------------------- | +| `center` | Rotates around the card center. | +| `top-center` | The upper edge feels anchored. | +| `bottom-center` | The lower edge feels anchored. | + +```tsx +SwipeDeckMotion.tinder({ + rotation: { + mode: 'fixed', + origin: 'bottom-center', + direction: 'default', + }, +}); +``` + +Use `direction: 'reverse'` when you want the same fixed anchor with the opposite +rotation sign. + +### Grab-Position Rotation + +Grab-position rotation is the default Tinder-like behavior. + +```tsx +SwipeDeckMotion.tinder({ + rotation: { + mode: 'grab-position', + direction: 'default', + maxDegrees: 25, + }, +}); +``` + +Upper-half grabs use a top-center anchor with the default rotation sign. +Lower-half grabs use a bottom-center anchor with the reverse rotation sign. +`direction: 'reverse'` flips that mapping. + +## Dismiss Target + +`dismiss.offscreenMultiplier` controls the successful swipe release target. + +- Successful swipes always dismiss offscreen. +- The default `1.5` sends the card to `clearDistance * 1.5`. +- `clearDistance` is resolved at release from the swipe direction, rotation + mode, rotation direction, and gesture start position. +- Values below `1` normalize to `1`. +- If `duration` is omitted, velocity-derived timing is computed from the + remaining distance to this target. + +Most apps can tune only `threshold`, `velocityThreshold`, `duration`, +`minDuration`, `maxDuration`, and `easing`. + +## Motion Precedence + +Motion values resolve in this order: + +1. factory motion defaults from `createSwipeDeck({ motion })` +2. `Root motion`, partially overriding only the fields it specifies +3. direct root props such as `swipeThreshold` and `velocityThreshold` + +Factory and Root motion are deep-merged. Changing `rotation.mode` does not reset +numeric rotation tuning such as `maxDegrees` or `inputRange`. + +## Preset Stability + +Keep motion presets stable with a module-scope constant or `useMemo`. + +```tsx +const profileDeckMotion = SwipeDeckMotion.tinder({ + rotation: { + mode: 'fixed', + origin: 'bottom-center', + }, + dismiss: { + threshold: ({ width }) => width * 0.3, + }, +}); + +const ProfileDeck = createSwipeDeck({ + motion: profileDeckMotion, +}); +``` diff --git a/docs/docs/1.x/en/guide/usage/multi-instance-management.mdx b/docs/docs/1.x/en/guide/usage/multi-instance-management.mdx new file mode 100644 index 0000000..a47066a --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/multi-instance-management.mdx @@ -0,0 +1,58 @@ +# Multi-Instance Management + +Use `id` only when you render multiple roots from the same factory. + +```tsx +function MultiDeckScreen() { + const nearbyState = ProfileDeck.useDeckState('nearby'); + + return ( + <> + item.id}> + {({ item }) => } + + + item.id}> + {({ item }) => } + + + {nearbyState.activeIndex + 1} + + ); +} +``` + +`id` is a factory-scoped deck namespace, not an item key. Two different +factories can both use the default id safely, but two mounted roots from the +same factory and same id are invalid. + +## Id Rules + +- Keep ids stable and low-cardinality. +- Use screen-level names such as `"nearby"` or `"recommended"`. +- Do not derive ids from item ids, timestamps, values that change per render, or + one-off route values. +- Create factories and ids outside render paths. + +The registry keeps one store per id for the lifetime of the factory so hooks, +actions, and interaction shared values stay stable. + +## Same-Factory Rule + +Hooks, actions, and interactions only connect to Roots created by the same +factory instance. + +```ts +const ProfileDeck = createSwipeDeck(); + +export const { + Root: ProfileDeckRoot, + Card: ProfileDeckCard, + useDeckState: useProfileDeckState, + useDeckActions: useProfileDeckActions, + useDeckInteraction: useProfileDeckInteraction, +} = ProfileDeck; +``` + +Calling `createSwipeDeck()` again creates a separate registry namespace +even when the item type and id are the same. diff --git a/docs/docs/1.x/en/guide/usage/programmatic-actions.mdx b/docs/docs/1.x/en/guide/usage/programmatic-actions.mdx new file mode 100644 index 0000000..2c4285b --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/programmatic-actions.mdx @@ -0,0 +1,75 @@ +# Programmatic Actions + +Programmatic actions come from `useDeckActions()`. Use them for buttons, +external controls, or any app logic that should dismiss the active card. + +```tsx +function LikeButton() { + const { swipeRight } = ProfileDeck.useDeckActions(); + + return Like; +} +``` + +## Action Motion + +`motion` controls manual drag feel. `actionMotion` controls only programmatic +actions such as `swipeLeft()` and `swipeRight()`. + +```tsx +import { + createSwipeDeck, + SwipeDeckActionMotion, + SwipeDeckMotion, +} from '@react-native-motion-kit/swipe-deck'; + +const ProfileDeck = createSwipeDeck({ + motion: SwipeDeckMotion.tinder(), + actionMotion: SwipeDeckActionMotion.springboard({ + anticipationDistance: ({ width }) => width * 0.04, + anticipationDuration: 80, + dismissDuration: 320, + }), +}); +``` + +## Recipes + +### `SwipeDeckActionMotion.direct(options?)` + +Dismisses immediately toward the action direction. Omitted values reuse the +deck's resolved dismiss duration, easing, and offscreen multiplier. + +```tsx +actions.swipeLeft( + SwipeDeckActionMotion.direct({ + duration: 180, + }), +); +``` + +### `SwipeDeckActionMotion.springboard(options?)` + +Moves a little in the opposite direction first, then dismisses offscreen. During +anticipation, swipe progress and live direction stay neutral so opposite-side +overlays do not flash. + +```tsx +const actionMotion = SwipeDeckActionMotion.springboard({ + anticipationDistance: 40, + anticipationDuration: 160, + dismissDuration: 500, +}); +``` + +## Precedence + +`actionMotion` is replacement-based, not deep-merged: + +1. factory `actionMotion` from `createSwipeDeck({ actionMotion })` +2. `Root actionMotion`, replacing the factory default for that Root +3. per-call recipe passed to `swipeLeft(recipe)` or `swipeRight(recipe)` + +Actions are callback-safe. If a React Native press event is passed to +`swipeRight` or `swipeLeft`, the event argument is ignored and the configured +action motion is used. diff --git a/docs/docs/1.x/en/guide/usage/undo.mdx b/docs/docs/1.x/en/guide/usage/undo.mdx new file mode 100644 index 0000000..155dd9d --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/undo.mdx @@ -0,0 +1,77 @@ +# Undo + +Undo is opt-in. Add `undoEnabled` to a Root when the deck exposes undo or +back-swipe UX. + +```tsx + item.id} undoEnabled> + {({ item }) => } + +``` + +When enabled, each successful swipe stores one key/index/direction metadata +entry in a LIFO undo stack. Lookups use a key-to-index map for the current +`data`, and invalid entries are pruned when data or keys change. + +When omitted, successful swipes do not store undo metadata, `canUndo` stays +`false`, and `actions.undo()` returns `false`. + +## Undo Button + +```tsx +function UndoButton() { + const { canUndo } = ProfileDeck.useDeckState(); + const { undo } = ProfileDeck.useDeckActions(); + + return ( + + Undo + + ); +} +``` + +## Undo Motion + +Use `SwipeDeckUndoMotion` to customize how a restored card enters. + +```tsx +import { createSwipeDeck, SwipeDeckUndoMotion } from '@react-native-motion-kit/swipe-deck'; + +const ProfileDeck = createSwipeDeck({ + undoMotion: SwipeDeckUndoMotion.spring({ + springConfig: { + damping: 36, + stiffness: 300, + mass: 3, + }, + }), +}); +``` + +Available recipes: + +- `SwipeDeckUndoMotion.spring(options?)`: restores with Reanimated `withSpring`. +- `SwipeDeckUndoMotion.timing(options?)`: restores with deterministic + `withTiming`. + +Both recipes accept: + +- `from: 'auto' | 'left' | 'right'`: `auto` returns from the original swipe + direction. +- `entryDistance`: number or layout callback for the offscreen start distance. + +`timing` also accepts `duration` and `easing`. Its default duration is `0`, so +the card is restored immediately unless you opt into custom motion. `spring` +accepts `springConfig`. + +## Precedence + +`undoMotion` is replacement-based: + +1. factory `undoMotion` from `createSwipeDeck({ undoMotion })` +2. `Root undoMotion`, replacing the factory default for that Root +3. per-call recipe passed to `actions.undo(recipe)` + +Undo is callback-safe. If a React Native press event is passed to `undo`, the +event argument is ignored. diff --git a/docs/docs/1.x/en/guide/usage/visible-card-budget.mdx b/docs/docs/1.x/en/guide/usage/visible-card-budget.mdx new file mode 100644 index 0000000..c14867c --- /dev/null +++ b/docs/docs/1.x/en/guide/usage/visible-card-budget.mdx @@ -0,0 +1,45 @@ +# Visible Card Budget + +`visibleCardCount` controls the maximum number of cards kept mounted from the +active card forward. + +```tsx +function CurrentOnlyDeck() { + return ( + item.id} visibleCardCount={1}> + {/* current card only */} + + ); +} + +function DefaultDeck() { + return ( + item.id} visibleCardCount={3}> + {/* default budget for smoother next-card promotion */} + + ); +} + +function DeepStackDeck() { + return ( + item.id} visibleCardCount={9}> + {/* deeper stacked UI */} + + ); +} +``` + +## Rules + +| Input | Mounted cards | +| ----------------------------------------------- | ---------------------------------------- | +| `visibleCardCount={1}` | Only the current card. | +| `visibleCardCount={2}` | Up to two cards when enough data exists. | +| `visibleCardCount={20}` with 10 remaining items | At most those 10 remaining items. | +| Even values | Kept as the maximum budget. | + +Values below `1` normalize to `1` when enough forward data exists. The mounted +count never exceeds the remaining data from the active index. + +Keep the budget as small as your UI allows. Increase it only when your design +visibly exposes a deeper stack or intentionally needs more cards pre-mounted. diff --git a/docs/docs/1.x/en/index.md b/docs/docs/1.x/en/index.md new file mode 100644 index 0000000..a3dba6b --- /dev/null +++ b/docs/docs/1.x/en/index.md @@ -0,0 +1,50 @@ +--- +pageType: home +description: High-performance Tinder-style swipe deck documentation for React Native apps. + +hero: + name: React Native Swipe Deck + text: Tinder-style swipe decks for React Native + tagline: High-performance card stacks powered by Reanimated, Worklets, and Gesture Handler + actions: + - theme: brand + text: Quick Start + link: /guide/getting-started/quick-start.html + - theme: alt + text: GitHub + link: https://github.com/react-native-motion-kit/react-native-swipe-deck + image: + src: /logo.png + alt: React Native Motion Kit logo +features: + - title: Gesture-First Deck UX + details: Drag, flick, threshold, and direction controls tuned for Tinder-style card stacks. + icon: 🤌 + - title: High-Performance Animations + details: Smooth card motion powered by React Native Reanimated shared values and worklets. + icon: 🏎️ + - title: Bounded Render Window + details: Mount only the active card and a small forward stack instead of the whole data set. + icon: 🪟 + - title: Item-Stable Promotion + details: Stable item keys let promoted cards keep their React Native view identity. + icon: 🧬 + - title: Typed Compound API + details: Create one typed deck family with Root, Card, hooks, actions, and events. + icon: 🧠 + - title: External Control API + details: Trigger swipeLeft, swipeRight, and undo from buttons or other UI components. + icon: 🎛️ + - title: Motion Recipes + details: Tune gesture motion, programmatic actions, and undo restores independently. + icon: 🎨 + - title: Multi-Instance Management + details: Manage multiple deck roots independently with stable factory-scoped IDs. + icon: 🧩 + - title: Undo Support + details: Opt into back-swipe UX with action-safe undo motion and LIFO history. + icon: ↩️ + - title: Easy-to-Use API + details: Start with Root and Card, then add hooks only when controls or events need them. + icon: 🪄 +--- diff --git a/docs/docs/1.x/ko/_nav.json b/docs/docs/1.x/ko/_nav.json new file mode 100644 index 0000000..4761e3e --- /dev/null +++ b/docs/docs/1.x/ko/_nav.json @@ -0,0 +1,7 @@ +[ + { + "text": "가이드", + "link": "/guide/getting-started/overview.html", + "activeMatch": "/guide/" + } +] diff --git a/docs/docs/1.x/ko/guide/_meta.json b/docs/docs/1.x/ko/guide/_meta.json new file mode 100644 index 0000000..9cc7069 --- /dev/null +++ b/docs/docs/1.x/ko/guide/_meta.json @@ -0,0 +1,12 @@ +[ + { + "type": "dir", + "name": "getting-started", + "label": "시작하기" + }, + { + "type": "dir", + "name": "usage", + "label": "사용법" + } +] diff --git a/docs/docs/1.x/ko/guide/getting-started/_meta.json b/docs/docs/1.x/ko/guide/getting-started/_meta.json new file mode 100644 index 0000000..17fcb81 --- /dev/null +++ b/docs/docs/1.x/ko/guide/getting-started/_meta.json @@ -0,0 +1 @@ +["overview", "installation", "quick-start", "ai"] diff --git a/docs/docs/1.x/ko/guide/getting-started/ai.mdx b/docs/docs/1.x/ko/guide/getting-started/ai.mdx new file mode 100644 index 0000000..c4c18b4 --- /dev/null +++ b/docs/docs/1.x/ko/guide/getting-started/ai.mdx @@ -0,0 +1,69 @@ +# AI 사용 가이드 + +AI assistant에게 코드를 생성하게 할 때 아래 규칙을 함께 전달하세요. 가장 흔한 integration +실수를 줄일 수 있습니다. + +## AI가 읽기 좋은 문서 + +이 사이트는 `rspress build` 시 AI 도구가 읽기 좋은 Markdown 파일을 함께 생성합니다. + +- [`/ko/llms.txt`](/ko/llms.txt): 페이지 링크와 요약을 담은 compact 문서 index입니다. + Agent가 필요한 페이지만 골라 읽게 할 때 사용하세요. +- [`/ko/llms-full.txt`](/ko/llms-full.txt): 한국어 문서 전체를 하나로 합친 Markdown + 파일입니다. Agent의 context budget이 충분하고 전체 API를 이해해야 할 때 사용하세요. +- [`/llms.txt`](/llms.txt)와 [`/llms-full.txt`](/llms-full.txt): English equivalents. + +공개 문서 URL이 생기기 전에는 로컬에서 build한 뒤 `docs/doc_build/` 아래의 파일을 +사용하세요. + +## 추천 프롬프트 + +```md +Use @react-native-motion-kit/swipe-deck. + +- Create one createSwipeDeck() factory outside render. +- Render Root and Card from that same factory. +- Use a stable getKey(item) value, usually item.id. +- Use factory hooks from the same factory instance as the Root. +- Use useDeckState/useDeckActions for React UI. +- Use useDeckInteraction for Reanimated UI-thread overlays. +- Use useDeckEvent/useDeckEventListener for committed swipe, undo, indexChange, + and endReached events. +- Add undoEnabled only when the UI exposes undo. +- Do not derive deck id from item ids, timestamps, or values that change each render. +``` + +## 좋은 Factory 형태 + +```tsx +// profile-deck.ts +import { createSwipeDeck } from '@react-native-motion-kit/swipe-deck'; + +export type Profile = { + id: string; + name: string; +}; + +export const ProfileDeck = createSwipeDeck(); +``` + +```tsx +// ProfileDeckScreen.tsx +import { ProfileDeck } from './profile-deck'; + +export function ProfileDeckScreen({ profiles }: { profiles: Profile[] }) { + return ( + item.id}> + {({ item }) => } + + ); +} +``` + +## 피해야 할 실수 + +- Component render path 안에서 `createSwipeDeck()`을 호출하지 마세요. +- 한 factory의 hook으로 다른 factory의 Root를 제어하지 마세요. +- Item이 삽입/삭제/재정렬될 수 있다면 array index를 key로 쓰지 마세요. +- Commit된 business logic에는 `useDeckInteraction`이 아니라 event hook을 사용하세요. +- Undo control이 없다면 `undoEnabled`를 켜지 마세요. diff --git a/docs/docs/1.x/ko/guide/getting-started/installation.mdx b/docs/docs/1.x/ko/guide/getting-started/installation.mdx new file mode 100644 index 0000000..9822f0c --- /dev/null +++ b/docs/docs/1.x/ko/guide/getting-started/installation.mdx @@ -0,0 +1,45 @@ +# 설치 + +패키지와 React Native gesture/animation peer dependency를 설치합니다. + +```sh +npm install @react-native-motion-kit/swipe-deck react-native-gesture-handler react-native-reanimated react-native-worklets +``` + +Yarn을 사용한다면: + +```sh +yarn add @react-native-motion-kit/swipe-deck react-native-gesture-handler react-native-reanimated react-native-worklets +``` + +## 최소 지원 버전 + +| Package | Minimum | +| ------------------------------ | -------- | +| `react` | `18.0.0` | +| `react-native` | `0.75.0` | +| `react-native-gesture-handler` | `2.24.0` | +| `react-native-reanimated` | `4.0.0` | +| `react-native-worklets` | `0.5.0` | + +## React Native 설정 + +사용 중인 React Native 또는 Expo 버전에 맞춰 Reanimated와 Worklets 설정을 완료하세요. +Babel 설정에서는 `react-native-worklets/plugin`을 마지막 Babel plugin으로 추가해야 합니다. + +```js title="babel.config.js" +module.exports = { + presets: ['module:@react-native/babel-preset'], + plugins: ['react-native-worklets/plugin'], +}; +``` + +Gesture Handler는 앱 surface가 `GestureHandlerRootView` 아래에 있어야 합니다. + +```tsx +import { GestureHandlerRootView } from 'react-native-gesture-handler'; + +export function AppRoot() { + return {/* app */}; +} +``` diff --git a/docs/docs/1.x/ko/guide/getting-started/overview.mdx b/docs/docs/1.x/ko/guide/getting-started/overview.mdx new file mode 100644 index 0000000..c9b2074 --- /dev/null +++ b/docs/docs/1.x/ko/guide/getting-started/overview.mdx @@ -0,0 +1,60 @@ +# 개요 + +`@react-native-motion-kit/swipe-deck`는 React Native용 고성능 Tinder 스타일 +swipe deck 라이브러리입니다. 부드러운 card stack, like/pass 버튼, progress +기반 overlay, type-safe compound API가 필요한 앱에 맞춰져 있습니다. + +## 핵심 모델 + +주요 API는 typed compound component family입니다. + +- `createSwipeDeck()`가 item type에 맞는 deck family를 만듭니다. +- `Root`는 data, gesture state, motion option, action, event, layout을 소유합니다. +- `Card`는 bounded forward window 안에 mount된 item을 렌더링합니다. +- Factory hook은 state, action, event, animated UI용 Reanimated shared value를 제공합니다. + +```tsx +import { createSwipeDeck } from '@react-native-motion-kit/swipe-deck'; + +type Profile = { + id: string; + name: string; +}; + +const ProfileDeck = createSwipeDeck(); +``` + +Factory는 한 번 만들고 shared module에서 export하세요. 같은 factory의 `Root` 주변에서 +그 factory hook을 사용해야 합니다. + +## 이 라이브러리가 해결하는 것 + +- 전체 data set을 한 번에 렌더링하지 않습니다. +- Stable key를 통해 promoted card가 item identity를 유지합니다. +- Manual drag motion과 programmatic action motion을 따로 조정할 수 있습니다. +- Interaction shared value는 UI thread에서 업데이트되어 gesture frame마다 React rerender를 만들지 않습니다. +- Event는 swipe, undo, index change, end reached 같은 commit된 model 변화를 표현합니다. + +## 핵심 개념 + +### Bounded Forward Window + +기본적으로 active index부터 최대 세 장을 mount합니다. + +1. current card +2. next card +3. next buffered card + +이 방식은 dismissed card를 다시 채우지 않으면서도 stack의 연속성을 유지합니다. +`visibleCardCount`로 최대 budget을 조정할 수 있습니다. + +### Stable Item Key + +`getKey`는 필수입니다. 같은 logical item은 swipe가 진행되어도 같은 key를 반환해야 하고, +서로 다른 item은 같은 key를 공유하지 않는 것이 좋습니다. Deck은 이 key를 각 mounted +card의 React identity로 사용합니다. + +### Commit Event와 Live Interaction + +Commit된 model 변화에는 event hook을 사용하세요. Card가 dragging, dismissing, restoring +중인지에 따라 frame-synchronous visual feedback이 필요하면 interaction shared value를 사용하세요. 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 new file mode 100644 index 0000000..4b70cf7 --- /dev/null +++ b/docs/docs/1.x/ko/guide/getting-started/quick-start.mdx @@ -0,0 +1,103 @@ +# 빠른 시작 + +Item type에 맞는 typed deck family를 하나 만드세요. 같은 factory의 `Root`, `Card`, +hook, action, event가 같은 registry namespace를 공유합니다. + +```tsx +import { Text, View } from 'react-native'; +import { createSwipeDeck, SwipeDeckMotion } from '@react-native-motion-kit/swipe-deck'; + +type Profile = { + id: string; + name: string; + bio: string; +}; + +const ProfileDeck = createSwipeDeck({ + motion: SwipeDeckMotion.tinder({ + drag: { + mode: 'horizontal', + liftYFactor: 0.15, + }, + rotation: { + mode: 'grab-position', + }, + dismiss: { + threshold: ({ width }) => width * 0.3, + velocityThreshold: 800, + minDuration: 300, + maxDuration: 520, + }, + }), +}); + +function ProfileDeckEvents() { + ProfileDeck.useDeckEventListener('swipe', ({ item, direction, source }) => { + console.log(item.name, direction, source); + }); + + ProfileDeck.useDeckEventListener('endReached', () => { + console.log('No more cards'); + }); + + return null; +} + +function ProfileCard({ profile, active }: { profile: Profile; active: boolean }) { + return ( + + {active ? '현재 카드' : '다음 카드'} + {profile.name} + {profile.bio} + + ); +} + +export function ProfileDeckScreen({ profiles }: { profiles: Profile[] }) { + return ( + <> + + item.id} visibleCardCount={3}> + + {({ item, isActive }) => } + + + + ); +} +``` + +## Control 추가 + +Counter와 button처럼 React로 렌더링되는 UI에는 state/action hook을 사용하세요. + +```tsx +function ProfileDeckControls() { + const { activeIndex, count, canSwipe, canUndo, isCompleted } = ProfileDeck.useDeckState(); + const { swipeLeft, swipeRight, undo } = ProfileDeck.useDeckActions(); + const current = activeIndex >= 0 ? activeIndex + 1 : 0; + + return ( + + {isCompleted ? 'Done' : `${current} / ${count}`} + + Nope + + + Undo + + + Like + + + ); +} +``` + +Undo UX를 노출할 때만 `undoEnabled`를 켜세요. + +```tsx + item.id} undoEnabled> + {({ item }) => } + +``` diff --git a/docs/docs/1.x/ko/guide/usage/_meta.json b/docs/docs/1.x/ko/guide/usage/_meta.json new file mode 100644 index 0000000..cd32246 --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/_meta.json @@ -0,0 +1,11 @@ +[ + "basic-usage", + "deck-hooks", + "handling-events", + "programmatic-actions", + "undo", + "motion", + "multi-instance-management", + "visible-card-budget", + "api-reference" +] diff --git a/docs/docs/1.x/ko/guide/usage/api-reference.mdx b/docs/docs/1.x/ko/guide/usage/api-reference.mdx new file mode 100644 index 0000000..7fd5c75 --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/api-reference.mdx @@ -0,0 +1,130 @@ +--- +description: 주요 export, Root와 Card props, hook, event, built-in motion helper를 빠르게 확인합니다. +--- + +# API 레퍼런스 + +## 주요 export + +```ts +export { + SwipeDeckActionMotion, + SwipeDeckMotion, + createSwipeDeck, + SwipeDeck, + SwipeDeckUndoMotion, +} from '@react-native-motion-kit/swipe-deck'; +``` + +[Source 보기](https://github.com/react-native-motion-kit/react-native-swipe-deck/blob/main/src/index.tsx) + +## `createSwipeDeck(config?)` + +Typed deck family를 만듭니다. + +```tsx +const ProfileDeck = createSwipeDeck({ + motion: SwipeDeckMotion.tinder(), +}); +``` + +반환되는 instance는 다음을 포함합니다. + +- `Root` +- `Card` +- `useDeckState` +- `useDeckActions` +- `useDeckInteraction` +- `useDeckEvent` +- `useDeckEventListener` + +## `SwipeDeck.Root` props + +[Source 보기](https://github.com/react-native-motion-kit/react-native-swipe-deck/blob/main/src/types.ts) + +| Prop | Type | 설명 | +| ------------------- | ------------------------------------ | ---------------------------------------------- | +| `id` | `string` | Factory-scoped deck namespace입니다. | +| `data` | `readonly T[]` | Deck이 렌더링할 ordered item입니다. | +| `getKey` | `(item: T, index: number) => string` | 필수 stable item key입니다. | +| `initialIndex` | `number` | 초기 active item index입니다. | +| `disabled` | `boolean` | accepted action과 gesture를 비활성화합니다. | +| `allowedDirections` | `AllowedDirections` | 허용할 dismiss direction을 제한합니다. | +| `swipeThreshold` | `SwipeThreshold` | Root-level dismiss threshold override입니다. | +| `velocityThreshold` | `number` | Root-level flick threshold override입니다. | +| `motion` | `SwipeDeckMotionPreset` | Gesture-driven motion preset입니다. | +| `actionMotion` | `SwipeDeckActionMotionRecipe` | Programmatic swipe motion recipe입니다. | +| `undoMotion` | `SwipeDeckUndoMotionRecipe` | Programmatic undo restore motion recipe입니다. | +| `undoEnabled` | `boolean` | Undo history tracking을 활성화합니다. | +| `visibleCardCount` | `number` | Forward mounted card의 최대 budget입니다. | +| `containerStyle` | `StyleProp` | Deck container에 적용할 style입니다. | +| `children` | `ReactNode` | Matching `SwipeDeck.Card`를 포함해야 합니다. | + +```ts +type AllowedDirections = readonly ('left' | 'right')[]; +type SwipeThreshold = number | ((layout: SwipeDeckLayout) => number); +``` + +Static `SwipeDeck.Root`는 `id`를 제외한 같은 props를 받습니다. + +## `SwipeDeck.Card` props + +| Prop | Type | 설명 | +| ---------- | ----------------------------------------- | ------------------------------------------ | +| `style` | `StyleProp` | Absolute card container에 적용됩니다. | +| `children` | `(info: SwipeRenderInfo) => ReactNode` | Bounded window의 item 하나를 렌더링합니다. | + +`SwipeRenderInfo`는 `item`, `index`, `offset`, `role`, `isActive`를 포함합니다. + +## State와 Actions + +```ts +type SwipeDeckState = { + activeIndex: number; + count: number; + isCompleted: boolean; + canSwipe: boolean; + canUndo: boolean; +}; + +type SwipeDeckActions = { + swipeLeft: SwipeDeckAction; + swipeRight: SwipeDeckAction; + undo: SwipeDeckUndoAction; +}; +``` + +Programmatic action은 action이 받아들여졌는지 알려주는 `boolean`을 반환합니다. + +## Interaction + +```ts +type SwipeDeckInteractionPhase = 'idle' | 'dragging' | 'dismissing' | 'undoing'; +``` + +`useDeckInteraction()`은 `progress`, `signedProgress`, `direction`, `dismissDirection`, +`translationX`, `translationY`, `isDragging`, `phase` Reanimated shared value를 반환합니다. + +## Events + +```ts +type SwipeDeckEventMap = { + swipe: SwipeEvent; + undo: UndoEvent; + indexChange: { index: number }; + endReached: true; +}; +``` + +최신 event snapshot에는 `useDeckEvent`를, imperative subscription에는 `useDeckEventListener`를 +사용하세요. + +## Motion Helpers + +- `SwipeDeckMotion.tinder(options?)` +- `SwipeDeckActionMotion.direct(options?)` +- `SwipeDeckActionMotion.springboard(options?)` +- `SwipeDeckUndoMotion.spring(options?)` +- `SwipeDeckUndoMotion.timing(options?)` + +동작 세부 사항은 이 reference보다 guide page를 먼저 참고하는 것을 권장합니다. diff --git a/docs/docs/1.x/ko/guide/usage/basic-usage.mdx b/docs/docs/1.x/ko/guide/usage/basic-usage.mdx new file mode 100644 index 0000000..9c78909 --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/basic-usage.mdx @@ -0,0 +1,78 @@ +--- +description: Factory API, Card render info, allowedDirections, static SwipeDeck API를 언제 쓰는지 정리합니다. +--- + +# 기본 사용법 + +## Factory API + +Factory API가 기본 API입니다. Deck state, action, event, interaction shared value, +또는 여러 named instance가 필요하다면 factory API를 사용하세요. + +```tsx +import { createSwipeDeck } from '@react-native-motion-kit/swipe-deck'; + +const ProfileDeck = createSwipeDeck(); + +function Screen() { + return ( + item.id}> + {({ item }) => } + + ); +} +``` + +Factory는 `Root`, `Card`, hook이 같은 item type을 공유하도록 해 JSX에서 generic을 +반복하지 않아도 됩니다. + +## Card Render Info + +`Card`는 mounted item마다 render info를 받습니다. + +| Field | 의미 | +| ---------- | ---------------------------------------------------------- | +| `item` | 사용자의 `data` 배열에 있는 item입니다. | +| `index` | `data` 안에서의 item index입니다. | +| `offset` | active item으로부터의 card offset입니다. | +| `role` | active card는 `'current'`, buffered card는 `'next'`입니다. | +| `isActive` | active card에서만 `true`입니다. | + +```tsx + + {({ item, role, isActive }) => } + +``` + +## Allowed Directions + +`allowedDirections`는 dismiss로 받아들일 방향을 제한합니다. + +```tsx + item.id} allowedDirections={['right']}> + {({ item }) => } + +``` + +- 생략하면 양방향을 모두 허용합니다. +- `['left']` 또는 `['right']`는 한 방향만 허용합니다. +- `[]`는 drag는 허용하지만 모든 dismiss release와 programmatic swipe action을 거절합니다. + +## Static API + +Card rendering만 필요하고 factory hook이 필요 없다면 static API를 사용할 수 있습니다. + +```tsx +import { SwipeDeck } from '@react-native-motion-kit/swipe-deck'; + +function InlineDeck() { + return ( + item.id}> + >{({ item }) => } + + ); +} +``` + +Static `Root`는 `id`를 받지 않습니다. Static `Root`와 `Card`는 factory처럼 item type을 +함께 고정하지 않으므로, typed render prop이 필요하면 `Card`에 item type을 직접 넘기세요. diff --git a/docs/docs/1.x/ko/guide/usage/deck-hooks.mdx b/docs/docs/1.x/ko/guide/usage/deck-hooks.mdx new file mode 100644 index 0000000..4799a3d --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/deck-hooks.mdx @@ -0,0 +1,97 @@ +# Deck Hooks + +Factory hook은 Provider prop이나 controller object 없이 deck state, action, interaction 값을 +제공합니다. + +```tsx +const ProfileDeck = createSwipeDeck(); +``` + +## `useDeckState(id?)` + +React로 렌더링되는 deck state를 반환합니다. + +| Field | 의미 | +| ------------- | ------------------------------------------------------- | +| `activeIndex` | 현재 active item index입니다. attach 전에는 `-1`입니다. | +| `count` | attach된 deck의 전체 item 수입니다. | +| `isCompleted` | 모든 item을 소비했는지 여부입니다. | +| `canSwipe` | dismiss action이 현재 받아들여질 수 있는지 여부입니다. | +| `canUndo` | 최신 valid swipe를 현재 복원할 수 있는지 여부입니다. | + +```tsx +function Counter() { + const { activeIndex, count, isCompleted } = ProfileDeck.useDeckState(); + const current = activeIndex >= 0 ? activeIndex + 1 : 0; + + return {isCompleted ? 'Done' : `${current} / ${count}`}; +} +``` + +현재 item이 필요하면 사용자의 `data[activeIndex]`에서 직접 계산하세요. Deck state는 +primitive하고 stable하게 유지됩니다. + +## `useDeckActions(id?)` + +Stable action callback을 반환합니다. + +```tsx +function Controls() { + const { canSwipe, canUndo } = ProfileDeck.useDeckState(); + const { swipeLeft, swipeRight, undo } = ProfileDeck.useDeckActions(); + + return ( + + + Nope + + + Undo + + + Like + + + ); +} +``` + +`swipeLeft()`와 `swipeRight()`는 action이 받아들여지면 `true`, deck이 unattached, +disabled, animating, unmeasured, completed 상태이거나 direction이 허용되지 않으면 `false`를 +반환합니다. `undo()`는 deck 완료 후에도 `canUndo`가 true이면 `true`를 반환합니다. + +## `useDeckInteraction(id?)` + +Progress 기반 UI를 위한 Reanimated shared value를 반환합니다. + +```tsx +function SwipeReactionOverlay() { + const { signedProgress } = ProfileDeck.useDeckInteraction(); + + const likeStyle = useAnimatedStyle(() => { + const progress = Math.max(signedProgress.get(), 0); + + return { + opacity: progress, + transform: [{ scale: 0.9 + progress * 0.18 }], + }; + }); + + return ; +} +``` + +Interaction value는 UI thread에서 업데이트되고 gesture frame마다 React rerender를 만들지 않습니다. + +| Value | 의미 | +| ------------------ | --------------------------------------------------------- | +| `progress` | `0`부터 `1`까지의 absolute swipe progress입니다. | +| `signedProgress` | `-1`부터 `1`까지의 signed progress입니다. | +| `direction` | raw live direction signal입니다. `-1`, `0`, `1`. | +| `dismissDirection` | accepted dismiss side입니다. `'left'`, `'right'`, `null`. | +| `translationX` | active card의 horizontal translation입니다. | +| `translationY` | active card의 vertical translation입니다. | +| `isDragging` | deck이 dragging 또는 dismissing 중인지 여부입니다. | +| `phase` | `idle`, `dragging`, `dismissing`, `undoing`. | + +Frame-synchronous visual feedback에는 `phase`를 사용하세요. Commit된 state 변화에는 event hook을 사용하세요. diff --git a/docs/docs/1.x/ko/guide/usage/handling-events.mdx b/docs/docs/1.x/ko/guide/usage/handling-events.mdx new file mode 100644 index 0000000..f3f18f4 --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/handling-events.mdx @@ -0,0 +1,78 @@ +# Event 처리 + +Event hook은 commit된 model event를 표현합니다. Live interaction value와 분리해서 생각하세요. + +## Event Map + +| Event | Payload | +| ------------- | ------------------------------------ | +| `swipe` | `{ item, index, direction, source }` | +| `undo` | `{ item, index, direction }` | +| `indexChange` | `{ index }` | +| `endReached` | `true` | + +`swipe.source`는 사용자가 pan gesture를 threshold/velocity 기준 이상으로 놓아 commit한 경우 +`'gesture'`입니다. `actions.swipeLeft()` 또는 `actions.swipeRight()`로 commit된 경우 +`'programmatic'`입니다. + +## `useDeckEvent` + +`useDeckEvent(eventName, initialValue?, id?)`는 React 렌더링 UI를 위한 최신 commit event +snapshot을 반환합니다. + +```tsx +function ProfileDeckStatus() { + const lastSwipe = ProfileDeck.useDeckEvent('swipe', null); + const endReached = ProfileDeck.useDeckEvent('endReached', false); + + return ( + + {endReached + ? 'Done' + : lastSwipe + ? `Last swipe: ${lastSwipe.direction} from ${lastSwipe.source}` + : 'No swipe yet'} + + ); +} +``` + +이 API는 latest-value API이며 event history가 아닙니다. Root가 attach/detach될 때 event +snapshot은 clear됩니다. + +Initial value는 event payload shape, `null`, `undefined`, 또는 `endReached`의 `false`로 +제한됩니다. `swipe` 같은 object event에는 `null`을 사용하세요. + +Initial value 없이 named deck을 읽어야 한다면 id를 두 번째 인자로 넘깁니다. + +```tsx +const lastSwipe = ProfileDeck.useDeckEvent('swipe', 'nearby'); +``` + +Initial value도 함께 넘기는 경우 id는 세 번째 인자입니다. + +## `useDeckEventListener` + +`useDeckEventListener(eventName, listener, id?)`는 앱 코드에 별도 React state를 만들지 않고 +imperative하게 event를 구독합니다. + +```tsx +function ProfileDeckEvents() { + ProfileDeck.useDeckEventListener('swipe', ({ item, direction, source }) => { + console.log(item, direction, source); + }); + + ProfileDeck.useDeckEventListener('undo', ({ item }) => { + console.log('Restored', item); + }); + + ProfileDeck.useDeckEventListener('endReached', () => { + console.log('No more cards'); + }); + + return null; +} +``` + +성공한 swipe는 `swipe -> indexChange -> endReached` 순서로 emit됩니다. Undo는 +`undo -> indexChange` 순서로 emit됩니다. diff --git a/docs/docs/1.x/ko/guide/usage/motion.mdx b/docs/docs/1.x/ko/guide/usage/motion.mdx new file mode 100644 index 0000000..a5b7d0a --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/motion.mdx @@ -0,0 +1,133 @@ +# Motion + +`SwipeDeckMotion.tinder()`는 Tinder 스타일 card stack을 위한 기본 motion preset입니다. + +```tsx +import { SwipeDeckMotion } from '@react-native-motion-kit/swipe-deck'; + +const motion = SwipeDeckMotion.tinder({ + drag: { + mode: 'horizontal', + liftYFactor: 0.15, + }, + rotation: { + mode: 'grab-position', + }, + dismiss: { + threshold: ({ width }) => width * 0.3, + velocityThreshold: 800, + minDuration: 300, + maxDuration: 520, + }, +}); +``` + +## Swipe Progress를 따라가는 것 + +Buffered next card는 swipe progress에 따라 애니메이션됩니다. + +- scale은 `1`에 가까워집니다. +- opacity는 `1`에 가까워집니다. +- `translateY`는 `0`에 가까워집니다. + +Swipe가 commit되면 dismissed card는 화면 밖으로 나가고, promoted next card는 item identity를 +유지하며, 새로운 future item이 bounded window에 들어옵니다. + +## Drag Mode + +`drag.mode`는 drag 중 active card가 손가락 translation을 어떻게 사용할지 제어합니다. + +| Mode | Active card 움직임 | +| ------------ | ----------------------------------------------- | +| `free` | 손가락의 X/Y 이동을 모두 따라갑니다. | +| `horizontal` | 손가락의 Y 이동은 무시하고 X 이동만 반영합니다. | + +`drag.liftYFactor`는 active card를 `abs(translationX) * liftYFactor`만큼 위로 올립니다. + +## Rotation + +`rotation.mode`는 회전 기준점을 고정할지, gesture 시작 위치에서 계산할지 제어합니다. + +### Fixed Rotation + +모든 gesture가 같은 anchor를 사용해야 한다면 fixed rotation을 사용하세요. + +| Origin | 느낌 | +| --------------- | -------------------------------------------- | +| `center` | 카드 중앙을 기준으로 회전합니다. | +| `top-center` | 카드 위쪽 edge가 고정된 축처럼 느껴집니다. | +| `bottom-center` | 카드 아래쪽 edge가 고정된 축처럼 느껴집니다. | + +```tsx +SwipeDeckMotion.tinder({ + rotation: { + mode: 'fixed', + origin: 'bottom-center', + direction: 'default', + }, +}); +``` + +같은 고정 anchor에서 회전 부호만 반대로 만들고 싶다면 `direction: 'reverse'`를 사용하세요. + +### Grab-Position Rotation + +Grab-position rotation은 기본 Tinder-like 동작입니다. + +```tsx +SwipeDeckMotion.tinder({ + rotation: { + mode: 'grab-position', + direction: 'default', + maxDegrees: 25, + }, +}); +``` + +카드 위쪽에서 잡으면 top-center anchor와 default rotation sign을 사용합니다. 아래쪽에서 잡으면 +bottom-center anchor와 reverse rotation sign을 사용합니다. `direction: 'reverse'`는 이 mapping을 +뒤집습니다. + +## Dismiss Target + +`dismiss.offscreenMultiplier`는 성공한 swipe의 release target을 제어합니다. + +- 성공한 swipe는 항상 화면 밖으로 dismiss됩니다. +- 기본값 `1.5`는 카드를 `clearDistance * 1.5` 위치로 보냅니다. +- `clearDistance`는 swipe direction, rotation mode, rotation direction, gesture start position으로 계산합니다. +- `1`보다 작은 값은 `1`로 정규화됩니다. +- `duration`을 생략하면 target까지 남은 거리로 velocity-derived timing을 계산합니다. + +대부분의 앱은 `threshold`, `velocityThreshold`, `duration`, `minDuration`, `maxDuration`, +`easing`만 조정해도 충분합니다. + +## Motion 우선순위 + +Motion 값은 다음 순서로 resolve됩니다. + +1. `createSwipeDeck({ motion })`의 factory motion default +2. 명시한 field만 부분 override하는 `Root motion` +3. `swipeThreshold`, `velocityThreshold` 같은 direct root prop + +Factory motion과 Root motion은 deep merge됩니다. `rotation.mode`를 바꿔도 `maxDegrees`, +`inputRange` 같은 numeric rotation tuning은 reset되지 않습니다. + +## Preset 안정성 + +Motion preset은 module-scope constant 또는 `useMemo`로 안정적으로 유지하세요. + +```tsx +const profileDeckMotion = SwipeDeckMotion.tinder({ + rotation: { + mode: 'fixed', + origin: 'bottom-center', + }, + dismiss: { + threshold: ({ width }) => width * 0.3, + }, +}); + +const ProfileDeck = createSwipeDeck({ + motion: profileDeckMotion, +}); +``` diff --git a/docs/docs/1.x/ko/guide/usage/multi-instance-management.mdx b/docs/docs/1.x/ko/guide/usage/multi-instance-management.mdx new file mode 100644 index 0000000..65d630c --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/multi-instance-management.mdx @@ -0,0 +1,56 @@ +# Multi-Instance Management + +같은 factory에서 여러 Root를 렌더링할 때만 `id`를 사용하세요. + +```tsx +function MultiDeckScreen() { + const nearbyState = ProfileDeck.useDeckState('nearby'); + + return ( + <> + item.id}> + {({ item }) => } + + + item.id}> + {({ item }) => } + + + {nearbyState.activeIndex + 1} + + ); +} +``` + +`id`는 item key가 아니라 factory 안에서 deck instance를 구분하는 namespace입니다. 서로 다른 +factory는 둘 다 default id를 써도 충돌하지 않지만, 같은 factory와 같은 id의 Root 두 개가 +동시에 mount되는 것은 잘못된 사용입니다. + +## Id 규칙 + +- 안정적이고 적은 개수의 id를 사용하세요. +- `"nearby"`, `"recommended"` 같은 화면/용도 단위 이름을 사용하세요. +- Item id, timestamp, 매 render마다 바뀌는 값, 일회성 route 값에서 id를 만들지 마세요. +- Factory와 id는 render path 밖에서 안정적으로 만들고 유지하세요. + +Registry는 hook, action, interaction shared value의 identity를 안정적으로 유지하기 위해 factory +lifetime 동안 id별 store를 유지합니다. + +## Same-Factory Rule + +Hook, action, interaction은 같은 factory instance에서 만든 Root에만 연결됩니다. + +```ts +const ProfileDeck = createSwipeDeck(); + +export const { + Root: ProfileDeckRoot, + Card: ProfileDeckCard, + useDeckState: useProfileDeckState, + useDeckActions: useProfileDeckActions, + useDeckInteraction: useProfileDeckInteraction, +} = ProfileDeck; +``` + +Item type과 id가 같아도 `createSwipeDeck()`를 다시 호출하면 별도 registry namespace가 +만들어집니다. diff --git a/docs/docs/1.x/ko/guide/usage/programmatic-actions.mdx b/docs/docs/1.x/ko/guide/usage/programmatic-actions.mdx new file mode 100644 index 0000000..bf9e297 --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/programmatic-actions.mdx @@ -0,0 +1,73 @@ +# Programmatic Actions + +Programmatic action은 `useDeckActions()`에서 가져옵니다. 버튼, 외부 control, 앱 로직에서 +active card를 dismiss할 때 사용하세요. + +```tsx +function LikeButton() { + const { swipeRight } = ProfileDeck.useDeckActions(); + + return Like; +} +``` + +## Action Motion + +`motion`은 manual drag feel을 제어합니다. `actionMotion`은 `swipeLeft()`와 `swipeRight()` +같은 programmatic action만 제어합니다. + +```tsx +import { + createSwipeDeck, + SwipeDeckActionMotion, + SwipeDeckMotion, +} from '@react-native-motion-kit/swipe-deck'; + +const ProfileDeck = createSwipeDeck({ + motion: SwipeDeckMotion.tinder(), + actionMotion: SwipeDeckActionMotion.springboard({ + anticipationDistance: ({ width }) => width * 0.04, + anticipationDuration: 80, + dismissDuration: 320, + }), +}); +``` + +## Recipe + +### `SwipeDeckActionMotion.direct(options?)` + +Action 방향으로 바로 dismiss합니다. 생략한 값은 deck에서 resolve된 dismiss duration, easing, +offscreen multiplier를 재사용합니다. + +```tsx +actions.swipeLeft( + SwipeDeckActionMotion.direct({ + duration: 180, + }), +); +``` + +### `SwipeDeckActionMotion.springboard(options?)` + +최종 방향의 반대쪽으로 살짝 움직인 뒤 화면 밖으로 dismiss합니다. Anticipation 동안 swipe +progress와 live direction은 neutral 상태로 유지되어 반대쪽 overlay가 순간적으로 보이지 않습니다. + +```tsx +const actionMotion = SwipeDeckActionMotion.springboard({ + anticipationDistance: 40, + anticipationDuration: 160, + dismissDuration: 500, +}); +``` + +## 우선순위 + +`actionMotion`은 deep merge가 아니라 replacement 방식입니다. + +1. `createSwipeDeck({ actionMotion })`의 factory `actionMotion` +2. 해당 Root에서 factory default를 대체하는 `Root actionMotion` +3. `swipeLeft(recipe)` 또는 `swipeRight(recipe)`에 넘긴 per-call recipe + +Action은 callback으로 바로 넘겨도 안전합니다. React Native press event가 `swipeRight` 또는 +`swipeLeft`로 전달되면 그 event 인자는 무시됩니다. diff --git a/docs/docs/1.x/ko/guide/usage/undo.mdx b/docs/docs/1.x/ko/guide/usage/undo.mdx new file mode 100644 index 0000000..606e18b --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/undo.mdx @@ -0,0 +1,74 @@ +# Undo + +Undo는 opt-in입니다. 해당 deck에서 undo/back-swipe UX를 제공할 때 Root에 `undoEnabled`를 +추가하세요. + +```tsx + item.id} undoEnabled> + {({ item }) => } + +``` + +활성화되면 성공한 swipe마다 key/index/direction metadata entry 하나를 LIFO undo stack에 +저장합니다. Lookup은 현재 `data`에 대한 key-to-index map을 사용하고, data나 key가 바뀌면 +invalid entry를 prune합니다. + +생략하면 성공한 swipe도 undo metadata를 저장하지 않고, `canUndo`는 `false`를 유지하며, +`actions.undo()`는 `false`를 반환합니다. + +## Undo Button + +```tsx +function UndoButton() { + const { canUndo } = ProfileDeck.useDeckState(); + const { undo } = ProfileDeck.useDeckActions(); + + return ( + + Undo + + ); +} +``` + +## Undo Motion + +`SwipeDeckUndoMotion`으로 restored card가 들어오는 motion을 조정할 수 있습니다. + +```tsx +import { createSwipeDeck, SwipeDeckUndoMotion } from '@react-native-motion-kit/swipe-deck'; + +const ProfileDeck = createSwipeDeck({ + undoMotion: SwipeDeckUndoMotion.spring({ + springConfig: { + damping: 36, + stiffness: 300, + mass: 3, + }, + }), +}); +``` + +제공되는 recipe는 다음과 같습니다. + +- `SwipeDeckUndoMotion.spring(options?)`: Reanimated `withSpring`으로 restore합니다. +- `SwipeDeckUndoMotion.timing(options?)`: deterministic한 `withTiming`으로 restore합니다. + +두 recipe는 공통으로 다음 옵션을 받습니다. + +- `from: 'auto' | 'left' | 'right'`: `auto`는 원래 swipe된 방향에서 card를 되돌립니다. +- `entryDistance`: 화면 밖 시작 거리를 number 또는 layout callback으로 지정합니다. + +`timing`은 `duration`, `easing`을 추가로 받고 기본 duration은 `0`입니다. 별도 motion을 +설정하지 않으면 card를 즉시 복원합니다. `spring`은 `springConfig`를 받습니다. + +## 우선순위 + +`undoMotion`은 replacement 방식입니다. + +1. `createSwipeDeck({ undoMotion })`의 factory `undoMotion` +2. 해당 Root에서 factory default를 대체하는 `Root undoMotion` +3. `actions.undo(recipe)`에 넘긴 per-call recipe + +Undo도 callback으로 바로 넘겨도 안전합니다. React Native press event가 `undo`로 전달되면 +그 event 인자는 무시됩니다. diff --git a/docs/docs/1.x/ko/guide/usage/visible-card-budget.mdx b/docs/docs/1.x/ko/guide/usage/visible-card-budget.mdx new file mode 100644 index 0000000..fb0306a --- /dev/null +++ b/docs/docs/1.x/ko/guide/usage/visible-card-budget.mdx @@ -0,0 +1,44 @@ +# Visible Card Budget + +`visibleCardCount`는 active card부터 forward 방향으로 mount할 card의 최대 개수를 제어합니다. + +```tsx +function CurrentOnlyDeck() { + return ( + item.id} visibleCardCount={1}> + {/* 현재 카드만 렌더링 */} + + ); +} + +function DefaultDeck() { + return ( + item.id} visibleCardCount={3}> + {/* 더 자연스러운 next-card promotion을 위한 기본 budget */} + + ); +} + +function DeepStackDeck() { + return ( + item.id} visibleCardCount={9}> + {/* 더 깊은 stack UI */} + + ); +} +``` + +## 규칙 + +| 입력 | Mount되는 card | +| ---------------------------------------------- | ----------------------------- | +| `visibleCardCount={1}` | 현재 카드만 | +| `visibleCardCount={2}` | 데이터가 충분할 때 최대 두 장 | +| 남은 데이터가 10개이고 `visibleCardCount={20}` | 최대 남은 10장 | +| 짝수 값 | 최대 budget으로 그대로 유지 | + +`1`보다 작은 값은 forward data가 충분할 때 `1`로 정규화됩니다. 실제 mount 개수는 active index부터 +남은 data 개수를 넘지 않습니다. + +UI가 허용하는 한 작은 budget을 유지하세요. 더 깊은 stack이 실제로 보이거나 더 많은 card를 미리 +mount해야 할 때만 늘리는 것을 권장합니다. diff --git a/docs/docs/1.x/ko/index.md b/docs/docs/1.x/ko/index.md new file mode 100644 index 0000000..109aee0 --- /dev/null +++ b/docs/docs/1.x/ko/index.md @@ -0,0 +1,50 @@ +--- +pageType: home +description: React Native 앱을 위한 고성능 Tinder 스타일 swipe deck 문서. + +hero: + name: React Native Swipe Deck + text: React Native용 Tinder 스타일 swipe deck + tagline: Reanimated, Worklets, Gesture Handler 기반의 고성능 card stack + actions: + - theme: brand + text: 빠른 시작 + link: /ko/guide/getting-started/quick-start.html + - theme: alt + text: GitHub + link: https://github.com/react-native-motion-kit/react-native-swipe-deck + image: + src: /logo.png + alt: React Native Motion Kit 로고 +features: + - title: Gesture 중심 Deck UX + details: Tinder 스타일 card stack에 맞춰 drag, flick, threshold, direction control을 조정합니다. + icon: 🤌 + - title: 고성능 애니메이션 + details: React Native Reanimated shared value와 worklet 기반으로 부드러운 card motion을 만듭니다. + icon: 🏎️ + - title: Bounded Render Window + details: 전체 데이터가 아니라 active card와 작은 forward stack만 mount합니다. + icon: 🪟 + - title: Item-Stable Promotion + details: 안정적인 item key로 promoted card가 React Native view identity를 유지합니다. + icon: 🧬 + - title: Typed Compound API + details: Root, Card, hook, action, event를 하나의 typed deck family로 묶습니다. + icon: 🧠 + - title: 외부 제어 API + details: button이나 다른 UI에서 swipeLeft, swipeRight, undo를 programmatic하게 실행합니다. + icon: 🎛️ + - title: Motion Recipes + details: gesture motion, programmatic action, undo restore를 각각 독립적으로 조정합니다. + icon: 🎨 + - title: Multi-Instance Management + details: 안정적인 factory-scoped id로 여러 deck root를 독립적으로 관리합니다. + icon: 🧩 + - title: Undo Support + details: opt-in undo history와 action-safe restore motion으로 back-swipe UX를 만듭니다. + icon: ↩️ + - title: 쉬운 API + details: Root와 Card로 시작하고, control이나 event가 필요할 때만 hook을 추가합니다. + icon: 🪄 +--- diff --git a/docs/docs/env.d.ts b/docs/docs/env.d.ts new file mode 100644 index 0000000..73badc4 --- /dev/null +++ b/docs/docs/env.d.ts @@ -0,0 +1,11 @@ +declare module '*.mdx' { + import type { ComponentType } from 'react'; + + const MDXComponent: ComponentType<{ + [key: string]: any; + }>; + + export default MDXComponent; +} + +declare module '*.css'; diff --git a/docs/docs/public/logo.png b/docs/docs/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b69e1e359c8ffa834f41fac6e94d98a0fe876d72 GIT binary patch literal 184611 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
    ~%b8nw2S~ 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 z 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
    7`t<40evDz62*d=)P+3cuMNFkx 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 O^? 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

    H~=%!WP+?j^4Otoaimg43PA(et;UwSh8(Ci0- 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 literal 0 HcmV?d00001 diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..582f32c --- /dev/null +++ b/docs/package.json @@ -0,0 +1,21 @@ +{ + "name": "@react-native-motion-kit/swipe-deck-docs", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "rspress build", + "dev": "rspress dev", + "preview": "rspress preview", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@rspress/core": "^2.0.13", + "@shikijs/transformers": "^4.1.0", + "@types/node": "^24", + "@types/react": "^19.2.0", + "react": "19.2.3", + "react-dom": "19.2.3", + "typescript": "^6.0.2" + } +} diff --git a/docs/rspress.config.ts b/docs/rspress.config.ts new file mode 100644 index 0000000..f4014ec --- /dev/null +++ b/docs/rspress.config.ts @@ -0,0 +1,63 @@ +import { defineConfig } from '@rspress/core'; +import { transformerNotationDiff, transformerNotationHighlight } from '@shikijs/transformers'; +import * as path from 'node:path'; + +export default defineConfig({ + root: path.join(__dirname, 'docs'), + lang: 'en', + title: 'React Native Swipe Deck', + description: 'High-performance Tinder-style swipe deck documentation for React Native apps.', + icon: '/logo.png', + logo: '/logo.png', + logoText: 'React Native Swipe Deck', + llms: true, + multiVersion: { + default: '1.x', + versions: ['1.x'], + }, + search: { + versioned: true, + }, + ssg: true, + markdown: { + showLineNumbers: true, + defaultWrapCode: false, + link: { + checkDeadLinks: { + excludes: ['/llms.txt', '/llms-full.txt', '/ko/llms.txt', '/ko/llms-full.txt'], + }, + }, + shiki: { + transformers: [transformerNotationDiff(), transformerNotationHighlight()], + }, + }, + themeConfig: { + lastUpdated: true, + socialLinks: [ + { + icon: 'github', + mode: 'link', + content: 'https://github.com/react-native-motion-kit/react-native-swipe-deck', + }, + { + icon: 'npm', + mode: 'link', + content: 'https://www.npmjs.com/package/@react-native-motion-kit/swipe-deck', + }, + ], + locales: [ + { + lang: 'en', + label: 'English', + }, + { + lang: 'ko', + label: '한국어', + }, + ], + editLink: { + docRepoBaseUrl: + 'https://github.com/react-native-motion-kit/react-native-swipe-deck/tree/main/docs/docs', + }, + }, +}); diff --git a/docs/theme/index.css b/docs/theme/index.css new file mode 100644 index 0000000..52c58b9 --- /dev/null +++ b/docs/theme/index.css @@ -0,0 +1,8 @@ +.rp-home-hero .home-install-command { + width: min(100%, 450px); + margin-top: 1rem; +} + +.rp-home-hero .home-install-command .rp-tabs { + margin: 0; +} diff --git a/docs/theme/index.tsx b/docs/theme/index.tsx new file mode 100644 index 0000000..a2a6f08 --- /dev/null +++ b/docs/theme/index.tsx @@ -0,0 +1,73 @@ +import './index.css'; +import { + HomeLayout as BasicHomeLayout, + NotFoundLayout as BasicNotFoundLayout, + PackageManagerTabs, +} from '@rspress/core/theme-original'; +import { useEffect } from 'react'; + +const GUIDE_SECTION_NAMES = new Set(['getting-started', 'usage']); +const INSTALL_PACKAGES = '@react-native-motion-kit/swipe-deck'; +const INSTALL_COMMANDS = { + npm: `npm install ${INSTALL_PACKAGES}`, + yarn: `yarn add ${INSTALL_PACKAGES}`, + pnpm: `pnpm add ${INSTALL_PACKAGES}`, + bun: `bun add ${INSTALL_PACKAGES}`, +}; + +function getGuideRedirectPath(pathname: string) { + const parts = pathname.split('/').filter(Boolean); + const prefix: string[] = []; + let rest = parts; + let hadDefaultVersionPrefix = false; + + if (rest[0] === '1.x') { + hadDefaultVersionPrefix = true; + rest = rest.slice(1); + } + + if (rest[0] === 'ko') { + prefix.push(rest[0]); + rest = rest.slice(1); + } + + const [section] = rest; + + if (hadDefaultVersionPrefix && section === 'guide') { + return `/${[...prefix, ...rest].join('/')}`; + } + + if (section && GUIDE_SECTION_NAMES.has(section)) { + return `/${[...prefix, 'guide', ...rest].join('/')}`; + } + + return null; +} + +function HomeLayout() { + return ( + + + + } + /> + ); +} + +function NotFoundLayout() { + useEffect(() => { + const redirectPath = getGuideRedirectPath(window.location.pathname); + + if (redirectPath) { + window.location.replace(`${redirectPath}${window.location.search}${window.location.hash}`); + } + }, []); + + return ; +} + +export { HomeLayout, NotFoundLayout }; +// oxlint-disable-next-line import/export +export * from '@rspress/core/theme-original'; diff --git a/docs/tsconfig.json b/docs/tsconfig.json new file mode 100644 index 0000000..fa4849d --- /dev/null +++ b/docs/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["DOM", "ES2020"], + "module": "ESNext", + "jsx": "react-jsx", + "noEmit": true, + "strict": true, + "skipLibCheck": true, + "isolatedModules": true, + "resolveJsonModule": true, + "moduleResolution": "bundler", + "useDefineForClassFields": true, + "allowImportingTsExtensions": true, + "paths": { + "@theme": ["./theme"] + } + }, + "include": ["docs/**/*", "theme/**/*", "rspress.config.ts"], + "mdx": { + "checkMdx": true + } +} diff --git a/package.json b/package.json index eb00933..aa428a9 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,35 @@ { "name": "@react-native-motion-kit/swipe-deck", "version": "1.3.0", - "description": "High-performance Tinder-style swipe deck and swipe cards for React Native, powered by Reanimated and Gesture Handler.", + "description": "High-performance Tinder-style swipe deck and swipe cards for React Native, powered by Reanimated, Worklets, and Gesture Handler.", "keywords": [ "android", "animation", "card-stack", + "card-swiper", "deck-swiper", + "expo", "gesture", "gesture-handler", "ios", "react-native", + "react-native-card-stack", + "react-native-card-swiper", + "react-native-deck-swiper", "react-native-gesture-handler", + "react-native-motion-kit", "react-native-reanimated", + "react-native-swipe-cards", "react-native-swipe-deck", + "react-native-worklets", "reanimated", "swipe-cards", "swipe-deck", + "swipeable-cards", "tinder-cards", - "tinder-style" + "tinder-style", + "tinder-swipe", + "worklets" ], "homepage": "https://github.com/react-native-motion-kit/react-native-swipe-deck#readme", "bugs": { @@ -32,7 +43,8 @@ }, "workspaces": [ ".", - "example" + "example", + "docs" ], "files": [ "src", diff --git a/tsconfig.build.json b/tsconfig.build.json index e50e85a..690b8ce 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,4 +1,5 @@ { "extends": "./tsconfig", + "include": ["src"], "exclude": ["example", "lib", "type-tests"] } diff --git a/tsconfig.json b/tsconfig.json index c041b18..eb98270 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,5 +26,6 @@ "strict": true, "target": "ESNext", "verbatimModuleSyntax": true - } + }, + "exclude": ["docs"] } diff --git a/yarn.lock b/yarn.lock index d0e78d8..11b3fc9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2035,6 +2035,34 @@ __metadata: languageName: node linkType: hard +"@emnapi/core@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/core@npm:1.10.0" + dependencies: + "@emnapi/wasi-threads": "npm:1.2.1" + tslib: "npm:^2.4.0" + checksum: 10c0/f51d08227857b60632de7714d708124f0e100a1462dde6df8221760939aa3204a73193830371830fac0716f3ccd2129f2cac1b17cd7d7958bc4da9018a296edb + languageName: node + linkType: hard + +"@emnapi/runtime@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/runtime@npm:1.10.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/953f14991d1aefb92ee6f8eb27dea725e484791a53a0cb5f47d9e0087b9a2c929ff2e92adf95af15d6ad456db6300c6b761ebf72b50a875b874a83520b3ba093 + languageName: node + linkType: hard + +"@emnapi/wasi-threads@npm:1.2.1": + version: 1.2.1 + resolution: "@emnapi/wasi-threads@npm:1.2.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/32fcfa81ab396533b2ec1f4082b1ff779a05d9c836bbbd3f4398405b0e6814c0d9503b7993130e37bc6941dbc1ded49f55e9700ae9ca4e803bab2b5bc5deb331 + languageName: node + linkType: hard + "@expo/cli@npm:55.0.32": version: 55.0.32 resolution: "@expo/cli@npm:55.0.32" @@ -2914,6 +2942,63 @@ __metadata: languageName: node linkType: hard +"@mdx-js/mdx@npm:^3.1.1": + version: 3.1.1 + resolution: "@mdx-js/mdx@npm:3.1.1" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdx": "npm:^2.0.0" + acorn: "npm:^8.0.0" + collapse-white-space: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + estree-util-scope: "npm:^1.0.0" + estree-walker: "npm:^3.0.0" + hast-util-to-jsx-runtime: "npm:^2.0.0" + markdown-extensions: "npm:^2.0.0" + recma-build-jsx: "npm:^1.0.0" + recma-jsx: "npm:^1.0.0" + recma-stringify: "npm:^1.0.0" + rehype-recma: "npm:^1.0.0" + remark-mdx: "npm:^3.0.0" + remark-parse: "npm:^11.0.0" + remark-rehype: "npm:^11.0.0" + source-map: "npm:^0.7.0" + unified: "npm:^11.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + unist-util-stringify-position: "npm:^4.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/371ed95e2bee7731f30a7ce57db66383a0b7470e66c38139427174cb456d6a40bf7d259f3652716370c1de64acfba50a1ba27eb8c556e7a431dc7940b04cb1a1 + languageName: node + linkType: hard + +"@mdx-js/react@npm:^3.1.1": + version: 3.1.1 + resolution: "@mdx-js/react@npm:3.1.1" + dependencies: + "@types/mdx": "npm:^2.0.0" + peerDependencies: + "@types/react": ">=16" + react: ">=16" + checksum: 10c0/34ca98bc2a0f969894ea144dc5c8a5294690505458cd24965cd9be854d779c193ad9192bf9143c4c18438fafd1902e100d99067e045c69319288562d497558c6 + languageName: node + linkType: hard + +"@napi-rs/wasm-runtime@npm:1.1.4": + version: 1.1.4 + resolution: "@napi-rs/wasm-runtime@npm:1.1.4" + dependencies: + "@tybys/wasm-util": "npm:^0.10.1" + peerDependencies: + "@emnapi/core": ^1.7.1 + "@emnapi/runtime": ^1.7.1 + checksum: 10c0/2e88e1955258949ccf2d18c79975821ad38071b465ef126a5e14110977b97868867b016c1ad046e963cccc42c0bd9db6c8ff5fd1ebb61b87bb3487f339041658 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -3207,6 +3292,20 @@ __metadata: languageName: node linkType: hard +"@react-native-motion-kit/swipe-deck-docs@workspace:docs": + version: 0.0.0-use.local + resolution: "@react-native-motion-kit/swipe-deck-docs@workspace:docs" + dependencies: + "@rspress/core": "npm:^2.0.13" + "@shikijs/transformers": "npm:^4.1.0" + "@types/node": "npm:^24" + "@types/react": "npm:^19.2.0" + react: "npm:19.2.3" + react-dom: "npm:19.2.3" + typescript: "npm:^6.0.2" + languageName: unknown + linkType: soft + "@react-native-motion-kit/swipe-deck@workspace:*, @react-native-motion-kit/swipe-deck@workspace:.": version: 0.0.0-use.local resolution: "@react-native-motion-kit/swipe-deck@workspace:." @@ -3676,6 +3775,344 @@ __metadata: languageName: node linkType: hard +"@rsbuild/core@npm:^2.0.9": + version: 2.0.15 + resolution: "@rsbuild/core@npm:2.0.15" + dependencies: + "@rspack/core": "npm:~2.0.8" + "@swc/helpers": "npm:^0.5.23" + peerDependencies: + core-js: ">= 3.0.0" + peerDependenciesMeta: + core-js: + optional: true + bin: + rsbuild: ./bin/rsbuild.js + checksum: 10c0/0aa77a2e4928e1b62b26fa986467d8226a89f2fb0680ae825a36f7e581a976e6bb43debcca4dcdb7fd8d68b05a7f7ef2e5b25b9769afd70ea2a65c1103b59e2e + languageName: node + linkType: hard + +"@rsbuild/plugin-react@npm:~2.0.1": + version: 2.0.1 + resolution: "@rsbuild/plugin-react@npm:2.0.1" + dependencies: + "@rspack/plugin-react-refresh": "npm:2.0.0" + react-refresh: "npm:^0.18.0" + peerDependencies: + "@rsbuild/core": ^2.0.0-0 + peerDependenciesMeta: + "@rsbuild/core": + optional: true + checksum: 10c0/b9bb8941ca8081a7231e5b61fe071f8eda79f09ef3177b1ba4d2472ad6df749931446e0a3c71f2de930b8cdf05eac90d37d7f50f498752577516a694c2ee43e9 + languageName: node + linkType: hard + +"@rspack/binding-darwin-arm64@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-darwin-arm64@npm:2.0.8" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rspack/binding-darwin-x64@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-darwin-x64@npm:2.0.8" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rspack/binding-linux-arm64-gnu@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-linux-arm64-gnu@npm:2.0.8" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rspack/binding-linux-arm64-musl@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-linux-arm64-musl@npm:2.0.8" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rspack/binding-linux-x64-gnu@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-linux-x64-gnu@npm:2.0.8" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rspack/binding-linux-x64-musl@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-linux-x64-musl@npm:2.0.8" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rspack/binding-wasm32-wasi@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-wasm32-wasi@npm:2.0.8" + dependencies: + "@emnapi/core": "npm:1.10.0" + "@emnapi/runtime": "npm:1.10.0" + "@napi-rs/wasm-runtime": "npm:1.1.4" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@rspack/binding-win32-arm64-msvc@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-win32-arm64-msvc@npm:2.0.8" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rspack/binding-win32-ia32-msvc@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-win32-ia32-msvc@npm:2.0.8" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rspack/binding-win32-x64-msvc@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding-win32-x64-msvc@npm:2.0.8" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rspack/binding@npm:2.0.8": + version: 2.0.8 + resolution: "@rspack/binding@npm:2.0.8" + dependencies: + "@rspack/binding-darwin-arm64": "npm:2.0.8" + "@rspack/binding-darwin-x64": "npm:2.0.8" + "@rspack/binding-linux-arm64-gnu": "npm:2.0.8" + "@rspack/binding-linux-arm64-musl": "npm:2.0.8" + "@rspack/binding-linux-x64-gnu": "npm:2.0.8" + "@rspack/binding-linux-x64-musl": "npm:2.0.8" + "@rspack/binding-wasm32-wasi": "npm:2.0.8" + "@rspack/binding-win32-arm64-msvc": "npm:2.0.8" + "@rspack/binding-win32-ia32-msvc": "npm:2.0.8" + "@rspack/binding-win32-x64-msvc": "npm:2.0.8" + dependenciesMeta: + "@rspack/binding-darwin-arm64": + optional: true + "@rspack/binding-darwin-x64": + optional: true + "@rspack/binding-linux-arm64-gnu": + optional: true + "@rspack/binding-linux-arm64-musl": + optional: true + "@rspack/binding-linux-x64-gnu": + optional: true + "@rspack/binding-linux-x64-musl": + optional: true + "@rspack/binding-wasm32-wasi": + optional: true + "@rspack/binding-win32-arm64-msvc": + optional: true + "@rspack/binding-win32-ia32-msvc": + optional: true + "@rspack/binding-win32-x64-msvc": + optional: true + checksum: 10c0/a5a61d6ea25fafb002bbdb6bc2600c4fba1ae1e2da3d4afd86b458eb83bfff413fa2415ecd83ffd7c4e8aa60f2cc90df6793a27e56681a5fdb415d0df428e42b + languageName: node + linkType: hard + +"@rspack/core@npm:~2.0.8": + version: 2.0.8 + resolution: "@rspack/core@npm:2.0.8" + dependencies: + "@rspack/binding": "npm:2.0.8" + peerDependencies: + "@module-federation/runtime-tools": ^0.24.1 || ^2.0.0 + "@swc/helpers": ^0.5.23 + peerDependenciesMeta: + "@module-federation/runtime-tools": + optional: true + "@swc/helpers": + optional: true + checksum: 10c0/7862d5e17df9bcf70de1472142df047188a1a87c028481225702af15d69940d9935b91502e05d04f42ccc12fcdd70d6d846222817a2054b18135b4143d483047 + languageName: node + linkType: hard + +"@rspack/plugin-react-refresh@npm:2.0.0": + version: 2.0.0 + resolution: "@rspack/plugin-react-refresh@npm:2.0.0" + peerDependencies: + "@rspack/core": ^2.0.0-0 + react-refresh: ">=0.10.0 <1.0.0" + peerDependenciesMeta: + "@rspack/core": + optional: true + checksum: 10c0/ee8e6492c0772536abb98ab5ec92d0e4ad092613a3a6085542f0b354131eef48f4d7cbe9a8cf9a9389d5e51d623d08a2c07594c8add5ad5fb54fd5543150ead1 + languageName: node + linkType: hard + +"@rspress/core@npm:^2.0.13": + version: 2.0.14 + resolution: "@rspress/core@npm:2.0.14" + dependencies: + "@mdx-js/mdx": "npm:^3.1.1" + "@mdx-js/react": "npm:^3.1.1" + "@rsbuild/core": "npm:^2.0.9" + "@rsbuild/plugin-react": "npm:~2.0.1" + "@rspress/shared": "npm:2.0.14" + "@shikijs/rehype": "npm:^4.0.2" + "@types/unist": "npm:^3.0.3" + "@unhead/react": "npm:^2.1.15" + body-scroll-lock: "npm:4.0.0-beta.0" + clsx: "npm:2.1.1" + copy-to-clipboard: "npm:^3.3.3" + flexsearch: "npm:0.8.212" + hast-util-heading-rank: "npm:^3.0.0" + hast-util-to-jsx-runtime: "npm:^2.3.6" + mdast-util-mdx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.1" + medium-zoom: "npm:1.1.0" + nprogress: "npm:^0.2.0" + react: "npm:^19.2.6" + react-dom: "npm:^19.2.6" + react-lazy-with-preload: "npm:^2.2.1" + react-reconciler: "npm:0.33.0" + react-render-to-markdown: "npm:19.1.0" + react-router-dom: "npm:^7.15.1" + rehype-external-links: "npm:^3.0.0" + rehype-raw: "npm:^7.0.0" + remark-cjk-friendly: "npm:^2.0.1" + remark-cjk-friendly-gfm-strikethrough: "npm:^2.0.1" + remark-gfm: "npm:^4.0.1" + remark-mdx: "npm:^3.1.1" + remark-parse: "npm:^11.0.0" + remark-stringify: "npm:^11.0.0" + scroll-into-view-if-needed: "npm:^3.1.0" + shiki: "npm:^4.0.2" + unified: "npm:^11.0.5" + unist-util-remove: "npm:^4.0.0" + unist-util-visit: "npm:^5.1.0" + unist-util-visit-children: "npm:^3.0.0" + bin: + rspress: bin/rspress.js + checksum: 10c0/118ae88259f55dae748f92bdb64a7185861612fe5d784ebb5991b2598b85320ec9a718a72f6015542b79f620c358a34ed9f4f83cf98ff2aab45036f44b0f9455 + languageName: node + linkType: hard + +"@rspress/shared@npm:2.0.14": + version: 2.0.14 + resolution: "@rspress/shared@npm:2.0.14" + dependencies: + "@rsbuild/core": "npm:^2.0.9" + "@shikijs/rehype": "npm:^4.0.2" + unified: "npm:^11.0.5" + checksum: 10c0/a33bec3b057886e549f5fbd5b6c754e770836533346b339241d2cc77a8792ee501654434afceac459fcc5b1bf1a7b0d1d2f940ba296df57a628e9697accde596 + languageName: node + linkType: hard + +"@shikijs/core@npm:4.3.0": + version: 4.3.0 + resolution: "@shikijs/core@npm:4.3.0" + dependencies: + "@shikijs/primitive": "npm:4.3.0" + "@shikijs/types": "npm:4.3.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + "@types/hast": "npm:^3.0.4" + hast-util-to-html: "npm:^9.0.5" + checksum: 10c0/b8a92d73137b9a2e3f3877565bf4a5b69e1615d28fdcb9c671f1681fbb1005b4719ad024945847d73536434aff0afbf30e6951d9dcd3b12a2613a816f6884955 + languageName: node + linkType: hard + +"@shikijs/engine-javascript@npm:4.3.0": + version: 4.3.0 + resolution: "@shikijs/engine-javascript@npm:4.3.0" + dependencies: + "@shikijs/types": "npm:4.3.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + oniguruma-to-es: "npm:^4.3.6" + checksum: 10c0/09afe0ec19f06ee6aa8dd3d7811fad143d473c9016cabfef8d4ed66748e4d2489c532ad8bbea54eb8e676c188b302078bbe836bac12bd8c2ae7e4eb7b1ff1a6c + languageName: node + linkType: hard + +"@shikijs/engine-oniguruma@npm:4.3.0": + version: 4.3.0 + resolution: "@shikijs/engine-oniguruma@npm:4.3.0" + dependencies: + "@shikijs/types": "npm:4.3.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + checksum: 10c0/aee8b08df9be4fbfe20def4828b721014c5c5d062e016796309c9f5910dab521fd3093d39ef54ce6cca19a592c7d0e81cbe62645dff2e3bcd75179f505051ac9 + languageName: node + linkType: hard + +"@shikijs/langs@npm:4.3.0": + version: 4.3.0 + resolution: "@shikijs/langs@npm:4.3.0" + dependencies: + "@shikijs/types": "npm:4.3.0" + checksum: 10c0/876cb2af730c66ec0f2c0946f7309d7e1706f42d4d360a1acb73d54c73edfa0786f8fcb2d70f5c2fca8ff04fdd25c28c7577fbe6bcf7d1ab73bf25579c9f1648 + languageName: node + linkType: hard + +"@shikijs/primitive@npm:4.3.0": + version: 4.3.0 + resolution: "@shikijs/primitive@npm:4.3.0" + dependencies: + "@shikijs/types": "npm:4.3.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + "@types/hast": "npm:^3.0.4" + checksum: 10c0/ce34e6bc917bd73e3aed0591c3ff2d7f73069c5dc1b1eb2cff3f5a7407340518568e3b2a43eb3dac6854dfc7cf146e60c7868de0f0fe68edb5873ba633a4c6a2 + languageName: node + linkType: hard + +"@shikijs/rehype@npm:^4.0.2": + version: 4.3.0 + resolution: "@shikijs/rehype@npm:4.3.0" + dependencies: + "@shikijs/types": "npm:4.3.0" + "@types/hast": "npm:^3.0.4" + hast-util-to-string: "npm:^3.0.1" + shiki: "npm:4.3.0" + unified: "npm:^11.0.5" + unist-util-visit: "npm:^5.1.0" + checksum: 10c0/37149f94a3dcbbd30d86e21d9d166ecdba4ff9bba75fe9dc1da6d8a7673508c6d41b0399ffc0fe79765c6dba5ab177e57b7a38c8daba10a8ead067bc5f6a7296 + languageName: node + linkType: hard + +"@shikijs/themes@npm:4.3.0": + version: 4.3.0 + resolution: "@shikijs/themes@npm:4.3.0" + dependencies: + "@shikijs/types": "npm:4.3.0" + checksum: 10c0/5c63942de6eabf6c6e72c801000cbf4042222d855ee94c0cd3e4b2b62c70083db47d6b542f9c789d9bc62552be139b436a4db270bb73cf1206f1e63802521a4b + languageName: node + linkType: hard + +"@shikijs/transformers@npm:^4.1.0": + version: 4.3.0 + resolution: "@shikijs/transformers@npm:4.3.0" + dependencies: + "@shikijs/core": "npm:4.3.0" + "@shikijs/types": "npm:4.3.0" + checksum: 10c0/270d575450d7982073edd20b16f50c23b998d10eb0cefa3a78588a8e5107b07c5d249ffd47ff041c8e0fb0ccb2db2ca28635b3edfa1a1dc63584e07851a10fbf + languageName: node + linkType: hard + +"@shikijs/types@npm:4.3.0": + version: 4.3.0 + resolution: "@shikijs/types@npm:4.3.0" + dependencies: + "@shikijs/vscode-textmate": "npm:^10.0.2" + "@types/hast": "npm:^3.0.4" + checksum: 10c0/b2f461511cefe20ba25978dfa2462246db7053d9fd03732e6c969c30fda413db9109e635aea5e58d56ab3946caa0d0bd6fdb043240a29c6f4ad5a4996442a823 + languageName: node + linkType: hard + +"@shikijs/vscode-textmate@npm:^10.0.2": + version: 10.0.2 + resolution: "@shikijs/vscode-textmate@npm:10.0.2" + checksum: 10c0/36b682d691088ec244de292dc8f91b808f95c89466af421cf84cbab92230f03c8348649c14b3251991b10ce632b0c715e416e992dd5f28ff3221dc2693fd9462 + languageName: node + linkType: hard + "@simple-libs/child-process-utils@npm:^1.0.0": version: 1.0.2 resolution: "@simple-libs/child-process-utils@npm:1.0.2" @@ -3731,6 +4168,15 @@ __metadata: languageName: node linkType: hard +"@swc/helpers@npm:^0.5.23": + version: 0.5.23 + resolution: "@swc/helpers@npm:0.5.23" + dependencies: + tslib: "npm:^2.8.0" + checksum: 10c0/02da7b4df465693933ecd4851cc193ec729c309939c8a84eccae5ec0010aafc3894e713b8ef8d13a6ba401759f0e900c88e2dcfef5872c27bb91e70f73275cce + languageName: node + linkType: hard + "@testing-library/react-native@npm:^14.0.0": version: 14.0.0 resolution: "@testing-library/react-native@npm:14.0.0" @@ -3793,6 +4239,15 @@ __metadata: languageName: node linkType: hard +"@tybys/wasm-util@npm:^0.10.1": + version: 0.10.3 + resolution: "@tybys/wasm-util@npm:0.10.3" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/fd2bd2a79c6cd8c79ed1cf7a0fa375c64589264c88a27acaf9756d556b453ea222b62a4f68dd2fbb8b3a78b6bab3b1f4fb2431b6afc6aeda8344b53a521a1cd3 + languageName: node + linkType: hard + "@types/babel__core@npm:^7, @types/babel__core@npm:^7.1.14": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" @@ -3834,6 +4289,31 @@ __metadata: languageName: node linkType: hard +"@types/debug@npm:^4.0.0": + version: 4.1.13 + resolution: "@types/debug@npm:4.1.13" + dependencies: + "@types/ms": "npm:*" + checksum: 10c0/e5e124021bbdb23a82727eee0a726ae0fc8a3ae1f57253cbcc47497f259afb357de7f6941375e773e1abbfa1604c1555b901a409d762ec2bb4c1612131d4afb7 + languageName: node + linkType: hard + +"@types/estree-jsx@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree-jsx@npm:1.0.5" + dependencies: + "@types/estree": "npm:*" + checksum: 10c0/07b354331516428b27a3ab99ee397547d47eb223c34053b48f84872fafb841770834b90cc1a0068398e7c7ccb15ec51ab00ec64b31dc5e3dbefd624638a35c6d + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:^1.0.0": + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 + languageName: node + linkType: hard + "@types/graceful-fs@npm:^4.1.3": version: 4.1.9 resolution: "@types/graceful-fs@npm:4.1.9" @@ -3850,6 +4330,15 @@ __metadata: languageName: node linkType: hard +"@types/hast@npm:^3.0.0, @types/hast@npm:^3.0.4": + version: 3.0.4 + resolution: "@types/hast@npm:3.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/3249781a511b38f1d330fd1e3344eed3c4e7ea8eff82e835d35da78e637480d36fad37a78be5a7aed8465d237ad0446abc1150859d0fde395354ea634decf9f7 + languageName: node + linkType: hard + "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": version: 2.0.6 resolution: "@types/istanbul-lib-coverage@npm:2.0.6" @@ -3875,6 +4364,29 @@ __metadata: languageName: node linkType: hard +"@types/mdast@npm:^4.0.0": + version: 4.0.4 + resolution: "@types/mdast@npm:4.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/84f403dbe582ee508fd9c7643ac781ad8597fcbfc9ccb8d4715a2c92e4545e5772cbd0dbdf18eda65789386d81b009967fdef01b24faf6640f817287f54d9c82 + languageName: node + linkType: hard + +"@types/mdx@npm:^2.0.0": + version: 2.0.14 + resolution: "@types/mdx@npm:2.0.14" + checksum: 10c0/f1e3873c1e36e2685fb99222bf81a23c55a8e2edf49d0c45cabf2c875b0ae814cd6050cce5770ff1c6881ac747d2ad33731e1de32139b04cf181d8d7e1943ff4 + languageName: node + linkType: hard + +"@types/ms@npm:*": + version: 2.1.0 + resolution: "@types/ms@npm:2.1.0" + checksum: 10c0/5ce692ffe1549e1b827d99ef8ff71187457e0eb44adbae38fdf7b9a74bae8d20642ee963c14516db1d35fa2652e65f47680fdf679dcbde52bbfadd021f497225 + languageName: node + linkType: hard + "@types/node@npm:*": version: 25.9.1 resolution: "@types/node@npm:25.9.1" @@ -3891,6 +4403,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^24": + version: 24.13.2 + resolution: "@types/node@npm:24.13.2" + dependencies: + undici-types: "npm:~7.18.0" + checksum: 10c0/d7d48a88a4feb0a6aac3cbfaf9ef3b12752b4b09447f88dd0b4c77c03b281e3d4330fe6982a99aedcd63fc16c7540a0c248b91eb2abb0b3edd884d7fe684e9ea + languageName: node + linkType: hard + "@types/react-reconciler@npm:~0.33.0": version: 0.33.0 resolution: "@types/react-reconciler@npm:0.33.0" @@ -3925,6 +4446,20 @@ __metadata: languageName: node linkType: hard +"@types/unist@npm:*, @types/unist@npm:^3.0.0, @types/unist@npm:^3.0.3": + version: 3.0.3 + resolution: "@types/unist@npm:3.0.3" + checksum: 10c0/2b1e4adcab78388e088fcc3c0ae8700f76619dbcb4741d7d201f87e2cb346bfc29a89003cfea2d76c996e1061452e14fcd737e8b25aacf949c1f2d6b2bc3dd60 + languageName: node + linkType: hard + +"@types/unist@npm:^2.0.0": + version: 2.0.11 + resolution: "@types/unist@npm:2.0.11" + checksum: 10c0/24dcdf25a168f453bb70298145eb043cfdbb82472db0bc0b56d6d51cd2e484b9ed8271d4ac93000a80da568f2402e9339723db262d0869e2bf13bc58e081768d + languageName: node + linkType: hard + "@types/yargs-parser@npm:*": version: 21.0.3 resolution: "@types/yargs-parser@npm:21.0.3" @@ -3941,6 +4476,13 @@ __metadata: languageName: node linkType: hard +"@ungap/structured-clone@npm:^1.0.0": + version: 1.3.2 + resolution: "@ungap/structured-clone@npm:1.3.2" + checksum: 10c0/4d76bb376ec3e15f38bdffe045377807c79057daf54ae17eeb977c5b95efddd2d726b38c15aeb5d5c1a45c64ad03aa7e8b1a6dc67895480cba536ffd1c7a06ec + languageName: node + linkType: hard + "@ungap/structured-clone@npm:^1.3.0": version: 1.3.1 resolution: "@ungap/structured-clone@npm:1.3.1" @@ -3948,6 +4490,17 @@ __metadata: languageName: node linkType: hard +"@unhead/react@npm:^2.1.15": + version: 2.1.15 + resolution: "@unhead/react@npm:2.1.15" + dependencies: + unhead: "npm:2.1.15" + peerDependencies: + react: ">=18.3.1" + checksum: 10c0/0a341187a86b9ac38065b521cad124bc0f8092052507551ffbc2d9538598c0dfcd0be7c473a9d117c20949aae0a02fced271a9b81d3826a6d62c0c69e1b4482b + languageName: node + linkType: hard + "@xmldom/xmldom@npm:^0.8.8": version: 0.8.13 resolution: "@xmldom/xmldom@npm:0.8.13" @@ -3998,6 +4551,24 @@ __metadata: languageName: node linkType: hard +"acorn-jsx@npm:^5.0.0": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 + languageName: node + linkType: hard + +"acorn@npm:^8.0.0": + version: 8.17.0 + resolution: "acorn@npm:8.17.0" + bin: + acorn: bin/acorn + checksum: 10c0/5dcefea5f8f023b6cc24cbe71fb5a8112b601d36c4fa07d14e4e6ffc2ee47383332c46b36c766d9437725aa6660156eae50efa0c838719823b50d7c327c4ed42 + languageName: node + linkType: hard + "acorn@npm:^8.15.0": version: 8.16.0 resolution: "acorn@npm:8.16.0" @@ -4176,6 +4747,15 @@ __metadata: languageName: node linkType: hard +"astring@npm:^1.8.0": + version: 1.9.0 + resolution: "astring@npm:1.9.0" + bin: + astring: bin/astring + checksum: 10c0/e7519544d9824494e80ef0e722bb3a0c543a31440d59691c13aeaceb75b14502af536b23f08db50aa6c632dafaade54caa25f0788aa7550b6b2d6e2df89e0830 + languageName: node + linkType: hard + "babel-jest@npm:^29.7.0": version: 29.7.0 resolution: "babel-jest@npm:29.7.0" @@ -4407,6 +4987,13 @@ __metadata: languageName: node linkType: hard +"bail@npm:^2.0.0": + version: 2.0.2 + resolution: "bail@npm:2.0.2" + checksum: 10c0/25cbea309ef6a1f56214187004e8f34014eb015713ea01fa5b9b7e9e776ca88d0fdffd64143ac42dc91966c915a4b7b683411b56e14929fad16153fc026ffb8b + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -4462,6 +5049,13 @@ __metadata: languageName: node linkType: hard +"body-scroll-lock@npm:4.0.0-beta.0": + version: 4.0.0-beta.0 + resolution: "body-scroll-lock@npm:4.0.0-beta.0" + checksum: 10c0/32a9553b83424e69f3784d7bbcef2949c43159ea13b5084c96dc08b1e2585e4eeb1e915f14e37a4ac44110339dfa6fa2ddde4d3d812be88ecbea060aa724a791 + languageName: node + linkType: hard + "bplist-creator@npm:0.1.0": version: 0.1.0 resolution: "bplist-creator@npm:0.1.0" @@ -4583,6 +5177,13 @@ __metadata: languageName: node linkType: hard +"ccount@npm:^2.0.0": + version: 2.0.1 + resolution: "ccount@npm:2.0.1" + checksum: 10c0/3939b1664390174484322bc3f45b798462e6c07ee6384cb3d645e0aa2f318502d174845198c1561930e1d431087f74cf1fe291ae9a4722821a9f4ba67e574350 + languageName: node + linkType: hard + "chalk@npm:^2.0.1, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" @@ -4611,8 +5212,36 @@ __metadata: languageName: node linkType: hard -"chardet@npm:^2.1.1": - version: 2.1.1 +"character-entities-html4@npm:^2.0.0": + version: 2.1.0 + resolution: "character-entities-html4@npm:2.1.0" + checksum: 10c0/fe61b553f083400c20c0b0fd65095df30a0b445d960f3bbf271536ae6c3ba676f39cb7af0b4bf2755812f08ab9b88f2feed68f9aebb73bb153f7a115fe5c6e40 + languageName: node + linkType: hard + +"character-entities-legacy@npm:^3.0.0": + version: 3.0.0 + resolution: "character-entities-legacy@npm:3.0.0" + checksum: 10c0/ec4b430af873661aa754a896a2b55af089b4e938d3d010fad5219299a6b6d32ab175142699ee250640678cd64bdecd6db3c9af0b8759ab7b155d970d84c4c7d1 + languageName: node + linkType: hard + +"character-entities@npm:^2.0.0": + version: 2.0.2 + resolution: "character-entities@npm:2.0.2" + checksum: 10c0/b0c645a45bcc90ff24f0e0140f4875a8436b8ef13b6bcd31ec02cfb2ca502b680362aa95386f7815bdc04b6464d48cf191210b3840d7c04241a149ede591a308 + languageName: node + linkType: hard + +"character-reference-invalid@npm:^2.0.0": + version: 2.0.1 + resolution: "character-reference-invalid@npm:2.0.1" + checksum: 10c0/2ae0dec770cd8659d7e8b0ce24392d83b4c2f0eb4a3395c955dce5528edd4cc030a794cfa06600fcdd700b3f2de2f9b8e40e309c0011c4180e3be64a0b42e6a1 + languageName: node + linkType: hard + +"chardet@npm:^2.1.1": + version: 2.1.1 resolution: "chardet@npm:2.1.1" checksum: 10c0/d8391dd412338442b3de0d3a488aa9327f8bcf74b62b8723d6bd0b85c4084d50b731320e0a7c710edb1d44de75969995d2784b80e4c13b004a6c7a0db4c6e793 languageName: node @@ -4732,6 +5361,13 @@ __metadata: languageName: node linkType: hard +"clsx@npm:2.1.1": + version: 2.1.1 + resolution: "clsx@npm:2.1.1" + checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 + languageName: node + linkType: hard + "co@npm:^4.6.0": version: 4.6.0 resolution: "co@npm:4.6.0" @@ -4739,6 +5375,13 @@ __metadata: languageName: node linkType: hard +"collapse-white-space@npm:^2.0.0": + version: 2.1.0 + resolution: "collapse-white-space@npm:2.1.0" + checksum: 10c0/b2e2800f4ab261e62eb27a1fbe853378296e3a726d6695117ed033e82d61fb6abeae4ffc1465d5454499e237005de9cfc52c9562dc7ca4ac759b9a222ef14453 + languageName: node + linkType: hard + "collect-v8-coverage@npm:^1.0.0": version: 1.0.3 resolution: "collect-v8-coverage@npm:1.0.3" @@ -4778,6 +5421,13 @@ __metadata: languageName: node linkType: hard +"comma-separated-tokens@npm:^2.0.0": + version: 2.0.3 + resolution: "comma-separated-tokens@npm:2.0.3" + checksum: 10c0/91f90f1aae320f1755d6957ef0b864fe4f54737f3313bd95e0802686ee2ca38bff1dd381964d00ae5db42912dd1f4ae5c2709644e82706ffc6f6842a813cdd67 + languageName: node + linkType: hard + "commander@npm:^12.0.0": version: 12.1.0 resolution: "commander@npm:12.1.0" @@ -4845,6 +5495,13 @@ __metadata: languageName: node linkType: hard +"compute-scroll-into-view@npm:^3.0.2": + version: 3.1.1 + resolution: "compute-scroll-into-view@npm:3.1.1" + checksum: 10c0/59761ed62304a9599b52ad75d0d6fbf0669ee2ab7dd472fdb0ad9da36628414c014dea7b5810046560180ad30ffec52a953d19297f66a1d4f3aa0999b9d2521d + languageName: node + linkType: hard + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -4901,6 +5558,22 @@ __metadata: languageName: node linkType: hard +"cookie@npm:^1.0.1": + version: 1.1.1 + resolution: "cookie@npm:1.1.1" + checksum: 10c0/79c4ddc0fcad9c4f045f826f42edf54bcc921a29586a4558b0898277fa89fb47be95bc384c2253f493af7b29500c830da28341274527328f18eba9f58afa112c + languageName: node + linkType: hard + +"copy-to-clipboard@npm:^3.3.3": + version: 3.3.3 + resolution: "copy-to-clipboard@npm:3.3.3" + dependencies: + toggle-selection: "npm:^1.0.6" + checksum: 10c0/3ebf5e8ee00601f8c440b83ec08d838e8eabb068c1fae94a9cda6b42f288f7e1b552f3463635f419af44bf7675afc8d0390d30876cf5c2d5d35f86d9c56a3e5f + languageName: node + linkType: hard + "core-js-compat@npm:^3.43.0, core-js-compat@npm:^3.48.0": version: 3.49.0 resolution: "core-js-compat@npm:3.49.0" @@ -4991,7 +5664,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0, debug@npm:^4.4.3": +"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0, debug@npm:^4.4.3": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -5012,6 +5685,15 @@ __metadata: languageName: node linkType: hard +"decode-named-character-reference@npm:^1.0.0": + version: 1.3.0 + resolution: "decode-named-character-reference@npm:1.3.0" + dependencies: + character-entities: "npm:^2.0.0" + checksum: 10c0/787f4c87f3b82ea342aa7c2d7b1882b6fb9511bb77f72ae44dcaabea0470bacd1e9c6a0080ab886545019fa0cb3a7109573fad6b61a362844c3a0ac52b36e4bb + languageName: node + linkType: hard + "dedent@npm:^1.0.0, dedent@npm:^1.7.2": version: 1.7.2 resolution: "dedent@npm:1.7.2" @@ -5083,6 +5765,13 @@ __metadata: languageName: node linkType: hard +"dequal@npm:^2.0.0": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 + languageName: node + linkType: hard + "destroy@npm:1.2.0": version: 1.2.0 resolution: "destroy@npm:1.2.0" @@ -5111,6 +5800,15 @@ __metadata: languageName: node linkType: hard +"devlop@npm:^1.0.0, devlop@npm:^1.1.0": + version: 1.1.0 + resolution: "devlop@npm:1.1.0" + dependencies: + dequal: "npm:^2.0.0" + checksum: 10c0/e0928ab8f94c59417a2b8389c45c55ce0a02d9ac7fd74ef62d01ba48060129e1d594501b77de01f3eeafc7cb00773819b0df74d96251cf20b31c5b3071f45c0e + languageName: node + linkType: hard + "diff-sequences@npm:^29.6.3": version: 29.6.3 resolution: "diff-sequences@npm:29.6.3" @@ -5218,6 +5916,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^6.0.0": + version: 6.0.1 + resolution: "entities@npm:6.0.1" + checksum: 10c0/ed836ddac5acb34341094eb495185d527bd70e8632b6c0d59548cbfa23defdbae70b96f9a405c82904efa421230b5b3fd2283752447d737beffd3f3e6ee74414 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -5264,6 +5969,30 @@ __metadata: languageName: node linkType: hard +"esast-util-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "esast-util-from-estree@npm:2.0.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + devlop: "npm:^1.0.0" + estree-util-visit: "npm:^2.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + checksum: 10c0/6c619bc6963314f8f64b32e3b101b321bf121f659e62b11e70f425619c2db6f1d25f4c594a57fd00908da96c67d9bfbf876eb5172abf9e13f47a71796f6630ff + languageName: node + linkType: hard + +"esast-util-from-js@npm:^2.0.0": + version: 2.0.1 + resolution: "esast-util-from-js@npm:2.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + acorn: "npm:^8.0.0" + esast-util-from-estree: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/3a446fb0b0d7bcd7e0157aa44b3b692802a08c93edbea81cc0f7fe4437bfdfb4b72e4563fe63b4e36d390086b71185dba4ac921f4180cc6349985c263cc74421 + languageName: node + linkType: hard + "escalade@npm:^3.1.1, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" @@ -5316,6 +6045,74 @@ __metadata: languageName: node linkType: hard +"estree-util-attach-comments@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-attach-comments@npm:3.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/ee69bb5c45e2ad074725b90ed181c1c934b29d81bce4b0c7761431e83c4c6ab1b223a6a3d6a4fbeb92128bc5d5ee201d5dd36cf1770aa5e16a40b0cf36e8a1f1 + languageName: node + linkType: hard + +"estree-util-build-jsx@npm:^3.0.0": + version: 3.0.1 + resolution: "estree-util-build-jsx@npm:3.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + estree-walker: "npm:^3.0.0" + checksum: 10c0/274c119817b8e7caa14a9778f1e497fea56cdd2b01df1a1ed037f843178992d3afe85e0d364d485e1e2e239255763553d1b647b15e4a7ba50851bcb43dc6bf80 + languageName: node + linkType: hard + +"estree-util-is-identifier-name@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-is-identifier-name@npm:3.0.0" + checksum: 10c0/d1881c6ed14bd588ebd508fc90bf2a541811dbb9ca04dec2f39d27dcaa635f85b5ed9bbbe7fc6fb1ddfca68744a5f7c70456b4b7108b6c4c52780631cc787c5b + languageName: node + linkType: hard + +"estree-util-scope@npm:^1.0.0": + version: 1.0.0 + resolution: "estree-util-scope@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + checksum: 10c0/ef8a573cc899277c613623a1722f630e2163abbc6e9e2f49e758c59b81b484e248b585df6df09a38c00fbfb6390117997cc80c1347b7a86bc1525d9e462b60d5 + languageName: node + linkType: hard + +"estree-util-to-js@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-to-js@npm:2.0.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + astring: "npm:^1.8.0" + source-map: "npm:^0.7.0" + checksum: 10c0/ac88cb831401ef99e365f92f4af903755d56ae1ce0e0f0fb8ff66e678141f3d529194f0fb15f6c78cd7554c16fda36854df851d58f9e05cfab15bddf7a97cea0 + languageName: node + linkType: hard + +"estree-util-visit@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-visit@npm:2.0.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/unist": "npm:^3.0.0" + checksum: 10c0/acda8b03cc8f890d79c7c7361f6c95331ba84b7ccc0c32b49f447fc30206b20002b37ffdfc97b6ad16e6fe065c63ecbae1622492e2b6b4775c15966606217f39 + languageName: node + linkType: hard + +"estree-walker@npm:^3.0.0": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -5572,6 +6369,13 @@ __metadata: languageName: node linkType: hard +"extend@npm:^3.0.0": + version: 3.0.2 + resolution: "extend@npm:3.0.2" + checksum: 10c0/73bf6e27406e80aa3e85b0d1c4fd987261e628064e170ca781125c0b635a3dabad5e05adbf07595ea0cf1e6c5396cacb214af933da7cbaf24fe75ff14818e8f9 + languageName: node + linkType: hard + "extendable-error@npm:^0.1.5": version: 0.1.7 resolution: "extendable-error@npm:0.1.7" @@ -5693,6 +6497,13 @@ __metadata: languageName: node linkType: hard +"flexsearch@npm:0.8.212": + version: 0.8.212 + resolution: "flexsearch@npm:0.8.212" + checksum: 10c0/557a320fe028e694579d9f3f4cacd6acab6bcfa9101a63dbacf23ddbc872310a3370586a12007cf080ed2dfe3c99e6b21dd1e83697f2b4734722fbd43285d782 + languageName: node + linkType: hard + "flow-enums-runtime@npm:^0.0.6": version: 0.0.6 resolution: "flow-enums-runtime@npm:0.0.6" @@ -5794,7 +6605,7 @@ __metadata: languageName: node linkType: hard -"get-east-asian-width@npm:^1.0.0": +"get-east-asian-width@npm:^1.0.0, get-east-asian-width@npm:^1.4.0": version: 1.6.0 resolution: "get-east-asian-width@npm:1.6.0" checksum: 10c0/7e72e9550fd49ca5b246f9af6bb2afc129c96412845ff6556b3274fd44817a381702ca17028efe9866b261a3d44254cbf21e6c90cf05b4b61675630af776d431 @@ -5944,6 +6755,182 @@ __metadata: languageName: node linkType: hard +"hast-util-from-parse5@npm:^8.0.0": + version: 8.0.3 + resolution: "hast-util-from-parse5@npm:8.0.3" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + devlop: "npm:^1.0.0" + hastscript: "npm:^9.0.0" + property-information: "npm:^7.0.0" + vfile: "npm:^6.0.0" + vfile-location: "npm:^5.0.0" + web-namespaces: "npm:^2.0.0" + checksum: 10c0/40ace6c0ad43c26f721c7499fe408e639cde917b2350c9299635e6326559855896dae3c3ebf7440df54766b96c4276a7823e8f376a2b6a28b37b591f03412545 + languageName: node + linkType: hard + +"hast-util-heading-rank@npm:^3.0.0": + version: 3.0.0 + resolution: "hast-util-heading-rank@npm:3.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/1879c84f629e73f1f13247ab349324355cd801363b44e3d46f763aa5c0ea3b42dcd47b46e5643a0502cf01a6b1fdb9208fd12852e44ca6c671b3e4bccf9369a1 + languageName: node + linkType: hard + +"hast-util-is-element@npm:^3.0.0": + version: 3.0.0 + resolution: "hast-util-is-element@npm:3.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/f5361e4c9859c587ca8eb0d8343492f3077ccaa0f58a44cd09f35d5038f94d65152288dcd0c19336ef2c9491ec4d4e45fde2176b05293437021570aa0bc3613b + languageName: node + linkType: hard + +"hast-util-parse-selector@npm:^4.0.0": + version: 4.0.0 + resolution: "hast-util-parse-selector@npm:4.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/5e98168cb44470dc274aabf1a28317e4feb09b1eaf7a48bbaa8c1de1b43a89cd195cb1284e535698e658e3ec26ad91bc5e52c9563c36feb75abbc68aaf68fb9f + languageName: node + linkType: hard + +"hast-util-raw@npm:^9.0.0": + version: 9.1.0 + resolution: "hast-util-raw@npm:9.1.0" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + hast-util-from-parse5: "npm:^8.0.0" + hast-util-to-parse5: "npm:^8.0.0" + html-void-elements: "npm:^3.0.0" + mdast-util-to-hast: "npm:^13.0.0" + parse5: "npm:^7.0.0" + unist-util-position: "npm:^5.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + web-namespaces: "npm:^2.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/d0d909d2aedecef6a06f0005cfae410d6475e6e182d768bde30c3af9fcbbe4f9beb0522bdc21d0679cb3c243c0df40385797ed255148d68b3d3f12e82d12aacc + languageName: node + linkType: hard + +"hast-util-to-estree@npm:^3.0.0": + version: 3.1.3 + resolution: "hast-util-to-estree@npm:3.1.3" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-attach-comments: "npm:^3.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + hast-util-whitespace: "npm:^3.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + style-to-js: "npm:^1.0.0" + unist-util-position: "npm:^5.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/8e86c075319082c8a6304c5bcdf24ec02466074571e993f58bfa2cfd70850ef46d33b5c402208597a87fe0f02f1e620bda5958217efb1b7396c81c486373b75f + languageName: node + linkType: hard + +"hast-util-to-html@npm:^9.0.5": + version: 9.0.5 + resolution: "hast-util-to-html@npm:9.0.5" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + ccount: "npm:^2.0.0" + comma-separated-tokens: "npm:^2.0.0" + hast-util-whitespace: "npm:^3.0.0" + html-void-elements: "npm:^3.0.0" + mdast-util-to-hast: "npm:^13.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + stringify-entities: "npm:^4.0.0" + zwitch: "npm:^2.0.4" + checksum: 10c0/b7a08c30bab4371fc9b4a620965c40b270e5ae7a8e94cf885f43b21705179e28c8e43b39c72885d1647965fb3738654e6962eb8b58b0c2a84271655b4d748836 + languageName: node + linkType: hard + +"hast-util-to-jsx-runtime@npm:^2.0.0, hast-util-to-jsx-runtime@npm:^2.3.6": + version: 2.3.6 + resolution: "hast-util-to-jsx-runtime@npm:2.3.6" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + hast-util-whitespace: "npm:^3.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + style-to-js: "npm:^1.0.0" + unist-util-position: "npm:^5.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/27297e02848fe37ef219be04a26ce708d17278a175a807689e94a821dcffc88aa506d62c3a85beed1f9a8544f7211bdcbcde0528b7b456a57c2e342c3fd11056 + languageName: node + linkType: hard + +"hast-util-to-parse5@npm:^8.0.0": + version: 8.0.1 + resolution: "hast-util-to-parse5@npm:8.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + web-namespaces: "npm:^2.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/8e8a1817c7ff8906ac66e7201b1b8d19d9e1b705e695a6e71620270d498d982ec1ecc0e227bd517f723e91e7fdfb90ef75f9ae64d14b3b65239a7d5e1194d7dd + languageName: node + linkType: hard + +"hast-util-to-string@npm:^3.0.1": + version: 3.0.1 + resolution: "hast-util-to-string@npm:3.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/b5fa1912a6ba6131affae52a0f4394406c4c0d23c2b0307f1d69988f1030c7bb830289303e67c5ad8f674f5f23a454c1dcd492c39e45a22c1f46d3c9bce5bd0c + languageName: node + linkType: hard + +"hast-util-whitespace@npm:^3.0.0": + version: 3.0.0 + resolution: "hast-util-whitespace@npm:3.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/b898bc9fe27884b272580d15260b6bbdabe239973a147e97fa98c45fa0ffec967a481aaa42291ec34fb56530dc2d484d473d7e2bae79f39c83f3762307edfea8 + languageName: node + linkType: hard + +"hastscript@npm:^9.0.0": + version: 9.0.1 + resolution: "hastscript@npm:9.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + hast-util-parse-selector: "npm:^4.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + checksum: 10c0/18dc8064e5c3a7a2ae862978e626b97a254e1c8a67ee9d0c9f06d373bba155ed805fc5b5ce21b990fb7bc174624889e5e1ce1cade264f1b1d58b48f994bc85ce + languageName: node + linkType: hard + "hermes-compiler@npm:0.14.1": version: 0.14.1 resolution: "hermes-compiler@npm:0.14.1" @@ -6047,6 +7034,13 @@ __metadata: languageName: node linkType: hard +"hookable@npm:^6.0.1": + version: 6.1.1 + resolution: "hookable@npm:6.1.1" + checksum: 10c0/bb46cd9ffc0a997af21febd97835da4e59a6989adec73dc3c215fcc44c7ac01de4781f251c3d420bf45862d2592a695f5f0de095b6f5df52db8afb5166938212 + languageName: node + linkType: hard + "hosted-git-info@npm:^7.0.0": version: 7.0.2 resolution: "hosted-git-info@npm:7.0.2" @@ -6063,6 +7057,13 @@ __metadata: languageName: node linkType: hard +"html-void-elements@npm:^3.0.0": + version: 3.0.0 + resolution: "html-void-elements@npm:3.0.0" + checksum: 10c0/a8b9ec5db23b7c8053876dad73a0336183e6162bf6d2677376d8b38d654fdc59ba74fdd12f8812688f7db6fad451210c91b300e472afc0909224e0a44c8610d2 + languageName: node + linkType: hard + "http-errors@npm:~2.0.1": version: 2.0.1 resolution: "http-errors@npm:2.0.1" @@ -6210,6 +7211,13 @@ __metadata: languageName: node linkType: hard +"inline-style-parser@npm:0.2.7": + version: 0.2.7 + resolution: "inline-style-parser@npm:0.2.7" + checksum: 10c0/d884d76f84959517430ae6c22f0bda59bb3f58f539f99aac75a8d786199ec594ed648c6ab4640531f9fc244b0ed5cd8c458078e592d016ef06de793beb1debff + languageName: node + linkType: hard + "invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" @@ -6219,6 +7227,13 @@ __metadata: languageName: node linkType: hard +"is-absolute-url@npm:^4.0.0": + version: 4.0.1 + resolution: "is-absolute-url@npm:4.0.1" + checksum: 10c0/6f8f603945bd9f2c6031758bbc12352fc647bd5d807cad10d96cc6300fd0e15240cc091521a61db767e4ec0bacff257b4f1015fd5249c147bbb4a4497356c72e + languageName: node + linkType: hard + "is-absolute@npm:^1.0.0": version: 1.0.0 resolution: "is-absolute@npm:1.0.0" @@ -6229,6 +7244,23 @@ __metadata: languageName: node linkType: hard +"is-alphabetical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphabetical@npm:2.0.1" + checksum: 10c0/932367456f17237533fd1fc9fe179df77957271020b83ea31da50e5cc472d35ef6b5fb8147453274ffd251134472ce24eb6f8d8398d96dee98237cdb81a6c9a7 + languageName: node + linkType: hard + +"is-alphanumerical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphanumerical@npm:2.0.1" + dependencies: + is-alphabetical: "npm:^2.0.0" + is-decimal: "npm:^2.0.0" + checksum: 10c0/4b35c42b18e40d41378293f82a3ecd9de77049b476f748db5697c297f686e1e05b072a6aaae2d16f54d2a57f85b00cbbe755c75f6d583d1c77d6657bd0feb5a2 + languageName: node + linkType: hard + "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" @@ -6245,6 +7277,13 @@ __metadata: languageName: node linkType: hard +"is-decimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-decimal@npm:2.0.1" + checksum: 10c0/8085dd66f7d82f9de818fba48b9e9c0429cb4291824e6c5f2622e96b9680b54a07a624cfc663b24148b8e853c62a1c987cfe8b0b5a13f5156991afaf6736e334 + languageName: node + linkType: hard + "is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": version: 2.2.1 resolution: "is-docker@npm:2.2.1" @@ -6304,6 +7343,13 @@ __metadata: languageName: node linkType: hard +"is-hexadecimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-hexadecimal@npm:2.0.1" + checksum: 10c0/3eb60fe2f1e2bbc760b927dcad4d51eaa0c60138cf7fc671803f66353ad90c301605b502c7ea4c6bb0548e1c7e79dfd37b73b632652e3b76030bba603a7e9626 + languageName: node + linkType: hard + "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -6332,7 +7378,7 @@ __metadata: languageName: node linkType: hard -"is-plain-obj@npm:^4.1.0": +"is-plain-obj@npm:^4.0.0, is-plain-obj@npm:^4.1.0": version: 4.1.0 resolution: "is-plain-obj@npm:4.1.0" checksum: 10c0/32130d651d71d9564dc88ba7e6fda0e91a1010a3694648e9f4f47bb6080438140696d3e3e15c741411d712e47ac9edc1a8a9de1fe76f3487b0d90be06ac9975e @@ -7358,6 +8404,13 @@ __metadata: languageName: node linkType: hard +"longest-streak@npm:^3.0.0": + version: 3.1.0 + resolution: "longest-streak@npm:3.1.0" + checksum: 10c0/7c2f02d0454b52834d1bcedef79c557bd295ee71fdabb02d041ff3aa9da48a90b5df7c0409156dedbc4df9b65da18742652aaea4759d6ece01f08971af6a7eaa + languageName: node + linkType: hard + "loose-envify@npm:^1.0.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -7410,6 +8463,20 @@ __metadata: languageName: node linkType: hard +"markdown-extensions@npm:^2.0.0": + version: 2.0.0 + resolution: "markdown-extensions@npm:2.0.0" + checksum: 10c0/406139da2aa0d5ebad86195c8e8c02412f873c452b4c087ae7bc767af37956141be449998223bb379eea179b5fd38dfa610602b6f29c22ddab5d51e627a7e41d + languageName: node + linkType: hard + +"markdown-table@npm:^3.0.0": + version: 3.0.4 + resolution: "markdown-table@npm:3.0.4" + checksum: 10c0/1257b31827629a54c24a5030a3dac952256c559174c95ce3ef89bebd6bff0cb1444b1fd667b1a1bb53307f83278111505b3e26f0c4e7b731e0060d435d2d930b + languageName: node + linkType: hard + "marky@npm:^1.2.2": version: 1.3.0 resolution: "marky@npm:1.3.0" @@ -7417,72 +8484,335 @@ __metadata: languageName: node linkType: hard -"memoize-one@npm:^5.0.0": - version: 5.2.1 - resolution: "memoize-one@npm:5.2.1" - checksum: 10c0/fd22dbe9a978a2b4f30d6a491fc02fb90792432ad0dab840dc96c1734d2bd7c9cdeb6a26130ec60507eb43230559523615873168bcbe8fafab221c30b11d54c1 +"mdast-util-find-and-replace@npm:^3.0.0": + version: 3.0.2 + resolution: "mdast-util-find-and-replace@npm:3.0.2" + dependencies: + "@types/mdast": "npm:^4.0.0" + escape-string-regexp: "npm:^5.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/c8417a35605d567772ff5c1aa08363ff3010b0d60c8ea68c53cba09bf25492e3dd261560425c1756535f3b7107f62e7ff3857cdd8fb1e62d1b2cc2ea6e074ca2 languageName: node linkType: hard -"meow@npm:^13.0.0": - version: 13.2.0 - resolution: "meow@npm:13.2.0" - checksum: 10c0/d5b339ae314715bcd0b619dd2f8a266891928e21526b4800d49b4fba1cc3fff7e2c1ff5edd3344149fac841bc2306157f858e8c4d5eaee4d52ce52ad925664ce +"mdast-util-from-markdown@npm:^2.0.0": + version: 2.0.3 + resolution: "mdast-util-from-markdown@npm:2.0.3" + dependencies: + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + decode-named-character-reference: "npm:^1.0.0" + devlop: "npm:^1.0.0" + mdast-util-to-string: "npm:^4.0.0" + micromark: "npm:^4.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-decode-string: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-stringify-position: "npm:^4.0.0" + checksum: 10c0/d3eac9ac2b88e3b41fb85aa81c7bfd1f4f8a2fde497ad805e66fea7b2abfe486ffd94d2a20f9fd2951dcdebe4916f3bdcf851319891dd62d343e26c2f02583ba languageName: node linkType: hard -"meow@npm:^14.0.0": - version: 14.1.0 - resolution: "meow@npm:14.1.0" - checksum: 10c0/f0ca4bb4fd08e4b9470fcbb7332deb61d72d40d4bda18ffb87c1a98e5014c0b44749ae9f0cab18fa532e26d61cef5d453831f9ae23ac09fa8ea0e0469be73ebc +"mdast-util-gfm-autolink-literal@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-gfm-autolink-literal@npm:2.0.1" + dependencies: + "@types/mdast": "npm:^4.0.0" + ccount: "npm:^2.0.0" + devlop: "npm:^1.0.0" + mdast-util-find-and-replace: "npm:^3.0.0" + micromark-util-character: "npm:^2.0.0" + checksum: 10c0/963cd22bd42aebdec7bdd0a527c9494d024d1ad0739c43dc040fee35bdfb5e29c22564330a7418a72b5eab51d47a6eff32bc0255ef3ccb5cebfe8970e91b81b6 languageName: node linkType: hard -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 +"mdast-util-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "mdast-util-gfm-footnote@npm:2.1.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.1.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + checksum: 10c0/8ab965ee6be3670d76ec0e95b2ba3101fc7444eec47564943ab483d96ac17d29da2a4e6146a2a288be30c21b48c4f3938a1e54b9a46fbdd321d49a5bc0077ed0 languageName: node linkType: hard -"merge2@npm:^1.3.0, merge2@npm:^1.4.1": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb +"mdast-util-gfm-strikethrough@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-strikethrough@npm:2.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/b053e93d62c7545019bd914271ea9e5667ad3b3b57d16dbf68e56fea39a7e19b4a345e781312714eb3d43fdd069ff7ee22a3ca7f6149dfa774554f19ce3ac056 languageName: node linkType: hard -"metro-babel-transformer@npm:0.83.7": - version: 0.83.7 - resolution: "metro-babel-transformer@npm:0.83.7" +"mdast-util-gfm-table@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-table@npm:2.0.0" dependencies: - "@babel/core": "npm:^7.25.2" - flow-enums-runtime: "npm:^0.0.6" - hermes-parser: "npm:0.35.0" - metro-cache-key: "npm:0.83.7" - nullthrows: "npm:^1.1.1" - checksum: 10c0/c50c2fe9fa3d3fbe382d8a482ebcc77d7dba0ef4673cee4904a55b9ea28dea4b86d3b80e9b9ac0cd2b094b9ecd0368c953bba0f1df1cfd36c3a27c666352fd86 + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + markdown-table: "npm:^3.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/128af47c503a53bd1c79f20642561e54a510ad5e2db1e418d28fefaf1294ab839e6c838e341aef5d7e404f9170b9ca3d1d89605f234efafde93ee51174a6e31e languageName: node linkType: hard -"metro-babel-transformer@npm:0.84.4": - version: 0.84.4 - resolution: "metro-babel-transformer@npm:0.84.4" +"mdast-util-gfm-task-list-item@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-task-list-item@npm:2.0.0" dependencies: - "@babel/core": "npm:^7.25.2" - flow-enums-runtime: "npm:^0.0.6" - hermes-parser: "npm:0.35.0" - metro-cache-key: "npm:0.84.4" - nullthrows: "npm:^1.1.1" - checksum: 10c0/d1ac996666334bc1cfe9d399cbf4cd747b675f6f8f758c2317eebcc52bd76046ed864ddb7b270efeb8cf337940a61fb03912e5c859b7cbc54687c2f5c41a9d2a + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/258d725288482b636c0a376c296431390c14b4f29588675297cb6580a8598ed311fc73ebc312acfca12cc8546f07a3a285a53a3b082712e2cbf5c190d677d834 languageName: node linkType: hard -"metro-cache-key@npm:0.83.7": - version: 0.83.7 - resolution: "metro-cache-key@npm:0.83.7" +"mdast-util-gfm@npm:^3.0.0": + version: 3.1.0 + resolution: "mdast-util-gfm@npm:3.1.0" dependencies: - flow-enums-runtime: "npm:^0.0.6" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-gfm-autolink-literal: "npm:^2.0.0" + mdast-util-gfm-footnote: "npm:^2.0.0" + mdast-util-gfm-strikethrough: "npm:^2.0.0" + mdast-util-gfm-table: "npm:^2.0.0" + mdast-util-gfm-task-list-item: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/4bedcfb6a20e39901c8772f0d2bb2d7a64ae87a54c13cbd92eec062cf470fbb68c2ad754e149af5b30794e2de61c978ab1de1ace03c0c40f443ca9b9b8044f81 + languageName: node + linkType: hard + +"mdast-util-mdx-expression@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdx-expression@npm:2.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/9a1e57940f66431f10312fa239096efa7627f375e7933b5d3162c0b5c1712a72ac87447aff2b6838d2bbd5c1311b188718cc90b33b67dc67a88550e0a6ef6183 + languageName: node + linkType: hard + +"mdast-util-mdx-jsx@npm:^3.0.0": + version: 3.2.0 + resolution: "mdast-util-mdx-jsx@npm:3.2.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + ccount: "npm:^2.0.0" + devlop: "npm:^1.1.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + parse-entities: "npm:^4.0.0" + stringify-entities: "npm:^4.0.0" + unist-util-stringify-position: "npm:^4.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/3acadaf3b962254f7ad2990fed4729961dc0217ca31fde9917986e880843f3ecf3392b1f22d569235cacd180d50894ad266db7af598aedca69d330d33c7ac613 + languageName: node + linkType: hard + +"mdast-util-mdx@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-mdx@npm:3.0.0" + dependencies: + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/4faea13f77d6bc9aa64ee41a5e4779110b73444a17fda363df6ebe880ecfa58b321155b71f8801c3faa6d70d6222a32a00cbd6dbf5fad8db417f4688bc9c74e1 + languageName: node + linkType: hard + +"mdast-util-mdxjs-esm@npm:^2.0.0, mdast-util-mdxjs-esm@npm:^2.0.1": + version: 2.0.1 + resolution: "mdast-util-mdxjs-esm@npm:2.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/5bda92fc154141705af2b804a534d891f28dac6273186edf1a4c5e3f045d5b01dbcac7400d27aaf91b7e76e8dce007c7b2fdf136c11ea78206ad00bdf9db46bc + languageName: node + linkType: hard + +"mdast-util-phrasing@npm:^4.0.0": + version: 4.1.0 + resolution: "mdast-util-phrasing@npm:4.1.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + unist-util-is: "npm:^6.0.0" + checksum: 10c0/bf6c31d51349aa3d74603d5e5a312f59f3f65662ed16c58017169a5fb0f84ca98578f626c5ee9e4aa3e0a81c996db8717096705521bddb4a0185f98c12c9b42f + languageName: node + linkType: hard + +"mdast-util-to-hast@npm:^13.0.0": + version: 13.2.1 + resolution: "mdast-util-to-hast@npm:13.2.1" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + trim-lines: "npm:^3.0.0" + unist-util-position: "npm:^5.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/3eeaf28a5e84e1e08e6d54a1a8a06c0fca88cb5d36f4cf8086f0177248d1ce6e4e751f4ad0da19a3dea1c6ea61bd80784acc3ae021e44ceeb21aa5413a375e43 + languageName: node + linkType: hard + +"mdast-util-to-markdown-cjk-friendly-gfm-strikethrough@npm:1.0.0": + version: 1.0.0 + resolution: "mdast-util-to-markdown-cjk-friendly-gfm-strikethrough@npm:1.0.0" + dependencies: + mdast-util-gfm-strikethrough: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.1.2" + micromark-extension-cjk-friendly-util: "npm:3.0.1" + micromark-util-symbol: "npm:^2.0.1" + peerDependencies: + "@types/mdast": "*" + peerDependenciesMeta: + "@types/mdast": + optional: true + checksum: 10c0/dc03d1001d8f5d2b33134935daa162d8f5bd307f1dc93af5b257487bdb216a0b60434d238c8f4f762f77c99767838a2f1f0790d355b711318df1de4f95072953 + languageName: node + linkType: hard + +"mdast-util-to-markdown-cjk-friendly@npm:1.0.0": + version: 1.0.0 + resolution: "mdast-util-to-markdown-cjk-friendly@npm:1.0.0" + dependencies: + mdast-util-to-markdown: "npm:^2.1.2" + micromark-extension-cjk-friendly-util: "npm:3.0.1" + micromark-util-symbol: "npm:^2.0.1" + peerDependencies: + "@types/mdast": "*" + peerDependenciesMeta: + "@types/mdast": + optional: true + checksum: 10c0/5fedb40578f136f74921abd3457626637328ddec8d0e60f490ee7c69b10308d5a580faa627a06a11303985d2c714ad46a883d4a436015c0e9639bd333b54ec6b + languageName: node + linkType: hard + +"mdast-util-to-markdown@npm:^2.0.0, mdast-util-to-markdown@npm:^2.1.2": + version: 2.1.2 + resolution: "mdast-util-to-markdown@npm:2.1.2" + dependencies: + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + longest-streak: "npm:^3.0.0" + mdast-util-phrasing: "npm:^4.0.0" + mdast-util-to-string: "npm:^4.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-decode-string: "npm:^2.0.0" + unist-util-visit: "npm:^5.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/4649722a6099f12e797bd8d6469b2b43b44e526b5182862d9c7766a3431caad2c0112929c538a972f214e63c015395e5d3f54bd81d9ac1b16e6d8baaf582f749 + languageName: node + linkType: hard + +"mdast-util-to-string@npm:^4.0.0": + version: 4.0.0 + resolution: "mdast-util-to-string@npm:4.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + checksum: 10c0/2d3c1af29bf3fe9c20f552ee9685af308002488f3b04b12fa66652c9718f66f41a32f8362aa2d770c3ff464c034860b41715902ada2306bb0a055146cef064d7 + languageName: node + linkType: hard + +"medium-zoom@npm:1.1.0": + version: 1.1.0 + resolution: "medium-zoom@npm:1.1.0" + checksum: 10c0/7d1f05e8eab045c33d7c04d4ee7bf04f5246cf7a720d7b5f5a51c36ab23666e363bcbb6bffae50b5948d5eb19361914cb0e26a1fce5c1fff7a266bc0217893f3 + languageName: node + linkType: hard + +"memoize-one@npm:^5.0.0": + version: 5.2.1 + resolution: "memoize-one@npm:5.2.1" + checksum: 10c0/fd22dbe9a978a2b4f30d6a491fc02fb90792432ad0dab840dc96c1734d2bd7c9cdeb6a26130ec60507eb43230559523615873168bcbe8fafab221c30b11d54c1 + languageName: node + linkType: hard + +"meow@npm:^13.0.0": + version: 13.2.0 + resolution: "meow@npm:13.2.0" + checksum: 10c0/d5b339ae314715bcd0b619dd2f8a266891928e21526b4800d49b4fba1cc3fff7e2c1ff5edd3344149fac841bc2306157f858e8c4d5eaee4d52ce52ad925664ce + languageName: node + linkType: hard + +"meow@npm:^14.0.0": + version: 14.1.0 + resolution: "meow@npm:14.1.0" + checksum: 10c0/f0ca4bb4fd08e4b9470fcbb7332deb61d72d40d4bda18ffb87c1a98e5014c0b44749ae9f0cab18fa532e26d61cef5d453831f9ae23ac09fa8ea0e0469be73ebc + languageName: node + linkType: hard + +"merge-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-stream@npm:2.0.0" + checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 + languageName: node + linkType: hard + +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb + languageName: node + linkType: hard + +"metro-babel-transformer@npm:0.83.7": + version: 0.83.7 + resolution: "metro-babel-transformer@npm:0.83.7" + dependencies: + "@babel/core": "npm:^7.25.2" + flow-enums-runtime: "npm:^0.0.6" + hermes-parser: "npm:0.35.0" + metro-cache-key: "npm:0.83.7" + nullthrows: "npm:^1.1.1" + checksum: 10c0/c50c2fe9fa3d3fbe382d8a482ebcc77d7dba0ef4673cee4904a55b9ea28dea4b86d3b80e9b9ac0cd2b094b9ecd0368c953bba0f1df1cfd36c3a27c666352fd86 + languageName: node + linkType: hard + +"metro-babel-transformer@npm:0.84.4": + version: 0.84.4 + resolution: "metro-babel-transformer@npm:0.84.4" + dependencies: + "@babel/core": "npm:^7.25.2" + flow-enums-runtime: "npm:^0.0.6" + hermes-parser: "npm:0.35.0" + metro-cache-key: "npm:0.84.4" + nullthrows: "npm:^1.1.1" + checksum: 10c0/d1ac996666334bc1cfe9d399cbf4cd747b675f6f8f758c2317eebcc52bd76046ed864ddb7b270efeb8cf337940a61fb03912e5c859b7cbc54687c2f5c41a9d2a + languageName: node + linkType: hard + +"metro-cache-key@npm:0.83.7": + version: 0.83.7 + resolution: "metro-cache-key@npm:0.83.7" + dependencies: + flow-enums-runtime: "npm:^0.0.6" checksum: 10c0/a2f20b86b173cd2be710552a49e6389a2c9ef994ac35873616bd4e5c34588beb8c93279bcf525295ca73b6d206ab0d9942f35cbd4a76e642d359bdab48924d7a languageName: node linkType: hard @@ -7900,6 +9230,497 @@ __metadata: languageName: node linkType: hard +"micromark-core-commonmark@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-core-commonmark@npm:2.0.3" + dependencies: + decode-named-character-reference: "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-factory-destination: "npm:^2.0.0" + micromark-factory-label: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-factory-title: "npm:^2.0.0" + micromark-factory-whitespace: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-html-tag-name: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-subtokenize: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bd4a794fdc9e88dbdf59eaf1c507ddf26e5f7ddf4e52566c72239c0f1b66adbcd219ba2cd42350debbe24471434d5f5e50099d2b3f4e5762ca222ba8e5b549ee + languageName: node + linkType: hard + +"micromark-extension-cjk-friendly-gfm-strikethrough@npm:2.0.1": + version: 2.0.1 + resolution: "micromark-extension-cjk-friendly-gfm-strikethrough@npm:2.0.1" + dependencies: + devlop: "npm:^1.1.0" + get-east-asian-width: "npm:^1.4.0" + micromark-extension-cjk-friendly-util: "npm:3.0.1" + micromark-util-character: "npm:^2.1.1" + micromark-util-chunked: "npm:^2.0.1" + micromark-util-resolve-all: "npm:^2.0.1" + micromark-util-symbol: "npm:^2.0.1" + peerDependencies: + micromark: ^4.0.0 + micromark-util-types: ^2.0.0 + peerDependenciesMeta: + micromark-util-types: + optional: true + checksum: 10c0/6e51e6101fc287322b12379b32052fb6cbfdb1f427f87671d1b5a3b9d4fc685b60eb8a01f897bb5fc1aeae6197ec668e8f0a3179db80870b11e295cc2fe4bbb3 + languageName: node + linkType: hard + +"micromark-extension-cjk-friendly-util@npm:3.0.1": + version: 3.0.1 + resolution: "micromark-extension-cjk-friendly-util@npm:3.0.1" + dependencies: + get-east-asian-width: "npm:^1.4.0" + micromark-util-character: "npm:^2.1.1" + micromark-util-symbol: "npm:^2.0.1" + peerDependenciesMeta: + micromark-util-types: + optional: true + checksum: 10c0/5a9210b21fcf38b6b6f17dd49587eb70cc17001294e49a81cc128975be8fcb7654d70ed198280c7d56e8664338c1cbe0ca9d4ecbe57348e380f0552b7178602c + languageName: node + linkType: hard + +"micromark-extension-cjk-friendly@npm:2.0.1": + version: 2.0.1 + resolution: "micromark-extension-cjk-friendly@npm:2.0.1" + dependencies: + devlop: "npm:^1.1.0" + micromark-extension-cjk-friendly-util: "npm:3.0.1" + micromark-util-chunked: "npm:^2.0.1" + micromark-util-resolve-all: "npm:^2.0.1" + micromark-util-symbol: "npm:^2.0.1" + peerDependencies: + micromark: ^4.0.0 + micromark-util-types: ^2.0.0 + peerDependenciesMeta: + micromark-util-types: + optional: true + checksum: 10c0/23bd7aabecc83f58508e29a181cf1baa5ad7e0612e1a227cdbd445214afbfd47e9bb2100e740d15728078eaeedd7820cdc70585f36c62ecb70e38bd6e017afa4 + languageName: node + linkType: hard + +"micromark-extension-gfm-autolink-literal@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-autolink-literal@npm:2.1.0" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/84e6fbb84ea7c161dfa179665dc90d51116de4c28f3e958260c0423e5a745372b7dcbc87d3cde98213b532e6812f847eef5ae561c9397d7f7da1e59872ef3efe + languageName: node + linkType: hard + +"micromark-extension-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-footnote@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/d172e4218968b7371b9321af5cde8c77423f73b233b2b0fcf3ff6fd6f61d2e0d52c49123a9b7910612478bf1f0d5e88c75a3990dd68f70f3933fe812b9f77edc + languageName: node + linkType: hard + +"micromark-extension-gfm-strikethrough@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-strikethrough@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/ef4f248b865bdda71303b494671b7487808a340b25552b11ca6814dff3fcfaab9be8d294643060bbdb50f79313e4a686ab18b99cbe4d3ee8a4170fcd134234fb + languageName: node + linkType: hard + +"micromark-extension-gfm-table@npm:^2.0.0": + version: 2.1.1 + resolution: "micromark-extension-gfm-table@npm:2.1.1" + dependencies: + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/04bc00e19b435fa0add62cd029d8b7eb6137522f77832186b1d5ef34544a9bd030c9cf85e92ddfcc5c31f6f0a58a43d4b96dba4fc21316037c734630ee12c912 + languageName: node + linkType: hard + +"micromark-extension-gfm-tagfilter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-tagfilter@npm:2.0.0" + dependencies: + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/995558843fff137ae4e46aecb878d8a4691cdf23527dcf1e2f0157d66786be9f7bea0109c52a8ef70e68e3f930af811828ba912239438e31a9cfb9981f44d34d + languageName: node + linkType: hard + +"micromark-extension-gfm-task-list-item@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-task-list-item@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/78aa537d929e9309f076ba41e5edc99f78d6decd754b6734519ccbbfca8abd52e1c62df68d41a6ae64d2a3fc1646cea955893c79680b0b4385ced4c52296181f + languageName: node + linkType: hard + +"micromark-extension-gfm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-gfm@npm:3.0.0" + dependencies: + micromark-extension-gfm-autolink-literal: "npm:^2.0.0" + micromark-extension-gfm-footnote: "npm:^2.0.0" + micromark-extension-gfm-strikethrough: "npm:^2.0.0" + micromark-extension-gfm-table: "npm:^2.0.0" + micromark-extension-gfm-tagfilter: "npm:^2.0.0" + micromark-extension-gfm-task-list-item: "npm:^2.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/970e28df6ebdd7c7249f52a0dda56e0566fbfa9ae56c8eeeb2445d77b6b89d44096880cd57a1c01e7821b1f4e31009109fbaca4e89731bff7b83b8519690e5d9 + languageName: node + linkType: hard + +"micromark-extension-mdx-expression@npm:^3.0.0": + version: 3.0.1 + resolution: "micromark-extension-mdx-expression@npm:3.0.1" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-factory-mdx-expression: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/4d8cc5353b083b06bd51c98389de9c198261a5b2b440b75e85000a18d10511f21ba77538d6dfde0e0589df9de3fba9a1d14c2448d30c92d6b461c26d86e397f4 + languageName: node + linkType: hard + +"micromark-extension-mdx-jsx@npm:^3.0.0": + version: 3.0.2 + resolution: "micromark-extension-mdx-jsx@npm:3.0.2" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + micromark-factory-mdx-expression: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/5693b2e51934ac29a6aab521eaa2151f891d1fe092550bbd4ce24e4dd7567c1421a54f5e585a57dfa1769a79570f6df57ddd7a98bf0889dd11d495847a266dd7 + languageName: node + linkType: hard + +"micromark-extension-mdx-md@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-mdx-md@npm:2.0.0" + dependencies: + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bae91c61273de0e5ba80a980c03470e6cd9d7924aa936f46fbda15d780704d9386e945b99eda200e087b96254fbb4271a9545d5ce02676cd6ae67886a8bf82df + languageName: node + linkType: hard + +"micromark-extension-mdxjs-esm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs-esm@npm:3.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/13e3f726495a960650cdedcba39198ace5bdc953ccb12c14d71fc9ed9bb88e40cc3ba9231e973f6984da3b3573e7ddb23ce409f7c16f52a8d57b608bf46c748d + languageName: node + linkType: hard + +"micromark-extension-mdxjs@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs@npm:3.0.0" + dependencies: + acorn: "npm:^8.0.0" + acorn-jsx: "npm:^5.0.0" + micromark-extension-mdx-expression: "npm:^3.0.0" + micromark-extension-mdx-jsx: "npm:^3.0.0" + micromark-extension-mdx-md: "npm:^2.0.0" + micromark-extension-mdxjs-esm: "npm:^3.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/fd84f036ddad0aabbc12e7f1b3e9dcfe31573bbc413c5ae903779ef0366d7a4c08193547e7ba75718c9f45654e45f52e575cfc2f23a5f89205a8a70d9a506aea + languageName: node + linkType: hard + +"micromark-factory-destination@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-destination@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bbafcf869cee5bf511161354cb87d61c142592fbecea051000ff116068dc85216e6d48519d147890b9ea5d7e2864a6341c0c09d9948c203bff624a80a476023c + languageName: node + linkType: hard + +"micromark-factory-label@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-label@npm:2.0.1" + dependencies: + devlop: "npm:^1.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/0137716b4ecb428114165505e94a2f18855c8bbea21b07a8b5ce514b32a595ed789d2b967125718fc44c4197ceaa48f6609d58807a68e778138d2e6b91b824e8 + languageName: node + linkType: hard + +"micromark-factory-mdx-expression@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-factory-mdx-expression@npm:2.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/a6004ef6272dd01a5d718f2affd7bfb5e08f0849340f5fd96ac823fbc5e9d3b3343acedda50805873ccda5e3b8af4d5fbb302abc874544044ac90c217345cf97 + languageName: node + linkType: hard + +"micromark-factory-space@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-space@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/f9ed43f1c0652d8d898de0ac2be3f77f776fffe7dd96bdbba1e02d7ce33d3853c6ff5daa52568fc4fa32cdf3a62d86b85ead9b9189f7211e1d69ff2163c450fb + languageName: node + linkType: hard + +"micromark-factory-title@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-title@npm:2.0.1" + dependencies: + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/e72fad8d6e88823514916890099a5af20b6a9178ccf78e7e5e05f4de99bb8797acb756257d7a3a57a53854cb0086bf8aab15b1a9e9db8982500dd2c9ff5948b6 + languageName: node + linkType: hard + +"micromark-factory-whitespace@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-whitespace@npm:2.0.1" + dependencies: + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/20a1ec58698f24b766510a309b23a10175034fcf1551eaa9da3adcbed3e00cd53d1ebe5f030cf873f76a1cec3c34eb8c50cc227be3344caa9ed25d56cf611224 + languageName: node + linkType: hard + +"micromark-util-character@npm:^2.0.0, micromark-util-character@npm:^2.1.1": + version: 2.1.1 + resolution: "micromark-util-character@npm:2.1.1" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/d3fe7a5e2c4060fc2a076f9ce699c82a2e87190a3946e1e5eea77f563869b504961f5668d9c9c014724db28ac32fa909070ea8b30c3a39bd0483cc6c04cc76a1 + languageName: node + linkType: hard + +"micromark-util-chunked@npm:^2.0.0, micromark-util-chunked@npm:^2.0.1": + version: 2.0.1 + resolution: "micromark-util-chunked@npm:2.0.1" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/b68c0c16fe8106949537bdcfe1be9cf36c0ccd3bc54c4007003cb0984c3750b6cdd0fd77d03f269a3382b85b0de58bde4f6eedbe7ecdf7244759112289b1ab56 + languageName: node + linkType: hard + +"micromark-util-classify-character@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-classify-character@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/8a02e59304005c475c332f581697e92e8c585bcd45d5d225a66c1c1b14ab5a8062705188c2ccec33cc998d33502514121478b2091feddbc751887fc9c290ed08 + languageName: node + linkType: hard + +"micromark-util-combine-extensions@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-combine-extensions@npm:2.0.1" + dependencies: + micromark-util-chunked: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/f15e282af24c8372cbb10b9b0b3e2c0aa681fea0ca323a44d6bc537dc1d9382c819c3689f14eaa000118f5a163245358ce6276b2cda9a84439cdb221f5d86ae7 + languageName: node + linkType: hard + +"micromark-util-decode-numeric-character-reference@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-decode-numeric-character-reference@npm:2.0.2" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/9c8a9f2c790e5593ffe513901c3a110e9ec8882a08f466da014112a25e5059b51551ca0aeb7ff494657d86eceb2f02ee556c6558b8d66aadc61eae4a240da0df + languageName: node + linkType: hard + +"micromark-util-decode-string@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-decode-string@npm:2.0.1" + dependencies: + decode-named-character-reference: "npm:^1.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/f24d75b2e5310be6e7b6dee532e0d17d3bf46996841d6295f2a9c87a2046fff4ab603c52ab9d7a7a6430a8b787b1574ae895849c603d262d1b22eef71736b5cb + languageName: node + linkType: hard + +"micromark-util-encode@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-encode@npm:2.0.1" + checksum: 10c0/b2b29f901093845da8a1bf997ea8b7f5e061ffdba85070dfe14b0197c48fda64ffcf82bfe53c90cf9dc185e69eef8c5d41cae3ba918b96bc279326921b59008a + languageName: node + linkType: hard + +"micromark-util-events-to-acorn@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-util-events-to-acorn@npm:2.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/unist": "npm:^3.0.0" + devlop: "npm:^1.0.0" + estree-util-visit: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/a4e0716e943ffdd16a918edf51d4f8291ec2692f5c4d04693dbef3358716fba891f288197afd102c14f4d98dac09d52351046ab7aad1d50b74677bdd5fa683c0 + languageName: node + linkType: hard + +"micromark-util-html-tag-name@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-html-tag-name@npm:2.0.1" + checksum: 10c0/ae80444db786fde908e9295f19a27a4aa304171852c77414516418650097b8afb401961c9edb09d677b06e97e8370cfa65638dde8438ebd41d60c0a8678b85b9 + languageName: node + linkType: hard + +"micromark-util-normalize-identifier@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-normalize-identifier@npm:2.0.1" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/5299265fa360769fc499a89f40142f10a9d4a5c3dd8e6eac8a8ef3c2e4a6570e4c009cf75ea46dce5ee31c01f25587bde2f4a5cc0a935584ae86dd857f2babbd + languageName: node + linkType: hard + +"micromark-util-resolve-all@npm:^2.0.0, micromark-util-resolve-all@npm:^2.0.1": + version: 2.0.1 + resolution: "micromark-util-resolve-all@npm:2.0.1" + dependencies: + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bb6ca28764696bb479dc44a2d5b5fe003e7177aeae1d6b0d43f24cc223bab90234092d9c3ce4a4d2b8df095ccfd820537b10eb96bb7044d635f385d65a4c984a + languageName: node + linkType: hard + +"micromark-util-sanitize-uri@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-sanitize-uri@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-encode: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/60e92166e1870fd4f1961468c2651013ff760617342918e0e0c3c4e872433aa2e60c1e5a672bfe5d89dc98f742d6b33897585cf86ae002cda23e905a3c02527c + languageName: node + linkType: hard + +"micromark-util-subtokenize@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-util-subtokenize@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bee69eece4393308e657c293ba80d92ebcb637e5f55e21dcf9c3fa732b91a8eda8ac248d76ff375e675175bfadeae4712e5158ef97eef1111789da1ce7ab5067 + languageName: node + linkType: hard + +"micromark-util-symbol@npm:^2.0.0, micromark-util-symbol@npm:^2.0.1": + version: 2.0.1 + resolution: "micromark-util-symbol@npm:2.0.1" + checksum: 10c0/f2d1b207771e573232436618e78c5e46cd4b5c560dd4a6d63863d58018abbf49cb96ec69f7007471e51434c60de3c9268ef2bf46852f26ff4aacd10f9da16fe9 + languageName: node + linkType: hard + +"micromark-util-types@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-types@npm:2.0.2" + checksum: 10c0/c8c15b96c858db781c4393f55feec10004bf7df95487636c9a9f7209e51002a5cca6a047c5d2a5dc669ff92da20e57aaa881e81a268d9ccadb647f9dce305298 + languageName: node + linkType: hard + +"micromark@npm:^4.0.0": + version: 4.0.2 + resolution: "micromark@npm:4.0.2" + dependencies: + "@types/debug": "npm:^4.0.0" + debug: "npm:^4.0.0" + decode-named-character-reference: "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-encode: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-subtokenize: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/07462287254219d6eda6eac8a3cebaff2994e0575499e7088027b825105e096e4f51e466b14b2a81b71933a3b6c48ee069049d87bc2c2127eee50d9cc69e8af6 + languageName: node + linkType: hard + "micromatch@npm:^4.0.4, micromatch@npm:^4.0.8": version: 4.0.8 resolution: "micromatch@npm:4.0.8" @@ -8181,6 +10002,13 @@ __metadata: languageName: node linkType: hard +"nprogress@npm:^0.2.0": + version: 0.2.0 + resolution: "nprogress@npm:0.2.0" + checksum: 10c0/eab9a923a1ad1eed71a455ecfbc358442dd9bcd71b9fa3fa1c67eddf5159360b182c218f76fca320c97541a1b45e19ced04e6dcb044a662244c5419f8ae9e821 + languageName: node + linkType: hard + "nullthrows@npm:^1.1.1": version: 1.1.1 resolution: "nullthrows@npm:1.1.1" @@ -8258,6 +10086,24 @@ __metadata: languageName: node linkType: hard +"oniguruma-parser@npm:^0.12.2": + version: 0.12.2 + resolution: "oniguruma-parser@npm:0.12.2" + checksum: 10c0/fe5255d2cd5a6b845d5a0abe1725898ef40cea5522290dba6ccc08cc388891e9e8007af4baa5059942b786ad44b2b677ef25948039c9ba3f057bd35d2c52076a + languageName: node + linkType: hard + +"oniguruma-to-es@npm:^4.3.6": + version: 4.3.6 + resolution: "oniguruma-to-es@npm:4.3.6" + dependencies: + oniguruma-parser: "npm:^0.12.2" + regex: "npm:^6.1.0" + regex-recursion: "npm:^6.0.2" + checksum: 10c0/044e08b98e706987c2882ccf228de2a671de4aff33e3bd370da137ba599c0d520549625ad26ecc8898502445c991e19f106f584e94382262ba2af02c908ca3cf + languageName: node + linkType: hard + "open@npm:^7.0.3": version: 7.4.2 resolution: "open@npm:7.4.2" @@ -8528,6 +10374,21 @@ __metadata: languageName: node linkType: hard +"parse-entities@npm:^4.0.0": + version: 4.0.2 + resolution: "parse-entities@npm:4.0.2" + dependencies: + "@types/unist": "npm:^2.0.0" + character-entities-legacy: "npm:^3.0.0" + character-reference-invalid: "npm:^2.0.0" + decode-named-character-reference: "npm:^1.0.0" + is-alphanumerical: "npm:^2.0.0" + is-decimal: "npm:^2.0.0" + is-hexadecimal: "npm:^2.0.0" + checksum: 10c0/a13906b1151750b78ed83d386294066daf5fb559e08c5af9591b2d98cc209123103016a01df776f65f8219ad26652d6d6b210d0974d452049cddfc53a8916c34 + languageName: node + linkType: hard + "parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -8549,6 +10410,15 @@ __metadata: languageName: node linkType: hard +"parse5@npm:^7.0.0": + version: 7.3.0 + resolution: "parse5@npm:7.3.0" + dependencies: + entities: "npm:^6.0.0" + checksum: 10c0/7fd2e4e247e85241d6f2a464d0085eed599a26d7b0a5233790c49f53473232eb85350e8133344d9b3fd58b89339e7ad7270fe1f89d28abe50674ec97b87f80b5 + languageName: node + linkType: hard + "parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" @@ -8760,6 +10630,13 @@ __metadata: languageName: node linkType: hard +"property-information@npm:^7.0.0": + version: 7.2.0 + resolution: "property-information@npm:7.2.0" + checksum: 10c0/03662c8f9e1544510914c5e594ae72963f67d261027a5fdc06c4134742584fe40dd49b959470d30e757e9fb70b297d8546ab1362a040364144029926ad4e07c4 + languageName: node + linkType: hard + "pump@npm:^3.0.0": version: 3.0.4 resolution: "pump@npm:3.0.4" @@ -8817,6 +10694,28 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:19.2.3": + version: 19.2.3 + resolution: "react-dom@npm:19.2.3" + dependencies: + scheduler: "npm:^0.27.0" + peerDependencies: + react: ^19.2.3 + checksum: 10c0/dc43f7ede06f46f3acc16ee83107c925530de9b91d1d0b3824583814746ff4c498ea64fd65cd83aba363205268adff52e2827c582634ae7b15069deaeabc4892 + languageName: node + linkType: hard + +"react-dom@npm:^19.2.6": + version: 19.2.7 + resolution: "react-dom@npm:19.2.7" + dependencies: + scheduler: "npm:^0.27.0" + peerDependencies: + react: ^19.2.7 + checksum: 10c0/970ff600f6e80d47d39e2f226f12f226173b3cba3382efc97c5f0cd663de9af38c7a4c11c213fb936094faeac83060d660247accaa96b752180d5b951b9cfecb + languageName: node + linkType: hard + "react-is-18@npm:react-is@^18.3.1, react-is@npm:^18.0.0": version: 18.3.1 resolution: "react-is@npm:18.3.1" @@ -8838,6 +10737,13 @@ __metadata: languageName: node linkType: hard +"react-lazy-with-preload@npm:^2.2.1": + version: 2.2.1 + resolution: "react-lazy-with-preload@npm:2.2.1" + checksum: 10c0/57c36baedc24a2c8fa148681dc7c5123ac183542964063b4a0433856a06d4edead27deb893012a43f75905af51a479b4409e688b97be3ef70cffff926954f6d2 + languageName: node + linkType: hard + "react-native-builder-bob@npm:^0.41.0": version: 0.41.0 resolution: "react-native-builder-bob@npm:0.41.0" @@ -9045,7 +10951,7 @@ __metadata: languageName: node linkType: hard -"react-reconciler@npm:~0.33.0": +"react-reconciler@npm:0.33.0, react-reconciler@npm:~0.33.0": version: 0.33.0 resolution: "react-reconciler@npm:0.33.0" dependencies: @@ -9063,6 +10969,52 @@ __metadata: languageName: node linkType: hard +"react-refresh@npm:^0.18.0": + version: 0.18.0 + resolution: "react-refresh@npm:0.18.0" + checksum: 10c0/34a262f7fd803433a534f50deb27a148112a81adcae440c7d1cbae7ef14d21ea8f2b3d783e858cb7698968183b77755a38b4d4b5b1d79b4f4689c2f6d358fff2 + languageName: node + linkType: hard + +"react-render-to-markdown@npm:19.1.0": + version: 19.1.0 + resolution: "react-render-to-markdown@npm:19.1.0" + dependencies: + react-reconciler: "npm:0.33.0" + peerDependencies: + react: ">=19" + checksum: 10c0/f24f733f20ddeaa43c3564b5e8fd60ffa851c026d5b5469569503b5fbef43da44d959d2ffdf64d0c11b2b26db673df0d7484d701775946c10d8996787d722d22 + languageName: node + linkType: hard + +"react-router-dom@npm:^7.15.1": + version: 7.18.0 + resolution: "react-router-dom@npm:7.18.0" + dependencies: + react-router: "npm:7.18.0" + peerDependencies: + react: ">=18" + react-dom: ">=18" + checksum: 10c0/035303f4d14680bf5356ab20e40889fc7bac281f59399c34b8fd0ed884e2f8e9e1b17ce7e668cad5e8bc1b428fe32a33d97509947568a23f4271e0392501304c + languageName: node + linkType: hard + +"react-router@npm:7.18.0": + version: 7.18.0 + resolution: "react-router@npm:7.18.0" + dependencies: + cookie: "npm:^1.0.1" + set-cookie-parser: "npm:^2.6.0" + peerDependencies: + react: ">=18" + react-dom: ">=18" + peerDependenciesMeta: + react-dom: + optional: true + checksum: 10c0/7ab6c6dc7efdc14092486d63f55b04f9e3ef269fdec8c695a513f69e55d02a9beab8f637a13396952815d85accf16e7db2d65d9cbb68def13c349be82ceb5aee + languageName: node + linkType: hard + "react@npm:19.2.3": version: 19.2.3 resolution: "react@npm:19.2.3" @@ -9070,6 +11022,13 @@ __metadata: languageName: node linkType: hard +"react@npm:^19.2.6": + version: 19.2.7 + resolution: "react@npm:19.2.7" + checksum: 10c0/0bd0e2f1bbd4ba97561c6597bf8a5fec05e6476fe61e165c1065598d16668efc6715205599c94d3ddd49d36cb0f21cbf1b9bcc18ee840b805ce222c3e8d558ac + languageName: node + linkType: hard + "read-yaml-file@npm:^1.1.0": version: 1.1.0 resolution: "read-yaml-file@npm:1.1.0" @@ -9082,6 +11041,56 @@ __metadata: languageName: node linkType: hard +"recma-build-jsx@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-build-jsx@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-util-build-jsx: "npm:^3.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/ca30f5163887b44c74682355da2625f7b49f33267699d22247913e513e043650cbdd6a7497cf13c60f09ad9e7bc2bd35bd20853672773c19188569814b56bb04 + languageName: node + linkType: hard + +"recma-jsx@npm:^1.0.0": + version: 1.0.1 + resolution: "recma-jsx@npm:1.0.1" + dependencies: + acorn-jsx: "npm:^5.0.0" + estree-util-to-js: "npm:^2.0.0" + recma-parse: "npm:^1.0.0" + recma-stringify: "npm:^1.0.0" + unified: "npm:^11.0.0" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/9921b1270581ff133b94678868e665ba0fb6285ee60a6936106bac4899196c2ffb02dde894d9bc088fbf3deacb3e2426a3452e72066bf1203cbefebd7809d93f + languageName: node + linkType: hard + +"recma-parse@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-parse@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + esast-util-from-js: "npm:^2.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/37c0990859a562d082e02d475ca5f4c8ef0840d285270f6699fe888cbb06260f97eb098585eda4aae416182c207fd19cf05e4f0b2dcf55cbf81dde4406d95545 + languageName: node + linkType: hard + +"recma-stringify@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-stringify@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-util-to-js: "npm:^2.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/c2ed4c0e8cf8a09aedcd47c5d016d47f6e1ff6c2d4b220e2abaf1b77713bf404756af2ea3ea7999aec5862e8825aff035edceb370c7fd8603a7e9da03bd6987e + languageName: node + linkType: hard + "redent@npm:^3.0.0": version: 3.0.0 resolution: "redent@npm:3.0.0" @@ -9115,6 +11124,31 @@ __metadata: languageName: node linkType: hard +"regex-recursion@npm:^6.0.2": + version: 6.0.2 + resolution: "regex-recursion@npm:6.0.2" + dependencies: + regex-utilities: "npm:^2.3.0" + checksum: 10c0/68e8b6889680e904b75d7f26edaf70a1a4dc1087406bff53face4c2929d918fd77c72223843fe816ac8ed9964f96b4160650e8d5909e26a998c6e9de324dadb1 + languageName: node + linkType: hard + +"regex-utilities@npm:^2.3.0": + version: 2.3.0 + resolution: "regex-utilities@npm:2.3.0" + checksum: 10c0/78c550a80a0af75223244fff006743922591bd8f61d91fef7c86b9b56cf9bbf8ee5d7adb6d8991b5e304c57c90103fc4818cf1e357b11c6c669b782839bd7893 + languageName: node + linkType: hard + +"regex@npm:^6.1.0": + version: 6.1.0 + resolution: "regex@npm:6.1.0" + dependencies: + regex-utilities: "npm:^2.3.0" + checksum: 10c0/6e0ee2a1c17d5a66dc1120dfc51899dedf6677857e83a0df4d5a822ebb8645a54a079772efc1ade382b67aad35e4e22b5bd2d33c05ed28b0e000f8f57eb0aec1 + languageName: node + linkType: hard + "regexpu-core@npm:^6.3.1": version: 6.4.0 resolution: "regexpu-core@npm:6.4.0" @@ -9147,6 +11181,134 @@ __metadata: languageName: node linkType: hard +"rehype-external-links@npm:^3.0.0": + version: 3.0.0 + resolution: "rehype-external-links@npm:3.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + hast-util-is-element: "npm:^3.0.0" + is-absolute-url: "npm:^4.0.0" + space-separated-tokens: "npm:^2.0.0" + unist-util-visit: "npm:^5.0.0" + checksum: 10c0/486b5db73d8fe72611d62b4eb0b56ec71025ea32bba764ad54473f714ca627be75e057ac29243763f85a77c3810f31727ce3e03c975b3803c1c98643d038e9ae + languageName: node + linkType: hard + +"rehype-raw@npm:^7.0.0": + version: 7.0.0 + resolution: "rehype-raw@npm:7.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + hast-util-raw: "npm:^9.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/1435b4b6640a5bc3abe3b2133885c4dbff5ef2190ef9cfe09d6a63f74dd7d7ffd0cede70603278560ccf1acbfb9da9faae4b68065a28bc5aa88ad18e40f32d52 + languageName: node + linkType: hard + +"rehype-recma@npm:^1.0.0": + version: 1.0.0 + resolution: "rehype-recma@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + hast-util-to-estree: "npm:^3.0.0" + checksum: 10c0/be60d7433a7f788a14f41da3e93ba9d9272c908ddef47757026cc4bbcc912f6301d56810349adf876d294a8d048626a0dbf6988aaa574afbfc29eac1ddc1eb74 + languageName: node + linkType: hard + +"remark-cjk-friendly-gfm-strikethrough@npm:^2.0.1": + version: 2.3.1 + resolution: "remark-cjk-friendly-gfm-strikethrough@npm:2.3.1" + dependencies: + mdast-util-to-markdown-cjk-friendly-gfm-strikethrough: "npm:1.0.0" + micromark-extension-cjk-friendly-gfm-strikethrough: "npm:2.0.1" + peerDependencies: + "@types/mdast": ^4.0.0 + unified: ^11.0.0 + peerDependenciesMeta: + "@types/mdast": + optional: true + checksum: 10c0/465fbe9716f6b589ae1e8cf0127f6d02b9ca07a09631a15b30c53b6ffbddbcb152154d844b2ed0931cbd609e27dfed227c614ac4f143dbb303f23d47c55714ce + languageName: node + linkType: hard + +"remark-cjk-friendly@npm:^2.0.1": + version: 2.3.1 + resolution: "remark-cjk-friendly@npm:2.3.1" + dependencies: + mdast-util-to-markdown-cjk-friendly: "npm:1.0.0" + micromark-extension-cjk-friendly: "npm:2.0.1" + peerDependencies: + "@types/mdast": ^4.0.0 + unified: ^11.0.0 + peerDependenciesMeta: + "@types/mdast": + optional: true + checksum: 10c0/323347462b83f4a0b6e842d45d933b8b5aefc99c41a4724075fc33383c8163115c86654781bdfc664f8350ffcdcd4d99dab4a98504aa890d5bbde2084fc52d2b + languageName: node + linkType: hard + +"remark-gfm@npm:^4.0.1": + version: 4.0.1 + resolution: "remark-gfm@npm:4.0.1" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-gfm: "npm:^3.0.0" + micromark-extension-gfm: "npm:^3.0.0" + remark-parse: "npm:^11.0.0" + remark-stringify: "npm:^11.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/427ecc6af3e76222662061a5f670a3e4e33ec5fffe2cabf04034da6a3f9a1bda1fc023e838a636385ba314e66e2bebbf017ca61ebea357eb0f5200fe0625a4b7 + languageName: node + linkType: hard + +"remark-mdx@npm:^3.0.0, remark-mdx@npm:^3.1.1": + version: 3.1.1 + resolution: "remark-mdx@npm:3.1.1" + dependencies: + mdast-util-mdx: "npm:^3.0.0" + micromark-extension-mdxjs: "npm:^3.0.0" + checksum: 10c0/3e5585d4c2448d8ac7548b1d148f04b89251ff47fbfc80be1428cecec2fc2530abe30a5da53bb031283f8a78933259df6120c1cd4cc7cc1d43978d508798ba88 + languageName: node + linkType: hard + +"remark-parse@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-parse@npm:11.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/6eed15ddb8680eca93e04fcb2d1b8db65a743dcc0023f5007265dda558b09db595a087f622062ccad2630953cd5cddc1055ce491d25a81f3317c858348a8dd38 + languageName: node + linkType: hard + +"remark-rehype@npm:^11.0.0": + version: 11.1.2 + resolution: "remark-rehype@npm:11.1.2" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + mdast-util-to-hast: "npm:^13.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/f9eccacfb596d9605581dc05bfad28635d6ded5dd0a18e88af5fd4df0d3fcf9612e1501d4513bc2164d833cfe9636dab20400080b09e53f155c6e1442a1231fb + languageName: node + linkType: hard + +"remark-stringify@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-stringify@npm:11.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/0cdb37ce1217578f6f847c7ec9f50cbab35df5b9e3903d543e74b405404e67c07defcb23cd260a567b41b769400f6de03c2c3d9cd6ae7a6707d5c8d89ead489f + languageName: node + linkType: hard + "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -9291,6 +11453,15 @@ __metadata: languageName: node linkType: hard +"scroll-into-view-if-needed@npm:^3.1.0": + version: 3.1.0 + resolution: "scroll-into-view-if-needed@npm:3.1.0" + dependencies: + compute-scroll-into-view: "npm:^3.0.2" + checksum: 10c0/1f46b090e1e04fcfdef1e384f6d7e615f9f84d4176faf4dbba7347cc0a6e491e5d578eaf4dbe9618dd3d8d38efafde58535b3e00f2a21ce4178c14be364850ff + languageName: node + linkType: hard + "semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" @@ -9349,6 +11520,13 @@ __metadata: languageName: node linkType: hard +"set-cookie-parser@npm:^2.6.0": + version: 2.7.2 + resolution: "set-cookie-parser@npm:2.7.2" + checksum: 10c0/4381a9eb7ee951dfe393fe7aacf76b9a3b4e93a684d2162ab35594fa4053cc82a4d7d7582bf397718012c9adcf839b8cd8f57c6c42901ea9effe33c752da4a45 + languageName: node + linkType: hard + "setprototypeof@npm:~1.2.0": version: 1.2.0 resolution: "setprototypeof@npm:1.2.0" @@ -9379,6 +11557,22 @@ __metadata: languageName: node linkType: hard +"shiki@npm:4.3.0, shiki@npm:^4.0.2": + version: 4.3.0 + resolution: "shiki@npm:4.3.0" + dependencies: + "@shikijs/core": "npm:4.3.0" + "@shikijs/engine-javascript": "npm:4.3.0" + "@shikijs/engine-oniguruma": "npm:4.3.0" + "@shikijs/langs": "npm:4.3.0" + "@shikijs/themes": "npm:4.3.0" + "@shikijs/types": "npm:4.3.0" + "@shikijs/vscode-textmate": "npm:^10.0.2" + "@types/hast": "npm:^3.0.4" + checksum: 10c0/17d0719bd1afa857a9513322ddbebc57d3292ed2ae536cb16cd32d1fa52811e7892a1f774824a4fe3de0e4cc9e60d4f99421914d8246517ca0146dce7e85f03a + languageName: node + linkType: hard + "signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" @@ -9473,6 +11667,20 @@ __metadata: languageName: node linkType: hard +"source-map@npm:^0.7.0": + version: 0.7.6 + resolution: "source-map@npm:0.7.6" + checksum: 10c0/59f6f05538539b274ba771d2e9e32f6c65451982510564438e048bc1352f019c6efcdc6dd07909b1968144941c14015c2c7d4369fb7c4d7d53ae769716dcc16c + languageName: node + linkType: hard + +"space-separated-tokens@npm:^2.0.0": + version: 2.0.2 + resolution: "space-separated-tokens@npm:2.0.2" + checksum: 10c0/6173e1d903dca41dcab6a2deed8b4caf61bd13b6d7af8374713500570aa929ff9414ae09a0519f4f8772df993300305a395d4871f35bc4ca72b6db57e1f30af8 + languageName: node + linkType: hard + "spawndamnit@npm:^3.0.1": version: 3.0.1 resolution: "spawndamnit@npm:3.0.1" @@ -9568,6 +11776,16 @@ __metadata: languageName: node linkType: hard +"stringify-entities@npm:^4.0.0": + version: 4.0.4 + resolution: "stringify-entities@npm:4.0.4" + dependencies: + character-entities-html4: "npm:^2.0.0" + character-entities-legacy: "npm:^3.0.0" + checksum: 10c0/537c7e656354192406bdd08157d759cd615724e9d0873602d2c9b2f6a5c0a8d0b1d73a0a08677848105c5eebac6db037b57c0b3a4ec86331117fa7319ed50448 + languageName: node + linkType: hard + "strip-ansi@npm:^5.2.0": version: 5.2.0 resolution: "strip-ansi@npm:5.2.0" @@ -9639,6 +11857,24 @@ __metadata: languageName: node linkType: hard +"style-to-js@npm:^1.0.0": + version: 1.1.21 + resolution: "style-to-js@npm:1.1.21" + dependencies: + style-to-object: "npm:1.0.14" + checksum: 10c0/94231aa80f58f442c3a5ae01a21d10701e5d62f96b4b3e52eab3499077ee52df203cc0df4a1a870707f5e99470859136ea8657b782a5f4ca7934e0ffe662a588 + languageName: node + linkType: hard + +"style-to-object@npm:1.0.14": + version: 1.0.14 + resolution: "style-to-object@npm:1.0.14" + dependencies: + inline-style-parser: "npm:0.2.7" + checksum: 10c0/854d9e9b77afc336e6d7b09348e7939f2617b34eb0895824b066d8cd1790284cb6d8b2ba36be88025b2595d715dba14b299ae76e4628a366541106f639e13679 + languageName: node + linkType: hard + "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -9797,6 +12033,13 @@ __metadata: languageName: node linkType: hard +"toggle-selection@npm:^1.0.6": + version: 1.0.6 + resolution: "toggle-selection@npm:1.0.6" + checksum: 10c0/f2cf1f2c70f374fd87b0cdc8007453ba9e981c4305a8bf4eac10a30e62ecdfd28bca7d18f8f15b15a506bf8a7bfb20dbe3539f0fcf2a2c8396c1a78d53e1f179 + languageName: node + linkType: hard + "toidentifier@npm:~1.0.1": version: 1.0.1 resolution: "toidentifier@npm:1.0.1" @@ -9818,6 +12061,27 @@ __metadata: languageName: node linkType: hard +"trim-lines@npm:^3.0.0": + version: 3.0.1 + resolution: "trim-lines@npm:3.0.1" + checksum: 10c0/3a1611fa9e52aa56a94c69951a9ea15b8aaad760eaa26c56a65330dc8adf99cb282fc07cc9d94968b7d4d88003beba220a7278bbe2063328eb23fb56f9509e94 + languageName: node + linkType: hard + +"trough@npm:^2.0.0": + version: 2.2.0 + resolution: "trough@npm:2.2.0" + checksum: 10c0/58b671fc970e7867a48514168894396dd94e6d9d6456aca427cc299c004fe67f35ed7172a36449086b2edde10e78a71a284ec0076809add6834fb8f857ccb9b0 + languageName: node + linkType: hard + +"tslib@npm:^2.4.0, tslib@npm:^2.8.0": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + "turbo@npm:^2.8.21": version: 2.9.16 resolution: "turbo@npm:2.9.16" @@ -9902,6 +12166,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~7.18.0": + version: 7.18.2 + resolution: "undici-types@npm:7.18.2" + checksum: 10c0/85a79189113a238959d7a647368e4f7c5559c3a404ebdb8fc4488145ce9426fcd82252a844a302798dfc0e37e6fb178ff481ed03bc4caf634c5757d9ef43521d + languageName: node + linkType: hard + "undici@npm:^6.25.0": version: 6.26.0 resolution: "undici@npm:6.26.0" @@ -9909,6 +12180,15 @@ __metadata: languageName: node linkType: hard +"unhead@npm:2.1.15": + version: 2.1.15 + resolution: "unhead@npm:2.1.15" + dependencies: + hookable: "npm:^6.0.1" + checksum: 10c0/ab266e9cda44d0b528ae3b62ce9136cb4f81bd2aa1e2d66431cefe6b41151a811971951e05b4d81e6adea105b65901d9091dffa29d646f1be6246691606b2407 + languageName: node + linkType: hard + "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.1 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.1" @@ -9947,6 +12227,98 @@ __metadata: languageName: node linkType: hard +"unified@npm:^11.0.0, unified@npm:^11.0.5": + version: 11.0.5 + resolution: "unified@npm:11.0.5" + dependencies: + "@types/unist": "npm:^3.0.0" + bail: "npm:^2.0.0" + devlop: "npm:^1.0.0" + extend: "npm:^3.0.0" + is-plain-obj: "npm:^4.0.0" + trough: "npm:^2.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/53c8e685f56d11d9d458a43e0e74328a4d6386af51c8ac37a3dcabec74ce5026da21250590d4aff6733ccd7dc203116aae2b0769abc18cdf9639a54ae528dfc9 + languageName: node + linkType: hard + +"unist-util-is@npm:^6.0.0": + version: 6.0.1 + resolution: "unist-util-is@npm:6.0.1" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/5a487d390193811d37a68264e204dbc7c15c40b8fc29b5515a535d921d071134f571d7b5cbd59bcd58d5ce1c0ab08f20fc4a1f0df2287a249c979267fc32ce06 + languageName: node + linkType: hard + +"unist-util-position-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "unist-util-position-from-estree@npm:2.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/39127bf5f0594e0a76d9241dec4f7aa26323517120ce1edd5ed91c8c1b9df7d6fb18af556e4b6250f1c7368825720ed892e2b6923be5cdc08a9bb16536dc37b3 + languageName: node + linkType: hard + +"unist-util-position@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-position@npm:5.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/dde3b31e314c98f12b4dc6402f9722b2bf35e96a4f2d463233dd90d7cde2d4928074a7a11eff0a5eb1f4e200f27fc1557e0a64a7e8e4da6558542f251b1b7400 + languageName: node + linkType: hard + +"unist-util-remove@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-remove@npm:4.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/30f3ed31095dd7f3109266d39c514fab5f2da3fb656d5f78a0e3e7700f219760f2f4d8286c810ae43c241fee3f0a8dd40f8d1e5ebeee3cb810581d5e7e8d4f7d + languageName: node + linkType: hard + +"unist-util-stringify-position@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-stringify-position@npm:4.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/dfe1dbe79ba31f589108cb35e523f14029b6675d741a79dea7e5f3d098785045d556d5650ec6a8338af11e9e78d2a30df12b1ee86529cded1098da3f17ee999e + languageName: node + linkType: hard + +"unist-util-visit-children@npm:^3.0.0": + version: 3.0.0 + resolution: "unist-util-visit-children@npm:3.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/51e95f54fbf11d414952c011c761c3960864948ad3fd2abe3989eb18b18d96b8f48e7ea5ab6f23264d1a3f4f5a1ff76312dd8f2196c78b762098403505c3abb9 + languageName: node + linkType: hard + +"unist-util-visit-parents@npm:^6.0.0": + version: 6.0.2 + resolution: "unist-util-visit-parents@npm:6.0.2" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + checksum: 10c0/f1e4019dbd930301825895e3737b1ee0cd682f7622ddd915062135cbb39f8c090aaece3a3b5eae1f2ea52ec33f0931abb8f8a8b5c48a511a4203e3d360a8cd49 + languageName: node + linkType: hard + +"unist-util-visit@npm:^5.0.0, unist-util-visit@npm:^5.1.0": + version: 5.1.0 + resolution: "unist-util-visit@npm:5.1.0" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/a56e1bbbf63fcb55abe379e660b9a3367787e8be1e2473bdb7e86cfa6f32b6c1fa0092432d7040b8a30b2fc674bbbe024ffe6d03c3d6bf4839b064f584463a4e + languageName: node + linkType: hard + "universalify@npm:^0.1.0": version: 0.1.2 resolution: "universalify@npm:0.1.2" @@ -10023,6 +12395,36 @@ __metadata: languageName: node linkType: hard +"vfile-location@npm:^5.0.0": + version: 5.0.3 + resolution: "vfile-location@npm:5.0.3" + dependencies: + "@types/unist": "npm:^3.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/1711f67802a5bc175ea69750d59863343ed43d1b1bb25c0a9063e4c70595e673e53e2ed5cdbb6dcdc370059b31605144d95e8c061b9361bcc2b036b8f63a4966 + languageName: node + linkType: hard + +"vfile-message@npm:^4.0.0": + version: 4.0.3 + resolution: "vfile-message@npm:4.0.3" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-stringify-position: "npm:^4.0.0" + checksum: 10c0/33d9f219610d27987689bb14fa5573d2daa146941d1a05416dd7702c4215b23f44ed81d059e70d0e4e24f9a57d5f4dc9f18d35a993f04cf9446a7abe6d72d0c0 + languageName: node + linkType: hard + +"vfile@npm:^6.0.0": + version: 6.0.3 + resolution: "vfile@npm:6.0.3" + dependencies: + "@types/unist": "npm:^3.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/e5d9eb4810623f23758cfc2205323e33552fb5972e5c2e6587babe08fe4d24859866277404fb9e2a20afb71013860d96ec806cb257536ae463c87d70022ab9ef + languageName: node + linkType: hard + "vlq@npm:^1.0.0": version: 1.0.1 resolution: "vlq@npm:1.0.1" @@ -10048,6 +12450,13 @@ __metadata: languageName: node linkType: hard +"web-namespaces@npm:^2.0.0": + version: 2.0.1 + resolution: "web-namespaces@npm:2.0.1" + checksum: 10c0/df245f466ad83bd5cd80bfffc1674c7f64b7b84d1de0e4d2c0934fb0782e0a599164e7197a4bce310ee3342fd61817b8047ff04f076a1ce12dd470584142a4bd + languageName: node + linkType: hard + "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" @@ -10290,3 +12699,10 @@ __metadata: checksum: 10c0/5718ec35e3c40b600316c5b4c5e4976f7fee68151bc8f8d90ec18a469be9571f072e1bbaace10f1e85cf8892ea12d90821b200e980ab46916a6166a4260a983c languageName: node linkType: hard + +"zwitch@npm:^2.0.0, zwitch@npm:^2.0.4": + version: 2.0.4 + resolution: "zwitch@npm:2.0.4" + checksum: 10c0/3c7830cdd3378667e058ffdb4cf2bb78ac5711214e2725900873accb23f3dfe5f9e7e5a06dcdc5f29605da976fc45c26d9a13ca334d6eea2245a15e77b8fc06e + languageName: node + linkType: hard From 3114049f02e84848b0ad2c91eb3eff612db6a81e Mon Sep 17 00:00:00 2001 From: harang Date: Fri, 26 Jun 2026 21:39:11 +0900 Subject: [PATCH 2/2] docs: keep Pressable examples runnable Wrap the button label in Text in both English and Korean programmatic action examples so copied React Native snippets do not render raw string children under Pressable. Constraint: React Native requires text strings to be rendered inside Text Rejected: Leave the inline Pressable example | copied snippet fails at runtime Confidence: high Scope-risk: narrow Tested: yarn workspace @react-native-motion-kit/swipe-deck-docs build Tested: yarn workspace @react-native-motion-kit/swipe-deck-docs typecheck Tested: yarn format; git diff --check --- docs/docs/1.x/en/guide/usage/programmatic-actions.mdx | 6 +++++- docs/docs/1.x/ko/guide/usage/programmatic-actions.mdx | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/docs/1.x/en/guide/usage/programmatic-actions.mdx b/docs/docs/1.x/en/guide/usage/programmatic-actions.mdx index 2c4285b..f84f0aa 100644 --- a/docs/docs/1.x/en/guide/usage/programmatic-actions.mdx +++ b/docs/docs/1.x/en/guide/usage/programmatic-actions.mdx @@ -7,7 +7,11 @@ external controls, or any app logic that should dismiss the active card. function LikeButton() { const { swipeRight } = ProfileDeck.useDeckActions(); - return Like; + return ( + + Like + + ); } ``` diff --git a/docs/docs/1.x/ko/guide/usage/programmatic-actions.mdx b/docs/docs/1.x/ko/guide/usage/programmatic-actions.mdx index bf9e297..d40abe1 100644 --- a/docs/docs/1.x/ko/guide/usage/programmatic-actions.mdx +++ b/docs/docs/1.x/ko/guide/usage/programmatic-actions.mdx @@ -7,7 +7,11 @@ active card를 dismiss할 때 사용하세요. function LikeButton() { const { swipeRight } = ProfileDeck.useDeckActions(); - return Like; + return ( + + Like + + ); } ```