-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(share): add Share plugin (close #105)
- Loading branch information
1 parent
0e0fcde
commit 77e5583
Showing
12 changed files
with
214 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import * as React from "react"; | ||
|
||
import { addToolbarButton, PluginProps } from "../../index.js"; | ||
import { resolveShareProps } from "./props.js"; | ||
import { ShareButton } from "./ShareButton.js"; | ||
|
||
export function Share({ augment }: PluginProps) { | ||
augment(({ toolbar, share, ...rest }) => ({ | ||
toolbar: addToolbarButton(toolbar, "share", <ShareButton />), | ||
share: resolveShareProps(share), | ||
...rest, | ||
})); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import * as React from "react"; | ||
|
||
import { createIcon, IconButton, isImageSlide, useLightboxProps, useLightboxState } from "../../index.js"; | ||
import { resolveShareProps } from "./props.js"; | ||
import { isShareSupported } from "./utils.js"; | ||
|
||
const ShareIcon = createIcon( | ||
"ShareIcon", | ||
<path d="m16 5-1.42 1.42-1.59-1.59V16h-1.98V4.83L9.42 6.42 8 5l4-4 4 4zm4 5v11c0 1.1-.9 2-2 2H6c-1.11 0-2-.9-2-2V10c0-1.11.89-2 2-2h3v2H6v11h12V10h-3V8h3c1.1 0 2 .89 2 2z" /> | ||
); | ||
|
||
export function ShareButton() { | ||
const { render, on, share: shareProps } = useLightboxProps(); | ||
const { share: customShare } = resolveShareProps(shareProps); | ||
const { currentSlide, currentIndex } = useLightboxState(); | ||
|
||
if (!isShareSupported()) return null; | ||
|
||
if (render.buttonShare) { | ||
return <>{render.buttonShare()}</>; | ||
} | ||
|
||
const share = | ||
(currentSlide && | ||
((typeof currentSlide.share === "object" && currentSlide.share) || | ||
(typeof currentSlide.share === "string" && { url: currentSlide.share }) || | ||
(isImageSlide(currentSlide) && { url: currentSlide.src }))) || | ||
undefined; | ||
|
||
// slides must be explicitly marked as shareable when custom share function is provided | ||
const canShare = customShare ? Boolean(currentSlide?.share) : share && navigator.canShare(share); | ||
|
||
const defaultShare = () => { | ||
if (share) { | ||
navigator.share(share).catch(() => {}); | ||
} | ||
}; | ||
|
||
const handleShare = () => { | ||
if (currentSlide) { | ||
(customShare || defaultShare)({ slide: currentSlide }); | ||
|
||
on.share?.({ index: currentIndex }); | ||
} | ||
}; | ||
|
||
return ( | ||
<IconButton | ||
label="Share" | ||
icon={ShareIcon} | ||
renderIcon={render.iconShare} | ||
disabled={!canShare} | ||
onClick={handleShare} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { PLUGIN_SHARE } from "../../index.js"; | ||
import { Share } from "./Share.js"; | ||
|
||
export { isShareSupported } from "./utils.js"; | ||
|
||
declare module "../../types.js" { | ||
interface GenericSlide { | ||
/** share url or share props */ | ||
share?: | ||
| boolean | ||
| string | ||
| { | ||
/** share url */ | ||
url?: string; | ||
/** share text */ | ||
text?: string; | ||
/** share title */ | ||
title?: string; | ||
}; | ||
} | ||
|
||
interface LightboxProps { | ||
/** Share plugin settings */ | ||
share?: { | ||
/** custom share function */ | ||
share?: ({ slide }: ShareFunctionProps) => void; | ||
}; | ||
} | ||
|
||
interface Render { | ||
/** render custom Share button */ | ||
buttonShare?: RenderFunction; | ||
/** render custom Share icon */ | ||
iconShare?: RenderFunction; | ||
} | ||
|
||
interface Callbacks { | ||
/** a callback called on slide share */ | ||
share?: Callback<ShareCallbackProps>; | ||
} | ||
|
||
interface ToolbarButtonKeys { | ||
[PLUGIN_SHARE]: null; | ||
} | ||
|
||
export interface ShareCallbackProps { | ||
index: number; | ||
} | ||
|
||
export interface ShareFunctionProps { | ||
slide: Slide; | ||
} | ||
} | ||
|
||
export default Share; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { LightboxProps } from "../../types.js"; | ||
|
||
export const defaultShareProps = { | ||
share: undefined, | ||
}; | ||
|
||
export const resolveShareProps = (share: LightboxProps["share"]) => ({ | ||
...defaultShareProps, | ||
...share, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export function isShareSupported() { | ||
return Boolean(navigator.canShare); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { render, screen } from "@testing-library/react"; | ||
import { vi } from "vitest"; | ||
|
||
import { clickButton, lightbox } from "../utils.js"; | ||
import { Share } from "../../src/plugins/index.js"; | ||
import { LightboxExternalProps } from "../../src/index.js"; | ||
|
||
function renderLightbox(props?: LightboxExternalProps) { | ||
return render(lightbox({ plugins: [Share], ...props })); | ||
} | ||
|
||
describe("Share", () => { | ||
beforeAll(() => { | ||
const shareCopy = navigator.share; | ||
const canShareCopy = navigator.canShare; | ||
|
||
navigator.share = () => Promise.resolve(); | ||
navigator.canShare = () => true; | ||
|
||
return () => { | ||
navigator.share = shareCopy; | ||
navigator.canShare = canShareCopy; | ||
}; | ||
}); | ||
|
||
it("renders the share button", () => { | ||
const share = vi.fn(); | ||
|
||
renderLightbox({ slides: [{ src: "image1" }, { src: "image2" }], on: { share } }); | ||
|
||
expect(screen.queryByLabelText("Share")).toBeInTheDocument(); | ||
|
||
clickButton("Share"); | ||
|
||
expect(share).toHaveBeenCalled(); | ||
}); | ||
|
||
it("doesn't crash with empty slides", () => { | ||
renderLightbox(); | ||
|
||
expect(screen.queryByRole("presentation")).toBeInTheDocument(); | ||
}); | ||
|
||
it("supports custom share button", () => { | ||
const buttonShare = vi.fn(); | ||
|
||
renderLightbox({ render: { buttonShare } }); | ||
|
||
expect(buttonShare).toHaveBeenCalled(); | ||
}); | ||
|
||
it("supports custom share function", () => { | ||
const share = vi.fn(); | ||
|
||
renderLightbox({ slides: [{ src: "image", share: true }], share: { share } }); | ||
|
||
clickButton("Share"); | ||
|
||
expect(share).toHaveBeenCalled(); | ||
}); | ||
}); |