react-editable-photo-grid 1.0.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +195 -1
- package/dist/index.js +1 -1
- package/package.json +12 -7
- package/src/PhotoGrid.tsx +130 -54
- package/src/components/Checkbox.tsx +27 -0
- package/src/components/NonScrollGallery.tsx +188 -0
- package/src/components/PhotoControls.tsx +29 -33
- package/src/components/RowControls.tsx +6 -8
- package/src/components/ScrollGallery.tsx +190 -0
- package/src/index.js +4 -1
- package/src/styles.css +328 -1
- package/src/types.ts +34 -4
- package/src/utils.tsx +120 -24
- package/.babelrc +0 -3
- package/tsconfig.json +0 -18
- package/webpack.config.js +0 -39
package/README.md
CHANGED
|
@@ -1 +1,195 @@
|
|
|
1
|
-
react-photo-grid
|
|
1
|
+
# react-editable-photo-grid
|
|
2
|
+
|
|
3
|
+
An editable photo grid for react applications.
|
|
4
|
+
```tsx
|
|
5
|
+
import React, { useState, useEffect } from 'react';
|
|
6
|
+
import { PhotoGrid, PhotoRows } from 'react-editable-photo-grid';
|
|
7
|
+
|
|
8
|
+
const Photos: React.FC = () => {
|
|
9
|
+
const [photos, setPhotos] = useState<PhotoRows>({}),
|
|
10
|
+
[changes, setChanges] = useState<Number>(0),
|
|
11
|
+
[selectedPhotos, setSelectedPhotos] = useState<Array<string>>([]);
|
|
12
|
+
|
|
13
|
+
const getData = () => {
|
|
14
|
+
// Fetch photos from API and update state
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
getData();
|
|
19
|
+
}, []);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<PhotoGrid
|
|
23
|
+
isEditing={true}
|
|
24
|
+
rows={photos}
|
|
25
|
+
updateRows={setPhotos}
|
|
26
|
+
selectedPhotos={selectedPhotos}
|
|
27
|
+
updateSelectedPhotos={setSelectedPhotos}
|
|
28
|
+
changes={changes}
|
|
29
|
+
increaseChanges={() => setChanges(changes + 1)}
|
|
30
|
+
imageSrcPrefix="/api/image"
|
|
31
|
+
imageSrcProperty="thumbnail_path"
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default Photos;
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## How to Install
|
|
40
|
+
```
|
|
41
|
+
npm i react-editable-photo-grid
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Required Props
|
|
45
|
+
|
|
46
|
+
Properties | Type | Description
|
|
47
|
+
------------ | ------------- | -------------
|
|
48
|
+
isEditing | Boolean | Switches the grid from display to editable
|
|
49
|
+
rows | PhotoRows | An array of rows where the keys are row numbers and items are photo arrays.
|
|
50
|
+
updateRows | Void | A method that updates the rows data from the parent
|
|
51
|
+
selectedPhotos | Array<string> | This can be populated with photo ids for batch operations
|
|
52
|
+
updateSelectedPhotos | Void | A method to update the selectedPhotos prop
|
|
53
|
+
changes | Number | Tracks when changes have been made (the editable part)
|
|
54
|
+
increaseChanges | Void | A method to update the changes prop
|
|
55
|
+
imageSrcPrefix | String | A string that represents the url prefix for each photo image src attribute. This will be used for the grid and gallery.
|
|
56
|
+
imageSrcProperty | String | Determines which photo property is used for the grid img src parameter.
|
|
57
|
+
useGallery | Boolean | Activate the Gallery component.
|
|
58
|
+
buttonArrows | ButtonArrows | Allows you to override the basic button arrows with custom html.
|
|
59
|
+
gallerySrcProperty | String | Determines which photo property is used for the gallery image src parameter.
|
|
60
|
+
galleryButtonArrows | GalleryButtonArrows | Allows you to override the gallery prev and next button arrows with custom html.
|
|
61
|
+
onPhotoClick | Void | A method that receives the photo id on click
|
|
62
|
+
onGallerySwipe | Void | A method that receives a photo object when the gallery is swiped
|
|
63
|
+
galleryType | String | Determines if the legacy gallery or the scroll gallery (beta) is to be used
|
|
64
|
+
|
|
65
|
+
## How to Use
|
|
66
|
+
|
|
67
|
+
To use the PhotoGrid component you can import it like this:
|
|
68
|
+
```tsx
|
|
69
|
+
import { PhotoGrid, PhotoRows, PhotoItem, sortPhotosIntoRows } from 'react-editable-photo-grid';
|
|
70
|
+
import { getPhotos } from 'api';
|
|
71
|
+
```
|
|
72
|
+
PhotoGrid represents the component and PhotoRows is the TS type for the data.
|
|
73
|
+
You can add the component to your code like this:
|
|
74
|
+
```tsx
|
|
75
|
+
const [photos, setPhotos] = useState<PhotoItem[]>([]),
|
|
76
|
+
[rows, setRows] = useState<PhotoRows[]>({})
|
|
77
|
+
|
|
78
|
+
const loadPhotos = (): void => {
|
|
79
|
+
const photos = await getPhotos();
|
|
80
|
+
setPhotos(photos);
|
|
81
|
+
setRows(sortPhotosIntoRows(photos));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<PhotoGrid
|
|
86
|
+
isEditing={true}
|
|
87
|
+
photos={photos}
|
|
88
|
+
rows={rows}
|
|
89
|
+
updateRows={setRows}
|
|
90
|
+
selectedPhotos={selectedPhotos}
|
|
91
|
+
updateSelectedPhotos={setSelectedPhotos}
|
|
92
|
+
changes={changes}
|
|
93
|
+
increaseChanges={() => setChanges(changes + 1)}
|
|
94
|
+
imageSrcPrefix="/api/image"
|
|
95
|
+
imageSrcProperty="/thumbnail_path"
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
```
|
|
99
|
+
### How data should be structured
|
|
100
|
+
|
|
101
|
+
Structure the data for the PhotoGrid like this:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
export interface PhotoRows {
|
|
105
|
+
[key: number]: PhotoItem[];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface PhotoItem {
|
|
109
|
+
id: string;
|
|
110
|
+
column: number;
|
|
111
|
+
image_path: string;
|
|
112
|
+
thumbnail_path: string;
|
|
113
|
+
carousel_key: number;
|
|
114
|
+
width: number;
|
|
115
|
+
height: number;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
PhotoItem represents a single photo data object. PhotoRows is an associative array where each key is a row number and items an array of associated photos.
|
|
120
|
+
|
|
121
|
+
### Passing a custom dropdown menu
|
|
122
|
+
|
|
123
|
+
You can add a menu to the grid by passing a component as the photoMenu prop. The grid will clone this prop and add it to each photo. There isn't a set format that a menu has to be but here is an example:
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
const PhotoMenu = (props: PhotoMenuProps) => {
|
|
127
|
+
return (
|
|
128
|
+
<div className="photomenu">
|
|
129
|
+
<Checkbox
|
|
130
|
+
value={props.photo.id}
|
|
131
|
+
onClick={props.updateSelectedPhotos}
|
|
132
|
+
checked={props.selectedPhotos.includes(props.photo.id)}
|
|
133
|
+
/>
|
|
134
|
+
<div>
|
|
135
|
+
<button
|
|
136
|
+
data-key={props.photo.id}
|
|
137
|
+
type="button"
|
|
138
|
+
onClick={props.openDropdown}
|
|
139
|
+
>
|
|
140
|
+
Edit
|
|
141
|
+
</button>
|
|
142
|
+
<ul
|
|
143
|
+
style={{ display: props.activeDropdown === props.photo.id ? 'block' : 'none' }}
|
|
144
|
+
>
|
|
145
|
+
<li>
|
|
146
|
+
<a
|
|
147
|
+
href={props.photo.id}
|
|
148
|
+
onClick={props.edit}>
|
|
149
|
+
Edit
|
|
150
|
+
</a>
|
|
151
|
+
</li>
|
|
152
|
+
</ul>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
And here is how you can prepare it for the grid:
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
const photoMenu = <PhotoMenu
|
|
163
|
+
selectedPhotos={selectedPhotos}
|
|
164
|
+
updateSelectedPhotos={updateSelectedPhotos}
|
|
165
|
+
activeDropdown={activeDropdown}
|
|
166
|
+
openDropdown={openDropdown}
|
|
167
|
+
edit={edit}
|
|
168
|
+
/>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
You can then pass photoMenu to the grid as a prop. See the sample component for more details
|
|
172
|
+
|
|
173
|
+
### Using the gallery
|
|
174
|
+
|
|
175
|
+
You can enable the gallery by passing the the required props like this:
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
<PhotoGrid
|
|
179
|
+
{ ... other props}
|
|
180
|
+
useGallery={true}
|
|
181
|
+
gallerySrcProperty="image_path"
|
|
182
|
+
/>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
This will make the gallery appear when a photo is clicked.
|
|
186
|
+
|
|
187
|
+
## Examples
|
|
188
|
+
|
|
189
|
+
See the samples directory for sample usage.
|
|
190
|
+
|
|
191
|
+
## How is it editable?
|
|
192
|
+
|
|
193
|
+
The PhotoGrid component allows you to structure your photos in rows and columns. As such it provides controls to change the position of the rows within the page and the columns within the rows. Each time an edit is made it updates the rows prop. It also increases the changes prop.
|
|
194
|
+
|
|
195
|
+
You can use the changes prop to work out if any edits have been made. You can then submit your edits to your API to permanently store the changes. The easiest way to achieve this is to add 'row' and 'column' properties to the data handled by your API.
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var n={365:(n,t,e)=>{e.d(t,{A:()=>l});var o=e(601),r=e.n(o),a=e(314),i=e.n(a)()(r());i.push([n.id,".photogrid {\n padding: 0 0.125rem;\n}\n\n.photogrid--row__controls {\n display: block;\n position: absolute;\n left: 0.25rem;\n top: 50%;\n transform: translateY(-50%);\n z-index: 20;\n}\n\n.photogrid--row__controls > li {\n display: block;\n}\n\n.photogrid--photo__controls {\n display: block;\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n bottom: 0.5rem;\n text-align: center;\n}\n\n.photogrid--photo__controls > li {\n display: inline-block;\n}\n\n.photogrid--photo__controls > li + li {\n margin-left: 0.25rem;\n}\n\n.photogrid--photo__controls .photo__control, .photogrid--row__controls .row__control {\n width: 36px;\n height: 36px;\n display: block;\n background: #ddd;\n color: #333;\n font-size: 1.5rem;\n line-height: 2rem;\n}\n\n.photogrid--photo__row {\n display: block;\n background: transparent;\n min-height: 0;\n position: relative;\n z-index: 10;\n padding: 0;\n}\n\n.photogrid--photo__row.editing {\n padding-left: 2.75rem;\n}\n\n.photogrid--photo__column {\n position: relative;\n vertical-align: middle;\n display: block;\n margin: 0.125rem;\n}\n\n.photogrid--photo__column > img {\n display: block;\n max-width: 100%;\n max-height: 700px;\n height: auto;\n margin: 0;\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n@media only screen and (min-width: 768px) {\n .photogrid--photo__row {\n display: flex;\n flex: 1 1 auto;\n }\n\n .photogrid--photo__column > img {\n display: inline-block;\n }\n}\n\n",""]);const l=i},314:n=>{n.exports=function(n){var t=[];return t.toString=function(){return this.map((function(t){var e="",o=void 0!==t[5];return t[4]&&(e+="@supports (".concat(t[4],") {")),t[2]&&(e+="@media ".concat(t[2]," {")),o&&(e+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),e+=n(t),o&&(e+="}"),t[2]&&(e+="}"),t[4]&&(e+="}"),e})).join("")},t.i=function(n,e,o,r,a){"string"==typeof n&&(n=[[null,n,void 0]]);var i={};if(o)for(var l=0;l<this.length;l++){var c=this[l][0];null!=c&&(i[c]=!0)}for(var u=0;u<n.length;u++){var s=[].concat(n[u]);o&&i[s[0]]||(void 0!==a&&(void 0===s[5]||(s[1]="@layer".concat(s[5].length>0?" ".concat(s[5]):""," {").concat(s[1],"}")),s[5]=a),e&&(s[2]?(s[1]="@media ".concat(s[2]," {").concat(s[1],"}"),s[2]=e):s[2]=e),r&&(s[4]?(s[1]="@supports (".concat(s[4],") {").concat(s[1],"}"),s[4]=r):s[4]="".concat(r)),t.push(s))}},t}},601:n=>{n.exports=function(n){return n[1]}},72:n=>{var t=[];function e(n){for(var e=-1,o=0;o<t.length;o++)if(t[o].identifier===n){e=o;break}return e}function o(n,o){for(var a={},i=[],l=0;l<n.length;l++){var c=n[l],u=o.base?c[0]+o.base:c[0],s=a[u]||0,p="".concat(u," ").concat(s);a[u]=s+1;var d=e(p),h={css:c[1],media:c[2],sourceMap:c[3],supports:c[4],layer:c[5]};if(-1!==d)t[d].references++,t[d].updater(h);else{var m=r(h,o);o.byIndex=l,t.splice(l,0,{identifier:p,updater:m,references:1})}i.push(p)}return i}function r(n,t){var e=t.domAPI(t);return e.update(n),function(t){if(t){if(t.css===n.css&&t.media===n.media&&t.sourceMap===n.sourceMap&&t.supports===n.supports&&t.layer===n.layer)return;e.update(n=t)}else e.remove()}}n.exports=function(n,r){var a=o(n=n||[],r=r||{});return function(n){n=n||[];for(var i=0;i<a.length;i++){var l=e(a[i]);t[l].references--}for(var c=o(n,r),u=0;u<a.length;u++){var s=e(a[u]);0===t[s].references&&(t[s].updater(),t.splice(s,1))}a=c}}},659:n=>{var t={};n.exports=function(n,e){var o=function(n){if(void 0===t[n]){var e=document.querySelector(n);if(window.HTMLIFrameElement&&e instanceof window.HTMLIFrameElement)try{e=e.contentDocument.head}catch(n){e=null}t[n]=e}return t[n]}(n);if(!o)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");o.appendChild(e)}},540:n=>{n.exports=function(n){var t=document.createElement("style");return n.setAttributes(t,n.attributes),n.insert(t,n.options),t}},56:(n,t,e)=>{n.exports=function(n){var t=e.nc;t&&n.setAttribute("nonce",t)}},825:n=>{n.exports=function(n){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var t=n.insertStyleElement(n);return{update:function(e){!function(n,t,e){var o="";e.supports&&(o+="@supports (".concat(e.supports,") {")),e.media&&(o+="@media ".concat(e.media," {"));var r=void 0!==e.layer;r&&(o+="@layer".concat(e.layer.length>0?" ".concat(e.layer):""," {")),o+=e.css,r&&(o+="}"),e.media&&(o+="}"),e.supports&&(o+="}");var a=e.sourceMap;a&&"undefined"!=typeof btoa&&(o+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),t.styleTagTransform(o,n,t.options)}(t,n,e)},remove:function(){!function(n){if(null===n.parentNode)return!1;n.parentNode.removeChild(n)}(t)}}}},113:n=>{n.exports=function(n,t){if(t.styleSheet)t.styleSheet.cssText=n;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(n))}}}},t={};function e(o){var r=t[o];if(void 0!==r)return r.exports;var a=t[o]={id:o,exports:{}};return n[o](a,a.exports,e),a.exports}e.n=n=>{var t=n&&n.__esModule?()=>n.default:()=>n;return e.d(t,{a:t}),t},e.d=(n,t)=>{for(var o in t)e.o(t,o)&&!e.o(n,o)&&Object.defineProperty(n,o,{enumerable:!0,get:t[o]})},e.o=(n,t)=>Object.prototype.hasOwnProperty.call(n,t),e.r=n=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.nc=void 0;var o={};e.r(o),e.d(o,{PhotoGrid:()=>j});const r=require("react");var a=e.n(r),i=function(){return i=Object.assign||function(n){for(var t,e=1,o=arguments.length;e<o;e++)for(var r in t=arguments[e])Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n},i.apply(this,arguments)},l=function(n){return n.sort((function(n,t){return Math.floor(n.column)-Math.floor(t.column)}))},c=function(n,t){var e=n.find((function(n){return n.id===t}));if(void 0===e)throw new TypeError("No photo was found in this row for that id");return e},u=function(n,t){var e=n.find((function(n){return n.column===t}));if(void 0===e)throw new TypeError("No photo was found in this row for that column");return e},s=function(n,t){return n.filter((function(n){return n.column!==t}))},p=function(n,t,e){return void 0===n&&(n=[]),t.column=e,n.push(t),n},d=function(n,t,e){var o=t.column,r=e.column;return n=s(n,o),n=s(n,r),n=p(n,t,r),p(n,e,o)},h=function(n){return"string"==typeof n&&(n=parseInt(n)),n},m=function(n){var t=n.currentTarget,e=t.dataset.id,o=t.dataset.row;if(!e||!o)throw new TypeError("id or row key missing from photo control");return{id:e,rowKey:parseInt(o)}},f=function(n,t,e){for(var o=t;o<=e;o++){var r=u(n,o);n=s(n,o),n=p(n,r,r.column-1)}return n},v=function(n,t,e,o,r){return delete n[r],delete n[e],n[r]=t,n[e]=o,n},w=e(72),g=e.n(w),y=e(825),_=e.n(y),b=e(659),E=e.n(b),C=e(56),k=e.n(C),x=e(540),T=e.n(x),K=e(113),N=e.n(K),P=e(365),M={};M.styleTagTransform=N(),M.setAttributes=k(),M.insert=E().bind(null,"head"),M.domAPI=_(),M.insertStyleElement=T(),g()(P.A,M),P.A&&P.A.locals&&P.A.locals;const R=function(n){return a().createElement("ul",{className:"photogrid--row__controls"},h(n.rowKey)>1&&a().createElement("li",null,a().createElement("button",{className:"row__control",onClick:n.moveRowUp,"data-row":n.rowKey},"↑")),h(n.rowKey)<n.rowCount&&a().createElement("li",null,a().createElement("button",{className:"row__control",onClick:n.moveRowDown,"data-row":n.rowKey},"↓")))},O=function(n){return a().createElement("ul",{className:"photogrid--photo__controls"},n.photo.column>1&&a().createElement("li",null,a().createElement("button",{type:"button",className:"photo__control",onClick:n.movePhotoLeft,"data-id":n.photo.id,"data-row":n.rowKey},"←")),h(n.rowKey)>1&&a().createElement("li",null,a().createElement("button",{type:"button",className:"photo__control",onClick:n.movePhotoUp,"data-id":n.photo.id,"data-row":n.rowKey},"↑")),h(n.rowKey)<n.rowCount||h(n.rowKey)===n.rowCount&&n.photoCount>1?a().createElement("li",null,a().createElement("button",{type:"button",className:"photo__control",onClick:n.movePhotoDown,"data-id":n.photo.id,"data-row":n.rowKey},"↓")):null,n.photo.column<n.photoCount&&a().createElement("li",null,a().createElement("button",{type:"button",className:"photo__control",onClick:n.movePhotoRight,"data-id":n.photo.id,"data-row":n.rowKey},"→")))},j=function(n){var t=function(t){!function(n,t){n.preventDefault();var e=m(n),o=e.id,r=e.rowKey,a=i({},t.rows),u=l(a[r]),d=r-1,h=[];null!=a[d]&&(h=l(a[d]));var v=c(u,o),w=v.column+1,g=u.length;u=s(u,v.column),delete a[r],u.length&&(f(u,w,g),a[r]=u),h=p(h,v,h.length+1),delete a[d],a[d]=h,t.updateRows(a),t.increaseChanges()}(t,n)},e=function(t){!function(n,t){n.preventDefault();var e=m(n),o=e.id,r=e.rowKey,a=i({},t.rows),d=l(a[r]),h=r+1,v=c(d,o),w=v.column+1,g=d.length;d=s(d,v.column),delete a[r],d.length&&(d=f(d,w,g));var y=null;null==a[h]?(v.column=1,y=[v]):(y=function(n,t){for(var e=t;e>0;e--){var o=u(n,e);n=s(n,e),n=p(n,o,o.column+1)}return n}(y=l(a[h]),y.length),y=p(y,v,1),delete a[h]),a[h]=y,d.length&&(a[r]=d),t.updateRows(a),t.increaseChanges()}(t,n)},o=function(t){!function(n,t){n.preventDefault();var e=m(n),o=e.id,r=e.rowKey,a=i({},t.rows),s=l(a[r]),p=c(s,o);if(1!==p.column){var h=u(s,p.column-1);s=d(s,h,p),delete a[r],a[r]=s,t.updateRows(a),t.increaseChanges()}}(t,n)},h=function(t){!function(n,t){n.preventDefault();var e=m(n),o=e.id,r=e.rowKey,a=i({},t.rows),s=l(a[r]),p=c(s,o);if(p.column!==s.length){var h=u(s,p.column+1);s=d(s,p,h),delete a[r],a[r]=s,t.updateRows(a),t.increaseChanges()}}(t,n)},w=function(t){!function(n,t){n.preventDefault();var e=n.currentTarget.dataset.row;if(!e)throw new TypeError("row missing from row control");var o=parseInt(e),r=o-1,a=i({},t.rows),c=l(a[o]),u=l(a[r]);a=v(a,c,o,u,r),t.updateRows(a),t.increaseChanges()}(t,n)},g=function(t){!function(n,t){n.preventDefault();var e=n.currentTarget.dataset.row;if(!e)throw new TypeError("row missing from row control");var o=parseInt(e),r=o+1,a=i({},t.rows),c=l(a[o]),u=l(a[r]);a=v(a,c,o,u,r),t.updateRows(a),t.increaseChanges()}(t,n)};return 0===Object.keys(n.rows).length?null:a().createElement("div",{className:"photogrid"},Object.entries(n.rows).map((function(i,c){return i[1].length&&a().createElement("div",{key:"row-"+c,className:n.isEditing?"photogrid--photo__row editing":"photogrid--photo__row"},a().createElement(a().Fragment,null,n.isEditing&&a().createElement(R,{rowKey:i[0],moveRowUp:w,moveRowDown:g,rowCount:Object.keys(n.rows).length}),l(i[1]).map((function(l,u){return a().createElement("div",{key:"photo-"+c+u,className:"photogrid--photo__column"},a().createElement("img",{width:l.width,height:l.height,"data-id":l.id,src:"/api/photos/"+l.thumbnail_path,alt:l.thumbnail_path}),n.isEditing&&a().createElement(a().Fragment,null,n.photoMenu?(0,r.cloneElement)(n.photoMenu,{photo:l}):null,a().createElement(O,{rowKey:i[0],photo:l,movePhotoDown:e,movePhotoLeft:o,movePhotoUp:t,movePhotoRight:h,rowCount:Object.keys(n.rows).length,photoCount:i[1].length})))}))))})))};module.exports=o})();
|
|
1
|
+
(()=>{var e={365:(e,n,t)=>{"use strict";t.d(n,{A:()=>l});var o=t(601),r=t.n(o),i=t(314),a=t.n(i)()(r());a.push([e.id,".photogrid--checkbox {\n background: white;\n border: 2px solid white;\n cursor: pointer;\n width: 18px;\n height: 18px;\n position: absolute;\n top: 10px;\n left: 10px;\n z-index: 10;\n}\n\n.photogrid--checkbox.active {\n background: #333;\n}\n\n.photogrid {\n padding: 0 0.125rem;\n}\n\n.photogrid--row__controls {\n display: block;\n position: absolute;\n left: 0.25rem;\n top: 50%;\n transform: translateY(-50%);\n z-index: 20;\n}\n\n.photogrid--row__controls > li {\n display: block;\n}\n\n.photogrid--photo__controls {\n display: block;\n width: 100%;\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n bottom: 0.5rem;\n text-align: center;\n}\n\n.photogrid--photo__controls > li {\n display: inline-block;\n}\n\n.photogrid--photo__controls > li + li {\n margin-left: 0.25rem;\n}\n\n.photogrid--row__controls > li + li {\n margin-top: 0.25rem;\n}\n\n.photogrid--photo__controls .photo__control, .photogrid--row__controls .row__control {\n width: 36px;\n height: 36px;\n display: block;\n background: #ddd;\n color: #333;\n font-size: 1.5rem;\n line-height: 2rem;\n}\n\n.photogrid--photo__row {\n display: block;\n background: transparent;\n min-height: 0;\n position: relative;\n z-index: 10;\n padding: 0;\n}\n\n.photogrid--photo__row.editing {\n padding-left: 2.75rem;\n}\n\n.photogrid--photo__column {\n position: relative;\n vertical-align: middle;\n display: block;\n margin: 0.125rem;\n}\n\n.photogrid--photo_overlay, .photogrid__gallery_item__overlay {\n min-height: 0;\n display: none;\n position: absolute;\n bottom: 0;\n left: 0;\n width: 100%;\n background: rgba(0, 0, 0, 0.4);\n color: white;\n padding: 0.5rem;\n z-index: 200;\n}\n\n.photogrid--photo_overlay h4, .photogrid__gallery_item__overlay h4 {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n padding: 0;\n}\n\n.photogrid--photo_overlay p, .photogrid__gallery_item__overlay p {\n margin: 7px 0 0 0;\n padding: 0;\n font-size: 12px;\n}\n\n.photogrid--photo__column > .photo__position {\n position: absolute;\n top: 0;\n z-index: 20;\n left: 50%;\n transform: translateX(-50%);\n background: rgba(0, 0, 0, 0.65);\n color: white;\n padding: 0.1rem;\n}\n\n.photogrid--photo__column > img {\n display: block;\n max-width: 100%;\n max-height: 750px;\n height: auto;\n margin: 0;\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n.custom__gallery {\n display: block;\n overflow: hidden;\n position: fixed;\n left: 0;\n top: 0;\n margin: 0 auto;\n width: 100%;\n height: 100vh;\n z-index: 9000;\n background: black;\n}\n\n.custom__gallery .custom__gallery__container {\n vertical-align: middle;\n display: block;\n height: 100%;\n margin: 0 auto;\n position: relative;\n}\n\n.custom__gallery .custom__gallery__container .previous__item {\n display: none;\n height: 50px;\n width: 50px;\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: white;\n font-size: 2rem;\n left: 50px;\n cursor: pointer;\n z-index: 9001;\n}\n\n.custom__gallery .custom__gallery__container .previous__item > * {\n pointer-events: none;\n}\n\n.custom__gallery .custom__gallery__container .custom__gallery__images {\n height: 100vh;\n text-align: center;\n}\n\n.custom__gallery .custom__gallery__container .custom__gallery__images .custom__gallery__item {\n position: relative;\n height: 100vh;\n display: none;\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n}\n\n.custom__gallery .custom__gallery__container .custom__gallery__images .custom__gallery__item.active {\n display: block;\n}\n\n.custom__gallery .custom__gallery__container .custom__gallery__images .custom__gallery__item img {\n display: block;\n position: relative;\n top: 50%;\n transform: translateY(-50%);\n max-width: 100%;\n height: auto;\n width: 100%;\n margin: 0 auto;\n line-height: 1;\n vertical-align: middle;\n outline: 0;\n}\n\n.custom__gallery .custom__gallery__container .custom__gallery__images .custom__gallery__item p {\n color: white;\n margin-top: 12px;\n}\n\n.custom__gallery .custom__gallery__container .next__item {\n display: none;\n height: 50px;\n width: 50px;\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: white;\n font-size: 2rem;\n right: 50px;\n cursor: pointer;\n z-index: 9001;\n}\n\n.custom__gallery .custom__gallery__container .next__item > * {\n pointer-events: none;\n}\n\n.custom__gallery .close__gallery {\n position: absolute;\n z-index: 9999;\n right: 0;\n background: none;\n color: white;\n border: none;\n font-size: 3rem;\n float: right;\n font-weight: 300;\n width: 73px;\n height: 73px;\n overflow: hidden;\n text-decoration: none;\n}\n\n.custom__gallery .close__gallery:active, .custom__gallery .close__gallery:focus {\n text-decoration: none;\n}\n\n\n.photogrid__gallery {\n width: 100%;\n text-align: center;\n overflow: hidden;\n position: fixed;\n height: 100vh;\n left: 0;\n top: 0;\n background-color: black;\n z-index: 400;\n margin: 0 auto;\n}\n\n.photogrid__gallery_scrollcontainer {\n display: flex;\n overflow-x: auto;\n overflow-y: hidden;\n scroll-snap-type: x mandatory;\n scroll-behavior: smooth;\n -webkit-overflow-scrolling: touch;\n height: 100vh;\n margin: 0 auto;\n width: 100%;\n}\n\n.photogrid__gallery_scrollcontainer::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n\n.photogrid__gallery_scrollcontainer::-webkit-scrollbar-thumb {\n background: #ddd;\n border-radius: 10px;\n}\n\n.photogrid__gallery_scrollcontainer::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.photogrid__gallery_item {\n width: 100%;\n height: 100vh;\n scroll-snap-align: start;\n transform-origin: center;\n transform: scale(1);\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n}\n\n.photogrid__gallery_item +.photogrid__gallery_item {\n margin-left: 1rem;\n}\n\n.photogrid__gallery_item > img {\n max-width: 100%;\n height: auto;\n display: block;\n margin: 0 auto;\n}\n\n.photogrid__gallery__hide {\n text-align: right;\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n padding-right: 0.5rem;\n z-index: 500;\n}\n\n.photogrid__gallery__hide > button {\n color: white;\n font-weight: 300;\n width: 73px;\n height: 73px;\n font-size: 3rem;\n background: none;\n border: none;\n}\n\n.photogrid__prev, .photogrid__next {\n display: none;\n width: auto;\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n color: white;\n z-index: 401;\n font-size: 2rem;\n}\n\n.photogrid__prev > button > *, .photogrid__next > button > * {\n pointer-events: none;\n}\n\n.photogrid__prev {\n left: 1.25rem;\n}\n\n.photogrid__next {\n right: 1.25rem;\n}\n\n@media only screen and (min-width: 768px) {\n .custom__gallery .custom__gallery__container .previous__item, .custom__gallery .custom__gallery__container .next__item {\n display: inline-block;\n }\n\n .photogrid--photo__row {\n display: flex;\n flex: 1 1 auto;\n }\n\n .photogrid--photo__column > img {\n display: inline-block;\n }\n}\n\n@media only screen and (min-width: 1024px) {\n .photogrid__prev, .photogrid__next {\n display: block;\n }\n}\n\n\n@media only screen and (min-width: 1280px) {\n .custom__gallery .custom__gallery__container .custom__gallery__images .custom__gallery__item img:hover + .custom__gallery__photo__overlay {\n display: block;\n }\n .photogrid--photo__column img:hover + .photogrid--photo_overlay {\n display: block;\n }\n .photogrid__gallery_item > img:hover .photogrid__gallery_item__overlay {\n display: block;\n }\n .photogrid__gallery_scrollcontainer {\n width: 91.6%;\n }\n}\n\n@media only screen and (min-width: 1400px) {\n .custom__gallery .custom__gallery__container {\n width: 92%;\n }\n\n .custom__gallery .custom__gallery__container .custom__gallery__images .custom__gallery__item img {\n max-width: 100%;\n height: 100%;\n width: auto;\n }\n}\n\n@media only screen and (min-width: 1536px) {\n .photogrid__gallery_scrollcontainer {\n width: 75%;\n }\n}\n",""]);const l=a},314:e=>{"use strict";e.exports=function(e){var n=[];return n.toString=function(){return this.map((function(n){var t="",o=void 0!==n[5];return n[4]&&(t+="@supports (".concat(n[4],") {")),n[2]&&(t+="@media ".concat(n[2]," {")),o&&(t+="@layer".concat(n[5].length>0?" ".concat(n[5]):""," {")),t+=e(n),o&&(t+="}"),n[2]&&(t+="}"),n[4]&&(t+="}"),t})).join("")},n.i=function(e,t,o,r,i){"string"==typeof e&&(e=[[null,e,void 0]]);var a={};if(o)for(var l=0;l<this.length;l++){var c=this[l][0];null!=c&&(a[c]=!0)}for(var s=0;s<e.length;s++){var u=[].concat(e[s]);o&&a[u[0]]||(void 0!==i&&(void 0===u[5]||(u[1]="@layer".concat(u[5].length>0?" ".concat(u[5]):""," {").concat(u[1],"}")),u[5]=i),t&&(u[2]?(u[1]="@media ".concat(u[2]," {").concat(u[1],"}"),u[2]=t):u[2]=t),r&&(u[4]?(u[1]="@supports (".concat(u[4],") {").concat(u[1],"}"),u[4]=r):u[4]="".concat(r)),n.push(u))}},n}},601:e=>{"use strict";e.exports=function(e){return e[1]}},181:(e,n,t)=>{var o=/^\s+|\s+$/g,r=/^[-+]0x[0-9a-f]+$/i,i=/^0b[01]+$/i,a=/^0o[0-7]+$/i,l=parseInt,c="object"==typeof t.g&&t.g&&t.g.Object===Object&&t.g,s="object"==typeof self&&self&&self.Object===Object&&self,u=c||s||Function("return this")(),p=Object.prototype.toString,d=Math.max,_=Math.min,m=function(){return u.Date.now()};function h(e){var n=typeof e;return!!e&&("object"==n||"function"==n)}function g(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==p.call(e)}(e))return NaN;if(h(e)){var n="function"==typeof e.valueOf?e.valueOf():e;e=h(n)?n+"":n}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(o,"");var t=i.test(e);return t||a.test(e)?l(e.slice(2),t?2:8):r.test(e)?NaN:+e}e.exports=function(e,n,t){var o,r,i,a,l,c,s=0,u=!1,p=!1,f=!0;if("function"!=typeof e)throw new TypeError("Expected a function");function y(n){var t=o,i=r;return o=r=void 0,s=n,a=e.apply(i,t)}function v(e){var t=e-c;return void 0===c||t>=n||t<0||p&&e-s>=i}function w(){var e=m();if(v(e))return b(e);l=setTimeout(w,function(e){var t=n-(e-c);return p?_(t,i-(e-s)):t}(e))}function b(e){return l=void 0,f&&o?y(e):(o=r=void 0,a)}function x(){var e=m(),t=v(e);if(o=arguments,r=this,c=e,t){if(void 0===l)return function(e){return s=e,l=setTimeout(w,n),u?y(e):a}(c);if(p)return l=setTimeout(w,n),y(c)}return void 0===l&&(l=setTimeout(w,n)),a}return n=g(n)||0,h(t)&&(u=!!t.leading,i=(p="maxWait"in t)?d(g(t.maxWait)||0,n):i,f="trailing"in t?!!t.trailing:f),x.cancel=function(){void 0!==l&&clearTimeout(l),s=0,o=c=r=l=void 0},x.flush=function(){return void 0===l?a:b(m())},x}},72:e=>{"use strict";var n=[];function t(e){for(var t=-1,o=0;o<n.length;o++)if(n[o].identifier===e){t=o;break}return t}function o(e,o){for(var i={},a=[],l=0;l<e.length;l++){var c=e[l],s=o.base?c[0]+o.base:c[0],u=i[s]||0,p="".concat(s," ").concat(u);i[s]=u+1;var d=t(p),_={css:c[1],media:c[2],sourceMap:c[3],supports:c[4],layer:c[5]};if(-1!==d)n[d].references++,n[d].updater(_);else{var m=r(_,o);o.byIndex=l,n.splice(l,0,{identifier:p,updater:m,references:1})}a.push(p)}return a}function r(e,n){var t=n.domAPI(n);return t.update(e),function(n){if(n){if(n.css===e.css&&n.media===e.media&&n.sourceMap===e.sourceMap&&n.supports===e.supports&&n.layer===e.layer)return;t.update(e=n)}else t.remove()}}e.exports=function(e,r){var i=o(e=e||[],r=r||{});return function(e){e=e||[];for(var a=0;a<i.length;a++){var l=t(i[a]);n[l].references--}for(var c=o(e,r),s=0;s<i.length;s++){var u=t(i[s]);0===n[u].references&&(n[u].updater(),n.splice(u,1))}i=c}}},659:e=>{"use strict";var n={};e.exports=function(e,t){var o=function(e){if(void 0===n[e]){var t=document.querySelector(e);if(window.HTMLIFrameElement&&t instanceof window.HTMLIFrameElement)try{t=t.contentDocument.head}catch(e){t=null}n[e]=t}return n[e]}(e);if(!o)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");o.appendChild(t)}},540:e=>{"use strict";e.exports=function(e){var n=document.createElement("style");return e.setAttributes(n,e.attributes),e.insert(n,e.options),n}},56:(e,n,t)=>{"use strict";e.exports=function(e){var n=t.nc;n&&e.setAttribute("nonce",n)}},825:e=>{"use strict";e.exports=function(e){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var n=e.insertStyleElement(e);return{update:function(t){!function(e,n,t){var o="";t.supports&&(o+="@supports (".concat(t.supports,") {")),t.media&&(o+="@media ".concat(t.media," {"));var r=void 0!==t.layer;r&&(o+="@layer".concat(t.layer.length>0?" ".concat(t.layer):""," {")),o+=t.css,r&&(o+="}"),t.media&&(o+="}"),t.supports&&(o+="}");var i=t.sourceMap;i&&"undefined"!=typeof btoa&&(o+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),n.styleTagTransform(o,e,n.options)}(n,e,t)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(n)}}}},113:e=>{"use strict";e.exports=function(e,n){if(n.styleSheet)n.styleSheet.cssText=e;else{for(;n.firstChild;)n.removeChild(n.firstChild);n.appendChild(document.createTextNode(e))}}}},n={};function t(o){var r=n[o];if(void 0!==r)return r.exports;var i=n[o]={id:o,exports:{}};return e[o](i,i.exports,t),i.exports}t.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return t.d(n,{a:n}),n},t.d=(e,n)=>{for(var o in n)t.o(n,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:n[o]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.nc=void 0;var o={};(()=>{"use strict";t.r(o),t.d(o,{Checkbox:()=>G,PhotoGrid:()=>H,PhotoItem:()=>e.PhotoItem,PhotoRows:()=>e.PhotoRows,imgSrcProperty:()=>B,sortPhotosIntoRows:()=>l});var e={};t.r(e),t.d(e,{B:()=>B});const n=require("react");var r=t.n(n),i=function(){return i=Object.assign||function(e){for(var n,t=1,o=arguments.length;t<o;t++)for(var r in n=arguments[t])Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r]);return e},i.apply(this,arguments)},a=function(e){return null!=e.name&&""!==e.name||null!=e.description&&""!==e.description},l=function(e){for(var n={},t=0,o=e;t<o.length;t++){var r=o[t],i=r.row;n[i]||(n[i]=[]),n[i].push(r)}return n},c=function(e,n){switch(n){case"id":return e.id;case"thumbnail_path":return e.thumbnail_path;case"image_path":return e.image_path}return e.image_path},s=function(e){return e.sort((function(e,n){return Math.floor(e.column)-Math.floor(n.column)}))},u=function(e,n){var t=e.find((function(e){return e.id===n}));if(void 0===t)throw new TypeError("No photo was found in this row for that id");return t},p=function(e,n){var t=e.find((function(e){return e.column===n}));if(void 0===t)throw new TypeError("No photo was found in this row for that column");return t},d=function(e,n){return e.filter((function(e){return e.column!==n}))},_=function(e,n,t){return void 0===e&&(e=[]),n.column=t,e.push(n),e},m=function(e,n,t){var o=n.column,r=t.column;return e=d(e,o),e=d(e,r),e=_(e,n,r),_(e,t,o)},h=function(e){return"string"==typeof e&&(e=parseInt(e)),e},g=function(e){var n=e.currentTarget,t=n.dataset.id,o=n.dataset.row;if(!t||!o)throw new TypeError("id or row key missing from photo control");return{id:t,rowKey:parseInt(o)}},f=function(e,n,t){for(var o=n;o<=t;o++){var r=p(e,o);e=d(e,o),e=_(e,r,r.column-1)}return e},y=function(e,n){return null==e[n]&&Object.entries(e).map((function(t){var o=t[0],r=t[1],i=parseInt(o);i>n&&(delete e[i],e[i-1]=r)})),e},v=function(e,n,t,o,r){return delete e[r],delete e[t],e[r]=n,e[t]=o,e},w=t(72),b=t.n(w),x=t(825),k=t.n(x),E=t(659),S=t.n(E),C=t(56),K=t.n(C),A=t(540),T=t.n(A),N=t(113),P=t.n(N),M=t(365),j={};j.styleTagTransform=P(),j.setAttributes=K(),j.insert=S().bind(null,"head"),j.domAPI=k(),j.insertStyleElement=T(),b()(M.A,j),M.A&&M.A.locals&&M.A.locals;const I=function(e){return r().createElement("ul",{className:"photogrid--row__controls"},h(e.rowKey)>1&&r().createElement("li",null,r().createElement("button",{className:"row__control move__row__up",onClick:e.moveRowUp,"data-row":e.rowKey,dangerouslySetInnerHTML:{__html:e.buttonArrows?e.buttonArrows.up:"↑"}})),h(e.rowKey)<e.rowCount&&r().createElement("li",null,r().createElement("button",{className:"row__control move__row__down",onClick:e.moveRowDown,"data-row":e.rowKey,dangerouslySetInnerHTML:{__html:e.buttonArrows?e.buttonArrows.down:"↓"}})))},z=function(e){return r().createElement("ul",{className:"photogrid--photo__controls"},e.photo.column>1&&r().createElement("li",null,r().createElement("button",{type:"button",className:"photo__control move__photo__left",onClick:e.movePhotoLeft,"data-id":e.photo.id,"data-row":e.rowKey,dangerouslySetInnerHTML:{__html:e.buttonArrows?e.buttonArrows.left:"←"}})),h(e.rowKey)>1&&r().createElement("li",null,r().createElement("button",{type:"button",className:"photo__control move__photo__up",onClick:e.movePhotoUp,"data-id":e.photo.id,"data-row":e.rowKey,dangerouslySetInnerHTML:{__html:e.buttonArrows?e.buttonArrows.up:"↑"}})),h(e.rowKey)<e.rowCount||h(e.rowKey)===e.rowCount&&e.photoCount>1?r().createElement("li",null,r().createElement("button",{type:"button",className:"photo__control move__photo__down",onClick:e.movePhotoDown,"data-id":e.photo.id,"data-row":e.rowKey,dangerouslySetInnerHTML:{__html:e.buttonArrows?e.buttonArrows.down:"↓"}})):null,e.photo.column<e.photoCount&&r().createElement("li",null,r().createElement("button",{type:"button",className:"photo__control move__photo__right",onClick:e.movePhotoRight,"data-id":e.photo.id,"data-row":e.rowKey,dangerouslySetInnerHTML:{__html:e.buttonArrows?e.buttonArrows.right:"→"}})))};var R=t(181),O=t.n(R);const D=function(e){var t=e.photos,o=e.imageSrcPrefix,i=e.imageSrcProperty,l=(e.onGallerySwipe,e.activeKey),c=e.setActiveKey,s=e.buttonArrows,u=(0,n.useState)(!1),p=u[0],d=u[1],_=(0,n.useRef)(null),m=(0,n.useRef)([]),h=(0,n.useState)(!1),g=(h[0],h[1]),f=function(e,n){switch(n){case"id":return e.id;case"thumbnail_path":return e.thumbnail_path;case"image_path":return e.image_path}return e.image_path},y=(0,n.useCallback)(O()((function(e){g(!1);var n=m.current[e],t=_.current;if(n&&t){var o=n.getBoundingClientRect(),r=t.getBoundingClientRect(),i=o.left-r.left+t.scrollLeft;t.scrollTo({left:i,behavior:"smooth"})}g(!0)}),100),[]),v=function(e){return e.preventDefault(),!1};return(0,n.useEffect)((function(){l>-1&&!1===p&&(d(!0),y(l))}),[l]),(0,n.useEffect)((function(){m.current.forEach((function(e,n){if(e){var t=e.getAttribute("data-src");t&&(e.src=t)}}))}),[t]),r().createElement("div",{className:"".concat(p?"block":"hidden"," photogrid__gallery")},r().createElement("div",{className:"photogrid__gallery__hide"},r().createElement("button",{onClick:function(){d(!1),c(-1)},type:"button"},"×")),r().createElement("div",{className:"photogrid__prev"},r().createElement("button",{type:"button",onClick:function(e){e.preventDefault(),null!=_.current&&_.current.scrollBy({top:0,left:-1,behavior:"smooth"})},dangerouslySetInnerHTML:{__html:s?s.prev:"←"}})),r().createElement("div",{ref:_,className:"photogrid__gallery_scrollcontainer",onScroll:function(e){}},t.length&&t.map((function(e,n){return r().createElement("div",{key:"".concat(n),className:"photogrid__gallery_item"},r().createElement("img",{ref:function(e){return m.current[n]=e},"data-index":n,"data-src":"".concat(o).concat(f(e,i)),alt:"gallery item",onContextMenu:v}),!0===a(e)&&r().createElement("div",{className:"photogrid__gallery_item__overlay"},null!=e.name&&""!==e.name&&r().createElement("h4",null,e.name),null!=e.description&&""!==e.description&&r().createElement("p",null,e.description)))}))),r().createElement("div",{className:"photogrid__next"},r().createElement("button",{type:"button",onClick:function(e){e.preventDefault(),null!=_.current&&_.current.scrollBy({top:0,left:800,behavior:"smooth"})},dangerouslySetInnerHTML:{__html:s?s.next:"→"}})))},L=function(e){var t=(0,n.useState)(null),o=t[0],i=t[1],l=(0,n.useState)(!1),s=l[0],u=l[1],p=function(n){var t=e.imageSrcProperty;return c(n,t)},d=function(){if(e.onGallerySwipe){var n=e.activeKey,t=e.photos[n];t&&e.onGallerySwipe(t)}},_=function(n){39===n.keyCode?e.activeKey<e.photos.length-1&&e.setActiveKey(e.activeKey+1):37===n.keyCode&&e.activeKey>0&&e.setActiveKey(e.activeKey-1),d()},m=function(){return!1};return(0,n.useEffect)((function(){return e.activeKey>-1&&!1===s&&u(!0),document.addEventListener("keydown",_),function(){document.removeEventListener("keydown",_)}}),[e.activeKey]),r().createElement("div",{className:"custom__gallery",style:{display:!0===s?"block":"none"},onTouchStart:function(e){var n=e.touches[0].clientX;i(n)},onTouchMove:function(n){if(null!==o){var t=n.touches[0].clientX,r=o-t;r>5&&e.activeKey<e.photos.length-1&&e.setActiveKey(e.activeKey+1),r<-5&&e.activeKey>0&&e.setActiveKey(e.activeKey-1),d(),i(null)}}},r().createElement("div",{className:"clearfix"},r().createElement("button",{className:"close__gallery",onClick:function(){u(!1),e.setActiveKey(-1)},type:"button"},"×")),r().createElement("div",{className:"custom__gallery__container"},e.activeKey>0&&r().createElement("button",{onClick:function(n){n.preventDefault(),e.activeKey>0&&(e.setActiveKey(e.activeKey-1),d())},className:"previous__item",dangerouslySetInnerHTML:{__html:e.buttonArrows?e.buttonArrows.prev:"←"}}),r().createElement("div",{className:"custom__gallery__images"},e.photos.length&&e.photos.map((function(n,t){return r().createElement("div",{key:"".concat(t),className:e.activeKey==t?"custom__gallery__item active":"custom__gallery__item"},r().createElement("img",{src:(o=t,i=e.activeKey,l=[i],i>0&&l.push(i-1),i<e.photos.length-1&&l.push(i+1),l.includes(o)?"".concat(e.imageSrcPrefix).concat(p(n)):""),alt:"gallery item",onContextMenu:m}),!0===a(n)&&r().createElement("div",{className:"custom__gallery__photo__overlay"},null!=n.name&&""!==n.name&&r().createElement("h4",null,n.name),null!=n.description&&""!==n.description&&r().createElement("p",null,n.description)));var o,i,l}))),e.activeKey<e.photos.length-1&&r().createElement("button",{onClick:function(n){n.preventDefault(),e.activeKey<e.photos.length-1&&(e.setActiveKey(e.activeKey+1),d())},className:"next__item",dangerouslySetInnerHTML:{__html:e.buttonArrows?e.buttonArrows.next:"→"}})))},H=function(e){var t=(0,n.useState)(-1),o=t[0],l=t[1],h=function(n){!function(e,n){e.preventDefault();var t=g(e),o=t.id,r=t.rowKey,a=i({},n.rows),l=s(a[r]),c=r-1,p=[];null!=a[c]&&(p=s(a[c]));var m=u(l,o),h=m.column+1,v=l.length;l=d(l,m.column),delete a[r],l.length&&(f(l,h,v),a[r]=l),p=_(p,m,p.length+1),delete a[c],a[c]=p,a=y(a,r),n.updateRows(a),n.increaseChanges()}(n,e)},w=function(n){!function(e,n){e.preventDefault();var t=g(e),o=t.id,r=t.rowKey,a=i({},n.rows),l=s(a[r]),c=r+1,m=u(l,o),h=m.column+1,v=l.length;l=d(l,m.column),delete a[r],l.length&&(l=f(l,h,v));var w=null;null==a[c]?(m.column=1,w=[m]):(w=function(e,n){for(var t=n;t>0;t--){var o=p(e,t);e=d(e,t),e=_(e,o,o.column+1)}return e}(w=s(a[c]),w.length),w=_(w,m,1),delete a[c]),a[c]=w,l.length&&(a[r]=l),a=y(a,r),n.updateRows(a),n.increaseChanges()}(n,e)},b=function(n){!function(e,n){e.preventDefault();var t=g(e),o=t.id,r=t.rowKey,a=i({},n.rows),l=s(a[r]),c=u(l,o);if(1!==c.column){var d=p(l,c.column-1);l=m(l,d,c),delete a[r],a[r]=l,n.updateRows(a),n.increaseChanges()}}(n,e)},x=function(n){!function(e,n){e.preventDefault();var t=g(e),o=t.id,r=t.rowKey,a=i({},n.rows),l=s(a[r]),c=u(l,o);if(c.column!==l.length){var d=p(l,c.column+1);l=m(l,c,d),delete a[r],a[r]=l,n.updateRows(a),n.increaseChanges()}}(n,e)},k=function(n){!function(e,n){e.preventDefault();var t=e.currentTarget.dataset.row;if(!t)throw new TypeError("row missing from row control");var o=parseInt(t),r=o-1,a=i({},n.rows),l=s(a[o]);if(null==a[r])delete a[o],a[r]=l;else{var c=s(a[r]);a=v(a,l,o,c,r)}n.updateRows(a),n.increaseChanges()}(n,e)},E=function(n){!function(e,n){e.preventDefault();var t=e.currentTarget.dataset.row;if(!t)throw new TypeError("row missing from row control");var o=parseInt(t),r=o+1,a=i({},n.rows),l=s(a[o]);if(!a[r])throw new TypeError("There is no next row!");var c=s(a[r]);a=v(a,l,o,c,r),n.updateRows(a),n.increaseChanges()}(n,e)},S=function(n){var t=e.imageSrcProperty;return c(n,t)},C=function(n){var t,o=n.currentTarget.dataset.id;if(!o)throw new TypeError("Photo id missing");if(e.onPhotoClick&&e.onPhotoClick(n),e.useGallery){var r=(t=o,e.photos.findIndex((function(e){return e.id&&e.id==t})));r>-1&&l(r)}},K=function(e){return e.preventDefault(),!1};return 0===Object.keys(e.rows).length?null:r().createElement("div",null,e.useGallery&&"scroll"===e.galleryType?r().createElement(D,{photos:e.photos,activeKey:o,setActiveKey:l,imageSrcPrefix:e.imageSrcPrefix,imageSrcProperty:e.gallerySrcProperty?e.gallerySrcProperty:"image_path",buttonArrows:e.galleryButtonArrows,onGallerySwipe:e.onGallerySwipe}):r().createElement(L,{photos:e.photos,activeKey:o,setActiveKey:l,imageSrcPrefix:e.imageSrcPrefix,imageSrcProperty:e.gallerySrcProperty?e.gallerySrcProperty:"image_path",buttonArrows:e.galleryButtonArrows,onGallerySwipe:e.onGallerySwipe}),r().createElement("div",{className:"photogrid"},Object.entries(e.rows).map((function(t,o){return t[1].length&&r().createElement("div",{key:"row-"+o,className:e.isEditing?"photogrid--photo__row editing":"photogrid--photo__row"},r().createElement(r().Fragment,null,e.isEditing&&r().createElement(I,{rowKey:t[0],moveRowUp:k,moveRowDown:E,rowCount:Object.keys(e.rows).length,buttonArrows:e.buttonArrows}),s(t[1]).map((function(i,l){return r().createElement("div",{key:"photo-"+o+l,className:"photogrid--photo__column"},r().createElement("img",{width:i.width,height:i.height,"data-id":i.id,src:"".concat(e.imageSrcPrefix).concat(S(i)),alt:i.thumbnail_path,onClick:C,className:e.useGallery?"cursor-pointer":"cursor-default",onContextMenu:K}),!e.isEditing&&!0===a(i)&&r().createElement("div",{className:"photogrid--photo_overlay"},null!=i.name&&""!==i.name&&r().createElement("h4",null,i.name),null!=i.description&&""!==i.description&&r().createElement("p",null,i.description)),e.isEditing&&r().createElement(r().Fragment,null,r().createElement("p",{className:"photo__position"},"R: ",t[0]," | C: ",i.column),e.photoMenu?(0,n.cloneElement)(e.photoMenu,{photo:i}):null,r().createElement(z,{rowKey:t[0],photo:i,movePhotoDown:w,movePhotoLeft:b,movePhotoUp:h,movePhotoRight:x,rowCount:Object.keys(e.rows).length,photoCount:t[1].length,buttonArrows:e.buttonArrows})))}))))}))))},G=function(e){return r().createElement("div",{className:e.checked?"photogrid--checkbox active":"photogrid--checkbox",onClick:function(n){n.preventDefault(),e.checked?e.onClick(e.value,!1):e.onClick(e.value,!0)}})};var B;!function(e){e.id="id",e.thumbnail_path="thumbnail_path",e.image_path="image_path"}(B||(B={}))})(),module.exports=o})();
|
package/package.json
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-editable-photo-grid",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "An editable photo grid built with React and Typescript",
|
|
5
|
-
"main": "index.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"src"
|
|
9
|
+
],
|
|
6
10
|
"scripts": {
|
|
7
11
|
"build": "webpack"
|
|
8
12
|
},
|
|
9
13
|
"peerDependencies": {
|
|
10
14
|
"@types/node": "^20.14.10",
|
|
11
15
|
"react": "^17.0.0 || ^18.0.0",
|
|
12
|
-
"react-dom": "^17.0.0 || ^18.0.0"
|
|
13
|
-
"typescript": "^5.5.3"
|
|
16
|
+
"react-dom": "^17.0.0 || ^18.0.0"
|
|
14
17
|
},
|
|
15
18
|
"devDependencies": {
|
|
16
19
|
"@babel/core": "^7.24.9",
|
|
17
20
|
"@babel/preset-env": "^7.24.8",
|
|
18
21
|
"@babel/preset-react": "^7.24.7",
|
|
19
22
|
"@babel/preset-typescript": "^7.24.7",
|
|
23
|
+
"@types/lodash.debounce": "^4.0.9",
|
|
20
24
|
"babel-loader": "^9.1.3",
|
|
21
25
|
"css-loader": "^7.1.2",
|
|
22
26
|
"style-loader": "^4.0.0",
|
|
@@ -27,7 +31,7 @@
|
|
|
27
31
|
},
|
|
28
32
|
"repository": {
|
|
29
33
|
"type": "git",
|
|
30
|
-
"url": "git+ssh://git@github.com/DominicHart/react-photo-grid.git"
|
|
34
|
+
"url": "git+ssh://git@github.com/DominicHart/react-editable-photo-grid.git"
|
|
31
35
|
},
|
|
32
36
|
"keywords": [
|
|
33
37
|
"photo",
|
|
@@ -38,11 +42,12 @@
|
|
|
38
42
|
"author": "Dominic Hart",
|
|
39
43
|
"license": "GPL-3.0",
|
|
40
44
|
"bugs": {
|
|
41
|
-
"url": "https://github.com/DominicHart/react-photo-grid/issues"
|
|
45
|
+
"url": "https://github.com/DominicHart/react-editable-photo-grid/issues"
|
|
42
46
|
},
|
|
43
|
-
"homepage": "https://github.com/DominicHart/react-photo-grid#readme",
|
|
47
|
+
"homepage": "https://github.com/DominicHart/react-editable-photo-grid#readme",
|
|
44
48
|
"dependencies": {
|
|
45
49
|
"@types/react": "^18.3.3",
|
|
50
|
+
"lodash.debounce": "^4.0.8",
|
|
46
51
|
"react": "^17.0.0 || ^18.0.0",
|
|
47
52
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
48
53
|
}
|
package/src/PhotoGrid.tsx
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import React, { cloneElement } from 'react';
|
|
2
|
-
import { PhotoGridProps } from './types';
|
|
3
|
-
import { sortRow, movePhotoLeft, movePhotoUp, movePhotoDown, movePhotoRight, moveRowUp, moveRowDown } from "./utils";
|
|
1
|
+
import React, { cloneElement, useState } from 'react';
|
|
2
|
+
import { PhotoGridProps, PhotoItem, imgSrcProperty } from './types';
|
|
3
|
+
import { sortRow, movePhotoLeft, movePhotoUp, movePhotoDown, movePhotoRight, moveRowUp, moveRowDown, getImageSrcProperty, photoHasDetails } from "./utils";
|
|
4
4
|
import RowControls from './components/RowControls';
|
|
5
5
|
import PhotoControls from './components/PhotoControls';
|
|
6
|
+
import ScrollGallery from './components/ScrollGallery';
|
|
7
|
+
import NonScrollGallery from './components/NonScrollGallery';
|
|
6
8
|
import './styles.css';
|
|
7
9
|
|
|
8
10
|
const PhotoGrid = (props: PhotoGridProps) => {
|
|
11
|
+
const [activeGalleryKey, setActiveGalleryKey] = useState<number>(-1);
|
|
12
|
+
|
|
9
13
|
const handleMovePhotoUp = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
10
14
|
movePhotoUp(e, props);
|
|
11
15
|
}
|
|
@@ -30,63 +34,135 @@ const PhotoGrid = (props: PhotoGridProps) => {
|
|
|
30
34
|
moveRowDown(e, props);
|
|
31
35
|
}
|
|
32
36
|
|
|
37
|
+
const getSrcProperty = (photo: PhotoItem): string => {
|
|
38
|
+
const property = props.imageSrcProperty as string;
|
|
39
|
+
return getImageSrcProperty(photo, property);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const getGalleryKey = (id: string): number => {
|
|
43
|
+
return props.photos.findIndex((photoItem: PhotoItem) => photoItem.id && photoItem.id == id);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const onPhotoClick = (e: React.MouseEvent<HTMLImageElement>): void => {
|
|
47
|
+
const photoId = e.currentTarget.dataset.id;
|
|
48
|
+
if (!photoId) {
|
|
49
|
+
throw new TypeError('Photo id missing');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (props.onPhotoClick) {
|
|
53
|
+
props.onPhotoClick(e);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (props.useGallery) {
|
|
57
|
+
const imageKey = getGalleryKey(photoId);
|
|
58
|
+
if (imageKey > -1) {
|
|
59
|
+
setActiveGalleryKey(imageKey);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const disableRightClick = (e: React.MouseEvent<HTMLImageElement>) => {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
33
69
|
if (Object.keys(props.rows).length === 0) {
|
|
34
70
|
return null;
|
|
35
71
|
}
|
|
36
72
|
|
|
37
73
|
return (
|
|
38
|
-
<div
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
<div>
|
|
75
|
+
{props.useGallery &&
|
|
76
|
+
props.galleryType === 'scroll' ?
|
|
77
|
+
<ScrollGallery
|
|
78
|
+
photos={props.photos}
|
|
79
|
+
activeKey={activeGalleryKey}
|
|
80
|
+
setActiveKey={setActiveGalleryKey}
|
|
81
|
+
imageSrcPrefix={props.imageSrcPrefix}
|
|
82
|
+
imageSrcProperty={props.gallerySrcProperty ? props.gallerySrcProperty : ('image_path' as imgSrcProperty)}
|
|
83
|
+
buttonArrows={props.galleryButtonArrows}
|
|
84
|
+
onGallerySwipe={props.onGallerySwipe}
|
|
85
|
+
/>
|
|
86
|
+
: <NonScrollGallery
|
|
87
|
+
photos={props.photos}
|
|
88
|
+
activeKey={activeGalleryKey}
|
|
89
|
+
setActiveKey={setActiveGalleryKey}
|
|
90
|
+
imageSrcPrefix={props.imageSrcPrefix}
|
|
91
|
+
imageSrcProperty={props.gallerySrcProperty ? props.gallerySrcProperty : ('image_path' as imgSrcProperty)}
|
|
92
|
+
buttonArrows={props.galleryButtonArrows}
|
|
93
|
+
onGallerySwipe={props.onGallerySwipe}
|
|
94
|
+
/>
|
|
95
|
+
}
|
|
96
|
+
<div className="photogrid">
|
|
97
|
+
{Object.entries(props.rows).map((row, i) =>
|
|
98
|
+
row[1].length &&
|
|
99
|
+
<div
|
|
100
|
+
key={'row-' + i}
|
|
101
|
+
className={props.isEditing ? "photogrid--photo__row editing" : "photogrid--photo__row"}
|
|
102
|
+
>
|
|
103
|
+
<>
|
|
104
|
+
{props.isEditing &&
|
|
105
|
+
<RowControls
|
|
106
|
+
rowKey={row[0]}
|
|
107
|
+
moveRowUp={handleMoveRowUp}
|
|
108
|
+
moveRowDown={handleMoveRowDown}
|
|
109
|
+
rowCount={Object.keys(props.rows).length}
|
|
110
|
+
buttonArrows={props.buttonArrows}
|
|
65
111
|
/>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
112
|
+
}
|
|
113
|
+
{sortRow(row[1]).map((photo, i2) =>
|
|
114
|
+
<div
|
|
115
|
+
key={'photo-' + i + i2}
|
|
116
|
+
className="photogrid--photo__column"
|
|
117
|
+
>
|
|
118
|
+
<img
|
|
119
|
+
width={photo.width}
|
|
120
|
+
height={photo.height}
|
|
121
|
+
data-id={photo.id}
|
|
122
|
+
src={`${props.imageSrcPrefix}${getSrcProperty(photo)}`}
|
|
123
|
+
alt={photo.thumbnail_path}
|
|
124
|
+
onClick={onPhotoClick}
|
|
125
|
+
className={props.useGallery ? "cursor-pointer" : 'cursor-default'}
|
|
126
|
+
onContextMenu={disableRightClick}
|
|
127
|
+
/>
|
|
128
|
+
|
|
129
|
+
{!props.isEditing && photoHasDetails(photo) === true && (
|
|
130
|
+
<div className="photogrid--photo_overlay">
|
|
131
|
+
{photo.name != undefined && photo.name !== '' && (
|
|
132
|
+
<h4>{photo.name}</h4>
|
|
133
|
+
)}
|
|
134
|
+
{photo.description != undefined && photo.description !== '' && (
|
|
135
|
+
<p>{photo.description}</p>
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
)}
|
|
139
|
+
{props.isEditing &&
|
|
140
|
+
<>
|
|
141
|
+
<p className="photo__position">R: {row[0]} | C: {photo.column}</p>
|
|
142
|
+
{props.photoMenu ?
|
|
143
|
+
cloneElement(props.photoMenu, {
|
|
144
|
+
photo: photo
|
|
145
|
+
})
|
|
146
|
+
: null}
|
|
147
|
+
<PhotoControls
|
|
148
|
+
rowKey={row[0]}
|
|
149
|
+
photo={photo}
|
|
150
|
+
movePhotoDown={handleMovePhotoDown}
|
|
151
|
+
movePhotoLeft={handleMovePhotoLeft}
|
|
152
|
+
movePhotoUp={handleMovePhotoUp}
|
|
153
|
+
movePhotoRight={handleMovePhotoRight}
|
|
154
|
+
rowCount={Object.keys(props.rows).length}
|
|
155
|
+
photoCount={row[1].length}
|
|
156
|
+
buttonArrows={props.buttonArrows}
|
|
157
|
+
/>
|
|
158
|
+
</>
|
|
159
|
+
}
|
|
160
|
+
</div>
|
|
161
|
+
)}
|
|
162
|
+
</>
|
|
163
|
+
</div>
|
|
164
|
+
)}
|
|
165
|
+
</div>
|
|
90
166
|
</div>
|
|
91
167
|
);
|
|
92
168
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type props = {
|
|
4
|
+
value: string;
|
|
5
|
+
onClick: (value: string, checked: boolean) => void;
|
|
6
|
+
checked: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const Checkbox = (props: props) => {
|
|
10
|
+
const toggleCheckbox = (e: React.MouseEvent<HTMLDivElement>): void => {
|
|
11
|
+
e.preventDefault();
|
|
12
|
+
if (props.checked) {
|
|
13
|
+
props.onClick(props.value, false);
|
|
14
|
+
} else {
|
|
15
|
+
props.onClick(props.value, true);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
className={props.checked ? "photogrid--checkbox active" : "photogrid--checkbox"}
|
|
22
|
+
onClick={toggleCheckbox}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default Checkbox;
|