@@ -20,20 +20,32 @@ import { applyTheme } from '../helpers/theme';
2020 * @param {InlineControlsProps } props
2121 */
2222function InlineControls ( { isCollapsed, setCollapsed, linkStyle = { } } ) {
23- const toggleLabel = isCollapsed ? 'More' : 'Less' ;
24-
2523 return (
26- < div className = "Excerpt__inline-controls" >
27- < div className = "Excerpt__toggle-container" >
24+ < div
25+ className = { classnames (
26+ // Position these controls at the bottom right of the excerpt
27+ 'absolute block right-0 bottom-0' ,
28+ // Give extra width for larger tap target and gradient fade
29+ // Fade transparent-to-white left-to-right to make the toggle
30+ // control text (More/Less) more readable above other text.
31+ // This gradient is implemented to-left to take advantage of Tailwind's
32+ // automatic to-transparent calculation: this avoids Safari's problem
33+ // with transparents in gradients:
34+ // https://bugs.webkit.org/show_bug.cgi?id=150940
35+ // https://tailwindcss.com/docs/gradient-color-stops#fading-to-transparent
36+ 'w-20 bg-gradient-to-l from-white'
37+ ) }
38+ >
39+ < div className = "flex justify-end" >
2840 < LinkButton
29- classes = "InlineLinkButton InlineLinkButton--underlined "
41+ classes = "inline underline "
3042 onClick = { ( ) => setCollapsed ( ! isCollapsed ) }
3143 expanded = { ! isCollapsed }
3244 title = "Toggle visibility of full excerpt text"
3345 style = { linkStyle }
3446 variant = "dark"
3547 >
36- { toggleLabel }
48+ { isCollapsed ? 'More' : 'Less' }
3749 </ LinkButton >
3850 </ div >
3951 </ div >
@@ -86,14 +98,13 @@ function Excerpt({
8698 const [ collapsedByInlineControls , setCollapsedByInlineControls ] =
8799 useState ( true ) ;
88100
89- // Container for the excerpt's content.
90101 const contentElement = /** @type {{ current: HTMLDivElement } } */ ( useRef ( ) ) ;
91102
92- // Measured height of `contentElement` in pixels.
103+ // Measured height of `contentElement` in pixels
93104 const [ contentHeight , setContentHeight ] = useState ( 0 ) ;
94105
95- // Update the measured height of the content after the initial render and
96- // when the size of the content element changes.
106+ // Update the measured height of the content container after initial render,
107+ // and when the size of the content element changes.
97108 const updateContentHeight = useCallback ( ( ) => {
98109 const newContentHeight = contentElement . current . clientHeight ;
99110 setContentHeight ( newContentHeight ) ;
@@ -133,18 +144,48 @@ function Excerpt({
133144 : onToggleCollapsed ( collapsed ) ;
134145
135146 return (
136- < div className = "Excerpt" style = { contentStyle } >
137- < div className = "Excerpt__content" ref = { contentElement } >
147+ < div
148+ data-testid = "excerpt-container"
149+ className = { classnames (
150+ 'relative overflow-hidden' ,
151+ 'transition-[max-height] ease-in duration-150'
152+ ) }
153+ style = { contentStyle }
154+ >
155+ < div
156+ className = { classnames (
157+ // Establish new block-formatting context to prevent margin-collapsing
158+ // in descendent elements from potentially "leaking out" and pushing
159+ // this element down from the top of the container.
160+ // See https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context
161+ // See https://github.com/hypothesis/client/issues/1518
162+ 'inline-block w-full'
163+ ) }
164+ data-testid = "excerpt-content"
165+ ref = { contentElement }
166+ >
138167 { children }
139168 </ div >
140169 < div
170+ data-testid = "excerpt-expand"
141171 role = "presentation"
142172 onClick = { ( ) => setCollapsed ( false ) }
143- className = { classnames ( {
144- Excerpt__shadow : true ,
145- 'Excerpt__shadow--transparent' : inlineControls ,
146- 'is-hidden' : ! isExpandable ,
147- } ) }
173+ className = { classnames (
174+ // This element provides a clickable area at the bottom of an
175+ // expandable excerpt to expand it.
176+ 'transition-[opacity] duration-150 ease-linear' ,
177+ 'absolute w-full bottom-0 h-touch-minimum' ,
178+ {
179+ // For expandable excerpts not using inlineControls, style this
180+ // element with a custom shadow-like gradient
181+ 'bg-gradient-to-b from-excerptStop1 via-excerptStop2 to-excerptStop3' :
182+ ! inlineControls && isExpandable ,
183+ 'bg-none' : inlineControls ,
184+ // Don't make this shadow visible OR clickable if there's nothing
185+ // to do here (the excerpt isn't expandable)
186+ 'opacity-0 pointer-events-none' : ! isExpandable ,
187+ }
188+ ) }
148189 title = "Show the full excerpt"
149190 />
150191 { isOverflowing && inlineControls && (
0 commit comments