Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix feedback button not loading #20

Merged
merged 2 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const preview = {
parameters: {
initialGlobals: {
marker: {
project: '60f162459a86003bf9d741b3',
}
}
},
};

export default preview;
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ export default {
}
```

Then create a file called `preview.js` in the same folder and add your [Marker project ID](https://marker.io/blog/integrate-web-app-browser-sdk) as a [parameter](https://storybook.js.org/docs/react/writing-stories/parameters).
Then create a file called `preview.js` in the same folder and add your [Marker project ID](https://marker.io/blog/integrate-web-app-browser-sdk) in the [initalGlobals](https://storybook.js.org/docs/essentials/toolbars-and-globals).

```js
export default {
parameters: {
initialGlobals: {
marker: {
project: 'abcd1234567890', // Your unique project ID
}
}
},
},
}
```

Expand All @@ -39,11 +39,13 @@ Only `project` is required, the [rest of the marker widget params](https://githu
Additionally, the `mode` option of [the browser SDK `capture` method](https://github.com/marker-io/browser-sdk?tab=readme-ov-file#widgetcapturemode) can be added to this config:

```js
export const parameters = {
marker: {
project: 'abcd1234567890', // <- Your unique project ID
mode: 'fullscreen', // fullscreen | advanced
}
export default {
initialGlobals: {
marker: {
project: 'abcd1234567890', // <- Your unique project ID
mode: 'fullscreen', // fullscreen | advanced
},
},
}
```

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
],
"scripts": {
"prepare": "tsup",
"storybook": "storybook dev -p 6006",
"storybook": "npm run prepare && storybook dev -p 6006",
"build-storybook": "storybook build",
"release": "semantic-release"
},
Expand Down
35 changes: 33 additions & 2 deletions src/FeedbackButton.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import markerSDK from '@marker.io/browser';
import { IconButton } from '@storybook/components';
import { CommentIcon } from '@storybook/icons';
import { useChannel } from '@storybook/manager-api';
import { useChannel, useGlobals } from '@storybook/manager-api';
import { styled } from '@storybook/theming';
import React, { useCallback, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';

import { EVENTS, TOOL_ID } from './constants';
import { hideDefaultMarkerButton } from './hideDefaultMarkerButton';

const IconButtonWithLabel = styled(IconButton)(() => ({
display: 'inline-flex',
Expand All @@ -27,17 +29,46 @@ const IconButtonLabel = styled.div(({ theme }) => ({

export default function FeedbackButton() {
const [markerLoaded, setMarkerLoaded] = useState(false);
const [globals] = useGlobals();
const { project, mode, ...config } = globals.marker ?? {};

const emit = useChannel({
// The loaded event will fire when the marker decorator loads
[EVENTS.LOADED]: () => {
if (window.Marker) {
// Unload the manager version of marker
window.Marker.unload();
}

setMarkerLoaded(true);
},
[EVENTS.CAPTURE]: () => {
window.Marker?.capture(mode)?.then(() => {
hideDefaultMarkerButton(); // This sometimes reappears after capturing
});
},
});

const handleSendFeedback = useCallback(() => {
emit(EVENTS.CAPTURE);
}, [emit]);

// If the decorator has not loaded within 3 seconds fallback to loading it on the manager.
// Screenshots may appear unstyled, but it's better than no feedback button displaying.
// This might happen on mdx docs stories where no decorators aren't called.
useEffect(() => {
clearTimeout(window.markerTimer);

if (project && !markerLoaded && !window.Marker) {
window.markerTimer = setTimeout(() => {
markerSDK.loadWidget({ project, ...config }).then(() => {
hideDefaultMarkerButton();
setMarkerLoaded(true);
});
}, 3000);
}
}, [project, markerLoaded]);

return markerLoaded ? (
<IconButtonWithLabel key={TOOL_ID} onClick={handleSendFeedback}>
<CommentIcon />
Expand Down
6 changes: 6 additions & 0 deletions src/hideDefaultMarkerButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const hideDefaultMarkerButton = () => {
const markerBtns = [
...document.querySelectorAll('.marker-app #feedback-button'),
];
markerBtns.forEach((markerBtn) => (markerBtn.style.display = 'none'));
};
30 changes: 10 additions & 20 deletions src/withMarker.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,30 @@
/* eslint-disable react-hooks/rules-of-hooks */
import markerSDK from '@marker.io/browser';
import { useChannel, useParameter } from '@storybook/preview-api';
import { useChannel, useGlobals } from '@storybook/preview-api';

import { EVENTS } from './constants';

const hideDefaultMarkerButton = () => {
const markerBtns = [
...document.querySelectorAll('.marker-app #feedback-button'),
];
markerBtns.forEach((markerBtn) => (markerBtn.style.display = 'none'));
};
import { hideDefaultMarkerButton } from './hideDefaultMarkerButton';

export const withMarker = (storyFn) => {
const { destination, project, mode, ...config } = useParameter('marker', {});
const [globals] = useGlobals();
const { project, mode, ...config } = globals.marker ?? {};

const emit = useChannel({
[EVENTS.CAPTURE]: () => {
window.Marker?.capture(mode).then(() => {
window.Marker?.capture(mode)?.then(() => {
hideDefaultMarkerButton(); // This sometimes reappears after capturing
});
},
});

if ((!destination && !project) || window.Marker) {
if (!project || window.Marker) {
return storyFn();
}

markerSDK
.loadWidget({
project: project ?? destination,
...config,
})
.then(() => {
hideDefaultMarkerButton();
emit(EVENTS.LOADED);
});
markerSDK.loadWidget({ project, ...config }).then(() => {
hideDefaultMarkerButton();
emit(EVENTS.LOADED);
});

return storyFn();
};
Loading