diff --git a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts index 34dc6c934..ca62e247d 100644 --- a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts +++ b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts @@ -241,10 +241,14 @@ describe('amplify render tests', () => { }); it('should have breakpoint specific generation', () => { - const generatedCode = generateWithAmplifyRenderer('componentWithBreakpoint'); - expect(generatedCode.componentText.includes('restProp')).toBe(true); - expect(generatedCode.componentText.includes('breakpointHook')).toBe(true); - expect(generatedCode.componentText.includes('breakpoint: breakpointHook')).toBe(true); + const { componentText } = generateWithAmplifyRenderer('componentWithBreakpoint'); + expect(componentText).toContain('restProp'); + expect(componentText).toContain('breakpointHook'); + expect(componentText).toContain('breakpoint: breakpointHook'); + expect(componentText).toContain('base: "small",'); + expect(componentText).toContain('small: "small",'); + expect(componentText).toContain('medium: "medium",'); + expect(componentText).not.toContain('large: "large"'); }); }); diff --git a/packages/codegen-ui-react/lib/react-studio-template-renderer.ts b/packages/codegen-ui-react/lib/react-studio-template-renderer.ts index 276b3cedc..f8c8c95af 100644 --- a/packages/codegen-ui-react/lib/react-studio-template-renderer.ts +++ b/packages/codegen-ui-react/lib/react-studio-template-renderer.ts @@ -34,6 +34,7 @@ import { validateComponentSchema, isSlotBinding, GenericDataSchema, + getBreakpoints, } from '@aws-amplify/codegen-ui'; import { EOL } from 'os'; import ts, { @@ -57,6 +58,7 @@ import ts, { addSyntheticLeadingComment, JsxSelfClosingElement, PropertyAssignment, + ObjectLiteralElementLike, } from 'typescript'; import { ImportCollection, ImportSource, ImportValue } from './imports'; import { ReactOutputManager } from './react-output-manager'; @@ -626,7 +628,7 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer this.importCollection.addMappedImport(ImportValue.MERGE_VARIANTS_OVERRIDES); statements.push(this.buildVariantDeclaration(component.variants)); if (hasBreakpoint) { - statements.push(this.buildDefaultBreakpointMap()); + statements.push(this.buildDefaultBreakpointMap(component)); statements.push(this.buildRestWithStyle()); } statements.push(this.buildOverridesFromVariantsAndProp(hasBreakpoint)); @@ -740,23 +742,24 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer * xxl: 'xxl', * }); */ - private buildDefaultBreakpointMap() { + private buildDefaultBreakpointMap(component: StudioComponent & Required>) { + const breakpoints = getBreakpoints(component); + const element: ObjectLiteralElementLike[] = []; + // if the first element is not base then we sent it anyway as the smallest size should default to base + if (breakpoints[0] !== 'base') { + element.push( + factory.createPropertyAssignment(factory.createIdentifier('base'), factory.createStringLiteral(breakpoints[0])), + ); + } + breakpoints.forEach((bp) => { + element.push(factory.createPropertyAssignment(factory.createIdentifier(bp), factory.createStringLiteral(bp))); + }); this.importCollection.addMappedImport(ImportValue.USE_BREAKPOINT_VALUE); return createHookStatement( 'breakpointHook', 'useBreakpointValue', - factory.createObjectLiteralExpression( - [ - factory.createPropertyAssignment(factory.createIdentifier('base'), factory.createStringLiteral('base')), - factory.createPropertyAssignment(factory.createIdentifier('large'), factory.createStringLiteral('large')), - factory.createPropertyAssignment(factory.createIdentifier('medium'), factory.createStringLiteral('medium')), - factory.createPropertyAssignment(factory.createIdentifier('small'), factory.createStringLiteral('small')), - factory.createPropertyAssignment(factory.createIdentifier('xl'), factory.createStringLiteral('xl')), - factory.createPropertyAssignment(factory.createIdentifier('xxl'), factory.createStringLiteral('xxl')), - ], - true, - ), + factory.createObjectLiteralExpression(element, true), ); } diff --git a/packages/codegen-ui/lib/renderer-helper.ts b/packages/codegen-ui/lib/renderer-helper.ts index 933f59be4..8b8794a15 100644 --- a/packages/codegen-ui/lib/renderer-helper.ts +++ b/packages/codegen-ui/lib/renderer-helper.ts @@ -25,6 +25,7 @@ import { StudioComponentProperty, StudioComponentSlotBinding, } from './types'; +import { breakpointSizes, BreakpointSizeType } from './utils/breakpoint-utils'; export function isStudioComponentWithBinding( component: StudioComponent | StudioComponentChild, @@ -56,9 +57,9 @@ export function isStudioComponentWithBreakpoints( component: StudioComponent | StudioComponentChild, ): component is StudioComponent & Required> { if (isStudioComponentWithVariants(component)) { - return Object.keys(component.variants) - .map((i) => component.variants[Number(i)].variantValues.breakpoint !== undefined) - .includes(true); + return component.variants.some((variant) => + breakpointSizes.includes(variant?.variantValues?.breakpoint as BreakpointSizeType), + ); } return false; } diff --git a/packages/codegen-ui/lib/utils/breakpoint-utils.ts b/packages/codegen-ui/lib/utils/breakpoint-utils.ts new file mode 100644 index 000000000..643fe6bae --- /dev/null +++ b/packages/codegen-ui/lib/utils/breakpoint-utils.ts @@ -0,0 +1,49 @@ +/* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import { StudioComponent } from '../types'; + +export const breakpointSizes = ['base', 'small', 'medium', 'large', 'xl', 'xxl'] as const; +export type BreakpointSizeType = typeof breakpointSizes[number]; +export const bpWeights: Record = { + base: 0, + small: 1, + medium: 2, + large: 3, + xl: 4, + xxl: 5, +}; + +/** + * sorts the breakpoints to the following order + * + * ['base', 'small', 'medium', 'large', 'xl', 'xxl'] + */ +export const sortBreakpoints = (bs: BreakpointSizeType[]): BreakpointSizeType[] => { + return bs.sort((lhs, rhs) => { + return bpWeights[lhs] - bpWeights[rhs]; + }); +}; + +export const getBreakpoints = (component: StudioComponent & Required>) => { + const breakpoints = component.variants.reduce((acc, variant) => { + if (variant.variantValues?.breakpoint) { + acc.push(variant.variantValues.breakpoint as BreakpointSizeType); + } + return acc; + }, []); + return sortBreakpoints(breakpoints); +}; diff --git a/packages/codegen-ui/lib/utils/index.ts b/packages/codegen-ui/lib/utils/index.ts index abbf5f9ed..67d60a387 100644 --- a/packages/codegen-ui/lib/utils/index.ts +++ b/packages/codegen-ui/lib/utils/index.ts @@ -19,3 +19,4 @@ export * from './state-reference-metadata'; export * from './string-formatter'; export * from './form-component-metadata'; export * from './form-to-component'; +export * from './breakpoint-utils';