@olundot/ui 0.23.1 → 0.24.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.
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +45 -30
- package/dist/index.js +252 -123
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @olundot/ui
|
|
2
2
|
|
|
3
|
+
## 0.24.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 052cb2d: DatePicker 기간 고르기를 다듬고 기간 이동을 더했습니다.
|
|
8
|
+
|
|
9
|
+
- 1024px 이상 `day` 기간 팝오버는 두 달을 나란히 보입니다(폭 558px). 이전 달, 다음 달 버튼은 양 끝에 하나씩이고 한 달씩 넘깁니다. 키보드는 두 달 사이를 그대로 넘습니다.
|
|
10
|
+
- `day` 기간에도 끝 버튼 「시작일」「종료일」을 둡니다. 누른 끝만 고칩니다. 두 끝이 찬 뒤 시작을 고르면 종료는 그대로 두고 반영합니다. 1024px 미만 시트에도 보입니다.
|
|
11
|
+
- 시작을 고른 뒤 가리킨 날(마우스, 키보드 포커스)까지 범위를 옅게 미리 보입니다.
|
|
12
|
+
- 새 prop `lockStart`(시작 끝 잠금)와 `endMin`(종료 전용 하한)을 더했습니다.
|
|
13
|
+
- 새 prop `onStep`, `prevStepDisabled`, `nextStepDisabled`: 칸 양옆에 「이전 기간」「다음 기간」 버튼을 두고, 옮길 폭은 사용하는 쪽이 정합니다.
|
|
14
|
+
|
|
3
15
|
## 0.23.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -66,7 +66,7 @@ type GhostDefaultActionStyle = {
|
|
|
66
66
|
declare const buttonCva: (props?: ({
|
|
67
67
|
appearance?: "filled" | "outline" | "ghost" | "link" | null | undefined;
|
|
68
68
|
tone?: "primary" | "neutral" | "danger" | null | undefined;
|
|
69
|
-
size?: "
|
|
69
|
+
size?: "xs" | "sm" | "md" | "lg" | "xl" | "default" | null | undefined;
|
|
70
70
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
71
71
|
type ButtonVariantsOptions = Parameters<typeof buttonCva>[0];
|
|
72
72
|
declare function buttonVariants(options?: ButtonVariantsOptions): string;
|
|
@@ -101,13 +101,13 @@ type CopyButtonProps = Omit<ButtonProps, 'appearance' | 'children' | 'loading' |
|
|
|
101
101
|
declare const CopyButton: React.ForwardRefExoticComponent<CopyButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
102
102
|
|
|
103
103
|
declare const inputVariants: (props?: ({
|
|
104
|
-
size?: "
|
|
104
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
105
105
|
fullWidth?: boolean | null | undefined;
|
|
106
106
|
surface?: SurfaceLevel | null | undefined;
|
|
107
107
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
108
108
|
declare const inputMessageVariants: (props?: ({
|
|
109
|
-
state?: "
|
|
110
|
-
size?: "
|
|
109
|
+
state?: "error" | "success" | "default" | null | undefined;
|
|
110
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
111
111
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
112
112
|
type InputState = NonNullable<VariantProps<typeof inputMessageVariants>["state"]>;
|
|
113
113
|
/** Canonical size type (0.2.0+). Use `size` prop with these values. */
|
|
@@ -155,11 +155,11 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
|
|
|
155
155
|
declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
|
|
156
156
|
|
|
157
157
|
declare const fileUploadZoneVariants: (props?: ({
|
|
158
|
-
size?: "
|
|
158
|
+
size?: "compact" | "default" | null | undefined;
|
|
159
159
|
surface?: SurfaceLevel | null | undefined;
|
|
160
160
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
161
161
|
declare const fileUploadIconVariants: (props?: ({
|
|
162
|
-
size?: "
|
|
162
|
+
size?: "compact" | "default" | null | undefined;
|
|
163
163
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
164
164
|
interface FileUploadZoneProps extends Omit<React.LabelHTMLAttributes<HTMLLabelElement>, "onChange">, VariantProps<typeof fileUploadZoneVariants> {
|
|
165
165
|
accept?: string;
|
|
@@ -203,12 +203,12 @@ interface InlineAlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'childre
|
|
|
203
203
|
declare const InlineAlert: React.ForwardRefExoticComponent<InlineAlertProps & React.RefAttributes<HTMLDivElement>>;
|
|
204
204
|
|
|
205
205
|
declare const textareaVariants: (props?: ({
|
|
206
|
-
size?: "
|
|
206
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
207
207
|
fullWidth?: boolean | null | undefined;
|
|
208
208
|
surface?: SurfaceLevel | null | undefined;
|
|
209
209
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
210
210
|
declare const textareaMessageVariants: (props?: ({
|
|
211
|
-
state?: "
|
|
211
|
+
state?: "error" | "success" | "default" | null | undefined;
|
|
212
212
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
213
213
|
type TextareaState = NonNullable<VariantProps<typeof textareaMessageVariants>["state"]>;
|
|
214
214
|
/** Canonical size type (0.2.0+). Use `size` prop with these values. */
|
|
@@ -257,14 +257,14 @@ interface TextareaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaEl
|
|
|
257
257
|
declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
|
|
258
258
|
|
|
259
259
|
declare const selectVariants: (props?: ({
|
|
260
|
-
size?: "
|
|
260
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
261
261
|
fullWidth?: boolean | null | undefined;
|
|
262
262
|
appearance?: "inline" | "field" | null | undefined;
|
|
263
263
|
surface?: SurfaceLevel | null | undefined;
|
|
264
264
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
265
265
|
declare const selectMessageVariants: (props?: ({
|
|
266
|
-
state?: "
|
|
267
|
-
size?: "
|
|
266
|
+
state?: "error" | "success" | "default" | null | undefined;
|
|
267
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
268
268
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
269
269
|
type SelectState = NonNullable<VariantProps<typeof selectMessageVariants>["state"]>;
|
|
270
270
|
/** Canonical size type (0.2.0+). Use `size` prop with these values. */
|
|
@@ -396,6 +396,15 @@ interface DatePickerBaseProps {
|
|
|
396
396
|
className?: string;
|
|
397
397
|
"aria-label"?: string;
|
|
398
398
|
"aria-describedby"?: string;
|
|
399
|
+
/**
|
|
400
|
+
* Shows "이전 기간" and "다음 기간" buttons beside the field, for views and filters that page
|
|
401
|
+
* through periods. Called with -1 or 1; the caller moves the value by its own step.
|
|
402
|
+
*/
|
|
403
|
+
onStep?: (direction: -1 | 1) => void;
|
|
404
|
+
/** Disables "이전 기간". */
|
|
405
|
+
prevStepDisabled?: boolean;
|
|
406
|
+
/** Disables "다음 기간" (the next period would pass `max`, for example). */
|
|
407
|
+
nextStepDisabled?: boolean;
|
|
399
408
|
}
|
|
400
409
|
interface DatePickerSingleProps extends DatePickerBaseProps {
|
|
401
410
|
selectionMode?: "single";
|
|
@@ -403,6 +412,8 @@ interface DatePickerSingleProps extends DatePickerBaseProps {
|
|
|
403
412
|
value: string;
|
|
404
413
|
onChange: (value: string) => void;
|
|
405
414
|
maxDays?: never;
|
|
415
|
+
lockStart?: never;
|
|
416
|
+
endMin?: never;
|
|
406
417
|
}
|
|
407
418
|
interface DatePickerRangeProps extends DatePickerBaseProps {
|
|
408
419
|
selectionMode: "range";
|
|
@@ -412,6 +423,10 @@ interface DatePickerRangeProps extends DatePickerBaseProps {
|
|
|
412
423
|
onChange: (value: DateRangeValue) => void;
|
|
413
424
|
/** Most days the range spans, the start day included. */
|
|
414
425
|
maxDays?: number;
|
|
426
|
+
/** Keeps the start as it is: its end button is disabled and only the end is picked. Give the reason in `description`. */
|
|
427
|
+
lockStart?: boolean;
|
|
428
|
+
/** Earliest end, in the value format. Unlike `min`, it leaves the start alone. With it, an earlier end day no longer swaps the ends. */
|
|
429
|
+
endMin?: string;
|
|
415
430
|
}
|
|
416
431
|
type DatePickerProps = DatePickerSingleProps | DatePickerRangeProps;
|
|
417
432
|
declare function DatePicker(props: DatePickerProps): react_jsx_runtime.JSX.Element;
|
|
@@ -1774,7 +1789,7 @@ interface StatusDotProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'ch
|
|
|
1774
1789
|
declare const StatusDot: React.ForwardRefExoticComponent<StatusDotProps & React.RefAttributes<HTMLSpanElement>>;
|
|
1775
1790
|
|
|
1776
1791
|
declare const notificationBadgeVariants: (props?: ({
|
|
1777
|
-
size?: "
|
|
1792
|
+
size?: "sm" | "md" | null | undefined;
|
|
1778
1793
|
placement?: "none" | "inline" | "corner" | null | undefined;
|
|
1779
1794
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1780
1795
|
type NotificationBadgeSize = NonNullable<VariantProps<typeof notificationBadgeVariants>['size']>;
|
|
@@ -1787,13 +1802,13 @@ declare const NotificationBadge: React.ForwardRefExoticComponent<NotificationBad
|
|
|
1787
1802
|
|
|
1788
1803
|
declare const chipVariants: (props?: ({
|
|
1789
1804
|
variant?: "filter" | "choice" | "removable" | "status-filter" | null | undefined;
|
|
1790
|
-
tone?: "
|
|
1791
|
-
size?: "
|
|
1805
|
+
tone?: "muted" | "accent" | "warning" | "success" | "neutral" | "danger" | null | undefined;
|
|
1806
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
1792
1807
|
pressed?: boolean | null | undefined;
|
|
1793
1808
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1794
1809
|
declare const chipCountVariants: (props?: ({
|
|
1795
|
-
tone?: "
|
|
1796
|
-
size?: "
|
|
1810
|
+
tone?: "muted" | "accent" | "warning" | "success" | "neutral" | "danger" | null | undefined;
|
|
1811
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
1797
1812
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1798
1813
|
type ChipVariant = NonNullable<VariantProps<typeof chipVariants>["variant"]>;
|
|
1799
1814
|
type ChipTone = NonNullable<VariantProps<typeof chipVariants>["tone"]>;
|
|
@@ -1807,7 +1822,7 @@ interface ChipProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
|
1807
1822
|
declare const Chip: React.ForwardRefExoticComponent<ChipProps & React.RefAttributes<HTMLButtonElement>>;
|
|
1808
1823
|
|
|
1809
1824
|
declare const emptyStateBaseVariants: (props?: ({
|
|
1810
|
-
size?: "
|
|
1825
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
1811
1826
|
bordered?: boolean | null | undefined;
|
|
1812
1827
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1813
1828
|
type EmptyStateTone = "neutral" | "muted" | "raised";
|
|
@@ -1819,7 +1834,7 @@ interface EmptyStateVariantOptions extends VariantProps<typeof emptyStateBaseVar
|
|
|
1819
1834
|
}
|
|
1820
1835
|
declare function emptyStateVariants({ size, tone, surface, bordered, className, }?: EmptyStateVariantOptions): string;
|
|
1821
1836
|
declare const emptyStateIconVariants: (props?: ({
|
|
1822
|
-
size?: "
|
|
1837
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
1823
1838
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1824
1839
|
type EmptyStateSize = NonNullable<VariantProps<typeof emptyStateBaseVariants>["size"]>;
|
|
1825
1840
|
interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, VariantProps<typeof emptyStateBaseVariants> {
|
|
@@ -1845,7 +1860,7 @@ interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "ti
|
|
|
1845
1860
|
declare const EmptyState: React.ForwardRefExoticComponent<EmptyStateProps & React.RefAttributes<HTMLDivElement>>;
|
|
1846
1861
|
|
|
1847
1862
|
declare const errorStateVariants: (props?: ({
|
|
1848
|
-
size?: "
|
|
1863
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
1849
1864
|
surface?: SurfaceLevel | null | undefined;
|
|
1850
1865
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1851
1866
|
interface ErrorStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, VariantProps<typeof errorStateVariants> {
|
|
@@ -1865,7 +1880,7 @@ declare const skeletonVariants: (props?: ({
|
|
|
1865
1880
|
shape?: "text" | "block" | "circle" | null | undefined;
|
|
1866
1881
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1867
1882
|
declare const spinnerVariants: (props?: ({
|
|
1868
|
-
size?: "
|
|
1883
|
+
size?: "sm" | "md" | "lg" | 16 | 24 | 32 | null | undefined;
|
|
1869
1884
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1870
1885
|
interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof skeletonVariants> {
|
|
1871
1886
|
}
|
|
@@ -1898,7 +1913,7 @@ interface SpinnerProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
|
1898
1913
|
declare const Spinner: React.ForwardRefExoticComponent<SpinnerProps & React.RefAttributes<HTMLSpanElement>>;
|
|
1899
1914
|
|
|
1900
1915
|
declare const iconButtonCva: (props?: ({
|
|
1901
|
-
size?: "
|
|
1916
|
+
size?: "xs" | "sm" | "md" | "lg" | "xl" | null | undefined;
|
|
1902
1917
|
pressed?: boolean | null | undefined;
|
|
1903
1918
|
appearance?: "filled" | "outline" | "ghost" | null | undefined;
|
|
1904
1919
|
tone?: "primary" | "neutral" | "danger" | null | undefined;
|
|
@@ -1907,7 +1922,7 @@ type IconButtonSize = NonNullable<VariantProps<typeof iconButtonCva>["size"]>;
|
|
|
1907
1922
|
type IconButtonVariantsOptions = NonNullable<Parameters<typeof iconButtonCva>[0]>;
|
|
1908
1923
|
declare function iconButtonVariants(options?: IconButtonVariantsOptions): string;
|
|
1909
1924
|
declare const iconButtonBadgeVariants: (props?: ({
|
|
1910
|
-
tone?: "error" | "
|
|
1925
|
+
tone?: "error" | "info" | "success" | null | undefined;
|
|
1911
1926
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
1912
1927
|
type IconButtonBadgeTone = NonNullable<VariantProps<typeof iconButtonBadgeVariants>["tone"]>;
|
|
1913
1928
|
type IconButtonIcon = React.ComponentType<React.SVGProps<SVGSVGElement> & {
|
|
@@ -2170,7 +2185,7 @@ interface ActionFooterProps extends Omit<React.HTMLAttributes<HTMLDivElement>, '
|
|
|
2170
2185
|
declare const ActionFooter: React.ForwardRefExoticComponent<ActionFooterProps & React.RefAttributes<HTMLDivElement>>;
|
|
2171
2186
|
|
|
2172
2187
|
declare const toastVariants: (props?: ({
|
|
2173
|
-
variant?: "
|
|
2188
|
+
variant?: "error" | "warning" | "info" | "success" | "default" | null | undefined;
|
|
2174
2189
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
2175
2190
|
declare const toastViewportVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
|
|
2176
2191
|
type ToastVariant = NonNullable<VariantProps<typeof toastVariants>['variant']>;
|
|
@@ -2224,19 +2239,19 @@ interface ToastProviderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
2224
2239
|
declare function ToastProvider({ children, maxToasts, className, ...props }: ToastProviderProps): react_jsx_runtime.JSX.Element;
|
|
2225
2240
|
|
|
2226
2241
|
declare const otpFieldVariants: (props?: ({
|
|
2227
|
-
size?: "
|
|
2242
|
+
size?: "compact" | "default" | null | undefined;
|
|
2228
2243
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
2229
2244
|
declare const otpFieldGroupVariants: (props?: ({
|
|
2230
|
-
size?: "
|
|
2245
|
+
size?: "compact" | "default" | null | undefined;
|
|
2231
2246
|
fluid?: boolean | null | undefined;
|
|
2232
2247
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
2233
2248
|
declare const otpCellVariants: (props?: ({
|
|
2234
|
-
size?: "
|
|
2249
|
+
size?: "compact" | "default" | null | undefined;
|
|
2235
2250
|
fluid?: boolean | null | undefined;
|
|
2236
2251
|
surface?: SurfaceLevel | null | undefined;
|
|
2237
2252
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
2238
2253
|
declare const otpFieldMessageVariants: (props?: ({
|
|
2239
|
-
state?: "
|
|
2254
|
+
state?: "error" | "default" | null | undefined;
|
|
2240
2255
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
2241
2256
|
type OTPFieldSize = NonNullable<VariantProps<typeof otpCellVariants>["size"]>;
|
|
2242
2257
|
interface OTPFieldProps extends Omit<React.FieldsetHTMLAttributes<HTMLFieldSetElement>, "onChange" | "children" | "defaultValue" | "value">, VariantProps<typeof otpFieldVariants> {
|
|
@@ -2263,10 +2278,10 @@ interface OTPFieldProps extends Omit<React.FieldsetHTMLAttributes<HTMLFieldSetEl
|
|
|
2263
2278
|
declare const OTPField: React.ForwardRefExoticComponent<OTPFieldProps & React.RefAttributes<HTMLFieldSetElement>>;
|
|
2264
2279
|
|
|
2265
2280
|
declare const searchFieldVariants: (props?: ({
|
|
2266
|
-
size?: "
|
|
2281
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
2267
2282
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
2268
2283
|
declare const searchFieldInputVariants: (props?: ({
|
|
2269
|
-
size?: "
|
|
2284
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
2270
2285
|
hasClear?: boolean | null | undefined;
|
|
2271
2286
|
surface?: SurfaceLevel | null | undefined;
|
|
2272
2287
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -2290,7 +2305,7 @@ declare const checkboxVariants: (props?: ({
|
|
|
2290
2305
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
2291
2306
|
declare const checkboxRootVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
|
|
2292
2307
|
declare const checkboxBoxVariants: (props?: ({
|
|
2293
|
-
size?: "
|
|
2308
|
+
size?: "sm" | "md" | null | undefined;
|
|
2294
2309
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
2295
2310
|
declare const checkboxGroupItemVariants: (props?: ({
|
|
2296
2311
|
appearance?: "card" | "plain" | null | undefined;
|
package/dist/index.js
CHANGED
|
@@ -1887,7 +1887,7 @@ Select.displayName = "Select";
|
|
|
1887
1887
|
|
|
1888
1888
|
// src/components/ui/date-picker.tsx
|
|
1889
1889
|
import * as React19 from "react";
|
|
1890
|
-
import { AlertCircle as AlertCircle4, Calendar as CalendarIcon, ChevronLeft, ChevronRight } from "lucide-react";
|
|
1890
|
+
import { AlertCircle as AlertCircle4, Calendar as CalendarIcon, ChevronLeft, ChevronRight, Lock } from "lucide-react";
|
|
1891
1891
|
|
|
1892
1892
|
// src/components/ui/dialog.tsx
|
|
1893
1893
|
import * as React17 from "react";
|
|
@@ -3704,7 +3704,7 @@ function formatRangeParts(value, granularity, now) {
|
|
|
3704
3704
|
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3705
3705
|
var WEEKDAYS = ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"];
|
|
3706
3706
|
var HOURS = Array.from({ length: 24 }, (_, hour) => hour);
|
|
3707
|
-
var POPOVER_WIDTH = { day: 280, minute: 424 };
|
|
3707
|
+
var POPOVER_WIDTH = { day: 280, dayRange: 558, minute: 424 };
|
|
3708
3708
|
var COLLISION_PADDING = 8;
|
|
3709
3709
|
var pad22 = (n) => String(n).padStart(2, "0");
|
|
3710
3710
|
var isoDay = (parts) => `${parts.year}-${pad22(parts.month)}-${pad22(parts.day)}`;
|
|
@@ -3742,11 +3742,17 @@ function DatePicker(props) {
|
|
|
3742
3742
|
id,
|
|
3743
3743
|
className,
|
|
3744
3744
|
"aria-label": ariaLabel,
|
|
3745
|
-
"aria-describedby": ariaDescribedBy
|
|
3745
|
+
"aria-describedby": ariaDescribedBy,
|
|
3746
|
+
onStep,
|
|
3747
|
+
prevStepDisabled = false,
|
|
3748
|
+
nextStepDisabled = false
|
|
3746
3749
|
} = props;
|
|
3747
3750
|
const range = props.selectionMode === "range";
|
|
3748
3751
|
const minute = granularity === "minute";
|
|
3749
3752
|
const maxDays = range ? props.maxDays : void 0;
|
|
3753
|
+
const lockStart = range && Boolean(props.lockStart);
|
|
3754
|
+
const endMinValue = range ? props.endMin : void 0;
|
|
3755
|
+
const popoverKind = minute ? "minute" : range ? "dayRange" : "day";
|
|
3750
3756
|
const field = useFormFieldControl();
|
|
3751
3757
|
const generatedId = React19.useId();
|
|
3752
3758
|
const baseId = `date-picker-${generatedId.replace(/:/g, "")}`;
|
|
@@ -3760,14 +3766,18 @@ function DatePicker(props) {
|
|
|
3760
3766
|
const parts = parseValue(max, granularity);
|
|
3761
3767
|
return parts && !minute ? { ...parts, hour: 23, minute: 59 } : parts;
|
|
3762
3768
|
}, [max, granularity, minute]);
|
|
3769
|
+
const endMinParts = React19.useMemo(() => parseValue(endMinValue, granularity), [endMinValue, granularity]);
|
|
3770
|
+
const swapEnds = !minute && !lockStart && !endMinParts;
|
|
3763
3771
|
const [open, setOpen] = React19.useState(false);
|
|
3764
3772
|
const [layer, setLayer] = React19.useState("popover");
|
|
3765
3773
|
const [align, setAlign] = React19.useState("start");
|
|
3766
3774
|
const [draft, setDraft] = React19.useState({ from: "", to: "" });
|
|
3767
|
-
const [
|
|
3775
|
+
const [pickedEnd, setActiveEnd] = React19.useState("from");
|
|
3776
|
+
const activeEnd = lockStart ? "to" : pickedEnd;
|
|
3768
3777
|
const [timeOpen, setTimeOpen] = React19.useState(false);
|
|
3769
3778
|
const [view, setView] = React19.useState(() => ({ year: 2e3, month: 1 }));
|
|
3770
3779
|
const [focusDay, setFocusDay] = React19.useState(() => todayParts(/* @__PURE__ */ new Date()));
|
|
3780
|
+
const [pointDay, setPointDay] = React19.useState(null);
|
|
3771
3781
|
const triggerRef = React19.useRef(null);
|
|
3772
3782
|
const [outerLabel, setOuterLabel] = React19.useState(void 0);
|
|
3773
3783
|
const [windowName, setWindowName] = React19.useState(void 0);
|
|
@@ -3807,7 +3817,7 @@ function DatePicker(props) {
|
|
|
3807
3817
|
setOuterLabel(labelTextOf(triggerRef.current));
|
|
3808
3818
|
}, [ariaLabel, label, field, triggerId]);
|
|
3809
3819
|
function startView() {
|
|
3810
|
-
const anchor = range ? parseValue(rangeValue.from, granularity) ?? parseValue(rangeValue.to, granularity) : parseValue(singleValue, granularity);
|
|
3820
|
+
const anchor = range ? (lockStart ? parseValue(rangeValue.to, granularity) : null) ?? parseValue(rangeValue.from, granularity) ?? parseValue(rangeValue.to, granularity) : parseValue(singleValue, granularity);
|
|
3811
3821
|
return anchor ?? parseValue(initialMonth, granularity) ?? todayParts(/* @__PURE__ */ new Date());
|
|
3812
3822
|
}
|
|
3813
3823
|
function handleOpenChange(next) {
|
|
@@ -3819,13 +3829,14 @@ function DatePicker(props) {
|
|
|
3819
3829
|
setDraft(rangeValue);
|
|
3820
3830
|
setActiveEnd(range && rangeValue.from && !rangeValue.to ? "to" : "from");
|
|
3821
3831
|
setTimeOpen(false);
|
|
3832
|
+
setPointDay(null);
|
|
3822
3833
|
followed.current = rangeValue;
|
|
3823
3834
|
lastEmitted.current = null;
|
|
3824
3835
|
setWindowName(currentWindowName());
|
|
3825
3836
|
const wide = isWideViewport();
|
|
3826
3837
|
setLayer(wide ? "popover" : "sheet");
|
|
3827
3838
|
const box = triggerRef.current?.getBoundingClientRect();
|
|
3828
|
-
const width = POPOVER_WIDTH[
|
|
3839
|
+
const width = POPOVER_WIDTH[popoverKind];
|
|
3829
3840
|
setAlign(box && typeof window !== "undefined" && box.left + width > window.innerWidth - COLLISION_PADDING ? "end" : "start");
|
|
3830
3841
|
}
|
|
3831
3842
|
setOpen(next);
|
|
@@ -3834,13 +3845,25 @@ function DatePicker(props) {
|
|
|
3834
3845
|
const toParts = parseValue(shownRange.to, granularity);
|
|
3835
3846
|
const singleParts = parseValue(singleValue, granularity);
|
|
3836
3847
|
const editing = range ? activeEnd === "from" ? fromParts : toParts : singleParts;
|
|
3837
|
-
const editMin = range && activeEnd === "to"
|
|
3848
|
+
const editMin = range && activeEnd === "to" ? [minParts, minute ? fromParts : null, endMinParts].reduce(
|
|
3849
|
+
(latest, parts) => parts && (!latest || minuteKey(parts) > minuteKey(latest)) ? parts : latest,
|
|
3850
|
+
null
|
|
3851
|
+
) : minParts;
|
|
3852
|
+
const editMax = (() => {
|
|
3853
|
+
if (!range || activeEnd !== "to" || !fromParts || maxDays === void 0) return maxParts;
|
|
3854
|
+
const last = { ...addDays(fromParts, maxDays - 1), hour: 23, minute: 59 };
|
|
3855
|
+
return maxParts && minuteKey(maxParts) < minuteKey(last) ? maxParts : last;
|
|
3856
|
+
})();
|
|
3838
3857
|
function commitRange(next, edited) {
|
|
3839
3858
|
const from = parseValue(next.from, granularity);
|
|
3840
3859
|
const to = parseValue(next.to, granularity);
|
|
3860
|
+
if (edited === "to" && to && (editMin && minuteKey(to) < minuteKey(editMin) || editMax && minuteKey(to) > minuteKey(editMax))) {
|
|
3861
|
+
return draft;
|
|
3862
|
+
}
|
|
3841
3863
|
let value = next;
|
|
3842
3864
|
if (from && to && (minuteKey(from) > minuteKey(to) || maxDays !== void 0 && daysBetween(from, to) > maxDays - 1)) {
|
|
3843
3865
|
const cleared = edited === "from" ? "to" : "from";
|
|
3866
|
+
if (lockStart && cleared === "from") return draft;
|
|
3844
3867
|
value = cleared === "to" ? { from: next.from, to: "" } : { from: "", to: next.to };
|
|
3845
3868
|
setActiveEnd(cleared);
|
|
3846
3869
|
}
|
|
@@ -3859,16 +3882,11 @@ function DatePicker(props) {
|
|
|
3859
3882
|
function dayDisabled(cell) {
|
|
3860
3883
|
if (minParts && dayKey(cell) < dayKey(minParts)) return true;
|
|
3861
3884
|
if (maxParts && dayKey(cell) > dayKey(maxParts)) return true;
|
|
3862
|
-
if (!range) return false;
|
|
3863
|
-
if (
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
}
|
|
3868
|
-
return false;
|
|
3869
|
-
}
|
|
3870
|
-
if (fromParts && !toParts && maxDays !== void 0) return daysBetween(fromParts, cell) > maxDays - 1;
|
|
3871
|
-
return false;
|
|
3885
|
+
if (!range || activeEnd !== "to") return false;
|
|
3886
|
+
if (endMinParts && dayKey(cell) < dayKey(endMinParts)) return true;
|
|
3887
|
+
if (!fromParts) return false;
|
|
3888
|
+
if (!swapEnds && dayKey(cell) < dayKey(fromParts)) return true;
|
|
3889
|
+
return maxDays !== void 0 && daysBetween(fromParts, cell) > maxDays - 1;
|
|
3872
3890
|
}
|
|
3873
3891
|
function selectDay(cell) {
|
|
3874
3892
|
if (dayDisabled(cell)) return;
|
|
@@ -3879,13 +3897,16 @@ function DatePicker(props) {
|
|
|
3879
3897
|
return;
|
|
3880
3898
|
}
|
|
3881
3899
|
if (!minute) {
|
|
3882
|
-
|
|
3883
|
-
|
|
3900
|
+
const picked = formatValue(cell, granularity);
|
|
3901
|
+
const filled = Boolean(fromParts && toParts);
|
|
3902
|
+
const next = activeEnd === "from" ? { from: picked, to: draft.to } : swapEnds && fromParts && dayKey(cell) < dayKey(fromParts) ? { from: picked, to: draft.from } : { from: draft.from, to: picked };
|
|
3903
|
+
const value = commitRange(next, activeEnd);
|
|
3904
|
+
if (!value.from || !value.to) {
|
|
3905
|
+
setActiveEnd(value.from ? "to" : "from");
|
|
3884
3906
|
return;
|
|
3885
3907
|
}
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
setOpen(false);
|
|
3908
|
+
if (activeEnd === "to" || !filled) setOpen(false);
|
|
3909
|
+
else setActiveEnd("to");
|
|
3889
3910
|
return;
|
|
3890
3911
|
}
|
|
3891
3912
|
if (activeEnd === "from") {
|
|
@@ -3893,7 +3914,7 @@ function DatePicker(props) {
|
|
|
3893
3914
|
if (!commitRange({ from: formatValue(nextFrom, granularity), to: draft.to }, "from").to) setActiveEnd("to");
|
|
3894
3915
|
return;
|
|
3895
3916
|
}
|
|
3896
|
-
const nextTo = clampParts({ ...baseFor("to"), year: cell.year, month: cell.month, day: cell.day }, editMin,
|
|
3917
|
+
const nextTo = clampParts({ ...baseFor("to"), year: cell.year, month: cell.month, day: cell.day }, editMin, editMax);
|
|
3897
3918
|
commitRange({ from: draft.from, to: formatValue(nextTo, granularity) }, "to");
|
|
3898
3919
|
}
|
|
3899
3920
|
function changeTime(patch) {
|
|
@@ -3901,9 +3922,18 @@ function DatePicker(props) {
|
|
|
3901
3922
|
props.onChange(formatValue(clampParts({ ...baseFor(null), ...patch }, minParts, maxParts), granularity));
|
|
3902
3923
|
return;
|
|
3903
3924
|
}
|
|
3904
|
-
const next = formatValue(clampParts({ ...baseFor(activeEnd), ...patch }, editMin,
|
|
3925
|
+
const next = formatValue(clampParts({ ...baseFor(activeEnd), ...patch }, editMin, editMax), granularity);
|
|
3905
3926
|
commitRange(activeEnd === "from" ? { from: next, to: draft.to } : { from: draft.from, to: next }, activeEnd);
|
|
3906
3927
|
}
|
|
3928
|
+
function activateEnd(end, kind) {
|
|
3929
|
+
setActiveEnd(end);
|
|
3930
|
+
const parts = end === "from" ? fromParts : toParts;
|
|
3931
|
+
if (!parts) return;
|
|
3932
|
+
const shown = kind === "popover" && popoverKind === "dayRange" ? 2 : 1;
|
|
3933
|
+
const offset = (parts.year - view.year) * 12 + parts.month - view.month;
|
|
3934
|
+
if (offset < 0 || offset >= shown) setView({ year: parts.year, month: parts.month });
|
|
3935
|
+
setFocusDay({ ...parts, hour: 0, minute: 0 });
|
|
3936
|
+
}
|
|
3907
3937
|
const endPlaceholder = minute ? "\uC885\uB8CC \uC77C\uC2DC" : "\uC885\uB8CC\uC77C";
|
|
3908
3938
|
let summary;
|
|
3909
3939
|
let summaryText = "";
|
|
@@ -3995,11 +4025,25 @@ function DatePicker(props) {
|
|
|
3995
4025
|
}
|
|
3996
4026
|
);
|
|
3997
4027
|
const today = todayParts(now);
|
|
4028
|
+
const preview = (() => {
|
|
4029
|
+
if (!range || !pointDay || dayDisabled(pointDay)) return null;
|
|
4030
|
+
const edited = activeEnd === "from" ? fromParts : toParts;
|
|
4031
|
+
if (edited && sameDay(pointDay, edited)) return null;
|
|
4032
|
+
if (activeEnd === "to" && fromParts) {
|
|
4033
|
+
return dayKey(pointDay) < dayKey(fromParts) ? { from: pointDay, to: fromParts, kept: fromParts } : { from: fromParts, to: pointDay, kept: fromParts };
|
|
4034
|
+
}
|
|
4035
|
+
if (activeEnd === "from" && toParts && dayKey(pointDay) <= dayKey(toParts) && (maxDays === void 0 || daysBetween(pointDay, toParts) <= maxDays - 1)) {
|
|
4036
|
+
return { from: pointDay, to: toParts, kept: toParts };
|
|
4037
|
+
}
|
|
4038
|
+
return null;
|
|
4039
|
+
})();
|
|
3998
4040
|
const selectedFor = (cell) => {
|
|
3999
4041
|
if (!range) return Boolean(singleParts && sameDay(cell, singleParts));
|
|
4042
|
+
if (preview) return sameDay(cell, preview.kept);
|
|
4000
4043
|
return Boolean(fromParts && sameDay(cell, fromParts) || toParts && sameDay(cell, toParts));
|
|
4001
4044
|
};
|
|
4002
|
-
const inRange = (cell) => Boolean(range && fromParts && toParts && dayKey(cell) > dayKey(fromParts) && dayKey(cell) < dayKey(toParts));
|
|
4045
|
+
const inRange = (cell) => Boolean(range && !preview && fromParts && toParts && dayKey(cell) > dayKey(fromParts) && dayKey(cell) < dayKey(toParts));
|
|
4046
|
+
const inPreview = (cell) => Boolean(preview && !sameDay(cell, preview.kept) && dayKey(cell) >= dayKey(preview.from) && dayKey(cell) <= dayKey(preview.to));
|
|
4003
4047
|
const focusCalendar = React19.useRef(false);
|
|
4004
4048
|
React19.useEffect(() => {
|
|
4005
4049
|
const active = typeof document !== "undefined" ? document.activeElement : null;
|
|
@@ -4032,6 +4076,7 @@ function DatePicker(props) {
|
|
|
4032
4076
|
{
|
|
4033
4077
|
kind,
|
|
4034
4078
|
baseId,
|
|
4079
|
+
months: kind === "popover" && popoverKind === "dayRange" ? 2 : 1,
|
|
4035
4080
|
view,
|
|
4036
4081
|
onView: setView,
|
|
4037
4082
|
focusDay,
|
|
@@ -4040,6 +4085,8 @@ function DatePicker(props) {
|
|
|
4040
4085
|
isDisabled: dayDisabled,
|
|
4041
4086
|
isSelected: selectedFor,
|
|
4042
4087
|
isInRange: inRange,
|
|
4088
|
+
isPreview: inPreview,
|
|
4089
|
+
onPoint: setPointDay,
|
|
4043
4090
|
onSelect: selectDay
|
|
4044
4091
|
}
|
|
4045
4092
|
);
|
|
@@ -4049,12 +4096,14 @@ function DatePicker(props) {
|
|
|
4049
4096
|
const timeRowValue = editing ? `${pad22(editing.hour)}:${pad22(editing.minute)}` : "-";
|
|
4050
4097
|
const panel = (kind) => /* @__PURE__ */ jsxs14("div", { "data-slot": "date-picker-panel", "data-layer": kind, "data-picker": baseId, className: "flex flex-col", children: [
|
|
4051
4098
|
popoverHeader != null ? /* @__PURE__ */ jsx16("div", { className: "mb-[var(--space-3)]", children: popoverHeader }) : null,
|
|
4052
|
-
range
|
|
4099
|
+
range ? /* @__PURE__ */ jsx16(
|
|
4053
4100
|
EndTabs,
|
|
4054
4101
|
{
|
|
4055
4102
|
kind,
|
|
4103
|
+
names: minute ? ["\uC2DC\uC791 \uC77C\uC2DC", "\uC885\uB8CC \uC77C\uC2DC"] : ["\uC2DC\uC791\uC77C", "\uC885\uB8CC\uC77C"],
|
|
4104
|
+
locked: lockStart ? "from" : void 0,
|
|
4056
4105
|
active: activeEnd,
|
|
4057
|
-
onActivate:
|
|
4106
|
+
onActivate: (end) => activateEnd(end, kind),
|
|
4058
4107
|
from: fromParts ? formatSingle(shownRange.from, granularity, now) : "",
|
|
4059
4108
|
to: toParts ? formatSingle(shownRange.to, granularity, now) : ""
|
|
4060
4109
|
}
|
|
@@ -4093,7 +4142,7 @@ function DatePicker(props) {
|
|
|
4093
4142
|
) : null
|
|
4094
4143
|
] })
|
|
4095
4144
|
] });
|
|
4096
|
-
const
|
|
4145
|
+
const picker = /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
4097
4146
|
/* @__PURE__ */ jsxs14(Popover, { open: open && layer === "popover", onOpenChange: handleOpenChange, children: [
|
|
4098
4147
|
/* @__PURE__ */ jsx16(PopoverAnchor, { asChild: true, children: trigger }),
|
|
4099
4148
|
/* @__PURE__ */ jsx16(
|
|
@@ -4102,7 +4151,7 @@ function DatePicker(props) {
|
|
|
4102
4151
|
align,
|
|
4103
4152
|
sideOffset: 4,
|
|
4104
4153
|
collisionPadding: COLLISION_PADDING,
|
|
4105
|
-
className: cn("p-[var(--space-3)]",
|
|
4154
|
+
className: cn("p-[var(--space-3)]", { day: "w-[280px]", dayRange: "w-[558px]", minute: "w-[424px]" }[popoverKind]),
|
|
4106
4155
|
"aria-label": titleText,
|
|
4107
4156
|
onOpenAutoFocus: (event) => {
|
|
4108
4157
|
event.preventDefault();
|
|
@@ -4125,6 +4174,34 @@ function DatePicker(props) {
|
|
|
4125
4174
|
] }),
|
|
4126
4175
|
/* @__PURE__ */ jsx16(Dialog, { open: open && layer === "sheet", onOpenChange: handleOpenChange, title: titleText, size: "sm", children: /* @__PURE__ */ jsx16("div", { className: "mx-auto w-full max-w-[360px]", children: panel("sheet") }) })
|
|
4127
4176
|
] });
|
|
4177
|
+
const stepSize = { sm: "sm", md: "md", lg: "lg" };
|
|
4178
|
+
const control = onStep ? /* @__PURE__ */ jsxs14("div", { "data-slot": "date-picker-stepper", className: cn("flex items-center gap-[var(--space-1)]", fullWidth ? "w-full" : "w-fit"), children: [
|
|
4179
|
+
/* @__PURE__ */ jsx16(
|
|
4180
|
+
IconButton,
|
|
4181
|
+
{
|
|
4182
|
+
icon: ChevronLeft,
|
|
4183
|
+
appearance: "outline",
|
|
4184
|
+
tone: "neutral",
|
|
4185
|
+
size: stepSize[size],
|
|
4186
|
+
"aria-label": "\uC774\uC804 \uAE30\uAC04",
|
|
4187
|
+
disabled: disabled || prevStepDisabled,
|
|
4188
|
+
onClick: () => onStep(-1)
|
|
4189
|
+
}
|
|
4190
|
+
),
|
|
4191
|
+
/* @__PURE__ */ jsx16("div", { className: cn("min-w-0", fullWidth && "flex-1"), children: picker }),
|
|
4192
|
+
/* @__PURE__ */ jsx16(
|
|
4193
|
+
IconButton,
|
|
4194
|
+
{
|
|
4195
|
+
icon: ChevronRight,
|
|
4196
|
+
appearance: "outline",
|
|
4197
|
+
tone: "neutral",
|
|
4198
|
+
size: stepSize[size],
|
|
4199
|
+
"aria-label": "\uB2E4\uC74C \uAE30\uAC04",
|
|
4200
|
+
disabled: disabled || nextStepDisabled,
|
|
4201
|
+
onClick: () => onStep(1)
|
|
4202
|
+
}
|
|
4203
|
+
)
|
|
4204
|
+
] }) : picker;
|
|
4128
4205
|
if (!topLabel && !showDescription && !showMessage) return control;
|
|
4129
4206
|
return /* @__PURE__ */ jsxs14("div", { "data-slot": "date-picker-field", className: cn("flex flex-col gap-[var(--space-1)]", fullWidth ? "w-full" : "w-fit"), children: [
|
|
4130
4207
|
topLabel ? /* @__PURE__ */ jsx16(
|
|
@@ -4148,51 +4225,69 @@ function DatePicker(props) {
|
|
|
4148
4225
|
DatePicker.displayName = "DatePicker";
|
|
4149
4226
|
function EndTabs({
|
|
4150
4227
|
kind,
|
|
4228
|
+
names,
|
|
4229
|
+
locked,
|
|
4151
4230
|
active,
|
|
4152
4231
|
onActivate,
|
|
4153
4232
|
from,
|
|
4154
4233
|
to
|
|
4155
4234
|
}) {
|
|
4156
4235
|
const ends = [
|
|
4157
|
-
{ end: "from", name:
|
|
4158
|
-
{ end: "to", name:
|
|
4236
|
+
{ end: "from", name: names[0], value: from },
|
|
4237
|
+
{ end: "to", name: names[1], value: to }
|
|
4159
4238
|
];
|
|
4160
|
-
return /* @__PURE__ */ jsx16("div", { "data-slot": "date-picker-ends", className: cn("mb-[var(--space-3)] grid grid-cols-2 gap-[var(--space-2)]", kind === "sheet" && "mb-[var(--space-4)]"), children: ends.map(({ end, name, value }) =>
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4239
|
+
return /* @__PURE__ */ jsx16("div", { "data-slot": "date-picker-ends", className: cn("mb-[var(--space-3)] grid grid-cols-2 gap-[var(--space-2)]", kind === "sheet" && "mb-[var(--space-4)]"), children: ends.map(({ end, name, value }) => {
|
|
4240
|
+
const isLocked = locked === end;
|
|
4241
|
+
return /* @__PURE__ */ jsxs14(
|
|
4242
|
+
"button",
|
|
4243
|
+
{
|
|
4244
|
+
type: "button",
|
|
4245
|
+
"data-slot": "date-picker-end",
|
|
4246
|
+
"aria-pressed": active === end,
|
|
4247
|
+
disabled: isLocked,
|
|
4248
|
+
onClick: () => onActivate(end),
|
|
4249
|
+
className: cn(
|
|
4250
|
+
"flex min-w-0 flex-col items-start rounded-[var(--radius-md)] border px-[var(--space-3)] py-[var(--space-2)] text-left",
|
|
4251
|
+
"outline-none focus-visible:shadow-[0_0_0_2px_var(--focus-ring)]",
|
|
4252
|
+
isLocked ? "cursor-not-allowed border-[var(--border)] bg-[var(--action-disabled-bg)]" : active === end ? "border-[var(--border-strong)] bg-[var(--action-selected)]" : "border-[var(--border)] hover:bg-[var(--action-hover)]"
|
|
4253
|
+
),
|
|
4254
|
+
children: [
|
|
4255
|
+
/* @__PURE__ */ jsxs14("span", { className: "flex w-full items-center justify-between gap-[var(--space-1)] text-[11px] leading-snug text-text-tertiary", children: [
|
|
4256
|
+
/* @__PURE__ */ jsx16("span", { children: name }),
|
|
4257
|
+
isLocked ? /* @__PURE__ */ jsx16(Lock, { "aria-hidden": "true", size: 12, strokeWidth: 2, className: "shrink-0" }) : null
|
|
4258
|
+
] }),
|
|
4259
|
+
/* @__PURE__ */ jsx16(
|
|
4260
|
+
"span",
|
|
4261
|
+
{
|
|
4262
|
+
className: cn(
|
|
4263
|
+
"w-full truncate text-[13px] font-semibold leading-snug font-numeric tabular-nums",
|
|
4264
|
+
isLocked ? "text-text-disabled" : value ? "text-foreground" : "text-text-tertiary"
|
|
4265
|
+
),
|
|
4266
|
+
children: value || "-"
|
|
4267
|
+
}
|
|
4268
|
+
)
|
|
4269
|
+
]
|
|
4270
|
+
},
|
|
4271
|
+
end
|
|
4272
|
+
);
|
|
4273
|
+
}) });
|
|
4179
4274
|
}
|
|
4180
|
-
function Calendar({ kind, baseId, view, onView, focusDay, onFocusDay, today, isDisabled, isSelected, isInRange, onSelect }) {
|
|
4181
|
-
const
|
|
4275
|
+
function Calendar({ kind, baseId, months, view, onView, focusDay, onFocusDay, today, isDisabled, isSelected, isInRange, isPreview, onPoint, onSelect }) {
|
|
4276
|
+
const rootRef = React19.useRef(null);
|
|
4182
4277
|
const focusPending = React19.useRef(false);
|
|
4183
|
-
const
|
|
4184
|
-
const
|
|
4185
|
-
const
|
|
4186
|
-
const tabbable = focusDay.year === view.year && focusDay.month === view.month ? focusDay : { ...focusDay, year: view.year, month: view.month, day: 1 };
|
|
4278
|
+
const shown = Array.from({ length: months }, (_, index) => addMonths(view.year, view.month, index));
|
|
4279
|
+
const inView = (day) => shown.some((month) => month.year === day.year && month.month === day.month);
|
|
4280
|
+
const tabbable = inView(focusDay) ? focusDay : { ...focusDay, year: view.year, month: view.month, day: 1 };
|
|
4187
4281
|
React19.useEffect(() => {
|
|
4188
4282
|
if (!focusPending.current) return;
|
|
4189
4283
|
focusPending.current = false;
|
|
4190
|
-
|
|
4284
|
+
rootRef.current?.querySelector(`[data-date="${isoDay(focusDay)}"]`)?.focus();
|
|
4191
4285
|
});
|
|
4192
4286
|
function move(next) {
|
|
4193
4287
|
focusPending.current = true;
|
|
4194
4288
|
onFocusDay(next);
|
|
4195
|
-
if (next
|
|
4289
|
+
if (inView(next)) return;
|
|
4290
|
+
onView(dayKey(next) < dayKey({ ...view, day: 1 }) ? { year: next.year, month: next.month } : addMonths(next.year, next.month, 1 - months));
|
|
4196
4291
|
}
|
|
4197
4292
|
function moveMonth(delta) {
|
|
4198
4293
|
onView(addMonths(view.year, view.month, delta));
|
|
@@ -4216,61 +4311,100 @@ function Calendar({ kind, baseId, view, onView, focusDay, onFocusDay, today, isD
|
|
|
4216
4311
|
move(target());
|
|
4217
4312
|
}
|
|
4218
4313
|
const sheet = kind === "sheet";
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
"
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4314
|
+
const navSize = sheet ? "md" : "xs";
|
|
4315
|
+
const headingId = (index) => index === 0 ? `${baseId}-month` : `${baseId}-month-${index + 1}`;
|
|
4316
|
+
const width = sheet ? "w-full" : "w-[256px]";
|
|
4317
|
+
const blankOutside = months > 1;
|
|
4318
|
+
return /* @__PURE__ */ jsxs14("div", { ref: rootRef, "data-slot": "date-picker-calendar", className: cn("flex flex-col", sheet ? "w-full" : "shrink-0"), children: [
|
|
4319
|
+
/* @__PURE__ */ jsx16("div", { className: "flex gap-[var(--space-5)]", children: shown.map((month, index) => (
|
|
4320
|
+
// Keyed by position, not month: the ‹ › pressed stays the same node and keeps focus.
|
|
4321
|
+
/* @__PURE__ */ jsxs14("div", { className: cn("flex items-center justify-between", width), children: [
|
|
4322
|
+
index === 0 ? /* @__PURE__ */ jsx16(IconButton, { icon: ChevronLeft, appearance: "ghost", tone: "neutral", size: navSize, "aria-label": "\uC774\uC804 \uB2EC", onClick: () => moveMonth(-1) }) : /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: "size-[28px]" }),
|
|
4323
|
+
/* @__PURE__ */ jsxs14("span", { id: headingId(index), "aria-live": "polite", className: "text-[13px] font-semibold text-text-primary font-numeric tabular-nums", children: [
|
|
4324
|
+
month.year,
|
|
4325
|
+
"\uB144 ",
|
|
4326
|
+
month.month,
|
|
4327
|
+
"\uC6D4"
|
|
4328
|
+
] }),
|
|
4329
|
+
index === months - 1 ? /* @__PURE__ */ jsx16(IconButton, { icon: ChevronRight, appearance: "ghost", tone: "neutral", size: navSize, "aria-label": "\uB2E4\uC74C \uB2EC", onClick: () => moveMonth(1) }) : /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: "size-[28px]" })
|
|
4330
|
+
] }, index)
|
|
4331
|
+
)) }),
|
|
4332
|
+
/* @__PURE__ */ jsx16(
|
|
4333
|
+
"div",
|
|
4334
|
+
{
|
|
4335
|
+
className: "mt-[var(--space-1)] flex gap-[var(--space-5)]",
|
|
4336
|
+
onMouseLeave: () => onPoint(null),
|
|
4337
|
+
onBlur: (event) => {
|
|
4338
|
+
if (!(event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget))) onPoint(null);
|
|
4339
|
+
},
|
|
4340
|
+
children: shown.map((month, index) => {
|
|
4341
|
+
const cells = buildCalendarCells(month.year, month.month).map((cell) => ({ ...cell, hour: 0, minute: 0 }));
|
|
4342
|
+
const weeks = Array.from({ length: 6 }, (_, week) => cells.slice(week * 7, week * 7 + 7));
|
|
4343
|
+
return /* @__PURE__ */ jsxs14(
|
|
4344
|
+
"div",
|
|
4345
|
+
{
|
|
4346
|
+
role: "grid",
|
|
4347
|
+
"aria-labelledby": headingId(index),
|
|
4348
|
+
"data-slot": "date-picker-grid",
|
|
4349
|
+
className: cn("flex flex-col gap-[2px]", width),
|
|
4350
|
+
children: [
|
|
4351
|
+
/* @__PURE__ */ jsx16("div", { role: "row", className: "grid grid-cols-7 gap-[2px]", children: WEEKDAYS.map((weekday) => /* @__PURE__ */ jsx16("span", { role: "columnheader", className: "py-[var(--space-1)] text-center text-[10px] font-semibold text-text-tertiary", children: weekday }, weekday)) }),
|
|
4352
|
+
weeks.map((week, row) => /* @__PURE__ */ jsx16("div", { role: "row", className: "grid grid-cols-7 gap-[2px]", children: week.map((cell) => {
|
|
4353
|
+
const outside = !cell.inMonth;
|
|
4354
|
+
if (outside && blankOutside) {
|
|
4355
|
+
return /* @__PURE__ */ jsx16("span", { role: "gridcell", "data-outside": "", className: "aspect-square" }, isoDay(cell));
|
|
4356
|
+
}
|
|
4357
|
+
const disabled = isDisabled(cell);
|
|
4358
|
+
const selected = !outside && isSelected(cell);
|
|
4359
|
+
const between = !outside && !selected && isInRange(cell);
|
|
4360
|
+
const previewed = !outside && !selected && isPreview(cell);
|
|
4361
|
+
const isToday = !outside && sameDay(cell, today);
|
|
4362
|
+
return /* @__PURE__ */ jsx16(
|
|
4363
|
+
"button",
|
|
4364
|
+
{
|
|
4365
|
+
type: "button",
|
|
4366
|
+
role: "gridcell",
|
|
4367
|
+
"data-date": outside ? void 0 : isoDay(cell),
|
|
4368
|
+
"data-selected": selected ? "" : void 0,
|
|
4369
|
+
"data-in-range": between ? "" : void 0,
|
|
4370
|
+
"data-preview": previewed ? "" : void 0,
|
|
4371
|
+
disabled: outside,
|
|
4372
|
+
tabIndex: !outside && sameDay(cell, tabbable) ? 0 : -1,
|
|
4373
|
+
"aria-label": `${cell.year}\uB144 ${cell.month}\uC6D4 ${cell.day}\uC77C`,
|
|
4374
|
+
"aria-selected": outside ? void 0 : selected,
|
|
4375
|
+
"aria-disabled": !outside && disabled ? true : void 0,
|
|
4376
|
+
"aria-current": isToday ? "date" : void 0,
|
|
4377
|
+
onClick: () => {
|
|
4378
|
+
if (outside || disabled) return;
|
|
4379
|
+
focusPending.current = false;
|
|
4380
|
+
onFocusDay(cell);
|
|
4381
|
+
onSelect(cell);
|
|
4382
|
+
},
|
|
4383
|
+
onKeyDown: (event) => onKeyDown(event, cell),
|
|
4384
|
+
onMouseEnter: () => onPoint(cell),
|
|
4385
|
+
onFocus: () => onPoint(cell),
|
|
4386
|
+
className: cn(
|
|
4387
|
+
"flex items-center justify-center rounded-[var(--radius-sm)] text-[12px] font-numeric tabular-nums outline-none",
|
|
4388
|
+
sheet ? "h-[40px] text-[14px]" : "aspect-square",
|
|
4389
|
+
"focus-visible:shadow-[0_0_0_2px_var(--focus-ring)]",
|
|
4390
|
+
outside || disabled ? "cursor-default text-text-disabled" : "cursor-pointer text-text-secondary hover:bg-[var(--action-hover)]",
|
|
4391
|
+
between && "bg-[var(--action-selected)] text-foreground",
|
|
4392
|
+
previewed && "bg-[var(--action-hover)] text-foreground shadow-[inset_0_1px_0_0_var(--border-strong),inset_0_-1px_0_0_var(--border-strong)]",
|
|
4393
|
+
isToday && !selected && "border border-[var(--border-strong)]",
|
|
4394
|
+
selected && "bg-[var(--primary)] font-bold text-[var(--primary-fg)] hover:bg-[var(--primary)]"
|
|
4395
|
+
),
|
|
4396
|
+
children: cell.day
|
|
4397
|
+
},
|
|
4398
|
+
isoDay(cell)
|
|
4399
|
+
);
|
|
4400
|
+
}) }, row))
|
|
4401
|
+
]
|
|
4257
4402
|
},
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
outside || disabled ? "cursor-default text-text-disabled" : "cursor-pointer text-text-secondary hover:bg-[var(--action-hover)]",
|
|
4264
|
-
between && "bg-[var(--action-selected)] text-foreground",
|
|
4265
|
-
isToday && !selected && "border border-[var(--border-strong)]",
|
|
4266
|
-
selected && "bg-[var(--primary)] font-bold text-[var(--primary-fg)] hover:bg-[var(--primary)]"
|
|
4267
|
-
),
|
|
4268
|
-
children: cell.day
|
|
4269
|
-
},
|
|
4270
|
-
isoDay(cell)
|
|
4271
|
-
);
|
|
4272
|
-
}) }, index))
|
|
4273
|
-
] })
|
|
4403
|
+
`${month.year}-${month.month}`
|
|
4404
|
+
);
|
|
4405
|
+
})
|
|
4406
|
+
}
|
|
4407
|
+
)
|
|
4274
4408
|
] });
|
|
4275
4409
|
}
|
|
4276
4410
|
function TimeColumns({ kind, baseId, editing, hasValue, centerKey, minuteStep, min, max, onChange, onEnter, autoFocus = false }) {
|
|
@@ -4328,15 +4462,10 @@ function TimeColumn({ kind, id, name, options, selected, centerKey, onSelect, on
|
|
|
4328
4462
|
if (!list || !item) return;
|
|
4329
4463
|
list.scrollTop = item.offsetTop - list.offsetTop - (list.clientHeight - item.offsetHeight) / 2;
|
|
4330
4464
|
}, [centerKey]);
|
|
4331
|
-
const
|
|
4465
|
+
const [focusAsk, setFocusAsk] = React19.useState(0);
|
|
4332
4466
|
React19.useEffect(() => {
|
|
4333
|
-
if (
|
|
4334
|
-
|
|
4335
|
-
pendingFocus.current = null;
|
|
4336
|
-
});
|
|
4337
|
-
function focusValue(value) {
|
|
4338
|
-
pendingFocus.current = value;
|
|
4339
|
-
}
|
|
4467
|
+
if (focusAsk) listRef.current?.querySelector('[aria-selected="true"]')?.focus();
|
|
4468
|
+
}, [focusAsk]);
|
|
4340
4469
|
function onKeyDown(event, value) {
|
|
4341
4470
|
if (event.key === "Enter") {
|
|
4342
4471
|
event.preventDefault();
|
|
@@ -4368,7 +4497,7 @@ function TimeColumn({ kind, id, name, options, selected, centerKey, onSelect, on
|
|
|
4368
4497
|
const next = target();
|
|
4369
4498
|
if (!next || next.value === value) return;
|
|
4370
4499
|
onSelect(next.value);
|
|
4371
|
-
|
|
4500
|
+
setFocusAsk((count) => count + 1);
|
|
4372
4501
|
}
|
|
4373
4502
|
const sheet = kind === "sheet";
|
|
4374
4503
|
return /* @__PURE__ */ jsxs14("div", { className: cn("flex flex-col", sheet ? "w-[88px]" : "h-full w-[56px]"), children: [
|
|
@@ -5621,7 +5750,7 @@ import * as React30 from "react";
|
|
|
5621
5750
|
import * as React29 from "react";
|
|
5622
5751
|
import { Tabs as TabsPrimitive } from "radix-ui";
|
|
5623
5752
|
import { cva as cva10 } from "class-variance-authority";
|
|
5624
|
-
import { Lock } from "lucide-react";
|
|
5753
|
+
import { Lock as Lock2 } from "lucide-react";
|
|
5625
5754
|
import { Fragment as Fragment10, jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
5626
5755
|
var tabsRootVariants = cva10("w-full", {
|
|
5627
5756
|
variants: {
|
|
@@ -5894,7 +6023,7 @@ var Tabs = React29.forwardRef(
|
|
|
5894
6023
|
/* @__PURE__ */ jsx26("span", { className: "sr-only", children: ` ${tab.badge}` })
|
|
5895
6024
|
] }) : null,
|
|
5896
6025
|
tab.disabled ? /* @__PURE__ */ jsx26(
|
|
5897
|
-
|
|
6026
|
+
Lock2,
|
|
5898
6027
|
{
|
|
5899
6028
|
"aria-hidden": "true",
|
|
5900
6029
|
"data-slot": "tabs-disabled-icon",
|