@shopify/app-bridge-core
Version:
**[Join our team and work on libraries like this one.](https://www.shopify.ca/careers)**
293 lines (290 loc) • 9.2 kB
JavaScript
import { getSingleButton } from '../buttonHelper.js';
import { actionWrapper, updateActionFromPayload, getMergedProps } from '../helper.js';
import { ActionSetWithChildren } from '../ActionSet.js';
import { Group, ComponentType } from '../types.js';
import { clickButton } from '../Button/index.js';
var Action;
(function (Action) {
Action["OPEN"] = "APP::MODAL::OPEN";
Action["CLOSE"] = "APP::MODAL::CLOSE";
Action["UPDATE"] = "APP::MODAL::UPDATE";
Action["UPDATE_CONTENT"] = "APP::MODAL::CONTENT::UPDATE";
Action["FOOTER_BUTTON_CLICK"] = "APP::MODAL::FOOTER::BUTTON::CLICK";
Action["FOOTER_BUTTON_UPDATE"] = "APP::MODAL::FOOTER::BUTTON::UPDATE";
Action["UPDATE_SIZE"] = "APP::MODAL::UPDATE_SIZE";
Action["DATA"] = "APP::MODAL::DATA";
})(Action || (Action = {}));
/**
* Options available to the Modal `size` param
* @public
*/
var Size;
(function (Size) {
/** Small modal size */
Size["Small"] = "small";
/** Medium modal size */
Size["Medium"] = "medium";
/** Large modal size (wider than medium) */
Size["Large"] = "large";
/** @deprecated as of 1.6.5 */
Size["Full"] = "full";
/**
* @deprecated as of 1.12.x
* @remarks
* This option has been removed in favour of the `setUpModalAutoSizing` utility.
*/
Size["Auto"] = "auto";
})(Size || (Size = {}));
const FOOTER_BUTTON_PROPS = {
group: Group.Modal,
subgroups: ['Footer'],
type: ComponentType.Button,
};
function openModal(modalPayload) {
return actionWrapper({
group: Group.Modal,
payload: modalPayload,
type: Action.OPEN,
});
}
function closeModal(modalClosePayload) {
return actionWrapper({
group: Group.Modal,
payload: modalClosePayload,
type: Action.CLOSE,
});
}
/**
* Action creator for modal update size action
* @internal
*/
function updateModalSize(updateSizePayload) {
return actionWrapper({
group: Group.Modal,
payload: updateSizePayload,
type: Action.UPDATE_SIZE,
});
}
function clickFooterButton(id, payload) {
const component = { id, ...FOOTER_BUTTON_PROPS };
return clickButton(Group.Modal, component, payload);
}
function update(payload) {
return actionWrapper({
payload,
group: Group.Modal,
type: Action.UPDATE,
});
}
function data(payload) {
return actionWrapper({
payload,
group: Group.Modal,
type: Action.DATA,
});
}
function isIframeModal(options) {
return (typeof options.url === 'string' ||
typeof options.path === 'string');
}
function isMessageModal(options) {
return typeof options.message === 'string';
}
class Modal extends ActionSetWithChildren {
title;
size = Size.Small;
footerPrimary;
footerPrimaryOptions;
footerSecondary;
footerSecondaryOptions;
get footer() {
if (!this.footerPrimary && !this.footerSecondary) {
return undefined;
}
return {
buttons: {
primary: this.footerPrimary,
secondary: this.footerSecondary,
},
};
}
get footerOptions() {
if (!this.footerPrimaryOptions && !this.footerSecondaryOptions) {
return undefined;
}
return {
buttons: {
primary: this.footerPrimaryOptions,
secondary: this.footerSecondaryOptions,
},
};
}
close() {
this.app.dispatch(closeModal({ id: this.id }));
}
setFooterPrimaryButton(newOptions, updateCb) {
const { subgroups } = FOOTER_BUTTON_PROPS;
this.footerPrimaryOptions = this.getChildButton(newOptions, this.footerPrimaryOptions);
this.footerPrimary = this.footerPrimaryOptions
? getSingleButton(this, this.footerPrimaryOptions, subgroups, (newPayload) => {
this.updatePrimaryFooterButton(newPayload, updateCb);
})
: undefined;
}
setFooterSecondaryButtons(newOptions, updateCb) {
const { subgroups } = FOOTER_BUTTON_PROPS;
const newButtons = newOptions || [];
const currentOptions = (this.footerOptions && this.footerOptions.buttons.secondary) || [];
this.footerSecondaryOptions = this.getUpdatedChildActions(newButtons, currentOptions);
this.footerSecondary = this.footerSecondaryOptions
? this.footerSecondaryOptions.map((action) => getSingleButton(this, action, subgroups, (newPayload) => {
this.updateSecondaryFooterButton(newPayload, updateCb);
}))
: undefined;
}
getChildButton(newAction, currentAction) {
const newButtons = newAction ? [newAction] : [];
const currentButtons = currentAction ? [currentAction] : [];
const updatedButton = this.getUpdatedChildActions(newButtons, currentButtons);
return updatedButton ? updatedButton[0] : undefined;
}
updatePrimaryFooterButton(newPayload, updateCb) {
if (!this.footer || !this.footer.buttons.primary) {
return;
}
if (updateActionFromPayload(this.footer.buttons.primary, newPayload)) {
updateCb();
}
}
updateSecondaryFooterButton(newPayload, updateCb) {
if (!this.footer || !this.footer.buttons || !this.footer.buttons.secondary) {
return;
}
let updated;
for (const action of this.footer.buttons.secondary) {
updated = updateActionFromPayload(action, newPayload);
if (updated) {
break;
}
}
if (updated) {
updateCb();
}
}
}
class ModalMessage extends Modal {
message;
constructor(app, options) {
super(app, Group.Modal, Group.Modal);
this.set(options, false);
}
get payload() {
return {
...this.options,
footer: this.footer,
id: this.id,
};
}
get options() {
return {
footer: this.footerOptions,
message: this.message,
size: this.size,
title: this.title,
};
}
set(options, shouldUpdate = true) {
const mergedOptions = getMergedProps(this.options, options);
const { title, footer, message, size } = mergedOptions;
this.title = title;
this.message = message;
this.size = size;
this.setFooterPrimaryButton(footer ? footer.buttons.primary : undefined, () => {
this.dispatch(Action.UPDATE);
});
this.setFooterSecondaryButtons(footer ? footer.buttons.secondary : undefined, () => {
this.dispatch(Action.UPDATE);
});
if (shouldUpdate) {
this.dispatch(Action.UPDATE);
}
return this;
}
dispatch(action) {
switch (action) {
case Action.OPEN:
this.app.dispatch(openModal(this.payload));
break;
case Action.CLOSE:
this.close();
break;
case Action.UPDATE:
this.app.dispatch(update(this.payload));
break;
}
return this;
}
}
class ModalIframe extends Modal {
url;
path;
loading;
constructor(app, options) {
super(app, Group.Modal, Group.Modal);
this.set(options, false);
}
get payload() {
return {
...this.options,
footer: this.footer,
id: this.id,
};
}
get options() {
return {
footer: this.footerOptions,
path: this.path,
size: this.size,
title: this.title,
url: this.url,
loading: this.loading,
};
}
set(options, shouldUpdate = true) {
const mergedOptions = getMergedProps(this.options, options);
const { title, footer, path, url, size, loading } = mergedOptions;
this.title = title;
this.url = url;
this.path = path;
this.size = size;
this.loading = loading;
this.setFooterPrimaryButton(footer ? footer.buttons.primary : undefined, () => {
this.dispatch(Action.UPDATE);
});
this.setFooterSecondaryButtons(footer ? footer.buttons.secondary : undefined, () => {
this.dispatch(Action.UPDATE);
});
if (shouldUpdate) {
this.dispatch(Action.UPDATE);
}
return this;
}
dispatch(action, payload) {
switch (action) {
case Action.OPEN:
this.app.dispatch(openModal(this.payload));
break;
case Action.CLOSE:
this.close();
break;
case Action.UPDATE:
this.app.dispatch(update(this.payload));
break;
case Action.DATA:
this.app.dispatch(data(payload || {}));
break;
}
return this;
}
}
export { Action, Modal, ModalIframe, ModalMessage, Size, clickFooterButton, closeModal, data, isIframeModal, isMessageModal, openModal, update, updateModalSize };