Add DateRangePicker component with segmented entry and calendar popup
Django CI/CD / test (push) Successful in 2m33s
Django CI/CD / build-and-push (push) Successful in 1m17s

Implements the DateRangePicker design: a DateRangeField that looks like a
single input but splits each date into DD/MM/YYYY part inputs (ordered by
the new common.time.dateformat_hyphenated), and a DateRangeCalendar popup
with a preset column (today, yesterday, last 7/30 days, this/last month,
this year), anchor-style range picking with an outlined/filled/muted range
track, and a Cancel / Clear / Select footer.

Typing fills each part's placeholder from the right (YYYY -> YY19 -> 1987),
auto-advances between parts, and Backspace/Delete reverts the active part.
The committed value lives in hidden ISO {prefix}-min/{prefix}-max inputs --
the same contract as DateRangeFilter, so filter_bar.js needs no changes.

As a tryout, the Purchased filter in PurchaseFilterBar now uses the
DateRangePicker; Refunded keeps the native-date DateRangeFilter, and the
native-path e2e tests were repointed at it.

Includes unit tests for the component family and the filter-bar
integration, plus Playwright e2e tests for segment entry, calendar
picking, presets, and footer actions.

https://claude.ai/code/session_017b75KJAu4kNNpZPu9NAPBM
This commit is contained in:
Claude
2026-06-11 17:49:22 +00:00
committed by Lukáš Kucharczyk
parent 15a97dee9a
commit 0fa860c237
10 changed files with 1552 additions and 11 deletions
+95
View File
@@ -918,6 +918,9 @@
.ms-2\.5 {
margin-inline-start: calc(var(--spacing) * 2.5);
}
.ms-auto {
margin-inline-start: auto;
}
.me-2 {
margin-inline-end: calc(var(--spacing) * 2);
}
@@ -1582,6 +1585,9 @@
.w-5\/6 {
width: calc(5 / 6 * 100%);
}
.w-8 {
width: calc(var(--spacing) * 8);
}
.w-10 {
width: calc(var(--spacing) * 10);
}
@@ -1597,6 +1603,12 @@
.w-72 {
width: calc(var(--spacing) * 72);
}
.w-\[2\.5ch\] {
width: 2.5ch;
}
.w-\[4\.5ch\] {
width: 4.5ch;
}
.w-\[300px\] {
width: 300px;
}
@@ -1736,6 +1748,9 @@
.cursor-pointer {
cursor: pointer;
}
.cursor-text {
cursor: text;
}
.resize {
resize: both;
}
@@ -1787,6 +1802,9 @@
.justify-start {
justify-content: flex-start;
}
.gap-0\.5 {
gap: calc(var(--spacing) * 0.5);
}
.gap-1 {
gap: calc(var(--spacing) * 1);
}
@@ -1836,6 +1854,9 @@
margin-inline-end: calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-x-reverse)));
}
}
.gap-y-0\.5 {
row-gap: calc(var(--spacing) * 0.5);
}
.gap-y-4 {
row-gap: calc(var(--spacing) * 4);
}
@@ -1904,6 +1925,9 @@
.rounded-xl {
border-radius: var(--radius-xl);
}
.rounded-xs {
border-radius: var(--radius-xs);
}
.rounded-s-base {
border-start-start-radius: var(--radius-base);
border-end-start-radius: var(--radius-base);
@@ -1958,6 +1982,10 @@
border-style: var(--tw-border-style);
border-width: 2px;
}
.border-y {
border-block-style: var(--tw-border-style);
border-block-width: 1px;
}
.border-e {
border-inline-end-style: var(--tw-border-style);
border-inline-end-width: 1px;
@@ -2030,6 +2058,12 @@
.border-brand {
border-color: var(--color-brand);
}
.border-brand\/70 {
border-color: color-mix(in srgb, oklch(48.8% 0.243 264.376) 70%, transparent);
@supports (color: color-mix(in lab, red, red)) {
border-color: color-mix(in oklab, var(--color-brand) 70%, transparent);
}
}
.border-default {
border-color: var(--color-default);
}
@@ -2121,12 +2155,24 @@
.bg-brand {
background-color: var(--color-brand);
}
.bg-brand\/10 {
background-color: color-mix(in srgb, oklch(48.8% 0.243 264.376) 10%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-brand) 10%, transparent);
}
}
.bg-brand\/15 {
background-color: color-mix(in srgb, oklch(48.8% 0.243 264.376) 15%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-brand) 15%, transparent);
}
}
.bg-brand\/30 {
background-color: color-mix(in srgb, oklch(48.8% 0.243 264.376) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-brand) 30%, transparent);
}
}
.bg-dark-backdrop\/70 {
background-color: color-mix(in srgb, oklch(13% 0.028 261.692) 70%, transparent);
@supports (color: color-mix(in lab, red, red)) {
@@ -2296,6 +2342,9 @@
padding: 0 !important;
}
}
.p-0 {
padding: calc(var(--spacing) * 0);
}
.p-1 {
padding: calc(var(--spacing) * 1);
}
@@ -2320,6 +2369,9 @@
.p-6 {
padding: calc(var(--spacing) * 6);
}
.px-0\.5 {
padding-inline: calc(var(--spacing) * 0.5);
}
.px-2 {
padding-inline: calc(var(--spacing) * 2);
}
@@ -2419,6 +2471,9 @@
.text-right {
text-align: right;
}
.text-start {
text-align: start;
}
.align-middle {
vertical-align: middle;
}
@@ -2714,9 +2769,15 @@
.decoration-dotted {
text-decoration-style: dotted;
}
.caret-transparent {
caret-color: transparent;
}
.opacity-0 {
opacity: 0%;
}
.opacity-40 {
opacity: 40%;
}
.opacity-50 {
opacity: 50%;
}
@@ -2752,6 +2813,13 @@
--tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.ring-2 {
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.ring-brand-strong {
--tw-ring-color: var(--color-brand-strong);
}
.outline {
outline-style: var(--tw-outline-style);
outline-width: 1px;
@@ -2817,6 +2885,9 @@
.\[program\:qcluster\] {
program: qcluster;
}
.ring-inset {
--tw-ring-inset: inset;
}
.group-hover\:absolute {
&:is(:where(.group):hover *) {
@media (hover: hover) {
@@ -2958,6 +3029,22 @@
padding-top: calc(var(--spacing) * 0);
}
}
.focus-within\:border-brand {
&:focus-within {
border-color: var(--color-brand);
}
}
.focus-within\:ring-1 {
&:focus-within {
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
}
.focus-within\:ring-brand {
&:focus-within {
--tw-ring-color: var(--color-brand);
}
}
.hover\:scale-110 {
&:hover {
@media (hover: hover) {
@@ -3223,6 +3310,14 @@
border-color: var(--color-brand);
}
}
.focus\:bg-brand\/30 {
&:focus {
background-color: color-mix(in srgb, oklch(48.8% 0.243 264.376) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-brand) 30%, transparent);
}
}
}
.focus\:text-blue-700 {
&:focus {
color: var(--color-blue-700);