@carlonicora/nextjs-jsonapi 3.3.4 → 3.3.6
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/{BlockNoteEditor-ZNEXXORX.mjs → BlockNoteEditor-BYMRWUVG.mjs} +2 -2
- package/dist/{BlockNoteEditor-J4TQJSHZ.js → BlockNoteEditor-USRMFZGP.js} +9 -9
- package/dist/{BlockNoteEditor-J4TQJSHZ.js.map → BlockNoteEditor-USRMFZGP.js.map} +1 -1
- package/dist/billing/index.js +333 -333
- package/dist/billing/index.mjs +1 -1
- package/dist/{chunk-KCZ6SPUQ.js → chunk-5WFYQE22.js} +234 -233
- package/dist/chunk-5WFYQE22.js.map +1 -0
- package/dist/{chunk-GCE4C7FG.mjs → chunk-CFZW6GU4.mjs} +14 -13
- package/dist/chunk-CFZW6GU4.mjs.map +1 -0
- package/dist/client/index.js +2 -2
- package/dist/client/index.mjs +1 -1
- package/dist/components/index.d.mts +39 -3
- package/dist/components/index.d.ts +39 -3
- package/dist/components/index.js +4 -2
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +3 -1
- package/dist/contexts/index.js +2 -2
- package/dist/contexts/index.mjs +1 -1
- package/dist/features/help/index.js +31 -31
- package/dist/features/help/index.mjs +1 -1
- package/dist/features/tokenusage/index.js +75 -75
- package/dist/features/tokenusage/index.mjs +1 -1
- package/package.json +1 -1
- package/src/components/forms/DatePickerPopover.tsx +31 -3
- package/src/components/forms/DateRangeSelector.tsx +36 -12
- package/src/components/forms/__tests__/DateRangeSelector.spec.ts +74 -0
- package/dist/chunk-GCE4C7FG.mjs.map +0 -1
- package/dist/chunk-KCZ6SPUQ.js.map +0 -1
- /package/dist/{BlockNoteEditor-ZNEXXORX.mjs.map → BlockNoteEditor-BYMRWUVG.mjs.map} +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { isValid, parse } from "date-fns";
|
|
4
4
|
import { Calendar as CalendarIcon, CircleXIcon } from "lucide-react";
|
|
5
|
-
import {
|
|
5
|
+
import { ReactElement, useMemo, useState } from "react";
|
|
6
6
|
import { useI18nDateFnsLocale, useI18nLocale } from "../../i18n";
|
|
7
7
|
import {
|
|
8
8
|
Calendar,
|
|
@@ -19,7 +19,19 @@ import {
|
|
|
19
19
|
import { cn } from "../../utils";
|
|
20
20
|
|
|
21
21
|
type DatePickerPopoverProps = {
|
|
22
|
-
|
|
22
|
+
/** MUST be a single element — it becomes the trigger element itself (see `render` below). */
|
|
23
|
+
children: ReactElement;
|
|
24
|
+
/**
|
|
25
|
+
* Whether the element passed as `children` is a real <button>.
|
|
26
|
+
*
|
|
27
|
+
* Base UI's trigger assumes it renders a native button. When `render` swaps
|
|
28
|
+
* in something else (a table cell's <div> wrapper), that assumption is wrong:
|
|
29
|
+
* native button semantics are lost and Base UI warns on every mount. Passing
|
|
30
|
+
* `false` makes it apply role="button" plus the keyboard handling itself, so
|
|
31
|
+
* a non-button trigger stays operable and accessible.
|
|
32
|
+
*/
|
|
33
|
+
nativeButton?: boolean;
|
|
34
|
+
|
|
23
35
|
value?: Date;
|
|
24
36
|
onSelect: (date?: Date) => void;
|
|
25
37
|
minDate?: Date;
|
|
@@ -29,6 +41,7 @@ type DatePickerPopoverProps = {
|
|
|
29
41
|
|
|
30
42
|
export const DatePickerPopover = ({
|
|
31
43
|
children,
|
|
44
|
+
nativeButton = true,
|
|
32
45
|
value,
|
|
33
46
|
onSelect,
|
|
34
47
|
minDate,
|
|
@@ -126,7 +139,22 @@ export const DatePickerPopover = ({
|
|
|
126
139
|
|
|
127
140
|
return (
|
|
128
141
|
<Popover open={isOpen} onOpenChange={setIsOpen}>
|
|
129
|
-
|
|
142
|
+
{/*
|
|
143
|
+
`render`, NOT `<PopoverTrigger>{children}</PopoverTrigger>`. Base UI's
|
|
144
|
+
Popover.Trigger otherwise renders its OWN <button> WRAPPING the child
|
|
145
|
+
and binds the open handler to that button. Two consequences, both real:
|
|
146
|
+
- Table callers pass a cell wrapper whose onClick calls
|
|
147
|
+
stopPropagation() (so clicking the cell does not trigger the row's
|
|
148
|
+
navigation). Being the deeper element, its handler runs FIRST, the
|
|
149
|
+
click never bubbles to Base UI's button, and the popover could never
|
|
150
|
+
open — for mouse users as much as for tests.
|
|
151
|
+
- Form callers pass a <Button>, which the wrapper turned into a
|
|
152
|
+
<button> inside a <button>: invalid HTML and a hydration error.
|
|
153
|
+
With `render` the child IS the trigger, so the handlers share one
|
|
154
|
+
element (stopPropagation stops ANCESTOR propagation, not other handlers
|
|
155
|
+
on the same node) and no nested button is produced.
|
|
156
|
+
*/}
|
|
157
|
+
<PopoverTrigger nativeButton={nativeButton} render={children} />
|
|
130
158
|
<PopoverContent className={cn("p-0", className)} align={align} onClick={(e) => e.stopPropagation()}>
|
|
131
159
|
<div className="p-3">
|
|
132
160
|
{/* Manual Input */}
|
|
@@ -9,6 +9,39 @@ import { useI18nDateFnsLocale } from "../../i18n";
|
|
|
9
9
|
import { Button, Calendar, Popover, PopoverContent, PopoverTrigger } from "../../shadcnui";
|
|
10
10
|
import { cn } from "../../utils";
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Decides the range to hold after react-day-picker reports a selection.
|
|
14
|
+
*
|
|
15
|
+
* react-day-picker's `addToRange` NEVER moves `from` when the current range is
|
|
16
|
+
* already COMPLETE and the clicked day falls after it — it returns
|
|
17
|
+
* `{ from, to: clickedDay }` (see its `from && to` branch). So "did `from`
|
|
18
|
+
* change?" cannot distinguish "the user is starting a new range" from "the user
|
|
19
|
+
* moved the end": it is true only for a click BEFORE `from`.
|
|
20
|
+
*
|
|
21
|
+
* That is the asymmetry this component shipped with. Its default range is the
|
|
22
|
+
* whole CURRENT month, so clicking any day in the current month landed after
|
|
23
|
+
* `from` and silently became the END date — the start could never be moved
|
|
24
|
+
* forward — while clicking a day in a PAST month fell before `from`, changed it,
|
|
25
|
+
* and appeared to work.
|
|
26
|
+
*
|
|
27
|
+
* A click on a complete range therefore starts a NEW range at the clicked day,
|
|
28
|
+
* which is the conventional range-picker behaviour. `triggerDate` is the day
|
|
29
|
+
* react-day-picker reports as the one that was clicked (`onSelect`'s second
|
|
30
|
+
* argument) — the only reliable source for it, since the computed range hides it.
|
|
31
|
+
*/
|
|
32
|
+
export function nextDateRange(params: {
|
|
33
|
+
current: DateRange | undefined;
|
|
34
|
+
computed: DateRange | undefined;
|
|
35
|
+
triggerDate: Date;
|
|
36
|
+
}): DateRange | undefined {
|
|
37
|
+
const { current, computed, triggerDate } = params;
|
|
38
|
+
// react-day-picker returns undefined to DESELECT (clicking the only selected
|
|
39
|
+
// day of a single-day range). Honour that before anything else.
|
|
40
|
+
if (!computed) return undefined;
|
|
41
|
+
if (current?.from && current?.to) return { from: triggerDate, to: undefined };
|
|
42
|
+
return computed;
|
|
43
|
+
}
|
|
44
|
+
|
|
12
45
|
type DateRangeSelectorProps = {
|
|
13
46
|
onDateChange: (date?: DateRange) => void;
|
|
14
47
|
avoidSettingDates?: boolean;
|
|
@@ -49,18 +82,9 @@ export function DateRangeSelector({ onDateChange, avoidSettingDates, showPreviou
|
|
|
49
82
|
}
|
|
50
83
|
}, [date, prevRange, onDateChange]);
|
|
51
84
|
|
|
52
|
-
//
|
|
53
|
-
const handleSelect = (range: DateRange | undefined) => {
|
|
54
|
-
|
|
55
|
-
setDate(undefined);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
// If a new start date is picked, reset end date
|
|
59
|
-
if (range.from && (!date?.from || range.from.getTime() !== date.from.getTime())) {
|
|
60
|
-
setDate({ from: range.from, to: undefined });
|
|
61
|
-
} else {
|
|
62
|
-
setDate(range);
|
|
63
|
-
}
|
|
85
|
+
// A click on an already-complete range starts a new one — see nextDateRange().
|
|
86
|
+
const handleSelect = (range: DateRange | undefined, triggerDate: Date) => {
|
|
87
|
+
setDate(nextDateRange({ current: date, computed: range, triggerDate }));
|
|
64
88
|
};
|
|
65
89
|
|
|
66
90
|
// Show placeholder button during SSR to prevent hydration mismatch
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { nextDateRange } from "../DateRangeSelector";
|
|
3
|
+
|
|
4
|
+
// The dates below mirror the component's own default range: the whole current
|
|
5
|
+
// month. "Today" is irrelevant to nextDateRange() — only the shape of the range
|
|
6
|
+
// matters — so fixed dates are used rather than a faked clock.
|
|
7
|
+
const AUG_1 = new Date(2026, 7, 1);
|
|
8
|
+
const AUG_10 = new Date(2026, 7, 10);
|
|
9
|
+
const AUG_20 = new Date(2026, 7, 20);
|
|
10
|
+
const AUG_31 = new Date(2026, 7, 31);
|
|
11
|
+
const JUL_10 = new Date(2026, 6, 10);
|
|
12
|
+
|
|
13
|
+
const CURRENT_MONTH = { from: AUG_1, to: AUG_31 };
|
|
14
|
+
|
|
15
|
+
describe("nextDateRange", () => {
|
|
16
|
+
// The reported bug: with the default (complete) current-month range, every
|
|
17
|
+
// click in the current month lands AFTER `from`, so react-day-picker returns
|
|
18
|
+
// { from: AUG_1, to: clicked } and `from` never moves. The selector must read
|
|
19
|
+
// that as "start a new range at the clicked day", not "move the end".
|
|
20
|
+
it("starts a new range when a complete range is clicked inside the current month", () => {
|
|
21
|
+
expect(
|
|
22
|
+
nextDateRange({
|
|
23
|
+
current: CURRENT_MONTH,
|
|
24
|
+
computed: { from: AUG_1, to: AUG_10 }, // what addToRange returns
|
|
25
|
+
triggerDate: AUG_10,
|
|
26
|
+
}),
|
|
27
|
+
).toEqual({ from: AUG_10, to: undefined });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// The half that always worked, and which must keep working: a click BEFORE
|
|
31
|
+
// `from` does move `from`, so react-day-picker returns { from: clicked, to }.
|
|
32
|
+
// Same outcome either way — the clicked day becomes the new start.
|
|
33
|
+
it("starts a new range when a complete range is clicked in a past month", () => {
|
|
34
|
+
expect(
|
|
35
|
+
nextDateRange({
|
|
36
|
+
current: CURRENT_MONTH,
|
|
37
|
+
computed: { from: JUL_10, to: AUG_31 },
|
|
38
|
+
triggerDate: JUL_10,
|
|
39
|
+
}),
|
|
40
|
+
).toEqual({ from: JUL_10, to: undefined });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("completes an in-progress range with the second click", () => {
|
|
44
|
+
expect(
|
|
45
|
+
nextDateRange({
|
|
46
|
+
current: { from: AUG_10, to: undefined },
|
|
47
|
+
computed: { from: AUG_10, to: AUG_20 },
|
|
48
|
+
triggerDate: AUG_20,
|
|
49
|
+
}),
|
|
50
|
+
).toEqual({ from: AUG_10, to: AUG_20 });
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("keeps react-day-picker's swap when the second click precedes the start", () => {
|
|
54
|
+
expect(
|
|
55
|
+
nextDateRange({
|
|
56
|
+
current: { from: AUG_20, to: undefined },
|
|
57
|
+
computed: { from: AUG_10, to: AUG_20 },
|
|
58
|
+
triggerDate: AUG_10,
|
|
59
|
+
}),
|
|
60
|
+
).toEqual({ from: AUG_10, to: AUG_20 });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("opens a range from the empty state", () => {
|
|
64
|
+
expect(
|
|
65
|
+
nextDateRange({ current: undefined, computed: { from: AUG_10, to: AUG_10 }, triggerDate: AUG_10 }),
|
|
66
|
+
).toEqual({ from: AUG_10, to: AUG_10 });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// react-day-picker returns undefined to DESELECT; that must survive the
|
|
70
|
+
// complete-range branch rather than being turned into a new start.
|
|
71
|
+
it("clears when react-day-picker deselects", () => {
|
|
72
|
+
expect(nextDateRange({ current: { from: AUG_10, to: AUG_10 }, computed: undefined, triggerDate: AUG_10 })).toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
});
|