Skip to content

Commit

Permalink
Merge pull request #157 from JaredReisinger/dev
Browse files Browse the repository at this point in the history
Dev -> Main
  • Loading branch information
JaredReisinger authored Jan 3, 2022
2 parents 5fc185b + 5cf5110 commit 67bbbbb
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
- run: npm run build

- if: ${{ github.event_name == 'push' && startsWith(matrix.node-version, '14.') }}
name: Publish code coverage
uses: codecov/codecov-action@v2
# with:
# verbose: true
Expand All @@ -43,6 +44,7 @@ jobs:
run: npx semantic-release

- if: ${{ github.event_name == 'push' && github.ref_name == 'main' && startsWith(matrix.node-version, '14.') }}
name: Publish styleguide
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
Expand Down
12 changes: 12 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ function App() {
crossword.current?.focus();
}, []);

const fillOneCell = useCallback((event) => {
crossword.current?.setGuess(0, 2, 'O');
}, []);

const fillAllAnswers = useCallback((event) => {
crossword.current?.fillAllAnswers();
}, []);
Expand Down Expand Up @@ -193,6 +197,10 @@ function App() {
crosswordProvider.current?.focus();
}, []);

const fillOneCellProvider = useCallback((event) => {
crosswordProvider.current?.setGuess(0, 2, 'O');
}, []);

const fillAllAnswersProvider = useCallback((event) => {
crosswordProvider.current?.fillAllAnswers();
}, []);
Expand Down Expand Up @@ -276,6 +284,7 @@ function App() {

<Commands>
<Command onClick={focus}>Focus</Command>
<Command onClick={fillOneCell}>Fill the first letter of 2-down</Command>
<Command onClick={fillAllAnswers}>Fill all answers</Command>
<Command onClick={reset}>Reset</Command>
<Command onClick={clearMessages}>Clear messages</Command>
Expand Down Expand Up @@ -303,6 +312,9 @@ function App() {

<Commands>
<Command onClick={focusProvider}>Focus</Command>
<Command onClick={fillOneCellProvider}>
Fill the first letter of 2-down
</Command>
<Command onClick={fillAllAnswersProvider}>Fill all answers</Command>
<Command onClick={resetProvider}>Reset</Command>
<Command onClick={clearMessagesProvider}>Clear messages</Command>
Expand Down
13 changes: 7 additions & 6 deletions src/Crossword.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ In addition to providing properties for styling, there are some properties to he

The following imperative methods can be called on a "ref" handle to the component:

| method name | parameters | description |
| ---------------------- | ---------- | --------------------------------------------------------------------------------------------------- |
| `focus()` | _(none)_ | Sets focus to the crossword component. |
| `reset()` | _(none)_ | Resets the entire crossword; clearing all answers in the grid and also any persisted data. |
| `fillAllAnswers()` | _(none)_ | Fills all the answers in the grid and calls the `onLoadedCorrect` callback with _**every**_ answer. |
| `isCrosswordCorrect()` | _(none)_ | Returns whether the crossword is entirely correct or not. |
| method name | parameters | description |
| --------------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `focus()` | _(none)_ | Sets focus to the crossword component. |
| `reset()` | _(none)_ | Resets the entire crossword; clearing all answers in the grid and also any persisted data. |
| `fillAllAnswers()` | _(none)_ | Fills all the answers in the grid and calls the `onLoadedCorrect` callback with _**every**_ answer. |
| `isCrosswordCorrect()` | _(none)_ | Returns whether the crossword is entirely correct or not. |
| `setGuess(row, col, guess)` | `(row: number, col: number, guess: string)` | Sets the “guess” value for a specific grid position. |

### Another example

Expand Down
8 changes: 8 additions & 0 deletions src/Crossword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ const Crossword = React.forwardRef<CrosswordImperative, CrosswordProps>(
* @since 2.2.0
*/
isCrosswordCorrect: () => !!providerRef.current?.isCrosswordCorrect(),

/**
* Sets the “guess” character for a specific grid position.
*
* @since 4.1.0
*/
setGuess: (row: number, col: number, guess: string) =>
providerRef.current?.setGuess(row, col, guess),
}),
[]
);
Expand Down
13 changes: 7 additions & 6 deletions src/CrosswordProvider.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ In addition to providing properties for styling, there are some properties to he

The following imperative methods can be called on a "ref" handle to the component:

| method name | parameters | description |
| ---------------------- | ---------- | --------------------------------------------------------------------------------------------------- |
| `focus()` | _(none)_ | Sets focus to the crossword component. |
| `reset()` | _(none)_ | Resets the entire crossword; clearing all answers in the grid and also any persisted data. |
| `fillAllAnswers()` | _(none)_ | Fills all the answers in the grid and calls the `onLoadedCorrect` callback with _**every**_ answer. |
| `isCrosswordCorrect()` | _(none)_ | Returns whether the crossword is entirely correct or not. |
| method name | parameters | description |
| --------------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `focus()` | _(none)_ | Sets focus to the crossword component. |
| `reset()` | _(none)_ | Resets the entire crossword; clearing all answers in the grid and also any persisted data. |
| `fillAllAnswers()` | _(none)_ | Fills all the answers in the grid and calls the `onLoadedCorrect` callback with _**every**_ answer. |
| `isCrosswordCorrect()` | _(none)_ | Returns whether the crossword is entirely correct or not. |
| `setGuess(row, col, guess)` | `(row: number, col: number, guess: string)` | Sets the “guess” value for a specific grid position. |
17 changes: 17 additions & 0 deletions src/CrosswordProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ export interface CrosswordProviderImperative {
* Returns whether the crossword is entirely correct or not.
*/
isCrosswordCorrect: () => boolean;

/**
* Sets the “guess” character for a specific grid position.
*
* @since 4.1.0
*/
setGuess: (row: number, col: number, guess: string) => void;
}

/**
Expand Down Expand Up @@ -848,6 +855,16 @@ const CrosswordProvider = React.forwardRef<
* Returns whether the crossword is entirely correct or not.
*/
isCrosswordCorrect: () => crosswordCorrect,

/**
* Sets the “guess” character for a specific grid position.
*
* @since 4.1.0
*/
setGuess: (row: number, col: number, guess: string) => {
// REVIEW: should we force-case this?
setCellCharacter(row, col, guess.toUpperCase());
},
}),
[clues, crosswordCorrect, onLoadedCorrect, useStorage]
);
Expand Down
18 changes: 18 additions & 0 deletions src/__test__/Crossword.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,22 @@ describe('imperative commands (forwarded to CrosswordProvider)', () => {

expect(isCorrect).toBeFalsy();
});

it('setGuess() can set a guess', () => {
const ref = React.createRef<CrosswordProvider>();
const { queryByText } = render(
<Crossword {...defaultProps} data={simpleData} ref={ref} />
);

let textEl = queryByText('T');
expect(textEl).toBeFalsy();

expect(ref.current).toBeTruthy();
act(() => {
ref.current?.setGuess(0, 0, 'T');
});

textEl = queryByText('T');
expect(textEl).toBeTruthy();
});
});
43 changes: 43 additions & 0 deletions src/__test__/CrosswordProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,21 @@ describe('imperative commands', () => {
expect(doc.activeElement).toBe(input);
});

it('focus without grid does nothing (except log)', () => {
const ref = React.createRef<CrosswordProviderImperative>();
/* const { container } = */ render(<Simple withClues forwardedRef={ref} />);

// const doc = container.ownerDocument;

expect(ref.current).toBeTruthy();
act(() => {
ref.current?.focus();
});

// TODO?: start with focus elsewhere and check that it doesn't change?
// expect(doc.activeElement).toBe(input);
});

it('resets data when requested', () => {
const ref = React.createRef<CrosswordProviderImperative>();
const { getByLabelText, queryByText } = render(
Expand Down Expand Up @@ -732,6 +747,34 @@ describe('imperative commands', () => {

expect(isCorrect).toBeFalsy();
});

it('setGuess() can set a guess', () => {
const ref = React.createRef<CrosswordProviderImperative>();
const { queryByText } = render(
<Simple withGrid withClues forwardedRef={ref} />
);

let textEl = queryByText('T');
expect(textEl).toBeFalsy();

expect(ref.current).toBeTruthy();
act(() => {
ref.current?.setGuess(0, 0, 'T');
});

textEl = queryByText('T');
expect(textEl).toBeTruthy();
});

it('setGuess() throws on an unused cell', () => {
const ref = React.createRef<CrosswordProviderImperative>();
render(<Simple withGrid withClues forwardedRef={ref} />);

expect(ref.current).toBeTruthy();
act(() => {
expect(() => ref.current?.setGuess(1, 0, 'T')).toThrow();
});
});
});

// for ease of calling, textEl is an HTMLElement.... but it's *really* a
Expand Down
42 changes: 42 additions & 0 deletions src/__test__/context.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// import { jest } from '@jest/globals';
import '@testing-library/jest-dom/extend-expect';

import { CrosswordContext, CrosswordContextType } from '../context';

// afterEach(cleanup);

describe('default CrosswordContext', () => {
// @ts-expect-error hack into React Context innards...
// eslint-disable-next-line no-underscore-dangle
const context = CrosswordContext.Consumer._context
._currentValue as CrosswordContextType;

it('has size zero', () => {
expect(context.size).toBe(0);
});

[
'handleInputKeyDown',
'handleInputChange',
'handleCellClick',
'handleInputClick',
'handleClueSelected',
'registerFocusHandler',
].forEach((handlerName) => {
describe(`${handlerName}()`, () => {
const handler = context[handlerName];

it('can be called', () => {
expect(() => {
handler();
}).not.toThrow();
});

it('does not throw with bad arguments', () => {
expect(() => {
handler('BOGUS', -10, 'WRONG');
}).not.toThrow();
});
});
});
});

0 comments on commit 67bbbbb

Please sign in to comment.