Skip to content

Commit

Permalink
Add Rendering primitive. (#194)
Browse files Browse the repository at this point in the history
* Add `Rendering` primitive.
  • Loading branch information
markpbaggett authored Apr 11, 2024
1 parent 71787aa commit e59c58b
Show file tree
Hide file tree
Showing 10 changed files with 295 additions and 0 deletions.
144 changes: 144 additions & 0 deletions pages/docs/rendering.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
---
title: Rendering
---

import IIIFBadge from "docs/components/IIIFBadge";
import { Rendering } from "src/components/Primitives";
import { Tabs, Tab } from "nextra/components";

# Rendering

The Rendering component is used to display a list of alternate formats related to a resource. Whereas SeeAlso is used
to link to a machine-readable resource such as metadata, the Rendering component alerts users that the resource is
available in another format such as PDF or ePub or has a related format. Because of the wide variety of formats that
resources can be available in, the Rendering component is flexible and be of any media type and contain any type of
data.

<IIIFBadge
href="https://iiif.io/api/presentation/3.0/#rendering"
text={["rendering"]}
/>

<Tabs items={["Code", "Example", "HTML"]}>
<Tab>
```jsx
<Rendering
rendering={[
{
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
type: "Text",
label: {
en: ["PDF version"],
},
format: "application/pdf",
},
]}
/>
```
</Tab>
<Tab>
<Rendering
rendering={[
{
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
type: "Text",
label: {
en: ["PDF version"],
},
format: "application/pdf",
},
]}
/>
</Tab>
<Tab>
```html
<ul class="c-PJLV">
<li class="c-PJLV">
<a
href="https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf"
target="_blank"
>
PDF version
</a>
</li>
</ul>
```
</Tab>
</Tabs>

## Usage

### React

```jsx
import { Rendering } from "@samvera/clover-iiif/primitives";
const CustomRendering = ({ rendering }) => {
return <Rendering rendering={rendering} />;
};
export default CustomRendering;
```

## API Reference

| Prop | Type | Default | Required |
| ----------- | ------------------------------------------------------------ | ------- | -------- |
| `as` | `ol`, `ul` | `ul` | -- |
| `rendering` | [rendering](https://iiif.io/api/presentation/3.0/#rendering) | -- | **Yes** |
| `className` | `string`, `undefined` | -- | -- |
| `style` | `CSSProperties`, `undefined` | -- | -- |
| `lang` | `string`, `undefined` | -- | -- |
| `title` | `string`, `undefined` | -- | -- |
| `data-*` | `string`, `undefined` | -- | -- |
| `aria-*` | `AriaAttributes`, `undefined` | -- | -- |

### Custom Element

The `Rendering` component can be rendered as either `ol` or `ul` elements. The default is `ul`.

<Tabs items={["Code", "Example", "HTML"]}>
<Tab>
```jsx
<Rendering
rendering={[
{
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
type: "Text",
label: {
en: ["PDF version"],
},
format: "application/pdf",
},
]}
as="ol"
/>
```
</Tab>
<Tab>
<Rendering
rendering={[
{
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
type: "Text",
label: {
en: ["PDF version"],
},
format: "application/pdf",
},
]}
as="ol"
/>
</Tab>
<Tab>
```html
<ol class="c-PJLV">
<li class="c-PJLV">
<a href="https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf">
PDF version
</a>
</li>
</ol>
```
</Tab>
</Tabs>
27 changes: 27 additions & 0 deletions pages/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Label,
Metadata,
PartOf,
Rendering,
RequiredStatement,
SeeAlso,
Summary,
Expand Down Expand Up @@ -306,6 +307,32 @@ import "swiper/css/pagination";
<SeeAlso seeAlso={manifest.seeAlso} />
```
</SplashElement>
<SplashElement
text="Rendering"
css={{ height: "14.6vh" }}
component={
<Rendering
className="clover-link"
rendering={[
{
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
type: "Text",
label: {
en: [
"PDF version"
]
},
format: "application/pdf"
}
]}
/>
}
href="docs/rendering"
>
```jsx
<Rendering rendering={manifest.rendering} />
```
</SplashElement>
<SplashElement
text="Homepage"
css={{ height: "14.6vh" }}
Expand Down
39 changes: 39 additions & 0 deletions src/components/Primitives/Rendering/Rendering.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";
import { styled } from "src/styles/stitches.config";
import { getLabelAsString } from "src/lib/label-helpers";
import { PrimitivesRendering } from "src/types/primitives";
import { sanitizeAttributes } from "src/lib/html-element";

const StyledRendering = styled("li", {});
const StyledWrapper = styled("ul", {});

const Rendering: React.FC<PrimitivesRendering> = (props) => {
const { as, rendering } = props;

/**
* Create attributes and remove React props
*/
const remove = ["as", "rendering"];
const attributes = sanitizeAttributes(props, remove);

return (
<StyledWrapper as={as}>
{rendering &&
rendering.map((resource) => {
const label = getLabelAsString(
resource.label,
attributes.lang,
) as string;
return (
<StyledRendering key={resource.id}>
<a href={resource.id} {...attributes} target="_blank">
{label ? label : resource.id}
</a>
</StyledRendering>
);
})}
</StyledWrapper>
);
};

export default Rendering;
5 changes: 5 additions & 0 deletions src/components/Primitives/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Markup from "src/components/Primitives/Markup/Markup";
import Metadata from "src/components/Primitives/Metadata/Metadata";
import MetadataItem from "src/components/Primitives/Metadata/Item";
import PartOf from "src/components/Primitives/PartOf/PartOf";
import Rendering from "src/components/Primitives/Rendering/Rendering";
import RequiredStatement from "src/components/Primitives/RequiredStatement/RequiredStatement";
import SeeAlso from "src/components/Primitives/SeeAlso/SeeAlso";
import Summary from "src/components/Primitives/Summary/Summary";
Expand All @@ -18,6 +19,7 @@ import {
PrimitivesMetadata,
PrimitivesMetadataItem,
PrimitivesPartOf,
PrimitivesRendering,
PrimitivesRequiredStatement,
PrimitivesSeeAlso,
PrimitivesSummary,
Expand All @@ -33,6 +35,7 @@ export interface CloverPrimitivesComposition {
Metadata: React.FC<PrimitivesMetadata>;
MetadataItem: React.FC<PrimitivesMetadataItem>;
PartOf: React.FC<PrimitivesPartOf>;
Rendering: React.FC<PrimitivesRendering>;
RequiredStatement: React.FC<PrimitivesRequiredStatement>;
SeeAlso: React.FC<PrimitivesSeeAlso>;
Summary: React.FC<PrimitivesSummary>;
Expand All @@ -52,6 +55,7 @@ Primitives.Markup = Markup;
Primitives.Metadata = Metadata;
Primitives.MetadataItem = MetadataItem;
Primitives.PartOf = PartOf;
Primitives.Rendering = Rendering;
Primitives.RequiredStatement = RequiredStatement;
Primitives.SeeAlso = SeeAlso;
Primitives.Summary = Summary;
Expand All @@ -66,6 +70,7 @@ export {
Metadata,
MetadataItem,
PartOf,
Rendering,
RequiredStatement,
SeeAlso,
Summary,
Expand Down
6 changes: 6 additions & 0 deletions src/components/Viewer/InformationPanel/About/About.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Homepage,
Id,
Metadata,
Rendering,
RequiredStatement,
Rights,
SeeAlso,
Expand All @@ -29,6 +30,7 @@ const About: React.FC = () => {

const [homepage, setHomepage] = useState<IIIFExternalWebResource[]>([]);
const [seeAlso, setSeeAlso] = useState<IIIFExternalWebResource[]>([]);
const [rendering, setRendering] = useState<IIIFExternalWebResource[]>([]);
const [thumbnail, setThumbnail] = useState<IIIFExternalWebResource[]>([]);

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

if (data.homepage?.length > 0) setHomepage(vault.get(data.homepage));
if (data.seeAlso?.length > 0) setSeeAlso(vault.get(data.seeAlso));
if (data.rendering?.length > 0) setRendering(vault.get(data.rendering));
if (data.thumbnail?.length > 0) setThumbnail(vault.get(data.thumbnail));
}, [activeManifest, vault]);

Expand All @@ -56,6 +59,9 @@ const About: React.FC = () => {
<SeeAlso
seeAlso={seeAlso as unknown as PrimitivesExternalWebResource[]}
/>
<Rendering
rendering={rendering as unknown as PrimitivesExternalWebResource[]}
/>
<Id id={manifest.id} htmlLabel="IIIF Manifest" />
</AboutContent>
</AboutStyled>
Expand Down
41 changes: 41 additions & 0 deletions src/components/Viewer/Properties/Rendering.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { render, screen } from "@testing-library/react";
import { PrimitivesExternalWebResource } from "src/types/primitives";
import PropertiesRendering from "src/components/Viewer/Properties/Rendering";
import React from "react";

const json: PrimitivesExternalWebResource[] = [
{
id: "https://drive.google.com/file/d/1aWo1lORRVTQ0VveV3aP5Ym6hfVXUqr8_/view?usp=sharing",
type: "Text",
label: {
en: ['Download "A study guide: Josh MacPhee"'],
},
format: "application/pdf",
},
{
id: "https://fixtures.iiif.io/other/UCLA/kabuki_ezukushi_rtl.pdf",
type: "Text",
label: {
en: ["PDF version"],
},
format: "application/pdf",
},
];

describe("IIIF rendering property component", () => {
it("renders", () => {
render(<PropertiesRendering rendering={json} />);

/**
* test anchors
*/
const links = screen.getAllByRole("link");
links.forEach((element, index) => {
const text = json[index].label?.en?.join(", ") as string;
expect(element).toHaveTextContent(text);

const href = json[index].id as string;
expect(element.getAttribute("href")).toBe(href);
});
});
});
22 changes: 22 additions & 0 deletions src/components/Viewer/Properties/Rendering.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { PrimitivesExternalWebResource } from "src/types/primitives";
import { Rendering } from "src/components/Primitives";
import React from "react";

interface PropertiesRenderingProps {
rendering: PrimitivesExternalWebResource[];
}

const PropertiesRendering: React.FC<PropertiesRenderingProps> = ({
rendering,
}) => {
if (rendering?.length === 0) return <></>;

return (
<>
<span className="manifest-property-title">Alternate formats</span>
<Rendering rendering={rendering} />
</>
);
};

export default PropertiesRendering;
2 changes: 2 additions & 0 deletions src/components/Viewer/Properties/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import PropertiesHomepage from "src/components/Viewer/Properties/Homepage";
import PropertiesId from "src/components/Viewer/Properties/Id";
import PropertiesMetadata from "src/components/Viewer/Properties/Metadata";
import PropertiesRendering from "src/components/Viewer/Properties/Rendering";
import PropertiesRequiredStatement from "src/components/Viewer/Properties/RequiredStatement";
import PropertiesRights from "src/components/Viewer/Properties/Rights";
import PropertiesSeeAlso from "src/components/Viewer/Properties/SeeAlso";
Expand All @@ -11,6 +12,7 @@ export {
PropertiesHomepage as Homepage,
PropertiesId as Id,
PropertiesMetadata as Metadata,
PropertiesRendering as Rendering,
PropertiesRequiredStatement as RequiredStatement,
PropertiesRights as Rights,
PropertiesSeeAlso as SeeAlso,
Expand Down
4 changes: 4 additions & 0 deletions src/dev.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Label,
Metadata,
PartOf,
Rendering,
RequiredStatement,
SeeAlso,
Summary,
Expand Down Expand Up @@ -63,6 +64,9 @@ const App = () => {
<SeeAlso
seeAlso={manifest.seeAlso as PrimitivesExternalWebResource[]}
/>
<Rendering
rendering={manifest.rendering as PrimitivesExternalWebResource[]}
/>
<Thumbnail
thumbnail={manifest.thumbnail as IIIFExternalWebResource[]}
altAsLabel={manifest.label as InternationalString}
Expand Down
Loading

0 comments on commit e59c58b

Please sign in to comment.