diff --git a/.changeset/forty-wombats-yell.md b/.changeset/forty-wombats-yell.md new file mode 100644 index 0000000000..8708e200e5 --- /dev/null +++ b/.changeset/forty-wombats-yell.md @@ -0,0 +1,5 @@ +--- +'@shopify/ui-extensions': patch +--- + +Add support for Function Settings component for Admin diff --git a/packages/ui-extensions/src/docs/shared/components/FunctionSettings.ts b/packages/ui-extensions/src/docs/shared/components/FunctionSettings.ts new file mode 100644 index 0000000000..8dc7b98c1d --- /dev/null +++ b/packages/ui-extensions/src/docs/shared/components/FunctionSettings.ts @@ -0,0 +1,28 @@ +import type {SharedReferenceEntityTemplateSchema} from '../docs-type'; + +const data: SharedReferenceEntityTemplateSchema = { + name: 'FunctionSettings', + description: + 'FunctionSettings should be used when configuring the metafield configuration of a Shopify Function. It provides a structure for various input fields and controls, such as text fields, checkboxes, and selections. It also integrates with the native Contextual Save Bar to handle form submission and reset actions.', + category: 'Polaris web components', + subCategory: 'Forms', + related: [ + { + type: 'component', + name: 'TextField', + url: '/docs/api/admin-extensions/components/forms/textfield', + }, + { + type: 'component', + name: 'NumberField', + url: '/docs/api/admin-extensions/components/forms/numberfield', + }, + { + type: 'component', + name: 'ChoiceList', + url: '/docs/api/admin-extensions/components/forms/choicelist', + }, + ], +}; + +export default data; diff --git a/packages/ui-extensions/src/surfaces/admin/components.d.ts b/packages/ui-extensions/src/surfaces/admin/components.d.ts index 1f10db6541..fc186fee8a 100644 --- a/packages/ui-extensions/src/surfaces/admin/components.d.ts +++ b/packages/ui-extensions/src/surfaces/admin/components.d.ts @@ -169,7 +169,7 @@ export interface ExtendableEvent extends Event { interface AggregateError$1 extends Error { errors: T[]; } -export interface ArgregatedErrorEvent extends ErrorEvent { +export interface AggregateErrorEvent extends ErrorEvent { error: AggregateError$1; } export type SizeKeyword = @@ -2100,7 +2100,7 @@ interface ColorPickerProps$1 extends GlobalProps, InputProps { * For RGB and RGBA, both the legacy syntax (comma-separated) and modern syntax (space-separate) are supported. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb * - * If the value is invalid, the component will select rgb(0, 0, 0). + * If the value is invalid, the component will return an empty string ''. * * Note that the `onChange` handler will emit the value in hex. */ @@ -2407,12 +2407,19 @@ interface DatePickerProps$1 extends GlobalProps, InputProps, FocusEventProps { */ value?: string; /** - * Callback when any date is selected. Will fire before `onChange`. + * Callback when any date is selected. + * + * - If `type="single"`, fires when a date is selected and happens before `onChange`. + * - If `type="multiple"`, fires when a date is selected before `onChange`. + * - If `type="range"`, fires when a first date is selected (with the partial value formatted as `YYYY-MM-DD--`), and when the last date is selected before `onChange`. */ onInput?: (event: Event) => void; /** - * Callback when the `value` is changed. For `type="single"` and `type="multiple"`, this is the same as `onInput`. - * For `type="range"`, this is only called when the range is completed by selecting the end date of the range. + * Callback when the value is committed. + * + * - If `type="single"`, fires when a date is selected after `onInput`. + * - If `type="multiple"`, fires when a date is selected after `onInput`. + * - If `type="range"`, fires when a range is completed by selecting the end date after `onInput`. */ onChange?: (event: Event) => void; } @@ -2432,6 +2439,16 @@ interface DateFieldProps$1 | 'onViewChange' >, AutocompleteProps { + /** + * Callback when the user makes any changes in the field. + * Also triggered when a date is selected using the date picker popup before `onChange`. + */ + onInput?: (event: Event) => void; + /** + * Callback when the user has **finished editing** a field, e.g. once they have blurred the field. + * Also triggered when a date is selected using the date picker popup after `onInput`. + */ + onChange?: (event: Event) => void; /** * Callback when the field has an invalid date. * This callback will be called, if the date typed is invalid or disabled. @@ -2562,7 +2579,7 @@ interface FunctionSettingsProps$1 extends GlobalProps, FormProps$1 { * highlight the fields that caused the errors, and display the error messages * to the user. */ - onError?: (event: ArgregatedErrorEvent) => void; + onError?: (event: AggregateErrorEvent) => void; } export interface FunctionSettingsError extends Error { /** @@ -6205,7 +6222,7 @@ export interface ModalJSXProps export type RequiredMoneyFieldProps = Required; export interface MoneyFieldProps extends Omit, - Pick { + Pick { value: Required['value']; } @@ -6215,7 +6232,8 @@ declare class MoneyField { accessor max: MoneyFieldProps['max']; accessor min: MoneyFieldProps['min']; - accessor step: MoneyFieldProps['step']; + get value(): string; + set value(value: string); constructor(); } declare global { @@ -6255,6 +6273,8 @@ declare class NumberField extends PreactFieldElement implements NumberFieldProps { + get value(): string; + set value(value: string); accessor inputMode: NumberFieldProps['inputMode']; accessor step: NumberFieldProps['step']; accessor max: NumberFieldProps['max']; diff --git a/packages/ui-extensions/src/surfaces/admin/components/FormExtensionComponents.ts b/packages/ui-extensions/src/surfaces/admin/components/FormExtensionComponents.ts new file mode 100644 index 0000000000..6850eca740 --- /dev/null +++ b/packages/ui-extensions/src/surfaces/admin/components/FormExtensionComponents.ts @@ -0,0 +1,5 @@ +import {StandardComponents} from './StandardComponents'; + +export type FormExtensionComponents = StandardComponents | 'Form'; + +export default FormExtensionComponents; diff --git a/packages/ui-extensions/src/surfaces/admin/components/FunctionSettings/FunctionSettings.ext.doc.ts b/packages/ui-extensions/src/surfaces/admin/components/FunctionSettings/FunctionSettings.ext.doc.ts new file mode 100644 index 0000000000..568200b622 --- /dev/null +++ b/packages/ui-extensions/src/surfaces/admin/components/FunctionSettings/FunctionSettings.ext.doc.ts @@ -0,0 +1,31 @@ +import {ReferenceEntityTemplateSchema} from '@shopify/generate-docs'; +import shared from '../../../../docs/shared/components/FunctionSettings'; + +const data: ReferenceEntityTemplateSchema = { + ...shared, + category: 'Polaris web components', + thumbnail: '/assets/templated-apis-screenshots/admin/components/form.png', + isVisualComponent: true, + definitions: [ + { + title: 'Events', + description: + 'Learn more about [registering events](/docs/api/app-home/using-polaris-components#event-handling).', + type: 'FormEvents', + }, + ], + defaultExample: { + codeblock: { + title: '', + tabs: [ + { + title: 'JSX', + code: './examples/default.tsx', + language: 'jsx', + }, + ], + }, + }, +}; + +export default data; diff --git a/packages/ui-extensions/src/surfaces/admin/components/FunctionSettings/examples/default.tsx b/packages/ui-extensions/src/surfaces/admin/components/FunctionSettings/examples/default.tsx new file mode 100644 index 0000000000..a8ab57db74 --- /dev/null +++ b/packages/ui-extensions/src/surfaces/admin/components/FunctionSettings/examples/default.tsx @@ -0,0 +1,38 @@ +import {render} from 'preact'; +import {useState} from 'preact/hooks'; + +export default async () => { + render(, document.body); +}; + +function Extension() { + const [percentage, setPercentage] = useState( + shopify.data.metafields[0].value, + ); + + async function applyExtensionMetafieldChange() { + await shopify.applyMetafieldChange({ + type: 'updateMetafield', + namespace: '$app:discounts-percentage', + key: 'function-configuration', + value: percentage, + valueType: 'integer', + }); + } + + return ( + e.waitUntil(applyExtensionMetafieldChange())} + onReset={resetForm} + > + setPercentage(event.currentTarget.value)} + /> + + ); +} diff --git a/packages/ui-extensions/src/surfaces/admin/components/FunctionSettingsComponents.ts b/packages/ui-extensions/src/surfaces/admin/components/FunctionSettingsComponents.ts new file mode 100644 index 0000000000..835ff43e42 --- /dev/null +++ b/packages/ui-extensions/src/surfaces/admin/components/FunctionSettingsComponents.ts @@ -0,0 +1,7 @@ +import {FormExtensionComponents} from './FormExtensionComponents'; + +export type FunctionSettingsComponents = + | FormExtensionComponents + | 'FunctionSettings'; + +export default FunctionSettingsComponents; diff --git a/packages/ui-extensions/src/surfaces/admin/components/MoneyField.d.ts b/packages/ui-extensions/src/surfaces/admin/components/MoneyField.d.ts index 847eea3d8a..8db45288d7 100644 --- a/packages/ui-extensions/src/surfaces/admin/components/MoneyField.d.ts +++ b/packages/ui-extensions/src/surfaces/admin/components/MoneyField.d.ts @@ -199,7 +199,7 @@ declare class PreactFieldElement export type RequiredMoneyFieldProps = Required; export interface MoneyFieldProps extends Omit, - Pick { + Pick { value: Required['value']; } @@ -209,7 +209,8 @@ declare class MoneyField { accessor max: MoneyFieldProps['max']; accessor min: MoneyFieldProps['min']; - accessor step: MoneyFieldProps['step']; + get value(): string; + set value(value: string); constructor(); } declare global { diff --git a/packages/ui-extensions/src/surfaces/admin/components/NumberField.d.ts b/packages/ui-extensions/src/surfaces/admin/components/NumberField.d.ts index e986030759..2b0f4501cd 100644 --- a/packages/ui-extensions/src/surfaces/admin/components/NumberField.d.ts +++ b/packages/ui-extensions/src/surfaces/admin/components/NumberField.d.ts @@ -214,6 +214,8 @@ declare class NumberField extends PreactFieldElement implements NumberFieldProps { + get value(): string; + set value(value: string); accessor inputMode: NumberFieldProps['inputMode']; accessor step: NumberFieldProps['step']; accessor max: NumberFieldProps['max']; diff --git a/packages/ui-extensions/src/surfaces/admin/components/shared.d.ts b/packages/ui-extensions/src/surfaces/admin/components/shared.d.ts index 1a42bb3a85..ca45729096 100644 --- a/packages/ui-extensions/src/surfaces/admin/components/shared.d.ts +++ b/packages/ui-extensions/src/surfaces/admin/components/shared.d.ts @@ -167,7 +167,7 @@ export interface ExtendableEvent extends Event { interface AggregateError$1 extends Error { errors: T[]; } -export interface ArgregatedErrorEvent extends ErrorEvent { +export interface AggregateErrorEvent extends ErrorEvent { error: AggregateError$1; } export type SizeKeyword = @@ -2098,7 +2098,7 @@ interface ColorPickerProps$1 extends GlobalProps, InputProps { * For RGB and RGBA, both the legacy syntax (comma-separated) and modern syntax (space-separate) are supported. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb * - * If the value is invalid, the component will select rgb(0, 0, 0). + * If the value is invalid, the component will return an empty string ''. * * Note that the `onChange` handler will emit the value in hex. */ @@ -2405,12 +2405,19 @@ interface DatePickerProps$1 extends GlobalProps, InputProps, FocusEventProps { */ value?: string; /** - * Callback when any date is selected. Will fire before `onChange`. + * Callback when any date is selected. + * + * - If `type="single"`, fires when a date is selected and happens before `onChange`. + * - If `type="multiple"`, fires when a date is selected before `onChange`. + * - If `type="range"`, fires when a first date is selected (with the partial value formatted as `YYYY-MM-DD--`), and when the last date is selected before `onChange`. */ onInput?: (event: Event) => void; /** - * Callback when the `value` is changed. For `type="single"` and `type="multiple"`, this is the same as `onInput`. - * For `type="range"`, this is only called when the range is completed by selecting the end date of the range. + * Callback when the value is committed. + * + * - If `type="single"`, fires when a date is selected after `onInput`. + * - If `type="multiple"`, fires when a date is selected after `onInput`. + * - If `type="range"`, fires when a range is completed by selecting the end date after `onInput`. */ onChange?: (event: Event) => void; } @@ -2430,6 +2437,16 @@ interface DateFieldProps$1 | 'onViewChange' >, AutocompleteProps { + /** + * Callback when the user makes any changes in the field. + * Also triggered when a date is selected using the date picker popup before `onChange`. + */ + onInput?: (event: Event) => void; + /** + * Callback when the user has **finished editing** a field, e.g. once they have blurred the field. + * Also triggered when a date is selected using the date picker popup after `onInput`. + */ + onChange?: (event: Event) => void; /** * Callback when the field has an invalid date. * This callback will be called, if the date typed is invalid or disabled. @@ -2560,7 +2577,7 @@ interface FunctionSettingsProps$1 extends GlobalProps, FormProps$1 { * highlight the fields that caused the errors, and display the error messages * to the user. */ - onError?: (event: ArgregatedErrorEvent) => void; + onError?: (event: AggregateErrorEvent) => void; } export interface FunctionSettingsError extends Error { /** diff --git a/packages/ui-extensions/src/surfaces/admin/extension-targets.ts b/packages/ui-extensions/src/surfaces/admin/extension-targets.ts index af82a7df6b..05f3a93d81 100644 --- a/packages/ui-extensions/src/surfaces/admin/extension-targets.ts +++ b/packages/ui-extensions/src/surfaces/admin/extension-targets.ts @@ -17,10 +17,10 @@ import { ShouldRenderApi, ShouldRenderOutput, } from './api/should-render/should-render'; -import type {StandardComponents} from './components/StandardComponents'; import type {BlockExtensionComponents} from './components/BlockExtensionComponents'; import type {ActionExtensionComponents} from './components/ActionExtensionComponents'; import type {PrintActionExtensionComponents} from './components/PrintActionExtensionComponents'; +import type {FunctionSettingsComponents} from './components/FunctionSettingsComponents'; export interface ExtensionTargets { /** @@ -59,7 +59,7 @@ export interface ExtensionTargets { */ 'admin.discount-details.function-settings.render': RenderExtension< DiscountFunctionSettingsApi<'admin.discount-details.function-settings.render'>, - BlockExtensionComponents + FunctionSettingsComponents >; /** @@ -487,11 +487,11 @@ export interface ExtensionTargets { */ 'admin.settings.internal-order-routing-rule.render': RenderExtension< OrderRoutingRuleApi<'admin.settings.internal-order-routing-rule.render'>, - StandardComponents + FunctionSettingsComponents >; 'admin.settings.order-routing-rule.render': RenderExtension< OrderRoutingRuleApi<'admin.settings.order-routing-rule.render'>, - StandardComponents + FunctionSettingsComponents >; /** @@ -501,7 +501,7 @@ export interface ExtensionTargets { */ 'admin.settings.validation.render': RenderExtension< ValidationSettingsApi<'admin.settings.validation.render'>, - StandardComponents + FunctionSettingsComponents >; // Admin action shouldRender targets