@bitrise/bitkit-v2 0.3.399 → 0.3.400-beta.2572

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.
@@ -3,9 +3,10 @@ import IconUpload from "../../icons/IconUpload.js";
3
3
  import BitkitButton from "../BitkitButton/BitkitButton.js";
4
4
  import BitkitField from "../BitkitField/BitkitField.js";
5
5
  import ImageCropper_default, { useImageCropperContext } from "../../atoms/ImageCropper/ImageCropper.js";
6
- import { forwardRef, useEffect, useMemo } from "react";
6
+ import { forwardRef, useEffect, useId, useMemo } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { Text } from "@chakra-ui/react/text";
9
+ import { useFieldContext } from "@chakra-ui/react/field";
9
10
  import { Card } from "@chakra-ui/react/card";
10
11
  import { FileUpload, useFileUploadContext } from "@chakra-ui/react/file-upload";
11
12
  import { VStack } from "@chakra-ui/react/stack";
@@ -42,13 +43,24 @@ var downscaleBlob = (blob, maxSize) => {
42
43
  image.src = url;
43
44
  });
44
45
  };
45
- var Dropzone = () => {
46
+ var Dropzone = (props) => {
47
+ const { label } = props;
46
48
  const { disabled } = useFileUploadContext();
49
+ const field = useFieldContext();
50
+ const instructionId = useId();
47
51
  const dropzoneLabel = disabled ? "Cannot upload file" : "Drag and drop file here or click to select";
48
- return /* @__PURE__ */ jsx(FileUpload.Dropzone, { children: /* @__PURE__ */ jsxs(FileUpload.DropzoneContent, { children: [/* @__PURE__ */ jsx(IconUpload, {}), /* @__PURE__ */ jsx(Text, {
49
- as: "span",
50
- children: dropzoneLabel
51
- })] }) });
52
+ const fieldControlProps = field?.getInputProps();
53
+ return /* @__PURE__ */ jsx(FileUpload.Dropzone, {
54
+ "aria-describedby": fieldControlProps?.["aria-describedby"],
55
+ "aria-errormessage": fieldControlProps?.["aria-errormessage"],
56
+ "aria-invalid": fieldControlProps?.["aria-invalid"],
57
+ "aria-labelledby": label && field ? `${field.ids.label} ${instructionId}` : instructionId,
58
+ children: /* @__PURE__ */ jsxs(FileUpload.DropzoneContent, { children: [/* @__PURE__ */ jsx(IconUpload, {}), /* @__PURE__ */ jsx(Text, {
59
+ as: "span",
60
+ id: instructionId,
61
+ children: dropzoneLabel
62
+ })] })
63
+ });
52
64
  };
53
65
  var ImagePreviewContent = (props) => {
54
66
  const { onCropChange, maxCroppedSize } = props;
@@ -135,10 +147,10 @@ var NonImagePreview = () => {
135
147
  });
136
148
  };
137
149
  var BitkitFileInputContent = (props) => {
138
- const { variant, aspectRatio, onCropChange, maxCroppedSize } = props;
150
+ const { variant, aspectRatio, label, onCropChange, maxCroppedSize } = props;
139
151
  const acceptedFile = useFileUploadContext().acceptedFiles[0];
140
152
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
141
- !acceptedFile && /* @__PURE__ */ jsx(Dropzone, {}),
153
+ !acceptedFile && /* @__PURE__ */ jsx(Dropzone, { label }),
142
154
  acceptedFile && variant === "image" && /* @__PURE__ */ jsx(ImagePreview, {
143
155
  aspectRatio,
144
156
  onCropChange,
@@ -155,10 +167,11 @@ var BitkitFileInput = forwardRef((props, ref) => {
155
167
  onFileAccepted?.(details.files[0]);
156
168
  };
157
169
  const contentProps = {
158
- variant,
159
170
  aspectRatio,
171
+ label: props.label,
172
+ maxCroppedSize,
160
173
  onCropChange,
161
- maxCroppedSize
174
+ variant
162
175
  };
163
176
  return /* @__PURE__ */ jsx(BitkitField, {
164
177
  ref,
@@ -1 +1 @@
1
- {"version":3,"file":"BitkitFileInput.js","names":[],"sources":["../../../lib/components/BitkitFileInput/BitkitFileInput.tsx"],"sourcesContent":["import { Card } from '@chakra-ui/react/card';\nimport {\n FileUpload,\n type FileUploadFileAcceptDetails,\n type FileUploadRootProps,\n useFileUploadContext,\n} from '@chakra-ui/react/file-upload';\nimport { VStack } from '@chakra-ui/react/stack';\nimport { Text } from '@chakra-ui/react/text';\nimport { splitProps as splitFileUploadProps } from '@zag-js/file-upload';\nimport { forwardRef, useEffect, useMemo } from 'react';\n\nimport ImageCropper, { useImageCropperContext } from '../../atoms/ImageCropper/ImageCropper';\nimport { IconMinusCircle, IconUpload } from '../../icons';\nimport BitkitButton from '../BitkitButton/BitkitButton';\nimport BitkitField, { type BitkitFieldProps } from '../BitkitField/BitkitField';\n\ntype BitkitFileInputProps = Omit<BitkitFieldProps, 'children' | 'state'> &\n Omit<FileUploadRootProps, 'disabled' | 'invalid'> & {\n aspectRatio?: number;\n /**\n * Max width/height (px) of the cropped output. The Ark cropper emits at the\n * selection's natural resolution with no size cap, so a large source image\n * can produce an oversized file; set this to downscale the output to fit.\n */\n maxCroppedSize?: number;\n onCropChange?: (file: File) => void;\n onFileAccepted?: (file: File) => void;\n state?: 'error' | 'disabled';\n };\n\n// Ark's getCroppedImage() emits at the selection's natural resolution and only\n// controls format/quality (no size cap), so downscale here when a max is set —\n// this keeps a large source image from producing an oversized upload. Preserves\n// the blob's MIME type; falls back to the original blob if it can't be decoded.\nconst downscaleBlob = (blob: Blob, maxSize: number): Promise<Blob> => {\n // A non-positive or non-finite max would produce a 0×0 / NaN canvas and corrupt\n // the output, so treat it as \"no cap\" and pass the blob through untouched.\n if (!Number.isFinite(maxSize) || maxSize <= 0) {\n return Promise.resolve(blob);\n }\n\n return new Promise((resolve) => {\n const url = URL.createObjectURL(blob);\n const image = new Image();\n\n image.onload = () => {\n URL.revokeObjectURL(url);\n const largestSide = Math.max(image.naturalWidth, image.naturalHeight);\n if (largestSide <= maxSize) {\n resolve(blob);\n return;\n }\n const scale = maxSize / largestSide;\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(image.naturalWidth * scale);\n canvas.height = Math.round(image.naturalHeight * scale);\n const context = canvas.getContext('2d');\n if (!context) {\n resolve(blob);\n return;\n }\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n canvas.toBlob((result) => resolve(result ?? blob), blob.type);\n };\n\n image.onerror = () => {\n URL.revokeObjectURL(url);\n resolve(blob);\n };\n\n image.src = url;\n });\n};\n\nconst Dropzone = () => {\n const { disabled } = useFileUploadContext();\n const dropzoneLabel = disabled ? 'Cannot upload file' : 'Drag and drop file here or click to select';\n\n return (\n <FileUpload.Dropzone>\n <FileUpload.DropzoneContent>\n <IconUpload />\n <Text as=\"span\">{dropzoneLabel}</Text>\n </FileUpload.DropzoneContent>\n </FileUpload.Dropzone>\n );\n};\n\nconst ImagePreviewContent = (props: Pick<BitkitFileInputProps, 'onCropChange' | 'maxCroppedSize'>) => {\n const { onCropChange, maxCroppedSize } = props;\n\n const { acceptedFiles } = useFileUploadContext();\n const { dragging, getCroppedImage } = useImageCropperContext();\n\n const acceptedFile = acceptedFiles[0];\n const objectUrl = useMemo(() => (acceptedFile ? URL.createObjectURL(acceptedFile) : undefined), [acceptedFile]);\n\n useEffect(() => {\n return () => {\n if (objectUrl) {\n URL.revokeObjectURL(objectUrl);\n }\n };\n }, [objectUrl]);\n\n useEffect(() => {\n if (!onCropChange || dragging) {\n return;\n }\n\n if (!acceptedFile) {\n return;\n }\n\n let cancelled = false;\n // Preserve the source MIME type — the Ark cropper defaults to image/png, which\n // would mismatch a .jpg name and bloat the file.\n getCroppedImage({ type: acceptedFile.type || undefined })\n .then((result) => {\n if (!(result instanceof Blob)) {\n return result;\n }\n return maxCroppedSize ? downscaleBlob(result, maxCroppedSize) : result;\n })\n .then((result) => {\n if (!cancelled && result instanceof Blob) {\n onCropChange(new File([result], acceptedFile.name, { type: result.type }));\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [getCroppedImage, acceptedFile, onCropChange, dragging, maxCroppedSize]);\n\n return (\n <ImageCropper.Viewport>\n <ImageCropper.Image src={objectUrl} />\n <ImageCropper.Selection>\n {ImageCropper.handles.map((position) => (\n <ImageCropper.Handle key={position} position={position}>\n <div />\n </ImageCropper.Handle>\n ))}\n </ImageCropper.Selection>\n </ImageCropper.Viewport>\n );\n};\n\nconst ImagePreview = (props: Pick<BitkitFileInputProps, 'aspectRatio' | 'onCropChange' | 'maxCroppedSize'>) => {\n const { aspectRatio, onCropChange, maxCroppedSize } = props;\n\n return (\n <ImageCropper.Root aspectRatio={aspectRatio} height=\"100%\">\n <ImagePreviewContent onCropChange={onCropChange} maxCroppedSize={maxCroppedSize} />\n </ImageCropper.Root>\n );\n};\n\nconst NonImagePreview = () => {\n const fileUpload = useFileUploadContext();\n const acceptedFile = fileUpload.acceptedFiles[0];\n\n return (\n <Card.Root asChild elevation={false}>\n <Card.Body display=\"flex\" paddingBlock=\"20\" paddingInline=\"24\" alignItems=\"center\" flex=\"1\">\n <VStack gap=\"4\" alignItems=\"flex-start\" flex=\"1\" minWidth=\"0\">\n <Text textStyle=\"comp/input/label\">Selected file</Text>\n <Text whiteSpace=\"nowrap\" textOverflow=\"ellipsis\" overflow=\"hidden\" maxWidth=\"100%\">\n {acceptedFile.name}\n </Text>\n </VStack>\n <BitkitButton icon={IconMinusCircle} variant=\"secondary\" size=\"md\" onClick={fileUpload.clearFiles}>\n Remove\n </BitkitButton>\n </Card.Body>\n </Card.Root>\n );\n};\n\nconst BitkitFileInputContent = (\n props: Pick<BitkitFileInputProps, 'variant' | 'aspectRatio' | 'onCropChange' | 'maxCroppedSize'>,\n) => {\n const { variant, aspectRatio, onCropChange, maxCroppedSize } = props;\n const acceptedFile = useFileUploadContext().acceptedFiles[0];\n\n return (\n <>\n {!acceptedFile && <Dropzone />}\n {acceptedFile && variant === 'image' && (\n <ImagePreview aspectRatio={aspectRatio} onCropChange={onCropChange} maxCroppedSize={maxCroppedSize} />\n )}\n {acceptedFile && variant !== 'image' && <NonImagePreview />}\n </>\n );\n};\n\nconst BitkitFileInput = forwardRef<HTMLDivElement, BitkitFileInputProps>((props, ref) => {\n const { aspectRatio, maxCroppedSize, onCropChange, onFileAccept, onFileAccepted, state, variant, ...rest } = props;\n const [fileUploadProps, fieldProps] = splitFileUploadProps(rest as never);\n\n const handleFileAccept = (details: FileUploadFileAcceptDetails) => {\n onFileAccept?.(details);\n onFileAccepted?.(details.files[0]);\n };\n\n const contentProps = {\n variant,\n aspectRatio,\n onCropChange,\n maxCroppedSize,\n };\n\n return (\n <BitkitField ref={ref} state={state} {...fieldProps}>\n <FileUpload.Root variant={variant} onFileAccept={handleFileAccept} {...fileUploadProps}>\n <FileUpload.HiddenInput />\n <BitkitFileInputContent {...contentProps} />\n </FileUpload.Root>\n </BitkitField>\n );\n});\n\nBitkitFileInput.displayName = 'BitkitFileInput';\n\nexport default BitkitFileInput;\n"],"mappings":"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"}
1
+ {"version":3,"file":"BitkitFileInput.js","names":[],"sources":["../../../lib/components/BitkitFileInput/BitkitFileInput.tsx"],"sourcesContent":["import { Card } from '@chakra-ui/react/card';\nimport { useFieldContext } from '@chakra-ui/react/field';\nimport {\n FileUpload,\n type FileUploadFileAcceptDetails,\n type FileUploadRootProps,\n useFileUploadContext,\n} from '@chakra-ui/react/file-upload';\nimport { VStack } from '@chakra-ui/react/stack';\nimport { Text } from '@chakra-ui/react/text';\nimport { splitProps as splitFileUploadProps } from '@zag-js/file-upload';\nimport { forwardRef, useEffect, useId, useMemo } from 'react';\n\nimport ImageCropper, { useImageCropperContext } from '../../atoms/ImageCropper/ImageCropper';\nimport { IconMinusCircle, IconUpload } from '../../icons';\nimport BitkitButton from '../BitkitButton/BitkitButton';\nimport BitkitField, { type BitkitFieldProps } from '../BitkitField/BitkitField';\n\ntype BitkitFileInputProps = Omit<BitkitFieldProps, 'children' | 'state'> &\n Omit<FileUploadRootProps, 'disabled' | 'invalid'> & {\n aspectRatio?: number;\n /**\n * Max width/height (px) of the cropped output. The Ark cropper emits at the\n * selection's natural resolution with no size cap, so a large source image\n * can produce an oversized file; set this to downscale the output to fit.\n */\n maxCroppedSize?: number;\n onCropChange?: (file: File) => void;\n onFileAccepted?: (file: File) => void;\n state?: 'error' | 'disabled';\n };\n\n// Ark's getCroppedImage() emits at the selection's natural resolution and only\n// controls format/quality (no size cap), so downscale here when a max is set —\n// this keeps a large source image from producing an oversized upload. Preserves\n// the blob's MIME type; falls back to the original blob if it can't be decoded.\nconst downscaleBlob = (blob: Blob, maxSize: number): Promise<Blob> => {\n // A non-positive or non-finite max would produce a 0×0 / NaN canvas and corrupt\n // the output, so treat it as \"no cap\" and pass the blob through untouched.\n if (!Number.isFinite(maxSize) || maxSize <= 0) {\n return Promise.resolve(blob);\n }\n\n return new Promise((resolve) => {\n const url = URL.createObjectURL(blob);\n const image = new Image();\n\n image.onload = () => {\n URL.revokeObjectURL(url);\n const largestSide = Math.max(image.naturalWidth, image.naturalHeight);\n if (largestSide <= maxSize) {\n resolve(blob);\n return;\n }\n const scale = maxSize / largestSide;\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(image.naturalWidth * scale);\n canvas.height = Math.round(image.naturalHeight * scale);\n const context = canvas.getContext('2d');\n if (!context) {\n resolve(blob);\n return;\n }\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n canvas.toBlob((result) => resolve(result ?? blob), blob.type);\n };\n\n image.onerror = () => {\n URL.revokeObjectURL(url);\n resolve(blob);\n };\n\n image.src = url;\n });\n};\n\nconst Dropzone = (props: Pick<BitkitFileInputProps, 'label'>) => {\n const { label } = props;\n const { disabled } = useFileUploadContext();\n const field = useFieldContext();\n const instructionId = useId();\n const dropzoneLabel = disabled ? 'Cannot upload file' : 'Drag and drop file here or click to select';\n const fieldControlProps = field?.getInputProps();\n\n return (\n <FileUpload.Dropzone\n aria-describedby={fieldControlProps?.['aria-describedby']}\n aria-errormessage={fieldControlProps?.['aria-errormessage']}\n aria-invalid={fieldControlProps?.['aria-invalid']}\n aria-labelledby={label && field ? `${field.ids.label} ${instructionId}` : instructionId}\n >\n <FileUpload.DropzoneContent>\n <IconUpload />\n <Text as=\"span\" id={instructionId}>\n {dropzoneLabel}\n </Text>\n </FileUpload.DropzoneContent>\n </FileUpload.Dropzone>\n );\n};\n\nconst ImagePreviewContent = (props: Pick<BitkitFileInputProps, 'onCropChange' | 'maxCroppedSize'>) => {\n const { onCropChange, maxCroppedSize } = props;\n\n const { acceptedFiles } = useFileUploadContext();\n const { dragging, getCroppedImage } = useImageCropperContext();\n\n const acceptedFile = acceptedFiles[0];\n const objectUrl = useMemo(() => (acceptedFile ? URL.createObjectURL(acceptedFile) : undefined), [acceptedFile]);\n\n useEffect(() => {\n return () => {\n if (objectUrl) {\n URL.revokeObjectURL(objectUrl);\n }\n };\n }, [objectUrl]);\n\n useEffect(() => {\n if (!onCropChange || dragging) {\n return;\n }\n\n if (!acceptedFile) {\n return;\n }\n\n let cancelled = false;\n // Preserve the source MIME type — the Ark cropper defaults to image/png, which\n // would mismatch a .jpg name and bloat the file.\n getCroppedImage({ type: acceptedFile.type || undefined })\n .then((result) => {\n if (!(result instanceof Blob)) {\n return result;\n }\n return maxCroppedSize ? downscaleBlob(result, maxCroppedSize) : result;\n })\n .then((result) => {\n if (!cancelled && result instanceof Blob) {\n onCropChange(new File([result], acceptedFile.name, { type: result.type }));\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [getCroppedImage, acceptedFile, onCropChange, dragging, maxCroppedSize]);\n\n return (\n <ImageCropper.Viewport>\n <ImageCropper.Image src={objectUrl} />\n <ImageCropper.Selection>\n {ImageCropper.handles.map((position) => (\n <ImageCropper.Handle key={position} position={position}>\n <div />\n </ImageCropper.Handle>\n ))}\n </ImageCropper.Selection>\n </ImageCropper.Viewport>\n );\n};\n\nconst ImagePreview = (props: Pick<BitkitFileInputProps, 'aspectRatio' | 'onCropChange' | 'maxCroppedSize'>) => {\n const { aspectRatio, onCropChange, maxCroppedSize } = props;\n\n return (\n <ImageCropper.Root aspectRatio={aspectRatio} height=\"100%\">\n <ImagePreviewContent onCropChange={onCropChange} maxCroppedSize={maxCroppedSize} />\n </ImageCropper.Root>\n );\n};\n\nconst NonImagePreview = () => {\n const fileUpload = useFileUploadContext();\n const acceptedFile = fileUpload.acceptedFiles[0];\n\n return (\n <Card.Root asChild elevation={false}>\n <Card.Body display=\"flex\" paddingBlock=\"20\" paddingInline=\"24\" alignItems=\"center\" flex=\"1\">\n <VStack gap=\"4\" alignItems=\"flex-start\" flex=\"1\" minWidth=\"0\">\n <Text textStyle=\"comp/input/label\">Selected file</Text>\n <Text whiteSpace=\"nowrap\" textOverflow=\"ellipsis\" overflow=\"hidden\" maxWidth=\"100%\">\n {acceptedFile.name}\n </Text>\n </VStack>\n <BitkitButton icon={IconMinusCircle} variant=\"secondary\" size=\"md\" onClick={fileUpload.clearFiles}>\n Remove\n </BitkitButton>\n </Card.Body>\n </Card.Root>\n );\n};\n\nconst BitkitFileInputContent = (\n props: Pick<BitkitFileInputProps, 'variant' | 'aspectRatio' | 'label' | 'onCropChange' | 'maxCroppedSize'>,\n) => {\n const { variant, aspectRatio, label, onCropChange, maxCroppedSize } = props;\n const acceptedFile = useFileUploadContext().acceptedFiles[0];\n\n return (\n <>\n {!acceptedFile && <Dropzone label={label} />}\n {acceptedFile && variant === 'image' && (\n <ImagePreview aspectRatio={aspectRatio} onCropChange={onCropChange} maxCroppedSize={maxCroppedSize} />\n )}\n {acceptedFile && variant !== 'image' && <NonImagePreview />}\n </>\n );\n};\n\nconst BitkitFileInput = forwardRef<HTMLDivElement, BitkitFileInputProps>((props, ref) => {\n const { aspectRatio, maxCroppedSize, onCropChange, onFileAccept, onFileAccepted, state, variant, ...rest } = props;\n const [fileUploadProps, fieldProps] = splitFileUploadProps(rest as never);\n\n const handleFileAccept = (details: FileUploadFileAcceptDetails) => {\n onFileAccept?.(details);\n onFileAccepted?.(details.files[0]);\n };\n\n const contentProps = {\n aspectRatio,\n label: props.label,\n maxCroppedSize,\n onCropChange,\n variant,\n };\n\n return (\n <BitkitField ref={ref} state={state} {...fieldProps}>\n <FileUpload.Root variant={variant} onFileAccept={handleFileAccept} {...fileUploadProps}>\n <FileUpload.HiddenInput />\n <BitkitFileInputContent {...contentProps} />\n </FileUpload.Root>\n </BitkitField>\n );\n});\n\nBitkitFileInput.displayName = 'BitkitFileInput';\n\nexport default BitkitFileInput;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bitrise/bitkit-v2",
3
3
  "private": false,
4
- "version": "0.3.399",
4
+ "version": "0.3.400-beta.2572",
5
5
  "description": "Bitrise Design System Components built with Chakra UI V3",
6
6
  "keywords": [
7
7
  "react",