From 2d96f827f0256d58cae030c8c1ea5b737f4641fc Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 08:54:48 -0400 Subject: [PATCH 01/16] fix issues with component preview when the website is in darkmode --- .../ComponentPreviewWrapper.tsx | 28 +++++++++++-------- .../componentPreviewWrapper.css | 4 +-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/docs/app/ui/components/componentExample/ComponentPreviewWrapper.tsx b/apps/docs/app/ui/components/componentExample/ComponentPreviewWrapper.tsx index 8d001ae12..61964930e 100644 --- a/apps/docs/app/ui/components/componentExample/ComponentPreviewWrapper.tsx +++ b/apps/docs/app/ui/components/componentExample/ComponentPreviewWrapper.tsx @@ -1,12 +1,12 @@ "use client"; -import { useState, memo, type ReactNode, useCallback } from "react"; +import { useState, memo, type ReactNode, useCallback, useContext, useEffect } from "react"; import Card from "@/components/card/Card.tsx"; import ThemeSwitch from "@/components/themeSwitch/ThemeSwitch.tsx"; -import type { ColorScheme } from "@/context/theme/ThemeProvider.tsx"; -import { StyledSystemProvider } from "@hopper-ui/styled-system"; +import { ThemeContext, type ColorScheme } from "@/context/theme/ThemeProvider.tsx"; import "./componentPreviewWrapper.css"; +import { HopperProvider } from "@hopper-ui/components"; interface ComponentPreviewWrapperProps { preview?: ReactNode; @@ -15,33 +15,39 @@ interface ComponentPreviewWrapperProps { } const ComponentPreviewWrapper = memo(({ preview, toggleButton, height = "13rem" }: ComponentPreviewWrapperProps) => { - const [colorScheme, setColorScheme] = useState<"light" | "dark">("light"); + const { colorMode = "light" } = useContext(ThemeContext); + const [localColorMode, setLocalColorMode] = useState(colorMode); + + useEffect(() => { + // keep the local color mode in sync with the global color mode when the global changes + setLocalColorMode(colorMode); + }, [colorMode]); const toggleTheme = useCallback(() => { - const theme: ColorScheme = colorScheme === "dark" + const theme: ColorScheme = localColorMode === "dark" ? "light" : "dark"; - setColorScheme(theme); - }, [colorScheme]); + setLocalColorMode(theme); + }, [localColorMode]); return (
{toggleButton}
- + {preview} - +
diff --git a/apps/docs/app/ui/components/componentExample/componentPreviewWrapper.css b/apps/docs/app/ui/components/componentExample/componentPreviewWrapper.css index ecf73d83a..b296a7d6b 100644 --- a/apps/docs/app/ui/components/componentExample/componentPreviewWrapper.css +++ b/apps/docs/app/ui/components/componentExample/componentPreviewWrapper.css @@ -7,7 +7,7 @@ height: 100%; } -[data-schema="light"] { +.hd-component-preview-wrapper[data-schema="light"] { .hd-component-preview-wrapper__card { --background: var(--hd-white); --dot-background: var(--hd-neutral-50); @@ -26,7 +26,7 @@ } } -[data-schema="dark"] { +.hd-component-preview-wrapper[data-schema="dark"] { .hd-component-preview-wrapper__card { --background: var(--hd-neutral-900); --dot-background: var(--hd-neutral-800); From 56d67700ce21c0717060e51bf7f222ee77655d4f Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 08:55:08 -0400 Subject: [PATCH 02/16] Complete the color-schemes doc --- .../components/concepts/color-schemes.mdx | 70 ++----------------- apps/docs/examples/Preview.ts | 15 ++++ .../docs/color-scheme/apply-nested.tsx | 16 +++++ .../docs/color-scheme/apply-system.tsx | 9 +++ .../docs/color-scheme/apply.tsx | 9 +++ .../docs/color-scheme/changing.tsx | 33 +++++++++ .../docs/color-scheme/useColorSchemeValue.tsx | 12 ++++ 7 files changed, 101 insertions(+), 63 deletions(-) create mode 100644 packages/components/src/HopperProvider/docs/color-scheme/apply-nested.tsx create mode 100644 packages/components/src/HopperProvider/docs/color-scheme/apply-system.tsx create mode 100644 packages/components/src/HopperProvider/docs/color-scheme/apply.tsx create mode 100644 packages/components/src/HopperProvider/docs/color-scheme/changing.tsx create mode 100644 packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx diff --git a/apps/docs/content/components/concepts/color-schemes.mdx b/apps/docs/content/components/concepts/color-schemes.mdx index 54efc5039..97f024ed5 100644 --- a/apps/docs/content/components/concepts/color-schemes.mdx +++ b/apps/docs/content/components/concepts/color-schemes.mdx @@ -1,5 +1,5 @@ --- -title: Color Schemes (WIP) +title: Color Schemes description: This page describes how color schemes work in Hopper, including how applications adapt to operating system dark mode. order: 5 --- @@ -14,67 +14,23 @@ We recommend that all Hopper applications support both light and dark mode. It c A color scheme can either be enforced by providing a specific light or dark value to a [HopperProvider](../application/hopper-provider.mdx). -{/* TODO: example */} -```tsx - - - -``` + + A color scheme can also be set to `system`, which will follow the [user's operating system setting](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme). When the `system` value is provided, an additional fallback color scheme must be specified to defaultColorScheme in case the theme provider is not able to access the user setting. -{/* TODO: example */} -```tsx - - - -``` + Color schemes can also be nested. You could have a dark themed dialog inside a light themed application. For example, this might be useful for certain experiences like color scheme previews, where you want to showcase a specific color scheme, regardless of the operating system setting. -{/* TODO: example */} -```tsx - - - - - - -``` + ## Changing the color scheme To manage the color scheme in your application, Hopper exposes a `ColorSchemeContext` and a `useColorSchemeContext` hook. -{/* TODO: example */} -```tsx -function ColorSchemeToggle() { - const { colorScheme, setColorScheme } = useColorSchemeContext(); - - const handleClick = useCallback(() => { - setColorScheme(colorScheme === "light" ? "dark" : "light"); - }, [colorScheme, setColorScheme]); - - return ( - - ); -} - -render(() => { - const { colorScheme: parentColorScheme } = useColorSchemeContext(); - - return ( - -
- -
-
- ); -}); -``` + ## Utility Methods @@ -84,16 +40,4 @@ Some features require the usage of custom colors. Those colors aren't like Hoppe To help with that, Hopper offers the `useColorSchemeValue` hook which will return the value matching the current color scheme of the closest `HopperProvider`. -{/* TODO: example */} -```tsx -import { useColorSchemeValue } from "@hopper-ui/components"; - -const color = useColorSchemeValue("#fff", "#000"); -const backgroundColor = useColorSchemeValue("#ff9048", "#fee2bb"); - -return ( -
- Content -
-); -``` + diff --git a/apps/docs/examples/Preview.ts b/apps/docs/examples/Preview.ts index 9e7a90f3b..ee17818d2 100644 --- a/apps/docs/examples/Preview.ts +++ b/apps/docs/examples/Preview.ts @@ -47,5 +47,20 @@ export const Previews: Record = { "buttons/docs/button/advancedCustomization": { component: lazy(() => import("@/../../packages/components/src/buttons/docs/button/advancedCustomization.tsx")) }, + "HopperProvider/docs/color-scheme/apply": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/color-scheme/apply.tsx")) + }, + "HopperProvider/docs/color-scheme/apply-system": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/color-scheme/apply-system.tsx")) + }, + "HopperProvider/docs/color-scheme/apply-nested": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/color-scheme/apply-nested.tsx")) + }, + "HopperProvider/docs/color-scheme/changing": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/color-scheme/changing.tsx")) + }, + "HopperProvider/docs/color-scheme/useColorSchemeValue": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx")) + }, }; \ No newline at end of file diff --git a/packages/components/src/HopperProvider/docs/color-scheme/apply-nested.tsx b/packages/components/src/HopperProvider/docs/color-scheme/apply-nested.tsx new file mode 100644 index 000000000..9468a8f18 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/color-scheme/apply-nested.tsx @@ -0,0 +1,16 @@ +import { Button, HopperProvider } from "@hopper-ui/components"; + +export default function Example() { + return ( + + + + + + + ); +} diff --git a/packages/components/src/HopperProvider/docs/color-scheme/apply-system.tsx b/packages/components/src/HopperProvider/docs/color-scheme/apply-system.tsx new file mode 100644 index 000000000..7287137d3 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/color-scheme/apply-system.tsx @@ -0,0 +1,9 @@ +import { Button, HopperProvider } from "@hopper-ui/components"; + +export default function Example() { + return ( + + + + ); +} diff --git a/packages/components/src/HopperProvider/docs/color-scheme/apply.tsx b/packages/components/src/HopperProvider/docs/color-scheme/apply.tsx new file mode 100644 index 000000000..a2160fe42 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/color-scheme/apply.tsx @@ -0,0 +1,9 @@ +import { Button, HopperProvider } from "@hopper-ui/components"; + +export default function Example() { + return ( + + + + ); +} diff --git a/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx b/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx new file mode 100644 index 000000000..aeb0c5832 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx @@ -0,0 +1,33 @@ +import { + Button, + HopperProvider, + useColorSchemeContext, + Div +} from "@hopper-ui/components"; +import { useCallback } from "react"; + +function ColorSchemeToggle() { + const { colorScheme, setColorScheme } = useColorSchemeContext(); + + const handleClick = useCallback(() => { + setColorScheme(colorScheme === "light" ? "dark" : "light"); + }, [colorScheme, setColorScheme]); + + return ( + + ); +} + +export default function Example() { + const { colorScheme: parentColorScheme } = useColorSchemeContext(); + + return ( + +
+ +
+
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx b/packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx new file mode 100644 index 000000000..55d185af7 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx @@ -0,0 +1,12 @@ +import { useColorSchemeValue, Div } from "@hopper-ui/components"; + +export default function Example() { + const color = useColorSchemeValue("#fff", "#000"); + const backgroundColor = useColorSchemeValue("#ff9048", "#fee2bb"); + + return ( +
+ Content +
+ ); +} From bbf4e4e34c4a2c635f32cd9bcf7fc2a0950de413 Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 11:46:56 -0400 Subject: [PATCH 03/16] complete responsive styles --- apps/docs/.eslintrc.json | 2 + .../breakpointTable/BreakpointTable.tsx | 24 +++++++ .../ui/components/simpleTable/SimpleTable.tsx | 52 +++++++++++++++ apps/docs/components/mdx/components.tsx | 4 +- .../components/concepts/color-schemes.mdx | 10 +-- .../components/concepts/responsive-styles.mdx | 66 +++---------------- .../content/tokens/core/border-radius.mdx | 2 +- apps/docs/content/tokens/core/color.mdx | 2 +- apps/docs/content/tokens/core/dimensions.mdx | 2 +- apps/docs/content/tokens/core/font-family.mdx | 2 +- apps/docs/content/tokens/core/font-size.mdx | 2 +- apps/docs/content/tokens/core/font-weight.mdx | 2 +- apps/docs/content/tokens/core/line-height.mdx | 2 +- apps/docs/content/tokens/core/motion.mdx | 4 +- apps/docs/content/tokens/core/shadow.mdx | 2 +- .../tokens/getting-started/introduction.mdx | 10 +-- .../content/tokens/semantic/elevation.mdx | 2 +- apps/docs/content/tokens/semantic/shape.mdx | 2 +- apps/docs/examples/Preview.ts | 12 ++++ .../docs/color-scheme/changing.tsx | 4 +- .../docs/color-scheme/useColorSchemeValue.tsx | 2 +- .../docs/responsive-styles/introduction.tsx | 22 +++++++ .../responsive-styles/mobile-first-do-not.tsx | 16 +++++ .../responsive-styles/mobile-first-do.tsx | 16 +++++ .../responsive-styles/useResponsiveValue.tsx | 17 +++++ 25 files changed, 197 insertions(+), 84 deletions(-) create mode 100644 apps/docs/app/ui/components/breakpointTable/BreakpointTable.tsx create mode 100644 apps/docs/app/ui/components/simpleTable/SimpleTable.tsx create mode 100644 packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx create mode 100644 packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do-not.tsx create mode 100644 packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do.tsx create mode 100644 packages/components/src/HopperProvider/docs/responsive-styles/useResponsiveValue.tsx diff --git a/apps/docs/.eslintrc.json b/apps/docs/.eslintrc.json index 66683dd8d..c5f06eaef 100644 --- a/apps/docs/.eslintrc.json +++ b/apps/docs/.eslintrc.json @@ -9,10 +9,12 @@ "@next/next/no-html-link-for-pages": "off" }, "globals": { + "BreakpointTable": true, "Card": true, "Callout": true, "Collapsible": true, "Table": true, + "TokenTable": true, "MotionPreview": true, "Footnote": true, "TypographyTable": true, diff --git a/apps/docs/app/ui/components/breakpointTable/BreakpointTable.tsx b/apps/docs/app/ui/components/breakpointTable/BreakpointTable.tsx new file mode 100644 index 000000000..74eafc334 --- /dev/null +++ b/apps/docs/app/ui/components/breakpointTable/BreakpointTable.tsx @@ -0,0 +1,24 @@ +"use client"; + +import SimpleTable from "../simpleTable/SimpleTable"; +import { Breakpoints } from "@hopper-ui/components"; + +export default function BreakpointTable() { + const breakpoints = Object.entries(Breakpoints).map(([key, value]) => { + return { + name: key, + value: `min-width: ${value}px` + }; + }); + + return ( + + ); +} diff --git a/apps/docs/app/ui/components/simpleTable/SimpleTable.tsx b/apps/docs/app/ui/components/simpleTable/SimpleTable.tsx new file mode 100644 index 000000000..d70457b4a --- /dev/null +++ b/apps/docs/app/ui/components/simpleTable/SimpleTable.tsx @@ -0,0 +1,52 @@ +import clsx from "clsx"; + +interface SimpleTableProps { + "aria-label"?: string; + headers: string[]; + data: { + name: string; + value: string; + }[]; + lastColumnAlignment?: "left" | "right"; +} + +export default async function SimpleTable({ "aria-label": ariaLabel, headers, data, lastColumnAlignment }: SimpleTableProps) { + return ( + + + + {headers.map((header, index) => { + const classNames = clsx("hd-table__column", { "hd-table__colum--right": index === headers.length - 1 && lastColumnAlignment === "right" }); + + return ( + // eslint-disable-next-line react/no-array-index-key + + ); + })} + + + + {data.map((row, rowIndex) => { + return ( + // eslint-disable-next-line react/no-array-index-key + + { + Object.entries(row).map(([key, value], index) => { + const classNames = clsx("hd-table__cell", { "hd-table__cell--right": index === headers.length - 1 && lastColumnAlignment === "right" }); + + return ( + + ); + }) + } + + ); + })} + +
+ {header} +
+ {value} +
+ ); +} diff --git a/apps/docs/components/mdx/components.tsx b/apps/docs/components/mdx/components.tsx index aab73ad87..bbfc2ca91 100644 --- a/apps/docs/components/mdx/components.tsx +++ b/apps/docs/components/mdx/components.tsx @@ -27,6 +27,7 @@ import type { PropTableProps } from "@/app/ui/components/propTable/PropTable.tsx import type { ComponentExampleProps } from "@/app/ui/components/componentExample/ComponentExample.tsx"; import { ComponentCodeWrapper } from "@/app/ui/components/componentExample/ComponentCodeWrapper.tsx"; import ComponentPreview from "@/app/ui/components/componentExample/ComponentPreview.tsx"; +import BreakpointTable from "@/app/ui/components/breakpointTable/BreakpointTable"; const MigrateGuide = dynamic(() => import("@/app/ui/components/migrateGuide/MigrateGuide.tsx")); const PropTable = dynamic(() => import("@/app/ui/components/propTable/PropTable.tsx")); @@ -41,8 +42,9 @@ export const components = { Image: NextImage, pre: Pre, MotionPreview: MotionPreview, + BreakpointTable: BreakpointTable, Footnote: Footnote, - Table: TokenTable, + TokenTable: TokenTable, TypographyTable: TypographyTable, TypographyVariantTable: TypographyVariantTable, IconTable: IconTable, diff --git a/apps/docs/content/components/concepts/color-schemes.mdx b/apps/docs/content/components/concepts/color-schemes.mdx index 97f024ed5..c039bfcd0 100644 --- a/apps/docs/content/components/concepts/color-schemes.mdx +++ b/apps/docs/content/components/concepts/color-schemes.mdx @@ -15,22 +15,22 @@ We recommend that all Hopper applications support both light and dark mode. It c A color scheme can either be enforced by providing a specific light or dark value to a [HopperProvider](../application/hopper-provider.mdx). - + A color scheme can also be set to `system`, which will follow the [user's operating system setting](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme). When the `system` value is provided, an additional fallback color scheme must be specified to defaultColorScheme in case the theme provider is not able to access the user setting. - + Color schemes can also be nested. You could have a dark themed dialog inside a light themed application. For example, this might be useful for certain experiences like color scheme previews, where you want to showcase a specific color scheme, regardless of the operating system setting. - + ## Changing the color scheme To manage the color scheme in your application, Hopper exposes a `ColorSchemeContext` and a `useColorSchemeContext` hook. - + ## Utility Methods @@ -40,4 +40,4 @@ Some features require the usage of custom colors. Those colors aren't like Hoppe To help with that, Hopper offers the `useColorSchemeValue` hook which will return the value matching the current color scheme of the closest `HopperProvider`. - + diff --git a/apps/docs/content/components/concepts/responsive-styles.mdx b/apps/docs/content/components/concepts/responsive-styles.mdx index 2f8282f73..646f348c4 100644 --- a/apps/docs/content/components/concepts/responsive-styles.mdx +++ b/apps/docs/content/components/concepts/responsive-styles.mdx @@ -1,5 +1,5 @@ --- -title: Responsive Styles (WIP) +title: Responsive Styles description: This page describes how Hopper style props accept a specialized syntax to support responsive breakpoints. These responsive properties help build adaptive user interfaces. order: 3 --- @@ -10,74 +10,29 @@ In addition to static values, all style props support object syntax to specify d In this example, the `Div` has a default background color, which is overridden at each breakpoint. Resize your browser window to see this in action. -{/* TODO: example and modify all the property values so it fits hopper */} -```tsx -
- Resize to see the background color change! -
-``` + ## Breakpoints There are five breakpoints available (+ the base), inspired by common device resolutions: {/* TODO: do a table here */} -| Name | Minimum width | -| ---- | ------------- | -| base | 0px | -| xs | 640px | -| sm | 768px | -| md | 1024px | -| lg | 1280px | -| xl | 1440px | + ## Working mobile-first By default, Hopper uses a mobile-first breakpoint system, similar to what you might be used to in other frameworks like Bootstrap or Tailwind. -{/* TODO start the sentence with a */} +{/* TODO start the sentence with a */} **Don't use `sm:` to target mobile devices** -{/* TODO: convert to example */} -```tsx -
- Text Content -
-``` + + {/* TODO start the sentence with a */} **Use `base` to target mobile, and override them at larger breakpoints** -{/* TODO: covnert to example */} -```tsx -
- Text Content -
-``` + For this reason, it's often a good idea to implement the mobile layout for a design first, then layer on any changes that make sense for sm screens, followed by md screens, etc. @@ -87,9 +42,4 @@ For this reason, it's often a good idea to implement the mobile layout for a des To resolve a responsive value within a React component, Hopper provides the useResponsiveValue hook. -{/* TODO example */} -```tsx -import { useResponsiveValue } from "@hopper-ui/components"; - -const isFluidValue = useResponsiveValue({ base: true, lg: false }); -``` + diff --git a/apps/docs/content/tokens/core/border-radius.mdx b/apps/docs/content/tokens/core/border-radius.mdx index 348872182..3d181b9a9 100644 --- a/apps/docs/content/tokens/core/border-radius.mdx +++ b/apps/docs/content/tokens/core/border-radius.mdx @@ -8,4 +8,4 @@ export const categoryKey = "borderRadius"; ## Tokens - + diff --git a/apps/docs/content/tokens/core/color.mdx b/apps/docs/content/tokens/core/color.mdx index 2d684a002..81898d334 100644 --- a/apps/docs/content/tokens/core/color.mdx +++ b/apps/docs/content/tokens/core/color.mdx @@ -10,4 +10,4 @@ export const categoryKey = "color"; ## Tokens -
+ diff --git a/apps/docs/content/tokens/core/dimensions.mdx b/apps/docs/content/tokens/core/dimensions.mdx index 677a09778..2c4818fd4 100644 --- a/apps/docs/content/tokens/core/dimensions.mdx +++ b/apps/docs/content/tokens/core/dimensions.mdx @@ -8,4 +8,4 @@ export const categoryKey = "size"; ## Tokens -
+ diff --git a/apps/docs/content/tokens/core/font-family.mdx b/apps/docs/content/tokens/core/font-family.mdx index 5dea25988..a7818446b 100644 --- a/apps/docs/content/tokens/core/font-family.mdx +++ b/apps/docs/content/tokens/core/font-family.mdx @@ -8,4 +8,4 @@ export const categoryKey = "fontFamily"; ## Tokens -
+ diff --git a/apps/docs/content/tokens/core/font-size.mdx b/apps/docs/content/tokens/core/font-size.mdx index 8809874fd..a709a693e 100644 --- a/apps/docs/content/tokens/core/font-size.mdx +++ b/apps/docs/content/tokens/core/font-size.mdx @@ -8,4 +8,4 @@ export const categoryKey = "fontSize"; ## Tokens -
+ diff --git a/apps/docs/content/tokens/core/font-weight.mdx b/apps/docs/content/tokens/core/font-weight.mdx index 047f53478..266705edb 100644 --- a/apps/docs/content/tokens/core/font-weight.mdx +++ b/apps/docs/content/tokens/core/font-weight.mdx @@ -8,4 +8,4 @@ export const categoryKey = "fontWeight"; ## Tokens -
+ diff --git a/apps/docs/content/tokens/core/line-height.mdx b/apps/docs/content/tokens/core/line-height.mdx index fb6e8bedd..52da92174 100644 --- a/apps/docs/content/tokens/core/line-height.mdx +++ b/apps/docs/content/tokens/core/line-height.mdx @@ -8,4 +8,4 @@ export const categoryKey = "lineHeight"; ## Tokens -
+ diff --git a/apps/docs/content/tokens/core/motion.mdx b/apps/docs/content/tokens/core/motion.mdx index 3e51bacac..33c59dbfe 100644 --- a/apps/docs/content/tokens/core/motion.mdx +++ b/apps/docs/content/tokens/core/motion.mdx @@ -44,7 +44,7 @@ In an animation declaration: Hopper exposes 5 durations, they help convey a message and makes animations smooth and responsive. -
+ ### Easings @@ -62,7 +62,7 @@ Used in animations that are designed to draw the user’s attention on what chan Used in animations that are meant to give a sense of completeness or resolution to the user. Use them wisely. -
+ ### Playground diff --git a/apps/docs/content/tokens/core/shadow.mdx b/apps/docs/content/tokens/core/shadow.mdx index 9e31cb84a..de80f5841 100644 --- a/apps/docs/content/tokens/core/shadow.mdx +++ b/apps/docs/content/tokens/core/shadow.mdx @@ -8,4 +8,4 @@ export const categoryKey = "shadow"; ## Tokens -
+ diff --git a/apps/docs/content/tokens/getting-started/introduction.mdx b/apps/docs/content/tokens/getting-started/introduction.mdx index 7f820d4b1..024e0e653 100644 --- a/apps/docs/content/tokens/getting-started/introduction.mdx +++ b/apps/docs/content/tokens/getting-started/introduction.mdx @@ -23,7 +23,7 @@ Hopper aims to provide a three tier token system, where each tier has their spec These tokens are referring to raw values such as a hexadecimal color code, border-width, or font-size. They are the building blocks of the design system. -
@@ -34,14 +34,14 @@ Semantic tokens carry design intent and are design context aware. They are the t #### Light -
#### Dark -
@@ -54,14 +54,14 @@ _Note: As no components are currently available, these tokens are not yet availa #### Light -
#### Dark -
diff --git a/apps/docs/content/tokens/semantic/elevation.mdx b/apps/docs/content/tokens/semantic/elevation.mdx index 880847b1d..b8d1983ae 100644 --- a/apps/docs/content/tokens/semantic/elevation.mdx +++ b/apps/docs/content/tokens/semantic/elevation.mdx @@ -14,4 +14,4 @@ export const categoryKey = "shadow"; ## Tokens -
+ diff --git a/apps/docs/content/tokens/semantic/shape.mdx b/apps/docs/content/tokens/semantic/shape.mdx index 411d5a270..3cba9dfca 100644 --- a/apps/docs/content/tokens/semantic/shape.mdx +++ b/apps/docs/content/tokens/semantic/shape.mdx @@ -10,4 +10,4 @@ export const categoryKey = "borderRadius"; ## Tokens -
+ diff --git a/apps/docs/examples/Preview.ts b/apps/docs/examples/Preview.ts index ee17818d2..910d9f0ac 100644 --- a/apps/docs/examples/Preview.ts +++ b/apps/docs/examples/Preview.ts @@ -62,5 +62,17 @@ export const Previews: Record = { "HopperProvider/docs/color-scheme/useColorSchemeValue": { component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx")) }, + "HopperProvider/docs/responsive-styles/introduction": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx")) + }, + "HopperProvider/docs/responsive-styles/mobile-first-do-not": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do-not.tsx")) + }, + "HopperProvider/docs/responsive-styles/mobile-first-do": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do.tsx")) + }, + "HopperProvider/docs/responsive-styles/useResponsiveValue": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/responsive-styles/useResponsiveValue.tsx")) + }, }; \ No newline at end of file diff --git a/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx b/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx index aeb0c5832..5d4c29795 100644 --- a/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx +++ b/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx @@ -1,8 +1,8 @@ import { Button, + Div, HopperProvider, - useColorSchemeContext, - Div + useColorSchemeContext } from "@hopper-ui/components"; import { useCallback } from "react"; diff --git a/packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx b/packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx index 55d185af7..e24b0616d 100644 --- a/packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx +++ b/packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx @@ -1,4 +1,4 @@ -import { useColorSchemeValue, Div } from "@hopper-ui/components"; +import { Div, useColorSchemeValue } from "@hopper-ui/components"; export default function Example() { const color = useColorSchemeValue("#fff", "#000"); diff --git a/packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx b/packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx new file mode 100644 index 000000000..f179606fc --- /dev/null +++ b/packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx @@ -0,0 +1,22 @@ + +import { Div, Text } from "@hopper-ui/components"; + +export default function Example() { + return ( +
+ Resize to see the background color change! +
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do-not.tsx b/packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do-not.tsx new file mode 100644 index 000000000..110ad68d0 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do-not.tsx @@ -0,0 +1,16 @@ + +import { Div, Text } from "@hopper-ui/components"; + +export default function Example() { + return ( +
+ Text Content +
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do.tsx b/packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do.tsx new file mode 100644 index 000000000..b831b523f --- /dev/null +++ b/packages/components/src/HopperProvider/docs/responsive-styles/mobile-first-do.tsx @@ -0,0 +1,16 @@ + +import { Div, Text } from "@hopper-ui/components"; + +export default function Example() { + return ( +
+ Text Content +
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/responsive-styles/useResponsiveValue.tsx b/packages/components/src/HopperProvider/docs/responsive-styles/useResponsiveValue.tsx new file mode 100644 index 000000000..7caa6f6df --- /dev/null +++ b/packages/components/src/HopperProvider/docs/responsive-styles/useResponsiveValue.tsx @@ -0,0 +1,17 @@ + +import { Div, useResponsiveValue } from "@hopper-ui/components"; + +export default function Example() { + const isFluidValue = useResponsiveValue({ base: true, lg: false }); + + return ( +
+ Content +
+ ); +} From 6cd36f37f644108edddc138200040ddba8a1ec13 Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 14:22:44 -0400 Subject: [PATCH 04/16] styling-layout and Hopper provider --- apps/docs/.eslintrc.json | 2 + .../ComponentPreviewWrapper.tsx | 8 +- .../ui/components/simpleTable/SimpleTable.tsx | 5 +- apps/docs/components/card/Card.tsx | 10 +- apps/docs/components/mdx/components.tsx | 11 +++ .../components/application/HopperProvider.mdx | 78 ++------------- .../content/components/concepts/layout.mdx | 88 ++++++++++++++++- .../content/components/concepts/styling.mdx | 96 ++++++++++++------- apps/docs/examples/Preview.ts | 6 ++ .../hopper-provider/client-side-routing.tsx | 12 +++ .../docs/hopper-provider/color-scheme.tsx | 9 ++ .../hopper-provider/inject-body-style.tsx | 9 ++ .../docs/hopper-provider/inject-css-var.tsx | 9 ++ .../docs/hopper-provider/locale.tsx | 9 ++ .../docs/hopper-provider/preview.tsx | 11 +++ .../src/HopperProvider/docs/layout/flex.tsx | 11 +++ .../src/HopperProvider/docs/layout/grid.tsx | 23 +++++ .../docs/styling/custom-component-html.tsx | 21 ++++ .../custom-component-useStyledSystem.tsx | 28 ++++++ .../docs/styling/escape-hatch.tsx | 18 ++++ .../docs/styling/shorthands.tsx | 9 ++ .../src/HopperProvider/docs/styling/usage.tsx | 18 ++++ 22 files changed, 366 insertions(+), 125 deletions(-) create mode 100644 packages/components/src/HopperProvider/docs/hopper-provider/client-side-routing.tsx create mode 100644 packages/components/src/HopperProvider/docs/hopper-provider/color-scheme.tsx create mode 100644 packages/components/src/HopperProvider/docs/hopper-provider/inject-body-style.tsx create mode 100644 packages/components/src/HopperProvider/docs/hopper-provider/inject-css-var.tsx create mode 100644 packages/components/src/HopperProvider/docs/hopper-provider/locale.tsx create mode 100644 packages/components/src/HopperProvider/docs/hopper-provider/preview.tsx create mode 100644 packages/components/src/HopperProvider/docs/layout/flex.tsx create mode 100644 packages/components/src/HopperProvider/docs/layout/grid.tsx create mode 100644 packages/components/src/HopperProvider/docs/styling/custom-component-html.tsx create mode 100644 packages/components/src/HopperProvider/docs/styling/custom-component-useStyledSystem.tsx create mode 100644 packages/components/src/HopperProvider/docs/styling/escape-hatch.tsx create mode 100644 packages/components/src/HopperProvider/docs/styling/shorthands.tsx create mode 100644 packages/components/src/HopperProvider/docs/styling/usage.tsx diff --git a/apps/docs/.eslintrc.json b/apps/docs/.eslintrc.json index c5f06eaef..0238f4a1a 100644 --- a/apps/docs/.eslintrc.json +++ b/apps/docs/.eslintrc.json @@ -21,6 +21,7 @@ "TypographyVariantTable": true, "Tabs": true, "TableSection": true, + "SimpleTable": true, "Switcher": true, "IconSpecTable": true, "Overview": true, @@ -28,6 +29,7 @@ "MigrateGuide": true, "PackageInstallation": true, "PropTable": true, + "CodeOnlyExample": true, "Example": true }, "overrides": [ diff --git a/apps/docs/app/ui/components/componentExample/ComponentPreviewWrapper.tsx b/apps/docs/app/ui/components/componentExample/ComponentPreviewWrapper.tsx index 61964930e..e29077a8c 100644 --- a/apps/docs/app/ui/components/componentExample/ComponentPreviewWrapper.tsx +++ b/apps/docs/app/ui/components/componentExample/ComponentPreviewWrapper.tsx @@ -11,10 +11,10 @@ import { HopperProvider } from "@hopper-ui/components"; interface ComponentPreviewWrapperProps { preview?: ReactNode; toggleButton?: ReactNode; - height?: string; + minHeight?: string; } -const ComponentPreviewWrapper = memo(({ preview, toggleButton, height = "13rem" }: ComponentPreviewWrapperProps) => { +const ComponentPreviewWrapper = memo(({ preview, toggleButton, minHeight = "13rem" }: ComponentPreviewWrapperProps) => { const { colorMode = "light" } = useContext(ThemeContext); const [localColorMode, setLocalColorMode] = useState(colorMode); @@ -35,7 +35,7 @@ const ComponentPreviewWrapper = memo(({ preview, toggleButton, height = "13rem"
{toggleButton} @@ -44,7 +44,7 @@ const ComponentPreviewWrapper = memo(({ preview, toggleButton, height = "13rem" colorMode={localColorMode} />
- + {preview} diff --git a/apps/docs/app/ui/components/simpleTable/SimpleTable.tsx b/apps/docs/app/ui/components/simpleTable/SimpleTable.tsx index d70457b4a..d9254c90f 100644 --- a/apps/docs/app/ui/components/simpleTable/SimpleTable.tsx +++ b/apps/docs/app/ui/components/simpleTable/SimpleTable.tsx @@ -3,10 +3,7 @@ import clsx from "clsx"; interface SimpleTableProps { "aria-label"?: string; headers: string[]; - data: { - name: string; - value: string; - }[]; + data: object[]; lastColumnAlignment?: "left" | "right"; } diff --git a/apps/docs/components/card/Card.tsx b/apps/docs/components/card/Card.tsx index 84251778a..7eae2dd2d 100644 --- a/apps/docs/components/card/Card.tsx +++ b/apps/docs/components/card/Card.tsx @@ -1,23 +1,21 @@ -import type { ReactNode } from "react"; +import type { ComponentProps } from "react"; import clsx from "clsx"; import "./card.css"; -export interface CardProps { - children: ReactNode; - className?: string; +export interface CardProps extends ComponentProps<"div">{ size?: "sm" | "md" | "lg"; align?: "start" | "center" | "end"; } -const Card = ({ children, className, size = "md", align = "center" }: CardProps) => { +const Card = ({ children, className, size = "md", align = "center", ...rest }: CardProps) => { const cardClass = clsx("hd-card", { [`hd-card--${size}`]: size !== "md", [`hd-card--${align}`]: align !== "center" }, className); return ( -
+
{children}
); diff --git a/apps/docs/components/mdx/components.tsx b/apps/docs/components/mdx/components.tsx index bbfc2ca91..5628d5266 100644 --- a/apps/docs/components/mdx/components.tsx +++ b/apps/docs/components/mdx/components.tsx @@ -28,6 +28,7 @@ import type { ComponentExampleProps } from "@/app/ui/components/componentExample import { ComponentCodeWrapper } from "@/app/ui/components/componentExample/ComponentCodeWrapper.tsx"; import ComponentPreview from "@/app/ui/components/componentExample/ComponentPreview.tsx"; import BreakpointTable from "@/app/ui/components/breakpointTable/BreakpointTable"; +import SimpleTable from "@/app/ui/components/simpleTable/SimpleTable"; const MigrateGuide = dynamic(() => import("@/app/ui/components/migrateGuide/MigrateGuide.tsx")); const PropTable = dynamic(() => import("@/app/ui/components/propTable/PropTable.tsx")); @@ -50,6 +51,7 @@ export const components = { IconTable: IconTable, IconSpecTable: IconSpecTable, Overview: Overview, + SimpleTable: SimpleTable, Tabs: Tabs, TableSection: TableSection, Switcher: Switcher, @@ -66,6 +68,15 @@ export const components = { preview={} />; }, + CodeOnlyExample: (props: ComponentExampleProps) => { + const { src } = props; + + return } + />; + }, MigrateGuide: (props: MigrateGuideProps) => { return ; }, diff --git a/apps/docs/content/components/application/HopperProvider.mdx b/apps/docs/content/components/application/HopperProvider.mdx index ddf3db048..779a3bf9b 100644 --- a/apps/docs/content/components/application/HopperProvider.mdx +++ b/apps/docs/content/components/application/HopperProvider.mdx @@ -7,20 +7,7 @@ links: source: https://github.com/gsoft-inc/wl-hopper/blob/main/packages/components/src/HopperProvider/src/HopperProvider.tsx --- -{/* TODO example at the top */} -```tsx -import { Button, HopperProvider } from "@hopper-ui/components"; - -function App() { - return ( - - - - ); -} -``` + ## Props (WIP) @@ -36,18 +23,7 @@ You can also nest multiple HopperProviders to create different themes or locales We recommend supporting both light and dark color schemes in your app, however, if you need to override this with an application specific setting, you can use the colorScheme prop. -{/* TODO example */} -```tsx -import { HopperProvider, Button } from "@hopper-ui/components"; - -function Demo() { - return ( - - - - ); -} -``` + See the [styling documentation](/components/concepts/styling) for more information about using Hopper color variables in your app to ensure it adapts to light and dark mode properly. @@ -58,18 +34,7 @@ See the [color schemes documentation](/components/concepts/color-schemes) for mo Another important setting for your application is the locale. By default, Hopper chooses the locale matching the user's browser/operating system language, but this can be overridden with the locale prop if you have an application specific setting. This prop accepts a [BCP 47](https://www.ietf.org/rfc/bcp/bcp47.txt) language code. Hopper currently supports the following locales: `en-US`, `en-UK`, `fr-CA`, `fr-FR`. -{/* TODO example */} -```tsx -import { HopperProvider } from "@hopper-ui/components"; - -function Demo() { - return ( - - {/* Your app here */} - - ); -} -``` + {/* TODO, hopper should re-export useLocale and document it? */} To access the current locale anywhere in your application, see the [useLocale](https://react-spectrum.adobe.com/react-aria/useLocale.html) hook. @@ -78,34 +43,14 @@ To access the current locale anywhere in your application, see the [useLocale](h The HopperProvider component accepts an optional router prop. This enables Hopper components that render links to perform client side navigation using your application or framework's client side router. See the [client side routing](/components/concepts/client-side-routing) guide for details on how to set this up. -```tsx -import { HopperProvider } from "@hopper-ui/components"; - -function Demo() { - const navigate = useNavigateFromYourRouter(); - return ( - - {/* Your app here */} - - ); -} -``` + ### Inject body styles `withBodyStyle` determines whether you want Hopper to style the body of your application. By default, it is set to false. You should enable it on the Hopper provider at the root of your application. -```tsx -import { HopperProvider } from "@hopper-ui/components"; + -function Demo() { - return ( - - {/* Your app here */} - - ); -} -``` `withBodyStyle` includes the following body elements styles: @@ -132,15 +77,4 @@ body { `withCssVariables` determines whether Hopper's CSS variables should be added to your application. By default, it is set to true, you should not change it unless you want to manage CSS variables via .css file (Note that in this case you will need to add the tokens manually, ideally with the [`@hopper-ui/tokens` package](/tokens/getting-started/usage)) -{/* TODO: Make this an example */} -```tsx -import { HopperProvider } from "@hopper-ui/components"; - -function Demo() { - return ( - - {/* Your app here */} - - ); -} -``` + diff --git a/apps/docs/content/components/concepts/layout.mdx b/apps/docs/content/components/concepts/layout.mdx index 17ea6c224..32a3f94a9 100644 --- a/apps/docs/content/components/concepts/layout.mdx +++ b/apps/docs/content/components/concepts/layout.mdx @@ -1,5 +1,5 @@ --- -title: Layout (WIP) +title: Layout description: This page describes how to build application layouts with Hopper using Flex or Grid. order: 1 --- @@ -8,14 +8,92 @@ This page will be heavily inspired by https://react-spectrum.adobe.com/react-spe ## Introduction +hopper includes layout components to help build applications more easily. The [Flex](./Flex) and [Grid](./Grid) +components are containers, which are responsible for the layout of their children. `Flex` follows the +[CSS flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) +algorithm, while `Grid` implements +[CSS grid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout). +These components provide props with pre-defined Hopper tokens for sizing, spacing, +and other layout options. You can use `Flex` and `Grid` together as needed to build different +parts of your application, and even nest them to create more complex layouts. + +In general, you should prefer using flex and grid over other CSS layout models. Spacing between components +should be left to parent layout components rather than added as via margins to specific children. This helps +ensure components are composable when reused in different places, and ensures that spacing is consistent. + +In addition to `Flex` and `Grid`, some Hopper components include pre-built layouts which you can +insert your content into via slots. You can read more about slots in the [slots](./slots) concept page. + ## Flex +The [flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) +layout model is a simple yet versatile method of laying out components in rows and columns. +You can use it to build vertical or horizontal stacks, simple wrapping grids, and more. The [Flex](./Flex) +component can be used to create flexbox containers, and any Hopper component can be used as a child. +Flex layouts can be nested to create more complex layouts. + +The `gap`, `rowGap` and `columnGap` can be defined with [Hopper space tokens](/tokens/semantic/space) +to ensure consistency across applications, and allow the layout to adapt to different devices automatically. + +### Example +This example shows a simple vertical stack, with a gap between each item defined using a [Hopper space token](/tokens/semantic/space). + + + +### Learn more + +You can learn more about `Flex` and see more examples on the [Flex](./Flex) page. In addition, +there are many great resources on the web for learning flexbox. + +* [The MDN guide to flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout) — full walkthrough +of flexbox layout. +* [A Complete Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) — great reference for all of the +properties supported by flexbox. + ## Grid -## Responsive layout +[CSS grid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout) +is a powerful way to lay out elements in two dimensions. It can be used to to build full page application +layouts, or smaller user interface elements. It is especially powerful because it allows you to build many types of +layouts without extra presentational elements, keeping your code clean and semantic. In addition, grid layouts +are automatically mirrored in right-to-left languages. + +The [Grid](./Grid) component can be used as a container to define a grid layout. Any Hopper component can be used as +a child of a `Grid`. The `Grid` component extends the CSS syntax to support +defining grids using [Hopper-defined dimension tokens](/tokens/core/dimensions). +This ensures that sizing and spacing is consistent between applications, and allows the layout to adapt to different devices +automatically. + +### Defining grids + +There are many ways to define grids, but the simplest is to use the `areas` prop to declaratively +specify your layout using named areas. This prop accepts an array of strings which represent rows. Within the rows, +you specify space separated names for grid areas. The children of the `Grid` can declare the `gridArea` prop, which +places them into these named regions. + +In addition, you can define the `columns` and `rows` +props on the `Grid` container to specify the widths and heights of the columns and rows respectively. This can be +done using [Hopper-defined dimension tokens](/tokens/core/dimensions) to ensure they are adaptive on various devices. -{/* TODO Make sure to include Link to responsive styles page */} +The following example shows how you could use `Grid` to declare a common application layout, with a header, sidebar, +content area, and footer. Notice how there are no nested layout elements — the layout is entirely declared in the +`Grid` and the children simply declare where they should be placed. -## Slots + + +### Learn more + +You can learn more about `Grid` and see more examples on the [Grid](./Grid) page. In addition, +there are many great resources on the web for learning CSS grid. + +* [The MDN guide to CSS grid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout) — full walkthrough of +grid layout. +* [A Complete Guide to Grid](https://css-tricks.com/snippets/css/complete-guide-grid) — great reference for all of the +properties supported by grid. +* [The Difference Between Explicit and Implicit Grids](https://css-tricks.com/difference-explicit-implicit-grids/) — an +article that discusses the various ways of defining grids. + +## Responsive layout -{/* TODO: Brielfy mention slots, but link to the slots concept page. */} +All props of the Flex and Grid components support object syntax to specify different values for the prop depending on the responsive breakpoint. +You can learn more about responsive styles on the [Responsive Styles](./responsive-styles) page. diff --git a/apps/docs/content/components/concepts/styling.mdx b/apps/docs/content/components/concepts/styling.mdx index 6b6d7131c..dece9dd3a 100644 --- a/apps/docs/content/components/concepts/styling.mdx +++ b/apps/docs/content/components/concepts/styling.mdx @@ -1,6 +1,6 @@ --- title: Styling (WIP) -description: This page describes how styling works in Hopper, including how to customize spacing, sizing, and positioning, and how to create your own custom components using Spectrum styles. +description: This page describes how styling works in Hopper, including how to customize spacing, sizing, and positioning, and how to create your own custom components using Hopper styles. order: 2 --- @@ -12,7 +12,7 @@ Hopper components are designed to be consistent across all Workleap applications A Hopper style property is a mapping of a CSS property to a component property. With style props, Hopper let you easily set style values for a curated set of CSS properties like font-size, margin, padding, width and many more. -All of the available style props are listed in the ["Properties List"](#Properties-List) section below. +All of the available style props are listed in the ["Properties List"](#properties-list) section below. ### Usage @@ -21,37 +21,24 @@ By default, only tokens are accepted as values for style props. They help promot If you need to pass a custom value, you can use the `UNSAFE_` prefix to bypass the token system. You can refer to the ["Escape hatches"](#Escape-hatches) section for more information. -{/* TODO: example */} -```tsx -
- Style properties are fun. -
-``` + ### Shorthands -Props like border and paddingX are also provided to help you save keystrokes. An exhaustive list of all the supported props is available in the ["Properties List"](#Properties-List) section. +Props like border and paddingX are also provided to help you save keystrokes. An exhaustive list of all the supported props is available in the ["Properties List"](#properties-list) section. -{/* TODO: example */} -```tsx -
- Shorthands. -
-``` + ### Escape hatches - TODO -using the `UNSAFE_` properties +While we encourage teams to utilize Hopper styles as it is, we do realize that sometimes product specific customizations may be needed. In these cases, we encourage you or your designers to talk to us. We may be able to suggest an alternative implementation strategy, or perhaps your design can help inform future Hopper additions. + +While the traditional className and style props are always supported in Hopper components, we also provide an escape hatch for passing custom values to style props. This is done by prefixing the prop name with `UNSAFE_`. + +The `UNSAFE_` prefix might look scary, but it's there to remind you that you're bypassing the token system. It's a way to ensure that you're aware that you're doing something that might not be automatically updated when tokens change. +It will also help you to search for these usages when you want to update them, or help us to provide missing tokens. + + ### Pseudo-classes @@ -61,14 +48,13 @@ When a CSS pseudo-class is not supported by Hopper style props, we recommend usi Since the following user action pseudo-classes are often used, some style props support them. These behaves like their pseudo CSS counterparts. -{/* TODO: table */} -|Suffix | Pseudo state | -|---|---| -| active | :active | -| hover | :hover | -| focus | :focus | + -Not all style props support user action pseudo-classes. Find out which props support user action pseudo-classes in the ["Properties List"](#Properties-List) section. +Not all style props support user action pseudo-classes. Find out which props support user action pseudo-classes in the ["Properties List"](#properties-list) section. ## HTML Elements @@ -82,7 +68,27 @@ For text elements, prefer a `` or `` component rather than ` + +### `useStyledSystem` + +If you need to build a more complex component, you can use the `useStyledSystem` function. This function allows you to create a custom component with Hopper style props. + +The `useStyledSystem` function returns a `stylingProps` object containing a resulting style object and a className. You can then spread the `stylingProps` object on your component, or merge them with your existing className and style properties. + +We don't automatically merge the `className` and `style` props because most of the className and style props in Hopper also accept a function. + + ## Properties List @@ -90,22 +96,44 @@ The following tables provide a list of all available style props by category. ### Space +{/* TODO */} + ### Color +{/* TODO */} + ### Typography +{/* TODO */} + ### Layout +{/* TODO */} + ### Flex Layout +{/* TODO */} + ### Grid Layout +{/* TODO */} + ### Background +{/* TODO */} + ### Border +{/* TODO */} + ### Position +{/* TODO */} + ### Shadow +{/* TODO */} + ### Miscellaneous + +{/* TODO */} diff --git a/apps/docs/examples/Preview.ts b/apps/docs/examples/Preview.ts index 910d9f0ac..11f6a8b9d 100644 --- a/apps/docs/examples/Preview.ts +++ b/apps/docs/examples/Preview.ts @@ -62,6 +62,12 @@ export const Previews: Record = { "HopperProvider/docs/color-scheme/useColorSchemeValue": { component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx")) }, + "HopperProvider/docs/layout/flex": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/layout/flex.tsx")) + }, + "HopperProvider/docs/layout/grid": { + component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/layout/grid.tsx")) + }, "HopperProvider/docs/responsive-styles/introduction": { component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx")) }, diff --git a/packages/components/src/HopperProvider/docs/hopper-provider/client-side-routing.tsx b/packages/components/src/HopperProvider/docs/hopper-provider/client-side-routing.tsx new file mode 100644 index 000000000..462e0b81f --- /dev/null +++ b/packages/components/src/HopperProvider/docs/hopper-provider/client-side-routing.tsx @@ -0,0 +1,12 @@ +import { HopperProvider } from "@hopper-ui/components"; + +export default function Example() { + // @ts-expect-error - This is a fake implementation + const navigate = useNavigateFromYourRouter(); + + return ( + +
{/* Your app here */}
+
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/hopper-provider/color-scheme.tsx b/packages/components/src/HopperProvider/docs/hopper-provider/color-scheme.tsx new file mode 100644 index 000000000..10ebec2c5 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/hopper-provider/color-scheme.tsx @@ -0,0 +1,9 @@ +import { Button, HopperProvider } from "@hopper-ui/components"; + +export default function Example() { + return ( + + + + ); +} diff --git a/packages/components/src/HopperProvider/docs/hopper-provider/inject-body-style.tsx b/packages/components/src/HopperProvider/docs/hopper-provider/inject-body-style.tsx new file mode 100644 index 000000000..d9fb9b775 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/hopper-provider/inject-body-style.tsx @@ -0,0 +1,9 @@ +import { HopperProvider } from "@hopper-ui/components"; + +export default function Example() { + return ( + +
{/* Your app here */}
+
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/hopper-provider/inject-css-var.tsx b/packages/components/src/HopperProvider/docs/hopper-provider/inject-css-var.tsx new file mode 100644 index 000000000..1d3b5b698 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/hopper-provider/inject-css-var.tsx @@ -0,0 +1,9 @@ +import { HopperProvider } from "@hopper-ui/components"; + +export default function Example() { + return ( + +
{/* Your app here */}
+
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/hopper-provider/locale.tsx b/packages/components/src/HopperProvider/docs/hopper-provider/locale.tsx new file mode 100644 index 000000000..42e83959e --- /dev/null +++ b/packages/components/src/HopperProvider/docs/hopper-provider/locale.tsx @@ -0,0 +1,9 @@ +import { HopperProvider } from "@hopper-ui/components"; + +export default function Example() { + return ( + +
{/* Your app here */}
+
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/hopper-provider/preview.tsx b/packages/components/src/HopperProvider/docs/hopper-provider/preview.tsx new file mode 100644 index 000000000..9401b38fe --- /dev/null +++ b/packages/components/src/HopperProvider/docs/hopper-provider/preview.tsx @@ -0,0 +1,11 @@ +import { Button, HopperProvider } from "@hopper-ui/components"; + +export default function Example() { + return ( + + + + ); +} diff --git a/packages/components/src/HopperProvider/docs/layout/flex.tsx b/packages/components/src/HopperProvider/docs/layout/flex.tsx new file mode 100644 index 000000000..f512a709c --- /dev/null +++ b/packages/components/src/HopperProvider/docs/layout/flex.tsx @@ -0,0 +1,11 @@ +import { Div, Flex } from "@hopper-ui/components"; + +export default function Example() { + return ( + +
+
+
+ + ); +} diff --git a/packages/components/src/HopperProvider/docs/layout/grid.tsx b/packages/components/src/HopperProvider/docs/layout/grid.tsx new file mode 100644 index 000000000..7633b8ce7 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/layout/grid.tsx @@ -0,0 +1,23 @@ +import { Div, Grid } from "@hopper-ui/components"; + +export default function Example() { + return ( + +
+
+
+
+ + ); +} diff --git a/packages/components/src/HopperProvider/docs/styling/custom-component-html.tsx b/packages/components/src/HopperProvider/docs/styling/custom-component-html.tsx new file mode 100644 index 000000000..c7ddafcf6 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/styling/custom-component-html.tsx @@ -0,0 +1,21 @@ +import { Div, DivProps } from "@hopper-ui/components"; + +interface MyCustomComponentProps extends Omit { + // your custom props here +} + +function MyCustomComponent(props: MyCustomComponentProps) { + return ( +
+ My Custom component +
+ ) +} + +export default function Example() { + return ( + + ); +} diff --git a/packages/components/src/HopperProvider/docs/styling/custom-component-useStyledSystem.tsx b/packages/components/src/HopperProvider/docs/styling/custom-component-useStyledSystem.tsx new file mode 100644 index 000000000..12771fbfb --- /dev/null +++ b/packages/components/src/HopperProvider/docs/styling/custom-component-useStyledSystem.tsx @@ -0,0 +1,28 @@ +import { Div, DivProps, useStyledSystem } from "@hopper-ui/components"; +import { forwardRef } from "react"; + +interface MyCustomComponentProps extends Omit { + // your custom props here +} + +function MyCustomComponent(props: MyCustomComponentProps) { + const { stylingProps, ...ownProps } = useStyledSystem(props); + const { className, style } = ownProps; + + const classNames = `${stylingProps.className} ${className}`; + const mergedStyles = { ...stylingProps.style, ...style }; + + return ( +
+ My Custom component +
+ ) +}; + +export default function Example() { + return ( + + ); +} diff --git a/packages/components/src/HopperProvider/docs/styling/escape-hatch.tsx b/packages/components/src/HopperProvider/docs/styling/escape-hatch.tsx new file mode 100644 index 000000000..13aa80452 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/styling/escape-hatch.tsx @@ -0,0 +1,18 @@ +import { Div } from "@hopper-ui/components"; + +export default function Example() { + return ( +
+ Style properties are fun. +
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/styling/shorthands.tsx b/packages/components/src/HopperProvider/docs/styling/shorthands.tsx new file mode 100644 index 000000000..78d6dcad2 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/styling/shorthands.tsx @@ -0,0 +1,9 @@ +import { Div } from "@hopper-ui/components"; + +export default function Example() { + return ( +
+ Shorthands. +
+ ); +} diff --git a/packages/components/src/HopperProvider/docs/styling/usage.tsx b/packages/components/src/HopperProvider/docs/styling/usage.tsx new file mode 100644 index 000000000..1138ecd50 --- /dev/null +++ b/packages/components/src/HopperProvider/docs/styling/usage.tsx @@ -0,0 +1,18 @@ +import { Div } from "@hopper-ui/components"; + +export default function Example() { + return ( +
+ Style properties are fun. +
+ ); +} From 8b989f0acabbd2ce333d5a941a68f8e22a3d0c83 Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 14:29:48 -0400 Subject: [PATCH 05/16] update component list --- .../docs/content/components/getting-started/component-list.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/docs/content/components/getting-started/component-list.mdx b/apps/docs/content/components/getting-started/component-list.mdx index d41819f98..541cda8c2 100644 --- a/apps/docs/content/components/getting-started/component-list.mdx +++ b/apps/docs/content/components/getting-started/component-list.mdx @@ -1,6 +1,5 @@ --- -title: Component List (WIP) -description: TBD +title: Component List order: 2 --- From 3203aca06cf3da2e67cfc371ee8328325b0da83b Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 14:31:34 -0400 Subject: [PATCH 06/16] fix title --- apps/docs/content/components/concepts/styling.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/content/components/concepts/styling.mdx b/apps/docs/content/components/concepts/styling.mdx index dece9dd3a..b8526179d 100644 --- a/apps/docs/content/components/concepts/styling.mdx +++ b/apps/docs/content/components/concepts/styling.mdx @@ -80,7 +80,7 @@ This is an example using a `Div`, but you can use any of the HTML Element compon -### `useStyledSystem` +### useStyledSystem If you need to build a more complex component, you can use the `useStyledSystem` function. This function allows you to create a custom component with Hopper style props. From 526260f2641c33003894ddf7b96f142a4509cd3a Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 15:00:33 -0400 Subject: [PATCH 07/16] fix some articles --- .../content/components/buttons/Button.mdx | 38 +++++++++++++++++-- .../content/components/navigation/Link.mdx | 2 +- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/apps/docs/content/components/buttons/Button.mdx b/apps/docs/content/components/buttons/Button.mdx index fb9a20b68..f94a0e46e 100644 --- a/apps/docs/content/components/buttons/Button.mdx +++ b/apps/docs/content/components/buttons/Button.mdx @@ -1,5 +1,5 @@ --- -title: Button +title: Button (TODO) description: Buttons are used to initialize an action. Button labels express what action will occur when the user interacts with it. category: "buttons" links: @@ -12,6 +12,29 @@ links: +## Guidelines + +TODO: If we have some guidelines about this component's usage + +### Accessibility ? + +TODO: If we have some guidelines about this component and accessibility + +## Anatomy + +TODO: We have anatomy screenshots from the Figma, we could most likely use them here + +### Concepts + +- [Client Side Routing](./client-side-routing) + +### Composed Components + +A `Button` uses the following components. + +- [Icon](./Icon) +- [Text](./Text) + ## Examples ### Variants @@ -27,7 +50,7 @@ A button can use different variants. **Danger** - For actions that could have destructive effects on the user’s data. -**Ghost-[primary|secondary|danger]** - For less prominent, and sometimes independent, actions. Ghost buttons can be used in isolation or paired with a primary button when there are multiple calls to action. Ghost buttons can also be used for sub-tasks on a +**Ghost ** -[primary|secondary|danger]** - For less prominent, and sometimes independent, actions. Ghost buttons can be used in isolation or paired with a primary button when there are multiple calls to action. Ghost buttons can also be used for sub-tasks on a page where a primary button for the main and final action is present. ### Sizes @@ -75,8 +98,9 @@ A button can be rendered as a react router link when using the href property, an +## Advanced customization -### Advanced Customization +### Contexts All Hopper Components exports a corresponding context that can be used to send props to them from a parent element. You can send any prop or ref via context that you could pass to the corresponding component. @@ -84,6 +108,14 @@ The local props and ref on the component are merged with the ones passed via con +### Custom Children + +TODO: Example of passing custom childrens to the components to fake a slot + +### Custom Component + +TODO: Example of creating a custom version of this component + ## Migration Notes (WIP) diff --git a/apps/docs/content/components/navigation/Link.mdx b/apps/docs/content/components/navigation/Link.mdx index 326fafcf5..05cc1e3b9 100644 --- a/apps/docs/content/components/navigation/Link.mdx +++ b/apps/docs/content/components/navigation/Link.mdx @@ -1,5 +1,5 @@ --- -title: TextLink (WIP) +title: Link (WIP) description: TBD category: "navigation" links: From dd704b9a89bc6d9a42c8a752638b177c7300ee6c Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 15:01:03 -0400 Subject: [PATCH 08/16] add wip --- apps/docs/content/components/buttons/Button.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/content/components/buttons/Button.mdx b/apps/docs/content/components/buttons/Button.mdx index f94a0e46e..65938d5e8 100644 --- a/apps/docs/content/components/buttons/Button.mdx +++ b/apps/docs/content/components/buttons/Button.mdx @@ -1,5 +1,5 @@ --- -title: Button (TODO) +title: Button (WIP) description: Buttons are used to initialize an action. Button labels express what action will occur when the user interacts with it. category: "buttons" links: From 8d16b126b940118fb914aa01128cd0bb5ace4e2b Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 15:03:48 -0400 Subject: [PATCH 09/16] remove wrong name --- apps/docs/.eslintrc.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/docs/.eslintrc.json b/apps/docs/.eslintrc.json index 0238f4a1a..66d9a5c27 100644 --- a/apps/docs/.eslintrc.json +++ b/apps/docs/.eslintrc.json @@ -13,7 +13,6 @@ "Card": true, "Callout": true, "Collapsible": true, - "Table": true, "TokenTable": true, "MotionPreview": true, "Footnote": true, From 6187cb5ab853819b183b00669f47a5ba47227651 Mon Sep 17 00:00:00 2001 From: Alexandre Asselin Date: Fri, 28 Jun 2024 15:04:54 -0400 Subject: [PATCH 10/16] fix build --- .../docs/styling/custom-component-useStyledSystem.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/components/src/HopperProvider/docs/styling/custom-component-useStyledSystem.tsx b/packages/components/src/HopperProvider/docs/styling/custom-component-useStyledSystem.tsx index 12771fbfb..64e1468dd 100644 --- a/packages/components/src/HopperProvider/docs/styling/custom-component-useStyledSystem.tsx +++ b/packages/components/src/HopperProvider/docs/styling/custom-component-useStyledSystem.tsx @@ -1,5 +1,4 @@ -import { Div, DivProps, useStyledSystem } from "@hopper-ui/components"; -import { forwardRef } from "react"; +import { type DivProps, useStyledSystem } from "@hopper-ui/components"; interface MyCustomComponentProps extends Omit { // your custom props here @@ -16,8 +15,8 @@ function MyCustomComponent(props: MyCustomComponentProps) {
My Custom component
- ) -}; + ); +} export default function Example() { return ( From 718b79dda76d269945b82c25f2846aca050b599c Mon Sep 17 00:00:00 2001 From: Franck Gaudin Date: Wed, 3 Jul 2024 15:51:37 -0400 Subject: [PATCH 11/16] chore(doc): work on Callout component --- .../components/callout/Callout.stories.tsx | 2 +- apps/docs/components/callout/Callout.tsx | 28 +++++++++++++++---- apps/docs/components/mdx/components.tsx | 3 +- .../components/application/HopperProvider.mdx | 2 +- .../components/concepts/responsive-styles.mdx | 3 +- 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/apps/docs/components/callout/Callout.stories.tsx b/apps/docs/components/callout/Callout.stories.tsx index bba9613fe..3771f972e 100644 --- a/apps/docs/components/callout/Callout.stories.tsx +++ b/apps/docs/components/callout/Callout.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; -import Callout from "./Callout.tsx"; +import { Callout } from "./Callout.tsx"; const meta = { title: "components/Callout", diff --git a/apps/docs/components/callout/Callout.tsx b/apps/docs/components/callout/Callout.tsx index f31705329..924deae83 100644 --- a/apps/docs/components/callout/Callout.tsx +++ b/apps/docs/components/callout/Callout.tsx @@ -1,17 +1,35 @@ -import type { ReactNode } from "react"; +import { createContext, type ForwardedRef, forwardRef, type ReactNode } from "react"; +import { type ContextValue, useContextProps } from "react-aria-components"; +import clsx from "clsx"; import "./callout.css"; export interface CalloutProps { children: ReactNode; + className?: string; + variant?: "information" | "success" | "warning"; } -const Callout = ({ children }: CalloutProps) => { +function Callout(props: CalloutProps, ref: ForwardedRef) { + [props, ref] = useContextProps(props, ref, CalloutContext); + const { children, className, variant = "information", ...other } = props; + return ( -
+
{children}
); -}; +} + +export const CalloutContext = createContext, HTMLDivElement>>({}); + +const _Callout = forwardRef(Callout); +_Callout.displayName = "Callout"; -export default Callout; +export { _Callout as Callout }; diff --git a/apps/docs/components/mdx/components.tsx b/apps/docs/components/mdx/components.tsx index 054841aa3..b3efebb1d 100644 --- a/apps/docs/components/mdx/components.tsx +++ b/apps/docs/components/mdx/components.tsx @@ -2,7 +2,7 @@ import type { HTMLAttributes, DetailedHTMLProps } from "react"; import dynamic from "next/dynamic"; import Card from "@/components/card/Card.tsx"; -import Callout from "@/components/callout/Callout.tsx"; +import { Callout } from "@/components/callout/Callout.tsx"; import NextImage from "@/components/image/Image.tsx"; import Pre from "@/components/pre/Pre.tsx"; import InlineCode from "@/components/code/InlineCode.tsx"; @@ -74,6 +74,7 @@ export const components = { return } />; }, diff --git a/apps/docs/content/components/application/HopperProvider.mdx b/apps/docs/content/components/application/HopperProvider.mdx index 779a3bf9b..c0cade38a 100644 --- a/apps/docs/content/components/application/HopperProvider.mdx +++ b/apps/docs/content/components/application/HopperProvider.mdx @@ -7,7 +7,7 @@ links: source: https://github.com/gsoft-inc/wl-hopper/blob/main/packages/components/src/HopperProvider/src/HopperProvider.tsx --- - + ## Props (WIP) diff --git a/apps/docs/content/components/concepts/responsive-styles.mdx b/apps/docs/content/components/concepts/responsive-styles.mdx index 646f348c4..1e5af451b 100644 --- a/apps/docs/content/components/concepts/responsive-styles.mdx +++ b/apps/docs/content/components/concepts/responsive-styles.mdx @@ -15,8 +15,7 @@ In this example, the `Div` has a default background color, which is overridden a ## Breakpoints There are five breakpoints available (+ the base), inspired by common device resolutions: - -{/* TODO: do a table here */} +x ## Working mobile-first From 28cd22faa85c730f7a73ec2a116e410c6a095849 Mon Sep 17 00:00:00 2001 From: Franck Gaudin Date: Thu, 4 Jul 2024 13:18:38 -0400 Subject: [PATCH 12/16] chore(docs): add variant feature on Callout component --- .../components/callout/Callout.stories.tsx | 30 +++++++++++- apps/docs/components/callout/Callout.tsx | 17 ++++++- apps/docs/components/callout/callout.css | 49 +++++++++++++++++-- apps/docs/components/icon/assets/check.svg | 10 ++++ apps/docs/components/icon/assets/error.svg | 11 +++++ apps/docs/components/icon/assets/info.svg | 11 +++++ apps/docs/components/icon/assets/message.svg | 5 ++ apps/docs/components/icon/assets/warning.svg | 8 +++ apps/docs/components/icon/index.tsx | 11 +++++ 9 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 apps/docs/components/icon/assets/check.svg create mode 100644 apps/docs/components/icon/assets/error.svg create mode 100644 apps/docs/components/icon/assets/info.svg create mode 100644 apps/docs/components/icon/assets/message.svg create mode 100644 apps/docs/components/icon/assets/warning.svg diff --git a/apps/docs/components/callout/Callout.stories.tsx b/apps/docs/components/callout/Callout.stories.tsx index 3771f972e..a25d19bf5 100644 --- a/apps/docs/components/callout/Callout.stories.tsx +++ b/apps/docs/components/callout/Callout.stories.tsx @@ -4,14 +4,40 @@ import { Callout } from "./Callout.tsx"; const meta = { title: "components/Callout", - component: Callout + component: Callout, + args: { + children: "Content of the callout" + } } satisfies Meta; export default meta; type Story = StoryObj; export const Default: Story = { + args: {} +}; + +export const Warning: Story = { args: { - children: "Content of the callout" + variant: "warning" + } +}; + +export const Success: Story = { + args: { + variant: "success" } }; + +export const Error: Story = { + args: { + variant: "error" + } +}; + +export const Message: Story = { + args: { + variant: "message" + } +}; + diff --git a/apps/docs/components/callout/Callout.tsx b/apps/docs/components/callout/Callout.tsx index 924deae83..108a9370e 100644 --- a/apps/docs/components/callout/Callout.tsx +++ b/apps/docs/components/callout/Callout.tsx @@ -1,19 +1,33 @@ +"use client"; + import { createContext, type ForwardedRef, forwardRef, type ReactNode } from "react"; import { type ContextValue, useContextProps } from "react-aria-components"; import clsx from "clsx"; +import { Icon, WarningIcon, CheckIcon, ErrorIcon, InfoIcon, MessageIcon } from "@/components/icon"; + import "./callout.css"; export interface CalloutProps { children: ReactNode; className?: string; - variant?: "information" | "success" | "warning"; + variant?: "information" | "success" | "warning" | "error" | "message"; } function Callout(props: CalloutProps, ref: ForwardedRef) { [props, ref] = useContextProps(props, ref, CalloutContext); const { children, className, variant = "information", ...other } = props; + const iconMap = { + information: InfoIcon, + success: CheckIcon, + warning: WarningIcon, + error: ErrorIcon, + message: MessageIcon + }; + + const IconSrc = iconMap[variant] || InfoIcon; + return (
) { ref={ref} role="alert" > + {children}
); diff --git a/apps/docs/components/callout/callout.css b/apps/docs/components/callout/callout.css index b0fb23109..f5207f5ae 100644 --- a/apps/docs/components/callout/callout.css +++ b/apps/docs/components/callout/callout.css @@ -1,6 +1,49 @@ .hd-callout { - background-color: var(--hd-color-accent-surface); + --hd-callout-icon-color: var(--hd-color-neutral-text); + --hd-callout-background-color: transparent; + + display: flex; + gap: 0.5rem; + align-items: center; + + font-family: var(--hd-title-font-family); + font-size: var(--hd-default-font-size); + line-height: 1.3; + + padding-block: var(--hd-space-2); + padding-inline: var(--hd-space-2); + + margin-block: var(--hd-space-3); + border-radius: 0.25rem; - border-left: 0.25rem solid var(--hd-color-accent-border); - padding: 1rem; + background-color: var(--hd-callout-background-color); +} + +.hd-callout__icon { + color: var(--hd-callout-icon-color); +} + +.hd-callout--information { + --hd-callout-icon-color: var(--hd-color-information-icon); + --hd-callout-background-color: var(--hd-color-information-surface); +} + +.hd-callout--warning { + --hd-callout-icon-color: var(--hd-color-warning-icon); + --hd-callout-background-color: var(--hd-color-warning-surface); +} + +.hd-callout--success { + --hd-callout-icon-color: var(--hd-color-success-icon); + --hd-callout-background-color: var(--hd-color-success-surface); +} + +.hd-callout--error { + --hd-callout-icon-color: var(--hd-color-error-icon); + --hd-callout-background-color: var(--hd-color-error-surface); +} + +.hd-callout--message { + --hd-callout-icon-color: var(--hd-color-message-icon); + --hd-callout-background-color: var(--hd-color-message-surface); } diff --git a/apps/docs/components/icon/assets/check.svg b/apps/docs/components/icon/assets/check.svg new file mode 100644 index 000000000..058846cd2 --- /dev/null +++ b/apps/docs/components/icon/assets/check.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/apps/docs/components/icon/assets/error.svg b/apps/docs/components/icon/assets/error.svg new file mode 100644 index 000000000..048151e8f --- /dev/null +++ b/apps/docs/components/icon/assets/error.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/apps/docs/components/icon/assets/info.svg b/apps/docs/components/icon/assets/info.svg new file mode 100644 index 000000000..9f709a8fe --- /dev/null +++ b/apps/docs/components/icon/assets/info.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/apps/docs/components/icon/assets/message.svg b/apps/docs/components/icon/assets/message.svg new file mode 100644 index 000000000..b3500fff5 --- /dev/null +++ b/apps/docs/components/icon/assets/message.svg @@ -0,0 +1,5 @@ + + + diff --git a/apps/docs/components/icon/assets/warning.svg b/apps/docs/components/icon/assets/warning.svg new file mode 100644 index 000000000..ae852bd1c --- /dev/null +++ b/apps/docs/components/icon/assets/warning.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/apps/docs/components/icon/index.tsx b/apps/docs/components/icon/index.tsx index 20f451e88..b1f1e6f0a 100644 --- a/apps/docs/components/icon/index.tsx +++ b/apps/docs/components/icon/index.tsx @@ -15,6 +15,12 @@ import TypescriptIcon from "./assets/typescript.svg"; import CollapseIcon from "./assets/collapse.svg"; import CodeIcon from "./assets/code.svg"; import EmptyComponent from "./assets/empty-component.svg"; +import CheckIcon from "./assets/check.svg"; +import ErrorIcon from "./assets/error.svg"; +import InfoIcon from "./assets/info.svg"; +import MessageIcon from "./assets/message.svg"; +import WarningIcon from "./assets/warning.svg"; + import Icon, { type IconProps } from "./Icon.tsx"; export { @@ -35,6 +41,11 @@ export { CodeIcon, TypescriptIcon, EmptyComponent, + CheckIcon, + ErrorIcon, + InfoIcon, + MessageIcon, + WarningIcon, Icon, IconProps }; From 94583442921c49c09ce0d723b2564b254459c8f6 Mon Sep 17 00:00:00 2001 From: Franck Gaudin Date: Thu, 4 Jul 2024 13:19:27 -0400 Subject: [PATCH 13/16] chore(docs): modify layout and content according to PR comments --- apps/docs/app/tokens.css | 24 +++++++++++++++++++ .../app/ui/components/overview/overview.css | 13 ++++++---- .../content/components/concepts/layout.mdx | 4 ++-- .../components/concepts/responsive-styles.mdx | 8 +++---- apps/docs/examples/Preview.ts | 8 +++---- .../docs/color-scheme/changing.tsx | 2 +- .../docs/layout => layout/docs}/flex.tsx | 0 .../docs/layout => layout/docs}/grid.tsx | 0 8 files changed, 42 insertions(+), 17 deletions(-) rename packages/components/src/{HopperProvider/docs/layout => layout/docs}/flex.tsx (100%) rename packages/components/src/{HopperProvider/docs/layout => layout/docs}/grid.tsx (100%) diff --git a/apps/docs/app/tokens.css b/apps/docs/app/tokens.css index 338f86b7a..e6cc1a8d1 100644 --- a/apps/docs/app/tokens.css +++ b/apps/docs/app/tokens.css @@ -87,6 +87,18 @@ --hd-color-accent-text: var(--hd-accent-700); --hd-color-accent-border: var(--hd-accent-700); --hd-color-accent-surface: var(--hd-accent-100); + + --hd-color-information-surface: #D9EFFF; + --hd-color-information-icon: #2E70A8; + --hd-color-message-surface: var(--hd-accent-100); + --hd-color-message-icon: var(--hd-accent-700); + --hd-color-warning-surface: #FFF8D6; + --hd-color-warning-icon: #E57723; + --hd-color-error-surface: #FDE6E5; + --hd-color-error-icon: #CB2E31; + --hd-color-success-surface: var(--hd-primary-100); + --hd-color-success-icon: var(--hd-primary-600); + --hd-color-surface-neutral-gradient: linear-gradient(0deg, #151515 0%, #353434 100%); --hd-color-surface-neutral-gradient-hover: linear-gradient(0deg, #353434 0%, #151515 100%); --hd-focus-ring: 0 0 0 0.125rem var(--hd-neutral-20), 0 0 0 0.25rem var(--hd-neutral-900); @@ -123,6 +135,18 @@ --hd-color-accent-text: var(--hd-accent-300); --hd-color-accent-border: var(--hd-accent-700); --hd-color-accent-surface: var(--hd-accent-900); + + --hd-color-information-surface: #D9EFFF; + --hd-color-information-icon: #2E70A8; + --hd-color-message-surface: var(--hd-accent-100); + --hd-color-message-icon: var(--hd-accent-700); + --hd-color-warning-surface: #FFF8D6; + --hd-color-warning-icon: #E57723; + --hd-color-error-surface: #FDE6E5; + --hd-color-error-icon: #CB2E31; + --hd-color-success-surface: var(--hd-primary-100); + --hd-color-success-icon: var(--hd-primary-600); + --hd-color-surface-neutral-gradient: linear-gradient(0deg, #F4F3EE 0%, var(--hd-neutral-0) 100%); --hd-color-surface-neutral-gradient-hover: linear-gradient(0deg, var(--hd-neutral-0) 0%, #F4F3EE 100%); --hd-focus-ring: 0 0 0 0.125rem var(--hd-neutral-800), 0 0 0 0.25rem var(--hd-neutral-20); diff --git a/apps/docs/app/ui/components/overview/overview.css b/apps/docs/app/ui/components/overview/overview.css index 27b061412..064760383 100644 --- a/apps/docs/app/ui/components/overview/overview.css +++ b/apps/docs/app/ui/components/overview/overview.css @@ -4,9 +4,16 @@ grid-template-columns: repeat(auto-fill, minmax(18.125rem, 1fr)); } +.hd-component-overview-item__link { + display: grid; + grid-template-rows: 9rem 1fr; + justify-items: stretch; + width: 100%; + height: 100%; +} + .hd-component-overview-item { overflow: hidden; - flex-direction: column; transition: box-shadow cubic-bezier(0.4, 0, 0.2, 1) 0.4s; } @@ -24,12 +31,8 @@ align-items: center; justify-content: center; width: 100%; - aspect-ratio: 16 / 9; } -.hd-component-overview-item__link { - width: 100%; -} .hd-component-overview-item__title { font-size: 1.125rem; diff --git a/apps/docs/content/components/concepts/layout.mdx b/apps/docs/content/components/concepts/layout.mdx index 32a3f94a9..dd53e7c81 100644 --- a/apps/docs/content/components/concepts/layout.mdx +++ b/apps/docs/content/components/concepts/layout.mdx @@ -38,7 +38,7 @@ to ensure consistency across applications, and allow the layout to adapt to diff ### Example This example shows a simple vertical stack, with a gap between each item defined using a [Hopper space token](/tokens/semantic/space). - + ### Learn more @@ -79,7 +79,7 @@ The following example shows how you could use `Grid` to declare a common applica content area, and footer. Notice how there are no nested layout elements — the layout is entirely declared in the `Grid` and the children simply declare where they should be placed. - + ### Learn more diff --git a/apps/docs/content/components/concepts/responsive-styles.mdx b/apps/docs/content/components/concepts/responsive-styles.mdx index 1e5af451b..eb94a5d2e 100644 --- a/apps/docs/content/components/concepts/responsive-styles.mdx +++ b/apps/docs/content/components/concepts/responsive-styles.mdx @@ -15,7 +15,7 @@ In this example, the `Div` has a default background color, which is overridden a ## Breakpoints There are five breakpoints available (+ the base), inspired by common device resolutions: -x + ## Working mobile-first @@ -23,13 +23,11 @@ x By default, Hopper uses a mobile-first breakpoint system, similar to what you might be used to in other frameworks like Bootstrap or Tailwind. {/* TODO start the sentence with a */} -**Don't use `sm:` to target mobile devices** +Don't use `sm:` to target mobile devices - -{/* TODO start the sentence with a */} -**Use `base` to target mobile, and override them at larger breakpoints** +Use `base` to target mobile devices diff --git a/apps/docs/examples/Preview.ts b/apps/docs/examples/Preview.ts index 11f6a8b9d..cf945172a 100644 --- a/apps/docs/examples/Preview.ts +++ b/apps/docs/examples/Preview.ts @@ -62,11 +62,11 @@ export const Previews: Record = { "HopperProvider/docs/color-scheme/useColorSchemeValue": { component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/color-scheme/useColorSchemeValue.tsx")) }, - "HopperProvider/docs/layout/flex": { - component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/layout/flex.tsx")) + "layout/docs/flex": { + component: lazy(() => import("@/../../packages/components/src/layout/docs/flex.tsx")) }, - "HopperProvider/docs/layout/grid": { - component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/layout/grid.tsx")) + "layout/docs/grid": { + component: lazy(() => import("@/../../packages/components/src/layout/docs/grid.tsx")) }, "HopperProvider/docs/responsive-styles/introduction": { component: lazy(() => import("@/../../packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx")) diff --git a/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx b/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx index 5d4c29795..2bd921435 100644 --- a/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx +++ b/packages/components/src/HopperProvider/docs/color-scheme/changing.tsx @@ -25,7 +25,7 @@ export default function Example() { return ( -
+
diff --git a/packages/components/src/HopperProvider/docs/layout/flex.tsx b/packages/components/src/layout/docs/flex.tsx similarity index 100% rename from packages/components/src/HopperProvider/docs/layout/flex.tsx rename to packages/components/src/layout/docs/flex.tsx diff --git a/packages/components/src/HopperProvider/docs/layout/grid.tsx b/packages/components/src/layout/docs/grid.tsx similarity index 100% rename from packages/components/src/HopperProvider/docs/layout/grid.tsx rename to packages/components/src/layout/docs/grid.tsx From f9949d8932beef7fbcd177d67fbd643f8811e185 Mon Sep 17 00:00:00 2001 From: Franck Gaudin Date: Thu, 4 Jul 2024 13:41:36 -0400 Subject: [PATCH 14/16] chore(docs): modify layout and content according to PR comments --- apps/docs/app/tokens.css | 4 ---- .../componentExample/componentPreviewWrapper.css | 2 ++ apps/docs/components/callout/callout.css | 6 ++---- apps/docs/content/components/concepts/color-schemes.mdx | 1 + apps/docs/content/components/concepts/layout.mdx | 7 +++---- .../HopperProvider/docs/responsive-styles/introduction.tsx | 3 +-- 6 files changed, 9 insertions(+), 14 deletions(-) diff --git a/apps/docs/app/tokens.css b/apps/docs/app/tokens.css index e6cc1a8d1..9018cafcf 100644 --- a/apps/docs/app/tokens.css +++ b/apps/docs/app/tokens.css @@ -87,7 +87,6 @@ --hd-color-accent-text: var(--hd-accent-700); --hd-color-accent-border: var(--hd-accent-700); --hd-color-accent-surface: var(--hd-accent-100); - --hd-color-information-surface: #D9EFFF; --hd-color-information-icon: #2E70A8; --hd-color-message-surface: var(--hd-accent-100); @@ -98,7 +97,6 @@ --hd-color-error-icon: #CB2E31; --hd-color-success-surface: var(--hd-primary-100); --hd-color-success-icon: var(--hd-primary-600); - --hd-color-surface-neutral-gradient: linear-gradient(0deg, #151515 0%, #353434 100%); --hd-color-surface-neutral-gradient-hover: linear-gradient(0deg, #353434 0%, #151515 100%); --hd-focus-ring: 0 0 0 0.125rem var(--hd-neutral-20), 0 0 0 0.25rem var(--hd-neutral-900); @@ -135,7 +133,6 @@ --hd-color-accent-text: var(--hd-accent-300); --hd-color-accent-border: var(--hd-accent-700); --hd-color-accent-surface: var(--hd-accent-900); - --hd-color-information-surface: #D9EFFF; --hd-color-information-icon: #2E70A8; --hd-color-message-surface: var(--hd-accent-100); @@ -146,7 +143,6 @@ --hd-color-error-icon: #CB2E31; --hd-color-success-surface: var(--hd-primary-100); --hd-color-success-icon: var(--hd-primary-600); - --hd-color-surface-neutral-gradient: linear-gradient(0deg, #F4F3EE 0%, var(--hd-neutral-0) 100%); --hd-color-surface-neutral-gradient-hover: linear-gradient(0deg, var(--hd-neutral-0) 0%, #F4F3EE 100%); --hd-focus-ring: 0 0 0 0.125rem var(--hd-neutral-800), 0 0 0 0.25rem var(--hd-neutral-20); diff --git a/apps/docs/app/ui/components/componentExample/componentPreviewWrapper.css b/apps/docs/app/ui/components/componentExample/componentPreviewWrapper.css index 37cca998c..c272b61a7 100644 --- a/apps/docs/app/ui/components/componentExample/componentPreviewWrapper.css +++ b/apps/docs/app/ui/components/componentExample/componentPreviewWrapper.css @@ -10,6 +10,7 @@ .hd-component-preview-wrapper[data-schema="light"] { .hd-component-preview-wrapper__card { --background: var(--hd-white); + --color: var(--hd-neutral-900); --dot-background: var(--hd-neutral-50); } @@ -29,6 +30,7 @@ .hd-component-preview-wrapper[data-schema="dark"] { .hd-component-preview-wrapper__card { --background: var(--hd-neutral-900); + --color: var(--hd-neutral-0); --dot-background: var(--hd-neutral-800); } diff --git a/apps/docs/components/callout/callout.css b/apps/docs/components/callout/callout.css index f5207f5ae..ced650d8f 100644 --- a/apps/docs/components/callout/callout.css +++ b/apps/docs/components/callout/callout.css @@ -1,20 +1,18 @@ .hd-callout { --hd-callout-icon-color: var(--hd-color-neutral-text); --hd-callout-background-color: transparent; + --hd-callout-text-color: var(--hd-neutral-900); display: flex; gap: 0.5rem; align-items: center; - font-family: var(--hd-title-font-family); font-size: var(--hd-default-font-size); line-height: 1.3; - + color: var(--hd-callout-text-color); padding-block: var(--hd-space-2); padding-inline: var(--hd-space-2); - margin-block: var(--hd-space-3); - border-radius: 0.25rem; background-color: var(--hd-callout-background-color); } diff --git a/apps/docs/content/components/concepts/color-schemes.mdx b/apps/docs/content/components/concepts/color-schemes.mdx index c039bfcd0..7d92d9c4f 100644 --- a/apps/docs/content/components/concepts/color-schemes.mdx +++ b/apps/docs/content/components/concepts/color-schemes.mdx @@ -18,6 +18,7 @@ A color scheme can either be enforced by providing a specific light or dark valu A color scheme can also be set to `system`, which will follow the [user's operating system setting](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme). + When the `system` value is provided, an additional fallback color scheme must be specified to defaultColorScheme in case the theme provider is not able to access the user setting. diff --git a/apps/docs/content/components/concepts/layout.mdx b/apps/docs/content/components/concepts/layout.mdx index dd53e7c81..11ba208a2 100644 --- a/apps/docs/content/components/concepts/layout.mdx +++ b/apps/docs/content/components/concepts/layout.mdx @@ -4,21 +4,20 @@ description: This page describes how to build application layouts with Hopper us order: 1 --- -This page will be heavily inspired by https://react-spectrum.adobe.com/react-spectrum/layout.html - ## Introduction -hopper includes layout components to help build applications more easily. The [Flex](./Flex) and [Grid](./Grid) +Hopper includes layout components to help build applications more easily. The [Flex](./Flex) and [Grid](./Grid) components are containers, which are responsible for the layout of their children. `Flex` follows the [CSS flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) algorithm, while `Grid` implements [CSS grid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout). + These components provide props with pre-defined Hopper tokens for sizing, spacing, and other layout options. You can use `Flex` and `Grid` together as needed to build different parts of your application, and even nest them to create more complex layouts. In general, you should prefer using flex and grid over other CSS layout models. Spacing between components -should be left to parent layout components rather than added as via margins to specific children. This helps +should be left to parent layout components rather than added as via margins to specific children. This ensures ensure components are composable when reused in different places, and ensures that spacing is consistent. In addition to `Flex` and `Grid`, some Hopper components include pre-built layouts which you can diff --git a/packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx b/packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx index f179606fc..1a68c4054 100644 --- a/packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx +++ b/packages/components/src/HopperProvider/docs/responsive-styles/introduction.tsx @@ -1,4 +1,3 @@ - import { Div, Text } from "@hopper-ui/components"; export default function Example() { @@ -16,7 +15,7 @@ export default function Example() { maxWidth="100%" padding="inset-md" > - Resize to see the background color change! + Resize the window to see the background color change!
); } From f36b7799e867b5205b5627f09299f96c45072a49 Mon Sep 17 00:00:00 2001 From: Franck Gaudin Date: Thu, 4 Jul 2024 13:44:47 -0400 Subject: [PATCH 15/16] chore(docs): modify layout and content according to PR comments --- apps/docs/content/components/concepts/responsive-styles.mdx | 3 +-- .../src/HopperProvider/docs/styling/custom-component-html.tsx | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/docs/content/components/concepts/responsive-styles.mdx b/apps/docs/content/components/concepts/responsive-styles.mdx index eb94a5d2e..0fc551c00 100644 --- a/apps/docs/content/components/concepts/responsive-styles.mdx +++ b/apps/docs/content/components/concepts/responsive-styles.mdx @@ -22,8 +22,7 @@ There are five breakpoints available (+ the base), inspired by common device res By default, Hopper uses a mobile-first breakpoint system, similar to what you might be used to in other frameworks like Bootstrap or Tailwind. -{/* TODO start the sentence with a */} -Don't use `sm:` to target mobile devices +Don`'`t use `sm:` to target mobile devices diff --git a/packages/components/src/HopperProvider/docs/styling/custom-component-html.tsx b/packages/components/src/HopperProvider/docs/styling/custom-component-html.tsx index c7ddafcf6..cf0770d5f 100644 --- a/packages/components/src/HopperProvider/docs/styling/custom-component-html.tsx +++ b/packages/components/src/HopperProvider/docs/styling/custom-component-html.tsx @@ -1,4 +1,4 @@ -import { Div, DivProps } from "@hopper-ui/components"; +import { Div, type DivProps } from "@hopper-ui/components"; interface MyCustomComponentProps extends Omit { // your custom props here @@ -9,7 +9,7 @@ function MyCustomComponent(props: MyCustomComponentProps) {
My Custom component
- ) + ); } export default function Example() { From 7f029a9f6538b4161367177cc243c6bc1ecf9224 Mon Sep 17 00:00:00 2001 From: Franck Gaudin Date: Thu, 4 Jul 2024 14:46:30 -0400 Subject: [PATCH 16/16] chore(docs): modify layout and content according to PR comments --- apps/docs/content/components/concepts/responsive-styles.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/content/components/concepts/responsive-styles.mdx b/apps/docs/content/components/concepts/responsive-styles.mdx index 0fc551c00..0c2d051b8 100644 --- a/apps/docs/content/components/concepts/responsive-styles.mdx +++ b/apps/docs/content/components/concepts/responsive-styles.mdx @@ -22,7 +22,7 @@ There are five breakpoints available (+ the base), inspired by common device res By default, Hopper uses a mobile-first breakpoint system, similar to what you might be used to in other frameworks like Bootstrap or Tailwind. -Don`'`t use `sm:` to target mobile devices +Don't use `sm:` to target mobile devices