Skip to content
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

Add useTheme hook for runtime Polaris tokens access #10252

Merged
merged 35 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d8ed7ce
Initial base/variant themes support
aaronccasanova Aug 16, 2023
6d47ec7
Initial toStyleSheet test updates
aaronccasanova Aug 17, 2023
9e5fd29
Add changeset entry
aaronccasanova Aug 17, 2023
e55195b
Fix toStyleSheet formatting
aaronccasanova Aug 18, 2023
33e7f99
Fix toStyleSheet comments
aaronccasanova Aug 18, 2023
6d3cd8d
Remove legacy --p-keyframes-* check from toStyleSheet
aaronccasanova Aug 18, 2023
24b86f2
Add createThemeVariant util
aaronccasanova Aug 18, 2023
3c315c6
Remove extraneous exports
aaronccasanova Aug 18, 2023
f46788d
Add newline terminator
aaronccasanova Aug 18, 2023
b0724fd
Remove valueExperimental type and tokens
aaronccasanova Aug 21, 2023
3ae7a11
Update all build artifacts to support theming
aaronccasanova Aug 21, 2023
185e77c
Remove theme support in JSON artifacts
aaronccasanova Aug 21, 2023
491c1b3
Add changeset entry
aaronccasanova Aug 21, 2023
0e40b68
Add typesVersions to resolve themes types
lgriffee Aug 22, 2023
396e078
Alias themeDefault to metadata
aaronccasanova Aug 22, 2023
0b8b9d5
Expose theme-agnostic vars for use in JavaScript
aaronccasanova Aug 23, 2023
f0b035a
Update AppProvider and add hooks for runtime theme var access
aaronccasanova Aug 24, 2023
08ce53d
Add variant theme types for consistency
aaronccasanova Aug 24, 2023
c45fd6a
Replace themes entry point with named export
aaronccasanova Aug 25, 2023
e26eb29
Merge branch 'main' of https://github.com/Shopify/polaris into base-v…
aaronccasanova Aug 25, 2023
a2e1a1d
Merge branch 'base-variant-themes' of https://github.com/Shopify/pola…
aaronccasanova Aug 25, 2023
bdf11af
Merge branch 'polaris-tokens-artifacts-2' of https://github.com/Shopi…
aaronccasanova Aug 25, 2023
139f51d
Remove themeVars
aaronccasanova Aug 25, 2023
68e0ac8
Add meta prefix to all themes, theme partials, types, and utilities
aaronccasanova Aug 25, 2023
ba08725
Add createThemeVariant export
aaronccasanova Aug 26, 2023
883f777
Add useTheme hook
aaronccasanova Aug 26, 2023
badcbab
Initial getTheme utility
aaronccasanova Aug 31, 2023
3846725
Merge branch 'multi-theme-support' of https://github.com/Shopify/pola…
aaronccasanova Aug 31, 2023
a043cc8
Remove create/get theme types and utilities
aaronccasanova Aug 31, 2023
8192368
Remove unused exports
aaronccasanova Aug 31, 2023
b6f901d
Restructure internal meta theme variants
aaronccasanova Aug 31, 2023
fdf62af
Clean up meta theme partial types
aaronccasanova Aug 31, 2023
1517ca2
Simplify useTheme
aaronccasanova Aug 31, 2023
2cc8384
Formatting
aaronccasanova Aug 31, 2023
7995f28
Update tests
aaronccasanova Aug 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions polaris-react/src/components/AppProvider/AppProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React, {Component} from 'react';
import type {ThemeName} from '@shopify/polaris-tokens';
import {themeNameDefault} from '@shopify/polaris-tokens';

import {EphemeralPresenceManager} from '../EphemeralPresenceManager';
import {MediaQueryProvider} from '../MediaQueryProvider';
import {FocusManager} from '../FocusManager';
import {PortalsManager} from '../PortalsManager';
import {I18n, I18nContext} from '../../utilities/i18n';
import {ThemeContext, getTheme} from '../../utilities/use-theme';
import {
ScrollLockManager,
ScrollLockManagerContext,
Expand Down Expand Up @@ -115,32 +118,40 @@ export class AppProvider extends Component<AppProviderProps, State> {
};
};

getThemeName = (): ThemeName =>
this.getFeatures().polarisSummerEditions2023
? 'Polaris-Summer-Editions-2023'
: themeNameDefault;

render() {
const {children} = this.props;
const features = this.getFeatures();
const themeName = this.getThemeName();

const {intl, link} = this.state;

return (
<FeaturesContext.Provider value={features}>
<I18nContext.Provider value={intl}>
<ScrollLockManagerContext.Provider value={this.scrollLockManager}>
<StickyManagerContext.Provider value={this.stickyManager}>
<LinkContext.Provider value={link}>
<MediaQueryProvider>
<PortalsManager>
<FocusManager>
<EphemeralPresenceManager>
{children}
</EphemeralPresenceManager>
</FocusManager>
</PortalsManager>
</MediaQueryProvider>
</LinkContext.Provider>
</StickyManagerContext.Provider>
</ScrollLockManagerContext.Provider>
</I18nContext.Provider>
</FeaturesContext.Provider>
<ThemeContext.Provider value={getTheme(themeName)}>
<FeaturesContext.Provider value={features}>
<I18nContext.Provider value={intl}>
<ScrollLockManagerContext.Provider value={this.scrollLockManager}>
<StickyManagerContext.Provider value={this.stickyManager}>
<LinkContext.Provider value={link}>
<MediaQueryProvider>
<PortalsManager>
<FocusManager>
<EphemeralPresenceManager>
{children}
</EphemeralPresenceManager>
</FocusManager>
</PortalsManager>
</MediaQueryProvider>
</LinkContext.Provider>
</StickyManagerContext.Provider>
</ScrollLockManagerContext.Provider>
</I18nContext.Provider>
</FeaturesContext.Provider>
</ThemeContext.Provider>
);
}
}
1 change: 1 addition & 0 deletions polaris-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ export {
export {ScrollLockManagerContext as _SECRET_INTERNAL_SCROLL_LOCK_MANAGER_CONTEXT} from './utilities/scroll-lock-manager';
export {WithinContentContext as _SECRET_INTERNAL_WITHIN_CONTENT_CONTEXT} from './utilities/within-content-context';
export {useEventListener} from './utilities/use-event-listener';
export {useTheme} from './utilities/use-theme';
export {useIndexResourceState} from './utilities/use-index-resource-state';
export {
useRowHovered as useIndexTableRowHovered,
Expand Down
21 changes: 21 additions & 0 deletions polaris-react/src/utilities/use-theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {createContext, useContext} from 'react';
import type {ThemeName} from '@shopify/polaris-tokens';
import {themes, themeNameDefault} from '@shopify/polaris-tokens';

export function getTheme(themeName: ThemeName) {
return themes[themeName];
}

export const ThemeContext = createContext(getTheme(themeNameDefault));

export function useTheme() {
const theme = useContext(ThemeContext);

if (!theme) {
throw new Error(
'No theme was provided. Your application must be wrapped in an <AppProvider> component. See https://polaris.shopify.com/components/app-provider for implementation instructions.',
);
}

return theme;
}
8 changes: 5 additions & 3 deletions polaris-tokens/scripts/toJSON.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import path from 'path';

import {themeDefault} from '../src/themes';
import {metaThemeDefault} from '../src/themes';

const outputDir = path.join(__dirname, '../dist/json');

Expand All @@ -12,9 +12,11 @@ export async function toJSON() {
}
});

for (const [tokenGroupName, tokenGroup] of Object.entries(themeDefault)) {
for (const [tokenGroupName, metaTokenGroup] of Object.entries(
metaThemeDefault,
)) {
const filePath = path.join(outputDir, `${tokenGroupName}.json`);

await fs.promises.writeFile(filePath, JSON.stringify(tokenGroup));
await fs.promises.writeFile(filePath, JSON.stringify(metaTokenGroup));
}
}
9 changes: 5 additions & 4 deletions polaris-tokens/scripts/toMediaConditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import fs from 'fs';
import path from 'path';

import {getMediaConditions} from '../src';
import {themeDefault} from '../src/themes';

import {extractTokenGroupValues} from './utils';
import {metaThemeDefault} from '../src/themes';
import {extractMetaTokenGroupValues} from '../src/themes/utils';

const scssOutputDir = path.join(__dirname, '../dist/scss');
const scssOutputPath = path.join(scssOutputDir, 'media-queries.scss');
Expand All @@ -17,7 +16,9 @@ export async function toMediaConditions() {
});

const mediaConditionEntries = Object.entries(
getMediaConditions(extractTokenGroupValues(themeDefault.breakpoints)),
getMediaConditions(
extractMetaTokenGroupValues(metaThemeDefault.breakpoints),
),
);

const styles = mediaConditionEntries
Expand Down
46 changes: 24 additions & 22 deletions polaris-tokens/scripts/toStyleSheet.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import fs from 'fs';
import path from 'path';

import type {ThemeShape, TokenGroupShape} from '../src/themes/types';
import {themePartials, themeDefault} from '../src/themes';
import type {MetaThemeShape, MetaTokenGroupShape} from '../src/themes/types';
import {metaThemeVariantPartials, metaThemeDefault} from '../src/themes';
import {themeNameDefault} from '../src/themes/constants';
import {createThemeSelector} from '../src/themes/utils';
import {createVar} from '../src/utilities';
Expand All @@ -13,28 +13,28 @@ const cssOutputPath = path.join(cssOutputDir, 'styles.css');
const scssOutputPath = path.join(scssOutputDir, 'styles.scss');

/** Creates CSS declarations from a base or variant partial theme. */
export function getThemeDecls(theme: ThemeShape) {
return Object.values(theme)
.map((tokenGroup) => getTokenGroupDecls(tokenGroup))
export function getMetaThemeDecls(metaTheme: MetaThemeShape) {
return Object.values(metaTheme)
.map((metaTokenGroup) => getMetaTokenGroupDecls(metaTokenGroup))
.join('');
}

/** Creates CSS declarations from a token group. */
export function getTokenGroupDecls(tokenGroup: TokenGroupShape) {
return Object.entries(tokenGroup)
.map(([token, {value}]) =>
token.startsWith('motion-keyframes')
? `${createVar(token)}:p-${token};`
: `${createVar(token)}:${value};`,
export function getMetaTokenGroupDecls(metaTokenGroup: MetaTokenGroupShape) {
return Object.entries(metaTokenGroup)
.map(([tokenName, {value}]) =>
tokenName.startsWith('motion-keyframes')
? `${createVar(tokenName)}:p-${tokenName};`
: `${createVar(tokenName)}:${value};`,
)
.join('');
}

/** Creates `@keyframes` rules for `motion-keyframes-*` tokens. */
export function getKeyframes(motion: TokenGroupShape) {
export function getKeyframes(motion: MetaTokenGroupShape) {
return Object.entries(motion)
.filter(([token]) => token.startsWith('motion-keyframes'))
.map(([token, {value}]) => `@keyframes p-${token}${value}`)
.filter(([tokenName]) => tokenName.startsWith('motion-keyframes'))
.map(([tokenName, {value}]) => `@keyframes p-${tokenName}${value}`)
.join('');
}

Expand All @@ -51,17 +51,19 @@ export async function toStyleSheet() {
}
});

const themePartialsEntries = Object.entries(themePartials).filter(
([themeName]) => themeName !== themeNameDefault,
);
const metaThemeVariantPartialsEntries = Object.entries(
metaThemeVariantPartials,
).filter(([themeName]) => themeName !== themeNameDefault);

const styles = [
`:root{color-scheme:light;${getThemeDecls(themeDefault)}}`,
themePartialsEntries.map(
([themeName, themePartial]) =>
`${createThemeSelector(themeName)}{${getThemeDecls(themePartial)}}`,
`:root{color-scheme:light;${getMetaThemeDecls(metaThemeDefault)}}`,
metaThemeVariantPartialsEntries.map(
([themeName, metaThemeVariantPartial]) =>
`${createThemeSelector(themeName)}{${getMetaThemeDecls(
metaThemeVariantPartial,
)}}`,
),
getKeyframes(themeDefault.motion),
getKeyframes(metaThemeDefault.motion),
// Newline terminator
'',
]
Expand Down
41 changes: 11 additions & 30 deletions polaris-tokens/scripts/toValues.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import fs from 'fs';
import path from 'path';

import {camelCase, camelCaseTransformMerge} from 'change-case';

import type {Entry, Entries} from '../src/types';
import type {ThemeShape} from '../src/themes/types';
import {createThemeVariant, themePartials, themeDefault} from '../src/themes';

import type {ExtractThemeValues} from './utils';
import {extractThemeValues, extractTokenGroupValues} from './utils';
import {metaThemeVariants, metaThemeDefault} from '../src/themes';
import {extractMetaThemeValues} from '../src/themes/utils';

const outputDir = path.join(__dirname, '../build');

Expand All @@ -19,37 +13,24 @@ export async function toValues() {
}
});

const themeDefaultEntries: Entries<ExtractThemeValues<ThemeShape>> =
Object.entries(themeDefault).map(
([tokenGroupName, tokenGroup]): Entry<ExtractThemeValues<ThemeShape>> => [
tokenGroupName,
extractTokenGroupValues(tokenGroup),
],
);
const themeDefault = extractMetaThemeValues(metaThemeDefault);

await fs.promises.writeFile(
path.join(outputDir, 'index.ts'),

[
`export * from '../src/index';`,
themeDefaultEntries.map(createExport),
createExport(['tokens', Object.fromEntries(themeDefaultEntries)]),
createExport([
'themePartials',
Object.fromEntries(
Object.entries(themePartials).map(([themeName, themePartial]) => [
themeName,
extractThemeValues(themePartial),
]),
),
]),
Object.entries(themeDefault).map(createExport),
createExport(['tokens', themeDefault]),
createExport([
'themes',
Object.fromEntries(
Object.entries(themePartials).map(([themeName, themePartial]) => [
themeName,
extractThemeValues(createThemeVariant(themePartial)),
]),
Object.entries(metaThemeVariants).map(
([themeName, metaThemeVariant]) => [
themeName,
extractMetaThemeValues(metaThemeVariant),
],
),
),
]),
]
Expand Down
4 changes: 4 additions & 0 deletions polaris-tokens/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export type {
MetadataGroup,
} from './types';

export type {ThemeName} from './themes/types';

export {themeNameDefault} from './themes/constants';

export type {
BorderTokenGroup,
BorderTokenName,
Expand Down
4 changes: 2 additions & 2 deletions polaris-tokens/src/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {themeDefault} from './themes';
import {metaThemeDefault} from './themes';
import type {Exact, MetadataBase} from './types';

export const metadata = themeDefault;
export const metadata = metaThemeDefault;

export type Metadata = typeof metadata;

Expand Down
8 changes: 3 additions & 5 deletions polaris-tokens/src/themes/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import {shadow} from '../token-groups/shadow';
import {space} from '../token-groups/space';
import {zIndex} from '../token-groups/zIndex';

import type {ThemeShape} from './types';
import type {MetaThemeShape} from './types';

const createThemeBase = createExact<ThemeShape>();
const createMetaThemeBase = createExact<MetaThemeShape>();

export const themeBase = createThemeBase({
export const metaThemeBase = createMetaThemeBase({
breakpoints: tokensToRems(breakpoints),
border: tokensToRems(border),
color,
Expand All @@ -22,5 +22,3 @@ export const themeBase = createThemeBase({
space: tokensToRems(space),
zIndex,
});

export type ThemeBase = typeof themeBase;
30 changes: 20 additions & 10 deletions polaris-tokens/src/themes/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import type {ThemePartials} from './types';
import {createThemeVariant} from './utils';
import type {MetaThemeVariantPartials, MetaThemeVariants} from './types';
import {createMetaThemeVariant} from './utils';
import {themeNameDefault} from './constants';
import {themeLightPartial} from './light';
import {themeLightUpliftPartial} from './light-uplift';
import {metaThemeLight, metaThemeLightPartial} from './light';
import {
metaThemeLightUplift,
metaThemeLightUpliftPartial,
} from './light-uplift';

export {createThemeVariant} from './utils';
export {createMetaThemeVariant} from './utils';

export const themePartials: ThemePartials = {
light: themeLightPartial,
'Polaris-Summer-Editions-2023': themeLightUpliftPartial,
export const metaThemeVariants: MetaThemeVariants = {
light: metaThemeLight,
'Polaris-Summer-Editions-2023': metaThemeLightUplift,
};

export const themeDefaultPartial = themePartials[themeNameDefault];
export const themeDefault = createThemeVariant(themeDefaultPartial);
export const metaThemeVariantPartials: MetaThemeVariantPartials = {
light: metaThemeLightPartial,
'Polaris-Summer-Editions-2023': metaThemeLightUpliftPartial,
};

export const metaThemeDefaultPartial =
metaThemeVariantPartials[themeNameDefault];

export const metaThemeDefault = createMetaThemeVariant(metaThemeDefaultPartial);
8 changes: 6 additions & 2 deletions polaris-tokens/src/themes/light-uplift.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as colors from '../colors-experimental';

import {createThemeVariantPartial} from './utils';
import {createMetaThemeVariant, createMetaThemeVariantPartial} from './utils';

export const themeLightUpliftPartial = createThemeVariantPartial({
export const metaThemeLightUpliftPartial = createMetaThemeVariantPartial({
motion: {
'motion-ease-out': {value: 'cubic-bezier(0.19, 0.91, 0.38, 1)'},
},
Expand Down Expand Up @@ -171,3 +171,7 @@ export const themeLightUpliftPartial = createThemeVariantPartial({
'color-text-magic': {value: colors.purple[14]},
},
});

export const metaThemeLightUplift = createMetaThemeVariant(
metaThemeLightUpliftPartial,
);
6 changes: 4 additions & 2 deletions polaris-tokens/src/themes/light.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {createThemeVariantPartial} from './utils';
import {createMetaThemeVariant, createMetaThemeVariantPartial} from './utils';

export const themeLightPartial = createThemeVariantPartial({});
export const metaThemeLightPartial = createMetaThemeVariantPartial({});

export const metaThemeLight = createMetaThemeVariant(metaThemeLightPartial);
Loading