@lekoala/date-picker 0.3.0 → 0.5.0

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 (41) hide show
  1. package/README.md +281 -263
  2. package/custom-elements.json +30 -0
  3. package/dist/date-picker.css +51 -46
  4. package/dist/date-picker.js +685 -204
  5. package/dist/date-picker.min.css +1 -1
  6. package/dist/date-picker.min.js +13 -13
  7. package/dist/date-picker.standalone.min.js +65 -60
  8. package/dist/types/control-classes.d.ts +30 -0
  9. package/dist/types/control-classes.d.ts.map +1 -0
  10. package/dist/types/date-calendar.d.ts +49 -3
  11. package/dist/types/date-calendar.d.ts.map +1 -1
  12. package/dist/types/date-field.d.ts +12 -4
  13. package/dist/types/date-field.d.ts.map +1 -1
  14. package/dist/types/date-picker.d.ts +106 -9
  15. package/dist/types/date-picker.d.ts.map +1 -1
  16. package/dist/types/date-range.d.ts +102 -20
  17. package/dist/types/date-range.d.ts.map +1 -1
  18. package/dist/types/date.d.ts +14 -2
  19. package/dist/types/date.d.ts.map +1 -1
  20. package/dist/types/index.d.ts +1 -0
  21. package/dist/types/index.d.ts.map +1 -1
  22. package/dist/types/intl.d.ts.map +1 -1
  23. package/dist/types/source.d.ts +1 -0
  24. package/dist/types/source.d.ts.map +1 -1
  25. package/docs/ACCESSIBILITY.md +6 -2
  26. package/docs/API.md +430 -358
  27. package/docs/DECISIONS.md +68 -49
  28. package/docs/MIGRATION-FLATPICKR.md +1 -1
  29. package/docs/TESTING.md +1 -1
  30. package/docs/USE_CASES.md +156 -141
  31. package/package.json +8 -8
  32. package/src/control-classes.js +50 -0
  33. package/src/date-calendar.js +188 -54
  34. package/src/date-field.js +9 -5
  35. package/src/date-picker.css +51 -46
  36. package/src/date-picker.js +392 -83
  37. package/src/date-range.js +184 -30
  38. package/src/date.js +57 -3
  39. package/src/index.js +1 -0
  40. package/src/intl.js +52 -17
  41. package/src/source.js +14 -4
@@ -6,6 +6,8 @@
6
6
  --dp-hover: color-mix(in srgb, var(--dp-fg) 5%, var(--dp-bg));
7
7
  --dp-accent: #2563eb;
8
8
  --dp-accent-fg: #fff;
9
+ --dp-focus: var(--dp-accent);
10
+ --dp-focus-width: 2px;
9
11
  --dp-radius: 0.5rem;
10
12
  --dp-day-size: 2.75rem;
11
13
  --dp-gap: 0.375rem;
@@ -44,7 +46,7 @@ date-calendar {
44
46
 
45
47
  .dp-calendar-header {
46
48
  display: grid;
47
- grid-template-columns: minmax(0, 1fr) auto auto auto;
49
+ grid-template-columns: minmax(0, 1fr) var(--dp-year-inline-size) auto auto;
48
50
  /* Stretch (not center): once a UA natural height exceeds
49
51
  --dp-header-control-size, the row grows to the tallest control and the
50
52
  others stretch to match, so month/year/nav stay equal. */
@@ -60,12 +62,16 @@ date-calendar {
60
62
  track stays under the month select so the fixed-width year input never
61
63
  stretches. Visual mirroring itself is left to the inherited `dir`. */
62
64
  date-calendar[data-year-first] .dp-calendar-header {
63
- grid-template-columns: auto minmax(0, 1fr) auto auto;
65
+ grid-template-columns: var(--dp-year-inline-size) minmax(0, 1fr) auto auto;
64
66
  }
65
67
 
66
68
  .dp-calendar-header :where(button, select, input) {
67
- min-block-size: var(--dp-header-control-size);
68
69
  box-sizing: border-box;
70
+ min-inline-size: 0;
71
+ }
72
+
73
+ .dp-calendar-header .dp-skin {
74
+ min-block-size: var(--dp-header-control-size);
69
75
  /* Shared vertical metrics: UA default padding/line-height differ per control
70
76
  (up to ~13px apart), which only shows once --dp-header-control-size drops
71
77
  below content size. */
@@ -78,8 +84,7 @@ date-calendar[data-year-first] .dp-calendar-header {
78
84
  line-height: 1.2;
79
85
  }
80
86
 
81
- .dp-calendar-header input {
82
- min-inline-size: 0;
87
+ .dp-calendar-header input.dp-skin {
83
88
  padding-inline: 0.45rem;
84
89
  }
85
90
 
@@ -89,11 +94,13 @@ date-calendar[data-year-first] .dp-calendar-header {
89
94
  control and the others stretch to match. */
90
95
  .dp-month-select {
91
96
  inline-size: 100%;
92
- min-inline-size: 0;
93
97
  /* Long month names in a narrow track (compact consumers, long locales)
94
98
  would paint under the caret: truncate with an ellipsis instead. */
95
99
  overflow: hidden;
96
100
  text-overflow: ellipsis;
101
+ }
102
+
103
+ .dp-month-select.dp-skin {
97
104
  appearance: none;
98
105
  padding-inline: 0.45rem 2rem;
99
106
  background-image:
@@ -109,18 +116,18 @@ date-calendar[data-year-first] .dp-calendar-header {
109
116
  /* Inherited RTL mirrors the header layout via the grid. The logical
110
117
  `padding-inline` already flips, so only the physically-positioned caret has
111
118
  to follow it to the other side. */
112
- [dir="rtl"] .dp-month-select,
113
- html[dir="rtl"] .dp-month-select {
119
+ [dir="rtl"] .dp-month-select.dp-skin,
120
+ html[dir="rtl"] .dp-month-select.dp-skin {
114
121
  background-position:
115
122
  0.9rem 50%,
116
123
  0.65rem 50%;
117
124
  }
118
125
 
119
126
  .dp-year-input {
120
- inline-size: var(--dp-year-inline-size);
127
+ inline-size: 100%;
121
128
  }
122
129
 
123
- .dp-nav {
130
+ .dp-nav.dp-skin {
124
131
  display: grid;
125
132
  place-items: center;
126
133
  inline-size: var(--dp-header-control-size);
@@ -137,30 +144,23 @@ html[dir="rtl"] .dp-month-select {
137
144
  pointer-events: none;
138
145
  }
139
146
 
140
- /* Inherited RTL mirrors the header layout via the grid; mirror the nav glyphs
141
- so previous/next keep their visual sense. Actions stay chronological: no
142
- button swap, no keyboard remapping. */
143
- [dir="rtl"] .dp-nav svg,
144
- html[dir="rtl"] .dp-nav svg {
145
- transform: scaleX(-1);
146
- }
147
-
148
- .dp-calendar-header :where(button, select, input):disabled,
147
+ .dp-calendar-header .dp-skin:disabled,
149
148
  .dp-picker-button:disabled {
150
149
  cursor: not-allowed;
151
150
  opacity: 0.45;
152
151
  }
153
152
 
154
- .dp-nav:hover:not(:disabled) {
153
+ .dp-nav.dp-skin:hover:not(:disabled) {
155
154
  background: var(--dp-hover);
156
155
  }
157
156
 
158
- /* Shared control focus: accent border + light halo. Day cells keep their
159
- dedicated outline ring below; the picker trigger has its own inner ring. */
160
- .dp-calendar-header :where(button, select, input):focus-visible {
161
- outline: none;
162
- border-color: var(--dp-accent);
163
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--dp-accent) 22%, transparent);
157
+ /* Inner outlines survive forced colors and keep focus inside each control.
158
+ The picker trigger uses a tighter inset around its icon below. */
159
+ .dp-calendar-header .dp-skin:focus-visible,
160
+ date-picker > input:not([type="hidden"]):focus-visible,
161
+ .dp-day:focus-visible {
162
+ outline: var(--dp-focus-width) solid var(--dp-focus);
163
+ outline-offset: calc(var(--dp-focus-width) * -1);
164
164
  }
165
165
 
166
166
  .dp-day:hover:not([data-disabled="true"]):not([data-selected="true"]):not([data-range-start="true"]):not(
@@ -205,15 +205,6 @@ html[dir="rtl"] .dp-nav svg {
205
205
  font-size: 0.875rem;
206
206
  }
207
207
 
208
- /* Inner ring: keyboard focus stays inside the cell instead of reading as a
209
- second selected state or bleeding onto a neighbouring range band. It is an
210
- `outline` (not an inset box-shadow) because forced colors computes
211
- box-shadow to `none`, which would erase the keyboard indicator entirely. */
212
- .dp-day:focus-visible {
213
- outline: 2px solid var(--dp-accent);
214
- outline-offset: -2px;
215
- }
216
-
217
208
  /* On an accent-filled cell the ring inverts so it stays readable. */
218
209
  .dp-day:is([data-selected="true"], [data-range-start="true"], [data-range-end="true"]):focus-visible {
219
210
  outline-color: var(--dp-accent-fg);
@@ -275,6 +266,28 @@ html[dir="rtl"] .dp-nav svg {
275
266
  border-end-end-radius: var(--dp-day-radius);
276
267
  }
277
268
 
269
+ /* Projected band: the range the next commit would produce. It reads as one
270
+ step short of the committed band, so a hovered, keyboard or dragged preview
271
+ is never mistaken for the selection itself. */
272
+ [data-range-preview] .dp-day:is([data-range-start="true"], [data-range-end="true"]) {
273
+ background: color-mix(in srgb, var(--dp-accent) 58%, var(--dp-bg));
274
+ }
275
+
276
+ [data-range-preview] .dp-day[data-in-range="true"] {
277
+ background: color-mix(in srgb, var(--dp-accent) 11%, var(--dp-bg));
278
+ }
279
+
280
+ /* Endpoint handles are draggable only while the committed range is complete
281
+ and its two ends sit on different days. */
282
+ [data-range-drag] .dp-day:is([data-range-start="true"], [data-range-end="true"]) {
283
+ cursor: grab;
284
+ }
285
+
286
+ [data-range-drag="active"],
287
+ [data-range-drag="active"] .dp-day {
288
+ cursor: grabbing;
289
+ }
290
+
278
291
  .dp-day-number {
279
292
  display: block;
280
293
  font-variant-numeric: tabular-nums;
@@ -320,14 +333,6 @@ date-picker {
320
333
  max-inline-size: 100%;
321
334
  }
322
335
 
323
- /* Visible focus is normalized to --dp-accent so the component holds together
324
- without a consumer stylesheet; the field's own look stays consumer-owned. */
325
- date-picker > input:not([type="hidden"]):focus-visible {
326
- border-color: var(--dp-accent);
327
- outline: none;
328
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--dp-accent) 20%, transparent);
329
- }
330
-
331
336
  /* Every authored control is a grid item. */
332
337
  date-picker > input:not([type="hidden"]) {
333
338
  min-inline-size: 0;
@@ -368,7 +373,7 @@ date-picker > input:not([type="hidden"]):not([type="time"]) {
368
373
  field already shows its own ring through :focus-visible). Same radius as
369
374
  everywhere else: no bespoke shape. */
370
375
  .dp-picker-button:focus-visible {
371
- outline: 2px solid var(--dp-accent);
376
+ outline: var(--dp-focus-width) solid var(--dp-focus);
372
377
  outline-offset: -5px;
373
378
  border-radius: var(--dp-radius);
374
379
  }
@@ -446,8 +451,8 @@ date-picker[range] > .dp-picker-button[data-endpoint="end"] {
446
451
  @media (forced-colors: active) {
447
452
  /* The author-drawn caret is a gradient and disappears here: hand the
448
453
  control back to the browser instead of trying to rebuild it. */
449
- .dp-month-select,
450
- [dir="rtl"] .dp-month-select {
454
+ .dp-month-select.dp-skin,
455
+ [dir="rtl"] .dp-month-select.dp-skin {
451
456
  appearance: auto;
452
457
  background-image: none;
453
458
  padding-inline: 0.45rem;