@koine/react 2.0.0-beta.125 → 2.0.0-beta.127

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.
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var utils = require('./utils.cjs.js');
6
+
7
+ /**
8
+ * TODO: include in this lib utilities like in https://github.com/react-icons/react-icons/blob/master/packages/react-icons/src/iconBase.tsx
9
+ *
10
+ * this is the `MdAdd` icon from `react-icons`
11
+ */let d=l=>/*#__PURE__*/jsxRuntime.jsxs("svg",{viewBox:"0 0 24 24",fill:"currentColor",stroke:"none",...l,children:[/*#__PURE__*/jsxRuntime.jsx("path",{d:"M0 0h24v24H0z"}),/*#__PURE__*/jsxRuntime.jsx("path",{d:"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"})]}),/**
12
+ * Style for button within a event cell
13
+ *
14
+ * Here we might differentiate week/month view where the first does not get
15
+ * ellipsed btn texts, with `Start` as block element and underneath the `Title`
16
+ * on multiple lines, but that would mean that we loose the ability to interweave
17
+ * single-day events among the spaces left by wider multi-days events.
18
+ */o={overflow:"hidden",whiteSpace:"nowrap",textOverflow:"ellipsis"};let CalendarDaygridCell=({eventClicked:a,setEventClicked:s,// eventHovered,
19
+ setEventHovered:h,view:c,maxEvents:u,events:p,calendarsMap:v,Cell:f="div",CellOverflow:y="div",CellEvent:$="div",CellEventBtn:m="div",CellEventTitle:w="span",CellEventStart:g="span"})=>{let[x,M]=react.useState(!1),O=p.filter(e=>!e.placeholder);return /*#__PURE__*/jsxRuntime.jsx(f,{children:p.map((t,p)=>{if(p===u&&!x)return /*#__PURE__*/jsxRuntime.jsxs(y,{onClick:()=>M(!0),children:[/*#__PURE__*/jsxRuntime.jsx(d,{}),O.length-u]},"overflowMessage"+p);if(p>u&&!x)return null;if(t.placeholder)return /*#__PURE__*/jsxRuntime.jsx(react.Fragment,{children:/*#__PURE__*/jsxRuntime.jsx($,{$placeholder:!0,children:/*#__PURE__*/jsxRuntime.jsx(m,{"aria-hidden":"true",style:{visibility:"hidden"},$placeholder:!0,children:/*#__PURE__*/jsxRuntime.jsx(w,{children:" "})})})},t.key);let f={zIndex:t.firstOfMulti?1:0,// to cover the following event days
20
+ position:"relative",width:t.firstOfMulti?`${100*t.width}%`:"100%"};v[t.calendar.id].on||// @ts-expect-error nevermind
21
+ (o.display="none");let k={$view:c,$selected:a?.uid===t.uid,$past:t.isPast,$color:t.color,$isOutOfRange:t.$isOutOfRange,$isToday:t.$isToday};return /*#__PURE__*/jsxRuntime.jsx(react.Fragment,{children:/*#__PURE__*/jsxRuntime.jsx($,{style:f,...k,children:/*#__PURE__*/jsxRuntime.jsx(m,{role:"button",style:o,...k,onClick:()=>s(e=>e?.uid===t.uid?null:t),onMouseEnter:()=>h(t),onMouseLeave:()=>h(null),children:t.allDay?/*#__PURE__*/jsxRuntime.jsx(w,{children:t.title}):/*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[/*#__PURE__*/jsxRuntime.jsx(g,{children:utils.getDisplayTime(t.start)}),/*#__PURE__*/jsxRuntime.jsx(w,{children:t.title})]})})})},t.key)})})};/* {i === events.length - 1 && isExpanded ? (
22
+ <CellOverflow onClick={() => expand(false)}>
23
+ <IconCollapse />
24
+ Show less
25
+ </CellOverflow>
26
+ ) : null} */
27
+
28
+ exports.CalendarDaygridCell = CalendarDaygridCell;
@@ -0,0 +1,26 @@
1
+ import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
+ import { useState, Fragment } from 'react';
3
+ import { getDisplayTime } from './utils.esm.js';
4
+
5
+ /**
6
+ * TODO: include in this lib utilities like in https://github.com/react-icons/react-icons/blob/master/packages/react-icons/src/iconBase.tsx
7
+ *
8
+ * this is the `MdAdd` icon from `react-icons`
9
+ */let d=l=>/*#__PURE__*/jsxs("svg",{viewBox:"0 0 24 24",fill:"currentColor",stroke:"none",...l,children:[/*#__PURE__*/jsx("path",{d:"M0 0h24v24H0z"}),/*#__PURE__*/jsx("path",{d:"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"})]}),/**
10
+ * Style for button within a event cell
11
+ *
12
+ * Here we might differentiate week/month view where the first does not get
13
+ * ellipsed btn texts, with `Start` as block element and underneath the `Title`
14
+ * on multiple lines, but that would mean that we loose the ability to interweave
15
+ * single-day events among the spaces left by wider multi-days events.
16
+ */o={overflow:"hidden",whiteSpace:"nowrap",textOverflow:"ellipsis"};let CalendarDaygridCell=({eventClicked:a,setEventClicked:s,// eventHovered,
17
+ setEventHovered:h,view:c,maxEvents:u,events:p,calendarsMap:v,Cell:f="div",CellOverflow:y="div",CellEvent:$="div",CellEventBtn:m="div",CellEventTitle:w="span",CellEventStart:g="span"})=>{let[x,M]=useState(!1),O=p.filter(e=>!e.placeholder);return /*#__PURE__*/jsx(f,{children:p.map((t,p)=>{if(p===u&&!x)return /*#__PURE__*/jsxs(y,{onClick:()=>M(!0),children:[/*#__PURE__*/jsx(d,{}),O.length-u]},"overflowMessage"+p);if(p>u&&!x)return null;if(t.placeholder)return /*#__PURE__*/jsx(Fragment,{children:/*#__PURE__*/jsx($,{$placeholder:!0,children:/*#__PURE__*/jsx(m,{"aria-hidden":"true",style:{visibility:"hidden"},$placeholder:!0,children:/*#__PURE__*/jsx(w,{children:" "})})})},t.key);let f={zIndex:t.firstOfMulti?1:0,// to cover the following event days
18
+ position:"relative",width:t.firstOfMulti?`${100*t.width}%`:"100%"};v[t.calendar.id].on||// @ts-expect-error nevermind
19
+ (o.display="none");let k={$view:c,$selected:a?.uid===t.uid,$past:t.isPast,$color:t.color,$isOutOfRange:t.$isOutOfRange,$isToday:t.$isToday};return /*#__PURE__*/jsx(Fragment,{children:/*#__PURE__*/jsx($,{style:f,...k,children:/*#__PURE__*/jsx(m,{role:"button",style:o,...k,onClick:()=>s(e=>e?.uid===t.uid?null:t),onMouseEnter:()=>h(t),onMouseLeave:()=>h(null),children:t.allDay?/*#__PURE__*/jsx(w,{children:t.title}):/*#__PURE__*/jsxs(Fragment$1,{children:[/*#__PURE__*/jsx(g,{children:getDisplayTime(t.start)}),/*#__PURE__*/jsx(w,{children:t.title})]})})})},t.key)})})};/* {i === events.length - 1 && isExpanded ? (
20
+ <CellOverflow onClick={() => expand(false)}>
21
+ <IconCollapse />
22
+ Show less
23
+ </CellOverflow>
24
+ ) : null} */
25
+
26
+ export { CalendarDaygridCell };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var format = require('date-fns/format');
5
+ var useDateLocale = require('./useDateLocale.cjs.js');
6
+
7
+ let KoineCalendarDaygridNav=({range:a,view:l,todayInView:r,handlePrev:i,handleNext:M,handleToday:d,handleView:y,locale:c,NavRoot:m="nav",NavTitle:s="div",NavBtns:b="div",NavBtnPrev:k="button",NavBtnNext:u="button",NavBtnToday:h="button",NavBtnViewMonth:f="button",NavBtnViewWeek:g="button"})=>{let[C,p]=a,v={locale:useDateLocale.useDateLocale(c)},x="";return "month"===l&&(x=format.format(C,"MMMM yyyy",v)),"week"===l&&(x=C.getMonth()===p.getMonth()?format.format(C,"# MMMM yyyy",v).replace("#",`${C.getDate()}-${p.getDate()}`):`${format.format(C,"d MMMM",v)} - ${format.format(p,"d MMMM yyyy",v)}`),/*#__PURE__*/jsxRuntime.jsxs(m,{children:[/*#__PURE__*/jsxRuntime.jsxs(b,{children:[/*#__PURE__*/jsxRuntime.jsx(k,{onClick:i}),/*#__PURE__*/jsxRuntime.jsx(u,{onClick:M}),/*#__PURE__*/jsxRuntime.jsx(h,{onClick:d,disabled:r}),/*#__PURE__*/jsxRuntime.jsx(f,{onClick:()=>y("month"),disabled:"month"===l}),/*#__PURE__*/jsxRuntime.jsx(g,{onClick:()=>y("week"),disabled:"week"===l})]}),/*#__PURE__*/jsxRuntime.jsx(s,{range:a,formatted:x})]})};
8
+
9
+ exports.KoineCalendarDaygridNav = KoineCalendarDaygridNav;
@@ -0,0 +1,7 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { format } from 'date-fns/format';
3
+ import { useDateLocale } from './useDateLocale.esm.js';
4
+
5
+ let KoineCalendarDaygridNav=({range:a,view:l,todayInView:r,handlePrev:i,handleNext:M,handleToday:d,handleView:y,locale:c,NavRoot:m="nav",NavTitle:s="div",NavBtns:b="div",NavBtnPrev:k="button",NavBtnNext:u="button",NavBtnToday:h="button",NavBtnViewMonth:f="button",NavBtnViewWeek:g="button"})=>{let[C,p]=a,v={locale:useDateLocale(c)},x="";return "month"===l&&(x=format(C,"MMMM yyyy",v)),"week"===l&&(x=C.getMonth()===p.getMonth()?format(C,"# MMMM yyyy",v).replace("#",`${C.getDate()}-${p.getDate()}`):`${format(C,"d MMMM",v)} - ${format(p,"d MMMM yyyy",v)}`),/*#__PURE__*/jsxs(m,{children:[/*#__PURE__*/jsxs(b,{children:[/*#__PURE__*/jsx(k,{onClick:i}),/*#__PURE__*/jsx(u,{onClick:M}),/*#__PURE__*/jsx(h,{onClick:d,disabled:r}),/*#__PURE__*/jsx(f,{onClick:()=>y("month"),disabled:"month"===l}),/*#__PURE__*/jsx(g,{onClick:()=>y("week"),disabled:"week"===l})]}),/*#__PURE__*/jsx(s,{range:a,formatted:x})]})};
6
+
7
+ export { KoineCalendarDaygridNav };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var eachWeekOfInterval = require('date-fns/eachWeekOfInterval');
5
+ var react = require('react');
6
+ var reactSwipeable = require('react-swipeable');
7
+ var CalendarDaygridCell = require('./CalendarDaygridCell.cjs.js');
8
+ var useDateLocale = require('./useDateLocale.cjs.js');
9
+ var utils = require('./utils.cjs.js');
10
+
11
+ let KoineCalendarDaygridTable=({locale:d,handlePrev:s,handleNext:c,events:h,dayLabels:f,view:b,range:u,eventClicked:v,setEventClicked:g,eventHovered:w,setEventHovered:y,calendarsMap:x={},maxEvents:j=5,Table:C="table",TableHead:D="thead",TableHeadCell:S="th",TableBody:k="tbody",TableBodyRow:z="tr",TableBodyCell:L="td",TableBodyCellDate:O="div",Cell:I,CellOverflow:K,CellEvent:M,CellEventBtn:R,CellEventTitle:T,CellEventStart:W})=>// ...props
12
+ {let q={Cell:I,CellOverflow:K,CellEvent:M,CellEventBtn:R,CellEventTitle:T,CellEventStart:W},[A,B]=react.useState(f||[0,1,2,3,4,5,6]),[E,F]=react.useState([]),// const [days, setDays] = useState(dayLabels || [...Array(7).keys()]);
13
+ G=useDateLocale.useDateLocale(d),{month:H,weeks:J}=react.useMemo(()=>(function(e){let[t,a]=e,i=eachWeekOfInterval.eachWeekOfInterval({start:t,end:a},{weekStartsOn:1});return {month:t.getMonth(),weeks:i}})(u),[u]),N=reactSwipeable.useSwipeable({onSwipedLeft:c,onSwipedRight:s});return react.useEffect(()=>{F(utils.processEventsInView(h,b,H,J));},[h,b,H,J]),react.useEffect(()=>{G&&G.localize&&!f&&B([1,2,3,4,5,6,0].map(// @ts-expect-error nevermind
14
+ e=>G.localize.day(e,{width:"abbreviated"})));},[G,f]),/*#__PURE__*/jsxRuntime.jsxs(C,{...N,children:[/*#__PURE__*/jsxRuntime.jsx(D,{children:/*#__PURE__*/jsxRuntime.jsx("tr",{children:A.map(t=>/*#__PURE__*/jsxRuntime.jsx(S,{scope:"column",children:t},t))})}),/*#__PURE__*/jsxRuntime.jsx(k,{children:E.map((r,a)=>/*#__PURE__*/jsxRuntime.jsx(z,{...r.props,children:r.days.map(r=>/*#__PURE__*/jsxRuntime.jsxs(L,{...r.props,children:[/*#__PURE__*/jsxRuntime.jsx(O,{...r.props,children:r.label}),r.events.length>0&&/*#__PURE__*/jsxRuntime.jsx(CalendarDaygridCell.CalendarDaygridCell,{eventClicked:v,setEventClicked:g,eventHovered:w,setEventHovered:y,view:b,maxEvents:j,events:r.events,timestamp:r.timestamp,calendarsMap:x,...q})]}))}))})]})};
15
+
16
+ exports.KoineCalendarDaygridTable = KoineCalendarDaygridTable;
@@ -0,0 +1,14 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { eachWeekOfInterval } from 'date-fns/eachWeekOfInterval';
3
+ import { useState, useMemo, useEffect } from 'react';
4
+ import { useSwipeable } from 'react-swipeable';
5
+ import { CalendarDaygridCell } from './CalendarDaygridCell.esm.js';
6
+ import { useDateLocale } from './useDateLocale.esm.js';
7
+ import { processEventsInView } from './utils.esm.js';
8
+
9
+ let KoineCalendarDaygridTable=({locale:d,handlePrev:s,handleNext:c,events:h,dayLabels:f,view:b,range:u,eventClicked:v,setEventClicked:g,eventHovered:w,setEventHovered:y,calendarsMap:x={},maxEvents:j=5,Table:C="table",TableHead:D="thead",TableHeadCell:S="th",TableBody:k="tbody",TableBodyRow:z="tr",TableBodyCell:L="td",TableBodyCellDate:O="div",Cell:I,CellOverflow:K,CellEvent:M,CellEventBtn:R,CellEventTitle:T,CellEventStart:W})=>// ...props
10
+ {let q={Cell:I,CellOverflow:K,CellEvent:M,CellEventBtn:R,CellEventTitle:T,CellEventStart:W},[A,B]=useState(f||[0,1,2,3,4,5,6]),[E,F]=useState([]),// const [days, setDays] = useState(dayLabels || [...Array(7).keys()]);
11
+ G=useDateLocale(d),{month:H,weeks:J}=useMemo(()=>(function(e){let[t,a]=e,i=eachWeekOfInterval({start:t,end:a},{weekStartsOn:1});return {month:t.getMonth(),weeks:i}})(u),[u]),N=useSwipeable({onSwipedLeft:c,onSwipedRight:s});return useEffect(()=>{F(processEventsInView(h,b,H,J));},[h,b,H,J]),useEffect(()=>{G&&G.localize&&!f&&B([1,2,3,4,5,6,0].map(// @ts-expect-error nevermind
12
+ e=>G.localize.day(e,{width:"abbreviated"})));},[G,f]),/*#__PURE__*/jsxs(C,{...N,children:[/*#__PURE__*/jsx(D,{children:/*#__PURE__*/jsx("tr",{children:A.map(t=>/*#__PURE__*/jsx(S,{scope:"column",children:t},t))})}),/*#__PURE__*/jsx(k,{children:E.map((r,a)=>/*#__PURE__*/jsx(z,{...r.props,children:r.days.map(r=>/*#__PURE__*/jsxs(L,{...r.props,children:[/*#__PURE__*/jsx(O,{...r.props,children:r.label}),r.events.length>0&&/*#__PURE__*/jsx(CalendarDaygridCell,{eventClicked:v,setEventClicked:g,eventHovered:w,setEventHovered:y,view:b,maxEvents:j,events:r.events,timestamp:r.timestamp,calendarsMap:x,...q})]}))}))})]})};
13
+
14
+ export { KoineCalendarDaygridTable };
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+
5
+ let KoineCalendarLegend=({calendarsMap:a={},toggleCalendarVisibility:s,LegendItem:d="div",LegendItemStatus:i="span",LegendItemLabel:l="span",LegendItemEvents:t="span"})=>// const sorted = Object.entries(calendarsMap).sort((a, b) => {
6
+ // const { name: nameA } = a[1];
7
+ // const { name: nameB } = b[1];
8
+ // if (nameA < nameB) return -1;
9
+ // else if (nameA > nameB) return 1;
10
+ // else return 0;
11
+ // });
12
+ /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment,{children:Object.entries(a).map(([r,a])=>/*#__PURE__*/jsxRuntime.jsxs(d,{onClick:()=>s(r),$color:a.color,$empty:0===a.events,disabled:0===a.events,children:[/*#__PURE__*/jsxRuntime.jsx(i,{children:a.on?"⬤":"⭘"}),/*#__PURE__*/jsxRuntime.jsx(l,{children:a.name}),/*#__PURE__*/jsxRuntime.jsx(t,{children:a.events})]},"CalendarLegend."+r))});
13
+
14
+ exports.KoineCalendarLegend = KoineCalendarLegend;
@@ -0,0 +1,12 @@
1
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
+
3
+ let KoineCalendarLegend=({calendarsMap:a={},toggleCalendarVisibility:s,LegendItem:d="div",LegendItemStatus:i="span",LegendItemLabel:l="span",LegendItemEvents:t="span"})=>// const sorted = Object.entries(calendarsMap).sort((a, b) => {
4
+ // const { name: nameA } = a[1];
5
+ // const { name: nameB } = b[1];
6
+ // if (nameA < nameB) return -1;
7
+ // else if (nameA > nameB) return 1;
8
+ // else return 0;
9
+ // });
10
+ /*#__PURE__*/jsx(Fragment,{children:Object.entries(a).map(([r,a])=>/*#__PURE__*/jsxs(d,{onClick:()=>s(r),$color:a.color,$empty:0===a.events,disabled:0===a.events,children:[/*#__PURE__*/jsx(i,{children:a.on?"⬤":"⭘"}),/*#__PURE__*/jsx(l,{children:a.name}),/*#__PURE__*/jsx(t,{children:a.events})]},"CalendarLegend."+r))});
11
+
12
+ export { KoineCalendarLegend };
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ var differenceInDays = require('date-fns/differenceInDays');
4
+ var subDays = require('date-fns/subDays');
5
+ var utils$1 = require('@koine/utils');
6
+ var utils = require('./utils.cjs.js');
7
+
8
+ /** Fall back to `process.env.GOOGLE_CALENDAR_API_KEY *//** Start gethering events from date *//** End gethering events at date *//**
9
+ * The default is the time zone of the calendar
10
+ * @see https://developers.google.com/calendar/api/v3/reference/events/list
11
+ *//** The calendars settings */let getCalendarsEventsFromGoogle=async({calendars:e,...t})=>{let a={};return await Promise.all(e.map(async e=>{utils.addCalendarEvents(await o({calendar:e,...t}),a);})),a};/** The calendar settings */async function o({apiKey:i,calendar:o,timeZone:m="",start:d,end:l}){let c={},u=new URLSearchParams({calendarId:o.id,timeZone:m,singleEvents:"true",maxAttendees:"1",maxResults:"9999",sanitizeHtml:"true",timeMin:d.toISOString(),timeMax:l.toISOString(),key:i||process.env.GOOGLE_CALENDAR_API_KEY||""}).toString(),f=/**
12
+ * Google event as it comes from Google's API
13
+ *//**
14
+ * Google calendar as it comes from Google's API
15
+ *//**
16
+ * Google event's date as it comes from Google's API
17
+ *//** When the event is "all day" we have `date` instead of `dateTime` */"https://www.googleapis.com/calendar/v3/calendars/"+o.id+"/events?"+u;try{let i=await fetch(f,{method:"GET"}),m=await i.json();o.name=o.name||m.summary,m.items.forEach(i=>{let m=function(i,o){let m=new Date(i.created),d=i.htmlLink,l=i.summary,c=i.status,u=new Date(i.start.date||i.start.dateTime),f=new Date(i.end.date||i.end.dateTime),w=o.color,g=utils$1.isUndefined(i.end.dateTime)&&utils$1.isString(i.end.date),p=i.location||"",D=i.description||"",// FIXME: he.decode(event.description || '');
18
+ h=m.getTime()+""+u.getTime();// multi-days all day events has as end date the date after to what we actually
19
+ // mean, hence we subtract one day. @see https://support.google.com/calendar/thread/10074544/google-calendar-all-day-events-are-showing-up-as-a-24-hr-event-across-time-zones?hl=en
20
+ g&&f>u&&(f=subDays.subDays(f,1)).setHours(23,59,59);let y=function(){let t=new Date(u),a=new Date(f),n=[utils.getEventTimestamp(t)];for(;differenceInDays.differenceInDays(a,t);)// console.log(title, differenceInDays(to, from))
21
+ t.setDate(t.getDate()+1),n.push(utils.getEventTimestamp(t));return n}(),E=utils$1.arrayToLookup(y),S=y.length>1;return {calendar:o,created:m,link:d,title:l,status:c,start:u,end:f,days:y,daysMap:E,multi:S,color:w,allDay:g,location:p,description:D,uid:h}}(i,o);c[m.uid]=m;});}catch(e){}// if (onError) onError(e);
22
+ return c}
23
+
24
+ exports.getCalendarsEventsFromGoogle = getCalendarsEventsFromGoogle;
@@ -0,0 +1,22 @@
1
+ import { differenceInDays } from 'date-fns/differenceInDays';
2
+ import { subDays } from 'date-fns/subDays';
3
+ import { isUndefined, isString, arrayToLookup } from '@koine/utils';
4
+ import { addCalendarEvents, getEventTimestamp } from './utils.esm.js';
5
+
6
+ /** Fall back to `process.env.GOOGLE_CALENDAR_API_KEY *//** Start gethering events from date *//** End gethering events at date *//**
7
+ * The default is the time zone of the calendar
8
+ * @see https://developers.google.com/calendar/api/v3/reference/events/list
9
+ *//** The calendars settings */let getCalendarsEventsFromGoogle=async({calendars:e,...t})=>{let a={};return await Promise.all(e.map(async e=>{addCalendarEvents(await o({calendar:e,...t}),a);})),a};/** The calendar settings */async function o({apiKey:i,calendar:o,timeZone:m="",start:d,end:l}){let c={},u=new URLSearchParams({calendarId:o.id,timeZone:m,singleEvents:"true",maxAttendees:"1",maxResults:"9999",sanitizeHtml:"true",timeMin:d.toISOString(),timeMax:l.toISOString(),key:i||process.env.GOOGLE_CALENDAR_API_KEY||""}).toString(),f=/**
10
+ * Google event as it comes from Google's API
11
+ *//**
12
+ * Google calendar as it comes from Google's API
13
+ *//**
14
+ * Google event's date as it comes from Google's API
15
+ *//** When the event is "all day" we have `date` instead of `dateTime` */"https://www.googleapis.com/calendar/v3/calendars/"+o.id+"/events?"+u;try{let i=await fetch(f,{method:"GET"}),m=await i.json();o.name=o.name||m.summary,m.items.forEach(i=>{let m=function(i,o){let m=new Date(i.created),d=i.htmlLink,l=i.summary,c=i.status,u=new Date(i.start.date||i.start.dateTime),f=new Date(i.end.date||i.end.dateTime),w=o.color,g=isUndefined(i.end.dateTime)&&isString(i.end.date),p=i.location||"",D=i.description||"",// FIXME: he.decode(event.description || '');
16
+ h=m.getTime()+""+u.getTime();// multi-days all day events has as end date the date after to what we actually
17
+ // mean, hence we subtract one day. @see https://support.google.com/calendar/thread/10074544/google-calendar-all-day-events-are-showing-up-as-a-24-hr-event-across-time-zones?hl=en
18
+ g&&f>u&&(f=subDays(f,1)).setHours(23,59,59);let y=function(){let t=new Date(u),a=new Date(f),n=[getEventTimestamp(t)];for(;differenceInDays(a,t);)// console.log(title, differenceInDays(to, from))
19
+ t.setDate(t.getDate()+1),n.push(getEventTimestamp(t));return n}(),E=arrayToLookup(y),S=y.length>1;return {calendar:o,created:m,link:d,title:l,status:c,start:u,end:f,days:y,daysMap:E,multi:S,color:w,allDay:g,location:p,description:D,uid:h}}(i,o);c[m.uid]=m;});}catch(e){}// if (onError) onError(e);
20
+ return c}
21
+
22
+ export { getCalendarsEventsFromGoogle };
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var calendarApiGoogle = require('./calendar-api-google.cjs.js');
5
+ var utils = require('./utils.cjs.js');
6
+
7
+ /** The locale to format with `date-fns` *//** Calendars infos to use *//** Fall back to `process.env.GOOGLE_CALENDAR_API_KEY *//** The key is the event `uid` *//** It defaults to the first of the current month *//** It defaults to the last day of the current month *//**
8
+ * The calendar view
9
+ * @default "month"
10
+ *//**
11
+ * The default is the time zone of the calendar
12
+ * @see https://developers.google.com/calendar/api/v3/reference/events/list
13
+ */let useCalendar=({locale:d,apiKey:c,calendars:p,events:g,start:m,end:y,view:v="month",timeZone:f="",onError:b})=>{let[w,T]=react.useState(v),D=m||utils.getStartDate(new Date,w),h=y||utils.getEndDate(D,w),[O,P]=react.useState([D,h]),[j,x]=react.useState(utils.isTodayInView(D,h)),[C,L]=react.useState(g||{}),[N,k]=react.useState(null),[q,z]=react.useState(null),[A,B]=react.useReducer((e,t)=>{let{type:l}=t;switch(l){case"events":{let l=t.payload;return Object.entries(e).reduce((e,[t,n])=>(e[t]={...n,events:l[t]||0},e),{})}case"visibility":{let l=t.payload;if("string"==typeof l)return {...e,[l]:{...e[l],on:!e[l].on}};return Object.entries(e).reduce((e,[t,n])=>(e[t]={...n,on:l.indexOf(t)>-1},e),{})}default:return e}},// initial state
14
+ p.reduce((e,t)=>(e[t.id]={...t,name:t.name||"",on:!0,events:0},e),{})),E=react.useCallback(e=>{B({type:"visibility",payload:e});},[B]),F=react.useCallback(e=>{let t={};for(let l in e){let{id:n}=e[l].calendar;t[n]=t[n]||0,t[n]++;}B({type:"events",payload:t});},[]),G=react.useCallback(async(e,t,l)=>{try{let n=await calendarApiGoogle.getCalendarsEventsFromGoogle({apiKey:c,calendars:e,timeZone:f,start:t,end:l});// setEvents(mergeCalendarEvents(events, newEvents));
15
+ L(n);}catch(e){b&&b(e);}},[L,c,f,b]),H=react.useCallback(()=>{let[e,t]=O,l=utils.getStartDate(new Date,w),n=utils.getEndDate(l,w);P([l,n]),// reset event only if we are not on the current view already
16
+ (e.getTime()!==l.getTime()||t.getTime()!==n.getTime())&&(z(null),k(null));},[w,O]),I=react.useCallback(()=>{P(([e])=>{let t=utils.getPrevDate(e,w),l=utils.getEndDate(t,w);return [t,l]}),z(null),k(null);},[w]),J=react.useCallback(()=>{P(([e])=>{let t=utils.getNextDate(e,w),l=utils.getEndDate(t,w);return [t,l]}),z(null),k(null);},[w]),K=react.useCallback(e=>{let t=utils.getStartDate(D,e),l=utils.getEndDate(t,e);P([t,l]),T(e),z(null),k(null);},[D]);return react.useEffect(()=>{let[e,t]=O;G(p,e,t),x(utils.isTodayInView(e,t));},// eslint-disable-next-line react-hooks/exhaustive-deps
17
+ [O]),react.useEffect(()=>{C&&F(C);},[C,F]),// when toggling a calendar we also remove the clicked event if that belongs
18
+ // to a now hidden calendar
19
+ react.useEffect(()=>{q&&!A[q.calendar.id].on&&z(null);},[A,q,z]),{view:w,eventClicked:q,setEventClicked:z,eventHovered:N,setEventHovered:k,getDaygridNavProps:()=>({locale:d,handlePrev:I,handleNext:J,handleToday:H,handleView:K,todayInView:j,range:O,view:w}),getDaygridTableProps:()=>({locale:d,events:C,eventClicked:q,setEventClicked:z,eventHovered:N,setEventHovered:k,handlePrev:I,handleNext:J,calendarsMap:A,range:O,view:w}),getLegendProps:()=>({calendarsMap:A,toggleCalendarVisibility:E})}};
20
+
21
+ exports.useCalendar = useCalendar;
@@ -0,0 +1,19 @@
1
+ import { useState, useReducer, useCallback, useEffect } from 'react';
2
+ import { getCalendarsEventsFromGoogle } from './calendar-api-google.esm.js';
3
+ import { getStartDate, getEndDate, isTodayInView, getPrevDate, getNextDate } from './utils.esm.js';
4
+
5
+ /** The locale to format with `date-fns` *//** Calendars infos to use *//** Fall back to `process.env.GOOGLE_CALENDAR_API_KEY *//** The key is the event `uid` *//** It defaults to the first of the current month *//** It defaults to the last day of the current month *//**
6
+ * The calendar view
7
+ * @default "month"
8
+ *//**
9
+ * The default is the time zone of the calendar
10
+ * @see https://developers.google.com/calendar/api/v3/reference/events/list
11
+ */let useCalendar=({locale:d,apiKey:c,calendars:p,events:g,start:m,end:y,view:v="month",timeZone:f="",onError:b})=>{let[w,T]=useState(v),D=m||getStartDate(new Date,w),h=y||getEndDate(D,w),[O,P]=useState([D,h]),[j,x]=useState(isTodayInView(D,h)),[C,L]=useState(g||{}),[N,k]=useState(null),[q,z]=useState(null),[A,B]=useReducer((e,t)=>{let{type:l}=t;switch(l){case"events":{let l=t.payload;return Object.entries(e).reduce((e,[t,n])=>(e[t]={...n,events:l[t]||0},e),{})}case"visibility":{let l=t.payload;if("string"==typeof l)return {...e,[l]:{...e[l],on:!e[l].on}};return Object.entries(e).reduce((e,[t,n])=>(e[t]={...n,on:l.indexOf(t)>-1},e),{})}default:return e}},// initial state
12
+ p.reduce((e,t)=>(e[t.id]={...t,name:t.name||"",on:!0,events:0},e),{})),E=useCallback(e=>{B({type:"visibility",payload:e});},[B]),F=useCallback(e=>{let t={};for(let l in e){let{id:n}=e[l].calendar;t[n]=t[n]||0,t[n]++;}B({type:"events",payload:t});},[]),G=useCallback(async(e,t,l)=>{try{let n=await getCalendarsEventsFromGoogle({apiKey:c,calendars:e,timeZone:f,start:t,end:l});// setEvents(mergeCalendarEvents(events, newEvents));
13
+ L(n);}catch(e){b&&b(e);}},[L,c,f,b]),H=useCallback(()=>{let[e,t]=O,l=getStartDate(new Date,w),n=getEndDate(l,w);P([l,n]),// reset event only if we are not on the current view already
14
+ (e.getTime()!==l.getTime()||t.getTime()!==n.getTime())&&(z(null),k(null));},[w,O]),I=useCallback(()=>{P(([e])=>{let t=getPrevDate(e,w),l=getEndDate(t,w);return [t,l]}),z(null),k(null);},[w]),J=useCallback(()=>{P(([e])=>{let t=getNextDate(e,w),l=getEndDate(t,w);return [t,l]}),z(null),k(null);},[w]),K=useCallback(e=>{let t=getStartDate(D,e),l=getEndDate(t,e);P([t,l]),T(e),z(null),k(null);},[D]);return useEffect(()=>{let[e,t]=O;G(p,e,t),x(isTodayInView(e,t));},// eslint-disable-next-line react-hooks/exhaustive-deps
15
+ [O]),useEffect(()=>{C&&F(C);},[C,F]),// when toggling a calendar we also remove the clicked event if that belongs
16
+ // to a now hidden calendar
17
+ useEffect(()=>{q&&!A[q.calendar.id].on&&z(null);},[A,q,z]),{view:w,eventClicked:q,setEventClicked:z,eventHovered:N,setEventHovered:k,getDaygridNavProps:()=>({locale:d,handlePrev:I,handleNext:J,handleToday:H,handleView:K,todayInView:j,range:O,view:w}),getDaygridTableProps:()=>({locale:d,events:C,eventClicked:q,setEventClicked:z,eventHovered:N,setEventHovered:k,handlePrev:I,handleNext:J,calendarsMap:A,range:O,view:w}),getLegendProps:()=>({calendarsMap:A,toggleCalendarVisibility:E})}};
18
+
19
+ export { useCalendar };
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ /**
6
+ * Dynamically import the date-fns correct locale
7
+ *
8
+ * Inspired by:
9
+ * @see https://robertmarshall.dev/blog/dynamically-import-datefns-locale-mui-datepicker-localization/
10
+ */let useDateLocale=(a,l="en")=>{let[r,n]=react.useState(),[o,c]=react.useState(l);return(// const [ready, setReady] = useState(false);
11
+ // If the user changes the locale listen to the change and import the locale that is now required.
12
+ react.useEffect(()=>{let e=async()=>{// This webpack option stops all of the date-fns files being imported and chunked.
13
+ // NB: this makes unnecessary numerous webpack chunks in applications
14
+ // that do not even use this hook, so we comment out the webpack dynamic
15
+ // import and its magic comment
16
+ // const localeToSet = await import(
17
+ // /FIXME: * webpackMode: "lazy", webpackChunkName: "df-[index]", webpackExclude: /_lib/ */
18
+ // `date-fns/locale/${locale}/index.js`,
19
+ // );
20
+ let e=await import('date-fns/locale/en-US');c(a||o),n(e.enUS);};// setReady(true);
21
+ // If the locale has not yet been loaded.
22
+ a!==o&&e();},[a,o]),r)};
23
+
24
+ exports.useDateLocale = useDateLocale;
@@ -0,0 +1,22 @@
1
+ import { useState, useEffect } from 'react';
2
+
3
+ /**
4
+ * Dynamically import the date-fns correct locale
5
+ *
6
+ * Inspired by:
7
+ * @see https://robertmarshall.dev/blog/dynamically-import-datefns-locale-mui-datepicker-localization/
8
+ */let useDateLocale=(a,l="en")=>{let[r,n]=useState(),[o,c]=useState(l);return(// const [ready, setReady] = useState(false);
9
+ // If the user changes the locale listen to the change and import the locale that is now required.
10
+ useEffect(()=>{let e=async()=>{// This webpack option stops all of the date-fns files being imported and chunked.
11
+ // NB: this makes unnecessary numerous webpack chunks in applications
12
+ // that do not even use this hook, so we comment out the webpack dynamic
13
+ // import and its magic comment
14
+ // const localeToSet = await import(
15
+ // /FIXME: * webpackMode: "lazy", webpackChunkName: "df-[index]", webpackExclude: /_lib/ */
16
+ // `date-fns/locale/${locale}/index.js`,
17
+ // );
18
+ let e=await import('date-fns/locale/en-US');c(a||o),n(e.enUS);};// setReady(true);
19
+ // If the locale has not yet been loaded.
20
+ a!==o&&e();},[a,o]),r)};
21
+
22
+ export { useDateLocale };
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ var addDays = require('date-fns/addDays');
4
+ var addMonths = require('date-fns/addMonths');
5
+ var addWeeks = require('date-fns/addWeeks');
6
+ var endOfMonth = require('date-fns/endOfMonth');
7
+ var endOfWeek = require('date-fns/endOfWeek');
8
+ var isWithinInterval = require('date-fns/isWithinInterval');
9
+ var startOfWeek = require('date-fns/startOfWeek');
10
+ var subMonths = require('date-fns/subMonths');
11
+ var subWeeks = require('date-fns/subWeeks');
12
+
13
+ let getEventTimestamp=e=>{let t=new Date(e);return t.setHours(0,0,0,0),t.valueOf()/1e3};let getDisplayTime=e=>e.getHours()+":"+"0".repeat(2-e.getMinutes().toString().length)+e.getMinutes();let getStartDate=(e,t)=>(e.setHours(0,0,0),"month"===t?e.setDate(1):"week"===t&&(e=startOfWeek.startOfWeek(e,{weekStartsOn:1})),e);let getEndDate=(e,t)=>{let r=e;return "month"===t?r=endOfMonth.endOfMonth(e):"week"===t&&(r=endOfWeek.endOfWeek(e,{weekStartsOn:1})),r.setHours(23,59,59),r};let getPrevDate=(e,t)=>"month"===t?subMonths.subMonths(e,1):subWeeks.subWeeks(e,1);let getNextDate=(e,a)=>"month"===a?addMonths.addMonths(e,1):addWeeks.addWeeks(e,1);let isTodayInView=(e,t)=>isWithinInterval.isWithinInterval(new Date,{start:e,end:t});let addCalendarEvents=(e,t)=>{for(let r in e){let a=e[r];t[r]=a;}return t};let i=e=>{let t={};for(let r in e){let a=e[r];a.days.forEach(e=>{t[e]=t[e]||{},t[e][r]=a;});}return t},d=e=>{let t=[];for(let r in e)t.push(e[r]);return(// sort events first multi, then all day then by start then by created date
14
+ t.sort((e,t)=>{let r=Number(t.multi)-Number(e.multi),a=Number(t.allDay)-Number(e.allDay),n=e.start.getTime()-t.start.getTime(),s=e.created.getTime()-t.created.getTime();return r||a||n||s}),t)};let processEventsInView=(t,r,a,n)=>{let s=i(t),o=d(t),l=new Date,m=getEventTimestamp(l),p={},f=[];for(let t=0;t<n.length;t++){let i={props:{key:`week.${t}`},days:[]},d=n[t],u=d.getDate(),g=getEventTimestamp(new Date(d)),h=getEventTimestamp(addDays.addDays(new Date(d),6));for(let e=0;e<7;e++){let t=new Date(new Date(d).setDate(u+e)),n=getEventTimestamp(t),f={$isToday:m===n,$isOutOfRange:"month"===r&&t.getMonth()!==a},v={props:{key:`day.${n}`,...f},timestamp:n+"",label:t.getDate()+"",events:[]};// check that we have events in this day
15
+ if(s?.[n]){let t=Object.keys(s[n]).map(()=>0);for(let r=0;r<o.length;r++){let a;let s=o[r],m=1,i=0;if(s.daysMap[n]){// if we already have the information on when the event has been
16
+ // vertically positioned use that index
17
+ if(// only for multi days events:
18
+ s.multi&&(// filter out the days outside of the current week view to avoid
19
+ // making a multi-days event chip wider than the week row or shorter
20
+ // than it should be (when event spans across weeks)
21
+ m=s.days.filter(e=>e>=g&&e<=h).length,// flag the first day of multi-days events, consider that an event
22
+ // might start in a day earlier (hence outside) of the current
23
+ // week/month view, so we always check for Mondays (dayNumber === 0)
24
+ (0===s.days.indexOf(n)||0===e)&&(a=!0)),p[s.uid])i=p[s.uid];else // now look for a free slot and use its index as `top`
25
+ for(let e=0;e<t.length;e++)if(1!==t[e]){i=e;break}// now mark the slot as busy
26
+ t[i]=1,// store the slot vertical position consistently for multi-days events
27
+ a&&(p[s.uid]=i),// push the event, they will be sorted later
28
+ v.events.push({key:`event.${n}-${i}`,...f,...s,isPast:l>s.end,firstOfMulti:a,top:i,width:m});}}// fill the empty slots with events' placeholders
29
+ for(let e=0;e<t.length;e++)1!==t[e]&&v.events.push({key:`event.${n}-${e}}`,placeholder:!0,top:e});// sort events and events placeholders by top position
30
+ v.events.sort((e,t)=>e.top-t.top);}i.days.push(v);}f.push(i);}return f};
31
+
32
+ exports.addCalendarEvents = addCalendarEvents;
33
+ exports.getDisplayTime = getDisplayTime;
34
+ exports.getEndDate = getEndDate;
35
+ exports.getEventTimestamp = getEventTimestamp;
36
+ exports.getNextDate = getNextDate;
37
+ exports.getPrevDate = getPrevDate;
38
+ exports.getStartDate = getStartDate;
39
+ exports.isTodayInView = isTodayInView;
40
+ exports.processEventsInView = processEventsInView;
@@ -0,0 +1,30 @@
1
+ import { addDays } from 'date-fns/addDays';
2
+ import { addMonths } from 'date-fns/addMonths';
3
+ import { addWeeks } from 'date-fns/addWeeks';
4
+ import { endOfMonth } from 'date-fns/endOfMonth';
5
+ import { endOfWeek } from 'date-fns/endOfWeek';
6
+ import { isWithinInterval } from 'date-fns/isWithinInterval';
7
+ import { startOfWeek } from 'date-fns/startOfWeek';
8
+ import { subMonths } from 'date-fns/subMonths';
9
+ import { subWeeks } from 'date-fns/subWeeks';
10
+
11
+ let getEventTimestamp=e=>{let t=new Date(e);return t.setHours(0,0,0,0),t.valueOf()/1e3};let getDisplayTime=e=>e.getHours()+":"+"0".repeat(2-e.getMinutes().toString().length)+e.getMinutes();let getStartDate=(e,t)=>(e.setHours(0,0,0),"month"===t?e.setDate(1):"week"===t&&(e=startOfWeek(e,{weekStartsOn:1})),e);let getEndDate=(e,t)=>{let r=e;return "month"===t?r=endOfMonth(e):"week"===t&&(r=endOfWeek(e,{weekStartsOn:1})),r.setHours(23,59,59),r};let getPrevDate=(e,t)=>"month"===t?subMonths(e,1):subWeeks(e,1);let getNextDate=(e,a)=>"month"===a?addMonths(e,1):addWeeks(e,1);let isTodayInView=(e,t)=>isWithinInterval(new Date,{start:e,end:t});let addCalendarEvents=(e,t)=>{for(let r in e){let a=e[r];t[r]=a;}return t};let i=e=>{let t={};for(let r in e){let a=e[r];a.days.forEach(e=>{t[e]=t[e]||{},t[e][r]=a;});}return t},d=e=>{let t=[];for(let r in e)t.push(e[r]);return(// sort events first multi, then all day then by start then by created date
12
+ t.sort((e,t)=>{let r=Number(t.multi)-Number(e.multi),a=Number(t.allDay)-Number(e.allDay),n=e.start.getTime()-t.start.getTime(),s=e.created.getTime()-t.created.getTime();return r||a||n||s}),t)};let processEventsInView=(t,r,a,n)=>{let s=i(t),o=d(t),l=new Date,m=getEventTimestamp(l),p={},f=[];for(let t=0;t<n.length;t++){let i={props:{key:`week.${t}`},days:[]},d=n[t],u=d.getDate(),g=getEventTimestamp(new Date(d)),h=getEventTimestamp(addDays(new Date(d),6));for(let e=0;e<7;e++){let t=new Date(new Date(d).setDate(u+e)),n=getEventTimestamp(t),f={$isToday:m===n,$isOutOfRange:"month"===r&&t.getMonth()!==a},v={props:{key:`day.${n}`,...f},timestamp:n+"",label:t.getDate()+"",events:[]};// check that we have events in this day
13
+ if(s?.[n]){let t=Object.keys(s[n]).map(()=>0);for(let r=0;r<o.length;r++){let a;let s=o[r],m=1,i=0;if(s.daysMap[n]){// if we already have the information on when the event has been
14
+ // vertically positioned use that index
15
+ if(// only for multi days events:
16
+ s.multi&&(// filter out the days outside of the current week view to avoid
17
+ // making a multi-days event chip wider than the week row or shorter
18
+ // than it should be (when event spans across weeks)
19
+ m=s.days.filter(e=>e>=g&&e<=h).length,// flag the first day of multi-days events, consider that an event
20
+ // might start in a day earlier (hence outside) of the current
21
+ // week/month view, so we always check for Mondays (dayNumber === 0)
22
+ (0===s.days.indexOf(n)||0===e)&&(a=!0)),p[s.uid])i=p[s.uid];else // now look for a free slot and use its index as `top`
23
+ for(let e=0;e<t.length;e++)if(1!==t[e]){i=e;break}// now mark the slot as busy
24
+ t[i]=1,// store the slot vertical position consistently for multi-days events
25
+ a&&(p[s.uid]=i),// push the event, they will be sorted later
26
+ v.events.push({key:`event.${n}-${i}`,...f,...s,isPast:l>s.end,firstOfMulti:a,top:i,width:m});}}// fill the empty slots with events' placeholders
27
+ for(let e=0;e<t.length;e++)1!==t[e]&&v.events.push({key:`event.${n}-${e}}`,placeholder:!0,top:e});// sort events and events placeholders by top position
28
+ v.events.sort((e,t)=>e.top-t.top);}i.days.push(v);}f.push(i);}return f};
29
+
30
+ export { addCalendarEvents, getDisplayTime, getEndDate, getEventTimestamp, getNextDate, getPrevDate, getStartDate, isTodayInView, processEventsInView };
package/calendar.cjs.js CHANGED
@@ -1,131 +1,17 @@
1
1
  'use strict';
2
2
 
3
- var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('react');
5
- var addDays = require('date-fns/addDays');
6
- var addMonths = require('date-fns/addMonths');
7
- var addWeeks = require('date-fns/addWeeks');
8
- var endOfMonth = require('date-fns/endOfMonth');
9
- var endOfWeek = require('date-fns/endOfWeek');
10
- var isWithinInterval = require('date-fns/isWithinInterval');
11
- var startOfWeek = require('date-fns/startOfWeek');
12
- var subMonths = require('date-fns/subMonths');
13
- var subWeeks = require('date-fns/subWeeks');
14
- var format = require('date-fns/format');
15
- var eachWeekOfInterval = require('date-fns/eachWeekOfInterval');
16
- var reactSwipeable = require('react-swipeable');
17
- var differenceInDays = require('date-fns/differenceInDays');
18
- var subDays = require('date-fns/subDays');
19
- var utils = require('@koine/utils');
3
+ var CalendarDaygridCell = require('./calendar/CalendarDaygridCell.cjs.js');
4
+ var CalendarDaygridNav = require('./calendar/CalendarDaygridNav.cjs.js');
5
+ var CalendarDaygridTable = require('./calendar/CalendarDaygridTable.cjs.js');
6
+ var CalendarLegend = require('./calendar/CalendarLegend.cjs.js');
7
+ var useCalendar = require('./calendar/useCalendar.cjs.js');
8
+ var useDateLocale = require('./calendar/useDateLocale.cjs.js');
20
9
 
21
- let getEventTimestamp=e=>{let t=new Date(e);return t.setHours(0,0,0,0),t.valueOf()/1e3};let getDisplayTime=e=>e.getHours()+":"+"0".repeat(2-e.getMinutes().toString().length)+e.getMinutes();let getStartDate=(e,t)=>(e.setHours(0,0,0),"month"===t?e.setDate(1):"week"===t&&(e=startOfWeek.startOfWeek(e,{weekStartsOn:1})),e);let getEndDate=(e,t)=>{let r=e;return "month"===t?r=endOfMonth.endOfMonth(e):"week"===t&&(r=endOfWeek.endOfWeek(e,{weekStartsOn:1})),r.setHours(23,59,59),r};let getPrevDate=(e,t)=>"month"===t?subMonths.subMonths(e,1):subWeeks.subWeeks(e,1);let getNextDate=(e,a)=>"month"===a?addMonths.addMonths(e,1):addWeeks.addWeeks(e,1);let isTodayInView=(e,t)=>isWithinInterval.isWithinInterval(new Date,{start:e,end:t});let addCalendarEvents=(e,t)=>{for(let r in e){let a=e[r];t[r]=a;}return t};let i=e=>{let t={};for(let r in e){let a=e[r];a.days.forEach(e=>{t[e]=t[e]||{},t[e][r]=a;});}return t},d$1=e=>{let t=[];for(let r in e)t.push(e[r]);return(// sort events first multi, then all day then by start then by created date
22
- t.sort((e,t)=>{let r=Number(t.multi)-Number(e.multi),a=Number(t.allDay)-Number(e.allDay),n=e.start.getTime()-t.start.getTime(),s=e.created.getTime()-t.created.getTime();return r||a||n||s}),t)};let processEventsInView=(t,r,a,n)=>{let s=i(t),o=d$1(t),l=new Date,m=getEventTimestamp(l),p={},f=[];for(let t=0;t<n.length;t++){let i={props:{key:`week.${t}`},days:[]},d=n[t],u=d.getDate(),g=getEventTimestamp(new Date(d)),h=getEventTimestamp(addDays.addDays(new Date(d),6));for(let e=0;e<7;e++){let t=new Date(new Date(d).setDate(u+e)),n=getEventTimestamp(t),f={$isToday:m===n,$isOutOfRange:"month"===r&&t.getMonth()!==a},v={props:{key:`day.${n}`,...f},timestamp:n+"",label:t.getDate()+"",events:[]};// check that we have events in this day
23
- if(s?.[n]){let t=Object.keys(s[n]).map(()=>0);for(let r=0;r<o.length;r++){let a;let s=o[r],m=1,i=0;if(s.daysMap[n]){// if we already have the information on when the event has been
24
- // vertically positioned use that index
25
- if(// only for multi days events:
26
- s.multi&&(// filter out the days outside of the current week view to avoid
27
- // making a multi-days event chip wider than the week row or shorter
28
- // than it should be (when event spans across weeks)
29
- m=s.days.filter(e=>e>=g&&e<=h).length,// flag the first day of multi-days events, consider that an event
30
- // might start in a day earlier (hence outside) of the current
31
- // week/month view, so we always check for Mondays (dayNumber === 0)
32
- (0===s.days.indexOf(n)||0===e)&&(a=!0)),p[s.uid])i=p[s.uid];else // now look for a free slot and use its index as `top`
33
- for(let e=0;e<t.length;e++)if(1!==t[e]){i=e;break}// now mark the slot as busy
34
- t[i]=1,// store the slot vertical position consistently for multi-days events
35
- a&&(p[s.uid]=i),// push the event, they will be sorted later
36
- v.events.push({key:`event.${n}-${i}`,...f,...s,isPast:l>s.end,firstOfMulti:a,top:i,width:m});}}// fill the empty slots with events' placeholders
37
- for(let e=0;e<t.length;e++)1!==t[e]&&v.events.push({key:`event.${n}-${e}}`,placeholder:!0,top:e});// sort events and events placeholders by top position
38
- v.events.sort((e,t)=>e.top-t.top);}i.days.push(v);}f.push(i);}return f};
39
10
 
40
- /**
41
- * TODO: include in this lib utilities like in https://github.com/react-icons/react-icons/blob/master/packages/react-icons/src/iconBase.tsx
42
- *
43
- * this is the `MdAdd` icon from `react-icons`
44
- */let d=l=>/*#__PURE__*/jsxRuntime.jsxs("svg",{viewBox:"0 0 24 24",fill:"currentColor",stroke:"none",...l,children:[/*#__PURE__*/jsxRuntime.jsx("path",{d:"M0 0h24v24H0z"}),/*#__PURE__*/jsxRuntime.jsx("path",{d:"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"})]}),/**
45
- * Style for button within a event cell
46
- *
47
- * Here we might differentiate week/month view where the first does not get
48
- * ellipsed btn texts, with `Start` as block element and underneath the `Title`
49
- * on multiple lines, but that would mean that we loose the ability to interweave
50
- * single-day events among the spaces left by wider multi-days events.
51
- */o$1={overflow:"hidden",whiteSpace:"nowrap",textOverflow:"ellipsis"};let CalendarDaygridCell=({eventClicked:a,setEventClicked:s,// eventHovered,
52
- setEventHovered:h,view:c,maxEvents:u,events:p,calendarsMap:v,Cell:f="div",CellOverflow:y="div",CellEvent:$="div",CellEventBtn:m="div",CellEventTitle:w="span",CellEventStart:g="span"})=>{let[x,M]=react.useState(!1),O=p.filter(e=>!e.placeholder);return /*#__PURE__*/jsxRuntime.jsx(f,{children:p.map((t,p)=>{if(p===u&&!x)return /*#__PURE__*/jsxRuntime.jsxs(y,{onClick:()=>M(!0),children:[/*#__PURE__*/jsxRuntime.jsx(d,{}),O.length-u]},"overflowMessage"+p);if(p>u&&!x)return null;if(t.placeholder)return /*#__PURE__*/jsxRuntime.jsx(react.Fragment,{children:/*#__PURE__*/jsxRuntime.jsx($,{$placeholder:!0,children:/*#__PURE__*/jsxRuntime.jsx(m,{"aria-hidden":"true",style:{visibility:"hidden"},$placeholder:!0,children:/*#__PURE__*/jsxRuntime.jsx(w,{children:" "})})})},t.key);let f={zIndex:t.firstOfMulti?1:0,// to cover the following event days
53
- position:"relative",width:t.firstOfMulti?`${100*t.width}%`:"100%"};v[t.calendar.id].on||// @ts-expect-error nevermind
54
- (o$1.display="none");let k={$view:c,$selected:a?.uid===t.uid,$past:t.isPast,$color:t.color,$isOutOfRange:t.$isOutOfRange,$isToday:t.$isToday};return /*#__PURE__*/jsxRuntime.jsx(react.Fragment,{children:/*#__PURE__*/jsxRuntime.jsx($,{style:f,...k,children:/*#__PURE__*/jsxRuntime.jsx(m,{role:"button",style:o$1,...k,onClick:()=>s(e=>e?.uid===t.uid?null:t),onMouseEnter:()=>h(t),onMouseLeave:()=>h(null),children:t.allDay?/*#__PURE__*/jsxRuntime.jsx(w,{children:t.title}):/*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[/*#__PURE__*/jsxRuntime.jsx(g,{children:getDisplayTime(t.start)}),/*#__PURE__*/jsxRuntime.jsx(w,{children:t.title})]})})})},t.key)})})};/* {i === events.length - 1 && isExpanded ? (
55
- <CellOverflow onClick={() => expand(false)}>
56
- <IconCollapse />
57
- Show less
58
- </CellOverflow>
59
- ) : null} */
60
11
 
61
- /**
62
- * Dynamically import the date-fns correct locale
63
- *
64
- * Inspired by:
65
- * @see https://robertmarshall.dev/blog/dynamically-import-datefns-locale-mui-datepicker-localization/
66
- */let useDateLocale=(a,l="en")=>{let[r,n]=react.useState(),[o,c]=react.useState(l);return(// const [ready, setReady] = useState(false);
67
- // If the user changes the locale listen to the change and import the locale that is now required.
68
- react.useEffect(()=>{let e=async()=>{// This webpack option stops all of the date-fns files being imported and chunked.
69
- // NB: this makes unnecessary numerous webpack chunks in applications
70
- // that do not even use this hook, so we comment out the webpack dynamic
71
- // import and its magic comment
72
- // const localeToSet = await import(
73
- // /FIXME: * webpackMode: "lazy", webpackChunkName: "df-[index]", webpackExclude: /_lib/ */
74
- // `date-fns/locale/${locale}/index.js`,
75
- // );
76
- let e=await import('date-fns/locale/en-US');c(a||o),n(e.enUS);};// setReady(true);
77
- // If the locale has not yet been loaded.
78
- a!==o&&e();},[a,o]),r)};
79
-
80
- let KoineCalendarDaygridNav=({range:a,view:l,todayInView:r,handlePrev:i,handleNext:M,handleToday:d,handleView:y,locale:c,NavRoot:m="nav",NavTitle:s="div",NavBtns:b="div",NavBtnPrev:k="button",NavBtnNext:u="button",NavBtnToday:h="button",NavBtnViewMonth:f="button",NavBtnViewWeek:g="button"})=>{let[C,p]=a,v={locale:useDateLocale(c)},x="";return "month"===l&&(x=format.format(C,"MMMM yyyy",v)),"week"===l&&(x=C.getMonth()===p.getMonth()?format.format(C,"# MMMM yyyy",v).replace("#",`${C.getDate()}-${p.getDate()}`):`${format.format(C,"d MMMM",v)} - ${format.format(p,"d MMMM yyyy",v)}`),/*#__PURE__*/jsxRuntime.jsxs(m,{children:[/*#__PURE__*/jsxRuntime.jsxs(b,{children:[/*#__PURE__*/jsxRuntime.jsx(k,{onClick:i}),/*#__PURE__*/jsxRuntime.jsx(u,{onClick:M}),/*#__PURE__*/jsxRuntime.jsx(h,{onClick:d,disabled:r}),/*#__PURE__*/jsxRuntime.jsx(f,{onClick:()=>y("month"),disabled:"month"===l}),/*#__PURE__*/jsxRuntime.jsx(g,{onClick:()=>y("week"),disabled:"week"===l})]}),/*#__PURE__*/jsxRuntime.jsx(s,{range:a,formatted:x})]})};
81
-
82
- let KoineCalendarDaygridTable=({locale:d,handlePrev:s,handleNext:c,events:h,dayLabels:f,view:b,range:u,eventClicked:v,setEventClicked:g,eventHovered:w,setEventHovered:y,calendarsMap:x={},maxEvents:j=5,Table:C="table",TableHead:D="thead",TableHeadCell:S="th",TableBody:k="tbody",TableBodyRow:z="tr",TableBodyCell:L="td",TableBodyCellDate:O="div",Cell:I,CellOverflow:K,CellEvent:M,CellEventBtn:R,CellEventTitle:T,CellEventStart:W})=>// ...props
83
- {let q={Cell:I,CellOverflow:K,CellEvent:M,CellEventBtn:R,CellEventTitle:T,CellEventStart:W},[A,B]=react.useState(f||[0,1,2,3,4,5,6]),[E,F]=react.useState([]),// const [days, setDays] = useState(dayLabels || [...Array(7).keys()]);
84
- G=useDateLocale(d),{month:H,weeks:J}=react.useMemo(()=>(function(e){let[t,a]=e,i=eachWeekOfInterval.eachWeekOfInterval({start:t,end:a},{weekStartsOn:1});return {month:t.getMonth(),weeks:i}})(u),[u]),N=reactSwipeable.useSwipeable({onSwipedLeft:c,onSwipedRight:s});return react.useEffect(()=>{F(processEventsInView(h,b,H,J));},[h,b,H,J]),react.useEffect(()=>{G&&G.localize&&!f&&B([1,2,3,4,5,6,0].map(// @ts-expect-error nevermind
85
- e=>G.localize.day(e,{width:"abbreviated"})));},[G,f]),/*#__PURE__*/jsxRuntime.jsxs(C,{...N,children:[/*#__PURE__*/jsxRuntime.jsx(D,{children:/*#__PURE__*/jsxRuntime.jsx("tr",{children:A.map(t=>/*#__PURE__*/jsxRuntime.jsx(S,{scope:"column",children:t},t))})}),/*#__PURE__*/jsxRuntime.jsx(k,{children:E.map((r,a)=>/*#__PURE__*/jsxRuntime.jsx(z,{...r.props,children:r.days.map(r=>/*#__PURE__*/jsxRuntime.jsxs(L,{...r.props,children:[/*#__PURE__*/jsxRuntime.jsx(O,{...r.props,children:r.label}),r.events.length>0&&/*#__PURE__*/jsxRuntime.jsx(CalendarDaygridCell,{eventClicked:v,setEventClicked:g,eventHovered:w,setEventHovered:y,view:b,maxEvents:j,events:r.events,timestamp:r.timestamp,calendarsMap:x,...q})]}))}))})]})};
86
-
87
- let KoineCalendarLegend=({calendarsMap:a={},toggleCalendarVisibility:s,LegendItem:d="div",LegendItemStatus:i="span",LegendItemLabel:l="span",LegendItemEvents:t="span"})=>// const sorted = Object.entries(calendarsMap).sort((a, b) => {
88
- // const { name: nameA } = a[1];
89
- // const { name: nameB } = b[1];
90
- // if (nameA < nameB) return -1;
91
- // else if (nameA > nameB) return 1;
92
- // else return 0;
93
- // });
94
- /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment,{children:Object.entries(a).map(([r,a])=>/*#__PURE__*/jsxRuntime.jsxs(d,{onClick:()=>s(r),$color:a.color,$empty:0===a.events,disabled:0===a.events,children:[/*#__PURE__*/jsxRuntime.jsx(i,{children:a.on?"⬤":"⭘"}),/*#__PURE__*/jsxRuntime.jsx(l,{children:a.name}),/*#__PURE__*/jsxRuntime.jsx(t,{children:a.events})]},"CalendarLegend."+r))});
95
-
96
- /** Fall back to `process.env.GOOGLE_CALENDAR_API_KEY *//** Start gethering events from date *//** End gethering events at date *//**
97
- * The default is the time zone of the calendar
98
- * @see https://developers.google.com/calendar/api/v3/reference/events/list
99
- *//** The calendars settings */let getCalendarsEventsFromGoogle=async({calendars:e,...t})=>{let a={};return await Promise.all(e.map(async e=>{addCalendarEvents(await o({calendar:e,...t}),a);})),a};/** The calendar settings */async function o({apiKey:i,calendar:o,timeZone:m="",start:d,end:l}){let c={},u=new URLSearchParams({calendarId:o.id,timeZone:m,singleEvents:"true",maxAttendees:"1",maxResults:"9999",sanitizeHtml:"true",timeMin:d.toISOString(),timeMax:l.toISOString(),key:i||process.env.GOOGLE_CALENDAR_API_KEY||""}).toString(),f=/**
100
- * Google event as it comes from Google's API
101
- *//**
102
- * Google calendar as it comes from Google's API
103
- *//**
104
- * Google event's date as it comes from Google's API
105
- *//** When the event is "all day" we have `date` instead of `dateTime` */"https://www.googleapis.com/calendar/v3/calendars/"+o.id+"/events?"+u;try{let i=await fetch(f,{method:"GET"}),m=await i.json();o.name=o.name||m.summary,m.items.forEach(i=>{let m=function(i,o){let m=new Date(i.created),d=i.htmlLink,l=i.summary,c=i.status,u=new Date(i.start.date||i.start.dateTime),f=new Date(i.end.date||i.end.dateTime),w=o.color,g=utils.isUndefined(i.end.dateTime)&&utils.isString(i.end.date),p=i.location||"",D=i.description||"",// FIXME: he.decode(event.description || '');
106
- h=m.getTime()+""+u.getTime();// multi-days all day events has as end date the date after to what we actually
107
- // mean, hence we subtract one day. @see https://support.google.com/calendar/thread/10074544/google-calendar-all-day-events-are-showing-up-as-a-24-hr-event-across-time-zones?hl=en
108
- g&&f>u&&(f=subDays.subDays(f,1)).setHours(23,59,59);let y=function(){let t=new Date(u),a=new Date(f),n=[getEventTimestamp(t)];for(;differenceInDays.differenceInDays(a,t);)// console.log(title, differenceInDays(to, from))
109
- t.setDate(t.getDate()+1),n.push(getEventTimestamp(t));return n}(),E=utils.arrayToLookup(y),S=y.length>1;return {calendar:o,created:m,link:d,title:l,status:c,start:u,end:f,days:y,daysMap:E,multi:S,color:w,allDay:g,location:p,description:D,uid:h}}(i,o);c[m.uid]=m;});}catch(e){}// if (onError) onError(e);
110
- return c}
111
-
112
- /** The locale to format with `date-fns` *//** Calendars infos to use *//** Fall back to `process.env.GOOGLE_CALENDAR_API_KEY *//** The key is the event `uid` *//** It defaults to the first of the current month *//** It defaults to the last day of the current month *//**
113
- * The calendar view
114
- * @default "month"
115
- *//**
116
- * The default is the time zone of the calendar
117
- * @see https://developers.google.com/calendar/api/v3/reference/events/list
118
- */let useCalendar=({locale:d,apiKey:c,calendars:p,events:g,start:m,end:y,view:v="month",timeZone:f="",onError:b})=>{let[w,T]=react.useState(v),D=m||getStartDate(new Date,w),h=y||getEndDate(D,w),[O,P]=react.useState([D,h]),[j,x]=react.useState(isTodayInView(D,h)),[C,L]=react.useState(g||{}),[N,k]=react.useState(null),[q,z]=react.useState(null),[A,B]=react.useReducer((e,t)=>{let{type:l}=t;switch(l){case"events":{let l=t.payload;return Object.entries(e).reduce((e,[t,n])=>(e[t]={...n,events:l[t]||0},e),{})}case"visibility":{let l=t.payload;if("string"==typeof l)return {...e,[l]:{...e[l],on:!e[l].on}};return Object.entries(e).reduce((e,[t,n])=>(e[t]={...n,on:l.indexOf(t)>-1},e),{})}default:return e}},// initial state
119
- p.reduce((e,t)=>(e[t.id]={...t,name:t.name||"",on:!0,events:0},e),{})),E=react.useCallback(e=>{B({type:"visibility",payload:e});},[B]),F=react.useCallback(e=>{let t={};for(let l in e){let{id:n}=e[l].calendar;t[n]=t[n]||0,t[n]++;}B({type:"events",payload:t});},[]),G=react.useCallback(async(e,t,l)=>{try{let n=await getCalendarsEventsFromGoogle({apiKey:c,calendars:e,timeZone:f,start:t,end:l});// setEvents(mergeCalendarEvents(events, newEvents));
120
- L(n);}catch(e){b&&b(e);}},[L,c,f,b]),H=react.useCallback(()=>{let[e,t]=O,l=getStartDate(new Date,w),n=getEndDate(l,w);P([l,n]),// reset event only if we are not on the current view already
121
- (e.getTime()!==l.getTime()||t.getTime()!==n.getTime())&&(z(null),k(null));},[w,O]),I=react.useCallback(()=>{P(([e])=>{let t=getPrevDate(e,w),l=getEndDate(t,w);return [t,l]}),z(null),k(null);},[w]),J=react.useCallback(()=>{P(([e])=>{let t=getNextDate(e,w),l=getEndDate(t,w);return [t,l]}),z(null),k(null);},[w]),K=react.useCallback(e=>{let t=getStartDate(D,e),l=getEndDate(t,e);P([t,l]),T(e),z(null),k(null);},[D]);return react.useEffect(()=>{let[e,t]=O;G(p,e,t),x(isTodayInView(e,t));},// eslint-disable-next-line react-hooks/exhaustive-deps
122
- [O]),react.useEffect(()=>{C&&F(C);},[C,F]),// when toggling a calendar we also remove the clicked event if that belongs
123
- // to a now hidden calendar
124
- react.useEffect(()=>{q&&!A[q.calendar.id].on&&z(null);},[A,q,z]),{view:w,eventClicked:q,setEventClicked:z,eventHovered:N,setEventHovered:k,getDaygridNavProps:()=>({locale:d,handlePrev:I,handleNext:J,handleToday:H,handleView:K,todayInView:j,range:O,view:w}),getDaygridTableProps:()=>({locale:d,events:C,eventClicked:q,setEventClicked:z,eventHovered:N,setEventHovered:k,handlePrev:I,handleNext:J,calendarsMap:A,range:O,view:w}),getLegendProps:()=>({calendarsMap:A,toggleCalendarVisibility:E})}};
125
-
126
- exports.CalendarDaygridCell = CalendarDaygridCell;
127
- exports.KoineCalendarDaygridNav = KoineCalendarDaygridNav;
128
- exports.KoineCalendarDaygridTable = KoineCalendarDaygridTable;
129
- exports.KoineCalendarLegend = KoineCalendarLegend;
130
- exports.useCalendar = useCalendar;
131
- exports.useDateLocale = useDateLocale;
12
+ exports.CalendarDaygridCell = CalendarDaygridCell.CalendarDaygridCell;
13
+ exports.KoineCalendarDaygridNav = CalendarDaygridNav.KoineCalendarDaygridNav;
14
+ exports.KoineCalendarDaygridTable = CalendarDaygridTable.KoineCalendarDaygridTable;
15
+ exports.KoineCalendarLegend = CalendarLegend.KoineCalendarLegend;
16
+ exports.useCalendar = useCalendar.useCalendar;
17
+ exports.useDateLocale = useDateLocale.useDateLocale;
package/calendar.esm.js CHANGED
@@ -1,124 +1,6 @@
1
- import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
- import { useState, Fragment, useEffect, useMemo, useReducer, useCallback } from 'react';
3
- import { addDays } from 'date-fns/addDays';
4
- import { addMonths } from 'date-fns/addMonths';
5
- import { addWeeks } from 'date-fns/addWeeks';
6
- import { endOfMonth } from 'date-fns/endOfMonth';
7
- import { endOfWeek } from 'date-fns/endOfWeek';
8
- import { isWithinInterval } from 'date-fns/isWithinInterval';
9
- import { startOfWeek } from 'date-fns/startOfWeek';
10
- import { subMonths } from 'date-fns/subMonths';
11
- import { subWeeks } from 'date-fns/subWeeks';
12
- import { format } from 'date-fns/format';
13
- import { eachWeekOfInterval } from 'date-fns/eachWeekOfInterval';
14
- import { useSwipeable } from 'react-swipeable';
15
- import { differenceInDays } from 'date-fns/differenceInDays';
16
- import { subDays } from 'date-fns/subDays';
17
- import { isUndefined, isString, arrayToLookup } from '@koine/utils';
18
-
19
- let getEventTimestamp=e=>{let t=new Date(e);return t.setHours(0,0,0,0),t.valueOf()/1e3};let getDisplayTime=e=>e.getHours()+":"+"0".repeat(2-e.getMinutes().toString().length)+e.getMinutes();let getStartDate=(e,t)=>(e.setHours(0,0,0),"month"===t?e.setDate(1):"week"===t&&(e=startOfWeek(e,{weekStartsOn:1})),e);let getEndDate=(e,t)=>{let r=e;return "month"===t?r=endOfMonth(e):"week"===t&&(r=endOfWeek(e,{weekStartsOn:1})),r.setHours(23,59,59),r};let getPrevDate=(e,t)=>"month"===t?subMonths(e,1):subWeeks(e,1);let getNextDate=(e,a)=>"month"===a?addMonths(e,1):addWeeks(e,1);let isTodayInView=(e,t)=>isWithinInterval(new Date,{start:e,end:t});let addCalendarEvents=(e,t)=>{for(let r in e){let a=e[r];t[r]=a;}return t};let i=e=>{let t={};for(let r in e){let a=e[r];a.days.forEach(e=>{t[e]=t[e]||{},t[e][r]=a;});}return t},d$1=e=>{let t=[];for(let r in e)t.push(e[r]);return(// sort events first multi, then all day then by start then by created date
20
- t.sort((e,t)=>{let r=Number(t.multi)-Number(e.multi),a=Number(t.allDay)-Number(e.allDay),n=e.start.getTime()-t.start.getTime(),s=e.created.getTime()-t.created.getTime();return r||a||n||s}),t)};let processEventsInView=(t,r,a,n)=>{let s=i(t),o=d$1(t),l=new Date,m=getEventTimestamp(l),p={},f=[];for(let t=0;t<n.length;t++){let i={props:{key:`week.${t}`},days:[]},d=n[t],u=d.getDate(),g=getEventTimestamp(new Date(d)),h=getEventTimestamp(addDays(new Date(d),6));for(let e=0;e<7;e++){let t=new Date(new Date(d).setDate(u+e)),n=getEventTimestamp(t),f={$isToday:m===n,$isOutOfRange:"month"===r&&t.getMonth()!==a},v={props:{key:`day.${n}`,...f},timestamp:n+"",label:t.getDate()+"",events:[]};// check that we have events in this day
21
- if(s?.[n]){let t=Object.keys(s[n]).map(()=>0);for(let r=0;r<o.length;r++){let a;let s=o[r],m=1,i=0;if(s.daysMap[n]){// if we already have the information on when the event has been
22
- // vertically positioned use that index
23
- if(// only for multi days events:
24
- s.multi&&(// filter out the days outside of the current week view to avoid
25
- // making a multi-days event chip wider than the week row or shorter
26
- // than it should be (when event spans across weeks)
27
- m=s.days.filter(e=>e>=g&&e<=h).length,// flag the first day of multi-days events, consider that an event
28
- // might start in a day earlier (hence outside) of the current
29
- // week/month view, so we always check for Mondays (dayNumber === 0)
30
- (0===s.days.indexOf(n)||0===e)&&(a=!0)),p[s.uid])i=p[s.uid];else // now look for a free slot and use its index as `top`
31
- for(let e=0;e<t.length;e++)if(1!==t[e]){i=e;break}// now mark the slot as busy
32
- t[i]=1,// store the slot vertical position consistently for multi-days events
33
- a&&(p[s.uid]=i),// push the event, they will be sorted later
34
- v.events.push({key:`event.${n}-${i}`,...f,...s,isPast:l>s.end,firstOfMulti:a,top:i,width:m});}}// fill the empty slots with events' placeholders
35
- for(let e=0;e<t.length;e++)1!==t[e]&&v.events.push({key:`event.${n}-${e}}`,placeholder:!0,top:e});// sort events and events placeholders by top position
36
- v.events.sort((e,t)=>e.top-t.top);}i.days.push(v);}f.push(i);}return f};
37
-
38
- /**
39
- * TODO: include in this lib utilities like in https://github.com/react-icons/react-icons/blob/master/packages/react-icons/src/iconBase.tsx
40
- *
41
- * this is the `MdAdd` icon from `react-icons`
42
- */let d=l=>/*#__PURE__*/jsxs("svg",{viewBox:"0 0 24 24",fill:"currentColor",stroke:"none",...l,children:[/*#__PURE__*/jsx("path",{d:"M0 0h24v24H0z"}),/*#__PURE__*/jsx("path",{d:"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"})]}),/**
43
- * Style for button within a event cell
44
- *
45
- * Here we might differentiate week/month view where the first does not get
46
- * ellipsed btn texts, with `Start` as block element and underneath the `Title`
47
- * on multiple lines, but that would mean that we loose the ability to interweave
48
- * single-day events among the spaces left by wider multi-days events.
49
- */o$1={overflow:"hidden",whiteSpace:"nowrap",textOverflow:"ellipsis"};let CalendarDaygridCell=({eventClicked:a,setEventClicked:s,// eventHovered,
50
- setEventHovered:h,view:c,maxEvents:u,events:p,calendarsMap:v,Cell:f="div",CellOverflow:y="div",CellEvent:$="div",CellEventBtn:m="div",CellEventTitle:w="span",CellEventStart:g="span"})=>{let[x,M]=useState(!1),O=p.filter(e=>!e.placeholder);return /*#__PURE__*/jsx(f,{children:p.map((t,p)=>{if(p===u&&!x)return /*#__PURE__*/jsxs(y,{onClick:()=>M(!0),children:[/*#__PURE__*/jsx(d,{}),O.length-u]},"overflowMessage"+p);if(p>u&&!x)return null;if(t.placeholder)return /*#__PURE__*/jsx(Fragment,{children:/*#__PURE__*/jsx($,{$placeholder:!0,children:/*#__PURE__*/jsx(m,{"aria-hidden":"true",style:{visibility:"hidden"},$placeholder:!0,children:/*#__PURE__*/jsx(w,{children:" "})})})},t.key);let f={zIndex:t.firstOfMulti?1:0,// to cover the following event days
51
- position:"relative",width:t.firstOfMulti?`${100*t.width}%`:"100%"};v[t.calendar.id].on||// @ts-expect-error nevermind
52
- (o$1.display="none");let k={$view:c,$selected:a?.uid===t.uid,$past:t.isPast,$color:t.color,$isOutOfRange:t.$isOutOfRange,$isToday:t.$isToday};return /*#__PURE__*/jsx(Fragment,{children:/*#__PURE__*/jsx($,{style:f,...k,children:/*#__PURE__*/jsx(m,{role:"button",style:o$1,...k,onClick:()=>s(e=>e?.uid===t.uid?null:t),onMouseEnter:()=>h(t),onMouseLeave:()=>h(null),children:t.allDay?/*#__PURE__*/jsx(w,{children:t.title}):/*#__PURE__*/jsxs(Fragment$1,{children:[/*#__PURE__*/jsx(g,{children:getDisplayTime(t.start)}),/*#__PURE__*/jsx(w,{children:t.title})]})})})},t.key)})})};/* {i === events.length - 1 && isExpanded ? (
53
- <CellOverflow onClick={() => expand(false)}>
54
- <IconCollapse />
55
- Show less
56
- </CellOverflow>
57
- ) : null} */
58
-
59
- /**
60
- * Dynamically import the date-fns correct locale
61
- *
62
- * Inspired by:
63
- * @see https://robertmarshall.dev/blog/dynamically-import-datefns-locale-mui-datepicker-localization/
64
- */let useDateLocale=(a,l="en")=>{let[r,n]=useState(),[o,c]=useState(l);return(// const [ready, setReady] = useState(false);
65
- // If the user changes the locale listen to the change and import the locale that is now required.
66
- useEffect(()=>{let e=async()=>{// This webpack option stops all of the date-fns files being imported and chunked.
67
- // NB: this makes unnecessary numerous webpack chunks in applications
68
- // that do not even use this hook, so we comment out the webpack dynamic
69
- // import and its magic comment
70
- // const localeToSet = await import(
71
- // /FIXME: * webpackMode: "lazy", webpackChunkName: "df-[index]", webpackExclude: /_lib/ */
72
- // `date-fns/locale/${locale}/index.js`,
73
- // );
74
- let e=await import('date-fns/locale/en-US');c(a||o),n(e.enUS);};// setReady(true);
75
- // If the locale has not yet been loaded.
76
- a!==o&&e();},[a,o]),r)};
77
-
78
- let KoineCalendarDaygridNav=({range:a,view:l,todayInView:r,handlePrev:i,handleNext:M,handleToday:d,handleView:y,locale:c,NavRoot:m="nav",NavTitle:s="div",NavBtns:b="div",NavBtnPrev:k="button",NavBtnNext:u="button",NavBtnToday:h="button",NavBtnViewMonth:f="button",NavBtnViewWeek:g="button"})=>{let[C,p]=a,v={locale:useDateLocale(c)},x="";return "month"===l&&(x=format(C,"MMMM yyyy",v)),"week"===l&&(x=C.getMonth()===p.getMonth()?format(C,"# MMMM yyyy",v).replace("#",`${C.getDate()}-${p.getDate()}`):`${format(C,"d MMMM",v)} - ${format(p,"d MMMM yyyy",v)}`),/*#__PURE__*/jsxs(m,{children:[/*#__PURE__*/jsxs(b,{children:[/*#__PURE__*/jsx(k,{onClick:i}),/*#__PURE__*/jsx(u,{onClick:M}),/*#__PURE__*/jsx(h,{onClick:d,disabled:r}),/*#__PURE__*/jsx(f,{onClick:()=>y("month"),disabled:"month"===l}),/*#__PURE__*/jsx(g,{onClick:()=>y("week"),disabled:"week"===l})]}),/*#__PURE__*/jsx(s,{range:a,formatted:x})]})};
79
-
80
- let KoineCalendarDaygridTable=({locale:d,handlePrev:s,handleNext:c,events:h,dayLabels:f,view:b,range:u,eventClicked:v,setEventClicked:g,eventHovered:w,setEventHovered:y,calendarsMap:x={},maxEvents:j=5,Table:C="table",TableHead:D="thead",TableHeadCell:S="th",TableBody:k="tbody",TableBodyRow:z="tr",TableBodyCell:L="td",TableBodyCellDate:O="div",Cell:I,CellOverflow:K,CellEvent:M,CellEventBtn:R,CellEventTitle:T,CellEventStart:W})=>// ...props
81
- {let q={Cell:I,CellOverflow:K,CellEvent:M,CellEventBtn:R,CellEventTitle:T,CellEventStart:W},[A,B]=useState(f||[0,1,2,3,4,5,6]),[E,F]=useState([]),// const [days, setDays] = useState(dayLabels || [...Array(7).keys()]);
82
- G=useDateLocale(d),{month:H,weeks:J}=useMemo(()=>(function(e){let[t,a]=e,i=eachWeekOfInterval({start:t,end:a},{weekStartsOn:1});return {month:t.getMonth(),weeks:i}})(u),[u]),N=useSwipeable({onSwipedLeft:c,onSwipedRight:s});return useEffect(()=>{F(processEventsInView(h,b,H,J));},[h,b,H,J]),useEffect(()=>{G&&G.localize&&!f&&B([1,2,3,4,5,6,0].map(// @ts-expect-error nevermind
83
- e=>G.localize.day(e,{width:"abbreviated"})));},[G,f]),/*#__PURE__*/jsxs(C,{...N,children:[/*#__PURE__*/jsx(D,{children:/*#__PURE__*/jsx("tr",{children:A.map(t=>/*#__PURE__*/jsx(S,{scope:"column",children:t},t))})}),/*#__PURE__*/jsx(k,{children:E.map((r,a)=>/*#__PURE__*/jsx(z,{...r.props,children:r.days.map(r=>/*#__PURE__*/jsxs(L,{...r.props,children:[/*#__PURE__*/jsx(O,{...r.props,children:r.label}),r.events.length>0&&/*#__PURE__*/jsx(CalendarDaygridCell,{eventClicked:v,setEventClicked:g,eventHovered:w,setEventHovered:y,view:b,maxEvents:j,events:r.events,timestamp:r.timestamp,calendarsMap:x,...q})]}))}))})]})};
84
-
85
- let KoineCalendarLegend=({calendarsMap:a={},toggleCalendarVisibility:s,LegendItem:d="div",LegendItemStatus:i="span",LegendItemLabel:l="span",LegendItemEvents:t="span"})=>// const sorted = Object.entries(calendarsMap).sort((a, b) => {
86
- // const { name: nameA } = a[1];
87
- // const { name: nameB } = b[1];
88
- // if (nameA < nameB) return -1;
89
- // else if (nameA > nameB) return 1;
90
- // else return 0;
91
- // });
92
- /*#__PURE__*/jsx(Fragment$1,{children:Object.entries(a).map(([r,a])=>/*#__PURE__*/jsxs(d,{onClick:()=>s(r),$color:a.color,$empty:0===a.events,disabled:0===a.events,children:[/*#__PURE__*/jsx(i,{children:a.on?"⬤":"⭘"}),/*#__PURE__*/jsx(l,{children:a.name}),/*#__PURE__*/jsx(t,{children:a.events})]},"CalendarLegend."+r))});
93
-
94
- /** Fall back to `process.env.GOOGLE_CALENDAR_API_KEY *//** Start gethering events from date *//** End gethering events at date *//**
95
- * The default is the time zone of the calendar
96
- * @see https://developers.google.com/calendar/api/v3/reference/events/list
97
- *//** The calendars settings */let getCalendarsEventsFromGoogle=async({calendars:e,...t})=>{let a={};return await Promise.all(e.map(async e=>{addCalendarEvents(await o({calendar:e,...t}),a);})),a};/** The calendar settings */async function o({apiKey:i,calendar:o,timeZone:m="",start:d,end:l}){let c={},u=new URLSearchParams({calendarId:o.id,timeZone:m,singleEvents:"true",maxAttendees:"1",maxResults:"9999",sanitizeHtml:"true",timeMin:d.toISOString(),timeMax:l.toISOString(),key:i||process.env.GOOGLE_CALENDAR_API_KEY||""}).toString(),f=/**
98
- * Google event as it comes from Google's API
99
- *//**
100
- * Google calendar as it comes from Google's API
101
- *//**
102
- * Google event's date as it comes from Google's API
103
- *//** When the event is "all day" we have `date` instead of `dateTime` */"https://www.googleapis.com/calendar/v3/calendars/"+o.id+"/events?"+u;try{let i=await fetch(f,{method:"GET"}),m=await i.json();o.name=o.name||m.summary,m.items.forEach(i=>{let m=function(i,o){let m=new Date(i.created),d=i.htmlLink,l=i.summary,c=i.status,u=new Date(i.start.date||i.start.dateTime),f=new Date(i.end.date||i.end.dateTime),w=o.color,g=isUndefined(i.end.dateTime)&&isString(i.end.date),p=i.location||"",D=i.description||"",// FIXME: he.decode(event.description || '');
104
- h=m.getTime()+""+u.getTime();// multi-days all day events has as end date the date after to what we actually
105
- // mean, hence we subtract one day. @see https://support.google.com/calendar/thread/10074544/google-calendar-all-day-events-are-showing-up-as-a-24-hr-event-across-time-zones?hl=en
106
- g&&f>u&&(f=subDays(f,1)).setHours(23,59,59);let y=function(){let t=new Date(u),a=new Date(f),n=[getEventTimestamp(t)];for(;differenceInDays(a,t);)// console.log(title, differenceInDays(to, from))
107
- t.setDate(t.getDate()+1),n.push(getEventTimestamp(t));return n}(),E=arrayToLookup(y),S=y.length>1;return {calendar:o,created:m,link:d,title:l,status:c,start:u,end:f,days:y,daysMap:E,multi:S,color:w,allDay:g,location:p,description:D,uid:h}}(i,o);c[m.uid]=m;});}catch(e){}// if (onError) onError(e);
108
- return c}
109
-
110
- /** The locale to format with `date-fns` *//** Calendars infos to use *//** Fall back to `process.env.GOOGLE_CALENDAR_API_KEY *//** The key is the event `uid` *//** It defaults to the first of the current month *//** It defaults to the last day of the current month *//**
111
- * The calendar view
112
- * @default "month"
113
- *//**
114
- * The default is the time zone of the calendar
115
- * @see https://developers.google.com/calendar/api/v3/reference/events/list
116
- */let useCalendar=({locale:d,apiKey:c,calendars:p,events:g,start:m,end:y,view:v="month",timeZone:f="",onError:b})=>{let[w,T]=useState(v),D=m||getStartDate(new Date,w),h=y||getEndDate(D,w),[O,P]=useState([D,h]),[j,x]=useState(isTodayInView(D,h)),[C,L]=useState(g||{}),[N,k]=useState(null),[q,z]=useState(null),[A,B]=useReducer((e,t)=>{let{type:l}=t;switch(l){case"events":{let l=t.payload;return Object.entries(e).reduce((e,[t,n])=>(e[t]={...n,events:l[t]||0},e),{})}case"visibility":{let l=t.payload;if("string"==typeof l)return {...e,[l]:{...e[l],on:!e[l].on}};return Object.entries(e).reduce((e,[t,n])=>(e[t]={...n,on:l.indexOf(t)>-1},e),{})}default:return e}},// initial state
117
- p.reduce((e,t)=>(e[t.id]={...t,name:t.name||"",on:!0,events:0},e),{})),E=useCallback(e=>{B({type:"visibility",payload:e});},[B]),F=useCallback(e=>{let t={};for(let l in e){let{id:n}=e[l].calendar;t[n]=t[n]||0,t[n]++;}B({type:"events",payload:t});},[]),G=useCallback(async(e,t,l)=>{try{let n=await getCalendarsEventsFromGoogle({apiKey:c,calendars:e,timeZone:f,start:t,end:l});// setEvents(mergeCalendarEvents(events, newEvents));
118
- L(n);}catch(e){b&&b(e);}},[L,c,f,b]),H=useCallback(()=>{let[e,t]=O,l=getStartDate(new Date,w),n=getEndDate(l,w);P([l,n]),// reset event only if we are not on the current view already
119
- (e.getTime()!==l.getTime()||t.getTime()!==n.getTime())&&(z(null),k(null));},[w,O]),I=useCallback(()=>{P(([e])=>{let t=getPrevDate(e,w),l=getEndDate(t,w);return [t,l]}),z(null),k(null);},[w]),J=useCallback(()=>{P(([e])=>{let t=getNextDate(e,w),l=getEndDate(t,w);return [t,l]}),z(null),k(null);},[w]),K=useCallback(e=>{let t=getStartDate(D,e),l=getEndDate(t,e);P([t,l]),T(e),z(null),k(null);},[D]);return useEffect(()=>{let[e,t]=O;G(p,e,t),x(isTodayInView(e,t));},// eslint-disable-next-line react-hooks/exhaustive-deps
120
- [O]),useEffect(()=>{C&&F(C);},[C,F]),// when toggling a calendar we also remove the clicked event if that belongs
121
- // to a now hidden calendar
122
- useEffect(()=>{q&&!A[q.calendar.id].on&&z(null);},[A,q,z]),{view:w,eventClicked:q,setEventClicked:z,eventHovered:N,setEventHovered:k,getDaygridNavProps:()=>({locale:d,handlePrev:I,handleNext:J,handleToday:H,handleView:K,todayInView:j,range:O,view:w}),getDaygridTableProps:()=>({locale:d,events:C,eventClicked:q,setEventClicked:z,eventHovered:N,setEventHovered:k,handlePrev:I,handleNext:J,calendarsMap:A,range:O,view:w}),getLegendProps:()=>({calendarsMap:A,toggleCalendarVisibility:E})}};
123
-
124
- export { CalendarDaygridCell, KoineCalendarDaygridNav, KoineCalendarDaygridTable, KoineCalendarLegend, useCalendar, useDateLocale };
1
+ export { CalendarDaygridCell } from './calendar/CalendarDaygridCell.esm.js';
2
+ export { KoineCalendarDaygridNav } from './calendar/CalendarDaygridNav.esm.js';
3
+ export { KoineCalendarDaygridTable } from './calendar/CalendarDaygridTable.esm.js';
4
+ export { KoineCalendarLegend } from './calendar/CalendarLegend.esm.js';
5
+ export { useCalendar } from './calendar/useCalendar.esm.js';
6
+ export { useDateLocale } from './calendar/useDateLocale.esm.js';
package/classed.d.ts CHANGED
@@ -4,5 +4,5 @@ type ClassedAugmentedProps<Props> = Props & {
4
4
  ref?: React.Ref<any>;
5
5
  };
6
6
  type ClassedFinalProps<Props, Component> = Component extends React.ReactHTML ? React.HTMLProps<Component> & ClassedAugmentedProps<Props> : ClassedAugmentedProps<Props>;
7
- export declare let classed: <Props, Component extends React.ElementType<any, keyof React.JSX.IntrinsicElements> = any>(component: Component) => (strings: TemplateStringsArray, ...args: ((props: Props) => string)[] | string[]) => React.ForwardRefExoticComponent<React.PropsWithoutRef<ClassedFinalProps<Props, Component>> & React.RefAttributes<Component>>;
7
+ export declare let classed: <Props, Component extends React.ElementType = any>(component: Component) => (strings: TemplateStringsArray, ...args: ((props: Props) => string)[] | string[]) => React.ForwardRefExoticComponent<React.PropsWithoutRef<ClassedFinalProps<Props, Component>> & React.RefAttributes<Component>>;
8
8
  export default classed;
@@ -1,5 +1,5 @@
1
1
  export type ExtendableComponent<Props = any> = React.ForwardRefExoticComponent<Props> | React.ExoticComponent<Props> | React.FC<Props> | ((props: Props) => JSX.Element);
2
- export declare let extendComponent: <Component extends ExtendableComponent<any>, DefaultProps extends {}>(component: Component, defaultProps: DefaultProps) => ((props: React.ComponentProps<Component>) => import("react").FunctionComponentElement<any>) & DefaultProps & {
2
+ export declare let extendComponent: <Component extends ExtendableComponent, DefaultProps extends {}>(component: Component, defaultProps: DefaultProps) => ((props: React.ComponentProps<Component>) => import("react").FunctionComponentElement<any>) & DefaultProps & {
3
3
  defaultProps: DefaultProps;
4
4
  };
5
5
  export interface OverridableComponents {
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ var yup = require('@kuus/yup');
4
+ var utils = require('@koine/utils');
5
+
6
+ /**
7
+ * Encode form
8
+ *
9
+ * Takes a record of yup validations and outputs a `yup` schema with encoded
10
+ * names (antispam technique) and a record of the encoded/decoded input `name`s.
11
+ *
12
+ * We skip the names prefixed wth an underscore which are considered programmatic
13
+ * form data not created by user input.
14
+ *
15
+ * FIXME: types https://github.com/jquense/yup/issues/1700
16
+ */let encodeForm=t=>{let o={},i={};for(let e in t)if(!e.startsWith("_")){let l=utils.encode(e);o[l]=t[e],i[e]=l;}return {encodedSchema:// we need `.required()` to correctly infer the type @see
17
+ // https://github.com/jquense/yup/issues/946
18
+ yup.object(o).required(),encodedNames:i}};/**
19
+ * Decode form data
20
+ *
21
+ * This function is meant to be used inside an api endpoint to gather an encoded
22
+ * form submit data and transform it to the decoded desired json data.
23
+ *
24
+ * Here too we skip encoding/decoding process for names prefixed wth an underscore
25
+ * which are considered programmatic form data not created by user input.
26
+ */let decodeForm=e=>{let r={};for(let i in e){let l=utils.decode(i);// always add underscore prefixed names as they are treated as internal
27
+ // private inputs outside of the honeypot system, normalise them here removing
28
+ // the underscore prefix
29
+ i.startsWith("_")?// @ts-expect-error nevermind
30
+ r[i.substring(1)]=e[i]:utils.isUndefined(e[i])||""!==e[l]||// @ts-expect-error nevermind
31
+ (r[l]=e[i]);}// console.log(formData, decoded, json);
32
+ return r};
33
+
34
+ exports.decodeForm = decodeForm;
35
+ exports.encodeForm = encodeForm;
@@ -10,11 +10,11 @@ export declare let encodeForm: <T extends ObjectShape = {}>(validationRules: T)
10
10
  readonly getter: (data: unknown) => unknown;
11
11
  readonly map?: ((value: unknown) => infer T_1) | undefined;
12
12
  readonly __isYupRef: boolean;
13
- getValue(value: any, parent?: {} | undefined, context?: {} | undefined): infer T_1;
13
+ getValue(value: any, parent?: {}, context?: {}): infer T_1;
14
14
  cast(value: any, options?: {
15
- parent?: {} | undefined;
16
- context?: {} | undefined;
17
- } | undefined): infer T_1;
15
+ parent?: {};
16
+ context?: {};
17
+ }): infer T_1;
18
18
  resolve(): any;
19
19
  describe(): import("@kuus/yup").SchemaRefDescription;
20
20
  toString(): string;
@@ -0,0 +1,32 @@
1
+ import { object } from '@kuus/yup';
2
+ import { encode, decode, isUndefined } from '@koine/utils';
3
+
4
+ /**
5
+ * Encode form
6
+ *
7
+ * Takes a record of yup validations and outputs a `yup` schema with encoded
8
+ * names (antispam technique) and a record of the encoded/decoded input `name`s.
9
+ *
10
+ * We skip the names prefixed wth an underscore which are considered programmatic
11
+ * form data not created by user input.
12
+ *
13
+ * FIXME: types https://github.com/jquense/yup/issues/1700
14
+ */let encodeForm=t=>{let o={},i={};for(let e in t)if(!e.startsWith("_")){let l=encode(e);o[l]=t[e],i[e]=l;}return {encodedSchema:// we need `.required()` to correctly infer the type @see
15
+ // https://github.com/jquense/yup/issues/946
16
+ object(o).required(),encodedNames:i}};/**
17
+ * Decode form data
18
+ *
19
+ * This function is meant to be used inside an api endpoint to gather an encoded
20
+ * form submit data and transform it to the decoded desired json data.
21
+ *
22
+ * Here too we skip encoding/decoding process for names prefixed wth an underscore
23
+ * which are considered programmatic form data not created by user input.
24
+ */let decodeForm=e=>{let r={};for(let i in e){let l=decode(i);// always add underscore prefixed names as they are treated as internal
25
+ // private inputs outside of the honeypot system, normalise them here removing
26
+ // the underscore prefix
27
+ i.startsWith("_")?// @ts-expect-error nevermind
28
+ r[i.substring(1)]=e[i]:isUndefined(e[i])||""!==e[l]||// @ts-expect-error nevermind
29
+ (r[l]=e[i]);}// console.log(formData, decoded, json);
30
+ return r};
31
+
32
+ export { decodeForm, encodeForm };
package/forms.cjs.js CHANGED
@@ -1,35 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var yup = require('@kuus/yup');
4
- var utils = require('@koine/utils');
3
+ var antispam = require('./forms/antispam.cjs.js');
5
4
 
6
- /**
7
- * Encode form
8
- *
9
- * Takes a record of yup validations and outputs a `yup` schema with encoded
10
- * names (antispam technique) and a record of the encoded/decoded input `name`s.
11
- *
12
- * We skip the names prefixed wth an underscore which are considered programmatic
13
- * form data not created by user input.
14
- *
15
- * FIXME: types https://github.com/jquense/yup/issues/1700
16
- */let encodeForm=t=>{let o={},i={};for(let e in t)if(!e.startsWith("_")){let l=utils.encode(e);o[l]=t[e],i[e]=l;}return {encodedSchema:// we need `.required()` to correctly infer the type @see
17
- // https://github.com/jquense/yup/issues/946
18
- yup.object(o).required(),encodedNames:i}};/**
19
- * Decode form data
20
- *
21
- * This function is meant to be used inside an api endpoint to gather an encoded
22
- * form submit data and transform it to the decoded desired json data.
23
- *
24
- * Here too we skip encoding/decoding process for names prefixed wth an underscore
25
- * which are considered programmatic form data not created by user input.
26
- */let decodeForm=e=>{let r={};for(let i in e){let l=utils.decode(i);// always add underscore prefixed names as they are treated as internal
27
- // private inputs outside of the honeypot system, normalise them here removing
28
- // the underscore prefix
29
- i.startsWith("_")?// @ts-expect-error nevermind
30
- r[i.substring(1)]=e[i]:utils.isUndefined(e[i])||""!==e[l]||// @ts-expect-error nevermind
31
- (r[l]=e[i]);}// console.log(formData, decoded, json);
32
- return r};
33
5
 
34
- exports.decodeForm = decodeForm;
35
- exports.encodeForm = encodeForm;
6
+
7
+ exports.decodeForm = antispam.decodeForm;
8
+ exports.encodeForm = antispam.encodeForm;
package/forms.esm.js CHANGED
@@ -1,32 +1 @@
1
- import { object } from '@kuus/yup';
2
- import { encode, decode, isUndefined } from '@koine/utils';
3
-
4
- /**
5
- * Encode form
6
- *
7
- * Takes a record of yup validations and outputs a `yup` schema with encoded
8
- * names (antispam technique) and a record of the encoded/decoded input `name`s.
9
- *
10
- * We skip the names prefixed wth an underscore which are considered programmatic
11
- * form data not created by user input.
12
- *
13
- * FIXME: types https://github.com/jquense/yup/issues/1700
14
- */let encodeForm=t=>{let o={},i={};for(let e in t)if(!e.startsWith("_")){let l=encode(e);o[l]=t[e],i[e]=l;}return {encodedSchema:// we need `.required()` to correctly infer the type @see
15
- // https://github.com/jquense/yup/issues/946
16
- object(o).required(),encodedNames:i}};/**
17
- * Decode form data
18
- *
19
- * This function is meant to be used inside an api endpoint to gather an encoded
20
- * form submit data and transform it to the decoded desired json data.
21
- *
22
- * Here too we skip encoding/decoding process for names prefixed wth an underscore
23
- * which are considered programmatic form data not created by user input.
24
- */let decodeForm=e=>{let r={};for(let i in e){let l=decode(i);// always add underscore prefixed names as they are treated as internal
25
- // private inputs outside of the honeypot system, normalise them here removing
26
- // the underscore prefix
27
- i.startsWith("_")?// @ts-expect-error nevermind
28
- r[i.substring(1)]=e[i]:isUndefined(e[i])||""!==e[l]||// @ts-expect-error nevermind
29
- (r[l]=e[i]);}// console.log(formData, decoded, json);
30
- return r};
31
-
32
- export { decodeForm, encodeForm };
1
+ export { decodeForm, encodeForm } from './forms/antispam.esm.js';
package/index.cjs.js CHANGED
@@ -26,10 +26,6 @@ var useSpinDelay = require('./useSpinDelay.cjs.js');
26
26
  var useTraceUpdate = require('./useTraceUpdate.cjs.js');
27
27
  var useUpdateEffect = require('./useUpdateEffect.cjs.js');
28
28
  var useWindowSize = require('./useWindowSize.cjs.js');
29
- require('react');
30
- require('@koine/utils');
31
- require('react/jsx-runtime');
32
- require('@koine/dom');
33
29
 
34
30
 
35
31
 
package/index.esm.js CHANGED
@@ -24,7 +24,3 @@ export { useSpinDelay } from './useSpinDelay.esm.js';
24
24
  export { useTraceUpdate } from './useTraceUpdate.esm.js';
25
25
  export { useUpdateEffect } from './useUpdateEffect.esm.js';
26
26
  export { useWindowSize } from './useWindowSize.esm.js';
27
- import 'react';
28
- import '@koine/utils';
29
- import 'react/jsx-runtime';
30
- import '@koine/dom';
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "name": "@koine/react",
3
3
  "sideEffects": false,
4
4
  "dependencies": {
5
- "@koine/dom": "2.0.0-beta.125",
6
- "@koine/utils": "2.0.0-beta.125"
5
+ "@koine/dom": "2.0.0-beta.127",
6
+ "@koine/utils": "2.0.0-beta.127"
7
7
  },
8
8
  "peerDependencies": {
9
9
  "@kuus/yup": "1.0.0-beta.7",
@@ -29,166 +29,199 @@
29
29
  "./package.json": "./package.json",
30
30
  ".": {
31
31
  "module": "./index.esm.js",
32
+ "types": "./index.esm.d.ts",
32
33
  "import": "./index.cjs.mjs",
33
34
  "default": "./index.cjs.js"
34
35
  },
35
36
  "./calendar": {
36
37
  "module": "./calendar.esm.js",
38
+ "types": "./calendar.esm.d.ts",
37
39
  "import": "./calendar.cjs.mjs",
38
40
  "default": "./calendar.cjs.js"
39
41
  },
40
42
  "./classed": {
41
43
  "module": "./classed.esm.js",
44
+ "types": "./classed.esm.d.ts",
42
45
  "import": "./classed.cjs.mjs",
43
46
  "default": "./classed.cjs.js"
44
47
  },
45
48
  "./createUseMediaQueryWidth": {
46
49
  "module": "./createUseMediaQueryWidth.esm.js",
50
+ "types": "./createUseMediaQueryWidth.esm.d.ts",
47
51
  "import": "./createUseMediaQueryWidth.cjs.mjs",
48
52
  "default": "./createUseMediaQueryWidth.cjs.js"
49
53
  },
50
54
  "./extendComponent": {
51
55
  "module": "./extendComponent.esm.js",
56
+ "types": "./extendComponent.esm.d.ts",
52
57
  "import": "./extendComponent.cjs.mjs",
53
58
  "default": "./extendComponent.cjs.js"
54
59
  },
55
60
  "./FaviconTags": {
56
61
  "module": "./FaviconTags.esm.js",
62
+ "types": "./FaviconTags.esm.d.ts",
57
63
  "import": "./FaviconTags.cjs.mjs",
58
64
  "default": "./FaviconTags.cjs.js"
59
65
  },
60
66
  "./forms": {
61
67
  "module": "./forms.esm.js",
68
+ "types": "./forms.esm.d.ts",
62
69
  "import": "./forms.cjs.mjs",
63
70
  "default": "./forms.cjs.js"
64
71
  },
65
72
  "./mergeRefs": {
66
73
  "module": "./mergeRefs.esm.js",
74
+ "types": "./mergeRefs.esm.d.ts",
67
75
  "import": "./mergeRefs.cjs.mjs",
68
76
  "default": "./mergeRefs.cjs.js"
69
77
  },
70
78
  "./Meta": {
71
79
  "module": "./Meta.esm.js",
80
+ "types": "./Meta.esm.d.ts",
72
81
  "import": "./Meta.cjs.mjs",
73
82
  "default": "./Meta.cjs.js"
74
83
  },
75
84
  "./NoJs": {
76
85
  "module": "./NoJs.esm.js",
86
+ "types": "./NoJs.esm.d.ts",
77
87
  "import": "./NoJs.cjs.mjs",
78
88
  "default": "./NoJs.cjs.js"
79
89
  },
80
90
  "./Polymorphic": {
81
91
  "module": "./Polymorphic.esm.js",
92
+ "types": "./Polymorphic.esm.d.ts",
82
93
  "import": "./Polymorphic.cjs.mjs",
83
94
  "default": "./Polymorphic.cjs.js"
84
95
  },
85
96
  "./types": {
86
97
  "module": "./types.esm.js",
98
+ "types": "./types.esm.d.ts",
87
99
  "import": "./types.cjs.mjs",
88
100
  "default": "./types.cjs.js"
89
101
  },
90
102
  "./useAsyncFn": {
91
103
  "module": "./useAsyncFn.esm.js",
104
+ "types": "./useAsyncFn.esm.d.ts",
92
105
  "import": "./useAsyncFn.cjs.mjs",
93
106
  "default": "./useAsyncFn.cjs.js"
94
107
  },
95
108
  "./useFirstMountState": {
96
109
  "module": "./useFirstMountState.esm.js",
110
+ "types": "./useFirstMountState.esm.d.ts",
97
111
  "import": "./useFirstMountState.cjs.mjs",
98
112
  "default": "./useFirstMountState.cjs.js"
99
113
  },
100
114
  "./useFixedOffset": {
101
115
  "module": "./useFixedOffset.esm.js",
116
+ "types": "./useFixedOffset.esm.d.ts",
102
117
  "import": "./useFixedOffset.cjs.mjs",
103
118
  "default": "./useFixedOffset.cjs.js"
104
119
  },
105
120
  "./useFocus": {
106
121
  "module": "./useFocus.esm.js",
122
+ "types": "./useFocus.esm.d.ts",
107
123
  "import": "./useFocus.cjs.mjs",
108
124
  "default": "./useFocus.cjs.js"
109
125
  },
110
126
  "./useInterval": {
111
127
  "module": "./useInterval.esm.js",
128
+ "types": "./useInterval.esm.d.ts",
112
129
  "import": "./useInterval.cjs.mjs",
113
130
  "default": "./useInterval.cjs.js"
114
131
  },
115
132
  "./useIsomorphicLayoutEffect": {
116
133
  "module": "./useIsomorphicLayoutEffect.esm.js",
134
+ "types": "./useIsomorphicLayoutEffect.esm.d.ts",
117
135
  "import": "./useIsomorphicLayoutEffect.cjs.mjs",
118
136
  "default": "./useIsomorphicLayoutEffect.cjs.js"
119
137
  },
120
138
  "./useKeyUp": {
121
139
  "module": "./useKeyUp.esm.js",
140
+ "types": "./useKeyUp.esm.d.ts",
122
141
  "import": "./useKeyUp.cjs.mjs",
123
142
  "default": "./useKeyUp.cjs.js"
124
143
  },
125
144
  "./useMeasure": {
126
145
  "module": "./useMeasure.esm.js",
146
+ "types": "./useMeasure.esm.d.ts",
127
147
  "import": "./useMeasure.cjs.mjs",
128
148
  "default": "./useMeasure.cjs.js"
129
149
  },
130
150
  "./useMountedState": {
131
151
  "module": "./useMountedState.esm.js",
152
+ "types": "./useMountedState.esm.d.ts",
132
153
  "import": "./useMountedState.cjs.mjs",
133
154
  "default": "./useMountedState.cjs.js"
134
155
  },
135
156
  "./useNavigateAway": {
136
157
  "module": "./useNavigateAway.esm.js",
158
+ "types": "./useNavigateAway.esm.d.ts",
137
159
  "import": "./useNavigateAway.cjs.mjs",
138
160
  "default": "./useNavigateAway.cjs.js"
139
161
  },
140
162
  "./usePrevious": {
141
163
  "module": "./usePrevious.esm.js",
164
+ "types": "./usePrevious.esm.d.ts",
142
165
  "import": "./usePrevious.cjs.mjs",
143
166
  "default": "./usePrevious.cjs.js"
144
167
  },
145
168
  "./usePreviousRef": {
146
169
  "module": "./usePreviousRef.esm.js",
170
+ "types": "./usePreviousRef.esm.d.ts",
147
171
  "import": "./usePreviousRef.cjs.mjs",
148
172
  "default": "./usePreviousRef.cjs.js"
149
173
  },
150
174
  "./useScrollPosition": {
151
175
  "module": "./useScrollPosition.esm.js",
176
+ "types": "./useScrollPosition.esm.d.ts",
152
177
  "import": "./useScrollPosition.cjs.mjs",
153
178
  "default": "./useScrollPosition.cjs.js"
154
179
  },
155
180
  "./useScrollThreshold": {
156
181
  "module": "./useScrollThreshold.esm.js",
182
+ "types": "./useScrollThreshold.esm.d.ts",
157
183
  "import": "./useScrollThreshold.cjs.mjs",
158
184
  "default": "./useScrollThreshold.cjs.js"
159
185
  },
160
186
  "./useScrollTo": {
161
187
  "module": "./useScrollTo.esm.js",
188
+ "types": "./useScrollTo.esm.d.ts",
162
189
  "import": "./useScrollTo.cjs.mjs",
163
190
  "default": "./useScrollTo.cjs.js"
164
191
  },
165
192
  "./useSmoothScroll": {
166
193
  "module": "./useSmoothScroll.esm.js",
194
+ "types": "./useSmoothScroll.esm.d.ts",
167
195
  "import": "./useSmoothScroll.cjs.mjs",
168
196
  "default": "./useSmoothScroll.cjs.js"
169
197
  },
170
198
  "./useSpinDelay": {
171
199
  "module": "./useSpinDelay.esm.js",
200
+ "types": "./useSpinDelay.esm.d.ts",
172
201
  "import": "./useSpinDelay.cjs.mjs",
173
202
  "default": "./useSpinDelay.cjs.js"
174
203
  },
175
204
  "./useTraceUpdate": {
176
205
  "module": "./useTraceUpdate.esm.js",
206
+ "types": "./useTraceUpdate.esm.d.ts",
177
207
  "import": "./useTraceUpdate.cjs.mjs",
178
208
  "default": "./useTraceUpdate.cjs.js"
179
209
  },
180
210
  "./useUpdateEffect": {
181
211
  "module": "./useUpdateEffect.esm.js",
212
+ "types": "./useUpdateEffect.esm.d.ts",
182
213
  "import": "./useUpdateEffect.cjs.mjs",
183
214
  "default": "./useUpdateEffect.cjs.js"
184
215
  },
185
216
  "./useWindowSize": {
186
217
  "module": "./useWindowSize.esm.js",
218
+ "types": "./useWindowSize.esm.d.ts",
187
219
  "import": "./useWindowSize.cjs.mjs",
188
220
  "default": "./useWindowSize.cjs.js"
189
221
  }
190
222
  },
191
223
  "module": "./index.esm.js",
192
224
  "main": "./index.cjs.js",
193
- "version": "2.0.0-beta.125"
225
+ "types": "./index.esm.d.ts",
226
+ "version": "2.0.0-beta.127"
194
227
  }
@@ -3,5 +3,5 @@ type Position = {
3
3
  y: number;
4
4
  };
5
5
  type ElementRef = React.MutableRefObject<HTMLElement | undefined>;
6
- export declare let useScrollPosition: (effect: (currentPosition: Position, prevPosition: Position) => void, deps?: import("react").DependencyList, element?: ElementRef, boundingElement?: ElementRef, wait?: number) => void;
6
+ export declare let useScrollPosition: (effect: (currentPosition: Position, prevPosition: Position) => void, deps?: React.DependencyList, element?: ElementRef, boundingElement?: ElementRef, wait?: number) => void;
7
7
  export default useScrollPosition;
@@ -6,7 +6,6 @@ var react = require('react');
6
6
  var utils = require('@koine/utils');
7
7
  var dom = require('@koine/dom');
8
8
  var useFixedOffset = require('./useFixedOffset.cjs.js');
9
- require('./useIsomorphicLayoutEffect.cjs.js');
10
9
 
11
10
  /**
12
11
  *
@@ -2,7 +2,6 @@ import { useCallback } from 'react';
2
2
  import { isNumber } from '@koine/utils';
3
3
  import { getOffsetTopSlim, scrollTo } from '@koine/dom';
4
4
  import { useFixedOffset } from './useFixedOffset.esm.js';
5
- import './useIsomorphicLayoutEffect.esm.js';
6
5
 
7
6
  /**
8
7
  *