@planningcenter/organization-avatars 2.0.5 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("react"),l=require("react-dom"),u=require("@planningcenter/url"),d=require("@planningcenter/tapestry"),f=require("@planningcenter/sweetest-alert"),p=require("@planningcenter/icons/paths/general"),m=require("@planningcenter/icons/paths/services"),h=require("react-dropzone");h=s(h,1);let g=require("react/jsx-runtime");function _(e){var t,n,r=``;if(typeof e==`string`||typeof e==`number`)r+=e;else if(typeof e==`object`)if(Array.isArray(e)){var i=e.length;for(t=0;t<i;t++)e[t]&&(n=_(e[t]))&&(r&&(r+=` `),r+=n)}else for(n in e)e[n]&&(r&&(r+=` `),r+=n);return r}function v(){for(var e,t,n=0,r=``,i=arguments.length;n<i;n++)(e=arguments[n])&&(t=_(e))&&(r&&(r+=` `),r+=t);return r}function y(){let e=document.querySelector(`meta[name="csrf-token"]`);if(!e||!e.content)throw Error(`CSRF token not found. Ensure your Rails application includes <meta name="csrf-token" content="..."> in the document head.`);return e.content}function b(e){let t=e.split(``);return[t.shift()?.toUpperCase(),t.join(``)].join(``)}var x=e=>e===`dark_mode_avatar`?`dark`:`light`,S=({open:e})=>(0,g.jsxs)(`h2`,{className:`pco-org-avatar__instructions`,children:[`Drag & drop your logo file to upload, or`,` `,(0,g.jsx)(d.Button,{label:`browse`,kind:`inline-text`,onClick:t=>{t.stopPropagation(),e()}})]});function C({avatarUrl:e,organization:t,mode:n,pcoEnv:r,readOnly:i,onAvatarUpdate:a,fallbackAvatarUrl:o}){let[s,_]=(0,c.useState)(null),[C,w]=(0,c.useState)(!1),[T,E]=(0,c.useState)(!1),[D,O]=(0,c.useState)(``),k=(0,c.useId)(),A=(0,c.useRef)(null),j=x(n),M=e||o,N=e=>{let[t]=e;t&&_(Object.assign(t,{preview:URL.createObjectURL(t)}))};(0,c.useEffect)(()=>()=>{s?.preview&&(URL.revokeObjectURL(s.preview),O(``))},[s]);let P=async e=>{let t=await fetch((0,u.pcoApiUrl)(`accounts`,{env:r}),{method:`PATCH`,headers:{"Content-Type":`application/json`,"X-CSRF-Token":y(),Accept:`application/json`},body:JSON.stringify({data:{attributes:e}})}),n=await t.json();if(!t.ok)throw n;return n},F=async e=>{if(e.preventDefault(),!(!s||C||T)){w(!0);try{let e=new FileReader,t=await new Promise((t,n)=>{e.onloadend=()=>t(e.result),e.onerror=n,e.readAsDataURL(s)}),r=await P({[n]:t,[`${n}_cache`]:``});_(null),a(n,r.data.attributes[n].url),A.current?.close()}catch{O(`We were unable to save your avatar.`)}finally{w(!1)}}},I=async()=>{C||T||(E(!0),(0,f.SweetestAlert)({type:`danger`,title:`Remove this logo?`,content:j===`light`?`Removing this logo means no logo will appear in light mode. This cannot be undone.`:o?`Removing this logo means your light mode logo will appear in dark mode. This cannot be undone.`:`Removing this logo means no logo will appear in dark mode. This cannot be undone.`,confirmButton:`Remove logo`,onConfirm:async()=>{try{await P({[`remove_${n}`]:`1`}),a(n,``),A.current?.close()}catch{O(`We were unable to delete your avatar.`)}finally{E(!1)}},onCancel:()=>{E(!1)}}))};return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)(`div`,{className:`pco-org-avatar`,children:[(0,g.jsx)(`button`,{type:`button`,onClick:()=>A.current?.showModal(),disabled:i,className:`pco-org-avatar__button pco-org-avatar__button--${j}`,children:M?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`img`,{src:M,alt:`Church logo for ${t}`}),(0,g.jsx)(`div`,{className:`tds-btn tds-btn--interaction tds-btn--icononly`,children:(0,g.jsx)(`svg`,{width:`14`,height:`14`,viewBox:`0 0 16 16`,fill:`currentColor`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.pencil})})})]}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`svg`,{width:`48`,height:`48`,viewBox:`0 0 16 16`,fill:`currentColor`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:m.image})}),(0,g.jsx)(`div`,{className:`tds-btn tds-btn--interaction tds-btn--icononly`,children:(0,g.jsx)(`svg`,{width:`14`,height:`14`,viewBox:`0 0 16 16`,fill:`currentColor`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.pencil})})})]})}),(0,g.jsxs)(`div`,{className:`pco-org-avatar__label`,children:[b(j),` mode`]})]}),(0,l.createPortal)((0,g.jsx)(`dialog`,{id:k,ref:A,className:`pco-org-avatar__dialog`,onClose:()=>{_(null),O(``)},children:(0,g.jsxs)(`form`,{onSubmit:F,children:[(0,g.jsxs)(`div`,{className:`pco-org-avatar__dialog-header`,children:[(0,g.jsxs)(`h1`,{className:`pco-org-avatar__dialog-title`,children:[`Church logo — `,j,` mode`]}),(0,g.jsx)(`button`,{type:`button`,onClick:()=>A.current?.close(),className:`pco-org-avatar__dialog-close`,"aria-label":`Close modal`,children:(0,g.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 16 16`,fill:`currentColor`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.smallX})})})]}),(0,g.jsxs)(`div`,{className:`pco-org-avatar__dialog-body`,children:[D&&(0,g.jsxs)(`div`,{role:`alert`,className:`pco-org-avatar-alert pco-org-avatar__dialog-alert`,children:[(0,g.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 16 16`,className:`symbol`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.exclamationTriangle})}),(0,g.jsx)(`p`,{children:D})]}),(0,g.jsx)(h.default,{accept:{"image/*":[`.jpg`,`.jpeg`,`.png`]},multiple:!1,onDropAccepted:N,children:({getRootProps:e,getInputProps:n,isFocused:r,isDragAccept:i,isDragReject:a,isDragActive:o,open:c})=>(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)(`div`,{...e({className:v(`pco-org-avatar__dialog-dropzone`,`pco-org-avatar__dialog-dropzone--${j}`,{"pco-org-avatar__dialog-dropzone--image":s||M,"pco-org-avatar__dialog-dropzone--focused":r,"pco-org-avatar__dialog-dropzone--accepted":i,"pco-org-avatar__dialog-dropzone--rejected":o&&a})}),children:[(0,g.jsx)(`input`,{...n()}),s?(0,g.jsx)(`img`,{src:s.preview,alt:`Church logo for ${t}`}):M?(0,g.jsx)(`img`,{src:M,alt:`Church logo for ${t}`}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`svg`,{width:`64`,height:`64`,viewBox:`0 0 16 16`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.toCloudArrow})}),o&&a?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`h2`,{children:`Wrong file type`}),(0,g.jsx)(`p`,{children:`Please upload a PNG or JPG file.`})]}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(S,{open:c}),(0,g.jsx)(`p`,{className:`pco-org-avatar__instructions-sub`,children:`Use a high-quality image (up to 20mb) with a transparent background.`})]})]})]}),(s||M)&&(0,g.jsx)(S,{open:c})]})})]}),(0,g.jsxs)(`div`,{className:`pco-org-avatar__dialog-actions`,children:[e&&j===`light`&&(0,g.jsx)(d.Button,{label:`Remove logo`,kind:`secondary-delete`,onClick:I,loading:T,disabled:T||C,className:`pco-org-avatar__dialog-delete`}),e&&j===`dark`&&(0,g.jsx)(d.Button,{label:`Use light mode logo`,kind:`secondary`,onClick:I,loading:T,disabled:T||C,className:`pco-org-avatar__dialog-delete`}),(0,g.jsx)(d.Button,{type:`button`,label:`Cancel`,onClick:()=>A.current?.close(),disabled:C||T}),(0,g.jsx)(d.Button,{type:`submit`,label:`Update logo`,kind:`primary`,loading:C,disabled:!s||C||T})]})]})}),document.body)]})}function w({avatarUrl:e,darkModeAvatarUrl:t,orgName:n,onAvatarUpdate:r,pcoEnv:i,readOnly:a,showDarkModeAvatar:o=!1}){let[s,l]=(0,c.useState)(e),[u,d]=(0,c.useState)(t),f=(e,t)=>{e===`avatar`?(l(t),r?.(`avatar`,t)):e===`dark_mode_avatar`&&(d(t),r?.(`dark_mode_avatar`,t))};return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)(`div`,{className:`pco-org-avatars`,children:[(0,g.jsx)(C,{avatarUrl:s,organization:n,mode:`avatar`,pcoEnv:i,readOnly:a,onAvatarUpdate:f}),o&&(0,g.jsx)(C,{avatarUrl:u,organization:n,mode:`dark_mode_avatar`,pcoEnv:i,readOnly:a,onAvatarUpdate:f,fallbackAvatarUrl:s})]}),o&&s&&!u&&(0,g.jsxs)(`div`,{className:`pco-org-avatar-alert`,children:[(0,g.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 16 16`,className:`symbol`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.infoCircle})}),(0,g.jsx)(`p`,{children:`The same logo is being used for both light and dark modes.`})]})]})}exports.OrganizationAvatars=w;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("react"),l=require("react-dom"),u=require("@planningcenter/url"),d=require("@planningcenter/tapestry"),f=require("@planningcenter/sweetest-alert"),p=require("@planningcenter/icons/paths/general"),m=require("@planningcenter/icons/paths/services"),h=require("react-dropzone");h=s(h,1);let g=require("react/jsx-runtime");function _(e){var t,n,r=``;if(typeof e==`string`||typeof e==`number`)r+=e;else if(typeof e==`object`)if(Array.isArray(e)){var i=e.length;for(t=0;t<i;t++)e[t]&&(n=_(e[t]))&&(r&&(r+=` `),r+=n)}else for(n in e)e[n]&&(r&&(r+=` `),r+=n);return r}function v(){for(var e,t,n=0,r=``,i=arguments.length;n<i;n++)(e=arguments[n])&&(t=_(e))&&(r&&(r+=` `),r+=t);return r}function y(){let e=document.querySelector(`meta[name="csrf-token"]`);if(!e||!e.content)throw Error(`CSRF token not found. Ensure your Rails application includes <meta name="csrf-token" content="..."> in the document head.`);return e.content}function b(e){let t=e.split(``);return[t.shift()?.toUpperCase(),t.join(``)].join(``)}var x=5e3;function S(e){return new Promise(t=>{let n=new Image,r=setTimeout(()=>t(null),x);n.onload=()=>{clearTimeout(r),t({width:n.naturalWidth,height:n.naturalHeight})},n.onerror=()=>{clearTimeout(r),t(null)},n.src=e})}var C=4e7,w=e=>e===`dark_mode_avatar`?`dark`:`light`,T=({open:e})=>(0,g.jsxs)(`h2`,{className:`pco-org-avatar__instructions`,children:[`Drag & drop your logo file to upload, or`,` `,(0,g.jsx)(d.Button,{label:`browse`,kind:`inline-text`,onClick:t=>{t.stopPropagation(),e()}})]});function E({avatarUrl:e,organization:t,mode:n,pcoEnv:r,readOnly:i,onAvatarUpdate:a,fallbackAvatarUrl:o}){let[s,_]=(0,c.useState)(null),[x,E]=(0,c.useState)(!1),[D,O]=(0,c.useState)(!1),[k,A]=(0,c.useState)(``),j=(0,c.useId)(),M=(0,c.useRef)(null),N=(0,c.useRef)(0),P=w(n),F=e||o,I=async e=>{let[t]=e;if(!t)return;let n=++N.current;A(``);let r=URL.createObjectURL(t),i=await S(r);if(n!==N.current){URL.revokeObjectURL(r);return}if(i&&i.width*i.height>C){URL.revokeObjectURL(r),_(null),A(`Image is too large. Resize it to under 6000 × 6000 pixels and try again.`);return}_(Object.assign(t,{preview:r}))};(0,c.useEffect)(()=>()=>{N.current+=1},[]),(0,c.useEffect)(()=>()=>{s?.preview&&URL.revokeObjectURL(s.preview)},[s]);let L=async e=>{let t=await fetch((0,u.pcoApiUrl)(`accounts`,{env:r}),{method:`PATCH`,headers:{"Content-Type":`application/json`,"X-CSRF-Token":y(),Accept:`application/json`},body:JSON.stringify({data:{attributes:e}})}),n=await t.json();if(!t.ok)throw n;return n},R=async e=>{if(e.preventDefault(),!(!s||x||D)){E(!0);try{let e=new FileReader,t=await new Promise((t,n)=>{e.onloadend=()=>t(e.result),e.onerror=n,e.readAsDataURL(s)}),r=await L({[n]:t,[`${n}_cache`]:``});_(null),a(n,r.data.attributes[n].url),M.current?.close()}catch{A(`We were unable to save your avatar.`)}finally{E(!1)}}},z=async()=>{x||D||(O(!0),(0,f.SweetestAlert)({type:`danger`,title:`Remove this logo?`,content:P===`light`?`Removing this logo means no logo will appear in light mode. This cannot be undone.`:o?`Removing this logo means your light mode logo will appear in dark mode. This cannot be undone.`:`Removing this logo means no logo will appear in dark mode. This cannot be undone.`,confirmButton:`Remove logo`,onConfirm:async()=>{try{await L({[`remove_${n}`]:`1`}),a(n,``),M.current?.close()}catch{A(`We were unable to delete your avatar.`)}finally{O(!1)}},onCancel:()=>{O(!1)}}))};return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)(`div`,{className:`pco-org-avatar`,children:[(0,g.jsx)(`button`,{type:`button`,onClick:()=>M.current?.showModal(),disabled:i,className:`pco-org-avatar__button pco-org-avatar__button--${P}`,children:F?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`img`,{src:F,alt:`Church logo for ${t}`}),(0,g.jsx)(`div`,{className:`tds-btn tds-btn--interaction tds-btn--icononly`,children:(0,g.jsx)(`svg`,{width:`14`,height:`14`,viewBox:`0 0 16 16`,fill:`currentColor`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.pencil})})})]}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`svg`,{width:`48`,height:`48`,viewBox:`0 0 16 16`,fill:`currentColor`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:m.image})}),(0,g.jsx)(`div`,{className:`tds-btn tds-btn--interaction tds-btn--icononly`,children:(0,g.jsx)(`svg`,{width:`14`,height:`14`,viewBox:`0 0 16 16`,fill:`currentColor`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.pencil})})})]})}),(0,g.jsxs)(`div`,{className:`pco-org-avatar__label`,children:[b(P),` mode`]})]}),(0,l.createPortal)((0,g.jsx)(`dialog`,{id:j,ref:M,className:`pco-org-avatar__dialog`,onClose:()=>{N.current+=1,_(null),A(``)},children:(0,g.jsxs)(`form`,{onSubmit:R,children:[(0,g.jsxs)(`div`,{className:`pco-org-avatar__dialog-header`,children:[(0,g.jsxs)(`h1`,{className:`pco-org-avatar__dialog-title`,children:[`Church logo — `,P,` mode`]}),(0,g.jsx)(`button`,{type:`button`,onClick:()=>M.current?.close(),className:`pco-org-avatar__dialog-close`,"aria-label":`Close modal`,children:(0,g.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 16 16`,fill:`currentColor`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.smallX})})})]}),(0,g.jsxs)(`div`,{className:`pco-org-avatar__dialog-body`,children:[k&&(0,g.jsxs)(`div`,{role:`alert`,className:`pco-org-avatar-alert pco-org-avatar__dialog-alert`,children:[(0,g.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 16 16`,className:`symbol`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.exclamationTriangle})}),(0,g.jsx)(`p`,{children:k})]}),(0,g.jsx)(h.default,{accept:{"image/*":[`.jpg`,`.jpeg`,`.png`]},multiple:!1,onDropAccepted:I,children:({getRootProps:e,getInputProps:n,isFocused:r,isDragAccept:i,isDragReject:a,isDragActive:o,open:c})=>(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)(`div`,{...e({className:v(`pco-org-avatar__dialog-dropzone`,`pco-org-avatar__dialog-dropzone--${P}`,{"pco-org-avatar__dialog-dropzone--image":s||F,"pco-org-avatar__dialog-dropzone--focused":r,"pco-org-avatar__dialog-dropzone--accepted":i,"pco-org-avatar__dialog-dropzone--rejected":o&&a})}),children:[(0,g.jsx)(`input`,{...n()}),s?(0,g.jsx)(`img`,{src:s.preview,alt:`Church logo for ${t}`}):F?(0,g.jsx)(`img`,{src:F,alt:`Church logo for ${t}`}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`svg`,{width:`64`,height:`64`,viewBox:`0 0 16 16`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.toCloudArrow})}),o&&a?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`h2`,{children:`Wrong file type`}),(0,g.jsx)(`p`,{children:`Please upload a PNG or JPG file.`})]}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(T,{open:c}),(0,g.jsx)(`p`,{className:`pco-org-avatar__instructions-sub`,children:`Use a high-quality image (up to 25 MB) with a transparent background.`})]})]})]}),(s||F)&&(0,g.jsx)(T,{open:c})]})})]}),(0,g.jsxs)(`div`,{className:`pco-org-avatar__dialog-actions`,children:[e&&P===`light`&&(0,g.jsx)(d.Button,{label:`Remove logo`,kind:`secondary-delete`,onClick:z,loading:D,disabled:D||x,className:`pco-org-avatar__dialog-delete`}),e&&P===`dark`&&(0,g.jsx)(d.Button,{label:`Use light mode logo`,kind:`secondary`,onClick:z,loading:D,disabled:D||x,className:`pco-org-avatar__dialog-delete`}),(0,g.jsx)(d.Button,{type:`button`,label:`Cancel`,onClick:()=>M.current?.close(),disabled:x||D}),(0,g.jsx)(d.Button,{type:`submit`,label:`Update logo`,kind:`primary`,loading:x,disabled:!s||x||D})]})]})}),document.body)]})}function D({avatarUrl:e,darkModeAvatarUrl:t,orgName:n,onAvatarUpdate:r,pcoEnv:i,readOnly:a,showDarkModeAvatar:o=!1}){let[s,l]=(0,c.useState)(e),[u,d]=(0,c.useState)(t),f=(e,t)=>{e===`avatar`?(l(t),r?.(`avatar`,t)):e===`dark_mode_avatar`&&(d(t),r?.(`dark_mode_avatar`,t))};return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)(`div`,{className:`pco-org-avatars`,children:[(0,g.jsx)(E,{avatarUrl:s,organization:n,mode:`avatar`,pcoEnv:i,readOnly:a,onAvatarUpdate:f}),o&&(0,g.jsx)(E,{avatarUrl:u,organization:n,mode:`dark_mode_avatar`,pcoEnv:i,readOnly:a,onAvatarUpdate:f,fallbackAvatarUrl:s})]}),o&&s&&!u&&(0,g.jsxs)(`div`,{className:`pco-org-avatar-alert`,children:[(0,g.jsx)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 16 16`,className:`symbol`,"aria-hidden":`true`,children:(0,g.jsx)(`path`,{d:p.infoCircle})}),(0,g.jsx)(`p`,{children:`The same logo is being used for both light and dark modes.`})]})]})}exports.OrganizationAvatars=D;
package/dist/index.js CHANGED
@@ -32,9 +32,23 @@ function x(e) {
32
32
  let t = e.split("");
33
33
  return [t.shift()?.toUpperCase(), t.join("")].join("");
34
34
  }
35
+ var S = 5e3;
36
+ function C(e) {
37
+ return new Promise((t) => {
38
+ let n = new Image(), r = setTimeout(() => t(null), S);
39
+ n.onload = () => {
40
+ clearTimeout(r), t({
41
+ width: n.naturalWidth,
42
+ height: n.naturalHeight
43
+ });
44
+ }, n.onerror = () => {
45
+ clearTimeout(r), t(null);
46
+ }, n.src = e;
47
+ });
48
+ }
35
49
  //#endregion
36
50
  //#region src/organization_avatar.tsx
37
- var S = (e) => e === "dark_mode_avatar" ? "dark" : "light", C = ({ open: e }) => /* @__PURE__ */ _("h2", {
51
+ var w = 4e7, T = (e) => e === "dark_mode_avatar" ? "dark" : "light", E = ({ open: e }) => /* @__PURE__ */ _("h2", {
38
52
  className: "pco-org-avatar__instructions",
39
53
  children: [
40
54
  "Drag & drop your logo file to upload, or",
@@ -48,16 +62,30 @@ var S = (e) => e === "dark_mode_avatar" ? "dark" : "light", C = ({ open: e }) =>
48
62
  })
49
63
  ]
50
64
  });
51
- function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onAvatarUpdate: D, fallbackAvatarUrl: O }) {
52
- let [k, A] = r(null), [j, M] = r(!1), [N, P] = r(!1), [F, I] = r(""), L = t(), R = n(null), z = S(w), B = l || O, V = (e) => {
65
+ function D({ avatarUrl: l, organization: v, mode: S, pcoEnv: D, readOnly: O, onAvatarUpdate: k, fallbackAvatarUrl: A }) {
66
+ let [j, M] = r(null), [N, P] = r(!1), [F, I] = r(!1), [L, R] = r(""), z = t(), B = n(null), V = n(0), H = T(S), U = l || A, W = async (e) => {
53
67
  let [t] = e;
54
- t && A(Object.assign(t, { preview: URL.createObjectURL(t) }));
68
+ if (!t) return;
69
+ let n = ++V.current;
70
+ R("");
71
+ let r = URL.createObjectURL(t), i = await C(r);
72
+ if (n !== V.current) {
73
+ URL.revokeObjectURL(r);
74
+ return;
75
+ }
76
+ if (i && i.width * i.height > w) {
77
+ URL.revokeObjectURL(r), M(null), R("Image is too large. Resize it to under 6000 × 6000 pixels and try again.");
78
+ return;
79
+ }
80
+ M(Object.assign(t, { preview: r }));
55
81
  };
56
82
  e(() => () => {
57
- k?.preview && (URL.revokeObjectURL(k.preview), I(""));
58
- }, [k]);
59
- let H = async (e) => {
60
- let t = await fetch(a("accounts", { env: T }), {
83
+ V.current += 1;
84
+ }, []), e(() => () => {
85
+ j?.preview && URL.revokeObjectURL(j.preview);
86
+ }, [j]);
87
+ let G = async (e) => {
88
+ let t = await fetch(a("accounts", { env: D }), {
61
89
  method: "PATCH",
62
90
  headers: {
63
91
  "Content-Type": "application/json",
@@ -68,40 +96,40 @@ function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onA
68
96
  }), n = await t.json();
69
97
  if (!t.ok) throw n;
70
98
  return n;
71
- }, U = async (e) => {
72
- if (e.preventDefault(), !(!k || j || N)) {
73
- M(!0);
99
+ }, K = async (e) => {
100
+ if (e.preventDefault(), !(!j || N || F)) {
101
+ P(!0);
74
102
  try {
75
103
  let e = new FileReader(), t = await new Promise((t, n) => {
76
- e.onloadend = () => t(e.result), e.onerror = n, e.readAsDataURL(k);
77
- }), n = await H({
78
- [w]: t,
79
- [`${w}_cache`]: ""
104
+ e.onloadend = () => t(e.result), e.onerror = n, e.readAsDataURL(j);
105
+ }), n = await G({
106
+ [S]: t,
107
+ [`${S}_cache`]: ""
80
108
  });
81
- A(null), D(w, n.data.attributes[w].url), R.current?.close();
109
+ M(null), k(S, n.data.attributes[S].url), B.current?.close();
82
110
  } catch {
83
- I("We were unable to save your avatar.");
111
+ R("We were unable to save your avatar.");
84
112
  } finally {
85
- M(!1);
113
+ P(!1);
86
114
  }
87
115
  }
88
- }, W = async () => {
89
- j || N || (P(!0), s({
116
+ }, q = async () => {
117
+ N || F || (I(!0), s({
90
118
  type: "danger",
91
119
  title: "Remove this logo?",
92
- content: z === "light" ? "Removing this logo means no logo will appear in light mode. This cannot be undone." : O ? "Removing this logo means your light mode logo will appear in dark mode. This cannot be undone." : "Removing this logo means no logo will appear in dark mode. This cannot be undone.",
120
+ content: H === "light" ? "Removing this logo means no logo will appear in light mode. This cannot be undone." : A ? "Removing this logo means your light mode logo will appear in dark mode. This cannot be undone." : "Removing this logo means no logo will appear in dark mode. This cannot be undone.",
93
121
  confirmButton: "Remove logo",
94
122
  onConfirm: async () => {
95
123
  try {
96
- await H({ [`remove_${w}`]: "1" }), D(w, ""), R.current?.close();
124
+ await G({ [`remove_${S}`]: "1" }), k(S, ""), B.current?.close();
97
125
  } catch {
98
- I("We were unable to delete your avatar.");
126
+ R("We were unable to delete your avatar.");
99
127
  } finally {
100
- P(!1);
128
+ I(!1);
101
129
  }
102
130
  },
103
131
  onCancel: () => {
104
- P(!1);
132
+ I(!1);
105
133
  }
106
134
  }));
107
135
  };
@@ -109,11 +137,11 @@ function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onA
109
137
  className: "pco-org-avatar",
110
138
  children: [/* @__PURE__ */ g("button", {
111
139
  type: "button",
112
- onClick: () => R.current?.showModal(),
113
- disabled: E,
114
- className: `pco-org-avatar__button pco-org-avatar__button--${z}`,
115
- children: B ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("img", {
116
- src: B,
140
+ onClick: () => B.current?.showModal(),
141
+ disabled: O,
142
+ className: `pco-org-avatar__button pco-org-avatar__button--${H}`,
143
+ children: U ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("img", {
144
+ src: U,
117
145
  alt: `Church logo for ${v}`
118
146
  }), /* @__PURE__ */ g("div", {
119
147
  className: "tds-btn tds-btn--interaction tds-btn--icononly",
@@ -145,17 +173,17 @@ function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onA
145
173
  })] })
146
174
  }), /* @__PURE__ */ _("div", {
147
175
  className: "pco-org-avatar__label",
148
- children: [x(z), " mode"]
176
+ children: [x(H), " mode"]
149
177
  })]
150
178
  }), i(/* @__PURE__ */ g("dialog", {
151
- id: L,
152
- ref: R,
179
+ id: z,
180
+ ref: B,
153
181
  className: "pco-org-avatar__dialog",
154
182
  onClose: () => {
155
- A(null), I("");
183
+ V.current += 1, M(null), R("");
156
184
  },
157
185
  children: /* @__PURE__ */ _("form", {
158
- onSubmit: U,
186
+ onSubmit: K,
159
187
  children: [
160
188
  /* @__PURE__ */ _("div", {
161
189
  className: "pco-org-avatar__dialog-header",
@@ -163,12 +191,12 @@ function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onA
163
191
  className: "pco-org-avatar__dialog-title",
164
192
  children: [
165
193
  "Church logo — ",
166
- z,
194
+ H,
167
195
  " mode"
168
196
  ]
169
197
  }), /* @__PURE__ */ g("button", {
170
198
  type: "button",
171
- onClick: () => R.current?.close(),
199
+ onClick: () => B.current?.close(),
172
200
  className: "pco-org-avatar__dialog-close",
173
201
  "aria-label": "Close modal",
174
202
  children: /* @__PURE__ */ g("svg", {
@@ -183,7 +211,7 @@ function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onA
183
211
  }),
184
212
  /* @__PURE__ */ _("div", {
185
213
  className: "pco-org-avatar__dialog-body",
186
- children: [F && /* @__PURE__ */ _("div", {
214
+ children: [L && /* @__PURE__ */ _("div", {
187
215
  role: "alert",
188
216
  className: "pco-org-avatar-alert pco-org-avatar__dialog-alert",
189
217
  children: [/* @__PURE__ */ g("svg", {
@@ -193,7 +221,7 @@ function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onA
193
221
  className: "symbol",
194
222
  "aria-hidden": "true",
195
223
  children: /* @__PURE__ */ g("path", { d: c })
196
- }), /* @__PURE__ */ g("p", { children: F })]
224
+ }), /* @__PURE__ */ g("p", { children: L })]
197
225
  }), /* @__PURE__ */ g(m, {
198
226
  accept: { "image/*": [
199
227
  ".jpg",
@@ -201,19 +229,19 @@ function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onA
201
229
  ".png"
202
230
  ] },
203
231
  multiple: !1,
204
- onDropAccepted: V,
232
+ onDropAccepted: W,
205
233
  children: ({ getRootProps: e, getInputProps: t, isFocused: n, isDragAccept: r, isDragReject: i, isDragActive: a, open: o }) => /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ _("div", {
206
- ...e({ className: y("pco-org-avatar__dialog-dropzone", `pco-org-avatar__dialog-dropzone--${z}`, {
207
- "pco-org-avatar__dialog-dropzone--image": k || B,
234
+ ...e({ className: y("pco-org-avatar__dialog-dropzone", `pco-org-avatar__dialog-dropzone--${H}`, {
235
+ "pco-org-avatar__dialog-dropzone--image": j || U,
208
236
  "pco-org-avatar__dialog-dropzone--focused": n,
209
237
  "pco-org-avatar__dialog-dropzone--accepted": r,
210
238
  "pco-org-avatar__dialog-dropzone--rejected": a && i
211
239
  }) }),
212
- children: [/* @__PURE__ */ g("input", { ...t() }), k ? /* @__PURE__ */ g("img", {
213
- src: k.preview,
240
+ children: [/* @__PURE__ */ g("input", { ...t() }), j ? /* @__PURE__ */ g("img", {
241
+ src: j.preview,
214
242
  alt: `Church logo for ${v}`
215
- }) : B ? /* @__PURE__ */ g("img", {
216
- src: B,
243
+ }) : U ? /* @__PURE__ */ g("img", {
244
+ src: U,
217
245
  alt: `Church logo for ${v}`
218
246
  }) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("svg", {
219
247
  width: "64",
@@ -221,44 +249,44 @@ function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onA
221
249
  viewBox: "0 0 16 16",
222
250
  "aria-hidden": "true",
223
251
  children: /* @__PURE__ */ g("path", { d: f })
224
- }), a && i ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("h2", { children: "Wrong file type" }), /* @__PURE__ */ g("p", { children: "Please upload a PNG or JPG file." })] }) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(C, { open: o }), /* @__PURE__ */ g("p", {
252
+ }), a && i ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("h2", { children: "Wrong file type" }), /* @__PURE__ */ g("p", { children: "Please upload a PNG or JPG file." })] }) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(E, { open: o }), /* @__PURE__ */ g("p", {
225
253
  className: "pco-org-avatar__instructions-sub",
226
- children: "Use a high-quality image (up to 20mb) with a transparent background."
254
+ children: "Use a high-quality image (up to 25 MB) with a transparent background."
227
255
  })] })] })]
228
- }), (k || B) && /* @__PURE__ */ g(C, { open: o })] })
256
+ }), (j || U) && /* @__PURE__ */ g(E, { open: o })] })
229
257
  })]
230
258
  }),
231
259
  /* @__PURE__ */ _("div", {
232
260
  className: "pco-org-avatar__dialog-actions",
233
261
  children: [
234
- l && z === "light" && /* @__PURE__ */ g(o, {
262
+ l && H === "light" && /* @__PURE__ */ g(o, {
235
263
  label: "Remove logo",
236
264
  kind: "secondary-delete",
237
- onClick: W,
238
- loading: N,
239
- disabled: N || j,
265
+ onClick: q,
266
+ loading: F,
267
+ disabled: F || N,
240
268
  className: "pco-org-avatar__dialog-delete"
241
269
  }),
242
- l && z === "dark" && /* @__PURE__ */ g(o, {
270
+ l && H === "dark" && /* @__PURE__ */ g(o, {
243
271
  label: "Use light mode logo",
244
272
  kind: "secondary",
245
- onClick: W,
246
- loading: N,
247
- disabled: N || j,
273
+ onClick: q,
274
+ loading: F,
275
+ disabled: F || N,
248
276
  className: "pco-org-avatar__dialog-delete"
249
277
  }),
250
278
  /* @__PURE__ */ g(o, {
251
279
  type: "button",
252
280
  label: "Cancel",
253
- onClick: () => R.current?.close(),
254
- disabled: j || N
281
+ onClick: () => B.current?.close(),
282
+ disabled: N || F
255
283
  }),
256
284
  /* @__PURE__ */ g(o, {
257
285
  type: "submit",
258
286
  label: "Update logo",
259
287
  kind: "primary",
260
- loading: j,
261
- disabled: !k || j || N
288
+ loading: N,
289
+ disabled: !j || N || F
262
290
  })
263
291
  ]
264
292
  })
@@ -268,20 +296,20 @@ function w({ avatarUrl: l, organization: v, mode: w, pcoEnv: T, readOnly: E, onA
268
296
  }
269
297
  //#endregion
270
298
  //#region src/organization_avatars.tsx
271
- function T({ avatarUrl: e, darkModeAvatarUrl: t, orgName: n, onAvatarUpdate: i, pcoEnv: a, readOnly: o, showDarkModeAvatar: s = !1 }) {
299
+ function O({ avatarUrl: e, darkModeAvatarUrl: t, orgName: n, onAvatarUpdate: i, pcoEnv: a, readOnly: o, showDarkModeAvatar: s = !1 }) {
272
300
  let [c, u] = r(e), [d, f] = r(t), p = (e, t) => {
273
301
  e === "avatar" ? (u(t), i?.("avatar", t)) : e === "dark_mode_avatar" && (f(t), i?.("dark_mode_avatar", t));
274
302
  };
275
303
  return /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ _("div", {
276
304
  className: "pco-org-avatars",
277
- children: [/* @__PURE__ */ g(w, {
305
+ children: [/* @__PURE__ */ g(D, {
278
306
  avatarUrl: c,
279
307
  organization: n,
280
308
  mode: "avatar",
281
309
  pcoEnv: a,
282
310
  readOnly: o,
283
311
  onAvatarUpdate: p
284
- }), s && /* @__PURE__ */ g(w, {
312
+ }), s && /* @__PURE__ */ g(D, {
285
313
  avatarUrl: d,
286
314
  organization: n,
287
315
  mode: "dark_mode_avatar",
@@ -303,4 +331,4 @@ function T({ avatarUrl: e, darkModeAvatarUrl: t, orgName: n, onAvatarUpdate: i,
303
331
  })] });
304
332
  }
305
333
  //#endregion
306
- export { T as OrganizationAvatars };
334
+ export { O as OrganizationAvatars };
package/dist/utils.d.ts CHANGED
@@ -1,2 +1,6 @@
1
1
  export declare function getCsrfToken(): string;
2
2
  export declare function capitalize(content: string): string;
3
+ export declare function getImageDimensions(src: string): Promise<{
4
+ width: number;
5
+ height: number;
6
+ } | null>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/organization-avatars",
3
- "version": "2.0.5",
3
+ "version": "2.1.0",
4
4
  "description": "Organization avatar upload components for Planning Center apps",
5
5
  "type": "module",
6
6
  "packageManager": "yarn@4.16.0+sha512.5374c94eb4ef6aa8188fb112f20c1aa6569f248d676c5e576e1fd2a1a4d8d87a96df65d9dfe1c2a0252cbe38bda46cf18d955005b81b43cc7607a5c9d56fd2b6",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@planningcenter/icons": "^15.33.0",
34
- "@planningcenter/sweetest-alert": "^2.2.0",
34
+ "@planningcenter/sweetest-alert": "^2.4.0",
35
35
  "@planningcenter/tapestry": ">=3.8.0",
36
36
  "@planningcenter/url": "^3.4.0",
37
37
  "react": "^18.3.0",
@@ -43,8 +43,8 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@planningcenter/icons": "^15.33.0",
46
- "@planningcenter/sweetest-alert": "^2.2.0",
47
- "@planningcenter/tapestry": "^4.6.1",
46
+ "@planningcenter/sweetest-alert": "^2.4.0",
47
+ "@planningcenter/tapestry": "^4.9.0",
48
48
  "@planningcenter/url": "^3.4.0",
49
49
  "@testing-library/dom": "^10.4.1",
50
50
  "@testing-library/jest-dom": "^6.9.1",