Skip to content

Commit

Permalink
Merge branch 'main' into update-gh-actions
Browse files Browse the repository at this point in the history
  • Loading branch information
aditya-67 committed Aug 25, 2024
2 parents e176656 + 5a83b38 commit daab232
Show file tree
Hide file tree
Showing 10 changed files with 672 additions and 490 deletions.
779 changes: 472 additions & 307 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fictoan-react",
"version": "1.2.8",
"version": "1.2.9",
"private": false,
"description": "",
"type": "module",
Expand Down
10 changes: 1 addition & 9 deletions src/components/ThemeProvider/ThemeProvider.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,6 @@ type Story = StoryObj<typeof ThemeProvider>;

export const Default: Story = {
args: {
theme: {
"paragraph-font-size": "4rem",
"card-bg": "var(--sky-light-80)",
"global-border-radius": "16px",
},
customColors: {
"peach": "#ff9e9e",
},
currentTheme: "light",
},
render: (args) => (
Expand All @@ -37,5 +29,5 @@ export const Default: Story = {
<Text className="text-peach">Change the theme!</Text>
</Card>
</ThemeProvider>
)
),
};
118 changes: 44 additions & 74 deletions src/components/ThemeProvider/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,102 +1,72 @@
import React, { useEffect, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";

import { Element } from "../Element/Element";
import type { UseThemeProps } from "./types";
import { CommonAndHTMLProps } from "../Element/constants";

export type ThemeProviderElementType = HTMLDivElement;
export type RenderProps = () => JSX.Element;

const storageKey = "fictoan-theme";
const themes = ["light", "dark"];

const ThemeContext = React.createContext<UseThemeProps | undefined>(undefined);
const defaultContext: UseThemeProps = { setTheme: (_) => {} };

export const useTheme = () => React.useContext(ThemeContext) ?? defaultContext;

export interface ThemeProviderProps extends CommonAndHTMLProps<ThemeProviderElementType> {
theme?: {
[key: string]: string;
};
customColors?: {
[key: string]: string;
};
currentTheme?: string;
}

const getTheme = (key: string, fallback?: string) => {
let theme;
try {
theme = localStorage.getItem(key) || undefined;
} catch (e) {
// Unsupported
}
return theme || fallback;
};

export const ThemeProvider = React.forwardRef(
(
{ theme, customColors, currentTheme, children, ...props }: ThemeProviderProps,
ref: React.Ref<ThemeProviderElementType>
) => {
({ currentTheme, children, ...props }: ThemeProviderProps, ref: React.Ref<ThemeProviderElementType>) => {
const [shouldRender, setShouldRender] = useState<boolean>(false);
const [themeState, setThemeState] = React.useState(() => getTheme(storageKey, "theme-light"));

useEffect(() => {
if (theme) {
const styleTag = getStyleTag("fictoan-theme");
addCssVariables(styleTag, theme);
if (!shouldRender) {
setShouldRender(true);
const setTheme = useCallback(
(newTheme: any) => {
if (!themes.includes(newTheme)) {
newTheme = "light";
}
}

return () => {
const styleTag = getStyleTag("fictoan-theme");
styleTag.innerHTML = "";
};
}, [theme]);

useEffect(() => {
if (customColors) {
const styleTag = getStyleTag("fictoan-custom-colors");
addCssVariables(styleTag, customColors);
const styles = Object.keys(customColors).map(
(colorName) => `
.bg-${colorName} {background-color: var(--${colorName});}
.text-${colorName} {color: var(--${colorName}); }
.fill-${colorName} {fill: var(--${colorName});}
.stroke-${colorName} {stroke: var(--${colorName});}
.border-${colorName} {border-color: var(--${colorName});}`
);
styleTag.appendChild(document.createTextNode(styles.join("\n")));
document.documentElement.className = "";
setThemeState(`theme-${newTheme}`);
document.documentElement.classList.add(`theme-${newTheme}`);
if (!shouldRender) {
setShouldRender(true);
}
}

return () => {
const styleTag = getStyleTag("fictoan-custom-colors");
styleTag.innerHTML = "";
};
}, [customColors]);
// Save to storage
try {
localStorage.setItem(storageKey, `theme-${newTheme}`);
} catch (e) {
// Unsupported
}
},
[themeState]
);

useEffect(() => {
if (currentTheme) {
document.documentElement.classList.add(currentTheme);
if (!shouldRender) {
setShouldRender(true);
}
setTheme(currentTheme);
}

return () => {
document.documentElement.className = "";
};
}, [currentTheme]);

const getStyleTag = (id: string): HTMLElement => {
let styleTag = document.getElementById(id);
if (!styleTag) {
styleTag = document.createElement("style");
styleTag.id = id;
document.head.appendChild(styleTag);
}
return styleTag;
};

const addCssVariables = (element: HTMLElement, variables: { [key: string]: string }) => {
let cssVariables: string | string[] = Object.entries(variables).map(
([variableName, variableValue]) => `--${variableName}: ${variableValue};`
);
cssVariables = ":root {\n" + cssVariables.join("\n") + "\n}";
element.appendChild(document.createTextNode(cssVariables));
};

return (
<Element<ThemeProviderElementType> as="div" data-theme-provider ref={ref} {...props}>
{shouldRender && children}
</Element>
<ThemeContext.Provider value={{ theme: themeState, setTheme }}>
<Element<ThemeProviderElementType> as="div" data-theme-provider ref={ref} {...props}>
{shouldRender && children}
</Element>
</ThemeContext.Provider>
);
}
);
2 changes: 1 addition & 1 deletion src/components/ThemeProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { ThemeProvider, type ThemeProviderProps } from "./ThemeProvider";
export { ThemeProvider, type ThemeProviderProps, useTheme } from "./ThemeProvider";
8 changes: 8 additions & 0 deletions src/components/ThemeProvider/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as React from "react";

export interface UseThemeProps {
/** Update the theme */
setTheme: React.Dispatch<React.SetStateAction<string>>;
/** Active theme name */
theme?: string | undefined;
}
101 changes: 52 additions & 49 deletions src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ export { Drawer, type DrawerProps } from "./Drawer";
export { Button, type ButtonProps } from "./Button";

// BREADCRUMBS =========================================================================================================
export {
Breadcrumbs, type BreadcrumbsProps,
BreadcrumbItem, type BreadcrumbItemProps
} from "./Breadcrumbs";
export { Breadcrumbs, type BreadcrumbsProps, BreadcrumbItem, type BreadcrumbItemProps } from "./Breadcrumbs";

// CALLOUT =============================================================================================================
export { Callout, type CalloutProps } from "./Callout";
Expand All @@ -32,46 +29,52 @@ export { ContentWrapper, type ContentWrapperProps } from "./ContentWrapper";
export { Divider, type DividerProps } from "./Divider";

// ELEMENT =============================================================================================================
export {
Element, type ElementProps,
Div,
Article,
Aside,
Body,
Footer,
Header,
Main,
Nav,
Section
} from "./Element";
export { Element, type ElementProps, Div, Article, Aside, Body, Footer, Header, Main, Nav, Section } from "./Element";

// FORM ================================================================================================================
export {
Form, type FormProps,
FormItem, type FormItemProps,
FormItemGroup, type FormItemGroupProps,
InputField, type InputFieldProps,
TextArea, type TextareaProps,
InputLabel,type InputLabelProps,
Select, type SelectProps,
Form,
type FormProps,
FormItem,
type FormItemProps,
FormItemGroup,
type FormItemGroupProps,
InputField,
type InputFieldProps,
TextArea,
type TextareaProps,
InputLabel,
type InputLabelProps,
Select,
type SelectProps,
SelectWithSearch,
FileUpload,type FileUploadProps,
RadioGroup,type RadioGroupProps,
RadioButton, type RadioButtonProps,
Checkbox, type CheckboxProps,
Switch, type SwitchProps,
Range, type RangeProps,
RadioTabGroup, type RadioTabGroupProps,
PinInputField, type PinInputFieldProps,
FileUpload,
type FileUploadProps,
RadioGroup,
type RadioGroupProps,
RadioButton,
type RadioButtonProps,
Checkbox,
type CheckboxProps,
Switch,
type SwitchProps,
Range,
type RangeProps,
RadioTabGroup,
type RadioTabGroupProps,
PinInputField,
type PinInputFieldProps,
} from "./Form";

// METER ===============================================================================================================
export { Meter, type MeterProps, type MeterMetaProps } from "./Meter";

// NOTIFICATIONS =======================================================================================================
export {
NotificationsWrapper, type NotificationsWrapperProps,
NotificationItem, type NotificationItemProps
NotificationsWrapper,
type NotificationsWrapperProps,
NotificationItem,
type NotificationItemProps,
} from "./Notification";

// PORTION =============================================================================================================
Expand All @@ -89,34 +92,34 @@ export { useOptionCard } from "./OptionCard";

// SIDEBAR =============================================================================================================
export {
SidebarWrapper, type SidebarWrapperProps,
SidebarHeader, type SidebarHeaderProps,
SidebarItem, type SidebarItemProps,
SidebarItemIcon, type SidebarItemIconProps,
SidebarItemText, type SidebarItemTextProps,
SidebarFooter, type SidebarFooterProps
SidebarWrapper,
type SidebarWrapperProps,
SidebarHeader,
type SidebarHeaderProps,
SidebarItem,
type SidebarItemProps,
SidebarItemIcon,
type SidebarItemIconProps,
SidebarItemText,
type SidebarItemTextProps,
SidebarFooter,
type SidebarFooterProps,
} from "./Sidebar";

// SPINNER =============================================================================================================
export { Spinner, type SpinnerProps } from "./Spinner";

// TABLE ===============================================================================================================
export {
Table, type TableProps,
TablePagination, type TablePaginationProps
} from "./Table";
export { Table, type TableProps, TablePagination, type TablePaginationProps } from "./Table";

// TABS ================================================================================================================
export { Tabs, type TabsProps } from "./Tabs";

// THEME PROVIDER ======================================================================================================
export { ThemeProvider, type ThemeProviderProps } from "./ThemeProvider";
export { ThemeProvider, type ThemeProviderProps, useTheme } from "./ThemeProvider";

// TOAST ===============================================================================================================
export {
ToastsWrapper, type ToastsWrapperProps,
ToastItem, type ToastItemProps
} from "./Toast";
export { ToastsWrapper, type ToastsWrapperProps, ToastItem, type ToastItemProps } from "./Toast";

// TYPOGRAPHY ==========================================================================================================
export {
Expand All @@ -128,5 +131,5 @@ export {
Heading5,
Heading6,
type TextProps,
type HeadingProps
type HeadingProps,
} from "./Typography";
Loading

0 comments on commit daab232

Please sign in to comment.