@dmsi/wedgekit-react 0.0.231 → 0.0.232

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.
Files changed (35) hide show
  1. package/dist/{chunk-A76MF7ZO.js → chunk-3M23BFB4.js} +2 -2
  2. package/dist/chunk-SQJ7MWY7.js +493 -0
  3. package/dist/chunk-VZVPD3XK.js +1182 -0
  4. package/dist/components/CalendarRange.cjs +4066 -224
  5. package/dist/components/CalendarRange.css +4831 -0
  6. package/dist/components/CalendarRange.js +23 -1
  7. package/dist/components/DateInput.cjs +3668 -326
  8. package/dist/components/DateInput.css +4831 -0
  9. package/dist/components/DateInput.js +20 -3
  10. package/dist/components/DateRangeInput.cjs +3668 -326
  11. package/dist/components/DateRangeInput.css +4831 -0
  12. package/dist/components/DateRangeInput.js +20 -3
  13. package/dist/components/FilterGroup.js +5 -5
  14. package/dist/components/MobileDataGrid.js +3 -3
  15. package/dist/components/Modal.js +4 -4
  16. package/dist/components/ModalButtons.js +2 -2
  17. package/dist/components/ModalHeader.js +2 -2
  18. package/dist/components/NavigationTab.js +2 -2
  19. package/dist/components/NavigationTabs.js +2 -2
  20. package/dist/components/Notification.js +3 -3
  21. package/dist/components/OptionPill.js +2 -2
  22. package/dist/components/PDFViewer.js +6 -6
  23. package/dist/components/Stepper.js +3 -3
  24. package/dist/components/Toast.js +3 -3
  25. package/dist/components/Upload.js +3 -3
  26. package/dist/components/index.css +3 -0
  27. package/dist/components/index.js +8 -1138
  28. package/dist/index.css +3 -0
  29. package/package.json +1 -1
  30. package/src/components/CalendarRange.tsx +316 -165
  31. package/dist/chunk-SE5DM2IJ.js +0 -350
  32. package/dist/{chunk-ED7FXZRX.js → chunk-BW2MWMVM.js} +3 -3
  33. package/dist/{chunk-FYW64H7N.js → chunk-JFPRYMID.js} +3 -3
  34. package/dist/{chunk-A5ROZWIH.js → chunk-R4H6D4SZ.js} +3 -3
  35. package/dist/{chunk-47KTDBGA.js → chunk-T7UCZWWK.js} +3 -3
package/dist/index.css CHANGED
@@ -1881,6 +1881,9 @@
1881
1881
  .py-4 {
1882
1882
  padding-block: calc(var(--spacing) * 4);
1883
1883
  }
1884
+ .py-\[2px\] {
1885
+ padding-block: 2px;
1886
+ }
1884
1887
  .py-\[15px\] {
1885
1888
  padding-block: 15px;
1886
1889
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dmsi/wedgekit-react",
3
3
  "private": false,
4
- "version": "0.0.231",
4
+ "version": "0.0.232",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "tsup",
@@ -6,8 +6,9 @@ import {
6
6
  layoutGap,
7
7
  } from "../classNames";
8
8
  import { Icon } from "./Icon";
9
- import React, { useEffect, useState } from "react";
9
+ import React, { useEffect, useRef, useState } from "react";
10
10
  import { Temporal } from "@js-temporal/polyfill";
11
+ import { Menu, MenuOption } from ".";
11
12
 
12
13
  export interface CalendarRangeProps {
13
14
  from?: string | number;
@@ -218,6 +219,19 @@ export function CalendarRange({
218
219
  };
219
220
  }
220
221
 
222
+ function getMonthDataWith(monthOffset: number) {
223
+ const monthDate = baseMonth.with({ month: monthOffset }).with({ day: 1 });
224
+ const days = monthDate.daysInMonth;
225
+ const firstDayOffset = monthDate.dayOfWeek % 7;
226
+ return {
227
+ name: monthDate.toLocaleString("en-US", { month: "long" }),
228
+ year: monthDate.year,
229
+ days,
230
+ firstDayOffset,
231
+ date: monthDate,
232
+ };
233
+ }
234
+
221
235
  // Click handlers
222
236
  function handleDayClick(date: Temporal.PlainDate) {
223
237
  if (isDateAvailable && !isDateAvailable(date)) return;
@@ -297,177 +311,314 @@ export function CalendarRange({
297
311
  )}
298
312
  >
299
313
  {(mode === "double" ? [0, 1] : [0]).map((offset, idx) => {
300
- const month = getMonthData(offset);
301
- // Always show 6 weeks (42 days)
302
- const totalCells = 42;
303
- const emptyCells = month.firstDayOffset;
304
314
  return (
305
- <React.Fragment key={month.name + month.year}>
306
- <div
307
- // key={month.name + month.year}
308
- className={clsx("flex flex-col")}
309
- >
310
- <div
311
- className={clsx(
312
- "flex flex-row items-center justify-between",
313
- typography.label,
314
- "text-text-action-primary-normal",
315
- )}
316
- >
317
- {idx === 0 ? (
318
- <button
319
- id={id ? `${id}-prev-month-button` : undefined}
320
- data-testid={
321
- testid ? `${testid}-prev-month-button` : undefined
322
- }
323
- type="button"
324
- className={clsx(
325
- "flex items-center justify-center rounded-base hover:bg-action-100 active:bg-action-300 text-icon-action-primary-normal",
326
- componentPadding,
327
- )}
328
- aria-label="Previous month"
329
- onClick={() =>
330
- setBaseMonth(baseMonth.subtract({ months: 1 }))
331
- }
332
- >
333
- <Icon name="chevron_left" size={24} />
334
- </button>
335
- ) : (
336
- <span className={clsx(componentPadding, "mr-1")} />
337
- )}
338
- <div className="flex gap-desktop-compact-component-padding">
339
- <span className="font-semibold text-text-action-primary-normal text-[14px] leading-[1] truncate">
340
- {month.name}
341
- </span>
342
- <span className="font-semibold text-text-action-primary-normal text-[14px] leading-[1] px-1 truncate">
343
- {month.year}
344
- </span>
345
- </div>
346
- {(mode === "double" ? idx === 1 : true) ? (
347
- <button
348
- id={id ? `${id}-next-month-button` : undefined}
349
- data-testid={
350
- testid ? `${testid}-next-month-button` : undefined
351
- }
352
- type="button"
353
- className={clsx(
354
- "flex items-center justify-center rounded-base hover:bg-action-100 active:bg-action-300 text-icon-action-primary-normal",
355
- componentPadding,
356
- )}
357
- aria-label="Next month"
358
- onClick={() => setBaseMonth(baseMonth.add({ months: 1 }))}
359
- >
360
- <Icon name="chevron_right" size={24} />
361
- </button>
362
- ) : (
363
- <span className={clsx(componentPadding, "ml-1")} />
364
- )}
365
- </div>
366
- <div className={clsx("grid grid-cols-7")}>
367
- {weekDays.map((d) => (
368
- <span
369
- key={d}
370
- className={clsx(
371
- typography.caption,
372
- "text-text-secondary-normal text-center",
373
- "w-10",
374
- )}
375
- >
376
- {d}
377
- </span>
378
- ))}
379
- </div>
380
- <div className={clsx("grid grid-cols-7")}>
381
- {Array.from({ length: totalCells }).map((_, i) => {
382
- const day = i - emptyCells + 1;
383
- const date = month.date.with({ day: 1 }).add({
384
- days: i - emptyCells,
385
- });
386
- const isInMonth = day > 0 && day <= month.days;
387
- const isToday = isInMonth && date.equals(today);
388
- const isSelected =
389
- isInMonth &&
390
- ((!pendingFrom && fromDate && date.equals(fromDate)) ||
391
- (!pendingFrom && toDate && date.equals(toDate)) ||
392
- (pendingFrom && date.equals(pendingFrom)));
393
- const inRange = isInMonth && isInRange(date);
394
- const isDisabled =
395
- !isInMonth ||
396
- (isDateAvailable ? !isDateAvailable(date) : false);
397
- // New: determine if this is the start or end of the range
315
+ <CalendarPane
316
+ key={idx}
317
+ getMonthData={getMonthData}
318
+ getMonthDataWith={getMonthDataWith}
319
+ offset={offset}
320
+ idx={idx}
321
+ id={id}
322
+ testid={testid}
323
+ baseMonth={baseMonth}
324
+ setBaseMonth={setBaseMonth}
325
+ mode={mode}
326
+ pendingFrom={pendingFrom}
327
+ weekDays={weekDays}
328
+ fromDate={fromDate}
329
+ toDate={toDate}
330
+ isDateAvailable={isDateAvailable}
331
+ disableRange={disableRange}
332
+ hoveredDate={hoveredDate}
333
+ isInRange={isInRange}
334
+ today={today}
335
+ setHoveredDate={setHoveredDate}
336
+ handleDayClick={handleDayClick}
337
+ />
338
+ );
339
+ })}
340
+ </div>
341
+ </div>
342
+ );
343
+ }
344
+ function CalendarPane({
345
+ getMonthData,
346
+ getMonthDataWith,
347
+ offset,
348
+ idx,
349
+ id,
350
+ testid,
351
+ baseMonth,
352
+ setBaseMonth,
353
+ mode,
354
+ pendingFrom,
355
+ weekDays,
356
+ fromDate,
357
+ toDate,
358
+ isDateAvailable,
359
+ disableRange,
360
+ hoveredDate,
361
+ isInRange,
362
+ today,
363
+ setHoveredDate,
364
+ handleDayClick,
365
+ }: {
366
+ getMonthData: (offset: number) => {
367
+ name: string;
368
+ year: number;
369
+ days: number;
370
+ firstDayOffset: number;
371
+ date: Temporal.PlainDate;
372
+ };
373
+ getMonthDataWith: (offset: number) => {
374
+ name: string;
375
+ year: number;
376
+ days: number;
377
+ firstDayOffset: number;
378
+ date: Temporal.PlainDate;
379
+ };
380
+ offset: number;
381
+ idx: number;
382
+ id: string | undefined;
383
+ testid: string | undefined;
384
+ baseMonth: Temporal.PlainDate;
385
+ setBaseMonth: (date: Temporal.PlainDate) => void;
386
+ mode: "single" | "range" | "double";
387
+ pendingFrom: Temporal.PlainDate | undefined;
388
+ weekDays: string[];
389
+ fromDate: Temporal.PlainDate | undefined;
390
+ toDate: Temporal.PlainDate | undefined;
391
+ isDateAvailable?: (date: Temporal.PlainDate) => boolean;
392
+ disableRange: boolean;
393
+ hoveredDate: Temporal.PlainDate | undefined;
394
+ isInRange: (date: Temporal.PlainDate) => boolean;
395
+ today: Temporal.PlainDate;
396
+ setHoveredDate: (date: Temporal.PlainDate | undefined) => void;
397
+ handleDayClick: (date: Temporal.PlainDate) => void;
398
+ }) {
399
+ const months = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
400
+ const years = Array.from({ length: 100 }).map(
401
+ (_, i) => baseMonth.year - 50 + i,
402
+ );
403
+ const [monthMenuOpen, setMonthMenuOpen] = useState(false);
404
+ const [yearMenuOpen, setYearMenuOpen] = useState(false);
398
405
 
399
- const hoverDateIsBeforePendingFrom =
400
- hoveredDate &&
401
- pendingFrom &&
402
- Temporal.PlainDate.compare(hoveredDate, pendingFrom) < 0;
406
+ const monthMenuRef = useRef<HTMLButtonElement | null>(null);
407
+ const yearMenuRef = useRef<HTMLButtonElement | null>(null);
408
+ const month = getMonthData(offset);
409
+ // Always show 6 weeks (42 days)
410
+ const totalCells = 42;
411
+ const emptyCells = month.firstDayOffset;
412
+ return (
413
+ <React.Fragment key={month.name + month.year}>
414
+ <div
415
+ // key={month.name + month.year}
416
+ className={clsx("flex flex-col")}
417
+ >
418
+ <div
419
+ className={clsx(
420
+ "flex flex-row items-center justify-between",
421
+ typography.label,
422
+ "text-text-action-primary-normal",
423
+ )}
424
+ >
425
+ {idx === 0 ? (
426
+ <button
427
+ id={id ? `${id}-prev-month-button` : undefined}
428
+ data-testid={testid ? `${testid}-prev-month-button` : undefined}
429
+ type="button"
430
+ className={clsx(
431
+ "flex items-center justify-center rounded-base hover:bg-action-100 active:bg-action-300 text-icon-action-primary-normal",
432
+ componentPadding,
433
+ )}
434
+ aria-label="Previous month"
435
+ onClick={() => setBaseMonth(baseMonth.subtract({ months: 1 }))}
436
+ >
437
+ <Icon name="chevron_left" size={24} />
438
+ </button>
439
+ ) : (
440
+ <span className={clsx(componentPadding, "mr-1")} />
441
+ )}
442
+ <div className="flex gap-desktop-compact-component-padding">
443
+ <button
444
+ ref={(el) => {
445
+ monthMenuRef.current = el;
446
+ }}
447
+ type="button"
448
+ onClick={() => {
449
+ setMonthMenuOpen(true);
450
+ setYearMenuOpen(false);
451
+ }}
452
+ className="font-semibold text-text-action-primary-normal text-[14px] py-[2px] truncate"
453
+ >
454
+ {month.name}
455
+ </button>
456
+ <Menu
457
+ show={monthMenuOpen}
458
+ positionTo={monthMenuRef}
459
+ setShow={() => setMonthMenuOpen(false)}
460
+ >
461
+ {months
462
+ .map((x) => [x, getMonthDataWith(x + 1)] as const)
463
+ .map(([x, m]) => (
464
+ <MenuOption
465
+ key={m.name}
466
+ selected={baseMonth.month === x + 1}
467
+ onClick={() => {
468
+ setBaseMonth(baseMonth.with({ month: x + 1 }));
469
+ setMonthMenuOpen(false);
470
+ }}
471
+ >
472
+ {m.name}
473
+ </MenuOption>
474
+ ))}
475
+ </Menu>
476
+ <button
477
+ ref={(el) => {
478
+ yearMenuRef.current = el;
479
+ }}
480
+ type="button"
481
+ onClick={() => {
482
+ setYearMenuOpen(true);
483
+ setMonthMenuOpen(false);
484
+ }}
485
+ className="font-semibold text-text-action-primary-normal text-[14px] py-[2px] truncate"
486
+ >
487
+ {month.year}
488
+ </button>
489
+ <Menu
490
+ show={yearMenuOpen}
491
+ positionTo={yearMenuRef}
492
+ setShow={() => setYearMenuOpen(false)}
493
+ >
494
+ {years.map((y) => (
495
+ <MenuOption
496
+ key={y}
497
+ selected={baseMonth.year === y}
498
+ onClick={() => {
499
+ setBaseMonth(baseMonth.with({ year: y }));
500
+ setYearMenuOpen(false);
501
+ }}
502
+ >
503
+ {y}
504
+ </MenuOption>
505
+ ))}
506
+ </Menu>
507
+ </div>
508
+ {(mode === "double" ? idx === 1 : true) ? (
509
+ <button
510
+ id={id ? `${id}-next-month-button` : undefined}
511
+ data-testid={testid ? `${testid}-next-month-button` : undefined}
512
+ type="button"
513
+ className={clsx(
514
+ "flex items-center justify-center rounded-base hover:bg-action-100 active:bg-action-300 text-icon-action-primary-normal",
515
+ componentPadding,
516
+ )}
517
+ aria-label="Next month"
518
+ onClick={() => setBaseMonth(baseMonth.add({ months: 1 }))}
519
+ >
520
+ <Icon name="chevron_right" size={24} />
521
+ </button>
522
+ ) : (
523
+ <span className={clsx(componentPadding, "ml-1")} />
524
+ )}
525
+ </div>
526
+ <div className={clsx("grid grid-cols-7")}>
527
+ {weekDays.map((d) => (
528
+ <span
529
+ key={d}
530
+ className={clsx(
531
+ typography.caption,
532
+ "text-text-secondary-normal text-center",
533
+ "w-10",
534
+ )}
535
+ >
536
+ {d}
537
+ </span>
538
+ ))}
539
+ </div>
540
+ <div className={clsx("grid grid-cols-7")}>
541
+ {Array.from({ length: totalCells }).map((_, i) => {
542
+ const day = i - emptyCells + 1;
543
+ const date = month.date.with({ day: 1 }).add({
544
+ days: i - emptyCells,
545
+ });
546
+ const isInMonth = day > 0 && day <= month.days;
547
+ const isToday = isInMonth && date.equals(today);
548
+ const isSelected =
549
+ isInMonth &&
550
+ ((!pendingFrom && fromDate && date.equals(fromDate)) ||
551
+ (!pendingFrom && toDate && date.equals(toDate)) ||
552
+ (pendingFrom && date.equals(pendingFrom)));
553
+ const inRange = isInMonth && isInRange(date);
554
+ const isDisabled =
555
+ !isInMonth || (isDateAvailable ? !isDateAvailable(date) : false);
556
+ // New: determine if this is the start or end of the range
403
557
 
404
- const hoverDateIsAfterPendingFrom =
405
- hoveredDate &&
406
- pendingFrom &&
407
- Temporal.PlainDate.compare(hoveredDate, pendingFrom) >= 0;
558
+ const hoverDateIsBeforePendingFrom =
559
+ hoveredDate &&
560
+ pendingFrom &&
561
+ Temporal.PlainDate.compare(hoveredDate, pendingFrom) < 0;
408
562
 
409
- const isRangeStart =
410
- mode === "single" && disableRange
411
- ? false
412
- : (!pendingFrom &&
413
- isInMonth &&
414
- fromDate &&
415
- date.equals(fromDate)) ||
416
- (hoverDateIsAfterPendingFrom &&
417
- date.equals(pendingFrom));
563
+ const hoverDateIsAfterPendingFrom =
564
+ hoveredDate &&
565
+ pendingFrom &&
566
+ Temporal.PlainDate.compare(hoveredDate, pendingFrom) >= 0;
418
567
 
419
- const isRangeEnd =
420
- mode === "single" && disableRange
421
- ? false
422
- : (!pendingFrom &&
423
- isInMonth &&
424
- toDate &&
425
- date.equals(toDate)) ||
426
- (hoverDateIsBeforePendingFrom &&
427
- date.equals(pendingFrom));
428
- return (
429
- <DateCell
430
- key={i}
431
- id={id ? `${id}-date-${date.toString()}` : undefined}
432
- testid={
433
- testid
434
- ? `${testid}-date-${date.toString()}`
435
- : undefined
436
- }
437
- date={date}
438
- isInMonth={!!isInMonth}
439
- isToday={!!isToday}
440
- isSelected={!!isSelected}
441
- inRange={!!inRange}
442
- isDisabled={!!isDisabled}
443
- onClick={() => handleDayClick(date)}
444
- onMouseEnter={() => setHoveredDate(date)}
445
- onMouseLeave={() => setHoveredDate(undefined)}
446
- isRangeStart={!!isRangeStart}
447
- isRangeEnd={!!isRangeEnd}
448
- isRangeDisabled={mode === "single" && disableRange}
449
- // Add cell padding for spacing
450
- cellPadding={componentPadding}
451
- />
452
- );
453
- })}
454
- </div>
455
- </div>
456
- {mode === "double" && idx === 0 && (
457
- <div
458
- className={clsx(
459
- "self-stretch bg-border-primary-normal rounded-base",
568
+ const isRangeStart =
569
+ mode === "single" && disableRange
570
+ ? false
571
+ : (!pendingFrom &&
572
+ isInMonth &&
573
+ fromDate &&
574
+ date.equals(fromDate)) ||
575
+ (hoverDateIsAfterPendingFrom && date.equals(pendingFrom));
460
576
 
461
- // 1px width, full height, matches Figma divider
462
- "w-px",
463
- )}
464
- />
465
- )}
466
- </React.Fragment>
467
- );
468
- })}
577
+ const isRangeEnd =
578
+ mode === "single" && disableRange
579
+ ? false
580
+ : (!pendingFrom &&
581
+ isInMonth &&
582
+ toDate &&
583
+ date.equals(toDate)) ||
584
+ (hoverDateIsBeforePendingFrom && date.equals(pendingFrom));
585
+ return (
586
+ <DateCell
587
+ key={i}
588
+ id={id ? `${id}-date-${date.toString()}` : undefined}
589
+ testid={
590
+ testid ? `${testid}-date-${date.toString()}` : undefined
591
+ }
592
+ date={date}
593
+ isInMonth={!!isInMonth}
594
+ isToday={!!isToday}
595
+ isSelected={!!isSelected}
596
+ inRange={!!inRange}
597
+ isDisabled={!!isDisabled}
598
+ onClick={() => handleDayClick(date)}
599
+ onMouseEnter={() => setHoveredDate(date)}
600
+ onMouseLeave={() => setHoveredDate(undefined)}
601
+ isRangeStart={!!isRangeStart}
602
+ isRangeEnd={!!isRangeEnd}
603
+ isRangeDisabled={mode === "single" && disableRange}
604
+ // Add cell padding for spacing
605
+ cellPadding={componentPadding}
606
+ />
607
+ );
608
+ })}
609
+ </div>
469
610
  </div>
470
- </div>
611
+ {mode === "double" && idx === 0 && (
612
+ <div
613
+ className={clsx(
614
+ "self-stretch bg-border-primary-normal rounded-base",
615
+
616
+ // 1px width, full height, matches Figma divider
617
+ "w-px",
618
+ )}
619
+ />
620
+ )}
621
+ </React.Fragment>
471
622
  );
472
623
  }
473
624