diff --git a/site/pages/_app.tsx b/site/pages/_app.tsx index 91f6572101..7c823471bf 100644 --- a/site/pages/_app.tsx +++ b/site/pages/_app.tsx @@ -155,7 +155,7 @@ export default class MyApp extends App { - app + .emotion-0 { + margin: 0; + padding: 0; + display: inline-grid; + -webkit-column-gap: 8px; + column-gap: 8px; + grid-template-columns: repeat(1, auto); + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-content: center; + -ms-flex-line-pack: center; + align-content: center; + justify-items: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + min-width: 80px; + min-height: 48px; + padding-inline: 16px; + padding-block: 12px; + box-sizing: border-box; + -webkit-text-decoration: none; + text-decoration: none; + min-height: 48px; + min-width: 80px; + cursor: default; + overflow: hidden; + border: none; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + background-color: #3358CC; + border-radius: 8px; + color: #FFFFFF; + cursor: pointer; +} + +.emotion-0 svg { + width: 24px; + height: 24px; +} + +.emotion-0 svg { + fill: #FFFFFF; +} + +.emotion-0:hover:not(:disabled) { + background-color: #254CAC; +} + +.emotion-0:active:not(:disabled) { + background-color: #12387A; +} + +.emotion-0:disabled { + background-color: #E2E2E2; + color: #ABABAB; +} + +.emotion-0:disabled svg { + fill: #ABABAB; +} + +.emotion-0:focus-visible:not(:disabled) { + outline-color: #3768FB; + outline-style: solid; + outline-width: 2px; + outline-offset: 2px; +} + +@media not all and (min-resolution: 0.001dpcm) { + @supports (-webkit-appearance: none) and (stroke-color: transparent) { + .emotion-0:focus-visible:not(:disabled) { + outline-style: auto; + } + } +} + +@media screen and (prefers-reduced-motion: no-preference) { + .emotion-0 { + transition-property: background-color; + transition-duration: 200ms; + transition-timing-function: cubic-bezier(0, 0, .5, 1); + } +} + +@media screen and (prefers-reduced-motion: reduce) { + .emotion-0 { + transition-property: background-color; + transition-duration: 0ms; + transition-timing-function: cubic-bezier(0, 0, .5, 1); + } +} + +.emotion-1 { + margin: 0; + font-family: "Poppins",sans-serif; + font-size: 14px; + line-height: 21px; + font-weight: 500; + letter-spacing: 0; + padding: 0.5px 0px; + display: inline-block; +} + +.emotion-1::before { + content: ''; + margin-bottom: -0.403em; + display: block; +} + +.emotion-1::after { + content: ''; + margin-top: -0.4em; + display: block; +} + + + +`; + +exports[`NewsKitProvider renders (slowly) with css variables and theme cache miss 1`] = ` + + .emotion-0 { + --borderWidth000: 0; + --borderWidth010: 1px; + --borderWidthDefault: 1px; + --borderWidth020: 2px; + --borderWidth030: 4px; + --borderRadiusSharp: 0; + --borderRadiusCircle: 50%; + --borderRadiusPill: 20rem; + --borderRadiusDefault: 8px; + -webkit---borderRadiusRounded010: 4px; + --borderRadiusRounded010: 4px; + -webkit---borderRadiusRounded020: 8px; + --borderRadiusRounded020: 8px; + -webkit---borderRadiusRounded030: 12px; + --borderRadiusRounded030: 12px; + -webkit---borderRadiusRounded040: 16px; + --borderRadiusRounded040: 16px; + -webkit---borderRadiusRounded050: 24px; + --borderRadiusRounded050: 24px; + --color-blue010: #ECF1FF; + --color-blue020: #D5E0FC; + --color-blue030: #AEBFFF; + --color-blue040: #8BA6F6; + --color-blue050: #708DE9; + --color-blue060: #3358CC; + --color-blue070: #254CAC; + --color-blue080: #12387A; + --color-blue090: #03264D; + --color-blue100: #060F2C; + --color-teal010: #E6F4F6; + --color-teal020: #C7E7EA; + --color-teal030: #97D0D6; + --color-teal040: #5EB8C0; + --color-teal050: #289FAB; + --color-teal060: #017582; + --color-teal070: #005B65; + --color-teal080: #004249; + --color-teal090: #002B30; + --color-teal100: #001314; + --color-red010: #FEECEC; + --color-red020: #FED8D8; + --color-red030: #FEB3B3; + --color-red040: #FE8888; + --color-red050: #FB5959; + --color-red060: #D60000; + --color-red070: #A90000; + --color-red080: #7D0000; + --color-red090: #550000; + --color-red100: #2D0000; + --color-green010: #E5F4EA; + --color-green020: #C8E4D0; + --color-green030: #95CAA3; + --color-green040: #6DB681; + --color-green050: #41A05B; + --color-green060: #007B22; + --color-green070: #00601A; + --color-green080: #004514; + --color-green090: #002D0D; + --color-green100: #001506; + --color-amber010: #FFEDE1; + --color-amber020: #FDDCC6; + --color-amber030: #FEB788; + --color-amber040: #F79247; + --color-amber050: #CD6900; + --color-amber060: #A75500; + --color-amber070: #804200; + --color-amber080: #5D2F00; + --color-amber090: #3C1F00; + --color-amber100: #1D0D02; + --color-neutral010: #F1F1F1; + --color-neutral020: #E2E2E2; + --color-neutral030: #C6C6C6; + --color-neutral040: #ABABAB; + --color-neutral050: #919191; + --color-neutral060: #6A6A6A; + --color-neutral070: #525252; + --color-neutral080: #3B3B3B; + --color-neutral090: #262626; + --color-neutral100: #111111; + --color-purple010: #EFF0FF; + --color-purple020: #DFE0FE; + --color-purple030: #C0C2FC; + --color-purple040: #A3A3FB; + --color-purple050: #8883F6; + --color-purple060: #6454E3; + --color-purple070: #4C33CC; + --color-purple080: #37239C; + --color-purple090: #231668; + --color-purple100: #0F0936; + --color-blackTint010: rgba(0,0,0,0.1); + --color-blackTint020: rgba(0,0,0,0.2); + --color-blackTint030: rgba(0,0,0,0.3); + --color-blackTint040: rgba(0,0,0,0.4); + --color-blackTint050: rgba(0,0,0,0.5); + --color-blackTint060: rgba(0,0,0,0.6); + --color-blackTint070: rgba(0,0,0,0.7); + --color-blackTint080: rgba(0,0,0,0.8); + --color-blackTint090: rgba(0,0,0,0.9); + --color-black: #0A0A0A; + --color-whiteTint010: rgba(255,255,255,0.1); + --color-whiteTint020: rgba(255,255,255,0.2); + --color-whiteTint030: rgba(255,255,255,0.3); + --color-whiteTint040: rgba(255,255,255,0.4); + --color-whiteTint050: rgba(255,255,255,0.5); + --color-whiteTint060: rgba(255,255,255,0.6); + --color-whiteTint070: rgba(255,255,255,0.7); + --color-whiteTint080: rgba(255,255,255,0.8); + --color-whiteTint090: rgba(255,255,255,0.9); + --color-white: #FFFFFF; + --color-socialTwitter: #1DA1F2; + --color-socialFacebook: #1877F2; + --color-socialInstagram: #C32AA3; + --color-socialYoutube: #FF0000; + --color-socialWhatsapp: #25D366; + --color-socialReddit: #FF4500; + --color-socialGithub: #000000; + --color-socialApple: #000000; + --color-socialGoogleBlue: #4285F4; + --color-socialGoogleRed: #DB4437; + --color-socialGoogleYellow: #F4B400; + --color-socialGoogleGreen: #0F9D58; + --color-focus010: #3768FB; + --color-transparent: transparent; + --color-blue055: #446BE4; + --color-purple055: #6E61E4; + --color-teal055: #06808E; + --color-darkBlue100: #09111C; + --color-darkBlue095: #0F1B2C; + --color-darkBlue090: #15263E; + --color-darkBlue080: #2E3F54; + --color-darkBlue070: #435365; + --color-darkBlue060: #5A6A79; + --color-darkBlue050: #85939C; + --color-darkBlue040: #A1ACB4; + --color-darkBlue030: #C0C7CC; + --color-darkBlue020: #DEE2E5; + --color-darkBlue010: #F0F1F3; + --color-inkBase: #3B3B3B; + --color-inkContrast: #111111; + --color-inkSubtle: #6A6A6A; + --color-inkNonEssential: #ABABAB; + --color-inkInverse: #FFFFFF; + --color-inkLight010: #FFFFFF; + --color-inkDark010: #111111; + --color-inkPositive: #007B22; + --color-inkNegative: #D60000; + --color-inkNotice: #525252; + --color-inkInformative: #017582; + --color-inkBrand010: #3358CC; + --color-inkBrand020: #12387A; + --color-interfaceBackground: #FFFFFF; + --color-interface010: #FFFFFF; + --color-interface020: #F1F1F1; + --color-interface030: #E2E2E2; + --color-interface040: #C6C6C6; + --color-interface050: #ABABAB; + --color-interface060: #111111; + --color-interfaceBrand010: #3358CC; + --color-interfaceBrand020: #12387A; + --color-interfacePositive010: #007B22; + --color-interfacePositive020: #E5F4EA; + --color-interfaceNegative010: #D60000; + --color-interfaceNegative020: #FEECEC; + --color-interfaceNotice010: #3B3B3B; + --color-interfaceNotice020: #F1F1F1; + --color-interfaceInformative010: #017582; + --color-interfaceInformative020: #E6F4F6; + --color-interfaceNeutral010: #3B3B3B; + --color-interfaceNeutral020: #F1F1F1; + --color-interfaceSkeleton010: #F1F1F1; + --color-interfaceSkeleton020: #E2E2E2; + --color-interactivePrimary010: #ECF1FF; + --color-interactivePrimary020: #D5E0FC; + --color-interactivePrimary030: #3358CC; + --color-interactivePrimary040: #254CAC; + --color-interactivePrimary050: #12387A; + --color-interactiveSecondary010: #F1F1F1; + --color-interactiveSecondary020: #E2E2E2; + --color-interactiveSecondary030: #3B3B3B; + --color-interactiveSecondary040: #262626; + --color-interactiveSecondary050: #111111; + --color-interactivePositive010: #E5F4EA; + --color-interactivePositive020: #C8E4D0; + --color-interactivePositive030: #007B22; + --color-interactivePositive040: #00601A; + --color-interactivePositive050: #004514; + --color-interactiveNegative010: #FEECEC; + --color-interactiveNegative020: #FED8D8; + --color-interactiveNegative030: #D60000; + --color-interactiveNegative040: #A90000; + --color-interactiveNegative050: #7D0000; + --color-interactiveInverse010: rgba(255,255,255,0.1); + --color-interactiveInverse020: rgba(255,255,255,0.2); + --color-interactiveInverse030: #FFFFFF; + --color-interactiveInverse040: rgba(255,255,255,0.7); + --color-interactiveInverse050: rgba(255,255,255,0.8); + --color-interactiveInput010: #F1F1F1; + --color-interactiveInput020: #919191; + --color-interactiveInput030: #ECF1FF; + --color-interactiveInput040: #3358CC; + --color-interactiveInput050: #254CAC; + --color-interactiveLink010: #3358CC; + --color-interactiveLink020: #254CAC; + --color-interactiveLink030: #12387A; + --color-interactiveDisabled010: #E2E2E2; + --color-interactiveVisited010: #6454E3; + --color-interactiveFocus010: #3768FB; + --color-interactiveFocus020: #FFFFFF; + --overlayGradientInverseVertical: linear-gradient(0deg, rgba(17,17,17,0.00) 0%, rgba(17,17,17,1.00) 100%); + --overlayGradientBaseVertical: linear-gradient(0deg, rgba(255,255,255,0.00) 0%, rgba(255,255,255,1.00) 100%); + --overlayGradientInverseHorizontal: linear-gradient(-90deg, rgba(17,17,17,0.00) 0%, rgba(17,17,17,1.00) 100%); + --overlayGradientBaseHorizontal: linear-gradient(-90deg, rgba(255,255,255,0.00) 0%, rgba(255,255,255,1.00) 100%); + --overlayGradientFromBottom: linear-gradient(180deg, rgba(10,10,10,0.00) 0%, rgba(10,10,10,1.00) 100%); + --overlayGradientFromBottomLeft: linear-gradient(225deg, rgba(10,10,10,0.00) 0%, rgba(10,10,10,1.00) 100%); + --overlayGradientFromBottomRight: linear-gradient(135deg, rgba(10,10,10,0.00) 0%, rgba(10,10,10,1.00) 100%); + --overlayGradientFromLeft: linear-gradient(-90deg, rgba(10,10,10,0.00) 0%, rgba(10,10,10,1.00) 100%); + --overlayGradientFromRight: linear-gradient(90deg, rgba(10,10,10,0.00) 0%, rgba(10,10,10,1.00) 100%); + --overlayGradientFromTop: linear-gradient(0deg, rgba(10,10,10,0.00) 0%, rgba(10,10,10,0.99) 100%); + --overlayGradientFromTopLeft: linear-gradient(-45deg, rgba(10,10,10,0.00) 0%, rgba(10,10,10,1.00) 99.25%); + --overlayGradientFromTopRight: linear-gradient(45deg, rgba(10,10,10,0.00) 0%, rgba(10,10,10,1.00) 100%); + --overlayTintInverse010: rgba(255,255,255,0.2); + --overlayTintInverse020: rgba(255,255,255,0.4); + --overlayTintInverse030: rgba(255,255,255,0.6); + --overlayTintInverse040: rgba(255,255,255,0.8); + --overlayTintBase010: rgba(0,0,0,0.2); + --overlayTintBase020: rgba(0,0,0,0.4); + --overlayTintBase030: rgba(0,0,0,0.6); + --overlayTintBase040: rgba(0,0,0,0.8); + --opacity000: 0; + --opacity010: 0.1; + --opacity020: 0.2; + --opacity030: 0.3; + --opacity040: 0.4; + --opacity050: 0.5; + --opacity060: 0.6; + --opacity070: 0.7; + --opacity080: 0.8; + --opacity090: 0.9; + --opacity100: 1; + --motionDuration000: 0ms; + --motionDuration010: 100ms; + --motionDuration020: 200ms; + --motionDuration030: 300ms; + --motionDuration040: 400ms; + --motionDuration050: 500ms; + --motionTimingLinear: linear; + --motionTimingEaseIn: cubic-bezier(.5, 0, 1, 1); + --motionTimingEaseOut: cubic-bezier(0, 0, .5, 1); + --motionTimingEaseInAndOut: cubic-bezier(.5, 0, .5, 1); + --shadow010: 0 0 2px 0 rgba(10,10,10,0.08); + --shadow020: 0 2px 4px 0 rgba(10,10,10,0.08); + --shadow030: 0 4px 8px 0 rgba(10,10,10,0.08); + --shadow040: 0 8px 16px 0 rgba(10,10,10,0.08); + --shadow050: 0 16px 24px 0 rgba(10,10,10,0.08); + --shadow060: 0 20px 32px 0 rgba(10,10,10,0.08); + --sizing000: 0; + --sizing010: 4px; + --sizing020: 8px; + --sizing030: 12px; + --sizing040: 16px; + --sizing045: 20px; + --sizing050: 24px; + --sizing060: 32px; + --sizing070: 40px; + --sizing080: 48px; + --sizing090: 64px; + --sizing100: 80px; + --sizing110: 120px; + --sizing120: 160px; + --iconSize005: 8px; + --iconSize010: 16px; + --iconSize020: 24px; + --iconSize030: 32px; + --iconSize040: 48px; + --iconSize050: 64px; + --space000: 0; + --space010: 4px; + --space020: 8px; + --space030: 12px; + --space040: 16px; + --space045: 20px; + --space050: 24px; + --space060: 32px; + --space070: 40px; + --space080: 48px; + --space090: 64px; + --space100: 80px; + --space110: 120px; + --space120: 160px; + --spaceInset000: 0; + --spaceInset010: 4px; + --spaceInset020: 8px; + --spaceInset030: 12px; + --spaceInset040: 16px; + --spaceInset045: 20px; + --spaceInset050: 24px; + --spaceInset060: 32px; + --spaceInset070: 48px; + --spaceInsetSquish000: 0; + --spaceInsetSquish010: 4px 8px; + --spaceInsetSquish020: 8px 12px; + --spaceInsetSquish030: 12px 16px; + --spaceInsetSquish040: 16px 24px; + --spaceInsetSquish050: 24px 32px; + --spaceInsetSquish060: 32px 48px; + --spaceInsetStretch000: 0; + --spaceInsetStretch010: 8px 4px; + --spaceInsetStretch020: 12px 8px; + --spaceInsetStretch030: 16px 12px; + --spaceInsetStretch040: 24px 16px; + --spaceInsetStretch050: 32px 24px; + --spaceInsetStretch060: 48px 32px; + --fontSize010: 12px; + --fontSize020: 14px; + --fontSize030: 16px; + --fontSize040: 18px; + --fontSize050: 20px; + --fontSize060: 22px; + --fontSize070: 24px; + --fontSize080: 28px; + --fontSize090: 32px; + --fontSize100: 36px; + --fontSize110: 40px; + --fontSize120: 44px; + --fontSize130: 48px; + --fontSize140: 56px; + --fontSize150: 64px; + --fontSize160: 80px; + --fontLineHeight010: 1; + --fontLineHeight020: 1.125; + --fontLineHeight030: 1.25; + --fontLineHeight040: 1.5; + --fontLineHeight050: 1.75; + --fontLineHeight060: 2; + --fontWeight010: 400; + --fontWeight020: 500; + --fontWeight030: 600; + --fontWeight040: 700; + --fontLetterSpacing010: -0.5px; + --fontLetterSpacing020: -0.25px; + --fontLetterSpacing030: 0; + --fontLetterSpacing040: 0.25px; + --fontLetterSpacing050: 0.5px; + --fontFamily010: "DM Sans",sans-serif; + --fontFamily020: "Bitter",serif; + --fontFamily030: "Poppins",sans-serif; +} + +.emotion-1 { + margin: 0; + padding: 0; + display: inline-grid; + -webkit-column-gap: 8px; + column-gap: 8px; + grid-template-columns: repeat(1, auto); + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-content: center; + -ms-flex-line-pack: center; + align-content: center; + justify-items: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + min-width: 80px; + min-height: 48px; + padding-inline: 16px; + padding-block: 12px; + box-sizing: border-box; + -webkit-text-decoration: none; + text-decoration: none; + min-height: 48px; + min-width: 80px; + cursor: default; + overflow: hidden; + border: none; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + background-color: #3358CC; + border-radius: 8px; + color: #FFFFFF; + cursor: pointer; +} + +.emotion-1 svg { + width: 24px; + height: 24px; +} + +.emotion-1 svg { + fill: #FFFFFF; +} + +.emotion-1:hover:not(:disabled) { + background-color: #254CAC; +} + +.emotion-1:active:not(:disabled) { + background-color: #12387A; +} + +.emotion-1:disabled { + background-color: #E2E2E2; + color: #ABABAB; +} + +.emotion-1:disabled svg { + fill: #ABABAB; +} + +.emotion-1:focus-visible:not(:disabled) { + outline-color: #3768FB; + outline-style: solid; + outline-width: 2px; + outline-offset: 2px; +} + +@media not all and (min-resolution: 0.001dpcm) { + @supports (-webkit-appearance: none) and (stroke-color: transparent) { + .emotion-1:focus-visible:not(:disabled) { + outline-style: auto; + } + } +} + +@media screen and (prefers-reduced-motion: no-preference) { + .emotion-1 { + transition-property: background-color; + transition-duration: 200ms; + transition-timing-function: cubic-bezier(0, 0, .5, 1); + } +} + +@media screen and (prefers-reduced-motion: reduce) { + .emotion-1 { + transition-property: background-color; + transition-duration: 0ms; + transition-timing-function: cubic-bezier(0, 0, .5, 1); + } +} + +.emotion-2 { + margin: 0; + font-family: "Poppins",sans-serif; + font-size: 14px; + line-height: 21px; + font-weight: 500; + letter-spacing: 0; + padding: 0.5px 0px; + display: inline-block; +} + +.emotion-2::before { + content: ''; + margin-bottom: -0.403em; + display: block; +} + +.emotion-2::after { + content: ''; + margin-top: -0.4em; + display: block; +} + +
+ +
`; -exports[`NewsKitProvider renders with css variables 1`] = ` +exports[`NewsKitProvider renders (slowly) with css variables and theme cache miss for unnamed theme 1`] = ` .emotion-0 { --borderWidth000: 0; @@ -357,10 +978,147 @@ exports[`NewsKitProvider renders with css variables 1`] = ` --fontFamily030: "Poppins",sans-serif; } +.emotion-1 { + margin: 0; + padding: 0; + display: inline-grid; + -webkit-column-gap: 8px; + column-gap: 8px; + grid-template-columns: repeat(1, auto); + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-align-content: center; + -ms-flex-line-pack: center; + align-content: center; + justify-items: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + min-width: 80px; + min-height: 48px; + padding-inline: 16px; + padding-block: 12px; + box-sizing: border-box; + -webkit-text-decoration: none; + text-decoration: none; + min-height: 48px; + min-width: 80px; + cursor: default; + overflow: hidden; + border: none; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + background-color: #3358CC; + border-radius: 8px; + color: #FFFFFF; + cursor: pointer; +} + +.emotion-1 svg { + width: 24px; + height: 24px; +} + +.emotion-1 svg { + fill: #FFFFFF; +} + +.emotion-1:hover:not(:disabled) { + background-color: #254CAC; +} + +.emotion-1:active:not(:disabled) { + background-color: #12387A; +} + +.emotion-1:disabled { + background-color: #E2E2E2; + color: #ABABAB; +} + +.emotion-1:disabled svg { + fill: #ABABAB; +} + +.emotion-1:focus-visible:not(:disabled) { + outline-color: #3768FB; + outline-style: solid; + outline-width: 2px; + outline-offset: 2px; +} + +@media not all and (min-resolution: 0.001dpcm) { + @supports (-webkit-appearance: none) and (stroke-color: transparent) { + .emotion-1:focus-visible:not(:disabled) { + outline-style: auto; + } + } +} + +@media screen and (prefers-reduced-motion: no-preference) { + .emotion-1 { + transition-property: background-color; + transition-duration: 200ms; + transition-timing-function: cubic-bezier(0, 0, .5, 1); + } +} + +@media screen and (prefers-reduced-motion: reduce) { + .emotion-1 { + transition-property: background-color; + transition-duration: 0ms; + transition-timing-function: cubic-bezier(0, 0, .5, 1); + } +} + +.emotion-2 { + margin: 0; + font-family: "Poppins",sans-serif; + font-size: 14px; + line-height: 21px; + font-weight: 500; + letter-spacing: 0; + padding: 0.5px 0px; + display: inline-block; +} + +.emotion-2::before { + content: ''; + margin-bottom: -0.403em; + display: block; +} + +.emotion-2::after { + content: ''; + margin-top: -0.4em; + display: block; +} +
- app +
`; + +exports[`NewsKitProvider renders as default 1`] = ` + + app + +`; diff --git a/src/newskit-provider/__tests__/newskitprovider.test.tsx b/src/newskit-provider/__tests__/newskitprovider.test.tsx index 4ce81d6b34..2c99302924 100644 --- a/src/newskit-provider/__tests__/newskitprovider.test.tsx +++ b/src/newskit-provider/__tests__/newskitprovider.test.tsx @@ -2,6 +2,7 @@ import React from 'react'; import {render} from '@testing-library/react'; import {NewsKitProvider} from '..'; import {newskitLightTheme} from '../../theme'; +import {Button} from '../../button'; describe('NewsKitProvider', () => { it('renders as default', () => { @@ -10,13 +11,45 @@ describe('NewsKitProvider', () => { ); expect(asFragment()).toMatchSnapshot(); }); - it('renders with css variables', () => { + + // Slow as withOwnTheme's cache map will be + // missing cache key of "no-theme-name-button-buttonSolidPrimary" + it('renders (slowly) with css variables and theme cache miss for unnamed theme', () => { + const namelessTheme = {...newskitLightTheme, name: ''}; + const {asFragment} = render( + + + , + ); + expect(asFragment()).toMatchSnapshot(); + }); + + // Slow as withOwnTheme's cache map will be + // missing cache key of "newskit-light-button-buttonSolidPrimary" + it('renders (slowly) with css variables and theme cache miss', () => { + const {asFragment} = render( + + + , + ); + expect(asFragment()).toMatchSnapshot(); + }); + + // Fast as withOwnTheme's cache map will be populated from the previous test. + // Uses cache key of "newskit-light-button-buttonSolidPrimary" + it('renders (fast) with theme cache hit', () => { const {asFragment} = render( - app + , ); expect(asFragment()).toMatchSnapshot(); diff --git a/src/newskit-provider/context.tsx b/src/newskit-provider/context.tsx index 14330a1f57..7d96e16883 100644 --- a/src/newskit-provider/context.tsx +++ b/src/newskit-provider/context.tsx @@ -2,6 +2,9 @@ import React from 'react'; // This provider is internal and is used only to detect when NewsKitProvider is used inside NewsKitProvider // On the very first Provider we set value of {initialized: true} based on that we know if NewsKitProvider is already used -export const NewsKitInternalContext = React.createContext({}); +export const NewsKitInternalContext = React.createContext({ + initialized: false, + themeOptions: {} as Record, +}); export const useNewsKitContext = () => React.useContext(NewsKitInternalContext); diff --git a/src/newskit-provider/newskit-provider.tsx b/src/newskit-provider/newskit-provider.tsx index 8c489788c3..5a0dc4dfa6 100644 --- a/src/newskit-provider/newskit-provider.tsx +++ b/src/newskit-provider/newskit-provider.tsx @@ -29,19 +29,16 @@ export const NewsKitProvider = ({ instrumentation: instrumentationProps = {}, themeOptions = {}, }: NewsKitProviderProps) => { - const NKContext = useNewsKitContext(); + const {initialized} = useNewsKitContext(); /* istanbul ignore if */ - if ( - process.env.NODE_ENV !== 'production' && - Object.keys(NKContext).length > 0 - ) { + if (process.env.NODE_ENV !== 'production' && initialized) { console.warn( 'You are using NewsKitProvider inside NewsKitProvider, this might cause unexpected behavior', ); } return ( - + diff --git a/src/test/__tests__/test-utils.test.ts b/src/test/__tests__/test-utils.test.ts index 8ccbf03cc7..d5e4870a34 100644 --- a/src/test/__tests__/test-utils.test.ts +++ b/src/test/__tests__/test-utils.test.ts @@ -1,6 +1,15 @@ import React from 'react'; import {fireEvent} from '@testing-library/react'; -import {renderWithImplementation, renderWithThemeInBody} from '../test-utils'; +import { + renderWithImplementation, + renderWithThemeInBody, + renderToFragmentInBody, + renderInBody, + applyAsyncStyling, + generateString, + isVisualTest, + isCypressTest, +} from '../test-utils'; import {LinkInline} from '../../link'; import {LinkProps} from '../../link/types'; @@ -22,6 +31,14 @@ describe('Test utils', () => { expect(onClickHandler).toHaveBeenCalled(); }); + test('renderInBody renders correctly', async () => { + const {findByText, asFragment} = renderInBody(ThemedLink, {}); + + await findByText('test link text'); + expect(asFragment).toBeDefined(); + expect(asFragment().getElementById('a11y-status-message')).toBeNull(); + }); + test('renderWithThemeInBody renders correctly', async () => { const {findByText, asFragment} = renderWithThemeInBody(ThemedLink, {}); @@ -29,4 +46,31 @@ describe('Test utils', () => { expect(asFragment).toBeDefined(); expect(asFragment().getElementById('a11y-status-message')).toBeNull(); }); + + test('renderToFragmentInBody renders correctly', async () => { + const fragment = renderToFragmentInBody(ThemedLink, {}); + + expect(fragment).toBeDefined(); + expect(fragment.getElementById('a11y-status-message')).toBeNull(); + }); + + test('renderToFragmentInBody renders correctly', async () => { + const response = await applyAsyncStyling(); + + expect(response).toBeUndefined(); + }); + + test('generateString matches length', async () => { + const response = generateString(4); + + expect(response).toEqual('****'); + }); + + test('isVisualTest returns a boolean', async () => { + expect(typeof isVisualTest).toBe('boolean'); + }); + + test('isCypressTest returns a boolean', async () => { + expect(typeof isCypressTest).toBe('boolean'); + }); }); diff --git a/src/theme/emotion.tsx b/src/theme/emotion.tsx index dd1ea393ef..c9555374c8 100644 --- a/src/theme/emotion.tsx +++ b/src/theme/emotion.tsx @@ -18,6 +18,7 @@ export interface ThemeProviderProps { theme: UncompiledTheme | Theme | ((outerTheme: Theme) => Theme); children: React.ReactNode; exposeCssVariables?: boolean; + useThemeCache?: boolean; } export const ThemeProvider: React.FC = ({ diff --git a/src/utils/with-own-theme.tsx b/src/utils/with-own-theme.tsx index 2988984a67..dd7111381e 100644 --- a/src/utils/with-own-theme.tsx +++ b/src/utils/with-own-theme.tsx @@ -7,6 +7,23 @@ import { useTheme, } from '../theme'; import {deepMerge} from './deep-merge'; +import {useNewsKitContext} from '../newskit-provider/context'; + +const themeCache = new Map(); + +const resolveKey = ( + theme: Theme, + defaults: Record, + stylePresets?: Record, +): string => { + const themeName = theme.name || 'no-theme-name'; + /* istanbul ignore next */ + const defaultsKey = Object.keys(defaults)[0] || 'no-defaults'; + const stylePresetKey = + Object.keys(stylePresets || {})[0] || 'no-stylePresets'; + + return `${themeName}-${defaultsKey}-${stylePresetKey}`; +}; export type NewsKitReactComponents = React.FC & { stylePresets?: Record; @@ -16,14 +33,25 @@ const mergeTheme = ( theme: Theme, defaults: Record, stylePresets?: Record, + useThemeCache?: boolean, ): Theme => { - const newTheme = compileTheme({ + const cacheKey = resolveKey(theme, defaults, stylePresets); + + if (useThemeCache && themeCache.has(cacheKey)) { + return themeCache.get(cacheKey); + } + + const componentTheme = compileTheme({ ...theme, + name: cacheKey, compiled: false, componentDefaults: deepMerge(defaults, theme.componentDefaults), stylePresets: deepMerge(stylePresets, theme.stylePresets), }); - return newTheme; + + themeCache.set(cacheKey, componentTheme); + + return componentTheme; }; const objectIsEmpty = (obj: Object) => Object.keys(obj).length === 0; @@ -37,9 +65,6 @@ export const withOwnTheme =

( defaults: Record; stylePresets?: Record; }) => { - const componentTheme = (globalTheme: Theme): Theme => - mergeTheme(globalTheme, defaults, stylePresets); - const WrappedComponent = React.forwardRef((props, ref) => { const theme = useTheme(); @@ -51,8 +76,18 @@ export const withOwnTheme =

( throw new Error(errorMessage); } + const {themeOptions} = useNewsKitContext(); + const componentTheme = (globalTheme: Theme): Theme => + mergeTheme( + globalTheme, + defaults, + stylePresets, + /* istanbul ignore next */ + themeOptions?.useThemeCache, + ); + return ( - + );