-
Notifications
You must be signed in to change notification settings - Fork 257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ui): component theming #5170
Open
dbanksdesign
wants to merge
37
commits into
main
Choose a base branch
from
component-theming/main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
5fa49fb
feat(ui): component theming (#4883)
dbanksdesign 9084dc2
Merge branch 'main' into component-theming/main
dbanksdesign 4652209
fixing test
dbanksdesign d675c4e
fixes
dbanksdesign 89c5cfe
LFG
dbanksdesign bff60ab
updates
dbanksdesign 014ab1b
Merge branch 'main' into component-theming/main
dbanksdesign 3b7594b
updates
dbanksdesign 861d1c6
adding more components and fixing things
dbanksdesign 74cc803
fixes
dbanksdesign d07f5ae
starting to migrate React primitive classnames
dbanksdesign f38ebe1
more work
dbanksdesign 3929d5b
working
dbanksdesign 1027758
migrating more primitives
dbanksdesign 10d4556
finishing removing ComponentClassNames
dbanksdesign dc83aa2
update accordion
dbanksdesign 8569e78
undo primitives changes
dbanksdesign 7031852
fixes
dbanksdesign c8ca4ba
fixing size increase
dbanksdesign 1790554
fixing size increase
dbanksdesign 098b9ce
fixing size increase
dbanksdesign 57198dd
fixing docs page
dbanksdesign 26e8fbd
updating internal names, removing unnecessary exports
dbanksdesign 9b73ca0
final cleanup
dbanksdesign 112be0f
add changeset
dbanksdesign 2a490a8
removing one more type export
dbanksdesign fa620ea
changing to defineComponentTheme and adding containerProps function
dbanksdesign 1b92c66
adding type benchmarks for themeing functions
dbanksdesign 98b1142
cleanup
dbanksdesign 745151e
Merge branch 'main' into component-theming/main
dbanksdesign 6dfa6a5
fiddling with the yarn.lock
dbanksdesign 86c1118
more fiddling
dbanksdesign c1bbcdb
please work
dbanksdesign badf3a7
fixing tests
dbanksdesign c3e0560
Merge branch 'main' into component-theming/main
dbanksdesign b68c1be
Merge branch 'main' into component-theming/main
dbanksdesign f937f27
adding animation support
dbanksdesign File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
--- | ||
"@aws-amplify/ui": minor | ||
"@aws-amplify/ui-react": minor | ||
--- | ||
|
||
feat(ui): experimental component theming | ||
|
||
This feature lets you fully style and theme built-in components even if there is no design token available. For example, previously you could not add a box shadow or gradient background to the built-in Button component unless you wrote plain CSS. Now you can style every CSS property for all the built-in components with type-safety! | ||
|
||
This also lets you define your own components and style them in the same type-safe way with zero runtime computation. | ||
|
||
### defineComponentTheme() | ||
|
||
```ts | ||
import { defineComponentTheme } from '@aws-amplify/ui-react/server'; | ||
|
||
export const buttonTheme = defineComponentTheme({ | ||
// because 'button' is a built-in component, we get type-safety and hints | ||
// based on the theme shape of our button | ||
name: 'button', | ||
theme: (tokens) => { | ||
return { | ||
textAlign: 'center', | ||
padding: tokens.space.xl, | ||
_modifiers: { | ||
primary: { | ||
backgroundColor: tokens.colors.primary[20], | ||
}, | ||
}, | ||
}; | ||
}, | ||
}); | ||
``` | ||
|
||
|
||
### createTheme() | ||
|
||
The theme object passed to `createTheme` now has an optional `components` array which is an array of component themes. | ||
|
||
```ts | ||
export const theme = createTheme({ | ||
name: 'my-theme', | ||
components: [ | ||
buttonTheme, | ||
customComponentTheme, | ||
] | ||
}) | ||
``` | ||
|
||
### <Theme /> RSC | ||
|
||
```tsx | ||
import { Theme } from '@aws-amplify/ui-react/server'; | ||
import { theme } from '@/theme'; | ||
|
||
export default function RootLayout({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
return ( | ||
<Theme theme={theme} colorMode="system"> | ||
{children} | ||
</Theme> | ||
) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"extends": "next/core-web-vitals", | ||
"rules": { | ||
"react-hooks/exhaustive-deps": "error" // override next eslint default | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
.yarn/install-state.gz | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/** @type {import('next').NextConfig} */ | ||
const nextConfig = {}; | ||
|
||
module.exports = nextConfig; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"name": "next-app-router", | ||
"version": "0.1.0", | ||
"private": true, | ||
"scripts": { | ||
"dev": "next dev", | ||
"build": "next build", | ||
"start": "next start", | ||
"lint": "next lint" | ||
}, | ||
"dependencies": { | ||
"@aws-amplify/ui-react": "^6.1.0", | ||
"next": "^14.1.1", | ||
"react": "18.2.0", | ||
"react-dom": "^18", | ||
"react-icons": "^4.3.1" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^14.14.31", | ||
"eslint-config-next": "^13.5.5" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module.exports = { | ||
plugins: { | ||
autoprefixer: {}, | ||
}, | ||
}; |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
@import '@aws-amplify/ui-react/styles/reset.css'; | ||
@import '@aws-amplify/ui-react/styles.css'; | ||
|
||
[data-amplify-theme] { | ||
background-color: var(--amplify-colors-background-primary); | ||
color: var(--amplify-colors-font-primary); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import type { Metadata } from 'next'; | ||
import './globals.css'; | ||
|
||
export const metadata: Metadata = { | ||
title: 'Amplify UI Next App Router Example', | ||
description: 'Generated by create next app', | ||
}; | ||
|
||
export default function RootLayout({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
return ( | ||
<html lang="en"> | ||
<body>{children}</body> | ||
</html> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Avatar } from '@/components/Avatar'; | ||
import { theme } from '@/theme'; | ||
import { ThemeStyle } from '@aws-amplify/ui-react/server'; | ||
import Link from 'next/link'; | ||
|
||
export default function Home() { | ||
return ( | ||
<main> | ||
<Link href="/theme">Theme</Link> | ||
<Link href="/theme-switcher">Theme Switcher</Link> | ||
<Avatar /> | ||
|
||
<div {...theme.containerProps({ colorMode: 'dark' })}> | ||
<h2>I'm dark</h2> | ||
<Avatar /> | ||
</div> | ||
</main> | ||
); | ||
} |
25 changes: 25 additions & 0 deletions
25
examples/next-app-router/src/app/theme-switcher/layout.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import * as React from 'react'; | ||
import type { ColorMode } from '@aws-amplify/ui-react'; | ||
import { ThemeStyle } from '@aws-amplify/ui-react/server'; | ||
import { theme } from '@/theme'; | ||
import { Header } from '@/components/Header'; | ||
import ThemeToggle from '@/components/ThemeToggle'; | ||
import { cookies } from 'next/headers'; | ||
|
||
export default function Layout({ children }: { children: React.ReactNode }) { | ||
const cookieStore = cookies(); | ||
const colorMode = cookieStore.get('colorMode'); | ||
|
||
return ( | ||
<div | ||
{...theme.containerProps({ colorMode: colorMode?.value as ColorMode })} | ||
> | ||
<Header> | ||
Amplify UI RSC | ||
<ThemeToggle initialValue={colorMode?.value as ColorMode} /> | ||
</Header> | ||
{children} | ||
<ThemeStyle theme={theme} /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { ThemeStyle } from '@aws-amplify/ui-react/server'; | ||
import { Avatar } from '@/components/Avatar'; | ||
import { theme } from '@/theme'; | ||
|
||
export default function ThemeSwitcherPage() { | ||
console.log('server!'); | ||
return ( | ||
<div | ||
className="flex w-full flex-row" | ||
style={{ | ||
backgroundColor: `var(--breakpoint-large, #f90)`, | ||
}} | ||
> | ||
<Avatar size="small" /> | ||
<Avatar /> | ||
<Avatar size="large" /> | ||
<div {...theme.containerProps({ colorMode: 'dark' })}> | ||
<div | ||
className="flex w-full flex-row" | ||
style={{ | ||
backgroundColor: `${theme.tokens.colors.background.primary}`, | ||
}} | ||
> | ||
<Avatar size="small" /> | ||
<Avatar /> | ||
<Avatar size="large" /> | ||
</div> | ||
</div> | ||
<ThemeStyle theme={theme} /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { | ||
ThemeStyle, | ||
createComponentClasses, | ||
} from '@aws-amplify/ui-react/server'; | ||
import { theme } from '@/theme'; | ||
|
||
const headingClasses = createComponentClasses({ name: 'heading' }); | ||
|
||
export default function RootLayout({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
return ( | ||
<div className="flex w-full flex-row"> | ||
<div className="flex-1 p-2"> | ||
<h2 className={headingClasses({ _modifiers: ['2'] })}>Custom theme</h2> | ||
|
||
<ThemeStyle theme={theme} /> | ||
<section {...theme.containerProps({ colorMode: 'dark' })}> | ||
{children} | ||
</section> | ||
</div> | ||
<div className="flex-1 p-2"> | ||
<h2 className={headingClasses({ _modifiers: ['2'] })}>Default theme</h2> | ||
{children} | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
'use client'; | ||
|
||
import { Avatar } from '@/components/Avatar'; | ||
import { MyClientComponent } from '@/components/ClientComponent'; | ||
import { MyServerComponent } from '@/components/ServerComponent'; | ||
import { theme } from '@/theme'; | ||
import { | ||
Alert, | ||
Badge, | ||
BadgeProps, | ||
Button, | ||
ButtonProps, | ||
Flex, | ||
Heading, | ||
Text, | ||
} from '@aws-amplify/ui-react'; | ||
|
||
const colorThemes = [undefined, 'success', 'info', 'warning', 'error']; | ||
|
||
export default function ThemePage() { | ||
return ( | ||
<Flex direction="column"> | ||
<Heading level={3}>Badges</Heading> | ||
<Flex direction="row"> | ||
{colorThemes.map((colorTheme, i) => ( | ||
<Badge | ||
key={`${i}-${colorTheme}`} | ||
variation={colorTheme as BadgeProps['variation']} | ||
> | ||
{colorTheme || 'default'} | ||
</Badge> | ||
))} | ||
</Flex> | ||
<Heading level={3}>Buttons</Heading> | ||
<Flex direction="row"> | ||
{colorThemes.map((colorTheme, i) => ( | ||
<Button | ||
key={`${i}-${colorTheme}`} | ||
colorTheme={colorTheme as ButtonProps['colorTheme']} | ||
> | ||
{colorTheme || 'default'} | ||
</Button> | ||
))} | ||
</Flex> | ||
<Flex direction="row"> | ||
{colorThemes.map((colorTheme, i) => ( | ||
<Button | ||
key={`${i}-${colorTheme}`} | ||
variation="link" | ||
colorTheme={colorTheme as ButtonProps['colorTheme']} | ||
> | ||
{colorTheme || 'default'} | ||
</Button> | ||
))} | ||
</Flex> | ||
<Flex direction="row"> | ||
{colorThemes.map((colorTheme, i) => ( | ||
<Button | ||
key={`${i}-${colorTheme}`} | ||
variation="primary" | ||
colorTheme={colorTheme as ButtonProps['colorTheme']} | ||
> | ||
{colorTheme || 'default'} | ||
</Button> | ||
))} | ||
</Flex> | ||
<Avatar isDisabled /> | ||
<MyClientComponent /> | ||
<MyServerComponent /> | ||
<Text color={theme.tokens.colors.font.success}>Success!</Text> | ||
<Alert heading="Hello" /> | ||
<Alert heading="Hello success" variation="success" /> | ||
<Alert heading="Hello" variation="info" /> | ||
</Flex> | ||
); | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note