Skip to content
This repository was archived by the owner on May 8, 2023. It is now read-only.

Commit c07a59c

Browse files
authored
Viewport decorator (#937)
1 parent 72c8248 commit c07a59c

File tree

9 files changed

+139
-83
lines changed

9 files changed

+139
-83
lines changed

examples/jsx-fixtures/components/WelcomeMessage/index.jsxfixture.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @flow
22

33
import React from 'react';
4-
import { Viewport } from '../../decorators/Viewport';
4+
import { Viewport } from 'react-cosmos-fixture';
55
import { Hello } from '.';
66

77
export default (

examples/jsx-fixtures/decorators/Viewport.js

Lines changed: 0 additions & 53 deletions
This file was deleted.

packages/react-cosmos-fixture/src/FixtureCapture/classState/shared.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as React from 'react';
22
import { isEqual } from 'lodash';
3-
import { FixtureState } from 'react-cosmos-shared2/fixtureState';
43

54
export type ElRefs = { [elPath: string]: React.Component };
65

@@ -22,15 +21,6 @@ export type CachedRefHandlers = {
2221
[elPath: string]: CachedRefHandler;
2322
};
2423

25-
// Make latest fixture state accessible in hooks callbacks
26-
export function useFixtureStateRef(fixtureState: FixtureState) {
27-
const ref = React.useRef(fixtureState);
28-
React.useEffect(() => {
29-
ref.current = fixtureState;
30-
});
31-
return ref;
32-
}
33-
3424
export function useUnmount(cb: () => void) {
3525
React.useEffect(() => cb, []);
3626
}

packages/react-cosmos-fixture/src/FixtureCapture/classState/useFixtureState.ts

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as React from 'react';
22
import { isEqual } from 'lodash';
33
import {
44
FixtureDecoratorId,
5+
FixtureState,
56
createValues,
67
extendWithValues,
78
getFixtureStateClassState,
@@ -15,7 +16,6 @@ import {
1516
ElRefs,
1617
InitialStates,
1718
CachedRefHandlers,
18-
useFixtureStateRef,
1919
useUnmount,
2020
replaceState
2121
} from './shared';
@@ -119,7 +119,7 @@ export function useFixtureState(
119119
}
120120
}
121121
});
122-
}, [children, fixtureState.classState]);
122+
}, [setFixtureState, children, fixtureState.classState]);
123123

124124
// Update prev fixture state ref *after* running effects that reference it
125125
React.useEffect(() => {
@@ -141,7 +141,7 @@ export function useFixtureState(
141141
}
142142

143143
elRefs.current[elPath] = elRef;
144-
setInitialState(elPath, elRef);
144+
setInitialState(initialStates.current, elPath, elRef);
145145

146146
const elementId = { decoratorId, elPath };
147147
const fsClassState = findFixtureStateClassState(
@@ -161,15 +161,28 @@ export function useFixtureState(
161161
replaceState(elRef, extendWithValues(state, fsClassState.values));
162162
}
163163
}
164+
}
164165

165-
function setInitialState(elPath: string, elRef: React.Component) {
166-
const found = initialStates.current[elPath];
167-
const type = elRef.constructor as React.ComponentClass;
166+
// Make latest fixture state accessible in ref callback
167+
function useFixtureStateRef(fixtureState: FixtureState) {
168+
const ref = React.useRef(fixtureState);
169+
React.useEffect(() => {
170+
ref.current = fixtureState;
171+
});
172+
return ref;
173+
}
168174

169-
// Keep the first state recevied for this type
170-
const initialStateExists = found && found.type === type;
171-
if (!initialStateExists && elRef.state) {
172-
initialStates.current[elPath] = { type, state: elRef.state };
173-
}
175+
function setInitialState(
176+
initialStates: InitialStates,
177+
elPath: string,
178+
elRef: React.Component
179+
) {
180+
const found = initialStates[elPath];
181+
const type = elRef.constructor as React.ComponentClass;
182+
183+
// Keep the first state recevied for this type
184+
const initialStateExists = found && found.type === type;
185+
if (!initialStateExists && elRef.state) {
186+
initialStates[elPath] = { type, state: elRef.state };
174187
}
175188
}

packages/react-cosmos-fixture/src/FixtureCapture/classState/useReadClassState.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from 'react-cosmos-shared2/fixtureState';
1111
import { FixtureContext } from '../../FixtureContext';
1212
import { findRelevantElementPaths } from '../shared/findRelevantElementPaths';
13-
import { ElRefs, useFixtureStateRef } from './shared';
13+
import { ElRefs } from './shared';
1414

1515
// How often to check the state of the loaded component and update the fixture
1616
// state if it changed
@@ -23,7 +23,6 @@ export function useReadClassState(
2323
) {
2424
const elPaths = findRelevantElementPaths(children);
2525
const { fixtureState, setFixtureState } = React.useContext(FixtureContext);
26-
const lastFixtureState = useFixtureStateRef(fixtureState);
2726
const timeoutId = React.useRef<null | number>(null);
2827

2928
React.useEffect(() => {
@@ -54,11 +53,7 @@ export function useReadClassState(
5453

5554
const { state } = elRefs.current[elPath];
5655
const elementId = { decoratorId, elPath };
57-
const fsClassState = findFixtureStateClassState(
58-
lastFixtureState.current,
59-
elementId
60-
);
61-
56+
const fsClassState = findFixtureStateClassState(fixtureState, elementId);
6257
if (
6358
fsClassState &&
6459
state &&

packages/react-cosmos-fixture/src/FixtureCapture/props/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export function usePropsCapture(
7777
}));
7878
}
7979
});
80-
}, [fixture, fixtureState.props]);
80+
}, [setFixtureState, fixture, fixtureState.props]);
8181

8282
React.useEffect(() => {
8383
prevFixtureRef.current = fixture;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import * as React from 'react';
2+
import { FixtureContext } from './FixtureContext';
3+
4+
type Props = {
5+
children: React.ReactNode;
6+
width: number;
7+
height: number;
8+
};
9+
10+
export function Viewport({ children, width, height }: Props) {
11+
const { setFixtureState } = React.useContext(FixtureContext);
12+
13+
React.useEffect(() => {
14+
setFixtureState(fixtureState => ({
15+
...fixtureState,
16+
viewport: { width, height }
17+
}));
18+
}, [setFixtureState, width, height]);
19+
20+
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18051
21+
return <>{children}</>;
22+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import * as React from 'react';
2+
import retry from '@skidding/async-retry';
3+
import { uuid } from 'react-cosmos-shared2/util';
4+
import { runFixtureConnectTests } from '../testHelpers';
5+
import { anyProps } from '../testHelpers/fixtureState';
6+
import { Viewport } from '..';
7+
8+
const rendererId = uuid();
9+
const fixtures = {
10+
first: (
11+
<Viewport width={320} height={240}>
12+
yo
13+
</Viewport>
14+
)
15+
};
16+
const decorators = {};
17+
const fixtureId = { path: 'first', name: null };
18+
19+
runFixtureConnectTests(mount => {
20+
it('renders children', async () => {
21+
await mount(
22+
{ rendererId, fixtures, decorators },
23+
async ({ renderer, selectFixture }) => {
24+
await selectFixture({
25+
rendererId,
26+
fixtureId,
27+
fixtureState: {}
28+
});
29+
await retry(() => expect(renderer.toJSON()).toBe('yo'));
30+
}
31+
);
32+
});
33+
34+
it('creates viewport fixture state', async () => {
35+
await mount(
36+
{ rendererId, fixtures, decorators },
37+
async ({ selectFixture, fixtureStateChange }) => {
38+
await selectFixture({
39+
rendererId,
40+
fixtureId,
41+
fixtureState: {}
42+
});
43+
await fixtureStateChange({
44+
rendererId,
45+
fixtureId,
46+
fixtureState: {
47+
props: [anyProps()],
48+
viewport: { width: 320, height: 240 }
49+
}
50+
});
51+
}
52+
);
53+
});
54+
55+
it('updates viewport fixture state', async () => {
56+
await mount(
57+
{ rendererId, fixtures, decorators },
58+
async ({ update, selectFixture, fixtureStateChange }) => {
59+
await selectFixture({
60+
rendererId,
61+
fixtureId,
62+
fixtureState: {}
63+
});
64+
update({
65+
rendererId,
66+
fixtures: {
67+
first: (
68+
<Viewport width={640} height={480}>
69+
yo
70+
</Viewport>
71+
)
72+
},
73+
decorators
74+
});
75+
await fixtureStateChange({
76+
rendererId,
77+
fixtureId,
78+
fixtureState: {
79+
props: [anyProps()],
80+
viewport: { width: 640, height: 480 }
81+
}
82+
});
83+
}
84+
);
85+
});
86+
});

packages/react-cosmos-fixture/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ export { FixtureContext } from './FixtureContext';
88

99
// Advanced: Use in fixtures to capture elements in render callback
1010
export { FixtureCapture } from './FixtureCapture';
11+
12+
// Use in fixtures
13+
export { Viewport } from './Viewport';

0 commit comments

Comments
 (0)