@eintrek/erp-theme 1.4.14 → 1.4.16
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/ui/select.d.ts +11 -0
- package/dist/index.esm.js +70 -22
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +70 -22
- package/dist/index.js.map +1 -1
- package/dist/lib/calendar-month.d.ts +29 -0
- package/dist/lib/calendar-month.test.d.ts +1 -0
- package/package.json +6 -3
|
@@ -3,6 +3,17 @@ import * as React from "react";
|
|
|
3
3
|
declare function Select({ onValueChange, onOpenChange, open, defaultOpen, ...props }: React.ComponentProps<typeof SelectPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
declare function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>): import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
declare function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
/**
|
|
7
|
+
* The trigger fills its container.
|
|
8
|
+
*
|
|
9
|
+
* Upstream ships w-fit, which sizes the control to whatever text happens to
|
|
10
|
+
* be in it — so a field reading "เลือก..." is narrow and the same field with
|
|
11
|
+
* a name in it is wide, and a form of them looks ragged. Across these apps
|
|
12
|
+
* 102 call sites had already written w-full to undo it and 158 had not,
|
|
13
|
+
* which is a default fighting almost everyone who uses it.
|
|
14
|
+
*
|
|
15
|
+
* A caller that wants the compact behaviour passes w-fit.
|
|
16
|
+
*/
|
|
6
17
|
declare function SelectTrigger({ className, size, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
7
18
|
size?: "sm" | "default";
|
|
8
19
|
}): import("react/jsx-runtime").JSX.Element;
|
package/dist/index.esm.js
CHANGED
|
@@ -263,8 +263,19 @@ function SelectGroup({ ...props }) {
|
|
|
263
263
|
function SelectValue({ ...props }) {
|
|
264
264
|
return jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
|
|
265
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* The trigger fills its container.
|
|
268
|
+
*
|
|
269
|
+
* Upstream ships w-fit, which sizes the control to whatever text happens to
|
|
270
|
+
* be in it — so a field reading "เลือก..." is narrow and the same field with
|
|
271
|
+
* a name in it is wide, and a form of them looks ragged. Across these apps
|
|
272
|
+
* 102 call sites had already written w-full to undo it and 158 had not,
|
|
273
|
+
* which is a default fighting almost everyone who uses it.
|
|
274
|
+
*
|
|
275
|
+
* A caller that wants the compact behaviour passes w-fit.
|
|
276
|
+
*/
|
|
266
277
|
function SelectTrigger({ className, size = "default", children, ...props }) {
|
|
267
|
-
return (jsxs(SelectPrimitive.Trigger, { "data-slot": "select-trigger", "data-size": size, className: cn$1("border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-
|
|
278
|
+
return (jsxs(SelectPrimitive.Trigger, { "data-slot": "select-trigger", "data-size": size, className: cn$1("border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-full items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className), ...props, children: [children, jsx(SelectPrimitive.Icon, { asChild: true, children: jsx(ChevronDownIcon, { className: "size-4 opacity-50" }) })] }));
|
|
268
279
|
}
|
|
269
280
|
function SelectContent({ className, children, position = "popper", ...props }) {
|
|
270
281
|
return (jsx(SelectPrimitive.Portal, { children: jsxs(SelectPrimitive.Content, { "data-slot": "select-content", className: cn$1("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md", position === "popper" &&
|
|
@@ -731,28 +742,64 @@ function getThaiMonthName(monthIndex) {
|
|
|
731
742
|
return THAI_MONTH_NAMES[monthIndex];
|
|
732
743
|
}
|
|
733
744
|
|
|
745
|
+
/**
|
|
746
|
+
* Month arithmetic for the calendar header.
|
|
747
|
+
*
|
|
748
|
+
* This lives apart from the component for one reason: the bug it fixes is
|
|
749
|
+
* invisible on 28 days out of 31. Driving the calendar through the UI proves
|
|
750
|
+
* nothing unless the machine's clock happens to read the 29th or later, so the
|
|
751
|
+
* behaviour has to be reachable by a test that supplies its own date.
|
|
752
|
+
*/
|
|
753
|
+
/**
|
|
754
|
+
* stepMonth moves one month in either direction, always landing on the 1st.
|
|
755
|
+
*
|
|
756
|
+
* The obvious implementation — copy the date and call setMonth(m + 1) — keeps
|
|
757
|
+
* the day of the month. From the 31st that asks for a day the target month
|
|
758
|
+
* does not have, and JavaScript rolls forward rather than complaining: 31
|
|
759
|
+
* August plus one month is 1 October, so September cannot be reached at all.
|
|
760
|
+
*
|
|
761
|
+
* It only ever bit a calendar opened with nothing selected, because that
|
|
762
|
+
* starting point is today — including today's day-of-month. On the 3rd the old
|
|
763
|
+
* code is indistinguishable from this one.
|
|
764
|
+
*/
|
|
765
|
+
function stepMonth(from, direction) {
|
|
766
|
+
return new Date(from.getFullYear(), from.getMonth() + (direction === "next" ? 1 : -1), 1);
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* monthAnchor is the month a calendar should open on.
|
|
770
|
+
*
|
|
771
|
+
* A field holding a value opens on that value's month. A field holding nothing
|
|
772
|
+
* opens on the current month — not on whatever month a different field was
|
|
773
|
+
* last browsed to, which is what a shared, unreset state produces.
|
|
774
|
+
*/
|
|
775
|
+
function monthAnchor(selected, today) {
|
|
776
|
+
const basis = selected ?? today;
|
|
777
|
+
return new Date(basis.getFullYear(), basis.getMonth(), 1);
|
|
778
|
+
}
|
|
779
|
+
|
|
734
780
|
/** Thai weekday abbreviations (Sunday-first, matching JS getDay()). */
|
|
735
781
|
const WEEK_DAYS_TH = ["อา.", "จ.", "อ.", "พ.", "พฤ.", "ศ.", "ส."];
|
|
736
782
|
function getInitialMonth(selected) {
|
|
783
|
+
// Work out which date the calendar should open around, then let monthAnchor
|
|
784
|
+
// pin it to the first. Pinning in one place is what stops an untouched
|
|
785
|
+
// calendar from carrying today's day-of-month into the month arrows —
|
|
786
|
+
// the bug that made the arrows skip a month from the 29th onward.
|
|
787
|
+
return monthAnchor(selectionBasis(selected), new Date());
|
|
788
|
+
}
|
|
789
|
+
function selectionBasis(selected) {
|
|
737
790
|
if (selected instanceof Date && !Number.isNaN(selected.getTime())) {
|
|
738
|
-
return
|
|
791
|
+
return selected;
|
|
739
792
|
}
|
|
740
793
|
if (Array.isArray(selected) && selected[0] instanceof Date) {
|
|
741
|
-
return
|
|
794
|
+
return selected[0];
|
|
742
795
|
}
|
|
743
796
|
if (selected &&
|
|
744
797
|
typeof selected === "object" &&
|
|
745
798
|
"from" in selected &&
|
|
746
799
|
selected.from instanceof Date) {
|
|
747
|
-
return
|
|
800
|
+
return selected.from;
|
|
748
801
|
}
|
|
749
|
-
|
|
750
|
-
//
|
|
751
|
-
// Returning today carried its day-of-month into the month arrows, which is
|
|
752
|
-
// what made an untouched calendar skip a month while one with a date
|
|
753
|
-
// already chosen behaved — the selected branches above all pin the day to 1.
|
|
754
|
-
const now = new Date();
|
|
755
|
-
return new Date(now.getFullYear(), now.getMonth(), 1);
|
|
802
|
+
return undefined;
|
|
756
803
|
}
|
|
757
804
|
function Calendar({ className, selected, onSelect, mode = "single", disabled, fromYear = 1900, toYear, }) {
|
|
758
805
|
const maxYear = toYear ?? new Date().getFullYear() + 10;
|
|
@@ -865,15 +912,10 @@ function Calendar({ className, selected, onSelect, mode = "single", disabled, fr
|
|
|
865
912
|
}
|
|
866
913
|
};
|
|
867
914
|
const navigateMonth = (direction) => {
|
|
868
|
-
//
|
|
869
|
-
//
|
|
870
|
-
//
|
|
871
|
-
|
|
872
|
-
// that does not exist in a 30-day month and JavaScript rolls it forward:
|
|
873
|
-
// 31 Aug + 1 month became 1 Oct, and September could not be reached at
|
|
874
|
-
// all. It bit every calendar opened with no value selected, because that
|
|
875
|
-
// starting point was today — including today's day-of-month.
|
|
876
|
-
setCurrentMonth((prev) => new Date(prev.getFullYear(), prev.getMonth() + (direction === "next" ? 1 : -1), 1));
|
|
915
|
+
// stepMonth, not setMonth — see the note in lib/calendar-month. The
|
|
916
|
+
// arithmetic lives there because it is only wrong on the 29th and later,
|
|
917
|
+
// and a test has to be able to say what day it is.
|
|
918
|
+
setCurrentMonth((prev) => stepMonth(prev, direction));
|
|
877
919
|
};
|
|
878
920
|
const handleMonthChange = (monthStr) => {
|
|
879
921
|
const nextMonth = Number.parseInt(monthStr, 10);
|
|
@@ -1448,7 +1490,13 @@ function DatePicker({ date, onDateChange, placeholder = "เลือกวั
|
|
|
1448
1490
|
const [open, setOpen] = React.useState(false);
|
|
1449
1491
|
const isDateDisabled = disabledDates ?? defaultDisabledDates;
|
|
1450
1492
|
const resolvedToYear = toYear ?? new Date().getFullYear() + 10;
|
|
1451
|
-
return (jsxs(Popover, { open: open && !disabled, onOpenChange: setOpen, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs("div", { className: "relative w-full", children: [jsx(Input, { readOnly: true, disabled: disabled, value: date ? formatDate(date) : "", placeholder: placeholder, className: cn$1("border-border bg-background text-foreground placeholder:text-muted-foreground w-full pr-9", disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer", className), id: id, "aria-label": date ? undefined : (ariaLabel ?? placeholder), "aria-required": ariaRequired, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby }), jsx(Calendar$1, { className: "text-muted-foreground pointer-events-none absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2" })] }) }), jsx(PopoverContent, { className: "w-auto overflow-visible p-0", align: "start", children: jsx(Calendar
|
|
1493
|
+
return (jsxs(Popover, { open: open && !disabled, onOpenChange: setOpen, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs("div", { className: "relative w-full", children: [jsx(Input, { readOnly: true, disabled: disabled, value: date ? formatDate(date) : "", placeholder: placeholder, className: cn$1("border-border bg-background text-foreground placeholder:text-muted-foreground w-full pr-9", disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer", className), id: id, "aria-label": date ? undefined : (ariaLabel ?? placeholder), "aria-required": ariaRequired, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby }), jsx(Calendar$1, { className: "text-muted-foreground pointer-events-none absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2" })] }) }), jsx(PopoverContent, { className: "w-auto overflow-visible p-0", align: "start", children: jsx(Calendar
|
|
1494
|
+
// Remount on each open so an empty field always starts on this
|
|
1495
|
+
// month. Without it the grid keeps whichever month was last browsed
|
|
1496
|
+
// — and when React reuses this instance for a different field, that
|
|
1497
|
+
// month is one the user was looking at in a *different* box, which
|
|
1498
|
+
// reads as the calendar opening on a random date.
|
|
1499
|
+
, { ...{ locale: th }, mode: "single", selected: date, onSelect: (selectedDate) => {
|
|
1452
1500
|
if (selectedDate instanceof Date) {
|
|
1453
1501
|
onDateChange?.(selectedDate);
|
|
1454
1502
|
setOpen(false);
|
|
@@ -1457,7 +1505,7 @@ function DatePicker({ date, onDateChange, placeholder = "เลือกวั
|
|
|
1457
1505
|
onDateChange?.(undefined);
|
|
1458
1506
|
setOpen(false);
|
|
1459
1507
|
}
|
|
1460
|
-
}, disabled: isDateDisabled, fromYear: fromYear, toYear: resolvedToYear, initialFocus: true }) })] }));
|
|
1508
|
+
}, disabled: isDateDisabled, fromYear: fromYear, toYear: resolvedToYear, initialFocus: true }, open ? "open" : "closed") })] }));
|
|
1461
1509
|
}
|
|
1462
1510
|
|
|
1463
1511
|
const labelVariants = cva("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
|