import { describe, it } from '@ephox/bedrock-client'; import { Optionals } from '@ephox/katamari'; import { SugarPosition } from '@ephox/sugar'; import { assert } from 'chai'; import * as fc from 'fast-check'; import * as Boxes from 'ephox/alloy/alien/Boxes'; import * as LayoutBounds from 'ephox/alloy/positioning/layout/LayoutBounds'; import { assertInBounds, boundsArb } from 'ephox/alloy/test/BoundsUtils'; describe('LayoutBoundsTest', () => { const dimensions = [ 'left' as const, 'right' as const, 'top' as const, 'bottom' as const ]; const restrictionArb = boundsArb().chain((anchorBox) => fc.constantFrom(...dimensions).map((dim) => ({ left: Optionals.someIf(dim === 'left', anchorBox.x), right: Optionals.someIf(dim === 'right', anchorBox.right), top: Optionals.someIf(dim === 'top', anchorBox.y), bottom: Optionals.someIf(dim === 'bottom', anchorBox.bottom) })) ); it('TINY-7545: the restricted layout bounds should always be inside the bounds', () => { const bubbleArb = fc.integer({ min: -20, max: 20 }); fc.assert(fc.property(boundsArb(), restrictionArb, bubbleArb, bubbleArb, (bounds, restriction, bubbleLeft, bubbleRight) => { const newBounds = LayoutBounds.adjustBounds(bounds, restriction, SugarPosition(bubbleLeft, bubbleRight)); assertInBounds(newBounds, bounds); })); }); it('TINY-7545: the left coord should be the anchor box/bounds plus the bubble offset', () => { const bounds = Boxes.bounds(0, 0, 100, 100); const inBoundsRestriction = LayoutBounds.boundsRestriction(Boxes.bounds(0, 0, 10, 100), { left: LayoutBounds.AnchorBoxBounds.RightEdge }); const outBoundsRestriction = LayoutBounds.boundsRestriction(Boxes.bounds(-20, 0, 10, 100), { left: LayoutBounds.AnchorBoxBounds.RightEdge }); // Note: bubbleLeft needs to be at least 10 less than the bounds width to make sure it fits fc.assert(fc.property(fc.integer({ min: 0, max: 90 }), fc.integer({ min: 0, max: 100 }), (bubbleLeft, bubbleTop) => { const newInBounds = LayoutBounds.adjustBounds(bounds, inBoundsRestriction, SugarPosition(bubbleLeft, bubbleTop)); assert.equal(newInBounds.x, 10 + bubbleLeft, 'left bounds have been changed'); assert.equal(newInBounds.right, bounds.right, 'right bounds are unchanged'); assert.equal(newInBounds.y, bounds.y, 'top bounds are unchanged'); assert.equal(newInBounds.bottom, bounds.bottom, 'bottom bounds are unchanged'); const newOutBounds = LayoutBounds.adjustBounds(bounds, outBoundsRestriction, SugarPosition(bubbleLeft, bubbleTop)); assert.equal(newOutBounds.x, bounds.x + bubbleLeft, 'left bounds have been changed'); assert.equal(newOutBounds.right, bounds.right, 'right bounds are unchanged'); assert.equal(newOutBounds.y, bounds.y, 'top bounds are unchanged'); assert.equal(newOutBounds.bottom, bounds.bottom, 'bottom bounds are unchanged'); })); }); it('TINY-7545: the bottom coord should be the anchor box/bounds minus the bubble offset', () => { const bounds = Boxes.bounds(0, 0, 100, 100); const inBoundsRestriction = LayoutBounds.boundsRestriction(Boxes.bounds(0, 80, 100, 50), { bottom: LayoutBounds.AnchorBoxBounds.TopEdge }); const outBoundsRestriction = LayoutBounds.boundsRestriction(Boxes.bounds(0, 150, 100, 50), { bottom: LayoutBounds.AnchorBoxBounds.TopEdge }); // Note: bubbleTop needs to between the bounds top (0) and the anchor top (80) coords fc.assert(fc.property(fc.integer({ min: 0, max: 100 }), fc.integer({ min: 0, max: 80 }), (bubbleLeft, bubbleTop) => { const newInBounds = LayoutBounds.adjustBounds(bounds, inBoundsRestriction, SugarPosition(bubbleLeft, -bubbleTop)); assert.equal(newInBounds.x, bounds.x, 'left bounds are unchanged'); assert.equal(newInBounds.right, bounds.right, 'right bounds are unchanged'); assert.equal(newInBounds.y, bounds.y, 'top bounds are unchanged'); assert.equal(newInBounds.bottom, 80 - bubbleTop, 'bottom bounds have been changed'); const newOutBounds = LayoutBounds.adjustBounds(bounds, outBoundsRestriction, SugarPosition(bubbleLeft, -bubbleTop)); assert.equal(newOutBounds.x, bounds.x, 'left bounds are unchanged'); assert.equal(newOutBounds.right, bounds.right, 'right bounds are unchanged'); assert.equal(newOutBounds.y, bounds.y, 'top bounds are unchanged'); assert.equal(newOutBounds.bottom, bounds.bottom - bubbleTop, 'bottom bounds have been changed'); })); }); it('TINY-7545: Anchor box with bubble that overlaps the edge is constrained to bounds', () => { const bounds = Boxes.bounds(0, 0, 100, 100); const restriction = LayoutBounds.boundsRestriction(Boxes.bounds(10, 0, 10, 100), { right: LayoutBounds.AnchorBoxBounds.LeftEdge }); const newBounds = LayoutBounds.adjustBounds(bounds, restriction, SugarPosition(-20, 0)); assert.equal(newBounds.x, bounds.x, 'left bounds are changed'); assert.equal(newBounds.right, bounds.x, 'right bounds have been changed and been constrained'); assert.equal(newBounds.y, bounds.y, 'top bounds are unchanged'); assert.equal(newBounds.bottom, bounds.bottom, 'bottom bounds are unchanged'); }); });