diff --git a/editor/src/components/canvas/plugins/tailwind-style-plugin.ts b/editor/src/components/canvas/plugins/tailwind-style-plugin.ts index b9ddd6b94542..21d5508638a0 100644 --- a/editor/src/components/canvas/plugins/tailwind-style-plugin.ts +++ b/editor/src/components/canvas/plugins/tailwind-style-plugin.ts @@ -23,20 +23,30 @@ function parseTailwindProperty( } const TailwindPropertyMapping: Record = { - gap: 'gap', - flexDirection: 'flexDirection', left: 'positionLeft', right: 'positionRight', top: 'positionTop', bottom: 'positionBottom', + width: 'width', height: 'height', - flexBasis: 'flexBasis', + padding: 'padding', paddingTop: 'paddingTop', paddingRight: 'paddingRight', paddingBottom: 'paddingBottom', paddingLeft: 'paddingLeft', + + justifyContent: 'justifyContent', + alignItems: 'alignItems', + flex: 'flex', + flexDirection: 'flexDirection', + flexGrow: 'flexGrow', + flexShrink: 'flexShrink', + flexBasis: 'flexBasis', + flexWrap: 'flexWrap', + gap: 'gap', + zIndex: 'zIndex', } diff --git a/editor/src/components/inspector/flex-direction-control.spec.browser2.tsx b/editor/src/components/inspector/flex-direction-control.spec.browser2.tsx index d9ad55ec3bca..5ea4e771d533 100644 --- a/editor/src/components/inspector/flex-direction-control.spec.browser2.tsx +++ b/editor/src/components/inspector/flex-direction-control.spec.browser2.tsx @@ -3,14 +3,16 @@ import { expectSingleUndo2Saves, hoverControlWithCheck, selectComponentsForTest, + setFeatureForBrowserTestsUseInDescribeBlockOnly, } from '../../utils/utils.test-utils' import { CanvasControlsContainerID } from '../canvas/controls/new-canvas-controls' import { getSubduedPaddingControlTestID } from '../canvas/controls/select-mode/subdued-padding-control' import { mouseClickAtPoint } from '../canvas/event-helpers.test-utils' import type { EditorRenderResult } from '../canvas/ui-jsx.test-utils' -import { renderTestEditorWithCode } from '../canvas/ui-jsx.test-utils' +import { renderTestEditorWithCode, renderTestEditorWithModel } from '../canvas/ui-jsx.test-utils' import type { FlexDirection } from './common/css-utils' import { FlexDirectionControlTestId, FlexDirectionToggleTestId } from './flex-direction-control' +import { TailwindProject } from './sections/flex-section.test-utils' describe('set flex direction', () => { it('set flex direction to row from not set', async () => { @@ -111,6 +113,62 @@ describe('set flex direction', () => { expect(controls.length).toEqual(4) }) }) + + describe('Tailwind', () => { + setFeatureForBrowserTestsUseInDescribeBlockOnly('Tailwind', true) + + it('set flex direction to column from not set', async () => { + const editor = await renderTestEditorWithModel( + TailwindProject('flex'), + 'await-first-dom-report', + ) + await selectDiv(editor) + await expectSingleUndo2Saves(editor, () => clickOn(editor, 'column')) + const div = editor.renderedDOM.getByTestId('mydiv') + expect(div.className).toEqual( + 'top-10 left-10 w-64 h-64 bg-slate-100 absolute flex flex-col', // flex-col is set by the control + ) + }) + + it('set flex direction to row-reverse from not set', async () => { + const editor = await renderTestEditorWithModel( + TailwindProject('flex'), + 'await-first-dom-report', + ) + await selectDiv(editor) + await expectSingleUndo2Saves(editor, () => clickOn(editor, 'row-reverse')) + const div = editor.renderedDOM.getByTestId('mydiv') + expect(div.className).toEqual( + 'top-10 left-10 w-64 h-64 bg-slate-100 absolute flex flex-row-reverse', // flex-row-reverse is set by the control + ) + }) + + it('set flex direction to column-reverse from not set', async () => { + const editor = await renderTestEditorWithModel( + TailwindProject('flex'), + 'await-first-dom-report', + ) + await selectDiv(editor) + await expectSingleUndo2Saves(editor, () => clickOn(editor, 'column-reverse')) + const div = editor.renderedDOM.getByTestId('mydiv') + expect(div.className).toEqual( + 'top-10 left-10 w-64 h-64 bg-slate-100 absolute flex flex-col-reverse', // flex-row-reverse is set by the control + ) + }) + + it('set flex direction to row from column', async () => { + const editor = await renderTestEditorWithModel( + TailwindProject('flex flex-col'), + 'await-first-dom-report', + ) + await selectDiv(editor) + await expectSingleUndo2Saves(editor, () => clickOn(editor, 'row')) + const div = editor.renderedDOM.getByTestId('mydiv') + expect(div.className).toEqual( + 'top-10 left-10 w-64 h-64 bg-slate-100 absolute flex flex-row', // flex-row is set by the control + ) + }) + }) }) async function selectDiv(editor: EditorRenderResult): Promise { diff --git a/editor/src/components/inspector/nine-block-control.spec.browser2.tsx b/editor/src/components/inspector/nine-block-control.spec.browser2.tsx index 121a4fe81528..82849f91d88a 100644 --- a/editor/src/components/inspector/nine-block-control.spec.browser2.tsx +++ b/editor/src/components/inspector/nine-block-control.spec.browser2.tsx @@ -3,14 +3,20 @@ import { expectSingleUndo2Saves, hoverControlWithCheck, selectComponentsForTest, + setFeatureForBrowserTestsUseInDescribeBlockOnly, } from '../../utils/utils.test-utils' import { CanvasControlsContainerID } from '../canvas/controls/new-canvas-controls' import { getSubduedPaddingControlTestID } from '../canvas/controls/select-mode/subdued-padding-control' import { mouseClickAtPoint } from '../canvas/event-helpers.test-utils' import type { EditorRenderResult } from '../canvas/ui-jsx.test-utils' -import { renderTestEditorWithCode } from '../canvas/ui-jsx.test-utils' +import { renderTestEditorWithCode, renderTestEditorWithModel } from '../canvas/ui-jsx.test-utils' import type { StartCenterEnd } from './inspector-common' import { NineBlockControlTestId, NineBlockSectors, NineBlockTestId } from './nine-block-controls' +import { + AlignItemsClassMapping, + JustifyContentClassMapping, + TailwindProject, +} from './sections/flex-section.test-utils' describe('Nine-block control', () => { describe('in flex row', () => { @@ -49,6 +55,27 @@ describe('Nine-block control', () => { expect(controls.length).toEqual(4) }) }) + + describe('Tailwind', () => { + setFeatureForBrowserTestsUseInDescribeBlockOnly('Tailwind', true) + + for (const [justifyContent, alignItems] of NineBlockSectors) { + it(`set ${justifyContent} and ${alignItems} via the nine-block control`, async () => { + const editor = await renderTestEditorWithModel( + TailwindProject('flex flex-row'), + 'await-first-dom-report', + ) + + const div = await doTest(editor, alignItems, justifyContent) + + expect(getComputedStyle(div).justifyContent).toEqual(justifyContent) + expect(getComputedStyle(div).alignItems).toEqual(alignItems) + expect(div.className).toEqual( + `top-10 left-10 w-64 h-64 bg-slate-100 absolute flex flex-row ${AlignItemsClassMapping[alignItems]} ${JustifyContentClassMapping[justifyContent]}`, + ) + }) + } + }) }) async function doTest( @@ -60,8 +87,8 @@ async function doTest( const div = editor.renderedDOM.getByTestId('mydiv') const divBounds = div.getBoundingClientRect() const divCorner = { - x: divBounds.x + 50, - y: divBounds.y + 40, + x: divBounds.x + 5, + y: divBounds.y + 4, } await mouseClickAtPoint(canvasControlsLayer, divCorner) diff --git a/editor/src/components/inspector/sections/flex-section.test-utils.ts b/editor/src/components/inspector/sections/flex-section.test-utils.ts new file mode 100644 index 000000000000..8cd3a3cbe6f1 --- /dev/null +++ b/editor/src/components/inspector/sections/flex-section.test-utils.ts @@ -0,0 +1,57 @@ +import { TailwindConfigPath } from '../../../core/tailwind/tailwind-config' +import { createModifiedProject } from '../../../sample-projects/sample-project-utils.test-utils' +import { StoryboardFilePath } from '../../editor/store/editor-state' + +export const JustifyContentClassMapping = { + 'flex-start': 'justify-start', + center: 'justify-center', + 'flex-end': 'justify-end', +} as const + +export const AlignItemsClassMapping = { + 'flex-start': 'items-start', + center: 'items-center', + 'flex-end': 'items-end', +} as const + +export const TailwindProject = (classes: string) => + createModifiedProject({ + [StoryboardFilePath]: ` + import React from 'react' + import { Scene, Storyboard } from 'utopia-api' + export var storyboard = ( + + +
+
+
+
+ + + ) + + `, + [TailwindConfigPath]: ` + const TailwindConfig = { } + export default TailwindConfig + `, + 'app.css': ` + @tailwind base; + @tailwind components; + @tailwind utilities;`, + }) diff --git a/editor/src/components/inspector/spaced-packed-control.spec.browser2.tsx b/editor/src/components/inspector/spaced-packed-control.spec.browser2.tsx index 5ffcca13b170..4e9974cd4e6d 100644 --- a/editor/src/components/inspector/spaced-packed-control.spec.browser2.tsx +++ b/editor/src/components/inspector/spaced-packed-control.spec.browser2.tsx @@ -3,11 +3,13 @@ import { expectSingleUndo2Saves, hoverControlWithCheck, selectComponentsForTest, + setFeatureForBrowserTestsUseInDescribeBlockOnly, } from '../../utils/utils.test-utils' import { getSubduedPaddingControlTestID } from '../canvas/controls/select-mode/subdued-padding-control' import { mouseClickAtPoint } from '../canvas/event-helpers.test-utils' import type { EditorRenderResult } from '../canvas/ui-jsx.test-utils' -import { renderTestEditorWithCode } from '../canvas/ui-jsx.test-utils' +import { renderTestEditorWithCode, renderTestEditorWithModel } from '../canvas/ui-jsx.test-utils' +import { TailwindProject } from './sections/flex-section.test-utils' import { PackedLabelCopy, SpacedLabelCopy, @@ -46,6 +48,35 @@ describe('spaced - packed control', () => { expect(div.style.justifyContent).toEqual('flex-start') }) + describe('Tailwind', () => { + setFeatureForBrowserTestsUseInDescribeBlockOnly('Tailwind', true) + it('set element to spaced layout', async () => { + const editor = await renderTestEditorWithModel( + TailwindProject('flex flex-row'), + 'await-first-dom-report', + ) + await selectComponentsForTest(editor, [EP.fromString('sb/scene/mydiv')]) + await expectSingleUndo2Saves(editor, () => clickButton(editor, SpacedLabelCopy)) + const div = editor.renderedDOM.getByTestId('mydiv') + expect(div.className).toEqual( + 'top-10 left-10 w-64 h-64 bg-slate-100 absolute flex flex-row justify-between', + ) + }) + it('set element to packed layout', async () => { + const editor = await renderTestEditorWithModel( + TailwindProject('flex flex-row'), + 'await-first-dom-report', + ) + await selectComponentsForTest(editor, [EP.fromString('sb/scene/mydiv')]) + await expectSingleUndo2Saves(editor, () => clickButton(editor, SpacedLabelCopy)) + await expectSingleUndo2Saves(editor, () => clickButton(editor, PackedLabelCopy)) + const div = editor.renderedDOM.getByTestId('mydiv') + expect(div.className).toEqual( + 'top-10 left-10 w-64 h-64 bg-slate-100 absolute flex flex-row justify-start', + ) + }) + }) + it('when spaced/packed control is hovered, padding hihglights are shown', async () => { const editor = await renderTestEditorWithCode(projectWithPadding, 'await-first-dom-report') await selectComponentsForTest(editor, [EP.fromString('sb/div')]) diff --git a/editor/src/components/inspector/three-bar-control.spec.browser2.tsx b/editor/src/components/inspector/three-bar-control.spec.browser2.tsx index 285d7f9e2a52..cf79060ee8ab 100644 --- a/editor/src/components/inspector/three-bar-control.spec.browser2.tsx +++ b/editor/src/components/inspector/three-bar-control.spec.browser2.tsx @@ -1,10 +1,16 @@ +import type { ElementPath } from 'utopia-shared/src/types' import * as EP from '../../core/shared/element-path' -import { expectSingleUndo2Saves, selectComponentsForTest } from '../../utils/utils.test-utils' +import { + expectSingleUndo2Saves, + selectComponentsForTest, + setFeatureForBrowserTestsUseInDescribeBlockOnly, +} from '../../utils/utils.test-utils' import { mouseClickAtPoint } from '../canvas/event-helpers.test-utils' import type { EditorRenderResult } from '../canvas/ui-jsx.test-utils' -import { renderTestEditorWithCode } from '../canvas/ui-jsx.test-utils' +import { renderTestEditorWithCode, renderTestEditorWithModel } from '../canvas/ui-jsx.test-utils' import type { FlexDirection } from './common/css-utils' import type { FlexAlignment } from './inspector-common' +import { AlignItemsClassMapping, TailwindProject } from './sections/flex-section.test-utils' import { ThreeBarControlTestId } from './three-bar-control' const StoryboardId = 'sb' @@ -13,56 +19,122 @@ const ParentId = 'p' describe('three bar control', () => { describe('set align-items in flex-direcion: column', () => { + const ElementToSelect = EP.fromString(`${StoryboardId}/${SceneId}/${ParentId}`) + it('align-items: start', async () => { const editor = await renderTestEditorWithCode(project('row'), 'await-first-dom-report') const desiredAlignItems: FlexAlignment = 'flex-start' - const div = await doTest(editor, ThreeBarControlTestId(desiredAlignItems)) + const div = await doTest( + editor, + ThreeBarControlTestId(desiredAlignItems), + ElementToSelect, + ParentId, + ) expect(div.style.alignItems).toEqual(desiredAlignItems) }) it('align-items: center', async () => { const editor = await renderTestEditorWithCode(project('row'), 'await-first-dom-report') const desiredAlignItems: FlexAlignment = 'center' - const div = await doTest(editor, ThreeBarControlTestId(desiredAlignItems)) + const div = await doTest( + editor, + ThreeBarControlTestId(desiredAlignItems), + ElementToSelect, + ParentId, + ) expect(div.style.alignItems).toEqual(desiredAlignItems) }) it('align-items: end', async () => { const editor = await renderTestEditorWithCode(project('row'), 'await-first-dom-report') const desiredAlignItems: FlexAlignment = 'flex-end' - const div = await doTest(editor, ThreeBarControlTestId(desiredAlignItems)) + const div = await doTest( + editor, + ThreeBarControlTestId(desiredAlignItems), + ElementToSelect, + ParentId, + ) expect(div.style.alignItems).toEqual(desiredAlignItems) }) }) describe('set align-items in flex-direcion: row', () => { + const ElementToSelect = EP.fromString(`${StoryboardId}/${SceneId}/${ParentId}`) + it('align-items: start', async () => { const editor = await renderTestEditorWithCode(project('column'), 'await-first-dom-report') const desiredAlignItems: FlexAlignment = 'flex-start' - const div = await doTest(editor, ThreeBarControlTestId(desiredAlignItems)) + const div = await doTest( + editor, + ThreeBarControlTestId(desiredAlignItems), + EP.fromString(`${StoryboardId}/${SceneId}/${ParentId}`), + ParentId, + ) expect(div.style.alignItems).toEqual(desiredAlignItems) }) it('align-items: center', async () => { const editor = await renderTestEditorWithCode(project('column'), 'await-first-dom-report') const desiredAlignItems: FlexAlignment = 'center' - const div = await doTest(editor, ThreeBarControlTestId(desiredAlignItems)) + const div = await doTest( + editor, + ThreeBarControlTestId(desiredAlignItems), + ElementToSelect, + ParentId, + ) expect(div.style.alignItems).toEqual(desiredAlignItems) }) it('align-items: end', async () => { const editor = await renderTestEditorWithCode(project('column'), 'await-first-dom-report') const desiredAlignItems: FlexAlignment = 'flex-end' - const div = await doTest(editor, ThreeBarControlTestId(desiredAlignItems)) + const div = await doTest( + editor, + ThreeBarControlTestId(desiredAlignItems), + ElementToSelect, + ParentId, + ) expect(div.style.alignItems).toEqual(desiredAlignItems) }) }) + + describe('Tailwind', () => { + setFeatureForBrowserTestsUseInDescribeBlockOnly('Tailwind', true) + + const ElementToSelect = EP.fromString('sb/scene/mydiv') + + const AlignItems = ['flex-start', 'center', 'flex-end'] as const + + for (const alignItems of AlignItems) { + it(`align-items: ${alignItems}`, async () => { + const editor = await renderTestEditorWithModel( + TailwindProject('flex flex-row justify-between'), + 'await-first-dom-report', + ) + const div = await doTest( + editor, + ThreeBarControlTestId(alignItems), + ElementToSelect, + 'mydiv', + ) + expect(getComputedStyle(div).alignItems).toEqual(alignItems) + expect(div.className).toEqual( + `top-10 left-10 w-64 h-64 bg-slate-100 absolute flex flex-row justify-between ${AlignItemsClassMapping[alignItems]}`, + ) + }) + } + }) }) -async function doTest(editor: EditorRenderResult, controlId: string): Promise { - await selectComponentsForTest(editor, [EP.fromString(`${StoryboardId}/${SceneId}/${ParentId}`)]) +async function doTest( + editor: EditorRenderResult, + controlId: string, + elementPath: ElementPath, + testId: string, +): Promise { + await selectComponentsForTest(editor, [elementPath]) - const div = editor.renderedDOM.getByTestId(ParentId) + const div = editor.renderedDOM.getByTestId(testId) const control = editor.renderedDOM.getByTestId(controlId) const controlBounds = control.getBoundingClientRect() await expectSingleUndo2Saves(editor, async () => {