@kaushverse/pickify 1.1.6 → 1.1.8

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