@kaushverse/pickify 1.1.5 → 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
@@ -293,31 +293,57 @@ function MultiPickerGroup({
293
293
  }) {
294
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;
300
+ (0, import_react2.useEffect)(() => {
301
+ if (defaultOpen && contentHeight > 0 && !isMeasured) {
302
+ setIsMeasured(true);
303
+ animatedHeight.setValue(contentHeight);
304
+ setOpen(true);
305
+ }
306
+ }, [contentHeight, defaultOpen, isMeasured]);
297
307
  const toggle = () => {
298
- const toValue = open ? 0 : contentHeight;
308
+ if (contentHeight === 0) return;
309
+ const newOpenState = !open;
310
+ const toValue = newOpenState ? contentHeight : 0;
299
311
  import_react_native2.Animated.timing(animatedHeight, {
300
312
  toValue,
301
313
  duration: 250,
302
314
  useNativeDriver: false
303
- }).start();
304
- setOpen(!open);
315
+ }).start(() => {
316
+ setOpen(newOpenState);
317
+ });
318
+ setOpen(newOpenState);
305
319
  };
306
320
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: styles.group, children: [
307
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.TouchableOpacity, { style: styles.header, onPress: toggle, children: [
308
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles.title, children: label }),
309
- renderGroupIcon?.({
310
- name: open ? "chevron-up" : "chevron-down",
311
- size: 18,
312
- color: "#6B7280"
313
- })
314
- ] }),
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
+ ),
315
337
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
316
338
  import_react_native2.View,
317
339
  {
318
340
  style: styles.hidden,
341
+ pointerEvents: "none",
319
342
  onLayout: (e) => {
320
- setContentHeight(e.nativeEvent.layout.height);
343
+ const height = e.nativeEvent.layout.height;
344
+ if (height > 0 && height !== contentHeight) {
345
+ setContentHeight(height);
346
+ }
321
347
  },
322
348
  children
323
349
  }
@@ -325,36 +351,53 @@ function MultiPickerGroup({
325
351
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
326
352
  import_react_native2.Animated.View,
327
353
  {
328
- style: {
329
- height: animatedHeight,
330
- overflow: "hidden"
331
- },
332
- 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 })
333
361
  }
334
362
  )
335
363
  ] });
336
364
  }
337
365
  var styles = import_react_native2.StyleSheet.create({
338
366
  group: {
339
- marginBottom: 12
367
+ marginBottom: 12,
368
+ backgroundColor: "#FFFFFF",
369
+ borderRadius: 8,
370
+ overflow: "hidden"
340
371
  },
341
372
  header: {
342
373
  flexDirection: "row",
343
374
  justifyContent: "space-between",
344
- alignItems: "center"
375
+ alignItems: "center",
376
+ paddingVertical: 12,
377
+ paddingHorizontal: 8,
378
+ backgroundColor: "#F9FAFB",
379
+ borderRadius: 8
345
380
  },
346
381
  title: {
347
382
  fontWeight: "600",
348
- fontSize: 14
383
+ fontSize: 14,
384
+ color: "#1F2937"
385
+ },
386
+ animatedContainer: {
387
+ overflow: "hidden"
349
388
  },
350
389
  content: {
351
- marginTop: 6
390
+ marginTop: 6,
391
+ paddingHorizontal: 8,
392
+ paddingBottom: 4
352
393
  },
353
- // invisible layout measurement
354
394
  hidden: {
355
395
  position: "absolute",
356
396
  opacity: 0,
357
- zIndex: -1
397
+ zIndex: -1,
398
+ top: 0,
399
+ left: 0,
400
+ right: 0
358
401
  }
359
402
  });
360
403
 
@@ -444,8 +487,30 @@ function MultiPickerModal({
444
487
  styles: styles2
445
488
  }) {
446
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;
447
492
  const isControlled = visible !== void 0 && setVisible !== void 0;
448
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]);
449
514
  const open = () => {
450
515
  if (isControlled) setVisible(true);
451
516
  else setInternalVisible(true);
@@ -461,7 +526,9 @@ function MultiPickerModal({
461
526
  const getLabel = () => {
462
527
  if (!selectedValues?.length) return placeholder;
463
528
  const all = groups.length ? groups.flatMap((g) => g.data) : options;
464
- 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(", ");
465
532
  };
466
533
  const renderList = () => {
467
534
  if (groups.length > 0) {
@@ -483,7 +550,7 @@ function MultiPickerModal({
483
550
  item.value
484
551
  ))
485
552
  },
486
- group.label
553
+ `${modalKey}-${group.label}`
487
554
  ));
488
555
  }
489
556
  return options.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -498,6 +565,16 @@ function MultiPickerModal({
498
565
  item.value
499
566
  ));
500
567
  };
568
+ const modalAnimatedStyle = {
569
+ transform: [
570
+ {
571
+ translateY: slideAnim.interpolate({
572
+ inputRange: [0, 1],
573
+ outputRange: [600, 0]
574
+ })
575
+ }
576
+ ]
577
+ };
501
578
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
502
579
  label && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.label, styles2?.label], children: label }),
503
580
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -505,8 +582,20 @@ function MultiPickerModal({
505
582
  {
506
583
  style: [defaultStyles3.box, styles2?.selectBox],
507
584
  onPress: open,
585
+ activeOpacity: 0.7,
508
586
  children: [
509
- /* @__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
+ ),
510
599
  renderInputIcon?.({
511
600
  name: "chevron-down",
512
601
  size: 18,
@@ -516,23 +605,52 @@ function MultiPickerModal({
516
605
  }
517
606
  ),
518
607
  error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.error, styles2?.error], children: error }),
519
- /* @__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: [
520
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
521
- import_react_native4.TouchableOpacity,
522
- {
523
- onPress: close,
524
- style: [defaultStyles3.done, styles2?.doneBtn],
525
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [defaultStyles3.doneText, styles2?.doneText], children: "Done" })
526
- }
527
- ),
528
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.ScrollView, { children: renderList() })
529
- ] }) }) })
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
+ )
530
646
  ] });
531
647
  }
532
648
  var defaultStyles3 = import_react_native4.StyleSheet.create({
533
649
  label: {
534
650
  marginBottom: 6,
535
- fontSize: 14
651
+ fontSize: 14,
652
+ fontWeight: "500",
653
+ color: "#374151"
536
654
  },
537
655
  box: {
538
656
  borderWidth: 1,
@@ -541,27 +659,37 @@ var defaultStyles3 = import_react_native4.StyleSheet.create({
541
659
  padding: 12,
542
660
  flexDirection: "row",
543
661
  justifyContent: "space-between",
544
- alignItems: "center"
662
+ alignItems: "center",
663
+ backgroundColor: "#FFFFFF"
545
664
  },
546
665
  text: {
547
- fontSize: 15
666
+ fontSize: 15,
667
+ color: "#1F2937",
668
+ flex: 1
669
+ },
670
+ placeholder: {
671
+ color: "#9CA3AF"
548
672
  },
549
673
  error: {
550
- color: "red",
674
+ color: "#EF4444",
551
675
  fontSize: 12,
552
676
  marginTop: 4
553
677
  },
554
678
  overlay: {
555
679
  flex: 1,
556
680
  justifyContent: "flex-end",
557
- backgroundColor: "rgba(0,0,0,0.3)"
681
+ backgroundColor: "rgba(0,0,0,0.4)"
558
682
  },
559
683
  container: {
560
684
  backgroundColor: "#fff",
561
685
  padding: 20,
562
686
  borderTopLeftRadius: 20,
563
687
  borderTopRightRadius: 20,
564
- maxHeight: "70%"
688
+ maxHeight: "70%",
689
+ minHeight: "40%"
690
+ },
691
+ scrollContent: {
692
+ paddingBottom: 20
565
693
  },
566
694
  done: {
567
695
  backgroundColor: "#6366f1",
@@ -569,11 +697,14 @@ var defaultStyles3 = import_react_native4.StyleSheet.create({
569
697
  paddingHorizontal: 14,
570
698
  borderRadius: 10,
571
699
  alignSelf: "flex-end",
572
- marginBottom: 10
700
+ marginBottom: 16,
701
+ minWidth: 80,
702
+ alignItems: "center"
573
703
  },
574
704
  doneText: {
575
705
  color: "#fff",
576
- fontWeight: "600"
706
+ fontWeight: "600",
707
+ fontSize: 14
577
708
  }
578
709
  });
579
710
 
@@ -605,18 +736,21 @@ var FloatingButton = class extends import_react4.default.Component {
605
736
  let translateX = 0;
606
737
  let translateY = 0;
607
738
  if (mode === "vertical") {
608
- translateY = -60 * (index + 1);
739
+ translateY = -70 * (index + 1);
740
+ translateX = 0;
609
741
  }
610
742
  if (mode === "horizontal") {
611
- translateX = -60 * (index + 1);
743
+ translateX = -70 * (index + 1);
744
+ translateY = 0;
612
745
  }
613
746
  if (mode === "circle") {
614
- const angleStep = Math.PI / 2;
615
- const angle = index / (actions.length - 1 || 1) * angleStep;
616
- const adjustedRadiusX = radius * 0.7;
617
- const adjustedRadiusY = radius;
618
- translateX = -adjustedRadiusX * Math.cos(angle);
619
- translateY = -adjustedRadiusY * 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);
620
754
  }
621
755
  const animStyle = {
622
756
  transform: [
@@ -635,7 +769,7 @@ var FloatingButton = class extends import_react4.default.Component {
635
769
  {
636
770
  scale: this.animation.interpolate({
637
771
  inputRange: [0, 0.5, 1],
638
- outputRange: [0, 1.1, 1]
772
+ outputRange: [0, 1.2, 1]
639
773
  })
640
774
  }
641
775
  ],
@@ -681,18 +815,48 @@ var FloatingButton = class extends import_react4.default.Component {
681
815
  }
682
816
  ]
683
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
+ };
684
828
  const mainIcon = mainIconName || "add";
685
829
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [defaultStyles4.container, styles2?.container, style], children: [
686
- 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
+ ),
687
851
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.TouchableWithoutFeedback, { onPress: this.toggleMenu, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
688
852
  import_react_native5.Animated.View,
689
853
  {
690
- style: [defaultStyles4.button, styles2?.mainButton, rotation],
691
- 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?.({
692
856
  name: mainIcon,
693
857
  size: 26,
694
858
  color: "#FFF"
695
- })
859
+ }) })
696
860
  }
697
861
  ) })
698
862
  ] });
@@ -701,9 +865,26 @@ var FloatingButton = class extends import_react4.default.Component {
701
865
  var defaultStyles4 = import_react_native5.StyleSheet.create({
702
866
  container: {
703
867
  position: "absolute",
704
- bottom: 110,
868
+ bottom: 100,
705
869
  right: 20,
706
- 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
707
888
  },
708
889
  button: {
709
890
  width: 60,
@@ -713,6 +894,15 @@ var defaultStyles4 = import_react_native5.StyleSheet.create({
713
894
  alignItems: "center",
714
895
  justifyContent: "center"
715
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
+ },
716
906
  secondary: {
717
907
  position: "absolute",
718
908
  width: 48,
@@ -720,7 +910,15 @@ var defaultStyles4 = import_react_native5.StyleSheet.create({
720
910
  borderRadius: 24,
721
911
  backgroundColor: "#F02A4B",
722
912
  alignItems: "center",
723
- 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
724
922
  }
725
923
  });
726
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
@@ -254,7 +255,7 @@ var toggleValue = (arr, value) => {
254
255
  };
255
256
 
256
257
  // src/components/MultiPickerGroup.tsx
257
- import { useRef, useState as useState2 } from "react";
258
+ import { useRef, useState as useState2, useEffect as useEffect2 } from "react";
258
259
  import {
259
260
  View as View2,
260
261
  Text as Text2,
@@ -271,31 +272,57 @@ function MultiPickerGroup({
271
272
  }) {
272
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;
279
+ useEffect2(() => {
280
+ if (defaultOpen && contentHeight > 0 && !isMeasured) {
281
+ setIsMeasured(true);
282
+ animatedHeight.setValue(contentHeight);
283
+ setOpen(true);
284
+ }
285
+ }, [contentHeight, defaultOpen, isMeasured]);
275
286
  const toggle = () => {
276
- const toValue = open ? 0 : contentHeight;
287
+ if (contentHeight === 0) return;
288
+ const newOpenState = !open;
289
+ const toValue = newOpenState ? contentHeight : 0;
277
290
  Animated.timing(animatedHeight, {
278
291
  toValue,
279
292
  duration: 250,
280
293
  useNativeDriver: false
281
- }).start();
282
- setOpen(!open);
294
+ }).start(() => {
295
+ setOpen(newOpenState);
296
+ });
297
+ setOpen(newOpenState);
283
298
  };
284
299
  return /* @__PURE__ */ jsxs2(View2, { style: styles.group, children: [
285
- /* @__PURE__ */ jsxs2(TouchableOpacity2, { style: styles.header, onPress: toggle, children: [
286
- /* @__PURE__ */ jsx2(Text2, { style: styles.title, children: label }),
287
- renderGroupIcon?.({
288
- name: open ? "chevron-up" : "chevron-down",
289
- size: 18,
290
- color: "#6B7280"
291
- })
292
- ] }),
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
+ ),
293
316
  /* @__PURE__ */ jsx2(
294
317
  View2,
295
318
  {
296
319
  style: styles.hidden,
320
+ pointerEvents: "none",
297
321
  onLayout: (e) => {
298
- setContentHeight(e.nativeEvent.layout.height);
322
+ const height = e.nativeEvent.layout.height;
323
+ if (height > 0 && height !== contentHeight) {
324
+ setContentHeight(height);
325
+ }
299
326
  },
300
327
  children
301
328
  }
@@ -303,36 +330,53 @@ function MultiPickerGroup({
303
330
  /* @__PURE__ */ jsx2(
304
331
  Animated.View,
305
332
  {
306
- style: {
307
- height: animatedHeight,
308
- overflow: "hidden"
309
- },
310
- 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 })
311
340
  }
312
341
  )
313
342
  ] });
314
343
  }
315
344
  var styles = StyleSheet2.create({
316
345
  group: {
317
- marginBottom: 12
346
+ marginBottom: 12,
347
+ backgroundColor: "#FFFFFF",
348
+ borderRadius: 8,
349
+ overflow: "hidden"
318
350
  },
319
351
  header: {
320
352
  flexDirection: "row",
321
353
  justifyContent: "space-between",
322
- alignItems: "center"
354
+ alignItems: "center",
355
+ paddingVertical: 12,
356
+ paddingHorizontal: 8,
357
+ backgroundColor: "#F9FAFB",
358
+ borderRadius: 8
323
359
  },
324
360
  title: {
325
361
  fontWeight: "600",
326
- fontSize: 14
362
+ fontSize: 14,
363
+ color: "#1F2937"
364
+ },
365
+ animatedContainer: {
366
+ overflow: "hidden"
327
367
  },
328
368
  content: {
329
- marginTop: 6
369
+ marginTop: 6,
370
+ paddingHorizontal: 8,
371
+ paddingBottom: 4
330
372
  },
331
- // invisible layout measurement
332
373
  hidden: {
333
374
  position: "absolute",
334
375
  opacity: 0,
335
- zIndex: -1
376
+ zIndex: -1,
377
+ top: 0,
378
+ left: 0,
379
+ right: 0
336
380
  }
337
381
  });
338
382
 
@@ -422,8 +466,30 @@ function MultiPickerModal({
422
466
  styles: styles2
423
467
  }) {
424
468
  const [internalVisible, setInternalVisible] = useState3(false);
469
+ const [modalKey, setModalKey] = useState3(0);
470
+ const slideAnim = useRef2(new Animated2.Value(0)).current;
425
471
  const isControlled = visible !== void 0 && setVisible !== void 0;
426
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]);
427
493
  const open = () => {
428
494
  if (isControlled) setVisible(true);
429
495
  else setInternalVisible(true);
@@ -439,7 +505,9 @@ function MultiPickerModal({
439
505
  const getLabel = () => {
440
506
  if (!selectedValues?.length) return placeholder;
441
507
  const all = groups.length ? groups.flatMap((g) => g.data) : options;
442
- 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(", ");
443
511
  };
444
512
  const renderList = () => {
445
513
  if (groups.length > 0) {
@@ -461,7 +529,7 @@ function MultiPickerModal({
461
529
  item.value
462
530
  ))
463
531
  },
464
- group.label
532
+ `${modalKey}-${group.label}`
465
533
  ));
466
534
  }
467
535
  return options.map((item) => /* @__PURE__ */ jsx4(
@@ -476,6 +544,16 @@ function MultiPickerModal({
476
544
  item.value
477
545
  ));
478
546
  };
547
+ const modalAnimatedStyle = {
548
+ transform: [
549
+ {
550
+ translateY: slideAnim.interpolate({
551
+ inputRange: [0, 1],
552
+ outputRange: [600, 0]
553
+ })
554
+ }
555
+ ]
556
+ };
479
557
  return /* @__PURE__ */ jsxs4(Fragment2, { children: [
480
558
  label && /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.label, styles2?.label], children: label }),
481
559
  /* @__PURE__ */ jsxs4(
@@ -483,8 +561,20 @@ function MultiPickerModal({
483
561
  {
484
562
  style: [defaultStyles3.box, styles2?.selectBox],
485
563
  onPress: open,
564
+ activeOpacity: 0.7,
486
565
  children: [
487
- /* @__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
+ ),
488
578
  renderInputIcon?.({
489
579
  name: "chevron-down",
490
580
  size: 18,
@@ -494,23 +584,52 @@ function MultiPickerModal({
494
584
  }
495
585
  ),
496
586
  error && /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.error, styles2?.error], children: error }),
497
- /* @__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: [
498
- /* @__PURE__ */ jsx4(
499
- TouchableOpacity4,
500
- {
501
- onPress: close,
502
- style: [defaultStyles3.done, styles2?.doneBtn],
503
- children: /* @__PURE__ */ jsx4(Text4, { style: [defaultStyles3.doneText, styles2?.doneText], children: "Done" })
504
- }
505
- ),
506
- /* @__PURE__ */ jsx4(ScrollView2, { children: renderList() })
507
- ] }) }) })
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
+ )
508
625
  ] });
509
626
  }
510
627
  var defaultStyles3 = StyleSheet4.create({
511
628
  label: {
512
629
  marginBottom: 6,
513
- fontSize: 14
630
+ fontSize: 14,
631
+ fontWeight: "500",
632
+ color: "#374151"
514
633
  },
515
634
  box: {
516
635
  borderWidth: 1,
@@ -519,27 +638,37 @@ var defaultStyles3 = StyleSheet4.create({
519
638
  padding: 12,
520
639
  flexDirection: "row",
521
640
  justifyContent: "space-between",
522
- alignItems: "center"
641
+ alignItems: "center",
642
+ backgroundColor: "#FFFFFF"
523
643
  },
524
644
  text: {
525
- fontSize: 15
645
+ fontSize: 15,
646
+ color: "#1F2937",
647
+ flex: 1
648
+ },
649
+ placeholder: {
650
+ color: "#9CA3AF"
526
651
  },
527
652
  error: {
528
- color: "red",
653
+ color: "#EF4444",
529
654
  fontSize: 12,
530
655
  marginTop: 4
531
656
  },
532
657
  overlay: {
533
658
  flex: 1,
534
659
  justifyContent: "flex-end",
535
- backgroundColor: "rgba(0,0,0,0.3)"
660
+ backgroundColor: "rgba(0,0,0,0.4)"
536
661
  },
537
662
  container: {
538
663
  backgroundColor: "#fff",
539
664
  padding: 20,
540
665
  borderTopLeftRadius: 20,
541
666
  borderTopRightRadius: 20,
542
- maxHeight: "70%"
667
+ maxHeight: "70%",
668
+ minHeight: "40%"
669
+ },
670
+ scrollContent: {
671
+ paddingBottom: 20
543
672
  },
544
673
  done: {
545
674
  backgroundColor: "#6366f1",
@@ -547,28 +676,31 @@ var defaultStyles3 = StyleSheet4.create({
547
676
  paddingHorizontal: 14,
548
677
  borderRadius: 10,
549
678
  alignSelf: "flex-end",
550
- marginBottom: 10
679
+ marginBottom: 16,
680
+ minWidth: 80,
681
+ alignItems: "center"
551
682
  },
552
683
  doneText: {
553
684
  color: "#fff",
554
- fontWeight: "600"
685
+ fontWeight: "600",
686
+ fontSize: 14
555
687
  }
556
688
  });
557
689
 
558
690
  // src/core/FloatingButton.tsx
559
691
  import React4 from "react";
560
692
  import {
561
- Animated as Animated2,
693
+ Animated as Animated3,
562
694
  StyleSheet as StyleSheet5,
563
695
  TouchableWithoutFeedback,
564
696
  View as View5
565
697
  } from "react-native";
566
698
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
567
699
  var FloatingButton = class extends React4.Component {
568
- animation = new Animated2.Value(0);
700
+ animation = new Animated3.Value(0);
569
701
  open = false;
570
702
  toggleMenu = () => {
571
- Animated2.spring(this.animation, {
703
+ Animated3.spring(this.animation, {
572
704
  toValue: this.open ? 0 : 1,
573
705
  useNativeDriver: true,
574
706
  damping: 12,
@@ -588,18 +720,21 @@ var FloatingButton = class extends React4.Component {
588
720
  let translateX = 0;
589
721
  let translateY = 0;
590
722
  if (mode === "vertical") {
591
- translateY = -60 * (index + 1);
723
+ translateY = -70 * (index + 1);
724
+ translateX = 0;
592
725
  }
593
726
  if (mode === "horizontal") {
594
- translateX = -60 * (index + 1);
727
+ translateX = -70 * (index + 1);
728
+ translateY = 0;
595
729
  }
596
730
  if (mode === "circle") {
597
- const angleStep = Math.PI / 2;
598
- const angle = index / (actions.length - 1 || 1) * angleStep;
599
- const adjustedRadiusX = radius * 0.7;
600
- const adjustedRadiusY = radius;
601
- translateX = -adjustedRadiusX * Math.cos(angle);
602
- translateY = -adjustedRadiusY * 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);
603
738
  }
604
739
  const animStyle = {
605
740
  transform: [
@@ -618,7 +753,7 @@ var FloatingButton = class extends React4.Component {
618
753
  {
619
754
  scale: this.animation.interpolate({
620
755
  inputRange: [0, 0.5, 1],
621
- outputRange: [0, 1.1, 1]
756
+ outputRange: [0, 1.2, 1]
622
757
  })
623
758
  }
624
759
  ],
@@ -633,7 +768,7 @@ var FloatingButton = class extends React4.Component {
633
768
  action.navigateTo?.();
634
769
  },
635
770
  children: /* @__PURE__ */ jsx5(
636
- Animated2.View,
771
+ Animated3.View,
637
772
  {
638
773
  style: [
639
774
  defaultStyles4.secondary,
@@ -664,18 +799,48 @@ var FloatingButton = class extends React4.Component {
664
799
  }
665
800
  ]
666
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
+ };
667
812
  const mainIcon = mainIconName || "add";
668
813
  return /* @__PURE__ */ jsxs5(View5, { style: [defaultStyles4.container, styles2?.container, style], children: [
669
- 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
+ ),
670
835
  /* @__PURE__ */ jsx5(TouchableWithoutFeedback, { onPress: this.toggleMenu, children: /* @__PURE__ */ jsx5(
671
- Animated2.View,
836
+ Animated3.View,
672
837
  {
673
- style: [defaultStyles4.button, styles2?.mainButton, rotation],
674
- children: renderMainIcon?.({
838
+ style: [defaultStyles4.mainButtonWrapper, rotation, scale],
839
+ children: /* @__PURE__ */ jsx5(View5, { style: [defaultStyles4.button, styles2?.mainButton], children: renderMainIcon?.({
675
840
  name: mainIcon,
676
841
  size: 26,
677
842
  color: "#FFF"
678
- })
843
+ }) })
679
844
  }
680
845
  ) })
681
846
  ] });
@@ -684,9 +849,26 @@ var FloatingButton = class extends React4.Component {
684
849
  var defaultStyles4 = StyleSheet5.create({
685
850
  container: {
686
851
  position: "absolute",
687
- bottom: 110,
852
+ bottom: 100,
688
853
  right: 20,
689
- 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
690
872
  },
691
873
  button: {
692
874
  width: 60,
@@ -696,6 +878,15 @@ var defaultStyles4 = StyleSheet5.create({
696
878
  alignItems: "center",
697
879
  justifyContent: "center"
698
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
+ },
699
890
  secondary: {
700
891
  position: "absolute",
701
892
  width: 48,
@@ -703,7 +894,15 @@ var defaultStyles4 = StyleSheet5.create({
703
894
  borderRadius: 24,
704
895
  backgroundColor: "#F02A4B",
705
896
  alignItems: "center",
706
- 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
707
906
  }
708
907
  });
709
908
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaushverse/pickify",
3
- "version": "1.1.5",
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",