Skip to content

Commit

Permalink
Merge 6a22458 into 704ccd2
Browse files Browse the repository at this point in the history
  • Loading branch information
sndrs authored Dec 12, 2024
2 parents 704ccd2 + 6a22458 commit 40850ee
Show file tree
Hide file tree
Showing 14 changed files with 102 additions and 59 deletions.
1 change: 1 addition & 0 deletions libs/@guardian/react-crossword/src/@types/Layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export type LayoutProps = {
AnagramHelper: typeof AnagramHelper;
Clues: typeof Clues;
SavedMessage: ComponentType;
gridWidth: number;
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import { groupedClues as data } from '../../stories/formats/grouped-clues';
import { progress12Across } from '../../stories/formats/grouped-clues.progress';
import { ContextProvider } from '../context/ContextProvider';
import { defaultTheme } from '../theme';
import { AnagramHelper } from './AnagramHelper';

const meta: Meta<typeof AnagramHelper> = {
Expand All @@ -11,6 +12,7 @@ const meta: Meta<typeof AnagramHelper> = {
(Story) => (
<ContextProvider
data={data}
theme={defaultTheme}
selectedEntryId="12-across"
userProgress={progress12Across}
>
Expand All @@ -31,7 +33,11 @@ export const Default: Story = {
export const LongClue: Story = {
decorators: [
(Story) => (
<ContextProvider data={data} selectedEntryId="7-across">
<ContextProvider
data={data}
theme={defaultTheme}
selectedEntryId="7-across"
>
<Story />
</ContextProvider>
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';
import { groupedClues as data } from '../../stories/formats/grouped-clues';
import { ContextProvider } from '../context/ContextProvider';
import { defaultTheme } from '../theme';
import { Clue } from './Clue';

const meta: Meta<typeof Clue> = {
Expand All @@ -11,7 +12,7 @@ const meta: Meta<typeof Clue> = {
},
decorators: [
(Story) => (
<ContextProvider data={data}>
<ContextProvider data={data} theme={defaultTheme}>
<Story />
</ContextProvider>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { groupedClues as data } from '../../stories/formats/grouped-clues';
import { progress } from '../../stories/formats/grouped-clues.progress';
import { ContextProvider } from '../context/ContextProvider';
import { ValidAnswersProvider } from '../context/ValidAnswers';
import { defaultTheme } from '../theme';
import { Clues } from './Clues';

const meta: Meta<typeof Clues> = {
Expand All @@ -16,7 +17,11 @@ const meta: Meta<typeof Clues> = {
localStorage.removeItem(data.id);

return (
<ContextProvider data={data} userProgress={progress}>
<ContextProvider
data={data}
userProgress={progress}
theme={defaultTheme}
>
<Story />
</ContextProvider>
);
Expand All @@ -37,7 +42,7 @@ export const Default: Story = {};
export const WithSuccess: Story = {
decorators: [
(Story) => (
<ContextProvider data={data} userProgress={progress}>
<ContextProvider data={data} userProgress={progress} theme={defaultTheme}>
<ValidAnswersProvider validAnswers={new Set(['7-across'])}>
<Story />
</ValidAnswersProvider>
Expand Down
34 changes: 19 additions & 15 deletions libs/@guardian/react-crossword/src/components/Clues.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { css } from '@emotion/react';
import type { ComponentType } from 'react';
import type { ComponentType, ReactNode } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import type { Direction } from '../@types/Direction';
import type { EntryID } from '../@types/Entry';
Expand All @@ -14,9 +14,10 @@ type Props = {
/** Use this to provide a custom header component for the list of clues. If
* undefined, the word 'across' or 'down' will be displayed, unstyled. */
Header?: ComponentType<{
/** If you use a custom clues header, this prop is required to force
* users to do something with it, for the sake of a11y... */
direction: Direction;
/** If you use a custom clues header, it must accept children so that we
* can provide a properly marked up `label` element, for the sake of
* a11y... */
children: ReactNode;
}>;
};

Expand Down Expand Up @@ -64,19 +65,22 @@ export const Clues = ({ direction, Header }: Props) => {
}
}

const label = (
<label
css={css`
color: currentColor;
`}
id={getId(`${direction}-label`)}
htmlFor={getId(`${direction}-hints`)}
>
{direction}
</label>
);

return (
<div ref={cluesRef}>
<label
css={css`
display: block;
color: currentColor;
text-transform: capitalize;
`}
id={getId(`${direction}-label`)}
htmlFor={getId(`${direction}-hints`)}
>
{Header ? <Header direction={direction} /> : direction}
</label>
{Header ? <Header>{label}</Header> : label}

<div
tabIndex={0}
id={getId(`${direction}-hints`)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';
import { groupedClues as data } from '../../stories/formats/grouped-clues';
import { ContextProvider } from '../context/ContextProvider';
import { defaultTheme } from '../theme';
import { Controls } from './Controls';

const meta: Meta<typeof Controls> = {
Expand All @@ -12,7 +13,11 @@ const meta: Meta<typeof Controls> = {
localStorage.removeItem(data.id);

return (
<ContextProvider data={data} selectedEntryId={data.entries[0].id}>
<ContextProvider
data={data}
theme={defaultTheme}
selectedEntryId={data.entries[0].id}
>
<Story />
</ContextProvider>
);
Expand All @@ -30,7 +35,7 @@ export const NoSelectedEntry: Story = {
(Story) => {
localStorage.removeItem(data.id);
return (
<ContextProvider data={data}>
<ContextProvider data={data} theme={defaultTheme}>
<Story />
</ContextProvider>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Meta, StoryFn, StoryObj } from '@storybook/react';
import type { ReactNode } from 'react';
import { groupedClues as data } from '../../stories/formats/grouped-clues';
import { progress } from '../../stories/formats/grouped-clues.progress';
import { quick as quickData } from '../../stories/formats/quick';
import type { Direction } from '../@types/Direction';
import type { LayoutProps } from '../@types/Layout';
import { Crossword } from './Crossword';

Expand Down Expand Up @@ -69,9 +69,16 @@ export const MultiplePlayersRow: StoryFn = () => {
};

export const CustomLayoutRaw: StoryFn = () => {
const Layout = ({ Clues, Grid, Controls, SavedMessage }: LayoutProps) => {
const Layout = ({
Clues,
Grid,
Controls,
SavedMessage,
gridWidth,
}: LayoutProps) => {
return (
<>
<p>gridWidth: {gridWidth}</p>
<Grid />
<Controls />
<SavedMessage />
Expand All @@ -84,7 +91,7 @@ export const CustomLayoutRaw: StoryFn = () => {
};

export const CustomisedLayout: StoryFn = () => {
const CluesHeader = (props: { direction: Direction }) => (
const CluesHeader = ({ children }: { children: ReactNode }) => (
<h2
style={{
fontFamily: 'monospace',
Expand All @@ -97,19 +104,26 @@ export const CustomisedLayout: StoryFn = () => {
justifyContent: 'center',
alignItems: 'center',
marginBottom: '0.5em',
color: 'royalblue',
}}
>
{props.direction === 'across' ? '👉' : '👇'}
{children}
</h2>
);

const Layout = ({ Clues, Grid, Controls, SavedMessage }: LayoutProps) => {
const Layout = ({
Clues,
Grid,
Controls,
SavedMessage,
gridWidth,
}: LayoutProps) => {
return (
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 20 }}>
<div style={{ flex: 1, minWidth: '15em' }}>
<Clues direction="across" Header={CluesHeader} />
</div>
<div style={{ flexBasis: 496, minWidth: '15em' }}>
<div style={{ flexBasis: gridWidth, minWidth: '15em' }}>
<Grid />
<Controls />
<div
Expand Down
23 changes: 19 additions & 4 deletions libs/@guardian/react-crossword/src/components/Crossword.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { css } from '@emotion/react';
import type { ComponentType, ReactNode } from 'react';
import { type ComponentType, type ReactNode, useMemo } from 'react';
import type { CAPICrossword } from '../@types/CAPI';
import type { Progress, Theme } from '../@types/crossword';
import type { LayoutProps } from '../@types/Layout';
import { ContextProvider } from '../context/ContextProvider';
import { useProgress } from '../context/Progress';
import { ScreenLayout } from '../layouts/ScreenLayout';
import { defaultTheme } from '../theme';
import { AnagramHelper } from './AnagramHelper';
import { Clues } from './Clues';
import { Controls } from './Controls';
Expand All @@ -30,7 +31,7 @@ const SavedMessage = () => {
);
};

const layoutProps: LayoutProps = {
const layoutComponents: Omit<LayoutProps, 'gridWidth'> = {
Grid,
Controls,
AnagramHelper,
Expand All @@ -47,9 +48,21 @@ export const Crossword = ({
}: CrosswordProps) => {
const LayoutComponent = Layout ?? ScreenLayout;

const theme = useMemo<Theme>(
() => ({ ...defaultTheme, ...userTheme }),
[userTheme],
);

const gridWidth = useMemo(
() =>
(theme.gridCellSize + theme.gridGutterSize) * data.dimensions.cols +
theme.gridGutterSize,
[theme.gridCellSize, theme.gridGutterSize, data.dimensions.cols],
);

return (
<ContextProvider
userTheme={userTheme}
theme={theme}
data={data}
userProgress={progress}
selectedEntryId={data.entries[0].id}
Expand All @@ -70,7 +83,9 @@ export const Crossword = ({
container-type: inline-size;
`}
>
{children ?? <LayoutComponent {...layoutProps} />}
{children ?? (
<LayoutComponent {...layoutComponents} gridWidth={gridWidth} />
)}
</div>
</ContextProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { progress } from '../../stories/formats/grouped-clues.progress';
import { separators as separatorData } from '../../stories/formats/separators';
import type { Progress as ProgressType } from '../@types/crossword';
import { ContextProvider } from '../context/ContextProvider';
import { defaultTheme } from '../theme';
import { Grid } from './Grid';

const meta: Meta<typeof Grid> = {
Expand All @@ -16,6 +17,7 @@ const meta: Meta<typeof Grid> = {
return (
<ContextProvider
data={data}
theme={defaultTheme}
userProgress={parameters.progress as ProgressType}
>
<Story />
Expand All @@ -39,7 +41,7 @@ export const Progress: Story = {
export const Separators: Story = {
decorators: [
(Story) => (
<ContextProvider data={separatorData}>
<ContextProvider data={separatorData} theme={defaultTheme}>
<Story />
</ContextProvider>
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';
import { groupedClues as data } from '../../stories/formats/grouped-clues';
import { ContextProvider } from '../context/ContextProvider';
import { defaultTheme } from '../theme';
import { SolutionDisplay } from './SolutionDisplay';

const meta: Meta<typeof SolutionDisplay> = {
Expand All @@ -9,7 +10,7 @@ const meta: Meta<typeof SolutionDisplay> = {
args: {},
decorators: [
(Story) => (
<ContextProvider data={data}>
<ContextProvider data={data} theme={defaultTheme}>
<Story />
</ContextProvider>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Meta } from '@storybook/react';
import { type StoryObj } from '@storybook/react';
import { groupedClues as data } from '../../stories/formats/grouped-clues';
import { ContextProvider } from '../context/ContextProvider';
import { defaultTheme } from '../theme';
import { WordWheel } from './WordWheel';

const meta: Meta<typeof WordWheel> = {
Expand All @@ -10,7 +11,7 @@ const meta: Meta<typeof WordWheel> = {
args: {},
decorators: [
(Story) => (
<ContextProvider data={data}>
<ContextProvider data={data} theme={defaultTheme}>
<Story />
</ContextProvider>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@

import type { ReactNode } from 'react';
import type { CAPICrossword } from '../@types/CAPI';
import type { Progress } from '../@types/crossword';
import type { Progress, Theme } from '../@types/crossword';
import type { EntryID } from '../@types/Entry';
import type { CrosswordProps } from '../components/Crossword';
import { CurrentCellProvider } from './CurrentCell';
import { CurrentClueProvider } from './CurrentClue';
import { DataProvider } from './Data';
Expand All @@ -35,19 +34,19 @@ export const ContextProvider = ({
data,
selectedEntryId,
userProgress,
userTheme,
theme,
children,
}: {
data: CAPICrossword;
selectedEntryId?: EntryID;
userProgress?: Progress;
userTheme?: Partial<CrosswordProps>;
theme: Theme;
children: ReactNode;
}) => {
const { entries, dimensions, solutionAvailable, id } = data;

return (
<ThemeProvider theme={userTheme}>
<ThemeProvider theme={theme}>
<UIStateProvider>
<DataProvider
entries={entries}
Expand Down
Loading

0 comments on commit 40850ee

Please sign in to comment.