From 061159f4bbef0755f50858e53b439d09095b5515 Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Tue, 24 Dec 2024 12:46:04 +0530 Subject: [PATCH 01/11] feat: calendar component --- example/storybook-nativewind/babel.config.js | 4 + .../src/components/Calendar/Calendar.tsx | 34 +++ .../components/Calendar/Calender.stories.tsx | 18 ++ .../nativewind/calendar/index.tsx | 252 ++++++++++++++++++ .../nativewind/calendar/styles.tsx | 48 ++++ example/storybook-nativewind/tsconfig.json | 1 + example/storybook/tsconfig.json | 3 + packages/unstyled/calendar/.npmignore | 20 ++ packages/unstyled/calendar/CHANGELOG.md | 5 + packages/unstyled/calendar/README.md | 61 +++++ packages/unstyled/calendar/babel.config.js | 25 ++ packages/unstyled/calendar/package.json | 80 ++++++ packages/unstyled/calendar/src/Calendar.tsx | 150 +++++++++++ .../unstyled/calendar/src/CalendarGrid.tsx | 10 + .../calendar/src/CalendarGridDays.tsx | 29 ++ .../calendar/src/CalendarGridWeek.tsx | 18 ++ .../unstyled/calendar/src/CalendarHeader.tsx | 9 + .../calendar/src/CalendarHeaderNext.tsx | 81 ++++++ .../calendar/src/CalendarHeaderPrev.tsx | 82 ++++++ .../calendar/src/CalendarHeaderTitle.tsx | 11 + packages/unstyled/calendar/src/Context.tsx | 18 ++ packages/unstyled/calendar/src/index.tsx | 68 +++++ packages/unstyled/calendar/src/types.ts | 184 +++++++++++++ packages/unstyled/calendar/tsconfig.json | 31 +++ 24 files changed, 1242 insertions(+) create mode 100644 example/storybook-nativewind/src/components/Calendar/Calendar.tsx create mode 100644 example/storybook-nativewind/src/components/Calendar/Calender.stories.tsx create mode 100644 example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx create mode 100644 example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx create mode 100644 packages/unstyled/calendar/.npmignore create mode 100644 packages/unstyled/calendar/CHANGELOG.md create mode 100644 packages/unstyled/calendar/README.md create mode 100644 packages/unstyled/calendar/babel.config.js create mode 100644 packages/unstyled/calendar/package.json create mode 100644 packages/unstyled/calendar/src/Calendar.tsx create mode 100644 packages/unstyled/calendar/src/CalendarGrid.tsx create mode 100644 packages/unstyled/calendar/src/CalendarGridDays.tsx create mode 100644 packages/unstyled/calendar/src/CalendarGridWeek.tsx create mode 100644 packages/unstyled/calendar/src/CalendarHeader.tsx create mode 100644 packages/unstyled/calendar/src/CalendarHeaderNext.tsx create mode 100644 packages/unstyled/calendar/src/CalendarHeaderPrev.tsx create mode 100644 packages/unstyled/calendar/src/CalendarHeaderTitle.tsx create mode 100644 packages/unstyled/calendar/src/Context.tsx create mode 100644 packages/unstyled/calendar/src/index.tsx create mode 100644 packages/unstyled/calendar/src/types.ts create mode 100644 packages/unstyled/calendar/tsconfig.json diff --git a/example/storybook-nativewind/babel.config.js b/example/storybook-nativewind/babel.config.js index 3470aff3d9..ea9264976d 100644 --- a/example/storybook-nativewind/babel.config.js +++ b/example/storybook-nativewind/babel.config.js @@ -39,6 +39,10 @@ module.exports = function (api) { __dirname, '../../packages/unstyled/input/src' ), + '@gluestack-ui/calendar': path.resolve( + __dirname, + '../../packages/unstyled/calendar/src' + ), '@gluestack-ui/tooltip': path.resolve( __dirname, '../../packages/unstyled/tooltip/src' diff --git a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx new file mode 100644 index 0000000000..7aaab0fcbb --- /dev/null +++ b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { + Calendar, + CalendarHeader, + CalendarHeaderNext, + CalendarHeaderPrev, + CalendarHeaderTitle, + CalendarGrid, + CalendarGridWeek, + CalendarGridDays, +} from '@/components/ui/calendar'; + +const CalendarBasic = () => { + return ( + + + + + + + + + + + + ); +}; + +CalendarBasic.description = + 'This is a basic Calendar component example. The Calendar component lets you quickly and easily add status indicators to your interface for improved usability. They are designed to be attention-grabbing and quickly convey important information.'; + +export default CalendarBasic; + +export { Calendar }; diff --git a/example/storybook-nativewind/src/components/Calendar/Calender.stories.tsx b/example/storybook-nativewind/src/components/Calendar/Calender.stories.tsx new file mode 100644 index 0000000000..41bfc83a0a --- /dev/null +++ b/example/storybook-nativewind/src/components/Calendar/Calender.stories.tsx @@ -0,0 +1,18 @@ +import type { ComponentMeta } from '@storybook/react-native'; +import Calendar from './Calendar'; + +const CalendarMeta: ComponentMeta = { + title: 'stories/Calendar', + component: Calendar, + // @ts-ignore + metaInfo: { + componentDescription: + 'A calendar component that allows users to select dates and navigate between months.', + }, + args: {}, + argTypes: {}, +}; + +export default CalendarMeta; + +export { Calendar }; diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx new file mode 100644 index 0000000000..c2444ecffd --- /dev/null +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx @@ -0,0 +1,252 @@ +'use client'; +import React from 'react'; +import { + View as RNView, + Pressable as RNPressable, + Text as RNText, + TextProps as RNTextProps, + Platform, +} from 'react-native'; +import { createCalendar } from '@gluestack-ui/calendar'; +import { withStyleContext } from '@gluestack-ui/nativewind-utils/withStyleContext'; +import { cssInterop } from 'nativewind'; +import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon'; +import { VariantProps } from '@gluestack-ui/nativewind-utils/types'; +import { + calendarStyle, + calendarGridStyle, + calendarGridWeekStyle, + calendarGridDaysStyle, + calendarHeaderStyle, + calendarNavStyle, + calendarTitleStyle, + calendarWeekCellStyle, + calendarDaysCellStyle, +} from './styles'; +import { ChevronRight, ChevronLeft } from 'lucide-react-native'; + +const SCOPE = 'CALENDAR'; + +const Root = withStyleContext(RNView, SCOPE); + +const Header = ( + Platform.OS === 'web' ? RNText : RNView +) as React.ComponentType; + +/** Creator */ + +const UICalendar = createCalendar({ + Root: Root, + HeaderPrev: RNPressable, + HeaderTitle: RNText, + HeaderNext: RNPressable, + Header: Header, + GridWeek: RNView, + GridDays: RNView, + Grid: RNView, +}); + +cssInterop(PrimitiveIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: 'classNameColor', + stroke: true, + }, + }, +}); + +type ICalendarProps = React.ComponentPropsWithoutRef & + VariantProps; + +type ICalendarGridProps = React.ComponentPropsWithoutRef< + typeof UICalendar.Grid +> & + VariantProps; + +type ICalendarGridWeekProps = React.ComponentPropsWithoutRef< + typeof UICalendar.GridWeek +> & + VariantProps; + +type ICalendarGridDaysProps = React.ComponentPropsWithoutRef< + typeof UICalendar.GridDays +> & + VariantProps; + +type ICalendarHeaderProps = React.ComponentPropsWithoutRef< + typeof UICalendar.Header +> & + VariantProps; + +type ICalendarHeaderPrevProps = React.ComponentPropsWithoutRef< + typeof UICalendar.HeaderPrev +> & + VariantProps; + +type ICalendarHeaderNextProps = React.ComponentPropsWithoutRef< + typeof UICalendar.HeaderNext +> & + VariantProps; + +type ICalendarHeaderTitleProps = React.ComponentPropsWithoutRef< + typeof UICalendar.HeaderTitle +> & + VariantProps; + +/** Components */ + +const Calendar = React.forwardRef< + React.ElementRef, + ICalendarProps +>(({ className, ...props }, ref) => { + return ( + + ); +}); + +const CalendarHeaderPrev = React.forwardRef< + React.ElementRef, + ICalendarHeaderPrevProps +>(({ className, ...props }, ref) => { + return ( + + + + ); +}); + +const CalendarHeaderNext = React.forwardRef< + React.ElementRef, + ICalendarHeaderNextProps +>(({ className, ...props }, ref) => { + return ( + + + + ); +}); + +const CalendarHeaderTitle = React.forwardRef< + React.ElementRef, + ICalendarHeaderTitleProps +>(({ className, ...props }, ref) => { + return ( + + ); +}); + +const CalendarHeader = React.forwardRef< + React.ElementRef, + ICalendarHeaderProps +>(({ className, ...props }, ref) => { + return ( + + ); +}); + +const CalendarGrid = React.forwardRef< + React.ElementRef, + ICalendarGridProps +>(({ className, ...props }, ref) => { + return ( + + ); +}); + +const CalendarGridWeek = React.forwardRef< + React.ElementRef, + ICalendarGridWeekProps +>(({ className, ...props }, ref) => { + return ( + { + return weekdays.map((day) => { + return ( + + {day} + + ); + }); + }} + /> + ); +}); + +const CalendarGridDays = React.forwardRef< + React.ElementRef, + ICalendarGridDaysProps +>(({ className, ...props }, ref) => { + return ( + { + return days.map((day) => { + return ( + + {day} + + ); + }); + }} + /> + ); +}); + +Calendar.displayName = 'Calendar'; +CalendarHeaderPrev.displayName = 'CalendarHeaderPrev'; +CalendarHeaderNext.displayName = 'CalendarHeaderNext'; +CalendarHeaderTitle.displayName = 'CalendarHeaderTitle'; +CalendarHeader.displayName = 'CalendarHeader'; +CalendarGrid.displayName = 'CalendarGrid'; +CalendarGridWeek.displayName = 'CalendarGridWeek'; +CalendarGridDays.displayName = 'CalendarGridDays'; + +export { + Calendar, + CalendarHeaderPrev, + CalendarHeaderNext, + CalendarHeaderTitle, + CalendarHeader, + CalendarGrid, + CalendarGridWeek, + CalendarGridDays, +}; diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx new file mode 100644 index 0000000000..c76567e527 --- /dev/null +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx @@ -0,0 +1,48 @@ +import { tva } from '@gluestack-ui/nativewind-utils/tva'; + +export const calendarStyle = tva({ + base: 'flex flex-col bg-white rounded-lg shadow-lg max-w-sm', +}); + +export const calendarNavStyle = tva({ + base: 'w-8 h-8 flex items-center justify-center rounded-full hover:bg-typography-100 active:bg-typography-200', +}); + +export const calendarTitleStyle = tva({ + base: 'text-lg font-semibold text-typography-800', +}); + +export const calendarHeaderStyle = tva({ + base: 'flex flex-row w-full justify-between items-center p-4 border-b border-typography-200', +}); + +export const calendarGridWeekStyle = tva({ + base: 'flex-row flex-wrap', +}); + +export const calendarGridDaysStyle = tva({ + base: 'flex-row flex-wrap', +}); + +export const calendarDaysCellStyle = tva({ + base: 'w-[14.28%] p-2 aspect-square items-center justify-center hover:bg-typography-50 active:bg-typography-100', + variants: { + isToday: { + true: 'bg-blue-50 font-bold text-blue-600', + }, + isSelected: { + true: 'bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800', + }, + isDisabled: { + true: 'text-typography-300 hover:bg-transparent cursor-not-allowed', + }, + }, +}); + +export const calendarWeekCellStyle = tva({ + base: 'w-[14.28%] p-2 aspect-square text-center text-typography-500 font-medium', +}); + +export const calendarGridStyle = tva({ + base: 'flex-col p-4', +}); diff --git a/example/storybook-nativewind/tsconfig.json b/example/storybook-nativewind/tsconfig.json index 9a4c532e1d..c79a9682b6 100644 --- a/example/storybook-nativewind/tsconfig.json +++ b/example/storybook-nativewind/tsconfig.json @@ -33,6 +33,7 @@ ], "@gluestack-ui/menu": ["../../packages/unstyled/menu/src"], "@gluestack-ui/select": ["../../packages/unstyled/select/src"], + "@gluestack-ui/calendar": ["../../packages/unstyled/calendar/src"], "@gluestack-ui/textarea": ["../../packages/unstyled/textarea/src"], "@gluestack-ui/link": ["../../packages/unstyled/link/src"], "@gluestack-ui/nativewind-utils/tva": [ diff --git a/example/storybook/tsconfig.json b/example/storybook/tsconfig.json index 41196d6c06..210ebadda5 100644 --- a/example/storybook/tsconfig.json +++ b/example/storybook/tsconfig.json @@ -19,6 +19,9 @@ ], "@react-native-aria/interactions": [ "../../packages/react-native-aria/interactions/src" + ], + "@gluestack-ui/unstyled/calendar": [ + "../../packages/unstyled/calendar/src" ] }, "emitDeclarationOnly": true, diff --git a/packages/unstyled/calendar/.npmignore b/packages/unstyled/calendar/.npmignore new file mode 100644 index 0000000000..187790b632 --- /dev/null +++ b/packages/unstyled/calendar/.npmignore @@ -0,0 +1,20 @@ +# Dotfiles +.babelrc +.eslintignore +.eslintrc.json +.gitattributes +_config.yml +.editorconfig + + +#Config files +babel.config.js + +# Documents +CONTRIBUTING.md +ISSUE_TEMPLATE.txt +img + +# Test cases +__tests__ +dist/__tests__ diff --git a/packages/unstyled/calendar/CHANGELOG.md b/packages/unstyled/calendar/CHANGELOG.md new file mode 100644 index 0000000000..e5e5638c29 --- /dev/null +++ b/packages/unstyled/calendar/CHANGELOG.md @@ -0,0 +1,5 @@ +# @gluestack-ui/calendar + +## 0.0.1 + +- Initial release diff --git a/packages/unstyled/calendar/README.md b/packages/unstyled/calendar/README.md new file mode 100644 index 0000000000..df81660426 --- /dev/null +++ b/packages/unstyled/calendar/README.md @@ -0,0 +1,61 @@ +# @gluestack-style/input + +## Installation + +To use `@gluestack-ui/input`, all you need to do is install the +`@gluestack-ui/input` package: + +```sh +$ yarn add @gluestack-ui/calendar + +# or + +$ npm i @gluestack-ui/calendar +``` + +## Usage + +The Input component is your go-to tool for gathering user input in a sleek and user-friendly text field. Whether you're designing a simple login form or a complex search feature, this component has got you covered. Here's an example how to use this package to create one: + +```jsx +import { Root, Input } from '../components/core/input/styled-components'; +import { createInput } from '@gluestack-ui/input'; +const InputField = createInput({ + Root, + Input, +}); +``` + +## Customizing the input: + +Default styling of all these components can be found in the components/core/input file. For reference, you can view the [source code](https://github.com/gluestack/gluestack-ui/blob/development/example/storybook/src/ui-components/Input/index.tsx) of the styled `input` components. + +```jsx +// import the styles +import { Root, Input } from '../components/core/input/styled-components'; + +// import the createInput function +import { createInput } from '@gluestack-ui/input'; + +//import any icon +import { searchIcon } from '@gluestack/icons'; + +// Understanding the API +const InputField = createInput({ + Root, + Input, +}); + +// Using the input component +export default () => ( + + + + + + +); +``` + +More guides on how to get started are available +[here](https://ui.gluestack.io/docs/components/forms/input). diff --git a/packages/unstyled/calendar/babel.config.js b/packages/unstyled/calendar/babel.config.js new file mode 100644 index 0000000000..b91297b45f --- /dev/null +++ b/packages/unstyled/calendar/babel.config.js @@ -0,0 +1,25 @@ +const path = require('path'); + +module.exports = function (api) { + api.cache(true); + return { + presets: ['babel-preset-expo'], + plugins: [ + process.env.NODE_ENV !== 'production' + ? [ + 'module-resolver', + { + alias: { + ['@gluestack-ui/utils']: path.resolve( + __dirname, + '../utils/src' + ), + // ['@gluestack-ui/utils']: path.resolve(__dirname, '../utils/src'), + // For development, we want to alias the library to the source + }, + }, + ] + : ['babel-plugin-react-docgen-typescript', { exclude: 'node_modules' }], + ], + }; +}; diff --git a/packages/unstyled/calendar/package.json b/packages/unstyled/calendar/package.json new file mode 100644 index 0000000000..dbc59ee581 --- /dev/null +++ b/packages/unstyled/calendar/package.json @@ -0,0 +1,80 @@ +{ + "name": "@gluestack-ui/calendar", + "description": "A universal headless Calendar component for React Native, Next.js & React", + "version": "0.0.1", + "main": "lib/index", + "module": "lib/index", + "types": "lib/index.d.ts", + "react-native": "src/index", + "source": "src/index", + "typings": "lib/index.d.ts", + "scripts": { + "prepare": "tsc", + "release": "release-it", + "watch": "tsc --watch", + "build": "tsc", + "clean": "rm -rf lib", + "dev:web": "cd example/native && yarn web --clear", + "storybook": "cd example/native/storybook && yarn web" + }, + "devDependencies": { + "@types/react": "^18.0.22", + "@types/react-native": "^0.72.3", + "babel-plugin-transform-remove-console": "^6.9.4", + "react": "^18.1.0", + "react-dom": "^18.1.0", + "react-native": "^0.72.4", + "react-native-builder-bob": "^0.20.1", + "react-native-web": "^0.19.9", + "tsconfig": "7", + "typescript": "^5.6.3" + }, + "dependencies": { + "@gluestack-ui/utils": "^0.1.14", + "@react-native-aria/focus": "^0.2.9", + "@react-native-aria/interactions": "0.2.13" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + }, + "homepage": "https://github.com/gluestack/gluestack-ui/tree/main/packages/unstyled/input#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/gluestack/gluestack-ui.git" + }, + "files": [ + "lib/", + "src/" + ], + "jest": { + "preset": "jest-expo", + "transform": { + "^.+\\.js$": "/node_modules/react-native/jest/preprocessor.js" + }, + "modulePathIgnorePatterns": [ + "/example/*", + "/lib/" + ], + "transformIgnorePatterns": [ + "node_modules/(?!(@react-native|react-native|expo-asset|expo-constants|@unimodules|react-native-unimodules|expo-font|react-native-svg|@expo/vector-icons|react-native-vector-icons|@react-native-aria/checkbox|@react-native-aria/interactions|@react-native-aria/button|@react-native-aria/switch|@react-native-aria/toggle|@react-native-aria/utils|@react-native-aria/*))" + ], + "setupFiles": [ + "/src/jest/mock.ts" + ] + }, + "keywords": [ + "react", + "native", + "react-native", + "calendar", + "gluestack-ui", + "universal", + "headless", + "typescript", + "component", + "android", + "ios", + "nextjs" + ] +} diff --git a/packages/unstyled/calendar/src/Calendar.tsx b/packages/unstyled/calendar/src/Calendar.tsx new file mode 100644 index 0000000000..a5db4abd1d --- /dev/null +++ b/packages/unstyled/calendar/src/Calendar.tsx @@ -0,0 +1,150 @@ +import React, { forwardRef, useMemo, useCallback } from 'react'; +import { CalendarContext } from './Context'; +import type { ICalendarProps } from './types'; + +const WEEKDAYS = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; +const MONTHS = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', +]; + +export function Calendar(StyledCalendar: any) { + return forwardRef( + ( + { + children, + value, + defaultValue, + onChange, + minDate, + maxDate, + ...props + }: ICalendarProps, + ref?: any + ) => { + const [selectedDate, setSelectedDate] = React.useState( + value ?? defaultValue + ); + const [currentMonth, setCurrentMonth] = React.useState( + selectedDate ?? new Date() + ); + + const isPrevDisabled = minDate ? currentMonth < minDate : false; + const isNextDisabled = maxDate ? currentMonth > maxDate : false; + + const title = useMemo(() => { + return `${ + MONTHS[currentMonth.getMonth()] + } ${currentMonth.getFullYear()}`; + }, [currentMonth]); + + const prevMonth = useCallback(() => { + const newDate = new Date( + currentMonth.getFullYear(), + currentMonth.getMonth() - 1, + 1 + ); + setCurrentMonth(newDate); + }, [currentMonth]); + + const nextMonth = useCallback(() => { + const newDate = new Date( + currentMonth.getFullYear(), + currentMonth.getMonth() + 1, + 1 + ); + setCurrentMonth(newDate); + }, [currentMonth]); + + const getDaysInMonth = useCallback(() => { + const year = currentMonth.getFullYear(); + const month = currentMonth.getMonth(); + const daysInMonth = new Date(year, month + 1, 0).getDate(); + const firstDayOfMonth = new Date(year, month, 1).getDay(); + + const days = []; + + for (let i = 0; i < firstDayOfMonth; i++) { + days.push(null); + } + + for (let i = 1; i <= daysInMonth; i++) { + days.push(i); + } + + return days; + }, [currentMonth]); + + const handleDateSelect = useCallback( + (day: number) => { + const newDate = new Date(currentMonth); + newDate.setDate(day); + if (minDate && newDate < minDate) return; + if (maxDate && newDate > maxDate) return; + + setSelectedDate(newDate); + onChange?.(newDate); + }, + [currentMonth, minDate, maxDate, onChange] + ); + + const isToday = useCallback( + (day: number) => { + const today = new Date(); + return ( + today.getDate() === day && + today.getMonth() === currentMonth.getMonth() && + today.getFullYear() === currentMonth.getFullYear() + ); + }, + [currentMonth] + ); + + const contextValue = useMemo( + () => ({ + selectedDate, + currentMonth, + title, + prevMonth, + nextMonth, + getDaysInMonth, + handleDateSelect, + isToday, + weekDays: WEEKDAYS, + months: MONTHS, + isPrevDisabled, + isNextDisabled, + }), + [ + selectedDate, + currentMonth, + title, + prevMonth, + nextMonth, + getDaysInMonth, + handleDateSelect, + isToday, + isPrevDisabled, + isNextDisabled, + ] + ); + return ( + + + {children} + + + ); + } + ); +} diff --git a/packages/unstyled/calendar/src/CalendarGrid.tsx b/packages/unstyled/calendar/src/CalendarGrid.tsx new file mode 100644 index 0000000000..e4c3e37ff1 --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarGrid.tsx @@ -0,0 +1,10 @@ +import React, { forwardRef } from 'react'; + +export const CalendarGrid = (StyledCalendarGrid: any) => + forwardRef(({ children, ...props }: any, ref?: any) => { + return ( + + {children} + + ); + }); diff --git a/packages/unstyled/calendar/src/CalendarGridDays.tsx b/packages/unstyled/calendar/src/CalendarGridDays.tsx new file mode 100644 index 0000000000..d64127e803 --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarGridDays.tsx @@ -0,0 +1,29 @@ +import React, { forwardRef } from 'react'; +import type { ICalendarDayProps } from './types'; +import { useCalendarContext } from './Context'; + +export const CalendarGridDays = (StyledCalendarGridDays: any) => + forwardRef(({ render, ...props }: any, ref?: any) => { + const { getDaysInMonth, handleDateSelect, isToday } = useCalendarContext(); + const days = getDaysInMonth(); + + const DayComponent = ({ day, ...dayProps }: ICalendarDayProps) => ( + day !== null && handleDateSelect(day)} + {...dayProps} + /> + ); + + return ( + + {render + ? render(days, DayComponent) + : // Default rendering + days.map((day, index) => ( + + ))} + + ); + }); diff --git a/packages/unstyled/calendar/src/CalendarGridWeek.tsx b/packages/unstyled/calendar/src/CalendarGridWeek.tsx new file mode 100644 index 0000000000..061f0de8c2 --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarGridWeek.tsx @@ -0,0 +1,18 @@ +import React, { forwardRef } from 'react'; +import { useCalendarContext } from './Context'; +export const CalendarGridWeek = (StyledCalendarGridWeek: any) => + forwardRef(({ children, render, ...props }: any, ref?: any) => { + const { weekDays } = useCalendarContext(); + + const Component = ({ weekday, ...props }: any) => ( + + ); + + const content = render ? render(weekDays, Component) : children; + + return ( + + {content} + + ); + }); diff --git a/packages/unstyled/calendar/src/CalendarHeader.tsx b/packages/unstyled/calendar/src/CalendarHeader.tsx new file mode 100644 index 0000000000..4b7032ceee --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarHeader.tsx @@ -0,0 +1,9 @@ +import React, { forwardRef } from 'react'; +export const CalendarHeader = (StyledCalendarHeader: any) => + forwardRef(({ children, ...props }: any, ref?: any) => { + return ( + + {children} + + ); + }); diff --git a/packages/unstyled/calendar/src/CalendarHeaderNext.tsx b/packages/unstyled/calendar/src/CalendarHeaderNext.tsx new file mode 100644 index 0000000000..74ec059428 --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarHeaderNext.tsx @@ -0,0 +1,81 @@ +import React, { forwardRef } from 'react'; +import { useHover, usePress } from '@react-native-aria/interactions'; +import { useFocus, useFocusRing } from '@react-native-aria/focus'; +import { composeEventHandlers } from '@gluestack-ui/utils'; +import { useCalendarContext } from './Context'; +export const CalendarHeaderNext = (StyledCalendarHeaderNext: any) => + forwardRef( + ( + { + isDisabled, + isPressed: isPressedProp, + isHovered: isHoveredProp, + isFocused: isFocusedProp, + isFocusVisible: isFocusVisibleProp, + ...props + }: any, + ref?: any + ) => { + const { isNextDisabled, nextMonth } = useCalendarContext(); + const handlePress = () => { + if (!isDisabled && !isNextDisabled) { + nextMonth(); + } + }; + const { isHovered, hoverProps }: any = useHover(); + const { isPressed, pressProps } = usePress({ + onPress: handlePress, + isDisabled: isDisabled || isNextDisabled, + }); + const { isFocused, focusProps } = useFocus(); + const { isFocusVisible, focusProps: focusRingProps }: any = + useFocusRing(); + return ( + + ); + } + ); diff --git a/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx b/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx new file mode 100644 index 0000000000..8145cfb997 --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx @@ -0,0 +1,82 @@ +import React, { forwardRef } from 'react'; +import { useHover, usePress } from '@react-native-aria/interactions'; +import { useFocus, useFocusRing } from '@react-native-aria/focus'; +import { composeEventHandlers } from '@gluestack-ui/utils'; +import { useCalendarContext } from './Context'; + +export const CalendarHeaderPrev = (StyledCalendarHeaderPrev: any) => + forwardRef( + ( + { + isDisabled, + isPressed: isPressedProp, + isHovered: isHoveredProp, + isFocused: isFocusedProp, + isFocusVisible: isFocusVisibleProp, + ...props + }: any, + ref?: any + ) => { + const { isPrevDisabled, prevMonth } = useCalendarContext(); + const handlePress = () => { + if (!isDisabled && !isPrevDisabled) { + prevMonth(); + } + }; + const { isHovered, hoverProps }: any = useHover(); + const { isPressed, pressProps } = usePress({ + onPress: handlePress, + isDisabled: isDisabled || isPrevDisabled, + }); + const { isFocused, focusProps } = useFocus(); + const { isFocusVisible, focusProps: focusRingProps }: any = + useFocusRing(); + return ( + + ); + } + ); diff --git a/packages/unstyled/calendar/src/CalendarHeaderTitle.tsx b/packages/unstyled/calendar/src/CalendarHeaderTitle.tsx new file mode 100644 index 0000000000..b03f28fe30 --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarHeaderTitle.tsx @@ -0,0 +1,11 @@ +import React, { forwardRef } from 'react'; +import { useCalendarContext } from './Context'; +export const CalendarHeaderTitle = (StyledCalendarHeaderTitle: any) => + forwardRef(({ ...props }: any, ref?: any) => { + const { title } = useCalendarContext(); + return ( + + {title} + + ); + }); diff --git a/packages/unstyled/calendar/src/Context.tsx b/packages/unstyled/calendar/src/Context.tsx new file mode 100644 index 0000000000..9125d3dfe8 --- /dev/null +++ b/packages/unstyled/calendar/src/Context.tsx @@ -0,0 +1,18 @@ +import { createContext, useContext } from 'react'; +import type { ICalendarContextValue } from './types'; + +export const CalendarContext = createContext({ + currentMonth: new Date(), + selectedDate: new Date(), + handleDateSelect: () => {}, + prevMonth: () => {}, + nextMonth: () => {}, + getDaysInMonth: () => [], + isToday: () => false, + WEEKDAYS: [], + MONTHS: [], + title: '', + isPrevDisabled: false, + isNextDisabled: false, +}); +export const useCalendarContext = () => useContext(CalendarContext); diff --git a/packages/unstyled/calendar/src/index.tsx b/packages/unstyled/calendar/src/index.tsx new file mode 100644 index 0000000000..cf9e5ac377 --- /dev/null +++ b/packages/unstyled/calendar/src/index.tsx @@ -0,0 +1,68 @@ +import type React from 'react'; +import { CalendarHeaderPrev } from './CalendarHeaderPrev'; +import { CalendarHeaderTitle } from './CalendarHeaderTitle'; +import { CalendarHeaderNext } from './CalendarHeaderNext'; +import { CalendarHeader } from './CalendarHeader'; +import { CalendarGridWeek } from './CalendarGridWeek'; +import { CalendarGridDays } from './CalendarGridDays'; +import { CalendarGrid } from './CalendarGrid'; +import { Calendar as CalendarMain } from './Calendar'; +import type { ICalendarComponentType } from './types'; + +export function createCalendar< + Calendar, + CalendarHeaderPrev, + CalendarHeaderTitle, + CalendarHeaderNext, + CalendarHeader, + CalendarGridWeek, + CalendarGridDays, + CalendarGrid +>({ + Root, + HeaderPrev, + HeaderTitle, + HeaderNext, + Header, + GridWeek, + GridDays, + Grid, +}: { + Root: React.ComponentType; + HeaderPrev: React.ComponentType; + HeaderTitle: React.ComponentType; + HeaderNext: React.ComponentType; + Header: React.ComponentType; + GridWeek: React.ComponentType; + GridDays: React.ComponentType; + Grid: React.ComponentType; +}) { + const Calendar = CalendarMain(Root) as any; + Calendar.HeaderPrev = CalendarHeaderPrev(HeaderPrev); + Calendar.HeaderTitle = CalendarHeaderTitle(HeaderTitle); + Calendar.HeaderNext = CalendarHeaderNext(HeaderNext); + Calendar.Header = CalendarHeader(Header); + Calendar.GridWeek = CalendarGridWeek(GridWeek); + Calendar.GridDays = CalendarGridDays(GridDays); + Calendar.Grid = CalendarGrid(Grid); + + Calendar.displayName = 'Calendar'; + Calendar.HeaderPrev.displayName = 'Calendar.HeaderPrev'; + Calendar.HeaderTitle.displayName = 'Calendar.HeaderTitle'; + Calendar.HeaderNext.displayName = 'Calendar.HeaderNext'; + Calendar.Header.displayName = 'Calendar.Header'; + Calendar.GridWeek.displayName = 'Calendar.GridWeek'; + Calendar.GridDays.displayName = 'Calendar.GridDays'; + Calendar.Grid.displayName = 'Calendar.Grid'; + + return Calendar as ICalendarComponentType< + Calendar, + CalendarHeaderPrev, + CalendarHeaderTitle, + CalendarHeaderNext, + CalendarHeader, + CalendarGridWeek, + CalendarGridDays, + CalendarGrid + >; +} diff --git a/packages/unstyled/calendar/src/types.ts b/packages/unstyled/calendar/src/types.ts new file mode 100644 index 0000000000..fca91112f9 --- /dev/null +++ b/packages/unstyled/calendar/src/types.ts @@ -0,0 +1,184 @@ +import type { PropsWithoutRef, RefAttributes } from 'react'; + +export interface ICalendarProps { + /** + * The value of the date. + */ + value?: Date; + /** + * The default value of the date in uncontrolled mode. + */ + defaultValue?: Date; + /** + * Event handler called when the selection of the date changes. + */ + onChange?: (date: Date) => void; + /** + * The minimum date that can be selected. + */ + minDate?: Date; + /** + * The maximum date that can be selected. + */ + maxDate?: Date; + /** + * Children components + */ + children?: React.ReactNode; +} + +export interface ICalendarHeaderNavProps { + /** + * If true, the button will be in pressed state. + */ + isPressed?: boolean; + /** + * If true, the button will be in hovered state. + */ + isHovered?: boolean; + /** + * If true, the button will be focused. + */ + isFocused?: boolean; + /** + * If true, the button focus ring will be visible. + */ + isFocusVisible?: boolean; + /** + * When true, prevents the user from interacting with the navigation button + */ + isDisabled?: boolean; +} + +export interface ICalendarGridWeekProps { + /** + * Render method for custom day rendering + */ + render?: ( + weekdays: string[], + Component: React.ComponentType + ) => React.ReactNode; +} + +export interface ICalendarDayProps { + /** + * The day number or null for empty cells + */ + day: number | null; + /** + * When true, indicates this day is selected + */ + isSelected?: boolean; + /** + * When true, indicates this is today's date + */ + isToday?: boolean; + /** + * When true, indicates this day cannot be selected + */ + isDisabled?: boolean; + /** + * Handler for when the day is pressed + */ + onPress?: (day: number) => void; +} + +export interface ICalendarGridDaysProps { + /** + * Render method for custom day rendering + */ + render?: ( + days: (number | null)[], + Component: React.ComponentType + ) => React.ReactNode; +} + +export interface ICalendarContextValue { + /** + * Currently selected date + */ + selectedDate: Date | undefined; + /** + * Currently displayed month + */ + currentMonth: Date; + /** + * Handler for date selection + */ + handleDateSelect: (day: number) => void; + /** + * Navigate to previous month + */ + prevMonth: () => void; + /** + * Navigate to next month + */ + nextMonth: () => void; + /** + * Get array of days for current month + */ + getDaysInMonth: () => (number | null)[]; + /** + * Check if a day is today + */ + isToday: (day: number) => boolean; + /** + * Weekdays + */ + weekDays: string[]; + /** + * Months + */ + months: string[]; + /** + * Current month and year + */ + title: string; + /** + * If true, the previous navigation button is disabled + */ + isPrevDisabled: boolean; + /** + * If true, the next navigation button is disabled + */ + isNextDisabled: boolean; +} + +export type ICalendarComponentType< + Root, + Header, + HeaderPrev, + HeaderTitle, + HeaderNext, + GridWeek, + GridDays, + Grid +> = React.ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes & ICalendarProps +> & { + Header: React.ForwardRefExoticComponent< + PropsWithoutRef
& RefAttributes
+ >; + HeaderPrev: React.ForwardRefExoticComponent< + PropsWithoutRef & + RefAttributes & + ICalendarHeaderNavProps + >; + HeaderNext: React.ForwardRefExoticComponent< + PropsWithoutRef & + RefAttributes & + ICalendarHeaderNavProps + >; + HeaderTitle: React.ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes + >; + Grid: React.ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes + >; + GridWeek: React.ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes & ICalendarGridWeekProps + >; + GridDays: React.ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes & ICalendarGridDaysProps + >; +}; diff --git a/packages/unstyled/calendar/tsconfig.json b/packages/unstyled/calendar/tsconfig.json new file mode 100644 index 0000000000..ac8f6075d2 --- /dev/null +++ b/packages/unstyled/calendar/tsconfig.json @@ -0,0 +1,31 @@ +{ + "include": ["./src"], + "exclude": ["node_modules", "example"], + "paths": {}, + "compilerOptions": { + "ignoreDeprecations": "5.0", + "noEmit": false, + "declaration": true, + "allowJs": true, + "allowUnreachableCode": false, + "allowUnusedLabels": true, + "esModuleInterop": true, + "verbatimModuleSyntax": true, + "forceConsistentCasingInFileNames": true, + "jsx": "preserve", + "lib": ["esnext", "dom"], + "module": "esnext", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUnusedLocals": false, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "esnext", + "outDir": "./lib" + } +} From 5c89c6c70a683b0ec295bbfca604aaf72875f876 Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Tue, 24 Dec 2024 17:11:48 +0530 Subject: [PATCH 02/11] feat: added docs --- .../components/Calendar/index.nw.stories.mdx | 376 ++++++++++++++++++ .../src/core-components/nativewind/index.ts | 1 + 2 files changed, 377 insertions(+) create mode 100644 example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx diff --git a/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx new file mode 100644 index 0000000000..07fb38110b --- /dev/null +++ b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx @@ -0,0 +1,376 @@ +--- +title: gluestack-ui Calendar Component | Installation, Usage, and API + +description: A flexible Calendar component for date selection and display in React Native applications. + +pageTitle: Calendar + +pageDescription: A customizable Calendar component that provides date selection, range selection, and event display capabilities. + +showHeader: true + +tag: alpha +--- + +import { Meta } from '@storybook/addon-docs'; + + + +import { Calendar, +CalendarHeader, +CalendarHeaderNext, +CalendarHeaderPrev, +CalendarHeaderTitle, +CalendarGrid, +CalendarGridWeek, +CalendarGridDays } from '../../core-components/nativewind'; +import { + AppProvider, + CodePreview, + Table, + TableContainer, + InlineCode, + Tabs +} from '@gluestack/design-system'; +import { transformedCode } from '../../utils'; +import Wrapper from '../../core-components/nativewind/Wrapper'; +import { CollapsibleCode } from '@gluestack/design-system'; + +# Calendar + +## Installation + + + + + CLI + + + Manual + + + + +<> + +### Run the following command: + ```bash + npx gluestack-ui add calendar + ``` + + + + +<> + + +### Step 1: Install the following dependencies: + +```bash +npm i +``` + +### Step 2: Copy and paste the following code into your project. + + + +```jsx +%%-- File: core-components/nativewind/calendar/index.tsx --%% +``` + + + + +### Step 3: Update the import paths to match your project setup. + + + + + + +## API Reference + +To use this component in your project, include the following import statement in your file. + +```jsx + +import { + Calendar, + CalendarHeader, + CalendarHeaderNext, + CalendarHeaderPrev, + CalendarHeaderTitle, + CalendarGrid, + CalendarGridWeek, + CalendarGridDays, +} from '@/components/ui/calendar'; + +``` +```jsx +export default () => ( + console.log(date)} + > + + + + + + + + + + +); +``` + +### Component Props + +This section provides a comprehensive reference list for the component props, detailing descriptions, properties, types, and default behavior for easy project integration. + +#### Calendar + +It is a context provider for entire calendar api. + +### Props + +<> + + + + + + Prop + + + Type + + + Default + + + Description + + + + + + + + value + + + + Date + + + - + + + Currently selected date + + + + + + defaultValue + + + + Date + + + Current date + + + Initial date for uncontrolled usage + + + + + + onChange + + + + (date: Date) => void + + + - + + + Called when date selection changes + + + + + + minDate + + + + Date + + + - + + + Minimum selectable date + + + + + + maxDate + + + + Date + + + - + + + Maximum selectable date + + + +
+
+ + +### CalendarGridWeek + +Component for rendering calendar week cells. Supports custom rendering through the render prop. + +<> + + + + + + Prop + + + Type + + + Default + + + Description + + + + + + + + render + + + + (props: RenderProps) => React.ReactNode + + + - + + + Custom renderer for date cells. Allows complete customization of how dates are displayed + + + +
+
+ + + +### CalendarGridDays + +Component for rendering calendar day cells. Supports custom rendering through the render prop. + + +<> + + + + + + Prop + + + Type + + + Default + + + Description + + + + + + + + render + + + + (props: RenderProps) => React.ReactNode + + + - + + + Custom renderer for date cells. Allows complete customization of how dates are displayed + + + +
+
+ + +### CalendarHeaderPrev & CalendarHeaderNext + +<> + + + + + + Prop + + + Type + + + Default + + + Description + + + + + + + + isDisabled + + + + boolean + + + false + + + If true, the button will be disabled + + + +
+
+ \ No newline at end of file diff --git a/example/storybook-nativewind/src/core-components/nativewind/index.ts b/example/storybook-nativewind/src/core-components/nativewind/index.ts index 23ee62e6aa..ab84d8afb9 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/index.ts +++ b/example/storybook-nativewind/src/core-components/nativewind/index.ts @@ -51,3 +51,4 @@ export * from './image-background'; export * from './skeleton'; export * from './bottomsheet'; export * from './drawer'; +export * from './calendar'; From 6f2fe9eee97c5a43e656d2ff1d77d38d07d7ce78 Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Fri, 27 Dec 2024 21:52:34 +0530 Subject: [PATCH 03/11] feat: update in Calendar API --- .../src/components/Calendar/Calendar.tsx | 27 +- .../components/Calendar/index.nw.stories.mdx | 21 + .../nativewind/calendar/index.tsx | 93 ++- .../nativewind/calendar/styles.tsx | 25 +- packages/unstyled/calendar/src/Calendar.tsx | 48 +- .../calendar/src/CalendarGridDays.tsx | 76 +- .../calendar/src/CalendarGridWeek.tsx | 11 +- packages/unstyled/calendar/src/Context.tsx | 5 +- packages/unstyled/calendar/src/types.ts | 22 +- yarn.lock | 717 +++++++++++++++++- 10 files changed, 901 insertions(+), 144 deletions(-) diff --git a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx index 7aaab0fcbb..2d9889d5e7 100644 --- a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx +++ b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx @@ -10,20 +10,8 @@ import { CalendarGridDays, } from '@/components/ui/calendar'; -const CalendarBasic = () => { - return ( - - - - - - - - - - - - ); +const CalendarBasic = ({ ...props }: any) => { + return ; }; CalendarBasic.description = @@ -31,4 +19,13 @@ CalendarBasic.description = export default CalendarBasic; -export { Calendar }; +export { + Calendar, + CalendarHeader, + CalendarHeaderNext, + CalendarHeaderPrev, + CalendarHeaderTitle, + CalendarGrid, + CalendarGridWeek, + CalendarGridDays, +}; diff --git a/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx index 07fb38110b..b7d9bd6533 100644 --- a/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx +++ b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx @@ -38,6 +38,27 @@ import { CollapsibleCode } from '@gluestack/design-system'; # Calendar + + + `, + transformCode: (code) => { + return transformedCode(code); + }, + scope: { + Calendar, + Wrapper, + }, + }} + /> + + +
+ ## Installation diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx index c2444ecffd..f2c2e7dcb3 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx @@ -4,8 +4,6 @@ import { View as RNView, Pressable as RNPressable, Text as RNText, - TextProps as RNTextProps, - Platform, } from 'react-native'; import { createCalendar } from '@gluestack-ui/calendar'; import { withStyleContext } from '@gluestack-ui/nativewind-utils/withStyleContext'; @@ -29,9 +27,11 @@ const SCOPE = 'CALENDAR'; const Root = withStyleContext(RNView, SCOPE); -const Header = ( - Platform.OS === 'web' ? RNText : RNView -) as React.ComponentType; +cssInterop(Root, { + className: { + target: 'style', + }, +}); /** Creator */ @@ -40,7 +40,7 @@ const UICalendar = createCalendar({ HeaderPrev: RNPressable, HeaderTitle: RNText, HeaderNext: RNPressable, - Header: Header, + Header: RNText, GridWeek: RNView, GridDays: RNView, Grid: RNView, @@ -99,19 +99,6 @@ type ICalendarHeaderTitleProps = React.ComponentPropsWithoutRef< /** Components */ -const Calendar = React.forwardRef< - React.ElementRef, - ICalendarProps ->(({ className, ...props }, ref) => { - return ( - - ); -}); - const CalendarHeaderPrev = React.forwardRef< React.ElementRef, ICalendarHeaderPrevProps @@ -190,17 +177,12 @@ const CalendarGridWeek = React.forwardRef< ref={ref} {...props} className={calendarGridWeekStyle({ class: className })} - render={(weekdays) => { - return weekdays.map((day) => { - return ( - - {day} - - ); - }); + render={(day) => { + return ( + + {day} + + ); }} /> ); @@ -215,22 +197,49 @@ const CalendarGridDays = React.forwardRef< ref={ref} {...props} className={calendarGridDaysStyle({ class: className })} - render={(days) => { - return days.map((day) => { - return ( - - {day} - - ); - }); - }} + render={(day, states) => ( + + {day?.getDate()} + + )} /> ); }); +const Calendar = React.forwardRef< + React.ElementRef, + ICalendarProps +>(({ children, className, ...props }, ref) => { + return children ? ( + + {children} + + ) : ( + + + + + + + + + + + + ); +}); + Calendar.displayName = 'Calendar'; CalendarHeaderPrev.displayName = 'CalendarHeaderPrev'; CalendarHeaderNext.displayName = 'CalendarHeaderNext'; diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx index c76567e527..0f404c2d8b 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx @@ -1,19 +1,19 @@ import { tva } from '@gluestack-ui/nativewind-utils/tva'; export const calendarStyle = tva({ - base: 'flex flex-col bg-white rounded-lg shadow-lg max-w-sm', + base: 'flex flex-col border border-outline-200 rounded-lg', }); export const calendarNavStyle = tva({ - base: 'w-8 h-8 flex items-center justify-center rounded-full hover:bg-typography-100 active:bg-typography-200', + base: 'w-6 h-6 flex items-center justify-center rounded-full hover:bg-typography-100 active:bg-typography-200', }); export const calendarTitleStyle = tva({ - base: 'text-lg font-semibold text-typography-800', + base: 'font-semibold text-typography-800 uppercase', }); export const calendarHeaderStyle = tva({ - base: 'flex flex-row w-full justify-between items-center p-4 border-b border-typography-200', + base: 'flex flex-row w-full justify-between items-center px-4 py-2 border-b border-typography-200', }); export const calendarGridWeekStyle = tva({ @@ -25,24 +25,13 @@ export const calendarGridDaysStyle = tva({ }); export const calendarDaysCellStyle = tva({ - base: 'w-[14.28%] p-2 aspect-square items-center justify-center hover:bg-typography-50 active:bg-typography-100', - variants: { - isToday: { - true: 'bg-blue-50 font-bold text-blue-600', - }, - isSelected: { - true: 'bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800', - }, - isDisabled: { - true: 'text-typography-300 hover:bg-transparent cursor-not-allowed', - }, - }, + base: 'w-[14.28%] p-2 aspect-square cursor-pointer flex items-center justify-center', }); export const calendarWeekCellStyle = tva({ - base: 'w-[14.28%] p-2 aspect-square text-center text-typography-500 font-medium', + base: 'w-[14.28%] p-2 aspect-square flex items-center justify-center text-typography-500 font-medium', }); export const calendarGridStyle = tva({ - base: 'flex-col p-4', + base: 'flex-col p-2', }); diff --git a/packages/unstyled/calendar/src/Calendar.tsx b/packages/unstyled/calendar/src/Calendar.tsx index a5db4abd1d..5aba24d401 100644 --- a/packages/unstyled/calendar/src/Calendar.tsx +++ b/packages/unstyled/calendar/src/Calendar.tsx @@ -42,6 +42,16 @@ export function Calendar(StyledCalendar: any) { const isPrevDisabled = minDate ? currentMonth < minDate : false; const isNextDisabled = maxDate ? currentMonth > maxDate : false; + const isDisabled = useCallback( + (day: Date | null) => { + if (!day) return false; + if (minDate && day < minDate) return true; + if (maxDate && day > maxDate) return true; + return false; + }, + [minDate, maxDate] + ); + const title = useMemo(() => { return `${ MONTHS[currentMonth.getMonth()] @@ -79,36 +89,30 @@ export function Calendar(StyledCalendar: any) { } for (let i = 1; i <= daysInMonth; i++) { - days.push(i); + days.push(new Date(year, month, i)); } return days; }, [currentMonth]); const handleDateSelect = useCallback( - (day: number) => { - const newDate = new Date(currentMonth); - newDate.setDate(day); - if (minDate && newDate < minDate) return; - if (maxDate && newDate > maxDate) return; - - setSelectedDate(newDate); - onChange?.(newDate); + (day: Date | null) => { + if (!day) return; + onChange?.(day); + setSelectedDate(day); }, - [currentMonth, minDate, maxDate, onChange] + [onChange] ); - const isToday = useCallback( - (day: number) => { - const today = new Date(); - return ( - today.getDate() === day && - today.getMonth() === currentMonth.getMonth() && - today.getFullYear() === currentMonth.getFullYear() - ); - }, - [currentMonth] - ); + const isToday = useCallback((day: Date | null) => { + if (!day) return false; + const today = new Date(); + return ( + today.getDate() === day.getDate() && + today.getMonth() === day.getMonth() && + today.getFullYear() === day.getFullYear() + ); + }, []); const contextValue = useMemo( () => ({ @@ -124,6 +128,7 @@ export function Calendar(StyledCalendar: any) { months: MONTHS, isPrevDisabled, isNextDisabled, + isDisabled, }), [ selectedDate, @@ -136,6 +141,7 @@ export function Calendar(StyledCalendar: any) { isToday, isPrevDisabled, isNextDisabled, + isDisabled, ] ); return ( diff --git a/packages/unstyled/calendar/src/CalendarGridDays.tsx b/packages/unstyled/calendar/src/CalendarGridDays.tsx index d64127e803..ff2bd9e805 100644 --- a/packages/unstyled/calendar/src/CalendarGridDays.tsx +++ b/packages/unstyled/calendar/src/CalendarGridDays.tsx @@ -1,29 +1,73 @@ import React, { forwardRef } from 'react'; -import type { ICalendarDayProps } from './types'; +import { useHover, usePress } from '@react-native-aria/interactions'; +import { useFocus, useFocusRing } from '@react-native-aria/focus'; +import { composeEventHandlers } from '@gluestack-ui/utils'; import { useCalendarContext } from './Context'; export const CalendarGridDays = (StyledCalendarGridDays: any) => forwardRef(({ render, ...props }: any, ref?: any) => { - const { getDaysInMonth, handleDateSelect, isToday } = useCalendarContext(); + const { + getDaysInMonth, + handleDateSelect, + isToday, + selectedDate, + isDisabled, + } = useCalendarContext(); const days = getDaysInMonth(); + const { isHovered, hoverProps }: any = useHover(); + const { isFocused, focusProps } = useFocus(); + const { isFocusVisible, focusProps: focusRingProps }: any = useFocusRing(); + const { isPressed, pressProps } = usePress({ + onPress: (day: Date) => handleDateSelect(day), + }); - const DayComponent = ({ day, ...dayProps }: ICalendarDayProps) => ( - day !== null && handleDateSelect(day)} - {...dayProps} - /> - ); + // can move to context + const isSameDate = (date1: Date, date2: Date): boolean => { + if (!date1 || !date2) return false; + return date1.getTime() === date2.getTime(); + }; return ( - {render - ? render(days, DayComponent) - : // Default rendering - days.map((day, index) => ( - - ))} + {days.map((day) => { + const DayProps = { + key: day?.getDate(), + states: { + disabled: isDisabled(day), + hover: isHovered, + focus: isFocused, + focusVisible: isFocusVisible, + active: isPressed, + today: isToday(day), + selected: day && selectedDate && isSameDate(day, selectedDate), + }, + dataSet: { + disabled: isDisabled(day) ? 'true' : 'false', + hover: isHovered ? 'true' : 'false', + focus: isFocused ? 'true' : 'false', + focusVisible: isFocusVisible ? 'true' : 'false', + active: isPressed ? 'true' : 'false', + today: isToday(day) ? 'true' : 'false', + selected: day && selectedDate && isSameDate(day, selectedDate), + }, + disabled: isDisabled(day), + onPressIn: composeEventHandlers(pressProps.onPressIn), + onPressOut: composeEventHandlers(pressProps.onPressOut), + onPress: composeEventHandlers(() => handleDateSelect(day)), + onHoverIn: composeEventHandlers(hoverProps.onHoverIn), + onHoverOut: composeEventHandlers(hoverProps.onHoverOut), + onFocus: composeEventHandlers( + focusProps.onFocus, + focusRingProps.onFocus + ), + onBlur: composeEventHandlers( + focusProps.onBlur, + focusRingProps.onBlur + ), + }; + const Day = render?.(day, DayProps); + return Day; + })} ); }); diff --git a/packages/unstyled/calendar/src/CalendarGridWeek.tsx b/packages/unstyled/calendar/src/CalendarGridWeek.tsx index 061f0de8c2..66ebadabaf 100644 --- a/packages/unstyled/calendar/src/CalendarGridWeek.tsx +++ b/packages/unstyled/calendar/src/CalendarGridWeek.tsx @@ -1,18 +1,11 @@ import React, { forwardRef } from 'react'; import { useCalendarContext } from './Context'; export const CalendarGridWeek = (StyledCalendarGridWeek: any) => - forwardRef(({ children, render, ...props }: any, ref?: any) => { + forwardRef(({ render, ...props }: any, ref?: any) => { const { weekDays } = useCalendarContext(); - - const Component = ({ weekday, ...props }: any) => ( - - ); - - const content = render ? render(weekDays, Component) : children; - return ( - {content} + {weekDays.map((weekday) => render?.(weekday))} ); }); diff --git a/packages/unstyled/calendar/src/Context.tsx b/packages/unstyled/calendar/src/Context.tsx index 9125d3dfe8..9b4d9f152b 100644 --- a/packages/unstyled/calendar/src/Context.tsx +++ b/packages/unstyled/calendar/src/Context.tsx @@ -9,10 +9,11 @@ export const CalendarContext = createContext({ nextMonth: () => {}, getDaysInMonth: () => [], isToday: () => false, - WEEKDAYS: [], - MONTHS: [], + weekDays: [], + months: [], title: '', isPrevDisabled: false, isNextDisabled: false, + isDisabled: () => false, }); export const useCalendarContext = () => useContext(CalendarContext); diff --git a/packages/unstyled/calendar/src/types.ts b/packages/unstyled/calendar/src/types.ts index fca91112f9..f6bedda7e8 100644 --- a/packages/unstyled/calendar/src/types.ts +++ b/packages/unstyled/calendar/src/types.ts @@ -55,7 +55,7 @@ export interface ICalendarGridWeekProps { * Render method for custom day rendering */ render?: ( - weekdays: string[], + weekdays: string, Component: React.ComponentType ) => React.ReactNode; } @@ -64,7 +64,7 @@ export interface ICalendarDayProps { /** * The day number or null for empty cells */ - day: number | null; + day: Date | null; /** * When true, indicates this day is selected */ @@ -80,17 +80,14 @@ export interface ICalendarDayProps { /** * Handler for when the day is pressed */ - onPress?: (day: number) => void; + onPress?: (date: Date) => void; } export interface ICalendarGridDaysProps { /** * Render method for custom day rendering */ - render?: ( - days: (number | null)[], - Component: React.ComponentType - ) => React.ReactNode; + render?: (days: Date | null, props: ICalendarDayProps) => React.ReactNode; } export interface ICalendarContextValue { @@ -105,7 +102,7 @@ export interface ICalendarContextValue { /** * Handler for date selection */ - handleDateSelect: (day: number) => void; + handleDateSelect: (day: Date | null) => void; /** * Navigate to previous month */ @@ -117,11 +114,11 @@ export interface ICalendarContextValue { /** * Get array of days for current month */ - getDaysInMonth: () => (number | null)[]; + getDaysInMonth: () => (Date | null)[]; /** * Check if a day is today */ - isToday: (day: number) => boolean; + isToday: (day: Date | null) => boolean; /** * Weekdays */ @@ -142,6 +139,11 @@ export interface ICalendarContextValue { * If true, the next navigation button is disabled */ isNextDisabled: boolean; + + /** + * If true, the day is disabled + */ + isDisabled: (day: Date | null) => boolean; } export type ICalendarComponentType< diff --git a/yarn.lock b/yarn.lock index dc70944f27..68b04d678a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2542,6 +2542,13 @@ react-is "^17.0.2" styled-components "5.2.1" +"@gluestack-style/animation-plugin@^0.1.12": + version "0.1.12" + resolved "https://registry.yarnpkg.com/@gluestack-style/animation-plugin/-/animation-plugin-0.1.12.tgz#887b57097397817c31fef25c8c53af381c11633e" + integrity sha512-lkj8iY5JBnhroUkP5gWE1zEpocb5GAK/G9SxL8DdWYQrsWOFpXr/mF/K67Dbxiv/n4B9BVff7sNTAddju+4UAw== + dependencies: + "@legendapp/motion" "^2.2.0" + "@gluestack-ui/button@^0.1.15": version "0.1.34" resolved "https://registry.yarnpkg.com/@gluestack-ui/button/-/button-0.1.34.tgz#f635aba6a9023d153f5dd82cd96a3785b6244951" @@ -2588,6 +2595,63 @@ dependencies: "@react-native-aria/focus" "^0.2.9" +"@gluestack/design-system@0.5.36": + version "0.5.36" + resolved "https://registry.yarnpkg.com/@gluestack/design-system/-/design-system-0.5.36.tgz#ee9c6a1dc3d0806eda5bd5781b58c3e8b3621dcf" + integrity sha512-d+Rp4nlK7f2Ban4j+B478ppVNvJmclH1YHXZZDSsV7yg1Fwpb1eNZlXr0E/9k+9bWiXzrqd91/1u8LjfWGAO/g== + dependencies: + "@docsearch/css" "3" + "@docsearch/react" "3" + "@expo/html-elements" "0.3.0" + "@gluestack-style/animation-resolver" "^1.0.1" + "@gluestack-style/legend-motion-animation-driver" "^1.0.1" + "@gluestack-style/react" "^1.0.45" + "@gluestack-ui/actionsheet" "^0.2.36" + "@gluestack-ui/alert" "^0.1.4" + "@gluestack-ui/alert-dialog" "^0.1.8" + "@gluestack-ui/avatar" "^0.1.6" + "@gluestack-ui/button" "^0.1.15" + "@gluestack-ui/checkbox" "^0.1.22" + "@gluestack-ui/config" "^1.0.13" + "@gluestack-ui/config-v2" "^1.0.1" + "@gluestack-ui/divider" "^0.1.3" + "@gluestack-ui/fab" "^0.1.6" + "@gluestack-ui/form-control" "^0.1.6" + "@gluestack-ui/hooks" "^0.1.0" + "@gluestack-ui/hstack" "^0.1.9" + "@gluestack-ui/icon" "^0.1.3" + "@gluestack-ui/input" "^0.1.5" + "@gluestack-ui/link" "^0.1.6" + "@gluestack-ui/menu" "^0.2.7" + "@gluestack-ui/modal" "^0.1.12" + "@gluestack-ui/overlay" "^0.1.3" + "@gluestack-ui/popover" "^0.1.28" + "@gluestack-ui/pressable" "^0.1.4" + "@gluestack-ui/progress" "^0.1.3" + "@gluestack-ui/provider" "^0.1.3" + "@gluestack-ui/radio" "^0.1.11" + "@gluestack-ui/react-native-aria" "^0.1.2" + "@gluestack-ui/select" "^0.1.20" + "@gluestack-ui/slider" "^0.1.18" + "@gluestack-ui/spinner" "^0.1.5" + "@gluestack-ui/switch" "^0.1.8" + "@gluestack-ui/tabs" "0.1.14" + "@gluestack-ui/textarea" "^0.1.7" + "@gluestack-ui/toast" "^0.1.7" + "@gluestack-ui/tooltip" "^0.1.6" + "@gluestack-ui/transitions" "^0.1.6" + "@gluestack-ui/utils" "^0.1.3" + "@gluestack-ui/vstack" "^0.1.10" + "@legendapp/motion" "^2.2.0" + "@react-native-aria/checkbox" "0.2.8" + axios "^1.4.0" + prettier "2.8.3" + prism-react-renderer "^1.3.5" + react-live "^3.1.1" + react-native "^0.72.5" + react-native-svg "13.4.0" + react-native-web "^0.19.9" + "@gluestack/design-system@^0.5.36": version "0.5.61" resolved "https://registry.yarnpkg.com/@gluestack/design-system/-/design-system-0.5.61.tgz#7977402176aa65e078bf540cd8d631104080477f" @@ -3433,7 +3497,19 @@ "@pnpm/network.ca-file" "^1.0.1" config-chain "^1.1.11" -"@react-aria/button@^3.7.0": +"@react-aria/breadcrumbs@^3.5.19": + version "3.5.19" + resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.19.tgz#e0a67e0e7017089fa0ee5eadd51a6da505b94cd4" + integrity sha512-mVngOPFYVVhec89rf/CiYQGTfaLRfHFtX+JQwY7sNYNqSA+gO8p4lNARe3Be6bJPgH+LUQuruIY9/ZDL6LT3HA== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/link" "^3.7.7" + "@react-aria/utils" "^3.26.0" + "@react-types/breadcrumbs" "^3.7.9" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/button@^3.11.0", "@react-aria/button@^3.7.0": version "3.11.0" resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.11.0.tgz#cb7790db23949ec9c1e698fa531ee5471cf2b515" integrity sha512-b37eIV6IW11KmNIAm65F3SEl2/mgj5BrHIysW6smZX3KoKWTGYsYfcQkmtNgY0GOSFfDxMCoolsZ6mxC00nSDA== @@ -3447,6 +3523,22 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" +"@react-aria/calendar@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.6.0.tgz#d5e7cf4beb8724648a7042dbc5bb519de4351906" + integrity sha512-tZ3nd5DP8uxckbj83Pt+4RqgcTWDlGi7njzc7QqFOG2ApfnYDUXbIpb/Q4KY6JNlJskG8q33wo0XfOwNy8J+eg== + dependencies: + "@internationalized/date" "^3.6.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/utils" "^3.26.0" + "@react-stately/calendar" "^3.6.0" + "@react-types/button" "^3.10.1" + "@react-types/calendar" "^3.5.0" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + "@react-aria/checkbox@3.2.1": version "3.2.1" resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.2.1.tgz#493d9d584b4db474645a4565c4f899ee3a579f07" @@ -3460,7 +3552,43 @@ "@react-stately/toggle" "^3.2.1" "@react-types/checkbox" "^3.2.1" -"@react-aria/combobox@^3.0.0-alpha.1": +"@react-aria/checkbox@^3.15.0": + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.15.0.tgz#4d224b71c65d6a079ff935ab22c806323f84b746" + integrity sha512-z/8xd4em7o0MroBXwkkwv7QRwiJaA1FwqMhRUb7iqtBGP2oSytBEDf0N7L09oci32a1P4ZPz2rMK5GlLh/PD6g== + dependencies: + "@react-aria/form" "^3.0.11" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/toggle" "^3.10.10" + "@react-aria/utils" "^3.26.0" + "@react-stately/checkbox" "^3.6.10" + "@react-stately/form" "^3.1.0" + "@react-stately/toggle" "^3.8.0" + "@react-types/checkbox" "^3.9.0" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/color@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@react-aria/color/-/color-3.0.2.tgz#3abeb7e9fa9756e1823e513921e04dcaa47b25cc" + integrity sha512-dSM5qQRcR1gRGYCBw0IGRmc29gjfoht3cQleKb8MMNcgHYa2oi5VdCs2yKXmYFwwVC6uPtnlNy9S6e0spqdr+w== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/numberfield" "^3.11.9" + "@react-aria/slider" "^3.7.14" + "@react-aria/spinbutton" "^3.6.10" + "@react-aria/textfield" "^3.15.0" + "@react-aria/utils" "^3.26.0" + "@react-aria/visually-hidden" "^3.8.18" + "@react-stately/color" "^3.8.1" + "@react-stately/form" "^3.1.0" + "@react-types/color" "^3.0.1" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/combobox@^3.0.0-alpha.1", "@react-aria/combobox@^3.11.0": version "3.11.0" resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.11.0.tgz#9489aaad342d092bf1fe1c4c382f6714316ac1c4" integrity sha512-s88YMmPkMO1WSoiH1KIyZDLJqUwvM2wHXXakj3cYw1tBHGo4rOUFq+JWQIbM5EDO4HOR4AUUqzIUd0NO7t3zyg== @@ -3481,7 +3609,31 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/dialog@*": +"@react-aria/datepicker@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.12.0.tgz#a82ff3ebd3ead20a00096d082c1e6be47bbd5886" + integrity sha512-VYNXioLfddIHpwQx211+rTYuunDmI7VHWBRetCpH3loIsVFuhFSRchTQpclAzxolO3g0vO7pMVj9VYt7Swp6kg== + dependencies: + "@internationalized/date" "^3.6.0" + "@internationalized/number" "^3.6.0" + "@internationalized/string" "^3.2.5" + "@react-aria/focus" "^3.19.0" + "@react-aria/form" "^3.0.11" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/spinbutton" "^3.6.10" + "@react-aria/utils" "^3.26.0" + "@react-stately/datepicker" "^3.11.0" + "@react-stately/form" "^3.1.0" + "@react-types/button" "^3.10.1" + "@react-types/calendar" "^3.5.0" + "@react-types/datepicker" "^3.9.0" + "@react-types/dialog" "^3.5.14" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/dialog@*", "@react-aria/dialog@^3.5.20": version "3.5.20" resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.20.tgz#6404d2c1bab1ea9ecce3ebc7adce64733ecea985" integrity sha512-l0GZVLgeOd3kL3Yj8xQW7wN3gn9WW3RLd/SGI9t7ciTq+I/FhftjXCWzXLlOCCTLMf+gv7eazecECtmoWUaZWQ== @@ -3493,6 +3645,33 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" +"@react-aria/disclosure@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@react-aria/disclosure/-/disclosure-3.0.0.tgz#36342210740fd659ad97678fe5a57896a7fcbd10" + integrity sha512-xO9QTQSvymujTjCs1iCQ4+dKZvtF/rVVaFZBKlUtqIqwTHMdqeZu4fh5miLEnTyVLNHMGzLrFggsd8Q+niC9Og== + dependencies: + "@react-aria/ssr" "^3.9.7" + "@react-aria/utils" "^3.26.0" + "@react-stately/disclosure" "^3.0.0" + "@react-types/button" "^3.10.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/dnd@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.8.0.tgz#7e3bfa3f509efeb9a872686e65641a719684e95a" + integrity sha512-JiqHY3E9fDU5Kb4gN22cuK6QNlpMCGe6ngR/BV+Q8mLEsdoWcoUAYOtYXVNNTRvCdVbEWI87FUU+ThyPpoDhNQ== + dependencies: + "@internationalized/string" "^3.2.5" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/overlays" "^3.24.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/dnd" "^3.5.0" + "@react-types/button" "^3.10.1" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + "@react-aria/focus@^3.11.0", "@react-aria/focus@^3.19.0", "@react-aria/focus@^3.2.3": version "3.19.0" resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.19.0.tgz#82b9a5b83f023b943a7970df3d059f49d61df05d" @@ -3515,6 +3694,42 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" +"@react-aria/grid@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.11.0.tgz#5ad6596745482e109b3b47f1fec7ce372f632707" + integrity sha512-lN5FpQgu2Rq0CzTPWmzRpq6QHcMmzsXYeClsgO3108uVp1/genBNAObYVTxGOKe/jb9q99trz8EtIn05O6KN1g== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/grid" "^3.10.0" + "@react-stately/selection" "^3.18.0" + "@react-types/checkbox" "^3.9.0" + "@react-types/grid" "^3.2.10" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/gridlist@^3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.10.0.tgz#adc2f9896a2759bb29cec428378c8ac85235a110" + integrity sha512-UcblfSZ7kJBrjg9mQ5VbnRevN81UiYB4NuL5PwIpBpridO7tnl4ew6+96PYU7Wj1chHhPS3x0b0zmuSVN7A0LA== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/grid" "^3.11.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/collections" "^3.12.0" + "@react-stately/list" "^3.11.1" + "@react-stately/tree" "^3.8.6" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + "@react-aria/i18n@^3.12.4", "@react-aria/i18n@^3.2.0": version "3.12.4" resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.4.tgz#4520ce48a1b6ebe4aa470d72eba300e65de01814" @@ -3548,6 +3763,18 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" +"@react-aria/link@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.7.7.tgz#5879c75068b63d55353b3e96b4fda0fa8753d1ad" + integrity sha512-eVBRcHKhNSsATYWv5wRnZXRqPVcKAWWakyvfrYePIKpC3s4BaHZyTGYdefk8ZwZdEOuQZBqLMnjW80q1uhtkuA== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-types/link" "^3.5.9" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + "@react-aria/listbox@^3.13.6", "@react-aria/listbox@^3.2.4": version "3.13.6" resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.13.6.tgz#43ff24f4a6540a9952729833201460fa6ab081f7" @@ -3590,6 +3817,33 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" +"@react-aria/meter@^3.4.18": + version "3.4.18" + resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.18.tgz#ff3f85f32ea30285e7e73386a641efdcedd88205" + integrity sha512-tTX3LLlmDIHqrC42dkdf+upb1c4UbhlpZ52gqB64lZD4OD4HE+vMTwNSe+7MRKMLvcdKPWCRC35PnxIHZ15kfQ== + dependencies: + "@react-aria/progress" "^3.4.18" + "@react-types/meter" "^3.4.5" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/numberfield@^3.11.9": + version "3.11.9" + resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.11.9.tgz#175f801b18740534dca023cfd9ce0349eff940b0" + integrity sha512-3tiGPx2y4zyOV7PmdBASes99ZZsFTZAJTnU45Z+p1CW4131lw7y2ZhbojBl7U6DaXAJvi1z6zY6cq2UE9w5a0Q== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/spinbutton" "^3.6.10" + "@react-aria/textfield" "^3.15.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/form" "^3.1.0" + "@react-stately/numberfield" "^3.9.8" + "@react-types/button" "^3.10.1" + "@react-types/numberfield" "^3.8.7" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + "@react-aria/overlays@^3.13.0", "@react-aria/overlays@^3.19.0", "@react-aria/overlays@^3.24.0", "@react-aria/overlays@^3.6.0", "@react-aria/overlays@^3.7.0": version "3.24.0" resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.24.0.tgz#7f97cd12506961abfab3ae653822cea05d1cacd3" @@ -3607,7 +3861,19 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/radio@^3.1.2": +"@react-aria/progress@^3.4.18": + version "3.4.18" + resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.18.tgz#948859ce1b0e13d935da7d4cbe6812d451472fe4" + integrity sha512-FOLgJ9t9i1u3oAAimybJG6r7/soNPBnJfWo4Yr6MmaUv90qVGa1h6kiuM5m9H/bm5JobAebhdfHit9lFlgsCmg== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/label" "^3.7.13" + "@react-aria/utils" "^3.26.0" + "@react-types/progress" "^3.5.8" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/radio@^3.1.2", "@react-aria/radio@^3.10.10": version "3.10.10" resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.10.10.tgz#18e2811fb3e72298414c880bd9405ea3f1d83f1f" integrity sha512-NVdeOVrsrHgSfwL2jWCCXFsWZb+RMRZErj5vthHQW4nkHECGOzeX56VaLWTSvdoCPqi9wdIX8A6K9peeAIgxzA== @@ -3623,6 +3889,40 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" +"@react-aria/searchfield@^3.7.11": + version "3.7.11" + resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.7.11.tgz#2be234280cc4fb58a316db6ba1f95ea34754c043" + integrity sha512-wFf6QxtBFfoxy0ANxI0+ftFEBGynVCY0+ce4H4Y9LpUTQsIKMp3sdc7LoUFORWw5Yee6Eid5cFPQX0Ymnk+ZJg== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/textfield" "^3.15.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/searchfield" "^3.5.8" + "@react-types/button" "^3.10.1" + "@react-types/searchfield" "^3.5.10" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/select@^3.15.0": + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.15.0.tgz#e0b955ed908039f734805e852b58dec4b159adc9" + integrity sha512-zgBOUNy81aJplfc3NKDJMv8HkXjBGzaFF3XDzNfW8vJ7nD9rcTRUN5SQ1XCEnKMv12B/Euk9zt6kd+tX0wk1vQ== + dependencies: + "@react-aria/form" "^3.0.11" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/listbox" "^3.13.6" + "@react-aria/menu" "^3.16.0" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-aria/visually-hidden" "^3.8.18" + "@react-stately/select" "^3.6.9" + "@react-types/button" "^3.10.1" + "@react-types/select" "^3.9.8" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + "@react-aria/selection@^3.21.0", "@react-aria/selection@^3.3.1", "@react-aria/selection@^3.3.2": version "3.21.0" resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.21.0.tgz#c5660e73a38db5e3e1cdc722e408b4489f5f589a" @@ -3636,7 +3936,7 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/separator@^3.3.0": +"@react-aria/separator@^3.3.0", "@react-aria/separator@^3.4.4": version "3.4.4" resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.4.4.tgz#7975177d256d8e864625d9823bf7a6de5a6b6460" integrity sha512-dH+qt0Mdh0nhKXCHW6AR4DF8DKLUBP26QYWaoThPdBwIpypH/JVKowpPtWms1P4b36U6XzHXHnTTEn/ZVoCqNA== @@ -3645,7 +3945,7 @@ "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/slider@^3.0.1": +"@react-aria/slider@^3.0.1", "@react-aria/slider@^3.7.14": version "3.7.14" resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.7.14.tgz#25a362725d6cd71e9b86477362a36c847c73384e" integrity sha512-7rOiKjLkEZ0j7mPMlwrqivc+K4OSfL14slaQp06GHRiJkhiWXh2/drPe15hgNq55HmBQBpA0umKMkJcqVgmXPA== @@ -3660,6 +3960,18 @@ "@react-types/slider" "^3.7.7" "@swc/helpers" "^0.5.0" +"@react-aria/spinbutton@^3.6.10": + version "3.6.10" + resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.10.tgz#72154873de807638e17570bd57e8491912b613b7" + integrity sha512-nhYEYk7xUNOZDaqiQ5w/nHH9ouqjJbabTWXH+KK7UR1oVGfo4z1wG94l8KWF3Z6SGGnBxzLJyTBguZ4g9aYTSg== + dependencies: + "@react-aria/i18n" "^3.12.4" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/utils" "^3.26.0" + "@react-types/button" "^3.10.1" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + "@react-aria/ssr@^3.0.1", "@react-aria/ssr@^3.9.7": version "3.9.7" resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.7.tgz#d89d129f7bbc5148657e6c952ac31c9353183770" @@ -3667,7 +3979,7 @@ dependencies: "@swc/helpers" "^0.5.0" -"@react-aria/switch@^3.1.1": +"@react-aria/switch@^3.1.1", "@react-aria/switch@^3.6.10": version "3.6.10" resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.6.10.tgz#8fa5729bc4e76ac3df51389a8996873142daedb8" integrity sha512-FtaI9WaEP1tAmra1sYlAkYXg9x75P5UtgY8pSbe9+1WRyWbuE1QZT+RNCTi3IU4fZ7iJQmXH6+VaMyzPlSUagw== @@ -3678,6 +3990,27 @@ "@react-types/switch" "^3.5.7" "@swc/helpers" "^0.5.0" +"@react-aria/table@^3.16.0": + version "3.16.0" + resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.16.0.tgz#f0ffb51f52494e68f2c3b81fba44278fbdc48c28" + integrity sha512-9xF9S3CJ7XRiiK92hsIKxPedD0kgcQWwqTMtj3IBynpQ4vsnRiW3YNIzrn9C3apjknRZDTSta8O2QPYCUMmw2A== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/grid" "^3.11.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/live-announcer" "^3.4.1" + "@react-aria/utils" "^3.26.0" + "@react-aria/visually-hidden" "^3.8.18" + "@react-stately/collections" "^3.12.0" + "@react-stately/flags" "^3.0.5" + "@react-stately/table" "^3.13.0" + "@react-types/checkbox" "^3.9.0" + "@react-types/grid" "^3.2.10" + "@react-types/shared" "^3.26.0" + "@react-types/table" "^3.10.3" + "@swc/helpers" "^0.5.0" + "@react-aria/tabs@3.0.0-alpha.2": version "3.0.0-alpha.2" resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.0.0-alpha.2.tgz#3b931d9c752c2dca4c2a1b975248b0ee751077a2" @@ -3693,6 +4026,36 @@ "@react-types/shared" "^3.2.1" "@react-types/tabs" "3.0.0-alpha.2" +"@react-aria/tabs@^3.9.8": + version "3.9.8" + resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.9.8.tgz#a0a647a4e2d1783125779473536419fd8caa9cfa" + integrity sha512-Nur/qRFBe+Zrt4xcCJV/ULXCS3Mlae+B89bp1Gl20vSDqk6uaPtGk+cS5k03eugOvas7AQapqNJsJgKd66TChw== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/tabs" "^3.7.0" + "@react-types/shared" "^3.26.0" + "@react-types/tabs" "^3.3.11" + "@swc/helpers" "^0.5.0" + +"@react-aria/tag@^3.4.8": + version "3.4.8" + resolved "https://registry.yarnpkg.com/@react-aria/tag/-/tag-3.4.8.tgz#856899a53c2be2b8aea3d5aca020edf8608246b2" + integrity sha512-exWl52bsFtJuzaqMYvSnLteUoPqb3Wf+uICru/yRtREJsWVqjJF38NCVlU73Yqd9qMPTctDrboSZFAWAWKDxoA== + dependencies: + "@react-aria/gridlist" "^3.10.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/selection" "^3.21.0" + "@react-aria/utils" "^3.26.0" + "@react-stately/list" "^3.11.1" + "@react-types/button" "^3.10.1" + "@react-types/shared" "^3.26.0" + "@swc/helpers" "^0.5.0" + "@react-aria/textfield@^3.15.0": version "3.15.0" resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.15.0.tgz#17ebac0b73f084622aaf9697576b82155bed67cb" @@ -3746,6 +4109,19 @@ "@react-types/shared" "^3.3.0" "@react-types/tooltip" "^3.1.0" +"@react-aria/tooltip@^3.7.10": + version "3.7.10" + resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.7.10.tgz#d710532e80337e50be818dfbf2cc54d0a9b8c592" + integrity sha512-Udi3XOnrF/SYIz72jw9bgB74MG/yCOzF5pozHj2FH2HiJlchYv/b6rHByV/77IZemdlkmL/uugrv/7raPLSlnw== + dependencies: + "@react-aria/focus" "^3.19.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-stately/tooltip" "^3.5.0" + "@react-types/shared" "^3.26.0" + "@react-types/tooltip" "^3.4.13" + "@swc/helpers" "^0.5.0" + "@react-aria/utils@^3.15.0", "@react-aria/utils@^3.26.0", "@react-aria/utils@^3.3.0", "@react-aria/utils@^3.4.1", "@react-aria/utils@^3.6.0": version "3.26.0" resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.26.0.tgz#833cbfa33e75d15835b757791b3f754432d2f948" @@ -4353,6 +4729,14 @@ dependencies: "@swc/helpers" "^0.5.0" +"@react-types/breadcrumbs@^3.7.9": + version "3.7.9" + resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.9.tgz#c75eae6158bd3631854bff7521c2373b42b0e37c" + integrity sha512-eARYJo8J+VfNV8vP4uw3L2Qliba9wLV2bx9YQCYf5Lc/OE5B/y4gaTLz+Y2P3Rtn6gBPLXY447zCs5i7gf+ICg== + dependencies: + "@react-types/link" "^3.5.9" + "@react-types/shared" "^3.26.0" + "@react-types/button@^3.10.1", "@react-types/button@^3.3.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.10.1.tgz#fc7ada2e83bc661b31c1473a82ec86dc11de057c" @@ -4415,6 +4799,13 @@ dependencies: "@react-types/shared" "^3.26.0" +"@react-types/link@^3.5.9": + version "3.5.9" + resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.5.9.tgz#bf61ff2780581de03920e6e43260844a81a38d2f" + integrity sha512-JcKDiDMqrq/5Vpn+BdWQEuXit4KN4HR/EgIi3yKnNbYkLzxBoeQZpQgvTaC7NEQeZnSqkyXQo3/vMUeX/ZNIKw== + dependencies: + "@react-types/shared" "^3.26.0" + "@react-types/listbox@^3.1.1", "@react-types/listbox@^3.5.3": version "3.5.3" resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.5.3.tgz#c5dbe8a67d67ca59de6b88aaa2f20fcf61fee1c5" @@ -4430,6 +4821,13 @@ "@react-types/overlays" "^3.8.11" "@react-types/shared" "^3.26.0" +"@react-types/meter@^3.4.5": + version "3.4.5" + resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.4.5.tgz#e06d4a2fabd24989c73541b032123c5de495b613" + integrity sha512-04w1lEtvP/c3Ep8ND8hhH2rwjz2MtQ8o8SNLhahen3u0rX3jKOgD4BvHujsyvXXTMjj1Djp74sGzNawb4Ppi9w== + dependencies: + "@react-types/progress" "^3.5.8" + "@react-types/numberfield@^3.8.7": version "3.8.7" resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.8.7.tgz#5a697fdf1bc405dbf55dafed713d47ed79f8e54b" @@ -4444,6 +4842,13 @@ dependencies: "@react-types/shared" "^3.26.0" +"@react-types/progress@^3.5.8": + version "3.5.8" + resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.8.tgz#62ce4207c7e8d640b794c6d89063ce21bdb5970d" + integrity sha512-PR0rN5mWevfblR/zs30NdZr+82Gka/ba7UHmYOW9/lkKlWeD7PHgl1iacpd/3zl/jUF22evAQbBHmk1mS6Mpqw== + dependencies: + "@react-types/shared" "^3.26.0" + "@react-types/radio@^3.1.1", "@react-types/radio@^3.8.5": version "3.8.5" resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.8.5.tgz#8e2dd1911fba829b7f1ebb40bccf9ca483f021fc" @@ -4967,6 +5372,18 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" +"@storybook/channels@7.6.20": + version "7.6.20" + resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-7.6.20.tgz#33d8292b1b16d7f504bf751c57a792477d1c3a9e" + integrity sha512-4hkgPSH6bJclB2OvLnkZOGZW1WptJs09mhQ6j6qLjgBZzL/ZdD6priWSd7iXrmPiN5TzUobkG4P4Dp7FjkiO7A== + dependencies: + "@storybook/client-logger" "7.6.20" + "@storybook/core-events" "7.6.20" + "@storybook/global" "^5.0.0" + qs "^6.10.0" + telejson "^7.2.0" + tiny-invariant "^1.3.1" + "@storybook/client-api@6.5.16", "@storybook/client-api@^6.5.14", "@storybook/client-api@^6.5.15": version "6.5.16" resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-6.5.16.tgz#13e5a7c3d1f0f951ec4ef51cfcf2c5aafb560e12" @@ -5001,6 +5418,13 @@ core-js "^3.8.2" global "^4.4.0" +"@storybook/client-logger@7.6.20": + version "7.6.20" + resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-7.6.20.tgz#1d6e93443091cccd50e269371aa786172d0c4659" + integrity sha512-NwG0VIJQCmKrSaN5GBDFyQgTAHLNishUPLW1NrzqTDNAhfZUoef64rPQlinbopa0H4OXmlB+QxbQIb3ubeXmSQ== + dependencies: + "@storybook/global" "^5.0.0" + "@storybook/components@6.5.16", "@storybook/components@^6.2.9", "@storybook/components@^6.5.14": version "6.5.16" resolved "https://registry.yarnpkg.com/@storybook/components/-/components-6.5.16.tgz#f8dc51213bc08fe32154be964e1e8b0e2f670ed6" @@ -5104,6 +5528,13 @@ dependencies: core-js "^3.8.2" +"@storybook/core-events@7.6.20": + version "7.6.20" + resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-7.6.20.tgz#6648d661d1c96841a4c2a710a35759b01b6a06a1" + integrity sha512-tlVDuVbDiNkvPDFAu+0ou3xBBYbx9zUURQz4G9fAq0ScgBOs/bpzcRrFb4mLpemUViBAd47tfZKdH4MAX45KVQ== + dependencies: + ts-dedent "^2.0.0" + "@storybook/core-server@6.5.16": version "6.5.16" resolved "https://registry.yarnpkg.com/@storybook/core-server/-/core-server-6.5.16.tgz#f40de3413de49388129d29c74e5e48321af03f12" @@ -5190,6 +5621,13 @@ dependencies: lodash "^4.17.15" +"@storybook/csf@^0.1.2": + version "0.1.13" + resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.13.tgz#c8a9bea2ae518a3d9700546748fa30a8b07f7f80" + integrity sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q== + dependencies: + type-fest "^2.19.0" + "@storybook/docs-tools@6.5.16": version "6.5.16" resolved "https://registry.yarnpkg.com/@storybook/docs-tools/-/docs-tools-6.5.16.tgz#1ec5433eeab63a214d37ffc4660cdaec9704ac39" @@ -5294,6 +5732,26 @@ dependencies: core-js "^3.8.2" +"@storybook/preview-api@^7.6.8": + version "7.6.20" + resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-7.6.20.tgz#688a435ee2cfe57eeb1e3053c18025a9e0a03bbb" + integrity sha512-3ic2m9LDZEPwZk02wIhNc3n3rNvbi7VDKn52hDXfAxnL5EYm7yDICAkaWcVaTfblru2zn0EDJt7ROpthscTW5w== + dependencies: + "@storybook/channels" "7.6.20" + "@storybook/client-logger" "7.6.20" + "@storybook/core-events" "7.6.20" + "@storybook/csf" "^0.1.2" + "@storybook/global" "^5.0.0" + "@storybook/types" "7.6.20" + "@types/qs" "^6.9.5" + dequal "^2.0.2" + lodash "^4.17.21" + memoizerific "^1.11.3" + qs "^6.10.0" + synchronous-promise "^2.0.15" + ts-dedent "^2.0.0" + util-deprecate "^1.0.2" + "@storybook/preview-web@6.5.16", "@storybook/preview-web@^6.5.14": version "6.5.16" resolved "https://registry.yarnpkg.com/@storybook/preview-web/-/preview-web-6.5.16.tgz#1d32a72be25776f9597e33ffc1914f3430fae689" @@ -5480,6 +5938,16 @@ memoizerific "^1.11.3" regenerator-runtime "^0.13.7" +"@storybook/types@7.6.20": + version "7.6.20" + resolved "https://registry.yarnpkg.com/@storybook/types/-/types-7.6.20.tgz#b8d62b30914b35e6750b1f4937da532432f02890" + integrity sha512-GncdY3x0LpbhmUAAJwXYtJDUQEwfF175gsjH0/fxPkxPoV7Sef9TM41jQLJW/5+6TnZoCZP/+aJZTJtq3ni23Q== + dependencies: + "@storybook/channels" "7.6.20" + "@types/babel__core" "^7.0.0" + "@types/express" "^4.7.0" + file-system-cache "2.3.0" + "@storybook/ui@6.5.16": version "6.5.16" resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-6.5.16.tgz#c73bf456e672ecf2370b4365070088487fc0ce57" @@ -5555,7 +6023,7 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@types/babel__core@^7.1.14", "@types/babel__core@^7.1.6": +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.6": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== @@ -5588,6 +6056,21 @@ dependencies: "@babel/types" "^7.20.7" +"@types/body-parser@*": + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + "@types/eslint-scope@^3.7.7": version "3.7.7" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" @@ -5614,6 +6097,26 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== +"@types/express-serve-static-core@^4.17.33": + version "4.19.6" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz#e01324c2a024ff367d92c66f48553ced0ab50267" + integrity sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@^4.7.0": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/glob@*": version "8.1.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-8.1.0.tgz#b63e70155391b0584dce44e7ea25190bbc38f2fc" @@ -5659,6 +6162,11 @@ resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + "@types/is-function@^1.0.0": version "1.0.3" resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.3.tgz#548f851db5d30a12abeea2569ba75890dbf89425" @@ -5716,6 +6224,11 @@ dependencies: "@types/unist" "^2" +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + "@types/minimatch@*", "@types/minimatch@^5.1.2": version "5.1.2" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" @@ -5793,11 +6306,16 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.8.tgz#95f6c6a08f2ad868ba230ead1d2d7f7be3db3837" integrity sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw== -"@types/qs@^6.9.5": +"@types/qs@*", "@types/qs@^6.9.5": version "6.9.17" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.17.tgz#fc560f60946d0aeff2f914eb41679659d3310e1a" integrity sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ== +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + "@types/react-native@^0.69.15": version "0.69.26" resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.69.26.tgz#95678998c369f42f8cf967644589b7890b6d211a" @@ -5833,6 +6351,23 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== +"@types/send@*": + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "*" + "@types/source-list-map@*": version "0.1.6" resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.6.tgz#164e169dd061795b50b83c19e4d3be09f8d3a454" @@ -5958,6 +6493,17 @@ "@typescript-eslint/typescript-estree" "5.62.0" debug "^4.3.4" +"@typescript-eslint/parser@^6.13.2": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== + dependencies: + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + "@typescript-eslint/scope-manager@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" @@ -5966,6 +6512,14 @@ "@typescript-eslint/types" "5.62.0" "@typescript-eslint/visitor-keys" "5.62.0" +"@typescript-eslint/scope-manager@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" + integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/type-utils@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" @@ -5981,6 +6535,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== +"@typescript-eslint/types@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" + integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== + "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" @@ -5994,6 +6553,20 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" + integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/utils@5.62.0", "@typescript-eslint/utils@^5.10.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" @@ -6016,6 +6589,14 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" + integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== + dependencies: + "@typescript-eslint/types" "6.21.0" + eslint-visitor-keys "^3.4.1" + "@ungap/structured-clone@^1.2.0": version "1.2.1" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.1.tgz#28fa185f67daaf7b7a1a8c1d445132c5d979f8bd" @@ -9496,6 +10077,11 @@ deprecation@^2.0.0: resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== +dequal@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + des.js@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" @@ -10655,6 +11241,14 @@ expo-modules-core@1.1.1: compare-versions "^3.4.0" invariant "^2.2.4" +expo-modules-core@1.5.12: + version "1.5.12" + resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-1.5.12.tgz#07eb4de4bf25a3ec3e1924403e73d13c656613fd" + integrity sha512-mY4wTDU458dhwk7IVxLNkePlYXjs9BTgk4NQHBUXf0LapXsvr+i711qPZaFNO4egf5qq6fQV+Yfd/KUguHstnQ== + dependencies: + compare-versions "^3.4.0" + invariant "^2.2.4" + expo-pwa@0.0.124: version "0.0.124" resolved "https://registry.yarnpkg.com/expo-pwa/-/expo-pwa-0.0.124.tgz#684e68aea6c7f95864a8cde17a57e223ed017199" @@ -10967,6 +11561,14 @@ file-loader@~6.0.0: loader-utils "^2.0.0" schema-utils "^2.6.5" +file-system-cache@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-2.3.0.tgz#201feaf4c8cd97b9d0d608e96861bb6005f46fe6" + integrity sha512-l4DMNdsIPsVnKrgEXbJwDJsA5mB8rGwHYERMgqQx/xAUtChPJMre1bXBzDEqqVbWv9AIbFezXMxeEkZDSrXUOQ== + dependencies: + fs-extra "11.1.1" + ramda "0.29.0" + file-system-cache@^1.0.5: version "1.1.0" resolved "https://registry.yarnpkg.com/file-system-cache/-/file-system-cache-1.1.0.tgz#984de17b976b75a77a27e08d6828137c1aa80fa1" @@ -11302,6 +11904,15 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" +fs-extra@11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" + integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3" @@ -15392,6 +16003,13 @@ minimatch@3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimatch@^5.0.1: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" @@ -17554,6 +18172,11 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +ramda@0.29.0: + version "0.29.0" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.29.0.tgz#fbbb67a740a754c8a4cbb41e2a6e0eb8507f55fb" + integrity sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA== + ramda@^0.28.0: version "0.28.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.28.0.tgz#acd785690100337e8b063cab3470019be427cc97" @@ -17612,6 +18235,51 @@ re-resizable@^6.9.11: resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.3.tgz#72c42532ede0cbcaf93308bcbfed782abbf97e79" integrity sha512-zvWb7X3RJMA4cuSrqoxgs3KR+D+pEXnGrD2FAD6BMYAULnZsSF4b7AOVyG6pC3VVNVOtlagGDCDmZSwWLjjBBw== +react-aria@^3.30.0: + version "3.36.0" + resolved "https://registry.yarnpkg.com/react-aria/-/react-aria-3.36.0.tgz#95a8e3340ab400bfec4d159e47da8861469e5bcd" + integrity sha512-AK5XyIhAN+e5HDlwlF+YwFrOrVI7RYmZ6kg/o7ZprQjkYqYKapXeUpWscmNm/3H2kDboE5Z4ymUnK6ZhobLqOw== + dependencies: + "@internationalized/string" "^3.2.5" + "@react-aria/breadcrumbs" "^3.5.19" + "@react-aria/button" "^3.11.0" + "@react-aria/calendar" "^3.6.0" + "@react-aria/checkbox" "^3.15.0" + "@react-aria/color" "^3.0.2" + "@react-aria/combobox" "^3.11.0" + "@react-aria/datepicker" "^3.12.0" + "@react-aria/dialog" "^3.5.20" + "@react-aria/disclosure" "^3.0.0" + "@react-aria/dnd" "^3.8.0" + "@react-aria/focus" "^3.19.0" + "@react-aria/gridlist" "^3.10.0" + "@react-aria/i18n" "^3.12.4" + "@react-aria/interactions" "^3.22.5" + "@react-aria/label" "^3.7.13" + "@react-aria/link" "^3.7.7" + "@react-aria/listbox" "^3.13.6" + "@react-aria/menu" "^3.16.0" + "@react-aria/meter" "^3.4.18" + "@react-aria/numberfield" "^3.11.9" + "@react-aria/overlays" "^3.24.0" + "@react-aria/progress" "^3.4.18" + "@react-aria/radio" "^3.10.10" + "@react-aria/searchfield" "^3.7.11" + "@react-aria/select" "^3.15.0" + "@react-aria/selection" "^3.21.0" + "@react-aria/separator" "^3.4.4" + "@react-aria/slider" "^3.7.14" + "@react-aria/ssr" "^3.9.7" + "@react-aria/switch" "^3.6.10" + "@react-aria/table" "^3.16.0" + "@react-aria/tabs" "^3.9.8" + "@react-aria/tag" "^3.4.8" + "@react-aria/textfield" "^3.15.0" + "@react-aria/tooltip" "^3.7.10" + "@react-aria/utils" "^3.26.0" + "@react-aria/visually-hidden" "^3.8.18" + "@react-types/shared" "^3.26.0" + react-dev-utils@~11.0.1: version "11.0.4" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a" @@ -17787,6 +18455,16 @@ react-native-css-interop@0.1.22: lightningcss "^1.27.0" semver "^7.6.3" +react-native-gesture-handler@^2.12.1: + version "2.21.2" + resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.21.2.tgz#824a098d7397212fbe51aa3a9df84833a4ea1c3f" + integrity sha512-HcwB225K9aeZ8e/B8nFzEh+2T4EPWTeamO1l/y3PcQ9cyCDYO2zja/G31ITpYRIqkip7XzGs6wI/gnHOQn1LDQ== + dependencies: + "@egjs/hammerjs" "^2.0.17" + hoist-non-react-statics "^3.3.0" + invariant "^2.2.4" + prop-types "^15.7.2" + react-native-gesture-handler@~2.14.0: version "2.14.1" resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.14.1.tgz#930640231024b7921435ab476aa501dd4a6b2e01" @@ -17865,7 +18543,7 @@ react-native-web@0.19.9, react-native-web@^0.18.1, react-native-web@^0.19.9: postcss-value-parser "^4.2.0" styleq "^0.1.3" -react-native@0.72.4, react-native@^0.70.3, react-native@^0.72.4: +react-native@0.72.4, react-native@^0.70.3, react-native@^0.72.4, react-native@^0.72.5: version "0.72.4" resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.72.4.tgz#97b57e22e4d7657eaf4d1f62a678511fcf9bdda7" integrity sha512-+vrObi0wZR+NeqL09KihAAdVlQ9IdplwznJWtYrjnQ4UbCW6rkzZJebRsugwUneSOKNFaHFEo1uKU89HsgtYBg== @@ -20051,6 +20729,13 @@ telejson@^6.0.8: lodash "^4.17.21" memoizerific "^1.11.3" +telejson@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/telejson/-/telejson-7.2.0.tgz#3994f6c9a8f8d7f2dba9be2c7c5bbb447e876f32" + integrity sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ== + dependencies: + memoizerific "^1.11.3" + temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" @@ -20251,6 +20936,11 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A== +tiny-invariant@^1.3.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== + tinycolor2@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" @@ -20371,6 +21061,11 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== +ts-api-utils@^1.0.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== + ts-dedent@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" @@ -20579,7 +21274,7 @@ type-fest@^1.0.1, type-fest@^1.0.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== -type-fest@^2.13.0, type-fest@^2.5.1: +type-fest@^2.13.0, type-fest@^2.19.0, type-fest@^2.5.1: version "2.19.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== From 12207fd32612ce0eaeacb575830b89b00ea0ab57 Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Tue, 7 Jan 2025 12:11:21 +0530 Subject: [PATCH 04/11] feat: pressable props for day component --- .../src/components/Calendar/Calendar.tsx | 24 +---- .../nativewind/calendar/index.tsx | 12 ++- .../nativewind/calendar/styles.tsx | 2 +- .../calendar/src/CalendarGridDays.tsx | 65 ++++-------- .../calendar/src/CalendarHeaderNext.tsx | 98 ++++--------------- .../calendar/src/CalendarHeaderPrev.tsx | 96 ++++-------------- packages/unstyled/calendar/src/Pressable.tsx | 85 ++++++++++++++++ packages/unstyled/calendar/src/types.ts | 5 +- 8 files changed, 155 insertions(+), 232 deletions(-) create mode 100644 packages/unstyled/calendar/src/Pressable.tsx diff --git a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx index 2d9889d5e7..0a823d751f 100644 --- a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx +++ b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx @@ -1,17 +1,8 @@ import React from 'react'; -import { - Calendar, - CalendarHeader, - CalendarHeaderNext, - CalendarHeaderPrev, - CalendarHeaderTitle, - CalendarGrid, - CalendarGridWeek, - CalendarGridDays, -} from '@/components/ui/calendar'; +import { Calendar } from '@/components/ui/calendar'; const CalendarBasic = ({ ...props }: any) => { - return ; + return ; }; CalendarBasic.description = @@ -19,13 +10,4 @@ CalendarBasic.description = export default CalendarBasic; -export { - Calendar, - CalendarHeader, - CalendarHeaderNext, - CalendarHeaderPrev, - CalendarHeaderTitle, - CalendarGrid, - CalendarGridWeek, - CalendarGridDays, -}; +export { Calendar }; diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx index f2c2e7dcb3..03a78f114f 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx @@ -197,13 +197,15 @@ const CalendarGridDays = React.forwardRef< ref={ref} {...props} className={calendarGridDaysStyle({ class: className })} - render={(day, states) => ( - ( + {day?.getDate()} - + )} /> ); diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx index 0f404c2d8b..1e280c3c88 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx @@ -25,7 +25,7 @@ export const calendarGridDaysStyle = tva({ }); export const calendarDaysCellStyle = tva({ - base: 'w-[14.28%] p-2 aspect-square cursor-pointer flex items-center justify-center', + base: 'w-[14.28%] aspect-square cursor-pointer flex items-center justify-center data-[selected=true]:bg-primary-0 rounded-lg', }); export const calendarWeekCellStyle = tva({ diff --git a/packages/unstyled/calendar/src/CalendarGridDays.tsx b/packages/unstyled/calendar/src/CalendarGridDays.tsx index ff2bd9e805..df475d487e 100644 --- a/packages/unstyled/calendar/src/CalendarGridDays.tsx +++ b/packages/unstyled/calendar/src/CalendarGridDays.tsx @@ -1,7 +1,5 @@ import React, { forwardRef } from 'react'; -import { useHover, usePress } from '@react-native-aria/interactions'; -import { useFocus, useFocusRing } from '@react-native-aria/focus'; -import { composeEventHandlers } from '@gluestack-ui/utils'; +import CommonPressable from './Pressable'; import { useCalendarContext } from './Context'; export const CalendarGridDays = (StyledCalendarGridDays: any) => @@ -14,14 +12,7 @@ export const CalendarGridDays = (StyledCalendarGridDays: any) => isDisabled, } = useCalendarContext(); const days = getDaysInMonth(); - const { isHovered, hoverProps }: any = useHover(); - const { isFocused, focusProps } = useFocus(); - const { isFocusVisible, focusProps: focusRingProps }: any = useFocusRing(); - const { isPressed, pressProps } = usePress({ - onPress: (day: Date) => handleDateSelect(day), - }); - // can move to context const isSameDate = (date1: Date, date2: Date): boolean => { if (!date1 || !date2) return false; return date1.getTime() === date2.getTime(); @@ -30,43 +21,23 @@ export const CalendarGridDays = (StyledCalendarGridDays: any) => return ( {days.map((day) => { - const DayProps = { - key: day?.getDate(), - states: { - disabled: isDisabled(day), - hover: isHovered, - focus: isFocused, - focusVisible: isFocusVisible, - active: isPressed, - today: isToday(day), - selected: day && selectedDate && isSameDate(day, selectedDate), - }, - dataSet: { - disabled: isDisabled(day) ? 'true' : 'false', - hover: isHovered ? 'true' : 'false', - focus: isFocused ? 'true' : 'false', - focusVisible: isFocusVisible ? 'true' : 'false', - active: isPressed ? 'true' : 'false', - today: isToday(day) ? 'true' : 'false', - selected: day && selectedDate && isSameDate(day, selectedDate), - }, - disabled: isDisabled(day), - onPressIn: composeEventHandlers(pressProps.onPressIn), - onPressOut: composeEventHandlers(pressProps.onPressOut), - onPress: composeEventHandlers(() => handleDateSelect(day)), - onHoverIn: composeEventHandlers(hoverProps.onHoverIn), - onHoverOut: composeEventHandlers(hoverProps.onHoverOut), - onFocus: composeEventHandlers( - focusProps.onFocus, - focusRingProps.onFocus - ), - onBlur: composeEventHandlers( - focusProps.onBlur, - focusRingProps.onBlur - ), - }; - const Day = render?.(day, DayProps); - return Day; + return ( + handleDateSelect(day)} + states={{ + today: isToday(day), + selected: day && selectedDate && isSameDate(day, selectedDate), + }} + dataSet={{ + today: isToday(day) ? 'true' : 'false', + selected: day && selectedDate && isSameDate(day, selectedDate), + }} + StyledComponent={(dayProps: any) => render(day, dayProps)} + /> + ); })} ); diff --git a/packages/unstyled/calendar/src/CalendarHeaderNext.tsx b/packages/unstyled/calendar/src/CalendarHeaderNext.tsx index 74ec059428..cb9f8e93a2 100644 --- a/packages/unstyled/calendar/src/CalendarHeaderNext.tsx +++ b/packages/unstyled/calendar/src/CalendarHeaderNext.tsx @@ -1,81 +1,23 @@ import React, { forwardRef } from 'react'; -import { useHover, usePress } from '@react-native-aria/interactions'; -import { useFocus, useFocusRing } from '@react-native-aria/focus'; -import { composeEventHandlers } from '@gluestack-ui/utils'; +import CommonPressable from './Pressable'; import { useCalendarContext } from './Context'; + export const CalendarHeaderNext = (StyledCalendarHeaderNext: any) => - forwardRef( - ( - { - isDisabled, - isPressed: isPressedProp, - isHovered: isHoveredProp, - isFocused: isFocusedProp, - isFocusVisible: isFocusVisibleProp, - ...props - }: any, - ref?: any - ) => { - const { isNextDisabled, nextMonth } = useCalendarContext(); - const handlePress = () => { - if (!isDisabled && !isNextDisabled) { - nextMonth(); - } - }; - const { isHovered, hoverProps }: any = useHover(); - const { isPressed, pressProps } = usePress({ - onPress: handlePress, - isDisabled: isDisabled || isNextDisabled, - }); - const { isFocused, focusProps } = useFocus(); - const { isFocusVisible, focusProps: focusRingProps }: any = - useFocusRing(); - return ( - - ); - } - ); + forwardRef(({ isDisabled, ...props }: any, ref?: any) => { + const { isNextDisabled, nextMonth } = useCalendarContext(); + const handlePress = () => { + if (!isDisabled && !isNextDisabled) { + nextMonth(); + } + }; + + return ( + + ); + }); diff --git a/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx b/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx index 8145cfb997..a97f4837d6 100644 --- a/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx +++ b/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx @@ -1,82 +1,22 @@ import React, { forwardRef } from 'react'; -import { useHover, usePress } from '@react-native-aria/interactions'; -import { useFocus, useFocusRing } from '@react-native-aria/focus'; -import { composeEventHandlers } from '@gluestack-ui/utils'; +import CommonPressable from './Pressable'; import { useCalendarContext } from './Context'; export const CalendarHeaderPrev = (StyledCalendarHeaderPrev: any) => - forwardRef( - ( - { - isDisabled, - isPressed: isPressedProp, - isHovered: isHoveredProp, - isFocused: isFocusedProp, - isFocusVisible: isFocusVisibleProp, - ...props - }: any, - ref?: any - ) => { - const { isPrevDisabled, prevMonth } = useCalendarContext(); - const handlePress = () => { - if (!isDisabled && !isPrevDisabled) { - prevMonth(); - } - }; - const { isHovered, hoverProps }: any = useHover(); - const { isPressed, pressProps } = usePress({ - onPress: handlePress, - isDisabled: isDisabled || isPrevDisabled, - }); - const { isFocused, focusProps } = useFocus(); - const { isFocusVisible, focusProps: focusRingProps }: any = - useFocusRing(); - return ( - - ); - } - ); + forwardRef(({ isDisabled, ...props }: any, ref?: any) => { + const { isPrevDisabled, prevMonth } = useCalendarContext(); + const handlePress = () => { + if (!isDisabled && !isPrevDisabled) { + prevMonth(); + } + }; + return ( + + ); + }); diff --git a/packages/unstyled/calendar/src/Pressable.tsx b/packages/unstyled/calendar/src/Pressable.tsx new file mode 100644 index 0000000000..43d10a2d68 --- /dev/null +++ b/packages/unstyled/calendar/src/Pressable.tsx @@ -0,0 +1,85 @@ +import React, { forwardRef } from 'react'; +import { useHover, usePress } from '@react-native-aria/interactions'; +import { useFocus, useFocusRing } from '@react-native-aria/focus'; +import { composeEventHandlers } from '@gluestack-ui/utils'; + +const Pressable = forwardRef( + ( + { + isDisabled = false, + isPressed: isPressedProp, + isHovered: isHoveredProp, + isFocused: isFocusedProp, + isFocusVisible: isFocusVisibleProp, + children, + StyledComponent, + onPress, + states: statesProp, + dataSet: dataSetProp, + ...props + }: any, + ref?: any + ) => { + const { isHovered, hoverProps } = useHover(); + const { isPressed, pressProps } = usePress({ + onPress, + isDisabled, + }); + const { isFocused, focusProps } = useFocus(); + const { isFocusVisible, focusRingProps }: any = useFocusRing(); + + const defaultStates = { + hover: isHoveredProp || isHovered, + focus: isFocusedProp || isFocused, + active: isPressedProp || isPressed, + disabled: isDisabled, + focusVisible: isFocusVisibleProp || isFocusVisible, + }; + + const defaultDataSet = { + hover: isHoveredProp || isHovered, + focus: isFocusedProp || isFocused, + active: isPressedProp || isPressed, + disabled: isDisabled, + focusVisible: isFocusVisibleProp || isFocusVisible, + }; + + return ( + + {children} + + ); + } +); + +export default Pressable; diff --git a/packages/unstyled/calendar/src/types.ts b/packages/unstyled/calendar/src/types.ts index f6bedda7e8..d3f29906a5 100644 --- a/packages/unstyled/calendar/src/types.ts +++ b/packages/unstyled/calendar/src/types.ts @@ -1,4 +1,5 @@ import type { PropsWithoutRef, RefAttributes } from 'react'; +import type { GestureResponderEvent } from 'react-native'; export interface ICalendarProps { /** @@ -80,14 +81,14 @@ export interface ICalendarDayProps { /** * Handler for when the day is pressed */ - onPress?: (date: Date) => void; + onPress?: (event: GestureResponderEvent) => void; } export interface ICalendarGridDaysProps { /** * Render method for custom day rendering */ - render?: (days: Date | null, props: ICalendarDayProps) => React.ReactNode; + render?: (days: Date | null, dayProps: any) => React.ReactNode; } export interface ICalendarContextValue { From b52ec6e00840a27e129a67f06fdf4a3b4556f2f6 Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Wed, 8 Jan 2025 10:21:34 +0530 Subject: [PATCH 05/11] feat: testing in mobile --- .../src/components/Calendar/Calendar.tsx | 51 ++++++++++++++++++- .../components/Calendar/index.nw.stories.mdx | 8 +-- .../nativewind/calendar/index.tsx | 40 +++++++++------ .../nativewind/calendar/styles.tsx | 10 +++- example/storybook-v7/babel.config.js | 4 ++ example/storybook-v7/tsconfig.json | 6 ++- packages/unstyled/calendar/src/Calendar.tsx | 23 +++++++-- .../calendar/src/CalendarGridDays.tsx | 38 +++++++------- .../calendar/src/CalendarGridWeek.tsx | 2 +- packages/unstyled/calendar/src/Pressable.tsx | 2 +- packages/unstyled/calendar/src/types.ts | 7 +-- 11 files changed, 135 insertions(+), 56 deletions(-) diff --git a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx index 0a823d751f..76daddb956 100644 --- a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx +++ b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx @@ -1,8 +1,55 @@ import React from 'react'; -import { Calendar } from '@/components/ui/calendar'; +import { + Calendar, + CalendarGrid, + CalendarGridDays, + CalendarGridWeek, + CalendarHeader, + CalendarHeaderNext, + CalendarHeaderPrev, + CalendarHeaderTitle, +} from '@/components/ui/calendar'; +import { Text } from '@/components/ui/text'; +import { Pressable } from '@/components/ui/pressable'; +import { cssInterop } from 'nativewind'; + +// note: required for nativewind to work on Storybook +cssInterop(Pressable, { + className: { + target: 'style', + }, +}); const CalendarBasic = ({ ...props }: any) => { - return ; + return ( + + + + + + + + + ( + + {day?.getDate()} + + )} + /> + + + ); }; CalendarBasic.description = diff --git a/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx index b7d9bd6533..61eb496740 100644 --- a/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx +++ b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx @@ -44,7 +44,7 @@ import { CollapsibleCode } from '@gluestack/design-system'; showArgsController={true} metaData={{ code: ` - + `, transformCode: (code) => { return transformedCode(code); @@ -292,7 +292,7 @@ Component for rendering calendar week cells. Supports custom rendering through t - (props: RenderProps) => React.ReactNode + (weekdays: string) => React.ReactNode - @@ -339,13 +339,13 @@ Component for rendering calendar day cells. Supports custom rendering through th - (props: RenderProps) => React.ReactNode + (day: Date | null, dayProps: any) => React.ReactNode - - Custom renderer for date cells. Allows complete customization of how dates are displayed + Custom renderer for date cells. Allows complete customization of how each date is displayed diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx index 03a78f114f..9098a57b89 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx @@ -40,7 +40,7 @@ const UICalendar = createCalendar({ HeaderPrev: RNPressable, HeaderTitle: RNText, HeaderNext: RNPressable, - Header: RNText, + Header: RNView, GridWeek: RNView, GridDays: RNView, Grid: RNView, @@ -109,7 +109,7 @@ const CalendarHeaderPrev = React.forwardRef< {...props} className={calendarNavStyle({ class: className })} > - + ); }); @@ -124,7 +124,7 @@ const CalendarHeaderNext = React.forwardRef< {...props} className={calendarNavStyle({ class: className })} > - + ); }); @@ -177,9 +177,12 @@ const CalendarGridWeek = React.forwardRef< ref={ref} {...props} className={calendarGridWeekStyle({ class: className })} - render={(day) => { + render={(day, index) => { return ( - + {day} ); @@ -191,22 +194,27 @@ const CalendarGridWeek = React.forwardRef< const CalendarGridDays = React.forwardRef< React.ElementRef, ICalendarGridDaysProps ->(({ className, ...props }, ref) => { +>(({ className, render, ...props }, ref) => { return ( ( - - {day?.getDate()} - - )} + render={ + render || + ((day, dayProps) => { + return ( + + {day?.getDate()} + + ); + }) + } /> ); }); diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx index 1e280c3c88..8530174d2e 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx @@ -5,7 +5,7 @@ export const calendarStyle = tva({ }); export const calendarNavStyle = tva({ - base: 'w-6 h-6 flex items-center justify-center rounded-full hover:bg-typography-100 active:bg-typography-200', + base: 'w-6 h-6 p-1 flex items-center justify-center rounded-full data-[hover=true]:bg-typography-100 data-[active=true]:bg-typography-200 data-[disabled=true]:opacity-40 data-[disabled=true]:cursor-not-allowed', }); export const calendarTitleStyle = tva({ @@ -25,7 +25,13 @@ export const calendarGridDaysStyle = tva({ }); export const calendarDaysCellStyle = tva({ - base: 'w-[14.28%] aspect-square cursor-pointer flex items-center justify-center data-[selected=true]:bg-primary-0 rounded-lg', + base: 'w-[14.28%] p-2 flex items-center justify-center rounded-lg', + variants: { + hasDay: { + true: 'cursor-pointer data-[today=true]:bg-primary-50 data-[selected=true]:data-[disabled=false]:bg-primary-50 data-[active=true]:data-[disabled=false]:bg-primary-50 data-[hover=true]:data-[disabled=false]:bg-primary-0 data-[disabled=true]:text-typography-300 data-[disabled=true]:cursor-not-allowed', + false: 'cursor-default', + }, + }, }); export const calendarWeekCellStyle = tva({ diff --git a/example/storybook-v7/babel.config.js b/example/storybook-v7/babel.config.js index 11c8afb87a..51382dcb67 100644 --- a/example/storybook-v7/babel.config.js +++ b/example/storybook-v7/babel.config.js @@ -120,6 +120,10 @@ module.exports = function (api) { __dirname, '../../packages/unstyled/toast/src' ), + '@gluestack-ui/calendar': path.join( + __dirname, + '../../packages/unstyled/calendar/src' + ), '@/extra-components/nativewind': path.resolve( __dirname, './../storybook-nativewind/src/core-components/nativewind' diff --git a/example/storybook-v7/tsconfig.json b/example/storybook-v7/tsconfig.json index b9567f6052..769ae77715 100644 --- a/example/storybook-v7/tsconfig.json +++ b/example/storybook-v7/tsconfig.json @@ -1,6 +1,10 @@ { "extends": "expo/tsconfig.base", "compilerOptions": { - "strict": true + "strict": true, + "baseUrl": ".", + "paths": { + "@gluestack-ui/calendar": ["../../packages/unstyled/calendar/src"] + } } } diff --git a/packages/unstyled/calendar/src/Calendar.tsx b/packages/unstyled/calendar/src/Calendar.tsx index 5aba24d401..ca9c3f4538 100644 --- a/packages/unstyled/calendar/src/Calendar.tsx +++ b/packages/unstyled/calendar/src/Calendar.tsx @@ -39,9 +39,6 @@ export function Calendar(StyledCalendar: any) { selectedDate ?? new Date() ); - const isPrevDisabled = minDate ? currentMonth < minDate : false; - const isNextDisabled = maxDate ? currentMonth > maxDate : false; - const isDisabled = useCallback( (day: Date | null) => { if (!day) return false; @@ -76,6 +73,24 @@ export function Calendar(StyledCalendar: any) { setCurrentMonth(newDate); }, [currentMonth]); + const isPrevDisabled = useMemo(() => { + if (!minDate) return false; + return ( + currentMonth.getFullYear() < minDate.getFullYear() || + (currentMonth.getFullYear() === minDate.getFullYear() && + currentMonth.getMonth() < minDate.getMonth()) + ); + }, [currentMonth, minDate]); + + const isNextDisabled = useMemo(() => { + if (!maxDate) return false; + return ( + currentMonth.getFullYear() > maxDate.getFullYear() || + (currentMonth.getFullYear() === maxDate.getFullYear() && + currentMonth.getMonth() >= maxDate.getMonth()) + ); + }, [currentMonth, maxDate]); + const getDaysInMonth = useCallback(() => { const year = currentMonth.getFullYear(); const month = currentMonth.getMonth(); @@ -98,8 +113,8 @@ export function Calendar(StyledCalendar: any) { const handleDateSelect = useCallback( (day: Date | null) => { if (!day) return; - onChange?.(day); setSelectedDate(day); + onChange?.(day); }, [onChange] ); diff --git a/packages/unstyled/calendar/src/CalendarGridDays.tsx b/packages/unstyled/calendar/src/CalendarGridDays.tsx index df475d487e..f0216dc059 100644 --- a/packages/unstyled/calendar/src/CalendarGridDays.tsx +++ b/packages/unstyled/calendar/src/CalendarGridDays.tsx @@ -20,25 +20,25 @@ export const CalendarGridDays = (StyledCalendarGridDays: any) => return ( - {days.map((day) => { - return ( - handleDateSelect(day)} - states={{ - today: isToday(day), - selected: day && selectedDate && isSameDate(day, selectedDate), - }} - dataSet={{ - today: isToday(day) ? 'true' : 'false', - selected: day && selectedDate && isSameDate(day, selectedDate), - }} - StyledComponent={(dayProps: any) => render(day, dayProps)} - /> - ); - })} + {days.map((day, index) => ( + handleDateSelect(day)} + states={{ + today: isToday(day), + selected: day && selectedDate && isSameDate(day, selectedDate), + disabled: isDisabled(day), + }} + dataSet={{ + today: isToday(day) ? 'true' : 'false', + selected: day && selectedDate && isSameDate(day, selectedDate), + disabled: isDisabled(day), + }} + StyledComponent={(dayProps: any) => render(day, dayProps)} + /> + ))} ); }); diff --git a/packages/unstyled/calendar/src/CalendarGridWeek.tsx b/packages/unstyled/calendar/src/CalendarGridWeek.tsx index 66ebadabaf..a97522484c 100644 --- a/packages/unstyled/calendar/src/CalendarGridWeek.tsx +++ b/packages/unstyled/calendar/src/CalendarGridWeek.tsx @@ -5,7 +5,7 @@ export const CalendarGridWeek = (StyledCalendarGridWeek: any) => const { weekDays } = useCalendarContext(); return ( - {weekDays.map((weekday) => render?.(weekday))} + {weekDays.map((weekday, index) => render?.(weekday, index))} ); }); diff --git a/packages/unstyled/calendar/src/Pressable.tsx b/packages/unstyled/calendar/src/Pressable.tsx index 43d10a2d68..094a57be18 100644 --- a/packages/unstyled/calendar/src/Pressable.tsx +++ b/packages/unstyled/calendar/src/Pressable.tsx @@ -26,7 +26,7 @@ const Pressable = forwardRef( isDisabled, }); const { isFocused, focusProps } = useFocus(); - const { isFocusVisible, focusRingProps }: any = useFocusRing(); + const { isFocusVisible, focusProps: focusRingProps }: any = useFocusRing(); const defaultStates = { hover: isHoveredProp || isHovered, diff --git a/packages/unstyled/calendar/src/types.ts b/packages/unstyled/calendar/src/types.ts index d3f29906a5..36045f7724 100644 --- a/packages/unstyled/calendar/src/types.ts +++ b/packages/unstyled/calendar/src/types.ts @@ -1,5 +1,4 @@ import type { PropsWithoutRef, RefAttributes } from 'react'; -import type { GestureResponderEvent } from 'react-native'; export interface ICalendarProps { /** @@ -55,10 +54,7 @@ export interface ICalendarGridWeekProps { /** * Render method for custom day rendering */ - render?: ( - weekdays: string, - Component: React.ComponentType - ) => React.ReactNode; + render?: (weekdays: string, index: number) => React.ReactNode; } export interface ICalendarDayProps { @@ -81,7 +77,6 @@ export interface ICalendarDayProps { /** * Handler for when the day is pressed */ - onPress?: (event: GestureResponderEvent) => void; } export interface ICalendarGridDaysProps { From 9a4d2efebd47d41b101b70189c37f7de8ca6d9f0 Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Wed, 8 Jan 2025 13:17:12 +0530 Subject: [PATCH 06/11] feat: update docs --- .../components/Calendar/index.nw.stories.mdx | 78 +++++++++++++++++-- packages/unstyled/calendar/README.md | 53 +------------ 2 files changed, 75 insertions(+), 56 deletions(-) diff --git a/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx index 61eb496740..0fc5327825 100644 --- a/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx +++ b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx @@ -23,7 +23,9 @@ CalendarHeaderPrev, CalendarHeaderTitle, CalendarGrid, CalendarGridWeek, -CalendarGridDays } from '../../core-components/nativewind'; +CalendarGridDays, +Pressable, +Text } from '../../core-components/nativewind'; import { AppProvider, CodePreview, @@ -152,7 +154,7 @@ This section provides a comprehensive reference list for the component props, de #### Calendar -It is a context provider for entire calendar api. +It inherits all the properties of React Native's `View` component. ### Props @@ -261,9 +263,13 @@ It is a context provider for entire calendar api. +### CalendarGrid + +It inherits all the properties of React Native's `View` component. + ### CalendarGridWeek -Component for rendering calendar week cells. Supports custom rendering through the render prop. +It inherits all the properties of React Native's `View` component. Renders calendar week cells and provides flexibility through a render prop for custom cell rendering. <> @@ -292,7 +298,7 @@ Component for rendering calendar week cells. Supports custom rendering through t - (weekdays: string) => React.ReactNode + (weekdays: string, index: number) => React.ReactNode - @@ -309,7 +315,7 @@ Component for rendering calendar week cells. Supports custom rendering through t ### CalendarGridDays -Component for rendering calendar day cells. Supports custom rendering through the render prop. +It inherits all the properties of React Native's `View` component. Renders calendar day cells and provides flexibility through a render prop for custom cell rendering. <> @@ -353,8 +359,18 @@ Component for rendering calendar day cells. Supports custom rendering through th +### CalendarHeader + +It inherits all the properties of React Native's `View` component. + +### CalendarHeaderTitle + +It inherits all the properties of React Native's `Text` component. + ### CalendarHeaderPrev & CalendarHeaderNext +It inherits all the properties of React Native's `Pressable` component. + <> @@ -394,4 +410,54 @@ Component for rendering calendar day cells. Supports custom rendering through th
- \ No newline at end of file + + +### Examples + +The Examples section provides visual representations of the different variants of the component, allowing you to quickly and easily determine which one best fits your needs. Simply copy the code and integrate it into your project. + +### Calendar with Custom Renderer +Here is a complete example of how to use the `Calendar` component with its `render` prop to customize the appearance of the calendar. + + + + + + + + + + + ( + + {day?.getDate()} + + )} + /> + +
+ `, + transformCode: (code) => { + return transformedCode(code); + }, + scope: { Calendar, CalendarHeader, CalendarHeaderPrev, CalendarHeaderNext, CalendarHeaderTitle, CalendarGrid, CalendarGridWeek, CalendarGridDays, Wrapper, Pressable, Text }, + argsType: {}, + }} + /> + \ No newline at end of file diff --git a/packages/unstyled/calendar/README.md b/packages/unstyled/calendar/README.md index df81660426..52963b67fa 100644 --- a/packages/unstyled/calendar/README.md +++ b/packages/unstyled/calendar/README.md @@ -1,9 +1,9 @@ -# @gluestack-style/input +# @gluestack-style/calendar ## Installation -To use `@gluestack-ui/input`, all you need to do is install the -`@gluestack-ui/input` package: +To use `@gluestack-ui/calendar`, all you need to do is install the +`@gluestack-ui/calendar` package: ```sh $ yarn add @gluestack-ui/calendar @@ -12,50 +12,3 @@ $ yarn add @gluestack-ui/calendar $ npm i @gluestack-ui/calendar ``` - -## Usage - -The Input component is your go-to tool for gathering user input in a sleek and user-friendly text field. Whether you're designing a simple login form or a complex search feature, this component has got you covered. Here's an example how to use this package to create one: - -```jsx -import { Root, Input } from '../components/core/input/styled-components'; -import { createInput } from '@gluestack-ui/input'; -const InputField = createInput({ - Root, - Input, -}); -``` - -## Customizing the input: - -Default styling of all these components can be found in the components/core/input file. For reference, you can view the [source code](https://github.com/gluestack/gluestack-ui/blob/development/example/storybook/src/ui-components/Input/index.tsx) of the styled `input` components. - -```jsx -// import the styles -import { Root, Input } from '../components/core/input/styled-components'; - -// import the createInput function -import { createInput } from '@gluestack-ui/input'; - -//import any icon -import { searchIcon } from '@gluestack/icons'; - -// Understanding the API -const InputField = createInput({ - Root, - Input, -}); - -// Using the input component -export default () => ( - - - - - - -); -``` - -More guides on how to get started are available -[here](https://ui.gluestack.io/docs/components/forms/input). From fcc84d66c808baf08c93ba4b1bc732210710cccd Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Wed, 8 Jan 2025 19:44:30 +0530 Subject: [PATCH 07/11] fix: code refactor --- .../src/core-components/nativewind/calendar/index.tsx | 11 +++++++---- .../core-components/nativewind/calendar/styles.tsx | 10 +++++----- packages/unstyled/calendar/src/CalendarGridDays.tsx | 3 +-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx index 9098a57b89..6a79e88255 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx @@ -109,7 +109,7 @@ const CalendarHeaderPrev = React.forwardRef< {...props} className={calendarNavStyle({ class: className })} > - + ); }); @@ -124,7 +124,7 @@ const CalendarHeaderNext = React.forwardRef< {...props} className={calendarNavStyle({ class: className })} > - + ); }); @@ -201,16 +201,19 @@ const CalendarGridDays = React.forwardRef< {...props} className={calendarGridDaysStyle({ class: className })} render={ - render || + render ?? ((day, dayProps) => { return ( - {day?.getDate()} + + {day?.getDate()} + ); }) diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx index 8530174d2e..32705dfbe1 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx @@ -5,7 +5,7 @@ export const calendarStyle = tva({ }); export const calendarNavStyle = tva({ - base: 'w-6 h-6 p-1 flex items-center justify-center rounded-full data-[hover=true]:bg-typography-100 data-[active=true]:bg-typography-200 data-[disabled=true]:opacity-40 data-[disabled=true]:cursor-not-allowed', + base: 'w-6 h-6 p-1 flex items-center justify-center rounded-full data-[hover=true]:bg-background-100 data-[active=true]:bg-background-200 data-[disabled=true]:opacity-40 data-[disabled=true]:cursor-not-allowed', }); export const calendarTitleStyle = tva({ @@ -13,7 +13,7 @@ export const calendarTitleStyle = tva({ }); export const calendarHeaderStyle = tva({ - base: 'flex flex-row w-full justify-between items-center px-4 py-2 border-b border-typography-200', + base: 'flex flex-row w-full justify-between items-center px-4 py-2 border-b border-outline-200', }); export const calendarGridWeekStyle = tva({ @@ -25,17 +25,17 @@ export const calendarGridDaysStyle = tva({ }); export const calendarDaysCellStyle = tva({ - base: 'w-[14.28%] p-2 flex items-center justify-center rounded-lg', + base: 'w-[15.15%] p-2 m-0.5 flex items-center justify-center rounded-lg', variants: { hasDay: { - true: 'cursor-pointer data-[today=true]:bg-primary-50 data-[selected=true]:data-[disabled=false]:bg-primary-50 data-[active=true]:data-[disabled=false]:bg-primary-50 data-[hover=true]:data-[disabled=false]:bg-primary-0 data-[disabled=true]:text-typography-300 data-[disabled=true]:cursor-not-allowed', + true: 'cursor-pointer data-[today=true]:bg-background-100 data-[selected=true]:data-[disabled=false]:bg-background-500 data-[active=true]:data-[disabled=false]:bg-background-500 data-[hover=true]:data-[disabled=false]:bg-background-50 data-[disabled=true]:cursor-not-allowed group', false: 'cursor-default', }, }, }); export const calendarWeekCellStyle = tva({ - base: 'w-[14.28%] p-2 aspect-square flex items-center justify-center text-typography-500 font-medium', + base: 'w-[14.28%] p-2 flex items-center justify-center text-typography-500 font-medium', }); export const calendarGridStyle = tva({ diff --git a/packages/unstyled/calendar/src/CalendarGridDays.tsx b/packages/unstyled/calendar/src/CalendarGridDays.tsx index f0216dc059..a63de1fb41 100644 --- a/packages/unstyled/calendar/src/CalendarGridDays.tsx +++ b/packages/unstyled/calendar/src/CalendarGridDays.tsx @@ -22,8 +22,7 @@ export const CalendarGridDays = (StyledCalendarGridDays: any) => {days.map((day, index) => ( handleDateSelect(day)} states={{ From c0635632c0663a7eb954fd9012d9d17336586e9a Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Thu, 9 Jan 2025 11:11:23 +0530 Subject: [PATCH 08/11] fix: remove styles for active state --- .../nativewind/calendar/styles.tsx | 2 +- packages/unstyled/calendar/src/Pressable.tsx | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx index 32705dfbe1..93d7594ebf 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx @@ -28,7 +28,7 @@ export const calendarDaysCellStyle = tva({ base: 'w-[15.15%] p-2 m-0.5 flex items-center justify-center rounded-lg', variants: { hasDay: { - true: 'cursor-pointer data-[today=true]:bg-background-100 data-[selected=true]:data-[disabled=false]:bg-background-500 data-[active=true]:data-[disabled=false]:bg-background-500 data-[hover=true]:data-[disabled=false]:bg-background-50 data-[disabled=true]:cursor-not-allowed group', + true: 'cursor-pointer data-[today=true]:bg-background-100 data-[selected=true]:data-[disabled=false]:bg-background-500 data-[hover=true]:data-[disabled=false]:bg-background-50 data-[disabled=true]:cursor-not-allowed group', false: 'cursor-default', }, }, diff --git a/packages/unstyled/calendar/src/Pressable.tsx b/packages/unstyled/calendar/src/Pressable.tsx index 094a57be18..be0bde2d5f 100644 --- a/packages/unstyled/calendar/src/Pressable.tsx +++ b/packages/unstyled/calendar/src/Pressable.tsx @@ -6,12 +6,11 @@ import { composeEventHandlers } from '@gluestack-ui/utils'; const Pressable = forwardRef( ( { - isDisabled = false, + isDisabled: isDisabledProp = false, isPressed: isPressedProp, isHovered: isHoveredProp, isFocused: isFocusedProp, isFocusVisible: isFocusVisibleProp, - children, StyledComponent, onPress, states: statesProp, @@ -23,7 +22,7 @@ const Pressable = forwardRef( const { isHovered, hoverProps } = useHover(); const { isPressed, pressProps } = usePress({ onPress, - isDisabled, + isDisabled: isDisabledProp, }); const { isFocused, focusProps } = useFocus(); const { isFocusVisible, focusProps: focusRingProps }: any = useFocusRing(); @@ -32,7 +31,7 @@ const Pressable = forwardRef( hover: isHoveredProp || isHovered, focus: isFocusedProp || isFocused, active: isPressedProp || isPressed, - disabled: isDisabled, + disabled: isDisabledProp, focusVisible: isFocusVisibleProp || isFocusVisible, }; @@ -40,7 +39,7 @@ const Pressable = forwardRef( hover: isHoveredProp || isHovered, focus: isFocusedProp || isFocused, active: isPressedProp || isPressed, - disabled: isDisabled, + disabled: isDisabledProp, focusVisible: isFocusVisibleProp || isFocusVisible, }; @@ -48,6 +47,7 @@ const Pressable = forwardRef( - {children} - + /> ); } ); From 764f6168e40066f8771d8cb4357624119f08e4f8 Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Thu, 9 Jan 2025 17:56:07 +0530 Subject: [PATCH 09/11] feat: api rename and restructure --- .../src/components/Calendar/Calendar.tsx | 34 ++-- .../components/Calendar/index.nw.stories.mdx | 160 ++++++++++++++---- .../nativewind/calendar/index.tsx | 130 ++++++++------ .../nativewind/calendar/styles.tsx | 12 +- .../{CalendarGrid.tsx => CalendarContent.tsx} | 6 +- .../unstyled/calendar/src/CalendarDate.tsx | 119 +++++++++++++ .../unstyled/calendar/src/CalendarDays.tsx | 24 +++ .../calendar/src/CalendarGridDays.tsx | 43 ----- .../calendar/src/CalendarGridWeek.tsx | 11 -- .../calendar/src/CalendarHeaderNext.tsx | 98 ++++++++--- .../calendar/src/CalendarHeaderPrev.tsx | 96 +++++++++-- .../unstyled/calendar/src/CalendarWeek.tsx | 14 ++ packages/unstyled/calendar/src/Pressable.tsx | 83 --------- packages/unstyled/calendar/src/index.tsx | 49 +++--- packages/unstyled/calendar/src/types.ts | 65 +++---- 15 files changed, 593 insertions(+), 351 deletions(-) rename packages/unstyled/calendar/src/{CalendarGrid.tsx => CalendarContent.tsx} (50%) create mode 100644 packages/unstyled/calendar/src/CalendarDate.tsx create mode 100644 packages/unstyled/calendar/src/CalendarDays.tsx delete mode 100644 packages/unstyled/calendar/src/CalendarGridDays.tsx delete mode 100644 packages/unstyled/calendar/src/CalendarGridWeek.tsx create mode 100644 packages/unstyled/calendar/src/CalendarWeek.tsx delete mode 100644 packages/unstyled/calendar/src/Pressable.tsx diff --git a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx index 76daddb956..0b98ed3af0 100644 --- a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx +++ b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx @@ -1,15 +1,15 @@ import React from 'react'; import { Calendar, - CalendarGrid, - CalendarGridDays, - CalendarGridWeek, + CalendarContent, + CalendarDays, + CalendarWeek, CalendarHeader, CalendarHeaderNext, CalendarHeaderPrev, CalendarHeaderTitle, } from '@/components/ui/calendar'; -import { Text } from '@/components/ui/text'; +// import { Text } from '@/components/ui/text'; import { Pressable } from '@/components/ui/pressable'; import { cssInterop } from 'nativewind'; @@ -34,20 +34,20 @@ const CalendarBasic = ({ ...props }: any) => { - - - ( - - {day?.getDate()} - - )} + + + ( + // + // {day?.getDate()} + // + // )} /> - +
); }; diff --git a/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx index 0fc5327825..ff2c9d59eb 100644 --- a/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx +++ b/example/storybook-nativewind/src/components/Calendar/index.nw.stories.mdx @@ -21,10 +21,11 @@ CalendarHeader, CalendarHeaderNext, CalendarHeaderPrev, CalendarHeaderTitle, -CalendarGrid, -CalendarGridWeek, -CalendarGridDays, +CalendarContent, +CalendarWeek, +CalendarDays, Pressable, +Box, Text } from '../../core-components/nativewind'; import { AppProvider, @@ -38,7 +39,7 @@ import { transformedCode } from '../../utils'; import Wrapper from '../../core-components/nativewind/Wrapper'; import { CollapsibleCode } from '@gluestack/design-system'; -# Calendar +This is an illustration of **Calendar** component. ( - - - - + + + +
); ``` @@ -263,11 +264,11 @@ It inherits all the properties of React Native's `View` component. -### CalendarGrid +### CalendarContent It inherits all the properties of React Native's `View` component. -### CalendarGridWeek +### CalendarWeek It inherits all the properties of React Native's `View` component. Renders calendar week cells and provides flexibility through a render prop for custom cell rendering. @@ -298,7 +299,7 @@ It inherits all the properties of React Native's `View` component. Renders calen - (weekdays: string, index: number) => React.ReactNode + {`({weekday: string}) => React.ReactNode`} - @@ -313,7 +314,7 @@ It inherits all the properties of React Native's `View` component. Renders calen -### CalendarGridDays +### CalendarDays It inherits all the properties of React Native's `View` component. Renders calendar day cells and provides flexibility through a render prop for custom cell rendering. @@ -345,7 +346,7 @@ It inherits all the properties of React Native's `View` component. Renders calen - (day: Date | null, dayProps: any) => React.ReactNode + {`({day: Date | null, dayProps: any}) => React.ReactNode`} - @@ -359,6 +360,57 @@ It inherits all the properties of React Native's `View` component. Renders calen +### CalendarDate + +A pressable component used for rendering individual date cells within `CalendarDays`. This component is used by default when no custom render function is provided to `CalendarDays` by the user. + +It inherits all the properties of React Native's `Pressable` component and handles states like selected, disabled, today, etc. + +```jsx +import { CalendarDate } from '@/components/ui/calendar'; +``` + +<> + + + + + + Prop + + + Type + + + Default + + + Description + + + + + + + + date + + + + Date | null + + + - + + + The date to be displayed + + + +
+
+ + ### CalendarHeader It inherits all the properties of React Native's `View` component. @@ -416,7 +468,7 @@ It inherits all the properties of React Native's `Pressable` component. The Examples section provides visual representations of the different variants of the component, allowing you to quickly and easily determine which one best fits your needs. Simply copy the code and integrate it into your project. -### Calendar with Custom Renderer +#### Calendar with Custom Renderer Here is a complete example of how to use the `Calendar` component with its `render` prop to customize the appearance of the calendar. @@ -426,38 +478,80 @@ Here is a complete example of how to use the `Calendar` component with its `rend metaData={{ code: ` console.log(day)} > - - - ( - - {day?.getDate()} - - )} + + + ( + + {day?.getDate()} + + )} /> - + `, transformCode: (code) => { return transformedCode(code); }, - scope: { Calendar, CalendarHeader, CalendarHeaderPrev, CalendarHeaderNext, CalendarHeaderTitle, CalendarGrid, CalendarGridWeek, CalendarGridDays, Wrapper, Pressable, Text }, + scope: { Calendar, CalendarHeader, CalendarHeaderPrev, CalendarHeaderNext, CalendarHeaderTitle, CalendarContent, CalendarWeek, CalendarDays, Wrapper, Pressable, Text }, argsType: {}, }} /> - \ No newline at end of file + + +#### Default Usage with CalendarDate +The default implementation uses `CalendarDate` internally: + +```jsx + + + + + + +``` + +#### Custom Implementation with CalendarDate +You can provide your own implementation while still using `CalendarDate`. + +```jsx + ( + + {/* Custom content inside CalendarDate */} + {day?.getDate()} + + )} +/> +``` + +#### Custom Implementation +Or create a completely custom date cell: + +```jsx + ( + + {day?.getDate()} + + )} +/> +``` \ No newline at end of file diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx index 6a79e88255..305eab572e 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx @@ -12,14 +12,14 @@ import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon'; import { VariantProps } from '@gluestack-ui/nativewind-utils/types'; import { calendarStyle, - calendarGridStyle, - calendarGridWeekStyle, - calendarGridDaysStyle, + calendarContentStyle, + calendarWeekStyle, + calendarDaysStyle, calendarHeaderStyle, calendarNavStyle, calendarTitleStyle, calendarWeekCellStyle, - calendarDaysCellStyle, + calendarDateStyle, } from './styles'; import { ChevronRight, ChevronLeft } from 'lucide-react-native'; @@ -41,9 +41,10 @@ const UICalendar = createCalendar({ HeaderTitle: RNText, HeaderNext: RNPressable, Header: RNView, - GridWeek: RNView, - GridDays: RNView, - Grid: RNView, + Week: RNView, + Days: RNView, + Content: RNView, + Date: RNPressable, }); cssInterop(PrimitiveIcon, { @@ -62,20 +63,20 @@ cssInterop(PrimitiveIcon, { type ICalendarProps = React.ComponentPropsWithoutRef & VariantProps; -type ICalendarGridProps = React.ComponentPropsWithoutRef< - typeof UICalendar.Grid +type ICalendarContentProps = React.ComponentPropsWithoutRef< + typeof UICalendar.Content > & - VariantProps; + VariantProps; -type ICalendarGridWeekProps = React.ComponentPropsWithoutRef< - typeof UICalendar.GridWeek +type ICalendarWeekProps = React.ComponentPropsWithoutRef< + typeof UICalendar.Week > & - VariantProps; + VariantProps; -type ICalendarGridDaysProps = React.ComponentPropsWithoutRef< - typeof UICalendar.GridDays +type ICalendarDaysProps = React.ComponentPropsWithoutRef< + typeof UICalendar.Days > & - VariantProps; + VariantProps; type ICalendarHeaderProps = React.ComponentPropsWithoutRef< typeof UICalendar.Header @@ -97,6 +98,11 @@ type ICalendarHeaderTitleProps = React.ComponentPropsWithoutRef< > & VariantProps; +type ICalendarDateProps = React.ComponentPropsWithoutRef< + typeof UICalendar.Date +> & + VariantProps; + /** Components */ const CalendarHeaderPrev = React.forwardRef< @@ -155,35 +161,32 @@ const CalendarHeader = React.forwardRef< ); }); -const CalendarGrid = React.forwardRef< - React.ElementRef, - ICalendarGridProps +const CalendarContent = React.forwardRef< + React.ElementRef, + ICalendarContentProps >(({ className, ...props }, ref) => { return ( - ); }); -const CalendarGridWeek = React.forwardRef< - React.ElementRef, - ICalendarGridWeekProps +const CalendarWeek = React.forwardRef< + React.ElementRef, + ICalendarWeekProps >(({ className, ...props }, ref) => { return ( - { + className={calendarWeekStyle({ class: className })} + render={({ weekday }: any) => { return ( - - {day} + + {weekday} ); }} @@ -191,30 +194,43 @@ const CalendarGridWeek = React.forwardRef< ); }); -const CalendarGridDays = React.forwardRef< - React.ElementRef, - ICalendarGridDaysProps +const CalendarDate = React.forwardRef< + React.ElementRef, + ICalendarDateProps +>(({ className, day, ...props }, ref) => { + return ( + + ); +}); + +const CalendarDays = React.forwardRef< + React.ElementRef, + ICalendarDaysProps >(({ className, render, ...props }, ref) => { return ( - { + (({ day, ...dayProps }: any) => { return ( - + {day?.getDate()} - + ); }) } @@ -245,10 +261,10 @@ const Calendar = React.forwardRef< - - - - + + + +
); }); @@ -258,9 +274,10 @@ CalendarHeaderPrev.displayName = 'CalendarHeaderPrev'; CalendarHeaderNext.displayName = 'CalendarHeaderNext'; CalendarHeaderTitle.displayName = 'CalendarHeaderTitle'; CalendarHeader.displayName = 'CalendarHeader'; -CalendarGrid.displayName = 'CalendarGrid'; -CalendarGridWeek.displayName = 'CalendarGridWeek'; -CalendarGridDays.displayName = 'CalendarGridDays'; +CalendarContent.displayName = 'CalendarContent'; +CalendarWeek.displayName = 'CalendarWeek'; +CalendarDays.displayName = 'CalendarDays'; +CalendarDate.displayName = 'CalendarDate'; export { Calendar, @@ -268,7 +285,8 @@ export { CalendarHeaderNext, CalendarHeaderTitle, CalendarHeader, - CalendarGrid, - CalendarGridWeek, - CalendarGridDays, + CalendarContent, + CalendarWeek, + CalendarDays, + CalendarDate, }; diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx index 93d7594ebf..42696b3142 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx @@ -1,7 +1,7 @@ import { tva } from '@gluestack-ui/nativewind-utils/tva'; export const calendarStyle = tva({ - base: 'flex flex-col border border-outline-200 rounded-lg', + base: 'flex flex-col border border-outline-200 rounded-lg bg-background-0', }); export const calendarNavStyle = tva({ @@ -16,19 +16,19 @@ export const calendarHeaderStyle = tva({ base: 'flex flex-row w-full justify-between items-center px-4 py-2 border-b border-outline-200', }); -export const calendarGridWeekStyle = tva({ +export const calendarWeekStyle = tva({ base: 'flex-row flex-wrap', }); -export const calendarGridDaysStyle = tva({ +export const calendarDaysStyle = tva({ base: 'flex-row flex-wrap', }); -export const calendarDaysCellStyle = tva({ +export const calendarDateStyle = tva({ base: 'w-[15.15%] p-2 m-0.5 flex items-center justify-center rounded-lg', variants: { hasDay: { - true: 'cursor-pointer data-[today=true]:bg-background-100 data-[selected=true]:data-[disabled=false]:bg-background-500 data-[hover=true]:data-[disabled=false]:bg-background-50 data-[disabled=true]:cursor-not-allowed group', + true: 'cursor-pointer data-[today=true]:bg-background-100 data-[selected=true]:data-[disabled=false]:bg-background-500 data-[active=true]:bg-background-500 data-[hover=true]:data-[disabled=false]:bg-background-50 data-[disabled=true]:cursor-not-allowed group', false: 'cursor-default', }, }, @@ -38,6 +38,6 @@ export const calendarWeekCellStyle = tva({ base: 'w-[14.28%] p-2 flex items-center justify-center text-typography-500 font-medium', }); -export const calendarGridStyle = tva({ +export const calendarContentStyle = tva({ base: 'flex-col p-2', }); diff --git a/packages/unstyled/calendar/src/CalendarGrid.tsx b/packages/unstyled/calendar/src/CalendarContent.tsx similarity index 50% rename from packages/unstyled/calendar/src/CalendarGrid.tsx rename to packages/unstyled/calendar/src/CalendarContent.tsx index e4c3e37ff1..8973f74242 100644 --- a/packages/unstyled/calendar/src/CalendarGrid.tsx +++ b/packages/unstyled/calendar/src/CalendarContent.tsx @@ -1,10 +1,10 @@ import React, { forwardRef } from 'react'; -export const CalendarGrid = (StyledCalendarGrid: any) => +export const CalendarContent = (StyledCalendarContent: any) => forwardRef(({ children, ...props }: any, ref?: any) => { return ( - + {children} - + ); }); diff --git a/packages/unstyled/calendar/src/CalendarDate.tsx b/packages/unstyled/calendar/src/CalendarDate.tsx new file mode 100644 index 0000000000..d398ac1912 --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarDate.tsx @@ -0,0 +1,119 @@ +import { useFocusRing, useFocus } from '@react-native-aria/focus'; +import React, { forwardRef } from 'react'; +import type { PressableProps } from 'react-native'; +import { useHover, usePress } from '@react-native-aria/interactions'; +import { composeEventHandlers } from '@gluestack-ui/utils'; +import { useCalendarContext } from './Context'; + +export const CalendarDate = (StyledCalendarDate: React.ComponentType) => + forwardRef( + ( + { + children, + states: externalStates, + dataSet: externalDataSet, + day, + ...props + }: Omit & { + states?: any; + dataSet?: any; + day: Date | null; + children?: + | (({ + hovered, + pressed, + focused, + focusVisible, + disabled, + }: { + hovered?: boolean; + pressed?: boolean; + focused?: boolean; + focusVisible?: boolean; + disabled?: boolean; + }) => React.ReactNode) + | React.ReactNode; + }, + ref?: any + ) => { + const { handleDateSelect, isToday, selectedDate, isDisabled } = + useCalendarContext(); + const { focusProps: focusRingProps, isFocusVisible }: any = + useFocusRing(); + const { pressProps, isPressed } = usePress({}); + const { isFocused, focusProps } = useFocus(); + const { isHovered, hoverProps }: any = useHover(); + + const isSameDate = (date: Date | null): boolean => { + if (!date) return false; + return date.getTime() === selectedDate?.getTime(); + }; + return ( + // @ts-ignore + handleDateSelect(day))} + // @ts-ignore - web only + onHoverIn={composeEventHandlers( + props?.onHoverIn, + hoverProps.onHoverIn + )} + // @ts-ignore - web only + onHoverOut={composeEventHandlers( + props?.onHoverOut, + hoverProps.onHoverOut + )} + // @ts-ignore - web only + onFocus={composeEventHandlers( + composeEventHandlers(props?.onFocus, focusProps.onFocus), + focusRingProps.onFocus + )} + // @ts-ignore - web only + onBlur={composeEventHandlers( + composeEventHandlers(props?.onBlur, focusProps.onBlur), + focusRingProps.onBlur + )} + > + {typeof children === 'function' + ? children({ + hovered: isHovered, + focused: isFocused, + pressed: isPressed, + disabled: props.disabled ?? undefined, + focusVisible: isFocusVisible, + }) + : children} + + ); + } + ); diff --git a/packages/unstyled/calendar/src/CalendarDays.tsx b/packages/unstyled/calendar/src/CalendarDays.tsx new file mode 100644 index 0000000000..ac87fe5ee4 --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarDays.tsx @@ -0,0 +1,24 @@ +import React, { forwardRef } from 'react'; +import { useCalendarContext } from './Context'; + +export const CalendarDays = (StyledCalendarDays: any) => + forwardRef(({ render, ...props }: any, ref?: any) => { + const { getDaysInMonth } = useCalendarContext(); + const days = getDaysInMonth(); + + return ( + + {days.map((day, index) => { + const dayProps = {}; + const Day = render; + return ( + + ); + })} + + ); + }); diff --git a/packages/unstyled/calendar/src/CalendarGridDays.tsx b/packages/unstyled/calendar/src/CalendarGridDays.tsx deleted file mode 100644 index a63de1fb41..0000000000 --- a/packages/unstyled/calendar/src/CalendarGridDays.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, { forwardRef } from 'react'; -import CommonPressable from './Pressable'; -import { useCalendarContext } from './Context'; - -export const CalendarGridDays = (StyledCalendarGridDays: any) => - forwardRef(({ render, ...props }: any, ref?: any) => { - const { - getDaysInMonth, - handleDateSelect, - isToday, - selectedDate, - isDisabled, - } = useCalendarContext(); - const days = getDaysInMonth(); - - const isSameDate = (date1: Date, date2: Date): boolean => { - if (!date1 || !date2) return false; - return date1.getTime() === date2.getTime(); - }; - - return ( - - {days.map((day, index) => ( - handleDateSelect(day)} - states={{ - today: isToday(day), - selected: day && selectedDate && isSameDate(day, selectedDate), - disabled: isDisabled(day), - }} - dataSet={{ - today: isToday(day) ? 'true' : 'false', - selected: day && selectedDate && isSameDate(day, selectedDate), - disabled: isDisabled(day), - }} - StyledComponent={(dayProps: any) => render(day, dayProps)} - /> - ))} - - ); - }); diff --git a/packages/unstyled/calendar/src/CalendarGridWeek.tsx b/packages/unstyled/calendar/src/CalendarGridWeek.tsx deleted file mode 100644 index a97522484c..0000000000 --- a/packages/unstyled/calendar/src/CalendarGridWeek.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React, { forwardRef } from 'react'; -import { useCalendarContext } from './Context'; -export const CalendarGridWeek = (StyledCalendarGridWeek: any) => - forwardRef(({ render, ...props }: any, ref?: any) => { - const { weekDays } = useCalendarContext(); - return ( - - {weekDays.map((weekday, index) => render?.(weekday, index))} - - ); - }); diff --git a/packages/unstyled/calendar/src/CalendarHeaderNext.tsx b/packages/unstyled/calendar/src/CalendarHeaderNext.tsx index cb9f8e93a2..74ec059428 100644 --- a/packages/unstyled/calendar/src/CalendarHeaderNext.tsx +++ b/packages/unstyled/calendar/src/CalendarHeaderNext.tsx @@ -1,23 +1,81 @@ import React, { forwardRef } from 'react'; -import CommonPressable from './Pressable'; +import { useHover, usePress } from '@react-native-aria/interactions'; +import { useFocus, useFocusRing } from '@react-native-aria/focus'; +import { composeEventHandlers } from '@gluestack-ui/utils'; import { useCalendarContext } from './Context'; - export const CalendarHeaderNext = (StyledCalendarHeaderNext: any) => - forwardRef(({ isDisabled, ...props }: any, ref?: any) => { - const { isNextDisabled, nextMonth } = useCalendarContext(); - const handlePress = () => { - if (!isDisabled && !isNextDisabled) { - nextMonth(); - } - }; - - return ( - - ); - }); + forwardRef( + ( + { + isDisabled, + isPressed: isPressedProp, + isHovered: isHoveredProp, + isFocused: isFocusedProp, + isFocusVisible: isFocusVisibleProp, + ...props + }: any, + ref?: any + ) => { + const { isNextDisabled, nextMonth } = useCalendarContext(); + const handlePress = () => { + if (!isDisabled && !isNextDisabled) { + nextMonth(); + } + }; + const { isHovered, hoverProps }: any = useHover(); + const { isPressed, pressProps } = usePress({ + onPress: handlePress, + isDisabled: isDisabled || isNextDisabled, + }); + const { isFocused, focusProps } = useFocus(); + const { isFocusVisible, focusProps: focusRingProps }: any = + useFocusRing(); + return ( + + ); + } + ); diff --git a/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx b/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx index a97f4837d6..8145cfb997 100644 --- a/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx +++ b/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx @@ -1,22 +1,82 @@ import React, { forwardRef } from 'react'; -import CommonPressable from './Pressable'; +import { useHover, usePress } from '@react-native-aria/interactions'; +import { useFocus, useFocusRing } from '@react-native-aria/focus'; +import { composeEventHandlers } from '@gluestack-ui/utils'; import { useCalendarContext } from './Context'; export const CalendarHeaderPrev = (StyledCalendarHeaderPrev: any) => - forwardRef(({ isDisabled, ...props }: any, ref?: any) => { - const { isPrevDisabled, prevMonth } = useCalendarContext(); - const handlePress = () => { - if (!isDisabled && !isPrevDisabled) { - prevMonth(); - } - }; - return ( - - ); - }); + forwardRef( + ( + { + isDisabled, + isPressed: isPressedProp, + isHovered: isHoveredProp, + isFocused: isFocusedProp, + isFocusVisible: isFocusVisibleProp, + ...props + }: any, + ref?: any + ) => { + const { isPrevDisabled, prevMonth } = useCalendarContext(); + const handlePress = () => { + if (!isDisabled && !isPrevDisabled) { + prevMonth(); + } + }; + const { isHovered, hoverProps }: any = useHover(); + const { isPressed, pressProps } = usePress({ + onPress: handlePress, + isDisabled: isDisabled || isPrevDisabled, + }); + const { isFocused, focusProps } = useFocus(); + const { isFocusVisible, focusProps: focusRingProps }: any = + useFocusRing(); + return ( + + ); + } + ); diff --git a/packages/unstyled/calendar/src/CalendarWeek.tsx b/packages/unstyled/calendar/src/CalendarWeek.tsx new file mode 100644 index 0000000000..531b32c2d6 --- /dev/null +++ b/packages/unstyled/calendar/src/CalendarWeek.tsx @@ -0,0 +1,14 @@ +import React, { forwardRef } from 'react'; +import { useCalendarContext } from './Context'; +export const CalendarWeek = (StyledCalendarWeek: any) => + forwardRef(({ render, ...props }: any, ref?: any) => { + const { weekDays } = useCalendarContext(); + return ( + + {weekDays.map((weekday, index) => { + const Weekday = render; + return ; + })} + + ); + }); diff --git a/packages/unstyled/calendar/src/Pressable.tsx b/packages/unstyled/calendar/src/Pressable.tsx deleted file mode 100644 index be0bde2d5f..0000000000 --- a/packages/unstyled/calendar/src/Pressable.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React, { forwardRef } from 'react'; -import { useHover, usePress } from '@react-native-aria/interactions'; -import { useFocus, useFocusRing } from '@react-native-aria/focus'; -import { composeEventHandlers } from '@gluestack-ui/utils'; - -const Pressable = forwardRef( - ( - { - isDisabled: isDisabledProp = false, - isPressed: isPressedProp, - isHovered: isHoveredProp, - isFocused: isFocusedProp, - isFocusVisible: isFocusVisibleProp, - StyledComponent, - onPress, - states: statesProp, - dataSet: dataSetProp, - ...props - }: any, - ref?: any - ) => { - const { isHovered, hoverProps } = useHover(); - const { isPressed, pressProps } = usePress({ - onPress, - isDisabled: isDisabledProp, - }); - const { isFocused, focusProps } = useFocus(); - const { isFocusVisible, focusProps: focusRingProps }: any = useFocusRing(); - - const defaultStates = { - hover: isHoveredProp || isHovered, - focus: isFocusedProp || isFocused, - active: isPressedProp || isPressed, - disabled: isDisabledProp, - focusVisible: isFocusVisibleProp || isFocusVisible, - }; - - const defaultDataSet = { - hover: isHoveredProp || isHovered, - focus: isFocusedProp || isFocused, - active: isPressedProp || isPressed, - disabled: isDisabledProp, - focusVisible: isFocusVisibleProp || isFocusVisible, - }; - - return ( - - ); - } -); - -export default Pressable; diff --git a/packages/unstyled/calendar/src/index.tsx b/packages/unstyled/calendar/src/index.tsx index cf9e5ac377..33160cb6fd 100644 --- a/packages/unstyled/calendar/src/index.tsx +++ b/packages/unstyled/calendar/src/index.tsx @@ -3,9 +3,10 @@ import { CalendarHeaderPrev } from './CalendarHeaderPrev'; import { CalendarHeaderTitle } from './CalendarHeaderTitle'; import { CalendarHeaderNext } from './CalendarHeaderNext'; import { CalendarHeader } from './CalendarHeader'; -import { CalendarGridWeek } from './CalendarGridWeek'; -import { CalendarGridDays } from './CalendarGridDays'; -import { CalendarGrid } from './CalendarGrid'; +import { CalendarWeek } from './CalendarWeek'; +import { CalendarDays } from './CalendarDays'; +import { CalendarDate } from './CalendarDate'; +import { CalendarContent } from './CalendarContent'; import { Calendar as CalendarMain } from './Calendar'; import type { ICalendarComponentType } from './types'; @@ -15,45 +16,50 @@ export function createCalendar< CalendarHeaderTitle, CalendarHeaderNext, CalendarHeader, - CalendarGridWeek, - CalendarGridDays, - CalendarGrid + CalendarWeek, + CalendarDays, + CalendarContent, + CalendarDate >({ Root, HeaderPrev, HeaderTitle, HeaderNext, Header, - GridWeek, - GridDays, - Grid, + Week, + Days, + Content, + Date, }: { Root: React.ComponentType; HeaderPrev: React.ComponentType; HeaderTitle: React.ComponentType; HeaderNext: React.ComponentType; Header: React.ComponentType; - GridWeek: React.ComponentType; - GridDays: React.ComponentType; - Grid: React.ComponentType; + Week: React.ComponentType; + Days: React.ComponentType; + Content: React.ComponentType; + Date: React.ComponentType; }) { const Calendar = CalendarMain(Root) as any; Calendar.HeaderPrev = CalendarHeaderPrev(HeaderPrev); Calendar.HeaderTitle = CalendarHeaderTitle(HeaderTitle); Calendar.HeaderNext = CalendarHeaderNext(HeaderNext); Calendar.Header = CalendarHeader(Header); - Calendar.GridWeek = CalendarGridWeek(GridWeek); - Calendar.GridDays = CalendarGridDays(GridDays); - Calendar.Grid = CalendarGrid(Grid); + Calendar.Week = CalendarWeek(Week); + Calendar.Days = CalendarDays(Days); + Calendar.Content = CalendarContent(Content); + Calendar.Date = CalendarDate(Date); Calendar.displayName = 'Calendar'; Calendar.HeaderPrev.displayName = 'Calendar.HeaderPrev'; Calendar.HeaderTitle.displayName = 'Calendar.HeaderTitle'; Calendar.HeaderNext.displayName = 'Calendar.HeaderNext'; Calendar.Header.displayName = 'Calendar.Header'; - Calendar.GridWeek.displayName = 'Calendar.GridWeek'; - Calendar.GridDays.displayName = 'Calendar.GridDays'; - Calendar.Grid.displayName = 'Calendar.Grid'; + Calendar.Week.displayName = 'Calendar.Week'; + Calendar.Days.displayName = 'Calendar.Days'; + Calendar.Content.displayName = 'Calendar.Content'; + Calendar.Date.displayName = 'Calendar.Date'; return Calendar as ICalendarComponentType< Calendar, @@ -61,8 +67,9 @@ export function createCalendar< CalendarHeaderTitle, CalendarHeaderNext, CalendarHeader, - CalendarGridWeek, - CalendarGridDays, - CalendarGrid + CalendarWeek, + CalendarDays, + CalendarContent, + CalendarDate >; } diff --git a/packages/unstyled/calendar/src/types.ts b/packages/unstyled/calendar/src/types.ts index 36045f7724..126cb86836 100644 --- a/packages/unstyled/calendar/src/types.ts +++ b/packages/unstyled/calendar/src/types.ts @@ -27,7 +27,7 @@ export interface ICalendarProps { children?: React.ReactNode; } -export interface ICalendarHeaderNavProps { +export interface ICalendarNavProps { /** * If true, the button will be in pressed state. */ @@ -50,40 +50,25 @@ export interface ICalendarHeaderNavProps { isDisabled?: boolean; } -export interface ICalendarGridWeekProps { +export interface ICalendarWeekProps { /** - * Render method for custom day rendering + * Render method for custom week rendering */ - render?: (weekdays: string, index: number) => React.ReactNode; + render?: ({ weekday }: { [key: string]: any }) => React.ReactNode; } -export interface ICalendarDayProps { - /** - * The day number or null for empty cells - */ - day: Date | null; - /** - * When true, indicates this day is selected - */ - isSelected?: boolean; - /** - * When true, indicates this is today's date - */ - isToday?: boolean; +export interface ICalendarDaysProps { /** - * When true, indicates this day cannot be selected - */ - isDisabled?: boolean; - /** - * Handler for when the day is pressed + * Render method for custom day rendering */ + render?: ({ day, ...dayProps }: { [key: string]: any }) => React.ReactNode; } -export interface ICalendarGridDaysProps { +export interface ICalendarDateProps { /** - * Render method for custom day rendering + * The date to be displayed */ - render?: (days: Date | null, dayProps: any) => React.ReactNode; + day: Date | null; } export interface ICalendarContextValue { @@ -148,9 +133,10 @@ export type ICalendarComponentType< HeaderPrev, HeaderTitle, HeaderNext, - GridWeek, - GridDays, - Grid + Week, + Days, + Content, + Date > = React.ForwardRefExoticComponent< PropsWithoutRef & RefAttributes & ICalendarProps > & { @@ -158,25 +144,24 @@ export type ICalendarComponentType< PropsWithoutRef
& RefAttributes
>; HeaderPrev: React.ForwardRefExoticComponent< - PropsWithoutRef & - RefAttributes & - ICalendarHeaderNavProps + PropsWithoutRef & RefAttributes & ICalendarNavProps >; HeaderNext: React.ForwardRefExoticComponent< - PropsWithoutRef & - RefAttributes & - ICalendarHeaderNavProps + PropsWithoutRef & RefAttributes & ICalendarNavProps >; HeaderTitle: React.ForwardRefExoticComponent< PropsWithoutRef & RefAttributes >; - Grid: React.ForwardRefExoticComponent< - PropsWithoutRef & RefAttributes + Content: React.ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes + >; + Week: React.ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes & ICalendarWeekProps >; - GridWeek: React.ForwardRefExoticComponent< - PropsWithoutRef & RefAttributes & ICalendarGridWeekProps + Days: React.ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes & ICalendarDaysProps >; - GridDays: React.ForwardRefExoticComponent< - PropsWithoutRef & RefAttributes & ICalendarGridDaysProps + Date: React.ForwardRefExoticComponent< + PropsWithoutRef & RefAttributes & ICalendarDateProps >; }; From f101c3994580f38a24c9d95dc9dc392d1f7c5d43 Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Thu, 9 Jan 2025 18:36:15 +0530 Subject: [PATCH 10/11] feat: dependency json update --- .../src/core-components/nativewind/dependencies.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/storybook-nativewind/src/core-components/nativewind/dependencies.json b/example/storybook-nativewind/src/core-components/nativewind/dependencies.json index 5db25292bc..9b600cbea1 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/dependencies.json +++ b/example/storybook-nativewind/src/core-components/nativewind/dependencies.json @@ -59,7 +59,7 @@ "card": { "dependencies": {} }, - "center": { + "calendar": { "dependencies": {} }, "checkbox": { @@ -234,5 +234,5 @@ "hooks": ["useBreakpointValue"] } }, - "IgnoredComponents": ["bottomsheet", "image-viewer"] + "IgnoredComponents": ["bottomsheet", "image-viewer", "calendar"] } From a9270a7c180b48f05b7e3fdb1c12a0749e254e1e Mon Sep 17 00:00:00 2001 From: Vaibhavi Kolloju Date: Thu, 23 Jan 2025 12:42:11 +0530 Subject: [PATCH 11/11] feat: functionality and grid update --- .../src/components/Calendar/Calendar.tsx | 22 +-- .../nativewind/calendar/index.tsx | 8 +- .../nativewind/calendar/styles.tsx | 19 ++- example/storybook-v7/package.json | 1 + example/storybook-v7/yarn.lock | 43 ++---- packages/unstyled/calendar/README.md | 61 +++++++++ packages/unstyled/calendar/package.json | 3 +- packages/unstyled/calendar/src/Calendar.tsx | 95 ++++++------- .../unstyled/calendar/src/CalendarContent.tsx | 7 +- .../unstyled/calendar/src/CalendarDate.tsx | 12 ++ .../unstyled/calendar/src/CalendarDays.tsx | 7 +- .../unstyled/calendar/src/CalendarHeader.tsx | 7 +- .../calendar/src/CalendarHeaderNext.tsx | 6 + .../calendar/src/CalendarHeaderPrev.tsx | 6 + .../calendar/src/CalendarHeaderTitle.tsx | 10 +- .../unstyled/calendar/src/CalendarWeek.tsx | 7 +- yarn.lock | 129 +++++++++--------- 17 files changed, 259 insertions(+), 184 deletions(-) diff --git a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx index 0b98ed3af0..bed75f0f63 100644 --- a/example/storybook-nativewind/src/components/Calendar/Calendar.tsx +++ b/example/storybook-nativewind/src/components/Calendar/Calendar.tsx @@ -9,16 +9,6 @@ import { CalendarHeaderPrev, CalendarHeaderTitle, } from '@/components/ui/calendar'; -// import { Text } from '@/components/ui/text'; -import { Pressable } from '@/components/ui/pressable'; -import { cssInterop } from 'nativewind'; - -// note: required for nativewind to work on Storybook -cssInterop(Pressable, { - className: { - target: 'style', - }, -}); const CalendarBasic = ({ ...props }: any) => { return ( @@ -36,17 +26,7 @@ const CalendarBasic = ({ ...props }: any) => { - ( - // - // {day?.getDate()} - // - // )} - /> + ); diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx index 305eab572e..7deefe7fec 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/index.tsx @@ -10,6 +10,7 @@ import { withStyleContext } from '@gluestack-ui/nativewind-utils/withStyleContex import { cssInterop } from 'nativewind'; import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon'; import { VariantProps } from '@gluestack-ui/nativewind-utils/types'; +import { ChevronRight, ChevronLeft } from 'lucide-react-native'; import { calendarStyle, calendarContentStyle, @@ -21,7 +22,6 @@ import { calendarWeekCellStyle, calendarDateStyle, } from './styles'; -import { ChevronRight, ChevronLeft } from 'lucide-react-native'; const SCOPE = 'CALENDAR'; @@ -115,7 +115,7 @@ const CalendarHeaderPrev = React.forwardRef< {...props} className={calendarNavStyle({ class: className })} > - + ); }); @@ -130,7 +130,7 @@ const CalendarHeaderNext = React.forwardRef< {...props} className={calendarNavStyle({ class: className })} > - + ); }); @@ -227,7 +227,7 @@ const CalendarDays = React.forwardRef< (({ day, ...dayProps }: any) => { return ( - + {day?.getDate()} diff --git a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx index 42696b3142..e5bd09d737 100644 --- a/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx +++ b/example/storybook-nativewind/src/core-components/nativewind/calendar/styles.tsx @@ -1,11 +1,12 @@ import { tva } from '@gluestack-ui/nativewind-utils/tva'; +import { isWeb } from '@gluestack-ui/nativewind-utils/IsWeb'; export const calendarStyle = tva({ base: 'flex flex-col border border-outline-200 rounded-lg bg-background-0', }); export const calendarNavStyle = tva({ - base: 'w-6 h-6 p-1 flex items-center justify-center rounded-full data-[hover=true]:bg-background-100 data-[active=true]:bg-background-200 data-[disabled=true]:opacity-40 data-[disabled=true]:cursor-not-allowed', + base: 'w-6 h-6 p-1 flex items-center justify-center rounded-lg border border-outline-200 data-[hover=true]:bg-background-100 data-[active=true]:bg-background-200 data-[disabled=true]:opacity-40 data-[disabled=true]:cursor-not-allowed', }); export const calendarTitleStyle = tva({ @@ -17,27 +18,31 @@ export const calendarHeaderStyle = tva({ }); export const calendarWeekStyle = tva({ - base: 'flex-row flex-wrap', + base: isWeb ? 'grid grid-cols-7' : 'flex flex-row w-full', }); export const calendarDaysStyle = tva({ - base: 'flex-row flex-wrap', + base: isWeb ? 'grid grid-cols-7' : 'flex flex-row flex-wrap', }); export const calendarDateStyle = tva({ - base: 'w-[15.15%] p-2 m-0.5 flex items-center justify-center rounded-lg', + base: `m-0.5 flex items-center justify-center rounded-lg aspect-square ${ + isWeb ? 'col-span-1' : 'basis-[12.6%]' + }`, variants: { hasDay: { - true: 'cursor-pointer data-[today=true]:bg-background-100 data-[selected=true]:data-[disabled=false]:bg-background-500 data-[active=true]:bg-background-500 data-[hover=true]:data-[disabled=false]:bg-background-50 data-[disabled=true]:cursor-not-allowed group', + true: 'cursor-pointer data-[today=true]:bg-background-100 data-[selected=true]:data-[disabled=false]:bg-background-800 data-[active=true]:bg-background-500 data-[hover=true]:data-[disabled=false]:bg-background-50 data-[disabled=true]:cursor-not-allowed group', false: 'cursor-default', }, }, }); export const calendarWeekCellStyle = tva({ - base: 'w-[14.28%] p-2 flex items-center justify-center text-typography-500 font-medium', + base: `m-0.5 flex items-center justify-center text-xs text-center text-typography-500 font-medium aspect-square ${ + isWeb ? 'col-span-1' : 'basis-[12.6%]' + }`, }); export const calendarContentStyle = tva({ - base: 'flex-col p-2', + base: `flex flex-col p-2`, }); diff --git a/example/storybook-v7/package.json b/example/storybook-v7/package.json index 8860fdbbf1..90893f8191 100644 --- a/example/storybook-v7/package.json +++ b/example/storybook-v7/package.json @@ -28,6 +28,7 @@ "@react-native-community/datetimepicker": "8.0.1", "@react-native-community/slider": "4.5.2", "autoprefixer": "^10.4.19", + "date-fns": "^4.1.0", "eas-cli": "^9.0.7", "expo": "^51.0.8", "expo-constants": "~16.0.1", diff --git a/example/storybook-v7/yarn.lock b/example/storybook-v7/yarn.lock index fa7b6bacf0..83d53284aa 100644 --- a/example/storybook-v7/yarn.lock +++ b/example/storybook-v7/yarn.lock @@ -7342,6 +7342,11 @@ data-view-byte-offset@^1.0.0: es-errors "^1.3.0" is-data-view "^1.0.1" +date-fns@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14" + integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg== + dateformat@4.6.3: version "4.6.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" @@ -11663,7 +11668,7 @@ postcss@^8.4.23, postcss@^8.4.33, postcss@~8.4.32: picocolors "^1.0.0" source-map-js "^1.2.0" -"prettier-fallback@npm:prettier@^3": +"prettier-fallback@npm:prettier@^3", prettier@^3.1.1: version "3.2.5" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== @@ -11673,11 +11678,6 @@ prettier@^2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -prettier@^3.1.1: - version "3.2.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" - integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== - pretty-bytes@5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" @@ -12970,16 +12970,7 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -13039,7 +13030,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -13053,13 +13044,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -14117,16 +14101,7 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@7.0.0, wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@7.0.0, wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== diff --git a/packages/unstyled/calendar/README.md b/packages/unstyled/calendar/README.md index 52963b67fa..c8f229f356 100644 --- a/packages/unstyled/calendar/README.md +++ b/packages/unstyled/calendar/README.md @@ -12,3 +12,64 @@ $ yarn add @gluestack-ui/calendar $ npm i @gluestack-ui/calendar ``` + +## Usage + +The Calendar component is designed for date selection with support for both single date and range selection. It provides a user-friendly interface for date picking with accessibility features built-in. Here's an example of how to use this package to create an : + +```jsx +import { View, Text, Pressable } from 'react-native'; +import { createCalendar } from '@gluestack-ui/calendar'; + +const Calendar = createCalendar({ + Root: View, + HeaderPrev: Pressable, + HeaderTitle: Text, + HeaderNext: Pressable, + Header: View, + Week: View, + Days: View, + Content: View, + Date: Pressable, +}); +``` + +## Customizing the calendar: + +Default styling of all these components can be found in the components/core/calendar file. For reference, you can view the [source code](https://github.com/gluestack/gluestack-ui/blob/development/example/storybook/src/ui-components/Calendar/index.tsx) of the styled `calendar` components. + +```jsx +import { View, Text, Pressable } from 'react-native'; +import { createCalendar } from '@gluestack-ui/calendar'; + +// Understanding the API +const Calendar = createCalendar({ + Root: View, + HeaderPrev: Pressable, + HeaderTitle: Text, + HeaderNext: Pressable, + Header: View, + Week: View, + Days: View, + Content: View, + Date: Pressable, +}); + +// Using the calendar component +export default () => ( + + + + + + + + + + + +); +``` + +More guides on how to get started are available +[here](https://ui.gluestack.io/docs/components/forms/calendar). diff --git a/packages/unstyled/calendar/package.json b/packages/unstyled/calendar/package.json index dbc59ee581..b230047b7b 100644 --- a/packages/unstyled/calendar/package.json +++ b/packages/unstyled/calendar/package.json @@ -32,7 +32,8 @@ "dependencies": { "@gluestack-ui/utils": "^0.1.14", "@react-native-aria/focus": "^0.2.9", - "@react-native-aria/interactions": "0.2.13" + "@react-native-aria/interactions": "0.2.13", + "date-fns": "^4.1.0" }, "peerDependencies": { "react": ">=16", diff --git a/packages/unstyled/calendar/src/Calendar.tsx b/packages/unstyled/calendar/src/Calendar.tsx index ca9c3f4538..a57bda2095 100644 --- a/packages/unstyled/calendar/src/Calendar.tsx +++ b/packages/unstyled/calendar/src/Calendar.tsx @@ -1,22 +1,28 @@ import React, { forwardRef, useMemo, useCallback } from 'react'; import { CalendarContext } from './Context'; import type { ICalendarProps } from './types'; - -const WEEKDAYS = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; -const MONTHS = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December', -]; +import { + format, + addMonths, + subMonths, + isSameDay, + isWithinInterval, + startOfMonth, + getDaysInMonth as getMonthDays, + getDay, + eachDayOfInterval, + startOfWeek, + endOfWeek, +} from 'date-fns'; + +const WEEKDAYS = eachDayOfInterval({ + start: startOfWeek(new Date()), + end: endOfWeek(new Date()), +}).map((day: Date) => format(day, 'EEEEEE')); + +const MONTHS = Array.from({ length: 12 }, (_, i) => + format(new Date(2024, i, 1), 'MMMM') +); export function Calendar(StyledCalendar: any) { return forwardRef( @@ -42,35 +48,26 @@ export function Calendar(StyledCalendar: any) { const isDisabled = useCallback( (day: Date | null) => { if (!day) return false; - if (minDate && day < minDate) return true; - if (maxDate && day > maxDate) return true; + if (minDate && maxDate) { + return !isWithinInterval(day, { start: minDate, end: maxDate }); + } + if (minDate) return day < minDate; + if (maxDate) return day > maxDate; return false; }, [minDate, maxDate] ); const title = useMemo(() => { - return `${ - MONTHS[currentMonth.getMonth()] - } ${currentMonth.getFullYear()}`; + return format(currentMonth, 'MMMM yyyy'); }, [currentMonth]); const prevMonth = useCallback(() => { - const newDate = new Date( - currentMonth.getFullYear(), - currentMonth.getMonth() - 1, - 1 - ); - setCurrentMonth(newDate); + setCurrentMonth(subMonths(currentMonth, 1)); }, [currentMonth]); const nextMonth = useCallback(() => { - const newDate = new Date( - currentMonth.getFullYear(), - currentMonth.getMonth() + 1, - 1 - ); - setCurrentMonth(newDate); + setCurrentMonth(addMonths(currentMonth, 1)); }, [currentMonth]); const isPrevDisabled = useMemo(() => { @@ -92,19 +89,15 @@ export function Calendar(StyledCalendar: any) { }, [currentMonth, maxDate]); const getDaysInMonth = useCallback(() => { - const year = currentMonth.getFullYear(); - const month = currentMonth.getMonth(); - const daysInMonth = new Date(year, month + 1, 0).getDate(); - const firstDayOfMonth = new Date(year, month, 1).getDay(); + const firstDayOfMonth = getDay(startOfMonth(currentMonth)); + const daysInMonth = getMonthDays(currentMonth); - const days = []; - - for (let i = 0; i < firstDayOfMonth; i++) { - days.push(null); - } + const days = Array(firstDayOfMonth).fill(null); for (let i = 1; i <= daysInMonth; i++) { - days.push(new Date(year, month, i)); + days.push( + new Date(currentMonth.getFullYear(), currentMonth.getMonth(), i) + ); } return days; @@ -121,12 +114,7 @@ export function Calendar(StyledCalendar: any) { const isToday = useCallback((day: Date | null) => { if (!day) return false; - const today = new Date(); - return ( - today.getDate() === day.getDate() && - today.getMonth() === day.getMonth() && - today.getFullYear() === day.getFullYear() - ); + return isSameDay(day, new Date()); }, []); const contextValue = useMemo( @@ -161,7 +149,14 @@ export function Calendar(StyledCalendar: any) { ); return ( - + {children} diff --git a/packages/unstyled/calendar/src/CalendarContent.tsx b/packages/unstyled/calendar/src/CalendarContent.tsx index 8973f74242..ca13ec914b 100644 --- a/packages/unstyled/calendar/src/CalendarContent.tsx +++ b/packages/unstyled/calendar/src/CalendarContent.tsx @@ -3,7 +3,12 @@ import React, { forwardRef } from 'react'; export const CalendarContent = (StyledCalendarContent: any) => forwardRef(({ children, ...props }: any, ref?: any) => { return ( - + {children} ); diff --git a/packages/unstyled/calendar/src/CalendarDate.tsx b/packages/unstyled/calendar/src/CalendarDate.tsx index d398ac1912..835f074455 100644 --- a/packages/unstyled/calendar/src/CalendarDate.tsx +++ b/packages/unstyled/calendar/src/CalendarDate.tsx @@ -48,11 +48,14 @@ export const CalendarDate = (StyledCalendarDate: React.ComponentType) => if (!date) return false; return date.getTime() === selectedDate?.getTime(); }; + + const label = day ? day.toLocaleDateString() : 'empty cell'; return ( // @ts-ignore ) => composeEventHandlers(props?.onBlur, focusProps.onBlur), focusRingProps.onBlur )} + role="gridcell" + accessible + accessibilityLabel={label} + accessibilityElementsHidden={ + isDisabled || props.disabled || day === null + } + aria-selected={day ? isSameDate(day) : false} + aria-disabled={props.disabled || isDisabled(day) || day === null} + aria-label={label} > {typeof children === 'function' ? children({ diff --git a/packages/unstyled/calendar/src/CalendarDays.tsx b/packages/unstyled/calendar/src/CalendarDays.tsx index ac87fe5ee4..4ecf6e1dca 100644 --- a/packages/unstyled/calendar/src/CalendarDays.tsx +++ b/packages/unstyled/calendar/src/CalendarDays.tsx @@ -7,7 +7,12 @@ export const CalendarDays = (StyledCalendarDays: any) => const days = getDaysInMonth(); return ( - + {days.map((day, index) => { const dayProps = {}; const Day = render; diff --git a/packages/unstyled/calendar/src/CalendarHeader.tsx b/packages/unstyled/calendar/src/CalendarHeader.tsx index 4b7032ceee..4a26fdef7b 100644 --- a/packages/unstyled/calendar/src/CalendarHeader.tsx +++ b/packages/unstyled/calendar/src/CalendarHeader.tsx @@ -2,7 +2,12 @@ import React, { forwardRef } from 'react'; export const CalendarHeader = (StyledCalendarHeader: any) => forwardRef(({ children, ...props }: any, ref?: any) => { return ( - + {children} ); diff --git a/packages/unstyled/calendar/src/CalendarHeaderNext.tsx b/packages/unstyled/calendar/src/CalendarHeaderNext.tsx index 74ec059428..bd8295a5da 100644 --- a/packages/unstyled/calendar/src/CalendarHeaderNext.tsx +++ b/packages/unstyled/calendar/src/CalendarHeaderNext.tsx @@ -48,7 +48,13 @@ export const CalendarHeaderNext = (StyledCalendarHeaderNext: any) => focusVisible: isFocusVisibleProp || isFocusVisible ? 'true' : 'false', }} + role="button" + aria-label="Next month" + aria-disabled={isDisabled || isNextDisabled} + aria-selected={isPressedProp || isPressed} + accessibilityLabel="Next month" disabled={isDisabled} + accessibilityElementsHidden={isDisabled || isNextDisabled} onPressIn={composeEventHandlers( props?.onPressIn, pressProps.onPressIn diff --git a/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx b/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx index 8145cfb997..2d20b8c00a 100644 --- a/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx +++ b/packages/unstyled/calendar/src/CalendarHeaderPrev.tsx @@ -49,7 +49,13 @@ export const CalendarHeaderPrev = (StyledCalendarHeaderPrev: any) => focusVisible: isFocusVisibleProp || isFocusVisible ? 'true' : 'false', }} + role="button" + aria-label="Previous month" + aria-disabled={isDisabled || isPrevDisabled} + aria-selected={isPressedProp || isPressed} + accessibilityLabel="Previous month" disabled={isDisabled} + accessibilityElementsHidden={isDisabled || isPrevDisabled} onPressIn={composeEventHandlers( props?.onPressIn, pressProps.onPressIn diff --git a/packages/unstyled/calendar/src/CalendarHeaderTitle.tsx b/packages/unstyled/calendar/src/CalendarHeaderTitle.tsx index b03f28fe30..4354521ce7 100644 --- a/packages/unstyled/calendar/src/CalendarHeaderTitle.tsx +++ b/packages/unstyled/calendar/src/CalendarHeaderTitle.tsx @@ -4,7 +4,15 @@ export const CalendarHeaderTitle = (StyledCalendarHeaderTitle: any) => forwardRef(({ ...props }: any, ref?: any) => { const { title } = useCalendarContext(); return ( - + {title} ); diff --git a/packages/unstyled/calendar/src/CalendarWeek.tsx b/packages/unstyled/calendar/src/CalendarWeek.tsx index 531b32c2d6..202393aaa6 100644 --- a/packages/unstyled/calendar/src/CalendarWeek.tsx +++ b/packages/unstyled/calendar/src/CalendarWeek.tsx @@ -4,7 +4,12 @@ export const CalendarWeek = (StyledCalendarWeek: any) => forwardRef(({ render, ...props }: any, ref?: any) => { const { weekDays } = useCalendarContext(); return ( - + {weekDays.map((weekday, index) => { const Weekday = render; return ; diff --git a/yarn.lock b/yarn.lock index 352ac66d02..8d3a260f6d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9927,6 +9927,11 @@ data-view-byte-offset@^1.0.1: es-errors "^1.3.0" is-data-view "^1.0.1" +date-fns@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14" + integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg== + dayjs@^1.8.15: version "1.11.13" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" @@ -14995,73 +15000,73 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lightningcss-darwin-arm64@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.28.2.tgz#a906fd84cb43d753cb5db9c367f8f38482e8fb03" - integrity sha512-/8cPSqZiusHSS+WQz0W4NuaqFjquys1x+NsdN/XOHb+idGHJSoJ7SoQTVl3DZuAgtPZwFZgRfb/vd1oi8uX6+g== - -lightningcss-darwin-x64@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.28.2.tgz#6c43249d4ae821416d0d78403eae56111d0c6a94" - integrity sha512-R7sFrXlgKjvoEG8umpVt/yutjxOL0z8KWf0bfPT3cYMOW4470xu5qSHpFdIOpRWwl3FKNMUdbKtMUjYt0h2j4g== - -lightningcss-freebsd-x64@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.28.2.tgz#804bc6652c6721e94a92e7bbb5e65165376cf108" - integrity sha512-l2qrCT+x7crAY+lMIxtgvV10R8VurzHAoUZJaVFSlHrN8kRLTvEg9ObojIDIexqWJQvJcVVV3vfzsEynpiuvgA== - -lightningcss-linux-arm-gnueabihf@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.28.2.tgz#c32595127b565690d854c9ff641831e4ad739ee1" - integrity sha512-DKMzpICBEKnL53X14rF7hFDu8KKALUJtcKdFUCW5YOlGSiwRSgVoRjM97wUm/E0NMPkzrTi/rxfvt7ruNK8meg== - -lightningcss-linux-arm64-gnu@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.28.2.tgz#85646f08c5efbfd7c94f8e5ed6392d5cf95fa42c" - integrity sha512-nhfjYkfymWZSxdtTNMWyhFk2ImUm0X7NAgJWFwnsYPOfmtWQEapzG/DXZTfEfMjSzERNUNJoQjPAbdqgB+sjiw== - -lightningcss-linux-arm64-musl@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.28.2.tgz#4d9bc20cf6de28c4d0c586d81c577891555ad831" - integrity sha512-1SPG1ZTNnphWvAv8RVOymlZ8BDtAg69Hbo7n4QxARvkFVCJAt0cgjAw1Fox0WEhf4PwnyoOBaVH0Z5YNgzt4dA== - -lightningcss-linux-x64-gnu@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.28.2.tgz#74bd797d7157817c4e42ec45f1844a69636a9d82" - integrity sha512-ZhQy0FcO//INWUdo/iEdbefntTdpPVQ0XJwwtdbBuMQe+uxqZoytm9M+iqR9O5noWFaxK+nbS2iR/I80Q2Ofpg== - -lightningcss-linux-x64-musl@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.28.2.tgz#13ce6db4c491ebbb93099d6427746ab7bff3774f" - integrity sha512-alb/j1NMrgQmSFyzTbN1/pvMPM+gdDw7YBuQ5VSgcFDypN3Ah0BzC2dTZbzwzaMdUVDszX6zH5MzjfVN1oGuww== - -lightningcss-win32-arm64-msvc@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.28.2.tgz#eaae12c4a58a545a3adf40b22ba9625e5c0ebd29" - integrity sha512-WnwcjcBeAt0jGdjlgbT9ANf30pF0C/QMb1XnLnH272DQU8QXh+kmpi24R55wmWBwaTtNAETZ+m35ohyeMiNt+g== - -lightningcss-win32-x64-msvc@1.28.2: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.28.2.tgz#1f7c4474b2dc3dd1c12e22de32e4de23bdfa41e7" - integrity sha512-3piBifyT3avz22o6mDKywQC/OisH2yDK+caHWkiMsF82i3m5wDBadyCjlCQ5VNgzYkxrWZgiaxHDdd5uxsi0/A== +lightningcss-darwin-arm64@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.1.tgz#dce17349c7b9f968f396ec240503de14e7b4870b" + integrity sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw== + +lightningcss-darwin-x64@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.1.tgz#e79c984180c57d00ee114210ceced83473d72dfc" + integrity sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA== + +lightningcss-freebsd-x64@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.1.tgz#4b3aec9620684a60c45266d50fd843869320f42f" + integrity sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ== + +lightningcss-linux-arm-gnueabihf@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.1.tgz#b80e9c4dd75652bec451ffd4d5779492a01791ff" + integrity sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg== + +lightningcss-linux-arm64-gnu@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.1.tgz#7825eb119ddf580a4a4f011c6f384a3f9c992060" + integrity sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ== + +lightningcss-linux-arm64-musl@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.1.tgz#389efccf80088dce2bb00e28bd7d1cfe36a71669" + integrity sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw== + +lightningcss-linux-x64-gnu@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.1.tgz#98fc5df5e39ac8ddc51e51f785849eb21131f789" + integrity sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw== + +lightningcss-linux-x64-musl@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.1.tgz#fb4f80895ba7dfa8048ee32e9716a1684fefd6b2" + integrity sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw== + +lightningcss-win32-arm64-msvc@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.1.tgz#fd4409fd1505d89d0ff66511c36df5a1379eb7cd" + integrity sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog== + +lightningcss-win32-x64-msvc@1.29.1: + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.1.tgz#54dcd52884f6cbf205a53d49239559603f194927" + integrity sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q== lightningcss@^1.27.0: - version "1.28.2" - resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.28.2.tgz#cc26fad9ad64a621bd39ac6248095891cf584cce" - integrity sha512-ePLRrbt3fgjXI5VFZOLbvkLD5ZRuxGKm+wJ3ujCqBtL3NanDHPo/5zicR5uEKAPiIjBYF99BM4K4okvMznjkVA== + version "1.29.1" + resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.29.1.tgz#1d4d62332fc5ba4b6c28e04a8c5638c76019702b" + integrity sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q== dependencies: detect-libc "^1.0.3" optionalDependencies: - lightningcss-darwin-arm64 "1.28.2" - lightningcss-darwin-x64 "1.28.2" - lightningcss-freebsd-x64 "1.28.2" - lightningcss-linux-arm-gnueabihf "1.28.2" - lightningcss-linux-arm64-gnu "1.28.2" - lightningcss-linux-arm64-musl "1.28.2" - lightningcss-linux-x64-gnu "1.28.2" - lightningcss-linux-x64-musl "1.28.2" - lightningcss-win32-arm64-msvc "1.28.2" - lightningcss-win32-x64-msvc "1.28.2" + lightningcss-darwin-arm64 "1.29.1" + lightningcss-darwin-x64 "1.29.1" + lightningcss-freebsd-x64 "1.29.1" + lightningcss-linux-arm-gnueabihf "1.29.1" + lightningcss-linux-arm64-gnu "1.29.1" + lightningcss-linux-arm64-musl "1.29.1" + lightningcss-linux-x64-gnu "1.29.1" + lightningcss-linux-x64-musl "1.29.1" + lightningcss-win32-arm64-msvc "1.29.1" + lightningcss-win32-x64-msvc "1.29.1" lilconfig@2.1.0: version "2.1.0"