Skip to content

Commit

Permalink
wip it doesn't work at all
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuruuh committed Feb 11, 2024
1 parent ee96a5a commit f5bbf49
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 43 deletions.
6 changes: 2 additions & 4 deletions src/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { useCallback, useState, type FC, type ReactNode } from 'react';
import {
CalendarContext,
type CalendarOverlap,
// type CalendarOverlap,
type CalendarState,
} from './context/CalendarContext';
import type { Setter } from './types/Setter';
// import type { Setter } from './types/Setter';
import { Weeks } from './components/Weeks';
import { Week } from './components/Week';
import { Day } from './components/Day';
import day, { type Dayjs } from 'dayjs';
import { CalendarPlugin } from './plugin';

export interface CalendarProps {
// selectedDate: Dayjs | null;
Expand All @@ -26,7 +25,6 @@ const Calendar: FC<CalendarProps> = (props) => {
children,
// overlap = 'overlap',
// altDateFormat = 'dddd D MMMM YYYY',
plugins = [],
viewedDate,
dayjs = () => day(),
} = props;
Expand Down
5 changes: 2 additions & 3 deletions src/context/CalendarContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ export interface CalendarState {
// maximumSelectableDate: Dayjs;
// controls: CalendarControls;
// overlap: CalendarOverlap;
plugins: CalendarPlugins,
viewedDate: Dayjs;
setViewedDate: Setter<Dayjs>;
viewedDate?: Dayjs;
// setViewedDate: Setter<Dayjs>;
dayjs(): Dayjs;
// altDateFormat: string;
}
Expand Down
69 changes: 47 additions & 22 deletions src/hooks/useCalendar.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,60 @@
import { useMemo } from 'react';
import highlightRange from '../plugins/highlight-range';
import controls from '../plugins/controls';
import { CalendarPlugin } from '../plugin';
import { CalendarPlugin, CalendarPluginDefinition, CalendarPlugins } from '../plugin';
import { CalendarControls } from '../context/CalendarContext';
import { CalendarOptions, useCalendar } from './useCalendar';
import type { Dayjs } from 'dayjs';
import type { Setter } from '../types/Setter';

type Expect<Assertion extends true> = Assertion;
export type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <
T,
>() => T extends Y ? 1 : 2
type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
? 1
: 2
? true
: false;

// The plugin definition to be preserved
() => {
const plugins = useMemo(() => [highlightRange(), controls()] as const, []);

type _ = Expect<
Equals<
readonly [
CalendarPlugin<{
dayInnerProps: {
isOutOfRange: boolean;
};
}>,
CalendarPlugin<{
calendarInnerProps: {
controls: CalendarControls;
};
}>,
],
typeof plugins
>
>;
(): Equals<
readonly [
CalendarPlugin<{
dayInnerProps: {
isOutOfRange: boolean;
};
}>,
CalendarPlugin<{
rootConfiguration: {
viewedDate: Dayjs;
setViewedDate: Setter<Dayjs>;
};
calendarInnerProps: {
controls: CalendarControls;
};
}>,
],
typeof plugins
> => true;

const { calendar } = useCalendar({ plugins, setViewedDate: () => {} });

// type Prettify<T extends Record<PropertyKey, unknown>> = {
// [K in keyof T]: T[K];
// };

type Options = MergedPluginProps<typeof plugins, 'dayInnerProps'>;

return <calendar.Root>{({ dayjs }) => <p>hello world</p>}</calendar.Root>;
};

type MergedPluginProps<T extends CalendarPlugins, Key extends keyof CalendarPluginDefinition> = T extends [
infer First,
...infer Rest
]
? First extends CalendarPlugin<infer FirstProps>
? Rest extends CalendarPlugins
? FirstProps[Key] & MergedPluginProps<Rest, Key>
: FirstProps[Key]
: {}
: {};
90 changes: 86 additions & 4 deletions src/hooks/useCalendar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,93 @@
import type { CalendarPlugins } from '../plugin';
import { useMemo, type FC, ReactNode, useCallback } from 'react';
import type { CalendarPlugin, CalendarPlugins } from '../plugin';
import day, { type Dayjs } from 'dayjs';
import type { CalendarState } from '../context/CalendarContext';
import type { UnionToIntersection } from '../types/UnionToIntersection';

export interface Calendar<TPlugins extends CalendarPlugins> {
plugins: TPlugins;
calendar: {
Root: FC<CalendarProps<TPlugins>>;
};
}

export function useCalendar<const TPlugins extends CalendarPlugins>({
export type CalendarOptions< TPlugins extends CalendarPlugins> = {
plugins: TPlugins;
viewedDate?: Dayjs;
dayjs?: () => Dayjs;
} & (TPlugins[number] extends CalendarPlugin<infer U>
? U
: {});
// ? UnionToIntersection<U['rootConfiguration']> extends Record<string, unknown>
// ? UnionToIntersection<U['rootConfiguration']> extends undefined
// ? never
// : UnionToIntersection<U['rootConfiguration']>
// : never);
// : {});

export type CalendarProps<TPlugins extends CalendarPlugins> = {
children:
| ReactNode
| ((
props: CalendarState &
(TPlugins[number] extends CalendarPlugin<infer U>
? UnionToIntersection<U['calendarInnerProps']>
: never),
) => ReactNode);
};

export function useCalendar<
const TPlugins extends CalendarPlugins = readonly [],
>({
plugins,
}: { plugins: TPlugins }): Calendar<TPlugins> {
return { plugins };
dayjs = () => day(),
viewedDate,
...props
}: CalendarOptions<TPlugins>): Calendar<TPlugins> {
function RootComponent({ children }: CalendarProps<TPlugins>) {
const dayFactory = useCallback(
() => dayjs().utc(true).second(0).minute(0).hour(12),
[dayjs],
);

const baseState: CalendarState = {
dayjs,
viewedDate: viewedDate ?? dayFactory(),
...props,
};

const state = {
...baseState,
...plugins
.map((plugin) =>
plugin.calendarHook !== undefined
? plugin.calendarHook(baseState)
: {},
)
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
};

return (
<>{typeof children === 'function' ? children(state as any) : children}</>
);
}

// const Root = useMemo(() => RootComponent, [dayjs]);

return {
plugins,
calendar: {
Root: RootComponent,
},
};
}

// const plugins = [{} as CalendarPlugin<{dayInnerProps: {isOutOfRange: boolean}}>, {} as CalendarPlugin<{dayInnerProps: {isSomething: boolean}}>] as const;
// const {calendar} = useCalendar({plugins});
// ty
// const e = <calendar.Root>{(props) => <p>Hello</p>}</calendar.Root>
// type E = CalendarState & (typeof plugins)[number] extends CalendarPlugin<infer U> ? U['dayInnerProps'] : never;
// type UnionToIntersection<U> =
// (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never;

// type What = (typeof plugins)[number] extends CalendarPlugin<infer U> ? UnionToIntersection<U['dayInnerProps']> : false;
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type { CalendarProps } from './Calendar';
// export type { CalendarProps } from './Calendar';
export type { DayInnerProps } from './components/Day';
export type { WeeksInnerProps } from './components/Weeks';
export type { WeekContextState } from './context/WeekContext';
Expand All @@ -13,4 +13,4 @@ export type { CalendarPlugin, CalendarPluginDefinition } from './plugin';
export type { Setter } from './types/Setter';
export type { WeekNumber, WeekNumbers } from './types/WeekNumber';

export { default as Calendar } from './Calendar';
// export { default as Calendar } from './Calendar';
7 changes: 5 additions & 2 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import type { CalendarState } from './context/CalendarContext';
import type { DayContextState } from './context/DayContext';

export type CalendarPlugins = ReadonlyArray<
CalendarPlugin<Record<PropertyKey, unknown>>
CalendarPlugin<CalendarPluginDefinition>
>;

export interface CalendarPluginDefinition {
rootConfiguration?: Record<string, unknown>;
dayInnerProps?: Record<string, unknown>;
calendarInnerProps?: Record<string, unknown>;
}
Expand All @@ -18,5 +19,7 @@ export interface CalendarPlugin<T extends CalendarPluginDefinition> {
calendarState: CalendarState,
dayState: DayContextState,
): T['dayInnerProps'];
calendarHook?(calendarState: CalendarState): T['calendarInnerProps'];
calendarHook?(
calendarState: CalendarState & T['rootConfiguration'],
): T['calendarInnerProps'];
}
8 changes: 5 additions & 3 deletions src/plugins/controls.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Dayjs, ManipulateType } from 'dayjs';
import type { CalendarControls } from '../context/CalendarContext';
import type { CalendarPlugin } from '../plugin';
import { Setter } from '../types/Setter';

// import { HightlightRangePluginId } from './highlight-range';
// console.log(HightlightRangePluginId);
Expand Down Expand Up @@ -34,9 +35,10 @@ export function createControlFactory(
};
}

export default function (
_ = {},
): CalendarPlugin<{ calendarInnerProps: { controls: CalendarControls } }> {
export default function (_ = {}): CalendarPlugin<{
rootConfiguration: { viewedDate: Dayjs; setViewedDate: Setter<Dayjs> };
calendarInnerProps: { controls: CalendarControls };
}> {
return {
id: 'controls',
calendarHook(state): { controls: CalendarControls } {
Expand Down
3 changes: 1 addition & 2 deletions tsconfig.bun.jsonc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./tsconfig.json",
"compilerOptions": {
"skipLibCheck": true,
"module": "ESNext",
Expand All @@ -11,11 +12,9 @@
"@zuruuh/react-calendar": ["./src/"]
}
},
"include": ["src"],
"files": [
"build.ts",
"bootstrap.tsx",
".ladle/vite.config.ts",
"package.json",
"docs/.vitepress/config.ts"
]
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"noImplicitAny": true,
// "noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true
},
"include": ["src", ".ladle"]
}

0 comments on commit f5bbf49

Please sign in to comment.