diff --git a/packages/ui-extensions-react/src/surfaces/checkout/hooks/buyer-journey.ts b/packages/ui-extensions-react/src/surfaces/checkout/hooks/buyer-journey.ts index 348af98e3..777c05c10 100644 --- a/packages/ui-extensions-react/src/surfaces/checkout/hooks/buyer-journey.ts +++ b/packages/ui-extensions-react/src/surfaces/checkout/hooks/buyer-journey.ts @@ -59,20 +59,20 @@ export function useBuyerJourneyIntercept< >(interceptor: Interceptor): void { const api = useApi(); - if ('buyerJourney' in api) { - const interceptorRef = useRef(interceptor); - interceptorRef.current = interceptor; + if (!('buyerJourney' in api)) { + throw new ExtensionHasNoMethodError('buyerJourney', api.extension.target); + } - useEffect(() => { - const teardownPromise = api.buyerJourney.intercept((interceptorProps) => - interceptorRef.current(interceptorProps), - ); + const interceptorRef = useRef(interceptor); + interceptorRef.current = interceptor; - return () => { - teardownPromise.then((teardown) => teardown()).catch(() => {}); - }; - }, [api.buyerJourney]); - } + return useEffect(() => { + const teardownPromise = api.buyerJourney.intercept((interceptorProps) => + interceptorRef.current(interceptorProps), + ); - throw new ExtensionHasNoMethodError('buyerJourney', api.extension.target); + return () => { + teardownPromise.then((teardown) => teardown()).catch(() => {}); + }; + }, [api.buyerJourney]); } diff --git a/packages/ui-extensions-react/src/surfaces/checkout/hooks/extension.ts b/packages/ui-extensions-react/src/surfaces/checkout/hooks/extension.ts index f444f9353..566475b43 100644 --- a/packages/ui-extensions-react/src/surfaces/checkout/hooks/extension.ts +++ b/packages/ui-extensions-react/src/surfaces/checkout/hooks/extension.ts @@ -1,22 +1,19 @@ -import type { - Extension, - RenderExtensionTarget, -} from '@shopify/ui-extensions/checkout'; +import type {Extension} from '@shopify/ui-extensions/checkout'; import {useApi} from './api'; /** * Returns the metadata about the extension. */ -export function useExtension< - Target extends RenderExtensionTarget = RenderExtensionTarget, ->(): Extension { - return useApi().extension as Extension; +export function useExtension(): Extension { + return useApi().extension as Extension; } /** * Returns the metadata about the extension. - * + * > Caution: This is deprecated, use `useExtension()` instead. * @deprecated Use `useExtension()` instead. */ -export const useExtensionData = useExtension; +export function useExtensionData(): Extension { + return useExtension(); +} diff --git a/packages/ui-extensions-react/src/surfaces/checkout/hooks/translate.ts b/packages/ui-extensions-react/src/surfaces/checkout/hooks/translate.ts index 86bc14246..993820f8d 100644 --- a/packages/ui-extensions-react/src/surfaces/checkout/hooks/translate.ts +++ b/packages/ui-extensions-react/src/surfaces/checkout/hooks/translate.ts @@ -17,8 +17,6 @@ export function useTranslate< const translate = useCallback( (...args) => { - // @ts-expect-error TypeScript loses track of the generic type argument - // here for some reason... const translation = i18n.translate(...args); if (!Array.isArray(translation)) { diff --git a/packages/ui-extensions-react/src/surfaces/customer-account/hooks/extension.ts b/packages/ui-extensions-react/src/surfaces/customer-account/hooks/extension.ts new file mode 100644 index 000000000..03594a85a --- /dev/null +++ b/packages/ui-extensions-react/src/surfaces/customer-account/hooks/extension.ts @@ -0,0 +1,19 @@ +import type {Extension} from '@shopify/ui-extensions/customer-account'; + +import {useApi} from './api'; + +/** + * Returns the metadata about the extension. + */ +export function useExtension(): Extension { + return useApi().extension; +} + +/** + * Returns the metadata about the extension. + * > Caution: This is deprecated, use `useExtension()` instead. + * @deprecated Use `useExtension()` instead. + */ +export function useExtensionData(): Extension { + return useExtension(); +} diff --git a/packages/ui-extensions-react/src/surfaces/customer-account/hooks/index.ts b/packages/ui-extensions-react/src/surfaces/customer-account/hooks/index.ts index 05bcf5bbc..061797b91 100644 --- a/packages/ui-extensions-react/src/surfaces/customer-account/hooks/index.ts +++ b/packages/ui-extensions-react/src/surfaces/customer-account/hooks/index.ts @@ -18,7 +18,7 @@ export {useTarget} from './target'; export {useAppMetafields} from './app-metafields'; export {useShop} from './shop'; export {useStorage} from './storage'; -export {useExtensionData} from './extension-data'; +export {useExtension, useExtensionData} from './extension'; export {useSubscription} from './subscription'; export { useCustomer, diff --git a/packages/ui-extensions-react/src/surfaces/customer-account/render.tsx b/packages/ui-extensions-react/src/surfaces/customer-account/render.tsx index c339dd603..21d3d52b5 100644 --- a/packages/ui-extensions-react/src/surfaces/customer-account/render.tsx +++ b/packages/ui-extensions-react/src/surfaces/customer-account/render.tsx @@ -44,6 +44,8 @@ export function reactExtension( await new Promise((resolve, reject) => { try { remoteRender( + // @ts-expect-error This is a hack around some type conflicts between the + // customer-account version of this target’s API and the checkout version. {element} , diff --git a/packages/ui-extensions/docs/surfaces/checkout/build-docs.sh b/packages/ui-extensions/docs/surfaces/checkout/build-docs.sh index 461e4dabc..dfef45a5b 100644 --- a/packages/ui-extensions/docs/surfaces/checkout/build-docs.sh +++ b/packages/ui-extensions/docs/surfaces/checkout/build-docs.sh @@ -21,9 +21,15 @@ fi COMPILE_DOCS="yarn tsc --project $DOCS_PATH/tsconfig.docs.json --types react --moduleResolution node --target esNext --module CommonJS && yarn generate-docs --overridePath ./$DOCS_PATH/typeOverride.json --input ./$DOCS_PATH/reference ./$SRC_PATH --typesInput ./$SRC_PATH ../ui-extensions-react/$SRC_PATH --output ./$DOCS_PATH/generated" COMPILE_STATIC_PAGES="yarn tsc $DOCS_PATH/staticPages/*.doc.ts --types react --moduleResolution node --target esNext --module CommonJS && yarn generate-docs --isLandingPage --input ./$DOCS_PATH/staticPages --output ./$DOCS_PATH/generated" +# `customer-accounts` has duplicate types that cause issues with documentation generation, +# so we erase its contents and replace them afterwards +echo "export {}" > src/surfaces/customer-account.ts + eval $COMPILE_DOCS && eval $COMPILE_STATIC_PAGES build_exit=$? +git checkout HEAD -- src/surfaces/customer-account.ts + # TODO: get generate-docs to stop requiring JS files: # https://github.com/Shopify/generate-docs#important-note find ./ -name '*.doc*.js' -exec rm -r {} \; diff --git a/packages/ui-extensions/docs/surfaces/checkout/reference/apis/extension-targets.doc.ts b/packages/ui-extensions/docs/surfaces/checkout/reference/apis/extension-targets.doc.ts index 7741cfad3..1fc6b762d 100644 --- a/packages/ui-extensions/docs/surfaces/checkout/reference/apis/extension-targets.doc.ts +++ b/packages/ui-extensions/docs/surfaces/checkout/reference/apis/extension-targets.doc.ts @@ -13,7 +13,7 @@ You register for [targets](/docs/api/checkout-ui-extensions/extension-targets-ov The API for each extension target is passed as an argument to your function. While all targets inherit the [\`StandardApi\`](/docs/api/checkout-ui-extensions/apis/standardapi), not all of them share the same properties and methods. -For example, the [\`purchase.checkout.cart-line-item.render-after\`](typesofextensiontargets-propertydetail-purchasecheckoutcartlineitemrenderafter) target has access to the [\`CheckoutApi\`](/docs/api/checkout-ui-extensions/apis/checkoutapi) to modify a checkout, but the [\`purchase.thank-you.cart-line-item.render-after\`](#typesofextensiontargets-propertydetail-purchasethankyoucartlineitemrenderafter) target does not. +For example, the [\`purchase.checkout.cart-line-item.render-after\`](#typesofextensiontargets-propertydetail-purchasecheckoutcartlineitemrenderafter) target has access to the [\`CheckoutApi\`](/docs/api/checkout-ui-extensions/apis/checkoutapi) to modify a checkout, but the [\`purchase.thank-you.cart-line-item.render-after\`](#typesofextensiontargets-propertydetail-purchasethankyoucartlineitemrenderafter) target does not. `, isVisualComponent: false, category: 'APIs', diff --git a/packages/ui-extensions/docs/surfaces/checkout/reference/examples/extension-targets.example.tsx b/packages/ui-extensions/docs/surfaces/checkout/reference/examples/extension-targets.example.tsx index cd05d81ed..255021db5 100644 --- a/packages/ui-extensions/docs/surfaces/checkout/reference/examples/extension-targets.example.tsx +++ b/packages/ui-extensions/docs/surfaces/checkout/reference/examples/extension-targets.example.tsx @@ -6,10 +6,11 @@ import { function Extension() { const {extension} = useApi(); + const {target} = extension; return ( - This extension is rendering in the {extension.target} + This extension is rendering in the {target} extension target. ); diff --git a/packages/ui-extensions/docs/surfaces/checkout/reference/hooks/extension.doc.ts b/packages/ui-extensions/docs/surfaces/checkout/reference/hooks/extension.doc.ts new file mode 100644 index 000000000..aac0d6e5d --- /dev/null +++ b/packages/ui-extensions/docs/surfaces/checkout/reference/hooks/extension.doc.ts @@ -0,0 +1,23 @@ +import {ReferenceEntityTemplateSchema} from '@shopify/generate-docs'; + +import {getLinksByTag} from '../helper.docs'; + +const data: ReferenceEntityTemplateSchema = { + name: 'useExtension', + description: '', + descriptionType: 'UseExtensionGeneratedType', + isVisualComponent: false, + type: 'hook', + category: 'React Hooks', + subCategory: 'Metadata', + definitions: [ + { + title: '', + description: '', + type: 'UseExtensionGeneratedType', + }, + ], + related: getLinksByTag('apis'), +}; + +export default data; diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/dynamic-extension-targets.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/dynamic-extension-targets.png index 7969f7a5a..afed1946c 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/dynamic-extension-targets.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/dynamic-extension-targets.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/static-extension-targets.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/static-extension-targets.png index 359647d11..a20d0faa7 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/static-extension-targets.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/static-extension-targets.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-information.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-information.png index ae84a05ba..53346d824 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-information.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-information.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-local-pickup.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-local-pickup.png index 5c74f094a..5e528996f 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-local-pickup.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-local-pickup.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-one-page-checkout.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-one-page-checkout.png index 08f94938d..fe3ddf6c9 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-one-page-checkout.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-one-page-checkout.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-status.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-status.png index 24a577fda..60db65bea 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-status.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-status.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary-order-status.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary-order-status.png index b446d6d3a..89f7bedbd 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary-order-status.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary-order-status.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary-thank-you.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary-thank-you.png index 635e4d927..09f708b5f 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary-thank-you.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary-thank-you.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary.png index 78e0656a3..fdbfe2361 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-order-summary.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-payment.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-payment.png index b15747a02..9e3a315a0 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-payment.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-payment.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-pickup-points.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-pickup-points.png index 5f0c9b252..b60dc1ed7 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-pickup-points.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-pickup-points.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-shipping.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-shipping.png index a89187dfb..9d5c8c3e7 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-shipping.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-shipping.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-shop-pay.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-shop-pay.png index 8bf6a7f99..0a50768f9 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-shop-pay.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-shop-pay.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-thank-you.png b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-thank-you.png index 1840e345b..03cc7d088 100644 Binary files a/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-thank-you.png and b/packages/ui-extensions/docs/surfaces/checkout/screenshots/supported-locations-thank-you.png differ diff --git a/packages/ui-extensions/docs/surfaces/checkout/staticPages/examples/migration/migration-output.txt b/packages/ui-extensions/docs/surfaces/checkout/staticPages/examples/migration/migration-output.txt new file mode 100644 index 000000000..50a2a85b5 --- /dev/null +++ b/packages/ui-extensions/docs/surfaces/checkout/staticPages/examples/migration/migration-output.txt @@ -0,0 +1,18 @@ +❯ yarn deploy +yarn run v1.22.19 +$ shopify app deploy + +╭─ info ───────────────────────────────────────────────────────────────────────────────────────────────╮ +│ │ +│ Extension migrations can't be undone. │ +│ │ +│ Your "my-extension" configuration has been updated. Migrating gives you access to new │ +│ features and won't impact the end user experience. All previous extension versions will reflect │ +│ this change. │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ + +? Migrate "my-extension"? + +> (y) Yes, confirm migration from "checkout_ui_extension" + (n) No, cancel diff --git a/packages/ui-extensions/docs/surfaces/checkout/staticPages/versioning-migration.doc.ts b/packages/ui-extensions/docs/surfaces/checkout/staticPages/versioning-migration.doc.ts new file mode 100644 index 000000000..4929acb65 --- /dev/null +++ b/packages/ui-extensions/docs/surfaces/checkout/staticPages/versioning-migration.doc.ts @@ -0,0 +1,368 @@ +import {LandingTemplateSchema} from '@shopify/generate-docs'; + +// Order of data shape mimics visual structure of page +// Anything in an array can have multiple objects + +const data: LandingTemplateSchema = { + title: 'API versioning and unified UI extensions', + description: ` +As of Summer Editions 2023 (July 26), we have introduced some important changes to checkout UI extensions: + +- The introduction of API versioning and the [associated API versioning strategy](/docs/api/usage/versioning) +- Changes to the configuration \`toml\` file that match the format for other app extensions +- \`extension points\` have been renamed to \`targets\` + +For more details on the above, [please visit our post on the ui-extensions public repository](https://github.com/Shopify/ui-extensions/discussions/1149) +`, + // The id for the page that is used for routing. If this documentation is for a primary landing page, confirm id matches the reference name. + id: 'versioning-migration', + sections: [ + { + type: 'Markdown', + anchorLink: 'what-changed-in-the-toml-file', + title: 'What changed in the toml file', + sectionContent: ` +The main changes you will need to make will be to your configuration file (\`shopify.ui.extension.toml\`). We changed a few of the fields you currently use to configure a UI extension: + +- \`type\`, which currently is set to \`checkout_ui_extension\`, must be updated to \`ui_extension\` +- \`extension_points\` is now \`[[extensions.targeting]]\` and is expanded to include additional details. Most notably, you will need to provide a \`module\`, which is a reference to the file in your project that implements the extension. \`metafields\` that you will query must also now be specified per-extension point +- a new mandatory field: \`api_version\`. This field must be a Shopify API version, in the same format you would use for [Shopify's REST and GraphQL APIs](https://shopify.dev/api/usage/versioning). This version will control what extension points, components, and APIs are available to your extension, and will come with the same 1 year (minimum) guarantee as our other APIs. The first public API version for checkout UI extensions will be \`2023-07\` +- \`handle\`, which should be set in the nested \`extensions\` level of your configuration file. This is a unique identifier for your extension, and will be used to reference it from other extensions. We recommend using dash casing for the handle (for example, \`my-extension\` for an extension named "My extension") +- \`shopify.ui.extension.toml\` is now \`shopify.extension.toml\` +`, + }, + { + type: 'GenericAccordion', + anchorLink: 'converting-the-extension-configuration-file', + title: 'Update the configuration file', + sectionContent: ` +First rename your \`shopify.ui.extension.toml\` file to \`shopify.extension.toml\`. + +Then update the extension configuration file to the new format. +`, + accordionContent: [ + { + title: 'Old shopify.extension.toml', + description: '', + codeblock: { + title: 'shopify.extension.toml', + tabs: [ + { + title: 'shopify.extension.toml', + code: ` +type = "checkout_ui_extension" +name = "My Extension" + +extension_points = [ + 'Checkout::Dynamic::Render' +] + +[[metafields]] +namespace = "my_namespace" +key = "my_key" + +[settings] +[[settings.fields]] +key = "banner_title" +type = "single_line_text_field" +name = "Banner title" +description = "Enter a title for the banner" + +`, + language: 'toml', + }, + ], + }, + }, + { + title: 'New shopify.extension.toml', + description: '', + codeblock: { + title: 'shopify.extension.toml', + tabs: [ + { + title: 'shopify.extension.toml', + code: ` +api_version = "2023-07" + +[[extensions]] +type = "ui_extension" +name = "My Extension" +handle = "my-extension" + +[[extensions.targeting]] +module = "./src/index.ts" +target = "purchase.checkout.block.render" + +[[extension_points.metafields]] +namespace = "my_namespace" +key = "my_key" + +[settings] +[[settings.fields]] +key = "banner_title" +type = "single_line_text_field" +name = "Banner title" +description = "Enter a title for the banner" + +`, + language: 'toml', + }, + ], + }, + }, + ], + }, + { + type: 'GenericAccordion', + anchorLink: 'packages', + title: 'Update the packages', + sectionContent: ` +We will be moving to a new set of packages for distributing UI extension APIs — \`@shopify/checkout-ui-extensions\` and \`@shopify/checkout-ui-extensions-react\` will be replaced with \`@shopify/ui-extensions/checkout\` and \`@shopify/ui-extensions-react/checkout\`. These new packages will allow you to implement extensions for multiple surfaces without requiring multiple dependencies. You'll need to update any import for the existing packages with the new package. + +In your \`package.json\`, replace any \`@shopify/checkout-ui-extension\` package with the \`@shopify/ui-extension\` equivalent. + +You will notice that the UI extension packages have a new versioning system. In the new versions, the "major" version number is the API version year (e.g., \`2023\`), the "minor" version number is the API version month (e.g., \`07\` for \`2023.07\`), and the "patch" version number is reserved by Shopify for making bugfixes on the contents of the package (e.g. \`.1\` for \`2023.07.1\`). You will need to match the version of the package you install to the API version your extension targets, so that you get access to the types and runtime utilities associated with that API version. We recommend using a version that locks in the major and minor version numbers, and allows the patch version to be updated, like the \`2023.7.x\` version range shown above. + +> Caution: +> The \`2023.7.x\` version range has a couple breaking changes compared to the \`0.27.x\` range of the \`@shopify/checkout-ui-extensions(-react)\` packages. If you want to upgrade to the new API versioning system, but continue to use the APIs you were using before without any changes, we also provide a \`2023.4.x\` version range that contains the same APIs as the \`0.27.x\` range of the old packages. +`, + accordionContent: [ + { + title: 'Old package.json', + description: '', + codeblock: { + title: 'package.json', + tabs: [ + { + title: 'package.json', + code: ` +{ + "dependencies": { + "@shopify/checkout-ui-extensions": "^0.27.0", + "@shopify/checkout-ui-extensions-react": "^0.27.0", + } +} +`, + language: 'json', + }, + ], + }, + }, + { + title: 'New package.json', + description: '', + codeblock: { + title: 'package.json', + tabs: [ + { + title: 'package.json', + code: ` +{ + "dependencies": { + "@shopify/ui-extensions": "2023.7.x", + "@shopify/ui-extensions-react": "2023.7.x", + } +} +`, + language: 'json', + }, + ], + }, + }, + ], + }, + { + type: 'GenericAccordion', + anchorLink: 'extension-points', + title: 'Update the extension points', + sectionContent: ` +Finally, the new format has a slightly different system for registering your extension point code. The file you list as the \`module\` for a given extension point **must** export your extension point code as the default export from the module.`, + accordionContent: [ + { + title: 'Old extension code (plain)', + description: '', + codeblock: { + title: 'index.ts', + tabs: [ + { + title: 'index.ts', + code: ` +import {extend, Banner} from '@shopify/checkout-ui-extensions'; + +extend('Checkout::Dynamic::Render', (root, {extensionPoint, i18n}) => { + root.appendChild( + root.createComponent( + Banner, + {title: 'My extension'}, + i18n.translate('welcome', {extensionPoint}), + ), + ); +}); +`, + language: 'ts', + }, + ], + }, + }, + { + title: 'New extension code (plain)', + description: '', + codeblock: { + title: 'index.ts', + tabs: [ + { + title: 'index.ts', + code: ` +import {extension, Banner} from '@shopify/ui-extensions/checkout'; + +export default extension( + 'purchase.checkout.block.render', + (root, {extension:{target}, i18n}) => { + root.appendChild( + root.createComponent( + Banner, + {title: 'My extension'}, + i18n.translate('welcome', {target}), + ), + ); + }, +); +`, + language: 'ts', + }, + ], + }, + }, + { + title: 'Old extension code (React)', + description: '', + codeblock: { + title: 'index.tsx', + tabs: [ + { + title: 'index.tsx', + code: ` +import { + useApi, + render, + Banner, + useTranslate, +} from '@shopify/checkout-ui-extensions-react'; + +render('Checkout::Dynamic::Render', () => ( + +)); + +function App() { + const {extensionPoint} = useApi(); + const translate = useTranslate(); + + return ( + + {translate('welcome', {extensionPoint})} + + ); +} +`, + language: 'tsx', + }, + ], + }, + }, + { + title: 'New extension code (React)', + description: '', + codeblock: { + title: 'index.tsx', + tabs: [ + { + title: 'index.tsx', + code: ` +import { + reactExtension, + useApi, + Banner, + useTranslate, +} from '@shopify/ui-extensions-react/checkout'; + +export default reactExtension( + 'purchase.checkout.block.render', + () => , +); + +function App() { + const {extension:{target}} = useApi(); + const translate = useTranslate(); + + return ( + + {translate('welcome', {target})} + + ); +} +`, + language: 'tsx', + }, + ], + }, + }, + ], + }, + { + type: 'Generic', + anchorLink: 'migrate', + title: 'Migrate your extensions', + sectionContent: + 'Deploy after applying the above changes to get your extensions migrated.', + codeblock: { + title: 'Deploy', + tabs: [ + { + title: 'Deploy', + code: './examples/migration/migration-output.txt', + language: 'plaintext', + }, + ], + }, + }, + { + type: 'Markdown', + anchorLink: 'extension-targets-list', + title: 'Reference: extension point to extension target', + sectionContent: ` +Extension targets are more flexible and powerful than extension points and they allow to link UI extensions with functions. + +| Extension point name | Extension target name | +|---|---| +| Checkout::Actions::RenderBefore | purchase.checkout.actions.render-before | +| Checkout::CartLineDetails::RenderAfter | purchase.checkout.cart-line-item.render-after | +| Checkout::CartLineDetails::RenderLineComponents | purchase.cart-line-item.line-components.render | +| Checkout::CartLines::RenderAfter | purchase.checkout.cart-line-list.render-after | +| Checkout::Contact::RenderAfter | purchase.checkout.contact.render-after | +| Checkout::DeliveryAddress::RenderBefore | purchase.checkout.delivery-address.render-before | +| Checkout::Dynamic::Render | purchase.checkout.block.render | +| Checkout::GiftCard::Render | purchase.checkout.gift-card.render | +| Checkout::OrderStatus::CartLineDetails::RenderAfter | customer-account.order-details.cart-line-item.render-after | +| Checkout::OrderStatus::CartLines::RenderAfter | customer-account.order-index.action.render | +| Checkout::OrderStatus::Dynamic::Render | customer-account.order-details.block.render | +| Checkout::PickupLocations::RenderAfter | purchase.checkout.pickup-location-list.render-after | +| Checkout::PickupLocations::RenderBefore | purchase.checkout.pickup-location-list.render-before | +| Checkout::PickupPoints::RenderAfter | purchase.checkout.pickup-point-list.render-after | +| Checkout::PickupPoints::RenderBefore | purchase.checkout.pickup-point-list.render-before | +| Checkout::Reductions::RenderAfter | purchase.checkout.reductions.render-after | +| Checkout::Reductions::RenderBefore | purchase.checkout.reductions.render-before | +| Checkout::ShippingMethodDetails::RenderAfter | purchase.checkout.shipping-option-item.render-after | +| Checkout::ShippingMethodDetails::RenderExpanded | purchase.checkout.shipping-option-item.details.render | +| Checkout::ShippingMethods::RenderAfter | purchase.checkout.shipping-option-list.render-after | +| Checkout::ShippingMethods::RenderBefore | purchase.checkout.shipping-option-list.render-before | +| Checkout::ThankYou::CartLineDetails::RenderAfter | purchase.thank-you.cart-line-item.render-after | +| Checkout::ThankYou::CartLines::RenderAfter | purchase.thank-you.cart-line-list.render-after | +| Checkout::ThankYou::CustomerInformation::RenderAfter | purchase.thank-you.contact-information.render-after | +| Checkout::ThankYou::Dynamic::Render | purchase.thank-you.block.render | +`, + }, + ], +}; + +export default data; diff --git a/packages/ui-extensions/src/surfaces/checkout/targets.ts b/packages/ui-extensions/src/surfaces/checkout/targets.ts index 5d8d0ae77..175a57127 100644 --- a/packages/ui-extensions/src/surfaces/checkout/targets.ts +++ b/packages/ui-extensions/src/surfaces/checkout/targets.ts @@ -1,8 +1,3 @@ -import type { - OrderStatusApi as CustomerAccountOrderStatusApi, - CartLineItemApi as CustomerAccountCartLineItemApi, -} from '../customer-account'; - import type {RenderExtension} from './extension'; import type { CartLineItemApi, @@ -264,7 +259,8 @@ export interface ExtensionTargets { * by [using a URL parameter](https://shopify.dev/docs/apps/checkout/best-practices/testing-ui-extensions#dynamic-extension-targets). */ 'customer-account.order-status.block.render': RenderExtension< - CustomerAccountOrderStatusApi<'customer-account.order-status.block.render'>, + OrderStatusApi & + CustomerAccountStandardApi<'customer-account.order-status.block.render'>, AnyComponent >; /** @@ -278,7 +274,8 @@ export interface ExtensionTargets { * @deprecated Use `customer-account.order-status.block.render` instead. */ 'Checkout::OrderStatus::Dynamic::Render': RenderExtension< - CustomerAccountOrderStatusApi<'customer-account.order-status.block.render'>, + OrderStatusApi & + CustomerAccountStandardApi<'Checkout::OrderStatus::Dynamic::Render'>, AnyComponent >; /** @@ -286,8 +283,9 @@ export interface ExtensionTargets { * under the line item properties element on the Order Status Page. */ 'customer-account.order-status.cart-line-item.render-after': RenderExtension< - CustomerAccountCartLineItemApi & - CustomerAccountOrderStatusApi<'customer-account.order-status.cart-line-item.render-after'>, + CartLineItemApi & + OrderStatusApi & + CustomerAccountStandardApi<'customer-account.order-status.cart-line-item.render-after'>, AnyComponent >; /** @@ -297,15 +295,17 @@ export interface ExtensionTargets { * @deprecated Use `customer-account.order-status.cart-line-item.render-after` instead. */ 'Checkout::OrderStatus::CartLineDetails::RenderAfter': RenderExtension< - CustomerAccountCartLineItemApi & - CustomerAccountOrderStatusApi<'customer-account.order-status.cart-line-item.render-after'>, + CartLineItemApi & + OrderStatusApi & + CustomerAccountStandardApi<'Checkout::OrderStatus::CartLineDetails::RenderAfter'>, AnyComponent >; /** * A static extension target that is rendered after all line items on the Order Status page. */ 'customer-account.order-status.cart-line-list.render-after': RenderExtension< - CustomerAccountOrderStatusApi<'customer-account.order-status.cart-line-item.render-after'>, + OrderStatusApi & + CustomerAccountStandardApi<'customer-account.order-status.cart-line-list.render-after'>, AnyComponent >; /** @@ -314,14 +314,16 @@ export interface ExtensionTargets { * @deprecated Use `customer-account.order-status.cart-line-list.render-after` instead. */ 'Checkout::OrderStatus::CartLines::RenderAfter': RenderExtension< - CustomerAccountOrderStatusApi<'customer-account.order-status.cart-line-item.render-after'>, + OrderStatusApi & + CustomerAccountStandardApi<'Checkout::OrderStatus::CartLines::RenderAfter'>, AnyComponent >; /** * A static extension target that is rendered after a purchase below the customer information on the Order Status page. */ 'customer-account.order-status.customer-information.render-after': RenderExtension< - CustomerAccountOrderStatusApi<'customer-account.order-status.customer-information.render-after'>, + OrderStatusApi & + CustomerAccountStandardApi<'customer-account.order-status.customer-information.render-after'>, AnyComponent >; /** @@ -330,7 +332,8 @@ export interface ExtensionTargets { * @deprecated Use `customer-account.order-status.customer-information.render-after` instead. */ 'Checkout::OrderStatus::CustomerInformation::RenderAfter': RenderExtension< - CustomerAccountOrderStatusApi<'customer-account.order-status.customer-information.render-after'>, + OrderStatusApi & + CustomerAccountStandardApi<'Checkout::OrderStatus::CustomerInformation::RenderAfter'>, AnyComponent >; /** @@ -663,3 +666,36 @@ export type ApiForRenderExtension = export type AllowedComponentsForRenderExtension< Target extends keyof RenderExtensions, > = ExtractedAllowedComponentsFromRenderExtension; + +/** + * The part of the standard API implemented for customer-account targets. Must + * match the types defined in the `surfaces/customer-account` section of this package. + */ +export type CustomerAccountStandardApi = + Pick< + StandardApi, + | 'analytics' + | 'appliedGiftCards' + | 'appMetafields' + | 'attributes' + | 'buyerIdentity' + | 'checkoutSettings' + | 'cost' + | 'discountCodes' + | 'discountAllocations' + | 'extension' + | 'extensionPoint' + | 'i18n' + | 'lines' + | 'localization' + | 'metafields' + | 'note' + | 'query' + | 'sessionToken' + | 'settings' + | 'shippingAddress' + | 'shop' + | 'storage' + | 'ui' + | 'version' + >;