-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
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
feat(theme-classic): toggle code wrap button #7036
Conversation
✅ [V2]
To edit notification comments on pull requests, go to your Netlify site settings. |
⚡️ Lighthouse report for the changes in this PR:
Lighthouse ran on https://deploy-preview-7036--docusaurus-2.netlify.app/ |
Size Change: +194 B (0%) Total Size: 802 kB
ℹ️ View Unchanged
|
I'm not sure about the value of this feature either 🤷♂️ Do we have examples of existing sites with this feature? There's a Canny request for this: https://docusaurus.canny.io/feature-requests/p/toggle-line-wrap-in-code-blocks And I did vote for it long ago, but it doesn't seem to have any significant traction, and I also don't see huge value in having it OOTB |
This feature is more likely to be useful for mobiles users, because on small screens code blocks will usually be scrollable. So let's wait for feedback from @slorber then. |
I'd like to see this added as we include a lot of WordPress hook examples and so, wrapping the code would make this easier for a non-technical users and as @lex111 mentioned, would help on mobile devices. :) |
I see. The mobile use-case makes a lot of sense. |
packages/docusaurus-theme-classic/src/theme/CodeBlock/WordWrapButton/styles.module.css
Show resolved
Hide resolved
packages/docusaurus-theme-classic/src/theme/CodeBlock/WordWrapButton/index.tsx
Outdated
Show resolved
Hide resolved
packages/docusaurus-theme-classic/src/theme/CodeBlock/WordWrapButton/index.tsx
Outdated
Show resolved
Hide resolved
packages/docusaurus-theme-classic/src/theme/CodeBlock/WordWrapButton/index.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks interesting, willing to add this feature 👍
Some implementation details worth reworking
packages/docusaurus-theme-translations/locales/fr/theme-common.json
Outdated
Show resolved
Hide resolved
.codeButton { | ||
--docusaurus-code-button-size: 2rem; | ||
position: absolute; | ||
right: calc(var(--ifm-pre-padding) / 2); | ||
top: calc(var(--ifm-pre-padding) / 2); | ||
width: var(--docusaurus-code-button-size); | ||
height: var(--docusaurus-code-button-size); | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
background: inherit; | ||
border: 1px solid var(--ifm-color-emphasis-300); | ||
border-radius: var(--ifm-global-radius); | ||
transition: opacity 200ms ease-in-out; | ||
opacity: 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should try to separate this CSS in 2 parts:
- the "inner" of a code button (can be extracted and moved to a separate CodeButton component)
- the rules that are responsible to position the button inside the parent component
setIsEnabled((value) => !value); | ||
|
||
const codeElement = codeBlockRef.current!.querySelector('code'); | ||
codeElement?.classList.toggle(styles.codeWithWordWrap!); | ||
}, [codeBlockRef]); | ||
const updateCodeIsScrollable = useCallback(() => { | ||
const {scrollWidth, clientWidth} = codeBlockRef.current!; | ||
setIsCodeScrollable(scrollWidth > clientWidth); | ||
}, [codeBlockRef]); | ||
const title = translate({ | ||
id: 'theme.CodeBlock.wordWrapToggle', | ||
message: 'Toggle word wrap', | ||
description: | ||
'The title attribute for toggle word wrapping button of code block lines', | ||
}); | ||
|
||
useEffect(() => { | ||
updateCodeIsScrollable(); | ||
|
||
window.addEventListener('resize', updateCodeIsScrollable); | ||
|
||
return () => { | ||
window.removeEventListener('resize', updateCodeIsScrollable); | ||
}; | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
|
||
if (!isCodeScrollable) { | ||
return null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all this code is quite technical and shouldn't be there
The button should preferably always render a button, and users swizzling it should be able to change its display/icon without having to manage this technical code.
I don't think the button should either handle a ref of parent code block. It's the parent that should decide if the toggle button should be displayed, not the button itself.
I'd suggest moving this complexity to a custom hook in theme-common, and using the hook inside <CodeBlock>
instead <WordWrapButton>
<WordWrapButton | ||
className={styles.codeButton} | ||
codeBlockRef={codeBlockRef} | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I have in mind:
<WordWrapButton | |
className={styles.codeButton} | |
codeBlockRef={codeBlockRef} | |
/> | |
{(wordWrap.enabled || wordWrap.codeScrollable) && ( | |
<WordWrapButton | |
className={styles.codeButton} | |
onClick={() => wordWrap.toggle()} | |
/> | |
)} |
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
|
||
if (!isCodeScrollable) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*/ | ||
|
||
.wordWrapButton { | ||
right: calc( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like the button to not decide where it will be rendered: that's the responsibility of the parent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like it either, I was thinking of grouping these buttons into one new div container, but it's not that easy because we would have to somehow get background of the current Prism color theme (need it for button background, not its container). Therefore inherit
value won't work here, so maybe we dynamically set two new CSS vars, like as --prism-background
and --prism-color
? Will that be acceptable solution?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this works? usePrismTheme().plain.backgroundColor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, in the case of button container, we need to set the style
attribute for each button inside to set the proper background. I think it's kind of redundant overhead, which we can avoid by dynamically creating two CSS vars that also can re-use in other places where the style
attribute is currently used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lex111 FWIW, Prism also inlines their styles, so it won't be too harmful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wouldn't want to overuse it, especially if there's a pretty appropriate alternative solution. Beside that, using inline styles would require creating one specific prop style
for each button component, which can also be avoided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this rule still necessary?
Looks to me it's not useful anymore => removing it and things keep working?
ebb2d9e
to
97e6922
Compare
….json Co-authored-by: Sébastien Lorber <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ready for re-review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Fixed a minor edge case in 5a14be5
Minor cleanups can probably be done, I think there's some unused CSS
Wonder if we could share more code between the 2 buttons, but that doesn't seem critical to merge
*/ | ||
|
||
.wordWrapButton { | ||
right: calc( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this rule still necessary?
Looks to me it's not useful anymore => removing it and things keep working?
packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/styles.module.css
Outdated
Show resolved
Hide resolved
} | ||
|
||
.wordWrapButtonIcon { | ||
width: 1.2rem; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we want to use the same size for all buttongroup icons? and introduce anv env variable to customize?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can keep it this way for now, but I guess the wordWrap svg could also be cropped somehow to take full space
packages/docusaurus-theme-classic/src/theme/CodeBlock/WordWrapButton/styles.module.css
Outdated
Show resolved
Hide resolved
packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/String.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM thanks 👍
Will do the minor change and merge
import {useState, useCallback, useEffect, useRef} from 'react'; | ||
|
||
export function useCodeWordWrap(): { | ||
readonly codeBlockRef: (node: HTMLPreElement | null) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not needed to use a function here you can return the React ref and assign it directly (like it was before, but instead it's created in the custom hook instead of the component
It looks like this was merged without being documented. Because it's not working in my testing, I'm looking for (and not finding) a way to disable this feature. |
@alexfornuto This is not an opt-in feature and there's no option for this. If you want to disable this, you have to swizzle What's not working for you? |
@Josh-Cena thanks for the reply. Example preview here shows the following example, two code blocks, each in a tab:
While other code blocks on the linked page display and use the wrap button, these do not behave as expected:
This example is using 2.0.0-beta.20 |
That seems like a bug. Please open an issue. |
is there a way to toggle it on by default? I'm using it to show paragraphs of text.. |
@magician11 #7875 is the closest. If you think that won't satisfy your use case please submit a new issue instead of posting under an old PR. |
Motivation
Code blocks with long lines sometimes inconvenient to read, especially on mobile devices. But what if next to the copy code button, there was a button to toggle line wrapping? I mean that button would show up only when needed (there are long lines in any code block which cause horizontal scrolling).
I'm still not sure about the need for this feature, but decided to implement it to demonstrate it action.
Have you read the Contributing Guidelines on pull requests?
Yes
Test Plan
Code for testing:
https://deploy-preview-7036--docusaurus-2.netlify.app/tests/pages/code-block-tests
Related PRs