diff --git a/packages/vue/src/controls/layout/helpers.ts b/packages/vue/src/controls/layout/helpers.ts index 360fb681d..d3ce931f6 100644 --- a/packages/vue/src/controls/layout/helpers.ts +++ b/packages/vue/src/controls/layout/helpers.ts @@ -180,6 +180,13 @@ export function createLayoutActions({ editor.updateNode(node.value.id, { [prop]: value }) } + function setSizeLimitToCurrent(prop: SizeLimitProp) { + const n = node.value + if (!n) return + const value = prop === 'minWidth' || prop === 'maxWidth' ? n.width : n.height + editor.updateNodeWithUndo(n.id, { [prop]: Math.round(value) }, `Set ${prop}`) + } + function commitSizeLimit(prop: SizeLimitProp, _value: number, previous: number) { if (!node.value) return editor.commitNodeUpdate(node.value.id, { [prop]: previous }, `Change ${prop}`) @@ -258,6 +265,7 @@ export function createLayoutActions({ return { updateProp, updateSizeLimit, + setSizeLimitToCurrent, commitSizeLimit, addSizeLimit, removeSizeLimit, diff --git a/packages/vue/src/controls/layout/use.ts b/packages/vue/src/controls/layout/use.ts index d66c30d39..c10147552 100644 --- a/packages/vue/src/controls/layout/use.ts +++ b/packages/vue/src/controls/layout/use.ts @@ -63,6 +63,7 @@ export function useLayout() { trackSizingOptions: createTrackSizingOptions(panels.value), updateProp: layoutActions.updateProp, updateSizeLimit: layoutActions.updateSizeLimit, + setSizeLimitToCurrent: layoutActions.setSizeLimitToCurrent, commitSizeLimit: layoutActions.commitSizeLimit, addSizeLimit: layoutActions.addSizeLimit, removeSizeLimit: layoutActions.removeSizeLimit, diff --git a/packages/vue/src/i18n/messages.ts b/packages/vue/src/i18n/messages.ts index 3c66622cd..2af3207d9 100644 --- a/packages/vue/src/i18n/messages.ts +++ b/packages/vue/src/i18n/messages.ts @@ -221,6 +221,8 @@ export const panelMessages = i18n('panels', { maxWidthShort: 'Max W', minHeightShort: 'Min H', maxHeightShort: 'Max H', + setToCurrentWidth: 'Set to current width', + setToCurrentHeight: 'Set to current height', sizingFillFr: 'Fill (fr)', sizingFixedPx: 'Fixed (px)' }) diff --git a/packages/vue/src/primitives/LayoutControls/LayoutControlsRoot.vue b/packages/vue/src/primitives/LayoutControls/LayoutControlsRoot.vue index e74b4481f..a0a165656 100644 --- a/packages/vue/src/primitives/LayoutControls/LayoutControlsRoot.vue +++ b/packages/vue/src/primitives/LayoutControls/LayoutControlsRoot.vue @@ -30,6 +30,7 @@ provideLayoutControls( :track-sizing-options="ctx.trackSizingOptions" :update-prop="ctx.updateProp" :update-size-limit="ctx.updateSizeLimit" + :set-size-limit-to-current="ctx.setSizeLimitToCurrent" :commit-size-limit="ctx.commitSizeLimit" :add-size-limit="ctx.addSizeLimit" :remove-size-limit="ctx.removeSizeLimit" diff --git a/src/components/properties/LayoutSection/SizeControls.vue b/src/components/properties/LayoutSection/SizeControls.vue index a57090b3b..c3f567f3a 100644 --- a/src/components/properties/LayoutSection/SizeControls.vue +++ b/src/components/properties/LayoutSection/SizeControls.vue @@ -20,9 +20,24 @@ import type { SizeLimitProp } from '@open-pencil/vue' type SizeSelectValue = LayoutSizing | `add-${SizeLimitProp}` | `remove-${SizeLimitProp}` +type ActiveSizeLimit = { + prop: SizeLimitProp + testId: string + icon: () => string + value: () => number | null + setLabel: () => string + removeLabel: () => string +} + const ctx = useLayoutControlsContext() const widthFieldRef = ref(null) const heightFieldRef = ref(null) +const limitFieldRefs = ref>({ + minWidth: null, + maxWidth: null, + minHeight: null, + maxHeight: null +}) const { panels } = useI18n() const sizingSelect = useSelectUI({ item: 'rounded py-1.5 pr-2 pl-6 text-xs' }) @@ -40,6 +55,41 @@ const widthLimitItems = [ } ] +const activeSizeLimits: ActiveSizeLimit[] = [ + { + prop: 'minWidth', + testId: 'layout-min-width-input', + icon: () => panels.value.minWidthShort, + value: () => ctx.node.minWidth, + setLabel: () => panels.value.setToCurrentWidth, + removeLabel: () => panels.value.removeMinWidth + }, + { + prop: 'maxWidth', + testId: 'layout-max-width-input', + icon: () => panels.value.maxWidthShort, + value: () => ctx.node.maxWidth, + setLabel: () => panels.value.setToCurrentWidth, + removeLabel: () => panels.value.removeMaxWidth + }, + { + prop: 'minHeight', + testId: 'layout-min-height-input', + icon: () => panels.value.minHeightShort, + value: () => ctx.node.minHeight, + setLabel: () => panels.value.setToCurrentHeight, + removeLabel: () => panels.value.removeMinHeight + }, + { + prop: 'maxHeight', + testId: 'layout-max-height-input', + icon: () => panels.value.maxHeightShort, + value: () => ctx.node.maxHeight, + setLabel: () => panels.value.setToCurrentHeight, + removeLabel: () => panels.value.removeMaxHeight + } +] + const heightLimitItems = [ { prop: 'minHeight' as const, @@ -63,6 +113,11 @@ function anchorRef(element: HTMLElement | null): HTMLElement | undefined { return element ?? undefined } +function handleLimitSelect(prop: SizeLimitProp, value: string) { + if (value === 'CURRENT') ctx.setSizeLimitToCurrent(prop) + else if (value === 'REMOVE') ctx.removeSizeLimit(prop) +} + function handleSizeSelect(axis: 'width' | 'height', value: SizeSelectValue) { if (value === 'FIXED' || value === 'HUG' || value === 'FILL') { if (axis === 'width') ctx.setWidthSizing(value) @@ -210,41 +265,54 @@ function handleSizeSelect(axis: 'width' | 'height', value: SizeSelectValue) { " class="mt-1.5 grid grid-cols-2 gap-1.5" > - - - - + diff --git a/tests/helpers/canvas.ts b/tests/helpers/canvas.ts index 0a9e28132..e1cdaa2ef 100644 --- a/tests/helpers/canvas.ts +++ b/tests/helpers/canvas.ts @@ -27,8 +27,12 @@ export class CanvasHelper { } async waitForInit() { - await this.page.locator('canvas[data-ready="1"]').waitFor({ timeout: 30000 }) - await this.page.locator('[data-test-id="canvas-loading"]').waitFor({ state: 'hidden', timeout: 30000 }) + await this.page + .locator('[data-test-id="canvas-element"][data-ready="1"]') + .waitFor({ timeout: 30000 }) + await this.page + .locator('[data-test-id="canvas-loading"]') + .waitFor({ state: 'hidden', timeout: 30000 }) await this.page.locator('#loader').waitFor({ state: 'detached', timeout: 30000 }) } @@ -53,13 +57,7 @@ export class CanvasHelper { await this.page.mouse.click(box.x + canvasX, box.y + canvasY) } - async drag( - fromX: number, - fromY: number, - toX: number, - toY: number, - steps = 10 - ) { + async drag(fromX: number, fromY: number, toX: number, toY: number, steps = 10) { const box = await this.canvasBounds() await this.page.mouse.move(box.x + fromX, box.y + fromY) await this.page.mouse.down()