Skip to content

Commit

Permalink
Merge branch 'main' into oa/anagram-helper-show-hide
Browse files Browse the repository at this point in the history
  • Loading branch information
oliverabrahams authored Jan 24, 2025
2 parents 17e9c94 + ca3aa52 commit 316ad8c
Show file tree
Hide file tree
Showing 9 changed files with 467 additions and 477 deletions.
2 changes: 2 additions & 0 deletions libs/@guardian/react-crossword/src/@types/crossword.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export type Theme = {

/** Border colour used to visually separate parts of the UI */
borderColor: string;
/** Border colour applied to the top of the clue lists */
clueListBorderColor: string;

/** The minimum width of a clue */
clueMinWidth: number;
Expand Down
22 changes: 12 additions & 10 deletions libs/@guardian/react-crossword/src/components/Cell.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import type { Theme } from '../@types/crossword';
import { ThemeProvider, useTheme } from '../context/Theme';
import { defaultTheme } from '../theme';
import type { CellProps } from './Cell';
import type { BaseCellProps } from './Cell';
import { Cell } from './Cell';

const meta: Meta<typeof Cell> = {
Expand Down Expand Up @@ -39,43 +39,45 @@ const meta: Meta<typeof Cell> = {
],
};

const args: CellProps = {
const args: BaseCellProps = {
x: 0,
y: 0,
data: {
x: 0,
y: 0,
group: ['1-across'],
},
isBlackCell: false,
};

export default meta;
type Story = StoryObj<typeof Cell>;

export const Default: Story = { args };
export const Default: Story = {
args: {
...args,
},
};

export const Black: Story = {
args: {
...args,
data: {
...args.data,
group: undefined,
},
isBlackCell: true,
},
};

export const Highlighted: Story = {
args: {
...args,
isHighlighted: true,
isConnected: true,
},
};

export const Active: Story = {
args: {
...args,
isActive: true,
isHighlighted: true,
isSelected: true,
isConnected: true,
},
};

Expand Down
114 changes: 73 additions & 41 deletions libs/@guardian/react-crossword/src/components/Cell.tsx
Original file line number Diff line number Diff line change
@@ -1,79 +1,111 @@
import { css } from '@emotion/react';
import { isUndefined } from '@guardian/libs';
import { textSans12 } from '@guardian/source/foundations';
import type { SVGProps } from 'react';
import { memo } from 'react';
import type { Cell as CellType } from '../@types/crossword';
import { useTheme } from '../context/Theme';

export type CellProps = {
export type BaseCellProps = {
data: CellType;
x: number;
y: number;
guess?: string;
/** is the cell receiving input? */
isFocused?: boolean;
isBlackCell: boolean;
/** is the cell connected in any way to the active clue? */
isHighlighted?: boolean;
/** is the cell for the active clue? */
isActive?: boolean;
isConnected?: boolean;
/** is the cell for the selected clue? */
isSelected?: boolean;
};

export type CellProps = BaseCellProps & SVGProps<SVGGElement>;

const CellComponent = ({
data,
x,
y,
guess = '',
isHighlighted,
isActive,
isBlackCell,
isConnected,
isSelected,
children,
...props
}: CellProps) => {
const theme = useTheme();

const backgroundColor = isUndefined(data.group)
const backgroundColor = isBlackCell
? 'transparent'
: isHighlighted
? isActive
: isConnected
? isSelected
? theme.selectedColor
: theme.connectedColor
: theme.gridForegroundColor;

return (
<g data-x={data.x} data-y={data.y}>
<g {...props}>
<rect
x={x}
y={y}
width={theme.gridCellSize}
height={theme.gridCellSize}
fill={backgroundColor}
aria-hidden="true"
role="presentation"
/>
{data.number && (
<text
x={x}
y={y}
dx={Math.max(1, theme.gridCellSize * 0.05)}
dy={Math.max(9, theme.gridCellSize * 0.22)}
fill={theme.textColor}
css={css`
${textSans12};
font-size: ${Math.max(9, Math.round(theme.gridCellSize * 0.2))}px;
`}
>
{data.number}
</text>
{!isBlackCell && (
<>
{data.number && (
<text
x={x}
y={y}
dx={Math.max(1, theme.gridCellSize * 0.05)}
dy={Math.max(9, theme.gridCellSize * 0.22)}
fill={theme.textColor}
css={css`
${textSans12};
font-size: ${Math.max(
9,
Math.round(theme.gridCellSize * 0.2),
)}px;
`}
aria-hidden="true"
role="presentation"
>
{data.number}
</text>
)}

{children ? (
<foreignObject
x={x}
y={y}
width={theme.gridCellSize}
height={theme.gridCellSize}
css={css`
position: relative;
`}
>
{children}
</foreignObject>
) : (
<text
x={x + theme.gridCellSize / 2}
y={y + theme.gridCellSize / 2}
dy={theme.gridCellSize * 0.07}
textAnchor="middle"
dominantBaseline="middle"
fill={theme.textColor}
css={css`
${textSans12};
font-size: ${theme.gridCellSize * 0.6}px;
`}
aria-hidden="true"
role="presentation"
>
{guess}
</text>
)}
</>
)}
<text
x={x + theme.gridCellSize / 2}
y={y + theme.gridCellSize / 2}
dy={theme.gridCellSize * 0.07}
textAnchor="middle"
dominantBaseline="middle"
fill={theme.textColor}
css={css`
${textSans12};
font-size: ${theme.gridCellSize * 0.6}px;
`}
>
{guess}
</text>
</g>
);
};
Expand Down
10 changes: 7 additions & 3 deletions libs/@guardian/react-crossword/src/components/Clues.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,13 @@ export const Clues = ({ direction, Header }: Props) => {
const selectClue = useCallback(
(entry: CAPIEntry) => {
setCurrentEntryId(entry.id);
setCurrentCell(
cells.getByCoords({ x: entry.position.x, y: entry.position.y }),
);
const newCell = cells.getByCoords({
x: entry.position.x,
y: entry.position.y,
});
if (newCell) {
setCurrentCell(newCell);
}
},
[cells, setCurrentCell, setCurrentEntryId],
);
Expand Down
7 changes: 1 addition & 6 deletions libs/@guardian/react-crossword/src/components/Crossword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,7 @@ export const Crossword = ({
);

return (
<ContextProvider
theme={theme}
data={data}
userProgress={progress}
selectedEntryId={data.entries[0].id}
>
<ContextProvider theme={theme} data={data} userProgress={progress}>
<div
role="application"
css={css`
Expand Down
Loading

0 comments on commit 316ad8c

Please sign in to comment.