reshaped 3.9.0-canary.3 → 3.9.0-canary.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,6 +24,8 @@ export type BaseProps = {
24
24
  firstWeekDay?: number;
25
25
  /** Dates that are selected */
26
26
  selectedDates?: Date[];
27
+ /** Dates that are disabled */
28
+ disabledDates?: Date[];
27
29
  /** Render a custom weekday label, can be used for localization */
28
30
  renderWeekDay?: (args: {
29
31
  weekDay: number;
@@ -121,7 +123,7 @@ export type MonthProps = {
121
123
  hoveredDate: Date | null;
122
124
  onDateHover: (date: Date) => void;
123
125
  onDateHoverEnd: (date: Date) => void;
124
- } & Pick<BaseProps, "max" | "min" | "firstWeekDay" | "selectedDates" | "renderMonthLabel" | "renderWeekDay" | "renderSelectedMonthLabel" | "renderDateAriaLabel" | "renderDateSlot"> & Pick<ControlledProps, "value" | "onChange" | "range">;
126
+ } & Pick<BaseProps, "max" | "min" | "firstWeekDay" | "selectedDates" | "disabledDates" | "renderMonthLabel" | "renderWeekDay" | "renderSelectedMonthLabel" | "renderDateAriaLabel" | "renderDateSlot"> & Pick<ControlledProps, "value" | "onChange" | "range">;
125
127
  export type YearProps = {
126
128
  monthDate: Date;
127
129
  onMonthClick: (month: number) => void;
@@ -136,7 +138,7 @@ export type DateProps = {
136
138
  renderAriaLabel?: MonthProps["renderDateAriaLabel"];
137
139
  renderSlot?: MonthProps["renderDateSlot"];
138
140
  onDateFocus: (date: Date) => void;
139
- } & Pick<MonthProps, "hoveredDate" | "onDateHover" | "onDateHoverEnd" | "onChange" | "range" | "min" | "max" | "selectedDates">;
141
+ } & Pick<MonthProps, "hoveredDate" | "onDateHover" | "onDateHoverEnd" | "onChange" | "range" | "min" | "max" | "selectedDates" | "disabledDates">;
140
142
  export type ControlsProps = {
141
143
  selectionMode: SelectionMode;
142
144
  monthsToRender: number;
@@ -9,7 +9,7 @@ import CalendarMonth from "./CalendarMonth.js";
9
9
  import CalendarYear from "./CalendarYear.js";
10
10
  import useCalendarKeyboardNavigation from "./useCalendarKeyboardNavigation.js";
11
11
  const CalendarControlled = (props) => {
12
- const { value, onChange, defaultMonth, month, onMonthChange, min, max, range, firstWeekDay, selectedDates, monthsToRender = 1, renderMonthLabel, renderSelectedMonthLabel, renderWeekDay, previousMonthAriaLabel, previousYearAriaLabel, nextMonthAriaLabel, nextYearAriaLabel, monthSelectionAriaLabel, renderMonthAriaLabel, renderDateAriaLabel, renderDateSlot, } = props;
12
+ const { value, onChange, defaultMonth, month, onMonthChange, min, max, range, firstWeekDay, selectedDates, disabledDates, monthsToRender = 1, renderMonthLabel, renderSelectedMonthLabel, renderWeekDay, previousMonthAriaLabel, previousYearAriaLabel, nextMonthAriaLabel, nextYearAriaLabel, monthSelectionAriaLabel, renderMonthAriaLabel, renderDateAriaLabel, renderDateSlot, } = props;
13
13
  const [selectionMode, setSelectionMode] = React.useState("date");
14
14
  const [monthDate, setMonthDate] = React.useState(month || defaultMonth || new Date());
15
15
  const [hoveredDate, setHoveredDate] = React.useState(null);
@@ -97,7 +97,7 @@ const CalendarControlled = (props) => {
97
97
  Array.from({ length: monthsToRender }).map((_, index) => {
98
98
  const currentMonthDate = new Date(monthDate);
99
99
  currentMonthDate.setMonth(currentMonthDate.getMonth() + index);
100
- return (_jsx(View.Item, { grow: true, children: _jsx(CalendarMonth, { date: currentMonthDate, value: value, onChange: onChange, min: min, max: max, range: range, firstWeekDay: firstWeekDay, hoveredDate: hoveredDate, selectedDates: selectedDates, onDateHover: handleDateHover, onDateHoverEnd: handleDateHoverEnd, renderWeekDay: renderWeekDay, renderDateAriaLabel: renderDateAriaLabel, renderDateSlot: renderDateSlot }) }, index));
100
+ return (_jsx(View.Item, { grow: true, children: _jsx(CalendarMonth, { date: currentMonthDate, value: value, onChange: onChange, min: min, max: max, range: range, firstWeekDay: firstWeekDay, hoveredDate: hoveredDate, selectedDates: selectedDates, disabledDates: disabledDates, onDateHover: handleDateHover, onDateHoverEnd: handleDateHoverEnd, renderWeekDay: renderWeekDay, renderDateAriaLabel: renderDateAriaLabel, renderDateSlot: renderDateSlot }) }, index));
101
101
  }), selectionMode === "month" && (_jsx(CalendarYear, { monthDate: monthDate, onMonthClick: handleMonthClick, renderMonthLabel: renderMonthLabel, renderMonthAriaLabel: renderMonthAriaLabel, min: min, max: max }))] })] }));
102
102
  };
103
103
  CalendarControlled.displayName = "CalendarControlled";
@@ -5,17 +5,19 @@ import { classNames } from "../../utilities/props.js";
5
5
  import s from "./Calendar.module.css";
6
6
  import { getLocalISODate } from "./Calendar.utils.js";
7
7
  const CalendarDate = (props) => {
8
- const { date, isoDate, startValue, endValue, disabled, focusable, onChange, range, hoveredDate, onDateHover, onDateHoverEnd, onDateFocus, selectedDates, renderAriaLabel, renderSlot, } = props;
8
+ const { date, isoDate, startValue, endValue, disabled: passedDisabled, focusable, onChange, range, hoveredDate, onDateHover, onDateHoverEnd, onDateFocus, selectedDates, disabledDates, renderAriaLabel, renderSlot, } = props;
9
9
  if (!date)
10
10
  return _jsx("td", { className: s.cell, "aria-hidden": "true" });
11
11
  const isoStartValue = startValue && getLocalISODate({ date: startValue });
12
12
  const isoEndValue = endValue && getLocalISODate({ date: endValue });
13
- const isStartValue = !!isoDate && !!isoStartValue && isoDate === isoStartValue;
14
- const isEndValue = !!isoDate && !!isoEndValue && isoDate === isoEndValue;
15
- const isAfterStartValue = startValue && date > startValue;
16
- const isBeforeEndValue = endValue && date < endValue;
17
- const isInHoveredRange = hoveredDate && !endValue && hoveredDate > date;
18
- const isInSelectedDates = !!selectedDates?.find((selectedDate) => getLocalISODate({ date: selectedDate }) === isoDate);
13
+ const isStartValue = Boolean(isoDate && !!isoStartValue && isoDate === isoStartValue);
14
+ const isEndValue = Boolean(isoDate && !!isoEndValue && isoDate === isoEndValue);
15
+ const isAfterStartValue = Boolean(isoDate && isoStartValue && isoDate > isoStartValue);
16
+ const isBeforeEndValue = Boolean(isoDate && isoEndValue && isoDate < isoEndValue);
17
+ const isInHoveredRange = Boolean(hoveredDate && !endValue && hoveredDate > date);
18
+ const isInSelectedDates = !!selectedDates?.some((selectedDate) => getLocalISODate({ date: selectedDate }) === isoDate);
19
+ const disabled = passedDisabled ||
20
+ disabledDates?.some((disabledDate) => getLocalISODate({ date: disabledDate }) === isoDate);
19
21
  let selection;
20
22
  switch (true) {
21
23
  case isAfterStartValue && isInHoveredRange:
@@ -5,7 +5,7 @@ import s from "./Calendar.module.css";
5
5
  import { getMonthWeeks, getWeekdayNames, getLocalISODate, isDateFocusable } from "./Calendar.utils.js";
6
6
  import CalendarDate from "./CalendarDate.js";
7
7
  const CalendarMonth = (props) => {
8
- const { date, value, onChange, min, max, range, firstWeekDay, selectedDates, hoveredDate, onDateHover, onDateHoverEnd, renderWeekDay, renderDateAriaLabel, renderDateSlot, } = props;
8
+ const { date, value, onChange, min, max, range, firstWeekDay, selectedDates, disabledDates, hoveredDate, onDateHover, onDateHoverEnd, renderWeekDay, renderDateAriaLabel, renderDateSlot, } = props;
9
9
  let foundFocusableDate = false;
10
10
  const [lastFocusedDate, setLastFocusedDate] = useState();
11
11
  const month = date.getMonth();
@@ -26,7 +26,7 @@ const CalendarMonth = (props) => {
26
26
  // eslint-disable-next-line react-hooks/immutability
27
27
  if (focusable)
28
28
  foundFocusableDate = true;
29
- return (_jsx(CalendarDate, { date: date, isoDate: isoDate, disabled: disabled, range: range, focusable: focusable, startValue: startValue, endValue: endValue, onChange: onChange, hoveredDate: hoveredDate, onDateHover: onDateHover, onDateHoverEnd: onDateHoverEnd, onDateFocus: setLastFocusedDate, renderAriaLabel: renderDateAriaLabel, selectedDates: selectedDates, renderSlot: renderDateSlot }, index));
29
+ return (_jsx(CalendarDate, { date: date, isoDate: isoDate, disabled: disabled, range: range, focusable: focusable, startValue: startValue, endValue: endValue, onChange: onChange, hoveredDate: hoveredDate, onDateHover: onDateHover, onDateHoverEnd: onDateHoverEnd, onDateFocus: setLastFocusedDate, renderAriaLabel: renderDateAriaLabel, selectedDates: selectedDates, disabledDates: disabledDates, renderSlot: renderDateSlot }, index));
30
30
  }) }, key));
31
31
  }) })] }));
32
32
  };
@@ -1,4 +1,3 @@
1
- import type * as T from "./Flyout.types";
2
1
  export declare const mouseEnter = 600;
3
- export declare const defaultStyles: T.Styles;
4
- export declare const resetStyles: T.Styles;
2
+ export declare const defaultStyles: React.CSSProperties;
3
+ export declare const resetStyles: React.CSSProperties;
@@ -23,17 +23,14 @@ export type Options = Pick<BaseProps, "width" | "fallbackAdjustLayout" | "fallba
23
23
  lastUsedPosition: Position;
24
24
  onPositionChoose: (position: Position) => void;
25
25
  };
26
- export type Styles = React.CSSProperties;
27
26
  export type State = {
28
- styles: Styles;
29
27
  position?: Position;
30
28
  status: "idle" | "rendered" | "positioned" | "visible" | "hidden";
31
29
  };
32
30
  export type FlyoutData = {
33
- styles: Styles;
34
31
  position: Position;
35
32
  };
36
- export type UseFlyoutData = Pick<State, "styles" | "position" | "status"> & {
33
+ export type UseFlyoutData = Pick<State, "position" | "status"> & {
37
34
  updatePosition: (args?: {
38
35
  sync?: boolean;
39
36
  fallback?: boolean;
@@ -72,7 +69,7 @@ export type TriggerAttributes = {
72
69
  onFocus?: () => void;
73
70
  onMouseDown?: () => void;
74
71
  onMouseEnter?: () => void;
75
- onMouseLeave?: () => void;
72
+ onMouseLeave?: (e: React.MouseEvent) => void;
76
73
  onTouchStart?: () => void;
77
74
  onClick?: () => void;
78
75
  "aria-describedby"?: string;
@@ -180,7 +177,7 @@ export type ContextProps = {
180
177
  }) => void;
181
178
  handleOpen: () => void;
182
179
  handleMouseEnter: () => void;
183
- handleMouseLeave: () => void;
180
+ handleMouseLeave: (e: React.MouseEvent) => void;
184
181
  handleMouseDown: () => void;
185
182
  handleTransitionEnd: (e: React.TransitionEvent) => void;
186
183
  handleTransitionStart: (e: TransitionEvent) => void;
@@ -12,7 +12,7 @@ import cooldown from "./utilities/cooldown.js";
12
12
  const FlyoutContent = (props) => {
13
13
  const { children, className, attributes } = props;
14
14
  const { flyout, id, flyoutElRef, triggerElRef, handleClose, handleTransitionEnd, handleTransitionStart, triggerType, handleMouseEnter, handleMouseLeave, handleContentMouseDown, handleContentMouseUp, contentClassName, contentAttributes, contentGap, contentMaxHeight, trapFocusMode, disableContentHover, autoFocus, width, containerRef: passedContainerRef, isSubmenu, } = useFlyoutContext();
15
- const { styles, status, position } = flyout;
15
+ const { status, position } = flyout;
16
16
  const [mounted, setMounted] = React.useState(false);
17
17
  const closestFixedContainer = React.useMemo(() => {
18
18
  if (!mounted)
@@ -95,7 +95,6 @@ const FlyoutContent = (props) => {
95
95
  role = "menubar";
96
96
  }
97
97
  const content = (_jsx(ContentProvider, { value: { elRef: flyoutElRef }, children: _jsx("div", { className: rootClassNames, style: {
98
- ...styles,
99
98
  "--rs-flyout-gap": contentGap,
100
99
  "--rs-flyout-max-h": contentMaxHeight,
101
100
  }, ref: flyoutElRef, onTransitionEnd: handleTransitionEnd, onMouseEnter: triggerType === "hover" ? handleMouseEnter : undefined, onMouseLeave: triggerType === "hover" ? handleMouseLeave : undefined, onMouseDown: handleContentMouseDown, onTouchStart: handleContentMouseDown, onMouseUp: handleContentMouseUp, onTouchEnd: handleContentMouseUp, children: _jsx("div", { role: role, ...attributes, id: id, tabIndex: !autoFocus ? -1 : undefined, "aria-modal": role === "dialog" ? true : undefined, style: { ...attributes?.style, ...contentAttributes?.style }, className: innerClassNames, children: children }) }) }));
@@ -146,11 +146,15 @@ const FlyoutControlled = (props) => {
146
146
  }, groupTimeouts && cooldown.status === "warming" ? timeouts.mouseEnter : 0);
147
147
  }
148
148
  }, [clearTimer, handleOpen, groupTimeouts]);
149
- const handleMouseLeave = React.useCallback(() => {
149
+ const handleMouseLeave = React.useCallback((e) => {
150
+ if (e.relatedTarget === flyoutElRef.current)
151
+ return;
152
+ if (e.relatedTarget === triggerElRef.current)
153
+ return;
150
154
  cooldown.cool();
151
155
  clearTimer();
152
156
  handleClose({});
153
- }, [clearTimer, handleClose]);
157
+ }, [clearTimer, handleClose, triggerElRef, flyoutElRef]);
154
158
  const handleTriggerClick = React.useCallback(() => {
155
159
  if (!isRendered) {
156
160
  handleOpen();
@@ -7,7 +7,7 @@ type UseFlyout = (args: Pick<T.Props, "width" | "position" | "defaultActive" | "
7
7
  triggerElRef: React.RefObject<HTMLElement | null>;
8
8
  flyoutElRef: React.RefObject<HTMLElement | null>;
9
9
  triggerBounds?: DOMRect | G.Coordinates | null;
10
- }) => Pick<T.State, "styles" | "position" | "status"> & {
10
+ }) => Pick<T.State, "position" | "status"> & {
11
11
  updatePosition: (options?: {
12
12
  sync?: boolean;
13
13
  }) => void;
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  import useRTL from "../../hooks/useRTL.js";
3
- import { defaultStyles, resetStyles } from "./Flyout.constants.js";
4
3
  import flyout from "./utilities/flyout.js";
5
4
  const flyoutReducer = (state, action) => {
6
5
  switch (action.type) {
@@ -8,7 +7,7 @@ const flyoutReducer = (state, action) => {
8
7
  if (state.status !== "idle")
9
8
  return state;
10
9
  // Disable events before it's positioned to avoid mouseleave getting triggered
11
- return { ...state, status: "rendered", styles: { pointerEvents: "none", ...resetStyles } };
10
+ return { ...state, status: "rendered" };
12
11
  case "position":
13
12
  if (!action.payload.sync && state.status !== "rendered")
14
13
  return state;
@@ -18,7 +17,6 @@ const flyoutReducer = (state, action) => {
18
17
  ...state,
19
18
  status: action.payload.sync ? "visible" : "positioned",
20
19
  position: action.payload.position,
21
- styles: { ...defaultStyles, ...action.payload.styles },
22
20
  };
23
21
  case "show":
24
22
  if (state.status !== "positioned")
@@ -31,7 +29,7 @@ const flyoutReducer = (state, action) => {
31
29
  case "remove":
32
30
  if (state.status !== "hidden" && state.status !== "visible")
33
31
  return state;
34
- return { ...state, status: "idle", styles: resetStyles };
32
+ return { ...state, status: "idle" };
35
33
  default:
36
34
  throw new Error("[Reshaped] Invalid flyout reducer type");
37
35
  }
@@ -47,7 +45,6 @@ const useFlyout = (args) => {
47
45
  const [isRTL] = useRTL();
48
46
  const [state, dispatch] = React.useReducer(flyoutReducer, {
49
47
  position: defaultPosition,
50
- styles: defaultStyles,
51
48
  status: "idle",
52
49
  });
53
50
  const render = React.useCallback(() => {
@@ -114,13 +111,12 @@ const useFlyout = (args) => {
114
111
  }, [state.status, updatePosition]);
115
112
  return React.useMemo(() => ({
116
113
  position: state.position,
117
- styles: state.styles,
118
114
  status: state.status,
119
115
  updatePosition,
120
116
  render,
121
117
  hide,
122
118
  remove,
123
119
  show,
124
- }), [render, updatePosition, hide, remove, show, state.position, state.styles, state.status]);
120
+ }), [render, updatePosition, hide, remove, show, state.position, state.status]);
125
121
  };
126
122
  export default useFlyout;
@@ -13,13 +13,13 @@ declare const calculatePosition: (args: {
13
13
  } & Pick<T.Options, "position" | "rtl" | "width" | "contentGap" | "contentShift" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight">) => {
14
14
  position: T.Position;
15
15
  styles: {
16
- left: number | undefined;
17
- right: number | undefined;
18
- top: number | undefined;
19
- bottom: number | undefined;
16
+ left: string | null;
17
+ right: string | null;
18
+ top: string | null;
19
+ bottom: string | null;
20
20
  transform: string;
21
- height: number | undefined;
22
- width: string | number | undefined;
21
+ height: string | null;
22
+ width: string | null;
23
23
  };
24
24
  boundaries: {
25
25
  left: number;
@@ -159,13 +159,13 @@ const calculatePosition = (args) => {
159
159
  return {
160
160
  position,
161
161
  styles: {
162
- left: right === null ? 0 : undefined,
163
- right: right === null ? undefined : 0,
164
- top: bottom === null ? 0 : undefined,
165
- bottom: bottom === null ? undefined : 0,
162
+ left: right === null ? "0px" : null,
163
+ right: right === null ? null : "0px",
164
+ top: bottom === null ? "0px" : null,
165
+ bottom: bottom === null ? null : "0px",
166
166
  transform: `translate(${translateX}px, ${translateY}px)`,
167
- height,
168
- width: width ?? passedWidth,
167
+ height: height !== undefined ? `${height}px` : null,
168
+ width: width !== undefined ? `${width}px` : (passedWidth ?? null),
169
169
  },
170
170
  boundaries: {
171
171
  left,
@@ -79,6 +79,9 @@ const flyout = (args) => {
79
79
  calculated = applyPosition(lastUsedPosition);
80
80
  onPositionChoose(calculated.position);
81
81
  targetClone.parentNode?.removeChild(targetClone);
82
- return calculated;
82
+ Object.entries(calculated.styles).forEach(([key, value]) => {
83
+ flyoutEl.style.setProperty(key, value);
84
+ });
85
+ return { position: calculated.position };
83
86
  };
84
87
  export default flyout;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "reshaped",
3
3
  "description": "Professionally crafted design system in React & Figma for building products of any scale and complexity",
4
- "version": "3.9.0-canary.3",
4
+ "version": "3.9.0-canary.5",
5
5
  "license": "MIT",
6
6
  "email": "hello@reshaped.so",
7
7
  "homepage": "https://reshaped.so",