@eintrek/erp-theme 1.4.8 → 1.4.10
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/formatted-number-input.d.ts +17 -0
- package/dist/components/ui/masked-text-input.d.ts +32 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +616 -396
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +620 -395
- package/dist/index.js.map +1 -1
- package/package.json +13 -11
package/dist/index.esm.js
CHANGED
|
@@ -213,133 +213,192 @@ function BreadcrumbSeparator({ children, className, ...props }) {
|
|
|
213
213
|
return (jsx("li", { "data-slot": "breadcrumb-separator", role: "presentation", "aria-hidden": "true", className: cn$1("[&>svg]:size-3.5", className), ...props, children: children ?? jsx(ChevronRight, {}) }));
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
onSelect?.({ from: date, to: undefined });
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
else if (mode === "multiple") {
|
|
296
|
-
const currentSelection = Array.isArray(selected) ? selected : [];
|
|
297
|
-
const isAlreadySelected = currentSelection.some(d => d.toDateString() === date.toDateString());
|
|
298
|
-
if (isAlreadySelected) {
|
|
299
|
-
onSelect?.(currentSelection.filter(d => d.toDateString() !== date.toDateString()));
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
302
|
-
onSelect?.([...currentSelection, date]);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
const navigateMonth = (direction) => {
|
|
307
|
-
setCurrentMonth(prev => {
|
|
308
|
-
const newMonth = new Date(prev);
|
|
309
|
-
if (direction === "prev") {
|
|
310
|
-
newMonth.setMonth(prev.getMonth() - 1);
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
newMonth.setMonth(prev.getMonth() + 1);
|
|
314
|
-
}
|
|
315
|
-
return newMonth;
|
|
316
|
-
});
|
|
317
|
-
};
|
|
318
|
-
const days = getDaysInMonth();
|
|
319
|
-
return (jsxs("div", { "data-slot": "calendar", className: cn$1("bg-background group/calendar p-3 w-fit", className), children: [jsxs("div", { className: "flex items-center justify-between mb-4", children: [jsx(Button, { variant: "ghost", size: "icon", onClick: () => navigateMonth("prev"), className: "h-8 w-8 p-0", children: jsx(ChevronLeftIcon, { className: "h-4 w-4" }) }), jsx("div", { className: "text-sm font-medium", children: currentMonth.toLocaleDateString("default", { month: "long", year: "numeric" }) }), jsx(Button, { variant: "ghost", size: "icon", onClick: () => navigateMonth("next"), className: "h-8 w-8 p-0", children: jsx(ChevronRightIcon, { className: "h-4 w-4" }) })] }), jsx("div", { className: "grid grid-cols-7 gap-1 mb-2", children: weekDays.map((day) => (jsx("div", { className: "text-muted-foreground text-xs font-normal text-center h-8 flex items-center justify-center", children: day }, day))) }), jsx("div", { className: "grid grid-cols-7 gap-1", children: days.map((date, index) => {
|
|
320
|
-
if (!date) {
|
|
321
|
-
return jsx("div", { className: "h-8" }, index);
|
|
322
|
-
}
|
|
323
|
-
const isDateSelected = isSelected(date);
|
|
324
|
-
const isDateToday = isToday(date);
|
|
325
|
-
const isDateDisabled = isDisabled(date);
|
|
326
|
-
return (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()));
|
|
327
|
-
}) })] }));
|
|
216
|
+
/**
|
|
217
|
+
* @module constants
|
|
218
|
+
* @summary Useful constants
|
|
219
|
+
* @description
|
|
220
|
+
* Collection of useful date constants.
|
|
221
|
+
*
|
|
222
|
+
* The constants could be imported from `date-fns/constants`:
|
|
223
|
+
*
|
|
224
|
+
* ```ts
|
|
225
|
+
* import { maxTime, minTime } from "./constants/date-fns/constants";
|
|
226
|
+
*
|
|
227
|
+
* function isAllowedTime(time) {
|
|
228
|
+
* return time <= maxTime && time >= minTime;
|
|
229
|
+
* }
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @constant
|
|
236
|
+
* @name constructFromSymbol
|
|
237
|
+
* @summary Symbol enabling Date extensions to inherit properties from the reference date.
|
|
238
|
+
*
|
|
239
|
+
* The symbol is used to enable the `constructFrom` function to construct a date
|
|
240
|
+
* using a reference date and a value. It allows to transfer extra properties
|
|
241
|
+
* from the reference date to the new date. It's useful for extensions like
|
|
242
|
+
* [`TZDate`](https://github.com/date-fns/tz) that accept a time zone as
|
|
243
|
+
* a constructor argument.
|
|
244
|
+
*/
|
|
245
|
+
const constructFromSymbol = Symbol.for("constructDateFrom");
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @name constructFrom
|
|
249
|
+
* @category Generic Helpers
|
|
250
|
+
* @summary Constructs a date using the reference date and the value
|
|
251
|
+
*
|
|
252
|
+
* @description
|
|
253
|
+
* The function constructs a new date using the constructor from the reference
|
|
254
|
+
* date and the given value. It helps to build generic functions that accept
|
|
255
|
+
* date extensions.
|
|
256
|
+
*
|
|
257
|
+
* It defaults to `Date` if the passed reference date is a number or a string.
|
|
258
|
+
*
|
|
259
|
+
* Starting from v3.7.0, it allows to construct a date using `[Symbol.for("constructDateFrom")]`
|
|
260
|
+
* enabling to transfer extra properties from the reference date to the new date.
|
|
261
|
+
* It's useful for extensions like [`TZDate`](https://github.com/date-fns/tz)
|
|
262
|
+
* that accept a time zone as a constructor argument.
|
|
263
|
+
*
|
|
264
|
+
* @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).
|
|
265
|
+
*
|
|
266
|
+
* @param date - The reference date to take constructor from
|
|
267
|
+
* @param value - The value to create the date
|
|
268
|
+
*
|
|
269
|
+
* @returns Date initialized using the given date and value
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* import { constructFrom } from "./constructFrom/date-fns";
|
|
273
|
+
*
|
|
274
|
+
* // A function that clones a date preserving the original type
|
|
275
|
+
* function cloneDate<DateType extends Date>(date: DateType): DateType {
|
|
276
|
+
* return constructFrom(
|
|
277
|
+
* date, // Use constructor from the given date
|
|
278
|
+
* date.getTime() // Use the date value to create a new date
|
|
279
|
+
* );
|
|
280
|
+
* }
|
|
281
|
+
*/
|
|
282
|
+
function constructFrom(date, value) {
|
|
283
|
+
if (typeof date === "function") return date(value);
|
|
284
|
+
|
|
285
|
+
if (date && typeof date === "object" && constructFromSymbol in date)
|
|
286
|
+
return date[constructFromSymbol](value);
|
|
287
|
+
|
|
288
|
+
if (date instanceof Date) return new date.constructor(value);
|
|
289
|
+
|
|
290
|
+
return new Date(value);
|
|
328
291
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* @name toDate
|
|
295
|
+
* @category Common Helpers
|
|
296
|
+
* @summary Convert the given argument to an instance of Date.
|
|
297
|
+
*
|
|
298
|
+
* @description
|
|
299
|
+
* Convert the given argument to an instance of Date.
|
|
300
|
+
*
|
|
301
|
+
* If the argument is an instance of Date, the function returns its clone.
|
|
302
|
+
*
|
|
303
|
+
* If the argument is a number, it is treated as a timestamp.
|
|
304
|
+
*
|
|
305
|
+
* If the argument is none of the above, the function returns Invalid Date.
|
|
306
|
+
*
|
|
307
|
+
* Starting from v3.7.0, it clones a date using `[Symbol.for("constructDateFrom")]`
|
|
308
|
+
* enabling to transfer extra properties from the reference date to the new date.
|
|
309
|
+
* It's useful for extensions like [`TZDate`](https://github.com/date-fns/tz)
|
|
310
|
+
* that accept a time zone as a constructor argument.
|
|
311
|
+
*
|
|
312
|
+
* **Note**: *all* Date arguments passed to any *date-fns* function is processed by `toDate`.
|
|
313
|
+
*
|
|
314
|
+
* @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).
|
|
315
|
+
* @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments.
|
|
316
|
+
*
|
|
317
|
+
* @param argument - The value to convert
|
|
318
|
+
*
|
|
319
|
+
* @returns The parsed date in the local time zone
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* // Clone the date:
|
|
323
|
+
* const result = toDate(new Date(2014, 1, 11, 11, 30, 30))
|
|
324
|
+
* //=> Tue Feb 11 2014 11:30:30
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* // Convert the timestamp to date:
|
|
328
|
+
* const result = toDate(1392098430000)
|
|
329
|
+
* //=> Tue Feb 11 2014 11:30:30
|
|
330
|
+
*/
|
|
331
|
+
function toDate(argument, context) {
|
|
332
|
+
// [TODO] Get rid of `toDate` or `constructFrom`?
|
|
333
|
+
return constructFrom(argument, argument);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* The {@link endOfMonth} function options.
|
|
338
|
+
*/
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @name endOfMonth
|
|
342
|
+
* @category Month Helpers
|
|
343
|
+
* @summary Return the end of a month for the given date.
|
|
344
|
+
*
|
|
345
|
+
* @description
|
|
346
|
+
* Return the end of a month for the given date.
|
|
347
|
+
* The result will be in the local timezone.
|
|
348
|
+
*
|
|
349
|
+
* @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).
|
|
350
|
+
* @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments.
|
|
351
|
+
*
|
|
352
|
+
* @param date - The original date
|
|
353
|
+
* @param options - An object with options
|
|
354
|
+
*
|
|
355
|
+
* @returns The end of a month
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* // The end of a month for 2 September 2014 11:55:00:
|
|
359
|
+
* const result = endOfMonth(new Date(2014, 8, 2, 11, 55, 0))
|
|
360
|
+
* //=> Tue Sep 30 2014 23:59:59.999
|
|
361
|
+
*/
|
|
362
|
+
function endOfMonth(date, options) {
|
|
363
|
+
const _date = toDate(date);
|
|
364
|
+
const month = _date.getMonth();
|
|
365
|
+
_date.setFullYear(_date.getFullYear(), month + 1, 0);
|
|
366
|
+
_date.setHours(23, 59, 59, 999);
|
|
367
|
+
return _date;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* The {@link startOfMonth} function options.
|
|
372
|
+
*/
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @name startOfMonth
|
|
376
|
+
* @category Month Helpers
|
|
377
|
+
* @summary Return the start of a month for the given date.
|
|
378
|
+
*
|
|
379
|
+
* @description
|
|
380
|
+
* Return the start of a month for the given date. The result will be in the local timezone.
|
|
381
|
+
*
|
|
382
|
+
* @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments.
|
|
383
|
+
* Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
|
|
384
|
+
* @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed,
|
|
385
|
+
* or inferred from the arguments.
|
|
386
|
+
*
|
|
387
|
+
* @param date - The original date
|
|
388
|
+
* @param options - An object with options
|
|
389
|
+
*
|
|
390
|
+
* @returns The start of a month
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* // The start of a month for 2 September 2014 11:55:00:
|
|
394
|
+
* const result = startOfMonth(new Date(2014, 8, 2, 11, 55, 0))
|
|
395
|
+
* //=> Mon Sep 01 2014 00:00:00
|
|
396
|
+
*/
|
|
397
|
+
function startOfMonth(date, options) {
|
|
398
|
+
const _date = toDate(date);
|
|
399
|
+
_date.setDate(1);
|
|
400
|
+
_date.setHours(0, 0, 0, 0);
|
|
401
|
+
return _date;
|
|
343
402
|
}
|
|
344
403
|
|
|
345
404
|
function buildFormatLongFn(args) {
|
|
@@ -494,123 +553,241 @@ function buildMatchPatternFn(args) {
|
|
|
494
553
|
}
|
|
495
554
|
|
|
496
555
|
/**
|
|
497
|
-
*
|
|
498
|
-
* @summary Useful constants
|
|
499
|
-
* @description
|
|
500
|
-
* Collection of useful date constants.
|
|
501
|
-
*
|
|
502
|
-
* The constants could be imported from `date-fns/constants`:
|
|
503
|
-
*
|
|
504
|
-
* ```ts
|
|
505
|
-
* import { maxTime, minTime } from "./constants/date-fns/constants";
|
|
506
|
-
*
|
|
507
|
-
* function isAllowedTime(time) {
|
|
508
|
-
* return time <= maxTime && time >= minTime;
|
|
509
|
-
* }
|
|
510
|
-
* ```
|
|
556
|
+
* Thai month names in Buddhist calendar
|
|
511
557
|
*/
|
|
512
|
-
|
|
513
|
-
|
|
558
|
+
const THAI_MONTH_NAMES = [
|
|
559
|
+
"มกราคม",
|
|
560
|
+
"กุมภาพันธ์",
|
|
561
|
+
"มีนาคม",
|
|
562
|
+
"เมษายน",
|
|
563
|
+
"พฤษภาคม",
|
|
564
|
+
"มิถุนายน",
|
|
565
|
+
"กรกฎาคม",
|
|
566
|
+
"สิงหาคม",
|
|
567
|
+
"กันยายน",
|
|
568
|
+
"ตุลาคม",
|
|
569
|
+
"พฤศจิกายน",
|
|
570
|
+
"ธันวาคม",
|
|
571
|
+
];
|
|
514
572
|
/**
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
* @summary Symbol enabling Date extensions to inherit properties from the reference date.
|
|
573
|
+
* Convert Gregorian year to Buddhist year
|
|
574
|
+
* Buddhist calendar is 543 years ahead of Gregorian calendar
|
|
518
575
|
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
576
|
+
* @param gregorianYear - The Gregorian year (e.g., 2024)
|
|
577
|
+
* @returns The Buddhist year (e.g., 2567)
|
|
578
|
+
*
|
|
579
|
+
* @example
|
|
580
|
+
* toBuddhistYear(2024); // returns 2567
|
|
524
581
|
*/
|
|
525
|
-
|
|
526
|
-
|
|
582
|
+
function toBuddhistYear(gregorianYear) {
|
|
583
|
+
return gregorianYear + 543;
|
|
584
|
+
}
|
|
527
585
|
/**
|
|
528
|
-
*
|
|
529
|
-
* @category Generic Helpers
|
|
530
|
-
* @summary Constructs a date using the reference date and the value
|
|
531
|
-
*
|
|
532
|
-
* @description
|
|
533
|
-
* The function constructs a new date using the constructor from the reference
|
|
534
|
-
* date and the given value. It helps to build generic functions that accept
|
|
535
|
-
* date extensions.
|
|
536
|
-
*
|
|
537
|
-
* It defaults to `Date` if the passed reference date is a number or a string.
|
|
538
|
-
*
|
|
539
|
-
* Starting from v3.7.0, it allows to construct a date using `[Symbol.for("constructDateFrom")]`
|
|
540
|
-
* enabling to transfer extra properties from the reference date to the new date.
|
|
541
|
-
* It's useful for extensions like [`TZDate`](https://github.com/date-fns/tz)
|
|
542
|
-
* that accept a time zone as a constructor argument.
|
|
543
|
-
*
|
|
544
|
-
* @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).
|
|
545
|
-
*
|
|
546
|
-
* @param date - The reference date to take constructor from
|
|
547
|
-
* @param value - The value to create the date
|
|
586
|
+
* Convert Buddhist year to Gregorian year
|
|
548
587
|
*
|
|
549
|
-
* @
|
|
588
|
+
* @param buddhistYear - The Buddhist year (e.g., 2567)
|
|
589
|
+
* @returns The Gregorian year (e.g., 2024)
|
|
550
590
|
*
|
|
551
591
|
* @example
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
* // A function that clones a date preserving the original type
|
|
555
|
-
* function cloneDate<DateType extends Date>(date: DateType): DateType {
|
|
556
|
-
* return constructFrom(
|
|
557
|
-
* date, // Use constructor from the given date
|
|
558
|
-
* date.getTime() // Use the date value to create a new date
|
|
559
|
-
* );
|
|
560
|
-
* }
|
|
592
|
+
* toGregorianYear(2567); // returns 2024
|
|
561
593
|
*/
|
|
562
|
-
function
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
if (date && typeof date === "object" && constructFromSymbol in date)
|
|
566
|
-
return date[constructFromSymbol](value);
|
|
567
|
-
|
|
568
|
-
if (date instanceof Date) return new date.constructor(value);
|
|
569
|
-
|
|
570
|
-
return new Date(value);
|
|
594
|
+
function toGregorianYear(buddhistYear) {
|
|
595
|
+
return buddhistYear - 543;
|
|
571
596
|
}
|
|
572
|
-
|
|
573
597
|
/**
|
|
574
|
-
*
|
|
575
|
-
* @category Common Helpers
|
|
576
|
-
* @summary Convert the given argument to an instance of Date.
|
|
577
|
-
*
|
|
578
|
-
* @description
|
|
579
|
-
* Convert the given argument to an instance of Date.
|
|
580
|
-
*
|
|
581
|
-
* If the argument is an instance of Date, the function returns its clone.
|
|
582
|
-
*
|
|
583
|
-
* If the argument is a number, it is treated as a timestamp.
|
|
584
|
-
*
|
|
585
|
-
* If the argument is none of the above, the function returns Invalid Date.
|
|
598
|
+
* Get the first and last day of a month
|
|
586
599
|
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
* It's useful for extensions like [`TZDate`](https://github.com/date-fns/tz)
|
|
590
|
-
* that accept a time zone as a constructor argument.
|
|
600
|
+
* @param date - The date within the month
|
|
601
|
+
* @returns Object with start and end dates of the month
|
|
591
602
|
*
|
|
592
|
-
*
|
|
603
|
+
* @example
|
|
604
|
+
* getMonthDateRange(new Date('2024-06-15'));
|
|
605
|
+
* // returns { start: Date('2024-06-01'), end: Date('2024-06-30') }
|
|
606
|
+
*/
|
|
607
|
+
function getMonthDateRange(date) {
|
|
608
|
+
const start = startOfMonth(date);
|
|
609
|
+
const end = endOfMonth(date);
|
|
610
|
+
return { start, end };
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Format a date to Thai Buddhist calendar month display
|
|
593
614
|
*
|
|
594
|
-
* @
|
|
595
|
-
* @
|
|
615
|
+
* @param date - The date to format
|
|
616
|
+
* @returns Formatted string in Thai Buddhist calendar (e.g., "มกราคม 2568")
|
|
596
617
|
*
|
|
597
|
-
* @
|
|
618
|
+
* @example
|
|
619
|
+
* formatThaiMonth(new Date('2024-01-15')); // returns "มกราคม 2567"
|
|
620
|
+
* formatThaiMonth(new Date('2024-12-25')); // returns "ธันวาคม 2567"
|
|
621
|
+
*/
|
|
622
|
+
function formatThaiMonth(date) {
|
|
623
|
+
const monthIndex = date.getMonth();
|
|
624
|
+
const gregorianYear = date.getFullYear();
|
|
625
|
+
const buddhistYear = toBuddhistYear(gregorianYear);
|
|
626
|
+
return `${THAI_MONTH_NAMES[monthIndex]} ${buddhistYear}`;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Format a date to short Thai Buddhist calendar format
|
|
598
630
|
*
|
|
599
|
-
* @
|
|
631
|
+
* @param date - The date to format
|
|
632
|
+
* @returns Formatted string (e.g., "01/2568")
|
|
600
633
|
*
|
|
601
634
|
* @example
|
|
602
|
-
* //
|
|
603
|
-
|
|
604
|
-
|
|
635
|
+
* formatThaiMonthShort(new Date('2024-01-15')); // returns "01/2567"
|
|
636
|
+
*/
|
|
637
|
+
function formatThaiMonthShort(date) {
|
|
638
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
639
|
+
const gregorianYear = date.getFullYear();
|
|
640
|
+
const buddhistYear = toBuddhistYear(gregorianYear);
|
|
641
|
+
return `${month}/${buddhistYear}`;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Get Thai month name by index (0-11)
|
|
645
|
+
*
|
|
646
|
+
* @param monthIndex - Month index (0 = January, 11 = December)
|
|
647
|
+
* @returns Thai month name
|
|
605
648
|
*
|
|
606
649
|
* @example
|
|
607
|
-
* //
|
|
608
|
-
*
|
|
609
|
-
* //=> Tue Feb 11 2014 11:30:30
|
|
650
|
+
* getThaiMonthName(0); // returns "มกราคม"
|
|
651
|
+
* getThaiMonthName(11); // returns "ธันวาคม"
|
|
610
652
|
*/
|
|
611
|
-
function
|
|
612
|
-
|
|
613
|
-
|
|
653
|
+
function getThaiMonthName(monthIndex) {
|
|
654
|
+
if (monthIndex < 0 || monthIndex > 11) {
|
|
655
|
+
throw new Error("Month index must be between 0 and 11");
|
|
656
|
+
}
|
|
657
|
+
return THAI_MONTH_NAMES[monthIndex];
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/** Thai weekday abbreviations (Sunday-first, matching JS getDay()). */
|
|
661
|
+
const WEEK_DAYS_TH = ["อา.", "จ.", "อ.", "พ.", "พฤ.", "ศ.", "ส."];
|
|
662
|
+
function formatMonthCaption(date) {
|
|
663
|
+
return `${THAI_MONTH_NAMES[date.getMonth()]} ${toBuddhistYear(date.getFullYear())}`;
|
|
664
|
+
}
|
|
665
|
+
function Calendar({ className, selected, onSelect, mode = "single", disabled, }) {
|
|
666
|
+
const [currentMonth, setCurrentMonth] = React.useState(new Date());
|
|
667
|
+
const today = new Date();
|
|
668
|
+
const year = currentMonth.getFullYear();
|
|
669
|
+
const month = currentMonth.getMonth();
|
|
670
|
+
const firstDayOfMonth = new Date(year, month, 1);
|
|
671
|
+
const lastDayOfMonth = new Date(year, month + 1, 0);
|
|
672
|
+
const firstDayOfWeek = firstDayOfMonth.getDay();
|
|
673
|
+
const daysInMonth = lastDayOfMonth.getDate();
|
|
674
|
+
const getDaysInMonth = () => {
|
|
675
|
+
const days = [];
|
|
676
|
+
// Add empty cells for days before the first day of the month
|
|
677
|
+
for (let i = 0; i < firstDayOfWeek; i++) {
|
|
678
|
+
days.push(null);
|
|
679
|
+
}
|
|
680
|
+
// Add days of the month
|
|
681
|
+
for (let day = 1; day <= daysInMonth; day++) {
|
|
682
|
+
days.push(new Date(year, month, day));
|
|
683
|
+
}
|
|
684
|
+
return days;
|
|
685
|
+
};
|
|
686
|
+
const isSelected = (date) => {
|
|
687
|
+
if (!selected)
|
|
688
|
+
return false;
|
|
689
|
+
if (mode === "single" && selected instanceof Date) {
|
|
690
|
+
return date.toDateString() === selected.toDateString();
|
|
691
|
+
}
|
|
692
|
+
if (mode === "range" && selected && typeof selected === "object" && "from" in selected) {
|
|
693
|
+
const range = selected;
|
|
694
|
+
if (range.from && range.to) {
|
|
695
|
+
return date >= range.from && date <= range.to;
|
|
696
|
+
}
|
|
697
|
+
if (range.from) {
|
|
698
|
+
return date.toDateString() === range.from.toDateString();
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
if (mode === "multiple" && Array.isArray(selected)) {
|
|
702
|
+
return selected.some(d => d.toDateString() === date.toDateString());
|
|
703
|
+
}
|
|
704
|
+
return false;
|
|
705
|
+
};
|
|
706
|
+
const isToday = (date) => {
|
|
707
|
+
return date.toDateString() === today.toDateString();
|
|
708
|
+
};
|
|
709
|
+
const isDisabled = (date) => {
|
|
710
|
+
if (disabled)
|
|
711
|
+
return disabled(date);
|
|
712
|
+
return false;
|
|
713
|
+
};
|
|
714
|
+
const handleDateClick = (date) => {
|
|
715
|
+
if (isDisabled(date))
|
|
716
|
+
return;
|
|
717
|
+
if (mode === "single") {
|
|
718
|
+
onSelect?.(date);
|
|
719
|
+
}
|
|
720
|
+
else if (mode === "range") {
|
|
721
|
+
// Simple range selection - click to set start, click again to set end
|
|
722
|
+
if (!selected || typeof selected !== "object" || !("from" in selected)) {
|
|
723
|
+
onSelect?.({ from: date, to: undefined });
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
const range = selected;
|
|
727
|
+
if (!range.from) {
|
|
728
|
+
onSelect?.({ from: date, to: undefined });
|
|
729
|
+
}
|
|
730
|
+
else if (!range.to) {
|
|
731
|
+
if (date >= range.from) {
|
|
732
|
+
onSelect?.({ from: range.from, to: date });
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
onSelect?.({ from: date, to: range.from });
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
onSelect?.({ from: date, to: undefined });
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
else if (mode === "multiple") {
|
|
744
|
+
const currentSelection = Array.isArray(selected) ? selected : [];
|
|
745
|
+
const isAlreadySelected = currentSelection.some(d => d.toDateString() === date.toDateString());
|
|
746
|
+
if (isAlreadySelected) {
|
|
747
|
+
onSelect?.(currentSelection.filter(d => d.toDateString() !== date.toDateString()));
|
|
748
|
+
}
|
|
749
|
+
else {
|
|
750
|
+
onSelect?.([...currentSelection, date]);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
const navigateMonth = (direction) => {
|
|
755
|
+
setCurrentMonth(prev => {
|
|
756
|
+
const newMonth = new Date(prev);
|
|
757
|
+
if (direction === "prev") {
|
|
758
|
+
newMonth.setMonth(prev.getMonth() - 1);
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
newMonth.setMonth(prev.getMonth() + 1);
|
|
762
|
+
}
|
|
763
|
+
return newMonth;
|
|
764
|
+
});
|
|
765
|
+
};
|
|
766
|
+
const days = getDaysInMonth();
|
|
767
|
+
return (jsxs("div", { "data-slot": "calendar", className: cn$1("bg-background group/calendar p-3 w-fit", className), children: [jsxs("div", { className: "flex items-center justify-between mb-4", children: [jsx(Button, { variant: "ghost", size: "icon", onClick: () => navigateMonth("prev"), className: "h-8 w-8 p-0", children: jsx(ChevronLeftIcon, { className: "h-4 w-4" }) }), jsx("div", { className: "text-sm font-medium", children: formatMonthCaption(currentMonth) }), jsx(Button, { variant: "ghost", size: "icon", onClick: () => navigateMonth("next"), className: "h-8 w-8 p-0", children: jsx(ChevronRightIcon, { className: "h-4 w-4" }) })] }), jsx("div", { className: "grid grid-cols-7 gap-1 mb-2", children: WEEK_DAYS_TH.map((day) => (jsx("div", { className: "text-muted-foreground text-xs font-normal text-center h-8 flex items-center justify-center", children: day }, day))) }), jsx("div", { className: "grid grid-cols-7 gap-1", children: days.map((date, index) => {
|
|
768
|
+
if (!date) {
|
|
769
|
+
return jsx("div", { className: "h-8" }, index);
|
|
770
|
+
}
|
|
771
|
+
const isDateSelected = isSelected(date);
|
|
772
|
+
const isDateToday = isToday(date);
|
|
773
|
+
const isDateDisabled = isDisabled(date);
|
|
774
|
+
return (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()));
|
|
775
|
+
}) })] }));
|
|
776
|
+
}
|
|
777
|
+
function DateInput({ value, onChange, placeholder = "Select date", className, disabled = false }) {
|
|
778
|
+
const handleChange = (event) => {
|
|
779
|
+
const dateValue = event.target.value;
|
|
780
|
+
if (dateValue) {
|
|
781
|
+
onChange?.(new Date(dateValue));
|
|
782
|
+
}
|
|
783
|
+
else {
|
|
784
|
+
onChange?.(undefined);
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
const formatDateForInput = (date) => {
|
|
788
|
+
return date.toISOString().split('T')[0];
|
|
789
|
+
};
|
|
790
|
+
return (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) }));
|
|
614
791
|
}
|
|
615
792
|
|
|
616
793
|
const formatDistanceLocale = {
|
|
@@ -13413,6 +13590,222 @@ function HoverCardContent({ className, align = "center", sideOffset = 4, ...prop
|
|
|
13413
13590
|
return (jsx(HoverCardPrimitive.Portal, { "data-slot": "hover-card-portal", children: jsx(HoverCardPrimitive.Content, { "data-slot": "hover-card-content", align: align, sideOffset: sideOffset, 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 z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden", className), ...props }) }));
|
|
13414
13591
|
}
|
|
13415
13592
|
|
|
13593
|
+
function countDigitsBefore$1(str, caret) {
|
|
13594
|
+
let n = 0;
|
|
13595
|
+
for (let i = 0; i < caret && i < str.length; i++) {
|
|
13596
|
+
if (/\d/.test(str[i]))
|
|
13597
|
+
n++;
|
|
13598
|
+
}
|
|
13599
|
+
return n;
|
|
13600
|
+
}
|
|
13601
|
+
function caretAfterDigits$1(str, digitCount) {
|
|
13602
|
+
if (digitCount <= 0)
|
|
13603
|
+
return 0;
|
|
13604
|
+
let seen = 0;
|
|
13605
|
+
for (let i = 0; i < str.length; i++) {
|
|
13606
|
+
if (/\d/.test(str[i])) {
|
|
13607
|
+
seen++;
|
|
13608
|
+
if (seen >= digitCount)
|
|
13609
|
+
return i + 1;
|
|
13610
|
+
}
|
|
13611
|
+
}
|
|
13612
|
+
return str.length;
|
|
13613
|
+
}
|
|
13614
|
+
function stripToRaw(input, allowNegative) {
|
|
13615
|
+
let s = input.replace(/,/g, "");
|
|
13616
|
+
const neg = allowNegative && s.startsWith("-");
|
|
13617
|
+
s = s.replace(/[^\d.]/g, "");
|
|
13618
|
+
// Keep only the first decimal point.
|
|
13619
|
+
const dot = s.indexOf(".");
|
|
13620
|
+
if (dot !== -1) {
|
|
13621
|
+
s = s.slice(0, dot + 1) + s.slice(dot + 1).replace(/\./g, "");
|
|
13622
|
+
}
|
|
13623
|
+
return neg ? `-${s}` : s;
|
|
13624
|
+
}
|
|
13625
|
+
function formatRaw(raw, decimals) {
|
|
13626
|
+
if (raw === "" || raw === "-" || raw === ".")
|
|
13627
|
+
return raw === "." ? "0." : raw;
|
|
13628
|
+
const neg = raw.startsWith("-");
|
|
13629
|
+
const body = neg ? raw.slice(1) : raw;
|
|
13630
|
+
const [intPart = "", fracPart] = body.split(".");
|
|
13631
|
+
const intFormatted = intPart === ""
|
|
13632
|
+
? ""
|
|
13633
|
+
: Number(intPart).toLocaleString("en-US", { maximumFractionDigits: 0 });
|
|
13634
|
+
let out = neg ? `-${intFormatted}` : intFormatted;
|
|
13635
|
+
if (fracPart !== undefined) {
|
|
13636
|
+
out += `.${fracPart.slice(0, decimals)}`;
|
|
13637
|
+
}
|
|
13638
|
+
return out;
|
|
13639
|
+
}
|
|
13640
|
+
function parseRaw(raw) {
|
|
13641
|
+
if (raw === "" || raw === "-" || raw === "." || raw === "-.")
|
|
13642
|
+
return "";
|
|
13643
|
+
const n = Number(raw);
|
|
13644
|
+
return Number.isFinite(n) ? n : "";
|
|
13645
|
+
}
|
|
13646
|
+
/**
|
|
13647
|
+
* Number input that shows thousand separators while typing (e.g. 100,000).
|
|
13648
|
+
* Emits a numeric model value without commas.
|
|
13649
|
+
*/
|
|
13650
|
+
function FormattedNumberInput({ value, onChange, decimals = 2, allowNegative = false, className, onBlur, ...props }) {
|
|
13651
|
+
const inputRef = React.useRef(null);
|
|
13652
|
+
const numeric = typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13653
|
+
const toRawFromNumeric = (n) => {
|
|
13654
|
+
if (decimals <= 0)
|
|
13655
|
+
return String(Math.trunc(n));
|
|
13656
|
+
// Avoid scientific notation; trim trailing zeros for cleaner edits.
|
|
13657
|
+
const fixed = n.toFixed(decimals);
|
|
13658
|
+
return fixed.replace(/\.?0+$/, "") || "0";
|
|
13659
|
+
};
|
|
13660
|
+
const [raw, setRaw] = React.useState(() => numeric === undefined ? "" : toRawFromNumeric(numeric));
|
|
13661
|
+
// Sync from external value when not actively mismatched (controlled reset).
|
|
13662
|
+
React.useEffect(() => {
|
|
13663
|
+
if (numeric === undefined) {
|
|
13664
|
+
if (raw !== "" && raw !== "-" && parseRaw(raw) === "") {
|
|
13665
|
+
// keep incomplete draft
|
|
13666
|
+
return;
|
|
13667
|
+
}
|
|
13668
|
+
if (parseRaw(raw) === "")
|
|
13669
|
+
setRaw("");
|
|
13670
|
+
return;
|
|
13671
|
+
}
|
|
13672
|
+
if (parseRaw(raw) === numeric)
|
|
13673
|
+
return;
|
|
13674
|
+
setRaw(toRawFromNumeric(numeric));
|
|
13675
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- only react to external value
|
|
13676
|
+
}, [numeric]);
|
|
13677
|
+
const display = formatRaw(raw, decimals);
|
|
13678
|
+
const accepts = React.useMemo(() => {
|
|
13679
|
+
const sign = allowNegative ? "-?" : "";
|
|
13680
|
+
return new RegExp(`^${sign}\\d*\\.?\\d{0,${decimals}}$`);
|
|
13681
|
+
}, [allowNegative, decimals]);
|
|
13682
|
+
return (jsx(Input, { ...props, ref: inputRef, type: "text", inputMode: "decimal", autoComplete: "off", className: cn$1(className), value: display, onChange: (event) => {
|
|
13683
|
+
const el = event.target;
|
|
13684
|
+
const nextRaw = stripToRaw(el.value, allowNegative);
|
|
13685
|
+
if (!accepts.test(nextRaw) && nextRaw !== "" && nextRaw !== "-") {
|
|
13686
|
+
return;
|
|
13687
|
+
}
|
|
13688
|
+
const digitsBefore = countDigitsBefore$1(el.value, el.selectionStart ?? el.value.length);
|
|
13689
|
+
setRaw(nextRaw);
|
|
13690
|
+
onChange(parseRaw(nextRaw));
|
|
13691
|
+
const nextDisplay = formatRaw(nextRaw, decimals);
|
|
13692
|
+
requestAnimationFrame(() => {
|
|
13693
|
+
const node = inputRef.current;
|
|
13694
|
+
if (!node)
|
|
13695
|
+
return;
|
|
13696
|
+
const pos = caretAfterDigits$1(nextDisplay, digitsBefore);
|
|
13697
|
+
node.setSelectionRange(pos, pos);
|
|
13698
|
+
});
|
|
13699
|
+
}, onBlur: (event) => {
|
|
13700
|
+
const parsed = parseRaw(raw);
|
|
13701
|
+
if (parsed === "") {
|
|
13702
|
+
setRaw("");
|
|
13703
|
+
onChange("");
|
|
13704
|
+
}
|
|
13705
|
+
else {
|
|
13706
|
+
const normalized = toRawFromNumeric(parsed);
|
|
13707
|
+
setRaw(normalized);
|
|
13708
|
+
onChange(parsed);
|
|
13709
|
+
}
|
|
13710
|
+
onBlur?.(event);
|
|
13711
|
+
} }));
|
|
13712
|
+
}
|
|
13713
|
+
|
|
13714
|
+
/** `#` = digit slot; any other character is a literal shown while typing. */
|
|
13715
|
+
const MASK_PRESETS = {
|
|
13716
|
+
/** Thai bank-style account: 555-5-55555-5 */
|
|
13717
|
+
bankAccount: "###-#-#####-#",
|
|
13718
|
+
/** Thai mobile (10 digits): 081-234-5678 */
|
|
13719
|
+
thaiPhone: "###-###-####",
|
|
13720
|
+
/** Thai national ID (13 digits): 1-2345-67890-12-3 */
|
|
13721
|
+
thaiNationalId: "#-####-#####-##-#",
|
|
13722
|
+
};
|
|
13723
|
+
function resolveMask(mask) {
|
|
13724
|
+
if (mask in MASK_PRESETS) {
|
|
13725
|
+
return MASK_PRESETS[mask];
|
|
13726
|
+
}
|
|
13727
|
+
return mask;
|
|
13728
|
+
}
|
|
13729
|
+
function maxDigits(pattern) {
|
|
13730
|
+
let n = 0;
|
|
13731
|
+
for (const ch of pattern)
|
|
13732
|
+
if (ch === "#")
|
|
13733
|
+
n++;
|
|
13734
|
+
return n;
|
|
13735
|
+
}
|
|
13736
|
+
/**
|
|
13737
|
+
* Map digits onto `#` slots. Literals appear as soon as the previous `#` is
|
|
13738
|
+
* filled; after the last typed digit, the next separator is shown so the mask
|
|
13739
|
+
* is visible while typing (e.g. "555-").
|
|
13740
|
+
*/
|
|
13741
|
+
function formatMasked(digits, pattern) {
|
|
13742
|
+
if (!digits)
|
|
13743
|
+
return "";
|
|
13744
|
+
let di = 0;
|
|
13745
|
+
let out = "";
|
|
13746
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
13747
|
+
const ch = pattern[i];
|
|
13748
|
+
if (ch === "#") {
|
|
13749
|
+
if (di >= digits.length)
|
|
13750
|
+
break;
|
|
13751
|
+
out += digits[di++];
|
|
13752
|
+
}
|
|
13753
|
+
else {
|
|
13754
|
+
if (di === 0)
|
|
13755
|
+
break;
|
|
13756
|
+
out += ch;
|
|
13757
|
+
}
|
|
13758
|
+
}
|
|
13759
|
+
return out;
|
|
13760
|
+
}
|
|
13761
|
+
function parseDigits(input, pattern) {
|
|
13762
|
+
return input.replace(/\D/g, "").slice(0, maxDigits(pattern));
|
|
13763
|
+
}
|
|
13764
|
+
function countDigitsBefore(str, caret) {
|
|
13765
|
+
let n = 0;
|
|
13766
|
+
for (let i = 0; i < caret && i < str.length; i++) {
|
|
13767
|
+
if (/\d/.test(str[i]))
|
|
13768
|
+
n++;
|
|
13769
|
+
}
|
|
13770
|
+
return n;
|
|
13771
|
+
}
|
|
13772
|
+
function caretAfterDigits(str, digitCount) {
|
|
13773
|
+
if (digitCount <= 0)
|
|
13774
|
+
return 0;
|
|
13775
|
+
let seen = 0;
|
|
13776
|
+
for (let i = 0; i < str.length; i++) {
|
|
13777
|
+
if (/\d/.test(str[i])) {
|
|
13778
|
+
seen++;
|
|
13779
|
+
if (seen >= digitCount)
|
|
13780
|
+
return i + 1;
|
|
13781
|
+
}
|
|
13782
|
+
}
|
|
13783
|
+
return str.length;
|
|
13784
|
+
}
|
|
13785
|
+
/**
|
|
13786
|
+
* Masked text input that shows separators while typing (e.g. 555-5-55555-5).
|
|
13787
|
+
* `value` / `onChange` use digits only.
|
|
13788
|
+
*/
|
|
13789
|
+
function MaskedTextInput({ value, onChange, mask, className, ...props }) {
|
|
13790
|
+
const inputRef = React.useRef(null);
|
|
13791
|
+
const pattern = resolveMask(mask);
|
|
13792
|
+
const display = formatMasked(value ?? "", pattern);
|
|
13793
|
+
return (jsx(Input, { ...props, ref: inputRef, type: "text", inputMode: "numeric", autoComplete: "off", className: cn$1(className), value: display, onChange: (event) => {
|
|
13794
|
+
const el = event.target;
|
|
13795
|
+
const digitsBefore = countDigitsBefore(el.value, el.selectionStart ?? el.value.length);
|
|
13796
|
+
const next = parseDigits(el.value, pattern);
|
|
13797
|
+
onChange(next);
|
|
13798
|
+
const nextDisplay = formatMasked(next, pattern);
|
|
13799
|
+
requestAnimationFrame(() => {
|
|
13800
|
+
const node = inputRef.current;
|
|
13801
|
+
if (!node)
|
|
13802
|
+
return;
|
|
13803
|
+
const pos = caretAfterDigits(nextDisplay, digitsBefore);
|
|
13804
|
+
node.setSelectionRange(pos, pos);
|
|
13805
|
+
});
|
|
13806
|
+
} }));
|
|
13807
|
+
}
|
|
13808
|
+
|
|
13416
13809
|
function InputField({ id, label, helperText, error, required, containerClassName, labelClassName, messageClassName, className, ref, ...props }) {
|
|
13417
13810
|
const reactId = React.useId();
|
|
13418
13811
|
const inputId = id ?? reactId;
|
|
@@ -34171,179 +34564,6 @@ const RegistryItemRow = ({ item }) => {
|
|
|
34171
34564
|
return (jsxs(TableRow, { children: [jsx(TableCell, { className: "w-50 font-medium", children: item.title }), jsx(TableCell, { children: jsx(Button, { variant: "link", asChild: true, children: jsx("a", { target: "_blank", href: `${getBaseUrl()}/registry/${item.name}`, children: "Link" }) }) }), jsx(TableCell, { children: jsx(Button, { variant: "link", asChild: true, children: jsx("a", { href: `${getBaseUrl()}/storybook/?path=/docs/${item.meta.story}--docs`, children: "Story" }) }) }), jsx(TableCell, { children: jsx(CommandBlock, { command: `npx shadcn@latest add ${getBaseUrl()}/registry/${item.name}` }) })] }, item.name));
|
|
34172
34565
|
};
|
|
34173
34566
|
|
|
34174
|
-
/**
|
|
34175
|
-
* The {@link endOfMonth} function options.
|
|
34176
|
-
*/
|
|
34177
|
-
|
|
34178
|
-
/**
|
|
34179
|
-
* @name endOfMonth
|
|
34180
|
-
* @category Month Helpers
|
|
34181
|
-
* @summary Return the end of a month for the given date.
|
|
34182
|
-
*
|
|
34183
|
-
* @description
|
|
34184
|
-
* Return the end of a month for the given date.
|
|
34185
|
-
* The result will be in the local timezone.
|
|
34186
|
-
*
|
|
34187
|
-
* @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).
|
|
34188
|
-
* @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments.
|
|
34189
|
-
*
|
|
34190
|
-
* @param date - The original date
|
|
34191
|
-
* @param options - An object with options
|
|
34192
|
-
*
|
|
34193
|
-
* @returns The end of a month
|
|
34194
|
-
*
|
|
34195
|
-
* @example
|
|
34196
|
-
* // The end of a month for 2 September 2014 11:55:00:
|
|
34197
|
-
* const result = endOfMonth(new Date(2014, 8, 2, 11, 55, 0))
|
|
34198
|
-
* //=> Tue Sep 30 2014 23:59:59.999
|
|
34199
|
-
*/
|
|
34200
|
-
function endOfMonth(date, options) {
|
|
34201
|
-
const _date = toDate(date);
|
|
34202
|
-
const month = _date.getMonth();
|
|
34203
|
-
_date.setFullYear(_date.getFullYear(), month + 1, 0);
|
|
34204
|
-
_date.setHours(23, 59, 59, 999);
|
|
34205
|
-
return _date;
|
|
34206
|
-
}
|
|
34207
|
-
|
|
34208
|
-
/**
|
|
34209
|
-
* The {@link startOfMonth} function options.
|
|
34210
|
-
*/
|
|
34211
|
-
|
|
34212
|
-
/**
|
|
34213
|
-
* @name startOfMonth
|
|
34214
|
-
* @category Month Helpers
|
|
34215
|
-
* @summary Return the start of a month for the given date.
|
|
34216
|
-
*
|
|
34217
|
-
* @description
|
|
34218
|
-
* Return the start of a month for the given date. The result will be in the local timezone.
|
|
34219
|
-
*
|
|
34220
|
-
* @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments.
|
|
34221
|
-
* Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
|
|
34222
|
-
* @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed,
|
|
34223
|
-
* or inferred from the arguments.
|
|
34224
|
-
*
|
|
34225
|
-
* @param date - The original date
|
|
34226
|
-
* @param options - An object with options
|
|
34227
|
-
*
|
|
34228
|
-
* @returns The start of a month
|
|
34229
|
-
*
|
|
34230
|
-
* @example
|
|
34231
|
-
* // The start of a month for 2 September 2014 11:55:00:
|
|
34232
|
-
* const result = startOfMonth(new Date(2014, 8, 2, 11, 55, 0))
|
|
34233
|
-
* //=> Mon Sep 01 2014 00:00:00
|
|
34234
|
-
*/
|
|
34235
|
-
function startOfMonth(date, options) {
|
|
34236
|
-
const _date = toDate(date);
|
|
34237
|
-
_date.setDate(1);
|
|
34238
|
-
_date.setHours(0, 0, 0, 0);
|
|
34239
|
-
return _date;
|
|
34240
|
-
}
|
|
34241
|
-
|
|
34242
|
-
/**
|
|
34243
|
-
* Thai month names in Buddhist calendar
|
|
34244
|
-
*/
|
|
34245
|
-
const THAI_MONTH_NAMES = [
|
|
34246
|
-
"มกราคม",
|
|
34247
|
-
"กุมภาพันธ์",
|
|
34248
|
-
"มีนาคม",
|
|
34249
|
-
"เมษายน",
|
|
34250
|
-
"พฤษภาคม",
|
|
34251
|
-
"มิถุนายน",
|
|
34252
|
-
"กรกฎาคม",
|
|
34253
|
-
"สิงหาคม",
|
|
34254
|
-
"กันยายน",
|
|
34255
|
-
"ตุลาคม",
|
|
34256
|
-
"พฤศจิกายน",
|
|
34257
|
-
"ธันวาคม",
|
|
34258
|
-
];
|
|
34259
|
-
/**
|
|
34260
|
-
* Convert Gregorian year to Buddhist year
|
|
34261
|
-
* Buddhist calendar is 543 years ahead of Gregorian calendar
|
|
34262
|
-
*
|
|
34263
|
-
* @param gregorianYear - The Gregorian year (e.g., 2024)
|
|
34264
|
-
* @returns The Buddhist year (e.g., 2567)
|
|
34265
|
-
*
|
|
34266
|
-
* @example
|
|
34267
|
-
* toBuddhistYear(2024); // returns 2567
|
|
34268
|
-
*/
|
|
34269
|
-
function toBuddhistYear(gregorianYear) {
|
|
34270
|
-
return gregorianYear + 543;
|
|
34271
|
-
}
|
|
34272
|
-
/**
|
|
34273
|
-
* Convert Buddhist year to Gregorian year
|
|
34274
|
-
*
|
|
34275
|
-
* @param buddhistYear - The Buddhist year (e.g., 2567)
|
|
34276
|
-
* @returns The Gregorian year (e.g., 2024)
|
|
34277
|
-
*
|
|
34278
|
-
* @example
|
|
34279
|
-
* toGregorianYear(2567); // returns 2024
|
|
34280
|
-
*/
|
|
34281
|
-
function toGregorianYear(buddhistYear) {
|
|
34282
|
-
return buddhistYear - 543;
|
|
34283
|
-
}
|
|
34284
|
-
/**
|
|
34285
|
-
* Get the first and last day of a month
|
|
34286
|
-
*
|
|
34287
|
-
* @param date - The date within the month
|
|
34288
|
-
* @returns Object with start and end dates of the month
|
|
34289
|
-
*
|
|
34290
|
-
* @example
|
|
34291
|
-
* getMonthDateRange(new Date('2024-06-15'));
|
|
34292
|
-
* // returns { start: Date('2024-06-01'), end: Date('2024-06-30') }
|
|
34293
|
-
*/
|
|
34294
|
-
function getMonthDateRange(date) {
|
|
34295
|
-
const start = startOfMonth(date);
|
|
34296
|
-
const end = endOfMonth(date);
|
|
34297
|
-
return { start, end };
|
|
34298
|
-
}
|
|
34299
|
-
/**
|
|
34300
|
-
* Format a date to Thai Buddhist calendar month display
|
|
34301
|
-
*
|
|
34302
|
-
* @param date - The date to format
|
|
34303
|
-
* @returns Formatted string in Thai Buddhist calendar (e.g., "มกราคม 2568")
|
|
34304
|
-
*
|
|
34305
|
-
* @example
|
|
34306
|
-
* formatThaiMonth(new Date('2024-01-15')); // returns "มกราคม 2567"
|
|
34307
|
-
* formatThaiMonth(new Date('2024-12-25')); // returns "ธันวาคม 2567"
|
|
34308
|
-
*/
|
|
34309
|
-
function formatThaiMonth(date) {
|
|
34310
|
-
const monthIndex = date.getMonth();
|
|
34311
|
-
const gregorianYear = date.getFullYear();
|
|
34312
|
-
const buddhistYear = toBuddhistYear(gregorianYear);
|
|
34313
|
-
return `${THAI_MONTH_NAMES[monthIndex]} ${buddhistYear}`;
|
|
34314
|
-
}
|
|
34315
|
-
/**
|
|
34316
|
-
* Format a date to short Thai Buddhist calendar format
|
|
34317
|
-
*
|
|
34318
|
-
* @param date - The date to format
|
|
34319
|
-
* @returns Formatted string (e.g., "01/2568")
|
|
34320
|
-
*
|
|
34321
|
-
* @example
|
|
34322
|
-
* formatThaiMonthShort(new Date('2024-01-15')); // returns "01/2567"
|
|
34323
|
-
*/
|
|
34324
|
-
function formatThaiMonthShort(date) {
|
|
34325
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
34326
|
-
const gregorianYear = date.getFullYear();
|
|
34327
|
-
const buddhistYear = toBuddhistYear(gregorianYear);
|
|
34328
|
-
return `${month}/${buddhistYear}`;
|
|
34329
|
-
}
|
|
34330
|
-
/**
|
|
34331
|
-
* Get Thai month name by index (0-11)
|
|
34332
|
-
*
|
|
34333
|
-
* @param monthIndex - Month index (0 = January, 11 = December)
|
|
34334
|
-
* @returns Thai month name
|
|
34335
|
-
*
|
|
34336
|
-
* @example
|
|
34337
|
-
* getThaiMonthName(0); // returns "มกราคม"
|
|
34338
|
-
* getThaiMonthName(11); // returns "ธันวาคม"
|
|
34339
|
-
*/
|
|
34340
|
-
function getThaiMonthName(monthIndex) {
|
|
34341
|
-
if (monthIndex < 0 || monthIndex > 11) {
|
|
34342
|
-
throw new Error("Month index must be between 0 and 11");
|
|
34343
|
-
}
|
|
34344
|
-
return THAI_MONTH_NAMES[monthIndex];
|
|
34345
|
-
}
|
|
34346
|
-
|
|
34347
34567
|
/**
|
|
34348
34568
|
* Convert a number to its Thai baht textual representation
|
|
34349
34569
|
* (e.g. 1234.50 → "หนึ่งพันสองร้อยสามสิบสี่บาทห้าสิบสตางค์").
|
|
@@ -34582,5 +34802,5 @@ const flagConfig = {
|
|
|
34582
34802
|
],
|
|
34583
34803
|
};
|
|
34584
34804
|
|
|
34585
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandBlock, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CustomSelectField2, DataTable, DataTableCell, DataTableColumnHeader, DataTableDateFilter, DataTableFacetedFilter, DataTableFilterDropdown, DataTableFilterList, DataTablePagination, DataTableRangeFilter, DataTableSkeleton, DataTableSliderFilter, DataTableSortList, DataTableToolbar, DataTableViewOptions, DateInput, DatePicker, DatePickerField, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Faceted, FacetedBadgeList, FacetedContent, FacetedEmpty, FacetedGroup, FacetedInput, FacetedItem, FacetedList, FacetedSeparator, FacetedTrigger, FileUploader, Footer, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FormSkeleton, Header, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputField, InputOTP, InputOTPGroup, InputOTPSlot, Label, LoadingScreen, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, PageHeader, Pagination$1 as Pagination, PaginationContent$1 as PaginationContent, PaginationEllipsis$1 as PaginationEllipsis, PaginationItem$1 as PaginationItem, PaginationLink$1 as PaginationLink, PaginationNext$1 as PaginationNext, PaginationPrevious$1 as PaginationPrevious, Popover, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, RegistryItemRow, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, Select, SelectContent, SelectField, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarTrigger, Skeleton, Slider, Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay, Switch, THAI_MONTH_NAMES, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, TextareaField, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, ValidationErrors, badgeVariants, buttonVariants, cn$1 as cn, convertFileToUploadedFile, convertFilesToUploadedFiles, dataTableConfig, databasePrefix, flagConfig, formatCurrency, formatDate, formatDateThai, formatDateThaiShort, formatFileSize, formatNumber, formatThaiMonth, formatThaiMonthShort, generateFileId, generateId, getBaseUrl, getCommonPinningStyles, getDefaultFilterOperator, getFilterOperators, getFiltersStateParser, getMonthDateRange, getSortingStateParser, getThaiMonthName, getValidFilters, isImageFile, navigationMenuTriggerStyle, siteConfig, thaiBahtText, toBuddhistIso, toBuddhistYear, toGregorianYear, toggleVariants, unknownError, useCallbackRef, useDataTable, useDebounce, useDebouncedCallback, useFormField, useIsMobile, useMediaQuery, validateFileSize, validateFileType };
|
|
34805
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandBlock, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CustomSelectField2, DataTable, DataTableCell, DataTableColumnHeader, DataTableDateFilter, DataTableFacetedFilter, DataTableFilterDropdown, DataTableFilterList, DataTablePagination, DataTableRangeFilter, DataTableSkeleton, DataTableSliderFilter, DataTableSortList, DataTableToolbar, DataTableViewOptions, DateInput, DatePicker, DatePickerField, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Faceted, FacetedBadgeList, FacetedContent, FacetedEmpty, FacetedGroup, FacetedInput, FacetedItem, FacetedList, FacetedSeparator, FacetedTrigger, FileUploader, Footer, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FormSkeleton, FormattedNumberInput, Header, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputField, InputOTP, InputOTPGroup, InputOTPSlot, Label, LoadingScreen, MASK_PRESETS, MaskedTextInput, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, PageHeader, Pagination$1 as Pagination, PaginationContent$1 as PaginationContent, PaginationEllipsis$1 as PaginationEllipsis, PaginationItem$1 as PaginationItem, PaginationLink$1 as PaginationLink, PaginationNext$1 as PaginationNext, PaginationPrevious$1 as PaginationPrevious, Popover, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, RegistryItemRow, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, Select, SelectContent, SelectField, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarTrigger, Skeleton, Slider, Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay, Switch, THAI_MONTH_NAMES, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, TextareaField, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, ValidationErrors, badgeVariants, buttonVariants, cn$1 as cn, convertFileToUploadedFile, convertFilesToUploadedFiles, dataTableConfig, databasePrefix, flagConfig, formatCurrency, formatDate, formatDateThai, formatDateThaiShort, formatFileSize, formatMasked as formatMaskedValue, formatNumber, formatThaiMonth, formatThaiMonthShort, generateFileId, generateId, getBaseUrl, getCommonPinningStyles, getDefaultFilterOperator, getFilterOperators, getFiltersStateParser, getMonthDateRange, getSortingStateParser, getThaiMonthName, getValidFilters, isImageFile, navigationMenuTriggerStyle, parseDigits as parseMaskedDigits, siteConfig, thaiBahtText, toBuddhistIso, toBuddhistYear, toGregorianYear, toggleVariants, unknownError, useCallbackRef, useDataTable, useDebounce, useDebouncedCallback, useFormField, useIsMobile, useMediaQuery, validateFileSize, validateFileType };
|
|
34586
34806
|
//# sourceMappingURL=index.esm.js.map
|