Skip to content
This repository was archived by the owner on Feb 25, 2024. It is now read-only.

Commit

Permalink
Tweak controls in embed (#315)
Browse files Browse the repository at this point in the history
* add initial scale meta tag to scale viz on the entire viewport on mobile view

* Tweak canvas controls on embed mode

- RESET and Fit To View are now available in all embed modes
- Zoom in and out buttons are only available if controls and zoom are both enabled
- Hand tool (pan button) is only available if controls and pan are both enabled
- Reset canvas button and Help button are no longer available in embed mode

* adds changeset

* update tests based on the new embed behavior
  • Loading branch information
farskid authored Nov 17, 2021
1 parent d10238a commit f98ce3f
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 68 deletions.
10 changes: 10 additions & 0 deletions .changeset/young-hats-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'xstate-viz-app': minor
---

Tweak controls options in embed mode

- RESET and Fit To View are now available in all embed modes
- Zoom in and out buttons are only available if controls and Zoom are both enabled
- Hand tool (pan button) is only available if controls and pan are both enabled
- Reset canvas button and Help button are no longer available in embed mode
39 changes: 25 additions & 14 deletions cypress/integration/embedded-mode.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { EmbedMode, EmbedPanel } from '../../src/types';

const sourceFileFixture = {
id: 'source-file-id',
text: `
Expand All @@ -15,7 +17,7 @@ createMachine({
};

describe('Embedded mode', () => {
describe('default (mode:viz)', () => {
describe('default (mode:viz)1', () => {
before(() => {
cy.interceptGraphQL({
getSourceFile: sourceFileFixture,
Expand All @@ -27,12 +29,13 @@ describe('Embedded mode', () => {
it('panels should be hidden', () => {
cy.getPanelsView().should('be.hidden');
});
it('zoom and pan buttons group should be hidden', () => {
cy.getControlButtons().should('not.exist');
});
it('canvas header should be hidden', () => {
cy.getCanvasHeader().should('not.exist');
});
it('RESET and fit_to_content should be visible', () => {
cy.getResetButton().should('be.visible');
cy.getFitToContentButton().should('be.visible');
});
});

describe('mode:panels', () => {
Expand All @@ -41,17 +44,21 @@ describe('Embedded mode', () => {
getSourceFile: sourceFileFixture,
});
});
it('RESET and fit_to_content should be visible', () => {
cy.getResetButton().should('be.visible');
cy.getFitToContentButton().should('be.visible');
});
it('should show panels view', () => {
cy.visitEmbedWithNextPageProps({
sourceFile: sourceFileFixture,
mode: 'panels',
mode: EmbedMode.Panels,
});
cy.getPanelsView().should('be.visible');
});
it('should show CODE panel by default', () => {
cy.visitEmbedWithNextPageProps({
sourceFile: sourceFileFixture,
mode: 'panels',
mode: EmbedMode.Panels,
});
cy.findByRole('tab', { name: /code/i }).should(
'have.attr',
Expand Down Expand Up @@ -79,7 +86,7 @@ describe('Embedded mode', () => {
it('should be able to make code editor editable', () => {
cy.visitEmbedWithNextPageProps({
sourceFile: sourceFileFixture,
mode: 'panels',
mode: EmbedMode.Panels,
readOnly: false,
});
const editor = cy.getMonacoEditor();
Expand All @@ -89,8 +96,8 @@ describe('Embedded mode', () => {
it('should be able to choose active panel', () => {
cy.visitEmbedWithNextPageProps({
sourceFile: sourceFileFixture,
mode: 'panels',
panel: 'state',
mode: EmbedMode.Panels,
panel: EmbedPanel.State,
});
cy.findByRole('tab', { name: /state/i }).should(
'have.attr',
Expand All @@ -102,7 +109,7 @@ describe('Embedded mode', () => {
it('should be able to hide the original link', () => {
cy.visitEmbedWithNextPageProps({
sourceFile: sourceFileFixture,
mode: 'panels',
mode: EmbedMode.Panels,
showOriginalLink: false,
});
cy.findByRole('link', { name: /open in stately\.ai\/viz/i }).should(
Expand All @@ -112,22 +119,22 @@ describe('Embedded mode', () => {
it('the visualize button should be hidden', () => {
cy.visitEmbedWithNextPageProps({
sourceFile: sourceFileFixture,
mode: 'panels',
mode: EmbedMode.Panels,
});
cy.contains('button', /visualize/i).should('not.exist');
});
it('the visualize button should be shown if readOnly is disabled', () => {
cy.visitEmbedWithNextPageProps({
sourceFile: sourceFileFixture,
mode: 'panels',
mode: EmbedMode.Panels,
readOnly: false,
});
cy.findByRole('button', { name: /visualize/i }).should('be.visible');
});
it('the "New" and "Login to fork" should be hidden', () => {
cy.visitEmbedWithNextPageProps({
sourceFile: sourceFileFixture,
mode: 'panels',
mode: EmbedMode.Panels,
});
[/new/i, /login to fork/i].forEach((text) => {
cy.contains('button', text).should('not.exist');
Expand All @@ -142,9 +149,13 @@ describe('Embedded mode', () => {
});
cy.visitEmbedWithNextPageProps({
sourceFile: sourceFileFixture,
mode: 'full',
mode: EmbedMode.Full,
});
});
it('RESET and fit_to_content should be visible', () => {
cy.getResetButton().should('be.visible');
cy.getFitToContentButton().should('be.visible');
});
it('should show both canvas and panels', () => {
cy.getCanvasGraph().should('be.visible');
cy.getPanelsView().should('be.visible');
Expand Down
9 changes: 9 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ const getResizeHandle = () => {
return cy.findByTestId('resize-handle');
};

const getResetButton = () => cy.findByText('RESET')
const getFitToContentButton = () => cy.findByLabelText('Fit to view')

type DeepPartial<T> = T extends Function
? T
: T extends Array<infer U>
Expand Down Expand Up @@ -273,6 +276,10 @@ declare global {

getEmbedPreview: typeof getEmbedPreview;
getResizeHandle: typeof getResizeHandle;

getResetButton: typeof getResetButton;

getFitToContentButton: typeof getFitToContentButton;
}
}
}
Expand All @@ -295,3 +302,5 @@ Cypress.Commands.add('getCanvasGraph', getCanvasGraph);
Cypress.Commands.add('getControlButtons', getControlButtons);
Cypress.Commands.add('getEmbedPreview', getEmbedPreview);
Cypress.Commands.add('getResizeHandle', getResizeHandle);
Cypress.Commands.add('getResetButton', getResetButton);
Cypress.Commands.add('getFitToContentButton', getFitToContentButton);
1 change: 1 addition & 0 deletions src/AppHead.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const AppHead = ({ importElk = true, ...props }: AppHeadProps) => {
return (
<Head>
<link rel="apple-touch-icon" href="/viz/[email protected]" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/viz/favicon.png" />
<title>{props.title}</title>
<meta name="description" content={props.description} />
Expand Down
124 changes: 70 additions & 54 deletions src/CanvasView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ export const CanvasView: React.FC = () => {

const canShowWelcomeMessage = sourceState.hasTag('canShowWelcomeMessage');

const showZoomButtonsInEmbed = useMemo(
() => !embed?.isEmbedded || (embed.controls && embed.zoom),
[embed],
);
const showPanButtonInEmbed = useMemo(
() => !embed?.isEmbedded || (embed.controls && embed.pan),
[embed],
);

return (
<Box
display="grid"
Expand All @@ -94,54 +103,60 @@ export const CanvasView: React.FC = () => {
)}
{isEmpty && canShowWelcomeMessage && <WelcomeArea />}
</CanvasContainer>
{!(embed?.isEmbedded && !embed.controls) && (
<Box
display="flex"
flexDirection="row"
alignItems="center"
justifyContent="flex-start"
position="absolute"
bottom={0}
left={0}
paddingX={2}
paddingY={3}
zIndex={1}
width="100%"
data-testid="controls"
>
<ButtonGroup size="sm" spacing={2} isAttached>
<IconButton
aria-label="Zoom out"
title="Zoom out"
icon={<MinusIcon />}
disabled={!shouldEnableZoomOutButton}
onClick={() => canvasService.send('ZOOM.OUT')}
variant="secondary"
/>
<IconButton
aria-label="Zoom in"
title="Zoom in"
icon={<AddIcon />}
disabled={!shouldEnableZoomInButton}
onClick={() => canvasService.send('ZOOM.IN')}
variant="secondary"
/>
<IconButton
aria-label="Fit to view"
title="Fit to view"
icon={<CompressIcon />}
onClick={() => canvasService.send('FIT_TO_VIEW')}
variant="secondary"
/>

<Box
display="flex"
flexDirection="row"
alignItems="center"
justifyContent="flex-start"
position="absolute"
bottom={0}
left={0}
paddingX={2}
paddingY={3}
zIndex={1}
width="100%"
data-testid="controls"
>
<ButtonGroup size="sm" spacing={2} isAttached>
{showZoomButtonsInEmbed && (
<>
<IconButton
aria-label="Zoom out"
title="Zoom out"
icon={<MinusIcon />}
disabled={!shouldEnableZoomOutButton}
onClick={() => canvasService.send('ZOOM.OUT')}
variant="secondary"
/>
<IconButton
aria-label="Zoom in"
title="Zoom in"
icon={<AddIcon />}
disabled={!shouldEnableZoomInButton}
onClick={() => canvasService.send('ZOOM.IN')}
variant="secondary"
/>
</>
)}
<IconButton
aria-label="Fit to view"
title="Fit to view"
icon={<CompressIcon />}
onClick={() => canvasService.send('FIT_TO_VIEW')}
variant="secondary"
/>
{!embed?.isEmbedded && (
<IconButton
aria-label="Reset canvas"
title="Reset canvas"
icon={<RepeatIcon />}
onClick={() => canvasService.send('POSITION.RESET')}
variant="secondary"
disabled={embed?.isEmbedded && !embed.zoom && !embed.pan}
/>
</ButtonGroup>
)}
</ButtonGroup>
{showPanButtonInEmbed && (
<IconButton
aria-label="Pan mode"
icon={<HandIcon />}
Expand All @@ -150,18 +165,19 @@ export const CanvasView: React.FC = () => {
onClick={() => setPanModeEnabled((v) => !v)}
aria-pressed={panModeEnabled}
variant={panModeEnabled ? 'secondaryPressed' : 'secondary'}
disabled={embed?.isEmbedded && !embed.pan}
/>
{simulationMode === 'visualizing' && (
<Button
size="sm"
marginLeft={2}
onClick={() => simService.send('MACHINES.RESET')}
variant="secondary"
>
RESET
</Button>
)}
)}
{simulationMode === 'visualizing' && (
<Button
size="sm"
marginLeft={2}
onClick={() => simService.send('MACHINES.RESET')}
variant="secondary"
>
RESET
</Button>
)}
{!embed?.isEmbedded && (
<Menu closeOnSelect={true} placement="top-end">
<MenuButton
as={IconButton}
Expand Down Expand Up @@ -206,8 +222,8 @@ export const CanvasView: React.FC = () => {
</MenuList>
</Portal>
</Menu>
</Box>
)}
)}
</Box>
</Box>
);
};

0 comments on commit f98ce3f

Please sign in to comment.