@azerion/bunosaurus-plugin-ideal-image 0.0.0-stage → 4.0.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.
Files changed (71) hide show
  1. package/README.md +6 -2
  2. package/lib/index.d.ts +10 -0
  3. package/lib/index.js +75 -0
  4. package/lib/theme/IdealImage/index.d.ts +9 -0
  5. package/lib/theme/IdealImage/index.js +96 -0
  6. package/lib/theme/IdealImageLegacy/LICENSE +20 -0
  7. package/lib/theme/IdealImageLegacy/README.md +13 -0
  8. package/lib/theme/IdealImageLegacy/components/Icon/Download.d.ts +2 -0
  9. package/lib/theme/IdealImageLegacy/components/Icon/Download.js +14 -0
  10. package/lib/theme/IdealImageLegacy/components/Icon/Loading.d.ts +2 -0
  11. package/lib/theme/IdealImageLegacy/components/Icon/Loading.js +14 -0
  12. package/lib/theme/IdealImageLegacy/components/Icon/Offline.d.ts +2 -0
  13. package/lib/theme/IdealImageLegacy/components/Icon/Offline.js +14 -0
  14. package/lib/theme/IdealImageLegacy/components/Icon/Warning.d.ts +2 -0
  15. package/lib/theme/IdealImageLegacy/components/Icon/Warning.js +14 -0
  16. package/lib/theme/IdealImageLegacy/components/Icon/index.d.ts +7 -0
  17. package/lib/theme/IdealImageLegacy/components/Icon/index.js +24 -0
  18. package/lib/theme/IdealImageLegacy/components/IdealImage/index.d.ts +46 -0
  19. package/lib/theme/IdealImageLegacy/components/IdealImage/index.js +352 -0
  20. package/lib/theme/IdealImageLegacy/components/IdealImage/waypoint.d.ts +10 -0
  21. package/lib/theme/IdealImageLegacy/components/IdealImage/waypoint.js +188 -0
  22. package/lib/theme/IdealImageLegacy/components/IdealImageWithDefaults/index.d.ts +32 -0
  23. package/lib/theme/IdealImageLegacy/components/IdealImageWithDefaults/index.js +11 -0
  24. package/lib/theme/IdealImageLegacy/components/Media/index.d.ts +20 -0
  25. package/lib/theme/IdealImageLegacy/components/Media/index.js +169 -0
  26. package/lib/theme/IdealImageLegacy/components/MediaWithDefaults/README.md +89 -0
  27. package/lib/theme/IdealImageLegacy/components/MediaWithDefaults/index.d.ts +32 -0
  28. package/lib/theme/IdealImageLegacy/components/MediaWithDefaults/index.js +11 -0
  29. package/lib/theme/IdealImageLegacy/components/composeStyle.d.ts +23 -0
  30. package/lib/theme/IdealImageLegacy/components/composeStyle.js +37 -0
  31. package/lib/theme/IdealImageLegacy/components/constants.d.ts +14 -0
  32. package/lib/theme/IdealImageLegacy/components/constants.js +24 -0
  33. package/lib/theme/IdealImageLegacy/components/helpers.d.ts +22 -0
  34. package/lib/theme/IdealImageLegacy/components/helpers.js +141 -0
  35. package/lib/theme/IdealImageLegacy/components/icons.d.ts +14 -0
  36. package/lib/theme/IdealImageLegacy/components/icons.js +16 -0
  37. package/lib/theme/IdealImageLegacy/components/loaders.d.ts +11 -0
  38. package/lib/theme/IdealImageLegacy/components/loaders.js +112 -0
  39. package/lib/theme/IdealImageLegacy/components/theme.d.ts +26 -0
  40. package/lib/theme/IdealImageLegacy/components/theme.js +26 -0
  41. package/lib/theme/IdealImageLegacy/components/theme.module.css +35 -0
  42. package/lib/theme/IdealImageLegacy/components/unfetch.d.ts +8 -0
  43. package/lib/theme/IdealImageLegacy/components/unfetch.js +74 -0
  44. package/lib/theme/IdealImageLegacy/index.d.ts +2 -0
  45. package/lib/theme/IdealImageLegacy/index.js +2 -0
  46. package/package.json +46 -4
  47. package/src/index.ts +94 -0
  48. package/src/plugin-ideal-image.d.ts +199 -0
  49. package/src/theme/IdealImage/index.tsx +108 -0
  50. package/src/theme/IdealImageLegacy/LICENSE +20 -0
  51. package/src/theme/IdealImageLegacy/README.md +13 -0
  52. package/src/theme/IdealImageLegacy/components/Icon/Download.js +14 -0
  53. package/src/theme/IdealImageLegacy/components/Icon/Loading.js +14 -0
  54. package/src/theme/IdealImageLegacy/components/Icon/Offline.js +14 -0
  55. package/src/theme/IdealImageLegacy/components/Icon/Warning.js +14 -0
  56. package/src/theme/IdealImageLegacy/components/Icon/index.js +24 -0
  57. package/src/theme/IdealImageLegacy/components/IdealImage/index.js +352 -0
  58. package/src/theme/IdealImageLegacy/components/IdealImage/waypoint.tsx +254 -0
  59. package/src/theme/IdealImageLegacy/components/IdealImageWithDefaults/index.js +11 -0
  60. package/src/theme/IdealImageLegacy/components/Media/index.js +169 -0
  61. package/src/theme/IdealImageLegacy/components/MediaWithDefaults/README.md +89 -0
  62. package/src/theme/IdealImageLegacy/components/MediaWithDefaults/index.js +11 -0
  63. package/src/theme/IdealImageLegacy/components/composeStyle.js +37 -0
  64. package/src/theme/IdealImageLegacy/components/constants.js +24 -0
  65. package/src/theme/IdealImageLegacy/components/helpers.js +141 -0
  66. package/src/theme/IdealImageLegacy/components/icons.js +16 -0
  67. package/src/theme/IdealImageLegacy/components/loaders.js +112 -0
  68. package/src/theme/IdealImageLegacy/components/theme.js +26 -0
  69. package/src/theme/IdealImageLegacy/components/theme.module.css +35 -0
  70. package/src/theme/IdealImageLegacy/components/unfetch.js +74 -0
  71. package/src/theme/IdealImageLegacy/index.tsx +3 -0
@@ -0,0 +1,141 @@
1
+ export const ssr =
2
+ typeof window === 'undefined' || window.navigator.userAgent === 'ReactSnap';
3
+
4
+ export const nativeConnection = !ssr && !!window.navigator.connection;
5
+
6
+ // export const getScreenWidth = () => {
7
+ // if (ssr) return 0
8
+ // const devicePixelRatio = window.devicePixelRatio || 1
9
+ // const {screen} = window
10
+ // const {width} = screen
11
+ // // const angle = (screen.orientation && screen.orientation.angle) || 0
12
+ // // return Math.max(width, height)
13
+ // // const rotated = Math.floor(angle / 90) % 2 !== 0
14
+ // // return (rotated ? height : width) * devicePixelRatio
15
+ // return width * devicePixelRatio
16
+ // }
17
+ // export const screenWidth = getScreenWidth()
18
+
19
+ export const guessMaxImageWidth = (dimensions, w) => {
20
+ if (ssr) return 0;
21
+
22
+ // Default to window object but don't use window as a default
23
+ // parameter so that this can be used on the server as well
24
+ if (!w) {
25
+ w = window;
26
+ }
27
+
28
+ const imgWidth = dimensions.width;
29
+
30
+ const {screen} = w;
31
+ const sWidth = screen.width;
32
+ const sHeight = screen.height;
33
+
34
+ const {documentElement} = document;
35
+ const windowWidth = w.innerWidth || documentElement.clientWidth;
36
+ const windowHeight = w.innerHeight || documentElement.clientHeight;
37
+ const devicePixelRatio = w.devicePixelRatio || 1;
38
+
39
+ const windowResized = sWidth > windowWidth;
40
+
41
+ let result;
42
+ if (windowResized) {
43
+ const body = document.getElementsByTagName('body')[0];
44
+ const scrollWidth = windowWidth - imgWidth;
45
+ const isScroll =
46
+ body.clientHeight > windowHeight || body.clientHeight > sHeight;
47
+ if (isScroll && scrollWidth <= 15) {
48
+ result = sWidth - scrollWidth;
49
+ } else {
50
+ result = (imgWidth / windowWidth) * sWidth;
51
+ }
52
+ } else {
53
+ result = imgWidth;
54
+ }
55
+
56
+ return result * devicePixelRatio;
57
+ };
58
+
59
+ export const bytesToSize = (bytes) => {
60
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
61
+ if (bytes === 0) return 'n/a';
62
+ const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
63
+ if (i === 0) return `${bytes} ${sizes[i]}`;
64
+ return `${(bytes / 1024 ** i).toFixed(1)} ${sizes[i]}`;
65
+ };
66
+
67
+ // async function supportsWebp() {
68
+ // if (typeof createImageBitmap === 'undefined' || typeof fetch === 'undefined')
69
+ // return false
70
+ // return fetch(
71
+ // 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=',
72
+ // )
73
+ // .then(response => response.blob())
74
+ // .then(blob => createImageBitmap(blob).then(() => true, () => false))
75
+ // }
76
+ // let webp = undefined
77
+ // const webpPromise = supportsWebp()
78
+ // webpPromise.then(x => (webp = x))
79
+ // export default () => {
80
+ // if (webp === undefined) return webpPromise
81
+ // return {
82
+ // then: callback => callback(webp),
83
+ // }
84
+ // }
85
+
86
+ const detectWebpSupport = () => {
87
+ if (ssr) return false;
88
+ const elem = document.createElement('canvas');
89
+ if (elem.getContext?.('2d')) {
90
+ // was able or not to get WebP representation
91
+ return elem.toDataURL('image/webp').indexOf('data:image/webp') === 0;
92
+ } else {
93
+ // very old browser like IE 8, canvas not supported
94
+ return false;
95
+ }
96
+ };
97
+
98
+ export const supportsWebp = detectWebpSupport();
99
+
100
+ const isWebp = (x) => x.format === 'webp' || x.src?.match(/\.webp($|\?.*)/i);
101
+
102
+ // eslint-disable-next-line no-shadow
103
+ export const selectSrc = ({srcSet, maxImageWidth, supportsWebp}) => {
104
+ if (srcSet.length === 0) throw new Error('Need at least one item in srcSet');
105
+ let supportedFormat, width;
106
+ if (supportsWebp) {
107
+ supportedFormat = srcSet.filter(isWebp);
108
+ if (supportedFormat.length === 0) supportedFormat = srcSet;
109
+ } else {
110
+ supportedFormat = srcSet.filter((x) => !isWebp(x));
111
+ if (supportedFormat.length === 0)
112
+ throw new Error('Need at least one supported format item in srcSet');
113
+ }
114
+ let widths = supportedFormat.filter((x) => x.width >= maxImageWidth);
115
+ if (widths.length === 0) {
116
+ widths = supportedFormat;
117
+ width = Math.max.apply(
118
+ null,
119
+ widths.map((x) => x.width),
120
+ );
121
+ } else {
122
+ width = Math.min.apply(
123
+ null,
124
+ widths.map((x) => x.width),
125
+ );
126
+ }
127
+ return supportedFormat.filter((x) => x.width === width)[0];
128
+ };
129
+
130
+ export const fallbackParams = ({srcSet, getUrl}) => {
131
+ if (!ssr) return {};
132
+ const notWebp = srcSet.filter((x) => !isWebp(x));
133
+ const first = notWebp[0];
134
+ return {
135
+ nsSrcSet: notWebp
136
+ .map((x) => `${getUrl ? getUrl(x) : x.src} ${x.width}w`)
137
+ .join(','),
138
+ nsSrc: getUrl ? getUrl(first) : first.src,
139
+ ssr,
140
+ };
141
+ };
@@ -0,0 +1,16 @@
1
+ import DownloadIcon from './Icon/Download';
2
+ import OfflineIcon from './Icon/Offline';
3
+ import WarningIcon from './Icon/Warning';
4
+ import LoadingIcon from './Icon/Loading';
5
+ import {icons} from './constants';
6
+
7
+ const {load, loading, loaded, error, noicon, offline} = icons;
8
+
9
+ export default {
10
+ [load]: DownloadIcon,
11
+ [loading]: LoadingIcon,
12
+ [loaded]: null,
13
+ [error]: WarningIcon,
14
+ [noicon]: null,
15
+ [offline]: OfflineIcon,
16
+ };
@@ -0,0 +1,112 @@
1
+ // There is an issue with cancelable interface
2
+ // It is not obvious that
3
+ // `image(src)` has `cancel` function
4
+ // but `image(src).then()` doesn't
5
+
6
+ import {unfetch, UnfetchAbortController} from './unfetch';
7
+
8
+ /**
9
+ * returns new "promise" with cancel function combined
10
+ *
11
+ * @param {Promise} p1 - first "promise" with cancel
12
+ * @param {Promise} p2 - second "promise" with cancel
13
+ * @returns {Promise} - new "promise" with cancel
14
+ */
15
+ export const combineCancel = (p1, p2) => {
16
+ if (!p2) return p1;
17
+ const result = p1.then(
18
+ (x) => x,
19
+ (x) => x,
20
+ );
21
+ result.cancel = () => {
22
+ p1.cancel();
23
+ p2.cancel();
24
+ };
25
+ return result;
26
+ };
27
+
28
+ export const timeout = (threshold) => {
29
+ let timerId;
30
+ const result = new Promise((resolve) => {
31
+ timerId = setTimeout(resolve, threshold);
32
+ });
33
+ result.cancel = () => {
34
+ // there is a bug with cancel somewhere in the code
35
+ // if (!timerId) throw new Error('Already canceled')
36
+ clearTimeout(timerId);
37
+ timerId = undefined;
38
+ };
39
+ return result;
40
+ };
41
+
42
+ // Caveat: image loader can not cancel download in some browsers
43
+ export const imageLoader = (src) => {
44
+ let img = new Image();
45
+ const result = new Promise((resolve, reject) => {
46
+ img.onload = resolve;
47
+ // eslint-disable-next-line no-multi-assign
48
+ img.onabort = img.onerror = () => reject({});
49
+ img.src = src;
50
+ });
51
+ result.cancel = () => {
52
+ if (!img) throw new Error('Already canceled');
53
+ // eslint-disable-next-line no-multi-assign
54
+ img.onload = img.onabort = img.onerror = undefined;
55
+ img.src = '';
56
+ img = undefined;
57
+ };
58
+ return result;
59
+ };
60
+
61
+ // Caveat: XHR loader can cause errors because of 'Access-Control-Allow-Origin'
62
+ // Caveat: we still need imageLoader to do actual decoding,
63
+ // but if images are uncachable this will lead to two requests
64
+ export const xhrLoader = (url, options) => {
65
+ let controller = new UnfetchAbortController();
66
+ const signal = controller.signal;
67
+ const result = new Promise((resolve, reject) =>
68
+ unfetch(url, {...options, signal}).then((response) => {
69
+ if (response.ok) {
70
+ response
71
+ .blob()
72
+ .then(() => imageLoader(url))
73
+ .then(resolve);
74
+ } else {
75
+ reject({status: response.status});
76
+ }
77
+ }, reject),
78
+ );
79
+ result.cancel = () => {
80
+ if (!controller) throw new Error('Already canceled');
81
+ controller.abort();
82
+ controller = undefined;
83
+ };
84
+ return result;
85
+ };
86
+
87
+ // Caveat: AbortController only supported in Chrome 66+
88
+ // Caveat: we still need imageLoader to do actual decoding,
89
+ // but if images are uncachable this will lead to two requests
90
+ // export const fetchLoader = (url, options) => {
91
+ // let controller = new AbortController()
92
+ // const signal = controller.signal
93
+ // const result = new Promise((resolve, reject) =>
94
+ // fetch(url, {...options, signal}).then(response => {
95
+ // if (response.ok) {
96
+ // options && options.onMeta && options.onMeta(response.headers)
97
+ // response
98
+ // .blob()
99
+ // .then(() => imageLoader(url))
100
+ // .then(resolve)
101
+ // } else {
102
+ // reject({status: response.status})
103
+ // }
104
+ // }, reject),
105
+ // )
106
+ // result.cancel = () => {
107
+ // if (!controller) throw new Error('Already canceled')
108
+ // controller.abort()
109
+ // controller = undefined
110
+ // }
111
+ // return result
112
+ // }
@@ -0,0 +1,26 @@
1
+ export default {
2
+ placeholder: {
3
+ backgroundSize: 'cover',
4
+ backgroundRepeat: 'no-repeat',
5
+ position: 'relative',
6
+ },
7
+ img: {
8
+ width: '100%',
9
+ height: 'auto',
10
+ maxWidth: '100%',
11
+ /* TODO: fix bug in styles */
12
+ marginBottom: '-4px',
13
+ },
14
+ icon: {
15
+ position: 'absolute',
16
+ top: '50%',
17
+ left: '50%',
18
+ transform: 'translate(-50%, -50%)',
19
+ textAlign: 'center',
20
+ },
21
+ noscript: {
22
+ position: 'absolute',
23
+ top: 0,
24
+ left: 0,
25
+ },
26
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ .placeholder {
9
+ background-size: cover;
10
+ background-repeat: no-repeat;
11
+ position: relative;
12
+ }
13
+
14
+ .img {
15
+ width: 100%;
16
+ height: auto;
17
+ max-width: 100%;
18
+ /* TODO: fix bug in styles */
19
+ margin-bottom: -4px;
20
+ transform: translate3d(0, 0, 0);
21
+ }
22
+
23
+ .icon {
24
+ position: absolute;
25
+ top: 50%;
26
+ left: 50%;
27
+ transform: translate(-50%, -50%);
28
+ text-align: center;
29
+ }
30
+
31
+ .noscript {
32
+ position: absolute;
33
+ top: 0;
34
+ left: 0;
35
+ }
@@ -0,0 +1,74 @@
1
+ export class UnfetchAbortController {
2
+ constructor() {
3
+ this.signal = {onabort: () => {}};
4
+ this.abort = () => this.signal.onabort();
5
+ }
6
+ }
7
+
8
+ // modified version of https://github.com/developit/unfetch
9
+ // - ponyfill instead of polyfill
10
+ // - add support for AbortController
11
+ export const unfetch = (url, options) => {
12
+ options = options || {};
13
+ return new Promise((resolve, reject) => {
14
+ const request = new XMLHttpRequest();
15
+
16
+ request.open(options.method || 'get', url, true);
17
+
18
+ // eslint-disable-next-line guard-for-in
19
+ for (const i in options.headers) {
20
+ request.setRequestHeader(i, options.headers[i]);
21
+ }
22
+
23
+ request.withCredentials = options.credentials === 'include';
24
+
25
+ request.onload = () => {
26
+ resolve(response());
27
+ };
28
+
29
+ request.onerror = reject;
30
+
31
+ if (options.signal)
32
+ options.signal.onabort = () => {
33
+ // eslint-disable-next-line no-multi-assign
34
+ request.onerror = request.onload = undefined;
35
+ request.abort();
36
+ };
37
+
38
+ request.send(options.body);
39
+
40
+ function response() {
41
+ const keys = [];
42
+ const all = [];
43
+ const headers = {};
44
+ let header;
45
+
46
+ request
47
+ .getAllResponseHeaders()
48
+ .replace(/^(.*?):\s*?([\s\S]*?)$/gm, (m, key, value) => {
49
+ keys.push((key = key.toLowerCase()));
50
+ all.push([key, value]);
51
+ header = headers[key];
52
+ headers[key] = header ? `${header},${value}` : value;
53
+ });
54
+
55
+ return {
56
+ // eslint-disable-next-line no-bitwise
57
+ ok: ((request.status / 100) | 0) === 2, // 200-299
58
+ status: request.status,
59
+ statusText: request.statusText,
60
+ url: request.responseURL,
61
+ clone: response,
62
+ text: () => Promise.resolve(request.responseText),
63
+ json: () => Promise.resolve(request.responseText).then(JSON.parse),
64
+ blob: () => Promise.resolve(new Blob([request.response])),
65
+ headers: {
66
+ keys: () => keys,
67
+ entries: () => all,
68
+ get: (n) => headers[n.toLowerCase()],
69
+ has: (n) => n.toLowerCase() in headers,
70
+ },
71
+ };
72
+ }
73
+ });
74
+ };
@@ -0,0 +1,3 @@
1
+ import IdealImageWithDefaults from './components/IdealImageWithDefaults';
2
+
3
+ export default IdealImageWithDefaults;