@kaushverse/pickify 1.1.9 → 1.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -151,9 +151,6 @@ type Props = {
151
151
  styles?: FloatingButtonStyles;
152
152
  style?: ViewStyle;
153
153
  mainIconName?: string;
154
- spacing?: number;
155
- offsetX?: number;
156
- offsetY?: number;
157
154
  };
158
155
  declare class FloatingButton extends React$1.Component<Props> {
159
156
  animation: Animated.Value;
package/dist/index.d.ts CHANGED
@@ -151,9 +151,6 @@ type Props = {
151
151
  styles?: FloatingButtonStyles;
152
152
  style?: ViewStyle;
153
153
  mainIconName?: string;
154
- spacing?: number;
155
- offsetX?: number;
156
- offsetY?: number;
157
154
  };
158
155
  declare class FloatingButton extends React$1.Component<Props> {
159
156
  animation: Animated.Value;
package/dist/index.js CHANGED
@@ -291,42 +291,46 @@ function MultiPickerGroup({
291
291
  renderGroupIcon,
292
292
  defaultOpen = false
293
293
  }) {
294
- const [open, setOpen] = (0, import_react2.useState)(false);
294
+ const [open, setOpen] = (0, import_react2.useState)(defaultOpen);
295
295
  const [contentHeight, setContentHeight] = (0, import_react2.useState)(0);
296
- const [isMounted, setIsMounted] = (0, import_react2.useState)(false);
296
+ const [isInitialized, setIsInitialized] = (0, import_react2.useState)(false);
297
297
  const animatedHeight = (0, import_react2.useRef)(new import_react_native2.Animated.Value(0)).current;
298
298
  const animationRef = (0, import_react2.useRef)(null);
299
299
  (0, import_react2.useEffect)(() => {
300
- setIsMounted(true);
301
- return () => {
302
- if (animationRef.current) {
303
- animationRef.current.stop();
300
+ if (contentHeight > 0 && !isInitialized) {
301
+ setIsInitialized(true);
302
+ if (defaultOpen) {
303
+ animatedHeight.setValue(contentHeight);
304
+ setOpen(true);
304
305
  }
305
- };
306
- }, []);
307
- (0, import_react2.useEffect)(() => {
308
- if (defaultOpen && contentHeight > 0 && !open) {
309
- animatedHeight.setValue(contentHeight);
310
- setOpen(true);
311
306
  }
312
- }, [defaultOpen, contentHeight]);
313
- const toggle = () => {
314
- if (contentHeight === 0) return;
307
+ }, [contentHeight, defaultOpen, animatedHeight, isInitialized]);
308
+ const toggle = (0, import_react2.useCallback)(() => {
315
309
  if (animationRef.current) {
316
310
  animationRef.current.stop();
317
311
  }
318
- const toValue = open ? 0 : contentHeight;
312
+ const newOpenState = !open;
313
+ const toValue = newOpenState ? contentHeight : 0;
319
314
  animationRef.current = import_react_native2.Animated.timing(animatedHeight, {
320
315
  toValue,
321
- duration: 200,
316
+ duration: 250,
322
317
  useNativeDriver: false
323
318
  });
324
319
  animationRef.current.start(() => {
325
- setOpen(!open);
320
+ setOpen(newOpenState);
326
321
  animationRef.current = null;
327
322
  });
328
- setOpen(!open);
329
- };
323
+ setOpen(newOpenState);
324
+ }, [open, contentHeight, animatedHeight]);
325
+ const handleLayout = (0, import_react2.useCallback)(
326
+ (event) => {
327
+ const height = event.nativeEvent.layout.height;
328
+ if (height > 0 && height !== contentHeight) {
329
+ setContentHeight(height);
330
+ }
331
+ },
332
+ [contentHeight]
333
+ );
330
334
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: styles.group, children: [
331
335
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
332
336
  import_react_native2.TouchableOpacity,
@@ -347,16 +351,9 @@ function MultiPickerGroup({
347
351
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
348
352
  import_react_native2.View,
349
353
  {
350
- style: styles.hidden,
354
+ style: styles.measureContainer,
355
+ onLayout: handleLayout,
351
356
  pointerEvents: "none",
352
- onLayout: (e) => {
353
- if (isMounted) {
354
- const height = e.nativeEvent.layout.height;
355
- if (height > 0 && height !== contentHeight) {
356
- setContentHeight(height);
357
- }
358
- }
359
- },
360
357
  children
361
358
  }
362
359
  ),
@@ -400,10 +397,10 @@ var styles = import_react_native2.StyleSheet.create({
400
397
  },
401
398
  content: {
402
399
  paddingTop: 8,
403
- paddingHorizontal: 12,
404
- paddingBottom: 4
400
+ paddingBottom: 4,
401
+ paddingHorizontal: 12
405
402
  },
406
- hidden: {
403
+ measureContainer: {
407
404
  position: "absolute",
408
405
  opacity: 0,
409
406
  zIndex: -1,
@@ -483,7 +480,6 @@ var defaultStyles2 = import_react_native3.StyleSheet.create({
483
480
 
484
481
  // src/core/MultiPickerModal.tsx
485
482
  var import_jsx_runtime4 = require("react/jsx-runtime");
486
- var { height: SCREEN_HEIGHT } = import_react_native4.Dimensions.get("window");
487
483
  function MultiPickerModal({
488
484
  visible,
489
485
  setVisible,
@@ -501,67 +497,36 @@ function MultiPickerModal({
501
497
  }) {
502
498
  const [internalVisible, setInternalVisible] = (0, import_react3.useState)(false);
503
499
  const [modalKey, setModalKey] = (0, import_react3.useState)(0);
504
- const slideAnim = (0, import_react3.useRef)(new import_react_native4.Animated.Value(SCREEN_HEIGHT)).current;
505
- const backdropAnim = (0, import_react3.useRef)(new import_react_native4.Animated.Value(0)).current;
506
- const isAnimating = (0, import_react3.useRef)(false);
500
+ const slideAnim = (0, import_react3.useRef)(new import_react_native4.Animated.Value(0)).current;
507
501
  const isControlled = visible !== void 0 && setVisible !== void 0;
508
502
  const isVisible = isControlled ? visible : internalVisible;
509
503
  (0, import_react3.useEffect)(() => {
510
504
  if (isVisible) {
511
505
  setModalKey((prev) => prev + 1);
512
- openModal();
506
+ import_react_native4.Animated.spring(slideAnim, {
507
+ toValue: 1,
508
+ useNativeDriver: true,
509
+ damping: 15,
510
+ mass: 0.8,
511
+ stiffness: 150
512
+ }).start();
513
513
  } else {
514
- closeModal();
515
- }
516
- }, [isVisible]);
517
- const openModal = () => {
518
- if (isAnimating.current) return;
519
- isAnimating.current = true;
520
- import_react_native4.Animated.parallel([
521
514
  import_react_native4.Animated.spring(slideAnim, {
522
515
  toValue: 0,
523
516
  useNativeDriver: true,
524
- damping: 20,
517
+ damping: 15,
525
518
  mass: 0.8,
526
- stiffness: 200
527
- }),
528
- import_react_native4.Animated.timing(backdropAnim, {
529
- toValue: 1,
530
- duration: 200,
531
- useNativeDriver: true
532
- })
533
- ]).start(() => {
534
- isAnimating.current = false;
535
- });
536
- };
537
- const closeModal = () => {
538
- if (isAnimating.current) return;
539
- isAnimating.current = true;
540
- import_react_native4.Animated.parallel([
541
- import_react_native4.Animated.timing(slideAnim, {
542
- toValue: SCREEN_HEIGHT,
543
- duration: 250,
544
- useNativeDriver: true
545
- }),
546
- import_react_native4.Animated.timing(backdropAnim, {
547
- toValue: 0,
548
- duration: 200,
549
- useNativeDriver: true
550
- })
551
- ]).start(() => {
552
- isAnimating.current = false;
553
- if (!isControlled) {
554
- setInternalVisible(false);
555
- }
556
- });
557
- };
519
+ stiffness: 150
520
+ }).start();
521
+ }
522
+ }, [isVisible]);
558
523
  const open = () => {
559
524
  if (isControlled) setVisible(true);
560
525
  else setInternalVisible(true);
561
526
  };
562
527
  const close = () => {
563
528
  if (isControlled) setVisible(false);
564
- else closeModal();
529
+ else setInternalVisible(false);
565
530
  };
566
531
  const handleSelect = (val) => {
567
532
  const updated = toggleValue(selectedValues, val);
@@ -572,19 +537,16 @@ function MultiPickerModal({
572
537
  const all = groups.length ? groups.flatMap((g) => g.data) : options;
573
538
  const selectedItems = all.filter((o) => selectedValues.includes(o.value)).map((o) => o.label);
574
539
  if (selectedItems.length === 0) return placeholder;
575
- if (selectedItems.length > 2) {
576
- return `${selectedItems.slice(0, 2).join(", ")} +${selectedItems.length - 2}`;
577
- }
578
540
  return selectedItems.join(", ");
579
541
  };
580
542
  const renderList = () => {
581
543
  if (groups.length > 0) {
582
- return groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
544
+ return groups.map((group, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
583
545
  MultiPickerGroup,
584
546
  {
585
547
  label: group.label,
586
548
  renderGroupIcon,
587
- defaultOpen: false,
549
+ defaultOpen: index === 0,
588
550
  children: group.data.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
589
551
  MultiPickerItem,
590
552
  {
@@ -612,14 +574,15 @@ function MultiPickerModal({
612
574
  item.value
613
575
  ));
614
576
  };
615
- const backdropStyle = {
616
- backgroundColor: backdropAnim.interpolate({
617
- inputRange: [0, 1],
618
- outputRange: ["rgba(0,0,0,0)", "rgba(0,0,0,0.5)"]
619
- })
620
- };
621
- const modalStyle = {
622
- transform: [{ translateY: slideAnim }]
577
+ const modalAnimatedStyle = {
578
+ transform: [
579
+ {
580
+ translateY: slideAnim.interpolate({
581
+ inputRange: [0, 1],
582
+ outputRange: [600, 0]
583
+ })
584
+ }
585
+ ]
623
586
  };
624
587
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
625
588
  label && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.label, styles2?.label], children: label }),
@@ -644,7 +607,7 @@ function MultiPickerModal({
644
607
  ),
645
608
  renderInputIcon?.({
646
609
  name: "chevron-down",
647
- size: 20,
610
+ size: 18,
648
611
  color: "#6B7280"
649
612
  })
650
613
  ]
@@ -658,45 +621,35 @@ function MultiPickerModal({
658
621
  transparent: true,
659
622
  animationType: "none",
660
623
  onRequestClose: close,
661
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.Animated.View, { style: [defaultStyles3.overlay, backdropStyle], children: [
662
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
663
- import_react_native4.TouchableOpacity,
664
- {
665
- style: defaultStyles3.backdropTouchable,
666
- activeOpacity: 1,
667
- onPress: close
668
- }
669
- ),
670
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
671
- import_react_native4.Animated.View,
672
- {
673
- style: [defaultStyles3.container, styles2?.container, modalStyle],
674
- children: [
675
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: defaultStyles3.header, children: [
676
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: defaultStyles3.handle }),
677
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: defaultStyles3.headerTitle, children: "Select Options" }),
678
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
679
- import_react_native4.TouchableOpacity,
680
- {
681
- onPress: close,
682
- style: defaultStyles3.doneBtn,
683
- activeOpacity: 0.7,
684
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: defaultStyles3.doneText, children: "Done" })
685
- }
686
- )
687
- ] }),
688
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
689
- import_react_native4.ScrollView,
690
- {
691
- showsVerticalScrollIndicator: false,
692
- contentContainerStyle: defaultStyles3.scrollContent,
693
- children: renderList()
694
- }
695
- )
696
- ]
697
- }
698
- )
699
- ] })
624
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: [defaultStyles3.overlay, styles2?.overlay], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
625
+ import_react_native4.Animated.View,
626
+ {
627
+ style: [
628
+ defaultStyles3.container,
629
+ styles2?.container,
630
+ modalAnimatedStyle
631
+ ],
632
+ children: [
633
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
634
+ import_react_native4.TouchableOpacity,
635
+ {
636
+ onPress: close,
637
+ style: [defaultStyles3.done, styles2?.doneBtn],
638
+ activeOpacity: 0.7,
639
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.doneText, styles2?.doneText], children: "Done" })
640
+ }
641
+ ),
642
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
643
+ import_react_native4.ScrollView,
644
+ {
645
+ showsVerticalScrollIndicator: false,
646
+ contentContainerStyle: defaultStyles3.scrollContent,
647
+ children: renderList()
648
+ }
649
+ )
650
+ ]
651
+ }
652
+ ) })
700
653
  }
701
654
  )
702
655
  ] });
@@ -733,71 +686,34 @@ var defaultStyles3 = import_react_native4.StyleSheet.create({
733
686
  },
734
687
  overlay: {
735
688
  flex: 1,
736
- justifyContent: "flex-end"
737
- },
738
- backdropTouchable: {
739
- position: "absolute",
740
- top: 0,
741
- left: 0,
742
- right: 0,
743
- bottom: 0
689
+ justifyContent: "flex-end",
690
+ backgroundColor: "rgba(0,0,0,0.4)"
744
691
  },
745
692
  container: {
746
- backgroundColor: "#FFFFFF",
693
+ backgroundColor: "#fff",
694
+ padding: 20,
747
695
  borderTopLeftRadius: 20,
748
696
  borderTopRightRadius: 20,
749
697
  maxHeight: "70%",
750
- minHeight: "40%",
751
- shadowColor: "#000",
752
- shadowOffset: {
753
- width: 0,
754
- height: -2
755
- },
756
- shadowOpacity: 0.1,
757
- shadowRadius: 4,
758
- elevation: 5
759
- },
760
- header: {
761
- flexDirection: "row",
762
- justifyContent: "space-between",
763
- alignItems: "center",
764
- paddingHorizontal: 20,
765
- paddingTop: 12,
766
- paddingBottom: 16,
767
- borderBottomWidth: 1,
768
- borderBottomColor: "#F0F0F0"
769
- },
770
- handle: {
771
- width: 40,
772
- height: 4,
773
- backgroundColor: "#E5E7EB",
774
- borderRadius: 2,
775
- position: "absolute",
776
- top: 8,
777
- alignSelf: "center"
698
+ minHeight: "40%"
778
699
  },
779
- headerTitle: {
780
- fontSize: 16,
781
- fontWeight: "600",
782
- color: "#1F2937",
783
- flex: 1,
784
- textAlign: "center"
700
+ scrollContent: {
701
+ paddingBottom: 20
785
702
  },
786
- doneBtn: {
787
- paddingVertical: 6,
788
- paddingHorizontal: 12,
703
+ done: {
789
704
  backgroundColor: "#6366f1",
790
- borderRadius: 8
705
+ paddingVertical: 10,
706
+ paddingHorizontal: 14,
707
+ borderRadius: 10,
708
+ alignSelf: "flex-end",
709
+ marginBottom: 16,
710
+ minWidth: 80,
711
+ alignItems: "center"
791
712
  },
792
713
  doneText: {
793
- color: "#FFFFFF",
714
+ color: "#fff",
794
715
  fontWeight: "600",
795
716
  fontSize: 14
796
- },
797
- scrollContent: {
798
- paddingHorizontal: 20,
799
- paddingTop: 12,
800
- paddingBottom: 24
801
717
  }
802
718
  });
803
719
 
@@ -805,7 +721,6 @@ var defaultStyles3 = import_react_native4.StyleSheet.create({
805
721
  var import_react4 = __toESM(require("react"));
806
722
  var import_react_native5 = require("react-native");
807
723
  var import_jsx_runtime5 = require("react/jsx-runtime");
808
- var { width: SCREEN_WIDTH, height: SCREEN_HEIGHT2 } = import_react_native5.Dimensions.get("window");
809
724
  var FloatingButton = class extends import_react4.default.Component {
810
725
  animation = new import_react_native5.Animated.Value(0);
811
726
  open = false;
@@ -813,8 +728,8 @@ var FloatingButton = class extends import_react4.default.Component {
813
728
  import_react_native5.Animated.spring(this.animation, {
814
729
  toValue: this.open ? 0 : 1,
815
730
  useNativeDriver: true,
816
- damping: 15,
817
- mass: 0.8,
731
+ damping: 12,
732
+ mass: 0.6,
818
733
  stiffness: 180
819
734
  }).start();
820
735
  this.open = !this.open;
@@ -825,28 +740,26 @@ var FloatingButton = class extends import_react4.default.Component {
825
740
  radius = 100,
826
741
  actions,
827
742
  renderItemIcon,
828
- styles: styles2,
829
- spacing = 75
830
- // Default spacing between buttons
743
+ styles: styles2
831
744
  } = this.props;
832
745
  let translateX = 0;
833
746
  let translateY = 0;
834
747
  if (mode === "vertical") {
835
- translateY = -spacing * (index + 1);
748
+ translateY = -70 * (index + 1);
836
749
  translateX = 0;
837
750
  }
838
751
  if (mode === "horizontal") {
839
- translateX = -spacing * (index + 1);
752
+ translateX = -70 * (index + 1);
840
753
  translateY = 0;
841
754
  }
842
755
  if (mode === "circle") {
843
756
  const totalActions = actions.length;
844
- const startAngle = Math.PI * 0.85;
845
- const endAngle = Math.PI * 0.15;
846
- const angle = startAngle - index / (totalActions - 1 || 1) * (startAngle - endAngle);
847
- const adjustedRadius = radius;
848
- translateX = -adjustedRadius * Math.cos(angle);
849
- translateY = -adjustedRadius * Math.sin(angle);
757
+ const startAngle = -Math.PI / 3;
758
+ const endAngle = -Math.PI * 0.8;
759
+ const angle = startAngle + index / (totalActions - 1 || 1) * (endAngle - startAngle);
760
+ const adjustedRadius = radius * 0.65;
761
+ translateX = adjustedRadius * Math.cos(angle);
762
+ translateY = adjustedRadius * Math.sin(angle);
850
763
  }
851
764
  const animStyle = {
852
765
  transform: [
@@ -900,15 +813,7 @@ var FloatingButton = class extends import_react4.default.Component {
900
813
  );
901
814
  };
902
815
  render() {
903
- const {
904
- renderMainIcon,
905
- styles: styles2,
906
- style,
907
- mainIconName,
908
- mode = "vertical",
909
- offsetX = 24,
910
- offsetY = 100
911
- } = this.props;
816
+ const { actions, renderMainIcon, styles: styles2, style, mainIconName } = this.props;
912
817
  const rotation = {
913
818
  transform: [
914
819
  {
@@ -930,26 +835,32 @@ var FloatingButton = class extends import_react4.default.Component {
930
835
  ]
931
836
  };
932
837
  const mainIcon = mainIconName || "add";
933
- const containerStyle = [
934
- defaultStyles4.container,
935
- styles2?.container,
936
- style,
937
- {
938
- bottom: offsetY,
939
- right: offsetX
940
- }
941
- ];
942
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: containerStyle, children: [
943
- this.props.actions.map(this.renderAction),
944
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.TouchableWithoutFeedback, { onPress: this.toggleMenu, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
838
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [defaultStyles4.container, styles2?.container, style], children: [
839
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
945
840
  import_react_native5.Animated.View,
946
841
  {
947
842
  style: [
948
- defaultStyles4.mainButtonWrapper,
949
- styles2?.mainButton,
950
- rotation,
951
- scale
843
+ defaultStyles4.circleContainer,
844
+ styles2?.circleContainer,
845
+ {
846
+ transform: [
847
+ {
848
+ scale: this.animation.interpolate({
849
+ inputRange: [0, 1],
850
+ outputRange: [0, 1]
851
+ })
852
+ }
853
+ ],
854
+ opacity: this.animation
855
+ }
952
856
  ],
857
+ children: actions.map(this.renderAction)
858
+ }
859
+ ),
860
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.TouchableWithoutFeedback, { onPress: this.toggleMenu, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
861
+ import_react_native5.Animated.View,
862
+ {
863
+ style: [defaultStyles4.mainButtonWrapper, rotation, scale],
953
864
  children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: [defaultStyles4.button, styles2?.mainButton], children: renderMainIcon?.({
954
865
  name: mainIcon,
955
866
  size: 26,
@@ -963,34 +874,44 @@ var FloatingButton = class extends import_react4.default.Component {
963
874
  var defaultStyles4 = import_react_native5.StyleSheet.create({
964
875
  container: {
965
876
  position: "absolute",
877
+ bottom: 100,
878
+ right: 20,
966
879
  alignItems: "center",
967
- justifyContent: "center",
968
- zIndex: 1e3
880
+ justifyContent: "center"
969
881
  },
970
882
  mainButtonWrapper: {
971
- width: 56,
972
- height: 56,
973
- borderRadius: 28,
883
+ width: 60,
884
+ height: 60,
885
+ borderRadius: 30,
974
886
  backgroundColor: "#F02A4B",
975
887
  alignItems: "center",
976
888
  justifyContent: "center",
977
889
  shadowColor: "#000",
978
890
  shadowOffset: {
979
891
  width: 0,
980
- height: 4
892
+ height: 2
981
893
  },
982
- shadowOpacity: 0.3,
983
- shadowRadius: 4.65,
984
- elevation: 8
894
+ shadowOpacity: 0.25,
895
+ shadowRadius: 3.84,
896
+ elevation: 5
985
897
  },
986
898
  button: {
987
- width: 56,
988
- height: 56,
989
- borderRadius: 28,
899
+ width: 60,
900
+ height: 60,
901
+ borderRadius: 30,
990
902
  backgroundColor: "#F02A4B",
991
903
  alignItems: "center",
992
904
  justifyContent: "center"
993
905
  },
906
+ circleContainer: {
907
+ position: "absolute",
908
+ width: 200,
909
+ height: 200,
910
+ right: -70,
911
+ bottom: -70,
912
+ alignItems: "center",
913
+ justifyContent: "center"
914
+ },
994
915
  secondary: {
995
916
  position: "absolute",
996
917
  width: 48,
package/dist/index.mjs CHANGED
@@ -246,8 +246,7 @@ import {
246
246
  TouchableOpacity as TouchableOpacity4,
247
247
  StyleSheet as StyleSheet4,
248
248
  ScrollView as ScrollView2,
249
- Animated as Animated2,
250
- Dimensions
249
+ Animated as Animated2
251
250
  } from "react-native";
252
251
 
253
252
  // src/utils/toggleValue.ts
@@ -256,7 +255,7 @@ var toggleValue = (arr, value) => {
256
255
  };
257
256
 
258
257
  // src/components/MultiPickerGroup.tsx
259
- import { useRef, useState as useState2, useEffect as useEffect2 } from "react";
258
+ import { useRef, useState as useState2, useEffect as useEffect2, useCallback } from "react";
260
259
  import {
261
260
  View as View2,
262
261
  Text as Text2,
@@ -271,42 +270,46 @@ function MultiPickerGroup({
271
270
  renderGroupIcon,
272
271
  defaultOpen = false
273
272
  }) {
274
- const [open, setOpen] = useState2(false);
273
+ const [open, setOpen] = useState2(defaultOpen);
275
274
  const [contentHeight, setContentHeight] = useState2(0);
276
- const [isMounted, setIsMounted] = useState2(false);
275
+ const [isInitialized, setIsInitialized] = useState2(false);
277
276
  const animatedHeight = useRef(new Animated.Value(0)).current;
278
277
  const animationRef = useRef(null);
279
278
  useEffect2(() => {
280
- setIsMounted(true);
281
- return () => {
282
- if (animationRef.current) {
283
- animationRef.current.stop();
279
+ if (contentHeight > 0 && !isInitialized) {
280
+ setIsInitialized(true);
281
+ if (defaultOpen) {
282
+ animatedHeight.setValue(contentHeight);
283
+ setOpen(true);
284
284
  }
285
- };
286
- }, []);
287
- useEffect2(() => {
288
- if (defaultOpen && contentHeight > 0 && !open) {
289
- animatedHeight.setValue(contentHeight);
290
- setOpen(true);
291
285
  }
292
- }, [defaultOpen, contentHeight]);
293
- const toggle = () => {
294
- if (contentHeight === 0) return;
286
+ }, [contentHeight, defaultOpen, animatedHeight, isInitialized]);
287
+ const toggle = useCallback(() => {
295
288
  if (animationRef.current) {
296
289
  animationRef.current.stop();
297
290
  }
298
- const toValue = open ? 0 : contentHeight;
291
+ const newOpenState = !open;
292
+ const toValue = newOpenState ? contentHeight : 0;
299
293
  animationRef.current = Animated.timing(animatedHeight, {
300
294
  toValue,
301
- duration: 200,
295
+ duration: 250,
302
296
  useNativeDriver: false
303
297
  });
304
298
  animationRef.current.start(() => {
305
- setOpen(!open);
299
+ setOpen(newOpenState);
306
300
  animationRef.current = null;
307
301
  });
308
- setOpen(!open);
309
- };
302
+ setOpen(newOpenState);
303
+ }, [open, contentHeight, animatedHeight]);
304
+ const handleLayout = useCallback(
305
+ (event) => {
306
+ const height = event.nativeEvent.layout.height;
307
+ if (height > 0 && height !== contentHeight) {
308
+ setContentHeight(height);
309
+ }
310
+ },
311
+ [contentHeight]
312
+ );
310
313
  return /* @__PURE__ */ jsxs2(View2, { style: styles.group, children: [
311
314
  /* @__PURE__ */ jsxs2(
312
315
  TouchableOpacity2,
@@ -327,16 +330,9 @@ function MultiPickerGroup({
327
330
  /* @__PURE__ */ jsx2(
328
331
  View2,
329
332
  {
330
- style: styles.hidden,
333
+ style: styles.measureContainer,
334
+ onLayout: handleLayout,
331
335
  pointerEvents: "none",
332
- onLayout: (e) => {
333
- if (isMounted) {
334
- const height = e.nativeEvent.layout.height;
335
- if (height > 0 && height !== contentHeight) {
336
- setContentHeight(height);
337
- }
338
- }
339
- },
340
336
  children
341
337
  }
342
338
  ),
@@ -380,10 +376,10 @@ var styles = StyleSheet2.create({
380
376
  },
381
377
  content: {
382
378
  paddingTop: 8,
383
- paddingHorizontal: 12,
384
- paddingBottom: 4
379
+ paddingBottom: 4,
380
+ paddingHorizontal: 12
385
381
  },
386
- hidden: {
382
+ measureContainer: {
387
383
  position: "absolute",
388
384
  opacity: 0,
389
385
  zIndex: -1,
@@ -463,7 +459,6 @@ var defaultStyles2 = StyleSheet3.create({
463
459
 
464
460
  // src/core/MultiPickerModal.tsx
465
461
  import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
466
- var { height: SCREEN_HEIGHT } = Dimensions.get("window");
467
462
  function MultiPickerModal({
468
463
  visible,
469
464
  setVisible,
@@ -481,67 +476,36 @@ function MultiPickerModal({
481
476
  }) {
482
477
  const [internalVisible, setInternalVisible] = useState3(false);
483
478
  const [modalKey, setModalKey] = useState3(0);
484
- const slideAnim = useRef2(new Animated2.Value(SCREEN_HEIGHT)).current;
485
- const backdropAnim = useRef2(new Animated2.Value(0)).current;
486
- const isAnimating = useRef2(false);
479
+ const slideAnim = useRef2(new Animated2.Value(0)).current;
487
480
  const isControlled = visible !== void 0 && setVisible !== void 0;
488
481
  const isVisible = isControlled ? visible : internalVisible;
489
482
  useEffect3(() => {
490
483
  if (isVisible) {
491
484
  setModalKey((prev) => prev + 1);
492
- openModal();
485
+ Animated2.spring(slideAnim, {
486
+ toValue: 1,
487
+ useNativeDriver: true,
488
+ damping: 15,
489
+ mass: 0.8,
490
+ stiffness: 150
491
+ }).start();
493
492
  } else {
494
- closeModal();
495
- }
496
- }, [isVisible]);
497
- const openModal = () => {
498
- if (isAnimating.current) return;
499
- isAnimating.current = true;
500
- Animated2.parallel([
501
493
  Animated2.spring(slideAnim, {
502
494
  toValue: 0,
503
495
  useNativeDriver: true,
504
- damping: 20,
496
+ damping: 15,
505
497
  mass: 0.8,
506
- stiffness: 200
507
- }),
508
- Animated2.timing(backdropAnim, {
509
- toValue: 1,
510
- duration: 200,
511
- useNativeDriver: true
512
- })
513
- ]).start(() => {
514
- isAnimating.current = false;
515
- });
516
- };
517
- const closeModal = () => {
518
- if (isAnimating.current) return;
519
- isAnimating.current = true;
520
- Animated2.parallel([
521
- Animated2.timing(slideAnim, {
522
- toValue: SCREEN_HEIGHT,
523
- duration: 250,
524
- useNativeDriver: true
525
- }),
526
- Animated2.timing(backdropAnim, {
527
- toValue: 0,
528
- duration: 200,
529
- useNativeDriver: true
530
- })
531
- ]).start(() => {
532
- isAnimating.current = false;
533
- if (!isControlled) {
534
- setInternalVisible(false);
535
- }
536
- });
537
- };
498
+ stiffness: 150
499
+ }).start();
500
+ }
501
+ }, [isVisible]);
538
502
  const open = () => {
539
503
  if (isControlled) setVisible(true);
540
504
  else setInternalVisible(true);
541
505
  };
542
506
  const close = () => {
543
507
  if (isControlled) setVisible(false);
544
- else closeModal();
508
+ else setInternalVisible(false);
545
509
  };
546
510
  const handleSelect = (val) => {
547
511
  const updated = toggleValue(selectedValues, val);
@@ -552,19 +516,16 @@ function MultiPickerModal({
552
516
  const all = groups.length ? groups.flatMap((g) => g.data) : options;
553
517
  const selectedItems = all.filter((o) => selectedValues.includes(o.value)).map((o) => o.label);
554
518
  if (selectedItems.length === 0) return placeholder;
555
- if (selectedItems.length > 2) {
556
- return `${selectedItems.slice(0, 2).join(", ")} +${selectedItems.length - 2}`;
557
- }
558
519
  return selectedItems.join(", ");
559
520
  };
560
521
  const renderList = () => {
561
522
  if (groups.length > 0) {
562
- return groups.map((group) => /* @__PURE__ */ jsx4(
523
+ return groups.map((group, index) => /* @__PURE__ */ jsx4(
563
524
  MultiPickerGroup,
564
525
  {
565
526
  label: group.label,
566
527
  renderGroupIcon,
567
- defaultOpen: false,
528
+ defaultOpen: index === 0,
568
529
  children: group.data.map((item) => /* @__PURE__ */ jsx4(
569
530
  MultiPickerItem,
570
531
  {
@@ -592,14 +553,15 @@ function MultiPickerModal({
592
553
  item.value
593
554
  ));
594
555
  };
595
- const backdropStyle = {
596
- backgroundColor: backdropAnim.interpolate({
597
- inputRange: [0, 1],
598
- outputRange: ["rgba(0,0,0,0)", "rgba(0,0,0,0.5)"]
599
- })
600
- };
601
- const modalStyle = {
602
- transform: [{ translateY: slideAnim }]
556
+ const modalAnimatedStyle = {
557
+ transform: [
558
+ {
559
+ translateY: slideAnim.interpolate({
560
+ inputRange: [0, 1],
561
+ outputRange: [600, 0]
562
+ })
563
+ }
564
+ ]
603
565
  };
604
566
  return /* @__PURE__ */ jsxs4(Fragment2, { children: [
605
567
  label && /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.label, styles2?.label], children: label }),
@@ -624,7 +586,7 @@ function MultiPickerModal({
624
586
  ),
625
587
  renderInputIcon?.({
626
588
  name: "chevron-down",
627
- size: 20,
589
+ size: 18,
628
590
  color: "#6B7280"
629
591
  })
630
592
  ]
@@ -638,45 +600,35 @@ function MultiPickerModal({
638
600
  transparent: true,
639
601
  animationType: "none",
640
602
  onRequestClose: close,
641
- children: /* @__PURE__ */ jsxs4(Animated2.View, { style: [defaultStyles3.overlay, backdropStyle], children: [
642
- /* @__PURE__ */ jsx4(
643
- TouchableOpacity4,
644
- {
645
- style: defaultStyles3.backdropTouchable,
646
- activeOpacity: 1,
647
- onPress: close
648
- }
649
- ),
650
- /* @__PURE__ */ jsxs4(
651
- Animated2.View,
652
- {
653
- style: [defaultStyles3.container, styles2?.container, modalStyle],
654
- children: [
655
- /* @__PURE__ */ jsxs4(View4, { style: defaultStyles3.header, children: [
656
- /* @__PURE__ */ jsx4(View4, { style: defaultStyles3.handle }),
657
- /* @__PURE__ */ jsx4(Text4, { style: defaultStyles3.headerTitle, children: "Select Options" }),
658
- /* @__PURE__ */ jsx4(
659
- TouchableOpacity4,
660
- {
661
- onPress: close,
662
- style: defaultStyles3.doneBtn,
663
- activeOpacity: 0.7,
664
- children: /* @__PURE__ */ jsx4(Text4, { style: defaultStyles3.doneText, children: "Done" })
665
- }
666
- )
667
- ] }),
668
- /* @__PURE__ */ jsx4(
669
- ScrollView2,
670
- {
671
- showsVerticalScrollIndicator: false,
672
- contentContainerStyle: defaultStyles3.scrollContent,
673
- children: renderList()
674
- }
675
- )
676
- ]
677
- }
678
- )
679
- ] })
603
+ children: /* @__PURE__ */ jsx4(View4, { style: [defaultStyles3.overlay, styles2?.overlay], children: /* @__PURE__ */ jsxs4(
604
+ Animated2.View,
605
+ {
606
+ style: [
607
+ defaultStyles3.container,
608
+ styles2?.container,
609
+ modalAnimatedStyle
610
+ ],
611
+ children: [
612
+ /* @__PURE__ */ jsx4(
613
+ TouchableOpacity4,
614
+ {
615
+ onPress: close,
616
+ style: [defaultStyles3.done, styles2?.doneBtn],
617
+ activeOpacity: 0.7,
618
+ children: /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.doneText, styles2?.doneText], children: "Done" })
619
+ }
620
+ ),
621
+ /* @__PURE__ */ jsx4(
622
+ ScrollView2,
623
+ {
624
+ showsVerticalScrollIndicator: false,
625
+ contentContainerStyle: defaultStyles3.scrollContent,
626
+ children: renderList()
627
+ }
628
+ )
629
+ ]
630
+ }
631
+ ) })
680
632
  }
681
633
  )
682
634
  ] });
@@ -713,71 +665,34 @@ var defaultStyles3 = StyleSheet4.create({
713
665
  },
714
666
  overlay: {
715
667
  flex: 1,
716
- justifyContent: "flex-end"
717
- },
718
- backdropTouchable: {
719
- position: "absolute",
720
- top: 0,
721
- left: 0,
722
- right: 0,
723
- bottom: 0
668
+ justifyContent: "flex-end",
669
+ backgroundColor: "rgba(0,0,0,0.4)"
724
670
  },
725
671
  container: {
726
- backgroundColor: "#FFFFFF",
672
+ backgroundColor: "#fff",
673
+ padding: 20,
727
674
  borderTopLeftRadius: 20,
728
675
  borderTopRightRadius: 20,
729
676
  maxHeight: "70%",
730
- minHeight: "40%",
731
- shadowColor: "#000",
732
- shadowOffset: {
733
- width: 0,
734
- height: -2
735
- },
736
- shadowOpacity: 0.1,
737
- shadowRadius: 4,
738
- elevation: 5
739
- },
740
- header: {
741
- flexDirection: "row",
742
- justifyContent: "space-between",
743
- alignItems: "center",
744
- paddingHorizontal: 20,
745
- paddingTop: 12,
746
- paddingBottom: 16,
747
- borderBottomWidth: 1,
748
- borderBottomColor: "#F0F0F0"
749
- },
750
- handle: {
751
- width: 40,
752
- height: 4,
753
- backgroundColor: "#E5E7EB",
754
- borderRadius: 2,
755
- position: "absolute",
756
- top: 8,
757
- alignSelf: "center"
677
+ minHeight: "40%"
758
678
  },
759
- headerTitle: {
760
- fontSize: 16,
761
- fontWeight: "600",
762
- color: "#1F2937",
763
- flex: 1,
764
- textAlign: "center"
679
+ scrollContent: {
680
+ paddingBottom: 20
765
681
  },
766
- doneBtn: {
767
- paddingVertical: 6,
768
- paddingHorizontal: 12,
682
+ done: {
769
683
  backgroundColor: "#6366f1",
770
- borderRadius: 8
684
+ paddingVertical: 10,
685
+ paddingHorizontal: 14,
686
+ borderRadius: 10,
687
+ alignSelf: "flex-end",
688
+ marginBottom: 16,
689
+ minWidth: 80,
690
+ alignItems: "center"
771
691
  },
772
692
  doneText: {
773
- color: "#FFFFFF",
693
+ color: "#fff",
774
694
  fontWeight: "600",
775
695
  fontSize: 14
776
- },
777
- scrollContent: {
778
- paddingHorizontal: 20,
779
- paddingTop: 12,
780
- paddingBottom: 24
781
696
  }
782
697
  });
783
698
 
@@ -787,11 +702,9 @@ import {
787
702
  Animated as Animated3,
788
703
  StyleSheet as StyleSheet5,
789
704
  TouchableWithoutFeedback,
790
- View as View5,
791
- Dimensions as Dimensions2
705
+ View as View5
792
706
  } from "react-native";
793
707
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
794
- var { width: SCREEN_WIDTH, height: SCREEN_HEIGHT2 } = Dimensions2.get("window");
795
708
  var FloatingButton = class extends React4.Component {
796
709
  animation = new Animated3.Value(0);
797
710
  open = false;
@@ -799,8 +712,8 @@ var FloatingButton = class extends React4.Component {
799
712
  Animated3.spring(this.animation, {
800
713
  toValue: this.open ? 0 : 1,
801
714
  useNativeDriver: true,
802
- damping: 15,
803
- mass: 0.8,
715
+ damping: 12,
716
+ mass: 0.6,
804
717
  stiffness: 180
805
718
  }).start();
806
719
  this.open = !this.open;
@@ -811,28 +724,26 @@ var FloatingButton = class extends React4.Component {
811
724
  radius = 100,
812
725
  actions,
813
726
  renderItemIcon,
814
- styles: styles2,
815
- spacing = 75
816
- // Default spacing between buttons
727
+ styles: styles2
817
728
  } = this.props;
818
729
  let translateX = 0;
819
730
  let translateY = 0;
820
731
  if (mode === "vertical") {
821
- translateY = -spacing * (index + 1);
732
+ translateY = -70 * (index + 1);
822
733
  translateX = 0;
823
734
  }
824
735
  if (mode === "horizontal") {
825
- translateX = -spacing * (index + 1);
736
+ translateX = -70 * (index + 1);
826
737
  translateY = 0;
827
738
  }
828
739
  if (mode === "circle") {
829
740
  const totalActions = actions.length;
830
- const startAngle = Math.PI * 0.85;
831
- const endAngle = Math.PI * 0.15;
832
- const angle = startAngle - index / (totalActions - 1 || 1) * (startAngle - endAngle);
833
- const adjustedRadius = radius;
834
- translateX = -adjustedRadius * Math.cos(angle);
835
- translateY = -adjustedRadius * Math.sin(angle);
741
+ const startAngle = -Math.PI / 3;
742
+ const endAngle = -Math.PI * 0.8;
743
+ const angle = startAngle + index / (totalActions - 1 || 1) * (endAngle - startAngle);
744
+ const adjustedRadius = radius * 0.65;
745
+ translateX = adjustedRadius * Math.cos(angle);
746
+ translateY = adjustedRadius * Math.sin(angle);
836
747
  }
837
748
  const animStyle = {
838
749
  transform: [
@@ -886,15 +797,7 @@ var FloatingButton = class extends React4.Component {
886
797
  );
887
798
  };
888
799
  render() {
889
- const {
890
- renderMainIcon,
891
- styles: styles2,
892
- style,
893
- mainIconName,
894
- mode = "vertical",
895
- offsetX = 24,
896
- offsetY = 100
897
- } = this.props;
800
+ const { actions, renderMainIcon, styles: styles2, style, mainIconName } = this.props;
898
801
  const rotation = {
899
802
  transform: [
900
803
  {
@@ -916,26 +819,32 @@ var FloatingButton = class extends React4.Component {
916
819
  ]
917
820
  };
918
821
  const mainIcon = mainIconName || "add";
919
- const containerStyle = [
920
- defaultStyles4.container,
921
- styles2?.container,
922
- style,
923
- {
924
- bottom: offsetY,
925
- right: offsetX
926
- }
927
- ];
928
- return /* @__PURE__ */ jsxs5(View5, { style: containerStyle, children: [
929
- this.props.actions.map(this.renderAction),
930
- /* @__PURE__ */ jsx5(TouchableWithoutFeedback, { onPress: this.toggleMenu, children: /* @__PURE__ */ jsx5(
822
+ return /* @__PURE__ */ jsxs5(View5, { style: [defaultStyles4.container, styles2?.container, style], children: [
823
+ /* @__PURE__ */ jsx5(
931
824
  Animated3.View,
932
825
  {
933
826
  style: [
934
- defaultStyles4.mainButtonWrapper,
935
- styles2?.mainButton,
936
- rotation,
937
- scale
827
+ defaultStyles4.circleContainer,
828
+ styles2?.circleContainer,
829
+ {
830
+ transform: [
831
+ {
832
+ scale: this.animation.interpolate({
833
+ inputRange: [0, 1],
834
+ outputRange: [0, 1]
835
+ })
836
+ }
837
+ ],
838
+ opacity: this.animation
839
+ }
938
840
  ],
841
+ children: actions.map(this.renderAction)
842
+ }
843
+ ),
844
+ /* @__PURE__ */ jsx5(TouchableWithoutFeedback, { onPress: this.toggleMenu, children: /* @__PURE__ */ jsx5(
845
+ Animated3.View,
846
+ {
847
+ style: [defaultStyles4.mainButtonWrapper, rotation, scale],
939
848
  children: /* @__PURE__ */ jsx5(View5, { style: [defaultStyles4.button, styles2?.mainButton], children: renderMainIcon?.({
940
849
  name: mainIcon,
941
850
  size: 26,
@@ -949,34 +858,44 @@ var FloatingButton = class extends React4.Component {
949
858
  var defaultStyles4 = StyleSheet5.create({
950
859
  container: {
951
860
  position: "absolute",
861
+ bottom: 100,
862
+ right: 20,
952
863
  alignItems: "center",
953
- justifyContent: "center",
954
- zIndex: 1e3
864
+ justifyContent: "center"
955
865
  },
956
866
  mainButtonWrapper: {
957
- width: 56,
958
- height: 56,
959
- borderRadius: 28,
867
+ width: 60,
868
+ height: 60,
869
+ borderRadius: 30,
960
870
  backgroundColor: "#F02A4B",
961
871
  alignItems: "center",
962
872
  justifyContent: "center",
963
873
  shadowColor: "#000",
964
874
  shadowOffset: {
965
875
  width: 0,
966
- height: 4
876
+ height: 2
967
877
  },
968
- shadowOpacity: 0.3,
969
- shadowRadius: 4.65,
970
- elevation: 8
878
+ shadowOpacity: 0.25,
879
+ shadowRadius: 3.84,
880
+ elevation: 5
971
881
  },
972
882
  button: {
973
- width: 56,
974
- height: 56,
975
- borderRadius: 28,
883
+ width: 60,
884
+ height: 60,
885
+ borderRadius: 30,
976
886
  backgroundColor: "#F02A4B",
977
887
  alignItems: "center",
978
888
  justifyContent: "center"
979
889
  },
890
+ circleContainer: {
891
+ position: "absolute",
892
+ width: 200,
893
+ height: 200,
894
+ right: -70,
895
+ bottom: -70,
896
+ alignItems: "center",
897
+ justifyContent: "center"
898
+ },
980
899
  secondary: {
981
900
  position: "absolute",
982
901
  width: 48,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaushverse/pickify",
3
- "version": "1.1.9",
3
+ "version": "1.1.11",
4
4
  "description": "A fully customizable React Native picker with search, multi-select, grouping, and async support.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",