+ );
+ const [state, dispatch] = React.useReducer(reducer, {
+ currentSteps,
+ });
+
+ return (
+
+ {children}
+
+ );
+};
+
+export type { Action, State, ValidTourName };
+export { UnstableGuidedTourContext, unstableUseGuidedTour, reducer };
diff --git a/packages/core/admin/admin/src/components/UnstableGuidedTour/Tours.tsx b/packages/core/admin/admin/src/components/UnstableGuidedTour/Tours.tsx
new file mode 100644
index 0000000000..5e5e640984
--- /dev/null
+++ b/packages/core/admin/admin/src/components/UnstableGuidedTour/Tours.tsx
@@ -0,0 +1,78 @@
+import type { State, Action } from './Context';
+
+/* -------------------------------------------------------------------------------------------------
+ * Tours
+ * -----------------------------------------------------------------------------------------------*/
+
+const tours = {
+ contentManager: createTour('contentManager', [
+ {
+ name: 'TEST',
+ content: () => (
+ <>
+ This is TEST
+ >
+ ),
+ },
+ ]),
+} as const;
+
+type Tours = typeof tours;
+
+/* -------------------------------------------------------------------------------------------------
+ * Tour factory
+ * -----------------------------------------------------------------------------------------------*/
+
+type TourStep = {
+ name: P;
+ content: Content;
+};
+
+type Content = ({
+ state,
+ dispatch,
+}: {
+ state: State;
+ dispatch: React.Dispatch;
+}) => React.ReactNode;
+
+function createTour>>(tourName: string, steps: T) {
+ type Components = {
+ [K in T[number]['name']]: React.ComponentType<{ children: React.ReactNode }>;
+ };
+
+ const tour = steps.reduce((acc, step, index) => {
+ if (step.name in acc) {
+ throw Error(`The tour: ${tourName} with step: ${step.name} has already been registered`);
+ }
+
+ acc[step.name as keyof Components] = ({ children }: { children: React.ReactNode }) => (
+
+
TODO: GuidedTourTooltip goes here and receives these props
+
+ content:
+ {step.content({ state: { currentSteps: { contentManager: 0 } }, dispatch: () => {} })}
+
+
+ children:
+ {children}
+
+
+ tourName:
+ {tourName}
+
+
+ step:
+ {index}
+
+
+ );
+
+ return acc;
+ }, {} as Components);
+
+ return tour;
+}
+
+export type { Content, Tours };
+export { tours };
diff --git a/packages/core/admin/admin/src/components/UnstableGuidedTour/tests/reducer.test.ts b/packages/core/admin/admin/src/components/UnstableGuidedTour/tests/reducer.test.ts
new file mode 100644
index 0000000000..afd350f7cb
--- /dev/null
+++ b/packages/core/admin/admin/src/components/UnstableGuidedTour/tests/reducer.test.ts
@@ -0,0 +1,49 @@
+import { type Action, reducer } from '../Context';
+
+describe('GuidedTour | reducer', () => {
+ describe('next_step', () => {
+ it('should increment the step count for the specified tour', () => {
+ const initialState = {
+ currentSteps: {
+ contentManager: 0,
+ },
+ };
+
+ const action: Action = {
+ type: 'next_step',
+ payload: 'contentManager',
+ };
+
+ const expectedState = {
+ currentSteps: {
+ contentManager: 1,
+ },
+ };
+
+ expect(reducer(initialState, action)).toEqual(expectedState);
+ });
+
+ it('should preserve other tour states when advancing a specific tour', () => {
+ const initialState = {
+ currentSteps: {
+ contentManager: 1,
+ contentTypeBuilder: 2,
+ },
+ };
+
+ const action: Action = {
+ type: 'next_step',
+ payload: 'contentManager',
+ };
+
+ const expectedState = {
+ currentSteps: {
+ contentManager: 2,
+ contentTypeBuilder: 2,
+ },
+ };
+
+ expect(reducer(initialState, action)).toEqual(expectedState);
+ });
+ });
+});
diff --git a/packages/core/admin/admin/src/index.ts b/packages/core/admin/admin/src/index.ts
index 4892b849fa..a02d88121d 100644
--- a/packages/core/admin/admin/src/index.ts
+++ b/packages/core/admin/admin/src/index.ts
@@ -26,6 +26,7 @@ export * from './components/SubNav';
export * from './components/GradientBadge';
export { useGuidedTour } from './components/GuidedTour/Provider';
+export { tours as unstable_tours } from './components/UnstableGuidedTour/Tours';
/**
* Features