sales-frontend-components 2.0.4 → 2.0.5

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/dist/index.cjs.js CHANGED
@@ -227,18 +227,6 @@ var _MessageEventManager = class _MessageEventManager2 {
227
227
  };
228
228
  __publicField(_MessageEventManager, "instance");
229
229
  var MessageEventManager = _MessageEventManager;
230
- function getCanvasExportFileInfo(imageUrl) {
231
- const ext = imageUrl.split(".").pop()?.split("?")[0]?.toLowerCase();
232
- switch (ext) {
233
- case "jpg":
234
- case "jpeg":
235
- return { contentType: "image/jpeg", fileExt: "jpg" };
236
- case "webp":
237
- return { contentType: "image/webp", fileExt: "webp" };
238
- default:
239
- return { contentType: "image/png", fileExt: "png" };
240
- }
241
- }
242
230
  function base64ToBlob(base64String, contentType = "") {
243
231
  const regex = /^data:([a-zA-Z0-9/+.-]+);base64,/;
244
232
  const matches = base64String.match(regex);
@@ -355,9 +343,9 @@ async function imageUrlToFileWithCanvas(imageUrl) {
355
343
  }
356
344
  try {
357
345
  ctx.drawImage(newImage, 0, 0);
358
- const { contentType, fileExt } = getCanvasExportFileInfo(imageUrl);
359
- const dataUrl = canvas.toDataURL(contentType);
360
- const blob = base64ToBlob(dataUrl, contentType);
346
+ const dataUrl = canvas.toDataURL();
347
+ const blob = base64ToBlob(dataUrl);
348
+ const fileExt = getExt(blob) ?? "png";
361
349
  resolve(blobToFile(blob, `image.${fileExt}`));
362
350
  } catch (error) {
363
351
  reject(
@@ -4565,7 +4553,7 @@ function resize(image, options = { ext: "jpeg", filesize: maxImageSize }) {
4565
4553
  });
4566
4554
  }
4567
4555
 
4568
- const genImageId = () => `camera-${Date.now()}-${Math.random()}`;
4556
+ const genImageId$1 = () => `camera-${Date.now()}-${Math.random()}`;
4569
4557
  function useCamera({
4570
4558
  onChange,
4571
4559
  resize: resizeOption = {
@@ -4593,7 +4581,7 @@ function useCamera({
4593
4581
  };
4594
4582
  const imageHandler = async (file) => {
4595
4583
  const newPhoto = {
4596
- id: genImageId(),
4584
+ id: genImageId$1(),
4597
4585
  src: URL.createObjectURL(resizeOption ? await resize(file, resizeOption) : file),
4598
4586
  name: `\uC11C\uB958\uC0AC\uC9C4_${attachedPhotos.length + 1}`
4599
4587
  };
@@ -4653,11 +4641,172 @@ function useCamera({
4653
4641
  const imageIndex = attachedPhotos.findIndex((image) => image.id === imageId);
4654
4642
  if (imageIndex > -1) {
4655
4643
  const item = attachedPhotos.splice(imageIndex, 1);
4656
- item[0] && URL.revokeObjectURL(item[0].src);
4644
+ if (item[0]) {
4645
+ URL.revokeObjectURL(item[0].src);
4646
+ }
4647
+ setAttachedPhotos([...attachedPhotos]);
4648
+ if (onDelete) {
4649
+ onDelete(imageId);
4650
+ }
4651
+ }
4652
+ };
4653
+ const deleteAllImages = () => {
4654
+ attachedPhotos.forEach((image) => {
4655
+ URL.revokeObjectURL(image.src);
4656
+ if (onDelete) {
4657
+ onDelete(image.id);
4658
+ }
4659
+ });
4660
+ setAttachedPhotos([]);
4661
+ };
4662
+ const CameraComponent = () => /* @__PURE__ */ jsxRuntime.jsx(
4663
+ Attachment,
4664
+ {
4665
+ show: !!show,
4666
+ onAddPhoto: onClick,
4667
+ onRemovePhoto: deleteImage,
4668
+ photos: attachedPhotos,
4669
+ type,
4670
+ buttonText
4671
+ }
4672
+ );
4673
+ React9.useEffect(() => {
4674
+ return () => {
4675
+ attachedPhotos.forEach((image) => {
4676
+ URL.revokeObjectURL(image.src);
4677
+ });
4678
+ };
4679
+ }, []);
4680
+ return {
4681
+ onClick,
4682
+ getImage: findImage,
4683
+ deleteImage,
4684
+ deleteAllImages,
4685
+ attachedPhotos,
4686
+ Attachment: CameraComponent,
4687
+ addImage: (data) => {
4688
+ setAttachedPhotos([
4689
+ ...attachedPhotos,
4690
+ ...data.map((item) => {
4691
+ let blobUrl = "";
4692
+ if (item.data instanceof Blob) {
4693
+ blobUrl = URL.createObjectURL(item.data);
4694
+ } else if (typeof item.data === "string") {
4695
+ blobUrl = URL.createObjectURL(base64ToBlob(item.data));
4696
+ }
4697
+ const newPhoto = {
4698
+ id: genImageId$1(),
4699
+ src: blobUrl,
4700
+ name: item.name || `\uC11C\uB958\uC0AC\uC9C4_${attachedPhotos.length + 1}`
4701
+ };
4702
+ return newPhoto;
4703
+ })
4704
+ ]);
4705
+ }
4706
+ };
4707
+ }
4708
+
4709
+ const genImageId = () => `camera-${Date.now()}-${Math.random()}`;
4710
+ function useCameraV2({
4711
+ onChange,
4712
+ resize: resizeOption = {
4713
+ processType: "mixed",
4714
+ resizeRatio: 5,
4715
+ width: 1920,
4716
+ // 300kb
4717
+ filesize: 300 * 1024,
4718
+ ext: "jpeg"
4719
+ },
4720
+ cameraOnly,
4721
+ onDelete,
4722
+ show,
4723
+ type = "multiple",
4724
+ buttonText,
4725
+ initData,
4726
+ useNativeCamera = false,
4727
+ responseFileType,
4728
+ convertType = "canvas"
4729
+ }) {
4730
+ const convertedInitData = initData?.map((data, index) => ({ ...data, id: String(index + 1) }));
4731
+ const [attachedPhotos, setAttachedPhotos] = React9.useState(convertedInitData || []);
4732
+ const findImage = async (imageId) => {
4733
+ const photo = attachedPhotos.find((image) => image.id === imageId);
4734
+ if (!photo) {
4735
+ throw new Error("[use-camera-v2] : Image not found");
4736
+ }
4737
+ const file = await imageUrlToFile(photo?.src, convertType);
4738
+ const convertedPhoto = {
4739
+ ...photo,
4740
+ src: URL.createObjectURL(resizeOption ? await resize(file, resizeOption) : file)
4741
+ };
4742
+ return convertedPhoto;
4743
+ };
4744
+ const imageHandler = async (uri) => {
4745
+ const newPhoto = {
4746
+ id: genImageId(),
4747
+ src: uri,
4748
+ name: `\uC11C\uB958\uC0AC\uC9C4_${attachedPhotos.length + 1}`
4749
+ };
4750
+ if (type === "single") {
4751
+ setAttachedPhotos([newPhoto]);
4752
+ } else {
4753
+ setAttachedPhotos([...attachedPhotos, newPhoto]);
4754
+ }
4755
+ if (onChange) {
4756
+ const file = await imageUrlToFile(uri, convertType);
4757
+ onChange(file);
4758
+ }
4759
+ };
4760
+ const onClick = () => {
4761
+ if (useNativeCamera) {
4762
+ salesFrontendBridge.Bridge.native.documentCapture({ responseFileType }).then(async ({ uri }) => {
4763
+ imageHandler(uri);
4764
+ });
4765
+ } else {
4766
+ const input = document.createElement("input");
4767
+ input.type = "file";
4768
+ input.accept = "image/*";
4769
+ if (cameraOnly) {
4770
+ input.capture = "camera";
4771
+ }
4772
+ input.addEventListener("change", async (event) => {
4773
+ const target = event.target;
4774
+ const { files } = target;
4775
+ if (files && files.length > 0) {
4776
+ const file = files[0];
4777
+ if (file) {
4778
+ await imageHandler(URL.createObjectURL(file));
4779
+ }
4780
+ }
4781
+ document.body.removeChild(input);
4782
+ });
4783
+ input.style.display = "none";
4784
+ document.body.appendChild(input);
4785
+ input.click();
4786
+ }
4787
+ };
4788
+ const deleteImage = (imageId) => {
4789
+ const imageIndex = attachedPhotos.findIndex((image) => image.id === imageId);
4790
+ if (imageIndex > -1) {
4791
+ const item = attachedPhotos.splice(imageIndex, 1);
4792
+ if (item[0]) {
4793
+ URL.revokeObjectURL(item[0].src);
4794
+ }
4657
4795
  setAttachedPhotos([...attachedPhotos]);
4658
- onDelete && onDelete(imageId);
4796
+ if (onDelete) {
4797
+ onDelete(imageId);
4798
+ }
4659
4799
  }
4660
4800
  };
4801
+ const deleteAllImages = () => {
4802
+ attachedPhotos.forEach((image) => {
4803
+ URL.revokeObjectURL(image.src);
4804
+ if (onDelete) {
4805
+ onDelete(image.id);
4806
+ }
4807
+ });
4808
+ setAttachedPhotos([]);
4809
+ };
4661
4810
  const CameraComponent = () => /* @__PURE__ */ jsxRuntime.jsx(
4662
4811
  Attachment,
4663
4812
  {
@@ -4680,6 +4829,7 @@ function useCamera({
4680
4829
  onClick,
4681
4830
  getImage: findImage,
4682
4831
  deleteImage,
4832
+ deleteAllImages,
4683
4833
  attachedPhotos,
4684
4834
  Attachment: CameraComponent,
4685
4835
  addImage: (data) => {
@@ -7140,6 +7290,7 @@ exports.testSignatureBase64Data = testSignatureBase64Data;
7140
7290
  exports.useAddressComponent = useAddressComponent;
7141
7291
  exports.useBankStockSearch = useBankStockSearch;
7142
7292
  exports.useCamera = useCamera;
7293
+ exports.useCameraV2 = useCameraV2;
7143
7294
  exports.useCanvasPaint = useCanvasPaint;
7144
7295
  exports.useCustomerSearch = useCustomerSearch;
7145
7296
  exports.useDownloader = useDownloader;
package/dist/index.d.ts CHANGED
@@ -103,83 +103,93 @@ interface StepIndicatorProps {
103
103
 
104
104
  declare const StepIndicator: ({ items, onClickItem, currentIndex, defaultValue, dotCount, isLoading }: StepIndicatorProps) => react_jsx_runtime.JSX.Element;
105
105
 
106
+ /**
107
+ * 카메라 훅이 화면에 표시하는 첨부 이미지 메타데이터입니다.
108
+ * 실제 업로드용 원본 `File` 자체가 아니라, 목록 렌더링과 삭제 처리를 위한 식별자/미리보기 정보를 담습니다.
109
+ */
106
110
  interface AttachedPhoto {
111
+ /** 첨부 이미지를 고유하게 식별하는 값입니다. 삭제, 교체, 정렬 시 기준 키로 사용합니다. */
107
112
  id: string;
113
+ /** 썸네일 또는 미리보기에 사용할 이미지 URL입니다. `blob:` URL, data URL, 원격 URL 등이 들어올 수 있습니다. */
108
114
  src: string;
115
+ /** 화면에 함께 표시할 파일명입니다. 없으면 UI에서 이름 표시를 생략할 수 있습니다. */
109
116
  name?: string;
110
117
  }
118
+ /**
119
+ * `useCamera` 훅 동작을 제어하는 옵션입니다.
120
+ * 호출부에서 첨부 UI 노출 방식, 카메라 실행 방식, 변환/리사이즈 정책을 함께 정의할 때 사용합니다.
121
+ */
111
122
  interface cameraOptions {
123
+ /**
124
+ * 화면 첫 렌더링 시 미리 보여줄 기존 첨부 이미지 목록입니다.
125
+ * `id`는 훅 내부에서 자동 생성하므로 호출부에서는 `src`, `name`만 전달하면 됩니다.
126
+ */
112
127
  initData?: Omit<AttachedPhoto, 'id'>[];
128
+ /** `Attachment` 컴포넌트를 즉시 노출할지 여부입니다. 별도 버튼으로 열고 싶다면 `false`를 사용합니다. */
113
129
  show: boolean;
130
+ /** 첨부 UI 표시 형태입니다. 단일 첨부, 다중 첨부, 선형 레이아웃 중 하나를 선택합니다. */
114
131
  type: cameraItemType;
115
- onChange: (file: File) => void;
116
- onDelete: (id: string) => void;
132
+ /** 사진이 추가된 직후 호출되는 콜백입니다. 리사이즈 전 원본 `File`을 전달받아 후속 업로드 처리에 사용합니다. */
133
+ onChange?: (file: File) => void;
134
+ /** 사용자가 기존 첨부 사진을 삭제했을 때 호출되는 콜백입니다. 전달값은 삭제된 사진의 `id`입니다. */
135
+ onDelete?: (id: string) => void;
136
+ /** 앱 환경에서 브리지 기반 네이티브 카메라/문서 캡처를 사용할지 여부입니다. */
117
137
  useNativeCamera?: boolean;
138
+ /** 웹 `input[type="file"]` 사용 시 앨범/파일 선택 없이 카메라 촬영만 허용할지 여부입니다. */
118
139
  cameraOnly: boolean;
140
+ /** 기본 첨부 버튼 문구를 덮어쓸 때 사용하는 텍스트입니다. */
119
141
  buttonText?: string;
120
- responseFileType?: 'base64' | 'scheme';
121
- convertType?: 'fetch' | 'xhr' | 'canvas';
122
- resize: {
142
+ /**
143
+ * 네이티브 캡처 결과의 응답 형식입니다.
144
+ * `scheme`은 파일/커스텀 스킴 URI를, `base64`는 Base64 문자열을 반환하도록 요청합니다.
145
+ */
146
+ responseFileType: 'base64' | 'scheme';
147
+ /**
148
+ * 이미지 URL을 `File`로 바꿀 때 사용할 변환 방식입니다.
149
+ * `fetch`, `xhr`, `canvas` 중 환경 제약과 호환성에 맞는 전략을 선택할 수 있습니다.
150
+ */
151
+ convertType: 'fetch' | 'xhr' | 'canvas';
152
+ /** 첨부 후 이미지 크기와 용량을 줄이기 위한 리사이즈 옵션입니다. */
153
+ resize?: {
154
+ /** 반복 축소 시 한 번에 줄일 비율입니다. `5`면 매 반복마다 약 5%씩 축소합니다. */
123
155
  resizeRatio?: number;
156
+ /** 어떤 기준으로 축소할지 결정합니다. 품질만, 픽셀 크기만, 또는 둘 다 조합해 처리할 수 있습니다. */
124
157
  processType?: 'quality' | 'px' | 'mixed';
158
+ /** 최종 목표 너비(px)입니다. 높이만 없는 경우 원본 비율을 유지해 자동 계산합니다. */
125
159
  width?: number;
160
+ /** 최종 목표 높이(px)입니다. 너비만 없는 경우 원본 비율을 유지해 자동 계산합니다. */
126
161
  height?: number;
162
+ /** 최종 목표 파일 크기(byte)입니다. 예: `300 * 1024`는 약 300KB입니다. */
127
163
  filesize?: number;
164
+ /** 출력 이미지 확장자입니다. 일반적으로 `jpeg` 또는 `png`를 사용합니다. */
128
165
  ext?: string;
129
166
  };
130
167
  }
131
168
  type cameraItemType = 'single' | 'multiple' | 'linear';
132
-
133
169
  interface AddImageInfo {
134
170
  data: Blob | string;
135
171
  name?: string;
136
172
  }
137
- /**
138
- * @param options Partial<cameraOptions>
139
- * initData
140
- * 화면최초 로딩시 초기값
141
- *
142
- * show
143
- * boolean
144
- * 화면진입시, Attachment 컴포넌트 노출여부, 별도의 버튼을 통해 호출할 경우 false.
145
- *
146
- * type
147
- * 'single' | 'multiple' | 'linear' Attachment 컴포넌트 타입
148
- *
149
- * onChange
150
- * (file: File) => void;
151
- *
152
- * onDelete
153
- * (id: string) => void;
154
- *
155
- * useNativeCamera
156
- * boolean
157
- * 앱환경에서, 네이티브의 카메라를 호출할경우 사용
158
- *
159
- * cameraOnly
160
- * boolean
161
- * useNativeCamera가 false인 경우에만 사용
162
- *
163
- * buttonText
164
- * string
165
- * Attachment 컴포넌트에 버튼을 표시할 경우에만 사용
166
- *
167
- * resize
168
- * 이미지가 입력된후 리사이즈를 할경우에만 사용
169
- * resize: {
170
- * width?: number;
171
- * height?: number;
172
- * filesize?: number;
173
- * ext?: string;
174
- * };
175
- *
176
- * responseFileType fetch로 이미지자원을 가져올때 ios이슈가 있어서,
177
- * scheme, base64 두가지 타입으로 설정가능하도록 변경됨
178
- */
173
+
179
174
  declare function useCamera({ onChange, resize: resizeOption, cameraOnly, onDelete, show, type, buttonText, initData, useNativeCamera, responseFileType, convertType }?: Partial<cameraOptions>): {
180
175
  onClick: () => void;
181
176
  getImage: (imageId: string) => AttachedPhoto | undefined;
182
177
  deleteImage: (imageId: string) => void;
178
+ deleteAllImages: () => void;
179
+ attachedPhotos: AttachedPhoto[];
180
+ Attachment: () => react_jsx_runtime.JSX.Element;
181
+ addImage: (data: AddImageInfo[]) => void;
182
+ };
183
+
184
+ declare function useCameraV2({ onChange, resize: resizeOption, cameraOnly, onDelete, show, type, buttonText, initData, useNativeCamera, responseFileType, convertType }: cameraOptions): {
185
+ onClick: () => void;
186
+ getImage: (imageId: string) => Promise<{
187
+ src: string;
188
+ id: string;
189
+ name?: string;
190
+ }>;
191
+ deleteImage: (imageId: string) => void;
192
+ deleteAllImages: () => void;
183
193
  attachedPhotos: AttachedPhoto[];
184
194
  Attachment: () => react_jsx_runtime.JSX.Element;
185
195
  addImage: (data: AddImageInfo[]) => void;
@@ -1007,5 +1017,5 @@ interface UseTermsReturn<T> {
1007
1017
  */
1008
1018
  declare function useTerms<T extends object>(initialValue: T): UseTermsReturn<T>;
1009
1019
 
1010
- export { AUTH_TEMPLATE_CODES, Attachment, BANK_STOCK_ICON_LIST, BANK_STOCK_SEARCH_MODAL_TABS, BankStockSearchModal, CustomerSearch, CustomerSearchModal, DeaCustomerSearchModal, DudDownload, DudUpload, EmployeeSearchModal, GtmIframe, HookFormCheckbox, HookFormCheckboxButton, HookFormDatePickerRenew, HookFormDateRangePickerRenew, HookFormSearchJobField, HookFormSegmentGroup, HookFormSelect, HookFormTextField, JobVehicleSearchModal, OrganizationSearchModal, RATING_DATA, RIV_SEARCH_PARAM_MAP, RivModalIframe, StepIndicator, TermsCancerCollectQR, TermsCancerMarketing, TermsCancerProvideQR, TermsCancerSystem, TermsCheckboxButton, TermsDesign, TermsExecution, TermsLoan, TermsMarketing, TermsMarketingCollectQR, TermsMarketingProviderQR, TermsMobileCard, TermsRadio, TermsRatingBar, TermsSignature, TermsTransfer, VERIFICATION_CODES, highlightOnSearchKeyword, resize, testSignatureBase64Data, useAddressComponent, useBankStockSearch, useCamera, useCanvasPaint, useCustomerSearch, useDownloader, useJobSearchModal, useJobVehicleSearch, useJobVehicleSearchModal, useNationalityComponent, useNxlOneModal, useRemoteIdentityVerification, useRemoteIdentityVerificationIframe, useSearchAddress, useSearchNationality, useSearchVisa, useTerms, useVisaComponent };
1020
+ export { AUTH_TEMPLATE_CODES, Attachment, BANK_STOCK_ICON_LIST, BANK_STOCK_SEARCH_MODAL_TABS, BankStockSearchModal, CustomerSearch, CustomerSearchModal, DeaCustomerSearchModal, DudDownload, DudUpload, EmployeeSearchModal, GtmIframe, HookFormCheckbox, HookFormCheckboxButton, HookFormDatePickerRenew, HookFormDateRangePickerRenew, HookFormSearchJobField, HookFormSegmentGroup, HookFormSelect, HookFormTextField, JobVehicleSearchModal, OrganizationSearchModal, RATING_DATA, RIV_SEARCH_PARAM_MAP, RivModalIframe, StepIndicator, TermsCancerCollectQR, TermsCancerMarketing, TermsCancerProvideQR, TermsCancerSystem, TermsCheckboxButton, TermsDesign, TermsExecution, TermsLoan, TermsMarketing, TermsMarketingCollectQR, TermsMarketingProviderQR, TermsMobileCard, TermsRadio, TermsRatingBar, TermsSignature, TermsTransfer, VERIFICATION_CODES, highlightOnSearchKeyword, resize, testSignatureBase64Data, useAddressComponent, useBankStockSearch, useCamera, useCameraV2, useCanvasPaint, useCustomerSearch, useDownloader, useJobSearchModal, useJobVehicleSearch, useJobVehicleSearchModal, useNationalityComponent, useNxlOneModal, useRemoteIdentityVerification, useRemoteIdentityVerificationIframe, useSearchAddress, useSearchNationality, useSearchVisa, useTerms, useVisaComponent };
1011
1021
  export type { AddImageInfo, AttachedPhoto, AttachmentProps, AuthCodeSet, AuthStep, BankStockSearchModalProps, BaseTermsProps, CustomerSearchProps, DownloadProps, DownloadTargetInfo, DownloaderProps, FormFactor, HookFormCheckboxButtonProps, HookFormCheckboxProps, HookFormDatePickerRenewProps, HookFormDateRangePickerRenewProps, HookFormSearchJobFieldProps, HookFormSegmentGroupProps, HookFormSelectProps, HookFormTextFieldProps, InitSearchParams, PaintProps, Pen, RemoteIdentityVerificationSuccess, RivModalIframeProps, RivModalIframeReturnProps, RivUrlParams, SearchInputProps, StepIndicatorProps, StepItem, TermsCancerMarketingData, TermsCancerMarketingProps, TermsCancerSystemData, TermsCancerSystemDataProps, TermsDesignData, TermsDesignProps, TermsExecutionData, TermsExecutionProps, TermsLoanData, TermsLoanDataProps, TermsMarketingData, TermsMarketingProps, TermsRadioOption, TermsRatingType, TermsSignatureData, UseRemoteIdentityVerificationProps, UseTermsReturn, Vehicle, VerificationResponse, cameraItemType, cameraOptions };
package/dist/index.esm.js CHANGED
@@ -225,18 +225,6 @@ var _MessageEventManager = class _MessageEventManager2 {
225
225
  };
226
226
  __publicField(_MessageEventManager, "instance");
227
227
  var MessageEventManager = _MessageEventManager;
228
- function getCanvasExportFileInfo(imageUrl) {
229
- const ext = imageUrl.split(".").pop()?.split("?")[0]?.toLowerCase();
230
- switch (ext) {
231
- case "jpg":
232
- case "jpeg":
233
- return { contentType: "image/jpeg", fileExt: "jpg" };
234
- case "webp":
235
- return { contentType: "image/webp", fileExt: "webp" };
236
- default:
237
- return { contentType: "image/png", fileExt: "png" };
238
- }
239
- }
240
228
  function base64ToBlob(base64String, contentType = "") {
241
229
  const regex = /^data:([a-zA-Z0-9/+.-]+);base64,/;
242
230
  const matches = base64String.match(regex);
@@ -353,9 +341,9 @@ async function imageUrlToFileWithCanvas(imageUrl) {
353
341
  }
354
342
  try {
355
343
  ctx.drawImage(newImage, 0, 0);
356
- const { contentType, fileExt } = getCanvasExportFileInfo(imageUrl);
357
- const dataUrl = canvas.toDataURL(contentType);
358
- const blob = base64ToBlob(dataUrl, contentType);
344
+ const dataUrl = canvas.toDataURL();
345
+ const blob = base64ToBlob(dataUrl);
346
+ const fileExt = getExt(blob) ?? "png";
359
347
  resolve(blobToFile(blob, `image.${fileExt}`));
360
348
  } catch (error) {
361
349
  reject(
@@ -4563,7 +4551,7 @@ function resize(image, options = { ext: "jpeg", filesize: maxImageSize }) {
4563
4551
  });
4564
4552
  }
4565
4553
 
4566
- const genImageId = () => `camera-${Date.now()}-${Math.random()}`;
4554
+ const genImageId$1 = () => `camera-${Date.now()}-${Math.random()}`;
4567
4555
  function useCamera({
4568
4556
  onChange,
4569
4557
  resize: resizeOption = {
@@ -4591,7 +4579,7 @@ function useCamera({
4591
4579
  };
4592
4580
  const imageHandler = async (file) => {
4593
4581
  const newPhoto = {
4594
- id: genImageId(),
4582
+ id: genImageId$1(),
4595
4583
  src: URL.createObjectURL(resizeOption ? await resize(file, resizeOption) : file),
4596
4584
  name: `\uC11C\uB958\uC0AC\uC9C4_${attachedPhotos.length + 1}`
4597
4585
  };
@@ -4651,11 +4639,172 @@ function useCamera({
4651
4639
  const imageIndex = attachedPhotos.findIndex((image) => image.id === imageId);
4652
4640
  if (imageIndex > -1) {
4653
4641
  const item = attachedPhotos.splice(imageIndex, 1);
4654
- item[0] && URL.revokeObjectURL(item[0].src);
4642
+ if (item[0]) {
4643
+ URL.revokeObjectURL(item[0].src);
4644
+ }
4645
+ setAttachedPhotos([...attachedPhotos]);
4646
+ if (onDelete) {
4647
+ onDelete(imageId);
4648
+ }
4649
+ }
4650
+ };
4651
+ const deleteAllImages = () => {
4652
+ attachedPhotos.forEach((image) => {
4653
+ URL.revokeObjectURL(image.src);
4654
+ if (onDelete) {
4655
+ onDelete(image.id);
4656
+ }
4657
+ });
4658
+ setAttachedPhotos([]);
4659
+ };
4660
+ const CameraComponent = () => /* @__PURE__ */ jsx(
4661
+ Attachment,
4662
+ {
4663
+ show: !!show,
4664
+ onAddPhoto: onClick,
4665
+ onRemovePhoto: deleteImage,
4666
+ photos: attachedPhotos,
4667
+ type,
4668
+ buttonText
4669
+ }
4670
+ );
4671
+ useEffect(() => {
4672
+ return () => {
4673
+ attachedPhotos.forEach((image) => {
4674
+ URL.revokeObjectURL(image.src);
4675
+ });
4676
+ };
4677
+ }, []);
4678
+ return {
4679
+ onClick,
4680
+ getImage: findImage,
4681
+ deleteImage,
4682
+ deleteAllImages,
4683
+ attachedPhotos,
4684
+ Attachment: CameraComponent,
4685
+ addImage: (data) => {
4686
+ setAttachedPhotos([
4687
+ ...attachedPhotos,
4688
+ ...data.map((item) => {
4689
+ let blobUrl = "";
4690
+ if (item.data instanceof Blob) {
4691
+ blobUrl = URL.createObjectURL(item.data);
4692
+ } else if (typeof item.data === "string") {
4693
+ blobUrl = URL.createObjectURL(base64ToBlob(item.data));
4694
+ }
4695
+ const newPhoto = {
4696
+ id: genImageId$1(),
4697
+ src: blobUrl,
4698
+ name: item.name || `\uC11C\uB958\uC0AC\uC9C4_${attachedPhotos.length + 1}`
4699
+ };
4700
+ return newPhoto;
4701
+ })
4702
+ ]);
4703
+ }
4704
+ };
4705
+ }
4706
+
4707
+ const genImageId = () => `camera-${Date.now()}-${Math.random()}`;
4708
+ function useCameraV2({
4709
+ onChange,
4710
+ resize: resizeOption = {
4711
+ processType: "mixed",
4712
+ resizeRatio: 5,
4713
+ width: 1920,
4714
+ // 300kb
4715
+ filesize: 300 * 1024,
4716
+ ext: "jpeg"
4717
+ },
4718
+ cameraOnly,
4719
+ onDelete,
4720
+ show,
4721
+ type = "multiple",
4722
+ buttonText,
4723
+ initData,
4724
+ useNativeCamera = false,
4725
+ responseFileType,
4726
+ convertType = "canvas"
4727
+ }) {
4728
+ const convertedInitData = initData?.map((data, index) => ({ ...data, id: String(index + 1) }));
4729
+ const [attachedPhotos, setAttachedPhotos] = useState(convertedInitData || []);
4730
+ const findImage = async (imageId) => {
4731
+ const photo = attachedPhotos.find((image) => image.id === imageId);
4732
+ if (!photo) {
4733
+ throw new Error("[use-camera-v2] : Image not found");
4734
+ }
4735
+ const file = await imageUrlToFile(photo?.src, convertType);
4736
+ const convertedPhoto = {
4737
+ ...photo,
4738
+ src: URL.createObjectURL(resizeOption ? await resize(file, resizeOption) : file)
4739
+ };
4740
+ return convertedPhoto;
4741
+ };
4742
+ const imageHandler = async (uri) => {
4743
+ const newPhoto = {
4744
+ id: genImageId(),
4745
+ src: uri,
4746
+ name: `\uC11C\uB958\uC0AC\uC9C4_${attachedPhotos.length + 1}`
4747
+ };
4748
+ if (type === "single") {
4749
+ setAttachedPhotos([newPhoto]);
4750
+ } else {
4751
+ setAttachedPhotos([...attachedPhotos, newPhoto]);
4752
+ }
4753
+ if (onChange) {
4754
+ const file = await imageUrlToFile(uri, convertType);
4755
+ onChange(file);
4756
+ }
4757
+ };
4758
+ const onClick = () => {
4759
+ if (useNativeCamera) {
4760
+ Bridge.native.documentCapture({ responseFileType }).then(async ({ uri }) => {
4761
+ imageHandler(uri);
4762
+ });
4763
+ } else {
4764
+ const input = document.createElement("input");
4765
+ input.type = "file";
4766
+ input.accept = "image/*";
4767
+ if (cameraOnly) {
4768
+ input.capture = "camera";
4769
+ }
4770
+ input.addEventListener("change", async (event) => {
4771
+ const target = event.target;
4772
+ const { files } = target;
4773
+ if (files && files.length > 0) {
4774
+ const file = files[0];
4775
+ if (file) {
4776
+ await imageHandler(URL.createObjectURL(file));
4777
+ }
4778
+ }
4779
+ document.body.removeChild(input);
4780
+ });
4781
+ input.style.display = "none";
4782
+ document.body.appendChild(input);
4783
+ input.click();
4784
+ }
4785
+ };
4786
+ const deleteImage = (imageId) => {
4787
+ const imageIndex = attachedPhotos.findIndex((image) => image.id === imageId);
4788
+ if (imageIndex > -1) {
4789
+ const item = attachedPhotos.splice(imageIndex, 1);
4790
+ if (item[0]) {
4791
+ URL.revokeObjectURL(item[0].src);
4792
+ }
4655
4793
  setAttachedPhotos([...attachedPhotos]);
4656
- onDelete && onDelete(imageId);
4794
+ if (onDelete) {
4795
+ onDelete(imageId);
4796
+ }
4657
4797
  }
4658
4798
  };
4799
+ const deleteAllImages = () => {
4800
+ attachedPhotos.forEach((image) => {
4801
+ URL.revokeObjectURL(image.src);
4802
+ if (onDelete) {
4803
+ onDelete(image.id);
4804
+ }
4805
+ });
4806
+ setAttachedPhotos([]);
4807
+ };
4659
4808
  const CameraComponent = () => /* @__PURE__ */ jsx(
4660
4809
  Attachment,
4661
4810
  {
@@ -4678,6 +4827,7 @@ function useCamera({
4678
4827
  onClick,
4679
4828
  getImage: findImage,
4680
4829
  deleteImage,
4830
+ deleteAllImages,
4681
4831
  attachedPhotos,
4682
4832
  Attachment: CameraComponent,
4683
4833
  addImage: (data) => {
@@ -7089,4 +7239,4 @@ function useTerms(initialValue) {
7089
7239
  };
7090
7240
  }
7091
7241
 
7092
- export { AUTH_TEMPLATE_CODES, Attachment, BANK_STOCK_ICON_LIST, BANK_STOCK_SEARCH_MODAL_TABS, BankStockSearchModal, CustomerSearch, CustomerSearchModal, DeaCustomerSearchModal, DudDownload, DudUpload, EmployeeSearchModal, GtmIframe, HookFormCheckbox, HookFormCheckboxButton, HookFormDatePickerRenew, HookFormDateRangePickerRenew, HookFormSearchJobField, HookFormSegmentGroup, HookFormSelect, HookFormTextField, JobVehicleSearchModal, OrganizationSearchModal, RATING_DATA, RIV_SEARCH_PARAM_MAP, RivModalIframe, StepIndicator, TermsCancerCollectQR, TermsCancerMarketing, TermsCancerProvideQR, TermsCancerSystem, TermsCheckboxButton, TermsDesign, TermsExecution, TermsLoan, TermsMarketing, TermsMarketingCollectQR, TermsMarketingProviderQR, TermsMobileCard, TermsRadio, TermsRatingBar, TermsSignature, TermsTransfer, VERIFICATION_CODES, highlightOnSearchKeyword, resize, testSignatureBase64Data, useAddressComponent, useBankStockSearch, useCamera, useCanvasPaint, useCustomerSearch, useDownloader, useJobSearchModal, useJobVehicleSearch, useJobVehicleSearchModal, useNationalityComponent, useNxlOneModal, useRemoteIdentityVerification, useRemoteIdentityVerificationIframe, useSearchAddress, useSearchNationality, useSearchVisa, useTerms, useVisaComponent };
7242
+ export { AUTH_TEMPLATE_CODES, Attachment, BANK_STOCK_ICON_LIST, BANK_STOCK_SEARCH_MODAL_TABS, BankStockSearchModal, CustomerSearch, CustomerSearchModal, DeaCustomerSearchModal, DudDownload, DudUpload, EmployeeSearchModal, GtmIframe, HookFormCheckbox, HookFormCheckboxButton, HookFormDatePickerRenew, HookFormDateRangePickerRenew, HookFormSearchJobField, HookFormSegmentGroup, HookFormSelect, HookFormTextField, JobVehicleSearchModal, OrganizationSearchModal, RATING_DATA, RIV_SEARCH_PARAM_MAP, RivModalIframe, StepIndicator, TermsCancerCollectQR, TermsCancerMarketing, TermsCancerProvideQR, TermsCancerSystem, TermsCheckboxButton, TermsDesign, TermsExecution, TermsLoan, TermsMarketing, TermsMarketingCollectQR, TermsMarketingProviderQR, TermsMobileCard, TermsRadio, TermsRatingBar, TermsSignature, TermsTransfer, VERIFICATION_CODES, highlightOnSearchKeyword, resize, testSignatureBase64Data, useAddressComponent, useBankStockSearch, useCamera, useCameraV2, useCanvasPaint, useCustomerSearch, useDownloader, useJobSearchModal, useJobVehicleSearch, useJobVehicleSearchModal, useNationalityComponent, useNxlOneModal, useRemoteIdentityVerification, useRemoteIdentityVerificationIframe, useSearchAddress, useSearchNationality, useSearchVisa, useTerms, useVisaComponent };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sales-frontend-components",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
@@ -45,12 +45,12 @@
45
45
  "sales-frontend-stores": "0.0.15",
46
46
  "sales-frontend-typescript-config": "0.0.2",
47
47
  "sales-frontend-assets": "0.0.27",
48
- "sales-frontend-api": "0.0.179",
49
- "sales-frontend-design-system": "0.2.3",
50
- "sales-frontend-bridge": "0.0.119",
51
- "sales-frontend-hooks": "0.0.180",
52
- "sales-frontend-solution": "0.0.59",
53
- "sales-frontend-debug": "0.0.77",
48
+ "sales-frontend-api": "0.0.180",
49
+ "sales-frontend-design-system": "0.2.4",
50
+ "sales-frontend-bridge": "0.0.120",
51
+ "sales-frontend-hooks": "0.0.181",
52
+ "sales-frontend-solution": "0.0.60",
53
+ "sales-frontend-debug": "0.0.78",
54
54
  "sales-frontend-vitest-config": "0.0.3"
55
55
  },
56
56
  "peerDependencies": {
@@ -58,19 +58,19 @@
58
58
  "react": ">=19.0.0",
59
59
  "react-dom": ">=19.0.0",
60
60
  "react-hook-form": "^7.58.1",
61
- "sales-frontend-api": "0.0.179",
61
+ "sales-frontend-api": "0.0.180",
62
62
  "sales-frontend-assets": "0.0.27",
63
63
  "sales-frontend-stores": "0.0.15",
64
- "sales-frontend-design-system": "0.2.3",
65
- "sales-frontend-bridge": "0.0.119",
66
- "sales-frontend-hooks": "0.0.180",
67
- "sales-frontend-solution": "0.0.59"
64
+ "sales-frontend-design-system": "0.2.4",
65
+ "sales-frontend-bridge": "0.0.120",
66
+ "sales-frontend-hooks": "0.0.181",
67
+ "sales-frontend-solution": "0.0.60"
68
68
  },
69
69
  "dependencies": {
70
70
  "classnames": "^2.5.1",
71
71
  "dayjs": "^1.11.13",
72
- "sales-frontend-utils": "0.0.71",
73
- "sales-frontend-debug": "0.0.77"
72
+ "sales-frontend-utils": "0.0.72",
73
+ "sales-frontend-debug": "0.0.78"
74
74
  },
75
75
  "scripts": {
76
76
  "lint": "eslint . --max-warnings 0",
@@ -1,25 +0,0 @@
1
- .container {
2
- display: flex;
3
- flex-direction: column;
4
- gap: 8px;
5
- padding: 16px;
6
- }
7
-
8
- .title {
9
- font-size: 16px;
10
- font-weight: 600;
11
- }
12
-
13
- .count {
14
- font-size: 14px;
15
- color: #666;
16
- }
17
-
18
- .button {
19
- padding: 8px 16px;
20
- color: #fff;
21
- cursor: pointer;
22
- background-color: #007bff;
23
- border: none;
24
- border-radius: 4px;
25
- }