formanitor 0.1.5 → 0.1.7

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.d.cts CHANGED
@@ -770,7 +770,10 @@ interface StoreConfig {
770
770
  prefillData?: Record<string, any>;
771
771
  role?: string;
772
772
  onEvent?: EventListener;
773
+ /** Handler for image, media, and signature uploads; fallback for file upload when `onFileUpload` is omitted. */
773
774
  onUpload?: UploadHandler;
775
+ /** Optional handler for `file_upload` fields only (`FormFileUploadWidget`). Uses `onUpload` when not set. */
776
+ onFileUpload?: UploadHandler;
774
777
  onDraftChange?: DraftChangeHandler;
775
778
  /**
776
779
  * Auth / OTP configuration. Lets the host app supply the API base URL and
@@ -872,6 +875,8 @@ declare class FormStore {
872
875
  */
873
876
  updateConfig(next: Partial<StoreConfig>): void;
874
877
  getUploadHandler(): UploadHandler | undefined;
878
+ /** Resolved handler for `file_upload` widgets: `onFileUpload` ?? `onUpload`. */
879
+ getFileUploadHandler(): UploadHandler | undefined;
875
880
  private preSubmitHandlers;
876
881
  registerPreSubmitHandler(fieldId: string, fn: () => Promise<void>): void;
877
882
  unregisterPreSubmitHandler(fieldId: string): void;
@@ -1194,12 +1199,14 @@ interface PresignedUploadResponse {
1194
1199
  upload_method: 'PUT' | 'POST';
1195
1200
  }
1196
1201
  interface CreateUploadHandlerOptions {
1202
+ /** Data server origin (no trailing slash), e.g. `https://dataserver.example.com`. */
1197
1203
  apiBaseUrl: string;
1198
1204
  headers?: Record<string, string>;
1199
1205
  }
1200
1206
  /**
1201
- * Creates an upload handler function that can be passed to FormProvider
1202
- * This handles the complete upload flow: get presigned URL -> upload to S3 -> return S3 key
1207
+ * Presigned upload handler: `POST …/api/forms/media-upload/` then PUT/POST file
1208
+ * to `presigned_url`. Use as `config.onUpload` on `FormProvider`; `file_upload`
1209
+ * fields use the same handler unless you set `config.onFileUpload`.
1203
1210
  */
1204
1211
  declare function createUploadHandler(options: CreateUploadHandlerOptions): (file: File | Blob, filename: string) => Promise<string>;
1205
1212
 
package/dist/index.d.ts CHANGED
@@ -770,7 +770,10 @@ interface StoreConfig {
770
770
  prefillData?: Record<string, any>;
771
771
  role?: string;
772
772
  onEvent?: EventListener;
773
+ /** Handler for image, media, and signature uploads; fallback for file upload when `onFileUpload` is omitted. */
773
774
  onUpload?: UploadHandler;
775
+ /** Optional handler for `file_upload` fields only (`FormFileUploadWidget`). Uses `onUpload` when not set. */
776
+ onFileUpload?: UploadHandler;
774
777
  onDraftChange?: DraftChangeHandler;
775
778
  /**
776
779
  * Auth / OTP configuration. Lets the host app supply the API base URL and
@@ -872,6 +875,8 @@ declare class FormStore {
872
875
  */
873
876
  updateConfig(next: Partial<StoreConfig>): void;
874
877
  getUploadHandler(): UploadHandler | undefined;
878
+ /** Resolved handler for `file_upload` widgets: `onFileUpload` ?? `onUpload`. */
879
+ getFileUploadHandler(): UploadHandler | undefined;
875
880
  private preSubmitHandlers;
876
881
  registerPreSubmitHandler(fieldId: string, fn: () => Promise<void>): void;
877
882
  unregisterPreSubmitHandler(fieldId: string): void;
@@ -1194,12 +1199,14 @@ interface PresignedUploadResponse {
1194
1199
  upload_method: 'PUT' | 'POST';
1195
1200
  }
1196
1201
  interface CreateUploadHandlerOptions {
1202
+ /** Data server origin (no trailing slash), e.g. `https://dataserver.example.com`. */
1197
1203
  apiBaseUrl: string;
1198
1204
  headers?: Record<string, string>;
1199
1205
  }
1200
1206
  /**
1201
- * Creates an upload handler function that can be passed to FormProvider
1202
- * This handles the complete upload flow: get presigned URL -> upload to S3 -> return S3 key
1207
+ * Presigned upload handler: `POST …/api/forms/media-upload/` then PUT/POST file
1208
+ * to `presigned_url`. Use as `config.onUpload` on `FormProvider`; `file_upload`
1209
+ * fields use the same handler unless you set `config.onFileUpload`.
1203
1210
  */
1204
1211
  declare function createUploadHandler(options: CreateUploadHandlerOptions): (file: File | Blob, filename: string) => Promise<string>;
1205
1212
 
package/dist/index.mjs CHANGED
@@ -1710,6 +1710,8 @@ var FormStore = class {
1710
1710
  updateConfig(next) {
1711
1711
  let needsReeval = false;
1712
1712
  if (next.onUpload !== void 0) this.config.onUpload = next.onUpload;
1713
+ if (next.onFileUpload !== void 0)
1714
+ this.config.onFileUpload = next.onFileUpload;
1713
1715
  if (next.onEvent !== void 0) this.config.onEvent = next.onEvent;
1714
1716
  if (next.onDraftChange !== void 0) this.config.onDraftChange = next.onDraftChange;
1715
1717
  if (next.voice !== void 0) this.config.voice = next.voice;
@@ -1730,6 +1732,10 @@ var FormStore = class {
1730
1732
  getUploadHandler() {
1731
1733
  return this.config.onUpload;
1732
1734
  }
1735
+ /** Resolved handler for `file_upload` widgets: `onFileUpload` ?? `onUpload`. */
1736
+ getFileUploadHandler() {
1737
+ return this.config.onFileUpload ?? this.config.onUpload;
1738
+ }
1733
1739
  preSubmitHandlers = /* @__PURE__ */ new Map();
1734
1740
  registerPreSubmitHandler(fieldId, fn) {
1735
1741
  this.preSubmitHandlers.set(fieldId, fn);
@@ -4038,7 +4044,7 @@ var FormFileUploadWidget = ({
4038
4044
  const accept = def.accept ?? "*/*";
4039
4045
  const maxSize = def.maxSize ?? 10 * 1024 * 1024;
4040
4046
  const allowMultiple = def.multiple === true;
4041
- const uploadHandler = store.getUploadHandler();
4047
+ const uploadHandler = store.getFileUploadHandler();
4042
4048
  const showLabel = isLabelVisible(fieldDef);
4043
4049
  if (!uploadHandler) {
4044
4050
  return /* @__PURE__ */ jsxs("div", { className: fieldWrapperClass(fieldDef, "space-y-2"), children: [
@@ -4047,7 +4053,7 @@ var FormFileUploadWidget = ({
4047
4053
  " ",
4048
4054
  /* @__PURE__ */ jsx(FieldRequiredIndicator, { fieldDef })
4049
4055
  ] }) : null,
4050
- /* @__PURE__ */ jsx("div", { className: "border-2 border-red-300 rounded-lg p-4 bg-red-50", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-red-600", children: "Upload handler not configured. Please provide an onUpload function in FormProvider config." }) })
4056
+ /* @__PURE__ */ jsx("div", { className: "border-2 border-red-300 rounded-lg p-4 bg-red-50", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-red-600", children: "Upload handler not configured. Provide `config.onFileUpload` or `config.onUpload` on FormProvider." }) })
4051
4057
  ] });
4052
4058
  }
4053
4059
  const hasStoredValue = value !== null && value !== void 0 && value !== "" && !(Array.isArray(value) && value.length === 0);
@@ -16287,33 +16293,44 @@ var FormControls = ({
16287
16293
  };
16288
16294
 
16289
16295
  // src/utils/createUploadHandler.ts
16290
- function createUploadHandler(options) {
16296
+ function normalizeBaseUrl(apiBaseUrl) {
16297
+ return apiBaseUrl.replace(/\/+$/, "");
16298
+ }
16299
+ async function uploadViaPresignedEndpoint(options, presignPath, file, filename) {
16291
16300
  const { apiBaseUrl, headers = {} } = options;
16292
- return async (file, filename) => {
16293
- const response = await fetch(`${apiBaseUrl}/api/forms/media-upload/`, {
16294
- method: "POST",
16295
- headers: {
16296
- "Content-Type": "application/json",
16297
- ...headers
16298
- },
16299
- body: JSON.stringify({ filename })
16300
- });
16301
- if (!response.ok) {
16302
- throw new Error(`Failed to get presigned URL: ${response.statusText}`);
16303
- }
16304
- const presignedData = await response.json();
16305
- const uploadResponse = await fetch(presignedData.presigned_url, {
16306
- method: presignedData.upload_method,
16307
- headers: {
16308
- "Content-Type": presignedData.content_type
16309
- },
16310
- body: file
16311
- });
16312
- if (!uploadResponse.ok) {
16313
- throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
16314
- }
16315
- return presignedData.s3_key;
16316
- };
16301
+ const base = normalizeBaseUrl(apiBaseUrl);
16302
+ const path = presignPath.startsWith("/") ? presignPath : `/${presignPath}`;
16303
+ const response = await fetch(`${base}${path}`, {
16304
+ method: "POST",
16305
+ headers: {
16306
+ "Content-Type": "application/json",
16307
+ ...headers
16308
+ },
16309
+ body: JSON.stringify({ filename })
16310
+ });
16311
+ if (!response.ok) {
16312
+ throw new Error(`Failed to get presigned URL: ${response.statusText}`);
16313
+ }
16314
+ const presignedData = await response.json();
16315
+ const uploadResponse = await fetch(presignedData.presigned_url, {
16316
+ method: presignedData.upload_method,
16317
+ headers: {
16318
+ "Content-Type": presignedData.content_type
16319
+ },
16320
+ body: file
16321
+ });
16322
+ if (!uploadResponse.ok) {
16323
+ throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
16324
+ }
16325
+ return presignedData.s3_key;
16326
+ }
16327
+ function createUploadHandler(options) {
16328
+ return async (file, filename) => uploadViaPresignedEndpoint(
16329
+ options,
16330
+ "/api/forms/media-upload/",
16331
+ file,
16332
+ filename
16333
+ );
16317
16334
  }
16318
16335
 
16319
16336
  export { AddInvestigationField, AddMedicationField, DifferentialDiagnosis, DynamicForm, DynamicFormV2, EMAIL_REGEX, FieldRenderer, FieldRequiredIndicator, FormControls, FormFileUploadWidget, FormProvider, FormStore, ImageUploadWidget, MAR_MEDICATION_ORDERS_META_KEY, MediaUploadWidget, MultiStepForm, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlyMediaUpload, ReadOnlySignature, ReadOnlyTable, RichTextWidget, SignatureUploadWidget, SmartForm, SmartTextareaWidget, Upload3 as Upload, createUploadHandler, evaluateRules, fieldControlClass, fieldDescriptionClass, fieldErrorClass, fieldLabelClass, fieldMetaRequestsMarMedicationOrdersButton, fieldWrapperClass, isLabelVisible, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, usePackages, useSmartKeywords, validateField, validateForm };