@focus-reactive/sanity-plugin-inline-svg-input
Version:
Sanity plugin to upload and preview inline SVGs
214 lines (202 loc) • 6.67 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: !0 });
var sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), react = require("react"), styled = require("styled-components"), DOMPurify = require("dompurify"), ui = require("@sanity/ui");
function _interopDefaultCompat(e) {
return e && typeof e == "object" && "default" in e ? e : { default: e };
}
var styled__default = /* @__PURE__ */ _interopDefaultCompat(styled), DOMPurify__default = /* @__PURE__ */ _interopDefaultCompat(DOMPurify);
const Container$1 = styled__default.default.div`
--svg-bg-color: rgba(23, 23, 23, 0.05);
background-image: linear-gradient(45deg, var(--svg-bg-color) 25%, transparent 25%),
linear-gradient(-45deg, var(--svg-bg-color) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, var(--svg-bg-color) 75%),
linear-gradient(-45deg, transparent 75%, var(--svg-bg-color) 75%);
background-size: 20px 20px;
background-position:
0 0,
0 10px,
10px -10px,
-10px 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 250px;
border: 1px solid var(--card-border-color);
border-radius: 3px;
position: relative;
&:focus-within {
border-color: var(--card-focus-ring-color);
}
&.dark {
--svg-bg-color: rgb(255, 255, 255, 0.1);
}
input[type='file'] {
opacity: 0;
z-index: -1;
position: absolute;
}
input[type='file']:focus + label {
outline: 2px solid;
}
* {
box-sizing: border-box;
}
`, SvgWrapper = styled__default.default.div`
display: flex;
max-height: 320px;
> div {
display: flex;
align-items: center;
justify-content: center;
}
svg {
max-height: 80%;
max-width: 80%;
display: flex;
margin: auto;
width: 100%;
height: 100%;
}
`, ButtonStyle = styled.css`
border-radius: 0.1875rem;
font: inherit;
outline: none;
border: 0;
padding: 0.85rem 1.75rem;
margin: 0;
color: #fff;
cursor: pointer;
font-size: 1rem;
font-weight: 500;
`, AddButton = styled__default.default.label`
${ButtonStyle};
color: #fff;
background-color: #4285f4;
&:hover {
background-color: #3a6fc8;
}
`, RemoveButton = styled__default.default.button`
${ButtonStyle};
position: absolute;
top: 10px;
right: 10px;
color: #fff;
background-color: #db4437;
&:hover {
background-color: #b43b31;
}
`, InlineSvgInput = ({ id, value, schemaType, onChange, focused }) => {
const inputRef = react.useRef(null), scheme = ui.usePrefersDark() ? "dark" : "light", isDarkMode = ui.useTheme().sanity.color.dark, handleChange = (event) => {
var _a, _b;
const file = (_b = (_a = event.target) == null ? void 0 : _a.files) == null ? void 0 : _b[0];
if (!file)
return;
const reader = new FileReader();
reader.onload = (readerEvent) => {
readerEvent.target && onChange(sanity.set(readerEvent.target.result));
}, reader.readAsText(file);
}, focus = () => {
inputRef.current && inputRef.current.focus();
};
react.useEffect(() => {
focused && focus();
}, [focused]);
const clickedRemoveSvg = () => (confirm("Are you sure you want to remove the SVG?") && (onChange(sanity.unset()), inputRef.current && (inputRef.current.value = "")), !1);
return /* @__PURE__ */ jsxRuntime.jsx(Container$1, { className: isDarkMode ? "dark" : "light", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.ThemeProvider, { scheme, children: [
/* @__PURE__ */ jsxRuntime.jsx(
"input",
{
accept: ".svg",
id,
ref: inputRef,
type: "file",
placeholder: schemaType.placeholder,
onChange: handleChange,
name: "inline-svg"
}
),
!value && /* @__PURE__ */ jsxRuntime.jsx(AddButton, { htmlFor: id, children: "Upload SVG" }),
value && /* @__PURE__ */ jsxRuntime.jsxs(SvgWrapper, { children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify__default.default.sanitize(value) } }),
/* @__PURE__ */ jsxRuntime.jsx(RemoveButton, { onClick: clickedRemoveSvg, children: "Remove SVG" })
] })
] }) });
}, inlineSvgType = sanity.defineType({
name: "inlineSvg",
title: "Inline SVG",
type: "string",
components: {
input: InlineSvgInput
}
}), InlineSvgPreview = styled__default.default.div`
svg {
width: 100%;
height: 100%;
}
`, InlineSvgPreviewComponent = ({
value,
className,
style
}) => value ? /* @__PURE__ */ jsxRuntime.jsx(
InlineSvgPreview,
{
dangerouslySetInnerHTML: { __html: DOMPurify__default.default.sanitize(value) },
className,
style
}
) : null, Container = styled__default.default.div`
display: flex;
align-items: center;
box-sizing: border-box;
* {
box-sizing: border-box;
}
`, IconStyle = styled.css`
width: 35px;
height: 35px;
margin-right: 8px;
flex-shrink: 0;
`, Icon = styled__default.default(InlineSvgPreviewComponent)`
${IconStyle}
`, IconStub = styled__default.default.div`
${IconStyle}
`, Title = styled__default.default.span`
display: block;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
overflow: clip;
font-size: 1rem;
line-height: calc(21 / 16);
color: ${({ empty }) => empty ? "#6e7683" : "inherit"}};
`, Subtitle = styled__default.default.span`
display: block;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
overflow: clip;
font-size: 0.8125rem;
line-height: calc(17 / 13);
color: #6e7683;
`, TextContainer = styled__default.default.div`
overflow: hidden;
`, InlineSvgPreviewItem = ({
icon,
title,
subtitle
}) => title && typeof title != "string" || subtitle && typeof subtitle != "string" ? /* @__PURE__ */ jsxRuntime.jsx(Container, { children: "`InlineSvgPreviewItem` supports only string values for `title` and `subtitle` props." }) : /* @__PURE__ */ jsxRuntime.jsxs(Container, { children: [
icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { value: icon }) : /* @__PURE__ */ jsxRuntime.jsx(IconStub, {}),
/* @__PURE__ */ jsxRuntime.jsxs(TextContainer, { children: [
title ? /* @__PURE__ */ jsxRuntime.jsx(Title, { children: title }) : /* @__PURE__ */ jsxRuntime.jsx(Title, { empty: !0, children: "Untitled" }),
subtitle && /* @__PURE__ */ jsxRuntime.jsx(Subtitle, { children: subtitle })
] })
] }), inlineSvgInput = sanity.definePlugin((config = {}) => ({
name: "sanity-plugin-inline-svg-input",
schema: {
types: [inlineSvgType]
}
}));
exports.InlineSvgPreviewComponent = InlineSvgPreviewComponent;
exports.InlineSvgPreviewItem = InlineSvgPreviewItem;
exports.inlineSvgInput = inlineSvgInput;
//# sourceMappingURL=index.js.map