Skip to content

Commit

Permalink
Migrate popovers and tooltips to Floating UI (#770)
Browse files Browse the repository at this point in the history
* - Add Floating UI library to tooltip package.
- Update Tooltip to use Floating UI instead of Tippy.

# Breaking
- Tooltip no longer supports props `trigger` and `disabled`.

* - Apply prettier.

* - Working on new Popover.

* - Everything seems to be working except z-index. Check StandardTable header.

* - Add portal to popovers.

* - Add support for all placements that were previously available. It was already supported by Floating UI, so just had to add the types.
- That fixes the TODOs.
  • Loading branch information
mattias800 committed Aug 23, 2024
1 parent da344c5 commit 8255df6
Show file tree
Hide file tree
Showing 40 changed files with 1,004 additions and 1,346 deletions.
5 changes: 0 additions & 5 deletions .storybook/manager.ts

This file was deleted.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
"@storybook/addon-links": "^8.2.9",
"@storybook/addon-mdx-gfm": "^8.2.9",
"@storybook/addon-storysource": "^8.2.9",
"@storybook/addons": "^7.6.17",
"@storybook/blocks": "^8.2.9",
"@storybook/react": "^8.2.9",
"@storybook/react-vite": "^8.2.9",
Expand Down
84 changes: 41 additions & 43 deletions packages/calendar/src/components/calendar/CalendarMonth.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box, Row, Text } from "@stenajs-webui/core";
import * as React from "react";
import { ReactNode } from "react";
import {
CalendarDayProps,
CalendarOnClicks,
Expand All @@ -21,7 +22,6 @@ import { CalendarDay } from "./renderers/CalendarDay";
import { FlatButton, stenaAngleDown } from "@stenajs-webui/elements";
import { WeekNumberCell } from "./renderers/WeekNumberCell";
import { DisabledDayWrapper } from "./DisabledDayWrapper";
import { ReactNode } from "react";

export interface CalendarMonthProps<T>
extends CalendarOnClicks<T>,
Expand Down Expand Up @@ -106,48 +106,46 @@ export function CalendarMonth<T>({
))}
</tr>
{month.weeks.map((week: WeekData) => (
<>
<tr key={week.weekNumber}>
{showWeekNumber && (
<td>
{renderWeekNumber ? (
renderWeekNumber(week, theme, onClickWeek)
) : (
<WeekNumberCell
week={week}
onClickWeek={onClickWeek}
theme={theme}
/>
)}
</td>
)}
{week.days.map((day) => (
<DisabledDayWrapper
dayComponent={dayComponent}
key={day.dateString}
day={day}
week={week}
month={month}
dayState={
statePerWeek &&
statePerWeek[week.weekNumber] &&
statePerWeek[week.weekNumber][day.dayOfMonth]
}
userData={
userDataPerWeek &&
userDataPerWeek[week.weekNumber] &&
userDataPerWeek[week.weekNumber][day.dayOfMonth]
}
onClickDay={onClickDay}
theme={theme}
extraDayContent={extraDayContent}
defaultHighlights={defaultHighlights}
minDate={minDate}
maxDate={maxDate}
/>
))}
</tr>
</>
<tr key={week.weekNumber}>
{showWeekNumber && (
<td>
{renderWeekNumber ? (
renderWeekNumber(week, theme, onClickWeek)
) : (
<WeekNumberCell
week={week}
onClickWeek={onClickWeek}
theme={theme}
/>
)}
</td>
)}
{week.days.map((day) => (
<DisabledDayWrapper
dayComponent={dayComponent}
key={day.dateString}
day={day}
week={week}
month={month}
dayState={
statePerWeek &&
statePerWeek[week.weekNumber] &&
statePerWeek[week.weekNumber][day.dayOfMonth]
}
userData={
userDataPerWeek &&
userDataPerWeek[week.weekNumber] &&
userDataPerWeek[week.weekNumber][day.dayOfMonth]
}
onClickDay={onClickDay}
theme={theme}
extraDayContent={extraDayContent}
defaultHighlights={defaultHighlights}
minDate={minDate}
maxDate={maxDate}
/>
))}
</tr>
))}
</tbody>
</table>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Box } from "@stenajs-webui/core";
import { stenaCalendar, TextInputButton } from "@stenajs-webui/elements";
import { TextInput, TextInputProps } from "@stenajs-webui/forms";
import { Popover } from "@stenajs-webui/tooltip";
import { ControlledPopover } from "@stenajs-webui/tooltip";
import { format } from "date-fns";
import * as React from "react";
import { defaultPopoverPlacement } from "../../../config/DefaultPopoverPlacement";
import { useCalendarPopoverUpdater } from "../../../features/internal-panel-state/UseCalendarPopoverUpdater";
import { DateFormats } from "../../../util/date/DateFormats";
import { SingleDateCalendar } from "../../calendar-types/single-date-calendar/SingleDateCalendar";
import {
Expand Down Expand Up @@ -42,16 +41,6 @@ export interface DateInputProps<T = unknown>
/**
* Portal target, HTML element. If not set, portal is not used.
*/
portalTarget?: HTMLElement | null;
/**
* Z-index of the calendar overlay.
* @default 100
*/
zIndex?: number;
/**
* Width of the input element.
* * @default 125px
*/
width?: string;
/**
* The calendar theme to use.
Expand All @@ -69,13 +58,11 @@ export const DateInput: React.FC<DateInputProps> = ({
displayFormat = DateFormats.fullDate,
placeholder = "Enter date",
value,
zIndex = 100,
calendarTheme = defaultCalendarTheme,
calendarProps,
openOnMount,
onClose,
onChange,
portalTarget,
variant,
width,
minDate,
Expand All @@ -85,48 +72,42 @@ export const DateInput: React.FC<DateInputProps> = ({
const { hideCalendar, showingCalendar, onSelectDate, showCalendar } =
useDateInput(onChange, onClose, openOnMount);

const { tippyRef, onChangePanel } = useCalendarPopoverUpdater();

return (
<Box width={width}>
<Popover
arrow={false}
lazy
visible={showingCalendar}
onClickOutside={hideCalendar}
<ControlledPopover
hideArrow
open={showingCalendar}
onRequestClose={hideCalendar}
renderTrigger={(props) => (
<Box {...props}>
<TextInput
type={"date"}
onFocus={showCalendar}
buttonRight={
<TextInputButton onClick={showCalendar} icon={stenaCalendar} />
}
value={value ? format(value, displayFormat) : ""}
placeholder={placeholder}
size={9}
disabled={disabled}
autoFocus={openOnMount}
variant={variant}
min={minDate}
max={maxDate}
/>
</Box>
)}
placement={defaultPopoverPlacement}
zIndex={zIndex}
appendTo={portalTarget ?? "parent"}
tippyRef={tippyRef}
disabled={disabled}
content={
<SingleDateCalendar
{...calendarProps}
onChange={onSelectDate}
value={value}
theme={calendarTheme}
onChangePanel={onChangePanel}
minDate={minDate}
maxDate={maxDate}
/>
}
>
<TextInput
type={"date"}
onFocus={showCalendar}
buttonRight={
<TextInputButton onClick={showCalendar} icon={stenaCalendar} />
}
value={value ? format(value, displayFormat) : ""}
placeholder={placeholder}
size={9}
disabled={disabled}
autoFocus={openOnMount}
variant={variant}
min={minDate}
max={maxDate}
<SingleDateCalendar
{...calendarProps}
onChange={onSelectDate}
value={value}
theme={calendarTheme}
minDate={minDate}
maxDate={maxDate}
/>
</Popover>
</ControlledPopover>
</Box>
);
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Box, useDelayedFalse } from "@stenajs-webui/core";
import { Box } from "@stenajs-webui/core";
import { stenaArrowRight } from "@stenajs-webui/elements";
import {
TextInputProps,
ValueAndOnValueChangeProps,
} from "@stenajs-webui/forms";
import { Popover } from "@stenajs-webui/tooltip";
import { ControlledPopover } from "@stenajs-webui/tooltip";
import { isAfter } from "date-fns";
import * as React from "react";
import { useMemo, useRef } from "react";
Expand Down Expand Up @@ -115,63 +115,61 @@ export function DateRangeDualTextInput<TData>({
[calendarProps?.statePerMonth, startDate, endDate, dateInFocus]
);

const delayedIsCalendarVisible = useDelayedFalse(isCalendarVisible, 300);

return (
<Box onKeyDown={onKeyDownHandler}>
<Popover
arrow={false}
lazy
disabled={disabled}
placement={defaultPopoverPlacement}
onClickOutside={hideCalendar}
visible={isCalendarVisible}
content={
delayedIsCalendarVisible && (
<CalendarWithMonthSwitcher
onClickDay={onClickDay}
dateInFocus={dateInFocus}
setDateInFocus={setDateInFocus}
currentPanel={currentPanel}
setCurrentPanel={setCurrentPanel}
minDate={minDate}
maxDate={maxDate}
{...calendarProps}
statePerMonth={statePerMonth}
<ControlledPopover
hideArrow
restoreFocus={false}
returnFocus={false}
renderTrigger={(props) => (
<Box {...props}>
<DualTextInput
autoFocusLeft={autoFocus}
onEsc={onEsc}
onEnter={onEnter}
onBlur={onBlur}
disabled={disabled}
separatorIcon={stenaArrowRight}
typeLeft={"date"}
typeRight={"date"}
placeholderLeft={"Start date"}
placeholderRight={"End date"}
onChangeLeft={inputLeftChangeHandler}
onChangeRight={inputRightChangeHandler}
onClickArrowDown={onClickArrowButton}
onClickCalendar={onClickCalendarButton}
onFocusLeft={onFocusLeft}
onFocusRight={onFocusRight}
onClickLeft={onFocusLeft}
onClickRight={onFocusRight}
inputRefLeft={startDateInputRef}
inputRefRight={endDateInputRef}
variant={startDateIsAfterEnd ? "error" : variant}
widthLeft={widthLeft}
widthRight={widthRight}
minLeft={minDate}
maxLeft={maxDate}
minRight={minDate}
maxRight={maxDate}
/>
)
}
</Box>
)}
placement={defaultPopoverPlacement}
onRequestClose={hideCalendar}
open={isCalendarVisible}
>
<DualTextInput
autoFocusLeft={autoFocus}
onEsc={onEsc}
onEnter={onEnter}
onBlur={onBlur}
disabled={disabled}
separatorIcon={stenaArrowRight}
typeLeft={"date"}
typeRight={"date"}
placeholderLeft={"Start date"}
placeholderRight={"End date"}
onChangeLeft={inputLeftChangeHandler}
onChangeRight={inputRightChangeHandler}
onClickArrowDown={onClickArrowButton}
onClickCalendar={onClickCalendarButton}
onFocusLeft={onFocusLeft}
onFocusRight={onFocusRight}
onClickLeft={onFocusLeft}
onClickRight={onFocusRight}
inputRefLeft={startDateInputRef}
inputRefRight={endDateInputRef}
variant={startDateIsAfterEnd ? "error" : variant}
widthLeft={widthLeft}
widthRight={widthRight}
minLeft={minDate}
maxLeft={maxDate}
minRight={minDate}
maxRight={maxDate}
<CalendarWithMonthSwitcher
onClickDay={onClickDay}
dateInFocus={dateInFocus}
setDateInFocus={setDateInFocus}
currentPanel={currentPanel}
setCurrentPanel={setCurrentPanel}
minDate={minDate}
maxDate={maxDate}
{...calendarProps}
statePerMonth={statePerMonth}
/>
</Popover>
</ControlledPopover>
</Box>
);
}
Loading

0 comments on commit 8255df6

Please sign in to comment.