From 9f8e3d6bd208a984b0b98f7a4196490e1bae6585 Mon Sep 17 00:00:00 2001 From: Taylor Bantle Date: Thu, 29 Feb 2024 10:09:14 -0800 Subject: [PATCH 1/3] coponents: Add tailwind provider, better types --- packages/components/.storybook/preview.tsx | 6 +-- .../components/src/Textarea/index.module.css | 8 ++- packages/components/src/Textarea/index.tsx | 4 +- packages/components/src/index.ts | 8 ++- packages/components/src/tailwind/Wrapper.tsx | 14 ----- .../src/tailwind/applyTheme/index.ts | 50 ----------------- .../src/tailwind/applyTheme/types.ts | 11 ---- .../src/tailwind/context/applyTheme.ts | 38 +++++++++++++ .../components/src/tailwind/context/index.tsx | 54 +++++++++++++++++++ .../components/src/tailwind/context/utils.ts | 9 ++++ .../src/tailwind/theme/base/colors.ts | 40 +++++++------- .../src/tailwind/theme/dolthub/colors.ts | 4 +- .../src/tailwind/theme/hosted/colors.ts | 10 ++-- .../src/tailwind/theme/workbench/colors.ts | 26 +++++++++ packages/components/src/tailwind/types.ts | 36 +++++++++++++ 15 files changed, 209 insertions(+), 109 deletions(-) delete mode 100644 packages/components/src/tailwind/Wrapper.tsx delete mode 100644 packages/components/src/tailwind/applyTheme/index.ts delete mode 100644 packages/components/src/tailwind/applyTheme/types.ts create mode 100644 packages/components/src/tailwind/context/applyTheme.ts create mode 100644 packages/components/src/tailwind/context/index.tsx create mode 100644 packages/components/src/tailwind/context/utils.ts create mode 100644 packages/components/src/tailwind/theme/workbench/colors.ts create mode 100644 packages/components/src/tailwind/types.ts diff --git a/packages/components/.storybook/preview.tsx b/packages/components/.storybook/preview.tsx index 36a0e11f..baf21e15 100644 --- a/packages/components/.storybook/preview.tsx +++ b/packages/components/.storybook/preview.tsx @@ -1,7 +1,7 @@ import { Preview } from "@storybook/react"; import React from "react"; import "../src/main.css"; -import ThemeWrapper from "../src/tailwind/Wrapper"; +import ThemeProvider from "../src/tailwind/context"; const preview: Preview = { parameters: { @@ -15,9 +15,9 @@ const preview: Preview = { }, decorators: [ Story => ( - + - + ), ], }; diff --git a/packages/components/src/Textarea/index.module.css b/packages/components/src/Textarea/index.module.css index bda8ee71..52b5e714 100644 --- a/packages/components/src/Textarea/index.module.css +++ b/packages/components/src/Textarea/index.module.css @@ -8,7 +8,11 @@ .mobileFriendly { @media (max-width: 640px) { - @apply border-t border-ld-lightgrey p-4 bg-white; + @apply border-t border-ld-lightgrey px-4 pt-3 mb-0 pb-4 bg-white; + + &:focus-within { + @apply bg-ld-lightpurple; + } } } @@ -42,7 +46,7 @@ @apply px-0 py-1 bg-white text-primary border-none; &:focus { - @apply bg-white outline outline-blue-300; + @apply bg-ld-lightpurple; } &:disabled { diff --git a/packages/components/src/Textarea/index.tsx b/packages/components/src/Textarea/index.tsx index d7741e8b..a983b74e 100644 --- a/packages/components/src/Textarea/index.tsx +++ b/packages/components/src/Textarea/index.tsx @@ -1,5 +1,5 @@ import cx from "classnames"; -import React, { forwardRef } from "react"; +import React, { ForwardedRef, forwardRef } from "react"; import css from "./index.module.css"; type Props = { @@ -30,7 +30,7 @@ const Textarea = ( mobileFriendly = false, ...textAreaProps }: Props, - ref: any, + ref: ForwardedRef, ) => (
{ - applyTheme(); - }, []); - - return props.children; -} diff --git a/packages/components/src/tailwind/applyTheme/index.ts b/packages/components/src/tailwind/applyTheme/index.ts deleted file mode 100644 index 2d4ac7b0..00000000 --- a/packages/components/src/tailwind/applyTheme/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { baseColorVariableValues } from "../theme/base/colors"; -import { IMappedTheme, ITheme } from "./types"; - -// Should be used to apply the theme to the root element of the app. Will use -// base colors in `theme/base/colors.ts` if no overrides are provided. -export default function applyTheme(tailwindColorOverrides?: ITheme) { - const themeObject: IMappedTheme = mapTheme( - tailwindColorOverrides - ? extend(baseColorVariableValues, tailwindColorOverrides) - : baseColorVariableValues, - ); - const root = document.documentElement; - - Object.keys(themeObject).forEach(property => { - if (property === "name") { - return; - } - const propertyVal = themeObject[property]; - const validation = validateRGB(propertyVal); - if (!validation) { - throw new Error(`Invalid RGB value for ${property}: ${propertyVal}`); - } - - root.style.setProperty(property, propertyVal); - }); -} - -function mapTheme(variables: ITheme): IMappedTheme { - return { - "--color-primary": variables["rgb-primary"] ?? "", - "--color-acc-1": variables["rgb-acc-1"] ?? "", - "--color-background-acc-1": variables["rgb-background-acc-1"] ?? "", - "--color-background-acc-start": variables["rgb-background-acc-start"] ?? "", - "--color-button-1": variables["rgb-button-1"] ?? "", - "--color-link-1": variables["rgb-link-1"] ?? "", - "--color-button-2": variables["rgb-button-2"] ?? "", - "--color-link-2": variables["rgb-link-2"] ?? "", - "--color-link-light": variables["rgb-link-light"] ?? "", - }; -} - -function extend(extending: ITheme, newTheme: ITheme): ITheme { - return { ...extending, ...newTheme }; -} - -function validateRGB(rgb: string | null): boolean { - if (!rgb) return true; - const rgbRegex = /^(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})$/; - return rgbRegex.test(rgb); -} diff --git a/packages/components/src/tailwind/applyTheme/types.ts b/packages/components/src/tailwind/applyTheme/types.ts deleted file mode 100644 index ca50efa9..00000000 --- a/packages/components/src/tailwind/applyTheme/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface ITheme { - [key: string]: string | undefined; -} - -export interface IThemes { - [key: string]: ITheme; -} - -export interface IMappedTheme { - [key: string]: string | null; -} diff --git a/packages/components/src/tailwind/context/applyTheme.ts b/packages/components/src/tailwind/context/applyTheme.ts new file mode 100644 index 00000000..f1412598 --- /dev/null +++ b/packages/components/src/tailwind/context/applyTheme.ts @@ -0,0 +1,38 @@ +import { IThemeRGB, IThemeVariables } from "../types"; + +// Should be used to apply the theme to the root element of the app. Will use +// base colors in `theme/base/colors.ts` if no overrides are provided. +export default function applyTheme(themeRGB: IThemeRGB) { + const themeObject: IThemeVariables = mapTheme(themeRGB); + const root = document.documentElement; + + Object.keys(themeObject).forEach(v => { + const propertyVal = themeObject[v as keyof IThemeVariables]; + const validation = validateRGB(propertyVal); + if (!validation) { + throw new Error(`Invalid RGB value for ${v}: ${propertyVal}`); + } + + root.style.setProperty(v, propertyVal); + }); +} + +function mapTheme(rgb: IThemeRGB): IThemeVariables { + return { + "--color-primary": rgb["rgb-primary"] ?? "", + "--color-acc-1": rgb["rgb-acc-1"] ?? "", + "--color-background-acc-1": rgb["rgb-background-acc-1"] ?? "", + "--color-background-acc-start": rgb["rgb-background-acc-start"] ?? "", + "--color-button-1": rgb["rgb-button-1"] ?? "", + "--color-link-1": rgb["rgb-link-1"] ?? "", + "--color-button-2": rgb["rgb-button-2"] ?? "", + "--color-link-2": rgb["rgb-link-2"] ?? "", + "--color-link-light": rgb["rgb-link-light"] ?? "", + }; +} + +function validateRGB(rgb: string): boolean { + if (!rgb) return true; + const rgbRegex = /^(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})$/; + return rgbRegex.test(rgb); +} diff --git a/packages/components/src/tailwind/context/index.tsx b/packages/components/src/tailwind/context/index.tsx new file mode 100644 index 00000000..bc4aabb6 --- /dev/null +++ b/packages/components/src/tailwind/context/index.tsx @@ -0,0 +1,54 @@ +import React, { createContext, useContext, useEffect } from "react"; +import { baseColorVariableValues } from "../theme/base/colors"; +import { IThemeColors, IThemeRGB } from "../types"; +import applyTheme from "./applyTheme"; +import { rgbToHex } from "./utils"; + +type Props = { + children: React.ReactNode; + themeRGBOverrides?: IThemeRGB; +}; + +type ThemeContextType = { + themeRGB: IThemeRGB; + convertThemeRGBToHex: () => IThemeColors; +}; + +const ThemeContext = createContext({ + themeRGB: baseColorVariableValues, + convertThemeRGBToHex: () => ({}), +}); + +// ThemedProvider applies tailwind theme default, potentially with provided overrides +export default function ThemeProvider(props: Props) { + const themeRGB: IThemeRGB = { + ...baseColorVariableValues, + ...(props.themeRGBOverrides ?? {}), + }; + + useEffect(() => { + applyTheme(themeRGB); + }, []); + + // Converts the theme from RGB to Hex + function convertThemeRGBToHex(): IThemeColors { + const hexThemeRGB: IThemeColors = {}; + Object.keys(themeRGB).forEach(key => { + const rgb = themeRGB[key as keyof IThemeRGB]; + if (!rgb) return ""; + const color = key.replace("rgb-", ""); + hexThemeRGB[color as keyof IThemeColors] = rgbToHex(rgb); + }); + return hexThemeRGB; + } + + return ( + + {props.children} + + ); +} + +export function useThemeContext() { + return useContext(ThemeContext); +} diff --git a/packages/components/src/tailwind/context/utils.ts b/packages/components/src/tailwind/context/utils.ts new file mode 100644 index 00000000..cc61a137 --- /dev/null +++ b/packages/components/src/tailwind/context/utils.ts @@ -0,0 +1,9 @@ +export function rgbToHex(rgb: string): string { + const [r, g, b] = rgb.split(", ").map(Number); + return `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`; +} + +function componentToHex(c: number): string { + var hex = c.toString(16); + return hex.length == 1 ? "0" + hex : hex; +} diff --git a/packages/components/src/tailwind/theme/base/colors.ts b/packages/components/src/tailwind/theme/base/colors.ts index 8112a308..0f3117ab 100644 --- a/packages/components/src/tailwind/theme/base/colors.ts +++ b/packages/components/src/tailwind/theme/base/colors.ts @@ -1,33 +1,36 @@ +import { IThemeColors, IThemeRGB } from "../../types"; + // TODO: Improve these names const staticColors = { - "acc-grey": "#b2c0c4", - "acc-red": "#ff9a99", - "acc-green": "#5ac58d", - "acc-lightgrey": "#c6cdd0", - "ld-darkgrey": "#95a3a7", - "ld-lightgrey": "#e1e5e7", - "ld-lightpurple": "#f1f3f8", - "ld-lightblue": "#f6f8f9", - "ld-darkergrey": "#384B52", + "ld-blue": "#6db0fc", "ld-darkerblue": "#1e2842", + "ld-darkergrey": "#384B52", "ld-darkestblue": "#182134", - "ld-blue": "#6db0fc", + "ld-darkgrey": "#95a3a7", "ld-green": "#5deda2", - "acc-linkblue": "#1f6dc6", - "acc-hoverlinkblue": "#3d91f0", - "acc-hoverblue": "#1d2c7f", + "ld-lightblue": "#f6f8f9", + "ld-lightgrey": "#e1e5e7", + "ld-lightpurple": "#f1f3f8", + + "acc-bright-green": "#29e3c1", + "acc-code": "#575662", "acc-darkgrey": "#5d6280", + "acc-green": "#5ac58d", + "acc-grey": "#b2c0c4", + "acc-hoverblue": "#1d2c7f", "acc-hovergreen": "#6fdda4", - "acc-lightgreen": "#d4f5e4", + "acc-hoverlinkblue": "#3d91f0", "acc-hoverred": "#fca8a7", - "acc-code": "#575662", + "acc-lightgreen": "#d4f5e4", + "acc-lightgrey": "#c6cdd0", + "acc-linkblue": "#1f6dc6", "acc-orange": "#ed8936", "acc-pink": "#d588d5", - "acc-bright-green": "#29e3c1", "acc-purple": "#805EDD", + "acc-red": "#ff9a99", }; -const configurableColors = { +const configurableColors: IThemeColors = { primary: withOpacity("--color-primary"), "acc-1": withOpacity("--color-acc-1"), "background-acc-1": withOpacity("--color-background-acc-1"), @@ -46,7 +49,7 @@ export default colors; // Can override these values by passing this object with different values to // `applyTheme` -export const baseColorVariableValues = { +export const baseColorVariableValues: IThemeRGB = { "rgb-primary": "1, 10, 64", "rgb-acc-1": "252, 66, 201", "rgb-background-acc-1": "24, 33, 52", @@ -60,7 +63,6 @@ export const baseColorVariableValues = { // Reference for using CSS variables in Tailwind: // https://tailwindcss.com/docs/customizing-colors#using-css-variables - function withOpacity(variableName: string): string { return `rgba(var(${variableName}), )`; } diff --git a/packages/components/src/tailwind/theme/dolthub/colors.ts b/packages/components/src/tailwind/theme/dolthub/colors.ts index fcd08ee6..fbc80fed 100644 --- a/packages/components/src/tailwind/theme/dolthub/colors.ts +++ b/packages/components/src/tailwind/theme/dolthub/colors.ts @@ -1,9 +1,9 @@ export const colors = { - "ld-pink": "#fc42c9", "ld-darkblue": "#010a40", + "ld-pink": "#fc42c9", "acc-altlightgreen": "#defbe4", - "acc-lightred": "#ffeaec", "acc-darkblue": "#183362", "acc-light-text": "#999db3", + "acc-lightred": "#ffeaec", }; diff --git a/packages/components/src/tailwind/theme/hosted/colors.ts b/packages/components/src/tailwind/theme/hosted/colors.ts index d180d201..c9d0c221 100644 --- a/packages/components/src/tailwind/theme/hosted/colors.ts +++ b/packages/components/src/tailwind/theme/hosted/colors.ts @@ -1,13 +1,15 @@ +import { IThemeRGB } from "../../types"; + export const colors = { - "ld-darkblue": "#183362", - "ld-mediumblue": "#2b5db6", "ld-bluegrey": "#284f94", - "ld-grey": "#f2f5fb", "ld-brightgreen": "#29e3c1", + "ld-darkblue": "#183362", + "ld-grey": "#f2f5fb", + "ld-mediumblue": "#2b5db6", "ld-orange": "#ff820f", }; -export const tailwindColorTheme = { +export const tailwindColorTheme: IThemeRGB = { "rgb-primary": "24, 51, 98", // ld-darkblue "rgb-acc-1": "237, 137, 54", // ld-orange "rgb-background-acc-1": "43, 93, 182", // ld-mediumblue diff --git a/packages/components/src/tailwind/theme/workbench/colors.ts b/packages/components/src/tailwind/theme/workbench/colors.ts new file mode 100644 index 00000000..0e6e6b26 --- /dev/null +++ b/packages/components/src/tailwind/theme/workbench/colors.ts @@ -0,0 +1,26 @@ +import { IThemeRGB } from "../../types"; + +export const colors = { + "ld-bluegrey": "#284f94", + "ld-brightgreen": "#29e3c1", + "ld-darkblue": "#183362", + "ld-darkerblue": "#192E3D", + "ld-grey": "#f2f5fb", + "ld-mediumblue": "#2E4459", + "ld-orange": "#FF7042", + + "acc-hoverlinkblue": "#1f6dc6", + "acc-linkblue": "#3d91f0", +}; + +export const tailwindColorTheme: IThemeRGB = { + "rgb-primary": "24, 51, 98", // ld-darkblue + "rgb-acc-1": "255, 112, 66", // ld-orange + "rgb-background-acc-1": "46, 68, 89", // ld-mediumblue + "rgb-background-acc-start": "46, 68, 89", // ld-mediumblue + "rgb-button-1": "31, 109, 198", // acc-hoverlinkblue + "rgb-link-1": "61, 145, 240", // acc-linkblue + "rgb-button-2": "61, 145, 240", // acc-linkblue + "rgb-link-2": "31, 109, 198", // acc-hoverlinkblue + "rgb-link-light": "109, 176, 252", // ld-blue +}; diff --git a/packages/components/src/tailwind/types.ts b/packages/components/src/tailwind/types.ts new file mode 100644 index 00000000..6e04eafc --- /dev/null +++ b/packages/components/src/tailwind/types.ts @@ -0,0 +1,36 @@ +export interface IThemeRGB { + "rgb-primary"?: string; + "rgb-acc-1"?: string; + "rgb-background-acc-1"?: string; + "rgb-background-acc-start"?: string; + "rgb-button-1"?: string; + "rgb-link-1"?: string; + "rgb-button-2"?: string; + "rgb-link-2"?: string; + "rgb-link-light"?: string; +} + +export interface IThemeVariables { + "--color-primary": string; + "--color-acc-1": string; + "--color-background-acc-1": string; + "--color-background-acc-start": string; + "--color-button-1": string; + "--color-link-1": string; + "--color-button-2": string; + "--color-link-2": string; + "--color-link-light": string; +} + +export interface IThemeColors { + primary?: string; + "acc-1"?: string; + "background-acc-1"?: string; + "background-acc-start"?: string; + "button-1"?: string; + "link-1"?: string; + "button-2"?: string; + "link-2"?: string; + "link-light"?: string; + "background-light"?: string; +} From cb8f220ff0480b3d18735a25c6915a74a944e895 Mon Sep 17 00:00:00 2001 From: Taylor Bantle Date: Thu, 29 Feb 2024 10:30:14 -0800 Subject: [PATCH 2/3] components: Fix lint: --- packages/components/src/Textarea/index.tsx | 2 +- .../components/src/tailwind/context/index.tsx | 16 ++++++++++------ .../components/src/tailwind/context/utils.ts | 4 ++-- packages/components/src/tailwind/types.ts | 2 ++ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/components/src/Textarea/index.tsx b/packages/components/src/Textarea/index.tsx index a983b74e..6ae01597 100644 --- a/packages/components/src/Textarea/index.tsx +++ b/packages/components/src/Textarea/index.tsx @@ -58,7 +58,7 @@ const Textarea = ( onChangeString ? onChangeString(e.target.value) : onChange?.(e) } ref={ref} - aria-label={textAreaProps["aria-label"] || "textarea"} + aria-label={textAreaProps["aria-label"] ?? "textarea"} />
); diff --git a/packages/components/src/tailwind/context/index.tsx b/packages/components/src/tailwind/context/index.tsx index bc4aabb6..45ec6c3e 100644 --- a/packages/components/src/tailwind/context/index.tsx +++ b/packages/components/src/tailwind/context/index.tsx @@ -16,10 +16,13 @@ type ThemeContextType = { const ThemeContext = createContext({ themeRGB: baseColorVariableValues, - convertThemeRGBToHex: () => ({}), + convertThemeRGBToHex: () => { + return {}; + }, }); -// ThemedProvider applies tailwind theme default, potentially with provided overrides +// ThemedProvider applies tailwind theme default, potentially with provided +// overrides. Must wrap your app root in this provider to use this library. export default function ThemeProvider(props: Props) { const themeRGB: IThemeRGB = { ...baseColorVariableValues, @@ -35,9 +38,10 @@ export default function ThemeProvider(props: Props) { const hexThemeRGB: IThemeColors = {}; Object.keys(themeRGB).forEach(key => { const rgb = themeRGB[key as keyof IThemeRGB]; - if (!rgb) return ""; - const color = key.replace("rgb-", ""); - hexThemeRGB[color as keyof IThemeColors] = rgbToHex(rgb); + if (rgb) { + const color = key.replace("rgb-", ""); + hexThemeRGB[color as keyof IThemeColors] = rgbToHex(rgb); + } }); return hexThemeRGB; } @@ -49,6 +53,6 @@ export default function ThemeProvider(props: Props) { ); } -export function useThemeContext() { +export function useThemeContext(): ThemeContextType { return useContext(ThemeContext); } diff --git a/packages/components/src/tailwind/context/utils.ts b/packages/components/src/tailwind/context/utils.ts index cc61a137..f422e84c 100644 --- a/packages/components/src/tailwind/context/utils.ts +++ b/packages/components/src/tailwind/context/utils.ts @@ -4,6 +4,6 @@ export function rgbToHex(rgb: string): string { } function componentToHex(c: number): string { - var hex = c.toString(16); - return hex.length == 1 ? "0" + hex : hex; + const hex = c.toString(16); + return hex.length === 1 ? `0${hex}` : hex; } diff --git a/packages/components/src/tailwind/types.ts b/packages/components/src/tailwind/types.ts index 6e04eafc..e7eb4d36 100644 --- a/packages/components/src/tailwind/types.ts +++ b/packages/components/src/tailwind/types.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/naming-convention */ + export interface IThemeRGB { "rgb-primary"?: string; "rgb-acc-1"?: string; From fea1f7bed98e73c407ccbbba5434fba91bcc8b3a Mon Sep 17 00:00:00 2001 From: Taylor Bantle Date: Thu, 29 Feb 2024 10:59:09 -0800 Subject: [PATCH 3/3] components: Publish --- packages/components/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/package.json b/packages/components/package.json index 0d69769a..bfe94b04 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -2,7 +2,7 @@ "name": "@dolthub/react-components", "author": "DoltHub", "description": "A collection of React components for common tasks", - "version": "0.1.4", + "version": "0.1.5", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "types": "dist/index.d.ts",