@mittwald/flow-react-components 0.2.0-alpha.872 → 0.2.0-alpha.874
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/CHANGELOG.md +12 -0
- package/dist/assets/doc-properties.json +11212 -11212
- package/dist/js/flr-universal.mjs +1 -0
- package/dist/js/flr-universal.mjs.map +1 -1
- package/dist/js/packages/components/src/components/ImageCropper/ImageCropper.mjs +24 -12
- package/dist/js/packages/components/src/components/ImageCropper/ImageCropper.mjs.map +1 -1
- package/dist/js/packages/components/src/components/ImageCropper/lib/getCroppedImageFile.mjs +15 -7
- package/dist/js/packages/components/src/components/ImageCropper/lib/getCroppedImageFile.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Navigation/components/NavigationGroup/NavigationGroup.mjs +21 -6
- package/dist/js/packages/components/src/components/Navigation/components/NavigationGroup/NavigationGroup.mjs.map +1 -1
- package/dist/js/packages/components/src/lib/hooks/useImageSrc.mjs +9 -19
- package/dist/js/packages/components/src/lib/hooks/useImageSrc.mjs.map +1 -1
- package/dist/types/components/ImageCropper/ImageCropper.d.ts.map +1 -1
- package/dist/types/components/ImageCropper/lib/getCroppedImageFile.d.ts +1 -1
- package/dist/types/components/ImageCropper/lib/getCroppedImageFile.d.ts.map +1 -1
- package/dist/types/components/ImageCropper/stories/Default.stories.d.ts.map +1 -1
- package/dist/types/components/Navigation/components/NavigationGroup/NavigationGroup.d.ts.map +1 -1
- package/dist/types/lib/hooks/useImageSrc.d.ts.map +1 -1
- package/package.json +7 -6
|
@@ -210,6 +210,7 @@ import './packages/components/src/components/IllustratedMessage/IllustratedMessa
|
|
|
210
210
|
import './packages/components/src/components/Image/Image.mjs';
|
|
211
211
|
import 'react-easy-crop';
|
|
212
212
|
import './packages/components/src/components/Slider/Slider.mjs';
|
|
213
|
+
import 'use-debounce';
|
|
213
214
|
import './packages/components/src/components/Initials/Initials.mjs';
|
|
214
215
|
export { IntlProvider } from './packages/components/src/components/IntlProvider/IntlProvider.mjs';
|
|
215
216
|
import './packages/components/src/components/LayoutCard/LayoutCard.mjs';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flr-universal.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"flr-universal.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
/* */
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
-
import { useState,
|
|
4
|
+
import { useState, useEffect } from 'react';
|
|
5
5
|
import Cropper from 'react-easy-crop';
|
|
6
6
|
import clsx from 'clsx';
|
|
7
7
|
import styles from './ImageCropper.module.scss.mjs';
|
|
@@ -10,6 +10,7 @@ import { getCroppedImageFile } from './lib/getCroppedImageFile.mjs';
|
|
|
10
10
|
import { useLocalizedStringFormatter } from '../TranslationProvider/useLocalizedStringFormatter.mjs';
|
|
11
11
|
import locales from '../../../../../_virtual/_.locale.json@849e6f494125ee27df10a461562fa893.mjs';
|
|
12
12
|
import { useImageSrc } from '../../lib/hooks/useImageSrc.mjs';
|
|
13
|
+
import { useDebouncedCallback } from 'use-debounce';
|
|
13
14
|
|
|
14
15
|
const ImageCropper = (props) => {
|
|
15
16
|
const {
|
|
@@ -22,25 +23,31 @@ const ImageCropper = (props) => {
|
|
|
22
23
|
...rest
|
|
23
24
|
} = props;
|
|
24
25
|
const imageSrc = useImageSrc(image);
|
|
26
|
+
const [mediaLoaded, setMediaLoaded] = useState(false);
|
|
25
27
|
const [crop, setCrop] = useState({ x: 0, y: 0 });
|
|
26
28
|
const [zoom, setZoom] = useState(1);
|
|
27
|
-
const [croppedAreaPixels, setCroppedAreaPixels] = useState();
|
|
28
|
-
const rootClassName = clsx(styles.imageCropper, className);
|
|
29
29
|
const stringFormatter = useLocalizedStringFormatter(locales, "ImageCropper");
|
|
30
|
-
const
|
|
31
|
-
|
|
30
|
+
const rootClassName = clsx(styles.imageCropper, className);
|
|
31
|
+
const debouncedCropComplete = useDebouncedCallback(
|
|
32
|
+
async (croppedAreaPixels) => {
|
|
33
|
+
if (!croppedAreaPixels) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
32
36
|
const croppedImageFile = await getCroppedImageFile(
|
|
33
37
|
imageSrc,
|
|
38
|
+
image ?? "",
|
|
34
39
|
croppedAreaPixels
|
|
35
40
|
);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
onCropComplete?.(croppedImageFile);
|
|
42
|
+
},
|
|
43
|
+
500,
|
|
44
|
+
{
|
|
45
|
+
leading: true
|
|
39
46
|
}
|
|
40
|
-
|
|
47
|
+
);
|
|
41
48
|
useEffect(() => {
|
|
42
|
-
|
|
43
|
-
}, [
|
|
49
|
+
setMediaLoaded(false);
|
|
50
|
+
}, [imageSrc]);
|
|
44
51
|
return /* @__PURE__ */ jsxs("div", { className: rootClassName, style: { width }, children: [
|
|
45
52
|
/* @__PURE__ */ jsx("div", { className: styles.cropperContainer, style: { height }, children: /* @__PURE__ */ jsx(
|
|
46
53
|
Cropper,
|
|
@@ -56,7 +63,12 @@ const ImageCropper = (props) => {
|
|
|
56
63
|
onCropChange: setCrop,
|
|
57
64
|
zoom,
|
|
58
65
|
onZoomChange: setZoom,
|
|
59
|
-
|
|
66
|
+
onMediaLoaded: () => setMediaLoaded(true),
|
|
67
|
+
onCropComplete: (_, croppedAreaPixels) => {
|
|
68
|
+
if (mediaLoaded) {
|
|
69
|
+
debouncedCropComplete(croppedAreaPixels);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
60
72
|
...rest
|
|
61
73
|
}
|
|
62
74
|
) }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageCropper.mjs","sources":["../../../../../../../src/components/ImageCropper/ImageCropper.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"ImageCropper.mjs","sources":["../../../../../../../src/components/ImageCropper/ImageCropper.tsx"],"sourcesContent":["import { type CSSProperties, type FC, useEffect, useState } from \"react\";\nimport Cropper, { type Area, type CropperProps } from \"react-easy-crop\";\nimport type { PropsWithClassName } from \"@/lib/types/props\";\nimport clsx from \"clsx\";\nimport styles from \"./ImageCropper.module.scss\";\nimport { Slider } from \"@/components/Slider\";\nimport { getCroppedImageFile } from \"@/components/ImageCropper/lib/getCroppedImageFile\";\nimport { useLocalizedStringFormatter } from \"@/components/TranslationProvider/useLocalizedStringFormatter\";\nimport locales from \"./locales/*.locale.json\";\nimport { useImageSrc } from \"@/lib/hooks/useImageSrc\";\nimport { useDebouncedCallback } from \"use-debounce\";\n\nexport interface ImageCropperProps\n extends PropsWithClassName, Partial<Pick<CropperProps, \"cropShape\">> {\n /** The image file to crop. */\n image?: File | string;\n /** Callback on crop complete. */\n onCropComplete?: (croppedImage: File) => void;\n /** The width of the component. @default 300 */\n width?: CSSProperties[\"width\"];\n /** The height of the component. @default 300 */\n height?: CSSProperties[\"height\"];\n /** The aspect ratio of the crop shape. */\n aspectRatio?: number;\n}\n\n/** @flr-generate all */\nexport const ImageCropper: FC<ImageCropperProps> = (props) => {\n const {\n image,\n className,\n onCropComplete,\n width = 300,\n height = 300,\n aspectRatio,\n ...rest\n } = props;\n\n const imageSrc = useImageSrc(image);\n\n const [mediaLoaded, setMediaLoaded] = useState(false);\n const [crop, setCrop] = useState({ x: 0, y: 0 });\n const [zoom, setZoom] = useState(1);\n\n const stringFormatter = useLocalizedStringFormatter(locales, \"ImageCropper\");\n const rootClassName = clsx(styles.imageCropper, className);\n\n const debouncedCropComplete = useDebouncedCallback(\n async (croppedAreaPixels: Area) => {\n if (!croppedAreaPixels) {\n return;\n }\n\n const croppedImageFile = await getCroppedImageFile(\n imageSrc,\n image ?? \"\",\n croppedAreaPixels,\n );\n\n onCropComplete?.(croppedImageFile);\n },\n 500,\n {\n leading: true,\n },\n );\n\n useEffect(() => {\n setMediaLoaded(false);\n }, [imageSrc]);\n\n return (\n <div className={rootClassName} style={{ width }}>\n <div className={styles.cropperContainer} style={{ height }}>\n <Cropper\n style={{\n containerStyle: {\n borderRadius: \"calc(var(--image-cropper--corner-radius) - 1px)\",\n },\n }}\n aspect={aspectRatio}\n crop={crop}\n image={imageSrc}\n onCropChange={setCrop}\n zoom={zoom}\n onZoomChange={setZoom}\n onMediaLoaded={() => setMediaLoaded(true)}\n onCropComplete={(_, croppedAreaPixels) => {\n if (mediaLoaded) {\n debouncedCropComplete(croppedAreaPixels);\n }\n }}\n {...rest}\n />\n </div>\n <Slider\n minValue={1}\n maxValue={3}\n step={0.01}\n value={zoom}\n sliderOnly\n onChange={(zoom) => setZoom(zoom as number)}\n aria-label={stringFormatter.format(\"zoom\")}\n />\n </div>\n );\n};\n\nexport default ImageCropper;\n"],"names":["zoom"],"mappings":";;;;;;;;;;;;AA2BO,MAAM,YAAA,GAAsC,CAAC,KAAA,KAAU;AAC5D,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,SAAA;AAAA,IACA,cAAA;AAAA,IACA,KAAA,GAAQ,GAAA;AAAA,IACR,MAAA,GAAS,GAAA;AAAA,IACT,WAAA;AAAA,IACA,GAAG;AAAA,GACL,GAAI,KAAA;AAEJ,EAAA,MAAM,QAAA,GAAW,YAAY,KAAK,CAAA;AAElC,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,KAAK,CAAA;AACpD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,QAAA,CAAS,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA;AAC/C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,CAAC,CAAA;AAElC,EAAA,MAAM,eAAA,GAAkB,2BAAA,CAA4B,OAAA,EAAS,cAAc,CAAA;AAC3E,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,MAAA,CAAO,YAAA,EAAc,SAAS,CAAA;AAEzD,EAAA,MAAM,qBAAA,GAAwB,oBAAA;AAAA,IAC5B,OAAO,iBAAA,KAA4B;AACjC,MAAA,IAAI,CAAC,iBAAA,EAAmB;AACtB,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,mBAAmB,MAAM,mBAAA;AAAA,QAC7B,QAAA;AAAA,QACA,KAAA,IAAS,EAAA;AAAA,QACT;AAAA,OACF;AAEA,MAAA,cAAA,GAAiB,gBAAgB,CAAA;AAAA,IACnC,CAAA;AAAA,IACA,GAAA;AAAA,IACA;AAAA,MACE,OAAA,EAAS;AAAA;AACX,GACF;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,cAAA,CAAe,KAAK,CAAA;AAAA,EACtB,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,4BACG,KAAA,EAAA,EAAI,SAAA,EAAW,eAAe,KAAA,EAAO,EAAE,OAAM,EAC5C,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,SAAI,SAAA,EAAW,MAAA,CAAO,kBAAkB,KAAA,EAAO,EAAE,QAAO,EACvD,QAAA,kBAAA,GAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO;AAAA,UACL,cAAA,EAAgB;AAAA,YACd,YAAA,EAAc;AAAA;AAChB,SACF;AAAA,QACA,MAAA,EAAQ,WAAA;AAAA,QACR,IAAA;AAAA,QACA,KAAA,EAAO,QAAA;AAAA,QACP,YAAA,EAAc,OAAA;AAAA,QACd,IAAA;AAAA,QACA,YAAA,EAAc,OAAA;AAAA,QACd,aAAA,EAAe,MAAM,cAAA,CAAe,IAAI,CAAA;AAAA,QACxC,cAAA,EAAgB,CAAC,CAAA,EAAG,iBAAA,KAAsB;AACxC,UAAA,IAAI,WAAA,EAAa;AACf,YAAA,qBAAA,CAAsB,iBAAiB,CAAA;AAAA,UACzC;AAAA,QACF,CAAA;AAAA,QACC,GAAG;AAAA;AAAA,KACN,EACF,CAAA;AAAA,oBACA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,QAAA,EAAU,CAAA;AAAA,QACV,QAAA,EAAU,CAAA;AAAA,QACV,IAAA,EAAM,IAAA;AAAA,QACN,KAAA,EAAO,IAAA;AAAA,QACP,UAAA,EAAU,IAAA;AAAA,QACV,QAAA,EAAU,CAACA,KAAAA,KAAS,OAAA,CAAQA,KAAc,CAAA;AAAA,QAC1C,YAAA,EAAY,eAAA,CAAgB,MAAA,CAAO,MAAM;AAAA;AAAA;AAC3C,GAAA,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
/* */
|
|
3
|
-
|
|
3
|
+
import { addAwaitedArrayBuffer } from '../../../../../core/src/file.mjs';
|
|
4
|
+
|
|
5
|
+
function getCroppedImageFile(imageSrc, sourceImage, pixelCrop) {
|
|
4
6
|
return new Promise((resolve, reject) => {
|
|
5
7
|
const image = new Image();
|
|
6
8
|
image.crossOrigin = "anonymous";
|
|
7
9
|
image.src = imageSrc;
|
|
8
10
|
image.onload = () => {
|
|
9
11
|
const canvas = document.createElement("canvas");
|
|
12
|
+
const ctx = canvas.getContext("2d");
|
|
10
13
|
canvas.width = pixelCrop.width;
|
|
11
14
|
canvas.height = pixelCrop.height;
|
|
12
|
-
const ctx = canvas.getContext("2d");
|
|
13
15
|
if (!ctx) {
|
|
14
16
|
reject(new Error("Failed to get canvas context"));
|
|
15
17
|
return;
|
|
@@ -25,18 +27,24 @@ function getCroppedImageFile(imageSrc, pixelCrop) {
|
|
|
25
27
|
pixelCrop.width,
|
|
26
28
|
pixelCrop.height
|
|
27
29
|
);
|
|
30
|
+
const isSourceImageJsFile = sourceImage instanceof File;
|
|
31
|
+
const sourceImageName = isSourceImageJsFile ? sourceImage.name : "cropped-image.png";
|
|
32
|
+
const sourceImageType = isSourceImageJsFile ? sourceImage.type : "image/png";
|
|
33
|
+
const quality = sourceImageType === "image/jpeg" ? 0.86 : sourceImageType === "image/webp" ? 0.82 : void 0;
|
|
28
34
|
canvas.toBlob(
|
|
29
35
|
(blob) => {
|
|
30
36
|
if (!blob) {
|
|
31
37
|
return;
|
|
32
38
|
}
|
|
33
|
-
const file = new File([blob],
|
|
34
|
-
type:
|
|
39
|
+
const file = new File([blob], sourceImageName, {
|
|
40
|
+
type: sourceImageType
|
|
41
|
+
});
|
|
42
|
+
addAwaitedArrayBuffer(file).then((fileWithArrayBuffer) => {
|
|
43
|
+
resolve(fileWithArrayBuffer);
|
|
35
44
|
});
|
|
36
|
-
resolve(file);
|
|
37
45
|
},
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
sourceImageType,
|
|
47
|
+
quality
|
|
40
48
|
);
|
|
41
49
|
};
|
|
42
50
|
image.onerror = () => {
|
package/dist/js/packages/components/src/components/ImageCropper/lib/getCroppedImageFile.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getCroppedImageFile.mjs","sources":["../../../../../../../../src/components/ImageCropper/lib/getCroppedImageFile.ts"],"sourcesContent":["import type { Area } from \"react-easy-crop\";\n\nexport function getCroppedImageFile(\n imageSrc: string,\n pixelCrop: Area,\n): Promise<File> {\n return new Promise((resolve, reject) => {\n const image = new Image();\n image.crossOrigin = \"anonymous\";\n image.src = imageSrc;\n\n image.onload = () => {\n const canvas = document.createElement(\"canvas\");\n canvas.width = pixelCrop.width;\n canvas.height = pixelCrop.height;\n
|
|
1
|
+
{"version":3,"file":"getCroppedImageFile.mjs","sources":["../../../../../../../../src/components/ImageCropper/lib/getCroppedImageFile.ts"],"sourcesContent":["import type { Area } from \"react-easy-crop\";\nimport { addAwaitedArrayBuffer } from \"@mittwald/flow-core\";\n\nexport function getCroppedImageFile(\n imageSrc: string,\n sourceImage: File | string,\n pixelCrop: Area,\n): Promise<File> {\n return new Promise((resolve, reject) => {\n const image = new Image();\n image.crossOrigin = \"anonymous\";\n image.src = imageSrc;\n\n image.onload = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n\n canvas.width = pixelCrop.width;\n canvas.height = pixelCrop.height;\n\n if (!ctx) {\n reject(new Error(\"Failed to get canvas context\"));\n return;\n }\n\n ctx.drawImage(\n image,\n pixelCrop.x,\n pixelCrop.y,\n pixelCrop.width,\n pixelCrop.height,\n 0,\n 0,\n pixelCrop.width,\n pixelCrop.height,\n );\n\n const isSourceImageJsFile = sourceImage instanceof File;\n const sourceImageName = isSourceImageJsFile\n ? sourceImage.name\n : \"cropped-image.png\";\n const sourceImageType = isSourceImageJsFile\n ? sourceImage.type\n : \"image/png\";\n\n const quality =\n sourceImageType === \"image/jpeg\"\n ? 0.86\n : sourceImageType === \"image/webp\"\n ? 0.82\n : undefined;\n\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n return;\n }\n\n const file = new File([blob], sourceImageName, {\n type: sourceImageType,\n });\n addAwaitedArrayBuffer(file).then((fileWithArrayBuffer) => {\n resolve(fileWithArrayBuffer);\n });\n },\n sourceImageType,\n quality,\n );\n };\n\n image.onerror = () => {\n reject(new Error(\"Failed to load image\"));\n };\n });\n}\n"],"names":[],"mappings":";;AAGO,SAAS,mBAAA,CACd,QAAA,EACA,WAAA,EACA,SAAA,EACe;AACf,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,EAAM;AACxB,IAAA,KAAA,CAAM,WAAA,GAAc,WAAA;AACpB,IAAA,KAAA,CAAM,GAAA,GAAM,QAAA;AAEZ,IAAA,KAAA,CAAM,SAAS,MAAM;AACnB,MAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,MAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAElC,MAAA,MAAA,CAAO,QAAQ,SAAA,CAAU,KAAA;AACzB,MAAA,MAAA,CAAO,SAAS,SAAA,CAAU,MAAA;AAE1B,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,8BAA8B,CAAC,CAAA;AAChD,QAAA;AAAA,MACF;AAEA,MAAA,GAAA,CAAI,SAAA;AAAA,QACF,KAAA;AAAA,QACA,SAAA,CAAU,CAAA;AAAA,QACV,SAAA,CAAU,CAAA;AAAA,QACV,SAAA,CAAU,KAAA;AAAA,QACV,SAAA,CAAU,MAAA;AAAA,QACV,CAAA;AAAA,QACA,CAAA;AAAA,QACA,SAAA,CAAU,KAAA;AAAA,QACV,SAAA,CAAU;AAAA,OACZ;AAEA,MAAA,MAAM,sBAAsB,WAAA,YAAuB,IAAA;AACnD,MAAA,MAAM,eAAA,GAAkB,mBAAA,GACpB,WAAA,CAAY,IAAA,GACZ,mBAAA;AACJ,MAAA,MAAM,eAAA,GAAkB,mBAAA,GACpB,WAAA,CAAY,IAAA,GACZ,WAAA;AAEJ,MAAA,MAAM,UACJ,eAAA,KAAoB,YAAA,GAChB,IAAA,GACA,eAAA,KAAoB,eAClB,IAAA,GACA,MAAA;AAER,MAAA,MAAA,CAAO,MAAA;AAAA,QACL,CAAC,IAAA,KAAS;AACR,UAAA,IAAI,CAAC,IAAA,EAAM;AACT,YAAA;AAAA,UACF;AAEA,UAAA,MAAM,OAAO,IAAI,IAAA,CAAK,CAAC,IAAI,GAAG,eAAA,EAAiB;AAAA,YAC7C,IAAA,EAAM;AAAA,WACP,CAAA;AACD,UAAA,qBAAA,CAAsB,IAAI,CAAA,CAAE,IAAA,CAAK,CAAC,mBAAA,KAAwB;AACxD,YAAA,OAAA,CAAQ,mBAAmB,CAAA;AAAA,UAC7B,CAAC,CAAA;AAAA,QACH,CAAA;AAAA,QACA,eAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF,CAAA;AAEA,IAAA,KAAA,CAAM,UAAU,MAAM;AACpB,MAAA,MAAA,CAAO,IAAI,KAAA,CAAM,sBAAsB,CAAC,CAAA;AAAA,IAC1C,CAAA;AAAA,EACF,CAAC,CAAA;AACH;;;;"}
|
|
@@ -12,7 +12,13 @@ import { flowComponent } from '../../../../lib/componentFactory/flowComponent.mj
|
|
|
12
12
|
import { LinkListTunnelExit } from '../LinkListTunnelExit/LinkListTunnelExit.mjs';
|
|
13
13
|
|
|
14
14
|
const NavigationGroup = flowComponent("NavigationGroup", (props) => {
|
|
15
|
-
const {
|
|
15
|
+
const {
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
collapsable,
|
|
19
|
+
"aria-label": ariaLabel,
|
|
20
|
+
...rest
|
|
21
|
+
} = props;
|
|
16
22
|
const rootClassName = clsx(
|
|
17
23
|
styles.navigationGroup,
|
|
18
24
|
collapsable && styles.collapsable,
|
|
@@ -21,7 +27,7 @@ const NavigationGroup = flowComponent("NavigationGroup", (props) => {
|
|
|
21
27
|
const generatedId = useId();
|
|
22
28
|
const propsContext = {
|
|
23
29
|
Label: {
|
|
24
|
-
id: generatedId,
|
|
30
|
+
id: ariaLabel ? void 0 : generatedId,
|
|
25
31
|
className: styles.label
|
|
26
32
|
},
|
|
27
33
|
Link: {
|
|
@@ -35,10 +41,19 @@ const NavigationGroup = flowComponent("NavigationGroup", (props) => {
|
|
|
35
41
|
children,
|
|
36
42
|
/* @__PURE__ */ jsx(Content, { children: /* @__PURE__ */ jsx(LinkListTunnelExit, { id: "groupLinks", component: "NavigationGroup" }) })
|
|
37
43
|
] });
|
|
38
|
-
const defaultUi = /* @__PURE__ */ jsxs(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
const defaultUi = /* @__PURE__ */ jsxs(
|
|
45
|
+
"section",
|
|
46
|
+
{
|
|
47
|
+
"aria-labelledby": ariaLabel ? void 0 : generatedId,
|
|
48
|
+
"aria-label": ariaLabel,
|
|
49
|
+
className: rootClassName,
|
|
50
|
+
...rest,
|
|
51
|
+
children: [
|
|
52
|
+
children,
|
|
53
|
+
/* @__PURE__ */ jsx(LinkListTunnelExit, { id: "groupLinks", component: "NavigationGroup" })
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
);
|
|
42
57
|
return /* @__PURE__ */ jsx(PropsContextProvider, { props: propsContext, dependencies: [generatedId], children: collapsable ? collapsableUi : defaultUi });
|
|
43
58
|
});
|
|
44
59
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NavigationGroup.mjs","sources":["../../../../../../../../../src/components/Navigation/components/NavigationGroup/NavigationGroup.tsx"],"sourcesContent":["import { type ComponentProps, type PropsWithChildren } from \"react\";\nimport { useId } from \"react\";\nimport clsx from \"clsx\";\nimport styles from \"./NavigationGroup.module.scss\";\nimport { type PropsContext, PropsContextProvider } from \"@/lib/propsContext\";\nimport { Accordion } from \"@/components/Accordion\";\nimport { Content } from \"@/components/Content\";\nimport {\n flowComponent,\n type FlowComponentProps,\n} from \"@/lib/componentFactory/flowComponent\";\nimport { LinkListTunnelExit } from \"@/components/Navigation/components/LinkListTunnelExit/LinkListTunnelExit\";\n\nexport interface NavigationGroupProps\n extends\n PropsWithChildren<ComponentProps<\"section\">>,\n FlowComponentProps<HTMLElement> {\n collapsable?: boolean;\n}\n\n/** @flr-generate all */\nexport const NavigationGroup = flowComponent(\"NavigationGroup\", (props) => {\n const {
|
|
1
|
+
{"version":3,"file":"NavigationGroup.mjs","sources":["../../../../../../../../../src/components/Navigation/components/NavigationGroup/NavigationGroup.tsx"],"sourcesContent":["import { type ComponentProps, type PropsWithChildren } from \"react\";\nimport { useId } from \"react\";\nimport clsx from \"clsx\";\nimport styles from \"./NavigationGroup.module.scss\";\nimport { type PropsContext, PropsContextProvider } from \"@/lib/propsContext\";\nimport { Accordion } from \"@/components/Accordion\";\nimport { Content } from \"@/components/Content\";\nimport {\n flowComponent,\n type FlowComponentProps,\n} from \"@/lib/componentFactory/flowComponent\";\nimport { LinkListTunnelExit } from \"@/components/Navigation/components/LinkListTunnelExit/LinkListTunnelExit\";\n\nexport interface NavigationGroupProps\n extends\n PropsWithChildren<ComponentProps<\"section\">>,\n FlowComponentProps<HTMLElement> {\n collapsable?: boolean;\n}\n\n/** @flr-generate all */\nexport const NavigationGroup = flowComponent(\"NavigationGroup\", (props) => {\n const {\n children,\n className,\n collapsable,\n \"aria-label\": ariaLabel,\n ...rest\n } = props;\n\n const rootClassName = clsx(\n styles.navigationGroup,\n collapsable && styles.collapsable,\n className,\n );\n\n const generatedId = useId();\n\n const propsContext: PropsContext = {\n Label: {\n id: ariaLabel ? undefined : generatedId,\n className: styles.label,\n },\n Link: {\n tunnel: {\n id: \"groupLinks\",\n component: \"NavigationGroup\",\n },\n },\n };\n\n const collapsableUi = (\n <Accordion defaultExpanded className={rootClassName}>\n {children}\n <Content>\n <LinkListTunnelExit id=\"groupLinks\" component=\"NavigationGroup\" />\n </Content>\n </Accordion>\n );\n\n const defaultUi = (\n <section\n aria-labelledby={ariaLabel ? undefined : generatedId}\n aria-label={ariaLabel}\n className={rootClassName}\n {...rest}\n >\n {children}\n <LinkListTunnelExit id=\"groupLinks\" component=\"NavigationGroup\" />\n </section>\n );\n\n return (\n <PropsContextProvider props={propsContext} dependencies={[generatedId]}>\n {collapsable ? collapsableUi : defaultUi}\n </PropsContextProvider>\n );\n});\n\nexport default NavigationGroup;\n"],"names":[],"mappings":";;;;;;;;;;;AAqBO,MAAM,eAAA,GAAkB,aAAA,CAAc,iBAAA,EAAmB,CAAC,KAAA,KAAU;AACzE,EAAA,MAAM;AAAA,IACJ,QAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA,EAAc,SAAA;AAAA,IACd,GAAG;AAAA,GACL,GAAI,KAAA;AAEJ,EAAA,MAAM,aAAA,GAAgB,IAAA;AAAA,IACpB,MAAA,CAAO,eAAA;AAAA,IACP,eAAe,MAAA,CAAO,WAAA;AAAA,IACtB;AAAA,GACF;AAEA,EAAA,MAAM,cAAc,KAAA,EAAM;AAE1B,EAAA,MAAM,YAAA,GAA6B;AAAA,IACjC,KAAA,EAAO;AAAA,MACL,EAAA,EAAI,YAAY,MAAA,GAAY,WAAA;AAAA,MAC5B,WAAW,MAAA,CAAO;AAAA,KACpB;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,MAAA,EAAQ;AAAA,QACN,EAAA,EAAI,YAAA;AAAA,QACJ,SAAA,EAAW;AAAA;AACb;AACF,GACF;AAEA,EAAA,MAAM,gCACJ,IAAA,CAAC,SAAA,EAAA,EAAU,eAAA,EAAe,IAAA,EAAC,WAAW,aAAA,EACnC,QAAA,EAAA;AAAA,IAAA,QAAA;AAAA,oBACD,GAAA,CAAC,WACC,QAAA,kBAAA,GAAA,CAAC,kBAAA,EAAA,EAAmB,IAAG,YAAA,EAAa,SAAA,EAAU,mBAAkB,CAAA,EAClE;AAAA,GAAA,EACF,CAAA;AAGF,EAAA,MAAM,SAAA,mBACJ,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,iBAAA,EAAiB,YAAY,MAAA,GAAY,WAAA;AAAA,MACzC,YAAA,EAAY,SAAA;AAAA,MACZ,SAAA,EAAW,aAAA;AAAA,MACV,GAAG,IAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,QAAA;AAAA,wBACD,GAAA,CAAC,kBAAA,EAAA,EAAmB,EAAA,EAAG,YAAA,EAAa,WAAU,iBAAA,EAAkB;AAAA;AAAA;AAAA,GAClE;AAGF,EAAA,uBACE,GAAA,CAAC,oBAAA,EAAA,EAAqB,KAAA,EAAO,YAAA,EAAc,YAAA,EAAc,CAAC,WAAW,CAAA,EAClE,QAAA,EAAA,WAAA,GAAc,aAAA,GAAgB,SAAA,EACjC,CAAA;AAEJ,CAAC;;;;"}
|
|
@@ -1,28 +1,18 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
/* */
|
|
3
|
-
import { useState,
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
4
|
|
|
5
5
|
const useImageSrc = (image) => {
|
|
6
|
-
const [
|
|
7
|
-
const onImageChange = useEffectEvent(() => {
|
|
8
|
-
if (image) {
|
|
9
|
-
if (typeof image === "string") {
|
|
10
|
-
setImageSrc(image);
|
|
11
|
-
} else {
|
|
12
|
-
const reader = new FileReader();
|
|
13
|
-
reader.onload = () => {
|
|
14
|
-
if (typeof reader.result === "string") {
|
|
15
|
-
setImageSrc(reader.result);
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
reader.readAsDataURL(image);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
});
|
|
6
|
+
const [src, setSrc] = useState(typeof image === "string" ? image : "");
|
|
22
7
|
useEffect(() => {
|
|
23
|
-
|
|
8
|
+
if (!image || typeof image === "string") {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const url = URL.createObjectURL(image);
|
|
12
|
+
setSrc(url);
|
|
13
|
+
return () => URL.revokeObjectURL(url);
|
|
24
14
|
}, [image]);
|
|
25
|
-
return
|
|
15
|
+
return src;
|
|
26
16
|
};
|
|
27
17
|
|
|
28
18
|
export { useImageSrc };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useImageSrc.mjs","sources":["../../../../../../../src/lib/hooks/useImageSrc.tsx"],"sourcesContent":["import { useEffect,
|
|
1
|
+
{"version":3,"file":"useImageSrc.mjs","sources":["../../../../../../../src/lib/hooks/useImageSrc.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport const useImageSrc = (image?: string | File) => {\n const [src, setSrc] = useState(typeof image === \"string\" ? image : \"\");\n\n useEffect(() => {\n if (!image || typeof image === \"string\") {\n return;\n }\n\n const url = URL.createObjectURL(image);\n setSrc(url);\n\n return () => URL.revokeObjectURL(url);\n }, [image]);\n\n return src;\n};\n"],"names":[],"mappings":";;AAEO,MAAM,WAAA,GAAc,CAAC,KAAA,KAA0B;AACpD,EAAA,MAAM,CAAC,KAAK,MAAM,CAAA,GAAI,SAAS,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,EAAE,CAAA;AAErE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACvC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,eAAA,CAAgB,KAAK,CAAA;AACrC,IAAA,MAAA,CAAO,GAAG,CAAA;AAEV,IAAA,OAAO,MAAM,GAAA,CAAI,eAAA,CAAgB,GAAG,CAAA;AAAA,EACtC,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,OAAO,GAAA;AACT;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageCropper.d.ts","sourceRoot":"","sources":["../../../../src/components/ImageCropper/ImageCropper.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ImageCropper.d.ts","sourceRoot":"","sources":["../../../../src/components/ImageCropper/ImageCropper.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,EAAE,EAAuB,MAAM,OAAO,CAAC;AACzE,OAAgB,EAAa,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAU5D,MAAM,WAAW,iBACf,SAAQ,kBAAkB,EAAE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACpE,8BAA8B;IAC9B,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACtB,iCAAiC;IACjC,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9C,+CAA+C;IAC/C,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,gDAAgD;IAChD,MAAM,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IACjC,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAwB;AACxB,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CA+E9C,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Area } from 'react-easy-crop';
|
|
2
|
-
export declare function getCroppedImageFile(imageSrc: string, pixelCrop: Area): Promise<File>;
|
|
2
|
+
export declare function getCroppedImageFile(imageSrc: string, sourceImage: File | string, pixelCrop: Area): Promise<File>;
|
|
3
3
|
//# sourceMappingURL=getCroppedImageFile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getCroppedImageFile.d.ts","sourceRoot":"","sources":["../../../../../src/components/ImageCropper/lib/getCroppedImageFile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"getCroppedImageFile.d.ts","sourceRoot":"","sources":["../../../../../src/components/ImageCropper/lib/getCroppedImageFile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAG5C,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,IAAI,GAAG,MAAM,EAC1B,SAAS,EAAE,IAAI,GACd,OAAO,CAAC,IAAI,CAAC,CAmEf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Default.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/ImageCropper/stories/Default.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"Default.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/ImageCropper/stories/Default.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AASzD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,YAAY,CA+BnC,CAAC;AACF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,YAAY,CAAC,CAAC;AAE3C,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC;AAEjC,eAAO,MAAM,YAAY,EAAE,KAmD1B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAoCtB,CAAC"}
|
package/dist/types/components/Navigation/components/NavigationGroup/NavigationGroup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NavigationGroup.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Navigation/components/NavigationGroup/NavigationGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAOpE,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,sCAAsC,CAAC;AAG9C,MAAM,WAAW,oBACf,SACE,iBAAiB,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,EAC5C,kBAAkB,CAAC,WAAW,CAAC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAwB;AACxB,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"NavigationGroup.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Navigation/components/NavigationGroup/NavigationGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAOpE,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,sCAAsC,CAAC;AAG9C,MAAM,WAAW,oBACf,SACE,iBAAiB,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,EAC5C,kBAAkB,CAAC,WAAW,CAAC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAwB;AACxB,eAAO,MAAM,eAAe,sGAwD1B,CAAC;AAEH,eAAe,eAAe,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useImageSrc.d.ts","sourceRoot":"","sources":["../../../../src/lib/hooks/useImageSrc.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"useImageSrc.d.ts","sourceRoot":"","sources":["../../../../src/lib/hooks/useImageSrc.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,GAAG,IAAI,WAehD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mittwald/flow-react-components",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.874",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A React implementation of Flow, mittwald’s design system",
|
|
6
6
|
"homepage": "https://mittwald.github.io/flow",
|
|
@@ -63,9 +63,9 @@
|
|
|
63
63
|
"@internationalized/string": "^3.2.9",
|
|
64
64
|
"@internationalized/string-compiler": "^3.4.1",
|
|
65
65
|
"@lezer/highlight": "^1.2.3",
|
|
66
|
-
"@mittwald/flow-icons": "0.2.0-alpha.
|
|
66
|
+
"@mittwald/flow-icons": "0.2.0-alpha.874",
|
|
67
67
|
"@mittwald/password-tools-js": "3.0.0-alpha.30",
|
|
68
|
-
"@mittwald/react-tunnel": "0.2.0-alpha.
|
|
68
|
+
"@mittwald/react-tunnel": "0.2.0-alpha.874",
|
|
69
69
|
"@mittwald/react-use-promise": "^4.2.2",
|
|
70
70
|
"@react-aria/form": "^3.2.1",
|
|
71
71
|
"@react-aria/i18n": "^3.13.1",
|
|
@@ -110,6 +110,7 @@
|
|
|
110
110
|
"remeda": "^2.39.0",
|
|
111
111
|
"type-fest": "^5.7.0",
|
|
112
112
|
"use-callback-ref": "^1.3.3",
|
|
113
|
+
"use-debounce": "^10.1.1",
|
|
113
114
|
"usehooks-ts": "^3.1.1",
|
|
114
115
|
"zod": "^4.4.3"
|
|
115
116
|
},
|
|
@@ -119,7 +120,7 @@
|
|
|
119
120
|
"@lezer/generator": "^1.8.0",
|
|
120
121
|
"@lezer/lr": "^1.4.10",
|
|
121
122
|
"@mittwald/flow-core": "",
|
|
122
|
-
"@mittwald/flow-design-tokens": "0.2.0-alpha.
|
|
123
|
+
"@mittwald/flow-design-tokens": "0.2.0-alpha.874",
|
|
123
124
|
"@mittwald/flow-icons-base": "",
|
|
124
125
|
"@mittwald/react-use-promise": "^4.2.2",
|
|
125
126
|
"@mittwald/remote-dom-react": "1.2.2-mittwald.10",
|
|
@@ -174,7 +175,7 @@
|
|
|
174
175
|
},
|
|
175
176
|
"peerDependencies": {
|
|
176
177
|
"@internationalized/date": "^3.12.2",
|
|
177
|
-
"@mittwald/flow-icons-pro": "0.2.0-alpha.
|
|
178
|
+
"@mittwald/flow-icons-pro": "0.2.0-alpha.873",
|
|
178
179
|
"@mittwald/react-use-promise": "^4.2.2",
|
|
179
180
|
"next": "^16.2.3",
|
|
180
181
|
"react": "^19.2.0",
|
|
@@ -195,5 +196,5 @@
|
|
|
195
196
|
"optional": true
|
|
196
197
|
}
|
|
197
198
|
},
|
|
198
|
-
"gitHead": "
|
|
199
|
+
"gitHead": "8d4b04c6cd6641cbacfd647aae90abeac04a85ef"
|
|
199
200
|
}
|