@kaushverse/pickify 1.1.6 → 1.1.7

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
@@ -140,6 +140,7 @@ type FloatingButtonStyles = {
140
140
  container?: ViewStyle;
141
141
  mainButton?: ViewStyle;
142
142
  secondaryButton?: ViewStyle;
143
+ circleContainer?: ViewStyle;
143
144
  };
144
145
  type Props = {
145
146
  actions: Action[];
package/dist/index.d.ts CHANGED
@@ -140,6 +140,7 @@ type FloatingButtonStyles = {
140
140
  container?: ViewStyle;
141
141
  mainButton?: ViewStyle;
142
142
  secondaryButton?: ViewStyle;
143
+ circleContainer?: ViewStyle;
143
144
  };
144
145
  type Props = {
145
146
  actions: Action[];
package/dist/index.js CHANGED
@@ -291,35 +291,49 @@ 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 animatedHeight = (0, import_react2.useRef)(new import_react_native2.Animated.Value(0)).current;
296
+ const [isMeasured, setIsMeasured] = (0, import_react2.useState)(false);
297
+ const animatedHeight = (0, import_react2.useRef)(
298
+ new import_react_native2.Animated.Value(defaultOpen ? 1 : 0)
299
+ ).current;
297
300
  (0, import_react2.useEffect)(() => {
298
- if (defaultOpen && contentHeight > 0) {
301
+ if (defaultOpen && contentHeight > 0 && !isMeasured) {
302
+ setIsMeasured(true);
299
303
  animatedHeight.setValue(contentHeight);
300
304
  setOpen(true);
301
305
  }
302
- }, [contentHeight, defaultOpen]);
306
+ }, [contentHeight, defaultOpen, isMeasured]);
303
307
  const toggle = () => {
304
308
  if (contentHeight === 0) return;
305
- const toValue = open ? 0 : contentHeight;
309
+ const newOpenState = !open;
310
+ const toValue = newOpenState ? contentHeight : 0;
306
311
  import_react_native2.Animated.timing(animatedHeight, {
307
312
  toValue,
308
313
  duration: 250,
309
314
  useNativeDriver: false
310
315
  }).start(() => {
311
- setOpen(!open);
316
+ setOpen(newOpenState);
312
317
  });
318
+ setOpen(newOpenState);
313
319
  };
314
320
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: styles.group, children: [
315
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.TouchableOpacity, { style: styles.header, onPress: toggle, children: [
316
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles.title, children: label }),
317
- renderGroupIcon?.({
318
- name: open ? "chevron-up" : "chevron-down",
319
- size: 18,
320
- color: "#6B7280"
321
- })
322
- ] }),
321
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
322
+ import_react_native2.TouchableOpacity,
323
+ {
324
+ style: styles.header,
325
+ onPress: toggle,
326
+ activeOpacity: 0.7,
327
+ children: [
328
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles.title, children: label }),
329
+ renderGroupIcon?.({
330
+ name: open ? "chevron-up" : "chevron-down",
331
+ size: 18,
332
+ color: "#6B7280"
333
+ })
334
+ ]
335
+ }
336
+ ),
323
337
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
324
338
  import_react_native2.View,
325
339
  {
@@ -327,7 +341,7 @@ function MultiPickerGroup({
327
341
  pointerEvents: "none",
328
342
  onLayout: (e) => {
329
343
  const height = e.nativeEvent.layout.height;
330
- if (height !== contentHeight) {
344
+ if (height > 0 && height !== contentHeight) {
331
345
  setContentHeight(height);
332
346
  }
333
347
  },
@@ -337,36 +351,51 @@ function MultiPickerGroup({
337
351
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
338
352
  import_react_native2.Animated.View,
339
353
  {
340
- style: {
341
- height: animatedHeight,
342
- overflow: "hidden"
343
- },
344
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles.content, children })
354
+ style: [
355
+ styles.animatedContainer,
356
+ {
357
+ height: animatedHeight
358
+ }
359
+ ],
360
+ children: contentHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles.content, children })
345
361
  }
346
362
  )
347
363
  ] });
348
364
  }
349
365
  var styles = import_react_native2.StyleSheet.create({
350
366
  group: {
351
- marginBottom: 12
367
+ marginBottom: 12,
368
+ backgroundColor: "#FFFFFF",
369
+ borderRadius: 8,
370
+ overflow: "hidden"
352
371
  },
353
372
  header: {
354
373
  flexDirection: "row",
355
374
  justifyContent: "space-between",
356
- alignItems: "center"
375
+ alignItems: "center",
376
+ paddingVertical: 12,
377
+ paddingHorizontal: 8,
378
+ backgroundColor: "#F9FAFB",
379
+ borderRadius: 8
357
380
  },
358
381
  title: {
359
382
  fontWeight: "600",
360
- fontSize: 14
383
+ fontSize: 14,
384
+ color: "#1F2937"
385
+ },
386
+ animatedContainer: {
387
+ overflow: "hidden"
361
388
  },
362
389
  content: {
363
- marginTop: 6
390
+ marginTop: 6,
391
+ paddingHorizontal: 8,
392
+ paddingBottom: 4
364
393
  },
365
- // invisible layout measurement
366
394
  hidden: {
367
395
  position: "absolute",
368
396
  opacity: 0,
369
397
  zIndex: -1,
398
+ top: 0,
370
399
  left: 0,
371
400
  right: 0
372
401
  }
@@ -458,8 +487,30 @@ function MultiPickerModal({
458
487
  styles: styles2
459
488
  }) {
460
489
  const [internalVisible, setInternalVisible] = (0, import_react3.useState)(false);
490
+ const [modalKey, setModalKey] = (0, import_react3.useState)(0);
491
+ const slideAnim = (0, import_react3.useRef)(new import_react_native4.Animated.Value(0)).current;
461
492
  const isControlled = visible !== void 0 && setVisible !== void 0;
462
493
  const isVisible = isControlled ? visible : internalVisible;
494
+ (0, import_react3.useEffect)(() => {
495
+ if (isVisible) {
496
+ setModalKey((prev) => prev + 1);
497
+ import_react_native4.Animated.spring(slideAnim, {
498
+ toValue: 1,
499
+ useNativeDriver: true,
500
+ damping: 15,
501
+ mass: 0.8,
502
+ stiffness: 150
503
+ }).start();
504
+ } else {
505
+ import_react_native4.Animated.spring(slideAnim, {
506
+ toValue: 0,
507
+ useNativeDriver: true,
508
+ damping: 15,
509
+ mass: 0.8,
510
+ stiffness: 150
511
+ }).start();
512
+ }
513
+ }, [isVisible]);
463
514
  const open = () => {
464
515
  if (isControlled) setVisible(true);
465
516
  else setInternalVisible(true);
@@ -475,7 +526,9 @@ function MultiPickerModal({
475
526
  const getLabel = () => {
476
527
  if (!selectedValues?.length) return placeholder;
477
528
  const all = groups.length ? groups.flatMap((g) => g.data) : options;
478
- return all.filter((o) => selectedValues.includes(o.value)).map((o) => o.label).join(", ");
529
+ const selectedItems = all.filter((o) => selectedValues.includes(o.value)).map((o) => o.label);
530
+ if (selectedItems.length === 0) return placeholder;
531
+ return selectedItems.join(", ");
479
532
  };
480
533
  const renderList = () => {
481
534
  if (groups.length > 0) {
@@ -497,7 +550,7 @@ function MultiPickerModal({
497
550
  item.value
498
551
  ))
499
552
  },
500
- group.label
553
+ `${modalKey}-${group.label}`
501
554
  ));
502
555
  }
503
556
  return options.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -512,6 +565,16 @@ function MultiPickerModal({
512
565
  item.value
513
566
  ));
514
567
  };
568
+ const modalAnimatedStyle = {
569
+ transform: [
570
+ {
571
+ translateY: slideAnim.interpolate({
572
+ inputRange: [0, 1],
573
+ outputRange: [600, 0]
574
+ })
575
+ }
576
+ ]
577
+ };
515
578
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
516
579
  label && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.label, styles2?.label], children: label }),
517
580
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -519,8 +582,20 @@ function MultiPickerModal({
519
582
  {
520
583
  style: [defaultStyles3.box, styles2?.selectBox],
521
584
  onPress: open,
585
+ activeOpacity: 0.7,
522
586
  children: [
523
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.text, styles2?.selectText], children: getLabel() }),
587
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
588
+ import_react_native4.Text,
589
+ {
590
+ style: [
591
+ defaultStyles3.text,
592
+ styles2?.selectText,
593
+ !selectedValues?.length && defaultStyles3.placeholder
594
+ ],
595
+ numberOfLines: 1,
596
+ children: getLabel()
597
+ }
598
+ ),
524
599
  renderInputIcon?.({
525
600
  name: "chevron-down",
526
601
  size: 18,
@@ -530,23 +605,52 @@ function MultiPickerModal({
530
605
  }
531
606
  ),
532
607
  error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.error, styles2?.error], children: error }),
533
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Modal, { visible: isVisible, transparent: true, animationType: "slide", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: [defaultStyles3.overlay, styles2?.overlay], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: [defaultStyles3.container, styles2?.container], children: [
534
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
535
- import_react_native4.TouchableOpacity,
536
- {
537
- onPress: close,
538
- style: [defaultStyles3.done, styles2?.doneBtn],
539
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.doneText, styles2?.doneText], children: "Done" })
540
- }
541
- ),
542
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.ScrollView, { children: renderList() })
543
- ] }) }) })
608
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
609
+ import_react_native4.Modal,
610
+ {
611
+ visible: isVisible,
612
+ transparent: true,
613
+ animationType: "none",
614
+ onRequestClose: close,
615
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: [defaultStyles3.overlay, styles2?.overlay], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
616
+ import_react_native4.Animated.View,
617
+ {
618
+ style: [
619
+ defaultStyles3.container,
620
+ styles2?.container,
621
+ modalAnimatedStyle
622
+ ],
623
+ children: [
624
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
625
+ import_react_native4.TouchableOpacity,
626
+ {
627
+ onPress: close,
628
+ style: [defaultStyles3.done, styles2?.doneBtn],
629
+ activeOpacity: 0.7,
630
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.doneText, styles2?.doneText], children: "Done" })
631
+ }
632
+ ),
633
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
634
+ import_react_native4.ScrollView,
635
+ {
636
+ showsVerticalScrollIndicator: false,
637
+ contentContainerStyle: defaultStyles3.scrollContent,
638
+ children: renderList()
639
+ }
640
+ )
641
+ ]
642
+ }
643
+ ) })
644
+ }
645
+ )
544
646
  ] });
545
647
  }
546
648
  var defaultStyles3 = import_react_native4.StyleSheet.create({
547
649
  label: {
548
650
  marginBottom: 6,
549
- fontSize: 14
651
+ fontSize: 14,
652
+ fontWeight: "500",
653
+ color: "#374151"
550
654
  },
551
655
  box: {
552
656
  borderWidth: 1,
@@ -555,27 +659,37 @@ var defaultStyles3 = import_react_native4.StyleSheet.create({
555
659
  padding: 12,
556
660
  flexDirection: "row",
557
661
  justifyContent: "space-between",
558
- alignItems: "center"
662
+ alignItems: "center",
663
+ backgroundColor: "#FFFFFF"
559
664
  },
560
665
  text: {
561
- fontSize: 15
666
+ fontSize: 15,
667
+ color: "#1F2937",
668
+ flex: 1
669
+ },
670
+ placeholder: {
671
+ color: "#9CA3AF"
562
672
  },
563
673
  error: {
564
- color: "red",
674
+ color: "#EF4444",
565
675
  fontSize: 12,
566
676
  marginTop: 4
567
677
  },
568
678
  overlay: {
569
679
  flex: 1,
570
680
  justifyContent: "flex-end",
571
- backgroundColor: "rgba(0,0,0,0.3)"
681
+ backgroundColor: "rgba(0,0,0,0.4)"
572
682
  },
573
683
  container: {
574
684
  backgroundColor: "#fff",
575
685
  padding: 20,
576
686
  borderTopLeftRadius: 20,
577
687
  borderTopRightRadius: 20,
578
- maxHeight: "70%"
688
+ maxHeight: "70%",
689
+ minHeight: "40%"
690
+ },
691
+ scrollContent: {
692
+ paddingBottom: 20
579
693
  },
580
694
  done: {
581
695
  backgroundColor: "#6366f1",
@@ -583,11 +697,14 @@ var defaultStyles3 = import_react_native4.StyleSheet.create({
583
697
  paddingHorizontal: 14,
584
698
  borderRadius: 10,
585
699
  alignSelf: "flex-end",
586
- marginBottom: 10
700
+ marginBottom: 16,
701
+ minWidth: 80,
702
+ alignItems: "center"
587
703
  },
588
704
  doneText: {
589
705
  color: "#fff",
590
- fontWeight: "600"
706
+ fontWeight: "600",
707
+ fontSize: 14
591
708
  }
592
709
  });
593
710
 
@@ -610,8 +727,8 @@ var FloatingButton = class extends import_react4.default.Component {
610
727
  };
611
728
  renderAction = (action, index) => {
612
729
  const {
613
- mode = "circle",
614
- radius = 90,
730
+ mode = "vertical",
731
+ radius = 100,
615
732
  actions,
616
733
  renderItemIcon,
617
734
  styles: styles2
@@ -619,17 +736,21 @@ var FloatingButton = class extends import_react4.default.Component {
619
736
  let translateX = 0;
620
737
  let translateY = 0;
621
738
  if (mode === "vertical") {
622
- translateY = -55 * (index + 1);
739
+ translateY = -70 * (index + 1);
740
+ translateX = 0;
623
741
  }
624
742
  if (mode === "horizontal") {
625
- translateX = -55 * (index + 1);
743
+ translateX = -70 * (index + 1);
744
+ translateY = 0;
626
745
  }
627
746
  if (mode === "circle") {
628
- const startAngle = Math.PI * 1.1;
629
- const endAngle = Math.PI * 1.9;
630
- const angle = startAngle + index / (actions.length - 1 || 1) * (endAngle - startAngle);
631
- translateX = radius * Math.cos(angle);
632
- translateY = radius * Math.sin(angle);
747
+ const totalActions = actions.length;
748
+ const startAngle = -Math.PI / 3;
749
+ const endAngle = -Math.PI * 0.8;
750
+ const angle = startAngle + index / (totalActions - 1 || 1) * (endAngle - startAngle);
751
+ const adjustedRadius = radius * 0.65;
752
+ translateX = adjustedRadius * Math.cos(angle);
753
+ translateY = adjustedRadius * Math.sin(angle);
633
754
  }
634
755
  const animStyle = {
635
756
  transform: [
@@ -648,7 +769,7 @@ var FloatingButton = class extends import_react4.default.Component {
648
769
  {
649
770
  scale: this.animation.interpolate({
650
771
  inputRange: [0, 0.5, 1],
651
- outputRange: [0, 1.1, 1]
772
+ outputRange: [0, 1.2, 1]
652
773
  })
653
774
  }
654
775
  ],
@@ -694,18 +815,48 @@ var FloatingButton = class extends import_react4.default.Component {
694
815
  }
695
816
  ]
696
817
  };
818
+ const scale = {
819
+ transform: [
820
+ {
821
+ scale: this.animation.interpolate({
822
+ inputRange: [0, 0.5, 1],
823
+ outputRange: [1, 1.1, 1]
824
+ })
825
+ }
826
+ ]
827
+ };
697
828
  const mainIcon = mainIconName || "add";
698
829
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [defaultStyles4.container, styles2?.container, style], children: [
699
- actions.map(this.renderAction),
830
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
831
+ import_react_native5.Animated.View,
832
+ {
833
+ style: [
834
+ defaultStyles4.circleContainer,
835
+ styles2?.circleContainer,
836
+ {
837
+ transform: [
838
+ {
839
+ scale: this.animation.interpolate({
840
+ inputRange: [0, 1],
841
+ outputRange: [0, 1]
842
+ })
843
+ }
844
+ ],
845
+ opacity: this.animation
846
+ }
847
+ ],
848
+ children: actions.map(this.renderAction)
849
+ }
850
+ ),
700
851
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.TouchableWithoutFeedback, { onPress: this.toggleMenu, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
701
852
  import_react_native5.Animated.View,
702
853
  {
703
- style: [defaultStyles4.button, styles2?.mainButton, rotation],
704
- children: renderMainIcon?.({
854
+ style: [defaultStyles4.mainButtonWrapper, rotation, scale],
855
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: [defaultStyles4.button, styles2?.mainButton], children: renderMainIcon?.({
705
856
  name: mainIcon,
706
857
  size: 26,
707
858
  color: "#FFF"
708
- })
859
+ }) })
709
860
  }
710
861
  ) })
711
862
  ] });
@@ -716,7 +867,24 @@ var defaultStyles4 = import_react_native5.StyleSheet.create({
716
867
  position: "absolute",
717
868
  bottom: 100,
718
869
  right: 20,
719
- alignItems: "center"
870
+ alignItems: "center",
871
+ justifyContent: "center"
872
+ },
873
+ mainButtonWrapper: {
874
+ width: 60,
875
+ height: 60,
876
+ borderRadius: 30,
877
+ backgroundColor: "#F02A4B",
878
+ alignItems: "center",
879
+ justifyContent: "center",
880
+ shadowColor: "#000",
881
+ shadowOffset: {
882
+ width: 0,
883
+ height: 2
884
+ },
885
+ shadowOpacity: 0.25,
886
+ shadowRadius: 3.84,
887
+ elevation: 5
720
888
  },
721
889
  button: {
722
890
  width: 60,
@@ -726,14 +894,31 @@ var defaultStyles4 = import_react_native5.StyleSheet.create({
726
894
  alignItems: "center",
727
895
  justifyContent: "center"
728
896
  },
897
+ circleContainer: {
898
+ position: "absolute",
899
+ width: 200,
900
+ height: 200,
901
+ right: -70,
902
+ bottom: -70,
903
+ alignItems: "center",
904
+ justifyContent: "center"
905
+ },
729
906
  secondary: {
730
907
  position: "absolute",
731
- width: 46,
732
- height: 46,
733
- borderRadius: 23,
908
+ width: 48,
909
+ height: 48,
910
+ borderRadius: 24,
734
911
  backgroundColor: "#F02A4B",
735
912
  alignItems: "center",
736
- justifyContent: "center"
913
+ justifyContent: "center",
914
+ shadowColor: "#000",
915
+ shadowOffset: {
916
+ width: 0,
917
+ height: 2
918
+ },
919
+ shadowOpacity: 0.25,
920
+ shadowRadius: 3.84,
921
+ elevation: 5
737
922
  }
738
923
  });
739
924
 
package/dist/index.mjs CHANGED
@@ -238,14 +238,15 @@ var defaultStyles = StyleSheet.create({
238
238
  });
239
239
 
240
240
  // src/core/MultiPickerModal.tsx
241
- import { useState as useState3 } from "react";
241
+ import { useState as useState3, useEffect as useEffect3, useRef as useRef2 } from "react";
242
242
  import {
243
243
  Modal as Modal2,
244
244
  View as View4,
245
245
  Text as Text4,
246
246
  TouchableOpacity as TouchableOpacity4,
247
247
  StyleSheet as StyleSheet4,
248
- ScrollView as ScrollView2
248
+ ScrollView as ScrollView2,
249
+ Animated as Animated2
249
250
  } from "react-native";
250
251
 
251
252
  // src/utils/toggleValue.ts
@@ -269,35 +270,49 @@ function MultiPickerGroup({
269
270
  renderGroupIcon,
270
271
  defaultOpen = false
271
272
  }) {
272
- const [open, setOpen] = useState2(false);
273
+ const [open, setOpen] = useState2(defaultOpen);
273
274
  const [contentHeight, setContentHeight] = useState2(0);
274
- const animatedHeight = useRef(new Animated.Value(0)).current;
275
+ const [isMeasured, setIsMeasured] = useState2(false);
276
+ const animatedHeight = useRef(
277
+ new Animated.Value(defaultOpen ? 1 : 0)
278
+ ).current;
275
279
  useEffect2(() => {
276
- if (defaultOpen && contentHeight > 0) {
280
+ if (defaultOpen && contentHeight > 0 && !isMeasured) {
281
+ setIsMeasured(true);
277
282
  animatedHeight.setValue(contentHeight);
278
283
  setOpen(true);
279
284
  }
280
- }, [contentHeight, defaultOpen]);
285
+ }, [contentHeight, defaultOpen, isMeasured]);
281
286
  const toggle = () => {
282
287
  if (contentHeight === 0) return;
283
- const toValue = open ? 0 : contentHeight;
288
+ const newOpenState = !open;
289
+ const toValue = newOpenState ? contentHeight : 0;
284
290
  Animated.timing(animatedHeight, {
285
291
  toValue,
286
292
  duration: 250,
287
293
  useNativeDriver: false
288
294
  }).start(() => {
289
- setOpen(!open);
295
+ setOpen(newOpenState);
290
296
  });
297
+ setOpen(newOpenState);
291
298
  };
292
299
  return /* @__PURE__ */ jsxs2(View2, { style: styles.group, children: [
293
- /* @__PURE__ */ jsxs2(TouchableOpacity2, { style: styles.header, onPress: toggle, children: [
294
- /* @__PURE__ */ jsx2(Text2, { style: styles.title, children: label }),
295
- renderGroupIcon?.({
296
- name: open ? "chevron-up" : "chevron-down",
297
- size: 18,
298
- color: "#6B7280"
299
- })
300
- ] }),
300
+ /* @__PURE__ */ jsxs2(
301
+ TouchableOpacity2,
302
+ {
303
+ style: styles.header,
304
+ onPress: toggle,
305
+ activeOpacity: 0.7,
306
+ children: [
307
+ /* @__PURE__ */ jsx2(Text2, { style: styles.title, children: label }),
308
+ renderGroupIcon?.({
309
+ name: open ? "chevron-up" : "chevron-down",
310
+ size: 18,
311
+ color: "#6B7280"
312
+ })
313
+ ]
314
+ }
315
+ ),
301
316
  /* @__PURE__ */ jsx2(
302
317
  View2,
303
318
  {
@@ -305,7 +320,7 @@ function MultiPickerGroup({
305
320
  pointerEvents: "none",
306
321
  onLayout: (e) => {
307
322
  const height = e.nativeEvent.layout.height;
308
- if (height !== contentHeight) {
323
+ if (height > 0 && height !== contentHeight) {
309
324
  setContentHeight(height);
310
325
  }
311
326
  },
@@ -315,36 +330,51 @@ function MultiPickerGroup({
315
330
  /* @__PURE__ */ jsx2(
316
331
  Animated.View,
317
332
  {
318
- style: {
319
- height: animatedHeight,
320
- overflow: "hidden"
321
- },
322
- children: /* @__PURE__ */ jsx2(View2, { style: styles.content, children })
333
+ style: [
334
+ styles.animatedContainer,
335
+ {
336
+ height: animatedHeight
337
+ }
338
+ ],
339
+ children: contentHeight > 0 && /* @__PURE__ */ jsx2(View2, { style: styles.content, children })
323
340
  }
324
341
  )
325
342
  ] });
326
343
  }
327
344
  var styles = StyleSheet2.create({
328
345
  group: {
329
- marginBottom: 12
346
+ marginBottom: 12,
347
+ backgroundColor: "#FFFFFF",
348
+ borderRadius: 8,
349
+ overflow: "hidden"
330
350
  },
331
351
  header: {
332
352
  flexDirection: "row",
333
353
  justifyContent: "space-between",
334
- alignItems: "center"
354
+ alignItems: "center",
355
+ paddingVertical: 12,
356
+ paddingHorizontal: 8,
357
+ backgroundColor: "#F9FAFB",
358
+ borderRadius: 8
335
359
  },
336
360
  title: {
337
361
  fontWeight: "600",
338
- fontSize: 14
362
+ fontSize: 14,
363
+ color: "#1F2937"
364
+ },
365
+ animatedContainer: {
366
+ overflow: "hidden"
339
367
  },
340
368
  content: {
341
- marginTop: 6
369
+ marginTop: 6,
370
+ paddingHorizontal: 8,
371
+ paddingBottom: 4
342
372
  },
343
- // invisible layout measurement
344
373
  hidden: {
345
374
  position: "absolute",
346
375
  opacity: 0,
347
376
  zIndex: -1,
377
+ top: 0,
348
378
  left: 0,
349
379
  right: 0
350
380
  }
@@ -436,8 +466,30 @@ function MultiPickerModal({
436
466
  styles: styles2
437
467
  }) {
438
468
  const [internalVisible, setInternalVisible] = useState3(false);
469
+ const [modalKey, setModalKey] = useState3(0);
470
+ const slideAnim = useRef2(new Animated2.Value(0)).current;
439
471
  const isControlled = visible !== void 0 && setVisible !== void 0;
440
472
  const isVisible = isControlled ? visible : internalVisible;
473
+ useEffect3(() => {
474
+ if (isVisible) {
475
+ setModalKey((prev) => prev + 1);
476
+ Animated2.spring(slideAnim, {
477
+ toValue: 1,
478
+ useNativeDriver: true,
479
+ damping: 15,
480
+ mass: 0.8,
481
+ stiffness: 150
482
+ }).start();
483
+ } else {
484
+ Animated2.spring(slideAnim, {
485
+ toValue: 0,
486
+ useNativeDriver: true,
487
+ damping: 15,
488
+ mass: 0.8,
489
+ stiffness: 150
490
+ }).start();
491
+ }
492
+ }, [isVisible]);
441
493
  const open = () => {
442
494
  if (isControlled) setVisible(true);
443
495
  else setInternalVisible(true);
@@ -453,7 +505,9 @@ function MultiPickerModal({
453
505
  const getLabel = () => {
454
506
  if (!selectedValues?.length) return placeholder;
455
507
  const all = groups.length ? groups.flatMap((g) => g.data) : options;
456
- return all.filter((o) => selectedValues.includes(o.value)).map((o) => o.label).join(", ");
508
+ const selectedItems = all.filter((o) => selectedValues.includes(o.value)).map((o) => o.label);
509
+ if (selectedItems.length === 0) return placeholder;
510
+ return selectedItems.join(", ");
457
511
  };
458
512
  const renderList = () => {
459
513
  if (groups.length > 0) {
@@ -475,7 +529,7 @@ function MultiPickerModal({
475
529
  item.value
476
530
  ))
477
531
  },
478
- group.label
532
+ `${modalKey}-${group.label}`
479
533
  ));
480
534
  }
481
535
  return options.map((item) => /* @__PURE__ */ jsx4(
@@ -490,6 +544,16 @@ function MultiPickerModal({
490
544
  item.value
491
545
  ));
492
546
  };
547
+ const modalAnimatedStyle = {
548
+ transform: [
549
+ {
550
+ translateY: slideAnim.interpolate({
551
+ inputRange: [0, 1],
552
+ outputRange: [600, 0]
553
+ })
554
+ }
555
+ ]
556
+ };
493
557
  return /* @__PURE__ */ jsxs4(Fragment2, { children: [
494
558
  label && /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.label, styles2?.label], children: label }),
495
559
  /* @__PURE__ */ jsxs4(
@@ -497,8 +561,20 @@ function MultiPickerModal({
497
561
  {
498
562
  style: [defaultStyles3.box, styles2?.selectBox],
499
563
  onPress: open,
564
+ activeOpacity: 0.7,
500
565
  children: [
501
- /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.text, styles2?.selectText], children: getLabel() }),
566
+ /* @__PURE__ */ jsx4(
567
+ Text4,
568
+ {
569
+ style: [
570
+ defaultStyles3.text,
571
+ styles2?.selectText,
572
+ !selectedValues?.length && defaultStyles3.placeholder
573
+ ],
574
+ numberOfLines: 1,
575
+ children: getLabel()
576
+ }
577
+ ),
502
578
  renderInputIcon?.({
503
579
  name: "chevron-down",
504
580
  size: 18,
@@ -508,23 +584,52 @@ function MultiPickerModal({
508
584
  }
509
585
  ),
510
586
  error && /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.error, styles2?.error], children: error }),
511
- /* @__PURE__ */ jsx4(Modal2, { visible: isVisible, transparent: true, animationType: "slide", children: /* @__PURE__ */ jsx4(View4, { style: [defaultStyles3.overlay, styles2?.overlay], children: /* @__PURE__ */ jsxs4(View4, { style: [defaultStyles3.container, styles2?.container], children: [
512
- /* @__PURE__ */ jsx4(
513
- TouchableOpacity4,
514
- {
515
- onPress: close,
516
- style: [defaultStyles3.done, styles2?.doneBtn],
517
- children: /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.doneText, styles2?.doneText], children: "Done" })
518
- }
519
- ),
520
- /* @__PURE__ */ jsx4(ScrollView2, { children: renderList() })
521
- ] }) }) })
587
+ /* @__PURE__ */ jsx4(
588
+ Modal2,
589
+ {
590
+ visible: isVisible,
591
+ transparent: true,
592
+ animationType: "none",
593
+ onRequestClose: close,
594
+ children: /* @__PURE__ */ jsx4(View4, { style: [defaultStyles3.overlay, styles2?.overlay], children: /* @__PURE__ */ jsxs4(
595
+ Animated2.View,
596
+ {
597
+ style: [
598
+ defaultStyles3.container,
599
+ styles2?.container,
600
+ modalAnimatedStyle
601
+ ],
602
+ children: [
603
+ /* @__PURE__ */ jsx4(
604
+ TouchableOpacity4,
605
+ {
606
+ onPress: close,
607
+ style: [defaultStyles3.done, styles2?.doneBtn],
608
+ activeOpacity: 0.7,
609
+ children: /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.doneText, styles2?.doneText], children: "Done" })
610
+ }
611
+ ),
612
+ /* @__PURE__ */ jsx4(
613
+ ScrollView2,
614
+ {
615
+ showsVerticalScrollIndicator: false,
616
+ contentContainerStyle: defaultStyles3.scrollContent,
617
+ children: renderList()
618
+ }
619
+ )
620
+ ]
621
+ }
622
+ ) })
623
+ }
624
+ )
522
625
  ] });
523
626
  }
524
627
  var defaultStyles3 = StyleSheet4.create({
525
628
  label: {
526
629
  marginBottom: 6,
527
- fontSize: 14
630
+ fontSize: 14,
631
+ fontWeight: "500",
632
+ color: "#374151"
528
633
  },
529
634
  box: {
530
635
  borderWidth: 1,
@@ -533,27 +638,37 @@ var defaultStyles3 = StyleSheet4.create({
533
638
  padding: 12,
534
639
  flexDirection: "row",
535
640
  justifyContent: "space-between",
536
- alignItems: "center"
641
+ alignItems: "center",
642
+ backgroundColor: "#FFFFFF"
537
643
  },
538
644
  text: {
539
- fontSize: 15
645
+ fontSize: 15,
646
+ color: "#1F2937",
647
+ flex: 1
648
+ },
649
+ placeholder: {
650
+ color: "#9CA3AF"
540
651
  },
541
652
  error: {
542
- color: "red",
653
+ color: "#EF4444",
543
654
  fontSize: 12,
544
655
  marginTop: 4
545
656
  },
546
657
  overlay: {
547
658
  flex: 1,
548
659
  justifyContent: "flex-end",
549
- backgroundColor: "rgba(0,0,0,0.3)"
660
+ backgroundColor: "rgba(0,0,0,0.4)"
550
661
  },
551
662
  container: {
552
663
  backgroundColor: "#fff",
553
664
  padding: 20,
554
665
  borderTopLeftRadius: 20,
555
666
  borderTopRightRadius: 20,
556
- maxHeight: "70%"
667
+ maxHeight: "70%",
668
+ minHeight: "40%"
669
+ },
670
+ scrollContent: {
671
+ paddingBottom: 20
557
672
  },
558
673
  done: {
559
674
  backgroundColor: "#6366f1",
@@ -561,28 +676,31 @@ var defaultStyles3 = StyleSheet4.create({
561
676
  paddingHorizontal: 14,
562
677
  borderRadius: 10,
563
678
  alignSelf: "flex-end",
564
- marginBottom: 10
679
+ marginBottom: 16,
680
+ minWidth: 80,
681
+ alignItems: "center"
565
682
  },
566
683
  doneText: {
567
684
  color: "#fff",
568
- fontWeight: "600"
685
+ fontWeight: "600",
686
+ fontSize: 14
569
687
  }
570
688
  });
571
689
 
572
690
  // src/core/FloatingButton.tsx
573
691
  import React4 from "react";
574
692
  import {
575
- Animated as Animated2,
693
+ Animated as Animated3,
576
694
  StyleSheet as StyleSheet5,
577
695
  TouchableWithoutFeedback,
578
696
  View as View5
579
697
  } from "react-native";
580
698
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
581
699
  var FloatingButton = class extends React4.Component {
582
- animation = new Animated2.Value(0);
700
+ animation = new Animated3.Value(0);
583
701
  open = false;
584
702
  toggleMenu = () => {
585
- Animated2.spring(this.animation, {
703
+ Animated3.spring(this.animation, {
586
704
  toValue: this.open ? 0 : 1,
587
705
  useNativeDriver: true,
588
706
  damping: 12,
@@ -593,8 +711,8 @@ var FloatingButton = class extends React4.Component {
593
711
  };
594
712
  renderAction = (action, index) => {
595
713
  const {
596
- mode = "circle",
597
- radius = 90,
714
+ mode = "vertical",
715
+ radius = 100,
598
716
  actions,
599
717
  renderItemIcon,
600
718
  styles: styles2
@@ -602,17 +720,21 @@ var FloatingButton = class extends React4.Component {
602
720
  let translateX = 0;
603
721
  let translateY = 0;
604
722
  if (mode === "vertical") {
605
- translateY = -55 * (index + 1);
723
+ translateY = -70 * (index + 1);
724
+ translateX = 0;
606
725
  }
607
726
  if (mode === "horizontal") {
608
- translateX = -55 * (index + 1);
727
+ translateX = -70 * (index + 1);
728
+ translateY = 0;
609
729
  }
610
730
  if (mode === "circle") {
611
- const startAngle = Math.PI * 1.1;
612
- const endAngle = Math.PI * 1.9;
613
- const angle = startAngle + index / (actions.length - 1 || 1) * (endAngle - startAngle);
614
- translateX = radius * Math.cos(angle);
615
- translateY = radius * Math.sin(angle);
731
+ const totalActions = actions.length;
732
+ const startAngle = -Math.PI / 3;
733
+ const endAngle = -Math.PI * 0.8;
734
+ const angle = startAngle + index / (totalActions - 1 || 1) * (endAngle - startAngle);
735
+ const adjustedRadius = radius * 0.65;
736
+ translateX = adjustedRadius * Math.cos(angle);
737
+ translateY = adjustedRadius * Math.sin(angle);
616
738
  }
617
739
  const animStyle = {
618
740
  transform: [
@@ -631,7 +753,7 @@ var FloatingButton = class extends React4.Component {
631
753
  {
632
754
  scale: this.animation.interpolate({
633
755
  inputRange: [0, 0.5, 1],
634
- outputRange: [0, 1.1, 1]
756
+ outputRange: [0, 1.2, 1]
635
757
  })
636
758
  }
637
759
  ],
@@ -646,7 +768,7 @@ var FloatingButton = class extends React4.Component {
646
768
  action.navigateTo?.();
647
769
  },
648
770
  children: /* @__PURE__ */ jsx5(
649
- Animated2.View,
771
+ Animated3.View,
650
772
  {
651
773
  style: [
652
774
  defaultStyles4.secondary,
@@ -677,18 +799,48 @@ var FloatingButton = class extends React4.Component {
677
799
  }
678
800
  ]
679
801
  };
802
+ const scale = {
803
+ transform: [
804
+ {
805
+ scale: this.animation.interpolate({
806
+ inputRange: [0, 0.5, 1],
807
+ outputRange: [1, 1.1, 1]
808
+ })
809
+ }
810
+ ]
811
+ };
680
812
  const mainIcon = mainIconName || "add";
681
813
  return /* @__PURE__ */ jsxs5(View5, { style: [defaultStyles4.container, styles2?.container, style], children: [
682
- actions.map(this.renderAction),
814
+ /* @__PURE__ */ jsx5(
815
+ Animated3.View,
816
+ {
817
+ style: [
818
+ defaultStyles4.circleContainer,
819
+ styles2?.circleContainer,
820
+ {
821
+ transform: [
822
+ {
823
+ scale: this.animation.interpolate({
824
+ inputRange: [0, 1],
825
+ outputRange: [0, 1]
826
+ })
827
+ }
828
+ ],
829
+ opacity: this.animation
830
+ }
831
+ ],
832
+ children: actions.map(this.renderAction)
833
+ }
834
+ ),
683
835
  /* @__PURE__ */ jsx5(TouchableWithoutFeedback, { onPress: this.toggleMenu, children: /* @__PURE__ */ jsx5(
684
- Animated2.View,
836
+ Animated3.View,
685
837
  {
686
- style: [defaultStyles4.button, styles2?.mainButton, rotation],
687
- children: renderMainIcon?.({
838
+ style: [defaultStyles4.mainButtonWrapper, rotation, scale],
839
+ children: /* @__PURE__ */ jsx5(View5, { style: [defaultStyles4.button, styles2?.mainButton], children: renderMainIcon?.({
688
840
  name: mainIcon,
689
841
  size: 26,
690
842
  color: "#FFF"
691
- })
843
+ }) })
692
844
  }
693
845
  ) })
694
846
  ] });
@@ -699,7 +851,24 @@ var defaultStyles4 = StyleSheet5.create({
699
851
  position: "absolute",
700
852
  bottom: 100,
701
853
  right: 20,
702
- alignItems: "center"
854
+ alignItems: "center",
855
+ justifyContent: "center"
856
+ },
857
+ mainButtonWrapper: {
858
+ width: 60,
859
+ height: 60,
860
+ borderRadius: 30,
861
+ backgroundColor: "#F02A4B",
862
+ alignItems: "center",
863
+ justifyContent: "center",
864
+ shadowColor: "#000",
865
+ shadowOffset: {
866
+ width: 0,
867
+ height: 2
868
+ },
869
+ shadowOpacity: 0.25,
870
+ shadowRadius: 3.84,
871
+ elevation: 5
703
872
  },
704
873
  button: {
705
874
  width: 60,
@@ -709,14 +878,31 @@ var defaultStyles4 = StyleSheet5.create({
709
878
  alignItems: "center",
710
879
  justifyContent: "center"
711
880
  },
881
+ circleContainer: {
882
+ position: "absolute",
883
+ width: 200,
884
+ height: 200,
885
+ right: -70,
886
+ bottom: -70,
887
+ alignItems: "center",
888
+ justifyContent: "center"
889
+ },
712
890
  secondary: {
713
891
  position: "absolute",
714
- width: 46,
715
- height: 46,
716
- borderRadius: 23,
892
+ width: 48,
893
+ height: 48,
894
+ borderRadius: 24,
717
895
  backgroundColor: "#F02A4B",
718
896
  alignItems: "center",
719
- justifyContent: "center"
897
+ justifyContent: "center",
898
+ shadowColor: "#000",
899
+ shadowOffset: {
900
+ width: 0,
901
+ height: 2
902
+ },
903
+ shadowOpacity: 0.25,
904
+ shadowRadius: 3.84,
905
+ elevation: 5
720
906
  }
721
907
  });
722
908
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaushverse/pickify",
3
- "version": "1.1.6",
3
+ "version": "1.1.7",
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",