@eintrek/erp-theme 1.4.9 → 1.4.11

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.js CHANGED
@@ -258,133 +258,266 @@ function BreadcrumbSeparator({ children, className, ...props }) {
258
258
  return (require$$1.jsx("li", { "data-slot": "breadcrumb-separator", role: "presentation", "aria-hidden": "true", className: cn$1("[&>svg]:size-3.5", className), ...props, children: children ?? require$$1.jsx(lucideReact.ChevronRight, {}) }));
259
259
  }
260
260
 
261
- function Calendar({ className, selected, onSelect, mode = "single", disabled, }) {
262
- const [currentMonth, setCurrentMonth] = React__namespace.useState(new Date());
263
- const today = new Date();
264
- const year = currentMonth.getFullYear();
265
- const month = currentMonth.getMonth();
266
- const firstDayOfMonth = new Date(year, month, 1);
267
- const lastDayOfMonth = new Date(year, month + 1, 0);
268
- const firstDayOfWeek = firstDayOfMonth.getDay();
269
- const daysInMonth = lastDayOfMonth.getDate();
270
- const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
271
- const getDaysInMonth = () => {
272
- const days = [];
273
- // Add empty cells for days before the first day of the month
274
- for (let i = 0; i < firstDayOfWeek; i++) {
275
- days.push(null);
276
- }
277
- // Add days of the month
278
- for (let day = 1; day <= daysInMonth; day++) {
279
- days.push(new Date(year, month, day));
280
- }
281
- return days;
282
- };
283
- const isSelected = (date) => {
284
- if (!selected)
285
- return false;
286
- if (mode === "single" && selected instanceof Date) {
287
- return date.toDateString() === selected.toDateString();
288
- }
289
- if (mode === "range" && selected && typeof selected === "object" && "from" in selected) {
290
- const range = selected;
291
- if (range.from && range.to) {
292
- return date >= range.from && date <= range.to;
293
- }
294
- if (range.from) {
295
- return date.toDateString() === range.from.toDateString();
296
- }
297
- }
298
- if (mode === "multiple" && Array.isArray(selected)) {
299
- return selected.some(d => d.toDateString() === date.toDateString());
300
- }
301
- return false;
302
- };
303
- const isToday = (date) => {
304
- return date.toDateString() === today.toDateString();
305
- };
306
- const isDisabled = (date) => {
307
- if (disabled)
308
- return disabled(date);
309
- return false;
310
- };
311
- const handleDateClick = (date) => {
312
- if (isDisabled(date))
313
- return;
314
- if (mode === "single") {
315
- onSelect?.(date);
316
- }
317
- else if (mode === "range") {
318
- // Simple range selection - click to set start, click again to set end
319
- if (!selected || typeof selected !== "object" || !("from" in selected)) {
320
- onSelect?.({ from: date, to: undefined });
321
- }
322
- else {
323
- const range = selected;
324
- if (!range.from) {
325
- onSelect?.({ from: date, to: undefined });
326
- }
327
- else if (!range.to) {
328
- if (date >= range.from) {
329
- onSelect?.({ from: range.from, to: date });
330
- }
331
- else {
332
- onSelect?.({ from: date, to: range.from });
333
- }
334
- }
335
- else {
336
- onSelect?.({ from: date, to: undefined });
337
- }
338
- }
339
- }
340
- else if (mode === "multiple") {
341
- const currentSelection = Array.isArray(selected) ? selected : [];
342
- const isAlreadySelected = currentSelection.some(d => d.toDateString() === date.toDateString());
343
- if (isAlreadySelected) {
344
- onSelect?.(currentSelection.filter(d => d.toDateString() !== date.toDateString()));
345
- }
346
- else {
347
- onSelect?.([...currentSelection, date]);
348
- }
349
- }
350
- };
351
- const navigateMonth = (direction) => {
352
- setCurrentMonth(prev => {
353
- const newMonth = new Date(prev);
354
- if (direction === "prev") {
355
- newMonth.setMonth(prev.getMonth() - 1);
356
- }
357
- else {
358
- newMonth.setMonth(prev.getMonth() + 1);
359
- }
360
- return newMonth;
361
- });
362
- };
363
- const days = getDaysInMonth();
364
- return (require$$1.jsxs("div", { "data-slot": "calendar", className: cn$1("bg-background group/calendar p-3 w-fit", className), children: [require$$1.jsxs("div", { className: "flex items-center justify-between mb-4", children: [require$$1.jsx(Button, { variant: "ghost", size: "icon", onClick: () => navigateMonth("prev"), className: "h-8 w-8 p-0", children: require$$1.jsx(lucideReact.ChevronLeftIcon, { className: "h-4 w-4" }) }), require$$1.jsx("div", { className: "text-sm font-medium", children: currentMonth.toLocaleDateString("default", { month: "long", year: "numeric" }) }), require$$1.jsx(Button, { variant: "ghost", size: "icon", onClick: () => navigateMonth("next"), className: "h-8 w-8 p-0", children: require$$1.jsx(lucideReact.ChevronRightIcon, { className: "h-4 w-4" }) })] }), require$$1.jsx("div", { className: "grid grid-cols-7 gap-1 mb-2", children: weekDays.map((day) => (require$$1.jsx("div", { className: "text-muted-foreground text-xs font-normal text-center h-8 flex items-center justify-center", children: day }, day))) }), require$$1.jsx("div", { className: "grid grid-cols-7 gap-1", children: days.map((date, index) => {
365
- if (!date) {
366
- return require$$1.jsx("div", { className: "h-8" }, index);
367
- }
368
- const isDateSelected = isSelected(date);
369
- const isDateToday = isToday(date);
370
- const isDateDisabled = isDisabled(date);
371
- return (require$$1.jsx(Button, { variant: "ghost", size: "icon", className: cn$1("h-8 w-8 p-0 text-sm font-normal", isDateSelected && "bg-primary text-primary-foreground", isDateToday && !isDateSelected && "bg-accent text-accent-foreground", isDateDisabled && "opacity-50 cursor-not-allowed", "hover:bg-accent hover:text-accent-foreground"), onClick: () => handleDateClick(date), disabled: isDateDisabled, children: date.getDate() }, date.toISOString()));
372
- }) })] }));
261
+ function Select({ onValueChange, onOpenChange, open, defaultOpen, ...props }) {
262
+ // Tracked in a ref, not state: this only needs to be readable inside the
263
+ // callback below, and putting it in state would re-render on every open.
264
+ const isOpenRef = React__namespace.useRef(defaultOpen ?? false);
265
+ if (open !== undefined)
266
+ isOpenRef.current = open;
267
+ return (require$$1.jsx(SelectPrimitive__namespace.Root, { "data-slot": "select", ...props, open: open, defaultOpen: defaultOpen, onOpenChange: next => {
268
+ isOpenRef.current = next;
269
+ onOpenChange?.(next);
270
+ }, onValueChange: value => {
271
+ // Drop ONLY the empty value Radix echoes back on its own.
272
+ //
273
+ // Radix keeps a hidden native <select> so the control works inside
274
+ // real forms. Whenever the controlled value changes it assigns that
275
+ // value to the native node and dispatches a synthetic change event,
276
+ // which comes straight back out through onValueChange:
277
+ //
278
+ // setValue.call(select, selectValue);
279
+ // select.dispatchEvent(new Event("change", { bubbles: true }));
280
+ // ...
281
+ // onChange: (event) => onValueChange(event.target.value)
282
+ //
283
+ // The native <option> list is registered by SelectItem, and the items
284
+ // live inside SelectContent — portalled, and only mounted while the
285
+ // menu is open. On a closed select the option for the incoming value
286
+ // usually does not exist yet, the DOM refuses the assignment,
287
+ // `select.value` collapses to "", and that empty string reaches the
288
+ // consumer. In a form this lands exactly when saved data arrives: the
289
+ // field is set to its stored value, Radix echoes "", and the handler
290
+ // writes that back — enum fields then snap to their fallback and zod
291
+ // rejects the submit with "received ''".
292
+ //
293
+ // The open check is what keeps a real "none" option working. Radix
294
+ // does NOT forbid <SelectItem value="">, and picking one is a
295
+ // legitimate way to clear a selection. A user pick always arrives
296
+ // while the menu is still open — SelectItem's handleSelect calls
297
+ // onValueChange(value) BEFORE onOpenChange(false) — whereas the echo
298
+ // above fires from an effect with the menu closed. So only the closed
299
+ // case is suppressed.
300
+ if (value === "" && !isOpenRef.current)
301
+ return;
302
+ onValueChange?.(value);
303
+ } }));
373
304
  }
374
- function DateInput({ value, onChange, placeholder = "Select date", className, disabled = false }) {
375
- const handleChange = (event) => {
376
- const dateValue = event.target.value;
377
- if (dateValue) {
378
- onChange?.(new Date(dateValue));
379
- }
380
- else {
381
- onChange?.(undefined);
382
- }
383
- };
384
- const formatDateForInput = (date) => {
385
- return date.toISOString().split('T')[0];
386
- };
387
- return (require$$1.jsx("input", { type: "date", value: value ? formatDateForInput(value) : "", onChange: handleChange, placeholder: placeholder, disabled: disabled, className: cn$1("flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", className) }));
305
+ function SelectGroup({ ...props }) {
306
+ return require$$1.jsx(SelectPrimitive__namespace.Group, { "data-slot": "select-group", ...props });
307
+ }
308
+ function SelectValue({ ...props }) {
309
+ return require$$1.jsx(SelectPrimitive__namespace.Value, { "data-slot": "select-value", ...props });
310
+ }
311
+ function SelectTrigger({ className, size = "default", children, ...props }) {
312
+ return (require$$1.jsxs(SelectPrimitive__namespace.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-fit 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, require$$1.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: require$$1.jsx(lucideReact.ChevronDownIcon, { className: "size-4 opacity-50" }) })] }));
313
+ }
314
+ function SelectContent({ className, children, position = "popper", ...props }) {
315
+ return (require$$1.jsx(SelectPrimitive__namespace.Portal, { children: require$$1.jsxs(SelectPrimitive__namespace.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" &&
316
+ "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className), position: position, ...props, children: [require$$1.jsx(SelectScrollUpButton, {}), require$$1.jsx(SelectPrimitive__namespace.Viewport, { className: cn$1("p-1", position === "popper" &&
317
+ "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"), children: children }), require$$1.jsx(SelectScrollDownButton, {})] }) }));
318
+ }
319
+ function SelectLabel({ className, ...props }) {
320
+ return (require$$1.jsx(SelectPrimitive__namespace.Label, { "data-slot": "select-label", className: cn$1("text-muted-foreground px-2 py-1.5 text-xs", className), ...props }));
321
+ }
322
+ function SelectItem({ className, children, ...props }) {
323
+ return (require$$1.jsxs(SelectPrimitive__namespace.Item, { "data-slot": "select-item", className: cn$1("focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className), ...props, children: [require$$1.jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: require$$1.jsx(SelectPrimitive__namespace.ItemIndicator, { children: require$$1.jsx(lucideReact.CheckIcon, { className: "size-4" }) }) }), require$$1.jsx(SelectPrimitive__namespace.ItemText, { children: children })] }));
324
+ }
325
+ function SelectSeparator({ className, ...props }) {
326
+ return (require$$1.jsx(SelectPrimitive__namespace.Separator, { "data-slot": "select-separator", className: cn$1("bg-border pointer-events-none -mx-1 my-1 h-px", className), ...props }));
327
+ }
328
+ function SelectScrollUpButton({ className, ...props }) {
329
+ return (require$$1.jsx(SelectPrimitive__namespace.ScrollUpButton, { "data-slot": "select-scroll-up-button", className: cn$1("flex cursor-default items-center justify-center py-1", className), ...props, children: require$$1.jsx(lucideReact.ChevronUpIcon, { className: "size-4" }) }));
330
+ }
331
+ function SelectScrollDownButton({ className, ...props }) {
332
+ return (require$$1.jsx(SelectPrimitive__namespace.ScrollDownButton, { "data-slot": "select-scroll-down-button", className: cn$1("flex cursor-default items-center justify-center py-1", className), ...props, children: require$$1.jsx(lucideReact.ChevronDownIcon, { className: "size-4" }) }));
333
+ }
334
+
335
+ /**
336
+ * @module constants
337
+ * @summary Useful constants
338
+ * @description
339
+ * Collection of useful date constants.
340
+ *
341
+ * The constants could be imported from `date-fns/constants`:
342
+ *
343
+ * ```ts
344
+ * import { maxTime, minTime } from "./constants/date-fns/constants";
345
+ *
346
+ * function isAllowedTime(time) {
347
+ * return time <= maxTime && time >= minTime;
348
+ * }
349
+ * ```
350
+ */
351
+
352
+
353
+ /**
354
+ * @constant
355
+ * @name constructFromSymbol
356
+ * @summary Symbol enabling Date extensions to inherit properties from the reference date.
357
+ *
358
+ * The symbol is used to enable the `constructFrom` function to construct a date
359
+ * using a reference date and a value. It allows to transfer extra properties
360
+ * from the reference date to the new date. It's useful for extensions like
361
+ * [`TZDate`](https://github.com/date-fns/tz) that accept a time zone as
362
+ * a constructor argument.
363
+ */
364
+ const constructFromSymbol = Symbol.for("constructDateFrom");
365
+
366
+ /**
367
+ * @name constructFrom
368
+ * @category Generic Helpers
369
+ * @summary Constructs a date using the reference date and the value
370
+ *
371
+ * @description
372
+ * The function constructs a new date using the constructor from the reference
373
+ * date and the given value. It helps to build generic functions that accept
374
+ * date extensions.
375
+ *
376
+ * It defaults to `Date` if the passed reference date is a number or a string.
377
+ *
378
+ * Starting from v3.7.0, it allows to construct a date using `[Symbol.for("constructDateFrom")]`
379
+ * enabling to transfer extra properties from the reference date to the new date.
380
+ * It's useful for extensions like [`TZDate`](https://github.com/date-fns/tz)
381
+ * that accept a time zone as a constructor argument.
382
+ *
383
+ * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
384
+ *
385
+ * @param date - The reference date to take constructor from
386
+ * @param value - The value to create the date
387
+ *
388
+ * @returns Date initialized using the given date and value
389
+ *
390
+ * @example
391
+ * import { constructFrom } from "./constructFrom/date-fns";
392
+ *
393
+ * // A function that clones a date preserving the original type
394
+ * function cloneDate<DateType extends Date>(date: DateType): DateType {
395
+ * return constructFrom(
396
+ * date, // Use constructor from the given date
397
+ * date.getTime() // Use the date value to create a new date
398
+ * );
399
+ * }
400
+ */
401
+ function constructFrom(date, value) {
402
+ if (typeof date === "function") return date(value);
403
+
404
+ if (date && typeof date === "object" && constructFromSymbol in date)
405
+ return date[constructFromSymbol](value);
406
+
407
+ if (date instanceof Date) return new date.constructor(value);
408
+
409
+ return new Date(value);
410
+ }
411
+
412
+ /**
413
+ * @name toDate
414
+ * @category Common Helpers
415
+ * @summary Convert the given argument to an instance of Date.
416
+ *
417
+ * @description
418
+ * Convert the given argument to an instance of Date.
419
+ *
420
+ * If the argument is an instance of Date, the function returns its clone.
421
+ *
422
+ * If the argument is a number, it is treated as a timestamp.
423
+ *
424
+ * If the argument is none of the above, the function returns Invalid Date.
425
+ *
426
+ * Starting from v3.7.0, it clones a date using `[Symbol.for("constructDateFrom")]`
427
+ * enabling to transfer extra properties from the reference date to the new date.
428
+ * It's useful for extensions like [`TZDate`](https://github.com/date-fns/tz)
429
+ * that accept a time zone as a constructor argument.
430
+ *
431
+ * **Note**: *all* Date arguments passed to any *date-fns* function is processed by `toDate`.
432
+ *
433
+ * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
434
+ * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments.
435
+ *
436
+ * @param argument - The value to convert
437
+ *
438
+ * @returns The parsed date in the local time zone
439
+ *
440
+ * @example
441
+ * // Clone the date:
442
+ * const result = toDate(new Date(2014, 1, 11, 11, 30, 30))
443
+ * //=> Tue Feb 11 2014 11:30:30
444
+ *
445
+ * @example
446
+ * // Convert the timestamp to date:
447
+ * const result = toDate(1392098430000)
448
+ * //=> Tue Feb 11 2014 11:30:30
449
+ */
450
+ function toDate(argument, context) {
451
+ // [TODO] Get rid of `toDate` or `constructFrom`?
452
+ return constructFrom(argument, argument);
453
+ }
454
+
455
+ /**
456
+ * The {@link endOfMonth} function options.
457
+ */
458
+
459
+ /**
460
+ * @name endOfMonth
461
+ * @category Month Helpers
462
+ * @summary Return the end of a month for the given date.
463
+ *
464
+ * @description
465
+ * Return the end of a month for the given date.
466
+ * The result will be in the local timezone.
467
+ *
468
+ * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
469
+ * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments.
470
+ *
471
+ * @param date - The original date
472
+ * @param options - An object with options
473
+ *
474
+ * @returns The end of a month
475
+ *
476
+ * @example
477
+ * // The end of a month for 2 September 2014 11:55:00:
478
+ * const result = endOfMonth(new Date(2014, 8, 2, 11, 55, 0))
479
+ * //=> Tue Sep 30 2014 23:59:59.999
480
+ */
481
+ function endOfMonth(date, options) {
482
+ const _date = toDate(date);
483
+ const month = _date.getMonth();
484
+ _date.setFullYear(_date.getFullYear(), month + 1, 0);
485
+ _date.setHours(23, 59, 59, 999);
486
+ return _date;
487
+ }
488
+
489
+ /**
490
+ * The {@link startOfMonth} function options.
491
+ */
492
+
493
+ /**
494
+ * @name startOfMonth
495
+ * @category Month Helpers
496
+ * @summary Return the start of a month for the given date.
497
+ *
498
+ * @description
499
+ * Return the start of a month for the given date. The result will be in the local timezone.
500
+ *
501
+ * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments.
502
+ * Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
503
+ * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed,
504
+ * or inferred from the arguments.
505
+ *
506
+ * @param date - The original date
507
+ * @param options - An object with options
508
+ *
509
+ * @returns The start of a month
510
+ *
511
+ * @example
512
+ * // The start of a month for 2 September 2014 11:55:00:
513
+ * const result = startOfMonth(new Date(2014, 8, 2, 11, 55, 0))
514
+ * //=> Mon Sep 01 2014 00:00:00
515
+ */
516
+ function startOfMonth(date, options) {
517
+ const _date = toDate(date);
518
+ _date.setDate(1);
519
+ _date.setHours(0, 0, 0, 0);
520
+ return _date;
388
521
  }
389
522
 
390
523
  function buildFormatLongFn(args) {
@@ -539,123 +672,290 @@ function buildMatchPatternFn(args) {
539
672
  }
540
673
 
541
674
  /**
542
- * @module constants
543
- * @summary Useful constants
544
- * @description
545
- * Collection of useful date constants.
546
- *
547
- * The constants could be imported from `date-fns/constants`:
548
- *
549
- * ```ts
550
- * import { maxTime, minTime } from "./constants/date-fns/constants";
551
- *
552
- * function isAllowedTime(time) {
553
- * return time <= maxTime && time >= minTime;
554
- * }
555
- * ```
675
+ * Thai month names in Buddhist calendar
556
676
  */
557
-
558
-
677
+ const THAI_MONTH_NAMES = [
678
+ "มกราคม",
679
+ "กุมภาพันธ์",
680
+ "มีนาคม",
681
+ "เมษายน",
682
+ "พฤษภาคม",
683
+ "มิถุนายน",
684
+ "กรกฎาคม",
685
+ "สิงหาคม",
686
+ "กันยายน",
687
+ "ตุลาคม",
688
+ "พฤศจิกายน",
689
+ "ธันวาคม",
690
+ ];
559
691
  /**
560
- * @constant
561
- * @name constructFromSymbol
562
- * @summary Symbol enabling Date extensions to inherit properties from the reference date.
692
+ * Convert Gregorian year to Buddhist year
693
+ * Buddhist calendar is 543 years ahead of Gregorian calendar
563
694
  *
564
- * The symbol is used to enable the `constructFrom` function to construct a date
565
- * using a reference date and a value. It allows to transfer extra properties
566
- * from the reference date to the new date. It's useful for extensions like
567
- * [`TZDate`](https://github.com/date-fns/tz) that accept a time zone as
568
- * a constructor argument.
695
+ * @param gregorianYear - The Gregorian year (e.g., 2024)
696
+ * @returns The Buddhist year (e.g., 2567)
697
+ *
698
+ * @example
699
+ * toBuddhistYear(2024); // returns 2567
569
700
  */
570
- const constructFromSymbol = Symbol.for("constructDateFrom");
571
-
701
+ function toBuddhistYear(gregorianYear) {
702
+ return gregorianYear + 543;
703
+ }
572
704
  /**
573
- * @name constructFrom
574
- * @category Generic Helpers
575
- * @summary Constructs a date using the reference date and the value
576
- *
577
- * @description
578
- * The function constructs a new date using the constructor from the reference
579
- * date and the given value. It helps to build generic functions that accept
580
- * date extensions.
581
- *
582
- * It defaults to `Date` if the passed reference date is a number or a string.
583
- *
584
- * Starting from v3.7.0, it allows to construct a date using `[Symbol.for("constructDateFrom")]`
585
- * enabling to transfer extra properties from the reference date to the new date.
586
- * It's useful for extensions like [`TZDate`](https://github.com/date-fns/tz)
587
- * that accept a time zone as a constructor argument.
588
- *
589
- * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
590
- *
591
- * @param date - The reference date to take constructor from
592
- * @param value - The value to create the date
705
+ * Convert Buddhist year to Gregorian year
593
706
  *
594
- * @returns Date initialized using the given date and value
707
+ * @param buddhistYear - The Buddhist year (e.g., 2567)
708
+ * @returns The Gregorian year (e.g., 2024)
595
709
  *
596
710
  * @example
597
- * import { constructFrom } from "./constructFrom/date-fns";
598
- *
599
- * // A function that clones a date preserving the original type
600
- * function cloneDate<DateType extends Date>(date: DateType): DateType {
601
- * return constructFrom(
602
- * date, // Use constructor from the given date
603
- * date.getTime() // Use the date value to create a new date
604
- * );
605
- * }
711
+ * toGregorianYear(2567); // returns 2024
606
712
  */
607
- function constructFrom(date, value) {
608
- if (typeof date === "function") return date(value);
609
-
610
- if (date && typeof date === "object" && constructFromSymbol in date)
611
- return date[constructFromSymbol](value);
612
-
613
- if (date instanceof Date) return new date.constructor(value);
614
-
615
- return new Date(value);
713
+ function toGregorianYear(buddhistYear) {
714
+ return buddhistYear - 543;
616
715
  }
617
-
618
716
  /**
619
- * @name toDate
620
- * @category Common Helpers
621
- * @summary Convert the given argument to an instance of Date.
622
- *
623
- * @description
624
- * Convert the given argument to an instance of Date.
625
- *
626
- * If the argument is an instance of Date, the function returns its clone.
627
- *
628
- * If the argument is a number, it is treated as a timestamp.
629
- *
630
- * If the argument is none of the above, the function returns Invalid Date.
717
+ * Get the first and last day of a month
631
718
  *
632
- * Starting from v3.7.0, it clones a date using `[Symbol.for("constructDateFrom")]`
633
- * enabling to transfer extra properties from the reference date to the new date.
634
- * It's useful for extensions like [`TZDate`](https://github.com/date-fns/tz)
635
- * that accept a time zone as a constructor argument.
719
+ * @param date - The date within the month
720
+ * @returns Object with start and end dates of the month
636
721
  *
637
- * **Note**: *all* Date arguments passed to any *date-fns* function is processed by `toDate`.
722
+ * @example
723
+ * getMonthDateRange(new Date('2024-06-15'));
724
+ * // returns { start: Date('2024-06-01'), end: Date('2024-06-30') }
725
+ */
726
+ function getMonthDateRange(date) {
727
+ const start = startOfMonth(date);
728
+ const end = endOfMonth(date);
729
+ return { start, end };
730
+ }
731
+ /**
732
+ * Format a date to Thai Buddhist calendar month display
638
733
  *
639
- * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
640
- * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments.
734
+ * @param date - The date to format
735
+ * @returns Formatted string in Thai Buddhist calendar (e.g., "มกราคม 2568")
641
736
  *
642
- * @param argument - The value to convert
737
+ * @example
738
+ * formatThaiMonth(new Date('2024-01-15')); // returns "มกราคม 2567"
739
+ * formatThaiMonth(new Date('2024-12-25')); // returns "ธันวาคม 2567"
740
+ */
741
+ function formatThaiMonth(date) {
742
+ const monthIndex = date.getMonth();
743
+ const gregorianYear = date.getFullYear();
744
+ const buddhistYear = toBuddhistYear(gregorianYear);
745
+ return `${THAI_MONTH_NAMES[monthIndex]} ${buddhistYear}`;
746
+ }
747
+ /**
748
+ * Format a date to short Thai Buddhist calendar format
643
749
  *
644
- * @returns The parsed date in the local time zone
750
+ * @param date - The date to format
751
+ * @returns Formatted string (e.g., "01/2568")
645
752
  *
646
753
  * @example
647
- * // Clone the date:
648
- * const result = toDate(new Date(2014, 1, 11, 11, 30, 30))
649
- * //=> Tue Feb 11 2014 11:30:30
754
+ * formatThaiMonthShort(new Date('2024-01-15')); // returns "01/2567"
755
+ */
756
+ function formatThaiMonthShort(date) {
757
+ const month = String(date.getMonth() + 1).padStart(2, "0");
758
+ const gregorianYear = date.getFullYear();
759
+ const buddhistYear = toBuddhistYear(gregorianYear);
760
+ return `${month}/${buddhistYear}`;
761
+ }
762
+ /**
763
+ * Get Thai month name by index (0-11)
764
+ *
765
+ * @param monthIndex - Month index (0 = January, 11 = December)
766
+ * @returns Thai month name
650
767
  *
651
768
  * @example
652
- * // Convert the timestamp to date:
653
- * const result = toDate(1392098430000)
654
- * //=> Tue Feb 11 2014 11:30:30
769
+ * getThaiMonthName(0); // returns "มกราคม"
770
+ * getThaiMonthName(11); // returns "ธันวาคม"
655
771
  */
656
- function toDate(argument, context) {
657
- // [TODO] Get rid of `toDate` or `constructFrom`?
658
- return constructFrom(argument, argument);
772
+ function getThaiMonthName(monthIndex) {
773
+ if (monthIndex < 0 || monthIndex > 11) {
774
+ throw new Error("Month index must be between 0 and 11");
775
+ }
776
+ return THAI_MONTH_NAMES[monthIndex];
777
+ }
778
+
779
+ /** Thai weekday abbreviations (Sunday-first, matching JS getDay()). */
780
+ const WEEK_DAYS_TH = ["อา.", "จ.", "อ.", "พ.", "พฤ.", "ศ.", "ส."];
781
+ function getInitialMonth(selected) {
782
+ if (selected instanceof Date && !Number.isNaN(selected.getTime())) {
783
+ return new Date(selected.getFullYear(), selected.getMonth(), 1);
784
+ }
785
+ if (Array.isArray(selected) && selected[0] instanceof Date) {
786
+ return new Date(selected[0].getFullYear(), selected[0].getMonth(), 1);
787
+ }
788
+ if (selected &&
789
+ typeof selected === "object" &&
790
+ "from" in selected &&
791
+ selected.from instanceof Date) {
792
+ return new Date(selected.from.getFullYear(), selected.from.getMonth(), 1);
793
+ }
794
+ return new Date();
795
+ }
796
+ function Calendar({ className, selected, onSelect, mode = "single", disabled, fromYear = 1900, toYear, }) {
797
+ const maxYear = toYear ?? new Date().getFullYear() + 10;
798
+ const [currentMonth, setCurrentMonth] = React__namespace.useState(() => getInitialMonth(selected));
799
+ // Jump the grid to the selected date when it changes (e.g. form load).
800
+ React__namespace.useEffect(() => {
801
+ const next = getInitialMonth(selected);
802
+ setCurrentMonth((prev) => {
803
+ if (prev.getFullYear() === next.getFullYear() &&
804
+ prev.getMonth() === next.getMonth()) {
805
+ return prev;
806
+ }
807
+ return next;
808
+ });
809
+ }, [selected]);
810
+ const today = new Date();
811
+ const year = currentMonth.getFullYear();
812
+ const month = currentMonth.getMonth();
813
+ const firstDayOfMonth = new Date(year, month, 1);
814
+ const lastDayOfMonth = new Date(year, month + 1, 0);
815
+ const firstDayOfWeek = firstDayOfMonth.getDay();
816
+ const daysInMonth = lastDayOfMonth.getDate();
817
+ const yearOptions = React__namespace.useMemo(() => {
818
+ const years = [];
819
+ const start = Math.min(fromYear, maxYear);
820
+ const end = Math.max(fromYear, maxYear);
821
+ for (let y = end; y >= start; y--) {
822
+ years.push(y);
823
+ }
824
+ return years;
825
+ }, [fromYear, maxYear]);
826
+ const getDaysInMonth = () => {
827
+ const days = [];
828
+ for (let i = 0; i < firstDayOfWeek; i++) {
829
+ days.push(null);
830
+ }
831
+ for (let day = 1; day <= daysInMonth; day++) {
832
+ days.push(new Date(year, month, day));
833
+ }
834
+ return days;
835
+ };
836
+ const isSelected = (date) => {
837
+ if (!selected)
838
+ return false;
839
+ if (mode === "single" && selected instanceof Date) {
840
+ return date.toDateString() === selected.toDateString();
841
+ }
842
+ if (mode === "range" &&
843
+ selected &&
844
+ typeof selected === "object" &&
845
+ "from" in selected) {
846
+ const range = selected;
847
+ if (range.from && range.to) {
848
+ return date >= range.from && date <= range.to;
849
+ }
850
+ if (range.from) {
851
+ return date.toDateString() === range.from.toDateString();
852
+ }
853
+ }
854
+ if (mode === "multiple" && Array.isArray(selected)) {
855
+ return selected.some((d) => d.toDateString() === date.toDateString());
856
+ }
857
+ return false;
858
+ };
859
+ const isToday = (date) => {
860
+ return date.toDateString() === today.toDateString();
861
+ };
862
+ const isDisabled = (date) => {
863
+ if (disabled)
864
+ return disabled(date);
865
+ return false;
866
+ };
867
+ const handleDateClick = (date) => {
868
+ if (isDisabled(date))
869
+ return;
870
+ if (mode === "single") {
871
+ onSelect?.(date);
872
+ }
873
+ else if (mode === "range") {
874
+ if (!selected || typeof selected !== "object" || !("from" in selected)) {
875
+ onSelect?.({ from: date, to: undefined });
876
+ }
877
+ else {
878
+ const range = selected;
879
+ if (!range.from) {
880
+ onSelect?.({ from: date, to: undefined });
881
+ }
882
+ else if (!range.to) {
883
+ if (date >= range.from) {
884
+ onSelect?.({ from: range.from, to: date });
885
+ }
886
+ else {
887
+ onSelect?.({ from: date, to: range.from });
888
+ }
889
+ }
890
+ else {
891
+ onSelect?.({ from: date, to: undefined });
892
+ }
893
+ }
894
+ }
895
+ else if (mode === "multiple") {
896
+ const currentSelection = Array.isArray(selected) ? selected : [];
897
+ const isAlreadySelected = currentSelection.some((d) => d.toDateString() === date.toDateString());
898
+ if (isAlreadySelected) {
899
+ onSelect?.(currentSelection.filter((d) => d.toDateString() !== date.toDateString()));
900
+ }
901
+ else {
902
+ onSelect?.([...currentSelection, date]);
903
+ }
904
+ }
905
+ };
906
+ const navigateMonth = (direction) => {
907
+ setCurrentMonth((prev) => {
908
+ const newMonth = new Date(prev);
909
+ if (direction === "prev") {
910
+ newMonth.setMonth(prev.getMonth() - 1);
911
+ }
912
+ else {
913
+ newMonth.setMonth(prev.getMonth() + 1);
914
+ }
915
+ return newMonth;
916
+ });
917
+ };
918
+ const handleMonthChange = (monthStr) => {
919
+ const nextMonth = Number.parseInt(monthStr, 10);
920
+ if (Number.isNaN(nextMonth))
921
+ return;
922
+ setCurrentMonth((prev) => new Date(prev.getFullYear(), nextMonth, 1));
923
+ };
924
+ const handleYearChange = (buddhistYearStr) => {
925
+ const gregorian = toGregorianYear(Number.parseInt(buddhistYearStr, 10));
926
+ if (Number.isNaN(gregorian))
927
+ return;
928
+ setCurrentMonth((prev) => new Date(gregorian, prev.getMonth(), 1));
929
+ };
930
+ const days = getDaysInMonth();
931
+ const canGoPrev = year > fromYear || (year === fromYear && month > 0);
932
+ const canGoNext = year < maxYear || (year === maxYear && month < 11);
933
+ return (require$$1.jsxs("div", { "data-slot": "calendar", className: cn$1("bg-background group/calendar p-3 w-fit", className), children: [require$$1.jsxs("div", { className: "mb-4 flex items-center justify-between gap-1", children: [require$$1.jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => navigateMonth("prev"), disabled: !canGoPrev, className: "h-8 w-8 shrink-0 p-0", "aria-label": "\u0E40\u0E14\u0E37\u0E2D\u0E19\u0E01\u0E48\u0E2D\u0E19\u0E2B\u0E19\u0E49\u0E32", children: require$$1.jsx(lucideReact.ChevronLeftIcon, { className: "h-4 w-4" }) }), require$$1.jsxs("div", { className: "flex min-w-0 flex-1 items-center justify-center gap-1", children: [require$$1.jsxs(Select, { value: String(month), onValueChange: handleMonthChange, children: [require$$1.jsx(SelectTrigger, { size: "sm", className: "h-8 w-[7.5rem] px-2 text-xs", "aria-label": "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E40\u0E14\u0E37\u0E2D\u0E19", children: require$$1.jsx(SelectValue, { children: THAI_MONTH_NAMES[month] }) }), require$$1.jsx(SelectContent, { className: "z-[100] max-h-60", children: THAI_MONTH_NAMES.map((name, index) => (require$$1.jsx(SelectItem, { value: String(index), children: name }, name))) })] }), require$$1.jsxs(Select, { value: String(toBuddhistYear(year)), onValueChange: handleYearChange, children: [require$$1.jsx(SelectTrigger, { size: "sm", className: "h-8 w-[5.5rem] px-2 text-xs", "aria-label": "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E1B\u0E35", children: require$$1.jsx(SelectValue, { children: toBuddhistYear(year) }) }), require$$1.jsx(SelectContent, { className: "z-[100] max-h-60", children: yearOptions.map((y) => (require$$1.jsx(SelectItem, { value: String(toBuddhistYear(y)), children: toBuddhistYear(y) }, y))) })] })] }), require$$1.jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => navigateMonth("next"), disabled: !canGoNext, className: "h-8 w-8 shrink-0 p-0", "aria-label": "\u0E40\u0E14\u0E37\u0E2D\u0E19\u0E16\u0E31\u0E14\u0E44\u0E1B", children: require$$1.jsx(lucideReact.ChevronRightIcon, { className: "h-4 w-4" }) })] }), require$$1.jsx("div", { className: "mb-2 grid grid-cols-7 gap-1", children: WEEK_DAYS_TH.map((day) => (require$$1.jsx("div", { className: "text-muted-foreground flex h-8 items-center justify-center text-center text-xs font-normal", children: day }, day))) }), require$$1.jsx("div", { className: "grid grid-cols-7 gap-1", children: days.map((date, index) => {
934
+ if (!date) {
935
+ return require$$1.jsx("div", { className: "h-8" }, index);
936
+ }
937
+ const isDateSelected = isSelected(date);
938
+ const isDateToday = isToday(date);
939
+ const isDateDisabled = isDisabled(date);
940
+ return (require$$1.jsx(Button, { type: "button", variant: "ghost", size: "icon", className: cn$1("h-8 w-8 p-0 text-sm font-normal", isDateSelected && "bg-primary text-primary-foreground", isDateToday &&
941
+ !isDateSelected &&
942
+ "bg-accent text-accent-foreground", isDateDisabled && "cursor-not-allowed opacity-50", "hover:bg-accent hover:text-accent-foreground"), onClick: () => handleDateClick(date), disabled: isDateDisabled, children: date.getDate() }, date.toISOString()));
943
+ }) })] }));
944
+ }
945
+ function DateInput({ value, onChange, placeholder = "Select date", className, disabled = false, }) {
946
+ const handleChange = (event) => {
947
+ const dateValue = event.target.value;
948
+ if (dateValue) {
949
+ onChange?.(new Date(dateValue));
950
+ }
951
+ else {
952
+ onChange?.(undefined);
953
+ }
954
+ };
955
+ const formatDateForInput = (date) => {
956
+ return date.toISOString().split("T")[0];
957
+ };
958
+ return (require$$1.jsx("input", { type: "date", value: value ? formatDateForInput(value) : "", onChange: handleChange, placeholder: placeholder, disabled: disabled, className: cn$1("border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", className) }));
659
959
  }
660
960
 
661
961
  const formatDistanceLocale = {
@@ -1157,10 +1457,11 @@ const defaultFormatDate = (date) => new Intl.DateTimeFormat("th-TH", {
1157
1457
  year: "numeric",
1158
1458
  timeZone: "Asia/Bangkok",
1159
1459
  }).format(date);
1160
- function DatePicker({ date, onDateChange, placeholder = "เลือกวันที่", disabled = false, disabledDates, formatDate = defaultFormatDate, className, id, ariaLabel, "aria-required": ariaRequired, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, }) {
1460
+ function DatePicker({ date, onDateChange, placeholder = "เลือกวันที่", disabled = false, disabledDates, formatDate = defaultFormatDate, fromYear = 1900, toYear, className, id, ariaLabel, "aria-required": ariaRequired, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, }) {
1161
1461
  const [open, setOpen] = React__namespace.useState(false);
1162
1462
  const isDateDisabled = disabledDates ?? defaultDisabledDates;
1163
- return (require$$1.jsxs(Popover, { open: open && !disabled, onOpenChange: setOpen, children: [require$$1.jsx(PopoverTrigger, { asChild: true, children: require$$1.jsxs("div", { className: "relative w-full", children: [require$$1.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 }), require$$1.jsx(lucideReact.Calendar, { className: "text-muted-foreground pointer-events-none absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2" })] }) }), require$$1.jsx(PopoverContent, { className: "w-[280px] overflow-hidden p-0", align: "start", children: require$$1.jsx(Calendar, { ...{ locale: th }, mode: "single", selected: date, onSelect: (selectedDate) => {
1463
+ const resolvedToYear = toYear ?? new Date().getFullYear() + 10;
1464
+ return (require$$1.jsxs(Popover, { open: open && !disabled, onOpenChange: setOpen, children: [require$$1.jsx(PopoverTrigger, { asChild: true, children: require$$1.jsxs("div", { className: "relative w-full", children: [require$$1.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 }), require$$1.jsx(lucideReact.Calendar, { className: "text-muted-foreground pointer-events-none absolute top-1/2 right-3 h-4 w-4 -translate-y-1/2" })] }) }), require$$1.jsx(PopoverContent, { className: "w-auto overflow-visible p-0", align: "start", children: require$$1.jsx(Calendar, { ...{ locale: th }, mode: "single", selected: date, onSelect: (selectedDate) => {
1164
1465
  if (selectedDate instanceof Date) {
1165
1466
  onDateChange?.(selectedDate);
1166
1467
  setOpen(false);
@@ -1169,7 +1470,7 @@ function DatePicker({ date, onDateChange, placeholder = "เลือกวั
1169
1470
  onDateChange?.(undefined);
1170
1471
  setOpen(false);
1171
1472
  }
1172
- }, disabled: isDateDisabled, initialFocus: true }) })] }));
1473
+ }, disabled: isDateDisabled, fromYear: fromYear, toYear: resolvedToYear, initialFocus: true }) })] }));
1173
1474
  }
1174
1475
 
1175
1476
  const labelVariants = classVarianceAuthority.cva("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
@@ -16252,80 +16553,6 @@ function ScrollBar({ className, orientation = "vertical", ...props }) {
16252
16553
  "h-2.5 flex-col border-t border-t-transparent", className), ...props, children: require$$1.jsx(ScrollAreaPrimitive__namespace.ScrollAreaThumb, { "data-slot": "scroll-area-thumb", className: "bg-border relative flex-1 rounded-full" }) }));
16253
16554
  }
16254
16555
 
16255
- function Select({ onValueChange, onOpenChange, open, defaultOpen, ...props }) {
16256
- // Tracked in a ref, not state: this only needs to be readable inside the
16257
- // callback below, and putting it in state would re-render on every open.
16258
- const isOpenRef = React__namespace.useRef(defaultOpen ?? false);
16259
- if (open !== undefined)
16260
- isOpenRef.current = open;
16261
- return (require$$1.jsx(SelectPrimitive__namespace.Root, { "data-slot": "select", ...props, open: open, defaultOpen: defaultOpen, onOpenChange: next => {
16262
- isOpenRef.current = next;
16263
- onOpenChange?.(next);
16264
- }, onValueChange: value => {
16265
- // Drop ONLY the empty value Radix echoes back on its own.
16266
- //
16267
- // Radix keeps a hidden native <select> so the control works inside
16268
- // real forms. Whenever the controlled value changes it assigns that
16269
- // value to the native node and dispatches a synthetic change event,
16270
- // which comes straight back out through onValueChange:
16271
- //
16272
- // setValue.call(select, selectValue);
16273
- // select.dispatchEvent(new Event("change", { bubbles: true }));
16274
- // ...
16275
- // onChange: (event) => onValueChange(event.target.value)
16276
- //
16277
- // The native <option> list is registered by SelectItem, and the items
16278
- // live inside SelectContent — portalled, and only mounted while the
16279
- // menu is open. On a closed select the option for the incoming value
16280
- // usually does not exist yet, the DOM refuses the assignment,
16281
- // `select.value` collapses to "", and that empty string reaches the
16282
- // consumer. In a form this lands exactly when saved data arrives: the
16283
- // field is set to its stored value, Radix echoes "", and the handler
16284
- // writes that back — enum fields then snap to their fallback and zod
16285
- // rejects the submit with "received ''".
16286
- //
16287
- // The open check is what keeps a real "none" option working. Radix
16288
- // does NOT forbid <SelectItem value="">, and picking one is a
16289
- // legitimate way to clear a selection. A user pick always arrives
16290
- // while the menu is still open — SelectItem's handleSelect calls
16291
- // onValueChange(value) BEFORE onOpenChange(false) — whereas the echo
16292
- // above fires from an effect with the menu closed. So only the closed
16293
- // case is suppressed.
16294
- if (value === "" && !isOpenRef.current)
16295
- return;
16296
- onValueChange?.(value);
16297
- } }));
16298
- }
16299
- function SelectGroup({ ...props }) {
16300
- return require$$1.jsx(SelectPrimitive__namespace.Group, { "data-slot": "select-group", ...props });
16301
- }
16302
- function SelectValue({ ...props }) {
16303
- return require$$1.jsx(SelectPrimitive__namespace.Value, { "data-slot": "select-value", ...props });
16304
- }
16305
- function SelectTrigger({ className, size = "default", children, ...props }) {
16306
- return (require$$1.jsxs(SelectPrimitive__namespace.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-fit 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, require$$1.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: require$$1.jsx(lucideReact.ChevronDownIcon, { className: "size-4 opacity-50" }) })] }));
16307
- }
16308
- function SelectContent({ className, children, position = "popper", ...props }) {
16309
- return (require$$1.jsx(SelectPrimitive__namespace.Portal, { children: require$$1.jsxs(SelectPrimitive__namespace.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" &&
16310
- "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className), position: position, ...props, children: [require$$1.jsx(SelectScrollUpButton, {}), require$$1.jsx(SelectPrimitive__namespace.Viewport, { className: cn$1("p-1", position === "popper" &&
16311
- "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"), children: children }), require$$1.jsx(SelectScrollDownButton, {})] }) }));
16312
- }
16313
- function SelectLabel({ className, ...props }) {
16314
- return (require$$1.jsx(SelectPrimitive__namespace.Label, { "data-slot": "select-label", className: cn$1("text-muted-foreground px-2 py-1.5 text-xs", className), ...props }));
16315
- }
16316
- function SelectItem({ className, children, ...props }) {
16317
- return (require$$1.jsxs(SelectPrimitive__namespace.Item, { "data-slot": "select-item", className: cn$1("focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className), ...props, children: [require$$1.jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: require$$1.jsx(SelectPrimitive__namespace.ItemIndicator, { children: require$$1.jsx(lucideReact.CheckIcon, { className: "size-4" }) }) }), require$$1.jsx(SelectPrimitive__namespace.ItemText, { children: children })] }));
16318
- }
16319
- function SelectSeparator({ className, ...props }) {
16320
- return (require$$1.jsx(SelectPrimitive__namespace.Separator, { "data-slot": "select-separator", className: cn$1("bg-border pointer-events-none -mx-1 my-1 h-px", className), ...props }));
16321
- }
16322
- function SelectScrollUpButton({ className, ...props }) {
16323
- return (require$$1.jsx(SelectPrimitive__namespace.ScrollUpButton, { "data-slot": "select-scroll-up-button", className: cn$1("flex cursor-default items-center justify-center py-1", className), ...props, children: require$$1.jsx(lucideReact.ChevronUpIcon, { className: "size-4" }) }));
16324
- }
16325
- function SelectScrollDownButton({ className, ...props }) {
16326
- return (require$$1.jsx(SelectPrimitive__namespace.ScrollDownButton, { "data-slot": "select-scroll-down-button", className: cn$1("flex cursor-default items-center justify-center py-1", className), ...props, children: require$$1.jsx(lucideReact.ChevronDownIcon, { className: "size-4" }) }));
16327
- }
16328
-
16329
16556
  function SelectField({ id, label, helperText, error, required, placeholder, value, defaultValue, onValueChange, disabled, options, children, containerClassName, labelClassName, triggerClassName, messageClassName, size, "aria-label": ariaLabel, "aria-describedby": ariaDescribedby, }) {
16330
16557
  const reactId = React__namespace.useId();
16331
16558
  const inputId = id ?? reactId;
@@ -34432,179 +34659,6 @@ const RegistryItemRow = ({ item }) => {
34432
34659
  return (require$$1.jsxs(TableRow, { children: [require$$1.jsx(TableCell, { className: "w-50 font-medium", children: item.title }), require$$1.jsx(TableCell, { children: require$$1.jsx(Button, { variant: "link", asChild: true, children: require$$1.jsx("a", { target: "_blank", href: `${getBaseUrl()}/registry/${item.name}`, children: "Link" }) }) }), require$$1.jsx(TableCell, { children: require$$1.jsx(Button, { variant: "link", asChild: true, children: require$$1.jsx("a", { href: `${getBaseUrl()}/storybook/?path=/docs/${item.meta.story}--docs`, children: "Story" }) }) }), require$$1.jsx(TableCell, { children: require$$1.jsx(CommandBlock, { command: `npx shadcn@latest add ${getBaseUrl()}/registry/${item.name}` }) })] }, item.name));
34433
34660
  };
34434
34661
 
34435
- /**
34436
- * The {@link endOfMonth} function options.
34437
- */
34438
-
34439
- /**
34440
- * @name endOfMonth
34441
- * @category Month Helpers
34442
- * @summary Return the end of a month for the given date.
34443
- *
34444
- * @description
34445
- * Return the end of a month for the given date.
34446
- * The result will be in the local timezone.
34447
- *
34448
- * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
34449
- * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments.
34450
- *
34451
- * @param date - The original date
34452
- * @param options - An object with options
34453
- *
34454
- * @returns The end of a month
34455
- *
34456
- * @example
34457
- * // The end of a month for 2 September 2014 11:55:00:
34458
- * const result = endOfMonth(new Date(2014, 8, 2, 11, 55, 0))
34459
- * //=> Tue Sep 30 2014 23:59:59.999
34460
- */
34461
- function endOfMonth(date, options) {
34462
- const _date = toDate(date);
34463
- const month = _date.getMonth();
34464
- _date.setFullYear(_date.getFullYear(), month + 1, 0);
34465
- _date.setHours(23, 59, 59, 999);
34466
- return _date;
34467
- }
34468
-
34469
- /**
34470
- * The {@link startOfMonth} function options.
34471
- */
34472
-
34473
- /**
34474
- * @name startOfMonth
34475
- * @category Month Helpers
34476
- * @summary Return the start of a month for the given date.
34477
- *
34478
- * @description
34479
- * Return the start of a month for the given date. The result will be in the local timezone.
34480
- *
34481
- * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments.
34482
- * Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
34483
- * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed,
34484
- * or inferred from the arguments.
34485
- *
34486
- * @param date - The original date
34487
- * @param options - An object with options
34488
- *
34489
- * @returns The start of a month
34490
- *
34491
- * @example
34492
- * // The start of a month for 2 September 2014 11:55:00:
34493
- * const result = startOfMonth(new Date(2014, 8, 2, 11, 55, 0))
34494
- * //=> Mon Sep 01 2014 00:00:00
34495
- */
34496
- function startOfMonth(date, options) {
34497
- const _date = toDate(date);
34498
- _date.setDate(1);
34499
- _date.setHours(0, 0, 0, 0);
34500
- return _date;
34501
- }
34502
-
34503
- /**
34504
- * Thai month names in Buddhist calendar
34505
- */
34506
- const THAI_MONTH_NAMES = [
34507
- "มกราคม",
34508
- "กุมภาพันธ์",
34509
- "มีนาคม",
34510
- "เมษายน",
34511
- "พฤษภาคม",
34512
- "มิถุนายน",
34513
- "กรกฎาคม",
34514
- "สิงหาคม",
34515
- "กันยายน",
34516
- "ตุลาคม",
34517
- "พฤศจิกายน",
34518
- "ธันวาคม",
34519
- ];
34520
- /**
34521
- * Convert Gregorian year to Buddhist year
34522
- * Buddhist calendar is 543 years ahead of Gregorian calendar
34523
- *
34524
- * @param gregorianYear - The Gregorian year (e.g., 2024)
34525
- * @returns The Buddhist year (e.g., 2567)
34526
- *
34527
- * @example
34528
- * toBuddhistYear(2024); // returns 2567
34529
- */
34530
- function toBuddhistYear(gregorianYear) {
34531
- return gregorianYear + 543;
34532
- }
34533
- /**
34534
- * Convert Buddhist year to Gregorian year
34535
- *
34536
- * @param buddhistYear - The Buddhist year (e.g., 2567)
34537
- * @returns The Gregorian year (e.g., 2024)
34538
- *
34539
- * @example
34540
- * toGregorianYear(2567); // returns 2024
34541
- */
34542
- function toGregorianYear(buddhistYear) {
34543
- return buddhistYear - 543;
34544
- }
34545
- /**
34546
- * Get the first and last day of a month
34547
- *
34548
- * @param date - The date within the month
34549
- * @returns Object with start and end dates of the month
34550
- *
34551
- * @example
34552
- * getMonthDateRange(new Date('2024-06-15'));
34553
- * // returns { start: Date('2024-06-01'), end: Date('2024-06-30') }
34554
- */
34555
- function getMonthDateRange(date) {
34556
- const start = startOfMonth(date);
34557
- const end = endOfMonth(date);
34558
- return { start, end };
34559
- }
34560
- /**
34561
- * Format a date to Thai Buddhist calendar month display
34562
- *
34563
- * @param date - The date to format
34564
- * @returns Formatted string in Thai Buddhist calendar (e.g., "มกราคม 2568")
34565
- *
34566
- * @example
34567
- * formatThaiMonth(new Date('2024-01-15')); // returns "มกราคม 2567"
34568
- * formatThaiMonth(new Date('2024-12-25')); // returns "ธันวาคม 2567"
34569
- */
34570
- function formatThaiMonth(date) {
34571
- const monthIndex = date.getMonth();
34572
- const gregorianYear = date.getFullYear();
34573
- const buddhistYear = toBuddhistYear(gregorianYear);
34574
- return `${THAI_MONTH_NAMES[monthIndex]} ${buddhistYear}`;
34575
- }
34576
- /**
34577
- * Format a date to short Thai Buddhist calendar format
34578
- *
34579
- * @param date - The date to format
34580
- * @returns Formatted string (e.g., "01/2568")
34581
- *
34582
- * @example
34583
- * formatThaiMonthShort(new Date('2024-01-15')); // returns "01/2567"
34584
- */
34585
- function formatThaiMonthShort(date) {
34586
- const month = String(date.getMonth() + 1).padStart(2, "0");
34587
- const gregorianYear = date.getFullYear();
34588
- const buddhistYear = toBuddhistYear(gregorianYear);
34589
- return `${month}/${buddhistYear}`;
34590
- }
34591
- /**
34592
- * Get Thai month name by index (0-11)
34593
- *
34594
- * @param monthIndex - Month index (0 = January, 11 = December)
34595
- * @returns Thai month name
34596
- *
34597
- * @example
34598
- * getThaiMonthName(0); // returns "มกราคม"
34599
- * getThaiMonthName(11); // returns "ธันวาคม"
34600
- */
34601
- function getThaiMonthName(monthIndex) {
34602
- if (monthIndex < 0 || monthIndex > 11) {
34603
- throw new Error("Month index must be between 0 and 11");
34604
- }
34605
- return THAI_MONTH_NAMES[monthIndex];
34606
- }
34607
-
34608
34662
  /**
34609
34663
  * Convert a number to its Thai baht textual representation
34610
34664
  * (e.g. 1234.50 → "หนึ่งพันสองร้อยสามสิบสี่บาทห้าสิบสตางค์").