@korsolutions/ui 0.0.18 → 0.0.20

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.
Files changed (56) hide show
  1. package/dist/components/index.d.mts +70 -4
  2. package/dist/components/index.mjs +224 -8
  3. package/dist/{index-Bfae0NgJ.d.mts → index-CGY0mO6z.d.mts} +216 -8
  4. package/dist/index.d.mts +3 -3
  5. package/dist/index.mjs +2 -2
  6. package/dist/primitives/index.d.mts +2 -2
  7. package/dist/primitives/index.mjs +2 -2
  8. package/dist/{primitives-B4L9y32H.mjs → primitives-P_8clvQr.mjs} +513 -11
  9. package/dist/{toast-manager-Vq38WK76.mjs → toast-manager-DSo9oN8w.mjs} +1 -1
  10. package/package.json +1 -1
  11. package/src/components/badge/badge.tsx +23 -0
  12. package/src/components/badge/variants/default.tsx +26 -0
  13. package/src/components/badge/variants/index.ts +7 -0
  14. package/src/components/badge/variants/secondary.tsx +26 -0
  15. package/src/components/button/button.tsx +7 -4
  16. package/src/components/dropdown-menu/dropdown-menu.tsx +49 -0
  17. package/src/components/dropdown-menu/variants/default.tsx +40 -0
  18. package/src/components/dropdown-menu/variants/index.ts +5 -0
  19. package/src/components/index.ts +4 -0
  20. package/src/components/popover/popover.tsx +51 -0
  21. package/src/components/popover/variants/default.tsx +26 -0
  22. package/src/components/popover/variants/index.ts +5 -0
  23. package/src/components/textarea/textarea.tsx +14 -0
  24. package/src/components/textarea/variants/default.tsx +38 -0
  25. package/src/components/textarea/variants/index.ts +5 -0
  26. package/src/hooks/useRelativePosition.ts +188 -0
  27. package/src/primitives/badge/badge-label.tsx +21 -0
  28. package/src/primitives/badge/badge-root.tsx +30 -0
  29. package/src/primitives/badge/context.ts +17 -0
  30. package/src/primitives/badge/index.ts +11 -0
  31. package/src/primitives/badge/types.ts +9 -0
  32. package/src/primitives/button/button-root.tsx +2 -4
  33. package/src/primitives/dropdown-menu/context.ts +25 -0
  34. package/src/primitives/dropdown-menu/dropdown-menu-button.tsx +47 -0
  35. package/src/primitives/dropdown-menu/dropdown-menu-content.tsx +39 -0
  36. package/src/primitives/dropdown-menu/dropdown-menu-divider.tsx +18 -0
  37. package/src/primitives/dropdown-menu/dropdown-menu-overlay.tsx +29 -0
  38. package/src/primitives/dropdown-menu/dropdown-menu-portal.tsx +21 -0
  39. package/src/primitives/dropdown-menu/dropdown-menu-root.tsx +35 -0
  40. package/src/primitives/dropdown-menu/dropdown-menu-trigger.tsx +47 -0
  41. package/src/primitives/dropdown-menu/index.ts +26 -0
  42. package/src/primitives/dropdown-menu/types.ts +13 -0
  43. package/src/primitives/index.ts +4 -0
  44. package/src/primitives/popover/context.ts +25 -0
  45. package/src/primitives/popover/index.ts +24 -0
  46. package/src/primitives/popover/popover-close.tsx +29 -0
  47. package/src/primitives/popover/popover-content.tsx +39 -0
  48. package/src/primitives/popover/popover-overlay.tsx +37 -0
  49. package/src/primitives/popover/popover-portal.tsx +21 -0
  50. package/src/primitives/popover/popover-root.tsx +35 -0
  51. package/src/primitives/popover/popover-trigger.tsx +47 -0
  52. package/src/primitives/popover/types.ts +7 -0
  53. package/src/primitives/textarea/index.ts +2 -0
  54. package/src/primitives/textarea/textarea.tsx +56 -0
  55. package/src/primitives/textarea/types.ts +5 -0
  56. package/src/utils/get-ref-layout.ts +16 -0
@@ -1,5 +1,6 @@
1
- import React, { createContext, useContext, useEffect, useState, useSyncExternalStore } from "react";
2
- import { ActivityIndicator, Image, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
1
+ import * as React$1 from "react";
2
+ import React, { createContext, forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState, useSyncExternalStore } from "react";
3
+ import { ActivityIndicator, Image, Pressable, StyleSheet, Text, TextInput, View, useWindowDimensions } from "react-native";
3
4
  import { Fragment, jsx } from "react/jsx-runtime";
4
5
 
5
6
  //#region src/primitives/portal/portal.tsx
@@ -122,14 +123,14 @@ const FieldPrimitive = {
122
123
 
123
124
  //#endregion
124
125
  //#region src/primitives/input/input.tsx
125
- const calculateState$3 = (props, isFocused) => {
126
+ const calculateState$5 = (props, isFocused) => {
126
127
  if (props.isDisabled) return "disabled";
127
128
  if (isFocused) return "focused";
128
129
  return "default";
129
130
  };
130
131
  function InputPrimitive(props) {
131
132
  const [isFocused, setIsFocused] = useState(false);
132
- const state = calculateState$3(props, isFocused);
133
+ const state = calculateState$5(props, isFocused);
133
134
  const composedStyles = [
134
135
  props.styles?.default?.style,
135
136
  props.styles?.[state]?.style,
@@ -168,7 +169,7 @@ const useButtonPrimitive = () => {
168
169
 
169
170
  //#endregion
170
171
  //#region src/primitives/button/button-root.tsx
171
- const calculateState$2 = (props, isHovered) => {
172
+ const calculateState$4 = (props, isHovered) => {
172
173
  if (props.isDisabled) return "disabled";
173
174
  if (props.isLoading) return "loading";
174
175
  if (isHovered) return "hovered";
@@ -176,7 +177,7 @@ const calculateState$2 = (props, isHovered) => {
176
177
  };
177
178
  function ButtonRoot(props) {
178
179
  const [isHovered, setIsHovered] = useState(false);
179
- const state = calculateState$2(props, isHovered);
180
+ const state = calculateState$4(props, isHovered);
180
181
  const calculatedStyle = [
181
182
  props.styles?.root?.default,
182
183
  props.styles?.root?.[state],
@@ -246,7 +247,7 @@ const useSelect = () => {
246
247
 
247
248
  //#endregion
248
249
  //#region src/primitives/select/select-root.tsx
249
- const calculateState$1 = (props) => {
250
+ const calculateState$3 = (props) => {
250
251
  if (props.isDisabled) return "disabled";
251
252
  return "default";
252
253
  };
@@ -254,7 +255,7 @@ function SelectRoot(props) {
254
255
  const [isOpen, setIsOpen] = useState(false);
255
256
  const [triggerLayout, setTriggerLayout] = useState(null);
256
257
  const [options, setOptions] = useState([]);
257
- const state = calculateState$1(props);
258
+ const state = calculateState$3(props);
258
259
  const composedStyles = calculateComposedStyles(props.styles, state, "root", props.style);
259
260
  const Component = props.render ?? View;
260
261
  return /* @__PURE__ */ jsx(SelectContext.Provider, {
@@ -370,7 +371,7 @@ function SelectContent(props) {
370
371
 
371
372
  //#endregion
372
373
  //#region src/primitives/select/select-option.tsx
373
- const calculateState = (selectState, hovered, selected) => {
374
+ const calculateState$2 = (selectState, hovered, selected) => {
374
375
  if (selectState === "disabled") return "disabled";
375
376
  if (selected) return "selected";
376
377
  if (hovered) return "hovered";
@@ -380,7 +381,7 @@ function SelectOption(props) {
380
381
  const [isHovered, setIsHovered] = useState(false);
381
382
  const select = useSelect();
382
383
  const isSelected = select.value === props.value;
383
- const optionState = calculateState(select.state, isHovered, isSelected);
384
+ const optionState = calculateState$2(select.state, isHovered, isSelected);
384
385
  const composedStyles = calculateComposedStyles(select.styles, optionState, "option", props.style);
385
386
  useEffect(() => {
386
387
  select.setOptions((prev) => {
@@ -661,4 +662,505 @@ const ToastPrimitive = {
661
662
  };
662
663
 
663
664
  //#endregion
664
- export { SelectPrimitive as a, FieldPrimitive as c, CardPrimitive as i, PortalHost as l, AvatarPrimitive as n, ButtonPrimitive as o, EmptyPrimitive as r, InputPrimitive as s, ToastPrimitive as t };
665
+ //#region src/primitives/badge/context.ts
666
+ const BadgeContext = createContext(void 0);
667
+ const useBadge = () => {
668
+ const context = useContext(BadgeContext);
669
+ if (!context) throw new Error("useBadge must be used within a BadgeProvider");
670
+ return context;
671
+ };
672
+
673
+ //#endregion
674
+ //#region src/primitives/badge/badge-root.tsx
675
+ function BadgeRoot(props) {
676
+ const composedStyle = calculateComposedStyles(props.styles, "default", "root", props.style);
677
+ const Component = props.render ?? View;
678
+ return /* @__PURE__ */ jsx(BadgeContext.Provider, {
679
+ value: {
680
+ state: "default",
681
+ styles: props.styles
682
+ },
683
+ children: /* @__PURE__ */ jsx(Component, {
684
+ ...props,
685
+ style: composedStyle
686
+ })
687
+ });
688
+ }
689
+
690
+ //#endregion
691
+ //#region src/primitives/badge/badge-label.tsx
692
+ function BadgeLabel(props) {
693
+ const badge = useBadge();
694
+ const composedStyle = calculateComposedStyles(badge.styles, badge.state, "label", props.style);
695
+ return /* @__PURE__ */ jsx(props.render ?? Text, {
696
+ ...props,
697
+ style: composedStyle
698
+ });
699
+ }
700
+
701
+ //#endregion
702
+ //#region src/primitives/badge/index.ts
703
+ const BadgePrimitive = {
704
+ Root: BadgeRoot,
705
+ Label: BadgeLabel
706
+ };
707
+
708
+ //#endregion
709
+ //#region src/primitives/textarea/textarea.tsx
710
+ const calculateState$1 = (props, isFocused) => {
711
+ if (props.isDisabled) return "disabled";
712
+ if (isFocused) return "focused";
713
+ return "default";
714
+ };
715
+ function TextareaPrimitive(props) {
716
+ const [isFocused, setIsFocused] = useState(false);
717
+ const state = calculateState$1(props, isFocused);
718
+ const composedStyles = [
719
+ props.styles?.default?.style,
720
+ props.styles?.[state]?.style,
721
+ props.style
722
+ ];
723
+ const composedProps = {
724
+ ...props.styles?.default,
725
+ ...props.styles?.[state],
726
+ ...props
727
+ };
728
+ return /* @__PURE__ */ jsx(props.render ?? TextInput, {
729
+ ...composedProps,
730
+ multiline: true,
731
+ onChange: void 0,
732
+ onChangeText: props.onChange,
733
+ onFocus: (e) => {
734
+ setIsFocused(true);
735
+ props.onFocus?.(e);
736
+ },
737
+ onBlur: (e) => {
738
+ setIsFocused(false);
739
+ props.onBlur?.(e);
740
+ },
741
+ readOnly: props.isDisabled || props.readOnly,
742
+ style: composedStyles
743
+ });
744
+ }
745
+
746
+ //#endregion
747
+ //#region src/primitives/dropdown-menu/context.ts
748
+ const DropdownMenuContext = createContext(void 0);
749
+ const useDropdownMenu = () => {
750
+ const context = useContext(DropdownMenuContext);
751
+ if (!context) throw new Error("useDropdownMenu must be used within a DropdownMenuRoot");
752
+ return context;
753
+ };
754
+
755
+ //#endregion
756
+ //#region src/hooks/useRelativePosition.ts
757
+ function useRelativePosition({ align, avoidCollisions, triggerPosition, contentLayout, alignOffset, insets, sideOffset, side }) {
758
+ const dimensions = useWindowDimensions();
759
+ return React$1.useMemo(() => {
760
+ if (!triggerPosition || !contentLayout) return {
761
+ position: "absolute",
762
+ opacity: 0,
763
+ top: dimensions.height,
764
+ zIndex: -9999999
765
+ };
766
+ return getContentStyle({
767
+ align,
768
+ avoidCollisions,
769
+ contentLayout,
770
+ side,
771
+ triggerPosition,
772
+ alignOffset,
773
+ insets,
774
+ sideOffset,
775
+ dimensions
776
+ });
777
+ }, [
778
+ align,
779
+ avoidCollisions,
780
+ side,
781
+ alignOffset,
782
+ insets,
783
+ triggerPosition,
784
+ contentLayout,
785
+ dimensions.width,
786
+ dimensions.height
787
+ ]);
788
+ }
789
+ const DEFAULT_LAYOUT = {
790
+ x: 0,
791
+ y: 0,
792
+ width: 0,
793
+ height: 0
794
+ };
795
+ const DEFAULT_POSITION = {
796
+ height: 0,
797
+ width: 0,
798
+ pageX: 0,
799
+ pageY: 0
800
+ };
801
+ function getSidePosition({ side, triggerPosition, contentLayout, sideOffset, insets, avoidCollisions, dimensions }) {
802
+ const insetTop = insets?.top ?? 0;
803
+ const insetBottom = insets?.bottom ?? 0;
804
+ const positionTop = triggerPosition?.pageY - sideOffset - contentLayout.height;
805
+ const positionBottom = triggerPosition.pageY + triggerPosition.height + sideOffset;
806
+ if (!avoidCollisions) return { top: side === "top" ? positionTop : positionBottom };
807
+ if (side === "top") return { top: Math.min(Math.max(insetTop, positionTop), dimensions.height - insetBottom - contentLayout.height) };
808
+ return { top: Math.min(dimensions.height - insetBottom - contentLayout.height, positionBottom) };
809
+ }
810
+ function getAlignPosition({ align, avoidCollisions, contentLayout, triggerPosition, alignOffset, insets, dimensions }) {
811
+ const insetLeft = insets?.left ?? 0;
812
+ const insetRight = insets?.right ?? 0;
813
+ const maxContentWidth = dimensions.width - insetLeft - insetRight;
814
+ const contentWidth = Math.min(contentLayout.width, maxContentWidth);
815
+ let left = getLeftPosition(align, triggerPosition.pageX, triggerPosition.width, contentWidth, alignOffset, insetLeft, insetRight, dimensions);
816
+ if (avoidCollisions) {
817
+ if (left < insetLeft || left + contentWidth > dimensions.width - insetRight) {
818
+ const spaceLeft = left - insetLeft;
819
+ const spaceRight = dimensions.width - insetRight - (left + contentWidth);
820
+ if (spaceLeft > spaceRight && spaceLeft >= contentWidth) left = insetLeft;
821
+ else if (spaceRight >= contentWidth) left = dimensions.width - insetRight - contentWidth;
822
+ else left = Math.max(insetLeft, (dimensions.width - contentWidth - insetRight) / 2);
823
+ }
824
+ }
825
+ return {
826
+ left,
827
+ maxWidth: maxContentWidth
828
+ };
829
+ }
830
+ function getLeftPosition(align, triggerPageX, triggerWidth, contentWidth, alignOffset, insetLeft, insetRight, dimensions) {
831
+ let left = 0;
832
+ if (align === "start") left = triggerPageX;
833
+ if (align === "center") left = triggerPageX + triggerWidth / 2 - contentWidth / 2;
834
+ if (align === "end") left = triggerPageX + triggerWidth - contentWidth;
835
+ return Math.max(insetLeft, Math.min(left + alignOffset, dimensions.width - contentWidth - insetRight));
836
+ }
837
+ function getContentStyle({ align, avoidCollisions, contentLayout, side, triggerPosition, alignOffset, insets, sideOffset, dimensions }) {
838
+ return Object.assign({ position: "absolute" }, getSidePosition({
839
+ side,
840
+ triggerPosition,
841
+ contentLayout,
842
+ sideOffset,
843
+ insets,
844
+ avoidCollisions,
845
+ dimensions
846
+ }), getAlignPosition({
847
+ align,
848
+ avoidCollisions,
849
+ triggerPosition,
850
+ contentLayout,
851
+ alignOffset,
852
+ insets,
853
+ dimensions
854
+ }));
855
+ }
856
+
857
+ //#endregion
858
+ //#region src/primitives/dropdown-menu/dropdown-menu-root.tsx
859
+ function DropdownMenuRoot(props) {
860
+ const [isOpen, setIsOpen] = useState(false);
861
+ const [triggerPosition, setTriggerPosition] = useState(DEFAULT_POSITION);
862
+ const [contentLayout, setContentLayout] = useState(DEFAULT_LAYOUT);
863
+ return /* @__PURE__ */ jsx(DropdownMenuContext.Provider, {
864
+ value: {
865
+ isOpen,
866
+ setIsOpen,
867
+ triggerPosition,
868
+ setTriggerPosition,
869
+ contentLayout,
870
+ setContentLayout,
871
+ styles: props.styles
872
+ },
873
+ children: props.children
874
+ });
875
+ }
876
+
877
+ //#endregion
878
+ //#region src/primitives/dropdown-menu/dropdown-menu-trigger.tsx
879
+ const DropdownMenuTrigger = forwardRef((props, ref) => {
880
+ const dropdownMenu = useDropdownMenu();
881
+ const triggerRef = useRef(null);
882
+ const onTriggerPress = async () => {
883
+ triggerRef.current?.measure((_x, _y, width, height, pageX, pageY) => {
884
+ dropdownMenu.setTriggerPosition({
885
+ height,
886
+ width,
887
+ pageX,
888
+ pageY
889
+ });
890
+ });
891
+ dropdownMenu.setIsOpen((prev) => !prev);
892
+ };
893
+ useImperativeHandle(ref, () => ({
894
+ open: () => dropdownMenu.setIsOpen(true),
895
+ close: () => dropdownMenu.setIsOpen(false)
896
+ }));
897
+ return React.cloneElement(props.children, {
898
+ ref: triggerRef,
899
+ onPress: onTriggerPress,
900
+ role: "button",
901
+ accessible: true,
902
+ accessibilityRole: "button",
903
+ accessibilityState: { expanded: dropdownMenu.isOpen },
904
+ ...props.children.props
905
+ });
906
+ });
907
+ DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
908
+
909
+ //#endregion
910
+ //#region src/primitives/dropdown-menu/dropdown-menu-content.tsx
911
+ function DropdownMenuContent(props) {
912
+ const menu = useDropdownMenu();
913
+ const composedStyle = [
914
+ useRelativePosition({
915
+ align: "start",
916
+ avoidCollisions: true,
917
+ triggerPosition: menu.triggerPosition,
918
+ contentLayout: menu.contentLayout,
919
+ alignOffset: 0,
920
+ side: "bottom",
921
+ sideOffset: 0
922
+ }),
923
+ menu.styles?.content,
924
+ props.style
925
+ ];
926
+ return /* @__PURE__ */ jsx(props.render ?? View, {
927
+ ...props,
928
+ onLayout: (e) => {
929
+ menu.setContentLayout(e.nativeEvent.layout);
930
+ },
931
+ style: composedStyle
932
+ });
933
+ }
934
+
935
+ //#endregion
936
+ //#region src/primitives/dropdown-menu/dropdown-menu-button.tsx
937
+ const calculateState = (isHovered) => {
938
+ if (isHovered) return "hovered";
939
+ return "default";
940
+ };
941
+ function DropdownMenuButton(props) {
942
+ const menu = useDropdownMenu();
943
+ const [isHovered, setIsHovered] = useState(false);
944
+ const state = calculateState(isHovered);
945
+ const composedStyle = [
946
+ menu.styles?.button?.default,
947
+ menu.styles?.button?.[state],
948
+ props.style
949
+ ];
950
+ const handlePress = () => {
951
+ props.onPress?.();
952
+ menu.setIsOpen((prev) => !prev);
953
+ };
954
+ return /* @__PURE__ */ jsx(props.render ?? Text, {
955
+ ...props,
956
+ onPress: handlePress,
957
+ onMouseEnter: () => setIsHovered(true),
958
+ onMouseLeave: () => setIsHovered(false),
959
+ style: composedStyle,
960
+ children: props.children
961
+ });
962
+ }
963
+
964
+ //#endregion
965
+ //#region src/primitives/dropdown-menu/dropdown-menu-divider.tsx
966
+ function DropdownMenuDivider(props) {
967
+ const composedStyle = [useDropdownMenu().styles?.divider, props.style];
968
+ return /* @__PURE__ */ jsx(props.render ?? View, {
969
+ ...props,
970
+ style: composedStyle
971
+ });
972
+ }
973
+
974
+ //#endregion
975
+ //#region src/primitives/dropdown-menu/dropdown-menu-portal.tsx
976
+ function DropdownMenuPortal(props) {
977
+ const menu = useDropdownMenu();
978
+ if (!menu.isOpen) return null;
979
+ return /* @__PURE__ */ jsx(Portal, {
980
+ name: "dropdown-menu-portal",
981
+ children: /* @__PURE__ */ jsx(DropdownMenuContext.Provider, {
982
+ value: menu,
983
+ children: props.children
984
+ })
985
+ });
986
+ }
987
+
988
+ //#endregion
989
+ //#region src/primitives/dropdown-menu/dropdown-menu-overlay.tsx
990
+ function DropdownMenuOverlay(props) {
991
+ const menu = useDropdownMenu();
992
+ const composedStyle = [
993
+ StyleSheet.absoluteFill,
994
+ menu.styles?.overlay,
995
+ props.style
996
+ ];
997
+ return /* @__PURE__ */ jsx(props.render ?? Pressable, {
998
+ onPress: () => {
999
+ menu.setIsOpen(false);
1000
+ },
1001
+ style: composedStyle,
1002
+ children: props.children
1003
+ });
1004
+ }
1005
+
1006
+ //#endregion
1007
+ //#region src/primitives/dropdown-menu/index.ts
1008
+ const DropdownMenuPrimitive = {
1009
+ Root: DropdownMenuRoot,
1010
+ Trigger: DropdownMenuTrigger,
1011
+ Portal: DropdownMenuPortal,
1012
+ Overlay: DropdownMenuOverlay,
1013
+ Content: DropdownMenuContent,
1014
+ Button: DropdownMenuButton,
1015
+ Divider: DropdownMenuDivider
1016
+ };
1017
+
1018
+ //#endregion
1019
+ //#region src/primitives/popover/context.ts
1020
+ const PopoverContext = createContext(void 0);
1021
+ const usePopover = () => {
1022
+ const context = useContext(PopoverContext);
1023
+ if (!context) throw new Error("usePopover must be used within a PopoverRoot");
1024
+ return context;
1025
+ };
1026
+
1027
+ //#endregion
1028
+ //#region src/primitives/popover/popover-root.tsx
1029
+ function PopoverRoot(props) {
1030
+ const [isOpen, setIsOpen] = useState(false);
1031
+ const [contentLayout, setContentLayout] = useState(DEFAULT_LAYOUT);
1032
+ const [triggerPosition, setTriggerPosition] = useState(DEFAULT_POSITION);
1033
+ return /* @__PURE__ */ jsx(PopoverContext.Provider, {
1034
+ value: {
1035
+ isOpen,
1036
+ setIsOpen,
1037
+ contentLayout,
1038
+ setContentLayout,
1039
+ triggerPosition,
1040
+ setTriggerPosition,
1041
+ styles: props.styles
1042
+ },
1043
+ children: props.children
1044
+ });
1045
+ }
1046
+
1047
+ //#endregion
1048
+ //#region src/primitives/popover/popover-trigger.tsx
1049
+ const PopoverTrigger = forwardRef((props, ref) => {
1050
+ const popover = usePopover();
1051
+ const triggerRef = useRef(null);
1052
+ const onTriggerPress = async () => {
1053
+ triggerRef.current?.measure((_x, _y, width, height, pageX, pageY) => {
1054
+ popover.setTriggerPosition({
1055
+ height,
1056
+ width,
1057
+ pageX,
1058
+ pageY
1059
+ });
1060
+ });
1061
+ popover.setIsOpen((prev) => !prev);
1062
+ };
1063
+ useImperativeHandle(ref, () => ({
1064
+ open: () => popover.setIsOpen(true),
1065
+ close: () => popover.setIsOpen(false)
1066
+ }));
1067
+ return React.cloneElement(props.children, {
1068
+ ref: triggerRef,
1069
+ onPress: onTriggerPress,
1070
+ role: "button",
1071
+ accessible: true,
1072
+ accessibilityRole: "button",
1073
+ accessibilityState: { expanded: popover.isOpen },
1074
+ ...props.children.props
1075
+ });
1076
+ });
1077
+ PopoverTrigger.displayName = "PopoverTrigger";
1078
+
1079
+ //#endregion
1080
+ //#region src/primitives/popover/popover-portal.tsx
1081
+ function PopoverPortal(props) {
1082
+ const popover = usePopover();
1083
+ if (!popover.isOpen) return null;
1084
+ return /* @__PURE__ */ jsx(Portal, {
1085
+ name: "popover-portal",
1086
+ children: /* @__PURE__ */ jsx(PopoverContext.Provider, {
1087
+ value: popover,
1088
+ children: props.children
1089
+ })
1090
+ });
1091
+ }
1092
+
1093
+ //#endregion
1094
+ //#region src/primitives/popover/popover-overlay.tsx
1095
+ function PopoverOverlay(props) {
1096
+ const { closeOnPress = true, ...restProps } = props;
1097
+ const popover = usePopover();
1098
+ const composedStyle = [
1099
+ StyleSheet.absoluteFill,
1100
+ popover.styles?.overlay,
1101
+ props.style
1102
+ ];
1103
+ return /* @__PURE__ */ jsx(props.render ?? Pressable, {
1104
+ ...restProps,
1105
+ onPress: () => {
1106
+ if (closeOnPress) popover.setIsOpen(false);
1107
+ props.onPress?.();
1108
+ },
1109
+ style: composedStyle,
1110
+ children: props.children
1111
+ });
1112
+ }
1113
+
1114
+ //#endregion
1115
+ //#region src/primitives/popover/popover-content.tsx
1116
+ function PopoverContent(props) {
1117
+ const popover = usePopover();
1118
+ const composedStyle = [
1119
+ useRelativePosition({
1120
+ align: "start",
1121
+ avoidCollisions: true,
1122
+ triggerPosition: popover.triggerPosition,
1123
+ contentLayout: popover.contentLayout,
1124
+ alignOffset: 0,
1125
+ side: "bottom",
1126
+ sideOffset: 0
1127
+ }),
1128
+ popover.styles?.content,
1129
+ props.style
1130
+ ];
1131
+ return /* @__PURE__ */ jsx(props.render ?? View, {
1132
+ ...props,
1133
+ onLayout: (e) => {
1134
+ popover.setContentLayout(e.nativeEvent.layout);
1135
+ },
1136
+ style: composedStyle
1137
+ });
1138
+ }
1139
+
1140
+ //#endregion
1141
+ //#region src/primitives/popover/popover-close.tsx
1142
+ function PopoverClose(props) {
1143
+ const popover = usePopover();
1144
+ return /* @__PURE__ */ jsx(props.render ?? Pressable, {
1145
+ ...props,
1146
+ onPress: () => {
1147
+ popover.setIsOpen(false);
1148
+ props.onPress?.();
1149
+ },
1150
+ style: props.style
1151
+ });
1152
+ }
1153
+
1154
+ //#endregion
1155
+ //#region src/primitives/popover/index.ts
1156
+ const PopoverPrimitive = {
1157
+ Root: PopoverRoot,
1158
+ Trigger: PopoverTrigger,
1159
+ Portal: PopoverPortal,
1160
+ Overlay: PopoverOverlay,
1161
+ Content: PopoverContent,
1162
+ Close: PopoverClose
1163
+ };
1164
+
1165
+ //#endregion
1166
+ export { BadgePrimitive as a, EmptyPrimitive as c, ButtonPrimitive as d, InputPrimitive as f, TextareaPrimitive as i, CardPrimitive as l, PortalHost as m, usePopover as n, ToastPrimitive as o, FieldPrimitive as p, DropdownMenuPrimitive as r, AvatarPrimitive as s, PopoverPrimitive as t, SelectPrimitive as u };
@@ -1,4 +1,4 @@
1
- import { t as ToastPrimitive } from "./primitives-B4L9y32H.mjs";
1
+ import { o as ToastPrimitive } from "./primitives-P_8clvQr.mjs";
2
2
  import React, { createContext, useContext, useEffect, useState, useSyncExternalStore } from "react";
3
3
  import { StyleSheet, View, useColorScheme } from "react-native";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@korsolutions/ui",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.mjs",
6
6
  "module": "dist/index.mjs",
@@ -0,0 +1,23 @@
1
+ import { BadgePrimitive } from "@/primitives";
2
+ import React from "react";
3
+ import { BadgeVariants } from "./variants";
4
+
5
+ interface BadgeProps {
6
+ children: string;
7
+ variant?: keyof typeof BadgeVariants;
8
+ color?: string;
9
+ }
10
+
11
+ export function Badge(props: BadgeProps) {
12
+ const useVariantStyles = BadgeVariants[props.variant || "default"];
13
+ const styles = useVariantStyles();
14
+
15
+ // Override background color if custom color is provided
16
+ const customStyle = props.color ? { backgroundColor: props.color } : undefined;
17
+
18
+ return (
19
+ <BadgePrimitive.Root styles={styles} style={customStyle}>
20
+ <BadgePrimitive.Label>{props.children}</BadgePrimitive.Label>
21
+ </BadgePrimitive.Root>
22
+ );
23
+ }
@@ -0,0 +1,26 @@
1
+ import { BadgeStyles } from "@/primitives";
2
+ import { useThemedStyles } from "@/utils/use-themed-styles";
3
+
4
+ export const useBadgeVariantDefault = (): BadgeStyles => {
5
+ return useThemedStyles(
6
+ ({ colors, radius, fontFamily, fontSize }): BadgeStyles => ({
7
+ root: {
8
+ default: {
9
+ backgroundColor: colors.primary,
10
+ paddingVertical: 4,
11
+ paddingHorizontal: 8,
12
+ borderRadius: radius,
13
+ alignSelf: "flex-start",
14
+ },
15
+ },
16
+ label: {
17
+ default: {
18
+ color: colors.primaryForeground,
19
+ fontSize: fontSize * 0.75,
20
+ fontWeight: "600",
21
+ fontFamily,
22
+ },
23
+ },
24
+ })
25
+ );
26
+ };
@@ -0,0 +1,7 @@
1
+ import { useBadgeVariantDefault } from "./default";
2
+ import { useBadgeVariantSecondary } from "./secondary";
3
+
4
+ export const BadgeVariants = {
5
+ default: useBadgeVariantDefault,
6
+ secondary: useBadgeVariantSecondary,
7
+ };
@@ -0,0 +1,26 @@
1
+ import { BadgeStyles } from "@/primitives";
2
+ import { useThemedStyles } from "@/utils/use-themed-styles";
3
+
4
+ export const useBadgeVariantSecondary = (): BadgeStyles => {
5
+ return useThemedStyles(
6
+ ({ colors, radius, fontFamily, fontSize }): BadgeStyles => ({
7
+ root: {
8
+ default: {
9
+ backgroundColor: colors.secondary,
10
+ paddingVertical: 4,
11
+ paddingHorizontal: 8,
12
+ borderRadius: radius,
13
+ alignSelf: "flex-start",
14
+ },
15
+ },
16
+ label: {
17
+ default: {
18
+ color: colors.secondaryForeground,
19
+ fontSize: fontSize * 0.75,
20
+ fontWeight: "600",
21
+ fontFamily,
22
+ },
23
+ },
24
+ })
25
+ );
26
+ };