Skip to content

Commit e59c58b

Browse files
authored
Add Rendering primitive. (#194)
* Add `Rendering` primitive.
1 parent 71787aa commit e59c58b

File tree

10 files changed

+295
-0
lines changed

10 files changed

+295
-0
lines changed

pages/docs/rendering.mdx

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
---
2+
title: Rendering
3+
---
4+
5+
import IIIFBadge from "docs/components/IIIFBadge";
6+
import { Rendering } from "src/components/Primitives";
7+
import { Tabs, Tab } from "nextra/components";
8+
9+
# Rendering
10+
11+
The Rendering component is used to display a list of alternate formats related to a resource. Whereas SeeAlso is used
12+
to link to a machine-readable resource such as metadata, the Rendering component alerts users that the resource is
13+
available in another format such as PDF or ePub or has a related format. Because of the wide variety of formats that
14+
resources can be available in, the Rendering component is flexible and be of any media type and contain any type of
15+
data.
16+
17+
<IIIFBadge
18+
href="https://iiif.io/api/presentation/3.0/#rendering"
19+
text={["rendering"]}
20+
/>
21+
22+
<Tabs items={["Code", "Example", "HTML"]}>
23+
<Tab>
24+
```jsx
25+
<Rendering
26+
rendering={[
27+
{
28+
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
29+
type: "Text",
30+
label: {
31+
en: ["PDF version"],
32+
},
33+
format: "application/pdf",
34+
},
35+
]}
36+
/>
37+
```
38+
</Tab>
39+
<Tab>
40+
<Rendering
41+
rendering={[
42+
{
43+
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
44+
type: "Text",
45+
label: {
46+
en: ["PDF version"],
47+
},
48+
format: "application/pdf",
49+
},
50+
]}
51+
/>
52+
</Tab>
53+
<Tab>
54+
```html
55+
<ul class="c-PJLV">
56+
<li class="c-PJLV">
57+
<a
58+
href="https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf"
59+
target="_blank"
60+
>
61+
PDF version
62+
</a>
63+
</li>
64+
</ul>
65+
```
66+
</Tab>
67+
</Tabs>
68+
69+
## Usage
70+
71+
### React
72+
73+
```jsx
74+
import { Rendering } from "@samvera/clover-iiif/primitives";
75+
76+
const CustomRendering = ({ rendering }) => {
77+
return <Rendering rendering={rendering} />;
78+
};
79+
80+
export default CustomRendering;
81+
```
82+
83+
## API Reference
84+
85+
| Prop | Type | Default | Required |
86+
| ----------- | ------------------------------------------------------------ | ------- | -------- |
87+
| `as` | `ol`, `ul` | `ul` | -- |
88+
| `rendering` | [rendering](https://iiif.io/api/presentation/3.0/#rendering) | -- | **Yes** |
89+
| `className` | `string`, `undefined` | -- | -- |
90+
| `style` | `CSSProperties`, `undefined` | -- | -- |
91+
| `lang` | `string`, `undefined` | -- | -- |
92+
| `title` | `string`, `undefined` | -- | -- |
93+
| `data-*` | `string`, `undefined` | -- | -- |
94+
| `aria-*` | `AriaAttributes`, `undefined` | -- | -- |
95+
96+
### Custom Element
97+
98+
The `Rendering` component can be rendered as either `ol` or `ul` elements. The default is `ul`.
99+
100+
<Tabs items={["Code", "Example", "HTML"]}>
101+
<Tab>
102+
```jsx
103+
<Rendering
104+
rendering={[
105+
{
106+
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
107+
type: "Text",
108+
label: {
109+
en: ["PDF version"],
110+
},
111+
format: "application/pdf",
112+
},
113+
]}
114+
as="ol"
115+
/>
116+
```
117+
</Tab>
118+
<Tab>
119+
<Rendering
120+
rendering={[
121+
{
122+
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
123+
type: "Text",
124+
label: {
125+
en: ["PDF version"],
126+
},
127+
format: "application/pdf",
128+
},
129+
]}
130+
as="ol"
131+
/>
132+
</Tab>
133+
<Tab>
134+
```html
135+
<ol class="c-PJLV">
136+
<li class="c-PJLV">
137+
<a href="https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf">
138+
PDF version
139+
</a>
140+
</li>
141+
</ol>
142+
```
143+
</Tab>
144+
</Tabs>

pages/index.mdx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
Label,
1111
Metadata,
1212
PartOf,
13+
Rendering,
1314
RequiredStatement,
1415
SeeAlso,
1516
Summary,
@@ -306,6 +307,32 @@ import "swiper/css/pagination";
306307
<SeeAlso seeAlso={manifest.seeAlso} />
307308
```
308309
</SplashElement>
310+
<SplashElement
311+
text="Rendering"
312+
css={{ height: "14.6vh" }}
313+
component={
314+
<Rendering
315+
className="clover-link"
316+
rendering={[
317+
{
318+
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
319+
type: "Text",
320+
label: {
321+
en: [
322+
"PDF version"
323+
]
324+
},
325+
format: "application/pdf"
326+
}
327+
]}
328+
/>
329+
}
330+
href="docs/rendering"
331+
>
332+
```jsx
333+
<Rendering rendering={manifest.rendering} />
334+
```
335+
</SplashElement>
309336
<SplashElement
310337
text="Homepage"
311338
css={{ height: "14.6vh" }}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from "react";
2+
import { styled } from "src/styles/stitches.config";
3+
import { getLabelAsString } from "src/lib/label-helpers";
4+
import { PrimitivesRendering } from "src/types/primitives";
5+
import { sanitizeAttributes } from "src/lib/html-element";
6+
7+
const StyledRendering = styled("li", {});
8+
const StyledWrapper = styled("ul", {});
9+
10+
const Rendering: React.FC<PrimitivesRendering> = (props) => {
11+
const { as, rendering } = props;
12+
13+
/**
14+
* Create attributes and remove React props
15+
*/
16+
const remove = ["as", "rendering"];
17+
const attributes = sanitizeAttributes(props, remove);
18+
19+
return (
20+
<StyledWrapper as={as}>
21+
{rendering &&
22+
rendering.map((resource) => {
23+
const label = getLabelAsString(
24+
resource.label,
25+
attributes.lang,
26+
) as string;
27+
return (
28+
<StyledRendering key={resource.id}>
29+
<a href={resource.id} {...attributes} target="_blank">
30+
{label ? label : resource.id}
31+
</a>
32+
</StyledRendering>
33+
);
34+
})}
35+
</StyledWrapper>
36+
);
37+
};
38+
39+
export default Rendering;

src/components/Primitives/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Markup from "src/components/Primitives/Markup/Markup";
55
import Metadata from "src/components/Primitives/Metadata/Metadata";
66
import MetadataItem from "src/components/Primitives/Metadata/Item";
77
import PartOf from "src/components/Primitives/PartOf/PartOf";
8+
import Rendering from "src/components/Primitives/Rendering/Rendering";
89
import RequiredStatement from "src/components/Primitives/RequiredStatement/RequiredStatement";
910
import SeeAlso from "src/components/Primitives/SeeAlso/SeeAlso";
1011
import Summary from "src/components/Primitives/Summary/Summary";
@@ -18,6 +19,7 @@ import {
1819
PrimitivesMetadata,
1920
PrimitivesMetadataItem,
2021
PrimitivesPartOf,
22+
PrimitivesRendering,
2123
PrimitivesRequiredStatement,
2224
PrimitivesSeeAlso,
2325
PrimitivesSummary,
@@ -33,6 +35,7 @@ export interface CloverPrimitivesComposition {
3335
Metadata: React.FC<PrimitivesMetadata>;
3436
MetadataItem: React.FC<PrimitivesMetadataItem>;
3537
PartOf: React.FC<PrimitivesPartOf>;
38+
Rendering: React.FC<PrimitivesRendering>;
3639
RequiredStatement: React.FC<PrimitivesRequiredStatement>;
3740
SeeAlso: React.FC<PrimitivesSeeAlso>;
3841
Summary: React.FC<PrimitivesSummary>;
@@ -52,6 +55,7 @@ Primitives.Markup = Markup;
5255
Primitives.Metadata = Metadata;
5356
Primitives.MetadataItem = MetadataItem;
5457
Primitives.PartOf = PartOf;
58+
Primitives.Rendering = Rendering;
5559
Primitives.RequiredStatement = RequiredStatement;
5660
Primitives.SeeAlso = SeeAlso;
5761
Primitives.Summary = Summary;
@@ -66,6 +70,7 @@ export {
6670
Metadata,
6771
MetadataItem,
6872
PartOf,
73+
Rendering,
6974
RequiredStatement,
7075
SeeAlso,
7176
Summary,

src/components/Viewer/InformationPanel/About/About.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Homepage,
77
Id,
88
Metadata,
9+
Rendering,
910
RequiredStatement,
1011
Rights,
1112
SeeAlso,
@@ -29,6 +30,7 @@ const About: React.FC = () => {
2930

3031
const [homepage, setHomepage] = useState<IIIFExternalWebResource[]>([]);
3132
const [seeAlso, setSeeAlso] = useState<IIIFExternalWebResource[]>([]);
33+
const [rendering, setRendering] = useState<IIIFExternalWebResource[]>([]);
3234
const [thumbnail, setThumbnail] = useState<IIIFExternalWebResource[]>([]);
3335

3436
useEffect(() => {
@@ -37,6 +39,7 @@ const About: React.FC = () => {
3739

3840
if (data.homepage?.length > 0) setHomepage(vault.get(data.homepage));
3941
if (data.seeAlso?.length > 0) setSeeAlso(vault.get(data.seeAlso));
42+
if (data.rendering?.length > 0) setRendering(vault.get(data.rendering));
4043
if (data.thumbnail?.length > 0) setThumbnail(vault.get(data.thumbnail));
4144
}, [activeManifest, vault]);
4245

@@ -56,6 +59,9 @@ const About: React.FC = () => {
5659
<SeeAlso
5760
seeAlso={seeAlso as unknown as PrimitivesExternalWebResource[]}
5861
/>
62+
<Rendering
63+
rendering={rendering as unknown as PrimitivesExternalWebResource[]}
64+
/>
5965
<Id id={manifest.id} htmlLabel="IIIF Manifest" />
6066
</AboutContent>
6167
</AboutStyled>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { render, screen } from "@testing-library/react";
2+
import { PrimitivesExternalWebResource } from "src/types/primitives";
3+
import PropertiesRendering from "src/components/Viewer/Properties/Rendering";
4+
import React from "react";
5+
6+
const json: PrimitivesExternalWebResource[] = [
7+
{
8+
id: "https://drive.google.com/file/d/1aWo1lORRVTQ0VveV3aP5Ym6hfVXUqr8_/view?usp=sharing",
9+
type: "Text",
10+
label: {
11+
en: ['Download "A study guide: Josh MacPhee"'],
12+
},
13+
format: "application/pdf",
14+
},
15+
{
16+
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
17+
type: "Text",
18+
label: {
19+
en: ["PDF version"],
20+
},
21+
format: "application/pdf",
22+
},
23+
];
24+
25+
describe("IIIF rendering property component", () => {
26+
it("renders", () => {
27+
render(<PropertiesRendering rendering={json} />);
28+
29+
/**
30+
* test anchors
31+
*/
32+
const links = screen.getAllByRole("link");
33+
links.forEach((element, index) => {
34+
const text = json[index].label?.en?.join(", ") as string;
35+
expect(element).toHaveTextContent(text);
36+
37+
const href = json[index].id as string;
38+
expect(element.getAttribute("href")).toBe(href);
39+
});
40+
});
41+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { PrimitivesExternalWebResource } from "src/types/primitives";
2+
import { Rendering } from "src/components/Primitives";
3+
import React from "react";
4+
5+
interface PropertiesRenderingProps {
6+
rendering: PrimitivesExternalWebResource[];
7+
}
8+
9+
const PropertiesRendering: React.FC<PropertiesRenderingProps> = ({
10+
rendering,
11+
}) => {
12+
if (rendering?.length === 0) return <></>;
13+
14+
return (
15+
<>
16+
<span className="manifest-property-title">Alternate formats</span>
17+
<Rendering rendering={rendering} />
18+
</>
19+
);
20+
};
21+
22+
export default PropertiesRendering;

src/components/Viewer/Properties/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import PropertiesHomepage from "src/components/Viewer/Properties/Homepage";
22
import PropertiesId from "src/components/Viewer/Properties/Id";
33
import PropertiesMetadata from "src/components/Viewer/Properties/Metadata";
4+
import PropertiesRendering from "src/components/Viewer/Properties/Rendering";
45
import PropertiesRequiredStatement from "src/components/Viewer/Properties/RequiredStatement";
56
import PropertiesRights from "src/components/Viewer/Properties/Rights";
67
import PropertiesSeeAlso from "src/components/Viewer/Properties/SeeAlso";
@@ -11,6 +12,7 @@ export {
1112
PropertiesHomepage as Homepage,
1213
PropertiesId as Id,
1314
PropertiesMetadata as Metadata,
15+
PropertiesRendering as Rendering,
1416
PropertiesRequiredStatement as RequiredStatement,
1517
PropertiesRights as Rights,
1618
PropertiesSeeAlso as SeeAlso,

src/dev.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Label,
88
Metadata,
99
PartOf,
10+
Rendering,
1011
RequiredStatement,
1112
SeeAlso,
1213
Summary,
@@ -63,6 +64,9 @@ const App = () => {
6364
<SeeAlso
6465
seeAlso={manifest.seeAlso as PrimitivesExternalWebResource[]}
6566
/>
67+
<Rendering
68+
rendering={manifest.rendering as PrimitivesExternalWebResource[]}
69+
/>
6670
<Thumbnail
6771
thumbnail={manifest.thumbnail as IIIFExternalWebResource[]}
6872
altAsLabel={manifest.label as InternationalString}

0 commit comments

Comments
 (0)