@morscherlab/mint-sdk 1.0.24 → 1.0.26
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/BaseButton-Dgqrze41.js +74 -0
- package/dist/BaseButton-Dgqrze41.js.map +1 -0
- package/dist/{ExperimentPopover-gdSA9ZCF.js → ExperimentPopover-DEzCbTqo.js} +2 -1
- package/dist/{ExperimentPopover-B29fIHQz.js → ExperimentPopover-mzmSfAUp.js} +25 -29
- package/dist/ExperimentPopover-mzmSfAUp.js.map +1 -0
- package/dist/{ExperimentSelectorModal-CX0oBzpV.js → ExperimentSelectorModal-CKV5w9IR.js} +5 -69
- package/dist/ExperimentSelectorModal-CKV5w9IR.js.map +1 -0
- package/dist/{ExperimentSelectorModal-BOzDs8TU.js → ExperimentSelectorModal-Dr99WzzZ.js} +2 -1
- package/dist/SettingsModal-Bl_9w2Y3.js +5 -0
- package/dist/{SettingsModal-BTyXD0uP.js → SettingsModal-CJgLadsN.js} +4 -4
- package/dist/{SettingsModal-BTyXD0uP.js.map → SettingsModal-CJgLadsN.js.map} +1 -1
- package/dist/{auth-D9q2GIcv.js → auth-DZAwEeis.js} +1 -1
- package/dist/{auth-D9q2GIcv.js.map → auth-DZAwEeis.js.map} +1 -1
- package/dist/components/BaseButton.vue.d.ts +2 -0
- package/dist/components/index.js +6 -5
- package/dist/{components-CzdeV1xe.js → components-BT_uVU5B.js} +14 -13
- package/dist/{components-CzdeV1xe.js.map → components-BT_uVU5B.js.map} +1 -1
- package/dist/composables/index.js +7 -7
- package/dist/{composables-Da-4XOe2.js → composables-BNP5NZte.js} +5 -5
- package/dist/{composables-Da-4XOe2.js.map → composables-BNP5NZte.js.map} +1 -1
- package/dist/{experiment-utils-D11yT3AR.js → experiment-utils-Bfa7CwPU.js} +1 -1
- package/dist/{experiment-utils-D11yT3AR.js.map → experiment-utils-Bfa7CwPU.js.map} +1 -1
- package/dist/index.js +13 -12
- package/dist/index.js.map +1 -1
- package/dist/install.js +6 -5
- package/dist/install.js.map +1 -1
- package/dist/stores/index.js +1 -1
- package/dist/styles.css +166 -381
- package/dist/templates/index.js +2 -2
- package/dist/{templates-Dnf8UNxg.js → templates-CNbPQNID.js} +2 -2
- package/dist/{templates-Dnf8UNxg.js.map → templates-CNbPQNID.js.map} +1 -1
- package/dist/{useControlSchema-Dkm-W_lg.js → useControlSchema-BZNdalmL.js} +2 -2
- package/dist/{useControlSchema-Dkm-W_lg.js.map → useControlSchema-BZNdalmL.js.map} +1 -1
- package/dist/{useDropdownState-Ben4DnjJ.js → useDropdownState-Bb-c_PeE.js} +1 -1
- package/dist/{useDropdownState-Ben4DnjJ.js.map → useDropdownState-Bb-c_PeE.js.map} +1 -1
- package/dist/{useExperimentSelector-BBaz0w51.js → useExperimentSelector-DdCy5VNv.js} +3 -3
- package/dist/{useExperimentSelector-BBaz0w51.js.map → useExperimentSelector-DdCy5VNv.js.map} +1 -1
- package/dist/{useFormBuilder-BOJ52N4M.js → useFormBuilder-DKekvXRs.js} +2 -2
- package/dist/{useFormBuilder-BOJ52N4M.js.map → useFormBuilder-DKekvXRs.js.map} +1 -1
- package/dist/{useProtocolTemplates-r2GOnnH1.js → useProtocolTemplates-COIsmhsZ.js} +6 -6
- package/dist/{useProtocolTemplates-r2GOnnH1.js.map → useProtocolTemplates-COIsmhsZ.js.map} +1 -1
- package/package.json +1 -1
- package/src/components/BaseButton.vue +2 -0
- package/src/components/ConfirmDialog.vue +19 -12
- package/src/styles/components/confirm-dialog.css +0 -124
- package/dist/ExperimentPopover-B29fIHQz.js.map +0 -1
- package/dist/ExperimentSelectorModal-CX0oBzpV.js.map +0 -1
- package/dist/SettingsModal-DXcSKk9D.js +0 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDropdownState-
|
|
1
|
+
{"version":3,"file":"useDropdownState-Bb-c_PeE.js","names":[],"sources":["../src/composables/useDropdownState.ts"],"sourcesContent":["import { ref, type Ref } from 'vue'\nimport { useEventListener } from './useEventListener'\n\nexport interface UseDropdownStateOptions {\n closeOnOutsideClick?: boolean\n closeOnEscape?: boolean\n insideRefs?: Array<Ref<HTMLElement | null>>\n onOpen?: () => void\n onClose?: () => void\n}\n\nexport interface UseDropdownStateReturn {\n isOpen: Ref<boolean>\n rootRef: Ref<HTMLElement | null>\n open: () => void\n close: () => void\n toggle: () => void\n handleClickOutside: (event: MouseEvent) => void\n handleKeydown: (event: KeyboardEvent) => void\n}\n\n/** Shared disclosure state for dropdown-style SDK components. */\nexport function useDropdownState(options: UseDropdownStateOptions = {}): UseDropdownStateReturn {\n const isOpen = ref(false)\n const rootRef = ref<HTMLElement | null>(null)\n const closeOnOutsideClick = options.closeOnOutsideClick ?? true\n const closeOnEscape = options.closeOnEscape ?? true\n\n function open(): void {\n if (isOpen.value) return\n isOpen.value = true\n options.onOpen?.()\n }\n\n function close(): void {\n if (!isOpen.value) return\n isOpen.value = false\n options.onClose?.()\n }\n\n function toggle(): void {\n if (isOpen.value) {\n close()\n } else {\n open()\n }\n }\n\n function handleClickOutside(event: MouseEvent): void {\n if (!closeOnOutsideClick || !isOpen.value || !rootRef.value) return\n const target = event.target\n if (\n target instanceof Node &&\n !rootRef.value.contains(target) &&\n !options.insideRefs?.some(ref => ref.value?.contains(target))\n ) {\n close()\n }\n }\n\n function handleKeydown(event: KeyboardEvent): void {\n if (closeOnEscape && event.key === 'Escape') {\n close()\n }\n }\n\n if (closeOnOutsideClick) {\n useEventListener(() => document, 'click', handleClickOutside)\n }\n if (closeOnEscape) {\n useEventListener(() => document, 'keydown', handleKeydown)\n }\n\n return {\n isOpen,\n rootRef,\n open,\n close,\n toggle,\n handleClickOutside,\n handleKeydown,\n }\n}\n"],"mappings":";;;;AAsBA,SAAgB,iBAAiB,UAAmC,EAAE,EAA0B;CAC9F,MAAM,SAAS,IAAI,MAAM;CACzB,MAAM,UAAU,IAAwB,KAAK;CAC7C,MAAM,sBAAsB,QAAQ,uBAAuB;CAC3D,MAAM,gBAAgB,QAAQ,iBAAiB;CAE/C,SAAS,OAAa;AACpB,MAAI,OAAO,MAAO;AAClB,SAAO,QAAQ;AACf,UAAQ,UAAU;;CAGpB,SAAS,QAAc;AACrB,MAAI,CAAC,OAAO,MAAO;AACnB,SAAO,QAAQ;AACf,UAAQ,WAAW;;CAGrB,SAAS,SAAe;AACtB,MAAI,OAAO,MACT,QAAO;MAEP,OAAM;;CAIV,SAAS,mBAAmB,OAAyB;AACnD,MAAI,CAAC,uBAAuB,CAAC,OAAO,SAAS,CAAC,QAAQ,MAAO;EAC7D,MAAM,SAAS,MAAM;AACrB,MACE,kBAAkB,QAClB,CAAC,QAAQ,MAAM,SAAS,OAAO,IAC/B,CAAC,QAAQ,YAAY,MAAK,QAAO,IAAI,OAAO,SAAS,OAAO,CAAC,CAE7D,QAAO;;CAIX,SAAS,cAAc,OAA4B;AACjD,MAAI,iBAAiB,MAAM,QAAQ,SACjC,QAAO;;AAIX,KAAI,oBACF,wBAAuB,UAAU,SAAS,mBAAmB;AAE/D,KAAI,cACF,wBAAuB,UAAU,WAAW,cAAc;AAG5D,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as useSettingsStore, t as useAuthStore } from "./auth-
|
|
2
|
-
import { o as datePresetToISO } from "./experiment-utils-
|
|
1
|
+
import { r as useSettingsStore, t as useAuthStore } from "./auth-DZAwEeis.js";
|
|
2
|
+
import { o as datePresetToISO } from "./experiment-utils-Bfa7CwPU.js";
|
|
3
3
|
import { computed, onScopeDispose, reactive, ref, watch } from "vue";
|
|
4
4
|
import axios from "axios";
|
|
5
5
|
//#region src/composables/useApi.ts
|
|
@@ -526,4 +526,4 @@ function useExperimentSelector(options = {}) {
|
|
|
526
526
|
//#endregion
|
|
527
527
|
export { useApi as i, useDebouncedWatch as n, useRequestSyncState as r, useExperimentSelector as t };
|
|
528
528
|
|
|
529
|
-
//# sourceMappingURL=useExperimentSelector-
|
|
529
|
+
//# sourceMappingURL=useExperimentSelector-DdCy5VNv.js.map
|
package/dist/{useExperimentSelector-BBaz0w51.js.map → useExperimentSelector-DdCy5VNv.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExperimentSelector-BBaz0w51.js","names":[],"sources":["../src/composables/useApi.ts","../src/composables/useRequestSyncState.ts","../src/composables/useDebouncedWatch.ts","../src/composables/useExperimentSelector.ts"],"sourcesContent":["import axios, { type AxiosInstance, type AxiosRequestConfig, type InternalAxiosRequestConfig } from 'axios'\nimport { useSettingsStore } from '../stores/settings'\nimport { useAuthStore } from '../stores/auth'\n\nlet apiClientInstance: AxiosInstance | null = null\nlet interceptorAttached = false\n\ninterface MintAxiosRequestConfig extends AxiosRequestConfig {\n _mintSkipAuth?: boolean\n}\n\ninterface MintInternalAxiosRequestConfig extends InternalAxiosRequestConfig {\n _mintSkipAuth?: boolean\n}\n\ntype MutableHeaders = Record<string, unknown> & {\n has?: (header: string) => boolean\n set?: (header: string, value: string) => void\n delete?: (header: string) => void\n}\n\nfunction joinUrlPath(baseUrl: string, path: string): string {\n if (!path) return baseUrl\n if (path.startsWith('?') || path.startsWith('#')) return `${baseUrl.replace(/\\/+$/, '')}${path}`\n const normalizedBase = baseUrl.replace(/\\/+$/, '')\n const normalizedPath = path.replace(/^\\/+/, '/')\n return `${normalizedBase}${normalizedPath.startsWith('/') ? normalizedPath : `/${normalizedPath}`}`\n}\n\nfunction getBasePath(baseUrl: string): string {\n if (!baseUrl) return '/'\n\n try {\n const origin = typeof window !== 'undefined' ? window.location.origin : 'http://localhost'\n return new URL(baseUrl, origin).pathname.replace(/\\/+$/, '') || '/'\n } catch {\n const path = baseUrl.replace(/^https?:\\/\\/[^/]+/i, '')\n return path.replace(/\\/+$/, '') || '/'\n }\n}\n\nfunction normalizeRequestUrl(baseUrl: string, url: string): string {\n if (!url || /^https?:\\/\\//.test(url)) return url\n\n const basePath = getBasePath(baseUrl)\n if (basePath === '/') return url\n\n const normalizedUrl = url.startsWith('/') ? url : `/${url}`\n if (\n normalizedUrl === basePath\n || normalizedUrl.startsWith(`${basePath}?`)\n || normalizedUrl.startsWith(`${basePath}#`)\n ) {\n return normalizedUrl.slice(basePath.length)\n }\n if (normalizedUrl.startsWith(`${basePath}/`)) {\n return normalizedUrl.slice(basePath.length) || ''\n }\n return url\n}\n\nfunction asMutableHeaders(headers: AxiosRequestConfig['headers']): MutableHeaders | null {\n return headers ? (headers as MutableHeaders) : null\n}\n\nfunction hasAuthorizationHeader(headers: AxiosRequestConfig['headers']): boolean {\n const bag = asMutableHeaders(headers)\n if (!bag) return false\n if (typeof bag.has === 'function') return bag.has('Authorization')\n return Object.keys(bag).some((key) => key.toLowerCase() === 'authorization')\n}\n\nfunction setAuthorizationHeader(headers: AxiosRequestConfig['headers'], value: string): void {\n const bag = asMutableHeaders(headers)\n if (!bag) return\n if (typeof bag.set === 'function') {\n bag.set('Authorization', value)\n return\n }\n bag.Authorization = value\n}\n\nfunction deleteAuthorizationHeader(headers: AxiosRequestConfig['headers']): void {\n const bag = asMutableHeaders(headers)\n if (!bag) return\n if (typeof bag.delete === 'function') {\n bag.delete('Authorization')\n return\n }\n for (const key of Object.keys(bag)) {\n if (key.toLowerCase() === 'authorization') delete bag[key]\n }\n}\n\nfunction getApiClient(): AxiosInstance {\n if (!apiClientInstance) {\n apiClientInstance = axios.create({\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n }\n return apiClientInstance\n}\n\nexport interface ApiClientOptions {\n baseUrl?: string\n timeout?: number\n withAuth?: boolean\n}\n\nexport interface UseApiReturn {\n client: AxiosInstance\n get: <T>(url: string, config?: AxiosRequestConfig) => Promise<T>\n post: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>\n put: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>\n patch: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>\n delete: <T>(url: string, config?: AxiosRequestConfig) => Promise<T>\n upload: <T>(url: string, file: File, fieldName?: string, additionalData?: Record<string, unknown>) => Promise<T>\n download: (url: string, filename?: string) => Promise<string>\n buildUrl: (path: string) => string\n buildWsUrl: (path: string) => string\n}\n\n/** Axios-based API client that injects the plugin base URL and JWT auth header on every request. */\nexport function useApi(options: ApiClientOptions = {}): UseApiReturn {\n const settingsStore = useSettingsStore()\n const authStore = useAuthStore()\n const apiClient = getApiClient()\n\n // Ensure auth store is initialized (reads token from localStorage)\n if (!authStore.isInitialized) {\n authStore.initialize()\n }\n\n // Attach auth interceptor only once (reads token dynamically, not from closure)\n if (!interceptorAttached) {\n apiClient.interceptors.request.use((config) => {\n const request = config as MintInternalAxiosRequestConfig\n if (request._mintSkipAuth) {\n delete request._mintSkipAuth\n deleteAuthorizationHeader(request.headers)\n return request\n }\n\n const currentAuthStore = useAuthStore()\n if (currentAuthStore.token && config.headers && !hasAuthorizationHeader(config.headers)) {\n setAuthorizationHeader(config.headers, `Bearer ${currentAuthStore.token}`)\n }\n return config\n })\n interceptorAttached = true\n }\n\n function getBaseUrl(): string {\n return options.baseUrl ?? settingsStore.getApiBaseUrl()\n }\n\n function normalizeUrl(url: string): string {\n return normalizeRequestUrl(getBaseUrl(), url)\n }\n\n // Build per-request config that applies this caller's options\n function requestConfig(config?: AxiosRequestConfig): MintAxiosRequestConfig {\n const base: MintAxiosRequestConfig = {\n baseURL: getBaseUrl(),\n timeout: options.timeout ?? settingsStore.requestTimeout,\n ...config,\n }\n // Strip auth header if explicitly disabled\n if (options.withAuth === false) {\n base._mintSkipAuth = true\n deleteAuthorizationHeader(base.headers)\n }\n return base\n }\n\n // Generic request methods\n async function get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.get<T>(normalizeUrl(url), requestConfig(config))\n return response.data\n }\n\n async function post<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.post<T>(normalizeUrl(url), data, requestConfig(config))\n return response.data\n }\n\n async function put<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.put<T>(normalizeUrl(url), data, requestConfig(config))\n return response.data\n }\n\n async function patch<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.patch<T>(normalizeUrl(url), data, requestConfig(config))\n return response.data\n }\n\n async function del<T>(url: string, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.delete<T>(normalizeUrl(url), requestConfig(config))\n return response.data\n }\n\n // File upload helper\n async function upload<T>(url: string, file: File, fieldName = 'file', additionalData?: Record<string, unknown>): Promise<T> {\n const formData = new FormData()\n formData.append(fieldName, file)\n\n if (additionalData) {\n Object.entries(additionalData).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n formData.append(key, typeof value === 'object' ? JSON.stringify(value) : String(value))\n }\n })\n }\n\n const response = await apiClient.post<T>(normalizeUrl(url), formData, requestConfig({\n // Let Axios set Content-Type with the correct multipart boundary\n headers: { 'Content-Type': undefined },\n }))\n return response.data\n }\n\n // Download helper - returns blob URL\n async function download(url: string, filename?: string): Promise<string> {\n const response = await apiClient.get(normalizeUrl(url), requestConfig({ responseType: 'blob' }))\n const blob = new Blob([response.data])\n const blobUrl = URL.createObjectURL(blob)\n\n // Optionally trigger download\n if (filename) {\n const link = document.createElement('a')\n link.href = blobUrl\n link.download = filename\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n // Revoke after a short delay to allow download to start;\n // return empty string since the URL will be invalidated\n setTimeout(() => URL.revokeObjectURL(blobUrl), 100)\n return ''\n }\n\n // Caller is responsible for revoking when no filename is provided\n return blobUrl\n }\n\n // Build full URL for external use (e.g., <a href=\"...\">)\n function buildUrl(path: string): string {\n const baseUrl = getBaseUrl()\n return joinUrlPath(baseUrl, normalizeRequestUrl(baseUrl, path))\n }\n\n // WebSocket URL builder\n function buildWsUrl(path: string): string {\n return joinUrlPath(settingsStore.getWsBaseUrl(), path)\n }\n\n return {\n client: apiClient,\n get,\n post,\n put,\n patch,\n delete: del,\n upload,\n download,\n buildUrl,\n buildWsUrl,\n }\n}\n","import { ref, type Ref } from 'vue'\n\nexport type RequestSyncSuccessKind = 'load' | 'save' | 'run'\n\nexport interface RequestSyncRunOptions {\n success?: RequestSyncSuccessKind\n errorMessage?: string\n}\n\nexport interface UseRequestSyncStateReturn {\n /** Whether a request is in progress. */\n loading: Ref<boolean>\n /** Message from the last failed request, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load operation, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save operation, or null. */\n lastSavedAt: Ref<Date | null>\n /** Timestamp of the last successful run operation, or null. */\n lastRunAt: Ref<Date | null>\n /** Clear the current error without changing loading or timestamps. */\n clearError: () => void\n /** Convert thrown values into a developer-facing error message. */\n readErrorMessage: (value: unknown, fallback?: string) => string\n /** Store and return a normalized error message. */\n setError: (value: unknown, fallback?: string) => string\n /** Mark the resource as successfully loaded. */\n markLoaded: (date?: Date) => void\n /** Mark the resource as successfully saved. */\n markSaved: (date?: Date) => void\n /** Mark the operation as successfully run. */\n markRun: (date?: Date) => void\n /** Run a request with shared loading/error handling and optional sync marking. */\n run: <T>(operation: () => Promise<T>, options?: RequestSyncRunOptions) => Promise<T>\n}\n\n/** Shared loading/error/timestamp state for generated plugin request helpers. */\nexport function useRequestSyncState(\n defaultErrorMessage = 'Request failed.',\n): UseRequestSyncStateReturn {\n const loading = ref(false)\n const error = ref<string | null>(null)\n const lastLoadedAt = ref<Date | null>(null)\n const lastSavedAt = ref<Date | null>(null)\n const lastRunAt = ref<Date | null>(null)\n\n function clearError(): void {\n error.value = null\n }\n\n function readErrorMessage(value: unknown, fallback = defaultErrorMessage): string {\n if (value instanceof Error && value.message) {\n return value.message\n }\n if (typeof value === 'string' && value.trim()) {\n return value\n }\n if (\n typeof value === 'object'\n && value !== null\n && 'message' in value\n && typeof (value as { message?: unknown }).message === 'string'\n && (value as { message: string }).message\n ) {\n return (value as { message: string }).message\n }\n return fallback\n }\n\n function setError(value: unknown, fallback?: string): string {\n const message = readErrorMessage(value, fallback)\n error.value = message\n return message\n }\n\n function markLoaded(date = new Date()): void {\n lastLoadedAt.value = date\n }\n\n function markSaved(date = new Date()): void {\n lastSavedAt.value = date\n }\n\n function markRun(date = new Date()): void {\n lastRunAt.value = date\n }\n\n async function run<T>(\n operation: () => Promise<T>,\n options: RequestSyncRunOptions = {},\n ): Promise<T> {\n loading.value = true\n clearError()\n try {\n const response = await operation()\n if (options.success === 'load') {\n markLoaded()\n } else if (options.success === 'save') {\n markSaved()\n } else if (options.success === 'run') {\n markRun()\n }\n return response\n } catch (err) {\n setError(err, options.errorMessage)\n throw err\n } finally {\n loading.value = false\n }\n }\n\n return {\n loading,\n error,\n lastLoadedAt,\n lastSavedAt,\n lastRunAt,\n clearError,\n readErrorMessage,\n setError,\n markLoaded,\n markSaved,\n markRun,\n run,\n }\n}\n","import {\n onScopeDispose,\n ref,\n watch,\n type Ref,\n type WatchOptions,\n type WatchSource,\n type WatchStopHandle,\n} from 'vue'\n\nexport type DebouncedWatchCleanup = () => void\nexport type DebouncedWatchSource<T> = WatchSource<T> | WatchSource<unknown>[] | (() => T)\nexport type DebouncedWatchCallback<T> = (\n value: T,\n oldValue: T | undefined,\n onCleanup: (cleanup: DebouncedWatchCleanup) => void,\n) => void | Promise<void>\n\nexport interface UseDebouncedWatchOptions extends WatchOptions {\n /** Debounce interval in milliseconds. */\n delay?: number\n}\n\nexport interface UseDebouncedWatchReturn {\n /** Whether a callback is currently scheduled. */\n isPending: Ref<boolean>\n /** Cancel the pending callback without stopping the watcher. */\n cancel: () => void\n /** Run the pending callback immediately, if one is scheduled. */\n flush: () => void\n /** Stop the watcher and clear pending callbacks. */\n stop: WatchStopHandle\n}\n\n/** Watch a Vue source with debounced callback execution and explicit cancel/flush controls. */\nexport function useDebouncedWatch<T>(\n source: DebouncedWatchSource<T>,\n callback: DebouncedWatchCallback<T>,\n options: UseDebouncedWatchOptions = {},\n): UseDebouncedWatchReturn {\n const { delay = 300, ...watchOptions } = options\n const isPending = ref(false)\n\n let timer: ReturnType<typeof setTimeout> | null = null\n let hasLatestValue = false\n let latestValue: T\n let latestOldValue: T | undefined\n let callbackCleanup: DebouncedWatchCleanup | null = null\n let stopped = false\n\n function clearTimer(): void {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n isPending.value = false\n }\n\n function runCallbackCleanup(): void {\n if (!callbackCleanup) return\n callbackCleanup()\n callbackCleanup = null\n }\n\n function cancel(): void {\n clearTimer()\n hasLatestValue = false\n latestOldValue = undefined\n }\n\n function flush(): void {\n if (!hasLatestValue) return\n const value = latestValue\n const oldValue = latestOldValue\n cancel()\n runCallbackCleanup()\n void callback(value, oldValue, (cleanup) => {\n callbackCleanup = cleanup\n })\n }\n\n function schedule(value: T, oldValue: T | undefined): void {\n cancel()\n hasLatestValue = true\n latestValue = value\n latestOldValue = oldValue\n isPending.value = true\n timer = setTimeout(flush, delay)\n }\n\n const stopWatch = watch(\n source as WatchSource<unknown> | WatchSource<unknown>[],\n (value, oldValue, onCleanup) => {\n schedule(value as T, oldValue as T | undefined)\n onCleanup(() => {\n cancel()\n runCallbackCleanup()\n })\n },\n watchOptions,\n )\n\n function stop(): void {\n if (stopped) return\n stopped = true\n stopWatch()\n cancel()\n runCallbackCleanup()\n }\n\n onScopeDispose(stop)\n\n return {\n isPending,\n cancel,\n flush,\n stop,\n }\n}\n","import { ref, reactive, computed, watch, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport { useDebouncedWatch } from './useDebouncedWatch'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport { datePresetToISO } from './experiment-utils'\nimport type {\n ExperimentSummary,\n ExperimentListResponse,\n ExperimentFilters,\n ExperimentTypeOption,\n ExperimentSortField,\n PlatformContext,\n SelectOption,\n} from '../types'\n\nfunction getPlatformContext(): PlatformContext | undefined {\n if (typeof window === 'undefined') return undefined\n return (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n}\n\nfunction getPlatformApiUrl(): string | undefined {\n return getPlatformContext()?.platformApiUrl\n}\n\nexport interface UseExperimentSelectorOptions {\n experimentType?: string\n allowedExperimentTypes?: string[] | null\n apiBaseUrl?: string\n limit?: number\n immediate?: boolean\n}\n\nexport interface UseExperimentSelectorReturn {\n /** Current page of fetched experiment rows. */\n experiments: Ref<ExperimentSummary[]>\n /** Total matching experiment count reported by the platform. */\n total: Ref<number>\n /** Currently selected experiment, or null. */\n selectedExperiment: Ref<ExperimentSummary | null>\n /** Mutable filters used for the next fetch. */\n filters: ExperimentFilters\n /** Whether experiment rows are currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful experiment fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Current zero-based page index. */\n page: Ref<number>\n /** Whether another page can be loaded. */\n hasMore: ComputedRef<boolean>\n // Sort\n /** Combined sort key in the form `<field>:<asc|desc>`. */\n sortKey: Ref<string>\n // Filter options\n /** Available experiment type options for filter UI. */\n experimentTypes: Ref<ExperimentTypeOption[]>\n /** Available project options for filter UI. */\n projects: Ref<SelectOption<string>[]>\n // Grouped view\n /** Fetched experiments grouped by project name. */\n groupedByProject: ComputedRef<[string, ExperimentSummary[]][]>\n // Methods\n /** Fetch the current page with the current filters. */\n fetch: () => Promise<void>\n /** Fetch and append the next page when available. */\n loadMore: () => Promise<void>\n /** Clear fetched rows and refetch page zero. */\n reset: () => void\n /** Select an experiment. */\n select: (experiment: ExperimentSummary) => void\n /** Clear selection and filters. */\n clear: () => void\n /** Fetch experiment type and project filter options. */\n fetchFilterOptions: () => Promise<void>\n}\n\n/** Fetches a paginated, filtered experiment list from the platform API for picker and selector UIs. */\nexport function useExperimentSelector(\n options: UseExperimentSelectorOptions = {},\n): UseExperimentSelectorReturn {\n const {\n limit = 100,\n immediate = false,\n experimentType,\n allowedExperimentTypes: optionAllowedExperimentTypes,\n apiBaseUrl,\n } = options\n const platformBase = apiBaseUrl ?? getPlatformApiUrl()\n const api = useApi()\n\n const experiments = ref<ExperimentSummary[]>([])\n const total = ref(0)\n const selectedExperiment = ref<ExperimentSummary | null>(null)\n const request = useRequestSyncState('Failed to fetch experiments')\n const isLoading = request.loading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n const page = ref(0)\n\n // Sort: combined key like \"created_at:desc\"\n const sortKey = ref<string>('created_at:desc')\n\n // Filter option data (fetched once, cached)\n const experimentTypes = ref<ExperimentTypeOption[]>([])\n const projects = ref<SelectOption<string>[]>([])\n let filterOptionsFetched = false\n\n const hasMore = computed(() => experiments.value.length < total.value)\n\n const filters: ExperimentFilters = reactive({\n search: undefined,\n status: undefined,\n project: undefined,\n experimentType: undefined,\n datePreset: undefined,\n })\n\n function normalizeExperimentTypes(values: string[] | null | undefined): string[] | null {\n if (values == null) return null\n return [...new Set(values.filter((value): value is string => typeof value === 'string' && value.length > 0))]\n }\n\n function currentAllowedExperimentTypes(): string[] | null {\n if (optionAllowedExperimentTypes !== undefined) {\n return normalizeExperimentTypes(optionAllowedExperimentTypes)\n }\n return normalizeExperimentTypes(getPlatformContext()?.allowedExperimentTypes)\n }\n\n function parseSortKey(): { sortBy: ExperimentSortField; sortOrder: 'asc' | 'desc' } {\n const [field, order] = sortKey.value.split(':')\n return {\n sortBy: (field || 'created_at') as ExperimentSortField,\n sortOrder: (order || 'desc') as 'asc' | 'desc',\n }\n }\n\n type ExperimentTypeScope =\n | { kind: 'all' }\n | { kind: 'blocked' }\n | { kind: 'single'; experimentType: string }\n | { kind: 'multi'; experimentTypes: string[] }\n\n function resolveExperimentTypeScope(): ExperimentTypeScope {\n const allowedTypes = currentAllowedExperimentTypes()\n const selectedType = experimentType ?? filters.experimentType ?? undefined\n\n if (selectedType) {\n if (allowedTypes && !allowedTypes.includes(selectedType)) {\n return { kind: 'blocked' }\n }\n return { kind: 'single', experimentType: selectedType }\n }\n\n if (allowedTypes) {\n if (allowedTypes.length === 0) return { kind: 'blocked' }\n if (allowedTypes.length === 1) return { kind: 'single', experimentType: allowedTypes[0] }\n return { kind: 'multi', experimentTypes: allowedTypes }\n }\n\n return { kind: 'all' }\n }\n\n function buildExperimentListUrl(typeFilter: string | undefined, skip: number, pageLimit: number): string {\n const params = new URLSearchParams()\n if (typeFilter) params.set('experiment_type', typeFilter)\n if (filters.status) params.set('status', filters.status)\n if (filters.search) params.set('search', filters.search)\n if (filters.project) params.set('project', filters.project)\n\n const { sortBy, sortOrder } = parseSortKey()\n params.set('sort_by', sortBy)\n params.set('sort_order', sortOrder)\n\n if (filters.datePreset) {\n params.set('created_after', datePresetToISO(filters.datePreset))\n }\n\n params.set('limit', String(pageLimit))\n params.set('skip', String(skip))\n\n const query = params.toString()\n const base = platformBase ?? ''\n return `${base}/experiments${query ? `?${query}` : ''}`\n }\n\n function sortExperiments(items: ExperimentSummary[]): ExperimentSummary[] {\n const { sortBy, sortOrder } = parseSortKey()\n const direction = sortOrder === 'desc' ? -1 : 1\n return [...items].sort((a, b) => {\n const aValue = a[sortBy] ?? ''\n const bValue = b[sortBy] ?? ''\n if (aValue < bValue) return -1 * direction\n if (aValue > bValue) return 1 * direction\n return 0\n })\n }\n\n async function fetchExperimentList(typeFilter: string | undefined, skip: number, pageLimit: number) {\n return await api.get<ExperimentListResponse>(buildExperimentListUrl(typeFilter, skip, pageLimit))\n }\n\n async function fetchScopedExperimentPage(): Promise<ExperimentListResponse> {\n const scope = resolveExperimentTypeScope()\n const pageSkip = page.value * limit\n\n if (scope.kind === 'blocked') {\n return { experiments: [], total: 0 }\n }\n\n if (scope.kind === 'multi') {\n const perTypeLimit = pageSkip + limit\n const responses = await Promise.all(\n scope.experimentTypes.map(type => fetchExperimentList(type, 0, perTypeLimit)),\n )\n const merged = sortExperiments(responses.flatMap(response => response.experiments))\n return {\n experiments: merged.slice(pageSkip, pageSkip + limit),\n total: responses.reduce((sum, response) => sum + response.total, 0),\n }\n }\n\n return await fetchExperimentList(\n scope.kind === 'single' ? scope.experimentType : undefined,\n pageSkip,\n limit,\n )\n }\n\n async function fetchExperiments(): Promise<void> {\n try {\n await request.run(async () => {\n const data = await fetchScopedExperimentPage()\n if (page.value === 0) {\n experiments.value = data.experiments\n } else {\n experiments.value = [...experiments.value, ...data.experiments]\n }\n total.value = data.total\n }, { success: 'load', errorMessage: 'Failed to fetch experiments' })\n } catch {\n if (page.value === 0) {\n experiments.value = []\n total.value = 0\n }\n }\n }\n\n async function fetchFilterOptions(): Promise<void> {\n if (filterOptionsFetched) return\n filterOptionsFetched = true\n\n const base = platformBase ?? ''\n const [typesRes, projectsRes] = await Promise.allSettled([\n api.get<Array<{ value: string; label: string; color?: string }>>(`${base}/experiments/experiment-types`),\n api.get<{ projects: Array<{ id: number; name: string }>; total: number }>(`${base}/projects`),\n ])\n\n if (typesRes.status === 'fulfilled' && Array.isArray(typesRes.value)) {\n const allowedTypes = currentAllowedExperimentTypes()\n const allowedSet = allowedTypes ? new Set(allowedTypes) : null\n experimentTypes.value = typesRes.value\n .filter(t => !allowedSet || allowedSet.has(t.value))\n .map(t => ({\n value: t.value,\n label: t.label,\n color: t.color,\n }))\n if (filters.experimentType && allowedSet && !allowedSet.has(filters.experimentType)) {\n filters.experimentType = undefined\n }\n }\n\n if (projectsRes.status === 'fulfilled' && projectsRes.value?.projects && Array.isArray(projectsRes.value.projects)) {\n projects.value = projectsRes.value.projects.map(p => ({\n value: p.name,\n label: p.name,\n }))\n }\n }\n\n async function loadMore(): Promise<void> {\n if (!hasMore.value || isLoading.value) return\n page.value++\n await fetchExperiments()\n }\n\n function reset(): void {\n page.value = 0\n experiments.value = []\n total.value = 0\n fetchExperiments()\n }\n\n function select(experiment: ExperimentSummary): void {\n selectedExperiment.value = experiment\n }\n\n function clear(): void {\n selectedExperiment.value = null\n filters.search = undefined\n filters.status = undefined\n filters.project = undefined\n filters.experimentType = undefined\n filters.datePreset = undefined\n sortKey.value = 'created_at:desc'\n page.value = 0\n request.clearError()\n }\n\n // Group experiments by project (client-side)\n const groupedByProject = computed<[string, ExperimentSummary[]][]>(() => {\n const groups = new Map<string, ExperimentSummary[]>()\n for (const exp of experiments.value) {\n const key = exp.project_name ?? exp.project ?? 'No project'\n const list = groups.get(key)\n if (list) {\n list.push(exp)\n } else {\n groups.set(key, [exp])\n }\n }\n // Sort alphabetically, \"No project\" last\n return [...groups.entries()].sort(([a], [b]) => {\n if (a === 'No project') return 1\n if (b === 'No project') return -1\n return a.localeCompare(b)\n })\n })\n\n const searchWatch = useDebouncedWatch(\n () => filters.search,\n () => {\n page.value = 0\n fetchExperiments()\n },\n { delay: 300 },\n )\n\n // Immediate watch on discrete filters and sort (cancel any pending search debounce)\n watch(\n () => [filters.status, filters.project, filters.experimentType, filters.datePreset, sortKey.value],\n () => {\n searchWatch.cancel()\n page.value = 0\n fetchExperiments()\n },\n )\n\n if (immediate) {\n fetchExperiments()\n }\n\n return {\n experiments,\n total,\n selectedExperiment,\n filters,\n isLoading,\n error,\n lastLoadedAt,\n page,\n hasMore,\n sortKey,\n experimentTypes,\n projects,\n groupedByProject,\n fetch: fetchExperiments,\n loadMore,\n reset,\n select,\n clear,\n fetchFilterOptions,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useExperimentSelector-DdCy5VNv.js","names":[],"sources":["../src/composables/useApi.ts","../src/composables/useRequestSyncState.ts","../src/composables/useDebouncedWatch.ts","../src/composables/useExperimentSelector.ts"],"sourcesContent":["import axios, { type AxiosInstance, type AxiosRequestConfig, type InternalAxiosRequestConfig } from 'axios'\nimport { useSettingsStore } from '../stores/settings'\nimport { useAuthStore } from '../stores/auth'\n\nlet apiClientInstance: AxiosInstance | null = null\nlet interceptorAttached = false\n\ninterface MintAxiosRequestConfig extends AxiosRequestConfig {\n _mintSkipAuth?: boolean\n}\n\ninterface MintInternalAxiosRequestConfig extends InternalAxiosRequestConfig {\n _mintSkipAuth?: boolean\n}\n\ntype MutableHeaders = Record<string, unknown> & {\n has?: (header: string) => boolean\n set?: (header: string, value: string) => void\n delete?: (header: string) => void\n}\n\nfunction joinUrlPath(baseUrl: string, path: string): string {\n if (!path) return baseUrl\n if (path.startsWith('?') || path.startsWith('#')) return `${baseUrl.replace(/\\/+$/, '')}${path}`\n const normalizedBase = baseUrl.replace(/\\/+$/, '')\n const normalizedPath = path.replace(/^\\/+/, '/')\n return `${normalizedBase}${normalizedPath.startsWith('/') ? normalizedPath : `/${normalizedPath}`}`\n}\n\nfunction getBasePath(baseUrl: string): string {\n if (!baseUrl) return '/'\n\n try {\n const origin = typeof window !== 'undefined' ? window.location.origin : 'http://localhost'\n return new URL(baseUrl, origin).pathname.replace(/\\/+$/, '') || '/'\n } catch {\n const path = baseUrl.replace(/^https?:\\/\\/[^/]+/i, '')\n return path.replace(/\\/+$/, '') || '/'\n }\n}\n\nfunction normalizeRequestUrl(baseUrl: string, url: string): string {\n if (!url || /^https?:\\/\\//.test(url)) return url\n\n const basePath = getBasePath(baseUrl)\n if (basePath === '/') return url\n\n const normalizedUrl = url.startsWith('/') ? url : `/${url}`\n if (\n normalizedUrl === basePath\n || normalizedUrl.startsWith(`${basePath}?`)\n || normalizedUrl.startsWith(`${basePath}#`)\n ) {\n return normalizedUrl.slice(basePath.length)\n }\n if (normalizedUrl.startsWith(`${basePath}/`)) {\n return normalizedUrl.slice(basePath.length) || ''\n }\n return url\n}\n\nfunction asMutableHeaders(headers: AxiosRequestConfig['headers']): MutableHeaders | null {\n return headers ? (headers as MutableHeaders) : null\n}\n\nfunction hasAuthorizationHeader(headers: AxiosRequestConfig['headers']): boolean {\n const bag = asMutableHeaders(headers)\n if (!bag) return false\n if (typeof bag.has === 'function') return bag.has('Authorization')\n return Object.keys(bag).some((key) => key.toLowerCase() === 'authorization')\n}\n\nfunction setAuthorizationHeader(headers: AxiosRequestConfig['headers'], value: string): void {\n const bag = asMutableHeaders(headers)\n if (!bag) return\n if (typeof bag.set === 'function') {\n bag.set('Authorization', value)\n return\n }\n bag.Authorization = value\n}\n\nfunction deleteAuthorizationHeader(headers: AxiosRequestConfig['headers']): void {\n const bag = asMutableHeaders(headers)\n if (!bag) return\n if (typeof bag.delete === 'function') {\n bag.delete('Authorization')\n return\n }\n for (const key of Object.keys(bag)) {\n if (key.toLowerCase() === 'authorization') delete bag[key]\n }\n}\n\nfunction getApiClient(): AxiosInstance {\n if (!apiClientInstance) {\n apiClientInstance = axios.create({\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n }\n return apiClientInstance\n}\n\nexport interface ApiClientOptions {\n baseUrl?: string\n timeout?: number\n withAuth?: boolean\n}\n\nexport interface UseApiReturn {\n client: AxiosInstance\n get: <T>(url: string, config?: AxiosRequestConfig) => Promise<T>\n post: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>\n put: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>\n patch: <T>(url: string, data?: unknown, config?: AxiosRequestConfig) => Promise<T>\n delete: <T>(url: string, config?: AxiosRequestConfig) => Promise<T>\n upload: <T>(url: string, file: File, fieldName?: string, additionalData?: Record<string, unknown>) => Promise<T>\n download: (url: string, filename?: string) => Promise<string>\n buildUrl: (path: string) => string\n buildWsUrl: (path: string) => string\n}\n\n/** Axios-based API client that injects the plugin base URL and JWT auth header on every request. */\nexport function useApi(options: ApiClientOptions = {}): UseApiReturn {\n const settingsStore = useSettingsStore()\n const authStore = useAuthStore()\n const apiClient = getApiClient()\n\n // Ensure auth store is initialized (reads token from localStorage)\n if (!authStore.isInitialized) {\n authStore.initialize()\n }\n\n // Attach auth interceptor only once (reads token dynamically, not from closure)\n if (!interceptorAttached) {\n apiClient.interceptors.request.use((config) => {\n const request = config as MintInternalAxiosRequestConfig\n if (request._mintSkipAuth) {\n delete request._mintSkipAuth\n deleteAuthorizationHeader(request.headers)\n return request\n }\n\n const currentAuthStore = useAuthStore()\n if (currentAuthStore.token && config.headers && !hasAuthorizationHeader(config.headers)) {\n setAuthorizationHeader(config.headers, `Bearer ${currentAuthStore.token}`)\n }\n return config\n })\n interceptorAttached = true\n }\n\n function getBaseUrl(): string {\n return options.baseUrl ?? settingsStore.getApiBaseUrl()\n }\n\n function normalizeUrl(url: string): string {\n return normalizeRequestUrl(getBaseUrl(), url)\n }\n\n // Build per-request config that applies this caller's options\n function requestConfig(config?: AxiosRequestConfig): MintAxiosRequestConfig {\n const base: MintAxiosRequestConfig = {\n baseURL: getBaseUrl(),\n timeout: options.timeout ?? settingsStore.requestTimeout,\n ...config,\n }\n // Strip auth header if explicitly disabled\n if (options.withAuth === false) {\n base._mintSkipAuth = true\n deleteAuthorizationHeader(base.headers)\n }\n return base\n }\n\n // Generic request methods\n async function get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.get<T>(normalizeUrl(url), requestConfig(config))\n return response.data\n }\n\n async function post<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.post<T>(normalizeUrl(url), data, requestConfig(config))\n return response.data\n }\n\n async function put<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.put<T>(normalizeUrl(url), data, requestConfig(config))\n return response.data\n }\n\n async function patch<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.patch<T>(normalizeUrl(url), data, requestConfig(config))\n return response.data\n }\n\n async function del<T>(url: string, config?: AxiosRequestConfig): Promise<T> {\n const response = await apiClient.delete<T>(normalizeUrl(url), requestConfig(config))\n return response.data\n }\n\n // File upload helper\n async function upload<T>(url: string, file: File, fieldName = 'file', additionalData?: Record<string, unknown>): Promise<T> {\n const formData = new FormData()\n formData.append(fieldName, file)\n\n if (additionalData) {\n Object.entries(additionalData).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n formData.append(key, typeof value === 'object' ? JSON.stringify(value) : String(value))\n }\n })\n }\n\n const response = await apiClient.post<T>(normalizeUrl(url), formData, requestConfig({\n // Let Axios set Content-Type with the correct multipart boundary\n headers: { 'Content-Type': undefined },\n }))\n return response.data\n }\n\n // Download helper - returns blob URL\n async function download(url: string, filename?: string): Promise<string> {\n const response = await apiClient.get(normalizeUrl(url), requestConfig({ responseType: 'blob' }))\n const blob = new Blob([response.data])\n const blobUrl = URL.createObjectURL(blob)\n\n // Optionally trigger download\n if (filename) {\n const link = document.createElement('a')\n link.href = blobUrl\n link.download = filename\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n // Revoke after a short delay to allow download to start;\n // return empty string since the URL will be invalidated\n setTimeout(() => URL.revokeObjectURL(blobUrl), 100)\n return ''\n }\n\n // Caller is responsible for revoking when no filename is provided\n return blobUrl\n }\n\n // Build full URL for external use (e.g., <a href=\"...\">)\n function buildUrl(path: string): string {\n const baseUrl = getBaseUrl()\n return joinUrlPath(baseUrl, normalizeRequestUrl(baseUrl, path))\n }\n\n // WebSocket URL builder\n function buildWsUrl(path: string): string {\n return joinUrlPath(settingsStore.getWsBaseUrl(), path)\n }\n\n return {\n client: apiClient,\n get,\n post,\n put,\n patch,\n delete: del,\n upload,\n download,\n buildUrl,\n buildWsUrl,\n }\n}\n","import { ref, type Ref } from 'vue'\n\nexport type RequestSyncSuccessKind = 'load' | 'save' | 'run'\n\nexport interface RequestSyncRunOptions {\n success?: RequestSyncSuccessKind\n errorMessage?: string\n}\n\nexport interface UseRequestSyncStateReturn {\n /** Whether a request is in progress. */\n loading: Ref<boolean>\n /** Message from the last failed request, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load operation, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save operation, or null. */\n lastSavedAt: Ref<Date | null>\n /** Timestamp of the last successful run operation, or null. */\n lastRunAt: Ref<Date | null>\n /** Clear the current error without changing loading or timestamps. */\n clearError: () => void\n /** Convert thrown values into a developer-facing error message. */\n readErrorMessage: (value: unknown, fallback?: string) => string\n /** Store and return a normalized error message. */\n setError: (value: unknown, fallback?: string) => string\n /** Mark the resource as successfully loaded. */\n markLoaded: (date?: Date) => void\n /** Mark the resource as successfully saved. */\n markSaved: (date?: Date) => void\n /** Mark the operation as successfully run. */\n markRun: (date?: Date) => void\n /** Run a request with shared loading/error handling and optional sync marking. */\n run: <T>(operation: () => Promise<T>, options?: RequestSyncRunOptions) => Promise<T>\n}\n\n/** Shared loading/error/timestamp state for generated plugin request helpers. */\nexport function useRequestSyncState(\n defaultErrorMessage = 'Request failed.',\n): UseRequestSyncStateReturn {\n const loading = ref(false)\n const error = ref<string | null>(null)\n const lastLoadedAt = ref<Date | null>(null)\n const lastSavedAt = ref<Date | null>(null)\n const lastRunAt = ref<Date | null>(null)\n\n function clearError(): void {\n error.value = null\n }\n\n function readErrorMessage(value: unknown, fallback = defaultErrorMessage): string {\n if (value instanceof Error && value.message) {\n return value.message\n }\n if (typeof value === 'string' && value.trim()) {\n return value\n }\n if (\n typeof value === 'object'\n && value !== null\n && 'message' in value\n && typeof (value as { message?: unknown }).message === 'string'\n && (value as { message: string }).message\n ) {\n return (value as { message: string }).message\n }\n return fallback\n }\n\n function setError(value: unknown, fallback?: string): string {\n const message = readErrorMessage(value, fallback)\n error.value = message\n return message\n }\n\n function markLoaded(date = new Date()): void {\n lastLoadedAt.value = date\n }\n\n function markSaved(date = new Date()): void {\n lastSavedAt.value = date\n }\n\n function markRun(date = new Date()): void {\n lastRunAt.value = date\n }\n\n async function run<T>(\n operation: () => Promise<T>,\n options: RequestSyncRunOptions = {},\n ): Promise<T> {\n loading.value = true\n clearError()\n try {\n const response = await operation()\n if (options.success === 'load') {\n markLoaded()\n } else if (options.success === 'save') {\n markSaved()\n } else if (options.success === 'run') {\n markRun()\n }\n return response\n } catch (err) {\n setError(err, options.errorMessage)\n throw err\n } finally {\n loading.value = false\n }\n }\n\n return {\n loading,\n error,\n lastLoadedAt,\n lastSavedAt,\n lastRunAt,\n clearError,\n readErrorMessage,\n setError,\n markLoaded,\n markSaved,\n markRun,\n run,\n }\n}\n","import {\n onScopeDispose,\n ref,\n watch,\n type Ref,\n type WatchOptions,\n type WatchSource,\n type WatchStopHandle,\n} from 'vue'\n\nexport type DebouncedWatchCleanup = () => void\nexport type DebouncedWatchSource<T> = WatchSource<T> | WatchSource<unknown>[] | (() => T)\nexport type DebouncedWatchCallback<T> = (\n value: T,\n oldValue: T | undefined,\n onCleanup: (cleanup: DebouncedWatchCleanup) => void,\n) => void | Promise<void>\n\nexport interface UseDebouncedWatchOptions extends WatchOptions {\n /** Debounce interval in milliseconds. */\n delay?: number\n}\n\nexport interface UseDebouncedWatchReturn {\n /** Whether a callback is currently scheduled. */\n isPending: Ref<boolean>\n /** Cancel the pending callback without stopping the watcher. */\n cancel: () => void\n /** Run the pending callback immediately, if one is scheduled. */\n flush: () => void\n /** Stop the watcher and clear pending callbacks. */\n stop: WatchStopHandle\n}\n\n/** Watch a Vue source with debounced callback execution and explicit cancel/flush controls. */\nexport function useDebouncedWatch<T>(\n source: DebouncedWatchSource<T>,\n callback: DebouncedWatchCallback<T>,\n options: UseDebouncedWatchOptions = {},\n): UseDebouncedWatchReturn {\n const { delay = 300, ...watchOptions } = options\n const isPending = ref(false)\n\n let timer: ReturnType<typeof setTimeout> | null = null\n let hasLatestValue = false\n let latestValue: T\n let latestOldValue: T | undefined\n let callbackCleanup: DebouncedWatchCleanup | null = null\n let stopped = false\n\n function clearTimer(): void {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n isPending.value = false\n }\n\n function runCallbackCleanup(): void {\n if (!callbackCleanup) return\n callbackCleanup()\n callbackCleanup = null\n }\n\n function cancel(): void {\n clearTimer()\n hasLatestValue = false\n latestOldValue = undefined\n }\n\n function flush(): void {\n if (!hasLatestValue) return\n const value = latestValue\n const oldValue = latestOldValue\n cancel()\n runCallbackCleanup()\n void callback(value, oldValue, (cleanup) => {\n callbackCleanup = cleanup\n })\n }\n\n function schedule(value: T, oldValue: T | undefined): void {\n cancel()\n hasLatestValue = true\n latestValue = value\n latestOldValue = oldValue\n isPending.value = true\n timer = setTimeout(flush, delay)\n }\n\n const stopWatch = watch(\n source as WatchSource<unknown> | WatchSource<unknown>[],\n (value, oldValue, onCleanup) => {\n schedule(value as T, oldValue as T | undefined)\n onCleanup(() => {\n cancel()\n runCallbackCleanup()\n })\n },\n watchOptions,\n )\n\n function stop(): void {\n if (stopped) return\n stopped = true\n stopWatch()\n cancel()\n runCallbackCleanup()\n }\n\n onScopeDispose(stop)\n\n return {\n isPending,\n cancel,\n flush,\n stop,\n }\n}\n","import { ref, reactive, computed, watch, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport { useDebouncedWatch } from './useDebouncedWatch'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport { datePresetToISO } from './experiment-utils'\nimport type {\n ExperimentSummary,\n ExperimentListResponse,\n ExperimentFilters,\n ExperimentTypeOption,\n ExperimentSortField,\n PlatformContext,\n SelectOption,\n} from '../types'\n\nfunction getPlatformContext(): PlatformContext | undefined {\n if (typeof window === 'undefined') return undefined\n return (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n}\n\nfunction getPlatformApiUrl(): string | undefined {\n return getPlatformContext()?.platformApiUrl\n}\n\nexport interface UseExperimentSelectorOptions {\n experimentType?: string\n allowedExperimentTypes?: string[] | null\n apiBaseUrl?: string\n limit?: number\n immediate?: boolean\n}\n\nexport interface UseExperimentSelectorReturn {\n /** Current page of fetched experiment rows. */\n experiments: Ref<ExperimentSummary[]>\n /** Total matching experiment count reported by the platform. */\n total: Ref<number>\n /** Currently selected experiment, or null. */\n selectedExperiment: Ref<ExperimentSummary | null>\n /** Mutable filters used for the next fetch. */\n filters: ExperimentFilters\n /** Whether experiment rows are currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful experiment fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Current zero-based page index. */\n page: Ref<number>\n /** Whether another page can be loaded. */\n hasMore: ComputedRef<boolean>\n // Sort\n /** Combined sort key in the form `<field>:<asc|desc>`. */\n sortKey: Ref<string>\n // Filter options\n /** Available experiment type options for filter UI. */\n experimentTypes: Ref<ExperimentTypeOption[]>\n /** Available project options for filter UI. */\n projects: Ref<SelectOption<string>[]>\n // Grouped view\n /** Fetched experiments grouped by project name. */\n groupedByProject: ComputedRef<[string, ExperimentSummary[]][]>\n // Methods\n /** Fetch the current page with the current filters. */\n fetch: () => Promise<void>\n /** Fetch and append the next page when available. */\n loadMore: () => Promise<void>\n /** Clear fetched rows and refetch page zero. */\n reset: () => void\n /** Select an experiment. */\n select: (experiment: ExperimentSummary) => void\n /** Clear selection and filters. */\n clear: () => void\n /** Fetch experiment type and project filter options. */\n fetchFilterOptions: () => Promise<void>\n}\n\n/** Fetches a paginated, filtered experiment list from the platform API for picker and selector UIs. */\nexport function useExperimentSelector(\n options: UseExperimentSelectorOptions = {},\n): UseExperimentSelectorReturn {\n const {\n limit = 100,\n immediate = false,\n experimentType,\n allowedExperimentTypes: optionAllowedExperimentTypes,\n apiBaseUrl,\n } = options\n const platformBase = apiBaseUrl ?? getPlatformApiUrl()\n const api = useApi()\n\n const experiments = ref<ExperimentSummary[]>([])\n const total = ref(0)\n const selectedExperiment = ref<ExperimentSummary | null>(null)\n const request = useRequestSyncState('Failed to fetch experiments')\n const isLoading = request.loading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n const page = ref(0)\n\n // Sort: combined key like \"created_at:desc\"\n const sortKey = ref<string>('created_at:desc')\n\n // Filter option data (fetched once, cached)\n const experimentTypes = ref<ExperimentTypeOption[]>([])\n const projects = ref<SelectOption<string>[]>([])\n let filterOptionsFetched = false\n\n const hasMore = computed(() => experiments.value.length < total.value)\n\n const filters: ExperimentFilters = reactive({\n search: undefined,\n status: undefined,\n project: undefined,\n experimentType: undefined,\n datePreset: undefined,\n })\n\n function normalizeExperimentTypes(values: string[] | null | undefined): string[] | null {\n if (values == null) return null\n return [...new Set(values.filter((value): value is string => typeof value === 'string' && value.length > 0))]\n }\n\n function currentAllowedExperimentTypes(): string[] | null {\n if (optionAllowedExperimentTypes !== undefined) {\n return normalizeExperimentTypes(optionAllowedExperimentTypes)\n }\n return normalizeExperimentTypes(getPlatformContext()?.allowedExperimentTypes)\n }\n\n function parseSortKey(): { sortBy: ExperimentSortField; sortOrder: 'asc' | 'desc' } {\n const [field, order] = sortKey.value.split(':')\n return {\n sortBy: (field || 'created_at') as ExperimentSortField,\n sortOrder: (order || 'desc') as 'asc' | 'desc',\n }\n }\n\n type ExperimentTypeScope =\n | { kind: 'all' }\n | { kind: 'blocked' }\n | { kind: 'single'; experimentType: string }\n | { kind: 'multi'; experimentTypes: string[] }\n\n function resolveExperimentTypeScope(): ExperimentTypeScope {\n const allowedTypes = currentAllowedExperimentTypes()\n const selectedType = experimentType ?? filters.experimentType ?? undefined\n\n if (selectedType) {\n if (allowedTypes && !allowedTypes.includes(selectedType)) {\n return { kind: 'blocked' }\n }\n return { kind: 'single', experimentType: selectedType }\n }\n\n if (allowedTypes) {\n if (allowedTypes.length === 0) return { kind: 'blocked' }\n if (allowedTypes.length === 1) return { kind: 'single', experimentType: allowedTypes[0] }\n return { kind: 'multi', experimentTypes: allowedTypes }\n }\n\n return { kind: 'all' }\n }\n\n function buildExperimentListUrl(typeFilter: string | undefined, skip: number, pageLimit: number): string {\n const params = new URLSearchParams()\n if (typeFilter) params.set('experiment_type', typeFilter)\n if (filters.status) params.set('status', filters.status)\n if (filters.search) params.set('search', filters.search)\n if (filters.project) params.set('project', filters.project)\n\n const { sortBy, sortOrder } = parseSortKey()\n params.set('sort_by', sortBy)\n params.set('sort_order', sortOrder)\n\n if (filters.datePreset) {\n params.set('created_after', datePresetToISO(filters.datePreset))\n }\n\n params.set('limit', String(pageLimit))\n params.set('skip', String(skip))\n\n const query = params.toString()\n const base = platformBase ?? ''\n return `${base}/experiments${query ? `?${query}` : ''}`\n }\n\n function sortExperiments(items: ExperimentSummary[]): ExperimentSummary[] {\n const { sortBy, sortOrder } = parseSortKey()\n const direction = sortOrder === 'desc' ? -1 : 1\n return [...items].sort((a, b) => {\n const aValue = a[sortBy] ?? ''\n const bValue = b[sortBy] ?? ''\n if (aValue < bValue) return -1 * direction\n if (aValue > bValue) return 1 * direction\n return 0\n })\n }\n\n async function fetchExperimentList(typeFilter: string | undefined, skip: number, pageLimit: number) {\n return await api.get<ExperimentListResponse>(buildExperimentListUrl(typeFilter, skip, pageLimit))\n }\n\n async function fetchScopedExperimentPage(): Promise<ExperimentListResponse> {\n const scope = resolveExperimentTypeScope()\n const pageSkip = page.value * limit\n\n if (scope.kind === 'blocked') {\n return { experiments: [], total: 0 }\n }\n\n if (scope.kind === 'multi') {\n const perTypeLimit = pageSkip + limit\n const responses = await Promise.all(\n scope.experimentTypes.map(type => fetchExperimentList(type, 0, perTypeLimit)),\n )\n const merged = sortExperiments(responses.flatMap(response => response.experiments))\n return {\n experiments: merged.slice(pageSkip, pageSkip + limit),\n total: responses.reduce((sum, response) => sum + response.total, 0),\n }\n }\n\n return await fetchExperimentList(\n scope.kind === 'single' ? scope.experimentType : undefined,\n pageSkip,\n limit,\n )\n }\n\n async function fetchExperiments(): Promise<void> {\n try {\n await request.run(async () => {\n const data = await fetchScopedExperimentPage()\n if (page.value === 0) {\n experiments.value = data.experiments\n } else {\n experiments.value = [...experiments.value, ...data.experiments]\n }\n total.value = data.total\n }, { success: 'load', errorMessage: 'Failed to fetch experiments' })\n } catch {\n if (page.value === 0) {\n experiments.value = []\n total.value = 0\n }\n }\n }\n\n async function fetchFilterOptions(): Promise<void> {\n if (filterOptionsFetched) return\n filterOptionsFetched = true\n\n const base = platformBase ?? ''\n const [typesRes, projectsRes] = await Promise.allSettled([\n api.get<Array<{ value: string; label: string; color?: string }>>(`${base}/experiments/experiment-types`),\n api.get<{ projects: Array<{ id: number; name: string }>; total: number }>(`${base}/projects`),\n ])\n\n if (typesRes.status === 'fulfilled' && Array.isArray(typesRes.value)) {\n const allowedTypes = currentAllowedExperimentTypes()\n const allowedSet = allowedTypes ? new Set(allowedTypes) : null\n experimentTypes.value = typesRes.value\n .filter(t => !allowedSet || allowedSet.has(t.value))\n .map(t => ({\n value: t.value,\n label: t.label,\n color: t.color,\n }))\n if (filters.experimentType && allowedSet && !allowedSet.has(filters.experimentType)) {\n filters.experimentType = undefined\n }\n }\n\n if (projectsRes.status === 'fulfilled' && projectsRes.value?.projects && Array.isArray(projectsRes.value.projects)) {\n projects.value = projectsRes.value.projects.map(p => ({\n value: p.name,\n label: p.name,\n }))\n }\n }\n\n async function loadMore(): Promise<void> {\n if (!hasMore.value || isLoading.value) return\n page.value++\n await fetchExperiments()\n }\n\n function reset(): void {\n page.value = 0\n experiments.value = []\n total.value = 0\n fetchExperiments()\n }\n\n function select(experiment: ExperimentSummary): void {\n selectedExperiment.value = experiment\n }\n\n function clear(): void {\n selectedExperiment.value = null\n filters.search = undefined\n filters.status = undefined\n filters.project = undefined\n filters.experimentType = undefined\n filters.datePreset = undefined\n sortKey.value = 'created_at:desc'\n page.value = 0\n request.clearError()\n }\n\n // Group experiments by project (client-side)\n const groupedByProject = computed<[string, ExperimentSummary[]][]>(() => {\n const groups = new Map<string, ExperimentSummary[]>()\n for (const exp of experiments.value) {\n const key = exp.project_name ?? exp.project ?? 'No project'\n const list = groups.get(key)\n if (list) {\n list.push(exp)\n } else {\n groups.set(key, [exp])\n }\n }\n // Sort alphabetically, \"No project\" last\n return [...groups.entries()].sort(([a], [b]) => {\n if (a === 'No project') return 1\n if (b === 'No project') return -1\n return a.localeCompare(b)\n })\n })\n\n const searchWatch = useDebouncedWatch(\n () => filters.search,\n () => {\n page.value = 0\n fetchExperiments()\n },\n { delay: 300 },\n )\n\n // Immediate watch on discrete filters and sort (cancel any pending search debounce)\n watch(\n () => [filters.status, filters.project, filters.experimentType, filters.datePreset, sortKey.value],\n () => {\n searchWatch.cancel()\n page.value = 0\n fetchExperiments()\n },\n )\n\n if (immediate) {\n fetchExperiments()\n }\n\n return {\n experiments,\n total,\n selectedExperiment,\n filters,\n isLoading,\n error,\n lastLoadedAt,\n page,\n hasMore,\n sortKey,\n experimentTypes,\n projects,\n groupedByProject,\n fetch: fetchExperiments,\n loadMore,\n reset,\n select,\n clear,\n fetchFilterOptions,\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as getTypeDefault, E as getFieldRegistryEntry } from "./useControlSchema-
|
|
1
|
+
import { D as getTypeDefault, E as getFieldRegistryEntry } from "./useControlSchema-BZNdalmL.js";
|
|
2
2
|
import { computed, onMounted, onUnmounted, reactive, ref, shallowRef, toRaw, watch } from "vue";
|
|
3
3
|
//#region src/composables/usePlatformContext.ts
|
|
4
4
|
var DEFAULT_CONTEXT = {
|
|
@@ -726,4 +726,4 @@ function useFormBuilder(schema, initialData, enhancements) {
|
|
|
726
726
|
//#endregion
|
|
727
727
|
export { usePlatformContext as i, evaluateCondition as n, useForm as r, useFormBuilder as t };
|
|
728
728
|
|
|
729
|
-
//# sourceMappingURL=useFormBuilder-
|
|
729
|
+
//# sourceMappingURL=useFormBuilder-DKekvXRs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormBuilder-BOJ52N4M.js","names":[],"sources":["../src/composables/usePlatformContext.ts","../src/composables/useFormValidation.ts","../src/composables/useForm.ts","../src/composables/formBuilderSchema.ts","../src/composables/useFormBuilder.ts"],"sourcesContent":["import { ref, computed, onMounted, onUnmounted } from 'vue'\nimport type { PlatformContext, PlatformContextOptions, PlatformEvent } from '../types'\n\nconst DEFAULT_CONTEXT: PlatformContext = {\n isIntegrated: false,\n theme: 'system',\n}\n\nconst platformContext = ref<PlatformContext>({ ...DEFAULT_CONTEXT })\n\n// Track allowed origins for postMessage security.\n// Inferred origins come from platform injection and URL params.\n// Consumer origins and allowAnyOrigin are tracked per composable instance.\nlet inferredOrigins: Set<string> = new Set()\nlet allowedOrigins: Set<string> = new Set()\nlet allowAnyOrigin = false\nlet initialized = false\nlet listenerCount = 0\nlet nextConsumerId = 0\nlet currentHandler: ((event: MessageEvent) => void) | null = null\nconst consumerOrigins: Map<number, Set<string>> = new Map()\nconst allowAnyOriginConsumers: Set<number> = new Set()\n\n/**\n * Derive origin from URL (protocol + host)\n */\nfunction getOriginFromUrl(url: string): string | null {\n try {\n const parsed = new URL(url)\n return parsed.origin\n } catch {\n return null\n }\n}\n\nfunction normalizeAllowedOrigins(origins: string[] | undefined): Set<string> {\n const normalized = new Set<string>()\n if (!origins) {\n return normalized\n }\n\n for (const origin of origins) {\n normalized.add(getOriginFromUrl(origin) || origin)\n }\n return normalized\n}\n\nfunction recomputeOriginPolicy(): void {\n allowedOrigins = new Set(inferredOrigins)\n for (const origins of consumerOrigins.values()) {\n for (const origin of origins) {\n allowedOrigins.add(origin)\n }\n }\n allowAnyOrigin = allowAnyOriginConsumers.size > 0\n}\n\nfunction resetPlatformContextState(): void {\n inferredOrigins = new Set()\n allowedOrigins = new Set()\n allowAnyOrigin = false\n initialized = false\n listenerCount = 0\n currentHandler = null\n consumerOrigins.clear()\n allowAnyOriginConsumers.clear()\n platformContext.value = { ...DEFAULT_CONTEXT }\n}\n\n/**\n * Check if an origin is allowed for postMessage communication\n */\nfunction isOriginAllowed(origin: string): boolean {\n // Development mode: allow any origin (must be explicitly enabled)\n if (allowAnyOrigin) {\n console.warn('[MINT SDK] postMessage origin validation disabled - only use in development')\n return true\n }\n\n // Same origin is always allowed\n if (origin === window.location.origin) {\n return true\n }\n\n // Check against allowed origins list\n return allowedOrigins.has(origin)\n}\n\n/**\n * Platform context composable for plugin integration with MINT Platform.\n *\n * Provides secure communication with the parent platform via postMessage.\n *\n * @param options - Configuration options\n * @param options.allowedOrigins - List of allowed origins for postMessage\n * @param options.allowAnyOrigin - Allow any origin (UNSAFE, development only)\n *\n * @example\n * ```typescript\n * // Basic usage - derives origin from platform injection\n * const { isIntegrated, user, theme } = usePlatformContext()\n *\n * // With explicit allowed origins\n * const { isIntegrated } = usePlatformContext({\n * allowedOrigins: ['https://mint.example.com']\n * })\n *\n * // Development mode (UNSAFE)\n * const { isIntegrated } = usePlatformContext({\n * allowAnyOrigin: import.meta.env.DEV\n * })\n * ```\n */\n/** Connects a plugin to the MINT platform via postMessage, exposing user, theme, and experiment context. */\nexport function usePlatformContext(options: PlatformContextOptions = {}) {\n const consumerId = ++nextConsumerId\n const instanceOrigins = normalizeAllowedOrigins(options.allowedOrigins)\n const instanceAllowAnyOrigin = options.allowAnyOrigin === true\n\n function detectPlatform(): void {\n const detectedOrigins = new Set<string>()\n\n // Check if running under MINT Platform by looking for platform-injected global\n const platformData = (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n\n if (platformData) {\n platformContext.value = {\n ...platformData,\n isIntegrated: true,\n }\n\n // Derive platform origin from injected data\n if (platformData.platformOrigin) {\n detectedOrigins.add(platformData.platformOrigin)\n } else if (platformData.platformApiUrl) {\n const origin = getOriginFromUrl(platformData.platformApiUrl)\n if (origin) {\n detectedOrigins.add(origin)\n }\n }\n } else {\n // Check for platform indicator in URL or localStorage\n const urlParams = new URLSearchParams(window.location.search)\n const hasPluginParam = urlParams.has('mint-plugin')\n\n // Try to get platform origin from URL parameter\n const platformOrigin = urlParams.get('mint-origin')\n if (platformOrigin) {\n const origin = getOriginFromUrl(platformOrigin)\n if (origin) {\n detectedOrigins.add(origin)\n }\n }\n\n platformContext.value = {\n isIntegrated: hasPluginParam,\n theme: (() => {\n try {\n const s = localStorage.getItem('mint-settings')\n if (s) return (JSON.parse(s).theme as 'light' | 'dark' | 'system') || 'system'\n } catch { /* ignore */ }\n return 'system'\n })(),\n platformOrigin: platformOrigin || undefined,\n }\n }\n\n inferredOrigins = detectedOrigins\n }\n\n function handlePlatformMessage(event: MessageEvent): void {\n // Only accept messages from parent window (platform)\n if (event.source !== window.parent) return\n\n // Validate origin for security\n if (!isOriginAllowed(event.origin)) {\n console.warn(`[MINT SDK] Rejected postMessage from untrusted origin: ${event.origin}`)\n return\n }\n\n try {\n const platformEvent = event.data as PlatformEvent\n if (!platformEvent.type?.startsWith('mint:')) return\n\n switch (platformEvent.type) {\n case 'mint:theme-changed':\n platformContext.value.theme = platformEvent.payload as 'light' | 'dark' | 'system'\n break\n case 'mint:user-changed':\n platformContext.value.user = platformEvent.payload as PlatformContext['user']\n break\n }\n } catch {\n // Ignore invalid messages\n }\n }\n\n /**\n * Send a message to the parent platform.\n * Uses validated target origin for security.\n */\n function sendToPlatform(event: PlatformEvent): void {\n if (!platformContext.value.isIntegrated || window.parent === window) {\n return\n }\n\n // Determine target origin\n let targetOrigin: string\n\n if (platformContext.value.platformOrigin) {\n // Use explicitly configured platform origin\n targetOrigin = platformContext.value.platformOrigin\n } else if (allowedOrigins.size > 0) {\n // Use first allowed origin (typically the platform)\n targetOrigin = allowedOrigins.values().next().value as string\n } else if (allowAnyOrigin) {\n // Development mode fallback\n targetOrigin = '*'\n console.warn('[MINT SDK] Using wildcard origin for postMessage - only use in development')\n } else {\n // Safety: if no origin is configured, log warning and don't send\n console.warn('[MINT SDK] Cannot send postMessage: no platform origin configured')\n return\n }\n\n window.parent.postMessage(event, targetOrigin)\n }\n\n /**\n * Request navigation to a path in the platform.\n */\n function navigate(path: string): void {\n sendToPlatform({\n type: 'mint:navigate',\n payload: path,\n })\n }\n\n /**\n * Show a notification in the platform.\n */\n function notify(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info'): void {\n sendToPlatform({\n type: 'mint:notification',\n payload: { message, type },\n })\n }\n\n onMounted(() => {\n consumerOrigins.set(consumerId, instanceOrigins)\n if (instanceAllowAnyOrigin) {\n allowAnyOriginConsumers.add(consumerId)\n }\n\n if (!initialized) {\n detectPlatform()\n currentHandler = handlePlatformMessage\n window.addEventListener('message', handlePlatformMessage)\n initialized = true\n }\n\n listenerCount++\n recomputeOriginPolicy()\n })\n\n onUnmounted(() => {\n consumerOrigins.delete(consumerId)\n allowAnyOriginConsumers.delete(consumerId)\n\n listenerCount = Math.max(0, listenerCount - 1)\n if (listenerCount === 0) {\n if (currentHandler) {\n window.removeEventListener('message', currentHandler)\n }\n resetPlatformContextState()\n return\n }\n\n recomputeOriginPolicy()\n })\n\n const isIntegrated = computed(() => platformContext.value.isIntegrated)\n const plugin = computed(() => platformContext.value.plugin)\n const user = computed(() => platformContext.value.user)\n const theme = computed(() => platformContext.value.theme)\n const features = computed(() => platformContext.value.features)\n\n return {\n context: platformContext,\n isIntegrated,\n plugin,\n user,\n theme,\n features,\n navigate,\n notify,\n sendToPlatform,\n }\n}\n","/**\n * Validation rule function type.\n * Returns error message string if invalid, undefined/null if valid.\n */\nexport type ValidationRule<T = unknown> = (value: T, formData: Record<string, unknown>) => string | undefined | null\n\n/**\n * Field validation rules configuration.\n */\nexport interface FieldRules<T = unknown> {\n required?: boolean | string\n minLength?: number | { value: number; message: string }\n maxLength?: number | { value: number; message: string }\n min?: number | { value: number; message: string }\n max?: number | { value: number; message: string }\n pattern?: RegExp | { value: RegExp; message: string }\n email?: boolean | string\n custom?: ValidationRule<T> | ValidationRule<T>[]\n}\n\nconst validators = {\n required: (value: unknown, message = 'This field is required'): string | null => {\n if (value === null || value === undefined || value === '') {\n return message\n }\n if (Array.isArray(value) && value.length === 0) {\n return message\n }\n return null\n },\n\n minLength: (value: unknown, min: number, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (value.length < min) {\n return message || `Must be at least ${min} characters`\n }\n return null\n },\n\n maxLength: (value: unknown, max: number, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (value.length > max) {\n return message || `Must be at most ${max} characters`\n }\n return null\n },\n\n min: (value: unknown, min: number, message?: string): string | null => {\n if (typeof value !== 'number') return null\n if (value < min) {\n return message || `Must be at least ${min}`\n }\n return null\n },\n\n max: (value: unknown, max: number, message?: string): string | null => {\n if (typeof value !== 'number') return null\n if (value > max) {\n return message || `Must be at most ${max}`\n }\n return null\n },\n\n pattern: (value: unknown, pattern: RegExp, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (!pattern.test(value)) {\n return message || 'Invalid format'\n }\n return null\n },\n\n email: (value: unknown, message = 'Invalid email address'): string | null => {\n if (typeof value !== 'string' || !value) return null\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(value)) {\n return message\n }\n return null\n },\n}\n\nexport function validateFieldValue(\n value: unknown,\n fieldRules: FieldRules | undefined,\n formData: Record<string, unknown>,\n): string | null {\n if (!fieldRules) return null\n\n if (fieldRules.required) {\n const message = typeof fieldRules.required === 'string' ? fieldRules.required : undefined\n const error = validators.required(value, message)\n if (error) return error\n }\n\n if (value === null || value === undefined || value === '') {\n return null\n }\n\n if (fieldRules.minLength !== undefined) {\n const config = typeof fieldRules.minLength === 'number'\n ? { value: fieldRules.minLength, message: undefined }\n : fieldRules.minLength\n const error = validators.minLength(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.maxLength !== undefined) {\n const config = typeof fieldRules.maxLength === 'number'\n ? { value: fieldRules.maxLength, message: undefined }\n : fieldRules.maxLength\n const error = validators.maxLength(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.min !== undefined) {\n const config = typeof fieldRules.min === 'number'\n ? { value: fieldRules.min, message: undefined }\n : fieldRules.min\n const error = validators.min(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.max !== undefined) {\n const config = typeof fieldRules.max === 'number'\n ? { value: fieldRules.max, message: undefined }\n : fieldRules.max\n const error = validators.max(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.pattern !== undefined) {\n const config = fieldRules.pattern instanceof RegExp\n ? { value: fieldRules.pattern, message: undefined }\n : fieldRules.pattern\n const error = validators.pattern(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.email) {\n const message = typeof fieldRules.email === 'string' ? fieldRules.email : undefined\n const error = validators.email(value, message)\n if (error) return error\n }\n\n if (fieldRules.custom) {\n const customRules = Array.isArray(fieldRules.custom) ? fieldRules.custom : [fieldRules.custom]\n for (const rule of customRules) {\n const error = rule(value, formData)\n if (error) return error\n }\n }\n\n return null\n}\n","import { ref, reactive, computed, toRaw, watch, type Ref } from 'vue'\nimport { validateFieldValue, type FieldRules } from './useFormValidation'\n\nexport type { FieldRules, ValidationRule } from './useFormValidation'\n\n/**\n * Field validation rules configuration.\n */\nexport interface FieldState {\n value: unknown\n error: string | null\n touched: boolean\n dirty: boolean\n}\n\n/**\n * Form state and methods.\n */\nexport interface UseFormReturn<T extends Record<string, unknown>> {\n // Form data (reactive)\n data: T\n\n // Field errors\n errors: Record<string, string | null>\n\n // Field touched state\n touched: Record<string, boolean>\n\n // Field dirty state (value changed from initial)\n dirty: Record<string, boolean>\n\n // Overall form state\n isValid: Ref<boolean>\n isDirty: Ref<boolean>\n isSubmitting: Ref<boolean>\n\n // Methods\n setFieldValue: <K extends keyof T>(field: K, value: T[K]) => void\n setFieldError: (field: string, error: string | null) => void\n setFieldTouched: (field: string, touched?: boolean) => void\n validateField: (field: string) => boolean\n validate: () => boolean\n reset: (values?: Partial<T>) => void\n /** Replace the full form state and treat the provided values as the new clean baseline. */\n replaceState: (values: T) => void\n handleSubmit: (onSubmit: (data: T) => Promise<void> | void) => (e?: Event) => Promise<void>\n getFieldProps: <K extends keyof T>(field: K) => {\n modelValue: T[K]\n 'onUpdate:modelValue': (value: T[K]) => void\n onBlur: () => void\n error: string | null\n }\n}\n\n/**\n * Form state management composable with validation.\n *\n * @param initialValues - Initial form values\n * @param rules - Validation rules for each field\n *\n * @example\n * ```typescript\n * const { data, errors, isValid, handleSubmit, getFieldProps } = useForm(\n * { email: '', password: '' },\n * {\n * email: { required: true, email: true },\n * password: { required: true, minLength: 8 },\n * }\n * )\n *\n * // In template\n * <BaseInput v-bind=\"getFieldProps('email')\" label=\"Email\" />\n * <BaseInput v-bind=\"getFieldProps('password')\" type=\"password\" label=\"Password\" />\n * <BaseButton @click=\"handleSubmit(onSubmit)\" :disabled=\"!isValid\">Submit</BaseButton>\n * ```\n */\n/** Reactive form state with field-level validation, dirty tracking, and submit handling. */\nexport function useForm<T extends Record<string, unknown>>(\n initialValues: T,\n rules: Partial<Record<keyof T, FieldRules>> = {}\n): UseFormReturn<T> {\n const cloneableInitialValues = deepToRaw(initialValues) as T\n\n // Deep copy initial values so nested objects are not shared\n let _initialValues = structuredClone(cloneableInitialValues)\n\n // Reactive form data\n const data = reactive(structuredClone(cloneableInitialValues)) as T\n\n // Field state - use simple Record types for better TS compatibility\n const errors = reactive<Record<string, string | null>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = null\n return acc\n }, {} as Record<string, string | null>)\n )\n\n const touched = reactive<Record<string, boolean>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = false\n return acc\n }, {} as Record<string, boolean>)\n )\n\n const dirty = reactive<Record<string, boolean>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = false\n return acc\n }, {} as Record<string, boolean>)\n )\n\n const isSubmitting = ref(false)\n\n // Watch data changes to track dirty state\n watch(\n () => ({ ...data }),\n (newData) => {\n for (const key of Object.keys(newData)) {\n dirty[key] = newData[key as keyof T] !== _initialValues[key as keyof T]\n }\n },\n { deep: true }\n )\n\n // Validate a single field\n function validateField(field: string): boolean {\n const value = data[field as keyof T]\n const fieldRules = rules[field as keyof T]\n const error = validateFieldValue(value, fieldRules, data as Record<string, unknown>)\n errors[field] = error\n return error === null\n }\n\n // Validate all fields\n function validate(): boolean {\n let isAllValid = true\n for (const field of Object.keys(data)) {\n if (!validateField(field)) {\n isAllValid = false\n }\n }\n return isAllValid\n }\n\n // Computed overall validity\n const isValid = computed(() => {\n return Object.values(errors).every(error => error === null)\n })\n\n // Computed overall dirty state\n const isDirty = computed(() => {\n return Object.values(dirty).some(d => d)\n })\n\n // Set field value\n function setFieldValue<K extends keyof T>(field: K, value: T[K]): void {\n ;(data as Record<string, unknown>)[field as string] = value\n if (touched[field as string]) {\n validateField(field as string)\n }\n }\n\n // Set field error\n function setFieldError(field: string, error: string | null): void {\n errors[field] = error\n }\n\n // Set field touched\n function setFieldTouched(field: string, isTouched = true): void {\n touched[field] = isTouched\n if (isTouched) {\n validateField(field)\n }\n }\n\n // Reset form\n function reset(values?: Partial<T>): void {\n const resetValues = values ? { ..._initialValues, ...values } : _initialValues\n for (const key of Object.keys(data)) {\n ;(data as Record<string, unknown>)[key] = structuredClone(deepToRaw(resetValues[key as keyof T]))\n errors[key] = null\n touched[key] = false\n dirty[key] = false\n }\n }\n\n function replaceState(values: T): void {\n const nextValues = structuredClone(deepToRaw(values)) as T\n _initialValues = structuredClone(nextValues)\n\n for (const key of Object.keys(data)) {\n if (key in nextValues) continue\n delete (data as Record<string, unknown>)[key]\n delete errors[key]\n delete touched[key]\n delete dirty[key]\n }\n\n for (const key of Object.keys(nextValues)) {\n ;(data as Record<string, unknown>)[key] = structuredClone(deepToRaw(nextValues[key as keyof T]))\n errors[key] = null\n touched[key] = false\n dirty[key] = false\n }\n }\n\n // Handle submit\n function handleSubmit(onSubmit: (data: T) => Promise<void> | void) {\n return async (e?: Event): Promise<void> => {\n e?.preventDefault()\n\n // Mark all fields as touched\n for (const field of Object.keys(data)) {\n touched[field] = true\n }\n\n if (!validate()) {\n return\n }\n\n isSubmitting.value = true\n try {\n await onSubmit(data)\n } finally {\n isSubmitting.value = false\n }\n }\n }\n\n // Get props for a field (for v-bind)\n function getFieldProps<K extends keyof T>(field: K) {\n const fieldStr = field as string\n return {\n modelValue: data[field],\n 'onUpdate:modelValue': (value: T[K]) => setFieldValue(field, value),\n onBlur: () => setFieldTouched(fieldStr),\n error: touched[fieldStr] ? errors[fieldStr] : null,\n }\n }\n\n return {\n data,\n errors,\n touched,\n dirty,\n isValid,\n isDirty,\n isSubmitting,\n setFieldValue,\n setFieldError,\n setFieldTouched,\n validateField,\n validate,\n reset,\n replaceState,\n handleSubmit,\n getFieldProps,\n }\n}\n\nfunction deepToRaw(value: unknown): unknown {\n const raw = toRaw(value)\n\n if (Array.isArray(raw)) {\n return raw.map(item => deepToRaw(item))\n }\n\n if (isPlainRecord(raw)) {\n return Object.fromEntries(\n Object.entries(raw).map(([key, item]) => [key, deepToRaw(item)])\n )\n }\n\n return raw\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]'\n}\n","import { getTypeDefault } from './formBuilderRegistry'\nimport type { FieldRules } from './useForm'\nimport type {\n FieldCondition,\n FieldValidation,\n FormEnhancements,\n FormFieldSchema,\n FormSchema,\n FormSectionSchema,\n} from '../types/form-builder'\n\n/**\n * Evaluate a JSON-serializable field condition against the current form data.\n *\n * Supports logical operators (`and`, `or`, `not`) and comparison operators\n * (`eq`, `neq`, `gt`, `lt`, `gte`, `lte`, `in`, `notIn`, `truthy`, `falsy`,\n * `contains`). Returns `true` if the condition passes.\n */\nexport function evaluateCondition(\n condition: FieldCondition,\n data: Record<string, unknown>,\n): boolean {\n if ('and' in condition) {\n return condition.and.every((c) => evaluateCondition(c, data))\n }\n if ('or' in condition) {\n return condition.or.some((c) => evaluateCondition(c, data))\n }\n if ('not' in condition) {\n return !evaluateCondition(condition.not, data)\n }\n\n const value = data[condition.field]\n\n if ('eq' in condition) return value === condition.eq\n if ('neq' in condition) return value !== condition.neq\n if ('gt' in condition) return typeof value === 'number' && value > condition.gt\n if ('lt' in condition) return typeof value === 'number' && value < condition.lt\n if ('gte' in condition) return typeof value === 'number' && value >= condition.gte\n if ('lte' in condition) return typeof value === 'number' && value <= condition.lte\n if ('in' in condition) return condition.in.includes(value)\n if ('notIn' in condition) return !condition.notIn.includes(value)\n if ('truthy' in condition) return !!value\n if ('falsy' in condition) return !value\n if ('contains' in condition) {\n if (typeof value === 'string') return value.includes(condition.contains)\n if (Array.isArray(value)) return value.includes(condition.contains)\n return false\n }\n\n return true\n}\n\n/** Return all sections across steps (wizard) or directly from a flat schema. */\nexport function collectSections(schema: FormSchema): FormSectionSchema[] {\n return schema.steps ? schema.steps.flatMap((step) => step.sections) : schema.sections\n}\n\n/** Return all field schemas in schema order, flattening sections and steps. */\nexport function flattenFields(schema: FormSchema): FormFieldSchema[] {\n return collectSections(schema).flatMap((section) => section.fields)\n}\n\n/** Convert a JSON-safe `FieldValidation` descriptor to a runtime `FieldRules` object. */\nfunction convertValidation(v: FieldValidation): FieldRules {\n const rules: FieldRules = {}\n\n if (v.required !== undefined) rules.required = v.required\n if (v.minLength !== undefined) rules.minLength = v.minLength\n if (v.maxLength !== undefined) rules.maxLength = v.maxLength\n if (v.min !== undefined) rules.min = v.min\n if (v.max !== undefined) rules.max = v.max\n if (v.email !== undefined) rules.email = v.email\n\n if (v.pattern !== undefined) {\n rules.pattern =\n typeof v.pattern === 'string'\n ? new RegExp(v.pattern)\n : { value: new RegExp(v.pattern.value), message: v.pattern.message }\n }\n\n return rules\n}\n\nexport function buildInitialValues<T extends Record<string, unknown>>(\n fields: readonly FormFieldSchema[],\n initialData?: Partial<T>,\n): Record<string, unknown> {\n const initialValues = {} as Record<string, unknown>\n\n for (const field of fields) {\n const key = field.name\n if (initialData && hasOwnKey(initialData, key)) {\n initialValues[key] = (initialData as Record<string, unknown>)[key]\n } else if (field.defaultValue !== undefined) {\n initialValues[key] = field.defaultValue\n } else {\n initialValues[key] = getTypeDefault(field.type)\n }\n }\n\n return initialValues\n}\n\nexport function buildRules<T extends Record<string, unknown>>(\n fields: readonly FormFieldSchema[],\n enhancements?: FormEnhancements<T>,\n): Partial<Record<string, FieldRules>> {\n const rules: Partial<Record<string, FieldRules>> = {}\n\n for (const field of fields) {\n const base: FieldRules = field.validation ? convertValidation(field.validation) : {}\n const enhancement = enhancements?.fields?.[field.name as keyof T]\n\n const customValidators: Array<(\n value: unknown,\n formData: Record<string, unknown>,\n ) => string | undefined | null> = []\n\n if (enhancement?.validate) {\n const fn = enhancement.validate\n customValidators.push((value, formData) => fn(value, formData as T))\n }\n\n if (customValidators.length > 0) {\n base.custom = customValidators\n }\n\n if (Object.keys(base).length > 0) {\n rules[field.name] = base\n }\n }\n\n return rules\n}\n\nexport function replaceArray<T>(target: T[], values: readonly T[]): void {\n target.splice(0, target.length, ...values)\n}\n\nexport function replaceRecord<TValue>(\n target: Partial<Record<string, TValue>>,\n source: Partial<Record<string, TValue>>,\n): void {\n for (const key of Object.keys(target)) {\n delete target[key]\n }\n Object.assign(target, source)\n}\n\nfunction hasOwnKey(source: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(source, key)\n}\n","import { reactive, ref, computed, shallowRef, watch } from 'vue'\nimport { useForm, type FieldRules, type UseFormReturn } from './useForm'\nimport { getFieldRegistryEntry } from './formBuilderRegistry'\nimport {\n buildInitialValues,\n buildRules,\n collectSections,\n evaluateCondition,\n flattenFields,\n replaceArray,\n replaceRecord,\n} from './formBuilderSchema'\nimport type {\n FormSchema,\n FormFieldSchema,\n FormSectionSchema,\n FormOptionInput,\n FormEnhancements,\n UseFormBuilderReturn,\n} from '../types/form-builder'\n\nexport { evaluateCondition } from './formBuilderSchema'\n\n// ---------------------------------------------------------------------------\n// useFormBuilder\n// ---------------------------------------------------------------------------\n\n/**\n * Drive a `FormSchema` as reactive form state.\n *\n * Builds initial values from schema defaults and `initialData`, derives\n * validation rules from `FieldValidation` descriptors and enhancement\n * validators, evaluates `FieldCondition` expressions for field/section\n * visibility, and wires wizard step navigation when `schema.steps` is set.\n *\n * @param schema - Declarative form or wizard schema.\n * @param initialData - Values that override schema defaults.\n * @param enhancements - TypeScript-only callbacks (dynamic options, validators,\n * submit handler, transform, field-change watcher).\n */\n/** Drives a declarative FormSchema as reactive state with conditional fields, wizard steps, and validation. */\nexport function useFormBuilder<T extends Record<string, unknown> = Record<string, unknown>>(\n schema: FormSchema,\n initialData?: Partial<T>,\n enhancements?: FormEnhancements<T>,\n): UseFormBuilderReturn<T> {\n const currentSchema = shallowRef(schema)\n const fields = reactive<FormFieldSchema[]>(flattenFields(schema))\n const sections = reactive<FormSectionSchema[]>(collectSections(schema))\n const rules = reactive<Partial<Record<string, FieldRules>>>(buildRules(fields, enhancements))\n\n // -- Create form -----------------------------------------------------------\n const form = useForm(\n buildInitialValues<T>(fields, initialData) as T,\n rules as Partial<Record<keyof T, FieldRules>>,\n )\n\n // -- Visibility ------------------------------------------------------------\n function isFieldVisible(name: string): boolean {\n const enhancement = enhancements?.fields?.[name as keyof T]\n if (enhancement?.visible) {\n return enhancement.visible(form.data as T)\n }\n\n const field = fields.find((f) => f.name === name)\n if (field?.condition) {\n return evaluateCondition(field.condition, form.data as Record<string, unknown>)\n }\n\n return true\n }\n\n function isSectionVisible(id: string): boolean {\n const section = sections.find((s) => s.id === id)\n if (section?.condition) {\n return evaluateCondition(section.condition, form.data as Record<string, unknown>)\n }\n return true\n }\n\n // -- Resolved field props --------------------------------------------------\n function getResolvedFieldProps(field: FormFieldSchema): Record<string, unknown> {\n const entry = getFieldRegistryEntry(field.type)\n const formProps = form.getFieldProps(field.name as keyof T)\n\n const merged: Record<string, unknown> = {\n ...entry.defaults,\n ...(field.props ?? {}),\n }\n\n // Dynamic enhancement props\n const enhancement = enhancements?.fields?.[field.name as keyof T]\n if (enhancement?.props) {\n Object.assign(merged, enhancement.props(form.data as T))\n }\n\n // Dynamic options\n const options = getFieldOptions(field.name)\n if (options) {\n merged.options = options\n }\n\n // Form field bindings\n if (entry.vModel) {\n merged.modelValue = formProps.modelValue\n merged['onUpdate:modelValue'] = formProps['onUpdate:modelValue']\n }\n merged.onBlur = formProps.onBlur\n\n // Error as boolean for components that use boolean error prop\n const errorMsg = formProps.error\n if (errorMsg) {\n merged.error = true\n }\n\n // Schema-level props\n if (field.placeholder) merged.placeholder = field.placeholder\n if (field.size) merged.size = field.size\n if (field.disabled) merged.disabled = true\n if (field.readonly) merged.readonly = true\n\n // Radio group needs a name prop\n if (field.type === 'radio' && !merged.name) {\n merged.name = field.name\n }\n\n return merged\n }\n\n function getFieldOptions(name: string): FormOptionInput[] | undefined {\n const enhancement = enhancements?.fields?.[name as keyof T]\n if (enhancement?.options) {\n return enhancement.options(form.data as T)\n }\n\n const field = fields.find((f) => f.name === name)\n if (field?.props?.options) {\n return field.props.options as FormOptionInput[]\n }\n\n return undefined\n }\n\n // -- Wizard state ----------------------------------------------------------\n const currentStep = ref(0)\n\n const isCurrentStepValid = computed(() => {\n if (!currentSchema.value.steps) return form.isValid.value\n\n const step = currentSchema.value.steps[currentStep.value]\n if (!step) return true\n\n for (const section of step.sections) {\n if (!isSectionVisible(section.id)) continue\n for (const field of section.fields) {\n if (!isFieldVisible(field.name)) continue\n if (!form.validateField(field.name)) return false\n }\n }\n return true\n })\n\n function goNext(): boolean {\n if (!currentSchema.value.steps) return false\n\n // Touch and validate all visible fields in current step\n const step = currentSchema.value.steps[currentStep.value]\n if (!step) return false\n\n let valid = true\n for (const section of step.sections) {\n if (!isSectionVisible(section.id)) continue\n for (const field of section.fields) {\n if (!isFieldVisible(field.name)) continue\n form.setFieldTouched(field.name, true)\n if (!form.validateField(field.name)) valid = false\n }\n }\n\n if (!valid) return false\n\n if (currentStep.value < currentSchema.value.steps.length - 1) {\n currentStep.value++\n }\n return true\n }\n\n function goBack(): void {\n if (currentStep.value > 0) {\n currentStep.value--\n }\n }\n\n function goToStep(index: number): void {\n if (!currentSchema.value.steps) return\n if (index >= 0 && index < currentSchema.value.steps.length) {\n currentStep.value = index\n }\n }\n\n // -- Validate (skip hidden fields) -----------------------------------------\n function validate(): boolean {\n let allValid = true\n for (const field of fields) {\n if (!isFieldVisible(field.name)) continue\n form.setFieldTouched(field.name, true)\n if (!form.validateField(field.name)) {\n allValid = false\n }\n }\n return allValid\n }\n\n // -- Submit ----------------------------------------------------------------\n async function submit(): Promise<void> {\n if (!validate()) return\n\n // Build submission data excluding hidden fields\n let submitData = {} as Record<string, unknown>\n for (const field of fields) {\n if (isFieldVisible(field.name)) {\n submitData[field.name] = (form.data as Record<string, unknown>)[field.name]\n }\n }\n\n if (enhancements?.transform) {\n submitData = enhancements.transform(submitData as T) as Record<string, unknown>\n }\n\n if (enhancements?.onSubmit) {\n form.isSubmitting.value = true\n try {\n await enhancements.onSubmit(submitData as T)\n } finally {\n form.isSubmitting.value = false\n }\n }\n }\n\n // -- Reset -----------------------------------------------------------------\n function reset(values?: Partial<T>): void {\n form.reset(values)\n currentStep.value = 0\n }\n\n function updateSchema(nextSchema: FormSchema, nextData?: Partial<T>): void {\n currentSchema.value = nextSchema\n\n const nextFields = flattenFields(nextSchema)\n replaceArray(fields, nextFields)\n replaceArray(sections, collectSections(nextSchema))\n replaceRecord(rules, buildRules(nextFields, enhancements))\n form.replaceState(buildInitialValues<T>(nextFields, nextData) as T)\n currentStep.value = 0\n }\n\n // -- onFieldChange wiring --------------------------------------------------\n if (enhancements?.onFieldChange) {\n const callback = enhancements.onFieldChange\n watch(\n () => ({ ...(form.data as Record<string, unknown>) }),\n (newData, oldData) => {\n if (!oldData) return\n for (const key of Object.keys(newData)) {\n if (newData[key] !== oldData[key]) {\n callback(key as keyof T, newData[key], newData as T)\n }\n }\n },\n { deep: true },\n )\n }\n\n return {\n form: form as UseFormReturn<T>,\n rules: rules as Partial<Record<keyof T, FieldRules>>,\n isFieldVisible,\n isSectionVisible,\n fields,\n getResolvedFieldProps,\n getFieldOptions,\n currentStep,\n isCurrentStepValid,\n goNext,\n goBack,\n goToStep,\n validate,\n reset,\n submit,\n updateSchema,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useFormBuilder-DKekvXRs.js","names":[],"sources":["../src/composables/usePlatformContext.ts","../src/composables/useFormValidation.ts","../src/composables/useForm.ts","../src/composables/formBuilderSchema.ts","../src/composables/useFormBuilder.ts"],"sourcesContent":["import { ref, computed, onMounted, onUnmounted } from 'vue'\nimport type { PlatformContext, PlatformContextOptions, PlatformEvent } from '../types'\n\nconst DEFAULT_CONTEXT: PlatformContext = {\n isIntegrated: false,\n theme: 'system',\n}\n\nconst platformContext = ref<PlatformContext>({ ...DEFAULT_CONTEXT })\n\n// Track allowed origins for postMessage security.\n// Inferred origins come from platform injection and URL params.\n// Consumer origins and allowAnyOrigin are tracked per composable instance.\nlet inferredOrigins: Set<string> = new Set()\nlet allowedOrigins: Set<string> = new Set()\nlet allowAnyOrigin = false\nlet initialized = false\nlet listenerCount = 0\nlet nextConsumerId = 0\nlet currentHandler: ((event: MessageEvent) => void) | null = null\nconst consumerOrigins: Map<number, Set<string>> = new Map()\nconst allowAnyOriginConsumers: Set<number> = new Set()\n\n/**\n * Derive origin from URL (protocol + host)\n */\nfunction getOriginFromUrl(url: string): string | null {\n try {\n const parsed = new URL(url)\n return parsed.origin\n } catch {\n return null\n }\n}\n\nfunction normalizeAllowedOrigins(origins: string[] | undefined): Set<string> {\n const normalized = new Set<string>()\n if (!origins) {\n return normalized\n }\n\n for (const origin of origins) {\n normalized.add(getOriginFromUrl(origin) || origin)\n }\n return normalized\n}\n\nfunction recomputeOriginPolicy(): void {\n allowedOrigins = new Set(inferredOrigins)\n for (const origins of consumerOrigins.values()) {\n for (const origin of origins) {\n allowedOrigins.add(origin)\n }\n }\n allowAnyOrigin = allowAnyOriginConsumers.size > 0\n}\n\nfunction resetPlatformContextState(): void {\n inferredOrigins = new Set()\n allowedOrigins = new Set()\n allowAnyOrigin = false\n initialized = false\n listenerCount = 0\n currentHandler = null\n consumerOrigins.clear()\n allowAnyOriginConsumers.clear()\n platformContext.value = { ...DEFAULT_CONTEXT }\n}\n\n/**\n * Check if an origin is allowed for postMessage communication\n */\nfunction isOriginAllowed(origin: string): boolean {\n // Development mode: allow any origin (must be explicitly enabled)\n if (allowAnyOrigin) {\n console.warn('[MINT SDK] postMessage origin validation disabled - only use in development')\n return true\n }\n\n // Same origin is always allowed\n if (origin === window.location.origin) {\n return true\n }\n\n // Check against allowed origins list\n return allowedOrigins.has(origin)\n}\n\n/**\n * Platform context composable for plugin integration with MINT Platform.\n *\n * Provides secure communication with the parent platform via postMessage.\n *\n * @param options - Configuration options\n * @param options.allowedOrigins - List of allowed origins for postMessage\n * @param options.allowAnyOrigin - Allow any origin (UNSAFE, development only)\n *\n * @example\n * ```typescript\n * // Basic usage - derives origin from platform injection\n * const { isIntegrated, user, theme } = usePlatformContext()\n *\n * // With explicit allowed origins\n * const { isIntegrated } = usePlatformContext({\n * allowedOrigins: ['https://mint.example.com']\n * })\n *\n * // Development mode (UNSAFE)\n * const { isIntegrated } = usePlatformContext({\n * allowAnyOrigin: import.meta.env.DEV\n * })\n * ```\n */\n/** Connects a plugin to the MINT platform via postMessage, exposing user, theme, and experiment context. */\nexport function usePlatformContext(options: PlatformContextOptions = {}) {\n const consumerId = ++nextConsumerId\n const instanceOrigins = normalizeAllowedOrigins(options.allowedOrigins)\n const instanceAllowAnyOrigin = options.allowAnyOrigin === true\n\n function detectPlatform(): void {\n const detectedOrigins = new Set<string>()\n\n // Check if running under MINT Platform by looking for platform-injected global\n const platformData = (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n\n if (platformData) {\n platformContext.value = {\n ...platformData,\n isIntegrated: true,\n }\n\n // Derive platform origin from injected data\n if (platformData.platformOrigin) {\n detectedOrigins.add(platformData.platformOrigin)\n } else if (platformData.platformApiUrl) {\n const origin = getOriginFromUrl(platformData.platformApiUrl)\n if (origin) {\n detectedOrigins.add(origin)\n }\n }\n } else {\n // Check for platform indicator in URL or localStorage\n const urlParams = new URLSearchParams(window.location.search)\n const hasPluginParam = urlParams.has('mint-plugin')\n\n // Try to get platform origin from URL parameter\n const platformOrigin = urlParams.get('mint-origin')\n if (platformOrigin) {\n const origin = getOriginFromUrl(platformOrigin)\n if (origin) {\n detectedOrigins.add(origin)\n }\n }\n\n platformContext.value = {\n isIntegrated: hasPluginParam,\n theme: (() => {\n try {\n const s = localStorage.getItem('mint-settings')\n if (s) return (JSON.parse(s).theme as 'light' | 'dark' | 'system') || 'system'\n } catch { /* ignore */ }\n return 'system'\n })(),\n platformOrigin: platformOrigin || undefined,\n }\n }\n\n inferredOrigins = detectedOrigins\n }\n\n function handlePlatformMessage(event: MessageEvent): void {\n // Only accept messages from parent window (platform)\n if (event.source !== window.parent) return\n\n // Validate origin for security\n if (!isOriginAllowed(event.origin)) {\n console.warn(`[MINT SDK] Rejected postMessage from untrusted origin: ${event.origin}`)\n return\n }\n\n try {\n const platformEvent = event.data as PlatformEvent\n if (!platformEvent.type?.startsWith('mint:')) return\n\n switch (platformEvent.type) {\n case 'mint:theme-changed':\n platformContext.value.theme = platformEvent.payload as 'light' | 'dark' | 'system'\n break\n case 'mint:user-changed':\n platformContext.value.user = platformEvent.payload as PlatformContext['user']\n break\n }\n } catch {\n // Ignore invalid messages\n }\n }\n\n /**\n * Send a message to the parent platform.\n * Uses validated target origin for security.\n */\n function sendToPlatform(event: PlatformEvent): void {\n if (!platformContext.value.isIntegrated || window.parent === window) {\n return\n }\n\n // Determine target origin\n let targetOrigin: string\n\n if (platformContext.value.platformOrigin) {\n // Use explicitly configured platform origin\n targetOrigin = platformContext.value.platformOrigin\n } else if (allowedOrigins.size > 0) {\n // Use first allowed origin (typically the platform)\n targetOrigin = allowedOrigins.values().next().value as string\n } else if (allowAnyOrigin) {\n // Development mode fallback\n targetOrigin = '*'\n console.warn('[MINT SDK] Using wildcard origin for postMessage - only use in development')\n } else {\n // Safety: if no origin is configured, log warning and don't send\n console.warn('[MINT SDK] Cannot send postMessage: no platform origin configured')\n return\n }\n\n window.parent.postMessage(event, targetOrigin)\n }\n\n /**\n * Request navigation to a path in the platform.\n */\n function navigate(path: string): void {\n sendToPlatform({\n type: 'mint:navigate',\n payload: path,\n })\n }\n\n /**\n * Show a notification in the platform.\n */\n function notify(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info'): void {\n sendToPlatform({\n type: 'mint:notification',\n payload: { message, type },\n })\n }\n\n onMounted(() => {\n consumerOrigins.set(consumerId, instanceOrigins)\n if (instanceAllowAnyOrigin) {\n allowAnyOriginConsumers.add(consumerId)\n }\n\n if (!initialized) {\n detectPlatform()\n currentHandler = handlePlatformMessage\n window.addEventListener('message', handlePlatformMessage)\n initialized = true\n }\n\n listenerCount++\n recomputeOriginPolicy()\n })\n\n onUnmounted(() => {\n consumerOrigins.delete(consumerId)\n allowAnyOriginConsumers.delete(consumerId)\n\n listenerCount = Math.max(0, listenerCount - 1)\n if (listenerCount === 0) {\n if (currentHandler) {\n window.removeEventListener('message', currentHandler)\n }\n resetPlatformContextState()\n return\n }\n\n recomputeOriginPolicy()\n })\n\n const isIntegrated = computed(() => platformContext.value.isIntegrated)\n const plugin = computed(() => platformContext.value.plugin)\n const user = computed(() => platformContext.value.user)\n const theme = computed(() => platformContext.value.theme)\n const features = computed(() => platformContext.value.features)\n\n return {\n context: platformContext,\n isIntegrated,\n plugin,\n user,\n theme,\n features,\n navigate,\n notify,\n sendToPlatform,\n }\n}\n","/**\n * Validation rule function type.\n * Returns error message string if invalid, undefined/null if valid.\n */\nexport type ValidationRule<T = unknown> = (value: T, formData: Record<string, unknown>) => string | undefined | null\n\n/**\n * Field validation rules configuration.\n */\nexport interface FieldRules<T = unknown> {\n required?: boolean | string\n minLength?: number | { value: number; message: string }\n maxLength?: number | { value: number; message: string }\n min?: number | { value: number; message: string }\n max?: number | { value: number; message: string }\n pattern?: RegExp | { value: RegExp; message: string }\n email?: boolean | string\n custom?: ValidationRule<T> | ValidationRule<T>[]\n}\n\nconst validators = {\n required: (value: unknown, message = 'This field is required'): string | null => {\n if (value === null || value === undefined || value === '') {\n return message\n }\n if (Array.isArray(value) && value.length === 0) {\n return message\n }\n return null\n },\n\n minLength: (value: unknown, min: number, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (value.length < min) {\n return message || `Must be at least ${min} characters`\n }\n return null\n },\n\n maxLength: (value: unknown, max: number, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (value.length > max) {\n return message || `Must be at most ${max} characters`\n }\n return null\n },\n\n min: (value: unknown, min: number, message?: string): string | null => {\n if (typeof value !== 'number') return null\n if (value < min) {\n return message || `Must be at least ${min}`\n }\n return null\n },\n\n max: (value: unknown, max: number, message?: string): string | null => {\n if (typeof value !== 'number') return null\n if (value > max) {\n return message || `Must be at most ${max}`\n }\n return null\n },\n\n pattern: (value: unknown, pattern: RegExp, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (!pattern.test(value)) {\n return message || 'Invalid format'\n }\n return null\n },\n\n email: (value: unknown, message = 'Invalid email address'): string | null => {\n if (typeof value !== 'string' || !value) return null\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(value)) {\n return message\n }\n return null\n },\n}\n\nexport function validateFieldValue(\n value: unknown,\n fieldRules: FieldRules | undefined,\n formData: Record<string, unknown>,\n): string | null {\n if (!fieldRules) return null\n\n if (fieldRules.required) {\n const message = typeof fieldRules.required === 'string' ? fieldRules.required : undefined\n const error = validators.required(value, message)\n if (error) return error\n }\n\n if (value === null || value === undefined || value === '') {\n return null\n }\n\n if (fieldRules.minLength !== undefined) {\n const config = typeof fieldRules.minLength === 'number'\n ? { value: fieldRules.minLength, message: undefined }\n : fieldRules.minLength\n const error = validators.minLength(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.maxLength !== undefined) {\n const config = typeof fieldRules.maxLength === 'number'\n ? { value: fieldRules.maxLength, message: undefined }\n : fieldRules.maxLength\n const error = validators.maxLength(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.min !== undefined) {\n const config = typeof fieldRules.min === 'number'\n ? { value: fieldRules.min, message: undefined }\n : fieldRules.min\n const error = validators.min(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.max !== undefined) {\n const config = typeof fieldRules.max === 'number'\n ? { value: fieldRules.max, message: undefined }\n : fieldRules.max\n const error = validators.max(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.pattern !== undefined) {\n const config = fieldRules.pattern instanceof RegExp\n ? { value: fieldRules.pattern, message: undefined }\n : fieldRules.pattern\n const error = validators.pattern(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.email) {\n const message = typeof fieldRules.email === 'string' ? fieldRules.email : undefined\n const error = validators.email(value, message)\n if (error) return error\n }\n\n if (fieldRules.custom) {\n const customRules = Array.isArray(fieldRules.custom) ? fieldRules.custom : [fieldRules.custom]\n for (const rule of customRules) {\n const error = rule(value, formData)\n if (error) return error\n }\n }\n\n return null\n}\n","import { ref, reactive, computed, toRaw, watch, type Ref } from 'vue'\nimport { validateFieldValue, type FieldRules } from './useFormValidation'\n\nexport type { FieldRules, ValidationRule } from './useFormValidation'\n\n/**\n * Field validation rules configuration.\n */\nexport interface FieldState {\n value: unknown\n error: string | null\n touched: boolean\n dirty: boolean\n}\n\n/**\n * Form state and methods.\n */\nexport interface UseFormReturn<T extends Record<string, unknown>> {\n // Form data (reactive)\n data: T\n\n // Field errors\n errors: Record<string, string | null>\n\n // Field touched state\n touched: Record<string, boolean>\n\n // Field dirty state (value changed from initial)\n dirty: Record<string, boolean>\n\n // Overall form state\n isValid: Ref<boolean>\n isDirty: Ref<boolean>\n isSubmitting: Ref<boolean>\n\n // Methods\n setFieldValue: <K extends keyof T>(field: K, value: T[K]) => void\n setFieldError: (field: string, error: string | null) => void\n setFieldTouched: (field: string, touched?: boolean) => void\n validateField: (field: string) => boolean\n validate: () => boolean\n reset: (values?: Partial<T>) => void\n /** Replace the full form state and treat the provided values as the new clean baseline. */\n replaceState: (values: T) => void\n handleSubmit: (onSubmit: (data: T) => Promise<void> | void) => (e?: Event) => Promise<void>\n getFieldProps: <K extends keyof T>(field: K) => {\n modelValue: T[K]\n 'onUpdate:modelValue': (value: T[K]) => void\n onBlur: () => void\n error: string | null\n }\n}\n\n/**\n * Form state management composable with validation.\n *\n * @param initialValues - Initial form values\n * @param rules - Validation rules for each field\n *\n * @example\n * ```typescript\n * const { data, errors, isValid, handleSubmit, getFieldProps } = useForm(\n * { email: '', password: '' },\n * {\n * email: { required: true, email: true },\n * password: { required: true, minLength: 8 },\n * }\n * )\n *\n * // In template\n * <BaseInput v-bind=\"getFieldProps('email')\" label=\"Email\" />\n * <BaseInput v-bind=\"getFieldProps('password')\" type=\"password\" label=\"Password\" />\n * <BaseButton @click=\"handleSubmit(onSubmit)\" :disabled=\"!isValid\">Submit</BaseButton>\n * ```\n */\n/** Reactive form state with field-level validation, dirty tracking, and submit handling. */\nexport function useForm<T extends Record<string, unknown>>(\n initialValues: T,\n rules: Partial<Record<keyof T, FieldRules>> = {}\n): UseFormReturn<T> {\n const cloneableInitialValues = deepToRaw(initialValues) as T\n\n // Deep copy initial values so nested objects are not shared\n let _initialValues = structuredClone(cloneableInitialValues)\n\n // Reactive form data\n const data = reactive(structuredClone(cloneableInitialValues)) as T\n\n // Field state - use simple Record types for better TS compatibility\n const errors = reactive<Record<string, string | null>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = null\n return acc\n }, {} as Record<string, string | null>)\n )\n\n const touched = reactive<Record<string, boolean>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = false\n return acc\n }, {} as Record<string, boolean>)\n )\n\n const dirty = reactive<Record<string, boolean>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = false\n return acc\n }, {} as Record<string, boolean>)\n )\n\n const isSubmitting = ref(false)\n\n // Watch data changes to track dirty state\n watch(\n () => ({ ...data }),\n (newData) => {\n for (const key of Object.keys(newData)) {\n dirty[key] = newData[key as keyof T] !== _initialValues[key as keyof T]\n }\n },\n { deep: true }\n )\n\n // Validate a single field\n function validateField(field: string): boolean {\n const value = data[field as keyof T]\n const fieldRules = rules[field as keyof T]\n const error = validateFieldValue(value, fieldRules, data as Record<string, unknown>)\n errors[field] = error\n return error === null\n }\n\n // Validate all fields\n function validate(): boolean {\n let isAllValid = true\n for (const field of Object.keys(data)) {\n if (!validateField(field)) {\n isAllValid = false\n }\n }\n return isAllValid\n }\n\n // Computed overall validity\n const isValid = computed(() => {\n return Object.values(errors).every(error => error === null)\n })\n\n // Computed overall dirty state\n const isDirty = computed(() => {\n return Object.values(dirty).some(d => d)\n })\n\n // Set field value\n function setFieldValue<K extends keyof T>(field: K, value: T[K]): void {\n ;(data as Record<string, unknown>)[field as string] = value\n if (touched[field as string]) {\n validateField(field as string)\n }\n }\n\n // Set field error\n function setFieldError(field: string, error: string | null): void {\n errors[field] = error\n }\n\n // Set field touched\n function setFieldTouched(field: string, isTouched = true): void {\n touched[field] = isTouched\n if (isTouched) {\n validateField(field)\n }\n }\n\n // Reset form\n function reset(values?: Partial<T>): void {\n const resetValues = values ? { ..._initialValues, ...values } : _initialValues\n for (const key of Object.keys(data)) {\n ;(data as Record<string, unknown>)[key] = structuredClone(deepToRaw(resetValues[key as keyof T]))\n errors[key] = null\n touched[key] = false\n dirty[key] = false\n }\n }\n\n function replaceState(values: T): void {\n const nextValues = structuredClone(deepToRaw(values)) as T\n _initialValues = structuredClone(nextValues)\n\n for (const key of Object.keys(data)) {\n if (key in nextValues) continue\n delete (data as Record<string, unknown>)[key]\n delete errors[key]\n delete touched[key]\n delete dirty[key]\n }\n\n for (const key of Object.keys(nextValues)) {\n ;(data as Record<string, unknown>)[key] = structuredClone(deepToRaw(nextValues[key as keyof T]))\n errors[key] = null\n touched[key] = false\n dirty[key] = false\n }\n }\n\n // Handle submit\n function handleSubmit(onSubmit: (data: T) => Promise<void> | void) {\n return async (e?: Event): Promise<void> => {\n e?.preventDefault()\n\n // Mark all fields as touched\n for (const field of Object.keys(data)) {\n touched[field] = true\n }\n\n if (!validate()) {\n return\n }\n\n isSubmitting.value = true\n try {\n await onSubmit(data)\n } finally {\n isSubmitting.value = false\n }\n }\n }\n\n // Get props for a field (for v-bind)\n function getFieldProps<K extends keyof T>(field: K) {\n const fieldStr = field as string\n return {\n modelValue: data[field],\n 'onUpdate:modelValue': (value: T[K]) => setFieldValue(field, value),\n onBlur: () => setFieldTouched(fieldStr),\n error: touched[fieldStr] ? errors[fieldStr] : null,\n }\n }\n\n return {\n data,\n errors,\n touched,\n dirty,\n isValid,\n isDirty,\n isSubmitting,\n setFieldValue,\n setFieldError,\n setFieldTouched,\n validateField,\n validate,\n reset,\n replaceState,\n handleSubmit,\n getFieldProps,\n }\n}\n\nfunction deepToRaw(value: unknown): unknown {\n const raw = toRaw(value)\n\n if (Array.isArray(raw)) {\n return raw.map(item => deepToRaw(item))\n }\n\n if (isPlainRecord(raw)) {\n return Object.fromEntries(\n Object.entries(raw).map(([key, item]) => [key, deepToRaw(item)])\n )\n }\n\n return raw\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]'\n}\n","import { getTypeDefault } from './formBuilderRegistry'\nimport type { FieldRules } from './useForm'\nimport type {\n FieldCondition,\n FieldValidation,\n FormEnhancements,\n FormFieldSchema,\n FormSchema,\n FormSectionSchema,\n} from '../types/form-builder'\n\n/**\n * Evaluate a JSON-serializable field condition against the current form data.\n *\n * Supports logical operators (`and`, `or`, `not`) and comparison operators\n * (`eq`, `neq`, `gt`, `lt`, `gte`, `lte`, `in`, `notIn`, `truthy`, `falsy`,\n * `contains`). Returns `true` if the condition passes.\n */\nexport function evaluateCondition(\n condition: FieldCondition,\n data: Record<string, unknown>,\n): boolean {\n if ('and' in condition) {\n return condition.and.every((c) => evaluateCondition(c, data))\n }\n if ('or' in condition) {\n return condition.or.some((c) => evaluateCondition(c, data))\n }\n if ('not' in condition) {\n return !evaluateCondition(condition.not, data)\n }\n\n const value = data[condition.field]\n\n if ('eq' in condition) return value === condition.eq\n if ('neq' in condition) return value !== condition.neq\n if ('gt' in condition) return typeof value === 'number' && value > condition.gt\n if ('lt' in condition) return typeof value === 'number' && value < condition.lt\n if ('gte' in condition) return typeof value === 'number' && value >= condition.gte\n if ('lte' in condition) return typeof value === 'number' && value <= condition.lte\n if ('in' in condition) return condition.in.includes(value)\n if ('notIn' in condition) return !condition.notIn.includes(value)\n if ('truthy' in condition) return !!value\n if ('falsy' in condition) return !value\n if ('contains' in condition) {\n if (typeof value === 'string') return value.includes(condition.contains)\n if (Array.isArray(value)) return value.includes(condition.contains)\n return false\n }\n\n return true\n}\n\n/** Return all sections across steps (wizard) or directly from a flat schema. */\nexport function collectSections(schema: FormSchema): FormSectionSchema[] {\n return schema.steps ? schema.steps.flatMap((step) => step.sections) : schema.sections\n}\n\n/** Return all field schemas in schema order, flattening sections and steps. */\nexport function flattenFields(schema: FormSchema): FormFieldSchema[] {\n return collectSections(schema).flatMap((section) => section.fields)\n}\n\n/** Convert a JSON-safe `FieldValidation` descriptor to a runtime `FieldRules` object. */\nfunction convertValidation(v: FieldValidation): FieldRules {\n const rules: FieldRules = {}\n\n if (v.required !== undefined) rules.required = v.required\n if (v.minLength !== undefined) rules.minLength = v.minLength\n if (v.maxLength !== undefined) rules.maxLength = v.maxLength\n if (v.min !== undefined) rules.min = v.min\n if (v.max !== undefined) rules.max = v.max\n if (v.email !== undefined) rules.email = v.email\n\n if (v.pattern !== undefined) {\n rules.pattern =\n typeof v.pattern === 'string'\n ? new RegExp(v.pattern)\n : { value: new RegExp(v.pattern.value), message: v.pattern.message }\n }\n\n return rules\n}\n\nexport function buildInitialValues<T extends Record<string, unknown>>(\n fields: readonly FormFieldSchema[],\n initialData?: Partial<T>,\n): Record<string, unknown> {\n const initialValues = {} as Record<string, unknown>\n\n for (const field of fields) {\n const key = field.name\n if (initialData && hasOwnKey(initialData, key)) {\n initialValues[key] = (initialData as Record<string, unknown>)[key]\n } else if (field.defaultValue !== undefined) {\n initialValues[key] = field.defaultValue\n } else {\n initialValues[key] = getTypeDefault(field.type)\n }\n }\n\n return initialValues\n}\n\nexport function buildRules<T extends Record<string, unknown>>(\n fields: readonly FormFieldSchema[],\n enhancements?: FormEnhancements<T>,\n): Partial<Record<string, FieldRules>> {\n const rules: Partial<Record<string, FieldRules>> = {}\n\n for (const field of fields) {\n const base: FieldRules = field.validation ? convertValidation(field.validation) : {}\n const enhancement = enhancements?.fields?.[field.name as keyof T]\n\n const customValidators: Array<(\n value: unknown,\n formData: Record<string, unknown>,\n ) => string | undefined | null> = []\n\n if (enhancement?.validate) {\n const fn = enhancement.validate\n customValidators.push((value, formData) => fn(value, formData as T))\n }\n\n if (customValidators.length > 0) {\n base.custom = customValidators\n }\n\n if (Object.keys(base).length > 0) {\n rules[field.name] = base\n }\n }\n\n return rules\n}\n\nexport function replaceArray<T>(target: T[], values: readonly T[]): void {\n target.splice(0, target.length, ...values)\n}\n\nexport function replaceRecord<TValue>(\n target: Partial<Record<string, TValue>>,\n source: Partial<Record<string, TValue>>,\n): void {\n for (const key of Object.keys(target)) {\n delete target[key]\n }\n Object.assign(target, source)\n}\n\nfunction hasOwnKey(source: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(source, key)\n}\n","import { reactive, ref, computed, shallowRef, watch } from 'vue'\nimport { useForm, type FieldRules, type UseFormReturn } from './useForm'\nimport { getFieldRegistryEntry } from './formBuilderRegistry'\nimport {\n buildInitialValues,\n buildRules,\n collectSections,\n evaluateCondition,\n flattenFields,\n replaceArray,\n replaceRecord,\n} from './formBuilderSchema'\nimport type {\n FormSchema,\n FormFieldSchema,\n FormSectionSchema,\n FormOptionInput,\n FormEnhancements,\n UseFormBuilderReturn,\n} from '../types/form-builder'\n\nexport { evaluateCondition } from './formBuilderSchema'\n\n// ---------------------------------------------------------------------------\n// useFormBuilder\n// ---------------------------------------------------------------------------\n\n/**\n * Drive a `FormSchema` as reactive form state.\n *\n * Builds initial values from schema defaults and `initialData`, derives\n * validation rules from `FieldValidation` descriptors and enhancement\n * validators, evaluates `FieldCondition` expressions for field/section\n * visibility, and wires wizard step navigation when `schema.steps` is set.\n *\n * @param schema - Declarative form or wizard schema.\n * @param initialData - Values that override schema defaults.\n * @param enhancements - TypeScript-only callbacks (dynamic options, validators,\n * submit handler, transform, field-change watcher).\n */\n/** Drives a declarative FormSchema as reactive state with conditional fields, wizard steps, and validation. */\nexport function useFormBuilder<T extends Record<string, unknown> = Record<string, unknown>>(\n schema: FormSchema,\n initialData?: Partial<T>,\n enhancements?: FormEnhancements<T>,\n): UseFormBuilderReturn<T> {\n const currentSchema = shallowRef(schema)\n const fields = reactive<FormFieldSchema[]>(flattenFields(schema))\n const sections = reactive<FormSectionSchema[]>(collectSections(schema))\n const rules = reactive<Partial<Record<string, FieldRules>>>(buildRules(fields, enhancements))\n\n // -- Create form -----------------------------------------------------------\n const form = useForm(\n buildInitialValues<T>(fields, initialData) as T,\n rules as Partial<Record<keyof T, FieldRules>>,\n )\n\n // -- Visibility ------------------------------------------------------------\n function isFieldVisible(name: string): boolean {\n const enhancement = enhancements?.fields?.[name as keyof T]\n if (enhancement?.visible) {\n return enhancement.visible(form.data as T)\n }\n\n const field = fields.find((f) => f.name === name)\n if (field?.condition) {\n return evaluateCondition(field.condition, form.data as Record<string, unknown>)\n }\n\n return true\n }\n\n function isSectionVisible(id: string): boolean {\n const section = sections.find((s) => s.id === id)\n if (section?.condition) {\n return evaluateCondition(section.condition, form.data as Record<string, unknown>)\n }\n return true\n }\n\n // -- Resolved field props --------------------------------------------------\n function getResolvedFieldProps(field: FormFieldSchema): Record<string, unknown> {\n const entry = getFieldRegistryEntry(field.type)\n const formProps = form.getFieldProps(field.name as keyof T)\n\n const merged: Record<string, unknown> = {\n ...entry.defaults,\n ...(field.props ?? {}),\n }\n\n // Dynamic enhancement props\n const enhancement = enhancements?.fields?.[field.name as keyof T]\n if (enhancement?.props) {\n Object.assign(merged, enhancement.props(form.data as T))\n }\n\n // Dynamic options\n const options = getFieldOptions(field.name)\n if (options) {\n merged.options = options\n }\n\n // Form field bindings\n if (entry.vModel) {\n merged.modelValue = formProps.modelValue\n merged['onUpdate:modelValue'] = formProps['onUpdate:modelValue']\n }\n merged.onBlur = formProps.onBlur\n\n // Error as boolean for components that use boolean error prop\n const errorMsg = formProps.error\n if (errorMsg) {\n merged.error = true\n }\n\n // Schema-level props\n if (field.placeholder) merged.placeholder = field.placeholder\n if (field.size) merged.size = field.size\n if (field.disabled) merged.disabled = true\n if (field.readonly) merged.readonly = true\n\n // Radio group needs a name prop\n if (field.type === 'radio' && !merged.name) {\n merged.name = field.name\n }\n\n return merged\n }\n\n function getFieldOptions(name: string): FormOptionInput[] | undefined {\n const enhancement = enhancements?.fields?.[name as keyof T]\n if (enhancement?.options) {\n return enhancement.options(form.data as T)\n }\n\n const field = fields.find((f) => f.name === name)\n if (field?.props?.options) {\n return field.props.options as FormOptionInput[]\n }\n\n return undefined\n }\n\n // -- Wizard state ----------------------------------------------------------\n const currentStep = ref(0)\n\n const isCurrentStepValid = computed(() => {\n if (!currentSchema.value.steps) return form.isValid.value\n\n const step = currentSchema.value.steps[currentStep.value]\n if (!step) return true\n\n for (const section of step.sections) {\n if (!isSectionVisible(section.id)) continue\n for (const field of section.fields) {\n if (!isFieldVisible(field.name)) continue\n if (!form.validateField(field.name)) return false\n }\n }\n return true\n })\n\n function goNext(): boolean {\n if (!currentSchema.value.steps) return false\n\n // Touch and validate all visible fields in current step\n const step = currentSchema.value.steps[currentStep.value]\n if (!step) return false\n\n let valid = true\n for (const section of step.sections) {\n if (!isSectionVisible(section.id)) continue\n for (const field of section.fields) {\n if (!isFieldVisible(field.name)) continue\n form.setFieldTouched(field.name, true)\n if (!form.validateField(field.name)) valid = false\n }\n }\n\n if (!valid) return false\n\n if (currentStep.value < currentSchema.value.steps.length - 1) {\n currentStep.value++\n }\n return true\n }\n\n function goBack(): void {\n if (currentStep.value > 0) {\n currentStep.value--\n }\n }\n\n function goToStep(index: number): void {\n if (!currentSchema.value.steps) return\n if (index >= 0 && index < currentSchema.value.steps.length) {\n currentStep.value = index\n }\n }\n\n // -- Validate (skip hidden fields) -----------------------------------------\n function validate(): boolean {\n let allValid = true\n for (const field of fields) {\n if (!isFieldVisible(field.name)) continue\n form.setFieldTouched(field.name, true)\n if (!form.validateField(field.name)) {\n allValid = false\n }\n }\n return allValid\n }\n\n // -- Submit ----------------------------------------------------------------\n async function submit(): Promise<void> {\n if (!validate()) return\n\n // Build submission data excluding hidden fields\n let submitData = {} as Record<string, unknown>\n for (const field of fields) {\n if (isFieldVisible(field.name)) {\n submitData[field.name] = (form.data as Record<string, unknown>)[field.name]\n }\n }\n\n if (enhancements?.transform) {\n submitData = enhancements.transform(submitData as T) as Record<string, unknown>\n }\n\n if (enhancements?.onSubmit) {\n form.isSubmitting.value = true\n try {\n await enhancements.onSubmit(submitData as T)\n } finally {\n form.isSubmitting.value = false\n }\n }\n }\n\n // -- Reset -----------------------------------------------------------------\n function reset(values?: Partial<T>): void {\n form.reset(values)\n currentStep.value = 0\n }\n\n function updateSchema(nextSchema: FormSchema, nextData?: Partial<T>): void {\n currentSchema.value = nextSchema\n\n const nextFields = flattenFields(nextSchema)\n replaceArray(fields, nextFields)\n replaceArray(sections, collectSections(nextSchema))\n replaceRecord(rules, buildRules(nextFields, enhancements))\n form.replaceState(buildInitialValues<T>(nextFields, nextData) as T)\n currentStep.value = 0\n }\n\n // -- onFieldChange wiring --------------------------------------------------\n if (enhancements?.onFieldChange) {\n const callback = enhancements.onFieldChange\n watch(\n () => ({ ...(form.data as Record<string, unknown>) }),\n (newData, oldData) => {\n if (!oldData) return\n for (const key of Object.keys(newData)) {\n if (newData[key] !== oldData[key]) {\n callback(key as keyof T, newData[key], newData as T)\n }\n }\n },\n { deep: true },\n )\n }\n\n return {\n form: form as UseFormReturn<T>,\n rules: rules as Partial<Record<keyof T, FieldRules>>,\n isFieldVisible,\n isSectionVisible,\n fields,\n getResolvedFieldProps,\n getFieldOptions,\n currentStep,\n isCurrentStepValid,\n goNext,\n goBack,\n goToStep,\n validate,\n reset,\n submit,\n updateSchema,\n }\n}\n"],"mappings":";;;AAGA,IAAM,kBAAmC;CACvC,cAAc;CACd,OAAO;CACR;AAED,IAAM,kBAAkB,IAAqB,EAAE,GAAG,iBAAiB,CAAC;AAKpE,IAAI,kCAA+B,IAAI,KAAK;AAC5C,IAAI,iCAA8B,IAAI,KAAK;AAC3C,IAAI,iBAAiB;AACrB,IAAI,cAAc;AAClB,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AACrB,IAAI,iBAAyD;AAC7D,IAAM,kCAA4C,IAAI,KAAK;AAC3D,IAAM,0CAAuC,IAAI,KAAK;;;;AAKtD,SAAS,iBAAiB,KAA4B;AACpD,KAAI;AAEF,SADe,IAAI,IAAI,IAAI,CACb;SACR;AACN,SAAO;;;AAIX,SAAS,wBAAwB,SAA4C;CAC3E,MAAM,6BAAa,IAAI,KAAa;AACpC,KAAI,CAAC,QACH,QAAO;AAGT,MAAK,MAAM,UAAU,QACnB,YAAW,IAAI,iBAAiB,OAAO,IAAI,OAAO;AAEpD,QAAO;;AAGT,SAAS,wBAA8B;AACrC,kBAAiB,IAAI,IAAI,gBAAgB;AACzC,MAAK,MAAM,WAAW,gBAAgB,QAAQ,CAC5C,MAAK,MAAM,UAAU,QACnB,gBAAe,IAAI,OAAO;AAG9B,kBAAiB,wBAAwB,OAAO;;AAGlD,SAAS,4BAAkC;AACzC,mCAAkB,IAAI,KAAK;AAC3B,kCAAiB,IAAI,KAAK;AAC1B,kBAAiB;AACjB,eAAc;AACd,iBAAgB;AAChB,kBAAiB;AACjB,iBAAgB,OAAO;AACvB,yBAAwB,OAAO;AAC/B,iBAAgB,QAAQ,EAAE,GAAG,iBAAiB;;;;;AAMhD,SAAS,gBAAgB,QAAyB;AAEhD,KAAI,gBAAgB;AAClB,UAAQ,KAAK,8EAA8E;AAC3F,SAAO;;AAIT,KAAI,WAAW,OAAO,SAAS,OAC7B,QAAO;AAIT,QAAO,eAAe,IAAI,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BnC,SAAgB,mBAAmB,UAAkC,EAAE,EAAE;CACvE,MAAM,aAAa,EAAE;CACrB,MAAM,kBAAkB,wBAAwB,QAAQ,eAAe;CACvE,MAAM,yBAAyB,QAAQ,mBAAmB;CAE1D,SAAS,iBAAuB;EAC9B,MAAM,kCAAkB,IAAI,KAAa;EAGzC,MAAM,eAAgB,OAA8D;AAEpF,MAAI,cAAc;AAChB,mBAAgB,QAAQ;IACtB,GAAG;IACH,cAAc;IACf;AAGD,OAAI,aAAa,eACf,iBAAgB,IAAI,aAAa,eAAe;YACvC,aAAa,gBAAgB;IACtC,MAAM,SAAS,iBAAiB,aAAa,eAAe;AAC5D,QAAI,OACF,iBAAgB,IAAI,OAAO;;SAG1B;GAEL,MAAM,YAAY,IAAI,gBAAgB,OAAO,SAAS,OAAO;GAC7D,MAAM,iBAAiB,UAAU,IAAI,cAAc;GAGnD,MAAM,iBAAiB,UAAU,IAAI,cAAc;AACnD,OAAI,gBAAgB;IAClB,MAAM,SAAS,iBAAiB,eAAe;AAC/C,QAAI,OACF,iBAAgB,IAAI,OAAO;;AAI/B,mBAAgB,QAAQ;IACtB,cAAc;IACd,cAAc;AACZ,SAAI;MACF,MAAM,IAAI,aAAa,QAAQ,gBAAgB;AAC/C,UAAI,EAAG,QAAQ,KAAK,MAAM,EAAE,CAAC,SAAyC;aAChE;AACR,YAAO;QACL;IACJ,gBAAgB,kBAAkB,KAAA;IACnC;;AAGH,oBAAkB;;CAGpB,SAAS,sBAAsB,OAA2B;AAExD,MAAI,MAAM,WAAW,OAAO,OAAQ;AAGpC,MAAI,CAAC,gBAAgB,MAAM,OAAO,EAAE;AAClC,WAAQ,KAAK,0DAA0D,MAAM,SAAS;AACtF;;AAGF,MAAI;GACF,MAAM,gBAAgB,MAAM;AAC5B,OAAI,CAAC,cAAc,MAAM,WAAW,QAAQ,CAAE;AAE9C,WAAQ,cAAc,MAAtB;IACE,KAAK;AACH,qBAAgB,MAAM,QAAQ,cAAc;AAC5C;IACF,KAAK;AACH,qBAAgB,MAAM,OAAO,cAAc;AAC3C;;UAEE;;;;;;CASV,SAAS,eAAe,OAA4B;AAClD,MAAI,CAAC,gBAAgB,MAAM,gBAAgB,OAAO,WAAW,OAC3D;EAIF,IAAI;AAEJ,MAAI,gBAAgB,MAAM,eAExB,gBAAe,gBAAgB,MAAM;WAC5B,eAAe,OAAO,EAE/B,gBAAe,eAAe,QAAQ,CAAC,MAAM,CAAC;WACrC,gBAAgB;AAEzB,kBAAe;AACf,WAAQ,KAAK,6EAA6E;SACrF;AAEL,WAAQ,KAAK,oEAAoE;AACjF;;AAGF,SAAO,OAAO,YAAY,OAAO,aAAa;;;;;CAMhD,SAAS,SAAS,MAAoB;AACpC,iBAAe;GACb,MAAM;GACN,SAAS;GACV,CAAC;;;;;CAMJ,SAAS,OAAO,SAAiB,OAAiD,QAAc;AAC9F,iBAAe;GACb,MAAM;GACN,SAAS;IAAE;IAAS;IAAM;GAC3B,CAAC;;AAGJ,iBAAgB;AACd,kBAAgB,IAAI,YAAY,gBAAgB;AAChD,MAAI,uBACF,yBAAwB,IAAI,WAAW;AAGzC,MAAI,CAAC,aAAa;AAChB,mBAAgB;AAChB,oBAAiB;AACjB,UAAO,iBAAiB,WAAW,sBAAsB;AACzD,iBAAc;;AAGhB;AACA,yBAAuB;GACvB;AAEF,mBAAkB;AAChB,kBAAgB,OAAO,WAAW;AAClC,0BAAwB,OAAO,WAAW;AAE1C,kBAAgB,KAAK,IAAI,GAAG,gBAAgB,EAAE;AAC9C,MAAI,kBAAkB,GAAG;AACvB,OAAI,eACF,QAAO,oBAAoB,WAAW,eAAe;AAEvD,8BAA2B;AAC3B;;AAGF,yBAAuB;GACvB;AAQF,QAAO;EACL,SAAS;EACT,cARmB,eAAe,gBAAgB,MAAM,aAAa;EASrE,QARa,eAAe,gBAAgB,MAAM,OAAO;EASzD,MARW,eAAe,gBAAgB,MAAM,KAAK;EASrD,OARY,eAAe,gBAAgB,MAAM,MAAM;EASvD,UARe,eAAe,gBAAgB,MAAM,SAAS;EAS7D;EACA;EACA;EACD;;;;ACrRH,IAAM,aAAa;CACjB,WAAW,OAAgB,UAAU,6BAA4C;AAC/E,MAAI,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU,GACrD,QAAO;AAET,MAAI,MAAM,QAAQ,MAAM,IAAI,MAAM,WAAW,EAC3C,QAAO;AAET,SAAO;;CAGT,YAAY,OAAgB,KAAa,YAAoC;AAC3E,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,MAAM,SAAS,IACjB,QAAO,WAAW,oBAAoB,IAAI;AAE5C,SAAO;;CAGT,YAAY,OAAgB,KAAa,YAAoC;AAC3E,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,MAAM,SAAS,IACjB,QAAO,WAAW,mBAAmB,IAAI;AAE3C,SAAO;;CAGT,MAAM,OAAgB,KAAa,YAAoC;AACrE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,QAAQ,IACV,QAAO,WAAW,oBAAoB;AAExC,SAAO;;CAGT,MAAM,OAAgB,KAAa,YAAoC;AACrE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,QAAQ,IACV,QAAO,WAAW,mBAAmB;AAEvC,SAAO;;CAGT,UAAU,OAAgB,SAAiB,YAAoC;AAC7E,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,CAAC,QAAQ,KAAK,MAAM,CACtB,QAAO,WAAW;AAEpB,SAAO;;CAGT,QAAQ,OAAgB,UAAU,4BAA2C;AAC3E,MAAI,OAAO,UAAU,YAAY,CAAC,MAAO,QAAO;AAEhD,MAAI,CADe,6BACH,KAAK,MAAM,CACzB,QAAO;AAET,SAAO;;CAEV;AAED,SAAgB,mBACd,OACA,YACA,UACe;AACf,KAAI,CAAC,WAAY,QAAO;AAExB,KAAI,WAAW,UAAU;EACvB,MAAM,UAAU,OAAO,WAAW,aAAa,WAAW,WAAW,WAAW,KAAA;EAChF,MAAM,QAAQ,WAAW,SAAS,OAAO,QAAQ;AACjD,MAAI,MAAO,QAAO;;AAGpB,KAAI,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU,GACrD,QAAO;AAGT,KAAI,WAAW,cAAc,KAAA,GAAW;EACtC,MAAM,SAAS,OAAO,WAAW,cAAc,WAC3C;GAAE,OAAO,WAAW;GAAW,SAAS,KAAA;GAAW,GACnD,WAAW;EACf,MAAM,QAAQ,WAAW,UAAU,OAAO,OAAO,OAAO,OAAO,QAAQ;AACvE,MAAI,MAAO,QAAO;;AAGpB,KAAI,WAAW,cAAc,KAAA,GAAW;EACtC,MAAM,SAAS,OAAO,WAAW,cAAc,WAC3C;GAAE,OAAO,WAAW;GAAW,SAAS,KAAA;GAAW,GACnD,WAAW;EACf,MAAM,QAAQ,WAAW,UAAU,OAAO,OAAO,OAAO,OAAO,QAAQ;AACvE,MAAI,MAAO,QAAO;;AAGpB,KAAI,WAAW,QAAQ,KAAA,GAAW;EAChC,MAAM,SAAS,OAAO,WAAW,QAAQ,WACrC;GAAE,OAAO,WAAW;GAAK,SAAS,KAAA;GAAW,GAC7C,WAAW;EACf,MAAM,QAAQ,WAAW,IAAI,OAAO,OAAO,OAAO,OAAO,QAAQ;AACjE,MAAI,MAAO,QAAO;;AAGpB,KAAI,WAAW,QAAQ,KAAA,GAAW;EAChC,MAAM,SAAS,OAAO,WAAW,QAAQ,WACrC;GAAE,OAAO,WAAW;GAAK,SAAS,KAAA;GAAW,GAC7C,WAAW;EACf,MAAM,QAAQ,WAAW,IAAI,OAAO,OAAO,OAAO,OAAO,QAAQ;AACjE,MAAI,MAAO,QAAO;;AAGpB,KAAI,WAAW,YAAY,KAAA,GAAW;EACpC,MAAM,SAAS,WAAW,mBAAmB,SACzC;GAAE,OAAO,WAAW;GAAS,SAAS,KAAA;GAAW,GACjD,WAAW;EACf,MAAM,QAAQ,WAAW,QAAQ,OAAO,OAAO,OAAO,OAAO,QAAQ;AACrE,MAAI,MAAO,QAAO;;AAGpB,KAAI,WAAW,OAAO;EACpB,MAAM,UAAU,OAAO,WAAW,UAAU,WAAW,WAAW,QAAQ,KAAA;EAC1E,MAAM,QAAQ,WAAW,MAAM,OAAO,QAAQ;AAC9C,MAAI,MAAO,QAAO;;AAGpB,KAAI,WAAW,QAAQ;EACrB,MAAM,cAAc,MAAM,QAAQ,WAAW,OAAO,GAAG,WAAW,SAAS,CAAC,WAAW,OAAO;AAC9F,OAAK,MAAM,QAAQ,aAAa;GAC9B,MAAM,QAAQ,KAAK,OAAO,SAAS;AACnC,OAAI,MAAO,QAAO;;;AAItB,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3ET,SAAgB,QACd,eACA,QAA8C,EAAE,EAC9B;CAClB,MAAM,yBAAyB,UAAU,cAAc;CAGvD,IAAI,iBAAiB,gBAAgB,uBAAuB;CAG5D,MAAM,OAAO,SAAS,gBAAgB,uBAAuB,CAAC;CAG9D,MAAM,SAAS,SACb,OAAO,KAAK,cAAc,CAAC,QAAQ,KAAK,QAAQ;AAC9C,MAAI,OAAO;AACX,SAAO;IACN,EAAE,CAAkC,CACxC;CAED,MAAM,UAAU,SACd,OAAO,KAAK,cAAc,CAAC,QAAQ,KAAK,QAAQ;AAC9C,MAAI,OAAO;AACX,SAAO;IACN,EAAE,CAA4B,CAClC;CAED,MAAM,QAAQ,SACZ,OAAO,KAAK,cAAc,CAAC,QAAQ,KAAK,QAAQ;AAC9C,MAAI,OAAO;AACX,SAAO;IACN,EAAE,CAA4B,CAClC;CAED,MAAM,eAAe,IAAI,MAAM;AAG/B,cACS,EAAE,GAAG,MAAM,IACjB,YAAY;AACX,OAAK,MAAM,OAAO,OAAO,KAAK,QAAQ,CACpC,OAAM,OAAO,QAAQ,SAAoB,eAAe;IAG5D,EAAE,MAAM,MAAM,CACf;CAGD,SAAS,cAAc,OAAwB;EAC7C,MAAM,QAAQ,KAAK;EACnB,MAAM,aAAa,MAAM;EACzB,MAAM,QAAQ,mBAAmB,OAAO,YAAY,KAAgC;AACpF,SAAO,SAAS;AAChB,SAAO,UAAU;;CAInB,SAAS,WAAoB;EAC3B,IAAI,aAAa;AACjB,OAAK,MAAM,SAAS,OAAO,KAAK,KAAK,CACnC,KAAI,CAAC,cAAc,MAAM,CACvB,cAAa;AAGjB,SAAO;;CAIT,MAAM,UAAU,eAAe;AAC7B,SAAO,OAAO,OAAO,OAAO,CAAC,OAAM,UAAS,UAAU,KAAK;GAC3D;CAGF,MAAM,UAAU,eAAe;AAC7B,SAAO,OAAO,OAAO,MAAM,CAAC,MAAK,MAAK,EAAE;GACxC;CAGF,SAAS,cAAiC,OAAU,OAAmB;AACnE,OAAiC,SAAmB;AACtD,MAAI,QAAQ,OACV,eAAc,MAAgB;;CAKlC,SAAS,cAAc,OAAe,OAA4B;AAChE,SAAO,SAAS;;CAIlB,SAAS,gBAAgB,OAAe,YAAY,MAAY;AAC9D,UAAQ,SAAS;AACjB,MAAI,UACF,eAAc,MAAM;;CAKxB,SAAS,MAAM,QAA2B;EACxC,MAAM,cAAc,SAAS;GAAE,GAAG;GAAgB,GAAG;GAAQ,GAAG;AAChE,OAAK,MAAM,OAAO,OAAO,KAAK,KAAK,EAAE;AACjC,QAAiC,OAAO,gBAAgB,UAAU,YAAY,KAAgB,CAAC;AACjG,UAAO,OAAO;AACd,WAAQ,OAAO;AACf,SAAM,OAAO;;;CAIjB,SAAS,aAAa,QAAiB;EACrC,MAAM,aAAa,gBAAgB,UAAU,OAAO,CAAC;AACrD,mBAAiB,gBAAgB,WAAW;AAE5C,OAAK,MAAM,OAAO,OAAO,KAAK,KAAK,EAAE;AACnC,OAAI,OAAO,WAAY;AACvB,UAAQ,KAAiC;AACzC,UAAO,OAAO;AACd,UAAO,QAAQ;AACf,UAAO,MAAM;;AAGf,OAAK,MAAM,OAAO,OAAO,KAAK,WAAW,EAAE;AACvC,QAAiC,OAAO,gBAAgB,UAAU,WAAW,KAAgB,CAAC;AAChG,UAAO,OAAO;AACd,WAAQ,OAAO;AACf,SAAM,OAAO;;;CAKjB,SAAS,aAAa,UAA6C;AACjE,SAAO,OAAO,MAA6B;AACzC,MAAG,gBAAgB;AAGnB,QAAK,MAAM,SAAS,OAAO,KAAK,KAAK,CACnC,SAAQ,SAAS;AAGnB,OAAI,CAAC,UAAU,CACb;AAGF,gBAAa,QAAQ;AACrB,OAAI;AACF,UAAM,SAAS,KAAK;aACZ;AACR,iBAAa,QAAQ;;;;CAM3B,SAAS,cAAiC,OAAU;EAClD,MAAM,WAAW;AACjB,SAAO;GACL,YAAY,KAAK;GACjB,wBAAwB,UAAgB,cAAc,OAAO,MAAM;GACnE,cAAc,gBAAgB,SAAS;GACvC,OAAO,QAAQ,YAAY,OAAO,YAAY;GAC/C;;AAGH,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;AAGH,SAAS,UAAU,OAAyB;CAC1C,MAAM,MAAM,MAAM,MAAM;AAExB,KAAI,MAAM,QAAQ,IAAI,CACpB,QAAO,IAAI,KAAI,SAAQ,UAAU,KAAK,CAAC;AAGzC,KAAI,cAAc,IAAI,CACpB,QAAO,OAAO,YACZ,OAAO,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,CAAC,CAAC,CACjE;AAGH,QAAO;;AAGT,SAAS,cAAc,OAAkD;AACvE,QAAO,OAAO,UAAU,SAAS,KAAK,MAAM,KAAK;;;;;;;;;;;ACnQnD,SAAgB,kBACd,WACA,MACS;AACT,KAAI,SAAS,UACX,QAAO,UAAU,IAAI,OAAO,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAE/D,KAAI,QAAQ,UACV,QAAO,UAAU,GAAG,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAE7D,KAAI,SAAS,UACX,QAAO,CAAC,kBAAkB,UAAU,KAAK,KAAK;CAGhD,MAAM,QAAQ,KAAK,UAAU;AAE7B,KAAI,QAAQ,UAAW,QAAO,UAAU,UAAU;AAClD,KAAI,SAAS,UAAW,QAAO,UAAU,UAAU;AACnD,KAAI,QAAQ,UAAW,QAAO,OAAO,UAAU,YAAY,QAAQ,UAAU;AAC7E,KAAI,QAAQ,UAAW,QAAO,OAAO,UAAU,YAAY,QAAQ,UAAU;AAC7E,KAAI,SAAS,UAAW,QAAO,OAAO,UAAU,YAAY,SAAS,UAAU;AAC/E,KAAI,SAAS,UAAW,QAAO,OAAO,UAAU,YAAY,SAAS,UAAU;AAC/E,KAAI,QAAQ,UAAW,QAAO,UAAU,GAAG,SAAS,MAAM;AAC1D,KAAI,WAAW,UAAW,QAAO,CAAC,UAAU,MAAM,SAAS,MAAM;AACjE,KAAI,YAAY,UAAW,QAAO,CAAC,CAAC;AACpC,KAAI,WAAW,UAAW,QAAO,CAAC;AAClC,KAAI,cAAc,WAAW;AAC3B,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,SAAS,UAAU,SAAS;AACxE,MAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,SAAS,UAAU,SAAS;AACnE,SAAO;;AAGT,QAAO;;;AAIT,SAAgB,gBAAgB,QAAyC;AACvE,QAAO,OAAO,QAAQ,OAAO,MAAM,SAAS,SAAS,KAAK,SAAS,GAAG,OAAO;;;AAI/E,SAAgB,cAAc,QAAuC;AACnE,QAAO,gBAAgB,OAAO,CAAC,SAAS,YAAY,QAAQ,OAAO;;;AAIrE,SAAS,kBAAkB,GAAgC;CACzD,MAAM,QAAoB,EAAE;AAE5B,KAAI,EAAE,aAAa,KAAA,EAAW,OAAM,WAAW,EAAE;AACjD,KAAI,EAAE,cAAc,KAAA,EAAW,OAAM,YAAY,EAAE;AACnD,KAAI,EAAE,cAAc,KAAA,EAAW,OAAM,YAAY,EAAE;AACnD,KAAI,EAAE,QAAQ,KAAA,EAAW,OAAM,MAAM,EAAE;AACvC,KAAI,EAAE,QAAQ,KAAA,EAAW,OAAM,MAAM,EAAE;AACvC,KAAI,EAAE,UAAU,KAAA,EAAW,OAAM,QAAQ,EAAE;AAE3C,KAAI,EAAE,YAAY,KAAA,EAChB,OAAM,UACJ,OAAO,EAAE,YAAY,WACjB,IAAI,OAAO,EAAE,QAAQ,GACrB;EAAE,OAAO,IAAI,OAAO,EAAE,QAAQ,MAAM;EAAE,SAAS,EAAE,QAAQ;EAAS;AAG1E,QAAO;;AAGT,SAAgB,mBACd,QACA,aACyB;CACzB,MAAM,gBAAgB,EAAE;AAExB,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,MAAM,MAAM;AAClB,MAAI,eAAe,UAAU,aAAa,IAAI,CAC5C,eAAc,OAAQ,YAAwC;WACrD,MAAM,iBAAiB,KAAA,EAChC,eAAc,OAAO,MAAM;MAE3B,eAAc,OAAO,eAAe,MAAM,KAAK;;AAInD,QAAO;;AAGT,SAAgB,WACd,QACA,cACqC;CACrC,MAAM,QAA6C,EAAE;AAErD,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,OAAmB,MAAM,aAAa,kBAAkB,MAAM,WAAW,GAAG,EAAE;EACpF,MAAM,cAAc,cAAc,SAAS,MAAM;EAEjD,MAAM,mBAG4B,EAAE;AAEpC,MAAI,aAAa,UAAU;GACzB,MAAM,KAAK,YAAY;AACvB,oBAAiB,MAAM,OAAO,aAAa,GAAG,OAAO,SAAc,CAAC;;AAGtE,MAAI,iBAAiB,SAAS,EAC5B,MAAK,SAAS;AAGhB,MAAI,OAAO,KAAK,KAAK,CAAC,SAAS,EAC7B,OAAM,MAAM,QAAQ;;AAIxB,QAAO;;AAGT,SAAgB,aAAgB,QAAa,QAA4B;AACvE,QAAO,OAAO,GAAG,OAAO,QAAQ,GAAG,OAAO;;AAG5C,SAAgB,cACd,QACA,QACM;AACN,MAAK,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,QAAO,OAAO;AAEhB,QAAO,OAAO,QAAQ,OAAO;;AAG/B,SAAS,UAAU,QAAgB,KAAsB;AACvD,QAAO,OAAO,UAAU,eAAe,KAAK,QAAQ,IAAI;;;;;;;;;;;;;;;;;;AC9G1D,SAAgB,eACd,QACA,aACA,cACyB;CACzB,MAAM,gBAAgB,WAAW,OAAO;CACxC,MAAM,SAAS,SAA4B,cAAc,OAAO,CAAC;CACjE,MAAM,WAAW,SAA8B,gBAAgB,OAAO,CAAC;CACvE,MAAM,QAAQ,SAA8C,WAAW,QAAQ,aAAa,CAAC;CAG7F,MAAM,OAAO,QACX,mBAAsB,QAAQ,YAAY,EAC1C,MACD;CAGD,SAAS,eAAe,MAAuB;EAC7C,MAAM,cAAc,cAAc,SAAS;AAC3C,MAAI,aAAa,QACf,QAAO,YAAY,QAAQ,KAAK,KAAU;EAG5C,MAAM,QAAQ,OAAO,MAAM,MAAM,EAAE,SAAS,KAAK;AACjD,MAAI,OAAO,UACT,QAAO,kBAAkB,MAAM,WAAW,KAAK,KAAgC;AAGjF,SAAO;;CAGT,SAAS,iBAAiB,IAAqB;EAC7C,MAAM,UAAU,SAAS,MAAM,MAAM,EAAE,OAAO,GAAG;AACjD,MAAI,SAAS,UACX,QAAO,kBAAkB,QAAQ,WAAW,KAAK,KAAgC;AAEnF,SAAO;;CAIT,SAAS,sBAAsB,OAAiD;EAC9E,MAAM,QAAQ,sBAAsB,MAAM,KAAK;EAC/C,MAAM,YAAY,KAAK,cAAc,MAAM,KAAgB;EAE3D,MAAM,SAAkC;GACtC,GAAG,MAAM;GACT,GAAI,MAAM,SAAS,EAAE;GACtB;EAGD,MAAM,cAAc,cAAc,SAAS,MAAM;AACjD,MAAI,aAAa,MACf,QAAO,OAAO,QAAQ,YAAY,MAAM,KAAK,KAAU,CAAC;EAI1D,MAAM,UAAU,gBAAgB,MAAM,KAAK;AAC3C,MAAI,QACF,QAAO,UAAU;AAInB,MAAI,MAAM,QAAQ;AAChB,UAAO,aAAa,UAAU;AAC9B,UAAO,yBAAyB,UAAU;;AAE5C,SAAO,SAAS,UAAU;AAI1B,MADiB,UAAU,MAEzB,QAAO,QAAQ;AAIjB,MAAI,MAAM,YAAa,QAAO,cAAc,MAAM;AAClD,MAAI,MAAM,KAAM,QAAO,OAAO,MAAM;AACpC,MAAI,MAAM,SAAU,QAAO,WAAW;AACtC,MAAI,MAAM,SAAU,QAAO,WAAW;AAGtC,MAAI,MAAM,SAAS,WAAW,CAAC,OAAO,KACpC,QAAO,OAAO,MAAM;AAGtB,SAAO;;CAGT,SAAS,gBAAgB,MAA6C;EACpE,MAAM,cAAc,cAAc,SAAS;AAC3C,MAAI,aAAa,QACf,QAAO,YAAY,QAAQ,KAAK,KAAU;EAG5C,MAAM,QAAQ,OAAO,MAAM,MAAM,EAAE,SAAS,KAAK;AACjD,MAAI,OAAO,OAAO,QAChB,QAAO,MAAM,MAAM;;CAOvB,MAAM,cAAc,IAAI,EAAE;CAE1B,MAAM,qBAAqB,eAAe;AACxC,MAAI,CAAC,cAAc,MAAM,MAAO,QAAO,KAAK,QAAQ;EAEpD,MAAM,OAAO,cAAc,MAAM,MAAM,YAAY;AACnD,MAAI,CAAC,KAAM,QAAO;AAElB,OAAK,MAAM,WAAW,KAAK,UAAU;AACnC,OAAI,CAAC,iBAAiB,QAAQ,GAAG,CAAE;AACnC,QAAK,MAAM,SAAS,QAAQ,QAAQ;AAClC,QAAI,CAAC,eAAe,MAAM,KAAK,CAAE;AACjC,QAAI,CAAC,KAAK,cAAc,MAAM,KAAK,CAAE,QAAO;;;AAGhD,SAAO;GACP;CAEF,SAAS,SAAkB;AACzB,MAAI,CAAC,cAAc,MAAM,MAAO,QAAO;EAGvC,MAAM,OAAO,cAAc,MAAM,MAAM,YAAY;AACnD,MAAI,CAAC,KAAM,QAAO;EAElB,IAAI,QAAQ;AACZ,OAAK,MAAM,WAAW,KAAK,UAAU;AACnC,OAAI,CAAC,iBAAiB,QAAQ,GAAG,CAAE;AACnC,QAAK,MAAM,SAAS,QAAQ,QAAQ;AAClC,QAAI,CAAC,eAAe,MAAM,KAAK,CAAE;AACjC,SAAK,gBAAgB,MAAM,MAAM,KAAK;AACtC,QAAI,CAAC,KAAK,cAAc,MAAM,KAAK,CAAE,SAAQ;;;AAIjD,MAAI,CAAC,MAAO,QAAO;AAEnB,MAAI,YAAY,QAAQ,cAAc,MAAM,MAAM,SAAS,EACzD,aAAY;AAEd,SAAO;;CAGT,SAAS,SAAe;AACtB,MAAI,YAAY,QAAQ,EACtB,aAAY;;CAIhB,SAAS,SAAS,OAAqB;AACrC,MAAI,CAAC,cAAc,MAAM,MAAO;AAChC,MAAI,SAAS,KAAK,QAAQ,cAAc,MAAM,MAAM,OAClD,aAAY,QAAQ;;CAKxB,SAAS,WAAoB;EAC3B,IAAI,WAAW;AACf,OAAK,MAAM,SAAS,QAAQ;AAC1B,OAAI,CAAC,eAAe,MAAM,KAAK,CAAE;AACjC,QAAK,gBAAgB,MAAM,MAAM,KAAK;AACtC,OAAI,CAAC,KAAK,cAAc,MAAM,KAAK,CACjC,YAAW;;AAGf,SAAO;;CAIT,eAAe,SAAwB;AACrC,MAAI,CAAC,UAAU,CAAE;EAGjB,IAAI,aAAa,EAAE;AACnB,OAAK,MAAM,SAAS,OAClB,KAAI,eAAe,MAAM,KAAK,CAC5B,YAAW,MAAM,QAAS,KAAK,KAAiC,MAAM;AAI1E,MAAI,cAAc,UAChB,cAAa,aAAa,UAAU,WAAgB;AAGtD,MAAI,cAAc,UAAU;AAC1B,QAAK,aAAa,QAAQ;AAC1B,OAAI;AACF,UAAM,aAAa,SAAS,WAAgB;aACpC;AACR,SAAK,aAAa,QAAQ;;;;CAMhC,SAAS,MAAM,QAA2B;AACxC,OAAK,MAAM,OAAO;AAClB,cAAY,QAAQ;;CAGtB,SAAS,aAAa,YAAwB,UAA6B;AACzE,gBAAc,QAAQ;EAEtB,MAAM,aAAa,cAAc,WAAW;AAC5C,eAAa,QAAQ,WAAW;AAChC,eAAa,UAAU,gBAAgB,WAAW,CAAC;AACnD,gBAAc,OAAO,WAAW,YAAY,aAAa,CAAC;AAC1D,OAAK,aAAa,mBAAsB,YAAY,SAAS,CAAM;AACnE,cAAY,QAAQ;;AAItB,KAAI,cAAc,eAAe;EAC/B,MAAM,WAAW,aAAa;AAC9B,eACS,EAAE,GAAI,KAAK,MAAkC,IACnD,SAAS,YAAY;AACpB,OAAI,CAAC,QAAS;AACd,QAAK,MAAM,OAAO,OAAO,KAAK,QAAQ,CACpC,KAAI,QAAQ,SAAS,QAAQ,KAC3B,UAAS,KAAgB,QAAQ,MAAM,QAAa;KAI1D,EAAE,MAAM,MAAM,CACf;;AAGH,QAAO;EACC;EACC;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { A as useConcentrationUnits, u as useControlWorkspace } from "./useControlSchema-
|
|
2
|
-
import { r as useSettingsStore } from "./auth-
|
|
3
|
-
import { u as resolveExperimentCode } from "./experiment-utils-
|
|
4
|
-
import { i as useApi, r as useRequestSyncState } from "./useExperimentSelector-
|
|
5
|
-
import { B as toBioTemplateComponentProps, F as getBioTemplateComponentProps$1, H as toBioTemplateComponentPropsById, Jt as getBioTemplatePresetInfo, L as toBioTemplateComponentBindings, P as getBioTemplateComponentBindings, Qt as getBioTemplatePackInfo, R as toBioTemplateComponentBindingsById, U as toBioTemplateComponentSnippets, V as toBioTemplateComponentPropsByComponent$1, W as toBioTemplateComponentUsage, d as createBioTemplatePresetCollectionFromControls, dn as extractTemplateCollection, i as createBioTemplateControlToolkit, p as createBioTemplatePackCollection, sn as createTemplateCollection, u as createBioTemplatePresetCollection, un as ensureTemplateFromCollection, z as toBioTemplateComponentImports } from "./templates-
|
|
1
|
+
import { A as useConcentrationUnits, u as useControlWorkspace } from "./useControlSchema-BZNdalmL.js";
|
|
2
|
+
import { r as useSettingsStore } from "./auth-DZAwEeis.js";
|
|
3
|
+
import { u as resolveExperimentCode } from "./experiment-utils-Bfa7CwPU.js";
|
|
4
|
+
import { i as useApi, r as useRequestSyncState } from "./useExperimentSelector-DdCy5VNv.js";
|
|
5
|
+
import { B as toBioTemplateComponentProps, F as getBioTemplateComponentProps$1, H as toBioTemplateComponentPropsById, Jt as getBioTemplatePresetInfo, L as toBioTemplateComponentBindings, P as getBioTemplateComponentBindings, Qt as getBioTemplatePackInfo, R as toBioTemplateComponentBindingsById, U as toBioTemplateComponentSnippets, V as toBioTemplateComponentPropsByComponent$1, W as toBioTemplateComponentUsage, d as createBioTemplatePresetCollectionFromControls, dn as extractTemplateCollection, i as createBioTemplateControlToolkit, p as createBioTemplatePackCollection, sn as createTemplateCollection, u as createBioTemplatePresetCollection, un as ensureTemplateFromCollection, z as toBioTemplateComponentImports } from "./templates-CNbPQNID.js";
|
|
6
6
|
import { computed, effectScope, getCurrentScope, inject, onMounted, onScopeDispose, onUnmounted, provide, reactive, readonly, ref, shallowRef, toRaw, toValue, unref, watch } from "vue";
|
|
7
7
|
//#region src/composables/useSortedItems.ts
|
|
8
8
|
/** Shared sorting for SDK tables and lists with stable empty-value handling. */
|
|
@@ -4184,4 +4184,4 @@ function useProtocolTemplates() {
|
|
|
4184
4184
|
//#endregion
|
|
4185
4185
|
export { parseCSV as A, APP_EXPERIMENT_KEY as B, useExpansionSet as C, hslToHex as D, hexToHsl as E, classKey as F, normalizeSearchQuery as G, useTheme as H, useWellPlateEditor as I, useSortedItems as J, useTextSearch as K, useDoseCalculator as L, extractSampleOptionsFromDesignData as M, unwrapExperimentDesignData as N, extractSamplesFromDesignData as O, DEFAULT_COLORS as P, DEFAULT_MOBILE_VIEWPORT_QUERY as R, resolveCurrentExperimentId as S, deriveShade as T, useToast as U, useAppExperiment as V, candidateMatchesSearch as W, useScheduleDrag as _, useReagentSeries as a, currentExperimentFromContext as b, useBioTemplatePresetWorkspace as c, getBioTemplateComponentProps as d, toBioTemplateComponentPropsByComponent as f, useExperimentSave as g, useTemplateCollection as h, generateDilutionSeries as i, extractSampleNamesFromDesignData as j, useAutoGroup as k, useBioTemplatePackWorkspace as l, useBioTemplateControls as m, DEFAULT_PRESETS as n, useGroupAssignment as o, useBioTemplateComponents as p, compareSortValues as q, DEFAULT_UNITS as r, useRackEditor as s, useProtocolTemplates as t, useBioTemplateWorkspace as u, useExperimentSamples as v, useSampleGroups as w, getInjectedPlatformContext as x, useExperimentData as y, useMobileSupportGate as z };
|
|
4186
4186
|
|
|
4187
|
-
//# sourceMappingURL=useProtocolTemplates-
|
|
4187
|
+
//# sourceMappingURL=useProtocolTemplates-COIsmhsZ.js.map
|