diff --git a/.changeset/fix-tags-input-overflow.md b/.changeset/fix-tags-input-overflow.md index c6d533e5820..ab88196d244 100644 --- a/.changeset/fix-tags-input-overflow.md +++ b/.changeset/fix-tags-input-overflow.md @@ -5,3 +5,6 @@ - **TagsInput**: Fix overflow issue where very long tags would overflow the container instead of truncating with ellipsis. + +- **CheckboxGroup**: Fix type issue where `CheckboxGroupProps` could not be + passed to the `CheckboxGroup` component. diff --git a/.changeset/improve-outline-border-visibility.md b/.changeset/improve-outline-border-visibility.md new file mode 100644 index 00000000000..4164702b78d --- /dev/null +++ b/.changeset/improve-outline-border-visibility.md @@ -0,0 +1,19 @@ +--- +"@chakra-ui/react": minor +"@chakra-ui/panda-preset": minor +--- + +### Added + +- **Semantic Tokens**: Add new `border` semantic token to all color palettes + (`gray.300`/`gray.700` for gray, `color.500`/`color.400` for colored palettes) + to improve outline component appearance + +### Changed + +- **Button, Badge, Tag, Checkbox**: Update outline variants to use + `colorPalette.border` instead of `colorPalette.muted` or global `border` token + for better appearance, especially for non-gray color palettes. + + > **NOTE**: All changes include CSS variable fallbacks to `colorPalette.muted` + > for backward compatibility. diff --git a/apps/compositions/src/examples/drawer-non-modal.tsx b/apps/compositions/src/examples/drawer-non-modal.tsx new file mode 100644 index 00000000000..4827695095e --- /dev/null +++ b/apps/compositions/src/examples/drawer-non-modal.tsx @@ -0,0 +1,37 @@ +import { Button, CloseButton, Drawer, Portal } from "@chakra-ui/react" + +export const DrawerNonModal = () => { + return ( + + + + + + + + + Drawer Title + + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. +

+
+ + + + + + + + + +
+
+
+
+ ) +} diff --git a/apps/www/content/docs/components/drawer.mdx b/apps/www/content/docs/components/drawer.mdx index ad43baa4ad5..8f5bd9718cf 100644 --- a/apps/www/content/docs/components/drawer.mdx +++ b/apps/www/content/docs/components/drawer.mdx @@ -103,6 +103,17 @@ corresponding sizes. For example: +### Non-Modal Drawer + +We don't recommend using a non-modal drawer due to the accessibility concerns +they present. In event you need it, here's what you can do: + +- set the `modal` prop to `false` +- set `pointerEvents` to `none` on the `Drawer.Positioner` component +- (optional)set the `closeOnInteractOutside` prop to `false` + + + ## Props ### Root diff --git a/apps/www/public/r/examples/drawer.json b/apps/www/public/r/examples/drawer.json index 48e0b9e8cbf..362bfe5bdb7 100644 --- a/apps/www/public/r/examples/drawer.json +++ b/apps/www/public/r/examples/drawer.json @@ -95,6 +95,15 @@ "import {\n Button,\n CloseButton,\n Drawer,\n For,\n HStack,\n Kbd,\n Portal,\n} from \"@chakra-ui/react\"" ], "importPath": "import { Drawer } from \"@chakra-ui/react\"" + }, + { + "name": "drawer-non-modal", + "content": "export const DrawerNonModal = () => {\n return (\n \n \n \n \n \n \n \n \n Drawer Title\n \n \n

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do\n eiusmod tempor incididunt ut labore et dolore magna aliqua.\n

\n
\n \n \n \n \n \n \n \n \n \n
\n
\n
\n
\n )\n}\n", + "hasSnippet": false, + "importPaths": [ + "import { Button, CloseButton, Drawer, Portal } from \"@chakra-ui/react\"" + ], + "importPath": "import { Drawer } from \"@chakra-ui/react\"" } ] -} \ No newline at end of file +} diff --git a/apps/www/public/r/examples/index.json b/apps/www/public/r/examples/index.json index df9603dc72d..998c8c2dcb0 100644 --- a/apps/www/public/r/examples/index.json +++ b/apps/www/public/r/examples/index.json @@ -289,6 +289,7 @@ "drawer-with-offset", "drawer-with-placement", "drawer-with-sizes", + "drawer-non-modal", "editable-basic", "editable-controlled", "editable-disabled", diff --git a/packages/panda-preset/src/recipes/badge.ts b/packages/panda-preset/src/recipes/badge.ts index 8df95c885dd..f0cb99ec25d 100644 --- a/packages/panda-preset/src/recipes/badge.ts +++ b/packages/panda-preset/src/recipes/badge.ts @@ -24,8 +24,10 @@ export const badgeRecipe = defineRecipe({ }, outline: { color: "colorPalette.fg", + "--outline-shadow-legacy": "colors.colorPalette.muted", + "--outline-shadow": "colors.colorPalette.border", shadow: "inset 0 0 0px 1px var(--shadow-color)", - shadowColor: "colorPalette.muted", + shadowColor: "var(--outline-shadow, var(--outline-shadow-legacy))", }, surface: { bg: "colorPalette.subtle", diff --git a/packages/panda-preset/src/recipes/button.ts b/packages/panda-preset/src/recipes/button.ts index bda7d98d700..a7440a6a4ad 100644 --- a/packages/panda-preset/src/recipes/button.ts +++ b/packages/panda-preset/src/recipes/button.ts @@ -147,7 +147,9 @@ export const buttonRecipe = defineRecipe({ }, outline: { borderWidth: "1px", - borderColor: "colorPalette.muted", + "--outline-color-legacy": "colors.colorPalette.muted", + "--outline-color": "colors.colorPalette.border", + borderColor: "var(--outline-color, var(--outline-color-legacy))", color: "colorPalette.fg", _hover: { bg: "colorPalette.subtle", diff --git a/packages/panda-preset/src/recipes/code.ts b/packages/panda-preset/src/recipes/code.ts index dfcda680574..88f0d9eb07d 100644 --- a/packages/panda-preset/src/recipes/code.ts +++ b/packages/panda-preset/src/recipes/code.ts @@ -20,8 +20,10 @@ export const codeRecipe = defineRecipe({ }, outline: { color: "colorPalette.fg", + "--outline-shadow-legacy": "colors.colorPalette.muted", + "--outline-shadow": "colors.colorPalette.border", shadow: "inset 0 0 0px 1px var(--shadow-color)", - shadowColor: "colorPalette.muted", + shadowColor: "var(--outline-shadow, var(--outline-shadow-legacy))", }, surface: { bg: "colorPalette.subtle", diff --git a/packages/panda-preset/src/semantic-tokens/colors.ts b/packages/panda-preset/src/semantic-tokens/colors.ts index 314c3b584bd..61a4ba5efcb 100644 --- a/packages/panda-preset/src/semantic-tokens/colors.ts +++ b/packages/panda-preset/src/semantic-tokens/colors.ts @@ -212,6 +212,12 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.gray.400}", }, }, + border: { + value: { + _light: "{colors.gray.200}", + _dark: "{colors.gray.800}", + }, + }, }, red: { contrast: { @@ -256,6 +262,12 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.red.500}", }, }, + border: { + value: { + _light: "{colors.red.500}", + _dark: "{colors.red.400}", + }, + }, }, orange: { contrast: { @@ -300,6 +312,12 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.orange.500}", }, }, + border: { + value: { + _light: "{colors.orange.500}", + _dark: "{colors.orange.400}", + }, + }, }, green: { contrast: { @@ -344,6 +362,12 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.green.500}", }, }, + border: { + value: { + _light: "{colors.green.500}", + _dark: "{colors.green.400}", + }, + }, }, blue: { contrast: { @@ -388,6 +412,12 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.blue.500}", }, }, + border: { + value: { + _light: "{colors.blue.500}", + _dark: "{colors.blue.400}", + }, + }, }, yellow: { contrast: { @@ -432,6 +462,12 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.yellow.500}", }, }, + border: { + value: { + _light: "{colors.yellow.500}", + _dark: "{colors.yellow.500}", + }, + }, }, teal: { contrast: { @@ -476,6 +512,12 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.teal.500}", }, }, + border: { + value: { + _light: "{colors.teal.500}", + _dark: "{colors.teal.400}", + }, + }, }, purple: { contrast: { @@ -520,6 +562,12 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.purple.500}", }, }, + border: { + value: { + _light: "{colors.purple.500}", + _dark: "{colors.purple.400}", + }, + }, }, pink: { contrast: { @@ -564,6 +612,12 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.pink.500}", }, }, + border: { + value: { + _light: "{colors.pink.500}", + _dark: "{colors.pink.400}", + }, + }, }, cyan: { contrast: { @@ -608,5 +662,11 @@ export const colors = defineSemanticTokens.colors({ _dark: "{colors.cyan.500}", }, }, + border: { + value: { + _light: "{colors.cyan.500}", + _dark: "{colors.cyan.400}", + }, + }, }, }) diff --git a/packages/panda-preset/src/slot-recipes/alert.ts b/packages/panda-preset/src/slot-recipes/alert.ts index 54e6d471d39..8a3cc720c9e 100644 --- a/packages/panda-preset/src/slot-recipes/alert.ts +++ b/packages/panda-preset/src/slot-recipes/alert.ts @@ -99,7 +99,9 @@ export const alertSlotRecipe = defineSlotRecipe({ root: { color: "colorPalette.fg", shadow: "inset 0 0 0px 1px var(--shadow-color)", - shadowColor: "colorPalette.muted", + "--outline-shadow-legacy": "colors.colorPalette.muted", + "--outline-shadow": "colors.colorPalette.border", + shadowColor: "var(--outline-shadow, var(--outline-shadow-legacy))", }, indicator: { color: "colorPalette.fg", diff --git a/packages/panda-preset/src/slot-recipes/avatar.ts b/packages/panda-preset/src/slot-recipes/avatar.ts index 5b06ff20ade..e501ca1c0ee 100644 --- a/packages/panda-preset/src/slot-recipes/avatar.ts +++ b/packages/panda-preset/src/slot-recipes/avatar.ts @@ -104,7 +104,9 @@ export const avatarSlotRecipe = defineSlotRecipe({ root: { color: "colorPalette.fg", borderWidth: "1px", - borderColor: "colorPalette.muted", + "--outline-shadow-legacy": "colors.colorPalette.muted", + "--outline-shadow": "colors.colorPalette.border", + borderColor: "var(--outline-shadow, var(--outline-shadow-legacy))", }, }, }, diff --git a/packages/panda-preset/src/slot-recipes/carousel.ts b/packages/panda-preset/src/slot-recipes/carousel.ts index ccf3bc6aea2..54037b3b948 100644 --- a/packages/panda-preset/src/slot-recipes/carousel.ts +++ b/packages/panda-preset/src/slot-recipes/carousel.ts @@ -7,54 +7,63 @@ export const carouselSlotRecipe = defineSlotRecipe({ "itemGroup", "item", "control", - "prevTrigger", "nextTrigger", - "autoplayTrigger", + "prevTrigger", "indicatorGroup", "indicator", + "autoplayTrigger", ], base: { root: { position: "relative", - overflow: "hidden", - "--carousel-spacing": "spacing.4", - }, - itemGroup: { display: "flex", - transition: "transform 0.3s ease-in-out", + gap: "2", + _horizontal: { + flexDirection: "column", + }, + _vertical: { + flexDirection: "row", + }, }, item: { - minWidth: "0", - flex: "0 0 auto", - width: "full", + _horizontal: { + width: "100%", + }, + _vertical: { + height: "100%", + }, }, control: { - position: "absolute", - top: "50%", - left: 0, - width: "100%", display: "flex", - justifyContent: "space-between", alignItems: "center", - transform: "translateY(-50%)", - px: "var(--carousel-spacing)", - zIndex: 2, + _horizontal: { + flexDirection: "row", + width: "100%", + }, + _vertical: { + flexDirection: "column", + height: "100%", + }, }, indicatorGroup: { display: "flex", justifyContent: "center", - gap: "2", - mt: "var(--carousel-spacing)", + gap: "3", + _horizontal: { + flexDirection: "row", + }, + _vertical: { + flexDirection: "column", + }, }, indicator: { - width: "3", - height: "3", + width: "2.5", + height: "2.5", borderRadius: "full", - bg: "bg.muted", - cursor: "pointer", - transition: "all 0.2s", - "&[data-current]": { - bg: "fg", + bg: "colorPalette.subtle", + cursor: "button", + _current: { + bg: "colorPalette.solid", }, }, }, diff --git a/packages/panda-preset/src/slot-recipes/tag.ts b/packages/panda-preset/src/slot-recipes/tag.ts index 0a063ec0103..0803522c157 100644 --- a/packages/panda-preset/src/slot-recipes/tag.ts +++ b/packages/panda-preset/src/slot-recipes/tag.ts @@ -121,8 +121,10 @@ export const tagSlotRecipe = defineSlotRecipe({ outline: { root: { color: "colorPalette.fg", + "--outline-shadow-legacy": "colors.colorPalette.muted", + "--outline-shadow": "colors.colorPalette.border", shadow: "inset 0 0 0px 1px var(--shadow-color)", - shadowColor: "colorPalette.muted", + shadowColor: "var(--outline-shadow, var(--outline-shadow-legacy))", }, }, surface: { diff --git a/packages/panda-preset/src/slot-recipes/tags-input.ts b/packages/panda-preset/src/slot-recipes/tags-input.ts index 4e81e553183..e66408dd64f 100644 --- a/packages/panda-preset/src/slot-recipes/tags-input.ts +++ b/packages/panda-preset/src/slot-recipes/tags-input.ts @@ -92,6 +92,7 @@ export const tagsInputSlotRecipe = defineSlotRecipe({ display: "flex", alignItems: "center", justifyContent: "center", + flexShrink: "0", boxSize: "calc(var(--tags-input-item-height) / 1.5)", cursor: { base: "button", diff --git a/packages/react/__stories__/drawer.stories.tsx b/packages/react/__stories__/drawer.stories.tsx index 70a1ec3547a..f0f3455715a 100644 --- a/packages/react/__stories__/drawer.stories.tsx +++ b/packages/react/__stories__/drawer.stories.tsx @@ -21,3 +21,4 @@ export { DrawerWithOffset as Offset } from "compositions/examples/drawer-with-of export { DrawerWithPlacement as Placement } from "compositions/examples/drawer-with-placement" export { DrawerWithConditionalVariants as ConditionalVariants } from "compositions/examples/drawer-with-conditional-variants" export { DrawerWithSizes as Sizes } from "compositions/examples/drawer-with-sizes" +export { DrawerNonModal as NonModal } from "compositions/examples/drawer-non-modal" diff --git a/packages/react/__tests__/css.test.ts b/packages/react/__tests__/css.test.ts index 3af57197dc2..df3174da642 100644 --- a/packages/react/__tests__/css.test.ts +++ b/packages/react/__tests__/css.test.ts @@ -303,6 +303,7 @@ describe("css", () => { "--chakra-colors-color-palette-800": "var(--chakra-colors-red-800)", "--chakra-colors-color-palette-900": "var(--chakra-colors-red-900)", "--chakra-colors-color-palette-950": "var(--chakra-colors-red-950)", + "--chakra-colors-color-palette-border": "var(--chakra-colors-red-border)", "--chakra-colors-color-palette-contrast": "var(--chakra-colors-red-contrast)", "--chakra-colors-color-palette-emphasized": "var(--chakra-colors-red-emphasized)", "--chakra-colors-color-palette-fg": "var(--chakra-colors-red-fg)", diff --git a/packages/react/src/components/checkbox/checkbox.tsx b/packages/react/src/components/checkbox/checkbox.tsx index b70be86cfdc..d0ca5a783d1 100644 --- a/packages/react/src/components/checkbox/checkbox.tsx +++ b/packages/react/src/components/checkbox/checkbox.tsx @@ -158,7 +158,7 @@ export const CheckboxGroup = chakra( }, }, { forwardAsChild: true }, -) +) as React.FC //////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/react/src/theme/recipes/alert.ts b/packages/react/src/theme/recipes/alert.ts index 719bf40dd01..10242a6a165 100644 --- a/packages/react/src/theme/recipes/alert.ts +++ b/packages/react/src/theme/recipes/alert.ts @@ -94,7 +94,9 @@ export const alertSlotRecipe = defineSlotRecipe({ root: { color: "colorPalette.fg", shadow: "inset 0 0 0px 1px var(--shadow-color)", - shadowColor: "colorPalette.muted", + "--outline-shadow-legacy": "colors.colorPalette.muted", + "--outline-shadow": "colors.colorPalette.border", + shadowColor: "var(--outline-shadow, var(--outline-shadow-legacy))", }, indicator: { color: "colorPalette.fg", diff --git a/packages/react/src/theme/recipes/avatar.ts b/packages/react/src/theme/recipes/avatar.ts index 1916114125a..5920ddb417d 100644 --- a/packages/react/src/theme/recipes/avatar.ts +++ b/packages/react/src/theme/recipes/avatar.ts @@ -107,7 +107,9 @@ export const avatarSlotRecipe = defineSlotRecipe({ root: { color: "colorPalette.fg", borderWidth: "1px", - borderColor: "colorPalette.muted", + "--outline-shadow-legacy": "colors.colorPalette.muted", + "--outline-shadow": "colors.colorPalette.border", + borderColor: "var(--outline-shadow, var(--outline-shadow-legacy))", }, }, }, diff --git a/packages/react/src/theme/recipes/badge.ts b/packages/react/src/theme/recipes/badge.ts index 0250367d77c..79721196a3e 100644 --- a/packages/react/src/theme/recipes/badge.ts +++ b/packages/react/src/theme/recipes/badge.ts @@ -24,8 +24,10 @@ export const badgeRecipe = defineRecipe({ }, outline: { color: "colorPalette.fg", + "--outline-shadow-legacy": "colors.colorPalette.muted", + "--outline-shadow": "colors.colorPalette.border", shadow: "inset 0 0 0px 1px var(--shadow-color)", - shadowColor: "colorPalette.muted", + shadowColor: "var(--outline-shadow, var(--outline-shadow-legacy))", }, surface: { bg: "colorPalette.subtle", diff --git a/packages/react/src/theme/recipes/button.ts b/packages/react/src/theme/recipes/button.ts index 7f8b01459e7..25e255e39e6 100644 --- a/packages/react/src/theme/recipes/button.ts +++ b/packages/react/src/theme/recipes/button.ts @@ -152,7 +152,9 @@ export const buttonRecipe = defineRecipe({ outline: { borderWidth: "1px", - borderColor: "colorPalette.muted", + "--outline-color-legacy": "colors.colorPalette.muted", + "--outline-color": "colors.colorPalette.border", + borderColor: "var(--outline-color, var(--outline-color-legacy))", color: "colorPalette.fg", _hover: { bg: "colorPalette.subtle", diff --git a/packages/react/src/theme/semantic-tokens/colors.ts b/packages/react/src/theme/semantic-tokens/colors.ts index b48effee9bb..cf9efa0f87f 100644 --- a/packages/react/src/theme/semantic-tokens/colors.ts +++ b/packages/react/src/theme/semantic-tokens/colors.ts @@ -111,6 +111,9 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.gray.400}", _dark: "{colors.gray.400}" }, }, + border: { + value: { _light: "{colors.gray.200}", _dark: "{colors.gray.800}" }, + }, }, red: { @@ -135,6 +138,9 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.red.500}", _dark: "{colors.red.500}" }, }, + border: { + value: { _light: "{colors.red.500}", _dark: "{colors.red.400}" }, + }, }, orange: { @@ -159,6 +165,9 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.orange.500}", _dark: "{colors.orange.500}" }, }, + border: { + value: { _light: "{colors.orange.500}", _dark: "{colors.orange.400}" }, + }, }, green: { @@ -183,6 +192,9 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.green.500}", _dark: "{colors.green.500}" }, }, + border: { + value: { _light: "{colors.green.500}", _dark: "{colors.green.400}" }, + }, }, blue: { @@ -207,6 +219,9 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.blue.500}", _dark: "{colors.blue.500}" }, }, + border: { + value: { _light: "{colors.blue.500}", _dark: "{colors.blue.400}" }, + }, }, yellow: { @@ -231,6 +246,9 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.yellow.500}", _dark: "{colors.yellow.500}" }, }, + border: { + value: { _light: "{colors.yellow.500}", _dark: "{colors.yellow.500}" }, + }, }, teal: { @@ -255,6 +273,9 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.teal.500}", _dark: "{colors.teal.500}" }, }, + border: { + value: { _light: "{colors.teal.500}", _dark: "{colors.teal.400}" }, + }, }, purple: { @@ -279,6 +300,9 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.purple.500}", _dark: "{colors.purple.500}" }, }, + border: { + value: { _light: "{colors.purple.500}", _dark: "{colors.purple.400}" }, + }, }, pink: { @@ -303,6 +327,9 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.pink.500}", _dark: "{colors.pink.500}" }, }, + border: { + value: { _light: "{colors.pink.500}", _dark: "{colors.pink.400}" }, + }, }, cyan: { @@ -327,5 +354,8 @@ export const semanticColors = defineSemanticTokens.colors({ focusRing: { value: { _light: "{colors.cyan.500}", _dark: "{colors.cyan.500}" }, }, + border: { + value: { _light: "{colors.cyan.500}", _dark: "{colors.cyan.400}" }, + }, }, })