minka-ds 0.3.9 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minka-ds",
3
- "version": "0.3.9",
3
+ "version": "0.3.11",
4
4
  "description": "Minka product design system — tokenized component library",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -29,14 +29,37 @@ export function DateTimeRangePicker({
29
29
  const range: DateRange | undefined =
30
30
  value?.from ? { from: value.from, to: value.to } : undefined
31
31
 
32
- function handleRangeSelect(selected: DateRange | undefined) {
33
- if (!selected?.from) { onChange(null); return }
34
- onChange({
35
- from: selected.from,
36
- to: selected.to ?? selected.from,
37
- startTime: value?.startTime ?? "",
38
- endTime: value?.endTime ?? "",
39
- })
32
+ // `anchor` is the source of truth for selection phase:
33
+ // anchor === null → no active pick (nothing selected, or a complete range)
34
+ // anchor !== null → first date is set, waiting for the second click
35
+ // This avoids the ambiguity of inferring phase from `from === to`.
36
+ const [anchor, setAnchor] = React.useState<Date | null>(null)
37
+
38
+ function handleDay(day: Date) {
39
+ const startTime = value?.startTime ?? ""
40
+ const endTime = value?.endTime ?? ""
41
+
42
+ // Picking the second date.
43
+ if (anchor) {
44
+ const spanMs = Math.abs(day.getTime() - anchor.getTime())
45
+ const withinCap = maxRangeDays == null || spanMs <= maxRangeDays * 86_400_000
46
+ if (withinCap) {
47
+ // Complete the range (order endpoints; can extend backward or forward).
48
+ const from = day < anchor ? day : anchor
49
+ const to = day < anchor ? anchor : day
50
+ setAnchor(null)
51
+ onChange({ from, to, startTime, endTime })
52
+ } else {
53
+ // Outside the cap → treat as a fresh start anchored on the clicked day.
54
+ setAnchor(day)
55
+ onChange({ from: day, to: day, startTime, endTime })
56
+ }
57
+ return
58
+ }
59
+
60
+ // No active pick (fresh, or restarting from a complete range).
61
+ setAnchor(day)
62
+ onChange({ from: day, to: day, startTime, endTime })
40
63
  }
41
64
 
42
65
  function handleStartTime(e: React.ChangeEvent<HTMLInputElement>) {
@@ -49,11 +72,6 @@ export function DateTimeRangePicker({
49
72
  onChange({ ...value, endTime: e.target.value })
50
73
  }
51
74
 
52
- const disabledAfter =
53
- maxRangeDays && range?.from
54
- ? { after: new Date(range.from.getTime() + maxRangeDays * 86_400_000) }
55
- : undefined
56
-
57
75
  return (
58
76
  <div className={cn(
59
77
  "[border-radius:var(--radius-card)] border border-[var(--color-border-default)] bg-[var(--color-bg-raised)] overflow-hidden w-fit",
@@ -64,8 +82,17 @@ export function DateTimeRangePicker({
64
82
  numberOfMonths={1}
65
83
  captionLayout="label"
66
84
  selected={range}
67
- onSelect={handleRangeSelect}
68
- disabled={disabledAfter}
85
+ onSelect={(_, selectedDay) => handleDay(selectedDay)}
86
+ // While picking the second date, soften days outside the ±maxRangeDays
87
+ // window — a visual hint of the recommended span. They stay clickable
88
+ // (clicking one re-anchors) and hover still works; this is a hint, not
89
+ // a block.
90
+ modifiers={
91
+ anchor && maxRangeDays != null
92
+ ? { outOfRange: (d: Date) => Math.abs(d.getTime() - anchor.getTime()) > maxRangeDays * 86_400_000 }
93
+ : undefined
94
+ }
95
+ modifiersClassNames={{ outOfRange: "text-[var(--color-text-hint)]" }}
69
96
  />
70
97
  <div className="border-t border-[var(--color-border-default)] px-4 py-3 flex flex-col gap-3">
71
98
  <div className="flex flex-col gap-1.5">