@korsolutions/ui 0.0.20 → 0.0.22
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/components/index.d.mts +50 -2
- package/dist/components/index.mjs +177 -4
- package/dist/hooks/index.d.mts +32 -2
- package/dist/hooks/index.mjs +79 -2
- package/dist/{index-CGY0mO6z.d.mts → index-vgnXBa4Z.d.mts} +98 -10
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -2
- package/dist/primitives/index.d.mts +3 -2
- package/dist/primitives/index.mjs +3 -2
- package/dist/{primitives-P_8clvQr.mjs → primitives-ApsPS0vU.mjs} +335 -118
- package/dist/{toast-manager-DSo9oN8w.mjs → toast-manager-Cdhl1ep0.mjs} +1 -1
- package/dist/use-numeric-mask-B9WZG25o.d.mts +33 -0
- package/dist/use-numeric-mask-BQlz1Pus.mjs +113 -0
- package/dist/use-relative-position-BTKEyT1F.mjs +106 -0
- package/dist/use-relative-position-DBzhrBU7.d.mts +61 -0
- package/package.json +1 -1
- package/src/components/calendar/calendar.tsx +31 -0
- package/src/components/calendar/index.ts +1 -0
- package/src/components/calendar/variants/default.tsx +127 -0
- package/src/components/calendar/variants/index.ts +5 -0
- package/src/components/index.ts +2 -1
- package/src/components/input/index.ts +2 -0
- package/src/components/input/numeric-input.tsx +73 -0
- package/src/hooks/index.ts +4 -1
- package/src/hooks/use-currency-mask.ts +141 -0
- package/src/hooks/use-numeric-mask.ts +202 -0
- package/src/primitives/calendar/calendar-day.tsx +64 -0
- package/src/primitives/calendar/calendar-header.tsx +21 -0
- package/src/primitives/calendar/calendar-nav-button.tsx +60 -0
- package/src/primitives/calendar/calendar-root.tsx +41 -0
- package/src/primitives/calendar/calendar-title.tsx +23 -0
- package/src/primitives/calendar/calendar-week-labels.tsx +45 -0
- package/src/primitives/calendar/calendar-weeks.tsx +47 -0
- package/src/primitives/calendar/context.ts +23 -0
- package/src/primitives/calendar/index.ts +26 -0
- package/src/primitives/calendar/types.ts +39 -0
- package/src/primitives/dropdown-menu/context.ts +1 -1
- package/src/primitives/dropdown-menu/dropdown-menu-content.tsx +1 -1
- package/src/primitives/dropdown-menu/dropdown-menu-root.tsx +1 -1
- package/src/primitives/index.ts +1 -0
- package/src/primitives/popover/context.ts +1 -1
- package/src/primitives/popover/popover-content.tsx +1 -1
- package/src/primitives/popover/popover-root.tsx +1 -1
- package/src/utils/date-utils.ts +113 -0
- /package/src/hooks/{useRelativePosition.ts → use-relative-position.ts} +0 -0
- /package/src/hooks/{useScreenSize.ts → use-screen-size.ts} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import React, { createContext, forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState, useSyncExternalStore } from "react";
|
|
3
|
-
import { ActivityIndicator, Image, Pressable, StyleSheet, Text, TextInput, View
|
|
1
|
+
import { n as DEFAULT_POSITION, r as useRelativePosition, t as DEFAULT_LAYOUT } from "./use-relative-position-BTKEyT1F.mjs";
|
|
2
|
+
import React, { createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
3
|
+
import { ActivityIndicator, Image, Pressable, StyleSheet, Text, TextInput, View } from "react-native";
|
|
4
4
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
5
5
|
|
|
6
6
|
//#region src/primitives/portal/portal.tsx
|
|
@@ -123,14 +123,14 @@ const FieldPrimitive = {
|
|
|
123
123
|
|
|
124
124
|
//#endregion
|
|
125
125
|
//#region src/primitives/input/input.tsx
|
|
126
|
-
const calculateState$
|
|
126
|
+
const calculateState$7 = (props, isFocused) => {
|
|
127
127
|
if (props.isDisabled) return "disabled";
|
|
128
128
|
if (isFocused) return "focused";
|
|
129
129
|
return "default";
|
|
130
130
|
};
|
|
131
131
|
function InputPrimitive(props) {
|
|
132
132
|
const [isFocused, setIsFocused] = useState(false);
|
|
133
|
-
const state = calculateState$
|
|
133
|
+
const state = calculateState$7(props, isFocused);
|
|
134
134
|
const composedStyles = [
|
|
135
135
|
props.styles?.default?.style,
|
|
136
136
|
props.styles?.[state]?.style,
|
|
@@ -169,7 +169,7 @@ const useButtonPrimitive = () => {
|
|
|
169
169
|
|
|
170
170
|
//#endregion
|
|
171
171
|
//#region src/primitives/button/button-root.tsx
|
|
172
|
-
const calculateState$
|
|
172
|
+
const calculateState$6 = (props, isHovered) => {
|
|
173
173
|
if (props.isDisabled) return "disabled";
|
|
174
174
|
if (props.isLoading) return "loading";
|
|
175
175
|
if (isHovered) return "hovered";
|
|
@@ -177,7 +177,7 @@ const calculateState$4 = (props, isHovered) => {
|
|
|
177
177
|
};
|
|
178
178
|
function ButtonRoot(props) {
|
|
179
179
|
const [isHovered, setIsHovered] = useState(false);
|
|
180
|
-
const state = calculateState$
|
|
180
|
+
const state = calculateState$6(props, isHovered);
|
|
181
181
|
const calculatedStyle = [
|
|
182
182
|
props.styles?.root?.default,
|
|
183
183
|
props.styles?.root?.[state],
|
|
@@ -247,7 +247,7 @@ const useSelect = () => {
|
|
|
247
247
|
|
|
248
248
|
//#endregion
|
|
249
249
|
//#region src/primitives/select/select-root.tsx
|
|
250
|
-
const calculateState$
|
|
250
|
+
const calculateState$5 = (props) => {
|
|
251
251
|
if (props.isDisabled) return "disabled";
|
|
252
252
|
return "default";
|
|
253
253
|
};
|
|
@@ -255,7 +255,7 @@ function SelectRoot(props) {
|
|
|
255
255
|
const [isOpen, setIsOpen] = useState(false);
|
|
256
256
|
const [triggerLayout, setTriggerLayout] = useState(null);
|
|
257
257
|
const [options, setOptions] = useState([]);
|
|
258
|
-
const state = calculateState$
|
|
258
|
+
const state = calculateState$5(props);
|
|
259
259
|
const composedStyles = calculateComposedStyles(props.styles, state, "root", props.style);
|
|
260
260
|
const Component = props.render ?? View;
|
|
261
261
|
return /* @__PURE__ */ jsx(SelectContext.Provider, {
|
|
@@ -371,7 +371,7 @@ function SelectContent(props) {
|
|
|
371
371
|
|
|
372
372
|
//#endregion
|
|
373
373
|
//#region src/primitives/select/select-option.tsx
|
|
374
|
-
const calculateState$
|
|
374
|
+
const calculateState$4 = (selectState, hovered, selected) => {
|
|
375
375
|
if (selectState === "disabled") return "disabled";
|
|
376
376
|
if (selected) return "selected";
|
|
377
377
|
if (hovered) return "hovered";
|
|
@@ -381,7 +381,7 @@ function SelectOption(props) {
|
|
|
381
381
|
const [isHovered, setIsHovered] = useState(false);
|
|
382
382
|
const select = useSelect();
|
|
383
383
|
const isSelected = select.value === props.value;
|
|
384
|
-
const optionState = calculateState$
|
|
384
|
+
const optionState = calculateState$4(select.state, isHovered, isSelected);
|
|
385
385
|
const composedStyles = calculateComposedStyles(select.styles, optionState, "option", props.style);
|
|
386
386
|
useEffect(() => {
|
|
387
387
|
select.setOptions((prev) => {
|
|
@@ -707,14 +707,14 @@ const BadgePrimitive = {
|
|
|
707
707
|
|
|
708
708
|
//#endregion
|
|
709
709
|
//#region src/primitives/textarea/textarea.tsx
|
|
710
|
-
const calculateState$
|
|
710
|
+
const calculateState$3 = (props, isFocused) => {
|
|
711
711
|
if (props.isDisabled) return "disabled";
|
|
712
712
|
if (isFocused) return "focused";
|
|
713
713
|
return "default";
|
|
714
714
|
};
|
|
715
715
|
function TextareaPrimitive(props) {
|
|
716
716
|
const [isFocused, setIsFocused] = useState(false);
|
|
717
|
-
const state = calculateState$
|
|
717
|
+
const state = calculateState$3(props, isFocused);
|
|
718
718
|
const composedStyles = [
|
|
719
719
|
props.styles?.default?.style,
|
|
720
720
|
props.styles?.[state]?.style,
|
|
@@ -752,108 +752,6 @@ const useDropdownMenu = () => {
|
|
|
752
752
|
return context;
|
|
753
753
|
};
|
|
754
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
755
|
//#endregion
|
|
858
756
|
//#region src/primitives/dropdown-menu/dropdown-menu-root.tsx
|
|
859
757
|
function DropdownMenuRoot(props) {
|
|
@@ -934,14 +832,14 @@ function DropdownMenuContent(props) {
|
|
|
934
832
|
|
|
935
833
|
//#endregion
|
|
936
834
|
//#region src/primitives/dropdown-menu/dropdown-menu-button.tsx
|
|
937
|
-
const calculateState = (isHovered) => {
|
|
835
|
+
const calculateState$2 = (isHovered) => {
|
|
938
836
|
if (isHovered) return "hovered";
|
|
939
837
|
return "default";
|
|
940
838
|
};
|
|
941
839
|
function DropdownMenuButton(props) {
|
|
942
840
|
const menu = useDropdownMenu();
|
|
943
841
|
const [isHovered, setIsHovered] = useState(false);
|
|
944
|
-
const state = calculateState(isHovered);
|
|
842
|
+
const state = calculateState$2(isHovered);
|
|
945
843
|
const composedStyle = [
|
|
946
844
|
menu.styles?.button?.default,
|
|
947
845
|
menu.styles?.button?.[state],
|
|
@@ -1163,4 +1061,323 @@ const PopoverPrimitive = {
|
|
|
1163
1061
|
};
|
|
1164
1062
|
|
|
1165
1063
|
//#endregion
|
|
1166
|
-
|
|
1064
|
+
//#region src/primitives/calendar/context.ts
|
|
1065
|
+
const CalendarContext = React.createContext(void 0);
|
|
1066
|
+
const useCalendarContext = () => {
|
|
1067
|
+
const context = React.useContext(CalendarContext);
|
|
1068
|
+
if (!context) throw new Error("Calendar components must be used within CalendarRoot");
|
|
1069
|
+
return context;
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
//#endregion
|
|
1073
|
+
//#region src/primitives/calendar/calendar-root.tsx
|
|
1074
|
+
function CalendarRoot(props) {
|
|
1075
|
+
const { children, value, onChange, defaultMonth = /* @__PURE__ */ new Date(), minDate, maxDate, style, styles, ...viewProps } = props;
|
|
1076
|
+
const [currentMonth, setCurrentMonth] = useState(defaultMonth);
|
|
1077
|
+
const containerStyle = [styles?.root, style];
|
|
1078
|
+
return /* @__PURE__ */ jsx(CalendarContext.Provider, {
|
|
1079
|
+
value: {
|
|
1080
|
+
value,
|
|
1081
|
+
onChange,
|
|
1082
|
+
currentMonth,
|
|
1083
|
+
setCurrentMonth,
|
|
1084
|
+
styles,
|
|
1085
|
+
minDate,
|
|
1086
|
+
maxDate
|
|
1087
|
+
},
|
|
1088
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
1089
|
+
...viewProps,
|
|
1090
|
+
style: containerStyle,
|
|
1091
|
+
children
|
|
1092
|
+
})
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
//#endregion
|
|
1097
|
+
//#region src/primitives/calendar/calendar-header.tsx
|
|
1098
|
+
function CalendarHeader(props) {
|
|
1099
|
+
const { children, style, ...viewProps } = props;
|
|
1100
|
+
const { styles } = useCalendarContext();
|
|
1101
|
+
const headerStyle = [styles?.header, style];
|
|
1102
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1103
|
+
...viewProps,
|
|
1104
|
+
style: headerStyle,
|
|
1105
|
+
children
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
//#endregion
|
|
1110
|
+
//#region src/utils/date-utils.ts
|
|
1111
|
+
const formatDate = (date, format) => {
|
|
1112
|
+
const months = [
|
|
1113
|
+
"January",
|
|
1114
|
+
"February",
|
|
1115
|
+
"March",
|
|
1116
|
+
"April",
|
|
1117
|
+
"May",
|
|
1118
|
+
"June",
|
|
1119
|
+
"July",
|
|
1120
|
+
"August",
|
|
1121
|
+
"September",
|
|
1122
|
+
"October",
|
|
1123
|
+
"November",
|
|
1124
|
+
"December"
|
|
1125
|
+
];
|
|
1126
|
+
const day = date.getDate();
|
|
1127
|
+
const month = months[date.getMonth()];
|
|
1128
|
+
const year = date.getFullYear();
|
|
1129
|
+
if (format === "MMMM yyyy") return `${month} ${year}`;
|
|
1130
|
+
if (format === "d") return day.toString();
|
|
1131
|
+
return date.toLocaleDateString();
|
|
1132
|
+
};
|
|
1133
|
+
const isDateSameDay = (date1, date2) => {
|
|
1134
|
+
return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
|
|
1135
|
+
};
|
|
1136
|
+
const isDateToday = (date) => {
|
|
1137
|
+
return isDateSameDay(date, /* @__PURE__ */ new Date());
|
|
1138
|
+
};
|
|
1139
|
+
const isDateBefore = (date1, date2) => {
|
|
1140
|
+
const d1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
|
|
1141
|
+
const d2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
|
|
1142
|
+
return d1.getTime() < d2.getTime();
|
|
1143
|
+
};
|
|
1144
|
+
const isDateAfter = (date1, date2) => {
|
|
1145
|
+
const d1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
|
|
1146
|
+
const d2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
|
|
1147
|
+
return d1.getTime() > d2.getTime();
|
|
1148
|
+
};
|
|
1149
|
+
const addMonths = (date, months) => {
|
|
1150
|
+
const newDate = new Date(date);
|
|
1151
|
+
newDate.setMonth(newDate.getMonth() + months);
|
|
1152
|
+
return newDate;
|
|
1153
|
+
};
|
|
1154
|
+
const subMonths = (date, months) => {
|
|
1155
|
+
return addMonths(date, -months);
|
|
1156
|
+
};
|
|
1157
|
+
const startOfMonth = (date) => {
|
|
1158
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
1159
|
+
};
|
|
1160
|
+
const endOfMonth = (date) => {
|
|
1161
|
+
return new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
|
1162
|
+
};
|
|
1163
|
+
const getDaysInMonth = (date) => {
|
|
1164
|
+
return endOfMonth(date).getDate();
|
|
1165
|
+
};
|
|
1166
|
+
const getFirstDayOfMonth = (date) => {
|
|
1167
|
+
return startOfMonth(date).getDay();
|
|
1168
|
+
};
|
|
1169
|
+
const isSameMonth = (date1, date2) => {
|
|
1170
|
+
return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth();
|
|
1171
|
+
};
|
|
1172
|
+
const getWeekDays = (month, year, week) => {
|
|
1173
|
+
const days = [];
|
|
1174
|
+
const firstDayOfMonth = new Date(year, month, 1).getDay();
|
|
1175
|
+
const daysInMonth = getDaysInMonth(new Date(year, month));
|
|
1176
|
+
const startDay = week * 7 - (firstDayOfMonth === 0 ? 6 : firstDayOfMonth - 1);
|
|
1177
|
+
for (let i = 0; i < 7; i++) {
|
|
1178
|
+
const day = startDay + i;
|
|
1179
|
+
let date;
|
|
1180
|
+
if (day < 1) {
|
|
1181
|
+
const prevMonth = month === 0 ? 11 : month - 1;
|
|
1182
|
+
const prevYear = month === 0 ? year - 1 : year;
|
|
1183
|
+
const daysInPrevMonth = getDaysInMonth(new Date(prevYear, prevMonth));
|
|
1184
|
+
date = new Date(prevYear, prevMonth, daysInPrevMonth + day);
|
|
1185
|
+
} else if (day > daysInMonth) {
|
|
1186
|
+
const nextMonth = month === 11 ? 0 : month + 1;
|
|
1187
|
+
const nextYear = month === 11 ? year + 1 : year;
|
|
1188
|
+
date = new Date(nextYear, nextMonth, day - daysInMonth);
|
|
1189
|
+
} else date = new Date(year, month, day);
|
|
1190
|
+
days.push(date);
|
|
1191
|
+
}
|
|
1192
|
+
return days;
|
|
1193
|
+
};
|
|
1194
|
+
const getWeeksInMonth = (date) => {
|
|
1195
|
+
const firstDayOfMonth = getFirstDayOfMonth(date);
|
|
1196
|
+
const daysInMonth = getDaysInMonth(date);
|
|
1197
|
+
return Math.ceil((firstDayOfMonth + daysInMonth) / 7);
|
|
1198
|
+
};
|
|
1199
|
+
|
|
1200
|
+
//#endregion
|
|
1201
|
+
//#region src/primitives/calendar/calendar-title.tsx
|
|
1202
|
+
function CalendarTitle(props) {
|
|
1203
|
+
const { children, style, formatStr = "MMMM yyyy", ...textProps } = props;
|
|
1204
|
+
const { currentMonth, styles } = useCalendarContext();
|
|
1205
|
+
const titleStyle = [styles?.headerTitle, style];
|
|
1206
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
1207
|
+
...textProps,
|
|
1208
|
+
style: titleStyle,
|
|
1209
|
+
children: children ?? formatDate(currentMonth, formatStr)
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
//#endregion
|
|
1214
|
+
//#region src/primitives/calendar/calendar-nav-button.tsx
|
|
1215
|
+
const calculateState$1 = (isDisabled, isHovered) => {
|
|
1216
|
+
if (isDisabled) return "disabled";
|
|
1217
|
+
if (isHovered) return "hovered";
|
|
1218
|
+
return "default";
|
|
1219
|
+
};
|
|
1220
|
+
function CalendarNavButton(props) {
|
|
1221
|
+
const { children = props.direction === "prev" ? "‹" : "›", direction, style, textStyle, ...pressableProps } = props;
|
|
1222
|
+
const { currentMonth, setCurrentMonth, minDate, maxDate, styles } = useCalendarContext();
|
|
1223
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
1224
|
+
const isDisabled = React.useMemo(() => {
|
|
1225
|
+
if (direction === "prev" && minDate) return subMonths(currentMonth, 1) < minDate;
|
|
1226
|
+
if (direction === "next" && maxDate) return addMonths(currentMonth, 1) > maxDate;
|
|
1227
|
+
return false;
|
|
1228
|
+
}, [
|
|
1229
|
+
direction,
|
|
1230
|
+
currentMonth,
|
|
1231
|
+
minDate,
|
|
1232
|
+
maxDate
|
|
1233
|
+
]);
|
|
1234
|
+
const state = calculateState$1(isDisabled, isHovered);
|
|
1235
|
+
const handlePress = () => {
|
|
1236
|
+
if (isDisabled) return;
|
|
1237
|
+
setCurrentMonth(direction === "prev" ? subMonths(currentMonth, 1) : addMonths(currentMonth, 1));
|
|
1238
|
+
};
|
|
1239
|
+
const buttonStyle = [
|
|
1240
|
+
styles?.navButton?.default,
|
|
1241
|
+
styles?.navButton?.[state],
|
|
1242
|
+
style
|
|
1243
|
+
];
|
|
1244
|
+
const textStyleCombined = [
|
|
1245
|
+
styles?.navButtonText?.default,
|
|
1246
|
+
styles?.navButtonText?.[state],
|
|
1247
|
+
textStyle
|
|
1248
|
+
];
|
|
1249
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
1250
|
+
...pressableProps,
|
|
1251
|
+
onPress: handlePress,
|
|
1252
|
+
onHoverIn: () => setIsHovered(true),
|
|
1253
|
+
onHoverOut: () => setIsHovered(false),
|
|
1254
|
+
disabled: isDisabled,
|
|
1255
|
+
style: buttonStyle,
|
|
1256
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1257
|
+
style: textStyleCombined,
|
|
1258
|
+
children
|
|
1259
|
+
})
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
//#endregion
|
|
1264
|
+
//#region src/primitives/calendar/calendar-week-labels.tsx
|
|
1265
|
+
function CalendarWeekLabel(props) {
|
|
1266
|
+
const { styles } = useCalendarContext();
|
|
1267
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
1268
|
+
numberOfLines: 1,
|
|
1269
|
+
style: [styles?.weekLabel, props.style],
|
|
1270
|
+
children: props.children
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
const DEFAULT_WEEK_DAYS = [
|
|
1274
|
+
"Su",
|
|
1275
|
+
"Mo",
|
|
1276
|
+
"Tu",
|
|
1277
|
+
"We",
|
|
1278
|
+
"Th",
|
|
1279
|
+
"Fr",
|
|
1280
|
+
"Sa"
|
|
1281
|
+
];
|
|
1282
|
+
function CalendarWeekLabels(props) {
|
|
1283
|
+
const { weekDays = DEFAULT_WEEK_DAYS, style } = props;
|
|
1284
|
+
const { styles } = useCalendarContext();
|
|
1285
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1286
|
+
style: [styles?.weekLabels, style],
|
|
1287
|
+
children: weekDays.map((day, index) => /* @__PURE__ */ jsx(CalendarWeekLabel, {
|
|
1288
|
+
style: styles?.weekLabel,
|
|
1289
|
+
children: day
|
|
1290
|
+
}, index))
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
//#endregion
|
|
1295
|
+
//#region src/primitives/calendar/calendar-day.tsx
|
|
1296
|
+
const calculateState = (date, selected, isCurrentMonth, isDisabled, isHovered) => {
|
|
1297
|
+
if (isDisabled) return "disabled";
|
|
1298
|
+
if (selected && isDateSameDay(date, selected)) return "selected";
|
|
1299
|
+
if (isDateToday(date)) return "today";
|
|
1300
|
+
if (isHovered) return "hovered";
|
|
1301
|
+
if (!isCurrentMonth) return "deprioritized";
|
|
1302
|
+
return "default";
|
|
1303
|
+
};
|
|
1304
|
+
function CalendarDay(props) {
|
|
1305
|
+
const calendar = useCalendarContext();
|
|
1306
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
1307
|
+
const isCurrentMonth = isSameMonth(props.date, calendar.currentMonth);
|
|
1308
|
+
const isDisabled = useMemo(() => {
|
|
1309
|
+
if (calendar.minDate && isDateBefore(props.date, calendar.minDate)) return true;
|
|
1310
|
+
if (calendar.maxDate && isDateAfter(props.date, calendar.maxDate)) return true;
|
|
1311
|
+
return false;
|
|
1312
|
+
}, [
|
|
1313
|
+
props.date,
|
|
1314
|
+
calendar.minDate,
|
|
1315
|
+
calendar.maxDate
|
|
1316
|
+
]);
|
|
1317
|
+
const state = calculateState(props.date, calendar.value, isCurrentMonth, isDisabled, isHovered);
|
|
1318
|
+
const handlePress = () => {
|
|
1319
|
+
console.log("Day pressed:", isDisabled, calendar.onChange);
|
|
1320
|
+
if (isDisabled || !calendar.onChange) return;
|
|
1321
|
+
calendar.onChange(props.date);
|
|
1322
|
+
};
|
|
1323
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
1324
|
+
onPress: handlePress,
|
|
1325
|
+
onHoverIn: () => setIsHovered(true),
|
|
1326
|
+
onHoverOut: () => setIsHovered(false),
|
|
1327
|
+
disabled: isDisabled,
|
|
1328
|
+
style: [
|
|
1329
|
+
calendar.styles?.dayButton?.default,
|
|
1330
|
+
calendar.styles?.dayButton?.[state],
|
|
1331
|
+
props.style
|
|
1332
|
+
],
|
|
1333
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1334
|
+
style: [
|
|
1335
|
+
calendar.styles?.dayText?.default,
|
|
1336
|
+
calendar.styles?.dayText?.[state],
|
|
1337
|
+
props.textStyle
|
|
1338
|
+
],
|
|
1339
|
+
children: formatDate(props.date, "d")
|
|
1340
|
+
})
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
//#endregion
|
|
1345
|
+
//#region src/primitives/calendar/calendar-weeks.tsx
|
|
1346
|
+
function CalendarWeek(props) {
|
|
1347
|
+
const { style, ...viewProps } = props;
|
|
1348
|
+
const { currentMonth, styles } = useCalendarContext();
|
|
1349
|
+
const days = getWeekDays(currentMonth.getMonth(), currentMonth.getFullYear(), props.index);
|
|
1350
|
+
const composedStyle = [styles?.week, style];
|
|
1351
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1352
|
+
...viewProps,
|
|
1353
|
+
style: composedStyle,
|
|
1354
|
+
children: days.map((day, index) => {
|
|
1355
|
+
return /* @__PURE__ */ jsx(CalendarDay, { date: day }, index);
|
|
1356
|
+
})
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
function CalendarWeeks(props) {
|
|
1360
|
+
const { currentMonth, styles } = useCalendarContext();
|
|
1361
|
+
const weeks = getWeeksInMonth(currentMonth);
|
|
1362
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1363
|
+
style: [styles?.weeks, props.style],
|
|
1364
|
+
children: Array.from({ length: weeks }).map((_, index) => {
|
|
1365
|
+
return /* @__PURE__ */ jsx(CalendarWeek, { index }, index);
|
|
1366
|
+
})
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
//#endregion
|
|
1371
|
+
//#region src/primitives/calendar/index.ts
|
|
1372
|
+
const CalendarPrimitive = {
|
|
1373
|
+
Root: CalendarRoot,
|
|
1374
|
+
Header: CalendarHeader,
|
|
1375
|
+
Title: CalendarTitle,
|
|
1376
|
+
NavButton: CalendarNavButton,
|
|
1377
|
+
CalendarWeekLabels,
|
|
1378
|
+
Weeks: CalendarWeeks,
|
|
1379
|
+
Day: CalendarDay
|
|
1380
|
+
};
|
|
1381
|
+
|
|
1382
|
+
//#endregion
|
|
1383
|
+
export { TextareaPrimitive as a, AvatarPrimitive as c, SelectPrimitive as d, ButtonPrimitive as f, PortalHost as h, DropdownMenuPrimitive as i, EmptyPrimitive as l, FieldPrimitive as m, PopoverPrimitive as n, BadgePrimitive as o, InputPrimitive as p, usePopover as r, ToastPrimitive as s, CalendarPrimitive as t, CardPrimitive as u };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as ToastPrimitive } from "./primitives-ApsPS0vU.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";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/hooks/use-numeric-mask.d.ts
|
|
2
|
+
type NumericMaskFormat = "currency" | "decimal" | "integer" | "percentage";
|
|
3
|
+
interface UseNumericMaskOptions {
|
|
4
|
+
format?: NumericMaskFormat;
|
|
5
|
+
locale?: string;
|
|
6
|
+
currency?: string;
|
|
7
|
+
precision?: number;
|
|
8
|
+
min?: number;
|
|
9
|
+
max?: number;
|
|
10
|
+
allowNegative?: boolean;
|
|
11
|
+
onChange?: (value: number | null) => void;
|
|
12
|
+
}
|
|
13
|
+
interface UseNumericMaskReturn {
|
|
14
|
+
value: string;
|
|
15
|
+
numericValue: number | null;
|
|
16
|
+
onChangeText: (text: string) => void;
|
|
17
|
+
onBlur: () => void;
|
|
18
|
+
onFocus: () => void;
|
|
19
|
+
keyboardType: "numeric" | "decimal-pad" | "number-pad";
|
|
20
|
+
setValue: (value: number | null) => void;
|
|
21
|
+
}
|
|
22
|
+
declare function useNumericMask({
|
|
23
|
+
format,
|
|
24
|
+
locale,
|
|
25
|
+
currency,
|
|
26
|
+
precision,
|
|
27
|
+
min,
|
|
28
|
+
max,
|
|
29
|
+
allowNegative,
|
|
30
|
+
onChange
|
|
31
|
+
}?: UseNumericMaskOptions): UseNumericMaskReturn;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { useNumericMask as i, UseNumericMaskOptions as n, UseNumericMaskReturn as r, NumericMaskFormat as t };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/use-numeric-mask.ts
|
|
4
|
+
function useNumericMask({ format = "decimal", locale = "en-US", currency = "USD", precision = 2, min, max, allowNegative = true, onChange } = {}) {
|
|
5
|
+
const [numericValue, setNumericValue] = useState(null);
|
|
6
|
+
const [displayValue, setDisplayValue] = useState("");
|
|
7
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
8
|
+
const effectivePrecision = format === "integer" ? 0 : precision;
|
|
9
|
+
const formatValue = useCallback((num) => {
|
|
10
|
+
if (num === null || isNaN(num)) return "";
|
|
11
|
+
switch (format) {
|
|
12
|
+
case "currency": return new Intl.NumberFormat(locale, {
|
|
13
|
+
style: "currency",
|
|
14
|
+
currency,
|
|
15
|
+
minimumFractionDigits: effectivePrecision,
|
|
16
|
+
maximumFractionDigits: effectivePrecision
|
|
17
|
+
}).format(num);
|
|
18
|
+
case "percentage": return new Intl.NumberFormat(locale, {
|
|
19
|
+
style: "percent",
|
|
20
|
+
minimumFractionDigits: effectivePrecision,
|
|
21
|
+
maximumFractionDigits: effectivePrecision
|
|
22
|
+
}).format(num / 100);
|
|
23
|
+
case "integer": return new Intl.NumberFormat(locale, {
|
|
24
|
+
minimumFractionDigits: 0,
|
|
25
|
+
maximumFractionDigits: 0
|
|
26
|
+
}).format(num);
|
|
27
|
+
case "decimal":
|
|
28
|
+
default: return new Intl.NumberFormat(locale, {
|
|
29
|
+
minimumFractionDigits: effectivePrecision,
|
|
30
|
+
maximumFractionDigits: effectivePrecision
|
|
31
|
+
}).format(num);
|
|
32
|
+
}
|
|
33
|
+
}, [
|
|
34
|
+
format,
|
|
35
|
+
locale,
|
|
36
|
+
currency,
|
|
37
|
+
effectivePrecision
|
|
38
|
+
]);
|
|
39
|
+
const parseValue = useCallback((text) => {
|
|
40
|
+
let cleaned = text.replace(/[^\d.-]/g, "");
|
|
41
|
+
if (!allowNegative) cleaned = cleaned.replace(/-/g, "");
|
|
42
|
+
const parsed = parseFloat(cleaned);
|
|
43
|
+
if (isNaN(parsed) || cleaned === "" || cleaned === "-") return null;
|
|
44
|
+
let constrained = parsed;
|
|
45
|
+
if (min !== void 0 && constrained < min) constrained = min;
|
|
46
|
+
if (max !== void 0 && constrained > max) constrained = max;
|
|
47
|
+
return constrained;
|
|
48
|
+
}, [
|
|
49
|
+
min,
|
|
50
|
+
max,
|
|
51
|
+
allowNegative
|
|
52
|
+
]);
|
|
53
|
+
const handleChangeText = useCallback((text) => {
|
|
54
|
+
if (isFocused) {
|
|
55
|
+
let cleaned = text.replace(/[^\d.-]/g, "");
|
|
56
|
+
if (!allowNegative && cleaned.includes("-")) return;
|
|
57
|
+
if (allowNegative) {
|
|
58
|
+
if ((cleaned.match(/-/g) || []).length > 1 || cleaned.includes("-") && cleaned.indexOf("-") !== 0) return;
|
|
59
|
+
}
|
|
60
|
+
if (effectivePrecision >= 0) {
|
|
61
|
+
const decimalIndex = cleaned.indexOf(".");
|
|
62
|
+
if (decimalIndex !== -1) {
|
|
63
|
+
if (cleaned.substring(decimalIndex + 1).length > effectivePrecision) return;
|
|
64
|
+
}
|
|
65
|
+
if ((cleaned.match(/\./g) || []).length > 1) return;
|
|
66
|
+
if (format === "integer" && cleaned.includes(".")) return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
setDisplayValue(text);
|
|
70
|
+
const value = parseValue(text);
|
|
71
|
+
setNumericValue(value);
|
|
72
|
+
onChange?.(value);
|
|
73
|
+
}, [
|
|
74
|
+
parseValue,
|
|
75
|
+
onChange,
|
|
76
|
+
isFocused,
|
|
77
|
+
effectivePrecision,
|
|
78
|
+
allowNegative,
|
|
79
|
+
format
|
|
80
|
+
]);
|
|
81
|
+
const handleBlur = useCallback(() => {
|
|
82
|
+
setIsFocused(false);
|
|
83
|
+
if (numericValue !== null) setDisplayValue(formatValue(numericValue));
|
|
84
|
+
else setDisplayValue("");
|
|
85
|
+
}, [numericValue, formatValue]);
|
|
86
|
+
const handleFocus = useCallback(() => {
|
|
87
|
+
setIsFocused(true);
|
|
88
|
+
if (numericValue !== null) setDisplayValue(numericValue.toString());
|
|
89
|
+
}, [numericValue]);
|
|
90
|
+
const setValue = useCallback((value) => {
|
|
91
|
+
setNumericValue(value);
|
|
92
|
+
if (value !== null) if (isFocused) setDisplayValue(value.toString());
|
|
93
|
+
else setDisplayValue(formatValue(value));
|
|
94
|
+
else setDisplayValue("");
|
|
95
|
+
onChange?.(value);
|
|
96
|
+
}, [
|
|
97
|
+
isFocused,
|
|
98
|
+
formatValue,
|
|
99
|
+
onChange
|
|
100
|
+
]);
|
|
101
|
+
return {
|
|
102
|
+
value: displayValue,
|
|
103
|
+
numericValue,
|
|
104
|
+
onChangeText: handleChangeText,
|
|
105
|
+
onBlur: handleBlur,
|
|
106
|
+
onFocus: handleFocus,
|
|
107
|
+
keyboardType: format === "integer" ? allowNegative ? "numeric" : "number-pad" : "decimal-pad",
|
|
108
|
+
setValue
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//#endregion
|
|
113
|
+
export { useNumericMask as t };
|