From 752d5fc3c3826ae9d867dd7f516274722c653a94 Mon Sep 17 00:00:00 2001
From: Chris Beer <chris@cbeer.info>
Date: Mon, 11 Dec 2023 15:31:12 -0800
Subject: [PATCH] Pull search hit styling up

---
 __tests__/src/components/SearchHit.test.js    |   5 +-
 .../src/components/SearchResults.test.js      |   4 +-
 src/components/SearchHit.js                   | 157 +++++++++++-------
 3 files changed, 97 insertions(+), 69 deletions(-)

diff --git a/__tests__/src/components/SearchHit.test.js b/__tests__/src/components/SearchHit.test.js
index c72cef108..e999a8b1e 100644
--- a/__tests__/src/components/SearchHit.test.js
+++ b/__tests__/src/components/SearchHit.test.js
@@ -67,14 +67,13 @@ describe('SearchHit', () => {
     it('renders the annotationLabel if present', () => {
       render(<Subject annotationLabel="The Anno Label" />);
 
-      expect(screen.getAllByRole('heading', { level: 6 })).toHaveLength(2);
-      expect(screen.getByRole('heading', { level: 6, name: 'The Anno Label' })).toHaveClass('MuiTypography-subtitle2');
+      expect(screen.getByRole('heading', { level: 4, name: 'The Anno Label' })).toBeInTheDocument();
     });
 
     it('does not render the typography if no annotation label is present', () => {
       render(<Subject />);
 
-      expect(screen.getByRole('heading', { level: 6 })).toBeInTheDocument();
+      expect(screen.getByRole('heading', { level: 4 })).toBeInTheDocument();
     });
   });
 
diff --git a/__tests__/src/components/SearchResults.test.js b/__tests__/src/components/SearchResults.test.js
index 14a906cb6..3579a9789 100644
--- a/__tests__/src/components/SearchResults.test.js
+++ b/__tests__/src/components/SearchResults.test.js
@@ -95,8 +95,8 @@ describe('SearchResults', () => {
         searchHits: [],
       });
 
-      expect(screen.getByRole('heading', { level: 6, name: 'The Anno Label' })).toBeInTheDocument();
-      expect(screen.getByRole('heading', { level: 6, name: 'Annother Anno Label' })).toBeInTheDocument();
+      expect(screen.getByRole('heading', { level: 4, name: 'The Anno Label' })).toBeInTheDocument();
+      expect(screen.getByRole('heading', { level: 4, name: 'Annother Anno Label' })).toBeInTheDocument();
     });
   });
 
diff --git a/src/components/SearchHit.js b/src/components/SearchHit.js
index f2db8a965..41a8be606 100644
--- a/src/components/SearchHit.js
+++ b/src/components/SearchHit.js
@@ -5,10 +5,45 @@ import ListItem from '@mui/material/ListItem';
 import ListItemText from '@mui/material/ListItemText';
 import Typography from '@mui/material/Typography';
 import Chip from '@mui/material/Chip';
+import { styled } from '@mui/material/styles';
 import SanitizedHtml from '../containers/SanitizedHtml';
 import TruncatedHit from '../lib/TruncatedHit';
 import { ScrollTo } from './ScrollTo';
 
+const Root = styled(ListItem, { name: 'SearchHit', slot: 'root' })(({ ownerState, theme }) => ({
+  '&.Mui-focused': {
+    '&:hover': {
+      ...(ownerState.windowSelected && {
+        backgroundColor: 'inherit',
+      }),
+    },
+    ...(ownerState.windowSelected && {
+      backgroundColor: 'inherit',
+    }),
+  },
+  paddingRight: theme.spacing(1),
+}));
+
+const CanvasLabel = styled('h4', { name: 'SearchHit', slot: 'canvasLabel' })(({ theme }) => ({
+  display: 'inline',
+  marginBottom: theme.spacing(1.5),
+}));
+
+const Counter = styled(Chip, { name: 'SearchHit', slot: 'counter' })(({ ownerState, theme }) => ({
+  // eslint-disable-next-line no-nested-ternary
+  backgroundColor: theme.palette.hitCounter.default,
+  ...(ownerState.windowSelected && {
+    backgroundColor: theme.palette.highlights.primary,
+  }),
+  ...(ownerState.adjacent && !ownerState.windowSelected && {
+    backgroundColor: theme.palette.highlights.secondary,
+  }),
+  height: 30,
+  marginRight: theme.spacing(1),
+  typography: 'subtitle2',
+  verticalAlign: 'inherit',
+}));
+
 /** */
 export class SearchHit extends Component {
   /** */
@@ -93,6 +128,25 @@ export class SearchHit extends Component {
     const truncatedHit = focused ? hit : hit && new TruncatedHit(hit, annotation);
     const truncated = hit && (truncatedHit.before !== hit.before || truncatedHit.after !== hit.after);
     const canvasLabelHtmlId = `${companionWindowId}-${index}`;
+    const ownerState = {
+      adjacent, focused, selected, windowSelected,
+    };
+
+    const header = (
+      <>
+        <Counter
+          component="span"
+          ownerState={ownerState}
+          label={index + 1}
+        />
+        <CanvasLabel id={canvasLabelHtmlId}>
+          {canvasLabel}
+          {annotationLabel && (
+            <Typography component="span" sx={{ display: 'block', marginTop: 1 }}>{annotationLabel}</Typography>
+          )}
+        </CanvasLabel>
+      </>
+    );
 
     return (
       <ScrollTo
@@ -100,81 +154,56 @@ export class SearchHit extends Component {
         offsetTop={96} // offset for the height of the form above
         scrollTo={windowSelected && !focused}
       >
-        <ListItem
+        <Root
+          ownerState={ownerState}
           className={windowSelected ? 'windowSelected' : ''}
-          sx={{
-            '&.Mui-focused': {
-              '&:hover': {
-                ...(windowSelected && {
-                  backgroundColor: 'inherit',
-                }),
-              },
-              ...(windowSelected && {
-                backgroundColor: 'inherit',
-              }),
-            },
-            paddingRight: 1,
-          }}
           divider
           button={!selected}
           component="li"
           onClick={this.handleClick}
           selected={selected}
         >
-          <ListItemText primaryTypographyProps={{ variant: 'body1' }}>
-            <Typography variant="subtitle2" sx={{ marginBottom: 1.5 }}>
-              <Chip
-                component="span"
-                label={index + 1}
-                sx={{
-                  // eslint-disable-next-line no-nested-ternary
-                  backgroundColor: windowSelected ? 'highlights.primary' : adjacent ? 'highlights.secondary' : 'hitCounter.default',
-                  height: 30,
-                  marginRight: 1,
-                  typography: 'subtitle2',
-                  verticalAlign: 'inherit',
-                }}
-              />
-              <span id={canvasLabelHtmlId}>
-                {canvasLabel}
-              </span>
-            </Typography>
-            {annotationLabel && (
-              <Typography variant="subtitle2">{annotationLabel}</Typography>
-            )}
-            {hit && (
+          <ListItemText
+            primary={header}
+            primaryTypographyProps={{ component: 'div', sx: { marginBottom: 1 }, variant: 'subtitle2' }}
+            secondaryTypographyProps={{ variant: 'body1' }}
+            secondary={(
               <>
-                <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.before} />
-                {' '}
-                <strong>
-                  <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.match} />
-                </strong>
-                {' '}
-                <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.after} />
-                {' '}
-                { truncated && !focused && (
-                  <Button
-                    sx={{
-                      '& span': {
-                        lineHeight: '1.5em',
-                      },
-                      margin: 0,
-                      padding: 0,
-                      textTransform: 'none',
-                    }}
-                    onClick={showDetails}
-                    color="secondary"
-                    size="small"
-                    aria-describedby={canvasLabelHtmlId}
-                  >
-                    {t('more')}
-                  </Button>
+                {hit && (
+                  <>
+                    <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.before} />
+                    {' '}
+                    <strong>
+                      <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.match} />
+                    </strong>
+                    {' '}
+                    <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.after} />
+                    {' '}
+                    {truncated && !focused && (
+                      <Button
+                        sx={{
+                          '& span': {
+                            lineHeight: '1.5em',
+                          },
+                          margin: 0,
+                          padding: 0,
+                          textTransform: 'none',
+                        }}
+                        onClick={showDetails}
+                        color="secondary"
+                        size="small"
+                        aria-describedby={canvasLabelHtmlId}
+                      >
+                        {t('more')}
+                      </Button>
+                    )}
+                  </>
                 )}
+                {!hit && annotation && <SanitizedHtml ruleSet="iiif" htmlString={annotation.chars} />}
               </>
             )}
-            {!hit && annotation && <SanitizedHtml ruleSet="iiif" htmlString={annotation.chars} />}
-          </ListItemText>
-        </ListItem>
+          />
+        </Root>
       </ScrollTo>
     );
   }
-- 
GitLab