diff --git a/CHANGELOG.md b/CHANGELOG.md index 49b31dc85d..1df2c0e89f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,57 @@ it according to semantic versioning. For example, if your PR adds a breaking cha should change the heading of the (upcoming) version to include a major version bump. --> +# 6.0.0-beta.24 + +## @rjsf/antd + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/chakra-ui + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/core + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/daisyui + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/fluentui-rc + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/mantine + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/mui + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/primereact + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/react-bootstrap + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/semantic-ui + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## @rjsf/shadcn + +- Updated the `README.md` to show the theme snapshot with the latest theme UI from the playground, making it a link to the theme + +## Dev / docs / playground + +- Updated the playground to modernize the UI using MUI components +- Updated the documentation to switch to using an animated gif based on the latest modernized playground UI + # 6.0.0-beta.23 ## @rjsf/core @@ -23,6 +74,7 @@ should change the heading of the (upcoming) version to include a major version b - Updated `Form` to support the new feature to do `onBlur` handling of `liveValidate` and `liveOmit` ## Dev / docs / playground + - Updated the playground to switch `liveValidate` and `liveOmit` from checkboxes to radio buttons for the new options - Updated `form-props.md` and `v6x upgrade guide.md` to document the new feature and deprecation @@ -127,6 +179,7 @@ should change the heading of the (upcoming) version to include a major version b - BREAKING CHANGE: Renamed `ArrayFieldItemButtonsTemplateType` to `ArrayFieldItemButtonsTemplateProps` and updated it to replace the `onAddIndexClick()`, `onCopyIndexClick()`, `onDropIndexClick()` and `onReorderClick()` callback-generator props with the `onAddItem()`, `onCopyItem()`, `onMoveUpItem()`, `onMoveDownItem()` and `onRemoveItem()` callback props ## Dev / docs / playground + - Updated the `formTests.tsx` snapshots to add an `anyOf` of all arrays with different item types and removed the disabling of the optional data controls feature for the optional object with oneOfs - Updated the snapshots in all of the themes accordingly - Updated the playground to make the same changes as `formTests.tsx` in the `optionalDataControls.ts` sample, moving the `experimental_defaultFormStateBehavior` inside of a `liveSettings` block diff --git a/packages/antd/README.md b/packages/antd/README.md index 4dde07ab4f..fc34b147e5 100644 --- a/packages/antd/README.md +++ b/packages/antd/README.md @@ -47,6 +47,8 @@ Ant Design theme, fields and widgets for `react-jsonschema-form`. +[product-screenshot](https://rjsf-team.github.io/@rjsf/antd) + ### Built With - [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form/) diff --git a/packages/antd/screenshot.png b/packages/antd/screenshot.png index d1d22e5f01..f52e6a5d84 100644 Binary files a/packages/antd/screenshot.png and b/packages/antd/screenshot.png differ diff --git a/packages/chakra-ui/README.md b/packages/chakra-ui/README.md index 33fe9056b5..e6e3c46224 100644 --- a/packages/chakra-ui/README.md +++ b/packages/chakra-ui/README.md @@ -48,7 +48,7 @@ ## About The Project -[![@rjsf/chakra-ui Screen Shot][product-screenshot]](https://rjsf-team.github.io/@rjsf/chakra-ui) +[product-screenshot](https://rjsf-team.github.io/@rjsf/chakra-ui) Exports `chakra-ui` theme, fields and widgets for `react-jsonschema-form`. diff --git a/packages/chakra-ui/screenshot.png b/packages/chakra-ui/screenshot.png index de7f75089f..c3dd5f3355 100644 Binary files a/packages/chakra-ui/screenshot.png and b/packages/chakra-ui/screenshot.png differ diff --git a/packages/core/README.md b/packages/core/README.md index babe670dac..2530f61b2d 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -47,6 +47,8 @@ Core logic and classic Bootstrap 3 theme for `react-jsonschema-form`. +[product-screenshot](https://rjsf-team.github.io/@rjsf/core) + ### Built With - [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form/) diff --git a/packages/core/screenshot.png b/packages/core/screenshot.png index da45a44792..da0974baaa 100644 Binary files a/packages/core/screenshot.png and b/packages/core/screenshot.png differ diff --git a/packages/daisyui/README.md b/packages/daisyui/README.md index 7ed2e2f6ff..75efd73f5b 100644 --- a/packages/daisyui/README.md +++ b/packages/daisyui/README.md @@ -12,8 +12,7 @@ This package integrates [DaisyUI](https://daisyui.com/), [Tailwind CSS](https:// ## Screenshots -![DaisyUI Form Example 1](daisy-screenshot1.png) -![DaisyUI Form Example 2](daisy-screenshot2.png) +[product-screenshot](https://rjsf-team.github.io/@rjsf/daisyui) ## Features diff --git a/packages/daisyui/daisy-screenshot1.png b/packages/daisyui/daisy-screenshot1.png deleted file mode 100644 index d96016f6bf..0000000000 Binary files a/packages/daisyui/daisy-screenshot1.png and /dev/null differ diff --git a/packages/daisyui/daisy-screenshot2.png b/packages/daisyui/daisy-screenshot2.png deleted file mode 100644 index 210388752c..0000000000 Binary files a/packages/daisyui/daisy-screenshot2.png and /dev/null differ diff --git a/packages/daisyui/screenshot.png b/packages/daisyui/screenshot.png new file mode 100644 index 0000000000..9236ef28f7 Binary files /dev/null and b/packages/daisyui/screenshot.png differ diff --git a/packages/docs/docs/00-introduction.mdx b/packages/docs/docs/00-introduction.mdx index ec7b1078c8..5ba2afbd8b 100644 --- a/packages/docs/docs/00-introduction.mdx +++ b/packages/docs/docs/00-introduction.mdx @@ -13,7 +13,7 @@ A simple [React](https://reactjs.org/) component capable of building HTML forms A [live playground](https://rjsf-team.github.io/react-jsonschema-form/) is hosted on GitHub Pages: - Playground + ![Playground](./rjsf-playground.gif) ## Philosophy diff --git a/packages/docs/docs/rjsf-playground.gif b/packages/docs/docs/rjsf-playground.gif new file mode 100644 index 0000000000..4c6d7241d5 Binary files /dev/null and b/packages/docs/docs/rjsf-playground.gif differ diff --git a/packages/fluentui-rc/README.md b/packages/fluentui-rc/README.md index 7805d4c1c4..7884993598 100644 --- a/packages/fluentui-rc/README.md +++ b/packages/fluentui-rc/README.md @@ -47,6 +47,8 @@ Fluent UI React Components (v9) theme, fields and widgets for `react-jsonschema-form`. +[product-screenshot](https://rjsf-team.github.io/@rjsf/fluentui-rc) + ### Built With - [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form/) diff --git a/packages/fluentui-rc/screenshot.png b/packages/fluentui-rc/screenshot.png index 58f044a107..fb6545379b 100644 Binary files a/packages/fluentui-rc/screenshot.png and b/packages/fluentui-rc/screenshot.png differ diff --git a/packages/mantine/README.md b/packages/mantine/README.md index fec61b5e5f..f6b528c602 100644 --- a/packages/mantine/README.md +++ b/packages/mantine/README.md @@ -50,6 +50,8 @@ `Mantine` theme, fields and widgets for `react-jsonschema-form`. +[product-screenshot](https://rjsf-team.github.io/@rjsf/mantine) + ### Built With - [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form/) diff --git a/packages/mantine/screenshot.png b/packages/mantine/screenshot.png index cf28b50329..1997883ec6 100644 Binary files a/packages/mantine/screenshot.png and b/packages/mantine/screenshot.png differ diff --git a/packages/mui/README.md b/packages/mui/README.md index bf4c938300..77f4656dd7 100644 --- a/packages/mui/README.md +++ b/packages/mui/README.md @@ -47,10 +47,10 @@ ## About The Project -[![@rjsf/mui Screen Shot][product-screenshot]](https://rjsf-team.github.io/@rjsf/mui) - Exports `MUI` version 5 theme, fields, and widgets for `react-jsonschema-form`. +[product-screenshot](https://rjsf-team.github.io/@rjsf/mui) + ### Built With - [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form/) diff --git a/packages/mui/screenshot.png b/packages/mui/screenshot.png index 112812215b..80ebb4e9a4 100644 Binary files a/packages/mui/screenshot.png and b/packages/mui/screenshot.png differ diff --git a/packages/playground/src/components/CopyLink.tsx b/packages/playground/src/components/CopyLink.tsx index 925ceda71c..9a2fca3e60 100644 --- a/packages/playground/src/components/CopyLink.tsx +++ b/packages/playground/src/components/CopyLink.tsx @@ -13,16 +13,17 @@ export default function CopyLink({ shareURL, onShare }: CopyLinkProps) { navigator.clipboard.writeText(input.current?.value ?? ''); } + const style = { maxWidth: '21.525rem', margin: '5px 0' }; if (!shareURL) { return ( - ); } return ( -
+
); } -function HeaderButtons({ playGroundFormRef }: { playGroundFormRef: MutableRefObject }) { +function OptionsButtons({ playGroundFormRef }: { playGroundFormRef: MutableRefObject }) { const submitClick = useCallback(() => { playGroundFormRef.current.submit(); }, [playGroundFormRef]); @@ -61,6 +68,7 @@ function HeaderButtons({ playGroundFormRef }: { playGroundFormRef: MutableRefObj const liveSettingsBooleanSchema: RJSFSchema = { type: 'object', + title: 'Form Options', properties: { disabled: { type: 'boolean', title: 'Disable whole form' }, readonly: { type: 'boolean', title: 'Readonly whole form' }, @@ -76,18 +84,6 @@ const liveSettingsBooleanSchema: RJSFSchema = { title: 'Show Error List', enum: [false, 'top', 'bottom'], }, - experimental_componentUpdateStrategy: { - type: 'string', - title: 'Component update strategy', - default: 'customDeep', - enum: ['customDeep', 'shallow', 'always'], - }, - }, -}; - -const liveSettingsSelectSchema: RJSFSchema = { - type: 'object', - properties: { experimental_defaultFormStateBehavior: { title: 'Default Form State Behavior (Experimental)', type: 'object', @@ -233,9 +229,6 @@ const liveSettingsBooleanUiSchema: UiSchema = { inline: true, }, }, -}; - -const liveSettingsSelectUiSchema: UiSchema = { experimental_defaultFormStateBehavior: { 'ui:options': { label: false, @@ -253,14 +246,12 @@ export interface LiveSettings { [key: string]: any; } -type HeaderProps = { +type OptionsDrawerProps = { schema: RJSFSchema; uiSchema: UiSchema; formData: any; shareURL: string | null; - themes: { [themeName: string]: ThemesType }; theme: string; - subtheme: string | null; sampleName: string; validators: { [validatorName: string]: ValidatorType; @@ -268,44 +259,26 @@ type HeaderProps = { validator: string; liveSettings: LiveSettings; playGroundFormRef: MutableRefObject; - onSampleSelected: SampleSelectorProps['onSelected']; - onThemeSelected: (theme: string, themeObj: ThemesType) => void; - setSubtheme: Dispatch>; - setStylesheet: Dispatch>; setValidator: Dispatch>; setLiveSettings: Dispatch>; setShareURL: Dispatch>; }; -export default function Header({ +export default function OptionsDrawer({ schema, uiSchema, formData, shareURL, - themes, theme, - subtheme, validators, validator, liveSettings, playGroundFormRef, - onThemeSelected, - setSubtheme, - setStylesheet, setValidator, setLiveSettings, setShareURL, sampleName, - onSampleSelected, -}: HeaderProps) { - const onSubthemeSelected = useCallback( - (subtheme: any, { stylesheet }: SubthemeType) => { - setSubtheme(subtheme); - setStylesheet(stylesheet || null); - }, - [setSubtheme, setStylesheet], - ); - +}: OptionsDrawerProps) { const onValidatorSelected = useCallback( (validator: string) => { setValidator(validator); @@ -344,52 +317,23 @@ export default function Header({ console.error(error); } }, [formData, liveSettings, schema, theme, uiSchema, validator, setShareURL, sampleName]); - + const drawerSx = { width: DRAWER_WIDTH, p: 1 }; return ( -
-

react-jsonschema-form

-
-
- -
-
-
-
- -
-
-
-
- -
-
- - {themes[theme] && themes[theme].subthemes && ( - - )} - - -
- -
-
- -
-
-
+ + + +
+ + + + +
); } diff --git a/packages/playground/src/components/Playground.tsx b/packages/playground/src/components/Playground.tsx index ce5cec9670..d360892988 100644 --- a/packages/playground/src/components/Playground.tsx +++ b/packages/playground/src/components/Playground.tsx @@ -1,13 +1,16 @@ import { ComponentType, FormEvent, useCallback, useEffect, useRef, useState } from 'react'; +import Box from '@mui/material/Box'; +import Divider from '@mui/material/Divider'; import { FormProps, IChangeEvent, withTheme } from '@rjsf/core'; import { ErrorSchema, RJSFSchema, RJSFValidationError, UiSchema, ValidatorType } from '@rjsf/utils'; import { isFunction } from 'lodash'; import { samples } from '../samples'; -import Header, { LiveSettings } from './Header'; import DemoFrame from './DemoFrame'; import ErrorBoundary from './ErrorBoundary'; import GeoPosition from './GeoPosition'; +import OptionsDrawer, { LiveSettings } from './OptionsDrawer'; +import SampleSelector from './SampleSelector'; import { ThemesType } from './ThemeSelector'; import Editors from './Editors'; import SpecialInput from './SpecialInput'; @@ -177,41 +180,28 @@ export default function Playground({ themes, validators }: PlaygroundProps) { }, []); return ( - <> -
- -
+ + + + + {showForm && ( )} -
- + + + ); } diff --git a/packages/playground/src/components/SampleSelector.tsx b/packages/playground/src/components/SampleSelector.tsx index 75cfecf91a..50094c0c79 100644 --- a/packages/playground/src/components/SampleSelector.tsx +++ b/packages/playground/src/components/SampleSelector.tsx @@ -1,30 +1,134 @@ -import { MouseEvent } from 'react'; +import { SyntheticEvent, useState } from 'react'; +import { styled, Theme, CSSObject } from '@mui/material/styles'; +import IconButton from '@mui/material/IconButton'; +import MuiDrawer from '@mui/material/Drawer'; +import MuiTab from '@mui/material/Tab'; +import Tabs from '@mui/material/Tabs'; +import Typography from '@mui/material/Typography'; +import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; + import { samples } from '../samples'; +const drawerWidth = 200; + +const openedMixin = (theme: Theme): CSSObject => ({ + width: drawerWidth, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen, + }), + overflowX: 'hidden', +}); + +const closedMixin = (theme: Theme): CSSObject => ({ + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + overflowX: 'hidden', + width: `calc(${theme.spacing(5)} + 1px)`, + [theme.breakpoints.up('sm')]: { + width: `calc(${theme.spacing(4)} + 1px)`, + }, +}); + +const DrawerHeader = styled('div')({ + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', +}); + +const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme }) => ({ + width: drawerWidth, + flexShrink: 0, + whiteSpace: 'nowrap', + boxSizing: 'border-box', + variants: [ + { + props: ({ open }) => open, + style: { + ...openedMixin(theme), + '& .MuiDrawer-paper': openedMixin(theme), + }, + }, + { + props: ({ open }) => !open, + style: { + ...closedMixin(theme), + '& .MuiDrawer-paper': closedMixin(theme), + }, + }, + ], + '& .MuiTab-root.Mui-selected': { + backgroundColor: 'lightgray', + }, +})); + +const Tab = styled(MuiTab)({ + padding: '4px', + fontSize: '1.25rem', + minWidth: '1rem', + minHeight: '1rem', + '&:hover': { + border: `1px solid gray`, + }, + selected: { + backgroundColor: 'lightgray', + }, +}); + export interface SampleSelectorProps { onSelected: (sampleName: string) => void; selectedSample: string; } export default function SampleSelector({ onSelected, selectedSample }: SampleSelectorProps) { - function onLabelClick(label: string) { - return (event: MouseEvent) => { - event.preventDefault(); - setTimeout(() => onSelected(label), 0); - }; + const [open, setOpen] = useState(true); + + const handleDrawerOpen = () => { + setOpen(true); + }; + const handleDrawerClose = () => { + setOpen(false); + }; + function onLabelClick(event: SyntheticEvent, label: string) { + event.preventDefault(); + setTimeout(() => onSelected(label), 0); } return ( -
    - {Object.keys(samples).map((label, i) => { - return ( -
  • - - {label} - -
  • - ); - })} -
+ + + {open && ( + + Samples + + )} + + {open ? : } + + + {open ? ( + + {Object.keys(samples).map((label) => ( + + ))} + + ) : ( + + {selectedSample} + + )} + ); } diff --git a/packages/playground/src/components/SubthemeSelector.tsx b/packages/playground/src/components/SubthemeSelector.tsx index abad11afa0..f90d8f00d2 100644 --- a/packages/playground/src/components/SubthemeSelector.tsx +++ b/packages/playground/src/components/SubthemeSelector.tsx @@ -1,4 +1,4 @@ -import { useCallback, useMemo } from 'react'; +import { SyntheticEvent, useCallback, useMemo } from 'react'; import Form, { IChangeEvent } from '@rjsf/core'; import { RJSFSchema, UiSchema } from '@rjsf/utils'; import localValidator from '@rjsf/validator-ajv8'; @@ -42,18 +42,24 @@ export default function SubthemeSelector({ subtheme, subthemes, select }: Subthe }, [select, subthemes], ); + const cancelBubble = (event: SyntheticEvent) => { + event.preventDefault(); + event.stopPropagation(); + }; return ( -
-
- +
+
+
+ +
); } diff --git a/packages/playground/src/components/ThemeSelector.tsx b/packages/playground/src/components/ThemeSelector.tsx index 842e6687a9..1495293452 100644 --- a/packages/playground/src/components/ThemeSelector.tsx +++ b/packages/playground/src/components/ThemeSelector.tsx @@ -1,4 +1,4 @@ -import { useCallback } from 'react'; +import { SyntheticEvent, useCallback } from 'react'; import Form, { IChangeEvent } from '@rjsf/core'; import { RJSFSchema, UiSchema } from '@rjsf/utils'; import localValidator from '@rjsf/validator-ajv8'; @@ -36,18 +36,24 @@ export default function ThemeSelector({ theme, themes, select }: ThemeSelectorPr }, [select, themes], ); + const cancelBubble = (event: SyntheticEvent) => { + event.preventDefault(); + event.stopPropagation(); + }; return ( -
-
- +
+
+
+ +
); } diff --git a/packages/playground/src/layout/Footer.tsx b/packages/playground/src/layout/Footer.tsx index 7601526765..cf90a4c688 100644 --- a/packages/playground/src/layout/Footer.tsx +++ b/packages/playground/src/layout/Footer.tsx @@ -1,10 +1,12 @@ +import { DRAWER_WIDTH } from '../components/OptionsDrawer'; + export default function Footer() { return (

Powered by react-jsonschema-form. {import.meta.env.VITE_SHOW_NETLIFY_BADGE === 'true' && ( -

+
diff --git a/packages/playground/src/samples/Sample.ts b/packages/playground/src/samples/Sample.ts index 06961f4b5e..e2a633f9b0 100644 --- a/packages/playground/src/samples/Sample.ts +++ b/packages/playground/src/samples/Sample.ts @@ -1,7 +1,7 @@ import { UiSchema } from '@rjsf/utils'; import { FormProps } from '@rjsf/core'; -import { LiveSettings } from '../components/Header'; +import { LiveSettings } from '../components/OptionsDrawer'; export type UiSchemaForTheme = (theme: string) => UiSchema; diff --git a/packages/primereact/README.md b/packages/primereact/README.md index 72d30bf7d6..fa2edf8761 100644 --- a/packages/primereact/README.md +++ b/packages/primereact/README.md @@ -42,6 +42,8 @@ PrimeReact theme, fields, and widgets for `react-jsonschema-form`. +[product-screenshot](https://rjsf-team.github.io/@rjsf/primereact) + ### Built With - [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form/) diff --git a/packages/primereact/screenshot.png b/packages/primereact/screenshot.png new file mode 100644 index 0000000000..84bc4c0473 Binary files /dev/null and b/packages/primereact/screenshot.png differ diff --git a/packages/react-bootstrap/README.md b/packages/react-bootstrap/README.md index 3fa3098c62..e5a35813f4 100644 --- a/packages/react-bootstrap/README.md +++ b/packages/react-bootstrap/README.md @@ -41,6 +41,8 @@ Exports `react-bootstrap` theme, fields and widgets for `react-jsonschema-form`. +[product-screenshot](https://rjsf-team.github.io/@rjsf/react-bootstrap) + ### Built With - [react-jsonschema-form](https://github.com/mozilla-services/react-jsonschema-form/) diff --git a/packages/react-bootstrap/screenshot.png b/packages/react-bootstrap/screenshot.png new file mode 100644 index 0000000000..e9e37af575 Binary files /dev/null and b/packages/react-bootstrap/screenshot.png differ diff --git a/packages/semantic-ui/README.md b/packages/semantic-ui/README.md index 43d991e866..c4f98ade6e 100644 --- a/packages/semantic-ui/README.md +++ b/packages/semantic-ui/README.md @@ -51,6 +51,8 @@ Exports `semantic-ui` theme, fields and widgets for `react-jsonschema-form`. +[product-screenshot](https://rjsf-team.github.io/@rjsf/semantic-ui) + ### Built With - [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form/) diff --git a/packages/semantic-ui/screenshot.png b/packages/semantic-ui/screenshot.png index 4943647a44..fd74f17381 100644 Binary files a/packages/semantic-ui/screenshot.png and b/packages/semantic-ui/screenshot.png differ diff --git a/packages/shadcn/README.md b/packages/shadcn/README.md index c6233126e1..a868ffd0b1 100644 --- a/packages/shadcn/README.md +++ b/packages/shadcn/README.md @@ -20,11 +20,6 @@ Request Feature

- -

-Logo -

- ## Table of Contents @@ -45,6 +40,8 @@ Exports `shadcn` theme, fields and widgets for `react-jsonschema-form`. +[![product-screenshot](./screenshot.png)](https://rjsf-team.github.io/@rjsf/shadcn) + [Live demo](https://react-jsonschema-form-shadcn-boilerplate.vercel.app/) ### Built With diff --git a/packages/shadcn/screenshot.png b/packages/shadcn/screenshot.png new file mode 100644 index 0000000000..b26ad79cce Binary files /dev/null and b/packages/shadcn/screenshot.png differ