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

Copy header link #30411

Open
wants to merge 2 commits into
base: next
Choose a base branch
from
Open

Conversation

scriptcoded
Copy link

@scriptcoded scriptcoded commented Jan 29, 2025

Closes #30407

What I did

  • Broke out createCopyToClipboardFunction to a separate file for clearer availability for reuse.
  • Added tests for createCopyToClipboardFunction. Decided not to fully test the fallback method since DOM mocking doesn't seem to be working and navigator.clipboard is pretty much generally available.
  • Made clicking the 🔗 icon next to a documentation header block also copy the URL. The copied URL is relative to the parent location.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

  1. Start Storybook, for example using as sandbox, e.g. yarn task --task sandbox --start-from auto --template react-vite/default-ts
  2. Open Storybook in your browser
  3. Click on the 🔗 icon of any header on the documentation page.
  4. Notice that the link was copied, and links to the manager view, not the iframe.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=<PR_NUMBER>

Greptile Summary

Extracted clipboard functionality into a reusable utility with modern API support and DOM fallback, improving code organization across Storybook components.

  • Added createCopyToClipboardFunction.ts with Clipboard API and DOM fallback implementation
  • Added unit tests focusing on Clipboard API functionality in createCopyToClipboardFunction.test.ts
  • Updated syntaxhighlighter.tsx to use the new utility instead of inline implementation
  • Added URL copying functionality to header links in mdx.tsx using the new utility
  • Improved code reusability by centralizing clipboard functionality in a single location

💡 (1/5) You can manually trigger the bot by mentioning @greptileai in a comment!

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 file(s) reviewed, 4 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +12 to +15
document.body.appendChild(tmp);
tmp.select();
document.execCommand('copy');
document.body.removeChild(tmp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: potential memory leak if an error occurs between appendChild and removeChild - wrap in try/finally

Suggested change
document.body.appendChild(tmp);
tmp.select();
document.execCommand('copy');
document.body.removeChild(tmp);
document.body.appendChild(tmp);
try {
tmp.select();
document.execCommand('copy');
} finally {
document.body.removeChild(tmp);
}

Comment on lines +13 to +15
global.document = {
createElement: vi.fn(),
} as any as Document;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Mocking document with just createElement is insufficient for testing the fallback copy mechanism. Need to mock body.appendChild, execCommand, body.removeChild, and activeElement.

Suggested change
global.document = {
createElement: vi.fn(),
} as any as Document;
global.document = {
createElement: vi.fn(),
body: {
appendChild: vi.fn(),
removeChild: vi.fn()
},
execCommand: vi.fn(),
activeElement: null
} as any as Document;

Comment on lines +56 to +59
// DOM mocking is not enabled which will cause the function to throw
try {
await copyToClipboard('text');
} catch (e) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Silently catching all errors masks potential issues. Should verify the expected error is thrown when DOM APIs are not available.

Comment on lines +195 to +196
const copyUrl = new URL(window.parent.location.href);
copyUrl.hash = hash;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Using window.parent.location.href could break if Storybook is embedded in a multi-level iframe structure. Consider using a more robust way to get the root URL.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 file(s) reviewed, 2 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +7 to +11
Object.assign(navigator, {
clipboard: {
writeText,
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider using vi.stubGlobal('navigator', {...}) instead of Object.assign for more reliable test setup and teardown

Comment on lines 205 to +206
onClick={(event: SyntheticEvent) => {
copyToClipboard(copyUrl.href);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: copyToClipboard should handle promise rejection from clipboard API

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant