@mirohq/design-system-calendar 0.1.82 → 0.2.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,117 +1,19 @@
1
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { Primitive } from '@mirohq/design-system-primitive';
3
3
  import { styled } from '@mirohq/design-system-stitches';
4
4
  import * as React from 'react';
5
5
  import React__default, { useRef, useCallback } from 'react';
6
- import { useLocale, useDateField, useDateSegment, useButton, useFocusRing, mergeProps, useDialog, usePopover, Overlay, DismissButton, useDateFormatter, useCalendarCell, useCalendarGrid, useDateRangePicker, useRangeCalendar, useCalendar, useDatePicker } from 'react-aria';
7
- import { createCalendar, isSameMonth, isSameDay, getDayOfWeek, isWeekend, isToday, getLocalTimeZone, getWeeksInMonth } from '@internationalized/date';
8
- import { useDateFieldState, useDateRangePickerState, useRangeCalendarState, useCalendarState, useDatePickerState } from 'react-stately';
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
9
  import { Flex } from '@mirohq/design-system-flex';
10
- import { IconChevronLeft, IconChevronRight, IconCalendarBlank } from '@mirohq/design-system-icons';
11
10
  import { Button as Button$1 } from '@mirohq/design-system-button';
12
-
13
- const StyledDataSegment = styled(Primitive.div, {
14
- color: "$text-neutrals-subtle",
15
- "&[data-value]": {
16
- color: "$text-neutrals"
17
- },
18
- "& span": {
19
- pointerEvents: "none",
20
- "&[data-placeholder]": {
21
- display: "none",
22
- height: "0",
23
- color: "$text-neutrals-subtle"
24
- }
25
- }
26
- });
27
-
28
- const FieldDateSegment = ({ segment, state }) => {
29
- const ref = useRef(null);
30
- const { segmentProps } = useDateSegment(segment, state, ref);
31
- const segmentPropsStyle = segmentProps.style;
32
- delete segmentProps.style;
33
- return /* @__PURE__ */ jsxs(
34
- StyledDataSegment,
35
- {
36
- ...segmentProps,
37
- UNSAFE_style: segmentPropsStyle,
38
- ref,
39
- "data-value": state.value !== null ? "" : void 0,
40
- children: [
41
- /* @__PURE__ */ jsx(
42
- "span",
43
- {
44
- "aria-hidden": "true",
45
- "data-placeholder": !segment.isPlaceholder ? "" : void 0,
46
- children: segment.placeholder
47
- }
48
- ),
49
- segment.isPlaceholder ? "" : segment.text
50
- ]
51
- }
52
- );
53
- };
54
- const TextField = React__default.forwardRef((props, forwardRef) => {
55
- const ref = useRef(null);
56
- const { locale } = useLocale();
57
- const state = useDateFieldState({
58
- ...props,
59
- isReadOnly: true,
60
- locale,
61
- createCalendar
62
- });
63
- const { fieldProps } = useDateField(props, state, ref);
64
- return /* @__PURE__ */ jsx(Flex, { ...fieldProps, ref: forwardRef, children: state.segments.map((segment, i) => /* @__PURE__ */ jsx(FieldDateSegment, { segment, state }, i)) });
65
- });
66
-
67
- const StyledButton = styled(Primitive.button, {
68
- padding: "0",
69
- backgroundColor: "$transparent",
70
- border: "none",
71
- cursor: "pointer",
72
- color: "$text-neutrals",
73
- "&[disabled]": {
74
- cursor: "not-allowed"
75
- }
76
- });
77
- const StyledFieldButton = styled(Primitive.button, {
78
- padding: "0",
79
- backgroundColor: "$transparent",
80
- border: "none",
81
- cursor: "pointer",
82
- square: "28px",
83
- "&[disabled]": {
84
- cursor: "not-allowed"
85
- },
86
- "& svg": {
87
- color: "$text-neutrals-subtle",
88
- square: "22px"
89
- },
90
- "&[data-custom]": {
91
- width: "100%",
92
- height: "unset"
93
- }
94
- });
95
-
96
- const Button = React__default.forwardRef((props, forwardRef) => {
97
- const { buttonProps } = useButton(props, forwardRef);
98
- const { focusProps } = useFocusRing();
99
- const { children } = props;
100
- return /* @__PURE__ */ jsx(StyledButton, { ...mergeProps(buttonProps, focusProps), ref: forwardRef, children });
101
- });
102
- const FieldButton = React__default.forwardRef((props, forwardRef) => {
103
- const { buttonProps } = useButton(props, forwardRef);
104
- const { customButton = false, children } = props;
105
- return /* @__PURE__ */ jsx(
106
- StyledFieldButton,
107
- {
108
- "data-custom": customButton ? "" : void 0,
109
- ...buttonProps,
110
- ref: forwardRef,
111
- children
112
- }
113
- );
114
- });
11
+ import { FloatingLabel } from '@mirohq/design-system-base-form';
12
+ import { IconChevronLeft, IconChevronRight, IconCross, IconCalendarBlank } from '@mirohq/design-system-icons';
13
+ import { textFieldStyles, actionButtonStyles } from '@mirohq/design-system-base-text-field';
14
+ import { focus as focus$1 } from '@mirohq/design-system-styles';
15
+ import { Tooltip } from '@mirohq/design-system-tooltip';
16
+ import { BaseButton } from '@mirohq/design-system-base-button';
115
17
 
116
18
  const Popover = (props) => {
117
19
  const ref = React.useRef(null);
@@ -134,29 +36,8 @@ const Popover = (props) => {
134
36
  ] });
135
37
  };
136
38
 
137
- const StyledPickerInput = styled(Primitive.div, {
138
- display: "flex",
139
- alignItems: "center",
140
- paddingLeft: "$150",
141
- paddingRight: "$100",
142
- border: "1px solid $border-neutrals",
143
- borderRadius: "$50",
144
- background: "$background-neutrals",
145
- color: "$text-neutrals",
146
- minWidth: "230px",
147
- boxSizing: "border-box",
148
- "&:hover": {
149
- border: "1px solid $border-primary-hover",
150
- cursor: "pointer"
151
- }
152
- });
153
- const StyledPickerInputContent = styled(Primitive.div, {
154
- display: "flex",
155
- alignItems: "center",
156
- fontSize: "$200",
157
- lineHeight: "24px",
158
- width: "100%",
159
- height: "48px"
39
+ const StyledGroup = styled(Primitive.div, {
40
+ position: "relative"
160
41
  });
161
42
  const StyledPicker = styled(Primitive.div, {});
162
43
 
@@ -231,6 +112,24 @@ const StyledClearContent = styled(Primitive.div, {
231
112
  borderTop: "1px solid $border-neutrals"
232
113
  });
233
114
 
115
+ const StyledButton = styled(Primitive.button, {
116
+ padding: "0",
117
+ backgroundColor: "$transparent",
118
+ border: "none",
119
+ cursor: "pointer",
120
+ color: "$text-neutrals",
121
+ "&[disabled]": {
122
+ cursor: "not-allowed"
123
+ }
124
+ });
125
+
126
+ const Button = React__default.forwardRef((props, forwardRef) => {
127
+ const { buttonProps } = useButton(props, forwardRef);
128
+ const { focusProps } = useFocusRing();
129
+ const { children } = props;
130
+ return /* @__PURE__ */ jsx(StyledButton, { ...mergeProps(buttonProps, focusProps), ref: forwardRef, children });
131
+ });
132
+
234
133
  const StyledHeaderTitle = styled(Flex, {
235
134
  justifyContent: "center",
236
135
  flex: "3",
@@ -406,6 +305,125 @@ const Grid = React__default.forwardRef(
406
305
  }
407
306
  );
408
307
 
308
+ const StyledPlaceholder = styled(Primitive.span, {
309
+ ...textFieldStyles.base.placeholder,
310
+ padding: "0 $50"
311
+ });
312
+ const StyledValue = styled(Primitive.span, {
313
+ padding: "0 $50"
314
+ });
315
+ const StyledTriggerContainer = styled(Primitive.div, {
316
+ position: "relative"
317
+ });
318
+ const StyledTrigger = styled(Primitive.button, {
319
+ all: "unset",
320
+ display: "inline-flex",
321
+ gap: "$50",
322
+ justifyContent: "space-between",
323
+ alignItems: "center",
324
+ height: "$10",
325
+ padding: "0 $100",
326
+ minWidth: "230px",
327
+ ...textFieldStyles.variants.idle,
328
+ "& svg": {
329
+ color: "$text-neutrals-subtle",
330
+ square: "22px"
331
+ },
332
+ _hover: textFieldStyles.variants.hovered,
333
+ ...focus$1.css(textFieldStyles.variants.focused),
334
+ variants: {
335
+ withClearButton: {
336
+ true: {
337
+ paddingRight: "calc($100 + $400)"
338
+ // initial left padding + clear button width + gap
339
+ }
340
+ }
341
+ }
342
+ });
343
+ const StyledCustomTrigger = styled(Primitive.button, {
344
+ width: "100%",
345
+ height: "unset",
346
+ padding: "0",
347
+ backgroundColor: "$transparent",
348
+ border: "none",
349
+ cursor: "pointer"
350
+ });
351
+
352
+ const StyledClearButton = styled(BaseButton, {
353
+ position: "absolute",
354
+ top: 0,
355
+ bottom: 0,
356
+ right: "calc($100 + 1px)",
357
+ // to compensate border width
358
+ margin: "auto",
359
+ ...actionButtonStyles
360
+ });
361
+
362
+ const ClearButton = React__default.forwardRef(({ "aria-label": ariaLabel, label, ...restProps }, forwardRef) => /* @__PURE__ */ jsxs(Tooltip, { children: [
363
+ /* @__PURE__ */ jsx(Tooltip.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
364
+ StyledClearButton,
365
+ {
366
+ ...restProps,
367
+ ref: forwardRef,
368
+ "aria-label": ariaLabel != null ? ariaLabel : label,
369
+ children: /* @__PURE__ */ jsx(IconCross, {})
370
+ }
371
+ ) }),
372
+ /* @__PURE__ */ jsx(Tooltip.Content, { children: label })
373
+ ] }));
374
+
375
+ function dateToString(value) {
376
+ if (value == null) {
377
+ return void 0;
378
+ }
379
+ if ("start" in value) {
380
+ if (value.start == null || value.end == null) {
381
+ return void 0;
382
+ }
383
+ return "".concat(value.start, " - ").concat(value.end);
384
+ }
385
+ return value.toString();
386
+ }
387
+ const Trigger = React__default.forwardRef(
388
+ ({
389
+ placeholder,
390
+ displayValue,
391
+ stateValue,
392
+ asChild = false,
393
+ clearable = true,
394
+ clearActionLabel,
395
+ onClear,
396
+ ...restProps
397
+ }, forwardRef) => {
398
+ const { buttonProps } = useButton(
399
+ restProps,
400
+ forwardRef
401
+ );
402
+ const { children } = restProps;
403
+ if (asChild) {
404
+ return /* @__PURE__ */ jsx(StyledCustomTrigger, { children });
405
+ }
406
+ const valueToDisplay = displayValue != null ? displayValue : dateToString(stateValue);
407
+ const clearButtonVisible = clearable && clearActionLabel !== void 0 && valueToDisplay != null;
408
+ return /* @__PURE__ */ jsxs(StyledTriggerContainer, { children: [
409
+ /* @__PURE__ */ jsxs(
410
+ StyledTrigger,
411
+ {
412
+ "data-custom": "",
413
+ ...buttonProps,
414
+ ref: forwardRef,
415
+ withClearButton: clearButtonVisible,
416
+ children: [
417
+ valueToDisplay != null ? /* @__PURE__ */ jsx(StyledValue, { children: valueToDisplay }) : /* @__PURE__ */ jsx(StyledPlaceholder, { children: placeholder }),
418
+ !clearButtonVisible && /* @__PURE__ */ jsx(IconCalendarBlank, { weight: "thin" })
419
+ ]
420
+ }
421
+ ),
422
+ clearButtonVisible && /* @__PURE__ */ jsx(ClearButton, { label: clearActionLabel, onPress: onClear })
423
+ ] });
424
+ }
425
+ );
426
+
409
427
  const RangePicker = React__default.forwardRef((props, forwardRef) => {
410
428
  const {
411
429
  predefinedRanges,
@@ -415,17 +433,21 @@ const RangePicker = React__default.forwardRef((props, forwardRef) => {
415
433
  clearButtonText,
416
434
  children,
417
435
  defaultOpen,
418
- onClear
436
+ onClear,
437
+ label,
438
+ placeholder,
439
+ displayValue
419
440
  } = props;
420
441
  const state = useDateRangePickerState(
421
442
  props
422
443
  );
423
444
  const ref = useRef(null);
424
445
  const { locale } = useLocale();
425
- const { groupProps, startFieldProps, endFieldProps, buttonProps } = useDateRangePicker(
446
+ const { groupProps, labelProps, buttonProps } = useDateRangePicker(
426
447
  {
427
448
  ...props,
428
- isOpen: defaultOpen
449
+ isOpen: defaultOpen,
450
+ label
429
451
  },
430
452
  state,
431
453
  ref
@@ -459,21 +481,32 @@ const RangePicker = React__default.forwardRef((props, forwardRef) => {
459
481
  },
460
482
  [rangeState, state]
461
483
  );
462
- const clear = () => {
484
+ const onClearHandler = () => {
463
485
  state.setValue({ start: null, end: null });
464
486
  if (onClear !== void 0) {
465
487
  onClear();
466
488
  state.close();
467
489
  }
468
490
  };
491
+ const clearableTrigger = clearButtonText !== void 0 && onClear !== void 0;
469
492
  return /* @__PURE__ */ jsxs(StyledPicker, { ref: forwardRef, children: [
470
- children === void 0 && /* @__PURE__ */ jsx(StyledPickerInput, { ...groupProps, ref, children: /* @__PURE__ */ jsxs(StyledPickerInputContent, { children: [
471
- /* @__PURE__ */ jsx(TextField, { ...startFieldProps }),
472
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2013" }),
473
- /* @__PURE__ */ jsx(TextField, { ...endFieldProps }),
474
- /* @__PURE__ */ jsx(Flex, { css: { marginLeft: "auto" }, children: /* @__PURE__ */ jsx(FieldButton, { ...buttonProps, children: /* @__PURE__ */ jsx(IconCalendarBlank, {}) }) })
475
- ] }) }),
476
- children !== null && /* @__PURE__ */ jsx("div", { ...groupProps, ref, children: /* @__PURE__ */ jsx(FieldButton, { ...buttonProps, customButton: true, children }) }),
493
+ children === void 0 && /* @__PURE__ */ jsxs(StyledGroup, { ...groupProps, ref, children: [
494
+ label !== void 0 && // todo refactoring: use Form Field context
495
+ /* @__PURE__ */ jsx(FloatingLabel, { floating: true, ...labelProps, children: label }),
496
+ /* @__PURE__ */ jsx(
497
+ Trigger,
498
+ {
499
+ ...buttonProps,
500
+ placeholder,
501
+ displayValue,
502
+ stateValue: state.value,
503
+ clearable: clearableTrigger,
504
+ clearActionLabel: clearableTrigger ? clearButtonText : void 0,
505
+ onClear: clearableTrigger ? onClearHandler : void 0
506
+ }
507
+ )
508
+ ] }),
509
+ children !== void 0 && /* @__PURE__ */ jsx("div", { ...groupProps, ref, children: /* @__PURE__ */ jsx(Trigger, { ...buttonProps, asChild: true, children }) }),
477
510
  state.isOpen && /* @__PURE__ */ jsx(Popover, { triggerRef: ref, state, placement: "bottom start", children: /* @__PURE__ */ jsx(StyledBody, { ref: forwardRef, children: /* @__PURE__ */ jsxs(StyledBodyContent, { children: [
478
511
  predefinedRanges !== void 0 && /* @__PURE__ */ jsx(
479
512
  PredefinedRanges,
@@ -508,7 +541,7 @@ const RangePicker = React__default.forwardRef((props, forwardRef) => {
508
541
  {
509
542
  size: "medium",
510
543
  type: "button",
511
- onClick: clear,
544
+ onClick: onClearHandler,
512
545
  disabled: rangeState.value === null,
513
546
  children: clearButtonText
514
547
  }
@@ -587,27 +620,47 @@ const DatePicker = React__default.forwardRef((props, forwardRef) => {
587
620
  children,
588
621
  clearButtonText,
589
622
  defaultOpen,
590
- onClear
623
+ onClear,
624
+ label,
625
+ placeholder,
626
+ displayValue
591
627
  } = props;
592
628
  const ref = useRef(null);
593
629
  const state = useDatePickerState(props);
594
- const { groupProps, fieldProps, buttonProps, calendarProps } = useDatePicker(
595
- { ...props, isOpen: defaultOpen },
630
+ const { groupProps, buttonProps, calendarProps, labelProps } = useDatePicker(
631
+ {
632
+ ...props,
633
+ isOpen: defaultOpen,
634
+ label
635
+ },
596
636
  state,
597
637
  ref
598
638
  );
599
- const clearState = () => {
639
+ const onClearHandler = () => {
600
640
  state.setValue(null);
601
641
  if (onClear !== void 0) {
602
642
  onClear();
603
643
  }
604
644
  };
645
+ const clearableTrigger = clearButtonText !== void 0 && onClear !== void 0;
605
646
  return /* @__PURE__ */ jsx(Fragment, { children: picker === "single" ? /* @__PURE__ */ jsxs(StyledPicker, { ref: forwardRef, children: [
606
- children === void 0 && /* @__PURE__ */ jsx(StyledPickerInput, { ...groupProps, ref, children: /* @__PURE__ */ jsxs(StyledPickerInputContent, { children: [
607
- /* @__PURE__ */ jsx(TextField, { ...fieldProps }),
608
- /* @__PURE__ */ jsx(Flex, { css: { marginLeft: "auto" }, children: /* @__PURE__ */ jsx(FieldButton, { ...buttonProps, children: /* @__PURE__ */ jsx(IconCalendarBlank, {}) }) })
609
- ] }) }),
610
- children !== void 0 && /* @__PURE__ */ jsx("div", { ...groupProps, ref, children: /* @__PURE__ */ jsx(FieldButton, { ...buttonProps, customButton: true, children }) }),
647
+ children === void 0 && /* @__PURE__ */ jsxs(StyledGroup, { ...groupProps, ref, children: [
648
+ label !== void 0 && // todo refactoring: use Form Field context
649
+ /* @__PURE__ */ jsx(FloatingLabel, { floating: true, ...labelProps, children: label }),
650
+ /* @__PURE__ */ jsx(
651
+ Trigger,
652
+ {
653
+ ...buttonProps,
654
+ placeholder,
655
+ displayValue,
656
+ stateValue: state.value,
657
+ clearable: clearableTrigger,
658
+ clearActionLabel: clearableTrigger ? clearButtonText : void 0,
659
+ onClear: clearableTrigger ? onClearHandler : void 0
660
+ }
661
+ )
662
+ ] }),
663
+ children !== void 0 && /* @__PURE__ */ jsx("div", { ...groupProps, ref, children: /* @__PURE__ */ jsx(Trigger, { ...buttonProps, asChild: true, children }) }),
611
664
  state.isOpen && /* @__PURE__ */ jsx(Popover, { triggerRef: ref, state, placement: "bottom start", children: /* @__PURE__ */ jsx(
612
665
  DatePickerBody,
613
666
  {
@@ -615,7 +668,7 @@ const DatePicker = React__default.forwardRef((props, forwardRef) => {
615
668
  defaultValue,
616
669
  predefinedRanges,
617
670
  visibleMonths,
618
- onClear: onClear !== void 0 ? clearState : void 0,
671
+ onClear: onClear !== void 0 ? onClearHandler : void 0,
619
672
  minDate,
620
673
  maxDate,
621
674
  clearButtonText: onClear !== void 0 ? clearButtonText : void 0,
@@ -630,7 +683,7 @@ const DatePicker = React__default.forwardRef((props, forwardRef) => {
630
683
  defaultValue,
631
684
  predefinedRanges,
632
685
  visibleMonths,
633
- onClear: onClear !== void 0 ? clearState : void 0,
686
+ onClear: onClear !== void 0 ? onClearHandler : void 0,
634
687
  minDate,
635
688
  maxDate,
636
689
  clearButtonText: onClear !== void 0 ? clearButtonText : void 0