@stableflow/pay-ui 0.2.0-beta-bb77113a4d-20261012 → 0.2.1
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.
|
@@ -157,7 +157,7 @@ function DateRangePicker(props) {
|
|
|
157
157
|
}
|
|
158
158
|
commit(calendarRangeFromPicks(draftStart, day));
|
|
159
159
|
};
|
|
160
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-
|
|
160
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-flex w-max max-w-full", className), children: [
|
|
161
161
|
/* @__PURE__ */ jsxs(
|
|
162
162
|
"button",
|
|
163
163
|
{
|
|
@@ -171,13 +171,13 @@ function DateRangePicker(props) {
|
|
|
171
171
|
setDraftStart(null);
|
|
172
172
|
},
|
|
173
173
|
className: cn(
|
|
174
|
-
"inline-flex cursor-pointer h-9 w-
|
|
174
|
+
"inline-flex cursor-pointer h-9 w-max max-w-full items-center gap-2 whitespace-nowrap rounded-[6px] border border-[#E3E3E3] bg-white px-3 text-sm font-medium text-black outline-none",
|
|
175
175
|
fontSans,
|
|
176
176
|
triggerClassName
|
|
177
177
|
),
|
|
178
178
|
children: [
|
|
179
|
-
/* @__PURE__ */ jsx("span", { className: "
|
|
180
|
-
/* @__PURE__ */ jsx("span", { className: "
|
|
179
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[#aaa]", children: "Time" }),
|
|
180
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0", children: formatDateRangeLabel(value) }),
|
|
181
181
|
/* @__PURE__ */ jsx(IconArrowDown, { className: cn("h-1.5 w-2.75 shrink-0 text-black transition-transform", open && "rotate-180") })
|
|
182
182
|
]
|
|
183
183
|
}
|
|
@@ -221,7 +221,7 @@ function DateRangePicker(props) {
|
|
|
221
221
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1", children: DATE_RANGE_WEEKDAY_LABELS.map((label) => /* @__PURE__ */ jsx("div", { className: "text-center text-[11px] font-medium text-[#aaa]", children: label }, label)) }),
|
|
222
222
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1", children: days.map((day) => {
|
|
223
223
|
const inMonth = isSameMonth(day, viewMonth);
|
|
224
|
-
const selected = isSameDay2(day,
|
|
224
|
+
const selected = draftStart ? isSameDay2(day, draftStart) : isSameDay2(day, value.from) || isSameDay2(day, value.to);
|
|
225
225
|
const inRange = !draftStart && isWithinInterval(day, { start: value.from, end: value.to });
|
|
226
226
|
return /* @__PURE__ */ jsx(
|
|
227
227
|
"button",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/date-range-picker/DateRangePicker.tsx","../../src/date-range-picker/config.ts","../../src/date-range-picker/utils.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n addMonths,\n eachDayOfInterval,\n endOfMonth,\n endOfWeek,\n format,\n isSameDay,\n isSameMonth,\n isWithinInterval,\n startOfMonth,\n startOfWeek,\n} from \"date-fns\";\nimport { IconArrowDown } from \"../icons/outline/arrow-down\";\nimport { cn } from \"../lib/cn\";\nimport { fontSans } from \"../lib/font\";\nimport { floatingLayerZIndex } from \"../overlay/stack\";\nimport { FLOATING_ALIGN, FLOATING_SIDE, useFloatingPosition } from \"../overlay/use-floating-position\";\nimport { DATE_RANGE_PRESET_OPTIONS, DATE_RANGE_WEEKDAY_LABELS } from \"./config\";\nimport { calendarRangeFromPicks, formatDateRangeLabel, lastNDaysRange, type DateRangeValue } from \"./utils\";\n\nexport type { DateRangeValue } from \"./utils\";\n\nexport function DateRangePicker(props: {\n value: DateRangeValue;\n onChange: (range: DateRangeValue) => void;\n className?: string;\n triggerClassName?: string;\n}) {\n const { value, onChange, className, triggerClassName } = props;\n const triggerRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const [open, setOpen] = useState(false);\n const [viewMonth, setViewMonth] = useState(() => startOfMonth(value.to));\n const [draftStart, setDraftStart] = useState<Date | null>(null);\n const panelStyle = useFloatingPosition({\n open,\n triggerRef,\n panelRef,\n side: FLOATING_SIDE.Bottom,\n align: FLOATING_ALIGN.Start,\n offset: 6,\n });\n\n useEffect(() => {\n if (open) setViewMonth(startOfMonth(value.to));\n }, [open, value.to]);\n\n useEffect(() => {\n if (!open) return;\n const onPointerDown = (event: MouseEvent) => {\n const target = event.target as Node | null;\n if (!target) return;\n if (triggerRef.current?.contains(target)) return;\n if (panelRef.current?.contains(target)) return;\n setOpen(false);\n setDraftStart(null);\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setOpen(false);\n setDraftStart(null);\n }\n };\n document.addEventListener(\"mousedown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"mousedown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [open]);\n\n const days = useMemo(() => {\n const monthStart = startOfMonth(viewMonth);\n return eachDayOfInterval({\n start: startOfWeek(monthStart),\n end: endOfWeek(endOfMonth(monthStart)),\n });\n }, [viewMonth]);\n\n const commit = (range: DateRangeValue) => {\n onChange(range);\n setDraftStart(null);\n setOpen(false);\n };\n\n const pickDay = (day: Date) => {\n if (!draftStart) {\n setDraftStart(day);\n return;\n }\n commit(calendarRangeFromPicks(draftStart, day));\n };\n\n return (\n <div className={cn(\"relative inline-block min-w-0\", className)}>\n <button\n ref={triggerRef}\n type=\"button\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-label=\"Select time range\"\n onClick={() => {\n setOpen((current) => !current);\n setDraftStart(null);\n }}\n className={cn(\n \"inline-flex cursor-pointer h-9 w-full min-w-0 items-center justify-between gap-2 overflow-hidden rounded-[6px] border border-[#E3E3E3] bg-white px-3 text-sm font-medium text-black outline-none\",\n fontSans,\n triggerClassName,\n )}\n >\n <span className=\"min-w-0 shrink truncate text-[#aaa]\">Time</span>\n <span className=\"flex min-w-0 flex-1 items-center justify-end gap-2 truncate text-right\">\n {formatDateRangeLabel(value)}\n </span>\n <IconArrowDown className={cn(\"h-1.5 w-2.75 shrink-0 text-black transition-transform\", open && \"rotate-180\")} />\n </button>\n {open && typeof document !== \"undefined\"\n ? createPortal(\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-label=\"Date range\"\n style={{ ...panelStyle, zIndex: floatingLayerZIndex() }}\n className={cn(\n \"w-[min(320px,calc(100vw-32px))] rounded-[16px] border border-black/10 bg-white p-4 shadow-[0_8px_24px_rgba(0,0,0,0.08)]\",\n fontSans,\n )}\n >\n <div className=\"mb-3 flex items-center justify-between\">\n <button\n type=\"button\"\n aria-label=\"Previous month\"\n onClick={() => setViewMonth((month) => addMonths(month, -1))}\n className=\"inline-flex size-8 cursor-pointer items-center justify-center rounded-full border-0 bg-transparent p-0 text-[#606060] hover:bg-black/5\"\n >\n <IconArrowDown className=\"h-1.5 w-2.75 rotate-90\" />\n </button>\n <span className=\"text-sm font-semibold text-black\">{format(viewMonth, \"yyyy MMM\")}</span>\n <button\n type=\"button\"\n aria-label=\"Next month\"\n onClick={() => setViewMonth((month) => addMonths(month, 1))}\n className=\"inline-flex size-8 cursor-pointer items-center justify-center rounded-full border-0 bg-transparent p-0 text-[#606060] hover:bg-black/5\"\n >\n <IconArrowDown className=\"h-1.5 w-2.75 -rotate-90\" />\n </button>\n </div>\n <div className=\"grid grid-cols-7 gap-1\">\n {DATE_RANGE_WEEKDAY_LABELS.map((label) => (\n <div key={label} className=\"text-center text-[11px] font-medium text-[#aaa]\">\n {label}\n </div>\n ))}\n </div>\n <div className=\"grid grid-cols-7 gap-1\">\n {days.map((day) => {\n const inMonth = isSameMonth(day, viewMonth);\n const selected = isSameDay(day, value.from) || isSameDay(day, value.to) || (draftStart ? isSameDay(day, draftStart) : false);\n const inRange = !draftStart && isWithinInterval(day, { start: value.from, end: value.to });\n return (\n <button\n key={day.toISOString()}\n type=\"button\"\n onClick={() => pickDay(day)}\n className={cn(\n \"h-8 cursor-pointer rounded-[8px] border-0 bg-transparent text-[13px] font-medium text-black hover:bg-black/5\",\n !inMonth && \"text-[#ccc]\",\n inRange && !selected && \"bg-black/5\",\n selected && \"bg-black text-white hover:bg-black\",\n )}\n >\n {format(day, \"d\")}\n </button>\n );\n })}\n </div>\n <div className=\"mt-3 flex flex-col gap-1 border-t border-black/10 pt-2\">\n {DATE_RANGE_PRESET_OPTIONS.map((option) => (\n <button\n key={option.days}\n type=\"button\"\n onClick={() => commit(lastNDaysRange(option.days))}\n className=\"cursor-pointer rounded-[8px] border-0 bg-transparent px-2 py-1.5 text-left text-sm font-medium text-black hover:bg-black/5\"\n >\n {option.label}\n </button>\n ))}\n </div>\n </div>,\n document.body,\n )\n : null}\n </div>\n );\n}\n\nexport default DateRangePicker;\n","export const DATE_RANGE_WEEKDAY_LABELS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"] as const;\n\nexport const DATE_RANGE_PRESET = {\n Days30: 30,\n Days7: 7,\n Days1: 1,\n} as const;\n\nexport const DATE_RANGE_PRESET_OPTIONS = [\n { days: DATE_RANGE_PRESET.Days30, label: \"Last 30 days\" },\n { days: DATE_RANGE_PRESET.Days7, label: \"Last 7 days\" },\n { days: DATE_RANGE_PRESET.Days1, label: \"Last 1 day\" },\n] as const;\n","import {\n differenceInCalendarDays,\n endOfDay,\n format,\n isSameDay,\n startOfDay,\n subDays,\n} from \"date-fns\";\nimport { DATE_RANGE_PRESET_OPTIONS } from \"./config\";\n\nexport type DateRangeValue = {\n from: Date;\n to: Date;\n};\n\nexport function calendarRangeFromPicks(start: Date, end: Date): DateRangeValue {\n if (isSameDay(start, end)) {\n return { from: startOfDay(end), to: endOfDay(end) };\n }\n const from = start.getTime() <= end.getTime() ? start : end;\n const to = start.getTime() <= end.getTime() ? end : start;\n return { from: startOfDay(from), to: endOfDay(to) };\n}\n\nexport function lastNDaysRange(days: number, now: Date = new Date()): DateRangeValue {\n return {\n from: startOfDay(subDays(now, days - 1)),\n to: endOfDay(now),\n };\n}\n\nexport function matchesLastNDays(range: DateRangeValue, days: number, now: Date = new Date()) {\n const expected = lastNDaysRange(days, now);\n return isSameDay(range.from, expected.from) && isSameDay(range.to, expected.to);\n}\n\nexport function formatDateRangeLabel(range: DateRangeValue, now: Date = new Date()) {\n const preset = DATE_RANGE_PRESET_OPTIONS.find((option) =>\n matchesLastNDays(range, option.days, now),\n );\n if (preset) return preset.label;\n if (isSameDay(range.from, range.to)) return format(range.from, \"MMM d, yyyy\");\n return `${format(range.from, \"MMM d, yyyy\")} – ${format(range.to, \"MMM d, yyyy\")}`;\n}\n\nexport function isInDateRange(iso: string, range: DateRangeValue) {\n const time = new Date(iso).getTime();\n if (Number.isNaN(time)) return true;\n return time >= range.from.getTime() && time <= range.to.getTime();\n}\n\nexport function rangeToUnixSeconds(range: DateRangeValue) {\n return {\n start_time: Math.floor(range.from.getTime() / 1000),\n end_time: Math.floor(range.to.getTime() / 1000),\n };\n}\n\nexport function dateRangeDayCount(range: DateRangeValue) {\n return differenceInCalendarDays(range.to, range.from) + 1;\n}\n"],"mappings":"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","names":["format","isSameDay","format","isSameDay"]}
|
|
1
|
+
{"version":3,"sources":["../../src/date-range-picker/DateRangePicker.tsx","../../src/date-range-picker/config.ts","../../src/date-range-picker/utils.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n addMonths,\n eachDayOfInterval,\n endOfMonth,\n endOfWeek,\n format,\n isSameDay,\n isSameMonth,\n isWithinInterval,\n startOfMonth,\n startOfWeek,\n} from \"date-fns\";\nimport { IconArrowDown } from \"../icons/outline/arrow-down\";\nimport { cn } from \"../lib/cn\";\nimport { fontSans } from \"../lib/font\";\nimport { floatingLayerZIndex } from \"../overlay/stack\";\nimport { FLOATING_ALIGN, FLOATING_SIDE, useFloatingPosition } from \"../overlay/use-floating-position\";\nimport { DATE_RANGE_PRESET_OPTIONS, DATE_RANGE_WEEKDAY_LABELS } from \"./config\";\nimport { calendarRangeFromPicks, formatDateRangeLabel, lastNDaysRange, type DateRangeValue } from \"./utils\";\n\nexport type { DateRangeValue } from \"./utils\";\n\nexport function DateRangePicker(props: {\n value: DateRangeValue;\n onChange: (range: DateRangeValue) => void;\n className?: string;\n triggerClassName?: string;\n}) {\n const { value, onChange, className, triggerClassName } = props;\n const triggerRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const [open, setOpen] = useState(false);\n const [viewMonth, setViewMonth] = useState(() => startOfMonth(value.to));\n const [draftStart, setDraftStart] = useState<Date | null>(null);\n const panelStyle = useFloatingPosition({\n open,\n triggerRef,\n panelRef,\n side: FLOATING_SIDE.Bottom,\n align: FLOATING_ALIGN.Start,\n offset: 6,\n });\n\n useEffect(() => {\n if (open) setViewMonth(startOfMonth(value.to));\n }, [open, value.to]);\n\n useEffect(() => {\n if (!open) return;\n const onPointerDown = (event: MouseEvent) => {\n const target = event.target as Node | null;\n if (!target) return;\n if (triggerRef.current?.contains(target)) return;\n if (panelRef.current?.contains(target)) return;\n setOpen(false);\n setDraftStart(null);\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setOpen(false);\n setDraftStart(null);\n }\n };\n document.addEventListener(\"mousedown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"mousedown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [open]);\n\n const days = useMemo(() => {\n const monthStart = startOfMonth(viewMonth);\n return eachDayOfInterval({\n start: startOfWeek(monthStart),\n end: endOfWeek(endOfMonth(monthStart)),\n });\n }, [viewMonth]);\n\n const commit = (range: DateRangeValue) => {\n onChange(range);\n setDraftStart(null);\n setOpen(false);\n };\n\n const pickDay = (day: Date) => {\n if (!draftStart) {\n setDraftStart(day);\n return;\n }\n commit(calendarRangeFromPicks(draftStart, day));\n };\n\n return (\n <div className={cn(\"relative inline-flex w-max max-w-full\", className)}>\n <button\n ref={triggerRef}\n type=\"button\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-label=\"Select time range\"\n onClick={() => {\n setOpen((current) => !current);\n setDraftStart(null);\n }}\n className={cn(\n \"inline-flex cursor-pointer h-9 w-max max-w-full items-center gap-2 whitespace-nowrap rounded-[6px] border border-[#E3E3E3] bg-white px-3 text-sm font-medium text-black outline-none\",\n fontSans,\n triggerClassName,\n )}\n >\n <span className=\"shrink-0 text-[#aaa]\">Time</span>\n <span className=\"shrink-0\">{formatDateRangeLabel(value)}</span>\n <IconArrowDown className={cn(\"h-1.5 w-2.75 shrink-0 text-black transition-transform\", open && \"rotate-180\")} />\n </button>\n {open && typeof document !== \"undefined\"\n ? createPortal(\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-label=\"Date range\"\n style={{ ...panelStyle, zIndex: floatingLayerZIndex() }}\n className={cn(\n \"w-[min(320px,calc(100vw-32px))] rounded-[16px] border border-black/10 bg-white p-4 shadow-[0_8px_24px_rgba(0,0,0,0.08)]\",\n fontSans,\n )}\n >\n <div className=\"mb-3 flex items-center justify-between\">\n <button\n type=\"button\"\n aria-label=\"Previous month\"\n onClick={() => setViewMonth((month) => addMonths(month, -1))}\n className=\"inline-flex size-8 cursor-pointer items-center justify-center rounded-full border-0 bg-transparent p-0 text-[#606060] hover:bg-black/5\"\n >\n <IconArrowDown className=\"h-1.5 w-2.75 rotate-90\" />\n </button>\n <span className=\"text-sm font-semibold text-black\">{format(viewMonth, \"yyyy MMM\")}</span>\n <button\n type=\"button\"\n aria-label=\"Next month\"\n onClick={() => setViewMonth((month) => addMonths(month, 1))}\n className=\"inline-flex size-8 cursor-pointer items-center justify-center rounded-full border-0 bg-transparent p-0 text-[#606060] hover:bg-black/5\"\n >\n <IconArrowDown className=\"h-1.5 w-2.75 -rotate-90\" />\n </button>\n </div>\n <div className=\"grid grid-cols-7 gap-1\">\n {DATE_RANGE_WEEKDAY_LABELS.map((label) => (\n <div key={label} className=\"text-center text-[11px] font-medium text-[#aaa]\">\n {label}\n </div>\n ))}\n </div>\n <div className=\"grid grid-cols-7 gap-1\">\n {days.map((day) => {\n const inMonth = isSameMonth(day, viewMonth);\n const selected = draftStart\n ? isSameDay(day, draftStart)\n : isSameDay(day, value.from) || isSameDay(day, value.to);\n const inRange = !draftStart && isWithinInterval(day, { start: value.from, end: value.to });\n return (\n <button\n key={day.toISOString()}\n type=\"button\"\n onClick={() => pickDay(day)}\n className={cn(\n \"h-8 cursor-pointer rounded-[8px] border-0 bg-transparent text-[13px] font-medium text-black hover:bg-black/5\",\n !inMonth && \"text-[#ccc]\",\n inRange && !selected && \"bg-black/5\",\n selected && \"bg-black text-white hover:bg-black\",\n )}\n >\n {format(day, \"d\")}\n </button>\n );\n })}\n </div>\n <div className=\"mt-3 flex flex-col gap-1 border-t border-black/10 pt-2\">\n {DATE_RANGE_PRESET_OPTIONS.map((option) => (\n <button\n key={option.days}\n type=\"button\"\n onClick={() => commit(lastNDaysRange(option.days))}\n className=\"cursor-pointer rounded-[8px] border-0 bg-transparent px-2 py-1.5 text-left text-sm font-medium text-black hover:bg-black/5\"\n >\n {option.label}\n </button>\n ))}\n </div>\n </div>,\n document.body,\n )\n : null}\n </div>\n );\n}\n\nexport default DateRangePicker;\n","export const DATE_RANGE_WEEKDAY_LABELS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"] as const;\n\nexport const DATE_RANGE_PRESET = {\n Days30: 30,\n Days7: 7,\n Days1: 1,\n} as const;\n\nexport const DATE_RANGE_PRESET_OPTIONS = [\n { days: DATE_RANGE_PRESET.Days30, label: \"Last 30 days\" },\n { days: DATE_RANGE_PRESET.Days7, label: \"Last 7 days\" },\n { days: DATE_RANGE_PRESET.Days1, label: \"Last 1 day\" },\n] as const;\n","import {\n differenceInCalendarDays,\n endOfDay,\n format,\n isSameDay,\n startOfDay,\n subDays,\n} from \"date-fns\";\nimport { DATE_RANGE_PRESET_OPTIONS } from \"./config\";\n\nexport type DateRangeValue = {\n from: Date;\n to: Date;\n};\n\nexport function calendarRangeFromPicks(start: Date, end: Date): DateRangeValue {\n if (isSameDay(start, end)) {\n return { from: startOfDay(end), to: endOfDay(end) };\n }\n const from = start.getTime() <= end.getTime() ? start : end;\n const to = start.getTime() <= end.getTime() ? end : start;\n return { from: startOfDay(from), to: endOfDay(to) };\n}\n\nexport function lastNDaysRange(days: number, now: Date = new Date()): DateRangeValue {\n return {\n from: startOfDay(subDays(now, days - 1)),\n to: endOfDay(now),\n };\n}\n\nexport function matchesLastNDays(range: DateRangeValue, days: number, now: Date = new Date()) {\n const expected = lastNDaysRange(days, now);\n return isSameDay(range.from, expected.from) && isSameDay(range.to, expected.to);\n}\n\nexport function formatDateRangeLabel(range: DateRangeValue, now: Date = new Date()) {\n const preset = DATE_RANGE_PRESET_OPTIONS.find((option) =>\n matchesLastNDays(range, option.days, now),\n );\n if (preset) return preset.label;\n if (isSameDay(range.from, range.to)) return format(range.from, \"MMM d, yyyy\");\n return `${format(range.from, \"MMM d, yyyy\")} – ${format(range.to, \"MMM d, yyyy\")}`;\n}\n\nexport function isInDateRange(iso: string, range: DateRangeValue) {\n const time = new Date(iso).getTime();\n if (Number.isNaN(time)) return true;\n return time >= range.from.getTime() && time <= range.to.getTime();\n}\n\nexport function rangeToUnixSeconds(range: DateRangeValue) {\n return {\n start_time: Math.floor(range.from.getTime() / 1000),\n end_time: Math.floor(range.to.getTime() / 1000),\n };\n}\n\nexport function dateRangeDayCount(range: DateRangeValue) {\n return differenceInCalendarDays(range.to, range.from) + 1;\n}\n"],"mappings":"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","names":["format","isSameDay","format","isSameDay"]}
|