@launchmystore/app-bridge-react
v1.0.4
Published
React hooks and components for the LaunchMyStore App Bridge SDK — useAppBridge, useToast, useModal, useResourcePicker, useSessionToken, useTitleBar and more.
Maintainers
Readme
@launchmystore/app-bridge-react
React hooks and components for the LaunchMyStore
App Bridge. Provides a seamless React integration for building LMS apps —
wraps @launchmystore/app-bridge
in idiomatic hooks (useToast, useModal, useResourcePicker,
useSessionToken, …).
About LaunchMyStore
LaunchMyStore is a multi-tenant e-commerce
platform that renders Shopify-compatible Liquid themes and runs a full
app ecosystem on top of them. Merchants get a branded storefront on a
custom domain; developers ship apps that extend the storefront,
checkout, and admin via the same Apps row, OAuth scopes, webhooks,
and declarative function manifests. This package is the React layer
between your app's iframe and the LMS admin shell.
Learn more: launchmystore.io · Docs: docs.launchmystore.io
Installation
npm install @launchmystore/app-bridge-react @launchmystore/app-bridgeQuick Start
Wrap your app with AppBridgeProvider:
import { AppBridgeProvider } from '@launchmystore/app-bridge-react';
function App() {
return (
<AppBridgeProvider config={{ apiKey: 'your-api-key', host: window.__LMS_HOST__ }}>
<MyApp />
</AppBridgeProvider>
);
}Then use hooks in your components:
import { useToast, useModal, useSessionToken } from '@launchmystore/app-bridge-react';
function MyComponent() {
const toast = useToast();
const { getToken } = useSessionToken();
const handleSave = async () => {
const token = await getToken();
await fetch('/api/v1/products.json', {
headers: { Authorization: `Bearer ${token}` },
});
toast.success('Saved!');
};
return <button onClick={handleSave}>Save</button>;
}Available Hooks
Core
useAppBridge()- Get the App Bridge instance directly
Toast Notifications
useToast()- Show toast notificationstoast.success(message)- Success toasttoast.error(message)- Error toasttoast.warning(message)- Warning toasttoast.info(message)- Info toast
Modals
useModal(options)- Open modals with primary/secondary actionsuseConfirmationModal()- Promise-based confirmation dialogs
Resource Pickers
useResourcePicker(options)- Generic resource pickeruseProductPicker(options)- Product picker shorthanduseCollectionPicker(options)- Collection picker shorthanduseCustomerPicker(options)- Customer picker shorthanduseFilePicker(options)- File picker shorthand
Save Bar
useContextualSaveBar(options)- Show/hide contextual save baruseDirtyState(options)- Combine dirty state with save bar
Navigation
useTitleBar(options)- Configure the admin title baruseNavigationMenu(options)- Configure the app navigation menuuseRedirect()- Navigate within the admin
Session & API
useSessionToken()- Get session tokens for API callsuseAuthenticatedFetch()- Fetch wrapper with automatic authuseAppQuery(url)- Data fetching hookuseAppMutation(url)- Mutation hook
Loading
useLoading()- Control the global loading indicator
Low-Level
useAppSubscription(action, callback)- Subscribe to App Bridge eventsuseAppDispatch()- Dispatch App Bridge actionsuseAppDispatchAndWait()- Dispatch and wait for response
Examples
Save Bar with Form
import { useContextualSaveBar } from '@launchmystore/app-bridge-react';
function SettingsForm() {
const [data, setData] = useState(initialData);
const [hasChanges, setHasChanges] = useState(false);
const saveBar = useContextualSaveBar({
message: 'Unsaved changes',
onSave: async () => {
saveBar.setSaveLoading(true);
await saveSettings(data);
saveBar.setSaveLoading(false);
setHasChanges(false);
saveBar.hide();
},
onDiscard: () => {
setData(initialData);
setHasChanges(false);
saveBar.hide();
},
});
useEffect(() => {
hasChanges ? saveBar.show() : saveBar.hide();
}, [hasChanges]);
return (
<input
value={data.name}
onChange={(e) => {
setData({ ...data, name: e.target.value });
setHasChanges(true);
}}
/>
);
}Resource Picker
import { useProductPicker } from '@launchmystore/app-bridge-react';
function ProductSelector() {
const [products, setProducts] = useState([]);
const picker = useProductPicker({
multiple: true,
onSelect: (selection) => setProducts(selection),
});
return (
<div>
<button onClick={picker.open}>Select Products</button>
<ul>
{products.map((p) => (
<li key={p.id}>{p.title}</li>
))}
</ul>
</div>
);
}Confirmation Modal
import { useConfirmationModal } from '@launchmystore/app-bridge-react';
function DeleteButton({ onDelete }) {
const confirm = useConfirmationModal();
const handleDelete = async () => {
const confirmed = await confirm({
title: 'Delete Item?',
message: 'This action cannot be undone.',
confirmLabel: 'Delete',
cancelLabel: 'Cancel',
});
if (confirmed) {
await onDelete();
}
};
return <button onClick={handleDelete}>Delete</button>;
}Data Fetching
import { useAppQuery, useAppMutation } from '@launchmystore/app-bridge-react';
function ProductList() {
const { data, loading, refetch } = useAppQuery('/api/v1/products.json');
const { mutate } = useAppMutation('/api/v1/products.json');
const createProduct = async () => {
await mutate({
method: 'POST',
body: { product: { title: 'New Product' } },
});
refetch();
};
if (loading) return <div>Loading...</div>;
return (
<div>
<button onClick={createProduct}>Create Product</button>
<ul>
{data?.products.map((p) => (
<li key={p.id}>{p.title}</li>
))}
</ul>
</div>
);
}TypeScript
All hooks are fully typed. Import types as needed:
import type {
UseToastReturn,
UseModalOptions,
ResourceType,
} from '@launchmystore/app-bridge-react';License
MIT
