swipe-row 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -121,6 +121,10 @@ function EmailList() {
121
121
  | `children` | `React.ReactNode` | **Required** | The main visible content of your row. |
122
122
  | `actions` | `SwipeAction[]` | **Required** | Array of action configurations to be revealed on swipe. |
123
123
  | `maxSwipe` | `number` | `undefined` | Override the automatic swipe width calculation (px). |
124
+ | `className` | `string` | `undefined` | Custom CSS class applied to the root container. |
125
+ | `style` | `React.CSSProperties` | `undefined` | Custom inline style applied to the root container. |
126
+ | `innerClassName` | `string` | `undefined` | Custom CSS class applied to the foreground swipeable element. |
127
+ | `innerStyle` | `React.CSSProperties` | `undefined` | Custom inline style applied to the foreground swipeable element. |
124
128
 
125
129
  ### `SwipeAction` Object
126
130
 
@@ -21,9 +21,17 @@ export type SwipeRowProps = {
21
21
  actions: SwipeAction[];
22
22
  /** Optional custom swipe threshold. Computed automatically if not provided. */
23
23
  maxSwipe?: number;
24
+ /** Custom className for the root container */
25
+ className?: string;
26
+ /** Custom inline style for the root container */
27
+ style?: React.CSSProperties;
28
+ /** Custom className for the foreground element */
29
+ innerClassName?: string;
30
+ /** Custom inline style for the foreground element */
31
+ innerStyle?: React.CSSProperties;
24
32
  };
25
33
  /**
26
34
  * SwipeRow creates an iOS style swipeable row element that reveals generic actions behind it.
27
35
  * Highly configurable and built for generic use across various projects.
28
36
  */
29
- export declare function SwipeRow({ children, actions, maxSwipe }: SwipeRowProps): import("react/jsx-runtime").JSX.Element;
37
+ export declare function SwipeRow({ children, actions, maxSwipe, className, style, innerClassName, innerStyle }: SwipeRowProps): import("react/jsx-runtime").JSX.Element;
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),e=require("framer-motion"),u=require("react"),b="_container_1y7jq_1",p="_actionsBackground_1y7jq_11",_="_actionButton_1y7jq_19",j="_foreground_1y7jq_35",s={container:b,actionsBackground:p,actionButton:_,foreground:j};function h({children:l,actions:c,maxSwipe:i}){const o=e.useMotionValue(0),d=u.useRef(null),g=u.useMemo(()=>-c.reduce((n,r)=>n+(r.width||80),0),[c]),t=i!==void 0?i:g,f=e.useTransform(o,[t/2,0],[1,0]),m=()=>{o.get()<t/2?e.animate(o,t,{type:"spring",bounce:0,duration:.3}):e.animate(o,0,{type:"spring",bounce:0,duration:.3})};return a.jsxs("div",{ref:d,className:s.container,children:[a.jsx(e.motion.div,{style:{opacity:f},className:s.actionsBackground,children:c.map((n,r)=>{const y=typeof n.label=="string"?n.label:`Action ${r}`;return a.jsx("button",{onClick:n.onClick,className:`${s.actionButton} ${n.className||""}`.trim(),style:{width:n.width||80,backgroundColor:n.backgroundColor||"#64748b",color:n.color||"white"},"aria-label":n.ariaLabel||y,children:n.label},r)})}),a.jsx(e.motion.div,{drag:"x",dragConstraints:{left:t,right:0},dragElastic:.1,style:{x:o},onDragEnd:m,className:s.foreground,children:l})]})}exports.SwipeRow=h;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),n=require("framer-motion"),u=require("react"),h="_container_1y7jq_1",k="_actionsBackground_1y7jq_11",w="_actionButton_1y7jq_19",B="_foreground_1y7jq_35",s={container:h,actionsBackground:k,actionButton:w,foreground:B};function q({children:l,actions:c,maxSwipe:i,className:d,style:g,innerClassName:m,innerStyle:f}){const e=n.useMotionValue(0),y=u.useRef(null),b=u.useMemo(()=>-c.reduce((t,r)=>t+(r.width||80),0),[c]),o=i!==void 0?i:b,p=n.useTransform(e,[o/2,0],[1,0]),_=()=>{e.get()<o/2?n.animate(e,o,{type:"spring",bounce:0,duration:.3}):n.animate(e,0,{type:"spring",bounce:0,duration:.3})};return a.jsxs("div",{ref:y,className:`${s.container} ${d||""}`.trim(),style:g,children:[a.jsx(n.motion.div,{style:{opacity:p},className:s.actionsBackground,children:c.map((t,r)=>{const j=typeof t.label=="string"?t.label:`Action ${r}`;return a.jsx("button",{onClick:t.onClick,className:`${s.actionButton} ${t.className||""}`.trim(),style:{width:t.width||80,backgroundColor:t.backgroundColor||"#64748b",color:t.color||"white"},"aria-label":t.ariaLabel||j,children:t.label},r)})}),a.jsx(n.motion.div,{drag:"x",dragConstraints:{left:o,right:0},dragElastic:.1,style:{x:e,...f},onDragEnd:_,className:`${s.foreground} ${m||""}`.trim(),children:l})]})}exports.SwipeRow=q;
2
2
  //# sourceMappingURL=swipe-row.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"swipe-row.cjs.js","sources":["../src/components/SwipeRow/SwipeRow.tsx"],"sourcesContent":["import { motion, useMotionValue, useTransform, animate } from 'framer-motion';\nimport { useRef, useMemo } from 'react';\nimport styles from './SwipeRow.module.css';\n\nexport type SwipeAction = {\n /** The visual content of the button (e.g. text or icon) */\n label: React.ReactNode;\n /** Callback triggered when this action is clicked */\n onClick: () => void;\n /** Background color for this action button */\n backgroundColor?: string;\n /** Text color for this action button */\n color?: string;\n /** Width of the button. Defaults to 80px */\n width?: number;\n /** Additional CSS class for the button */\n className?: string;\n /** Accessibility label. Defaults to label if it is a string a fallback string */\n ariaLabel?: string;\n};\n\nexport type SwipeRowProps = {\n /** The content to be displayed in the row */\n children: React.ReactNode;\n /** An array of action objects to render behind the row */\n actions: SwipeAction[];\n /** Optional custom swipe threshold. Computed automatically if not provided. */\n maxSwipe?: number;\n};\n\n/**\n * SwipeRow creates an iOS style swipeable row element that reveals generic actions behind it.\n * Highly configurable and built for generic use across various projects.\n */\nexport function SwipeRow({ children, actions, maxSwipe }: SwipeRowProps) {\n const x = useMotionValue(0);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const calculatedMaxSwipe = useMemo(() => {\n return -actions.reduce((acc, action) => acc + (action.width || 80), 0);\n }, [actions]);\n\n const swipeDistance = maxSwipe !== undefined ? maxSwipe : calculatedMaxSwipe;\n\n const backgroundOpacity = useTransform(x, [swipeDistance / 2, 0], [1, 0]);\n\n const handleDragEnd = () => {\n const current = x.get();\n\n // Swipe threshold to snap open\n if (current < swipeDistance / 2) {\n animate(x, swipeDistance, { type: 'spring', bounce: 0, duration: 0.3 });\n } else {\n animate(x, 0, { type: 'spring', bounce: 0, duration: 0.3 });\n }\n };\n\n return (\n <div ref={containerRef} className={styles.container}>\n {/* ACTIONS BACKGROUND */}\n <motion.div\n style={{ opacity: backgroundOpacity }}\n className={styles.actionsBackground}\n >\n {actions.map((action, index) => {\n const defaultAria = typeof action.label === 'string' ? action.label : `Action ${index}`;\n return (\n <button\n key={index}\n onClick={action.onClick}\n className={`${styles.actionButton} ${action.className || ''}`.trim()}\n style={{\n width: action.width || 80,\n backgroundColor: action.backgroundColor || '#64748b', // Slate\n color: action.color || 'white',\n }}\n aria-label={action.ariaLabel || defaultAria}\n >\n {action.label}\n </button>\n );\n })}\n </motion.div>\n\n {/* FOREGROUND */}\n <motion.div\n drag=\"x\"\n dragConstraints={{ left: swipeDistance, right: 0 }}\n dragElastic={0.1}\n style={{ x }}\n onDragEnd={handleDragEnd}\n className={styles.foreground}\n >\n {children}\n </motion.div>\n </div>\n );\n}\n"],"names":["SwipeRow","children","actions","maxSwipe","x","useMotionValue","containerRef","useRef","calculatedMaxSwipe","useMemo","acc","action","swipeDistance","backgroundOpacity","useTransform","handleDragEnd","animate","styles","jsx","motion","index","defaultAria"],"mappings":"8UAkCO,SAASA,EAAS,CAAE,SAAAC,EAAU,QAAAC,EAAS,SAAAC,GAA2B,CACvE,MAAMC,EAAIC,EAAAA,eAAe,CAAC,EACpBC,EAAeC,EAAAA,OAAuB,IAAI,EAE1CC,EAAqBC,EAAAA,QAAQ,IAC1B,CAACP,EAAQ,OAAO,CAACQ,EAAKC,IAAWD,GAAOC,EAAO,OAAS,IAAK,CAAC,EACpE,CAACT,CAAO,CAAC,EAENU,EAAgBT,IAAa,OAAYA,EAAWK,EAEpDK,EAAoBC,EAAAA,aAAaV,EAAG,CAACQ,EAAgB,EAAG,CAAC,EAAG,CAAC,EAAG,CAAC,CAAC,EAElEG,EAAgB,IAAM,CACVX,EAAE,IAAA,EAGJQ,EAAgB,EAC5BI,UAAQZ,EAAGQ,EAAe,CAAE,KAAM,SAAU,OAAQ,EAAG,SAAU,GAAK,EAEtEI,UAAQZ,EAAG,EAAG,CAAE,KAAM,SAAU,OAAQ,EAAG,SAAU,GAAK,CAE9D,EAEA,cACG,MAAA,CAAI,IAAKE,EAAc,UAAWW,EAAO,UAExC,SAAA,CAAAC,EAAAA,IAACC,EAAAA,OAAO,IAAP,CACC,MAAO,CAAE,QAASN,CAAA,EAClB,UAAWI,EAAO,kBAEjB,SAAAf,EAAQ,IAAI,CAACS,EAAQS,IAAU,CAC9B,MAAMC,EAAc,OAAOV,EAAO,OAAU,SAAWA,EAAO,MAAQ,UAAUS,CAAK,GACrF,OACEF,EAAAA,IAAC,SAAA,CAEC,QAASP,EAAO,QAChB,UAAW,GAAGM,EAAO,YAAY,IAAIN,EAAO,WAAa,EAAE,GAAG,KAAA,EAC9D,MAAO,CACL,MAAOA,EAAO,OAAS,GACvB,gBAAiBA,EAAO,iBAAmB,UAC3C,MAAOA,EAAO,OAAS,OAAA,EAEzB,aAAYA,EAAO,WAAaU,EAE/B,SAAAV,EAAO,KAAA,EAVHS,CAAA,CAaX,CAAC,CAAA,CAAA,EAIHF,EAAAA,IAACC,EAAAA,OAAO,IAAP,CACC,KAAK,IACL,gBAAiB,CAAE,KAAMP,EAAe,MAAO,CAAA,EAC/C,YAAa,GACb,MAAO,CAAE,EAAAR,CAAA,EACT,UAAWW,EACX,UAAWE,EAAO,WAEjB,SAAAhB,CAAA,CAAA,CACH,EACF,CAEJ"}
1
+ {"version":3,"file":"swipe-row.cjs.js","sources":["../src/components/SwipeRow/SwipeRow.tsx"],"sourcesContent":["import { motion, useMotionValue, useTransform, animate } from 'framer-motion';\nimport { useRef, useMemo } from 'react';\nimport styles from './SwipeRow.module.css';\n\nexport type SwipeAction = {\n /** The visual content of the button (e.g. text or icon) */\n label: React.ReactNode;\n /** Callback triggered when this action is clicked */\n onClick: () => void;\n /** Background color for this action button */\n backgroundColor?: string;\n /** Text color for this action button */\n color?: string;\n /** Width of the button. Defaults to 80px */\n width?: number;\n /** Additional CSS class for the button */\n className?: string;\n /** Accessibility label. Defaults to label if it is a string a fallback string */\n ariaLabel?: string;\n};\n\nexport type SwipeRowProps = {\n /** The content to be displayed in the row */\n children: React.ReactNode;\n /** An array of action objects to render behind the row */\n actions: SwipeAction[];\n /** Optional custom swipe threshold. Computed automatically if not provided. */\n maxSwipe?: number;\n /** Custom className for the root container */\n className?: string;\n /** Custom inline style for the root container */\n style?: React.CSSProperties;\n /** Custom className for the foreground element */\n innerClassName?: string;\n /** Custom inline style for the foreground element */\n innerStyle?: React.CSSProperties;\n};\n\n/**\n * SwipeRow creates an iOS style swipeable row element that reveals generic actions behind it.\n * Highly configurable and built for generic use across various projects.\n */\nexport function SwipeRow({ children, actions, maxSwipe, className, style, innerClassName, innerStyle }: SwipeRowProps) {\n const x = useMotionValue(0);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const calculatedMaxSwipe = useMemo(() => {\n return -actions.reduce((acc, action) => acc + (action.width || 80), 0);\n }, [actions]);\n\n const swipeDistance = maxSwipe !== undefined ? maxSwipe : calculatedMaxSwipe;\n\n const backgroundOpacity = useTransform(x, [swipeDistance / 2, 0], [1, 0]);\n\n const handleDragEnd = () => {\n const current = x.get();\n\n // Swipe threshold to snap open\n if (current < swipeDistance / 2) {\n animate(x, swipeDistance, { type: 'spring', bounce: 0, duration: 0.3 });\n } else {\n animate(x, 0, { type: 'spring', bounce: 0, duration: 0.3 });\n }\n };\n\n return (\n <div ref={containerRef} className={`${styles.container} ${className || ''}`.trim()} style={style}>\n {/* ACTIONS BACKGROUND */}\n <motion.div\n style={{ opacity: backgroundOpacity }}\n className={styles.actionsBackground}\n >\n {actions.map((action, index) => {\n const defaultAria = typeof action.label === 'string' ? action.label : `Action ${index}`;\n return (\n <button\n key={index}\n onClick={action.onClick}\n className={`${styles.actionButton} ${action.className || ''}`.trim()}\n style={{\n width: action.width || 80,\n backgroundColor: action.backgroundColor || '#64748b', // Slate\n color: action.color || 'white',\n }}\n aria-label={action.ariaLabel || defaultAria}\n >\n {action.label}\n </button>\n );\n })}\n </motion.div>\n\n {/* FOREGROUND */}\n <motion.div\n drag=\"x\"\n dragConstraints={{ left: swipeDistance, right: 0 }}\n dragElastic={0.1}\n style={{ x, ...innerStyle }}\n onDragEnd={handleDragEnd}\n className={`${styles.foreground} ${innerClassName || ''}`.trim()}\n >\n {children}\n </motion.div>\n </div>\n );\n}\n"],"names":["SwipeRow","children","actions","maxSwipe","className","style","innerClassName","innerStyle","x","useMotionValue","containerRef","useRef","calculatedMaxSwipe","useMemo","acc","action","swipeDistance","backgroundOpacity","useTransform","handleDragEnd","animate","jsxs","styles","jsx","motion","index","defaultAria"],"mappings":"8UA0CO,SAASA,EAAS,CAAE,SAAAC,EAAU,QAAAC,EAAS,SAAAC,EAAU,UAAAC,EAAW,MAAAC,EAAO,eAAAC,EAAgB,WAAAC,GAA6B,CACrH,MAAMC,EAAIC,EAAAA,eAAe,CAAC,EACpBC,EAAeC,EAAAA,OAAuB,IAAI,EAE1CC,EAAqBC,EAAAA,QAAQ,IAC1B,CAACX,EAAQ,OAAO,CAACY,EAAKC,IAAWD,GAAOC,EAAO,OAAS,IAAK,CAAC,EACpE,CAACb,CAAO,CAAC,EAENc,EAAgBb,IAAa,OAAYA,EAAWS,EAEpDK,EAAoBC,EAAAA,aAAaV,EAAG,CAACQ,EAAgB,EAAG,CAAC,EAAG,CAAC,EAAG,CAAC,CAAC,EAElEG,EAAgB,IAAM,CACVX,EAAE,IAAA,EAGJQ,EAAgB,EAC5BI,UAAQZ,EAAGQ,EAAe,CAAE,KAAM,SAAU,OAAQ,EAAG,SAAU,GAAK,EAEtEI,UAAQZ,EAAG,EAAG,CAAE,KAAM,SAAU,OAAQ,EAAG,SAAU,GAAK,CAE9D,EAEA,OACEa,EAAAA,KAAC,MAAA,CAAI,IAAKX,EAAc,UAAW,GAAGY,EAAO,SAAS,IAAIlB,GAAa,EAAE,GAAG,KAAA,EAAQ,MAAAC,EAElF,SAAA,CAAAkB,EAAAA,IAACC,EAAAA,OAAO,IAAP,CACC,MAAO,CAAE,QAASP,CAAA,EAClB,UAAWK,EAAO,kBAEjB,SAAApB,EAAQ,IAAI,CAACa,EAAQU,IAAU,CAC9B,MAAMC,EAAc,OAAOX,EAAO,OAAU,SAAWA,EAAO,MAAQ,UAAUU,CAAK,GACrF,OACEF,EAAAA,IAAC,SAAA,CAEC,QAASR,EAAO,QAChB,UAAW,GAAGO,EAAO,YAAY,IAAIP,EAAO,WAAa,EAAE,GAAG,KAAA,EAC9D,MAAO,CACL,MAAOA,EAAO,OAAS,GACvB,gBAAiBA,EAAO,iBAAmB,UAC3C,MAAOA,EAAO,OAAS,OAAA,EAEzB,aAAYA,EAAO,WAAaW,EAE/B,SAAAX,EAAO,KAAA,EAVHU,CAAA,CAaX,CAAC,CAAA,CAAA,EAIHF,EAAAA,IAACC,EAAAA,OAAO,IAAP,CACC,KAAK,IACL,gBAAiB,CAAE,KAAMR,EAAe,MAAO,CAAA,EAC/C,YAAa,GACb,MAAO,CAAE,EAAAR,EAAG,GAAGD,CAAA,EACf,UAAWY,EACX,UAAW,GAAGG,EAAO,UAAU,IAAIhB,GAAkB,EAAE,GAAG,KAAA,EAEzD,SAAAL,CAAA,CAAA,CACH,EACF,CAEJ"}
@@ -1,24 +1,24 @@
1
- import { jsxs as y, jsx as c } from "react/jsx-runtime";
2
- import { useMotionValue as b, useTransform as _, motion as i, animate as l } from "framer-motion";
3
- import { useRef as h, useMemo as k } from "react";
4
- const B = "_container_1y7jq_1", w = "_actionsBackground_1y7jq_11", j = "_actionButton_1y7jq_19", C = "_foreground_1y7jq_35", e = {
5
- container: B,
6
- actionsBackground: w,
7
- actionButton: j,
8
- foreground: C
1
+ import { jsxs as k, jsx as c } from "react/jsx-runtime";
2
+ import { useMotionValue as B, useTransform as w, motion as i, animate as l } from "framer-motion";
3
+ import { useRef as $, useMemo as j } from "react";
4
+ const C = "_container_1y7jq_1", N = "_actionsBackground_1y7jq_11", q = "_actionButton_1y7jq_19", v = "_foreground_1y7jq_35", e = {
5
+ container: C,
6
+ actionsBackground: N,
7
+ actionButton: q,
8
+ foreground: v
9
9
  };
10
- function x({ children: u, actions: a, maxSwipe: s }) {
11
- const n = b(0), d = h(null), g = k(() => -a.reduce((o, r) => o + (r.width || 80), 0), [a]), t = s !== void 0 ? s : g, f = _(n, [t / 2, 0], [1, 0]), m = () => {
10
+ function M({ children: u, actions: a, maxSwipe: s, className: d, style: g, innerClassName: m, innerStyle: f }) {
11
+ const n = B(0), p = $(null), y = j(() => -a.reduce((o, r) => o + (r.width || 80), 0), [a]), t = s !== void 0 ? s : y, b = w(n, [t / 2, 0], [1, 0]), _ = () => {
12
12
  n.get() < t / 2 ? l(n, t, { type: "spring", bounce: 0, duration: 0.3 }) : l(n, 0, { type: "spring", bounce: 0, duration: 0.3 });
13
13
  };
14
- return /* @__PURE__ */ y("div", { ref: d, className: e.container, children: [
14
+ return /* @__PURE__ */ k("div", { ref: p, className: `${e.container} ${d || ""}`.trim(), style: g, children: [
15
15
  /* @__PURE__ */ c(
16
16
  i.div,
17
17
  {
18
- style: { opacity: f },
18
+ style: { opacity: b },
19
19
  className: e.actionsBackground,
20
20
  children: a.map((o, r) => {
21
- const p = typeof o.label == "string" ? o.label : `Action ${r}`;
21
+ const h = typeof o.label == "string" ? o.label : `Action ${r}`;
22
22
  return /* @__PURE__ */ c(
23
23
  "button",
24
24
  {
@@ -30,7 +30,7 @@ function x({ children: u, actions: a, maxSwipe: s }) {
30
30
  // Slate
31
31
  color: o.color || "white"
32
32
  },
33
- "aria-label": o.ariaLabel || p,
33
+ "aria-label": o.ariaLabel || h,
34
34
  children: o.label
35
35
  },
36
36
  r
@@ -44,15 +44,15 @@ function x({ children: u, actions: a, maxSwipe: s }) {
44
44
  drag: "x",
45
45
  dragConstraints: { left: t, right: 0 },
46
46
  dragElastic: 0.1,
47
- style: { x: n },
48
- onDragEnd: m,
49
- className: e.foreground,
47
+ style: { x: n, ...f },
48
+ onDragEnd: _,
49
+ className: `${e.foreground} ${m || ""}`.trim(),
50
50
  children: u
51
51
  }
52
52
  )
53
53
  ] });
54
54
  }
55
55
  export {
56
- x as SwipeRow
56
+ M as SwipeRow
57
57
  };
58
58
  //# sourceMappingURL=swipe-row.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"swipe-row.es.js","sources":["../src/components/SwipeRow/SwipeRow.tsx"],"sourcesContent":["import { motion, useMotionValue, useTransform, animate } from 'framer-motion';\nimport { useRef, useMemo } from 'react';\nimport styles from './SwipeRow.module.css';\n\nexport type SwipeAction = {\n /** The visual content of the button (e.g. text or icon) */\n label: React.ReactNode;\n /** Callback triggered when this action is clicked */\n onClick: () => void;\n /** Background color for this action button */\n backgroundColor?: string;\n /** Text color for this action button */\n color?: string;\n /** Width of the button. Defaults to 80px */\n width?: number;\n /** Additional CSS class for the button */\n className?: string;\n /** Accessibility label. Defaults to label if it is a string a fallback string */\n ariaLabel?: string;\n};\n\nexport type SwipeRowProps = {\n /** The content to be displayed in the row */\n children: React.ReactNode;\n /** An array of action objects to render behind the row */\n actions: SwipeAction[];\n /** Optional custom swipe threshold. Computed automatically if not provided. */\n maxSwipe?: number;\n};\n\n/**\n * SwipeRow creates an iOS style swipeable row element that reveals generic actions behind it.\n * Highly configurable and built for generic use across various projects.\n */\nexport function SwipeRow({ children, actions, maxSwipe }: SwipeRowProps) {\n const x = useMotionValue(0);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const calculatedMaxSwipe = useMemo(() => {\n return -actions.reduce((acc, action) => acc + (action.width || 80), 0);\n }, [actions]);\n\n const swipeDistance = maxSwipe !== undefined ? maxSwipe : calculatedMaxSwipe;\n\n const backgroundOpacity = useTransform(x, [swipeDistance / 2, 0], [1, 0]);\n\n const handleDragEnd = () => {\n const current = x.get();\n\n // Swipe threshold to snap open\n if (current < swipeDistance / 2) {\n animate(x, swipeDistance, { type: 'spring', bounce: 0, duration: 0.3 });\n } else {\n animate(x, 0, { type: 'spring', bounce: 0, duration: 0.3 });\n }\n };\n\n return (\n <div ref={containerRef} className={styles.container}>\n {/* ACTIONS BACKGROUND */}\n <motion.div\n style={{ opacity: backgroundOpacity }}\n className={styles.actionsBackground}\n >\n {actions.map((action, index) => {\n const defaultAria = typeof action.label === 'string' ? action.label : `Action ${index}`;\n return (\n <button\n key={index}\n onClick={action.onClick}\n className={`${styles.actionButton} ${action.className || ''}`.trim()}\n style={{\n width: action.width || 80,\n backgroundColor: action.backgroundColor || '#64748b', // Slate\n color: action.color || 'white',\n }}\n aria-label={action.ariaLabel || defaultAria}\n >\n {action.label}\n </button>\n );\n })}\n </motion.div>\n\n {/* FOREGROUND */}\n <motion.div\n drag=\"x\"\n dragConstraints={{ left: swipeDistance, right: 0 }}\n dragElastic={0.1}\n style={{ x }}\n onDragEnd={handleDragEnd}\n className={styles.foreground}\n >\n {children}\n </motion.div>\n </div>\n );\n}\n"],"names":["SwipeRow","children","actions","maxSwipe","x","useMotionValue","containerRef","useRef","calculatedMaxSwipe","useMemo","acc","action","swipeDistance","backgroundOpacity","useTransform","handleDragEnd","animate","styles","jsx","motion","index","defaultAria"],"mappings":";;;;;;;;;AAkCO,SAASA,EAAS,EAAE,UAAAC,GAAU,SAAAC,GAAS,UAAAC,KAA2B;AACvE,QAAMC,IAAIC,EAAe,CAAC,GACpBC,IAAeC,EAAuB,IAAI,GAE1CC,IAAqBC,EAAQ,MAC1B,CAACP,EAAQ,OAAO,CAACQ,GAAKC,MAAWD,KAAOC,EAAO,SAAS,KAAK,CAAC,GACpE,CAACT,CAAO,CAAC,GAENU,IAAgBT,MAAa,SAAYA,IAAWK,GAEpDK,IAAoBC,EAAaV,GAAG,CAACQ,IAAgB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAElEG,IAAgB,MAAM;AAI1B,IAHgBX,EAAE,IAAA,IAGJQ,IAAgB,IAC5BI,EAAQZ,GAAGQ,GAAe,EAAE,MAAM,UAAU,QAAQ,GAAG,UAAU,KAAK,IAEtEI,EAAQZ,GAAG,GAAG,EAAE,MAAM,UAAU,QAAQ,GAAG,UAAU,KAAK;AAAA,EAE9D;AAEA,2BACG,OAAA,EAAI,KAAKE,GAAc,WAAWW,EAAO,WAExC,UAAA;AAAA,IAAA,gBAAAC;AAAA,MAACC,EAAO;AAAA,MAAP;AAAA,QACC,OAAO,EAAE,SAASN,EAAA;AAAA,QAClB,WAAWI,EAAO;AAAA,QAEjB,UAAAf,EAAQ,IAAI,CAACS,GAAQS,MAAU;AAC9B,gBAAMC,IAAc,OAAOV,EAAO,SAAU,WAAWA,EAAO,QAAQ,UAAUS,CAAK;AACrF,iBACE,gBAAAF;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,SAASP,EAAO;AAAA,cAChB,WAAW,GAAGM,EAAO,YAAY,IAAIN,EAAO,aAAa,EAAE,GAAG,KAAA;AAAA,cAC9D,OAAO;AAAA,gBACL,OAAOA,EAAO,SAAS;AAAA,gBACvB,iBAAiBA,EAAO,mBAAmB;AAAA;AAAA,gBAC3C,OAAOA,EAAO,SAAS;AAAA,cAAA;AAAA,cAEzB,cAAYA,EAAO,aAAaU;AAAA,cAE/B,UAAAV,EAAO;AAAA,YAAA;AAAA,YAVHS;AAAA,UAAA;AAAA,QAaX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,IAIH,gBAAAF;AAAA,MAACC,EAAO;AAAA,MAAP;AAAA,QACC,MAAK;AAAA,QACL,iBAAiB,EAAE,MAAMP,GAAe,OAAO,EAAA;AAAA,QAC/C,aAAa;AAAA,QACb,OAAO,EAAE,GAAAR,EAAA;AAAA,QACT,WAAWW;AAAA,QACX,WAAWE,EAAO;AAAA,QAEjB,UAAAhB;AAAA,MAAA;AAAA,IAAA;AAAA,EACH,GACF;AAEJ;"}
1
+ {"version":3,"file":"swipe-row.es.js","sources":["../src/components/SwipeRow/SwipeRow.tsx"],"sourcesContent":["import { motion, useMotionValue, useTransform, animate } from 'framer-motion';\nimport { useRef, useMemo } from 'react';\nimport styles from './SwipeRow.module.css';\n\nexport type SwipeAction = {\n /** The visual content of the button (e.g. text or icon) */\n label: React.ReactNode;\n /** Callback triggered when this action is clicked */\n onClick: () => void;\n /** Background color for this action button */\n backgroundColor?: string;\n /** Text color for this action button */\n color?: string;\n /** Width of the button. Defaults to 80px */\n width?: number;\n /** Additional CSS class for the button */\n className?: string;\n /** Accessibility label. Defaults to label if it is a string a fallback string */\n ariaLabel?: string;\n};\n\nexport type SwipeRowProps = {\n /** The content to be displayed in the row */\n children: React.ReactNode;\n /** An array of action objects to render behind the row */\n actions: SwipeAction[];\n /** Optional custom swipe threshold. Computed automatically if not provided. */\n maxSwipe?: number;\n /** Custom className for the root container */\n className?: string;\n /** Custom inline style for the root container */\n style?: React.CSSProperties;\n /** Custom className for the foreground element */\n innerClassName?: string;\n /** Custom inline style for the foreground element */\n innerStyle?: React.CSSProperties;\n};\n\n/**\n * SwipeRow creates an iOS style swipeable row element that reveals generic actions behind it.\n * Highly configurable and built for generic use across various projects.\n */\nexport function SwipeRow({ children, actions, maxSwipe, className, style, innerClassName, innerStyle }: SwipeRowProps) {\n const x = useMotionValue(0);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const calculatedMaxSwipe = useMemo(() => {\n return -actions.reduce((acc, action) => acc + (action.width || 80), 0);\n }, [actions]);\n\n const swipeDistance = maxSwipe !== undefined ? maxSwipe : calculatedMaxSwipe;\n\n const backgroundOpacity = useTransform(x, [swipeDistance / 2, 0], [1, 0]);\n\n const handleDragEnd = () => {\n const current = x.get();\n\n // Swipe threshold to snap open\n if (current < swipeDistance / 2) {\n animate(x, swipeDistance, { type: 'spring', bounce: 0, duration: 0.3 });\n } else {\n animate(x, 0, { type: 'spring', bounce: 0, duration: 0.3 });\n }\n };\n\n return (\n <div ref={containerRef} className={`${styles.container} ${className || ''}`.trim()} style={style}>\n {/* ACTIONS BACKGROUND */}\n <motion.div\n style={{ opacity: backgroundOpacity }}\n className={styles.actionsBackground}\n >\n {actions.map((action, index) => {\n const defaultAria = typeof action.label === 'string' ? action.label : `Action ${index}`;\n return (\n <button\n key={index}\n onClick={action.onClick}\n className={`${styles.actionButton} ${action.className || ''}`.trim()}\n style={{\n width: action.width || 80,\n backgroundColor: action.backgroundColor || '#64748b', // Slate\n color: action.color || 'white',\n }}\n aria-label={action.ariaLabel || defaultAria}\n >\n {action.label}\n </button>\n );\n })}\n </motion.div>\n\n {/* FOREGROUND */}\n <motion.div\n drag=\"x\"\n dragConstraints={{ left: swipeDistance, right: 0 }}\n dragElastic={0.1}\n style={{ x, ...innerStyle }}\n onDragEnd={handleDragEnd}\n className={`${styles.foreground} ${innerClassName || ''}`.trim()}\n >\n {children}\n </motion.div>\n </div>\n );\n}\n"],"names":["SwipeRow","children","actions","maxSwipe","className","style","innerClassName","innerStyle","x","useMotionValue","containerRef","useRef","calculatedMaxSwipe","useMemo","acc","action","swipeDistance","backgroundOpacity","useTransform","handleDragEnd","animate","jsxs","styles","jsx","motion","index","defaultAria"],"mappings":";;;;;;;;;AA0CO,SAASA,EAAS,EAAE,UAAAC,GAAU,SAAAC,GAAS,UAAAC,GAAU,WAAAC,GAAW,OAAAC,GAAO,gBAAAC,GAAgB,YAAAC,KAA6B;AACrH,QAAMC,IAAIC,EAAe,CAAC,GACpBC,IAAeC,EAAuB,IAAI,GAE1CC,IAAqBC,EAAQ,MAC1B,CAACX,EAAQ,OAAO,CAACY,GAAKC,MAAWD,KAAOC,EAAO,SAAS,KAAK,CAAC,GACpE,CAACb,CAAO,CAAC,GAENc,IAAgBb,MAAa,SAAYA,IAAWS,GAEpDK,IAAoBC,EAAaV,GAAG,CAACQ,IAAgB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAElEG,IAAgB,MAAM;AAI1B,IAHgBX,EAAE,IAAA,IAGJQ,IAAgB,IAC5BI,EAAQZ,GAAGQ,GAAe,EAAE,MAAM,UAAU,QAAQ,GAAG,UAAU,KAAK,IAEtEI,EAAQZ,GAAG,GAAG,EAAE,MAAM,UAAU,QAAQ,GAAG,UAAU,KAAK;AAAA,EAE9D;AAEA,SACE,gBAAAa,EAAC,OAAA,EAAI,KAAKX,GAAc,WAAW,GAAGY,EAAO,SAAS,IAAIlB,KAAa,EAAE,GAAG,KAAA,GAAQ,OAAAC,GAElF,UAAA;AAAA,IAAA,gBAAAkB;AAAA,MAACC,EAAO;AAAA,MAAP;AAAA,QACC,OAAO,EAAE,SAASP,EAAA;AAAA,QAClB,WAAWK,EAAO;AAAA,QAEjB,UAAApB,EAAQ,IAAI,CAACa,GAAQU,MAAU;AAC9B,gBAAMC,IAAc,OAAOX,EAAO,SAAU,WAAWA,EAAO,QAAQ,UAAUU,CAAK;AACrF,iBACE,gBAAAF;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,SAASR,EAAO;AAAA,cAChB,WAAW,GAAGO,EAAO,YAAY,IAAIP,EAAO,aAAa,EAAE,GAAG,KAAA;AAAA,cAC9D,OAAO;AAAA,gBACL,OAAOA,EAAO,SAAS;AAAA,gBACvB,iBAAiBA,EAAO,mBAAmB;AAAA;AAAA,gBAC3C,OAAOA,EAAO,SAAS;AAAA,cAAA;AAAA,cAEzB,cAAYA,EAAO,aAAaW;AAAA,cAE/B,UAAAX,EAAO;AAAA,YAAA;AAAA,YAVHU;AAAA,UAAA;AAAA,QAaX,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,IAIH,gBAAAF;AAAA,MAACC,EAAO;AAAA,MAAP;AAAA,QACC,MAAK;AAAA,QACL,iBAAiB,EAAE,MAAMR,GAAe,OAAO,EAAA;AAAA,QAC/C,aAAa;AAAA,QACb,OAAO,EAAE,GAAAR,GAAG,GAAGD,EAAA;AAAA,QACf,WAAWY;AAAA,QACX,WAAW,GAAGG,EAAO,UAAU,IAAIhB,KAAkB,EAAE,GAAG,KAAA;AAAA,QAEzD,UAAAL;AAAA,MAAA;AAAA,IAAA;AAAA,EACH,GACF;AAEJ;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swipe-row",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "A highly customizable, iOS-style swipeable row component for React applications.",
5
5
  "type": "module",
6
6
  "main": "./dist/swipe-row.cjs.js",