@mirohq/design-system-calendar 0.4.7 → 1.0.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/dist/module.js CHANGED
@@ -1,85 +1,220 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { Primitive } from '@mirohq/design-system-primitive';
3
- import { styled } from '@mirohq/design-system-stitches';
4
- import * as React from 'react';
5
- import React__default, { useRef, useCallback } from 'react';
6
- import { useDialog, usePopover, Overlay, DismissButton, useButton, useFocusRing, mergeProps, useDateFormatter, useCalendarCell, useLocale, useCalendarGrid, useDateRangePicker, useRangeCalendar, useCalendar, useDatePicker } from 'react-aria';
7
- import { isSameMonth, isSameDay, getDayOfWeek, isWeekend, isToday, getLocalTimeZone, getWeeksInMonth, createCalendar } from '@internationalized/date';
8
- import { useDateRangePickerState, useRangeCalendarState, useCalendarState, useDatePickerState } from 'react-stately';
9
- import { Flex } from '@mirohq/design-system-flex';
10
- import { Button as Button$1 } from '@mirohq/design-system-button';
11
- import { FloatingLabel } from '@mirohq/design-system-base-form';
12
- import { IconChevronLeft, IconChevronRight, IconCross, IconCalendarBlank } from '@mirohq/design-system-icons';
2
+ import React, { createContext, useState, useMemo, useCallback, useContext, useRef, useEffect } from 'react';
3
+ import { useButton, useFocusRing, mergeProps, useDateFormatter, useCalendarCell, useLocale, useCalendarGrid, useCalendar, useRangeCalendar, I18nProvider } from 'react-aria';
4
+ import * as RadixPopover from '@radix-ui/react-popover';
5
+ import { Trigger as Trigger$1, Content as Content$1 } from '@radix-ui/react-popover';
6
+ import { useFormFieldContext, FloatingLabel } from '@mirohq/design-system-base-form';
7
+ import { IconCross, IconCalendarBlank, IconChevronLeft, IconChevronRight } from '@mirohq/design-system-icons';
13
8
  import { useNewDesignLanguage } from '@mirohq/design-system-experiments';
9
+ import { stringAttrValue } from '@mirohq/design-system-utils';
10
+ import { Primitive } from '@mirohq/design-system-primitive';
11
+ import { styled, theme } from '@mirohq/design-system-stitches';
14
12
  import { textFieldStyles, actionButtonStyles } from '@mirohq/design-system-base-text-field';
15
- import { focus as focus$1 } from '@mirohq/design-system-styles';
16
- import { Tooltip } from '@mirohq/design-system-tooltip';
13
+ import { focus } from '@mirohq/design-system-styles';
17
14
  import { BaseButton } from '@mirohq/design-system-base-button';
15
+ import { Tooltip } from '@mirohq/design-system-tooltip';
16
+ import { useControllableState } from '@radix-ui/react-use-controllable-state';
17
+ import { useCalendarState, useRangeCalendarState } from 'react-stately';
18
+ import { isSameMonth, isSameDay, getDayOfWeek, isWeekend, isToday, getLocalTimeZone, getWeeksInMonth, createCalendar } from '@internationalized/date';
19
+ import { Flex } from '@mirohq/design-system-flex';
20
+ import { Button } from '@mirohq/design-system-button';
21
+
22
+ const StyledPlaceholder = styled(Primitive.span, {
23
+ ...textFieldStyles.base.placeholder.old,
24
+ padding: "0 $50"
25
+ });
26
+ const StyledValue$1 = styled(Primitive.span, {
27
+ padding: "0 $50"
28
+ });
29
+ const StyledTrigger = styled(BaseButton, {
30
+ display: "inline-flex",
31
+ gap: "$50",
32
+ justifyContent: "space-between",
33
+ alignItems: "center",
34
+ height: "$10",
35
+ padding: "0 $100",
36
+ minWidth: "230px",
37
+ ...textFieldStyles.variants.idle,
38
+ "& svg": {
39
+ color: "$text-neutrals-subtle",
40
+ square: "22px"
41
+ },
42
+ _hover: textFieldStyles.variants.hovered,
43
+ variants: {
44
+ v1: {
45
+ true: {
46
+ ...textFieldStyles.v1.idle,
47
+ ...focus.css(textFieldStyles.v1.focused)
48
+ },
49
+ false: {
50
+ ...focus.css(textFieldStyles.variants.focused)
51
+ }
52
+ },
53
+ withClearButton: {
54
+ true: {
55
+ paddingRight: "calc($100 + $400)"
56
+ // initial left padding + clear button width + gap
57
+ }
58
+ }
59
+ }
60
+ });
61
+ const StyledCustomTrigger = styled(BaseButton, {
62
+ width: "100%",
63
+ height: "unset",
64
+ padding: "0",
65
+ backgroundColor: "$transparent",
66
+ border: "none",
67
+ cursor: "pointer"
68
+ });
18
69
 
19
- const Popover = (props) => {
20
- const ref = React.useRef(null);
21
- const { state, children } = props;
22
- const { dialogProps } = useDialog(props, ref);
23
- const { popoverProps, underlayProps } = usePopover(
70
+ const StyledClearAction = styled(BaseButton, {
71
+ position: "absolute",
72
+ top: 0,
73
+ bottom: 0,
74
+ right: "calc($100 + 1px)",
75
+ // to compensate border width
76
+ margin: "auto",
77
+ ...actionButtonStyles
78
+ });
79
+
80
+ const ClearAction = React.forwardRef(({ "aria-label": ariaLabel, label, ...restProps }, forwardRef) => /* @__PURE__ */ jsxs(Tooltip, { children: [
81
+ /* @__PURE__ */ jsx(Tooltip.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
82
+ StyledClearAction,
24
83
  {
25
- ...props,
26
- popoverRef: ref
84
+ ...restProps,
85
+ ref: forwardRef,
86
+ "aria-label": ariaLabel != null ? ariaLabel : label,
87
+ children: /* @__PURE__ */ jsx(IconCross, {})
88
+ }
89
+ ) }),
90
+ /* @__PURE__ */ jsx(Tooltip.Content, { children: label })
91
+ ] }));
92
+
93
+ const CalendarContext = createContext({});
94
+ const CalendarProvider = ({
95
+ children,
96
+ visibleMonths = 1,
97
+ value: valueProp,
98
+ defaultValue: defaultValueProp,
99
+ onValueChange,
100
+ open: openProp,
101
+ defaultOpen: defaultOpenProp,
102
+ onOpen,
103
+ onClose,
104
+ ...restProps
105
+ }) => {
106
+ var _a;
107
+ const [immediateSave, setImmediateSave] = useState(false);
108
+ const [internalCalendarValue, setInternalCalendarValue] = useState(valueProp != null ? valueProp : defaultValueProp);
109
+ const visibleDuration = useMemo(
110
+ () => ({
111
+ months: visibleMonths
112
+ }),
113
+ [visibleMonths]
114
+ );
115
+ const [value, setValue] = useControllableState({
116
+ prop: valueProp,
117
+ defaultProp: defaultValueProp,
118
+ onChange: onValueChange
119
+ });
120
+ const [open = false, setOpen] = useControllableState({
121
+ prop: openProp,
122
+ defaultProp: defaultOpenProp,
123
+ onChange: (state) => {
124
+ if (state) {
125
+ onOpen == null ? void 0 : onOpen();
126
+ } else {
127
+ onClose == null ? void 0 : onClose();
128
+ }
129
+ }
130
+ });
131
+ const onCalendarDateClick = useCallback(
132
+ (value2) => {
133
+ if (immediateSave) {
134
+ setInternalCalendarValue(value2);
135
+ } else {
136
+ setValue(value2);
137
+ setOpen(false);
138
+ }
27
139
  },
28
- state
140
+ [setValue, setOpen, immediateSave, setInternalCalendarValue]
141
+ );
142
+ const onSaveClick = () => {
143
+ setValue(internalCalendarValue);
144
+ setOpen(false);
145
+ };
146
+ return /* @__PURE__ */ jsx(
147
+ CalendarContext.Provider,
148
+ {
149
+ value: {
150
+ ...restProps,
151
+ visibleDuration,
152
+ value,
153
+ setValue,
154
+ open,
155
+ setOpen,
156
+ onCalendarDateClick,
157
+ setImmediateSave,
158
+ onSaveClick,
159
+ // value should not be undefined otherwise react-aria calendar will complain in console
160
+ calendarValue: (_a = immediateSave ? internalCalendarValue : value) != null ? _a : null
161
+ },
162
+ children
163
+ }
29
164
  );
30
- return /* @__PURE__ */ jsxs(Overlay, { children: [
31
- /* @__PURE__ */ jsx("div", { ...underlayProps }),
32
- /* @__PURE__ */ jsxs("div", { ...popoverProps, ref, children: [
33
- /* @__PURE__ */ jsx(DismissButton, { onDismiss: state.close }),
34
- /* @__PURE__ */ jsx("div", { ...dialogProps, ref, children }),
35
- /* @__PURE__ */ jsx(DismissButton, { onDismiss: state.close })
36
- ] })
37
- ] });
38
165
  };
166
+ const useCalendarContext = () => useContext(CalendarContext);
39
167
 
40
- const StyledGroup = styled(Primitive.div, {
41
- position: "relative"
42
- });
43
- const StyledPicker = styled(Primitive.div, {});
44
-
45
- const StyledPredefinedRanges = styled(Primitive.div, {
46
- display: "flex",
47
- flexDirection: "column",
48
- borderRight: "1px solid $border-neutrals",
49
- padding: "$300 $200 0 $200",
50
- "& button": {
51
- backgroundColor: "$transparent",
52
- border: "none",
53
- fontSize: "$200",
54
- padding: "0 0 0 $100",
55
- textAlign: "left",
56
- lineHeight: "24px",
57
- color: "$text-neutrals",
58
- marginBottom: "$150",
59
- borderRadius: "$50",
60
- minWidth: "125px",
61
- cursor: "pointer",
62
- "&:hover": {
63
- backgroundColor: "$background-primary-prominent-hover",
64
- color: "$text-primary-inverted",
65
- fontWeight: "600"
168
+ const Trigger = React.forwardRef(
169
+ ({
170
+ id,
171
+ "aria-describedby": ariaDescribedBy,
172
+ placeholder,
173
+ asChild = false,
174
+ clearable = true,
175
+ clearLabel,
176
+ onClear,
177
+ children,
178
+ ...restProps
179
+ }, forwardRef) => {
180
+ const [v1] = useNewDesignLanguage();
181
+ const { value, setValue } = useCalendarContext();
182
+ const { formElementId, ariaDescribedBy: formFieldContextDescribedBy } = useFormFieldContext();
183
+ if (asChild) {
184
+ return /* @__PURE__ */ jsx(Trigger$1, { ref: forwardRef, asChild: true, children: /* @__PURE__ */ jsx(StyledCustomTrigger, { asChild: true, ...restProps, children }) });
66
185
  }
186
+ const onClearHandler = () => {
187
+ setValue(void 0);
188
+ if (onClear !== void 0) {
189
+ onClear();
190
+ }
191
+ };
192
+ const clearButtonVisible = clearable && value != null && clearLabel !== void 0;
193
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
194
+ /* @__PURE__ */ jsx(Trigger$1, { ref: forwardRef, asChild: true, children: /* @__PURE__ */ jsxs(
195
+ StyledTrigger,
196
+ {
197
+ id: id != null ? id : formElementId,
198
+ "aria-describedby": stringAttrValue(
199
+ ariaDescribedBy,
200
+ formFieldContextDescribedBy
201
+ ),
202
+ v1,
203
+ withClearButton: clearButtonVisible,
204
+ ...restProps,
205
+ children: [
206
+ value != null ? /* @__PURE__ */ jsx(StyledValue$1, { children }) : /* @__PURE__ */ jsx(StyledPlaceholder, { children: placeholder }),
207
+ !clearButtonVisible && /* @__PURE__ */ jsx(IconCalendarBlank, { weight: "thin" })
208
+ ]
209
+ }
210
+ ) }),
211
+ clearButtonVisible && /* @__PURE__ */ jsx(ClearAction, { label: clearLabel, onPress: onClearHandler })
212
+ ] });
67
213
  }
68
- });
69
-
70
- const PredefinedRanges = React__default.forwardRef(({ range, onClick }, forwardRef) => /* @__PURE__ */ jsx(StyledPredefinedRanges, { ref: forwardRef, children: range == null ? void 0 : range.map((date, i) => /* @__PURE__ */ jsx(
71
- Button$1,
72
- {
73
- variant: "ghost",
74
- size: "medium",
75
- type: "button",
76
- onClick: () => onClick(date),
77
- children: date.label
78
- },
79
- i
80
- )) }));
214
+ );
81
215
 
82
- const StyledBody = styled(Primitive.div, {
216
+ const StyledContent = styled(Content$1, {
217
+ zIndex: "$calendar",
83
218
  display: "inline-block",
84
219
  background: "$background-neutrals"
85
220
  });
@@ -109,11 +244,23 @@ const StyledBodyContentRight = styled(Primitive.div, {
109
244
  paddingRight: "$200"
110
245
  });
111
246
  const StyledClearContent = styled(Primitive.div, {
247
+ display: "flex",
248
+ gap: "$100",
112
249
  padding: "$200",
113
250
  borderTop: "1px solid $border-neutrals"
114
251
  });
115
252
 
116
- const StyledButton = styled(Primitive.button, {
253
+ const StyledHeaderTitle = styled(Flex, {
254
+ justifyContent: "center",
255
+ flex: "3",
256
+ color: "$text-neutrals"
257
+ });
258
+ const StyledHeader = styled(Flex, {
259
+ padding: "0 $200",
260
+ color: "$text-neutrals"
261
+ });
262
+
263
+ const StyledHeaderButton = styled(Primitive.button, {
117
264
  padding: "0",
118
265
  backgroundColor: "$transparent",
119
266
  border: "none",
@@ -124,21 +271,18 @@ const StyledButton = styled(Primitive.button, {
124
271
  }
125
272
  });
126
273
 
127
- const Button = React__default.forwardRef((props, forwardRef) => {
274
+ const HeaderButton = React.forwardRef((props, forwardRef) => {
128
275
  const { buttonProps } = useButton(props, forwardRef);
129
276
  const { focusProps } = useFocusRing();
130
277
  const { children } = props;
131
- return /* @__PURE__ */ jsx(StyledButton, { ...mergeProps(buttonProps, focusProps), ref: forwardRef, children });
132
- });
133
-
134
- const StyledHeaderTitle = styled(Flex, {
135
- justifyContent: "center",
136
- flex: "3",
137
- color: "$text-neutrals"
138
- });
139
- const StyledHeader = styled(Flex, {
140
- padding: "0 $200",
141
- color: "$text-neutrals"
278
+ return /* @__PURE__ */ jsx(
279
+ StyledHeaderButton,
280
+ {
281
+ ...mergeProps(buttonProps, focusProps),
282
+ ref: forwardRef,
283
+ children
284
+ }
285
+ );
142
286
  });
143
287
 
144
288
  const Header = ({
@@ -153,14 +297,14 @@ const Header = ({
153
297
  timeZone: state.timeZone
154
298
  });
155
299
  return /* @__PURE__ */ jsxs(StyledHeader, { children: [
156
- /* @__PURE__ */ jsx(Button, { ...prevButtonProps, children: /* @__PURE__ */ jsx(IconChevronLeft, {}) }),
300
+ /* @__PURE__ */ jsx(HeaderButton, { ...prevButtonProps, children: /* @__PURE__ */ jsx(IconChevronLeft, {}) }),
157
301
  /* @__PURE__ */ jsx(StyledHeaderTitle, { children: /* @__PURE__ */ jsx("h2", { children: monthDateFormatter.format(
158
302
  state.visibleRange.start.toDate(state.timeZone)
159
303
  ) }) }),
160
- visibleMonths !== void 0 && /* @__PURE__ */ jsx(StyledHeaderTitle, { children: /* @__PURE__ */ jsx("h2", { children: monthDateFormatter.format(
304
+ visibleMonths === 2 && /* @__PURE__ */ jsx(StyledHeaderTitle, { children: /* @__PURE__ */ jsx("h2", { children: monthDateFormatter.format(
161
305
  state.visibleRange.start.add({ months: 1 }).toDate(state.timeZone)
162
306
  ) }) }),
163
- /* @__PURE__ */ jsx(Button, { ...nextButtonProps, children: /* @__PURE__ */ jsx(IconChevronRight, {}) })
307
+ /* @__PURE__ */ jsx(HeaderButton, { ...nextButtonProps, children: /* @__PURE__ */ jsx(IconChevronRight, {}) })
164
308
  ] });
165
309
  };
166
310
 
@@ -230,45 +374,43 @@ const StyledCell = styled(Primitive.div, {
230
374
  }
231
375
  });
232
376
 
233
- const Cell = React__default.forwardRef(
234
- (props, forwardRef) => {
235
- const { state, date, currentMonth } = props;
236
- const ref = useRef(null);
237
- const { cellProps, buttonProps, isSelected, isDisabled, formattedDate } = useCalendarCell({ date }, state, ref);
238
- const isOutsideMonth = !isSameMonth(currentMonth, date);
239
- const isSelectionStart = state.highlightedRange !== void 0 && state.highlightedRange !== null ? isSameDay(date, state.highlightedRange.start) : isSelected;
240
- const isSelectionEnd = state.highlightedRange !== void 0 && state.highlightedRange !== null ? isSameDay(date, state.highlightedRange.end) : isSelected;
241
- const { locale } = useLocale();
242
- const dayOfWeek = getDayOfWeek(date, locale);
243
- const isWeekendDay = isWeekend(date, locale);
244
- const isRoundedLeft = isSelected && (isSelectionStart || dayOfWeek === 0 || date.day === 1);
245
- const isRoundedRight = isSelected && (isSelectionEnd || dayOfWeek === 6 || date.day === date.calendar.getDaysInMonth(date));
246
- const { focusProps } = useFocusRing();
247
- return /* @__PURE__ */ jsx("td", { ...cellProps, children: /* @__PURE__ */ jsx(
248
- StyledCell,
249
- {
250
- ...mergeProps(buttonProps, focusProps),
251
- ref: forwardRef,
252
- "data-selected": isSelected ? "" : void 0,
253
- "data-selection-start": isRoundedLeft ? "" : void 0,
254
- "data-selection-end": isRoundedRight ? "" : void 0,
255
- "data-disabled": isDisabled ? "" : void 0,
256
- "data-hidden": isOutsideMonth ? "" : void 0,
257
- children: /* @__PURE__ */ jsx(
258
- StyledCellContent,
259
- {
260
- "data-selected-middle": isSelected && !(isSelectionStart || isSelectionEnd) ? "" : void 0,
261
- "data-selection": isSelectionStart || isSelectionEnd ? "" : void 0,
262
- "data-disabled": isDisabled ? "" : void 0,
263
- "data-today": isToday(date, getLocalTimeZone()) ? "" : void 0,
264
- "data-weekend": isWeekendDay ? "" : void 0,
265
- children: formattedDate
266
- }
267
- )
268
- }
269
- ) });
270
- }
271
- );
377
+ const Cell = (props) => {
378
+ const { state, date, currentMonth } = props;
379
+ const ref = useRef(null);
380
+ const { cellProps, buttonProps, isSelected, isDisabled, formattedDate } = useCalendarCell({ date }, state, ref);
381
+ const isOutsideMonth = !isSameMonth(currentMonth, date);
382
+ const isSelectionStart = state.highlightedRange !== void 0 && state.highlightedRange !== null ? isSameDay(date, state.highlightedRange.start) : isSelected;
383
+ const isSelectionEnd = state.highlightedRange !== void 0 && state.highlightedRange !== null ? isSameDay(date, state.highlightedRange.end) : isSelected;
384
+ const { locale } = useLocale();
385
+ const dayOfWeek = getDayOfWeek(date, locale);
386
+ const isWeekendDay = isWeekend(date, locale);
387
+ const isRoundedLeft = isSelected && (isSelectionStart || dayOfWeek === 0 || date.day === 1);
388
+ const isRoundedRight = isSelected && (isSelectionEnd || dayOfWeek === 6 || date.day === date.calendar.getDaysInMonth(date));
389
+ const { focusProps } = useFocusRing();
390
+ return /* @__PURE__ */ jsx("td", { ...cellProps, children: /* @__PURE__ */ jsx(
391
+ StyledCell,
392
+ {
393
+ ...mergeProps(buttonProps, focusProps),
394
+ ref,
395
+ "data-selected": isSelected ? "" : void 0,
396
+ "data-selection-start": isRoundedLeft ? "" : void 0,
397
+ "data-selection-end": isRoundedRight ? "" : void 0,
398
+ "data-disabled": isDisabled ? "" : void 0,
399
+ "data-hidden": isOutsideMonth ? "" : void 0,
400
+ children: /* @__PURE__ */ jsx(
401
+ StyledCellContent,
402
+ {
403
+ "data-selected-middle": isSelected && !(isSelectionStart || isSelectionEnd) ? "" : void 0,
404
+ "data-selection": isSelectionStart || isSelectionEnd ? "" : void 0,
405
+ "data-disabled": isDisabled ? "" : void 0,
406
+ "data-today": isToday(date, getLocalTimeZone()) ? "" : void 0,
407
+ "data-weekend": isWeekendDay ? "" : void 0,
408
+ children: formattedDate
409
+ }
410
+ )
411
+ }
412
+ ) });
413
+ };
272
414
 
273
415
  const StyledGrid = styled(Primitive.table, {
274
416
  borderCollapse: "separate",
@@ -279,7 +421,7 @@ const StyledDays = styled(Primitive.th, {
279
421
  color: "$text-neutrals"
280
422
  });
281
423
 
282
- const Grid = React__default.forwardRef(
424
+ const Grid = React.forwardRef(
283
425
  (props, forwardRef) => {
284
426
  const { locale } = useLocale();
285
427
  const { state, offset = {} } = props;
@@ -306,411 +448,269 @@ const Grid = React__default.forwardRef(
306
448
  }
307
449
  );
308
450
 
309
- const StyledPlaceholder = styled(Primitive.span, {
310
- ...textFieldStyles.base.placeholder.old,
311
- padding: "0 $50"
312
- });
313
- const StyledValue = styled(Primitive.span, {
314
- padding: "0 $50"
315
- });
316
- const StyledTriggerContainer = styled(Primitive.div, {
317
- position: "relative"
318
- });
319
- const StyledTrigger = styled(Primitive.button, {
320
- all: "unset",
321
- display: "inline-flex",
322
- gap: "$50",
323
- justifyContent: "space-between",
324
- alignItems: "center",
325
- height: "$10",
326
- padding: "0 $100",
327
- minWidth: "230px",
328
- ...textFieldStyles.variants.idle,
329
- "& svg": {
330
- color: "$text-neutrals-subtle",
331
- square: "22px"
332
- },
333
- _hover: textFieldStyles.variants.hovered,
334
- variants: {
335
- v1: {
336
- true: {
337
- ...textFieldStyles.v1.idle,
338
- ...focus$1.css(textFieldStyles.v1.focused)
339
- },
340
- false: {
341
- ...focus$1.css(textFieldStyles.variants.focused)
342
- }
343
- },
344
- withClearButton: {
345
- true: {
346
- paddingRight: "calc($100 + $400)"
347
- // initial left padding + clear button width + gap
348
- }
349
- }
350
- }
351
- });
352
- const StyledCustomTrigger = styled(Primitive.button, {
353
- width: "100%",
354
- height: "unset",
355
- padding: "0",
356
- backgroundColor: "$transparent",
357
- border: "none",
358
- cursor: "pointer"
359
- });
360
-
361
- const StyledClearButton = styled(BaseButton, {
362
- position: "absolute",
363
- top: 0,
364
- bottom: 0,
365
- right: "calc($100 + 1px)",
366
- // to compensate border width
367
- margin: "auto",
368
- ...actionButtonStyles
369
- });
370
-
371
- const ClearButton = React__default.forwardRef(({ "aria-label": ariaLabel, label, ...restProps }, forwardRef) => /* @__PURE__ */ jsxs(Tooltip, { children: [
372
- /* @__PURE__ */ jsx(Tooltip.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
373
- StyledClearButton,
374
- {
375
- ...restProps,
376
- ref: forwardRef,
377
- "aria-label": ariaLabel != null ? ariaLabel : label,
378
- children: /* @__PURE__ */ jsx(IconCross, {})
379
- }
380
- ) }),
381
- /* @__PURE__ */ jsx(Tooltip.Content, { children: label })
382
- ] }));
383
-
384
- function dateToString(value) {
385
- if (value == null) {
386
- return void 0;
387
- }
388
- if ("start" in value) {
389
- if (value.start == null || value.end == null) {
390
- return void 0;
391
- }
392
- return "".concat(value.start, " - ").concat(value.end);
393
- }
394
- return value.toString();
395
- }
396
- const Trigger = React__default.forwardRef(
397
- ({
398
- placeholder,
399
- displayValue,
400
- stateValue,
401
- asChild = false,
402
- clearable = true,
403
- clearActionLabel,
404
- onClear,
405
- ...restProps
406
- }, forwardRef) => {
407
- const [v1] = useNewDesignLanguage();
408
- const { buttonProps } = useButton(
409
- restProps,
410
- forwardRef
411
- );
412
- const { children } = restProps;
413
- if (asChild) {
414
- return /* @__PURE__ */ jsx(StyledCustomTrigger, { ...buttonProps, children });
415
- }
416
- const valueToDisplay = displayValue != null ? displayValue : dateToString(stateValue);
417
- const clearButtonVisible = clearable && clearActionLabel !== void 0 && valueToDisplay != null;
418
- return /* @__PURE__ */ jsxs(StyledTriggerContainer, { children: [
419
- /* @__PURE__ */ jsxs(
420
- StyledTrigger,
451
+ const CONTENT_OFFSET = parseInt(theme.space[50]);
452
+ const SharedContent = React.forwardRef(
453
+ ({ calendarProps, prevButtonProps, nextButtonProps, children, state }, forwardRef) => {
454
+ const { visibleDuration } = useCalendarContext();
455
+ return /* @__PURE__ */ jsx(StyledBodyContent, { ...calendarProps, ref: forwardRef, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
456
+ /* @__PURE__ */ jsx(
457
+ Header,
421
458
  {
422
- "data-custom": "",
423
- ...buttonProps,
424
- v1,
425
- ref: forwardRef,
426
- withClearButton: clearButtonVisible,
427
- children: [
428
- valueToDisplay != null ? /* @__PURE__ */ jsx(StyledValue, { children: valueToDisplay }) : /* @__PURE__ */ jsx(StyledPlaceholder, { children: placeholder }),
429
- !clearButtonVisible && /* @__PURE__ */ jsx(IconCalendarBlank, { weight: "thin" })
430
- ]
459
+ state,
460
+ prevButtonProps,
461
+ nextButtonProps,
462
+ visibleMonths: visibleDuration.months
431
463
  }
432
464
  ),
433
- clearButtonVisible && /* @__PURE__ */ jsx(ClearButton, { label: clearActionLabel, onPress: onClear })
434
- ] });
465
+ /* @__PURE__ */ jsxs(StyledGridContent, { children: [
466
+ /* @__PURE__ */ jsx(StyledBodyContentLeft, { children: /* @__PURE__ */ jsx(Grid, { state }) }),
467
+ visibleDuration.months === 2 && /* @__PURE__ */ jsx(StyledBodyContentRight, { children: /* @__PURE__ */ jsx(Grid, { state, offset: { months: 1 } }) })
468
+ ] }),
469
+ children != null && /* @__PURE__ */ jsx(StyledClearContent, { children })
470
+ ] }) });
435
471
  }
436
472
  );
437
-
438
- const RangePicker = React__default.forwardRef((props, forwardRef) => {
473
+ const DatePickerContent = ({ children }) => {
474
+ const { locale } = useLocale();
439
475
  const {
440
- predefinedRanges,
476
+ calendarValue,
477
+ visibleDuration,
441
478
  minDate,
442
479
  maxDate,
443
- visibleMonths,
444
- clearButtonText,
445
- children,
446
- defaultOpen,
447
- onClear,
448
- label,
449
- placeholder,
450
- displayValue
451
- } = props;
452
- const state = useDateRangePickerState(
453
- props
480
+ onCalendarDateClick
481
+ } = useCalendarContext();
482
+ const state = useCalendarState({
483
+ value: calendarValue,
484
+ visibleDuration,
485
+ minValue: minDate,
486
+ maxValue: maxDate,
487
+ autoFocus: true,
488
+ onChange: onCalendarDateClick,
489
+ locale,
490
+ createCalendar
491
+ });
492
+ const { calendarProps, prevButtonProps, nextButtonProps } = useCalendar(
493
+ {},
494
+ state
454
495
  );
455
- const ref = useRef(null);
456
- const { locale } = useLocale();
457
- const { groupProps, labelProps, buttonProps } = useDateRangePicker(
496
+ return /* @__PURE__ */ jsx(
497
+ SharedContent,
458
498
  {
459
- ...props,
460
- isOpen: defaultOpen,
461
- label
462
- },
463
- state,
464
- ref
499
+ calendarProps,
500
+ prevButtonProps,
501
+ nextButtonProps,
502
+ state,
503
+ children
504
+ }
465
505
  );
466
- const change = (value) => {
467
- state.setValue(value);
468
- state.close();
469
- };
470
- const rangeState = useRangeCalendarState({
471
- ...props,
472
- visibleDuration: visibleMonths,
506
+ };
507
+ const RangePickerContent = ({ children }) => {
508
+ const { locale } = useLocale();
509
+ const {
510
+ calendarValue,
511
+ visibleDuration,
512
+ minDate,
513
+ maxDate,
514
+ onCalendarDateClick
515
+ } = useCalendarContext();
516
+ const ref = useRef(null);
517
+ const state = useRangeCalendarState({
518
+ value: calendarValue,
519
+ visibleDuration,
473
520
  minValue: minDate,
474
521
  maxValue: maxDate,
475
522
  autoFocus: true,
476
- onFocusChange: focus,
477
- onChange: change,
523
+ onChange: onCalendarDateClick,
478
524
  locale,
479
525
  createCalendar
480
526
  });
481
527
  const { calendarProps, prevButtonProps, nextButtonProps } = useRangeCalendar(
482
- props,
483
- rangeState,
528
+ {},
529
+ state,
484
530
  ref
485
531
  );
486
- const rangeClick = useCallback(
487
- (selectedRange) => {
488
- if (selectedRange.range !== void 0) {
489
- state.setValue(selectedRange.range);
490
- rangeState.setValue(selectedRange.range);
532
+ return /* @__PURE__ */ jsx(
533
+ SharedContent,
534
+ {
535
+ ref,
536
+ calendarProps,
537
+ prevButtonProps,
538
+ nextButtonProps,
539
+ state,
540
+ children
541
+ }
542
+ );
543
+ };
544
+ const Content = React.forwardRef(
545
+ ({
546
+ side = "bottom",
547
+ sideOffset = CONTENT_OFFSET,
548
+ align = "start",
549
+ alignOffset = 0,
550
+ collisionPadding = 0,
551
+ avoidCollisions = true,
552
+ sticky = "partial",
553
+ hideWhenDetached = true,
554
+ children,
555
+ ...restProps
556
+ }, forwardRef) => {
557
+ const { picker, open } = useCalendarContext();
558
+ if (!open) {
559
+ return null;
560
+ }
561
+ return /* @__PURE__ */ jsx(
562
+ StyledContent,
563
+ {
564
+ ...restProps,
565
+ ref: forwardRef,
566
+ side,
567
+ sideOffset,
568
+ align,
569
+ alignOffset,
570
+ collisionPadding,
571
+ avoidCollisions,
572
+ sticky,
573
+ hideWhenDetached,
574
+ children: picker === "single" ? /* @__PURE__ */ jsx(DatePickerContent, { children }) : /* @__PURE__ */ jsx(RangePickerContent, { children })
491
575
  }
492
- },
493
- [rangeState, state]
576
+ );
577
+ }
578
+ );
579
+
580
+ const StyledValue = styled(Primitive.span, {});
581
+
582
+ const DEFAULT_FORMAT = {
583
+ day: "2-digit",
584
+ month: "short",
585
+ year: "numeric"
586
+ };
587
+ const DEFAULT_TIMEZONE = "UTC";
588
+ function formatDate(date, formatter) {
589
+ return formatter.format(date.toDate(DEFAULT_TIMEZONE));
590
+ }
591
+ function formatValue(value, formatter) {
592
+ if (value == null) {
593
+ return void 0;
594
+ }
595
+ if ("start" in value) {
596
+ if (value.start == null || value.end == null) {
597
+ return void 0;
598
+ }
599
+ return "".concat(formatDate(value.start, formatter), " - ").concat(formatDate(
600
+ value.end,
601
+ formatter
602
+ ));
603
+ }
604
+ return formatDate(value, formatter);
605
+ }
606
+ const Value = React.forwardRef(({ format = DEFAULT_FORMAT, ...restProps }, forwardRef) => {
607
+ const { value } = useCalendarContext();
608
+ const formatWithTimeZone = useMemo(
609
+ () => ({ ...format, DEFAULT_TIMEZONE }),
610
+ [format]
494
611
  );
612
+ const dateFormatter = useDateFormatter(formatWithTimeZone);
613
+ const valueToDisplay = formatValue(value, dateFormatter);
614
+ return /* @__PURE__ */ jsx(StyledValue, { ref: forwardRef, ...restProps, children: valueToDisplay });
615
+ });
616
+
617
+ const ClearButton = React.forwardRef(({ onClear, children, ...restProps }, forwardRef) => {
618
+ const { value, setValue } = useCalendarContext();
495
619
  const onClearHandler = () => {
496
- state.setValue({ start: null, end: null });
620
+ setValue(void 0);
497
621
  if (onClear !== void 0) {
498
622
  onClear();
499
- state.close();
500
623
  }
501
624
  };
502
- const clearableTrigger = clearButtonText !== void 0 && onClear !== void 0;
503
- return /* @__PURE__ */ jsxs(StyledPicker, { ref: forwardRef, children: [
504
- children === void 0 && /* @__PURE__ */ jsxs(StyledGroup, { ...groupProps, ref, children: [
505
- label !== void 0 && // todo refactoring: use Form Field context
506
- /* @__PURE__ */ jsx(FloatingLabel, { floating: true, ...labelProps, children: label }),
507
- /* @__PURE__ */ jsx(
508
- Trigger,
509
- {
510
- ...buttonProps,
511
- placeholder,
512
- displayValue,
513
- stateValue: state.value,
514
- clearable: clearableTrigger,
515
- clearActionLabel: clearableTrigger ? clearButtonText : void 0,
516
- onClear: clearableTrigger ? onClearHandler : void 0
517
- }
518
- )
519
- ] }),
520
- children !== void 0 && /* @__PURE__ */ jsx("div", { ...groupProps, ref, children: /* @__PURE__ */ jsx(Trigger, { ...buttonProps, asChild: true, children }) }),
521
- state.isOpen && /* @__PURE__ */ jsx(Popover, { triggerRef: ref, state, placement: "bottom start", children: /* @__PURE__ */ jsx(StyledBody, { ref: forwardRef, children: /* @__PURE__ */ jsxs(StyledBodyContent, { children: [
522
- predefinedRanges !== void 0 && /* @__PURE__ */ jsx(
523
- PredefinedRanges,
524
- {
525
- range: predefinedRanges,
526
- onClick: rangeClick
527
- }
528
- ),
529
- /* @__PURE__ */ jsxs(Flex, { direction: "column", ...calendarProps, children: [
530
- /* @__PURE__ */ jsx(
531
- Header,
532
- {
533
- state: rangeState,
534
- prevButtonProps,
535
- nextButtonProps,
536
- visibleMonths
537
- }
538
- ),
539
- /* @__PURE__ */ jsxs(StyledGridContent, { children: [
540
- /* @__PURE__ */ jsx(StyledBodyContentLeft, { children: /* @__PURE__ */ jsx(Grid, { state: rangeState }) }),
541
- visibleMonths !== void 0 && /* @__PURE__ */ jsx(StyledBodyContentRight, { children: /* @__PURE__ */ jsx(
542
- Grid,
543
- {
544
- onChange: change,
545
- state: rangeState,
546
- offset: { months: 1 }
547
- }
548
- ) })
549
- ] }),
550
- onClear !== void 0 && /* @__PURE__ */ jsx(StyledClearContent, { children: /* @__PURE__ */ jsx(
551
- Button$1,
552
- {
553
- size: "medium",
554
- type: "button",
555
- onClick: onClearHandler,
556
- disabled: rangeState.value === null,
557
- children: clearButtonText
558
- }
559
- ) })
560
- ] })
561
- ] }) }) })
562
- ] });
625
+ return /* @__PURE__ */ jsx(
626
+ Button,
627
+ {
628
+ ...restProps,
629
+ ref: forwardRef,
630
+ variant: "ghost",
631
+ size: "medium",
632
+ onClick: onClearHandler,
633
+ disabled: value === null,
634
+ children
635
+ }
636
+ );
563
637
  });
564
638
 
565
- const DatePickerBody = React__default.forwardRef((props, forwardRef) => {
566
- const {
567
- predefinedRanges,
568
- visibleMonths,
569
- onClear,
570
- minDate,
571
- maxDate,
572
- clearButtonText
573
- } = props;
574
- const { locale } = useLocale();
575
- const state = useCalendarState({
576
- ...props,
577
- visibleDuration: visibleMonths,
578
- minValue: minDate,
579
- maxValue: maxDate,
580
- locale,
581
- createCalendar
582
- });
583
- const { calendarProps, prevButtonProps, nextButtonProps } = useCalendar(
584
- props,
585
- state
586
- );
587
- const dateClick = useCallback(
588
- (selectedRange) => {
589
- if (selectedRange.date !== void 0)
590
- state.setValue(selectedRange.date);
591
- },
592
- [state]
639
+ const SaveButton = React.forwardRef(({ onSave, children, ...restProps }, forwardRef) => {
640
+ const { setImmediateSave, onSaveClick } = useCalendarContext();
641
+ useEffect(() => {
642
+ setImmediateSave(true);
643
+ return () => setImmediateSave(false);
644
+ }, [setImmediateSave]);
645
+ const onSaveHandler = () => {
646
+ onSaveClick();
647
+ if (onSave !== void 0) {
648
+ onSave();
649
+ }
650
+ };
651
+ return /* @__PURE__ */ jsx(
652
+ Button,
653
+ {
654
+ ref: forwardRef,
655
+ ...restProps,
656
+ variant: "primary",
657
+ size: "medium",
658
+ onClick: onSaveHandler,
659
+ children
660
+ }
593
661
  );
594
- return /* @__PURE__ */ jsx(StyledBody, { ref: forwardRef, children: /* @__PURE__ */ jsxs(StyledBodyContent, { ...calendarProps, children: [
595
- predefinedRanges !== void 0 && /* @__PURE__ */ jsx(PredefinedRanges, { range: predefinedRanges, onClick: dateClick }),
596
- /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
597
- /* @__PURE__ */ jsx(
598
- Header,
599
- {
600
- state,
601
- prevButtonProps,
602
- nextButtonProps,
603
- visibleMonths
604
- }
605
- ),
606
- /* @__PURE__ */ jsxs(StyledGridContent, { children: [
607
- /* @__PURE__ */ jsx(StyledBodyContentLeft, { children: /* @__PURE__ */ jsx(Grid, { state }) }),
608
- visibleMonths !== void 0 && /* @__PURE__ */ jsx(StyledBodyContentRight, { children: /* @__PURE__ */ jsx(Grid, { state, offset: { months: 1 } }) })
609
- ] }),
610
- onClear !== void 0 && /* @__PURE__ */ jsx(StyledClearContent, { children: /* @__PURE__ */ jsx(
611
- Button$1,
612
- {
613
- size: "medium",
614
- onClick: onClear,
615
- disabled: state.value === null,
616
- children: clearButtonText
617
- }
618
- ) })
619
- ] })
620
- ] }) });
621
662
  });
622
663
 
623
- const DatePicker = React__default.forwardRef((props, forwardRef) => {
624
- const {
664
+ const StyledCalendar = styled(Primitive.div, {
665
+ position: "relative"
666
+ });
667
+
668
+ const Root = React.forwardRef(({ children, ...restProps }, forwardRef) => {
669
+ const { open, setOpen } = useCalendarContext();
670
+ const { label, isFloatingLabel } = useFormFieldContext();
671
+ return /* @__PURE__ */ jsx(RadixPopover.Root, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(StyledCalendar, { ref: forwardRef, ...restProps, children: [
672
+ label !== null && isFloatingLabel && /* @__PURE__ */ jsx(FloatingLabel, { floating: true, size: "medium", children: label }),
673
+ children
674
+ ] }) });
675
+ });
676
+ const Calendar = React.forwardRef(
677
+ ({
625
678
  picker,
626
- predefinedRanges,
627
- visibleMonths,
628
679
  defaultValue,
680
+ value,
681
+ onValueChange,
682
+ defaultOpen,
683
+ open,
684
+ onClose,
685
+ onOpen,
686
+ locale,
687
+ visibleMonths,
629
688
  minDate,
630
689
  maxDate,
631
690
  children,
632
- clearButtonText,
633
- defaultOpen,
634
- onClear,
635
- label,
636
- placeholder,
637
- displayValue
638
- } = props;
639
- const ref = useRef(null);
640
- const state = useDatePickerState(props);
641
- const { groupProps, buttonProps, calendarProps, labelProps } = useDatePicker(
642
- {
643
- ...props,
644
- isOpen: defaultOpen,
645
- label
646
- },
647
- state,
648
- ref
649
- );
650
- const onClearHandler = () => {
651
- state.setValue(null);
652
- if (onClear !== void 0) {
653
- onClear();
654
- }
655
- };
656
- const clearableTrigger = clearButtonText !== void 0 && onClear !== void 0;
657
- return /* @__PURE__ */ jsx(Fragment, { children: picker === "single" ? /* @__PURE__ */ jsxs(StyledPicker, { ref: forwardRef, children: [
658
- children === void 0 && /* @__PURE__ */ jsxs(StyledGroup, { ...groupProps, ref, children: [
659
- label !== void 0 && // todo refactoring: use Form Field context
660
- /* @__PURE__ */ jsx(FloatingLabel, { floating: true, ...labelProps, children: label }),
661
- /* @__PURE__ */ jsx(
662
- Trigger,
663
- {
664
- ...buttonProps,
665
- placeholder,
666
- displayValue,
667
- stateValue: state.value,
668
- clearable: clearableTrigger,
669
- clearActionLabel: clearableTrigger ? clearButtonText : void 0,
670
- onClear: clearableTrigger ? onClearHandler : void 0
671
- }
672
- )
673
- ] }),
674
- children !== void 0 && /* @__PURE__ */ jsx("div", { ...groupProps, ref, children: /* @__PURE__ */ jsx(Trigger, { ...buttonProps, asChild: true, children }) }),
675
- state.isOpen && /* @__PURE__ */ jsx(Popover, { triggerRef: ref, state, placement: "bottom start", children: /* @__PURE__ */ jsx(
676
- DatePickerBody,
677
- {
678
- ...calendarProps,
679
- defaultValue,
680
- predefinedRanges,
681
- visibleMonths,
682
- onClear: onClear !== void 0 ? onClearHandler : void 0,
683
- minDate,
684
- maxDate,
685
- clearButtonText: onClear !== void 0 ? clearButtonText : void 0,
686
- ref: forwardRef
687
- }
688
- ) })
689
- ] }) : /* @__PURE__ */ jsx(
690
- DatePickerBody,
691
- {
692
- ...calendarProps,
693
- ref: forwardRef,
691
+ ...props
692
+ }, forwardRef) => {
693
+ const providerProps = {
694
+ picker,
694
695
  defaultValue,
695
- predefinedRanges,
696
+ value,
697
+ onValueChange,
696
698
  visibleMonths,
697
- onClear: onClear !== void 0 ? onClearHandler : void 0,
698
699
  minDate,
699
700
  maxDate,
700
- clearButtonText: onClear !== void 0 ? clearButtonText : void 0
701
- }
702
- ) });
703
- });
704
-
705
- const StyledCalendar = styled(Primitive.div, {});
706
- const Calendar = React__default.forwardRef(({ picker, defaultValue, ...props }, forwardRef) => /* @__PURE__ */ jsx(StyledCalendar, { ref: forwardRef, children: picker === "range" ? /* @__PURE__ */ jsx(RangePicker, { defaultValue, ...props }) : /* @__PURE__ */ jsx(
707
- DatePicker,
708
- {
709
- defaultValue,
710
- ...props,
711
- picker
701
+ defaultOpen,
702
+ open,
703
+ onClose,
704
+ onOpen
705
+ };
706
+ return /* @__PURE__ */ jsx(I18nProvider, { locale, children: /* @__PURE__ */ jsx(CalendarProvider, { ...providerProps, children: /* @__PURE__ */ jsx(Root, { ...props, ref: forwardRef, children }) }) });
712
707
  }
713
- ) }));
708
+ );
709
+ Calendar.Trigger = Trigger;
710
+ Calendar.Content = Content;
711
+ Calendar.Value = Value;
712
+ Calendar.ClearButton = ClearButton;
713
+ Calendar.SaveButton = SaveButton;
714
714
 
715
715
  export { Calendar };
716
716
  //# sourceMappingURL=module.js.map