Files
sofa/apps/native/src/components/ui/swipeable-row.tsx
T
jakeandClaude Opus 4.6 2b0c683b7b refactor: replace Biome with oxlint + oxfmt
Migrate the entire monorepo from Biome 2.4.7 to oxlint 1.56.0 (linter)
and oxfmt 0.41.0 (formatter) for faster lint/format and broader rule
coverage.

- Add `.oxlintrc.json` with React, TypeScript, unicorn, import plugins
  and correctness/suspicious categories
- Add `.oxfmtrc.json` with 2-space indent, import sorting, and Tailwind
  class sorting (all 30+ custom className attributes migrated)
- Add `docs/.oxlintrc.json` and `docs/.oxfmtrc.json` with Next.js plugin
- Update all 12 workspace package.json scripts: `oxlint`, `oxfmt`,
  `oxfmt --check`
- Add `format:check` turbo task and CI step
- Update VS Code settings/extensions to use `oxc.oxc-vscode`
- Update CI path triggers from `biome.json` to new config files
- Remove all `biome-ignore` comments and fix shadowed variables
- Delete `biome.json` and `docs/biome.json`
- Reformat entire codebase with oxfmt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:26:50 -04:00

62 lines
1.9 KiB
TypeScript

import { IconTrash } from "@tabler/icons-react-native";
import type { PropsWithChildren } from "react";
import { View } from "react-native";
import ReanimatedSwipeable from "react-native-gesture-handler/ReanimatedSwipeable";
import type { SharedValue } from "react-native-reanimated";
import Animated, { interpolate, useAnimatedStyle } from "react-native-reanimated";
import { ScaledIcon } from "@/components/ui/scaled-icon";
import * as Haptics from "@/utils/haptics";
const ACTION_WIDTH = 80;
function RightAction({ drag }: { drag: SharedValue<number> }) {
const animatedStyle = useAnimatedStyle(() => {
const scale = interpolate(drag.get(), [0, -ACTION_WIDTH], [0.6, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return { transform: [{ scale }] };
});
return (
<View className="bg-destructive items-center justify-center" style={{ width: ACTION_WIDTH }}>
<Animated.View style={animatedStyle}>
<ScaledIcon icon={IconTrash} size={22} color="#fff" />
</Animated.View>
</View>
);
}
interface SwipeableRowProps extends PropsWithChildren {
onDelete: () => void;
}
export function SwipeableRow({ onDelete, children }: SwipeableRowProps) {
return (
<View
accessibilityActions={[{ name: "delete", label: "Delete" }]}
onAccessibilityAction={(event) => {
if (event.nativeEvent.actionName === "delete") {
onDelete();
}
}}
>
<ReanimatedSwipeable
friction={2}
rightThreshold={40}
overshootRight={false}
renderRightActions={(_progress, drag) => <RightAction drag={drag} />}
onSwipeableOpen={(direction) => {
if (direction === "left") {
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
onDelete();
}
}}
>
{children}
</ReanimatedSwipeable>
</View>
);
}