@spacesync/client 0.1.0 → 0.1.2
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/README.md +9 -14
- package/dist/analog-clock-picker.d.ts +2 -2
- package/dist/analog-clock-picker.js +12 -406
- package/dist/analog-clock-picker.js.map +1 -1
- package/dist/api.js +7 -87
- package/dist/api.js.map +1 -1
- package/dist/app-modal.d.ts +7 -8
- package/dist/app-modal.js +3 -74
- package/dist/app-modal.js.map +1 -1
- package/dist/app-shell-mobile-nav.d.ts +1 -2
- package/dist/app-shell-mobile-nav.js +2 -66
- package/dist/app-shell-mobile-nav.js.map +1 -1
- package/dist/app-web-shell.d.ts +2 -2
- package/dist/app-web-shell.js +1 -4
- package/dist/app-web-shell.js.map +1 -1
- package/dist/booking-schedule-calendars.d.ts +12 -12
- package/dist/booking-schedule-calendars.js +13 -402
- package/dist/booking-schedule-calendars.js.map +1 -1
- package/dist/chat-stick-to-bottom.d.ts +1 -2
- package/dist/chat-stick-to-bottom.js +12 -48
- package/dist/chat-stick-to-bottom.js.map +1 -1
- package/dist/chunk-4A6RCBB5.js +4925 -0
- package/dist/chunk-4A6RCBB5.js.map +1 -0
- package/dist/chunk-4NNK5IXY.js +79 -0
- package/dist/chunk-4NNK5IXY.js.map +1 -0
- package/dist/chunk-4Y5DBM6Z.js +6 -0
- package/dist/chunk-4Y5DBM6Z.js.map +1 -0
- package/dist/chunk-7YCAAP43.js +107 -0
- package/dist/chunk-7YCAAP43.js.map +1 -0
- package/dist/chunk-DMPSQ22Q.js +11 -0
- package/dist/chunk-DMPSQ22Q.js.map +1 -0
- package/dist/chunk-FCY5FYJB.js +104 -0
- package/dist/chunk-FCY5FYJB.js.map +1 -0
- package/dist/chunk-H7EX6B6N.js +580 -0
- package/dist/chunk-H7EX6B6N.js.map +1 -0
- package/dist/chunk-HCHASUB6.js +13 -0
- package/dist/chunk-HCHASUB6.js.map +1 -0
- package/dist/chunk-L65F4EMK.js +34 -0
- package/dist/chunk-L65F4EMK.js.map +1 -0
- package/dist/chunk-LUB7QWGU.js +301 -0
- package/dist/chunk-LUB7QWGU.js.map +1 -0
- package/dist/chunk-OMSJWTSZ.js +120 -0
- package/dist/chunk-OMSJWTSZ.js.map +1 -0
- package/dist/chunk-OWNUMPUC.js +9 -0
- package/dist/chunk-OWNUMPUC.js.map +1 -0
- package/dist/chunk-P65TMY3D.js +87 -0
- package/dist/chunk-P65TMY3D.js.map +1 -0
- package/dist/chunk-PBNBLCC2.js +84 -0
- package/dist/chunk-PBNBLCC2.js.map +1 -0
- package/dist/chunk-RV5PMZYZ.js +63 -0
- package/dist/chunk-RV5PMZYZ.js.map +1 -0
- package/dist/chunk-VHINHHZQ.js +48 -0
- package/dist/chunk-VHINHHZQ.js.map +1 -0
- package/dist/chunk-VVXGQKN7.js +107 -0
- package/dist/chunk-VVXGQKN7.js.map +1 -0
- package/dist/chunk-XU3EFSQX.js +22 -0
- package/dist/chunk-XU3EFSQX.js.map +1 -0
- package/dist/chunk-YAVEMXXV.js +381 -0
- package/dist/chunk-YAVEMXXV.js.map +1 -0
- package/dist/chunk-ZIJQ7BXU.js +27 -0
- package/dist/chunk-ZIJQ7BXU.js.map +1 -0
- package/dist/detail-page-header.d.ts +3 -3
- package/dist/detail-page-header.js +5 -149
- package/dist/detail-page-header.js.map +1 -1
- package/dist/{dialog-CIdvylPK.d.ts → dialog-CPkbi5N3.d.ts} +10 -11
- package/dist/file-picker-field.d.ts +2 -2
- package/dist/file-picker-field.js +3 -163
- package/dist/file-picker-field.js.map +1 -1
- package/dist/file-viewer-dialog.d.ts +2 -2
- package/dist/file-viewer-dialog.js +12 -223
- package/dist/file-viewer-dialog.js.map +1 -1
- package/dist/floor-switcher.d.ts +2 -2
- package/dist/floor-switcher.js +13 -323
- package/dist/floor-switcher.js.map +1 -1
- package/dist/forms.js +1 -23
- package/dist/forms.js.map +1 -1
- package/dist/image-picker-field.d.ts +7 -4
- package/dist/image-picker-field.js +17 -60
- package/dist/image-picker-field.js.map +1 -1
- package/dist/layout-canvas-view.d.ts +2 -2
- package/dist/layout-canvas-view.js +17 -220
- package/dist/layout-canvas-view.js.map +1 -1
- package/dist/lib/dateDisplay.js +1 -82
- package/dist/lib/dateDisplay.js.map +1 -1
- package/dist/live-resource-meta.js +1 -25
- package/dist/live-resource-meta.js.map +1 -1
- package/dist/live-space-pulse-dot.d.ts +2 -2
- package/dist/live-space-pulse-dot.js +2 -16
- package/dist/live-space-pulse-dot.js.map +1 -1
- package/dist/notification-sidebar-preview.d.ts +3 -3
- package/dist/notification-sidebar-preview.js +3 -61
- package/dist/notification-sidebar-preview.js.map +1 -1
- package/dist/page-list-chrome.d.ts +25 -25
- package/dist/page-list-chrome.js +6 -968
- package/dist/page-list-chrome.js.map +1 -1
- package/dist/platform-support-message-composer.d.ts +4 -4
- package/dist/platform-support-message-composer.js +15 -218
- package/dist/platform-support-message-composer.js.map +1 -1
- package/dist/shell-sidebar-nav.js +8 -13
- package/dist/shell-sidebar-nav.js.map +1 -1
- package/dist/shell-theme.js +1 -7
- package/dist/shell-theme.js.map +1 -1
- package/dist/shell-top-bar-chrome.js +3 -103
- package/dist/shell-top-bar-chrome.js.map +1 -1
- package/dist/shell-top-bar.d.ts +3 -3
- package/dist/shell-top-bar.js +1 -69
- package/dist/shell-top-bar.js.map +1 -1
- package/dist/support-presence-status.d.ts +2 -2
- package/dist/support-presence-status.js +3 -41
- package/dist/support-presence-status.js.map +1 -1
- package/dist/theme-appearance-control.d.ts +2 -2
- package/dist/theme-appearance-control.js +4 -63
- package/dist/theme-appearance-control.js.map +1 -1
- package/dist/theme-boot-script.js +1 -2
- package/dist/theme-boot-script.js.map +1 -1
- package/dist/theme-provider.d.ts +2 -2
- package/dist/theme-provider.js +2 -23
- package/dist/theme-provider.js.map +1 -1
- package/dist/ui.d.ts +261 -262
- package/dist/ui.js +11 -5635
- package/dist/ui.js.map +1 -1
- package/package.json +11 -2
package/dist/forms.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/errors.ts","../src/forms/useApiForm.ts"],"names":[],"mappings":";;;;;;AAwBO,IAAM,cAAA,GAAN,MAAM,eAAA,SAAuB,KAAA,CAAM;AAAA,EAC/B,IAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EAET,WAAA,CAAY,IAAA,EAA0B,OAAA,EAAiB,OAAA,GAAiC,EAAC,EAAG;AAC1F,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,aAAa,OAAA,CAAQ,UAAA;AAC1B,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,OAAA;AACvB,IAAA,IAAA,CAAK,cAAc,OAAA,CAAQ,WAAA;AAC3B,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,eAAA,CAAe,SAAS,CAAA;AAAA,EACtD;AACF,CAAA;AAEO,SAAS,iBAAiB,GAAA,EAAqC;AACpE,EAAA,OAAO,GAAA,YAAe,cAAA;AACxB;;;ACLO,SAAS,UAAA,CAAsC,QAAiB,OAAA,EAA0C;AAK/G,EAAA,MAAM,IAAA,GAAO,QAA0B,EAAE,QAAA,EAAU,YAAY,MAAe,CAAA,EAAG,GAAG,OAAA,EAAS,CAAA;AAE7F,EAAA,MAAM,gBAAgB,CACpB,OAAA,EACA,kBAEA,IAAA,CAAK,YAAA,CAAa,OAAO,MAAA,KAAW;AAClC,IAAA,IAAI;AACF,MAAA,MAAM,QAAQ,MAAM,CAAA;AAAA,IACtB,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,CAAC,gBAAA,CAAiB,GAAG,CAAA,EAAG,MAAM,GAAA;AAElC,MAAA,IAAI,aAAA,EAAe,UAAA,GAAa,GAAA,EAAK,IAAI,CAAA,EAAG;AAE5C,MAAA,QAAQ,IAAI,IAAA;AAAM,QAChB,KAAK,SAAA;AACH,UAAA,IAAA,CAAK,QAAA,CAAS,QAAQ,EAAE,IAAA,EAAM,WAAW,OAAA,EAAS,GAAA,CAAI,SAAS,CAAA;AAC/D,UAAA;AAAA,QACF,KAAK,YAAA,EAAc;AACjB,UAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,MAAA,CAAO,KAAK,IAAA,CAAK,SAAA,EAAW,CAAC,CAAA;AACzD,UAAA,IAAI,SAAA,GAAY,KAAA;AAChB,UAAA,KAAA,MAAW,UAAA,IAAc,GAAA,CAAI,WAAA,IAAe,EAAC,EAAG;AAC9C,YAAA,IAAI,WAAA,CAAY,GAAA,CAAI,UAAA,CAAW,IAAI,CAAA,EAAG;AACpC,cAAA,IAAA,CAAK,QAAA,CAAS,WAAW,IAAA,EAAqC;AAAA,gBAC5D,IAAA,EAAM,QAAA;AAAA,gBACN,SAAS,UAAA,CAAW;AAAA,eACrB,CAAA;AACD,cAAA,SAAA,GAAY,IAAA;AAAA,YACd;AAAA,UACF;AACA,UAAA,IAAI,CAAC,SAAA,EAAW,IAAA,CAAK,QAAA,CAAS,MAAA,EAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,OAAA,EAAS,GAAA,CAAI,OAAA,EAAS,CAAA;AAC9E,UAAA;AAAA,QACF;AAAA,QACA,KAAK,MAAA;AAAA,QACL;AACE,UAAA,IAAA,CAAK,QAAA,CAAS,QAAQ,EAAE,IAAA,EAAM,UAAU,OAAA,EAAS,GAAA,CAAI,SAAS,CAAA;AAC9D,UAAA;AAAA;AACJ,IACF;AAAA,EACF,CAAC,CAAA;AAEH,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,aAAA,EAAc;AAClC","file":"forms.js","sourcesContent":["import axios from \"axios\";\nimport { z } from \"zod\";\nimport { apiErrorBodySchema } from \"./envelope\";\n\n/**\n * - \"network\": the request never got a response at all (server unreachable, timeout, CORS/preflight failure).\n * - \"validation\": HTTP 400 from our API where `error.details` is the Zod-issues shape produced by\n * `validate.middleware.ts` — field-mappable.\n * - \"http\": every other status our API returns (401, 403, 404, 409, 500, ...). Not field-specific by default.\n */\nexport type ApiClientErrorKind = \"network\" | \"validation\" | \"http\";\n\nexport interface ApiFieldError {\n /** Dot-path, e.g. \"email\" — matched against react-hook-form field names. */\n path: string;\n message: string;\n}\n\nexport interface ApiClientErrorOptions {\n statusCode?: number;\n details?: unknown;\n fieldErrors?: ApiFieldError[];\n}\n\nexport class ApiClientError extends Error {\n readonly kind: ApiClientErrorKind;\n readonly statusCode?: number;\n readonly details?: unknown;\n readonly fieldErrors?: ApiFieldError[];\n\n constructor(kind: ApiClientErrorKind, message: string, options: ApiClientErrorOptions = {}) {\n super(message);\n this.name = \"ApiClientError\";\n this.kind = kind;\n this.statusCode = options.statusCode;\n this.details = options.details;\n this.fieldErrors = options.fieldErrors;\n Object.setPrototypeOf(this, ApiClientError.prototype);\n }\n}\n\nexport function isApiClientError(err: unknown): err is ApiClientError {\n return err instanceof ApiClientError;\n}\n\ninterface ZodLikeIssue {\n path: Array<string | number>;\n message: string;\n}\n\nfunction isZodIssueArray(details: unknown): details is ZodLikeIssue[] {\n return (\n Array.isArray(details) &&\n details.length > 0 &&\n details.every(\n (issue) =>\n typeof issue === \"object\" &&\n issue !== null &&\n Array.isArray((issue as ZodLikeIssue).path) &&\n typeof (issue as ZodLikeIssue).message === \"string\",\n )\n );\n}\n\nfunction toFieldErrors(issues: ZodLikeIssue[]): ApiFieldError[] {\n return issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n }));\n}\n\n/**\n * Normalizes anything that can be thrown while making a request (axios error,\n * envelope-shape mismatch, or an unexpected exception) into one `ApiClientError`,\n * classified by `kind` so callers like `useApiForm` can apply a sensible default\n * per failure mode instead of treating a dropped connection the same as a 409.\n */\nexport function normalizeAxiosError(err: unknown): ApiClientError {\n if (isApiClientError(err)) return err;\n\n if (axios.isAxiosError(err)) {\n if (!err.response) {\n return new ApiClientError(\"network\", \"Unable to reach the server. Check your connection and try again.\");\n }\n\n const status = err.response.status;\n const parsedBody = apiErrorBodySchema.safeParse(err.response.data);\n const message = parsedBody.success ? parsedBody.data.error.message : `Request failed with status ${status}`;\n const details = parsedBody.success ? parsedBody.data.error.details : undefined;\n\n if (status === 400 && isZodIssueArray(details)) {\n return new ApiClientError(\"validation\", message, {\n statusCode: status,\n details,\n fieldErrors: toFieldErrors(details),\n });\n }\n\n return new ApiClientError(\"http\", message, { statusCode: status, details });\n }\n\n if (err instanceof z.ZodError) {\n // The server responded 2xx but the payload didn't match the schema we expected -\n // a frontend/backend contract mismatch, not a user-facing form error.\n return new ApiClientError(\"http\", \"Unexpected response shape from the server.\", {\n details: err.issues,\n });\n }\n\n const message = err instanceof Error ? err.message : \"Something went wrong. Please try again.\";\n return new ApiClientError(\"http\", message);\n}\n","import { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n useForm,\n type FieldPath,\n type FieldValues,\n type UseFormProps,\n type UseFormReturn,\n} from \"react-hook-form\";\nimport type { z } from \"zod\";\nimport { isApiClientError, type ApiClientError } from \"../api/errors\";\n\nexport interface SubmitWithApiOptions<TFieldValues extends FieldValues> {\n /**\n * Called before the default per-`kind` handling below. Return `true` if you fully handled the\n * error yourself (e.g. mapped a 409 \"email already registered\" onto the `email` field) - this\n * skips the default handling. Return `false`/`undefined` to fall back to it.\n */\n onApiError?: (error: ApiClientError, form: UseFormReturn<TFieldValues>) => boolean | void;\n}\n\n/**\n * Wraps `react-hook-form` + the zod resolver, and gives `submitWithApi` a default error-handling\n * policy per `ApiClientError.kind`:\n *\n * - client-side validation (bad email, missing field) never reaches here - `zodResolver` blocks the\n * submit and populates per-field errors before `onValid` runs.\n * - \"network\" (server unreachable) -> root error, generic \"can't reach the server\" wording.\n * - \"validation\" (server-side 400 with field-mappable issues) -> mapped onto matching fields by name;\n * anything that can't be matched falls back to a root error.\n * - \"http\" (401/403/404/409/500, etc.) -> root error by default; not reliably field-mappable from the\n * backend's response shape, so a specific form can opt in via `onApiError` (e.g. map a register 409\n * onto the `email` field).\n *\n * A 401 caused by an expired session on an *authenticated* call has already been resolved one layer\n * down, inside `createApiClient`'s response interceptor (silent refresh-and-retry) - by the time an\n * error reaches here, refresh already failed and the app-level `onAuthExpired` callback already fired,\n * so this hook doesn't need auth-specific branching of its own.\n */\nexport function useApiForm<TSchema extends z.ZodType>(schema: TSchema, options?: UseFormProps<z.infer<TSchema>>) {\n // `zodResolver`'s overloads require a concrete Zod schema type it can pattern-match against\n // (Zod v3's `_def.typeName` vs. v4's `_zod`), which a generic `TSchema extends z.ZodType` can't\n // structurally prove even though it's always a real schema at runtime - this is a documented\n // typing limitation of `@hookform/resolvers`, not unsafe in practice.\n const form = useForm<z.infer<TSchema>>({ resolver: zodResolver(schema as never), ...options });\n\n const submitWithApi = (\n onValid: (values: z.infer<TSchema>) => Promise<void>,\n submitOptions?: SubmitWithApiOptions<z.infer<TSchema>>,\n ) =>\n form.handleSubmit(async (values) => {\n try {\n await onValid(values);\n } catch (err) {\n if (!isApiClientError(err)) throw err; // programmer bug - don't swallow, let it surface normally\n\n if (submitOptions?.onApiError?.(err, form)) return; // caller fully handled it\n\n switch (err.kind) {\n case \"network\":\n form.setError(\"root\", { type: \"network\", message: err.message });\n break;\n case \"validation\": {\n const knownFields = new Set(Object.keys(form.getValues()));\n let mappedAny = false;\n for (const fieldError of err.fieldErrors ?? []) {\n if (knownFields.has(fieldError.path)) {\n form.setError(fieldError.path as FieldPath<z.infer<TSchema>>, {\n type: \"server\",\n message: fieldError.message,\n });\n mappedAny = true;\n }\n }\n if (!mappedAny) form.setError(\"root\", { type: \"server\", message: err.message });\n break;\n }\n case \"http\":\n default:\n form.setError(\"root\", { type: \"server\", message: err.message });\n break;\n }\n }\n });\n\n return { ...form, submitWithApi };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/forms/useApiForm.ts"],"names":[],"mappings":";;;;AAsCO,SAAS,UAAA,CAAsC,QAAiB,OAAA,EAA0C;AAK/G,EAAA,MAAM,IAAA,GAAO,QAA0B,EAAE,QAAA,EAAU,YAAY,MAAe,CAAA,EAAG,GAAG,OAAA,EAAS,CAAA;AAE7F,EAAA,MAAM,gBAAgB,CACpB,OAAA,EACA,kBAEA,IAAA,CAAK,YAAA,CAAa,OAAO,MAAA,KAAW;AAClC,IAAA,IAAI;AACF,MAAA,MAAM,QAAQ,MAAM,CAAA;AAAA,IACtB,SAAS,GAAA,EAAK;AACZ,MAAA,IAAI,CAAC,gBAAA,CAAiB,GAAG,CAAA,EAAG,MAAM,GAAA;AAElC,MAAA,IAAI,aAAA,EAAe,UAAA,GAAa,GAAA,EAAK,IAAI,CAAA,EAAG;AAE5C,MAAA,QAAQ,IAAI,IAAA;AAAM,QAChB,KAAK,SAAA;AACH,UAAA,IAAA,CAAK,QAAA,CAAS,QAAQ,EAAE,IAAA,EAAM,WAAW,OAAA,EAAS,GAAA,CAAI,SAAS,CAAA;AAC/D,UAAA;AAAA,QACF,KAAK,YAAA,EAAc;AACjB,UAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,MAAA,CAAO,KAAK,IAAA,CAAK,SAAA,EAAW,CAAC,CAAA;AACzD,UAAA,IAAI,SAAA,GAAY,KAAA;AAChB,UAAA,KAAA,MAAW,UAAA,IAAc,GAAA,CAAI,WAAA,IAAe,EAAC,EAAG;AAC9C,YAAA,IAAI,WAAA,CAAY,GAAA,CAAI,UAAA,CAAW,IAAI,CAAA,EAAG;AACpC,cAAA,IAAA,CAAK,QAAA,CAAS,WAAW,IAAA,EAAqC;AAAA,gBAC5D,IAAA,EAAM,QAAA;AAAA,gBACN,SAAS,UAAA,CAAW;AAAA,eACrB,CAAA;AACD,cAAA,SAAA,GAAY,IAAA;AAAA,YACd;AAAA,UACF;AACA,UAAA,IAAI,CAAC,SAAA,EAAW,IAAA,CAAK,QAAA,CAAS,MAAA,EAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,OAAA,EAAS,GAAA,CAAI,OAAA,EAAS,CAAA;AAC9E,UAAA;AAAA,QACF;AAAA,QACA,KAAK,MAAA;AAAA,QACL;AACE,UAAA,IAAA,CAAK,QAAA,CAAS,QAAQ,EAAE,IAAA,EAAM,UAAU,OAAA,EAAS,GAAA,CAAI,SAAS,CAAA;AAC9D,UAAA;AAAA;AACJ,IACF;AAAA,EACF,CAAC,CAAA;AAEH,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,aAAA,EAAc;AAClC","file":"forms.js","sourcesContent":["import { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n useForm,\n type FieldPath,\n type FieldValues,\n type UseFormProps,\n type UseFormReturn,\n} from \"react-hook-form\";\nimport type { z } from \"zod\";\nimport { isApiClientError, type ApiClientError } from \"../api/errors\";\n\nexport interface SubmitWithApiOptions<TFieldValues extends FieldValues> {\n /**\n * Called before the default per-`kind` handling below. Return `true` if you fully handled the\n * error yourself (e.g. mapped a 409 \"email already registered\" onto the `email` field) - this\n * skips the default handling. Return `false`/`undefined` to fall back to it.\n */\n onApiError?: (error: ApiClientError, form: UseFormReturn<TFieldValues>) => boolean | void;\n}\n\n/**\n * Wraps `react-hook-form` + the zod resolver, and gives `submitWithApi` a default error-handling\n * policy per `ApiClientError.kind`:\n *\n * - client-side validation (bad email, missing field) never reaches here - `zodResolver` blocks the\n * submit and populates per-field errors before `onValid` runs.\n * - \"network\" (server unreachable) -> root error, generic \"can't reach the server\" wording.\n * - \"validation\" (server-side 400 with field-mappable issues) -> mapped onto matching fields by name;\n * anything that can't be matched falls back to a root error.\n * - \"http\" (401/403/404/409/500, etc.) -> root error by default; not reliably field-mappable from the\n * backend's response shape, so a specific form can opt in via `onApiError` (e.g. map a register 409\n * onto the `email` field).\n *\n * A 401 caused by an expired session on an *authenticated* call has already been resolved one layer\n * down, inside `createApiClient`'s response interceptor (silent refresh-and-retry) - by the time an\n * error reaches here, refresh already failed and the app-level `onAuthExpired` callback already fired,\n * so this hook doesn't need auth-specific branching of its own.\n */\nexport function useApiForm<TSchema extends z.ZodType>(schema: TSchema, options?: UseFormProps<z.infer<TSchema>>) {\n // `zodResolver`'s overloads require a concrete Zod schema type it can pattern-match against\n // (Zod v3's `_def.typeName` vs. v4's `_zod`), which a generic `TSchema extends z.ZodType` can't\n // structurally prove even though it's always a real schema at runtime - this is a documented\n // typing limitation of `@hookform/resolvers`, not unsafe in practice.\n const form = useForm<z.infer<TSchema>>({ resolver: zodResolver(schema as never), ...options });\n\n const submitWithApi = (\n onValid: (values: z.infer<TSchema>) => Promise<void>,\n submitOptions?: SubmitWithApiOptions<z.infer<TSchema>>,\n ) =>\n form.handleSubmit(async (values) => {\n try {\n await onValid(values);\n } catch (err) {\n if (!isApiClientError(err)) throw err; // programmer bug - don't swallow, let it surface normally\n\n if (submitOptions?.onApiError?.(err, form)) return; // caller fully handled it\n\n switch (err.kind) {\n case \"network\":\n form.setError(\"root\", { type: \"network\", message: err.message });\n break;\n case \"validation\": {\n const knownFields = new Set(Object.keys(form.getValues()));\n let mappedAny = false;\n for (const fieldError of err.fieldErrors ?? []) {\n if (knownFields.has(fieldError.path)) {\n form.setError(fieldError.path as FieldPath<z.infer<TSchema>>, {\n type: \"server\",\n message: fieldError.message,\n });\n mappedAny = true;\n }\n }\n if (!mappedAny) form.setError(\"root\", { type: \"server\", message: err.message });\n break;\n }\n case \"http\":\n default:\n form.setError(\"root\", { type: \"server\", message: err.message });\n break;\n }\n }\n });\n\n return { ...form, submitWithApi };\n}\n"]}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
declare function ImagePickerField({ label, value,
|
|
3
|
+
declare function ImagePickerField({ label, value, onFileSelected, onRemove, description, previewAlt, disabled, }: {
|
|
4
4
|
label?: string;
|
|
5
|
+
/** Preview URL supplied by the parent (`blob:`, signed HTTPS, or empty). */
|
|
5
6
|
value?: string;
|
|
6
|
-
|
|
7
|
+
onFileSelected: (file: File) => void;
|
|
8
|
+
onRemove?: () => void;
|
|
7
9
|
description?: string;
|
|
8
10
|
previewAlt?: string;
|
|
9
|
-
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}): React.JSX.Element;
|
|
10
13
|
|
|
11
14
|
export { ImagePickerField };
|
|
@@ -1,70 +1,23 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Button } from './chunk-VHINHHZQ.js';
|
|
2
|
+
import './chunk-DMPSQ22Q.js';
|
|
2
3
|
import { useRef } from 'react';
|
|
3
4
|
import { ImagePlus, Trash2, Upload } from 'lucide-react';
|
|
4
|
-
import {
|
|
5
|
-
import { cva } from 'class-variance-authority';
|
|
6
|
-
import { clsx } from 'clsx';
|
|
7
|
-
import { twMerge } from 'tailwind-merge';
|
|
8
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
9
6
|
|
|
10
|
-
// src/files/image-picker-field.tsx
|
|
11
|
-
function cn(...inputs) {
|
|
12
|
-
return twMerge(clsx(inputs));
|
|
13
|
-
}
|
|
14
|
-
var buttonVariants = cva(
|
|
15
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-all disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
16
|
-
{
|
|
17
|
-
variants: {
|
|
18
|
-
variant: {
|
|
19
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80 active:scale-[0.98]",
|
|
20
|
-
destructive: "bg-destructive text-white hover:bg-destructive/90 active:bg-destructive/80 active:scale-[0.98] focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 dark:active:bg-destructive/70",
|
|
21
|
-
outline: "border bg-background text-foreground hover:bg-accent hover:text-accent-foreground active:bg-accent/80 active:scale-[0.98] dark:bg-input/30 dark:border-input dark:hover:bg-input/50 dark:active:bg-input/60",
|
|
22
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 active:bg-secondary/70 active:scale-[0.98]",
|
|
23
|
-
ghost: "hover:bg-accent hover:text-accent-foreground active:bg-accent/90 active:scale-[0.98] dark:hover:bg-accent/50 dark:active:bg-accent/40",
|
|
24
|
-
link: "text-primary underline-offset-4 hover:underline active:text-primary/80"
|
|
25
|
-
},
|
|
26
|
-
size: {
|
|
27
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
28
|
-
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
29
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
30
|
-
icon: "size-9 rounded-md"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
defaultVariants: {
|
|
34
|
-
variant: "default",
|
|
35
|
-
size: "default"
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
var Button = React.forwardRef(function Button2({ className, variant, size, asChild = false, ...props }, ref) {
|
|
40
|
-
const Comp = asChild ? Slot : "button";
|
|
41
|
-
return /* @__PURE__ */ jsx(
|
|
42
|
-
Comp,
|
|
43
|
-
{
|
|
44
|
-
ref,
|
|
45
|
-
"data-slot": "button",
|
|
46
|
-
className: cn(buttonVariants({ variant, size }), className),
|
|
47
|
-
...props
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
});
|
|
51
|
-
Button.displayName = "Button";
|
|
52
7
|
function ImagePickerField({
|
|
53
8
|
label = "Image",
|
|
54
9
|
value,
|
|
55
|
-
|
|
10
|
+
onFileSelected,
|
|
11
|
+
onRemove,
|
|
56
12
|
description,
|
|
57
|
-
previewAlt = "Selected image"
|
|
13
|
+
previewAlt = "Selected image",
|
|
14
|
+
disabled = false
|
|
58
15
|
}) {
|
|
59
16
|
const inputRef = useRef(null);
|
|
60
17
|
const handleFileChange = (files) => {
|
|
61
18
|
const file = files?.[0];
|
|
62
|
-
if (!file) return;
|
|
63
|
-
|
|
64
|
-
reader.onload = () => {
|
|
65
|
-
if (typeof reader.result === "string") onChange(reader.result);
|
|
66
|
-
};
|
|
67
|
-
reader.readAsDataURL(file);
|
|
19
|
+
if (!file || disabled) return;
|
|
20
|
+
onFileSelected(file);
|
|
68
21
|
};
|
|
69
22
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
70
23
|
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: label }),
|
|
@@ -77,6 +30,7 @@ function ImagePickerField({
|
|
|
77
30
|
type: "button",
|
|
78
31
|
variant: "link",
|
|
79
32
|
size: "sm",
|
|
33
|
+
disabled,
|
|
80
34
|
onClick: () => inputRef.current?.click(),
|
|
81
35
|
className: "h-auto gap-1.5 p-0 text-xs font-medium text-blue-600 dark:text-blue-400",
|
|
82
36
|
children: [
|
|
@@ -85,32 +39,34 @@ function ImagePickerField({
|
|
|
85
39
|
]
|
|
86
40
|
}
|
|
87
41
|
),
|
|
88
|
-
/* @__PURE__ */ jsxs(
|
|
42
|
+
onRemove ? /* @__PURE__ */ jsxs(
|
|
89
43
|
Button,
|
|
90
44
|
{
|
|
91
45
|
type: "button",
|
|
92
46
|
variant: "link",
|
|
93
47
|
size: "sm",
|
|
94
|
-
|
|
48
|
+
disabled,
|
|
49
|
+
onClick: onRemove,
|
|
95
50
|
className: "h-auto gap-1.5 p-0 text-xs font-medium text-red-600",
|
|
96
51
|
children: [
|
|
97
52
|
/* @__PURE__ */ jsx(Trash2, { size: 13 }),
|
|
98
53
|
"Remove"
|
|
99
54
|
]
|
|
100
55
|
}
|
|
101
|
-
)
|
|
56
|
+
) : null
|
|
102
57
|
] })
|
|
103
58
|
] }) : /* @__PURE__ */ jsxs(
|
|
104
59
|
Button,
|
|
105
60
|
{
|
|
106
61
|
type: "button",
|
|
107
62
|
variant: "outline",
|
|
63
|
+
disabled,
|
|
108
64
|
onClick: () => inputRef.current?.click(),
|
|
109
65
|
className: "flex aspect-[4/3] h-auto max-w-sm w-full flex-col items-center justify-center gap-2 rounded-xl border-dashed bg-muted/50 px-4 py-5 text-center shadow-none hover:border-blue-300 hover:bg-blue-50/30 dark:hover:bg-blue-950/25",
|
|
110
66
|
children: [
|
|
111
67
|
/* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 items-center justify-center rounded-xl border border-border bg-card", children: /* @__PURE__ */ jsx(Upload, { size: 15, className: "text-muted-foreground" }) }),
|
|
112
68
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: "Choose image" }),
|
|
113
|
-
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-normal text-muted-foreground whitespace-normal", children: description ?? "JPG, PNG
|
|
69
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-normal text-muted-foreground whitespace-normal", children: description ?? "JPG, PNG, WebP or GIF." })
|
|
114
70
|
]
|
|
115
71
|
}
|
|
116
72
|
),
|
|
@@ -120,6 +76,7 @@ function ImagePickerField({
|
|
|
120
76
|
ref: inputRef,
|
|
121
77
|
type: "file",
|
|
122
78
|
accept: "image/*",
|
|
79
|
+
disabled,
|
|
123
80
|
className: "hidden",
|
|
124
81
|
onChange: (event) => {
|
|
125
82
|
handleFileChange(event.target.files);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/
|
|
1
|
+
{"version":3,"sources":["../src/files/image-picker-field.tsx"],"names":[],"mappings":";;;;;;AAIO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,KAAA,GAAQ,OAAA;AAAA,EACR,KAAA;AAAA,EACA,cAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA,GAAa,gBAAA;AAAA,EACb,QAAA,GAAW;AACb,CAAA,EASG;AACD,EAAA,MAAM,QAAA,GAAW,OAAyB,IAAI,CAAA;AAE9C,EAAA,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAA2B;AACnD,IAAA,MAAM,IAAA,GAAO,QAAQ,CAAC,CAAA;AACtB,IAAA,IAAI,CAAC,QAAQ,QAAA,EAAU;AACvB,IAAA,cAAA,CAAe,IAAI,CAAA;AAAA,EACrB,CAAA;AAEA,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uBAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,2CAAA,EAA6C,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,IACnE,KAAA,mBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kEAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,SAAI,GAAA,EAAK,KAAA,EAAO,GAAA,EAAK,UAAA,EAAY,WAAU,kCAAA,EAAmC,CAAA;AAAA,sBAC/E,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0EAAA,EACb,QAAA,EAAA;AAAA,wBAAA,IAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,OAAA,EAAQ,MAAA;AAAA,YACR,IAAA,EAAK,IAAA;AAAA,YACL,QAAA;AAAA,YACA,OAAA,EAAS,MAAM,QAAA,CAAS,OAAA,EAAS,KAAA,EAAM;AAAA,YACvC,SAAA,EAAU,yEAAA;AAAA,YAEV,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,SAAA,EAAA,EAAU,MAAM,EAAA,EAAI,CAAA;AAAA,cAAE;AAAA;AAAA;AAAA,SAEzB;AAAA,QACC,QAAA,mBACC,IAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,OAAA,EAAQ,MAAA;AAAA,YACR,IAAA,EAAK,IAAA;AAAA,YACL,QAAA;AAAA,YACA,OAAA,EAAS,QAAA;AAAA,YACT,SAAA,EAAU,qDAAA;AAAA,YAEV,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,MAAM,EAAA,EAAI,CAAA;AAAA,cAAE;AAAA;AAAA;AAAA,SAEtB,GACE;AAAA,OAAA,EACN;AAAA,KAAA,EACF,CAAA,mBAEA,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,OAAA,EAAQ,SAAA;AAAA,QACR,QAAA;AAAA,QACA,OAAA,EAAS,MAAM,QAAA,CAAS,OAAA,EAAS,KAAA,EAAM;AAAA,QACvC,SAAA,EAAU,gOAAA;AAAA,QAEV,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,WAAU,kFAAA,EACd,QAAA,kBAAA,GAAA,CAAC,UAAO,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,uBAAA,EAAwB,CAAA,EACtD,CAAA;AAAA,0BACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,qCAAA,EAAsC,QAAA,EAAA,cAAA,EAAY,CAAA;AAAA,0BAClE,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iEAAA,EACb,yBAAe,wBAAA,EAClB;AAAA;AAAA;AAAA,KACF;AAAA,oBAEF,GAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAK,MAAA;AAAA,QACL,MAAA,EAAO,SAAA;AAAA,QACP,QAAA;AAAA,QACA,SAAA,EAAU,QAAA;AAAA,QACV,QAAA,EAAU,CAAC,KAAA,KAAU;AACnB,UAAA,gBAAA,CAAiB,KAAA,CAAM,OAAO,KAAK,CAAA;AACnC,UAAA,KAAA,CAAM,OAAO,KAAA,GAAQ,EAAA;AAAA,QACvB;AAAA;AAAA;AACF,GAAA,EACF,CAAA;AAEJ","file":"image-picker-field.js","sourcesContent":["import { useRef } from \"react\";\nimport { ImagePlus, Trash2, Upload } from \"lucide-react\";\nimport { Button } from \"../ui/button\";\n\nexport function ImagePickerField({\n label = \"Image\",\n value,\n onFileSelected,\n onRemove,\n description,\n previewAlt = \"Selected image\",\n disabled = false,\n}: {\n label?: string;\n /** Preview URL supplied by the parent (`blob:`, signed HTTPS, or empty). */\n value?: string;\n onFileSelected: (file: File) => void;\n onRemove?: () => void;\n description?: string;\n previewAlt?: string;\n disabled?: boolean;\n}) {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleFileChange = (files: FileList | null) => {\n const file = files?.[0];\n if (!file || disabled) return;\n onFileSelected(file);\n };\n\n return (\n <div className=\"flex flex-col gap-1.5\">\n <label className=\"text-xs font-medium text-muted-foreground\">{label}</label>\n {value ? (\n <div className=\"max-w-sm overflow-hidden rounded-xl border border-border bg-card\">\n <img src={value} alt={previewAlt} className=\"aspect-[4/3] w-full object-cover\" />\n <div className=\"flex items-center justify-between gap-2 border-t border-border px-3 py-2\">\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n disabled={disabled}\n onClick={() => inputRef.current?.click()}\n className=\"h-auto gap-1.5 p-0 text-xs font-medium text-blue-600 dark:text-blue-400\"\n >\n <ImagePlus size={13} />\n Change image\n </Button>\n {onRemove ? (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n disabled={disabled}\n onClick={onRemove}\n className=\"h-auto gap-1.5 p-0 text-xs font-medium text-red-600\"\n >\n <Trash2 size={13} />\n Remove\n </Button>\n ) : null}\n </div>\n </div>\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => inputRef.current?.click()}\n className=\"flex aspect-[4/3] h-auto max-w-sm w-full flex-col items-center justify-center gap-2 rounded-xl border-dashed bg-muted/50 px-4 py-5 text-center shadow-none hover:border-blue-300 hover:bg-blue-50/30 dark:hover:bg-blue-950/25\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-xl border border-border bg-card\">\n <Upload size={15} className=\"text-muted-foreground\" />\n </span>\n <span className=\"text-xs font-medium text-foreground\">Choose image</span>\n <span className=\"text-[11px] font-normal text-muted-foreground whitespace-normal\">\n {description ?? \"JPG, PNG, WebP or GIF.\"}\n </span>\n </Button>\n )}\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"image/*\"\n disabled={disabled}\n className=\"hidden\"\n onChange={(event) => {\n handleFileChange(event.target.files);\n event.target.value = \"\";\n }}\n />\n </div>\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
|
|
3
3
|
type LayoutCanvasResourceType = "desks" | "rooms" | "other";
|
|
4
4
|
interface LayoutCanvasRect {
|
|
@@ -52,6 +52,6 @@ interface LayoutCanvasViewProps {
|
|
|
52
52
|
searchPlaceholder?: string;
|
|
53
53
|
}
|
|
54
54
|
declare function matchesCanvasResourceSearch(resourceName: string, planName: string | undefined, query: string): boolean;
|
|
55
|
-
declare function LayoutCanvasView({ layout, rows, onResourceSelect, resourceQuickBook, searchQuery, onSearchQueryChange, searchPlaceholder, }: LayoutCanvasViewProps):
|
|
55
|
+
declare function LayoutCanvasView({ layout, rows, onResourceSelect, resourceQuickBook, searchQuery, onSearchQueryChange, searchPlaceholder, }: LayoutCanvasViewProps): React.JSX.Element;
|
|
56
56
|
|
|
57
57
|
export { type LayoutCanvasResourceQuickBook, LayoutCanvasView, type LayoutCanvasViewProps, type LayoutCanvasViewRow, matchesCanvasResourceSearch };
|
|
@@ -1,228 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useTheme } from './chunk-XU3EFSQX.js';
|
|
2
|
+
import './chunk-4Y5DBM6Z.js';
|
|
3
|
+
import { LIVE_RESOURCE_TYPE_META } from './chunk-ZIJQ7BXU.js';
|
|
4
|
+
import { Tooltip, TooltipTrigger, TooltipContent, Popover, PopoverAnchor, PopoverContent } from './chunk-4A6RCBB5.js';
|
|
5
|
+
import './chunk-RV5PMZYZ.js';
|
|
6
|
+
import './chunk-L65F4EMK.js';
|
|
7
|
+
import './chunk-PBNBLCC2.js';
|
|
8
|
+
import './chunk-VVXGQKN7.js';
|
|
9
|
+
import './chunk-7YCAAP43.js';
|
|
10
|
+
import { PageListSearchField } from './chunk-H7EX6B6N.js';
|
|
11
|
+
import './chunk-LUB7QWGU.js';
|
|
12
|
+
import { Button } from './chunk-VHINHHZQ.js';
|
|
13
|
+
import './chunk-FCY5FYJB.js';
|
|
14
|
+
import './chunk-OWNUMPUC.js';
|
|
15
|
+
import { cn } from './chunk-DMPSQ22Q.js';
|
|
2
16
|
import { useMemo, useState, useRef, useCallback, useEffect } from 'react';
|
|
3
|
-
import { Minus, Plus, Maximize2, Box, DoorOpen, Armchair,
|
|
4
|
-
import {
|
|
5
|
-
import { twMerge } from 'tailwind-merge';
|
|
6
|
-
import { Slot } from '@radix-ui/react-slot';
|
|
7
|
-
import { cva } from 'class-variance-authority';
|
|
8
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
9
|
-
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
10
|
-
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
11
|
-
import { useTheme } from 'next-themes';
|
|
12
|
-
|
|
13
|
-
// src/live-space/layout-canvas-view.tsx
|
|
17
|
+
import { Minus, Plus, Maximize2, Box, DoorOpen, Armchair, Calendar } from 'lucide-react';
|
|
18
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
14
19
|
|
|
15
20
|
// src/live-space/layout-canvas-types.ts
|
|
16
21
|
var DEFAULT_CANVAS_WIDTH = 1200;
|
|
17
22
|
var DEFAULT_CANVAS_HEIGHT = 900;
|
|
18
|
-
var LIVE_RESOURCE_TYPE_META = {
|
|
19
|
-
desks: {
|
|
20
|
-
label: "Desk",
|
|
21
|
-
rowAccent: "text-blue-700 bg-blue-50 border-blue-100",
|
|
22
|
-
Icon: Armchair,
|
|
23
|
-
iconTile: "bg-blue-50 text-blue-600 border-blue-100 dark:bg-blue-950/50 dark:text-blue-400 dark:border-blue-900/50"
|
|
24
|
-
},
|
|
25
|
-
rooms: {
|
|
26
|
-
label: "Room",
|
|
27
|
-
rowAccent: "text-orange-700 bg-orange-50 border-orange-100",
|
|
28
|
-
Icon: DoorOpen,
|
|
29
|
-
iconTile: "bg-orange-50 text-orange-600 border-orange-100 dark:bg-orange-950/50 dark:text-orange-400 dark:border-orange-900/50"
|
|
30
|
-
},
|
|
31
|
-
other: {
|
|
32
|
-
label: "Other",
|
|
33
|
-
rowAccent: "text-purple-700 bg-purple-50 border-purple-100",
|
|
34
|
-
Icon: Box,
|
|
35
|
-
iconTile: "bg-purple-50 text-purple-600 border-purple-100 dark:bg-purple-950/50 dark:text-purple-400 dark:border-purple-900/50"
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
function cn(...inputs) {
|
|
39
|
-
return twMerge(clsx(inputs));
|
|
40
|
-
}
|
|
41
|
-
var buttonVariants = cva(
|
|
42
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-all disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
43
|
-
{
|
|
44
|
-
variants: {
|
|
45
|
-
variant: {
|
|
46
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80 active:scale-[0.98]",
|
|
47
|
-
destructive: "bg-destructive text-white hover:bg-destructive/90 active:bg-destructive/80 active:scale-[0.98] focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 dark:active:bg-destructive/70",
|
|
48
|
-
outline: "border bg-background text-foreground hover:bg-accent hover:text-accent-foreground active:bg-accent/80 active:scale-[0.98] dark:bg-input/30 dark:border-input dark:hover:bg-input/50 dark:active:bg-input/60",
|
|
49
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 active:bg-secondary/70 active:scale-[0.98]",
|
|
50
|
-
ghost: "hover:bg-accent hover:text-accent-foreground active:bg-accent/90 active:scale-[0.98] dark:hover:bg-accent/50 dark:active:bg-accent/40",
|
|
51
|
-
link: "text-primary underline-offset-4 hover:underline active:text-primary/80"
|
|
52
|
-
},
|
|
53
|
-
size: {
|
|
54
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
55
|
-
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
56
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
57
|
-
icon: "size-9 rounded-md"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
defaultVariants: {
|
|
61
|
-
variant: "default",
|
|
62
|
-
size: "default"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
);
|
|
66
|
-
var Button = React.forwardRef(function Button2({ className, variant, size, asChild = false, ...props }, ref) {
|
|
67
|
-
const Comp = asChild ? Slot : "button";
|
|
68
|
-
return /* @__PURE__ */ jsx(
|
|
69
|
-
Comp,
|
|
70
|
-
{
|
|
71
|
-
ref,
|
|
72
|
-
"data-slot": "button",
|
|
73
|
-
className: cn(buttonVariants({ variant, size }), className),
|
|
74
|
-
...props
|
|
75
|
-
}
|
|
76
|
-
);
|
|
77
|
-
});
|
|
78
|
-
Button.displayName = "Button";
|
|
79
|
-
var inputVariants = cva(
|
|
80
|
-
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground border-border bg-card text-foreground flex w-full min-w-0 rounded-md border px-3 py-1 text-base transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:border-blue-400 focus-visible:ring-[3px] focus-visible:ring-blue-500/25 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-red-400 aria-invalid:ring-red-500/20 md:text-sm",
|
|
81
|
-
{
|
|
82
|
-
variants: {
|
|
83
|
-
size: {
|
|
84
|
-
sm: "h-8 text-sm",
|
|
85
|
-
default: "h-9",
|
|
86
|
-
lg: "h-10",
|
|
87
|
-
xl: "h-11"
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
defaultVariants: {
|
|
91
|
-
size: "default"
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
);
|
|
95
|
-
var Input = React.forwardRef(function Input2({ className, type, size, ...props }, ref) {
|
|
96
|
-
return /* @__PURE__ */ jsx(
|
|
97
|
-
"input",
|
|
98
|
-
{
|
|
99
|
-
ref,
|
|
100
|
-
type,
|
|
101
|
-
"data-slot": "input",
|
|
102
|
-
className: cn(inputVariants({ size }), className),
|
|
103
|
-
...props
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
});
|
|
107
|
-
function SearchField({
|
|
108
|
-
value,
|
|
109
|
-
onChange,
|
|
110
|
-
placeholder,
|
|
111
|
-
className,
|
|
112
|
-
size = "default",
|
|
113
|
-
"aria-label": ariaLabel
|
|
114
|
-
}) {
|
|
115
|
-
const heightClass = size === "lg" ? "h-11" : "h-10";
|
|
116
|
-
const iconSize = size === "lg" ? 16 : 16;
|
|
117
|
-
return /* @__PURE__ */ jsxs(
|
|
118
|
-
"div",
|
|
119
|
-
{
|
|
120
|
-
className: cn(
|
|
121
|
-
"flex items-center gap-2 rounded-md border border-border bg-card px-3 w-full focus-within:border-blue-400 focus-within:ring-[3px] focus-within:ring-blue-500/25 transition-all",
|
|
122
|
-
heightClass,
|
|
123
|
-
className
|
|
124
|
-
),
|
|
125
|
-
children: [
|
|
126
|
-
/* @__PURE__ */ jsx(Search, { size: iconSize, className: "text-muted-foreground shrink-0", strokeWidth: 2.25 }),
|
|
127
|
-
/* @__PURE__ */ jsx(
|
|
128
|
-
Input,
|
|
129
|
-
{
|
|
130
|
-
type: "search",
|
|
131
|
-
value,
|
|
132
|
-
onChange: (e) => onChange(e.target.value),
|
|
133
|
-
placeholder,
|
|
134
|
-
"aria-label": ariaLabel,
|
|
135
|
-
className: "flex-1 border-0 bg-transparent shadow-none focus-visible:ring-0 px-0 min-w-0 h-auto"
|
|
136
|
-
}
|
|
137
|
-
)
|
|
138
|
-
]
|
|
139
|
-
}
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
function PageListSearchField({
|
|
143
|
-
value,
|
|
144
|
-
onChange,
|
|
145
|
-
placeholder,
|
|
146
|
-
className
|
|
147
|
-
}) {
|
|
148
|
-
return /* @__PURE__ */ jsx(
|
|
149
|
-
SearchField,
|
|
150
|
-
{
|
|
151
|
-
value,
|
|
152
|
-
onChange,
|
|
153
|
-
placeholder,
|
|
154
|
-
className
|
|
155
|
-
}
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
function Popover({ ...props }) {
|
|
159
|
-
return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
|
|
160
|
-
}
|
|
161
|
-
function PopoverContent({
|
|
162
|
-
className,
|
|
163
|
-
align = "center",
|
|
164
|
-
sideOffset = 4,
|
|
165
|
-
...props
|
|
166
|
-
}) {
|
|
167
|
-
return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
168
|
-
PopoverPrimitive.Content,
|
|
169
|
-
{
|
|
170
|
-
"data-slot": "popover-content",
|
|
171
|
-
align,
|
|
172
|
-
sideOffset,
|
|
173
|
-
className: cn(
|
|
174
|
-
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border border-white/10 p-4 shadow-md outline-hidden",
|
|
175
|
-
className
|
|
176
|
-
),
|
|
177
|
-
...props
|
|
178
|
-
}
|
|
179
|
-
) });
|
|
180
|
-
}
|
|
181
|
-
function PopoverAnchor({ ...props }) {
|
|
182
|
-
return /* @__PURE__ */ jsx(PopoverPrimitive.Anchor, { "data-slot": "popover-anchor", ...props });
|
|
183
|
-
}
|
|
184
|
-
function TooltipProvider({
|
|
185
|
-
delayDuration = 0,
|
|
186
|
-
...props
|
|
187
|
-
}) {
|
|
188
|
-
return /* @__PURE__ */ jsx(
|
|
189
|
-
TooltipPrimitive.Provider,
|
|
190
|
-
{
|
|
191
|
-
"data-slot": "tooltip-provider",
|
|
192
|
-
delayDuration,
|
|
193
|
-
...props
|
|
194
|
-
}
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
function Tooltip({ ...props }) {
|
|
198
|
-
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
|
|
199
|
-
}
|
|
200
|
-
function TooltipTrigger({ ...props }) {
|
|
201
|
-
return /* @__PURE__ */ jsx(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
202
|
-
}
|
|
203
|
-
function TooltipContent({
|
|
204
|
-
className,
|
|
205
|
-
sideOffset = 0,
|
|
206
|
-
children,
|
|
207
|
-
...props
|
|
208
|
-
}) {
|
|
209
|
-
return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
210
|
-
TooltipPrimitive.Content,
|
|
211
|
-
{
|
|
212
|
-
"data-slot": "tooltip-content",
|
|
213
|
-
sideOffset,
|
|
214
|
-
className: cn(
|
|
215
|
-
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
216
|
-
className
|
|
217
|
-
),
|
|
218
|
-
...props,
|
|
219
|
-
children: [
|
|
220
|
-
children,
|
|
221
|
-
/* @__PURE__ */ jsx(TooltipPrimitive.Arrow, { className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
|
|
222
|
-
]
|
|
223
|
-
}
|
|
224
|
-
) });
|
|
225
|
-
}
|
|
226
23
|
function matchesCanvasResourceSearch(resourceName, planName, query) {
|
|
227
24
|
const q = query.trim().toLowerCase();
|
|
228
25
|
if (!q) return true;
|