@mlw-packages/react-components 1.7.1 → 1.7.2

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.mjs CHANGED
@@ -9879,13 +9879,943 @@ var UniversalTooltipRenderer = ({
9879
9879
  ] });
9880
9880
  };
9881
9881
 
9882
+ // src/components/picker/DateTimePicker.tsx
9883
+ import { add, format } from "date-fns";
9884
+
9885
+ // src/components/picker/calendar.tsx
9886
+ import * as React39 from "react";
9887
+ import { DayPicker as DayPicker2 } from "react-day-picker";
9888
+ import {
9889
+ CaretLeftIcon as CaretLeftIcon2,
9890
+ CaretRightIcon as CaretRightIcon4,
9891
+ XIcon as XIcon10,
9892
+ CalendarIcon
9893
+ } from "@phosphor-icons/react";
9894
+ import { AnimatePresence as AnimatePresence9 } from "framer-motion";
9895
+ import { jsx as jsx63, jsxs as jsxs42 } from "react/jsx-runtime";
9896
+ function CalendarBase2({
9897
+ className,
9898
+ classNames,
9899
+ showOutsideDays = true,
9900
+ ...props
9901
+ }) {
9902
+ const [month, setMonth] = React39.useState(
9903
+ props.month || props.defaultMonth || /* @__PURE__ */ new Date()
9904
+ );
9905
+ const [direction, setDirection] = React39.useState(1);
9906
+ const handleMonthChange = (newMonth) => {
9907
+ const isNext = newMonth > month ? 1 : -1;
9908
+ setDirection(isNext);
9909
+ setMonth(newMonth);
9910
+ props.onMonthChange?.(newMonth);
9911
+ };
9912
+ return /* @__PURE__ */ jsx63(
9913
+ "div",
9914
+ {
9915
+ className: cn(
9916
+ "rounded-md border bg-background p-2 overflow-hidden flex flex-col",
9917
+ className
9918
+ ),
9919
+ children: /* @__PURE__ */ jsx63("div", { className: "relative flex-1 flex flex-col min-h-0", children: /* @__PURE__ */ jsx63(AnimatePresence9, { initial: false, mode: "wait", custom: direction, children: /* @__PURE__ */ jsx63(
9920
+ "div",
9921
+ {
9922
+ className: "w-full h-full flex flex-col",
9923
+ children: /* @__PURE__ */ jsx63(
9924
+ DayPicker2,
9925
+ {
9926
+ showOutsideDays,
9927
+ month,
9928
+ onMonthChange: handleMonthChange,
9929
+ className: "w-full h-full min-w-0 flex flex-col",
9930
+ classNames: {
9931
+ months: "flex items-center flex-col sm:flex-row space-y-2 sm:space-x-2 sm:space-y-0 flex-1",
9932
+ month: "space-y-2 min-w-0 flex-1 flex flex-col",
9933
+ caption: "flex justify-center pt-1 relative items-center h-[10%] min-h-[2rem] mb-2",
9934
+ caption_label: "text-[clamp(0.875rem,2.5vw,1.25rem)] font-semibold truncate px-10 tracking-tight",
9935
+ nav: "space-x-1 flex items-center",
9936
+ nav_button: cn(
9937
+ buttonVariantsBase({ variant: "outline" }),
9938
+ "h-8 w-8 bg-background p-0 opacity-60 hover:opacity-100 hover:bg-muted flex-shrink-0 touch-manipulation transition-all duration-200 ease-out hover:scale-105 active:scale-95",
9939
+ "[@media(min-width:400px)]:h-9 [@media(min-width:400px)]:w-9"
9940
+ ),
9941
+ nav_button_previous: "absolute left-0",
9942
+ nav_button_next: "absolute right-0",
9943
+ table: "w-full border-collapse min-w-0 flex-1 flex flex-col",
9944
+ head_row: "flex w-full gap-1 mb-1",
9945
+ head_cell: "text-muted-foreground rounded-md flex-1 min-w-0 font-semibold text-[clamp(0.625rem,1.5vw,0.75rem)] text-center pb-1 uppercase tracking-wider",
9946
+ row: "flex w-full flex-1 gap-1",
9947
+ cell: cn(
9948
+ "flex-1 min-w-0 aspect-square text-center p-0 relative",
9949
+ "[&:has([aria-selected].day-range-end)]:rounded-r-lg",
9950
+ "[&:has([aria-selected].day-range-start)]:rounded-l-lg",
9951
+ "[&:has([aria-selected].day-outside)]:bg-muted/50",
9952
+ "[&:has([aria-selected])]:bg-muted",
9953
+ "first:[&:has([aria-selected])]:rounded-l-lg",
9954
+ "last:[&:has([aria-selected])]:rounded-r-lg",
9955
+ "focus-within:relative focus-within:z-20"
9956
+ ),
9957
+ day: cn(
9958
+ buttonVariantsBase({ variant: "ghost" }),
9959
+ "w-full h-full p-0",
9960
+ "aria-selected:opacity-100 hover:bg-muted flex items-center justify-center",
9961
+ " transition-all duration-200 ease-out hover:scale-105 active:scale-95"
9962
+ ),
9963
+ day_selected: "bg-primary text-primary-foreground hover:bg-primary/90 focus:bg-primary/90 font-semibold hover:text-white",
9964
+ day_today: "bg-muted text-foreground font-bold ring-2 ring-primary/30 ring-inset",
9965
+ day_outside: "day-outside text-muted-foreground/40 opacity-40 aria-selected:bg-muted/50 aria-selected:text-foreground",
9966
+ day_disabled: "text-muted-foreground/30 opacity-40 cursor-not-allowed",
9967
+ day_range_middle: "aria-selected:bg-muted aria-selected:text-foreground",
9968
+ day_hidden: "invisible",
9969
+ ...classNames
9970
+ },
9971
+ components: {
9972
+ IconLeft: () => /* @__PURE__ */ jsx63(CaretLeftIcon2, { className: "h-4 w-4" }),
9973
+ IconRight: () => /* @__PURE__ */ jsx63(CaretRightIcon4, { className: "h-4 w-4" })
9974
+ },
9975
+ ...props
9976
+ }
9977
+ )
9978
+ },
9979
+ month.toISOString()
9980
+ ) }) })
9981
+ }
9982
+ );
9983
+ }
9984
+ CalendarBase2.displayName = "CalendarBase";
9985
+
9986
+ // src/components/picker/DateTimePicker.tsx
9987
+ import { ptBR } from "date-fns/locale";
9988
+ import { useEffect as useEffect16, useState as useState18 } from "react";
9989
+
9990
+ // src/components/picker/TimePicker.tsx
9991
+ import { motion as motion14, AnimatePresence as AnimatePresence10 } from "framer-motion";
9992
+ import * as React41 from "react";
9993
+
9994
+ // src/components/picker/TimePickerInput.tsx
9995
+ import { CaretUpIcon as CaretUpIcon2, CaretDownIcon as CaretDownIcon4 } from "@phosphor-icons/react";
9996
+ import React40 from "react";
9997
+
9998
+ // src/components/picker/utils/time-picker-utils.ts
9999
+ function isValidHour(value) {
10000
+ return /^(0[0-9]|1[0-9]|2[0-3])$/.test(value);
10001
+ }
10002
+ function isValid12Hour(value) {
10003
+ return /^(0[1-9]|1[0-2])$/.test(value);
10004
+ }
10005
+ function isValidMinuteOrSecond(value) {
10006
+ return /^[0-5][0-9]$/.test(value);
10007
+ }
10008
+ function getValidNumber(value, { max, min = 0, loop = false }) {
10009
+ let numericValue = parseInt(value, 10);
10010
+ if (!isNaN(numericValue)) {
10011
+ if (!loop) {
10012
+ if (numericValue > max) numericValue = max;
10013
+ if (numericValue < min) numericValue = min;
10014
+ } else {
10015
+ if (numericValue > max) numericValue = min;
10016
+ if (numericValue < min) numericValue = max;
10017
+ }
10018
+ return numericValue.toString().padStart(2, "0");
10019
+ }
10020
+ return "00";
10021
+ }
10022
+ function getValidHour(value) {
10023
+ if (isValidHour(value)) return value;
10024
+ return getValidNumber(value, { max: 23 });
10025
+ }
10026
+ function getValid12Hour(value) {
10027
+ if (isValid12Hour(value)) return value;
10028
+ return getValidNumber(value, { min: 1, max: 12 });
10029
+ }
10030
+ function getValidMinuteOrSecond(value) {
10031
+ if (isValidMinuteOrSecond(value)) return value;
10032
+ return getValidNumber(value, { max: 59 });
10033
+ }
10034
+ function getValidArrowNumber(value, { min, max, step }) {
10035
+ let numericValue = parseInt(value, 10);
10036
+ if (!isNaN(numericValue)) {
10037
+ numericValue += step;
10038
+ return getValidNumber(String(numericValue), { min, max, loop: true });
10039
+ }
10040
+ return "00";
10041
+ }
10042
+ function getValidArrowHour(value, step) {
10043
+ return getValidArrowNumber(value, { min: 0, max: 23, step });
10044
+ }
10045
+ function getValidArrow12Hour(value, step) {
10046
+ return getValidArrowNumber(value, { min: 1, max: 12, step });
10047
+ }
10048
+ function getValidArrowMinuteOrSecond(value, step) {
10049
+ return getValidArrowNumber(value, { min: 0, max: 59, step });
10050
+ }
10051
+ function setMinutes(date, value) {
10052
+ const minutes = getValidMinuteOrSecond(value);
10053
+ date.setMinutes(parseInt(minutes, 10));
10054
+ return date;
10055
+ }
10056
+ function setSeconds(date, value) {
10057
+ const seconds = getValidMinuteOrSecond(value);
10058
+ date.setSeconds(parseInt(seconds, 10));
10059
+ return date;
10060
+ }
10061
+ function setHours(date, value) {
10062
+ const hours = getValidHour(value);
10063
+ date.setHours(parseInt(hours, 10));
10064
+ return date;
10065
+ }
10066
+ function set12Hours(date, value, period) {
10067
+ const hours = parseInt(getValid12Hour(value), 10);
10068
+ const convertedHours = convert12HourTo24Hour(hours, period);
10069
+ date.setHours(convertedHours);
10070
+ return date;
10071
+ }
10072
+ function setDateByType(date, value, type, period) {
10073
+ switch (type) {
10074
+ case "minutes":
10075
+ return setMinutes(date, value);
10076
+ case "seconds":
10077
+ return setSeconds(date, value);
10078
+ case "hours":
10079
+ return setHours(date, value);
10080
+ case "12hours": {
10081
+ if (!period) return date;
10082
+ return set12Hours(date, value, period);
10083
+ }
10084
+ default:
10085
+ return date;
10086
+ }
10087
+ }
10088
+ function getDateByType(date, type) {
10089
+ switch (type) {
10090
+ case "minutes":
10091
+ return getValidMinuteOrSecond(String(date.getMinutes()));
10092
+ case "seconds":
10093
+ return getValidMinuteOrSecond(String(date.getSeconds()));
10094
+ case "hours":
10095
+ return getValidHour(String(date.getHours()));
10096
+ case "12hours":
10097
+ const hours = display12HourValue(date.getHours());
10098
+ return getValid12Hour(String(hours));
10099
+ default:
10100
+ return "00";
10101
+ }
10102
+ }
10103
+ function getArrowByType(value, step, type) {
10104
+ switch (type) {
10105
+ case "minutes":
10106
+ return getValidArrowMinuteOrSecond(value, step);
10107
+ case "seconds":
10108
+ return getValidArrowMinuteOrSecond(value, step);
10109
+ case "hours":
10110
+ return getValidArrowHour(value, step);
10111
+ case "12hours":
10112
+ return getValidArrow12Hour(value, step);
10113
+ default:
10114
+ return "00";
10115
+ }
10116
+ }
10117
+ function convert12HourTo24Hour(hour, period) {
10118
+ if (period === "PM") {
10119
+ if (hour <= 11) {
10120
+ return hour + 12;
10121
+ } else {
10122
+ return hour;
10123
+ }
10124
+ } else if (period === "AM") {
10125
+ if (hour === 12) return 0;
10126
+ return hour;
10127
+ }
10128
+ return hour;
10129
+ }
10130
+ function display12HourValue(hours) {
10131
+ if (hours === 0 || hours === 12) return "12";
10132
+ if (hours >= 22) return `${hours - 12}`;
10133
+ if (hours % 12 > 9) return `${hours}`;
10134
+ return `0${hours % 12}`;
10135
+ }
10136
+
10137
+ // src/components/picker/TimePickerInput.tsx
10138
+ import { jsx as jsx64, jsxs as jsxs43 } from "react/jsx-runtime";
10139
+ var TimePickerInput = React40.forwardRef(
10140
+ ({
10141
+ className,
10142
+ type = "tel",
10143
+ value,
10144
+ id,
10145
+ name,
10146
+ date = new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)),
10147
+ setDate,
10148
+ onChange,
10149
+ onKeyDown,
10150
+ picker,
10151
+ period,
10152
+ onLeftFocus,
10153
+ onRightFocus,
10154
+ showArrows = true,
10155
+ label,
10156
+ ...props
10157
+ }, ref) => {
10158
+ const [flag, setFlag] = React40.useState(false);
10159
+ const [prevIntKey, setPrevIntKey] = React40.useState("0");
10160
+ const [isFocused, setIsFocused] = React40.useState(false);
10161
+ React40.useEffect(() => {
10162
+ if (flag) {
10163
+ const timer = setTimeout(() => {
10164
+ setFlag(false);
10165
+ }, 2e3);
10166
+ return () => clearTimeout(timer);
10167
+ }
10168
+ }, [flag]);
10169
+ const calculatedValue = React40.useMemo(() => {
10170
+ return getDateByType(date, picker);
10171
+ }, [date, picker]);
10172
+ const calculateNewValue = (key) => {
10173
+ if (picker === "12hours") {
10174
+ if (flag && calculatedValue.slice(1, 2) === "1" && prevIntKey === "0")
10175
+ return "0" + key;
10176
+ }
10177
+ return !flag ? "0" + key : calculatedValue.slice(1, 2) + key;
10178
+ };
10179
+ const handleArrowClick = (direction) => {
10180
+ const step = direction === "up" ? 1 : -1;
10181
+ const newValue = getArrowByType(calculatedValue, step, picker);
10182
+ if (flag) setFlag(false);
10183
+ const tempDate = new Date(date);
10184
+ setDate(setDateByType(tempDate, newValue, picker, period));
10185
+ };
10186
+ const handleKeyDown = (e) => {
10187
+ if (e.key === "Tab") return;
10188
+ e.preventDefault();
10189
+ if (e.key === "ArrowRight") onRightFocus?.();
10190
+ if (e.key === "ArrowLeft") onLeftFocus?.();
10191
+ if (["ArrowUp", "ArrowDown"].includes(e.key)) {
10192
+ const step = e.key === "ArrowUp" ? 1 : -1;
10193
+ const newValue = getArrowByType(calculatedValue, step, picker);
10194
+ if (flag) setFlag(false);
10195
+ const tempDate = new Date(date);
10196
+ setDate(setDateByType(tempDate, newValue, picker, period));
10197
+ }
10198
+ if (e.key >= "0" && e.key <= "9") {
10199
+ if (picker === "12hours") setPrevIntKey(e.key);
10200
+ const newValue = calculateNewValue(e.key);
10201
+ if (flag) onRightFocus?.();
10202
+ setFlag((prev) => !prev);
10203
+ const tempDate = new Date(date);
10204
+ setDate(setDateByType(tempDate, newValue, picker, period));
10205
+ }
10206
+ };
10207
+ const getPickerLabel = () => {
10208
+ if (label) return label;
10209
+ switch (picker) {
10210
+ case "hours":
10211
+ case "12hours":
10212
+ return "Horas";
10213
+ case "minutes":
10214
+ return "Minutos";
10215
+ case "seconds":
10216
+ return "Segundos";
10217
+ default:
10218
+ return "";
10219
+ }
10220
+ };
10221
+ const getAriaLabel = () => {
10222
+ const baseLabel = getPickerLabel();
10223
+ return `${baseLabel}, valor atual: ${calculatedValue}.`;
10224
+ };
10225
+ return /* @__PURE__ */ jsxs43("div", { className: "relative group flex flex-col items-center", children: [
10226
+ getPickerLabel() && /* @__PURE__ */ jsx64(
10227
+ "label",
10228
+ {
10229
+ htmlFor: id || picker,
10230
+ className: "text-xs sm:text-sm font-medium text-muted-foreground mb-1 sm:mb-2 select-none",
10231
+ children: getPickerLabel()
10232
+ }
10233
+ ),
10234
+ /* @__PURE__ */ jsxs43(
10235
+ "div",
10236
+ {
10237
+ className: cn(
10238
+ "relative flex flex-col items-center",
10239
+ "transition-all duration-200"
10240
+ ),
10241
+ children: [
10242
+ showArrows && /* @__PURE__ */ jsx64(
10243
+ "button",
10244
+ {
10245
+ type: "button",
10246
+ onClick: () => handleArrowClick("up"),
10247
+ className: cn(
10248
+ "flex items-center justify-center w-10 sm:w-12 h-5 sm:h-6 mb-1",
10249
+ "rounded-t",
10250
+ "bg-background hover:bg-accent active:bg-accent/80 transition-colors",
10251
+ "text-muted-foreground hover:text-foreground",
10252
+ "focus:outline-none focus:ring-1 focus:ring-ring",
10253
+ "touch-manipulation",
10254
+ isFocused && "border-ring"
10255
+ ),
10256
+ tabIndex: -1,
10257
+ "aria-label": `Incrementar ${getPickerLabel().toLowerCase()}`,
10258
+ children: /* @__PURE__ */ jsx64(CaretUpIcon2, { size: 14, className: "sm:w-4 sm:h-4" })
10259
+ }
10260
+ ),
10261
+ /* @__PURE__ */ jsxs43("div", { className: "relative", children: [
10262
+ /* @__PURE__ */ jsx64(
10263
+ "input",
10264
+ {
10265
+ ref,
10266
+ id: id || picker,
10267
+ name: name || picker,
10268
+ className: cn(
10269
+ "w-16 sm:w-20 h-10 sm:h-12 text-center font-mono text-lg sm:text-xl font-semibold",
10270
+ "border-2 rounded-lg",
10271
+ "bg-background text-foreground",
10272
+ "transition-all duration-200",
10273
+ "focus:outline-none focus:ring-2 focus:ring-ring focus:border-ring",
10274
+ "selection:bg-primary selection:text-primary-foreground",
10275
+ "touch-manipulation",
10276
+ showArrows && "rounded-lg",
10277
+ isFocused && "ring-2 ring-ring border-ring shadow-md",
10278
+ className
10279
+ ),
10280
+ value: value || calculatedValue,
10281
+ onChange: (e) => {
10282
+ e.preventDefault();
10283
+ onChange?.(e);
10284
+ },
10285
+ onFocus: (e) => {
10286
+ setIsFocused(true);
10287
+ props.onFocus?.(e);
10288
+ e.target.select();
10289
+ },
10290
+ onBlur: (e) => {
10291
+ setIsFocused(false);
10292
+ props.onBlur?.(e);
10293
+ },
10294
+ type,
10295
+ inputMode: "decimal",
10296
+ onKeyDown: (e) => {
10297
+ onKeyDown?.(e);
10298
+ handleKeyDown(e);
10299
+ },
10300
+ "aria-label": getAriaLabel(),
10301
+ "aria-describedby": `${id || picker}-help`,
10302
+ autoComplete: "off",
10303
+ spellCheck: false,
10304
+ ...props
10305
+ }
10306
+ ),
10307
+ isFocused && /* @__PURE__ */ jsx64("div", { className: "absolute inset-0 rounded-lg ring-2 ring-primary/20 pointer-events-none animate-pulse" })
10308
+ ] }),
10309
+ showArrows && /* @__PURE__ */ jsx64(
10310
+ "button",
10311
+ {
10312
+ type: "button",
10313
+ onClick: () => handleArrowClick("down"),
10314
+ className: cn(
10315
+ "flex items-center justify-center w-10 sm:w-12 h-5 sm:h-6 mt-1",
10316
+ "rounded-b",
10317
+ "bg-background hover:bg-accent active:bg-accent/80 transition-colors",
10318
+ "text-muted-foreground hover:text-foreground",
10319
+ "focus:outline-none focus:ring-1 focus:ring-ring",
10320
+ "touch-manipulation",
10321
+ isFocused && "border-ring"
10322
+ ),
10323
+ tabIndex: -1,
10324
+ "aria-label": `Decrementar ${getPickerLabel().toLowerCase()}`,
10325
+ children: /* @__PURE__ */ jsx64(CaretDownIcon4, { size: 14, className: "sm:w-4 sm:h-4" })
10326
+ }
10327
+ )
10328
+ ]
10329
+ }
10330
+ )
10331
+ ] });
10332
+ }
10333
+ );
10334
+ TimePickerInput.displayName = "TimePickerInput";
10335
+
10336
+ // src/components/picker/TimePicker.tsx
10337
+ import { Fragment as Fragment8, jsx as jsx65, jsxs as jsxs44 } from "react/jsx-runtime";
10338
+ function TimePicker({
10339
+ date,
10340
+ setDate,
10341
+ hideSeconds,
10342
+ enableButton
10343
+ }) {
10344
+ const minuteRef = React41.useRef(null);
10345
+ const hourRef = React41.useRef(null);
10346
+ const secondRef = React41.useRef(null);
10347
+ const containerVariants = {
10348
+ hidden: { opacity: 0, y: 10 },
10349
+ visible: {
10350
+ opacity: 1,
10351
+ y: 0,
10352
+ transition: {
10353
+ duration: 0.3,
10354
+ staggerChildren: 0.1
10355
+ }
10356
+ }
10357
+ };
10358
+ const itemVariants2 = {
10359
+ hidden: { opacity: 0, y: 10 },
10360
+ visible: { opacity: 1, y: 0 }
10361
+ };
10362
+ return /* @__PURE__ */ jsxs44(
10363
+ motion14.div,
10364
+ {
10365
+ variants: containerVariants,
10366
+ initial: "hidden",
10367
+ animate: "visible",
10368
+ className: "flex items-end justify-center gap-2 sm:gap-3 p-2 sm:p-3 md:p-4 rounded-lg bg-muted/20 border border-border/50 w-full max-w-full overflow-hidden",
10369
+ children: [
10370
+ /* @__PURE__ */ jsx65(
10371
+ motion14.div,
10372
+ {
10373
+ variants: itemVariants2,
10374
+ className: "grid gap-1 sm:gap-2 text-center flex-shrink-0 min-w-0",
10375
+ children: /* @__PURE__ */ jsx65(
10376
+ TimePickerInput,
10377
+ {
10378
+ picker: "hours",
10379
+ date,
10380
+ setDate,
10381
+ ref: hourRef,
10382
+ onRightFocus: () => minuteRef.current?.focus(),
10383
+ enableButton
10384
+ }
10385
+ )
10386
+ }
10387
+ ),
10388
+ /* @__PURE__ */ jsx65(
10389
+ motion14.div,
10390
+ {
10391
+ variants: itemVariants2,
10392
+ className: "grid gap-1 sm:gap-2 text-center flex-shrink-0 min-w-0",
10393
+ children: /* @__PURE__ */ jsx65(
10394
+ TimePickerInput,
10395
+ {
10396
+ picker: "minutes",
10397
+ date,
10398
+ setDate,
10399
+ ref: minuteRef,
10400
+ onLeftFocus: () => hourRef.current?.focus(),
10401
+ onRightFocus: () => secondRef.current?.focus(),
10402
+ enableButton
10403
+ }
10404
+ )
10405
+ }
10406
+ ),
10407
+ /* @__PURE__ */ jsx65(AnimatePresence10, { children: !hideSeconds && /* @__PURE__ */ jsx65(Fragment8, { children: /* @__PURE__ */ jsx65(
10408
+ motion14.div,
10409
+ {
10410
+ variants: itemVariants2,
10411
+ initial: "hidden",
10412
+ animate: "visible",
10413
+ exit: "hidden",
10414
+ className: "grid gap-1 sm:gap-2 text-center flex-shrink-0 min-w-0",
10415
+ children: /* @__PURE__ */ jsx65(
10416
+ TimePickerInput,
10417
+ {
10418
+ picker: "seconds",
10419
+ date,
10420
+ setDate,
10421
+ ref: secondRef,
10422
+ onLeftFocus: () => minuteRef.current?.focus(),
10423
+ enableButton
10424
+ }
10425
+ )
10426
+ }
10427
+ ) }) })
10428
+ ]
10429
+ }
10430
+ );
10431
+ }
10432
+
10433
+ // src/components/picker/DateTimePicker.tsx
10434
+ import { CalendarBlankIcon, ClockIcon } from "@phosphor-icons/react";
10435
+ import { jsx as jsx66, jsxs as jsxs45 } from "react/jsx-runtime";
10436
+ function DateTimePicker({
10437
+ label,
10438
+ date,
10439
+ onChange,
10440
+ display,
10441
+ hideSeconds,
10442
+ hideHour,
10443
+ hideMinute,
10444
+ fromDate,
10445
+ toDate,
10446
+ disabled,
10447
+ className,
10448
+ error
10449
+ }) {
10450
+ const [internalDate, setInternalDate] = useState18(date);
10451
+ const [open, setOpen] = useState18(false);
10452
+ const [timePickerOpen, setTimePickerOpen] = useState18(false);
10453
+ const handleSelect = (newDay) => {
10454
+ if (!newDay) return;
10455
+ if (!internalDate) {
10456
+ setInternalDate(newDay);
10457
+ onChange(newDay);
10458
+ return;
10459
+ }
10460
+ const diff = newDay.getTime() - internalDate.getTime();
10461
+ const diffInDays = diff / (1e3 * 60 * 60 * 24);
10462
+ const newDateFull = add(internalDate, { days: Math.ceil(diffInDays) });
10463
+ setInternalDate(newDateFull);
10464
+ onChange(newDateFull);
10465
+ };
10466
+ const handleTimeChange = (newDate) => {
10467
+ setInternalDate(newDate);
10468
+ onChange(newDate);
10469
+ };
10470
+ const getTimeFormat = () => {
10471
+ if (hideHour && hideMinute) return "";
10472
+ if (hideHour) return hideSeconds ? "mm" : "mm:ss";
10473
+ if (hideMinute) return hideSeconds ? "HH" : "HH':00'";
10474
+ return hideSeconds ? "HH:mm" : "HH:mm:ss";
10475
+ };
10476
+ const getDisplayFormat = () => {
10477
+ const timeFormat = getTimeFormat();
10478
+ if (!timeFormat) return "PPP";
10479
+ return `PPP - ${timeFormat}`;
10480
+ };
10481
+ useEffect16(() => {
10482
+ if (date) {
10483
+ setInternalDate(date);
10484
+ }
10485
+ }, [date, open]);
10486
+ return /* @__PURE__ */ jsxs45("div", { className: cn("space-y-2 w-full sm:w-auto", className), children: [
10487
+ label && /* @__PURE__ */ jsx66(LabelBase_default, { children: label }),
10488
+ /* @__PURE__ */ jsxs45(PopoverBase, { open, onOpenChange: setOpen, children: [
10489
+ /* @__PURE__ */ jsx66(PopoverTriggerBase, { disabled, asChild: true, children: /* @__PURE__ */ jsxs45(
10490
+ ButtonBase,
10491
+ {
10492
+ variant: "outline",
10493
+ className: cn(
10494
+ "w-full justify-start text-left min-w-0 overflow-hidden",
10495
+ !date && "text-muted-foreground/"
10496
+ ),
10497
+ children: [
10498
+ /* @__PURE__ */ jsx66("span", { className: "truncate flex-1", children: date ? display ? format(date, "dd/MM/yyyy") : format(date, getDisplayFormat(), { locale: ptBR }) : "Selecione uma Data" }),
10499
+ /* @__PURE__ */ jsx66(CalendarBlankIcon, { className: "flex-shrink-0 w-5 h-5 sm:w-6 sm:h-6" })
10500
+ ]
10501
+ }
10502
+ ) }),
10503
+ /* @__PURE__ */ jsx66(ErrorMessage_default, { error }),
10504
+ /* @__PURE__ */ jsx66(
10505
+ PopoverContentBase,
10506
+ {
10507
+ className: "w-full p-0",
10508
+ align: "center",
10509
+ sideOffset: 4,
10510
+ side: "bottom",
10511
+ avoidCollisions: true,
10512
+ collisionPadding: 8,
10513
+ children: /* @__PURE__ */ jsxs45("div", { className: "flex flex-col space-y-2 sm:space-y-3 p-2 sm:p-3 md:p-4 max-h-[calc(100vh-4rem)] overflow-y-auto", children: [
10514
+ /* @__PURE__ */ jsx66(
10515
+ CalendarBase2,
10516
+ {
10517
+ mode: "single",
10518
+ locale: ptBR,
10519
+ selected: internalDate,
10520
+ onSelect: (d) => handleSelect(d),
10521
+ initialFocus: true,
10522
+ fromDate,
10523
+ toDate,
10524
+ className: cn("w-full", hideHour && hideMinute && "border-0")
10525
+ }
10526
+ ),
10527
+ !(hideHour && hideMinute) && /* @__PURE__ */ jsx66("div", { className: "flex justify-center w-full px-2", children: /* @__PURE__ */ jsxs45(
10528
+ PopoverBase,
10529
+ {
10530
+ open: timePickerOpen,
10531
+ onOpenChange: setTimePickerOpen,
10532
+ children: [
10533
+ /* @__PURE__ */ jsx66(PopoverTriggerBase, { asChild: true, children: /* @__PURE__ */ jsxs45(
10534
+ ButtonBase,
10535
+ {
10536
+ variant: "outline",
10537
+ size: "default",
10538
+ className: cn(
10539
+ "flex items-center justify-center gap-1.5 sm:gap-2",
10540
+ "px-2 sm:px-3 py-1.5 sm:py-2",
10541
+ "text-sm sm:text-base font-semibold w-full max-w-xs",
10542
+ "border-2 border-primary/20 rounded-lg",
10543
+ "bg-background hover:bg-primary/10 hover:border-primary/30",
10544
+ "transition-all duration-200",
10545
+ "shadow-sm hover:shadow-md active:scale-[0.98]",
10546
+ "min-h-[36px] sm:min-h-[40px]"
10547
+ ),
10548
+ children: [
10549
+ /* @__PURE__ */ jsx66(ClockIcon, { className: "text-primary flex-shrink-0 w-4 h-4 sm:w-5 sm:h-5" }),
10550
+ /* @__PURE__ */ jsx66("span", { className: "text-black truncate", children: internalDate ? format(internalDate, getTimeFormat() || "HH:mm", {
10551
+ locale: ptBR
10552
+ }) : "00:00" })
10553
+ ]
10554
+ }
10555
+ ) }),
10556
+ /* @__PURE__ */ jsx66(
10557
+ PopoverContentBase,
10558
+ {
10559
+ className: "w-[calc(100vw-2rem)] max-w-sm p-3 sm:p-3 rounded-md",
10560
+ align: "center",
10561
+ side: "top",
10562
+ sideOffset: 8,
10563
+ avoidCollisions: true,
10564
+ collisionPadding: 8,
10565
+ children: /* @__PURE__ */ jsxs45("div", { className: "flex flex-col items-center space-y-2 sm:space-y-3", children: [
10566
+ /* @__PURE__ */ jsx66("h4", { className: "text-sm sm:text-base font-medium text-center", children: "Alterar Hor\xE1rio" }),
10567
+ /* @__PURE__ */ jsx66(
10568
+ TimePicker,
10569
+ {
10570
+ setDate: handleTimeChange,
10571
+ date: internalDate,
10572
+ hideSeconds
10573
+ }
10574
+ ),
10575
+ /* @__PURE__ */ jsx66(
10576
+ ButtonBase,
10577
+ {
10578
+ size: "sm",
10579
+ variant: "destructive",
10580
+ onClick: () => setTimePickerOpen(false),
10581
+ className: "w-full text-xs sm:text-sm min-h-[36px] sm:min-h-[40px]",
10582
+ children: "Fechar"
10583
+ }
10584
+ )
10585
+ ] })
10586
+ }
10587
+ )
10588
+ ]
10589
+ }
10590
+ ) })
10591
+ ] })
10592
+ }
10593
+ )
10594
+ ] })
10595
+ ] });
10596
+ }
10597
+
10598
+ // src/components/picker/RangePicker.tsx
10599
+ import * as React42 from "react";
10600
+ import {
10601
+ DayPicker as DayPicker3
10602
+ } from "react-day-picker";
10603
+ import {
10604
+ CaretLeftIcon as CaretLeftIcon3,
10605
+ CaretRightIcon as CaretRightIcon5,
10606
+ CalendarBlankIcon as CalendarBlankIcon2
10607
+ } from "@phosphor-icons/react";
10608
+ import { motion as motion15, AnimatePresence as AnimatePresence11, useAnimation } from "framer-motion";
10609
+ import { CalendarDotIcon } from "@phosphor-icons/react/dist/ssr";
10610
+ import { jsx as jsx67, jsxs as jsxs46 } from "react/jsx-runtime";
10611
+ function RangePicker({
10612
+ value,
10613
+ onChange,
10614
+ label = "Selecionar intervalo",
10615
+ minDate,
10616
+ maxDate,
10617
+ error
10618
+ }) {
10619
+ const [open, setOpen] = React42.useState(false);
10620
+ const [range, setRange] = React42.useState(value);
10621
+ const controls = useAnimation();
10622
+ React42.useEffect(() => {
10623
+ setRange(value);
10624
+ }, [value]);
10625
+ const handleSelect = (selected) => {
10626
+ setRange(selected);
10627
+ onChange?.(selected);
10628
+ };
10629
+ const handleClear = () => {
10630
+ setRange(void 0);
10631
+ onChange?.(void 0);
10632
+ };
10633
+ return /* @__PURE__ */ jsxs46(PopoverBase, { open, onOpenChange: setOpen, children: [
10634
+ /* @__PURE__ */ jsx67(PopoverTriggerBase, { asChild: true, children: /* @__PURE__ */ jsx67(
10635
+ motion15.div,
10636
+ {
10637
+ whileTap: { scale: 0.97 },
10638
+ whileHover: { scale: open ? 1.03 : 1.01 },
10639
+ transition: { type: "spring", stiffness: 300, damping: 20 },
10640
+ children: /* @__PURE__ */ jsxs46(
10641
+ ButtonBase,
10642
+ {
10643
+ variant: "outline",
10644
+ className: "flex gap-2 transition-all duration-200 min-w-[250px] text-left justify-between items-center",
10645
+ children: [
10646
+ /* @__PURE__ */ jsx67(
10647
+ motion15.span,
10648
+ {
10649
+ className: "text-sm font-medium",
10650
+ transition: { duration: 0.2 },
10651
+ animate: controls,
10652
+ children: range?.from && range?.to ? `${range.from.toLocaleDateString()} - ${range.to.toLocaleDateString()}` : label
10653
+ }
10654
+ ),
10655
+ /* @__PURE__ */ jsx67(
10656
+ motion15.span,
10657
+ {
10658
+ animate: open ? { rotate: 8, scale: 1.15 } : { rotate: 0, scale: 1 },
10659
+ transition: { type: "spring", stiffness: 300, damping: 18 },
10660
+ children: /* @__PURE__ */ jsx67(CalendarBlankIcon2, { className: "w-4 h-4 transition-transform group-hover:scale-110" })
10661
+ }
10662
+ )
10663
+ ]
10664
+ }
10665
+ )
10666
+ }
10667
+ ) }),
10668
+ /* @__PURE__ */ jsx67(ErrorMessage_default, { error }),
10669
+ /* @__PURE__ */ jsx67(AnimatePresence11, { children: open && /* @__PURE__ */ jsx67(
10670
+ PopoverContentBase,
10671
+ {
10672
+ asChild: true,
10673
+ className: "w-auto min-w-[250px] p-0 shadow-xl overflow-y-hidden",
10674
+ children: /* @__PURE__ */ jsxs46(
10675
+ motion15.div,
10676
+ {
10677
+ initial: { opacity: 0, y: 16 },
10678
+ animate: { opacity: 1, y: 0 },
10679
+ exit: { opacity: 0, y: 16 },
10680
+ transition: { duration: 0.18, ease: "easeOut" },
10681
+ children: [
10682
+ /* @__PURE__ */ jsx67("div", { className: "p-4", children: /* @__PURE__ */ jsx67(
10683
+ motion15.div,
10684
+ {
10685
+ initial: { opacity: 0, y: 8 },
10686
+ animate: { opacity: 1, y: 0 },
10687
+ exit: { opacity: 0, y: 8 },
10688
+ transition: { duration: 0.18 },
10689
+ className: "w-full",
10690
+ children: /* @__PURE__ */ jsx67(
10691
+ DayPicker3,
10692
+ {
10693
+ mode: "range",
10694
+ selected: range,
10695
+ onSelect: handleSelect,
10696
+ showOutsideDays: true,
10697
+ fromDate: minDate,
10698
+ toDate: maxDate,
10699
+ className: "min-w-0 flex flex-col",
10700
+ classNames: {
10701
+ months: "flex items-center flex-col sm:flex-row space-y-2 sm:space-x-2 sm:space-y-0 flex-1",
10702
+ month: "space-y-2 min-w-0 flex-1 flex flex-col",
10703
+ caption: "flex justify-center pt-1 relative items-center h-[10%] min-h-[2rem] mb-2",
10704
+ caption_label: "text-[clamp(0.875rem,2.5vw,1.25rem)] font-semibold truncate px-10 tracking-tight",
10705
+ nav: "space-x-1 flex items-center",
10706
+ nav_button: cn(
10707
+ buttonVariantsBase({ variant: "outline" }),
10708
+ "h-8 w-8 bg-background p-0 opacity-60 hover:opacity-100 hover:bg-muted flex-shrink-0 touch-manipulation transition-all duration-200 ease-out hover:scale-105 active:scale-95",
10709
+ "[@media(min-width:400px)]:h-9 [@media(min-width:400px)]:w-9"
10710
+ ),
10711
+ nav_button_previous: "absolute left-0",
10712
+ nav_button_next: "absolute right-0",
10713
+ table: "w-full border-collapse min-w-0 flex-1 flex flex-col",
10714
+ head_row: "flex w-full gap-1 mb-1",
10715
+ head_cell: "text-muted-foreground rounded-md flex-1 min-w-0 font-semibold text-[clamp(0.625rem,1.5vw,0.75rem)] text-center pb-1 uppercase tracking-wider",
10716
+ row: "flex w-full flex-1 gap-1",
10717
+ cell: cn(
10718
+ "flex-1 min-w-0 aspect-square text-center relative",
10719
+ "[&:has([aria-selected].day-range-end)]:rounded-r-lg",
10720
+ "[&:has([aria-selected].day-range-start)]:rounded-l-lg",
10721
+ "[&:has([aria-selected].day-outside)]:bg-muted/50",
10722
+ "[&:has([aria-selected])]:bg-muted",
10723
+ "first:[&:has([aria-selected])]:rounded-l-lg",
10724
+ "last:[&:has([aria-selected])]:rounded-r-lg",
10725
+ "focus-within:relative focus-within:z-20"
10726
+ ),
10727
+ day: cn(
10728
+ buttonVariantsBase({ variant: "ghost" }),
10729
+ "w-full h-full min-w-9",
10730
+ "aria-selected:opacity-100 hover:bg-muted flex items-center justify-center p-1",
10731
+ "transition-all duration-200 ease-out !scale-100 aria-selected:!scale-100 hover:!scale-100 active:!scale-100"
10732
+ ),
10733
+ day_selected: "bg-primary text-primary-foreground hover:bg-primary/90 focus:bg-primary/90 font-semibold hover:text-white !scale-100 p-1 !border-0 !outline-none",
10734
+ day_today: "bg-muted text-foreground font-bold ring-2 ring-primary/50 ring-inset p-1 !border-0 !outline-none",
10735
+ day_outside: "day-outside text-muted-foreground/40 opacity-40 aria-selected:bg-muted/50 aria-selected:text-foreground",
10736
+ day_disabled: "text-muted-foreground/30 opacity-40 cursor-not-allowed",
10737
+ day_range_middle: "aria-selected:bg-muted aria-selected:text-foreground",
10738
+ day_hidden: "invisible"
10739
+ },
10740
+ components: {
10741
+ IconLeft: () => /* @__PURE__ */ jsx67(CaretLeftIcon3, { className: "h-4 w-4" }),
10742
+ IconRight: () => /* @__PURE__ */ jsx67(CaretRightIcon5, { className: "h-4 w-4" })
10743
+ }
10744
+ }
10745
+ )
10746
+ }
10747
+ ) }),
10748
+ /* @__PURE__ */ jsxs46("div", { className: "flex justify-end gap-2 px-4 pb-4", children: [
10749
+ /* @__PURE__ */ jsx67("div", { style: { display: "inline-block" }, children: /* @__PURE__ */ jsx67(
10750
+ motion15.div,
10751
+ {
10752
+ whileHover: { scale: 1.03 },
10753
+ whileTap: { scale: 0.95 },
10754
+ children: /* @__PURE__ */ jsx67(
10755
+ ButtonBase,
10756
+ {
10757
+ variant: "outline",
10758
+ onClick: () => {
10759
+ setRange({
10760
+ from: /* @__PURE__ */ new Date(),
10761
+ to: /* @__PURE__ */ new Date()
10762
+ });
10763
+ },
10764
+ children: /* @__PURE__ */ jsx67(CalendarDotIcon, {})
10765
+ }
10766
+ )
10767
+ }
10768
+ ) }),
10769
+ /* @__PURE__ */ jsx67("div", { style: { display: "inline-block" }, children: /* @__PURE__ */ jsx67(
10770
+ motion15.div,
10771
+ {
10772
+ whileHover: { scale: 1.03 },
10773
+ whileTap: { scale: 0.95 },
10774
+ children: /* @__PURE__ */ jsx67(
10775
+ DeleteButton,
10776
+ {
10777
+ variant: "outline",
10778
+ onClick: handleClear,
10779
+ disabled: !range?.from && !range?.to,
10780
+ className: "hover:bg-destructive hover:text-white",
10781
+ children: "Limpar"
10782
+ }
10783
+ )
10784
+ }
10785
+ ) }),
10786
+ /* @__PURE__ */ jsx67("div", { style: { display: "inline-block", width: "100%" }, children: /* @__PURE__ */ jsx67(
10787
+ motion15.div,
10788
+ {
10789
+ whileHover: { scale: 1.02 },
10790
+ whileTap: { scale: 0.98 },
10791
+ children: /* @__PURE__ */ jsx67(
10792
+ ButtonBase,
10793
+ {
10794
+ className: "font-semibold w-full text-center",
10795
+ onClick: () => setOpen(false),
10796
+ disabled: !range?.from || !range?.to,
10797
+ children: "Selecionar"
10798
+ }
10799
+ )
10800
+ }
10801
+ ) })
10802
+ ] })
10803
+ ]
10804
+ }
10805
+ )
10806
+ }
10807
+ ) })
10808
+ ] });
10809
+ }
10810
+ RangePicker.displayName = "RangePicker";
10811
+
9882
10812
  // src/hooks/use-drag.tsx
9883
- import { useState as useState17, useCallback as useCallback12, useRef as useRef7, useEffect as useEffect16 } from "react";
10813
+ import { useState as useState20, useCallback as useCallback12, useRef as useRef8, useEffect as useEffect18 } from "react";
9884
10814
  var useDrag = (options = {}) => {
9885
- const [isDragging, setIsDragging] = useState17(null);
9886
- const [positions, setPositions] = useState17({});
9887
- const dragStartPos = useRef7(null);
9888
- const dragId = useRef7(null);
10815
+ const [isDragging, setIsDragging] = useState20(null);
10816
+ const [positions, setPositions] = useState20({});
10817
+ const dragStartPos = useRef8(null);
10818
+ const dragId = useRef8(null);
9889
10819
  const handleMouseDown = useCallback12((id, e) => {
9890
10820
  e.preventDefault();
9891
10821
  const currentPosition = positions[id] || { top: 0, left: 0 };
@@ -9923,7 +10853,7 @@ var useDrag = (options = {}) => {
9923
10853
  dragStartPos.current = null;
9924
10854
  dragId.current = null;
9925
10855
  }, [options]);
9926
- useEffect16(() => {
10856
+ useEffect18(() => {
9927
10857
  if (isDragging) {
9928
10858
  document.addEventListener("mousemove", handleMouseMove);
9929
10859
  document.addEventListener("mouseup", handleMouseUp);
@@ -10015,6 +10945,7 @@ export {
10015
10945
  CommandSeparatorBase,
10016
10946
  CommandShortcutBase,
10017
10947
  CopyButton,
10948
+ DateTimePicker,
10018
10949
  DeleteButton,
10019
10950
  DestructiveDialog,
10020
10951
  DialogBase,
@@ -10106,6 +11037,7 @@ export {
10106
11037
  ProgressCirclesBase,
10107
11038
  ProgressPanelsBase,
10108
11039
  ProgressSegmentsBase,
11040
+ RangePicker,
10109
11041
  RefreshButton,
10110
11042
  SaveButton,
10111
11043
  ScrollAreaBase,
@@ -10175,6 +11107,8 @@ export {
10175
11107
  TabsTriggerBase,
10176
11108
  TextAreaBase,
10177
11109
  ThemeProviderBase,
11110
+ TimePicker,
11111
+ TimePickerInput,
10178
11112
  Toaster,
10179
11113
  TooltipBase,
10180
11114
  TooltipContentBase,
@@ -10191,14 +11125,34 @@ export {
10191
11125
  badgeVariants,
10192
11126
  buttonVariantsBase,
10193
11127
  compactTick,
11128
+ convert12HourTo24Hour,
10194
11129
  detectDataFields,
10195
11130
  detectXAxis,
11131
+ display12HourValue,
10196
11132
  formatFieldName,
10197
11133
  generateAdditionalColors,
11134
+ getArrowByType,
11135
+ getDateByType,
11136
+ getValid12Hour,
11137
+ getValidArrow12Hour,
11138
+ getValidArrowHour,
11139
+ getValidArrowMinuteOrSecond,
11140
+ getValidArrowNumber,
11141
+ getValidHour,
11142
+ getValidMinuteOrSecond,
11143
+ getValidNumber,
11144
+ isValid12Hour,
11145
+ isValidHour,
11146
+ isValidMinuteOrSecond,
10198
11147
  niceCeil,
10199
11148
  pillLabelRenderer_default as renderPillLabel,
10200
11149
  resolveChartMargins,
10201
11150
  resolveContainerPaddingLeft,
11151
+ set12Hours,
11152
+ setDateByType,
11153
+ setHours,
11154
+ setMinutes,
11155
+ setSeconds,
10202
11156
  toast2 as toast,
10203
11157
  useChartHighlights,
10204
11158
  useDrag,