Skip to content

Commit d871d3f

Browse files
authored
Crossword component documentation (#1970)
* Add features to README * Add details of props and examples of data formats * Add image of example crossword grid * Add links and minor copy updates
1 parent d5c0377 commit d871d3f

File tree

2 files changed

+214
-6
lines changed

2 files changed

+214
-6
lines changed

libs/@guardian/react-crossword/README.md

+214-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,221 @@
11
# `@guardian/react-crossword`
22

3-
A standalone component for rendering crosswords.
3+
A standalone React component for rendering crosswords.
44

5-
> [!NOTE]
6-
> This code is a WIP of v3 of the NPM package.
7-
>
8-
> The current version of the package is v2.0.0 and lives at https://github.com/guardian/react-crossword.
5+
<img src="assets/example-grid.png" />
96

10-
## Install
7+
## Features
8+
9+
- Renders crossword grid and clues
10+
- Displays separators in grid for hyphenated and multiple-word answers
11+
- Layout is responsive (and can be customised)
12+
- Attempted clues are greyed out in the clue list
13+
- Clicking on a clue highlights the associated row or column
14+
- Groups clues together when they span multiple columns or rows
15+
- Progress is saved to local storage
16+
- Answers can be checked and revealed
17+
- Smart clearing when checking answers that strikes through incorrect letters
18+
- Anagram helper
19+
- Accessible: elements in the crossword are clearly labelled to communicate context and state to assistive technology
20+
- Keyboard navigable: you can tab between the grid, clues and controls, and these can be navigated with the arrow key
21+
- Includes print styles
22+
- Includes support for theming and custom colour schemes
23+
24+
## API
25+
26+
### Props
27+
28+
| Prop | Details |
29+
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
30+
| `data` | (_Required_) Data to render the crossword, including clues, answers and metadata (See [**Crossword data format**](#crossword-data-format)) |
31+
| `progress` | (_Optional_) Current state of the grid (See [**Progress format**](#progress-format)) |
32+
| `Layout` | (_Optional_) Allows default layout to be customised (See [**Layout**](#layout)) |
33+
34+
Any of the keys from the default theme can also be passed as a prop to customise the appearance of the crossword. These are detailed in the [**Theming**](#theming) section.
35+
36+
### Crossword data format
37+
38+
This is an example set of data used to create the crossword shown above:
39+
40+
```js
41+
{
42+
id: 'crosswords/example/1',
43+
number: 1,
44+
name: 'Example crossword No 1',
45+
creator: {
46+
name: 'James',
47+
webUrl: 'https://www.theguardian.com/profile/maskarade',
48+
},
49+
date: 1740149419743,
50+
webPublicationDate: 1740149419743,
51+
entries: [
52+
{
53+
id: '1-across',
54+
number: 1,
55+
humanNumber: '1',
56+
clue: 'Toy on a string (2-2)',
57+
direction: 'across',
58+
length: 4,
59+
group: ['1-across'],
60+
position: { x: 0, y: 0 },
61+
separatorLocations: {
62+
'-': [2],
63+
},
64+
solution: 'YOYO',
65+
},
66+
{
67+
id: '2-across',
68+
number: 2,
69+
humanNumber: '2',
70+
clue: 'Have a rest (3,4)',
71+
direction: 'across',
72+
length: 7,
73+
group: ['2-across'],
74+
position: { x: 0, y: 2 },
75+
separatorLocations: {
76+
',': [3],
77+
},
78+
solution: 'LIEDOWN',
79+
},
80+
{
81+
id: '1-down',
82+
number: 1,
83+
humanNumber: '1',
84+
clue: 'Colour (6)',
85+
direction: 'down',
86+
length: 6,
87+
group: ['1-down'],
88+
position: { x: 0, y: 0 },
89+
separatorLocations: {},
90+
solution: 'YELLOW',
91+
},
92+
{
93+
id: '3-down',
94+
number: 3,
95+
humanNumber: '3',
96+
clue: 'Bits and bobs (4,3,4)',
97+
direction: 'down',
98+
length: 7,
99+
group: ['3-down', '4-down'],
100+
position: { x: 3, y: 0 },
101+
separatorLocations: {
102+
',': [4],
103+
},
104+
solution: 'ODDSAND',
105+
},
106+
{
107+
id: '4-down',
108+
number: 4,
109+
humanNumber: '4',
110+
clue: 'See 3 down',
111+
direction: 'down',
112+
length: 4,
113+
group: ['3-down', '4-down'],
114+
position: {
115+
x: 6,
116+
y: 1,
117+
},
118+
separatorLocations: {},
119+
solution: 'ENDS',
120+
},
121+
],
122+
solutionAvailable: true,
123+
dateSolutionAvailable: 1542326400000,
124+
dimensions: {
125+
cols: 13,
126+
rows: 13,
127+
},
128+
crosswordType: 'quick',
129+
pdf: 'https://crosswords-static.guim.co.uk/gdn.quick.20250221.pdf',
130+
}
131+
```
132+
133+
### Progress format
134+
135+
Grid progress is stored as a simple 2 dimensional array and is persisted in local storage. Each element in the array contains the value of the corresponding grid cell. Cells that are empty or not part of an answer are represented as an empty string.
136+
137+
The example crossword above is represented as:
138+
139+
```js
140+
[
141+
['Y', 'E', 'L', 'L', 'O', 'W', ''],
142+
['O', '', 'I', '', '', '', ''],
143+
['Y', '', 'E', '', '', '', ''],
144+
['O', 'D', 'D', 'S', 'A', 'N', 'D'],
145+
['', '', 'O', '', '', '', ''],
146+
['', '', 'W', '', '', '', ''],
147+
['', 'E', 'N', 'D', 'S', '', ''],
148+
];
149+
```
150+
151+
The data is indexed by column (x) and then row (y) so the data in the array when printed is transposed when compared to the visual layout of the grid.
152+
153+
For example, the last letter of _2 across_ is in the 7th column and 3rd row of the grid so would be accessed as `progress[6][2]` giving us 'N'.
154+
155+
### Theming
156+
157+
The following keys from the crossword theme can be passed to the `Crossword` component to customise its appearance:
158+
159+
| Key | Description |
160+
| --------------------------------- | ------------------------------------------------------------------------- |
161+
| `gridBackgroundColor` | background colour of 'black' squares/dividers etc on the grid |
162+
| `gridForegroundColor` | background colour of 'white' squares on the grid |
163+
| `gridPrintBackgroundColor` | background colour of 'black' squares on grid when printed |
164+
| `gridGutterSize` | size of the gap between grid cells |
165+
| `gridCellSize` | length of one side of a cell on on the grid |
166+
| `gridCellStrikeThrough` | colour of the strike through on an incorrect cell |
167+
| `textColor` | main text colour (grid text, clues etc.) |
168+
| `focusColor` | colour of the currently selected cell border |
169+
| `selectedColor` | colour of cells / clues that are currently selected |
170+
| `connectedColor` | colour of cells / clues that are connected to the currently selected clue |
171+
| `buttonBackgroundColor` | background colour of clue-helper buttons |
172+
| `buttonBackgroundHoverColor` | hover colour of clue-helper buttons |
173+
| `borderColor` | border colour used to visually separate parts of the UI |
174+
| `clueListBorderColor` | border colour applied to the top of the clue lists |
175+
| `clueMinWidth` | minimum width of a clue |
176+
| `clueMaxWidth` | maximum width of a clue |
177+
| `anagramHelperBackgroundColor` | background colour of the anagram helper |
178+
| `anagramHelperCandidateTextColor` | text colour of shuffled letter that are not yet on the grid |
179+
| `focusedClueBackgroundColour` | background colour for the focused clue |
180+
181+
## Architecture
182+
183+
### Layout
184+
185+
A custom layout component can passed to the `Crossword` component via the `Layout` prop. The individual components that the crossword is composed of are passed to the layout as props so that additional elements or styles can be applied as required. (This is used in DCR to customise the layout and allow the insertion of ad slots.)
186+
187+
This is a simplified example of a layout:
188+
189+
```tsx
190+
const Layout: CrosswordProps['Layout'] = ({
191+
Grid,
192+
Clues,
193+
Controls,
194+
SavedMessage,
195+
AnagramHelper,
196+
FocusedClue,
197+
}) => {
198+
return (
199+
<div>
200+
<AnagramHelper />
201+
<div>
202+
<FocusedClue />
203+
<Grid />
204+
<FocusedClue />
205+
<Controls />
206+
<SavedMessage />
207+
</div>
208+
209+
<div>
210+
<Clues direction="across" />
211+
<Clues direction="down" />
212+
</div>
213+
</div>
214+
);
215+
};
216+
```
217+
218+
## Installation
11219

12220
```sh
13221
$ pnpm add @guardian/react-crossword
Loading

0 commit comments

Comments
 (0)