@refraktor/dates 0.0.3 → 0.0.5

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 (63) hide show
  1. package/build/components/date-range-picker/date-range-picker.d.ts +4 -0
  2. package/build/components/date-range-picker/date-range-picker.d.ts.map +1 -0
  3. package/build/components/date-range-picker/date-range-picker.js +379 -0
  4. package/build/components/date-range-picker/date-range-picker.types.d.ts +100 -0
  5. package/build/components/date-range-picker/date-range-picker.types.d.ts.map +1 -0
  6. package/build/components/date-range-picker/date-range-picker.types.js +1 -0
  7. package/build/components/date-range-picker/index.d.ts +3 -0
  8. package/build/components/date-range-picker/index.d.ts.map +1 -0
  9. package/build/components/date-range-picker/index.js +1 -0
  10. package/build/components/time-input/index.d.ts +1 -1
  11. package/build/components/time-input/index.d.ts.map +1 -1
  12. package/build/components/time-input/time-input.d.ts.map +1 -1
  13. package/build/components/time-input/time-input.js +7 -196
  14. package/build/components/time-input/time-input.types.d.ts +5 -83
  15. package/build/components/time-input/time-input.types.d.ts.map +1 -1
  16. package/build/components/time-picker/index.d.ts +1 -1
  17. package/build/components/time-picker/index.d.ts.map +1 -1
  18. package/build/components/time-picker/time-picker.d.ts.map +1 -1
  19. package/build/components/time-picker/time-picker.js +498 -350
  20. package/build/components/time-picker/time-picker.types.d.ts +96 -61
  21. package/build/components/time-picker/time-picker.types.d.ts.map +1 -1
  22. package/build/style.css +2 -2
  23. package/package.json +33 -4
  24. package/.turbo/turbo-build.log +0 -4
  25. package/refraktor-dates-0.0.1-alpha.0.tgz +0 -0
  26. package/src/components/date-input/date-input.tsx +0 -379
  27. package/src/components/date-input/date-input.types.ts +0 -161
  28. package/src/components/date-input/index.ts +0 -13
  29. package/src/components/date-picker/date-picker.tsx +0 -649
  30. package/src/components/date-picker/date-picker.types.ts +0 -145
  31. package/src/components/date-picker/index.ts +0 -15
  32. package/src/components/dates-provider/context.ts +0 -18
  33. package/src/components/dates-provider/dates-provider.tsx +0 -136
  34. package/src/components/dates-provider/index.ts +0 -10
  35. package/src/components/dates-provider/types.ts +0 -33
  36. package/src/components/dates-provider/use-dates.ts +0 -5
  37. package/src/components/index.ts +0 -9
  38. package/src/components/month-input/index.ts +0 -13
  39. package/src/components/month-input/month-input.tsx +0 -366
  40. package/src/components/month-input/month-input.types.ts +0 -139
  41. package/src/components/month-picker/index.ts +0 -14
  42. package/src/components/month-picker/month-picker.tsx +0 -458
  43. package/src/components/month-picker/month-picker.types.ts +0 -117
  44. package/src/components/picker-shared/index.ts +0 -7
  45. package/src/components/picker-shared/picker-header.tsx +0 -178
  46. package/src/components/picker-shared/picker-header.types.ts +0 -49
  47. package/src/components/picker-shared/picker.styles.ts +0 -69
  48. package/src/components/picker-shared/picker.types.ts +0 -4
  49. package/src/components/time-input/index.ts +0 -23
  50. package/src/components/time-input/time-input.tsx +0 -453
  51. package/src/components/time-input/time-input.types.ts +0 -163
  52. package/src/components/time-picker/index.ts +0 -19
  53. package/src/components/time-picker/time-picker.tsx +0 -737
  54. package/src/components/time-picker/time-picker.types.ts +0 -135
  55. package/src/components/year-input/index.ts +0 -13
  56. package/src/components/year-input/year-input.tsx +0 -350
  57. package/src/components/year-input/year-input.types.ts +0 -118
  58. package/src/components/year-picker/index.ts +0 -15
  59. package/src/components/year-picker/year-picker.tsx +0 -504
  60. package/src/components/year-picker/year-picker.types.ts +0 -108
  61. package/src/index.ts +0 -3
  62. package/src/style.css +0 -1
  63. package/tsconfig.json +0 -13
@@ -1,504 +0,0 @@
1
- import { useId, useUncontrolled } from "@refraktor/utils";
2
- import { KeyboardEvent, useEffect, useMemo, useState } from "react";
3
- import {
4
- createClassNamesConfig,
5
- createComponentConfig,
6
- factory,
7
- useTheme,
8
- useClassNames,
9
- useProps
10
- } from "@refraktor/core";
11
- import {
12
- getGridColumns,
13
- getPickerSizeStyles,
14
- PickerHeader
15
- } from "../picker-shared";
16
- import {
17
- YearPickerClassNames,
18
- YearPickerFactoryPayload,
19
- YearPickerNavigationDirection,
20
- YearPickerProps,
21
- YearPickerRange
22
- } from "./year-picker.types";
23
-
24
- const DEFAULT_YEARS_PER_PAGE = 9;
25
- const DEFAULT_COLUMNS = 3;
26
-
27
- const defaultProps = {
28
- yearsPerPage: DEFAULT_YEARS_PER_PAGE,
29
- columns: DEFAULT_COLUMNS,
30
- disabled: false,
31
- size: "md",
32
- radius: "default"
33
- } satisfies Partial<YearPickerProps>;
34
-
35
- type YearBounds = {
36
- min: number;
37
- max: number;
38
- hasMin: boolean;
39
- hasMax: boolean;
40
- };
41
-
42
- const toSafeInteger = (value: number | undefined, fallback: number) => {
43
- if (!Number.isFinite(value)) {
44
- return fallback;
45
- }
46
-
47
- return Math.trunc(value as number);
48
- };
49
-
50
- const clamp = (value: number, min: number, max: number) =>
51
- Math.min(max, Math.max(min, value));
52
-
53
- const getBounds = (minYear?: number, maxYear?: number): YearBounds => {
54
- const hasMin = Number.isFinite(minYear);
55
- const hasMax = Number.isFinite(maxYear);
56
-
57
- const min = hasMin
58
- ? Math.trunc(minYear as number)
59
- : Number.MIN_SAFE_INTEGER;
60
- const max = hasMax
61
- ? Math.trunc(maxYear as number)
62
- : Number.MAX_SAFE_INTEGER;
63
-
64
- if (min <= max) {
65
- return { min, max, hasMin, hasMax };
66
- }
67
-
68
- return {
69
- min: max,
70
- max: min,
71
- hasMin,
72
- hasMax
73
- };
74
- };
75
-
76
- const getCenteredRangeStart = (year: number, yearsPerPage: number) =>
77
- year - Math.floor(yearsPerPage / 2);
78
-
79
- const clampRangeStart = (
80
- rangeStart: number,
81
- bounds: YearBounds,
82
- yearsPerPage: number
83
- ) => {
84
- const totalVisibleYears = bounds.max - bounds.min + 1;
85
-
86
- if (totalVisibleYears <= yearsPerPage) {
87
- return bounds.min;
88
- }
89
-
90
- const maxStart = bounds.max - yearsPerPage + 1;
91
-
92
- return clamp(rangeStart, bounds.min, maxStart);
93
- };
94
-
95
- const getRangeEnd = (
96
- rangeStart: number,
97
- yearsPerPage: number,
98
- bounds: YearBounds
99
- ) => Math.min(rangeStart + yearsPerPage - 1, bounds.max);
100
-
101
- const ensureRangeContainsYear = (
102
- year: number,
103
- rangeStart: number,
104
- bounds: YearBounds,
105
- yearsPerPage: number
106
- ) => {
107
- const normalizedRangeStart = clampRangeStart(
108
- rangeStart,
109
- bounds,
110
- yearsPerPage
111
- );
112
- const rangeEnd = getRangeEnd(normalizedRangeStart, yearsPerPage, bounds);
113
-
114
- if (year >= normalizedRangeStart && year <= rangeEnd) {
115
- return normalizedRangeStart;
116
- }
117
-
118
- return clampRangeStart(
119
- getCenteredRangeStart(year, yearsPerPage),
120
- bounds,
121
- yearsPerPage
122
- );
123
- };
124
-
125
- const getVisibleYears = (
126
- rangeStart: number,
127
- bounds: YearBounds,
128
- yearsPerPage: number
129
- ) => {
130
- const years: number[] = [];
131
-
132
- for (let index = 0; index < yearsPerPage; index += 1) {
133
- const year = rangeStart + index;
134
-
135
- if (year < bounds.min || year > bounds.max) {
136
- continue;
137
- }
138
-
139
- years.push(year);
140
- }
141
-
142
- return years;
143
- };
144
-
145
- const YearPicker = factory<YearPickerFactoryPayload>((_props, ref) => {
146
- const { cx, getRadius } = useTheme();
147
- const {
148
- id,
149
- value,
150
- defaultValue,
151
- onChange,
152
- minYear,
153
- maxYear,
154
- yearsPerPage,
155
- columns,
156
- disabled,
157
- size,
158
- radius,
159
- getYearLabel,
160
- getYearAriaLabel,
161
- getHeaderLabel,
162
- getNavigationAriaLabel,
163
- className,
164
- classNames,
165
- ...props
166
- } = useProps("YearPicker", defaultProps, _props);
167
- const classes = useClassNames("YearPicker", classNames);
168
-
169
- const _id = useId(id);
170
-
171
- const currentYear = new Date().getFullYear();
172
- const bounds = useMemo(
173
- () => getBounds(minYear, maxYear),
174
- [minYear, maxYear]
175
- );
176
- const safeYearsPerPage = Math.max(
177
- 1,
178
- toSafeInteger(yearsPerPage, DEFAULT_YEARS_PER_PAGE)
179
- );
180
- const safeColumns = clamp(
181
- toSafeInteger(columns, DEFAULT_COLUMNS),
182
- 1,
183
- Math.min(6, safeYearsPerPage)
184
- );
185
-
186
- const [selectedYearState, setSelectedYear, isControlled] = useUncontrolled<
187
- number | undefined
188
- >({
189
- value,
190
- defaultValue,
191
- finalValue: undefined,
192
- onChange: (nextYear) => {
193
- if (nextYear !== undefined) {
194
- onChange?.(nextYear);
195
- }
196
- }
197
- });
198
-
199
- const initialSelectedYear = clamp(
200
- toSafeInteger(selectedYearState, currentYear),
201
- bounds.min,
202
- bounds.max
203
- );
204
-
205
- const [rangeStart, setRangeStart] = useState(() =>
206
- clampRangeStart(
207
- getCenteredRangeStart(initialSelectedYear, safeYearsPerPage),
208
- bounds,
209
- safeYearsPerPage
210
- )
211
- );
212
-
213
- const selectedYear =
214
- selectedYearState === undefined
215
- ? undefined
216
- : clamp(
217
- toSafeInteger(selectedYearState, currentYear),
218
- bounds.min,
219
- bounds.max
220
- );
221
-
222
- const rangeAnchorYear =
223
- selectedYear ?? clamp(currentYear, bounds.min, bounds.max);
224
-
225
- useEffect(() => {
226
- if (isControlled) {
227
- return;
228
- }
229
-
230
- if (selectedYearState === undefined || selectedYear === undefined) {
231
- return;
232
- }
233
-
234
- if (selectedYearState !== selectedYear) {
235
- setSelectedYear(selectedYear);
236
- }
237
- }, [
238
- bounds.max,
239
- bounds.min,
240
- isControlled,
241
- selectedYear,
242
- selectedYearState,
243
- setSelectedYear
244
- ]);
245
-
246
- useEffect(() => {
247
- setRangeStart((previousRangeStart) =>
248
- ensureRangeContainsYear(
249
- rangeAnchorYear,
250
- previousRangeStart,
251
- bounds,
252
- safeYearsPerPage
253
- )
254
- );
255
- }, [bounds, rangeAnchorYear, safeYearsPerPage]);
256
-
257
- const visibleYears = useMemo(
258
- () => getVisibleYears(rangeStart, bounds, safeYearsPerPage),
259
- [bounds, rangeStart, safeYearsPerPage]
260
- );
261
-
262
- const visibleRange: YearPickerRange = {
263
- start: visibleYears[0] ?? rangeStart,
264
- end:
265
- visibleYears[visibleYears.length - 1] ??
266
- getRangeEnd(rangeStart, safeYearsPerPage, bounds)
267
- };
268
-
269
- const sizeStyles = getPickerSizeStyles(size);
270
-
271
- const canGoPrevious =
272
- !disabled && (!bounds.hasMin || rangeStart > bounds.min);
273
- const canGoNext =
274
- !disabled &&
275
- (!bounds.hasMax ||
276
- getRangeEnd(rangeStart, safeYearsPerPage, bounds) < bounds.max);
277
-
278
- const resolveNavigationLabel = (
279
- direction: YearPickerNavigationDirection
280
- ) => {
281
- if (getNavigationAriaLabel) {
282
- return getNavigationAriaLabel(direction, visibleRange);
283
- }
284
-
285
- return direction === "previous"
286
- ? "Show previous years"
287
- : "Show next years";
288
- };
289
-
290
- const resolveYearAriaLabel = (year: number, isSelected: boolean) => {
291
- if (getYearAriaLabel) {
292
- return getYearAriaLabel(year, isSelected);
293
- }
294
-
295
- return isSelected ? `Year ${year}, selected` : `Choose year ${year}`;
296
- };
297
-
298
- const setYear = (nextYear: number) => {
299
- if (disabled) {
300
- return;
301
- }
302
-
303
- const normalizedYear = clamp(nextYear, bounds.min, bounds.max);
304
-
305
- if (normalizedYear === selectedYear) {
306
- return;
307
- }
308
-
309
- setSelectedYear(normalizedYear);
310
- };
311
-
312
- const shiftRange = (direction: -1 | 1) => {
313
- setRangeStart((previousRangeStart) =>
314
- clampRangeStart(
315
- previousRangeStart + direction * safeYearsPerPage,
316
- bounds,
317
- safeYearsPerPage
318
- )
319
- );
320
- };
321
-
322
- const handlePrevious = () => {
323
- if (!canGoPrevious) {
324
- return;
325
- }
326
-
327
- shiftRange(-1);
328
- };
329
-
330
- const handleNext = () => {
331
- if (!canGoNext) {
332
- return;
333
- }
334
-
335
- shiftRange(1);
336
- };
337
-
338
- const handleYearSelect = (year: number) => {
339
- setRangeStart((previousRangeStart) =>
340
- ensureRangeContainsYear(
341
- year,
342
- previousRangeStart,
343
- bounds,
344
- safeYearsPerPage
345
- )
346
- );
347
- setYear(year);
348
- };
349
-
350
- const handleGridKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
351
- if (disabled) {
352
- return;
353
- }
354
-
355
- const keyboardBaseYear =
356
- selectedYear ?? visibleYears[0] ?? rangeAnchorYear;
357
-
358
- const keyboardSteps: Record<string, number> = {
359
- ArrowLeft: -1,
360
- ArrowRight: 1,
361
- ArrowUp: -safeColumns,
362
- ArrowDown: safeColumns
363
- };
364
-
365
- const step = keyboardSteps[event.key];
366
-
367
- if (step !== undefined) {
368
- event.preventDefault();
369
- const nextYear = clamp(
370
- keyboardBaseYear + step,
371
- bounds.min,
372
- bounds.max
373
- );
374
- handleYearSelect(nextYear);
375
- return;
376
- }
377
-
378
- if (event.key === "Home") {
379
- event.preventDefault();
380
-
381
- if (visibleYears.length > 0) {
382
- handleYearSelect(visibleYears[0]);
383
- }
384
-
385
- return;
386
- }
387
-
388
- if (event.key === "End") {
389
- event.preventDefault();
390
-
391
- if (visibleYears.length > 0) {
392
- handleYearSelect(visibleYears[visibleYears.length - 1]);
393
- }
394
-
395
- return;
396
- }
397
-
398
- if (event.key === "PageUp") {
399
- event.preventDefault();
400
- handleYearSelect(keyboardBaseYear - safeYearsPerPage);
401
- return;
402
- }
403
-
404
- if (event.key === "PageDown") {
405
- event.preventDefault();
406
- handleYearSelect(keyboardBaseYear + safeYearsPerPage);
407
- }
408
- };
409
-
410
- const hasVisibleSelection =
411
- selectedYear !== undefined && visibleYears.includes(selectedYear);
412
-
413
- return (
414
- <div
415
- ref={ref}
416
- id={_id}
417
- className={cx(
418
- "inline-flex w-full flex-col gap-2 bg-[var(--refraktor-bg)] p-2",
419
- getRadius(radius),
420
- classes.root,
421
- className
422
- )}
423
- {...props}
424
- >
425
- <PickerHeader
426
- label={
427
- getHeaderLabel
428
- ? getHeaderLabel(visibleRange)
429
- : `${visibleRange.start} - ${visibleRange.end}`
430
- }
431
- onPrevious={handlePrevious}
432
- onNext={handleNext}
433
- previousDisabled={!canGoPrevious}
434
- nextDisabled={!canGoNext}
435
- previousLabel={resolveNavigationLabel("previous")}
436
- nextLabel={resolveNavigationLabel("next")}
437
- size={size}
438
- radius={radius}
439
- classNames={{
440
- root: classes.header,
441
- controls: classes.headerControls,
442
- control: classes.headerControl,
443
- previousControl: classes.headerPreviousControl,
444
- nextControl: classes.headerNextControl,
445
- label: classes.headerLabel
446
- }}
447
- />
448
-
449
- <div
450
- role="grid"
451
- aria-label="Year picker"
452
- className={cx(
453
- "grid",
454
- getGridColumns(safeColumns),
455
- sizeStyles.gridGap,
456
- classes.grid
457
- )}
458
- onKeyDown={handleGridKeyDown}
459
- >
460
- {visibleYears.map((year, index) => {
461
- const isSelected = year === selectedYear;
462
- const tabIndex =
463
- isSelected || (!hasVisibleSelection && index === 0)
464
- ? 0
465
- : -1;
466
-
467
- return (
468
- <button
469
- key={year}
470
- type="button"
471
- role="gridcell"
472
- aria-selected={isSelected}
473
- aria-label={resolveYearAriaLabel(year, isSelected)}
474
- tabIndex={tabIndex}
475
- data-active={isSelected}
476
- data-disabled={disabled}
477
- disabled={disabled}
478
- className={cx(
479
- "inline-flex items-center justify-center font-medium text-[var(--refraktor-text)] transition-colors",
480
- isSelected
481
- ? "bg-[var(--refraktor-primary)] text-[var(--refraktor-primary-text)]"
482
- : "hover:bg-[var(--refraktor-bg-hover)]",
483
- disabled &&
484
- "pointer-events-none cursor-not-allowed opacity-50 data-[disabled=true]:pointer-events-none",
485
- sizeStyles.cell,
486
- getRadius(radius),
487
- classes.year
488
- )}
489
- onClick={() => handleYearSelect(year)}
490
- >
491
- {getYearLabel ? getYearLabel(year) : year}
492
- </button>
493
- );
494
- })}
495
- </div>
496
- </div>
497
- );
498
- });
499
-
500
- YearPicker.displayName = "@refraktor/dates/YearPicker";
501
- YearPicker.configure = createComponentConfig<YearPickerProps>();
502
- YearPicker.classNames = createClassNamesConfig<YearPickerClassNames>();
503
-
504
- export default YearPicker;
@@ -1,108 +0,0 @@
1
- import { ComponentPropsWithoutRef, ReactNode } from "react";
2
- import {
3
- RefraktorRadius,
4
- RefraktorSize,
5
- createClassNamesConfig,
6
- createComponentConfig,
7
- FactoryPayload
8
- } from "@refraktor/core";
9
-
10
- export type YearPickerValue = number;
11
- export type YearPickerSize = RefraktorSize;
12
- export type YearPickerRadius = RefraktorRadius;
13
-
14
- export type YearPickerNavigationDirection = "previous" | "next";
15
-
16
- export type YearPickerRange = {
17
- start: number;
18
- end: number;
19
- };
20
-
21
- export type YearPickerOnChange = (year: YearPickerValue) => void;
22
-
23
- export type YearPickerGetYearLabel = (year: YearPickerValue) => ReactNode;
24
-
25
- export type YearPickerGetYearAriaLabel = (
26
- year: YearPickerValue,
27
- selected: boolean
28
- ) => string;
29
-
30
- export type YearPickerGetHeaderLabel = (range: YearPickerRange) => ReactNode;
31
-
32
- export type YearPickerGetNavigationAriaLabel = (
33
- direction: YearPickerNavigationDirection,
34
- range: YearPickerRange
35
- ) => string;
36
-
37
- export type YearPickerClassNames = {
38
- root?: string;
39
- header?: string;
40
- headerControls?: string;
41
- headerControl?: string;
42
- headerPreviousControl?: string;
43
- headerNextControl?: string;
44
- headerLabel?: string;
45
- grid?: string;
46
- year?: string;
47
- yearActive?: string;
48
- };
49
-
50
- export interface YearPickerProps
51
- extends Omit<ComponentPropsWithoutRef<"div">, "onChange"> {
52
- /** Active year (controlled). */
53
- value?: YearPickerValue;
54
-
55
- /** Initial active year (uncontrolled). */
56
- defaultValue?: YearPickerValue;
57
-
58
- /** Callback called when active year changes. */
59
- onChange?: YearPickerOnChange;
60
-
61
- /** Minimum selectable year. */
62
- minYear?: number;
63
-
64
- /** Maximum selectable year. */
65
- maxYear?: number;
66
-
67
- /** Years rendered in one page @default `9` */
68
- yearsPerPage?: number;
69
-
70
- /** Grid columns used by the year list @default `3` */
71
- columns?: number;
72
-
73
- /** Whether all year controls are disabled @default `false` */
74
- disabled?: boolean;
75
-
76
- /** Component size @default `md` */
77
- size?: YearPickerSize;
78
-
79
- /** Border radius @default `default` */
80
- radius?: YearPickerRadius;
81
-
82
- /** Custom year label renderer. */
83
- getYearLabel?: YearPickerGetYearLabel;
84
-
85
- /** Custom aria-label generator for year buttons. */
86
- getYearAriaLabel?: YearPickerGetYearAriaLabel;
87
-
88
- /** Custom header label renderer for visible range. */
89
- getHeaderLabel?: YearPickerGetHeaderLabel;
90
-
91
- /** Custom aria-label generator for previous/next controls. */
92
- getNavigationAriaLabel?: YearPickerGetNavigationAriaLabel;
93
-
94
- /** Used for editing root class name. */
95
- className?: string;
96
-
97
- /** Used for styling different parts of the component. */
98
- classNames?: YearPickerClassNames;
99
- }
100
-
101
- export interface YearPickerFactoryPayload extends FactoryPayload {
102
- props: YearPickerProps;
103
- ref: HTMLDivElement;
104
- compound: {
105
- configure: ReturnType<typeof createComponentConfig<YearPickerProps>>;
106
- classNames: ReturnType<typeof createClassNamesConfig<YearPickerClassNames>>;
107
- };
108
- }
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- import "./style.css";
2
-
3
- export * from "./components";
package/src/style.css DELETED
@@ -1 +0,0 @@
1
- @import "tailwindcss";
package/tsconfig.json DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "outDir": "./build",
5
- "rootDir": "./src",
6
- "declaration": true,
7
- "declarationMap": true,
8
- "noEmit": false,
9
- "allowImportingTsExtensions": false
10
- },
11
- "include": ["src/**/*"],
12
- "exclude": ["node_modules", "build"]
13
- }