@alfakit/core 0.1.10 → 0.1.12

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/components.css +19 -0
  3. package/dist/actions.d.ts +6 -0
  4. package/dist/actions.d.ts.map +1 -1
  5. package/dist/actions.js +21 -2
  6. package/dist/actions.js.map +1 -1
  7. package/dist/advanced-fields.d.ts +6 -0
  8. package/dist/advanced-fields.d.ts.map +1 -1
  9. package/dist/advanced-fields.js +20 -1
  10. package/dist/advanced-fields.js.map +1 -1
  11. package/dist/chart.d.ts.map +1 -1
  12. package/dist/chart.js +23 -15
  13. package/dist/chart.js.map +1 -1
  14. package/dist/conflicts.d.ts.map +1 -1
  15. package/dist/conflicts.js +3 -5
  16. package/dist/conflicts.js.map +1 -1
  17. package/dist/index.d.ts +6 -6
  18. package/dist/index.js +6 -6
  19. package/dist/item-actions.d.ts +10 -0
  20. package/dist/item-actions.d.ts.map +1 -1
  21. package/dist/item-actions.js +8 -1
  22. package/dist/item-actions.js.map +1 -1
  23. package/dist/prefetch.d.ts.map +1 -1
  24. package/dist/prefetch.js +12 -3
  25. package/dist/prefetch.js.map +1 -1
  26. package/dist/presence.d.ts +0 -4
  27. package/dist/presence.d.ts.map +1 -1
  28. package/dist/presence.js +15 -2
  29. package/dist/presence.js.map +1 -1
  30. package/dist/realtime.d.ts +8 -0
  31. package/dist/realtime.d.ts.map +1 -1
  32. package/dist/realtime.js +13 -1
  33. package/dist/realtime.js.map +1 -1
  34. package/dist/schema/actions.d.ts +10 -0
  35. package/dist/schema/actions.d.ts.map +1 -1
  36. package/dist/schema/actions.js.map +1 -1
  37. package/dist/schema/components.d.ts +5 -0
  38. package/dist/schema/components.d.ts.map +1 -1
  39. package/dist/schema/components.js.map +1 -1
  40. package/dist/schema/form.d.ts +4 -0
  41. package/dist/schema/form.d.ts.map +1 -1
  42. package/dist/schema/form.js.map +1 -1
  43. package/dist/schema/panel.d.ts +2 -0
  44. package/dist/schema/panel.d.ts.map +1 -1
  45. package/dist/schema/panel.js.map +1 -1
  46. package/dist/schema/widgets.d.ts +5 -0
  47. package/dist/schema/widgets.d.ts.map +1 -1
  48. package/dist/standalone.d.ts +7 -0
  49. package/dist/standalone.d.ts.map +1 -1
  50. package/dist/standalone.js +42 -6
  51. package/dist/standalone.js.map +1 -1
  52. package/dist/starter-kit.d.ts.map +1 -1
  53. package/dist/starter-kit.js +17 -2
  54. package/dist/starter-kit.js.map +1 -1
  55. package/dist/theme.d.ts.map +1 -1
  56. package/dist/theme.js +2 -1
  57. package/dist/theme.js.map +1 -1
  58. package/package.json +1 -1
@@ -144,6 +144,14 @@ export declare const PANEL_TOAST_OFFSET: {
144
144
  top: string;
145
145
  };
146
146
  export type SonnerPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
147
+ /**
148
+ * The direction overlays anchored to a screen edge (the toaster, the schema inspector's
149
+ * sheet) are placed by: the panel's reading direction, except in starter kit mode, where
150
+ * the host app owns `<html dir>` and its layout (the kit's sidebar stays on the left in a
151
+ * right-to-left panel language). There they take the document's side, so "top end" never
152
+ * lands on the kit's sidebar, while their content keeps the panel's direction (W-D-03).
153
+ */
154
+ export declare function overlayPlacementDirection(direction: 'ltr' | 'rtl', starterKit: boolean | undefined): 'ltr' | 'rtl';
147
155
  /**
148
156
  * The toaster position for the panel's `toastPosition()` (logical: `start`/`end`) in the
149
157
  * current reading direction. Defaults to the top end.
@@ -1 +1 @@
1
- {"version":3,"file":"realtime.d.ts","names":[],"sources":["../src/realtime.ts"],"mappings":";;;;;qBAKa;;qBAGA;;qBAGA;KAER,wBAAwB,SAAS;KACjC,iBAAiB,SAAS;;iBAGd;EACf,aAAa,UAAU;EACvB,8BAA8B,UAAU;EACxC,QAAQ,eAAe,UAAU;EACjC,eAAe,eAAe,WAAW;;;iBAI1B,gCAAgC;EAC/C,KAAK,WAAW;EAChB,QAAQ,WAAW;EACnB,QAAQ,WAAW;EACnB,SAAS,eAAe,MAAM;EAC9B,kBAAkB,eAAe,WAAW,MAAM;;;iBAInC;EACf,QAAQ,kBAAkB;EAC1B,MAAM,kBAAkB;EACxB,OAAO;EACP;;;;;;wBAOc,WAAW;;YAiBf,iBAAiB;;YAGjB,wBAAwB;EAClC;EACA;;;;;;YAOU,eACV,SAAS,0BACN,8BAA8B,QAAQ;KAEtC,gBAAgB,sBAAsB,QAAQ;;;;;wBAgBnC,kBACd,QAAQ,mCACR;EAAW,OAAO,WAAW;EAAoB;;;wBAenC,oBAAoB;;wBAKpB;;;;;;wBASA,eAAe,QAAQ;;wBAyDvB;;wBASA,mBAAmB;;wBAOnB,cAAc;EAAW,SAAS;;;;;;;wBAmBlC,eAAe,kCAC7B,MAAM,UACN,MAAM,GACN;EAEA,SAAS,uBAAuB,0BAA0B;EAC1D;;;;;;;wBAiCc,SACd,UAAU,MAAM,kCAChB;EAAW,OAAO;EAAiB;;;qBAgCxB;;iBAGI;EACf;;EAEA;EACA;;EAEA;;EAEA;;;;;;wBA2Bc,uBACd,qBACA,WAAW,QAAQ,uBACnB;EAAW;EAA+B,OAAO;;iBA2BlC;;EAEf;;EAEA,OAAO;;EAEP,iBAAiB,cAAc;;EAE/B;;;;;;;wBAQc,yBAAyB,SAAS;;wBA6ClC;;wBAOA,4BAA4B;;;;;;qBAe/B;EAAsB;;YAEvB;;;;;wBAOI,qBACd,UAAU,kCACV,2BACC"}
1
+ {"version":3,"file":"realtime.d.ts","names":[],"sources":["../src/realtime.ts"],"mappings":";;;;;qBAKa;;qBAGA;;qBAGA;KAER,wBAAwB,SAAS;KACjC,iBAAiB,SAAS;;iBAGd;EACf,aAAa,UAAU;EACvB,8BAA8B,UAAU;EACxC,QAAQ,eAAe,UAAU;EACjC,eAAe,eAAe,WAAW;;;iBAI1B,gCAAgC;EAC/C,KAAK,WAAW;EAChB,QAAQ,WAAW;EACnB,QAAQ,WAAW;EACnB,SAAS,eAAe,MAAM;EAC9B,kBAAkB,eAAe,WAAW,MAAM;;;iBAInC;EACf,QAAQ,kBAAkB;EAC1B,MAAM,kBAAkB;EACxB,OAAO;EACP;;;;;;wBAOc,WAAW;;YAiBf,iBAAiB;;YAGjB,wBAAwB;EAClC;EACA;;;;;;YAOU,eACV,SAAS,0BACN,8BAA8B,QAAQ;KAEtC,gBAAgB,sBAAsB,QAAQ;;;;;wBAgBnC,kBACd,QAAQ,mCACR;EAAW,OAAO,WAAW;EAAoB;;;wBAenC,oBAAoB;;wBAKpB;;;;;;wBASA,eAAe,QAAQ;;wBAyDvB;;wBASA,mBAAmB;;wBAOnB,cAAc;EAAW,SAAS;;;;;;;wBAmBlC,eAAe,kCAC7B,MAAM,UACN,MAAM,GACN;EAEA,SAAS,uBAAuB,0BAA0B;EAC1D;;;;;;;wBAiCc,SACd,UAAU,MAAM,kCAChB;EAAW,OAAO;EAAiB;;;qBAgCxB;;iBAGI;EACf;;EAEA;EACA;;EAEA;;EAEA;;;;;;wBA2Bc,uBACd,qBACA,WAAW,QAAQ,uBACnB;EAAW;EAA+B,OAAO;;iBA2BlC;;EAEf;;EAEA,OAAO;;EAEP,iBAAiB,cAAc;;EAE/B;;;;;;;wBAQc,yBAAyB,SAAS;;wBA6ClC;;wBAOA,4BAA4B;;;;;;qBAe/B;EAAsB;;YAEvB;;;;;;;;wBAUI,0BACd,0BACA;;;;;wBAYc,qBACd,UAAU,kCACV,2BACC"}
package/dist/realtime.js CHANGED
@@ -239,6 +239,18 @@ function onDatabaseNotificationsSent(callback) {
239
239
  */
240
240
  const PANEL_TOAST_OFFSET = { top: "4.5rem" };
241
241
  /**
242
+ * The direction overlays anchored to a screen edge (the toaster, the schema inspector's
243
+ * sheet) are placed by: the panel's reading direction, except in starter kit mode, where
244
+ * the host app owns `<html dir>` and its layout (the kit's sidebar stays on the left in a
245
+ * right-to-left panel language). There they take the document's side, so "top end" never
246
+ * lands on the kit's sidebar, while their content keeps the panel's direction (W-D-03).
247
+ */
248
+ function overlayPlacementDirection(direction, starterKit) {
249
+ if (starterKit !== true) return direction;
250
+ if (typeof document === "undefined") return "ltr";
251
+ return document.documentElement.dir.toLowerCase() === "rtl" ? "rtl" : "ltr";
252
+ }
253
+ /**
242
254
  * The toaster position for the panel's `toastPosition()` (logical: `start`/`end`) in the
243
255
  * current reading direction. Defaults to the top end.
244
256
  */
@@ -248,6 +260,6 @@ function resolveToastPosition(position, direction) {
248
260
  return `${vertical}-${horizontal === "start" === (direction === "ltr") ? "left" : "right"}`;
249
261
  }
250
262
  //#endregion
251
- export { BROADCAST_NOTIFICATION, DATABASE_NOTIFICATIONS_EVENT, DATABASE_NOTIFICATIONS_SENT, PANEL_TOAST_OFFSET, RECORD_CHANGED_EVENT, acquireChannel, announceDatabaseNotificationsSent, configureRealtime, currentSocketId, getEcho, isRealtimeEnabled, listenForRecordChanges, onDatabaseNotificationsSent, realtimeHeaders, realtimeSettings, resetRealtime, resolveEcho, resolveToastPosition, subscribeToNotifications, withEcho };
263
+ export { BROADCAST_NOTIFICATION, DATABASE_NOTIFICATIONS_EVENT, DATABASE_NOTIFICATIONS_SENT, PANEL_TOAST_OFFSET, RECORD_CHANGED_EVENT, acquireChannel, announceDatabaseNotificationsSent, configureRealtime, currentSocketId, getEcho, isRealtimeEnabled, listenForRecordChanges, onDatabaseNotificationsSent, overlayPlacementDirection, realtimeHeaders, realtimeSettings, resetRealtime, resolveEcho, resolveToastPosition, subscribeToNotifications, withEcho };
252
264
 
253
265
  //# sourceMappingURL=realtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"realtime.js","names":[],"sources":["../src/realtime.ts"],"sourcesContent":["import type { NotificationSchema } from './schema/notifications'\nimport type { ToastPosition } from './schema/panel'\nimport type { RealtimeSchema } from './schema/realtime'\n\n/** Broadcast type of a toast pushed with `Notification::broadcast()`. */\nexport const BROADCAST_NOTIFICATION = 'alfakit.notification'\n\n/** Broadcast type sent by `sendToDatabase(..., isEventDispatched: true)`. */\nexport const DATABASE_NOTIFICATIONS_SENT = 'alfakit.database-notifications.sent'\n\n/** Window event the notifications menu listens to, to reload itself. */\nexport const DATABASE_NOTIFICATIONS_EVENT = 'alfakit:database-notifications-sent'\n\ntype NotificationCallback = (payload: Record<string, unknown>) => void\ntype EventCallback = (payload: Record<string, unknown>) => void\n\n/** The part of a Laravel Echo private channel Alfakit uses. */\nexport interface EchoChannelLike {\n notification(callback: NotificationCallback): unknown\n stopListeningForNotification?(callback: NotificationCallback): unknown\n listen?(event: string, callback: EventCallback): unknown\n stopListening?(event: string, callback?: EventCallback): unknown\n}\n\n/** The part of a Laravel Echo presence channel Alfakit uses (`Echo.join()`). */\nexport interface EchoPresenceChannelLike extends EchoChannelLike {\n here(callback: (members: unknown[]) => void): unknown\n joining(callback: (member: unknown) => void): unknown\n leaving(callback: (member: unknown) => void): unknown\n whisper?(event: string, data: Record<string, unknown>): unknown\n listenForWhisper?(event: string, callback: (data: Record<string, unknown>) => void): unknown\n}\n\n/** The part of Laravel Echo Alfakit uses (`window.Echo`). */\nexport interface EchoLike {\n private(channel: string): EchoChannelLike\n join?(channel: string): EchoPresenceChannelLike\n leave?(channel: string): void\n socketId?(): string | undefined\n}\n\n/**\n * The app's Laravel Echo instance, when one is set up as `window.Echo` (or was created by\n * `resolveEcho()`). Always null on the server, so SSR never touches it.\n */\nexport function getEcho(): EchoLike | null {\n if (typeof window === 'undefined') {\n return null\n }\n\n const echo = (window as unknown as { Echo?: unknown }).Echo\n\n if (echo && typeof (echo as EchoLike).private === 'function') {\n return echo as EchoLike\n }\n\n return createdEcho\n}\n\n// ---------------------------------------------------------------- Connection\n\n/** The settings `configureRealtime()` takes (`PanelSchema.realtime`). */\nexport type RealtimeConfig = RealtimeSchema\n\n/** Options for creating Echo: the panel's Echo options plus its auth endpoint and CSRF token. */\nexport type EchoConnectionOptions = Record<string, unknown> & {\n authEndpoint?: string\n csrfToken?: string\n}\n\n/**\n * Creates the Echo instance when the app has no `window.Echo` (`createAlfakit({ echo })`),\n * e.g. `(options) => new Echo({ ...options, broadcaster: 'reverb', Pusher })`.\n */\nexport type EchoFactory = (\n options: EchoConnectionOptions,\n) => EchoLike | null | undefined | Promise<EchoLike | null | undefined>\n\ntype ModuleLoader = (specifier: string) => Promise<Record<string, unknown>>\n\nlet realtimeConfig: (RealtimeConfig & { csrfToken?: string }) | null = null\nlet echoFactory: EchoFactory | null = null\nlet createdEcho: EchoLike | null = null\nlet pendingEcho: Promise<EchoLike | null> | null = null\n\n// The packages are optional peers the app installs: the specifier is a variable so bundlers\n// don't require them, and a missing package just means \"no Echo\".\nlet loadModule: ModuleLoader = (specifier) =>\n import(/* @vite-ignore */ /* webpackIgnore: true */ specifier) as Promise<Record<string, unknown>>\n\n/**\n * Set the panel's realtime settings (renderers call this with `panel.realtime` and the\n * CSRF token) and, optionally, an Echo instance or factory from `createAlfakit({ echo })`.\n */\nexport function configureRealtime(\n config: RealtimeConfig | null | undefined,\n options: { echo?: EchoLike | EchoFactory | null; csrfToken?: string } = {},\n): void {\n realtimeConfig = config ? { ...config, csrfToken: options.csrfToken } : null\n\n if (options.echo !== undefined) {\n if (typeof options.echo === 'function') {\n echoFactory = options.echo\n } else {\n createdEcho = options.echo\n echoFactory = null\n }\n }\n}\n\n/** The settings given to `configureRealtime()`. */\nexport function realtimeSettings(): RealtimeConfig | null {\n return realtimeConfig\n}\n\n/** Whether `Panel::realtime()` is on for this page. */\nexport function isRealtimeEnabled(): boolean {\n return Boolean(realtimeConfig?.live)\n}\n\n/**\n * The Echo instance to use: `window.Echo`, one made by the `createAlfakit({ echo })`\n * factory, or (with `config('alfakit.broadcasting.echo')`) one made from `laravel-echo`\n * and `pusher-js` if the app installed them. Null when none is available or on the server.\n */\nexport function resolveEcho(): Promise<EchoLike | null> {\n const existing = getEcho()\n\n if (existing || typeof window === 'undefined') {\n return Promise.resolve(existing)\n }\n\n pendingEcho ??= createEcho().then((echo) => {\n createdEcho = echo ?? null\n\n // Try again on the next call when nothing could be created.\n if (!createdEcho) pendingEcho = null\n\n return createdEcho\n })\n\n return pendingEcho\n}\n\nasync function createEcho(): Promise<EchoLike | null> {\n const config = realtimeConfig\n const options: EchoConnectionOptions = {\n ...(config?.echo ?? {}),\n ...(config?.authEndpoint ? { authEndpoint: config.authEndpoint } : {}),\n ...(config?.csrfToken ? { csrfToken: config.csrfToken } : {}),\n }\n\n try {\n if (echoFactory) {\n return (await echoFactory(options)) ?? null\n }\n\n if (!config?.live || !config.echo) {\n return null\n }\n\n const [echoModule, pusherModule] = await Promise.all([\n loadModule('laravel-echo'),\n loadModule('pusher-js'),\n ])\n const Echo = (echoModule.default ?? echoModule.Echo) as\n (new (options: Record<string, unknown>) => EchoLike) | undefined\n const Pusher = pusherModule.default ?? pusherModule.Pusher\n\n if (typeof Echo !== 'function') {\n return null\n }\n\n ;(window as unknown as { Pusher?: unknown }).Pusher ??= Pusher\n\n return new Echo({ broadcaster: 'reverb', ...options, Pusher })\n } catch {\n return null\n }\n}\n\n/** The socket id of the current Echo connection, sent as `X-Socket-ID` so Laravel's `toOthers()` skips this tab. */\nexport function currentSocketId(): string | undefined {\n try {\n return getEcho()?.socketId?.() || undefined\n } catch {\n return undefined\n }\n}\n\n/** `X-Socket-ID` when connected (merged into the requests of the renderers). */\nexport function realtimeHeaders(): Record<string, string> {\n const id = currentSocketId()\n\n return id ? { 'X-Socket-ID': id } : {}\n}\n\n/** Forget the connection and settings (tests). */\nexport function resetRealtime(options: { loader?: ModuleLoader } = {}): void {\n realtimeConfig = null\n echoFactory = null\n createdEcho = null\n pendingEcho = null\n channelRefs.clear()\n\n if (options.loader) loadModule = options.loader\n}\n\n// ---------------------------------------------------------------- Shared channels\n\nconst channelRefs = new Map<string, number>()\n\n/**\n * Use a channel of `echo` until the returned release function is called. Echo shares a\n * channel object per name, so it is left only when its last user releases it (a record's\n * presence avatars and conflict banner share its presence channel).\n */\nexport function acquireChannel<T extends 'private' | 'presence'>(\n echo: EchoLike,\n kind: T,\n name: string,\n): {\n channel: T extends 'presence' ? EchoPresenceChannelLike : EchoChannelLike\n release: () => void\n} | null {\n const channel = kind === 'presence' ? echo.join?.(name) : echo.private(name)\n\n if (!channel) return null\n\n const key = name\n channelRefs.set(key, (channelRefs.get(key) ?? 0) + 1)\n let released = false\n\n return {\n channel: channel as T extends 'presence' ? EchoPresenceChannelLike : EchoChannelLike,\n release: () => {\n if (released) return\n released = true\n\n const count = (channelRefs.get(key) ?? 1) - 1\n\n if (count <= 0) {\n channelRefs.delete(key)\n echo.leave?.(name)\n } else {\n channelRefs.set(key, count)\n }\n },\n }\n}\n\n/**\n * Run `connect` with Echo as soon as it is available: right away with `window.Echo`, else\n * once `resolveEcho()` settles. `onUnavailable` runs when there is no Echo. Returns the\n * cleanup, which also cancels a pending connection.\n */\nexport function withEcho(\n connect: (echo: EchoLike) => (() => void) | void,\n options: { echo?: EchoLike | null; onUnavailable?: () => (() => void) | void } = {},\n): () => void {\n let cleanup: (() => void) | void\n let active = true\n\n const start = (echo: EchoLike | null) => {\n if (!active) return\n\n cleanup = echo ? connect(echo) : options.onUnavailable?.()\n }\n\n if (options.echo !== undefined) {\n start(options.echo)\n } else {\n const echo = getEcho()\n\n if (echo || typeof window === 'undefined') {\n start(echo)\n } else {\n void resolveEcho().then(start)\n }\n }\n\n return () => {\n active = false\n cleanup?.()\n }\n}\n\n// ---------------------------------------------------------------- Record changes\n\n/** Echo event of `RecordChanged` (`broadcastAs()` is `alfakit.record`). */\nexport const RECORD_CHANGED_EVENT = '.alfakit.record'\n\n/** A record was created, updated, deleted or restored. Keys only: refetch to see the data. */\nexport interface RecordChange {\n event: 'created' | 'updated' | 'deleted' | 'restored'\n /** The model class with `-` for `\\\\`. */\n model: string\n key: string | number\n /** The user who changed it, when known. */\n by?: string | number | null\n /** Milliseconds since the epoch. */\n at?: number\n}\n\nfunction asRecordChange(payload: Record<string, unknown>): RecordChange | null {\n const event = payload.event\n const key = payload.key\n\n if (\n (event !== 'created' && event !== 'updated' && event !== 'deleted' && event !== 'restored') ||\n (typeof key !== 'string' && typeof key !== 'number')\n ) {\n return null\n }\n\n return {\n event,\n key,\n model: typeof payload.model === 'string' ? payload.model : '',\n by: typeof payload.by === 'string' || typeof payload.by === 'number' ? payload.by : null,\n at: typeof payload.at === 'number' ? payload.at : Date.now(),\n }\n}\n\n/**\n * Listen for record changes on a channel (`private` for models, `presence` for a record).\n * Returns the cleanup (a no-op without Echo).\n */\nexport function listenForRecordChanges(\n channelName: string,\n callback: (change: RecordChange) => void,\n options: { kind?: 'private' | 'presence'; echo?: EchoLike | null } = {},\n): () => void {\n return withEcho(\n (echo) => {\n const acquired = acquireChannel(echo, options.kind ?? 'private', channelName)\n\n if (!acquired) return\n\n const listener: EventCallback = (payload) => {\n const change = asRecordChange(payload)\n\n if (change) callback(change)\n }\n\n acquired.channel.listen?.(RECORD_CHANGED_EVENT, listener)\n\n return () => {\n acquired.channel.stopListening?.(RECORD_CHANGED_EVENT, listener)\n acquired.release()\n }\n },\n { echo: options.echo },\n )\n}\n\n// ---------------------------------------------------------------- Notifications\n\nexport interface RealtimeSubscriptionOptions {\n /** The user's private channel (`PanelSchema.realtime.channel`). */\n channel: string\n /** Defaults to `window.Echo`, or the Echo `resolveEcho()` creates. */\n echo?: EchoLike | null\n /** A broadcast toast arrived. */\n onNotification: (notification: NotificationSchema) => void\n /** A database notification was stored: reload the bell. */\n onDatabaseNotificationsSent?: () => void\n}\n\n/**\n * Listen for the user's broadcast notifications. Returns the unsubscribe function (a no-op\n * when Echo is missing). Each toast is delivered once, even if Echo reconnects or the\n * subscription is made twice (React strict mode).\n */\nexport function subscribeToNotifications(options: RealtimeSubscriptionOptions): () => void {\n if (!options.channel) {\n return () => {}\n }\n\n const seen = new Set<string>()\n\n return withEcho(\n (echo) => {\n let active = true\n\n const callback: NotificationCallback = (payload) => {\n if (!active) return\n\n if (payload.type === DATABASE_NOTIFICATIONS_SENT) {\n options.onDatabaseNotificationsSent?.()\n\n return\n }\n\n if (payload.format !== 'alfakit') return\n\n const id = typeof payload.id === 'string' ? payload.id : ''\n\n if (id !== '' && seen.has(id)) return\n if (id !== '') seen.add(id)\n\n const { type: _type, ...notification } = payload\n\n options.onNotification(notification as unknown as NotificationSchema)\n }\n\n const channel = echo.private(options.channel)\n channel.notification(callback)\n\n return () => {\n active = false\n channel.stopListeningForNotification?.(callback)\n }\n },\n { echo: options.echo },\n )\n}\n\n/** Tell mounted notification menus to reload (`DATABASE_NOTIFICATIONS_EVENT`). */\nexport function announceDatabaseNotificationsSent(): void {\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent(DATABASE_NOTIFICATIONS_EVENT))\n }\n}\n\n/** Run `callback` whenever a database notification is announced. Returns the cleanup. */\nexport function onDatabaseNotificationsSent(callback: () => void): () => void {\n if (typeof window === 'undefined') {\n return () => {}\n }\n\n window.addEventListener(DATABASE_NOTIFICATIONS_EVENT, callback)\n\n return () => window.removeEventListener(DATABASE_NOTIFICATIONS_EVENT, callback)\n}\n\n/**\n * Offset of the panel's toaster: toasts at the top start below the sticky top bar (3.5rem\n * high) instead of covering the breadcrumbs, search and switchers, on phones too (where they\n * span the screen). The other sides keep sonner's defaults.\n */\nexport const PANEL_TOAST_OFFSET: { top: string } = { top: '4.5rem' }\n\nexport type SonnerPosition =\n 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\n\n/**\n * The toaster position for the panel's `toastPosition()` (logical: `start`/`end`) in the\n * current reading direction. Defaults to the top end.\n */\nexport function resolveToastPosition(\n position: ToastPosition | null | undefined,\n direction: 'ltr' | 'rtl',\n): SonnerPosition {\n const [vertical, horizontal] = (position ?? 'top-end').split('-') as [\n 'top' | 'bottom',\n 'start' | 'center' | 'end',\n ]\n\n if (horizontal === 'center') {\n return `${vertical}-center`\n }\n\n const isLeft = (horizontal === 'start') === (direction === 'ltr')\n\n return `${vertical}-${isLeft ? 'left' : 'right'}`\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"realtime.js","names":[],"sources":["../src/realtime.ts"],"sourcesContent":["import type { NotificationSchema } from './schema/notifications'\nimport type { ToastPosition } from './schema/panel'\nimport type { RealtimeSchema } from './schema/realtime'\n\n/** Broadcast type of a toast pushed with `Notification::broadcast()`. */\nexport const BROADCAST_NOTIFICATION = 'alfakit.notification'\n\n/** Broadcast type sent by `sendToDatabase(..., isEventDispatched: true)`. */\nexport const DATABASE_NOTIFICATIONS_SENT = 'alfakit.database-notifications.sent'\n\n/** Window event the notifications menu listens to, to reload itself. */\nexport const DATABASE_NOTIFICATIONS_EVENT = 'alfakit:database-notifications-sent'\n\ntype NotificationCallback = (payload: Record<string, unknown>) => void\ntype EventCallback = (payload: Record<string, unknown>) => void\n\n/** The part of a Laravel Echo private channel Alfakit uses. */\nexport interface EchoChannelLike {\n notification(callback: NotificationCallback): unknown\n stopListeningForNotification?(callback: NotificationCallback): unknown\n listen?(event: string, callback: EventCallback): unknown\n stopListening?(event: string, callback?: EventCallback): unknown\n}\n\n/** The part of a Laravel Echo presence channel Alfakit uses (`Echo.join()`). */\nexport interface EchoPresenceChannelLike extends EchoChannelLike {\n here(callback: (members: unknown[]) => void): unknown\n joining(callback: (member: unknown) => void): unknown\n leaving(callback: (member: unknown) => void): unknown\n whisper?(event: string, data: Record<string, unknown>): unknown\n listenForWhisper?(event: string, callback: (data: Record<string, unknown>) => void): unknown\n}\n\n/** The part of Laravel Echo Alfakit uses (`window.Echo`). */\nexport interface EchoLike {\n private(channel: string): EchoChannelLike\n join?(channel: string): EchoPresenceChannelLike\n leave?(channel: string): void\n socketId?(): string | undefined\n}\n\n/**\n * The app's Laravel Echo instance, when one is set up as `window.Echo` (or was created by\n * `resolveEcho()`). Always null on the server, so SSR never touches it.\n */\nexport function getEcho(): EchoLike | null {\n if (typeof window === 'undefined') {\n return null\n }\n\n const echo = (window as unknown as { Echo?: unknown }).Echo\n\n if (echo && typeof (echo as EchoLike).private === 'function') {\n return echo as EchoLike\n }\n\n return createdEcho\n}\n\n// ---------------------------------------------------------------- Connection\n\n/** The settings `configureRealtime()` takes (`PanelSchema.realtime`). */\nexport type RealtimeConfig = RealtimeSchema\n\n/** Options for creating Echo: the panel's Echo options plus its auth endpoint and CSRF token. */\nexport type EchoConnectionOptions = Record<string, unknown> & {\n authEndpoint?: string\n csrfToken?: string\n}\n\n/**\n * Creates the Echo instance when the app has no `window.Echo` (`createAlfakit({ echo })`),\n * e.g. `(options) => new Echo({ ...options, broadcaster: 'reverb', Pusher })`.\n */\nexport type EchoFactory = (\n options: EchoConnectionOptions,\n) => EchoLike | null | undefined | Promise<EchoLike | null | undefined>\n\ntype ModuleLoader = (specifier: string) => Promise<Record<string, unknown>>\n\nlet realtimeConfig: (RealtimeConfig & { csrfToken?: string }) | null = null\nlet echoFactory: EchoFactory | null = null\nlet createdEcho: EchoLike | null = null\nlet pendingEcho: Promise<EchoLike | null> | null = null\n\n// The packages are optional peers the app installs: the specifier is a variable so bundlers\n// don't require them, and a missing package just means \"no Echo\".\nlet loadModule: ModuleLoader = (specifier) =>\n import(/* @vite-ignore */ /* webpackIgnore: true */ specifier) as Promise<Record<string, unknown>>\n\n/**\n * Set the panel's realtime settings (renderers call this with `panel.realtime` and the\n * CSRF token) and, optionally, an Echo instance or factory from `createAlfakit({ echo })`.\n */\nexport function configureRealtime(\n config: RealtimeConfig | null | undefined,\n options: { echo?: EchoLike | EchoFactory | null; csrfToken?: string } = {},\n): void {\n realtimeConfig = config ? { ...config, csrfToken: options.csrfToken } : null\n\n if (options.echo !== undefined) {\n if (typeof options.echo === 'function') {\n echoFactory = options.echo\n } else {\n createdEcho = options.echo\n echoFactory = null\n }\n }\n}\n\n/** The settings given to `configureRealtime()`. */\nexport function realtimeSettings(): RealtimeConfig | null {\n return realtimeConfig\n}\n\n/** Whether `Panel::realtime()` is on for this page. */\nexport function isRealtimeEnabled(): boolean {\n return Boolean(realtimeConfig?.live)\n}\n\n/**\n * The Echo instance to use: `window.Echo`, one made by the `createAlfakit({ echo })`\n * factory, or (with `config('alfakit.broadcasting.echo')`) one made from `laravel-echo`\n * and `pusher-js` if the app installed them. Null when none is available or on the server.\n */\nexport function resolveEcho(): Promise<EchoLike | null> {\n const existing = getEcho()\n\n if (existing || typeof window === 'undefined') {\n return Promise.resolve(existing)\n }\n\n pendingEcho ??= createEcho().then((echo) => {\n createdEcho = echo ?? null\n\n // Try again on the next call when nothing could be created.\n if (!createdEcho) pendingEcho = null\n\n return createdEcho\n })\n\n return pendingEcho\n}\n\nasync function createEcho(): Promise<EchoLike | null> {\n const config = realtimeConfig\n const options: EchoConnectionOptions = {\n ...(config?.echo ?? {}),\n ...(config?.authEndpoint ? { authEndpoint: config.authEndpoint } : {}),\n ...(config?.csrfToken ? { csrfToken: config.csrfToken } : {}),\n }\n\n try {\n if (echoFactory) {\n return (await echoFactory(options)) ?? null\n }\n\n if (!config?.live || !config.echo) {\n return null\n }\n\n const [echoModule, pusherModule] = await Promise.all([\n loadModule('laravel-echo'),\n loadModule('pusher-js'),\n ])\n const Echo = (echoModule.default ?? echoModule.Echo) as\n (new (options: Record<string, unknown>) => EchoLike) | undefined\n const Pusher = pusherModule.default ?? pusherModule.Pusher\n\n if (typeof Echo !== 'function') {\n return null\n }\n\n ;(window as unknown as { Pusher?: unknown }).Pusher ??= Pusher\n\n return new Echo({ broadcaster: 'reverb', ...options, Pusher })\n } catch {\n return null\n }\n}\n\n/** The socket id of the current Echo connection, sent as `X-Socket-ID` so Laravel's `toOthers()` skips this tab. */\nexport function currentSocketId(): string | undefined {\n try {\n return getEcho()?.socketId?.() || undefined\n } catch {\n return undefined\n }\n}\n\n/** `X-Socket-ID` when connected (merged into the requests of the renderers). */\nexport function realtimeHeaders(): Record<string, string> {\n const id = currentSocketId()\n\n return id ? { 'X-Socket-ID': id } : {}\n}\n\n/** Forget the connection and settings (tests). */\nexport function resetRealtime(options: { loader?: ModuleLoader } = {}): void {\n realtimeConfig = null\n echoFactory = null\n createdEcho = null\n pendingEcho = null\n channelRefs.clear()\n\n if (options.loader) loadModule = options.loader\n}\n\n// ---------------------------------------------------------------- Shared channels\n\nconst channelRefs = new Map<string, number>()\n\n/**\n * Use a channel of `echo` until the returned release function is called. Echo shares a\n * channel object per name, so it is left only when its last user releases it (a record's\n * presence avatars and conflict banner share its presence channel).\n */\nexport function acquireChannel<T extends 'private' | 'presence'>(\n echo: EchoLike,\n kind: T,\n name: string,\n): {\n channel: T extends 'presence' ? EchoPresenceChannelLike : EchoChannelLike\n release: () => void\n} | null {\n const channel = kind === 'presence' ? echo.join?.(name) : echo.private(name)\n\n if (!channel) return null\n\n const key = name\n channelRefs.set(key, (channelRefs.get(key) ?? 0) + 1)\n let released = false\n\n return {\n channel: channel as T extends 'presence' ? EchoPresenceChannelLike : EchoChannelLike,\n release: () => {\n if (released) return\n released = true\n\n const count = (channelRefs.get(key) ?? 1) - 1\n\n if (count <= 0) {\n channelRefs.delete(key)\n echo.leave?.(name)\n } else {\n channelRefs.set(key, count)\n }\n },\n }\n}\n\n/**\n * Run `connect` with Echo as soon as it is available: right away with `window.Echo`, else\n * once `resolveEcho()` settles. `onUnavailable` runs when there is no Echo. Returns the\n * cleanup, which also cancels a pending connection.\n */\nexport function withEcho(\n connect: (echo: EchoLike) => (() => void) | void,\n options: { echo?: EchoLike | null; onUnavailable?: () => (() => void) | void } = {},\n): () => void {\n let cleanup: (() => void) | void\n let active = true\n\n const start = (echo: EchoLike | null) => {\n if (!active) return\n\n cleanup = echo ? connect(echo) : options.onUnavailable?.()\n }\n\n if (options.echo !== undefined) {\n start(options.echo)\n } else {\n const echo = getEcho()\n\n if (echo || typeof window === 'undefined') {\n start(echo)\n } else {\n void resolveEcho().then(start)\n }\n }\n\n return () => {\n active = false\n cleanup?.()\n }\n}\n\n// ---------------------------------------------------------------- Record changes\n\n/** Echo event of `RecordChanged` (`broadcastAs()` is `alfakit.record`). */\nexport const RECORD_CHANGED_EVENT = '.alfakit.record'\n\n/** A record was created, updated, deleted or restored. Keys only: refetch to see the data. */\nexport interface RecordChange {\n event: 'created' | 'updated' | 'deleted' | 'restored'\n /** The model class with `-` for `\\\\`. */\n model: string\n key: string | number\n /** The user who changed it, when known. */\n by?: string | number | null\n /** Milliseconds since the epoch. */\n at?: number\n}\n\nfunction asRecordChange(payload: Record<string, unknown>): RecordChange | null {\n const event = payload.event\n const key = payload.key\n\n if (\n (event !== 'created' && event !== 'updated' && event !== 'deleted' && event !== 'restored') ||\n (typeof key !== 'string' && typeof key !== 'number')\n ) {\n return null\n }\n\n return {\n event,\n key,\n model: typeof payload.model === 'string' ? payload.model : '',\n by: typeof payload.by === 'string' || typeof payload.by === 'number' ? payload.by : null,\n at: typeof payload.at === 'number' ? payload.at : Date.now(),\n }\n}\n\n/**\n * Listen for record changes on a channel (`private` for models, `presence` for a record).\n * Returns the cleanup (a no-op without Echo).\n */\nexport function listenForRecordChanges(\n channelName: string,\n callback: (change: RecordChange) => void,\n options: { kind?: 'private' | 'presence'; echo?: EchoLike | null } = {},\n): () => void {\n return withEcho(\n (echo) => {\n const acquired = acquireChannel(echo, options.kind ?? 'private', channelName)\n\n if (!acquired) return\n\n const listener: EventCallback = (payload) => {\n const change = asRecordChange(payload)\n\n if (change) callback(change)\n }\n\n acquired.channel.listen?.(RECORD_CHANGED_EVENT, listener)\n\n return () => {\n acquired.channel.stopListening?.(RECORD_CHANGED_EVENT, listener)\n acquired.release()\n }\n },\n { echo: options.echo },\n )\n}\n\n// ---------------------------------------------------------------- Notifications\n\nexport interface RealtimeSubscriptionOptions {\n /** The user's private channel (`PanelSchema.realtime.channel`). */\n channel: string\n /** Defaults to `window.Echo`, or the Echo `resolveEcho()` creates. */\n echo?: EchoLike | null\n /** A broadcast toast arrived. */\n onNotification: (notification: NotificationSchema) => void\n /** A database notification was stored: reload the bell. */\n onDatabaseNotificationsSent?: () => void\n}\n\n/**\n * Listen for the user's broadcast notifications. Returns the unsubscribe function (a no-op\n * when Echo is missing). Each toast is delivered once, even if Echo reconnects or the\n * subscription is made twice (React strict mode).\n */\nexport function subscribeToNotifications(options: RealtimeSubscriptionOptions): () => void {\n if (!options.channel) {\n return () => {}\n }\n\n const seen = new Set<string>()\n\n return withEcho(\n (echo) => {\n let active = true\n\n const callback: NotificationCallback = (payload) => {\n if (!active) return\n\n if (payload.type === DATABASE_NOTIFICATIONS_SENT) {\n options.onDatabaseNotificationsSent?.()\n\n return\n }\n\n if (payload.format !== 'alfakit') return\n\n const id = typeof payload.id === 'string' ? payload.id : ''\n\n if (id !== '' && seen.has(id)) return\n if (id !== '') seen.add(id)\n\n const { type: _type, ...notification } = payload\n\n options.onNotification(notification as unknown as NotificationSchema)\n }\n\n const channel = echo.private(options.channel)\n channel.notification(callback)\n\n return () => {\n active = false\n channel.stopListeningForNotification?.(callback)\n }\n },\n { echo: options.echo },\n )\n}\n\n/** Tell mounted notification menus to reload (`DATABASE_NOTIFICATIONS_EVENT`). */\nexport function announceDatabaseNotificationsSent(): void {\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent(DATABASE_NOTIFICATIONS_EVENT))\n }\n}\n\n/** Run `callback` whenever a database notification is announced. Returns the cleanup. */\nexport function onDatabaseNotificationsSent(callback: () => void): () => void {\n if (typeof window === 'undefined') {\n return () => {}\n }\n\n window.addEventListener(DATABASE_NOTIFICATIONS_EVENT, callback)\n\n return () => window.removeEventListener(DATABASE_NOTIFICATIONS_EVENT, callback)\n}\n\n/**\n * Offset of the panel's toaster: toasts at the top start below the sticky top bar (3.5rem\n * high) instead of covering the breadcrumbs, search and switchers, on phones too (where they\n * span the screen). The other sides keep sonner's defaults.\n */\nexport const PANEL_TOAST_OFFSET: { top: string } = { top: '4.5rem' }\n\nexport type SonnerPosition =\n 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\n\n/**\n * The direction overlays anchored to a screen edge (the toaster, the schema inspector's\n * sheet) are placed by: the panel's reading direction, except in starter kit mode, where\n * the host app owns `<html dir>` and its layout (the kit's sidebar stays on the left in a\n * right-to-left panel language). There they take the document's side, so \"top end\" never\n * lands on the kit's sidebar, while their content keeps the panel's direction (W-D-03).\n */\nexport function overlayPlacementDirection(\n direction: 'ltr' | 'rtl',\n starterKit: boolean | undefined,\n): 'ltr' | 'rtl' {\n if (starterKit !== true) return direction\n if (typeof document === 'undefined') return 'ltr'\n\n return document.documentElement.dir.toLowerCase() === 'rtl' ? 'rtl' : 'ltr'\n}\n\n/**\n * The toaster position for the panel's `toastPosition()` (logical: `start`/`end`) in the\n * current reading direction. Defaults to the top end.\n */\nexport function resolveToastPosition(\n position: ToastPosition | null | undefined,\n direction: 'ltr' | 'rtl',\n): SonnerPosition {\n const [vertical, horizontal] = (position ?? 'top-end').split('-') as [\n 'top' | 'bottom',\n 'start' | 'center' | 'end',\n ]\n\n if (horizontal === 'center') {\n return `${vertical}-center`\n }\n\n const isLeft = (horizontal === 'start') === (direction === 'ltr')\n\n return `${vertical}-${isLeft ? 'left' : 'right'}`\n}\n"],"mappings":"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"}
@@ -23,6 +23,11 @@ export interface ActionSchema {
23
23
  openUrlInNewTab?: boolean;
24
24
  /** `postToUrl()`: clicking sends a POST request to `url` instead of visiting it. */
25
25
  postToUrl?: boolean;
26
+ /**
27
+ * `download()`: `url` serves a file to save, so it is a plain link with the `download`
28
+ * attribute, never an Inertia visit (which would fetch the file and discard it).
29
+ */
30
+ download?: boolean;
26
31
  /** True when clicking opens a modal (confirmation and/or form) before executing. */
27
32
  hasModal?: boolean;
28
33
  /** True when the action runs server-side logic (vs. a plain link). */
@@ -187,6 +192,11 @@ export interface ActionResultFlash {
187
192
  arguments?: Record<string, unknown> | null;
188
193
  hasModal: boolean;
189
194
  };
195
+ /**
196
+ * The handler returned a file (`response()->streamDownload()`, `Storage::download()` …): a
197
+ * signed, one-time link the browser opens to save it.
198
+ */
199
+ download?: string;
190
200
  }
191
201
  //#endregion
192
202
  //# sourceMappingURL=actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","names":[],"sources":["../../src/schema/actions.ts"],"mappings":";;;;;;iBAgBiB;EACf;EACA;EACA;EACA,OAAO;EACP,eAAe;EACf,QAAQ;;EAER,UAAU;EACV;EACA,OAAO;EACP;EACA,aAAa;EACb;EACA;EACA;EACA;;EAEA;;EAEA;;EAEA;EACA;EACA,SAAS;;;;;EAKT;EACA,kBAAkB;;;;;EAKlB;;;;;EAKA;;;;;EAKA;EACA,YAAY;;EAEZ;;iBAGe;EACf;EACA;EACA,OAAO;EACP,QAAQ;EACR,UAAU;EACV,OAAO;EACP;EACA;;;;;EAKA;;EAEA;;EAEA,gBAAgB;;EAEhB;;EAEA;EACA,SAAS,MAAM,eAAe;;YAGpB,kBAAkB,eAAe;wBAE7B,cAAc,QAAQ,kBAAkB,UAAU;;iBAKjD;EACf;EACA;EACA;EACA,OAAO;EACP,YAAY;EACZ,OAAO;EACP;;EAEA;EACA,YAAY;;EAEZ,yBAAyB;;EAEzB;EACA;;EAEA;;EAEA,mBAAmB;;EAEnB,oBAAoB;;;;;EAKpB;;;;;;EAMA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;;EAEd,aAAa;;EAEb,cAAc;;;;;EAKd;EACA;;EAEA;;EAEA;EACA,UAAU;EACV,gBAAgB;EAChB,OAAO;;EAEP,qBAAqB;;;;;;EAMrB;;EAEA,qBAAqB;;EAErB,oBAAoB;;;;;EAKpB;EACA,SAAS;;;;;;iBAOM;EACf;EACA,gBAAgB;;;iBAID;EACf;EACA;EACA;EACA;;;;;EAKA;;EAEA,aAAa;IAAQ;IAAc,MAAM;;;EAEzC;IACE;IACA,YAAY;IACZ"}
1
+ {"version":3,"file":"actions.d.ts","names":[],"sources":["../../src/schema/actions.ts"],"mappings":";;;;;;iBAgBiB;EACf;EACA;EACA;EACA,OAAO;EACP,eAAe;EACf,QAAQ;;EAER,UAAU;EACV;EACA,OAAO;EACP;EACA,aAAa;EACb;EACA;EACA;EACA;;EAEA;;;;;EAKA;;EAEA;;EAEA;EACA;EACA,SAAS;;;;;EAKT;EACA,kBAAkB;;;;;EAKlB;;;;;EAKA;;;;;EAKA;EACA,YAAY;;EAEZ;;iBAGe;EACf;EACA;EACA,OAAO;EACP,QAAQ;EACR,UAAU;EACV,OAAO;EACP;EACA;;;;;EAKA;;EAEA;;EAEA,gBAAgB;;EAEhB;;EAEA;EACA,SAAS,MAAM,eAAe;;YAGpB,kBAAkB,eAAe;wBAE7B,cAAc,QAAQ,kBAAkB,UAAU;;iBAKjD;EACf;EACA;EACA;EACA,OAAO;EACP,YAAY;EACZ,OAAO;EACP;;EAEA;EACA,YAAY;;EAEZ,yBAAyB;;EAEzB;EACA;;EAEA;;EAEA,mBAAmB;;EAEnB,oBAAoB;;;;;EAKpB;;;;;;EAMA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;;EAEd,aAAa;;EAEb,cAAc;;;;;EAKd;EACA;;EAEA;;EAEA;EACA,UAAU;EACV,gBAAgB;EAChB,OAAO;;EAEP,qBAAqB;;;;;;EAMrB;;EAEA,qBAAqB;;EAErB,oBAAoB;;;;;EAKpB;EACA,SAAS;;;;;;iBAOM;EACf;EACA,gBAAgB;;;iBAID;EACf;EACA;EACA;EACA;;;;;EAKA;;EAEA,aAAa;IAAQ;IAAc,MAAM;;;EAEzC;IACE;IACA,YAAY;IACZ;;;;;;EAMF"}
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","names":[],"sources":["../../src/schema/actions.ts"],"sourcesContent":["import type {\n ActionVariant,\n Alignment,\n Attributes,\n Color,\n IconName,\n IconPosition,\n RecordKey,\n Size,\n Width,\n} from './common'\nimport type { SchemaComponent } from './components'\nimport type { FormPayload } from './form'\nimport type { NotificationSchema } from './notifications'\n\n/** A button descriptor. The modal (if any) is fetched lazily from the modal endpoint. */\nexport interface ActionSchema {\n type: 'Action' | 'BulkAction'\n name: string\n label?: string | null\n icon?: IconName\n iconPosition?: IconPosition\n color?: Color\n /** `'badge'`: `badge()` without an argument, the trigger rendered as a badge. */\n variant?: ActionVariant | 'badge'\n outlined?: boolean\n size?: Size\n badge?: string | number\n badgeColor?: Color\n tooltip?: string\n disabled?: boolean\n url?: string\n openUrlInNewTab?: boolean\n /** `postToUrl()`: clicking sends a POST request to `url` instead of visiting it. */\n postToUrl?: boolean\n /** True when clicking opens a modal (confirmation and/or form) before executing. */\n hasModal?: boolean\n /** True when the action runs server-side logic (vs. a plain link). */\n hasAction?: boolean\n keyBindings?: string[]\n record?: RecordKey\n /**\n * `Action::formId()`: the page form (`form`, `form:{name}`) this button submits. The\n * runner sends that form's state as the action's data, wherever the button is.\n */\n formId?: string\n extraAttributes?: Attributes\n /**\n * A record action that receives the table's selection (`accessSelectedRecords()`): the\n * renderer sends the selected keys with it (`selectedRecordsArguments()`).\n */\n accessSelectedRecords?: boolean\n /**\n * `labeledFrom('md')`: icon only below this breakpoint, label from it up (the label\n * stays the accessible name).\n */\n labeledFrom?: 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n /**\n * `makeModalSubmitAction()`: the button submits the modal it sits in, running the\n * parent action with `arguments`.\n */\n submitsModal?: boolean\n arguments?: Record<string, unknown>\n /** `openDatabaseNotifications()`: clicking opens the database notifications panel. */\n opensDatabaseNotifications?: boolean\n}\n\nexport interface ActionGroupSchema {\n type: 'ActionGroup'\n label?: string\n icon?: IconName\n color?: Color\n variant?: ActionVariant\n size?: Size\n tooltip?: string\n dropdownPlacement?: string\n /**\n * `dropdown(false)`: a nested group is a divided section of its parent dropdown; a\n * top-level group renders its actions inline.\n */\n dropdown?: boolean\n /** `buttonGroup()`: the actions render as joined buttons. */\n buttonGroup?: boolean\n /** `dropdownWidth()`: `xs` … `7xl`. */\n dropdownWidth?: Width\n /** `dropdownOffset()`: pixels between the trigger and the dropdown. */\n dropdownOffset?: number\n /** `maxHeight()`: a CSS length; the dropdown scrolls beyond it. */\n maxHeight?: string\n actions: Array<ActionSchema | ActionGroupSchema>\n}\n\nexport type AnyActionSchema = ActionSchema | ActionGroupSchema\n\nexport function isActionGroup(action: AnyActionSchema): action is ActionGroupSchema {\n return action.type === 'ActionGroup'\n}\n\n/** Response of the modal endpoint. */\nexport interface ActionModalSchema {\n name: string\n heading?: string\n description?: string\n icon?: IconName\n iconColor?: Color\n width: Width\n slideOver?: boolean\n /** `slideOverPosition(SlideOverPosition::Start)`: the slide-over enters from the start side. */\n slideOverPosition?: 'start' | 'end'\n alignment?: Alignment\n /** `modalFooterActionsAlignment()`: footer buttons only (`alignment` moves the heading too). */\n footerActionsAlignment?: Alignment\n /** `stickyModalHeader()`: the heading stays visible while the content scrolls. */\n stickyHeader?: boolean\n stickyFooter?: boolean\n /** `modalClickThrough()`: no backdrop; the page underneath stays usable. */\n clickThrough?: boolean\n /** `extraModalWindowAttributes()` */\n windowAttributes?: Attributes\n /** `extraModalOverlayAttributes()` */\n overlayAttributes?: Attributes\n /**\n * `cancelParentActionsOnClose()`: closing this nested modal closes its parents too\n * (`true`), or the parents up to and including the named one.\n */\n cancelParentActionsOnClose?: true | string\n /**\n * `overlayParentActions()`: this nested modal opens on top of its parent, which stays\n * visible. Without it the parent modal is hidden while this one is open (Filament's\n * default).\n */\n overlayParent?: boolean\n autofocus: boolean\n closeByClickingAway: boolean\n closeByEscaping: boolean\n closeButton: boolean\n submitLabel?: string\n cancelLabel?: string\n submitColor?: Color\n /** Icon of the submit button (`modalSubmitAction(fn (Action $a) => $a->icon(…))`). */\n submitIcon?: IconName\n /** Colour of the cancel button (`modalCancelAction(fn (Action $a) => $a->color(…))`). */\n cancelColor?: Color\n /**\n * Ask before closing the modal (and before leaving the page) while its form has unsaved\n * changes: `unsavedChangesAlert()` or the panel's `unsavedChangesAlerts()`.\n */\n unsavedChangesAlert?: boolean\n requiresConfirmation?: boolean\n /** The form is a wizard (`->steps()`): the submit button shows on the last step only. */\n wizard?: boolean\n /** Ask for the current password (`requiresPasswordConfirmation()`, not confirmed recently). */\n passwordConfirmation?: boolean\n content?: SchemaComponent[]\n contentFooter?: SchemaComponent[]\n form?: FormPayload\n /** Footer buttons; they run as nested actions of this one (and may open their own modal). */\n extraFooterActions?: AnyActionSchema[]\n /**\n * `CreateAction`: label of the \"Create & create another\" button (absent with\n * `createAnother(false)`). It runs the action with the `another` argument; the modal\n * then stays open with a fresh form.\n */\n createAnotherLabel?: string\n /** `createAnotherAction()`: colour of the \"Create & create another\" button (outline). */\n createAnotherColor?: Color\n /** `createAnotherAction()`: icon of the \"Create & create another\" button. */\n createAnotherIcon?: IconName\n /**\n * `preserveFormDataWhenCreatingAnother()`: `true` keeps every top-level field after\n * \"Create & create another\", a list keeps the named fields only.\n */\n preserveFormData?: boolean | string[]\n record?: RecordKey\n}\n\n/**\n * Response of the modal endpoint when `mountUsing()` halted or cancelled the action: the\n * modal doesn't open; the notifications it sent are shown.\n */\nexport interface ActionModalCancelledResponse {\n cancelled: true\n notifications?: NotificationSchema[]\n}\n\n/** Flashed by the action endpoint after a run. */\nexport interface ActionResultFlash {\n name: string\n status: 'success' | 'halted' | 'cancelled'\n closeModal?: boolean\n deselectRecords?: boolean | null\n /**\n * A nested action asked to close the modals it was opened from (`cancelParentActions()`):\n * all of them (`true`), or those up to and including the named parent.\n */\n cancelParentActions?: boolean | string | null\n /** `fillData()`: values a nested action wrote into its parents' forms, per parent name. */\n parentData?: Array<{ name: string; data: Record<string, unknown> }>\n /** `replaceMountedAction()`: the action that opens (or runs) in place of this one. */\n replaceMountedAction?: {\n name: string\n arguments?: Record<string, unknown> | null\n hasModal: boolean\n }\n}\n"],"mappings":";AA8FA,SAAgB,cAAc,QAAsD;CAClF,OAAO,OAAO,SAAS;AACzB"}
1
+ {"version":3,"file":"actions.js","names":[],"sources":["../../src/schema/actions.ts"],"sourcesContent":["import type {\n ActionVariant,\n Alignment,\n Attributes,\n Color,\n IconName,\n IconPosition,\n RecordKey,\n Size,\n Width,\n} from './common'\nimport type { SchemaComponent } from './components'\nimport type { FormPayload } from './form'\nimport type { NotificationSchema } from './notifications'\n\n/** A button descriptor. The modal (if any) is fetched lazily from the modal endpoint. */\nexport interface ActionSchema {\n type: 'Action' | 'BulkAction'\n name: string\n label?: string | null\n icon?: IconName\n iconPosition?: IconPosition\n color?: Color\n /** `'badge'`: `badge()` without an argument, the trigger rendered as a badge. */\n variant?: ActionVariant | 'badge'\n outlined?: boolean\n size?: Size\n badge?: string | number\n badgeColor?: Color\n tooltip?: string\n disabled?: boolean\n url?: string\n openUrlInNewTab?: boolean\n /** `postToUrl()`: clicking sends a POST request to `url` instead of visiting it. */\n postToUrl?: boolean\n /**\n * `download()`: `url` serves a file to save, so it is a plain link with the `download`\n * attribute, never an Inertia visit (which would fetch the file and discard it).\n */\n download?: boolean\n /** True when clicking opens a modal (confirmation and/or form) before executing. */\n hasModal?: boolean\n /** True when the action runs server-side logic (vs. a plain link). */\n hasAction?: boolean\n keyBindings?: string[]\n record?: RecordKey\n /**\n * `Action::formId()`: the page form (`form`, `form:{name}`) this button submits. The\n * runner sends that form's state as the action's data, wherever the button is.\n */\n formId?: string\n extraAttributes?: Attributes\n /**\n * A record action that receives the table's selection (`accessSelectedRecords()`): the\n * renderer sends the selected keys with it (`selectedRecordsArguments()`).\n */\n accessSelectedRecords?: boolean\n /**\n * `labeledFrom('md')`: icon only below this breakpoint, label from it up (the label\n * stays the accessible name).\n */\n labeledFrom?: 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n /**\n * `makeModalSubmitAction()`: the button submits the modal it sits in, running the\n * parent action with `arguments`.\n */\n submitsModal?: boolean\n arguments?: Record<string, unknown>\n /** `openDatabaseNotifications()`: clicking opens the database notifications panel. */\n opensDatabaseNotifications?: boolean\n}\n\nexport interface ActionGroupSchema {\n type: 'ActionGroup'\n label?: string\n icon?: IconName\n color?: Color\n variant?: ActionVariant\n size?: Size\n tooltip?: string\n dropdownPlacement?: string\n /**\n * `dropdown(false)`: a nested group is a divided section of its parent dropdown; a\n * top-level group renders its actions inline.\n */\n dropdown?: boolean\n /** `buttonGroup()`: the actions render as joined buttons. */\n buttonGroup?: boolean\n /** `dropdownWidth()`: `xs` … `7xl`. */\n dropdownWidth?: Width\n /** `dropdownOffset()`: pixels between the trigger and the dropdown. */\n dropdownOffset?: number\n /** `maxHeight()`: a CSS length; the dropdown scrolls beyond it. */\n maxHeight?: string\n actions: Array<ActionSchema | ActionGroupSchema>\n}\n\nexport type AnyActionSchema = ActionSchema | ActionGroupSchema\n\nexport function isActionGroup(action: AnyActionSchema): action is ActionGroupSchema {\n return action.type === 'ActionGroup'\n}\n\n/** Response of the modal endpoint. */\nexport interface ActionModalSchema {\n name: string\n heading?: string\n description?: string\n icon?: IconName\n iconColor?: Color\n width: Width\n slideOver?: boolean\n /** `slideOverPosition(SlideOverPosition::Start)`: the slide-over enters from the start side. */\n slideOverPosition?: 'start' | 'end'\n alignment?: Alignment\n /** `modalFooterActionsAlignment()`: footer buttons only (`alignment` moves the heading too). */\n footerActionsAlignment?: Alignment\n /** `stickyModalHeader()`: the heading stays visible while the content scrolls. */\n stickyHeader?: boolean\n stickyFooter?: boolean\n /** `modalClickThrough()`: no backdrop; the page underneath stays usable. */\n clickThrough?: boolean\n /** `extraModalWindowAttributes()` */\n windowAttributes?: Attributes\n /** `extraModalOverlayAttributes()` */\n overlayAttributes?: Attributes\n /**\n * `cancelParentActionsOnClose()`: closing this nested modal closes its parents too\n * (`true`), or the parents up to and including the named one.\n */\n cancelParentActionsOnClose?: true | string\n /**\n * `overlayParentActions()`: this nested modal opens on top of its parent, which stays\n * visible. Without it the parent modal is hidden while this one is open (Filament's\n * default).\n */\n overlayParent?: boolean\n autofocus: boolean\n closeByClickingAway: boolean\n closeByEscaping: boolean\n closeButton: boolean\n submitLabel?: string\n cancelLabel?: string\n submitColor?: Color\n /** Icon of the submit button (`modalSubmitAction(fn (Action $a) => $a->icon(…))`). */\n submitIcon?: IconName\n /** Colour of the cancel button (`modalCancelAction(fn (Action $a) => $a->color(…))`). */\n cancelColor?: Color\n /**\n * Ask before closing the modal (and before leaving the page) while its form has unsaved\n * changes: `unsavedChangesAlert()` or the panel's `unsavedChangesAlerts()`.\n */\n unsavedChangesAlert?: boolean\n requiresConfirmation?: boolean\n /** The form is a wizard (`->steps()`): the submit button shows on the last step only. */\n wizard?: boolean\n /** Ask for the current password (`requiresPasswordConfirmation()`, not confirmed recently). */\n passwordConfirmation?: boolean\n content?: SchemaComponent[]\n contentFooter?: SchemaComponent[]\n form?: FormPayload\n /** Footer buttons; they run as nested actions of this one (and may open their own modal). */\n extraFooterActions?: AnyActionSchema[]\n /**\n * `CreateAction`: label of the \"Create & create another\" button (absent with\n * `createAnother(false)`). It runs the action with the `another` argument; the modal\n * then stays open with a fresh form.\n */\n createAnotherLabel?: string\n /** `createAnotherAction()`: colour of the \"Create & create another\" button (outline). */\n createAnotherColor?: Color\n /** `createAnotherAction()`: icon of the \"Create & create another\" button. */\n createAnotherIcon?: IconName\n /**\n * `preserveFormDataWhenCreatingAnother()`: `true` keeps every top-level field after\n * \"Create & create another\", a list keeps the named fields only.\n */\n preserveFormData?: boolean | string[]\n record?: RecordKey\n}\n\n/**\n * Response of the modal endpoint when `mountUsing()` halted or cancelled the action: the\n * modal doesn't open; the notifications it sent are shown.\n */\nexport interface ActionModalCancelledResponse {\n cancelled: true\n notifications?: NotificationSchema[]\n}\n\n/** Flashed by the action endpoint after a run. */\nexport interface ActionResultFlash {\n name: string\n status: 'success' | 'halted' | 'cancelled'\n closeModal?: boolean\n deselectRecords?: boolean | null\n /**\n * A nested action asked to close the modals it was opened from (`cancelParentActions()`):\n * all of them (`true`), or those up to and including the named parent.\n */\n cancelParentActions?: boolean | string | null\n /** `fillData()`: values a nested action wrote into its parents' forms, per parent name. */\n parentData?: Array<{ name: string; data: Record<string, unknown> }>\n /** `replaceMountedAction()`: the action that opens (or runs) in place of this one. */\n replaceMountedAction?: {\n name: string\n arguments?: Record<string, unknown> | null\n hasModal: boolean\n }\n /**\n * The handler returned a file (`response()->streamDownload()`, `Storage::download()` …): a\n * signed, one-time link the browser opens to save it.\n */\n download?: string\n}\n"],"mappings":";AAmGA,SAAgB,cAAc,QAAsD;CAClF,OAAO,OAAO,SAAS;AACzB"}
@@ -539,6 +539,11 @@ export type ItemActionsSchema = Partial<Record<ItemActionName, ItemActionSchema
539
539
  export interface ItemActionsProps {
540
540
  /** Field-level built-in actions (item actions evaluated without an item). */
541
541
  itemActions?: ItemActionsSchema;
542
+ /**
543
+ * `extraItemActions()` evaluated without an item (`$arguments['item']` null), for items
544
+ * the browser added since the last response; server-rendered items carry their own.
545
+ */
546
+ extraItemActions?: ActionSchema[];
542
547
  /** `reorderableWithButtons(false)`: no move up / down buttons. */
543
548
  reorderableWithButtons?: boolean;
544
549
  /** `reorderableWithDragAndDrop(false)`: no drag handle. */
@@ -1 +1 @@
1
- {"version":3,"file":"components.d.ts","names":[],"sources":["../../src/schema/components.ts"],"mappings":"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"}
1
+ {"version":3,"file":"components.d.ts","names":[],"sources":["../../src/schema/components.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"components.js","names":[],"sources":["../../src/schema/components.ts"],"sourcesContent":["import type { ActionSchema, AnyActionSchema } from './actions'\nimport type {\n BuilderSchema,\n CodeEditorSchema,\n ModalTableSelectSchema,\n SliderSchema,\n ToggleButtonsSchema,\n} from './advanced-fields'\nimport type {\n Alignment,\n Attributes,\n Breakpoints,\n Color,\n ColumnSpanValue,\n IconName,\n IconPosition,\n Operation,\n OptionOrGroup,\n Size,\n VirtualizeSchema,\n} from './common'\nimport type { FileManagerPickerSchema } from './file-manager'\nimport type { IconPickerSchema } from './icon-picker'\n\n/** Properties every schema component carries. */\nexport interface BaseComponent {\n type: string\n key: string\n id?: string\n label?: string | null\n disabled?: boolean\n columns?: Breakpoints\n columnSpan?: Breakpoints<ColumnSpanValue>\n columnStart?: Breakpoints<number | string | null>\n /** `columnOrder()`: CSS `order` in the parent grid, per breakpoint. */\n columnOrder?: Breakpoints<number | null>\n extraAttributes?: Attributes\n meta?: Record<string, unknown>\n /** `false` keeps the component at its natural width inside a `Flex`. */\n grow?: boolean\n /** Child components (layout containers). */\n schema?: SchemaComponent[]\n /** `dense()`: half the gap between the children (layout containers). */\n dense?: boolean\n /** `gap(false)`: no gap between the children (layout containers). */\n gap?: false\n /** `exposeContext()`: what a custom frontend component may read about its schema. */\n context?: SchemaComponentContext\n /**\n * `deferLoading()`: sent without its children on the page's first response; the\n * renderer loads them from `schemaDeferred` once the placeholder is in view.\n */\n deferred?: boolean\n /** State paths of the fields inside a deferred component (loaded early on errors). */\n deferredPaths?: string[]\n}\n\n/** Server-provided context of a component (`exposeContext()`), read with the renderers' context helper. */\nexport interface SchemaComponentContext {\n operation?: Operation | null\n recordKey?: string | number | null\n /** The record attributes listed in `exposeContext(record: [...])`. */\n record?: Record<string, unknown> | null\n /** `exposeContext(data: [...])`. */\n data?: Record<string, unknown> | null\n /** The state path of the component's container (e.g. `items.0` in a repeater item); relative `get()` paths start here. */\n basePath?: string | null\n}\n\nexport interface LiveConfig {\n onBlur: boolean\n debounce: number | null\n}\n\n/**\n * Actions attached to a field or entry: before (`prefixActions`) and after\n * (`suffixActions`) the control, and next to the label (`hintActions`). They run as field\n * actions (`field:{schema}::{key}`, see `fieldActionContext()`).\n */\nexport interface FieldActions {\n prefixActions?: ActionSchema[]\n suffixActions?: ActionSchema[]\n hintActions?: ActionSchema[]\n}\n\n/**\n * Content slots of a field or entry (`aboveLabel()`, `afterContent()`…). The error message\n * slots exist on fields only and show while the field has a validation error.\n */\nexport type ContentSlotName =\n | 'aboveLabel'\n | 'beforeLabel'\n | 'afterLabel'\n | 'belowLabel'\n | 'aboveContent'\n | 'beforeContent'\n | 'afterContent'\n | 'belowContent'\n | 'aboveErrorMessage'\n | 'belowErrorMessage'\n\n/**\n * One item of a content slot: a schema component (strings arrive as `Text`, `Htmlable`\n * values as `Html`) or an action / action group, run as a field action.\n */\nexport type ContentSlotItem =\n { component: SchemaComponent; action?: never } | { action: AnyActionSchema; component?: never }\n\nexport interface ContentSlotSchema {\n items: ContentSlotItem[]\n /** `afterLabel` defaults to `end`, every other slot to `start`. */\n alignment: 'start' | 'end' | 'between'\n}\n\nexport interface ContentSlots {\n slots?: Partial<Record<ContentSlotName, ContentSlotSchema>>\n}\n\n/** Properties every form field carries. */\nexport interface BaseField extends BaseComponent, FieldActions, ContentSlots {\n name: string\n statePath: string\n required?: boolean\n readOnly?: boolean\n autofocus?: boolean\n placeholder?: string\n helperText?: string\n /** HTML: plain strings are escaped by the server, `Htmlable` values are sent as is. */\n hint?: string\n hintIcon?: IconName\n hintColor?: Color\n /** `inlineLabel()`: the label sits beside the control from the `sm` breakpoint up. */\n inlineLabel?: boolean\n live?: LiveConfig\n extraInputAttributes?: Attributes\n /** Attributes for the `data-slot=\"field\"` wrapper, merged with `extraAttributes`. */\n extraFieldWrapperAttributes?: Attributes\n /** `allowHtmlValidationMessages()`: the error message is rendered as HTML. */\n allowHtmlValidationMessages?: boolean\n /**\n * `->translatable()`: the state is a `{ [locale code]: value }` object and the renderer\n * shows one input per language (see `translatableLocaleField()`).\n */\n translatable?: TranslatableSchema\n}\n\n/** A language of a translatable field. */\nexport interface TranslatableLocaleSchema {\n code: string\n /** BCP 47 tag for the `lang` attribute. */\n tag: string\n /** The language's own name. */\n label: string\n direction: 'ltr' | 'rtl'\n /** Must be filled when the field is required. */\n required?: boolean | null\n}\n\nexport interface TranslatableSchema {\n locales: TranslatableLocaleSchema[]\n defaultLocale: string\n}\n\nexport interface Affixes {\n prefix?: string\n suffix?: string\n prefixIcon?: IconName\n suffixIcon?: IconName\n prefixIconColor?: Color\n suffixIconColor?: Color\n}\n\n// ---------------------------------------------------------------- Fields\n\nexport interface TextInputSchema extends BaseField, Affixes {\n type: 'TextInput'\n inputType: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | (string & {})\n revealable?: boolean\n minLength?: number\n maxLength?: number\n min?: number\n max?: number\n step?: number | string\n mask?: string\n /** `autocomplete(false)` arrives as `off`. */\n autocomplete?: string\n inputMode?: string\n datalist?: string[]\n /** HTML `autocapitalize` hint (`on`, `off`, `none`, `sentences`, `words`, `characters`). */\n autocapitalize?: 'on' | 'off' | 'none' | 'sentences' | 'words' | 'characters' | (string & {})\n /** `copyable()`: a button in the input copies its value. */\n copyable?: boolean\n copyMessage?: string\n /** Milliseconds the copied confirmation stays visible. */\n copyMessageDuration?: number\n}\n\nexport interface TextareaSchema extends BaseField {\n type: 'Textarea'\n rows?: number\n cols?: number\n minLength?: number\n maxLength?: number\n autosize?: boolean\n}\n\nexport interface HiddenSchema extends BaseField {\n type: 'Hidden'\n}\n\n/** `OneTimeCodeInput`: a numeric code with `autocomplete=\"one-time-code\"`. */\nexport interface OneTimeCodeInputSchema extends BaseField {\n type: 'OneTimeCodeInput'\n /** Number of digits. */\n length: number\n /** `submitOnCompletion()`: submit the form once every digit is entered. */\n submitOnCompletion?: boolean\n}\n\nexport interface CheckboxSchema extends BaseField {\n type: 'Checkbox'\n inline: boolean\n}\n\nexport interface ToggleSchema extends BaseField {\n type: 'Toggle'\n inline: boolean\n onIcon?: IconName\n offIcon?: IconName\n onColor?: Color\n offColor?: Color\n}\n\nexport interface SelectSchema extends BaseField, Affixes {\n type: 'Select'\n options: OptionOrGroup[]\n /** Labels for the currently selected values of a searchable select. */\n selectedLabels?: Record<string, string>\n multiple?: boolean\n searchable?: boolean\n native?: boolean\n selectablePlaceholder: boolean\n searchDebounce?: number\n noSearchResultsMessage?: string\n searchPrompt?: string\n loadingMessage?: string\n /** Shown when the select has no options at all. */\n noOptionsMessage?: string\n /** Shown while search results load. */\n searchingMessage?: string\n /** Option labels are HTML (sanitised by the server). */\n allowHtml?: boolean\n /** `false`: long option labels are truncated instead of wrapping. */\n wrapOptionLabels?: false\n maxItems?: number\n minItems?: number\n /** `reorderable()` on a multi-select: chosen chips can be reordered (drag or keyboard). */\n reorderable?: boolean\n}\n\nexport interface CheckboxListSchema extends BaseField {\n type: 'CheckboxList'\n options: OptionOrGroup[]\n searchable?: boolean\n /** `noSearchResultsMessage()`: shown when the search matches no option. */\n noSearchResultsMessage?: string\n /** `searchPrompt()`: placeholder of the search input. */\n searchPrompt?: string\n /** `searchDebounce()`: milliseconds to wait after typing before filtering. */\n searchDebounce?: number\n bulkToggleable?: boolean\n inline?: boolean\n gridColumns?: number\n /** `column` fills the grid column by column; row by row otherwise. */\n gridDirection?: OptionsGridDirection\n /** Option labels are HTML (sanitised by the server). */\n allowHtml?: boolean\n /** Customised bulk toggle links (`selectAllAction()` / `deselectAllAction()`). */\n selectAllAction?: BulkToggleActionSchema\n deselectAllAction?: BulkToggleActionSchema\n}\n\nexport type OptionsGridDirection = 'row' | 'column'\n\nexport interface BulkToggleActionSchema {\n label?: string\n icon?: IconName\n hidden?: boolean\n}\n\nexport interface RadioSchema extends BaseField {\n type: 'Radio'\n options: OptionOrGroup[]\n inline?: boolean\n}\n\nexport interface DatePickerSchema extends BaseField, Affixes {\n type: 'DatePicker' | 'DateTimePicker' | 'TimePicker'\n /** PHP date format of the stored value. */\n format: string\n displayFormat?: string\n hasDate: boolean\n hasTime: boolean\n hasSeconds?: boolean\n minDate?: string\n maxDate?: string\n disabledDates?: string[]\n native: boolean\n timezone: string\n firstDayOfWeek: number\n closeOnDateSelection: boolean\n /** Steps of the time inputs (`hoursStep()`, `minutesStep()`, `secondsStep()`). */\n hoursStep?: number\n minutesStep?: number\n secondsStep?: number\n /** The month the calendar opens on while empty, in the storage format. */\n defaultFocusedDate?: string\n /** `locale()`: BCP 47 tag for this picker's names and display format (the panel's otherwise). */\n locale?: string\n /** `datalist()`: suggested values in the storage format (native pickers only). */\n datalist?: string[]\n}\n\nexport interface MoneyInputSchema extends BaseField, Affixes {\n type: 'MoneyInput'\n /** ISO 4217 code. */\n currency: string\n /** Minor-unit digits of the currency (USD 2, BHD 3, JPY 0). */\n decimals: number\n min?: number\n max?: number\n}\n\nexport interface ColorPickerSchema extends BaseField {\n type: 'ColorPicker'\n format: 'hex' | 'rgb' | 'rgba' | 'hsl'\n}\n\nexport interface TagsInputSchema extends BaseField {\n type: 'TagsInput'\n suggestions?: string[]\n splitKeys: string[]\n color?: Color\n reorderable?: boolean\n tagPrefix?: string\n tagSuffix?: string\n}\n\nexport interface KeyValueSchema extends BaseField {\n type: 'KeyValue'\n keyLabel: string\n valueLabel: string\n keyPlaceholder?: string\n valuePlaceholder?: string\n addActionLabel: string\n addable: boolean\n deletable: boolean\n reorderable: boolean\n editableKeys: boolean\n editableValues: boolean\n /** `addAction()`, `deleteAction()`, `reorderAction()`; null = hidden. */\n itemActions?: Partial<Record<'add' | 'delete' | 'reorder', ItemActionSchema | null>>\n}\n\nexport interface UploadedFile {\n path: string\n name: string\n url?: string\n /** `getOpenableFileUrlUsing()`: where \"open\" links to, when not `url`. */\n openUrl?: string\n /** `getDownloadableFileUrlUsing()`: where \"download\" links to, when not `url`. */\n downloadUrl?: string\n /** `fetchFileInformation()`: the stored file no longer exists on its disk. */\n missing?: boolean\n temporary?: boolean\n size?: number\n}\n\n/** Logical sides of a file upload's controls (`removeUploadedFileButtonPosition()`…). */\nexport interface FileUploadPositions {\n removeButton?: 'start' | 'end'\n progressIndicator?: 'start' | 'end'\n uploadButton?: 'start' | 'center' | 'end'\n}\n\nexport interface FileUploadSchema extends BaseField {\n type: 'FileUpload'\n multiple?: boolean\n image?: boolean\n avatar?: boolean\n acceptedFileTypes?: string[]\n maxSize?: number\n minSize?: number\n /** Encrypted limits sent with each upload so the endpoint applies the field's `maxSize()`. */\n uploadPolicy?: string | null\n maxFiles?: number\n minFiles?: number\n downloadable?: boolean\n openable?: boolean\n previewable: boolean\n reorderable?: boolean\n deletable: boolean\n panelLayout: 'compact' | 'grid' | 'integrated' | 'circle' | (string & {})\n /** `panelAspectRatio()`: aspect ratio of the drop zone, e.g. `'2:1'`. */\n panelAspectRatio?: string\n imagePreviewHeight?: number | string\n /** `maxParallelUploads()`: files of one selection uploading at once (default 1). */\n maxParallelUploads?: number\n /** `appendFiles(false)`: new uploads go before the existing files. */\n appendFiles?: boolean\n /** `mimeTypeMap()`: extension → MIME type, for extensions browsers don't recognise. */\n mimeTypeMap?: Record<string, string>\n positions?: FileUploadPositions\n /** Images are cropped/resized in the browser before upload with these options. */\n imageCropAspectRatio?: string\n imageResizeMode?: 'cover' | 'contain' | 'force' | (string & {})\n imageResizeTargetWidth?: number\n imageResizeTargetHeight?: number\n uploadingMessage?: string\n /** `imageEditor()`: crop / rotate / flip each image before it is uploaded. */\n imageEditor?: FileUploadImageEditorSchema | null\n /** `imageAspectRatio()`: ratios the server accepts (checked on the file's pixels). */\n imageAspectRatio?: string[] | null\n /** `imageDimensions()`: pixel limits the server checks. */\n imageDimensions?: {\n minWidth?: number\n minHeight?: number\n maxWidth?: number\n maxHeight?: number\n } | null\n /** Re-encode JPEGs upright in the browser (sent only when the server can't do it). */\n orientImagesFromExif?: boolean | null\n /** `pasteable()`: accept files pasted while the drop zone has focus. */\n pasteable?: boolean\n files: UploadedFile[]\n}\n\nexport interface FileUploadImageEditorSchema {\n /** `'16:9'`-style ratios; `null` is free cropping. The first one is selected. */\n aspectRatios: Array<string | null>\n /** `circleCropper()`: a round viewport (the output stays square). */\n circle: boolean\n /** `imageEditorMode()` (Cropper.js `viewMode`): `0` lets the crop leave the image. */\n mode?: 0 | 1 | 2 | 3\n /** `imageEditorEmptyFillColor()`: colour of the empty space around the image. */\n emptyFillColor?: string | null\n /** `imageEditorViewportWidth()/Height()`: the crop ratio the editor opens with. */\n viewportWidth?: number | null\n viewportHeight?: number | null\n}\n\n/** A custom block a RichEditor can insert (`RichEditor::blocks()`). */\nexport interface RichEditorCustomBlockSchema {\n id: string\n label: string\n icon?: IconName\n /** The panel group (`customBlocks(['Marketing' => [...]])`). */\n group?: string\n /**\n * The field action (`customBlock:{id}`) that inserts the block: with a modal when the\n * block has a configuration form. It returns `{ id, config, preview }`.\n */\n action: ActionSchema\n}\n\n/** A mention trigger (`RichEditor::mentions()`). */\nexport interface RichEditorMentionSchema {\n /** The character that starts a mention, e.g. `@` or `#`. */\n trigger: string\n /** Static items; omitted when the server searches them (`getSearchResultsUsing`). */\n items?: Array<{ id: string; label: string }>\n /** Search on the server through the options endpoint as the user types. */\n searchable?: boolean\n searchDebounce?: number\n}\n\n/** A merge tag (`RichEditor::mergeTags()`), stored as `{{ id }}`. */\nexport interface RichEditorMergeTagSchema {\n id: string\n label: string\n}\n\n/** A toolbar dropdown (`ToolbarButtonGroup::make()`), referenced as `group:{n}` in a toolbar. */\nexport interface RichEditorToolbarGroupSchema {\n label: string\n /** Fixed trigger icon; without one the trigger shows the active (or first) button's icon. */\n icon?: IconName\n buttons: string[]\n /** `textualButtons()`: list the buttons with their labels. */\n textual?: boolean\n}\n\n/** A toolbar button from a rich content plugin (`RichEditorTool`). */\nexport interface RichEditorToolSchema {\n name: string\n label: string\n icon?: IconName\n /** Tiptap chain commands run on click: `[name, ...args]` each. */\n commands?: Array<[string, ...unknown[]]>\n /**\n * The plugin's editor action (opened with `editorSelection` and `attributes` arguments).\n * It may return `{ editorCommands, editorSelection }` (`RichEditor::runCommands()`).\n */\n action?: ActionSchema\n /** Pressed while this mark or node (with these attributes) is active. */\n active?: { name: string; attributes?: Record<string, unknown> }\n}\n\nexport interface RichEditorSchema extends BaseField {\n type: 'RichEditor' | 'MarkdownEditor'\n /** Button names, `'|'` separators and `group:{n}` dropdowns (see `toolbarButtonGroups`). */\n toolbarButtons: string[]\n toolbarButtonGroups?: Record<string, RichEditorToolbarGroupSchema> | null\n /**\n * `floatingToolbars()`: buttons shown next to the selection, keyed by node name\n * (`paragraph`, `heading`, `table`, `image`, …).\n */\n floatingToolbars?: Record<string, string[]> | null\n stickyToolbar?: boolean | null\n stickyPanels?: boolean | null\n /** CSS length; null measures the panel's sticky topbar. */\n stickyOffset?: string | null\n /** `resizableImages()`: drag handles; the width is stored on the image. */\n resizableImages?: boolean | null\n minimalCustomBlockControls?: boolean | null\n customBlocksGrid?: boolean | null\n searchableCustomBlocks?: boolean | null\n /** The panel open on load (`activePanel()`). */\n activePanel?: 'customBlocks' | 'mergeTags' | null\n /** Plugin toolbar buttons, usable by name in the toolbars. */\n editorTools?: RichEditorToolSchema[] | null\n /** Registry keys of plugin Tiptap extensions (`createAlfakit({ richEditorExtensions })`). */\n extensions?: string[] | null\n fileAttachments: {\n disk: string\n directory: string | null\n /** MIME types an inserted image may have; the server checks them on save. */\n acceptedFileTypes?: string[]\n /** Kilobytes. */\n maxSize?: number\n /** Encrypted limits sent with each upload (size and types of attachments). */\n uploadPolicy?: string | null\n }\n /** The `textColor` button's palette (`textColors()`); only sent with that button. */\n textColors?: Array<{ value: string; label: string }> | null\n /** `customTextColors()`: also offer a free colour picker. */\n customTextColors?: boolean | null\n minHeight?: number\n maxHeight?: number\n /**\n * `linkProtocols()`: URL schemes links may use (relative links always can); null keeps\n * the defaults. The server drops other links when the content is saved.\n */\n linkProtocols?: string[] | null\n /**\n * MarkdownEditor: the Markdown state rendered as HTML, which is what the editor loads.\n * A translatable editor gets one document per language code (see\n * `translatableLocaleField()`, which picks the current one).\n */\n html?: string | Record<string, string | null> | null\n /** RichEditor: the state is a Tiptap JSON document instead of HTML. */\n json?: boolean\n customBlocks?: RichEditorCustomBlockSchema[]\n mentions?: RichEditorMentionSchema[]\n mergeTags?: RichEditorMergeTagSchema[]\n}\n\n/** A column of a Repeater or RepeatableEntry shown as a table (`->table([...])`). */\nexport interface TableColumnSchema {\n label: string\n /** The item component the column shows: a field's relative state path or an entry's name. */\n name?: string\n hiddenLabel?: boolean\n required?: boolean\n /** CSS width, e.g. `200px` or `30%`. */\n width?: string\n alignment?: 'start' | 'center' | 'end'\n wrapHeader?: boolean\n}\n\n/** Built-in actions of a Repeater, Builder or KeyValue (`deleteAction(fn ($a) => …)`). */\nexport type ItemActionName =\n | 'add'\n | 'delete'\n | 'clone'\n | 'reorder'\n | 'moveUp'\n | 'moveDown'\n | 'collapse'\n | 'expand'\n | 'collapseAll'\n | 'expandAll'\n\n/**\n * A built-in item action. Without `server` the renderer applies it in the browser; with\n * it (customised with a modal, handler or hooks) it runs through the field action\n * endpoint with `arguments.item` (`items` for reorder, `block` for a Builder's add).\n */\nexport interface ItemActionSchema extends ActionSchema {\n server?: boolean\n}\n\n/** Customised built-in actions by name; null = hidden. Absent names use the renderer's default. */\nexport type ItemActionsSchema = Partial<Record<ItemActionName, ItemActionSchema | null>>\n\n/** Item action props shared by Repeater and Builder. */\nexport interface ItemActionsProps {\n /** Field-level built-in actions (item actions evaluated without an item). */\n itemActions?: ItemActionsSchema\n /** `reorderableWithButtons(false)`: no move up / down buttons. */\n reorderableWithButtons?: boolean\n /** `reorderableWithDragAndDrop(false)`: no drag handle. */\n reorderableWithDragAndDrop?: boolean\n addActionAlignment?: Alignment\n itemNumbers?: boolean\n}\n\n/** Per-item action props: customised built-ins for this item, `extraItemActions()`. */\nexport interface ItemActionsItemProps {\n itemActions?: ItemActionsSchema\n actions?: ActionSchema[]\n}\n\nexport interface RepeaterItemSchema extends ItemActionsItemProps {\n key: string\n label?: string | null\n schema: SchemaComponent[]\n}\n\nexport interface RepeaterSchema extends BaseField, ItemActionsProps {\n type: 'Repeater'\n items: RepeaterItemSchema[]\n /** Blank item schema; `__INDEX__` placeholders must be replaced with the new index. */\n template: SchemaComponent[]\n templateState: Record<string, unknown>\n simple?: boolean\n minItems?: number\n maxItems?: number\n addable: boolean\n deletable: boolean\n reorderable: boolean\n cloneable?: boolean\n collapsible?: boolean\n collapsed?: boolean\n addActionLabel: string\n grid?: Breakpoints\n /** Render items as table rows: one column per item field, in schema order. */\n table?: TableColumnSchema[]\n /** `compact()`: a table layout with tighter cells. */\n compact?: boolean\n /** Render only the visible items above a threshold (`virtualize()`, on by default). */\n virtualize?: VirtualizeSchema\n}\n\nexport type FieldSchema =\n | TextInputSchema\n | TextareaSchema\n | HiddenSchema\n | OneTimeCodeInputSchema\n | CheckboxSchema\n | ToggleSchema\n | SelectSchema\n | CheckboxListSchema\n | RadioSchema\n | DatePickerSchema\n | MoneyInputSchema\n | ColorPickerSchema\n | TagsInputSchema\n | KeyValueSchema\n | FileUploadSchema\n | RichEditorSchema\n | RepeaterSchema\n | BuilderSchema\n | ToggleButtonsSchema\n | SliderSchema\n | CodeEditorSchema\n | ModalTableSelectSchema\n | IconPickerSchema\n | FileManagerPickerSchema\n\nexport const FIELD_TYPES = [\n 'TextInput',\n 'Textarea',\n 'Hidden',\n 'OneTimeCodeInput',\n 'Checkbox',\n 'Toggle',\n 'Select',\n 'CheckboxList',\n 'Radio',\n 'DatePicker',\n 'DateTimePicker',\n 'MoneyInput',\n 'TimePicker',\n 'ColorPicker',\n 'TagsInput',\n 'KeyValue',\n 'FileUpload',\n 'RichEditor',\n 'MarkdownEditor',\n 'Repeater',\n 'Builder',\n 'ToggleButtons',\n 'Slider',\n 'CodeEditor',\n 'ModalTableSelect',\n 'IconPicker',\n // alfasix/alfakit-file-manager\n 'FileManagerPicker',\n] as const\n\nexport function isField(component: SchemaComponent): component is FieldSchema {\n return (\n 'statePath' in component &&\n typeof (component as BaseField).statePath === 'string' &&\n (FIELD_TYPES as readonly string[]).includes(component.type)\n )\n}\n\n// ---------------------------------------------------------------- Layout\n\nexport interface GridSchema extends BaseComponent {\n type: 'Grid'\n}\n\nexport interface GroupSchema extends BaseComponent {\n type: 'Group'\n}\n\n/**\n * Fields fused into one control (shared border, no gaps). Child labels become\n * screen-reader text and their errors are listed below the group.\n */\nexport interface FusedGroupSchema extends BaseComponent {\n type: 'FusedGroup'\n}\n\nexport interface SectionSchema extends BaseComponent {\n type: 'Section'\n heading?: string\n /** The heading's level (`2` = `h2`): `rootHeadingLevel()` plus the nesting depth. */\n headingLevel?: number\n description?: string\n icon?: IconName\n collapsible?: boolean\n collapsed?: boolean\n /** `persistCollapsed()`: the local storage key the collapsed state is kept under. */\n persistCollapsed?: string\n compact?: boolean\n aside?: boolean\n secondary?: boolean\n headerActions?: AnyActionSchema[]\n /** `afterHeader()`: actions and components at the end of the header. */\n afterHeader?: ContentSlotItem[]\n footerActions?: AnyActionSchema[]\n /** `footerActionsAlignment()`: alignment of `footerActions` (default `start`). */\n footerActionsAlignment?: Alignment\n /** `footer()`: actions and components in the footer, after `footerActions`. */\n footer?: ContentSlotItem[]\n}\n\nexport interface FieldsetSchema extends BaseComponent {\n type: 'Fieldset'\n /** `contained(false)`: no border or padding around the fields. */\n contained?: false\n}\n\nexport interface TabSchema extends BaseComponent {\n type: 'Tab'\n /**\n * The tab's readable value in the query string when its tabs `persistTabInQueryString()`:\n * its `id()`, explicit `key()` or label slug (`?tab=billing-address`).\n */\n queryValue?: string\n icon?: IconName\n iconPosition?: IconPosition\n badge?: string | number\n badgeColor?: Color\n /** `Tab::badgeTooltip()`: shown on hover (title) of the badge. */\n badgeTooltip?: string\n /** `deferBadge()`: the badge is loaded from `schemaDeferred` after the page renders. */\n badgeDeferred?: boolean\n}\n\n/** What `schemaDeferred` returns for a `Tab::deferBadge()` tab. */\nexport interface DeferredBadgeSchema {\n badge?: string | number | null\n badgeColor?: Color | null\n badgeTooltip?: string | null\n}\n\nexport interface TabsSchema extends BaseComponent {\n type: 'Tabs'\n schema: TabSchema[]\n activeTab: number\n contained?: boolean\n vertical?: boolean\n queryStringKey?: string\n /** `scrollable(false)`: the tab list wraps instead of scrolling sideways. */\n scrollable?: false\n /** `persistTab()`: where the active tab is remembered in the browser. */\n persistTab?: { key: string; storage: 'local' | 'session' }\n}\n\nexport interface StepSchema extends BaseComponent {\n type: 'Step'\n description?: string\n icon?: IconName\n /** Icon once the step is completed (falls back to the wizard's, then a check mark). */\n completedIcon?: IconName\n}\n\nexport interface WizardSchema extends BaseComponent {\n type: 'Wizard'\n schema: StepSchema[]\n startStep: number\n skippable?: boolean\n submitActionLabel?: string\n /** `submitAction(Action)`: rendered on the last step, runs through the action endpoint. */\n submitAction?: ActionSchema\n /** `submitAction(Htmlable)`: markup rendered on the last step. */\n submitActionHtml?: string\n nextActionLabel: string\n previousActionLabel: string\n /**\n * `nextAction(fn)` / `previousAction(fn)`: the button's appearance; `false` hides it.\n * Absent when not customised (the default buttons render).\n */\n nextAction?: ActionSchema | false\n previousAction?: ActionSchema | false\n completedIcon?: IconName\n /** Query-string key the current step is kept under (`true` from older servers = `step`). */\n persistStepInQueryString?: string | boolean\n /**\n * `goToStep()`: the server asked the wizard to show the step with this key. `id` is new\n * on every response, so the same step can be requested again.\n */\n goToStep?: { step: string; id: string }\n}\n\nexport interface PlaceholderSchema extends BaseComponent {\n type: 'Placeholder'\n content?: string\n helperText?: string\n}\n\nexport interface HtmlSchema extends BaseComponent {\n type: 'Html'\n content: string\n}\n\nexport interface TextSchema extends BaseComponent {\n type: 'Text'\n content: string\n color?: Color\n icon?: IconName\n size?: string\n weight?: string\n badge?: boolean\n /** `sans`, `serif` or `mono`. */\n fontFamily?: string\n tooltip?: string\n /** `copyable()`: a button copies `content` to the clipboard. */\n copyable?: boolean\n copyMessage?: string\n /** Milliseconds the copy confirmation shows. */\n copyMessageDuration?: number\n}\n\n/** A custom frontend component registered in the renderer. */\nexport interface ViewSchema extends BaseComponent {\n type: 'View'\n component: string\n props?: Record<string, unknown>\n}\n\n/** Children side by side, stacked below the `from` breakpoint. */\nexport interface FlexSchema extends BaseComponent {\n type: 'Flex'\n from: 'default' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n verticalAlignment?: 'start' | 'center' | 'end'\n /** `alignment()`: horizontal alignment of the children (`justify` spreads them like `between`). */\n alignment?: Alignment\n}\n\n/** A highlighted message box. `description` is HTML (plain strings escaped by the server). */\nexport interface CalloutSchema extends BaseComponent {\n type: 'Callout'\n heading?: string\n description?: string\n icon?: IconName\n /** `iconSize()`: `sm`, `md` or `lg` (default). */\n iconSize?: Size\n color?: Color\n /**\n * `status()` / `danger()`…: kept after `color(null)` so the icon keeps its status colour\n * and danger/warning callouts keep `role=\"alert\"`.\n */\n status?: Color\n /** `iconColor()`: overrides the icon's colour. */\n iconColor?: Color\n actions?: AnyActionSchema[]\n /** `footerActionsAlignment()`: alignment of `actions` (default `start`). */\n footerActionsAlignment?: Alignment\n /** `controls()` and `controlActions()`: shown in the top end corner. */\n controls?: ContentSlotItem[]\n /** `footer()`: actions and components under the description. */\n footer?: ContentSlotItem[]\n}\n\n/**\n * A row of action buttons placed freely in a form or infolist. The actions run in the\n * component's field context (`field:{schema}::{key}`), like a field's suffix actions.\n */\nexport interface ActionsComponentSchema extends BaseComponent {\n type: 'Actions'\n actions: AnyActionSchema[]\n alignment?: Alignment\n verticalAlignment?: 'start' | 'center' | 'end'\n fullWidth?: boolean\n}\n\n/** Placeholder for missing content. `description` is HTML (escaped by the server). */\nexport interface EmptyStateComponentSchema extends BaseComponent {\n type: 'EmptyState'\n heading?: string\n description?: string\n icon?: IconName\n color?: Color\n contained: boolean\n actions?: AnyActionSchema[]\n /** `footer()`: actions and components under the description (after `actions`). */\n footer?: ContentSlotItem[]\n}\n\nexport interface IconSchema extends BaseComponent {\n type: 'Icon'\n icon: IconName\n color?: Color\n size?: Size | string\n tooltip?: string\n}\n\nexport interface ImageSchema extends BaseComponent {\n type: 'Image'\n url: string\n alt: string\n /** CSS lengths. */\n imageWidth?: string\n imageHeight?: string\n alignment?: Alignment\n circular?: boolean\n tooltip?: string\n}\n\n/** A bulleted list; every child component is one item. */\nexport interface UnorderedListSchema extends BaseComponent {\n type: 'UnorderedList'\n size?: Size | string\n}\n\nexport type LayoutSchema =\n | FlexSchema\n | CalloutSchema\n | ActionsComponentSchema\n | EmptyStateComponentSchema\n | IconSchema\n | ImageSchema\n | UnorderedListSchema\n | GridSchema\n | GroupSchema\n | FusedGroupSchema\n | SectionSchema\n | FieldsetSchema\n | TabsSchema\n | TabSchema\n | WizardSchema\n | StepSchema\n | PlaceholderSchema\n | HtmlSchema\n | TextSchema\n | ViewSchema\n\n// ---------------------------------------------------------------- Infolist entries\n\nexport interface BaseEntry extends BaseComponent, FieldActions, ContentSlots {\n name: string\n state?: unknown\n url?: string\n openUrlInNewTab?: boolean\n tooltip?: string\n helperText?: string\n /** HTML: plain strings are escaped by the server, `Htmlable` values are sent as is. */\n hint?: string\n hintIcon?: IconName\n hintColor?: Color\n placeholder?: string\n /** `inlineLabel()`: the label sits beside the value from the `sm` breakpoint up. */\n inlineLabel?: boolean\n /**\n * Attributes for the `data-slot=\"entry\"` wrapper. `extraAttributes` go on the value\n * (`data-slot=\"entry-value\"`).\n */\n extraEntryWrapperAttributes?: Attributes\n /** `alignment()`: horizontal alignment of the value. */\n alignment?: Alignment\n}\n\nexport interface TextStyleProps {\n size?: string\n weight?: string\n fontFamily?: string\n lineClamp?: number\n badge?: boolean\n copyable?: boolean\n copyMessage?: string\n /** Milliseconds the copy confirmation shows (`copyMessageDuration()`, default 1500). */\n copyMessageDuration?: number\n wrap?: boolean\n}\n\nexport interface FormattedStateProps {\n html?: boolean\n listWithLineBreaks?: boolean\n bulleted?: boolean\n placeholder?: string\n boolean?: boolean\n /**\n * `limitList()` + `expandableLimitedList()`: every item is sent; the first `listLimit`\n * show with a \"+N more\" toggle for the rest.\n */\n expandableLimitedList?: boolean\n listLimit?: number\n}\n\n/** `ring()` / `overlap()` / `extraImgAttributes()` of image columns and entries. */\nexport interface ImageStackProps {\n /** Ring width in pixels around stacked images (0–8, default 2). */\n ring?: number\n /** Overlap of stacked images in quarter rems (0–8, default 2). */\n overlap?: number\n}\n\nexport interface TextEntrySchema extends BaseEntry, TextStyleProps, FormattedStateProps {\n type: 'TextEntry'\n state?: string | number | boolean | Array<string | number> | null\n color?: Color\n icon?: IconName\n iconPosition?: IconPosition\n iconColor?: Color\n /** Per-item colours of a list state (enums whose items differ), aligned with the items. */\n itemColors?: Array<Color | null>\n /** Per-item icons of a list state, aligned with the items. */\n itemIcons?: Array<IconName | null>\n /** Per-item links of a relationship list (`tags.name` with a `url()` closure). */\n itemUrls?: Array<string | null>\n prose?: boolean\n}\n\nexport interface IconEntrySchema extends BaseEntry {\n type: 'IconEntry'\n icon?: IconName\n color?: Color\n size?: Size | string\n}\n\nexport interface ImageEntrySchema extends BaseEntry, ImageStackProps {\n type: 'ImageEntry'\n /** HTML attributes for every `<img>` (`extraImgAttributes()`). */\n extraImgAttributes?: Attributes\n state?: string[]\n circular?: boolean\n square?: boolean\n size?: number | string\n height?: number | string\n width?: number | string\n stacked?: boolean\n limit?: number\n /** `limitedRemainingText(false)` hides the \"+N\" of images past `limit` (shown by default). */\n limitedRemainingText?: boolean\n /** Text size of the \"+N\" (`limitedRemainingText(size:)`). */\n limitedRemainingTextSize?: 'xs' | 'sm' | 'md' | 'lg'\n /** Alternative text shared by every image. */\n alt?: string\n /** Alternative text per image, aligned with `state`, when a closure gives different texts. */\n alts?: Array<string | null>\n}\n\n/** Highlighted read-only code. Array state arrives as pretty-printed JSON. */\nexport interface CodeEntrySchema extends BaseEntry {\n type: 'CodeEntry'\n state?: string | null\n /** Highlighting grammar (`json`, `php`, `js`…); unknown grammars render as plain code. */\n grammar?: string\n /** Theme names exposed to CSS as `data-light-theme` / `data-dark-theme`. */\n lightTheme?: string\n darkTheme?: string\n copyable?: boolean\n copyMessage?: string\n /** Milliseconds the copy confirmation shows. */\n copyMessageDuration?: number\n}\n\nexport interface ColorEntrySchema extends BaseEntry, TextStyleProps {\n type: 'ColorEntry'\n state?: string | string[] | null\n}\n\nexport interface KeyValueEntrySchema extends BaseEntry {\n type: 'KeyValueEntry'\n state?: Record<string, unknown>\n keyLabel: string\n valueLabel: string\n}\n\nexport interface RepeatableEntrySchema extends BaseEntry {\n type: 'RepeatableEntry'\n items: SchemaComponent[][]\n contained: boolean\n grid?: Breakpoints\n /** Render items as table rows: one column per item entry, in schema order. */\n table?: TableColumnSchema[]\n}\n\n/** An entry rendered by an application component registered under `component`. */\nexport interface ViewEntrySchema extends BaseEntry {\n type: 'ViewEntry'\n component?: string\n props?: Record<string, unknown>\n}\n\nexport type EntrySchema =\n | ViewEntrySchema\n | TextEntrySchema\n | IconEntrySchema\n | ImageEntrySchema\n | CodeEntrySchema\n | ColorEntrySchema\n | KeyValueEntrySchema\n | RepeatableEntrySchema\n\nexport type SchemaComponent =\n FieldSchema | LayoutSchema | EntrySchema | (BaseComponent & { type: string })\n\nexport type { Alignment }\n"],"mappings":";AAwqBA,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;AACF;AAEA,SAAgB,QAAQ,WAAsD;CAC5E,OACE,eAAe,aACf,OAAQ,UAAwB,cAAc,YAC7C,YAAkC,SAAS,UAAU,IAAI;AAE9D"}
1
+ {"version":3,"file":"components.js","names":[],"sources":["../../src/schema/components.ts"],"sourcesContent":["import type { ActionSchema, AnyActionSchema } from './actions'\nimport type {\n BuilderSchema,\n CodeEditorSchema,\n ModalTableSelectSchema,\n SliderSchema,\n ToggleButtonsSchema,\n} from './advanced-fields'\nimport type {\n Alignment,\n Attributes,\n Breakpoints,\n Color,\n ColumnSpanValue,\n IconName,\n IconPosition,\n Operation,\n OptionOrGroup,\n Size,\n VirtualizeSchema,\n} from './common'\nimport type { FileManagerPickerSchema } from './file-manager'\nimport type { IconPickerSchema } from './icon-picker'\n\n/** Properties every schema component carries. */\nexport interface BaseComponent {\n type: string\n key: string\n id?: string\n label?: string | null\n disabled?: boolean\n columns?: Breakpoints\n columnSpan?: Breakpoints<ColumnSpanValue>\n columnStart?: Breakpoints<number | string | null>\n /** `columnOrder()`: CSS `order` in the parent grid, per breakpoint. */\n columnOrder?: Breakpoints<number | null>\n extraAttributes?: Attributes\n meta?: Record<string, unknown>\n /** `false` keeps the component at its natural width inside a `Flex`. */\n grow?: boolean\n /** Child components (layout containers). */\n schema?: SchemaComponent[]\n /** `dense()`: half the gap between the children (layout containers). */\n dense?: boolean\n /** `gap(false)`: no gap between the children (layout containers). */\n gap?: false\n /** `exposeContext()`: what a custom frontend component may read about its schema. */\n context?: SchemaComponentContext\n /**\n * `deferLoading()`: sent without its children on the page's first response; the\n * renderer loads them from `schemaDeferred` once the placeholder is in view.\n */\n deferred?: boolean\n /** State paths of the fields inside a deferred component (loaded early on errors). */\n deferredPaths?: string[]\n}\n\n/** Server-provided context of a component (`exposeContext()`), read with the renderers' context helper. */\nexport interface SchemaComponentContext {\n operation?: Operation | null\n recordKey?: string | number | null\n /** The record attributes listed in `exposeContext(record: [...])`. */\n record?: Record<string, unknown> | null\n /** `exposeContext(data: [...])`. */\n data?: Record<string, unknown> | null\n /** The state path of the component's container (e.g. `items.0` in a repeater item); relative `get()` paths start here. */\n basePath?: string | null\n}\n\nexport interface LiveConfig {\n onBlur: boolean\n debounce: number | null\n}\n\n/**\n * Actions attached to a field or entry: before (`prefixActions`) and after\n * (`suffixActions`) the control, and next to the label (`hintActions`). They run as field\n * actions (`field:{schema}::{key}`, see `fieldActionContext()`).\n */\nexport interface FieldActions {\n prefixActions?: ActionSchema[]\n suffixActions?: ActionSchema[]\n hintActions?: ActionSchema[]\n}\n\n/**\n * Content slots of a field or entry (`aboveLabel()`, `afterContent()`…). The error message\n * slots exist on fields only and show while the field has a validation error.\n */\nexport type ContentSlotName =\n | 'aboveLabel'\n | 'beforeLabel'\n | 'afterLabel'\n | 'belowLabel'\n | 'aboveContent'\n | 'beforeContent'\n | 'afterContent'\n | 'belowContent'\n | 'aboveErrorMessage'\n | 'belowErrorMessage'\n\n/**\n * One item of a content slot: a schema component (strings arrive as `Text`, `Htmlable`\n * values as `Html`) or an action / action group, run as a field action.\n */\nexport type ContentSlotItem =\n { component: SchemaComponent; action?: never } | { action: AnyActionSchema; component?: never }\n\nexport interface ContentSlotSchema {\n items: ContentSlotItem[]\n /** `afterLabel` defaults to `end`, every other slot to `start`. */\n alignment: 'start' | 'end' | 'between'\n}\n\nexport interface ContentSlots {\n slots?: Partial<Record<ContentSlotName, ContentSlotSchema>>\n}\n\n/** Properties every form field carries. */\nexport interface BaseField extends BaseComponent, FieldActions, ContentSlots {\n name: string\n statePath: string\n required?: boolean\n readOnly?: boolean\n autofocus?: boolean\n placeholder?: string\n helperText?: string\n /** HTML: plain strings are escaped by the server, `Htmlable` values are sent as is. */\n hint?: string\n hintIcon?: IconName\n hintColor?: Color\n /** `inlineLabel()`: the label sits beside the control from the `sm` breakpoint up. */\n inlineLabel?: boolean\n live?: LiveConfig\n extraInputAttributes?: Attributes\n /** Attributes for the `data-slot=\"field\"` wrapper, merged with `extraAttributes`. */\n extraFieldWrapperAttributes?: Attributes\n /** `allowHtmlValidationMessages()`: the error message is rendered as HTML. */\n allowHtmlValidationMessages?: boolean\n /**\n * `->translatable()`: the state is a `{ [locale code]: value }` object and the renderer\n * shows one input per language (see `translatableLocaleField()`).\n */\n translatable?: TranslatableSchema\n}\n\n/** A language of a translatable field. */\nexport interface TranslatableLocaleSchema {\n code: string\n /** BCP 47 tag for the `lang` attribute. */\n tag: string\n /** The language's own name. */\n label: string\n direction: 'ltr' | 'rtl'\n /** Must be filled when the field is required. */\n required?: boolean | null\n}\n\nexport interface TranslatableSchema {\n locales: TranslatableLocaleSchema[]\n defaultLocale: string\n}\n\nexport interface Affixes {\n prefix?: string\n suffix?: string\n prefixIcon?: IconName\n suffixIcon?: IconName\n prefixIconColor?: Color\n suffixIconColor?: Color\n}\n\n// ---------------------------------------------------------------- Fields\n\nexport interface TextInputSchema extends BaseField, Affixes {\n type: 'TextInput'\n inputType: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | (string & {})\n revealable?: boolean\n minLength?: number\n maxLength?: number\n min?: number\n max?: number\n step?: number | string\n mask?: string\n /** `autocomplete(false)` arrives as `off`. */\n autocomplete?: string\n inputMode?: string\n datalist?: string[]\n /** HTML `autocapitalize` hint (`on`, `off`, `none`, `sentences`, `words`, `characters`). */\n autocapitalize?: 'on' | 'off' | 'none' | 'sentences' | 'words' | 'characters' | (string & {})\n /** `copyable()`: a button in the input copies its value. */\n copyable?: boolean\n copyMessage?: string\n /** Milliseconds the copied confirmation stays visible. */\n copyMessageDuration?: number\n}\n\nexport interface TextareaSchema extends BaseField {\n type: 'Textarea'\n rows?: number\n cols?: number\n minLength?: number\n maxLength?: number\n autosize?: boolean\n}\n\nexport interface HiddenSchema extends BaseField {\n type: 'Hidden'\n}\n\n/** `OneTimeCodeInput`: a numeric code with `autocomplete=\"one-time-code\"`. */\nexport interface OneTimeCodeInputSchema extends BaseField {\n type: 'OneTimeCodeInput'\n /** Number of digits. */\n length: number\n /** `submitOnCompletion()`: submit the form once every digit is entered. */\n submitOnCompletion?: boolean\n}\n\nexport interface CheckboxSchema extends BaseField {\n type: 'Checkbox'\n inline: boolean\n}\n\nexport interface ToggleSchema extends BaseField {\n type: 'Toggle'\n inline: boolean\n onIcon?: IconName\n offIcon?: IconName\n onColor?: Color\n offColor?: Color\n}\n\nexport interface SelectSchema extends BaseField, Affixes {\n type: 'Select'\n options: OptionOrGroup[]\n /** Labels for the currently selected values of a searchable select. */\n selectedLabels?: Record<string, string>\n multiple?: boolean\n searchable?: boolean\n native?: boolean\n selectablePlaceholder: boolean\n searchDebounce?: number\n noSearchResultsMessage?: string\n searchPrompt?: string\n loadingMessage?: string\n /** Shown when the select has no options at all. */\n noOptionsMessage?: string\n /** Shown while search results load. */\n searchingMessage?: string\n /** Option labels are HTML (sanitised by the server). */\n allowHtml?: boolean\n /** `false`: long option labels are truncated instead of wrapping. */\n wrapOptionLabels?: false\n maxItems?: number\n minItems?: number\n /** `reorderable()` on a multi-select: chosen chips can be reordered (drag or keyboard). */\n reorderable?: boolean\n}\n\nexport interface CheckboxListSchema extends BaseField {\n type: 'CheckboxList'\n options: OptionOrGroup[]\n searchable?: boolean\n /** `noSearchResultsMessage()`: shown when the search matches no option. */\n noSearchResultsMessage?: string\n /** `searchPrompt()`: placeholder of the search input. */\n searchPrompt?: string\n /** `searchDebounce()`: milliseconds to wait after typing before filtering. */\n searchDebounce?: number\n bulkToggleable?: boolean\n inline?: boolean\n gridColumns?: number\n /** `column` fills the grid column by column; row by row otherwise. */\n gridDirection?: OptionsGridDirection\n /** Option labels are HTML (sanitised by the server). */\n allowHtml?: boolean\n /** Customised bulk toggle links (`selectAllAction()` / `deselectAllAction()`). */\n selectAllAction?: BulkToggleActionSchema\n deselectAllAction?: BulkToggleActionSchema\n}\n\nexport type OptionsGridDirection = 'row' | 'column'\n\nexport interface BulkToggleActionSchema {\n label?: string\n icon?: IconName\n hidden?: boolean\n}\n\nexport interface RadioSchema extends BaseField {\n type: 'Radio'\n options: OptionOrGroup[]\n inline?: boolean\n}\n\nexport interface DatePickerSchema extends BaseField, Affixes {\n type: 'DatePicker' | 'DateTimePicker' | 'TimePicker'\n /** PHP date format of the stored value. */\n format: string\n displayFormat?: string\n hasDate: boolean\n hasTime: boolean\n hasSeconds?: boolean\n minDate?: string\n maxDate?: string\n disabledDates?: string[]\n native: boolean\n timezone: string\n firstDayOfWeek: number\n closeOnDateSelection: boolean\n /** Steps of the time inputs (`hoursStep()`, `minutesStep()`, `secondsStep()`). */\n hoursStep?: number\n minutesStep?: number\n secondsStep?: number\n /** The month the calendar opens on while empty, in the storage format. */\n defaultFocusedDate?: string\n /** `locale()`: BCP 47 tag for this picker's names and display format (the panel's otherwise). */\n locale?: string\n /** `datalist()`: suggested values in the storage format (native pickers only). */\n datalist?: string[]\n}\n\nexport interface MoneyInputSchema extends BaseField, Affixes {\n type: 'MoneyInput'\n /** ISO 4217 code. */\n currency: string\n /** Minor-unit digits of the currency (USD 2, BHD 3, JPY 0). */\n decimals: number\n min?: number\n max?: number\n}\n\nexport interface ColorPickerSchema extends BaseField {\n type: 'ColorPicker'\n format: 'hex' | 'rgb' | 'rgba' | 'hsl'\n}\n\nexport interface TagsInputSchema extends BaseField {\n type: 'TagsInput'\n suggestions?: string[]\n splitKeys: string[]\n color?: Color\n reorderable?: boolean\n tagPrefix?: string\n tagSuffix?: string\n}\n\nexport interface KeyValueSchema extends BaseField {\n type: 'KeyValue'\n keyLabel: string\n valueLabel: string\n keyPlaceholder?: string\n valuePlaceholder?: string\n addActionLabel: string\n addable: boolean\n deletable: boolean\n reorderable: boolean\n editableKeys: boolean\n editableValues: boolean\n /** `addAction()`, `deleteAction()`, `reorderAction()`; null = hidden. */\n itemActions?: Partial<Record<'add' | 'delete' | 'reorder', ItemActionSchema | null>>\n}\n\nexport interface UploadedFile {\n path: string\n name: string\n url?: string\n /** `getOpenableFileUrlUsing()`: where \"open\" links to, when not `url`. */\n openUrl?: string\n /** `getDownloadableFileUrlUsing()`: where \"download\" links to, when not `url`. */\n downloadUrl?: string\n /** `fetchFileInformation()`: the stored file no longer exists on its disk. */\n missing?: boolean\n temporary?: boolean\n size?: number\n}\n\n/** Logical sides of a file upload's controls (`removeUploadedFileButtonPosition()`…). */\nexport interface FileUploadPositions {\n removeButton?: 'start' | 'end'\n progressIndicator?: 'start' | 'end'\n uploadButton?: 'start' | 'center' | 'end'\n}\n\nexport interface FileUploadSchema extends BaseField {\n type: 'FileUpload'\n multiple?: boolean\n image?: boolean\n avatar?: boolean\n acceptedFileTypes?: string[]\n maxSize?: number\n minSize?: number\n /** Encrypted limits sent with each upload so the endpoint applies the field's `maxSize()`. */\n uploadPolicy?: string | null\n maxFiles?: number\n minFiles?: number\n downloadable?: boolean\n openable?: boolean\n previewable: boolean\n reorderable?: boolean\n deletable: boolean\n panelLayout: 'compact' | 'grid' | 'integrated' | 'circle' | (string & {})\n /** `panelAspectRatio()`: aspect ratio of the drop zone, e.g. `'2:1'`. */\n panelAspectRatio?: string\n imagePreviewHeight?: number | string\n /** `maxParallelUploads()`: files of one selection uploading at once (default 1). */\n maxParallelUploads?: number\n /** `appendFiles(false)`: new uploads go before the existing files. */\n appendFiles?: boolean\n /** `mimeTypeMap()`: extension → MIME type, for extensions browsers don't recognise. */\n mimeTypeMap?: Record<string, string>\n positions?: FileUploadPositions\n /** Images are cropped/resized in the browser before upload with these options. */\n imageCropAspectRatio?: string\n imageResizeMode?: 'cover' | 'contain' | 'force' | (string & {})\n imageResizeTargetWidth?: number\n imageResizeTargetHeight?: number\n uploadingMessage?: string\n /** `imageEditor()`: crop / rotate / flip each image before it is uploaded. */\n imageEditor?: FileUploadImageEditorSchema | null\n /** `imageAspectRatio()`: ratios the server accepts (checked on the file's pixels). */\n imageAspectRatio?: string[] | null\n /** `imageDimensions()`: pixel limits the server checks. */\n imageDimensions?: {\n minWidth?: number\n minHeight?: number\n maxWidth?: number\n maxHeight?: number\n } | null\n /** Re-encode JPEGs upright in the browser (sent only when the server can't do it). */\n orientImagesFromExif?: boolean | null\n /** `pasteable()`: accept files pasted while the drop zone has focus. */\n pasteable?: boolean\n files: UploadedFile[]\n}\n\nexport interface FileUploadImageEditorSchema {\n /** `'16:9'`-style ratios; `null` is free cropping. The first one is selected. */\n aspectRatios: Array<string | null>\n /** `circleCropper()`: a round viewport (the output stays square). */\n circle: boolean\n /** `imageEditorMode()` (Cropper.js `viewMode`): `0` lets the crop leave the image. */\n mode?: 0 | 1 | 2 | 3\n /** `imageEditorEmptyFillColor()`: colour of the empty space around the image. */\n emptyFillColor?: string | null\n /** `imageEditorViewportWidth()/Height()`: the crop ratio the editor opens with. */\n viewportWidth?: number | null\n viewportHeight?: number | null\n}\n\n/** A custom block a RichEditor can insert (`RichEditor::blocks()`). */\nexport interface RichEditorCustomBlockSchema {\n id: string\n label: string\n icon?: IconName\n /** The panel group (`customBlocks(['Marketing' => [...]])`). */\n group?: string\n /**\n * The field action (`customBlock:{id}`) that inserts the block: with a modal when the\n * block has a configuration form. It returns `{ id, config, preview }`.\n */\n action: ActionSchema\n}\n\n/** A mention trigger (`RichEditor::mentions()`). */\nexport interface RichEditorMentionSchema {\n /** The character that starts a mention, e.g. `@` or `#`. */\n trigger: string\n /** Static items; omitted when the server searches them (`getSearchResultsUsing`). */\n items?: Array<{ id: string; label: string }>\n /** Search on the server through the options endpoint as the user types. */\n searchable?: boolean\n searchDebounce?: number\n}\n\n/** A merge tag (`RichEditor::mergeTags()`), stored as `{{ id }}`. */\nexport interface RichEditorMergeTagSchema {\n id: string\n label: string\n}\n\n/** A toolbar dropdown (`ToolbarButtonGroup::make()`), referenced as `group:{n}` in a toolbar. */\nexport interface RichEditorToolbarGroupSchema {\n label: string\n /** Fixed trigger icon; without one the trigger shows the active (or first) button's icon. */\n icon?: IconName\n buttons: string[]\n /** `textualButtons()`: list the buttons with their labels. */\n textual?: boolean\n}\n\n/** A toolbar button from a rich content plugin (`RichEditorTool`). */\nexport interface RichEditorToolSchema {\n name: string\n label: string\n icon?: IconName\n /** Tiptap chain commands run on click: `[name, ...args]` each. */\n commands?: Array<[string, ...unknown[]]>\n /**\n * The plugin's editor action (opened with `editorSelection` and `attributes` arguments).\n * It may return `{ editorCommands, editorSelection }` (`RichEditor::runCommands()`).\n */\n action?: ActionSchema\n /** Pressed while this mark or node (with these attributes) is active. */\n active?: { name: string; attributes?: Record<string, unknown> }\n}\n\nexport interface RichEditorSchema extends BaseField {\n type: 'RichEditor' | 'MarkdownEditor'\n /** Button names, `'|'` separators and `group:{n}` dropdowns (see `toolbarButtonGroups`). */\n toolbarButtons: string[]\n toolbarButtonGroups?: Record<string, RichEditorToolbarGroupSchema> | null\n /**\n * `floatingToolbars()`: buttons shown next to the selection, keyed by node name\n * (`paragraph`, `heading`, `table`, `image`, …).\n */\n floatingToolbars?: Record<string, string[]> | null\n stickyToolbar?: boolean | null\n stickyPanels?: boolean | null\n /** CSS length; null measures the panel's sticky topbar. */\n stickyOffset?: string | null\n /** `resizableImages()`: drag handles; the width is stored on the image. */\n resizableImages?: boolean | null\n minimalCustomBlockControls?: boolean | null\n customBlocksGrid?: boolean | null\n searchableCustomBlocks?: boolean | null\n /** The panel open on load (`activePanel()`). */\n activePanel?: 'customBlocks' | 'mergeTags' | null\n /** Plugin toolbar buttons, usable by name in the toolbars. */\n editorTools?: RichEditorToolSchema[] | null\n /** Registry keys of plugin Tiptap extensions (`createAlfakit({ richEditorExtensions })`). */\n extensions?: string[] | null\n fileAttachments: {\n disk: string\n directory: string | null\n /** MIME types an inserted image may have; the server checks them on save. */\n acceptedFileTypes?: string[]\n /** Kilobytes. */\n maxSize?: number\n /** Encrypted limits sent with each upload (size and types of attachments). */\n uploadPolicy?: string | null\n }\n /** The `textColor` button's palette (`textColors()`); only sent with that button. */\n textColors?: Array<{ value: string; label: string }> | null\n /** `customTextColors()`: also offer a free colour picker. */\n customTextColors?: boolean | null\n minHeight?: number\n maxHeight?: number\n /**\n * `linkProtocols()`: URL schemes links may use (relative links always can); null keeps\n * the defaults. The server drops other links when the content is saved.\n */\n linkProtocols?: string[] | null\n /**\n * MarkdownEditor: the Markdown state rendered as HTML, which is what the editor loads.\n * A translatable editor gets one document per language code (see\n * `translatableLocaleField()`, which picks the current one).\n */\n html?: string | Record<string, string | null> | null\n /** RichEditor: the state is a Tiptap JSON document instead of HTML. */\n json?: boolean\n customBlocks?: RichEditorCustomBlockSchema[]\n mentions?: RichEditorMentionSchema[]\n mergeTags?: RichEditorMergeTagSchema[]\n}\n\n/** A column of a Repeater or RepeatableEntry shown as a table (`->table([...])`). */\nexport interface TableColumnSchema {\n label: string\n /** The item component the column shows: a field's relative state path or an entry's name. */\n name?: string\n hiddenLabel?: boolean\n required?: boolean\n /** CSS width, e.g. `200px` or `30%`. */\n width?: string\n alignment?: 'start' | 'center' | 'end'\n wrapHeader?: boolean\n}\n\n/** Built-in actions of a Repeater, Builder or KeyValue (`deleteAction(fn ($a) => …)`). */\nexport type ItemActionName =\n | 'add'\n | 'delete'\n | 'clone'\n | 'reorder'\n | 'moveUp'\n | 'moveDown'\n | 'collapse'\n | 'expand'\n | 'collapseAll'\n | 'expandAll'\n\n/**\n * A built-in item action. Without `server` the renderer applies it in the browser; with\n * it (customised with a modal, handler or hooks) it runs through the field action\n * endpoint with `arguments.item` (`items` for reorder, `block` for a Builder's add).\n */\nexport interface ItemActionSchema extends ActionSchema {\n server?: boolean\n}\n\n/** Customised built-in actions by name; null = hidden. Absent names use the renderer's default. */\nexport type ItemActionsSchema = Partial<Record<ItemActionName, ItemActionSchema | null>>\n\n/** Item action props shared by Repeater and Builder. */\nexport interface ItemActionsProps {\n /** Field-level built-in actions (item actions evaluated without an item). */\n itemActions?: ItemActionsSchema\n /**\n * `extraItemActions()` evaluated without an item (`$arguments['item']` null), for items\n * the browser added since the last response; server-rendered items carry their own.\n */\n extraItemActions?: ActionSchema[]\n /** `reorderableWithButtons(false)`: no move up / down buttons. */\n reorderableWithButtons?: boolean\n /** `reorderableWithDragAndDrop(false)`: no drag handle. */\n reorderableWithDragAndDrop?: boolean\n addActionAlignment?: Alignment\n itemNumbers?: boolean\n}\n\n/** Per-item action props: customised built-ins for this item, `extraItemActions()`. */\nexport interface ItemActionsItemProps {\n itemActions?: ItemActionsSchema\n actions?: ActionSchema[]\n}\n\nexport interface RepeaterItemSchema extends ItemActionsItemProps {\n key: string\n label?: string | null\n schema: SchemaComponent[]\n}\n\nexport interface RepeaterSchema extends BaseField, ItemActionsProps {\n type: 'Repeater'\n items: RepeaterItemSchema[]\n /** Blank item schema; `__INDEX__` placeholders must be replaced with the new index. */\n template: SchemaComponent[]\n templateState: Record<string, unknown>\n simple?: boolean\n minItems?: number\n maxItems?: number\n addable: boolean\n deletable: boolean\n reorderable: boolean\n cloneable?: boolean\n collapsible?: boolean\n collapsed?: boolean\n addActionLabel: string\n grid?: Breakpoints\n /** Render items as table rows: one column per item field, in schema order. */\n table?: TableColumnSchema[]\n /** `compact()`: a table layout with tighter cells. */\n compact?: boolean\n /** Render only the visible items above a threshold (`virtualize()`, on by default). */\n virtualize?: VirtualizeSchema\n}\n\nexport type FieldSchema =\n | TextInputSchema\n | TextareaSchema\n | HiddenSchema\n | OneTimeCodeInputSchema\n | CheckboxSchema\n | ToggleSchema\n | SelectSchema\n | CheckboxListSchema\n | RadioSchema\n | DatePickerSchema\n | MoneyInputSchema\n | ColorPickerSchema\n | TagsInputSchema\n | KeyValueSchema\n | FileUploadSchema\n | RichEditorSchema\n | RepeaterSchema\n | BuilderSchema\n | ToggleButtonsSchema\n | SliderSchema\n | CodeEditorSchema\n | ModalTableSelectSchema\n | IconPickerSchema\n | FileManagerPickerSchema\n\nexport const FIELD_TYPES = [\n 'TextInput',\n 'Textarea',\n 'Hidden',\n 'OneTimeCodeInput',\n 'Checkbox',\n 'Toggle',\n 'Select',\n 'CheckboxList',\n 'Radio',\n 'DatePicker',\n 'DateTimePicker',\n 'MoneyInput',\n 'TimePicker',\n 'ColorPicker',\n 'TagsInput',\n 'KeyValue',\n 'FileUpload',\n 'RichEditor',\n 'MarkdownEditor',\n 'Repeater',\n 'Builder',\n 'ToggleButtons',\n 'Slider',\n 'CodeEditor',\n 'ModalTableSelect',\n 'IconPicker',\n // alfasix/alfakit-file-manager\n 'FileManagerPicker',\n] as const\n\nexport function isField(component: SchemaComponent): component is FieldSchema {\n return (\n 'statePath' in component &&\n typeof (component as BaseField).statePath === 'string' &&\n (FIELD_TYPES as readonly string[]).includes(component.type)\n )\n}\n\n// ---------------------------------------------------------------- Layout\n\nexport interface GridSchema extends BaseComponent {\n type: 'Grid'\n}\n\nexport interface GroupSchema extends BaseComponent {\n type: 'Group'\n}\n\n/**\n * Fields fused into one control (shared border, no gaps). Child labels become\n * screen-reader text and their errors are listed below the group.\n */\nexport interface FusedGroupSchema extends BaseComponent {\n type: 'FusedGroup'\n}\n\nexport interface SectionSchema extends BaseComponent {\n type: 'Section'\n heading?: string\n /** The heading's level (`2` = `h2`): `rootHeadingLevel()` plus the nesting depth. */\n headingLevel?: number\n description?: string\n icon?: IconName\n collapsible?: boolean\n collapsed?: boolean\n /** `persistCollapsed()`: the local storage key the collapsed state is kept under. */\n persistCollapsed?: string\n compact?: boolean\n aside?: boolean\n secondary?: boolean\n headerActions?: AnyActionSchema[]\n /** `afterHeader()`: actions and components at the end of the header. */\n afterHeader?: ContentSlotItem[]\n footerActions?: AnyActionSchema[]\n /** `footerActionsAlignment()`: alignment of `footerActions` (default `start`). */\n footerActionsAlignment?: Alignment\n /** `footer()`: actions and components in the footer, after `footerActions`. */\n footer?: ContentSlotItem[]\n}\n\nexport interface FieldsetSchema extends BaseComponent {\n type: 'Fieldset'\n /** `contained(false)`: no border or padding around the fields. */\n contained?: false\n}\n\nexport interface TabSchema extends BaseComponent {\n type: 'Tab'\n /**\n * The tab's readable value in the query string when its tabs `persistTabInQueryString()`:\n * its `id()`, explicit `key()` or label slug (`?tab=billing-address`).\n */\n queryValue?: string\n icon?: IconName\n iconPosition?: IconPosition\n badge?: string | number\n badgeColor?: Color\n /** `Tab::badgeTooltip()`: shown on hover (title) of the badge. */\n badgeTooltip?: string\n /** `deferBadge()`: the badge is loaded from `schemaDeferred` after the page renders. */\n badgeDeferred?: boolean\n}\n\n/** What `schemaDeferred` returns for a `Tab::deferBadge()` tab. */\nexport interface DeferredBadgeSchema {\n badge?: string | number | null\n badgeColor?: Color | null\n badgeTooltip?: string | null\n}\n\nexport interface TabsSchema extends BaseComponent {\n type: 'Tabs'\n schema: TabSchema[]\n activeTab: number\n contained?: boolean\n vertical?: boolean\n queryStringKey?: string\n /** `scrollable(false)`: the tab list wraps instead of scrolling sideways. */\n scrollable?: false\n /** `persistTab()`: where the active tab is remembered in the browser. */\n persistTab?: { key: string; storage: 'local' | 'session' }\n}\n\nexport interface StepSchema extends BaseComponent {\n type: 'Step'\n description?: string\n icon?: IconName\n /** Icon once the step is completed (falls back to the wizard's, then a check mark). */\n completedIcon?: IconName\n}\n\nexport interface WizardSchema extends BaseComponent {\n type: 'Wizard'\n schema: StepSchema[]\n startStep: number\n skippable?: boolean\n submitActionLabel?: string\n /** `submitAction(Action)`: rendered on the last step, runs through the action endpoint. */\n submitAction?: ActionSchema\n /** `submitAction(Htmlable)`: markup rendered on the last step. */\n submitActionHtml?: string\n nextActionLabel: string\n previousActionLabel: string\n /**\n * `nextAction(fn)` / `previousAction(fn)`: the button's appearance; `false` hides it.\n * Absent when not customised (the default buttons render).\n */\n nextAction?: ActionSchema | false\n previousAction?: ActionSchema | false\n completedIcon?: IconName\n /** Query-string key the current step is kept under (`true` from older servers = `step`). */\n persistStepInQueryString?: string | boolean\n /**\n * `goToStep()`: the server asked the wizard to show the step with this key. `id` is new\n * on every response, so the same step can be requested again.\n */\n goToStep?: { step: string; id: string }\n}\n\nexport interface PlaceholderSchema extends BaseComponent {\n type: 'Placeholder'\n content?: string\n helperText?: string\n}\n\nexport interface HtmlSchema extends BaseComponent {\n type: 'Html'\n content: string\n}\n\nexport interface TextSchema extends BaseComponent {\n type: 'Text'\n content: string\n color?: Color\n icon?: IconName\n size?: string\n weight?: string\n badge?: boolean\n /** `sans`, `serif` or `mono`. */\n fontFamily?: string\n tooltip?: string\n /** `copyable()`: a button copies `content` to the clipboard. */\n copyable?: boolean\n copyMessage?: string\n /** Milliseconds the copy confirmation shows. */\n copyMessageDuration?: number\n}\n\n/** A custom frontend component registered in the renderer. */\nexport interface ViewSchema extends BaseComponent {\n type: 'View'\n component: string\n props?: Record<string, unknown>\n}\n\n/** Children side by side, stacked below the `from` breakpoint. */\nexport interface FlexSchema extends BaseComponent {\n type: 'Flex'\n from: 'default' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n verticalAlignment?: 'start' | 'center' | 'end'\n /** `alignment()`: horizontal alignment of the children (`justify` spreads them like `between`). */\n alignment?: Alignment\n}\n\n/** A highlighted message box. `description` is HTML (plain strings escaped by the server). */\nexport interface CalloutSchema extends BaseComponent {\n type: 'Callout'\n heading?: string\n description?: string\n icon?: IconName\n /** `iconSize()`: `sm`, `md` or `lg` (default). */\n iconSize?: Size\n color?: Color\n /**\n * `status()` / `danger()`…: kept after `color(null)` so the icon keeps its status colour\n * and danger/warning callouts keep `role=\"alert\"`.\n */\n status?: Color\n /** `iconColor()`: overrides the icon's colour. */\n iconColor?: Color\n actions?: AnyActionSchema[]\n /** `footerActionsAlignment()`: alignment of `actions` (default `start`). */\n footerActionsAlignment?: Alignment\n /** `controls()` and `controlActions()`: shown in the top end corner. */\n controls?: ContentSlotItem[]\n /** `footer()`: actions and components under the description. */\n footer?: ContentSlotItem[]\n}\n\n/**\n * A row of action buttons placed freely in a form or infolist. The actions run in the\n * component's field context (`field:{schema}::{key}`), like a field's suffix actions.\n */\nexport interface ActionsComponentSchema extends BaseComponent {\n type: 'Actions'\n actions: AnyActionSchema[]\n alignment?: Alignment\n verticalAlignment?: 'start' | 'center' | 'end'\n fullWidth?: boolean\n}\n\n/** Placeholder for missing content. `description` is HTML (escaped by the server). */\nexport interface EmptyStateComponentSchema extends BaseComponent {\n type: 'EmptyState'\n heading?: string\n description?: string\n icon?: IconName\n color?: Color\n contained: boolean\n actions?: AnyActionSchema[]\n /** `footer()`: actions and components under the description (after `actions`). */\n footer?: ContentSlotItem[]\n}\n\nexport interface IconSchema extends BaseComponent {\n type: 'Icon'\n icon: IconName\n color?: Color\n size?: Size | string\n tooltip?: string\n}\n\nexport interface ImageSchema extends BaseComponent {\n type: 'Image'\n url: string\n alt: string\n /** CSS lengths. */\n imageWidth?: string\n imageHeight?: string\n alignment?: Alignment\n circular?: boolean\n tooltip?: string\n}\n\n/** A bulleted list; every child component is one item. */\nexport interface UnorderedListSchema extends BaseComponent {\n type: 'UnorderedList'\n size?: Size | string\n}\n\nexport type LayoutSchema =\n | FlexSchema\n | CalloutSchema\n | ActionsComponentSchema\n | EmptyStateComponentSchema\n | IconSchema\n | ImageSchema\n | UnorderedListSchema\n | GridSchema\n | GroupSchema\n | FusedGroupSchema\n | SectionSchema\n | FieldsetSchema\n | TabsSchema\n | TabSchema\n | WizardSchema\n | StepSchema\n | PlaceholderSchema\n | HtmlSchema\n | TextSchema\n | ViewSchema\n\n// ---------------------------------------------------------------- Infolist entries\n\nexport interface BaseEntry extends BaseComponent, FieldActions, ContentSlots {\n name: string\n state?: unknown\n url?: string\n openUrlInNewTab?: boolean\n tooltip?: string\n helperText?: string\n /** HTML: plain strings are escaped by the server, `Htmlable` values are sent as is. */\n hint?: string\n hintIcon?: IconName\n hintColor?: Color\n placeholder?: string\n /** `inlineLabel()`: the label sits beside the value from the `sm` breakpoint up. */\n inlineLabel?: boolean\n /**\n * Attributes for the `data-slot=\"entry\"` wrapper. `extraAttributes` go on the value\n * (`data-slot=\"entry-value\"`).\n */\n extraEntryWrapperAttributes?: Attributes\n /** `alignment()`: horizontal alignment of the value. */\n alignment?: Alignment\n}\n\nexport interface TextStyleProps {\n size?: string\n weight?: string\n fontFamily?: string\n lineClamp?: number\n badge?: boolean\n copyable?: boolean\n copyMessage?: string\n /** Milliseconds the copy confirmation shows (`copyMessageDuration()`, default 1500). */\n copyMessageDuration?: number\n wrap?: boolean\n}\n\nexport interface FormattedStateProps {\n html?: boolean\n listWithLineBreaks?: boolean\n bulleted?: boolean\n placeholder?: string\n boolean?: boolean\n /**\n * `limitList()` + `expandableLimitedList()`: every item is sent; the first `listLimit`\n * show with a \"+N more\" toggle for the rest.\n */\n expandableLimitedList?: boolean\n listLimit?: number\n}\n\n/** `ring()` / `overlap()` / `extraImgAttributes()` of image columns and entries. */\nexport interface ImageStackProps {\n /** Ring width in pixels around stacked images (0–8, default 2). */\n ring?: number\n /** Overlap of stacked images in quarter rems (0–8, default 2). */\n overlap?: number\n}\n\nexport interface TextEntrySchema extends BaseEntry, TextStyleProps, FormattedStateProps {\n type: 'TextEntry'\n state?: string | number | boolean | Array<string | number> | null\n color?: Color\n icon?: IconName\n iconPosition?: IconPosition\n iconColor?: Color\n /** Per-item colours of a list state (enums whose items differ), aligned with the items. */\n itemColors?: Array<Color | null>\n /** Per-item icons of a list state, aligned with the items. */\n itemIcons?: Array<IconName | null>\n /** Per-item links of a relationship list (`tags.name` with a `url()` closure). */\n itemUrls?: Array<string | null>\n prose?: boolean\n}\n\nexport interface IconEntrySchema extends BaseEntry {\n type: 'IconEntry'\n icon?: IconName\n color?: Color\n size?: Size | string\n}\n\nexport interface ImageEntrySchema extends BaseEntry, ImageStackProps {\n type: 'ImageEntry'\n /** HTML attributes for every `<img>` (`extraImgAttributes()`). */\n extraImgAttributes?: Attributes\n state?: string[]\n circular?: boolean\n square?: boolean\n size?: number | string\n height?: number | string\n width?: number | string\n stacked?: boolean\n limit?: number\n /** `limitedRemainingText(false)` hides the \"+N\" of images past `limit` (shown by default). */\n limitedRemainingText?: boolean\n /** Text size of the \"+N\" (`limitedRemainingText(size:)`). */\n limitedRemainingTextSize?: 'xs' | 'sm' | 'md' | 'lg'\n /** Alternative text shared by every image. */\n alt?: string\n /** Alternative text per image, aligned with `state`, when a closure gives different texts. */\n alts?: Array<string | null>\n}\n\n/** Highlighted read-only code. Array state arrives as pretty-printed JSON. */\nexport interface CodeEntrySchema extends BaseEntry {\n type: 'CodeEntry'\n state?: string | null\n /** Highlighting grammar (`json`, `php`, `js`…); unknown grammars render as plain code. */\n grammar?: string\n /** Theme names exposed to CSS as `data-light-theme` / `data-dark-theme`. */\n lightTheme?: string\n darkTheme?: string\n copyable?: boolean\n copyMessage?: string\n /** Milliseconds the copy confirmation shows. */\n copyMessageDuration?: number\n}\n\nexport interface ColorEntrySchema extends BaseEntry, TextStyleProps {\n type: 'ColorEntry'\n state?: string | string[] | null\n}\n\nexport interface KeyValueEntrySchema extends BaseEntry {\n type: 'KeyValueEntry'\n state?: Record<string, unknown>\n keyLabel: string\n valueLabel: string\n}\n\nexport interface RepeatableEntrySchema extends BaseEntry {\n type: 'RepeatableEntry'\n items: SchemaComponent[][]\n contained: boolean\n grid?: Breakpoints\n /** Render items as table rows: one column per item entry, in schema order. */\n table?: TableColumnSchema[]\n}\n\n/** An entry rendered by an application component registered under `component`. */\nexport interface ViewEntrySchema extends BaseEntry {\n type: 'ViewEntry'\n component?: string\n props?: Record<string, unknown>\n}\n\nexport type EntrySchema =\n | ViewEntrySchema\n | TextEntrySchema\n | IconEntrySchema\n | ImageEntrySchema\n | CodeEntrySchema\n | ColorEntrySchema\n | KeyValueEntrySchema\n | RepeatableEntrySchema\n\nexport type SchemaComponent =\n FieldSchema | LayoutSchema | EntrySchema | (BaseComponent & { type: string })\n\nexport type { Alignment }\n"],"mappings":";AA6qBA,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;AACF;AAEA,SAAgB,QAAQ,WAAsD;CAC5E,OACE,eAAe,aACf,OAAQ,UAAwB,cAAc,YAC7C,YAAkC,SAAS,UAAU,IAAI;AAE9D"}
@@ -55,6 +55,8 @@ export interface InfolistBlock {
55
55
  type: 'Infolist';
56
56
  key: string;
57
57
  components: SchemaComponent[];
58
+ /** The infolist's `columns()` (one column on the profile page's security part). */
59
+ columns?: Breakpoints;
58
60
  }
59
61
  export interface SchemaBlock {
60
62
  type: 'Schema';
@@ -78,6 +80,8 @@ export interface FieldActionResponse {
78
80
  result?: unknown;
79
81
  closeModal?: boolean;
80
82
  redirect?: string | null;
83
+ /** A file the handler returned: a signed, one-time link to save it from. */
84
+ download?: string | null;
81
85
  /** The owning form after the action ran (partial when fingerprints were sent). */
82
86
  form?: SchemaRefreshResponse;
83
87
  /** Notifications the action sent (field actions answer with JSON, not a page visit). */
@@ -1 +1 @@
1
- {"version":3,"file":"form.d.ts","names":[],"sources":["../../src/schema/form.ts"],"mappings":";;;;;;iBAMiB;EACf,YAAY;EACZ,OAAO;EACP,UAAU;;;;;;EAMV,eAAe;;;iBAIA;EACf;EACA,WAAW;;;iBAII;EACf;EACA,SAAS;EACT,cAAc;EACd,UAAU;;EAEV,OAAO;EACP;;EAEA;;;iBAIe,kBAAkB;EACjC;EACA;;EAEA;EACA,SAAS;EACT,YAAY;;;;;EAKZ;;;;;EAKA;;iBAGe;EACf;EACA;EACA,YAAY;;iBAGG;EACf;EACA;EACA,YAAY;;iBAGG;EACf;EACA;EACA,OAAO;IAAQ;IAAe;;;;YAIpB,wBAAwB,cAAc;wBAElC,qBACd,SAAS,wBACR,WAAW;;iBAKG;EACf;EACA;EACA;EACA;;EAEA,OAAO;;EAEP,gBAAgB;;;;;;;iBAQD;EACf;EACA,gBAAgB;;iBAGD;EACf,UAAU;IAAQ;IAAe;;EACjC,SAAS"}
1
+ {"version":3,"file":"form.d.ts","names":[],"sources":["../../src/schema/form.ts"],"mappings":";;;;;;iBAMiB;EACf,YAAY;EACZ,OAAO;EACP,UAAU;;;;;;EAMV,eAAe;;;iBAIA;EACf;EACA,WAAW;;;iBAII;EACf;EACA,SAAS;EACT,cAAc;EACd,UAAU;;EAEV,OAAO;EACP;;EAEA;;;iBAIe,kBAAkB;EACjC;EACA;;EAEA;EACA,SAAS;EACT,YAAY;;;;;EAKZ;;;;;EAKA;;iBAGe;EACf;EACA;EACA,YAAY;;EAEZ,UAAU;;iBAGK;EACf;EACA;EACA,YAAY;;iBAGG;EACf;EACA;EACA,OAAO;IAAQ;IAAe;;;;YAIpB,wBAAwB,cAAc;wBAElC,qBACd,SAAS,wBACR,WAAW;;iBAKG;EACf;EACA;EACA;EACA;;EAEA;;EAEA,OAAO;;EAEP,gBAAgB;;;;;;;iBAQD;EACf;EACA,gBAAgB;;iBAGD;EACf,UAAU;IAAQ;IAAe;;EACjC,SAAS"}
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","names":[],"sources":["../../src/schema/form.ts"],"sourcesContent":["import type { ActionSchema } from './actions'\nimport type { Breakpoints, Operation } from './common'\nimport type { SchemaComponent } from './components'\nimport type { NotificationSchema } from './notifications'\n\n/** `Schema::toPayload()` — a component tree plus its state. */\nexport interface FormPayload {\n components: SchemaComponent[]\n state: Record<string, unknown>\n columns?: Breakpoints\n /**\n * Component fingerprints (index path → `own:subtree` hashes), sent for forms with live\n * fields or field actions. The store sends them back so a refresh answers with only\n * what changed (`PartialFormPayload`).\n */\n fingerprints?: Record<string, string>\n}\n\n/** A component replaced by a partial refresh, at its index path (`0.2` = `components[0].schema[2]`). */\nexport interface SchemaPatch {\n path: string\n component: SchemaComponent\n}\n\n/** A refresh answered with only the components and state keys that changed. */\nexport interface PartialFormPayload {\n partial: true\n patches: SchemaPatch[]\n fingerprints: Record<string, string>\n columns?: Breakpoints\n /** With `partialState`, only the top-level keys that differ from the state that was sent. */\n state: Record<string, unknown> | unknown[]\n partialState?: boolean\n /** Top-level keys that were sent but no longer exist (fields that became hidden). */\n removedState?: string[]\n}\n\n/** A page-level form block, including its submit actions. */\nexport interface FormBlock extends FormPayload {\n type: 'Form'\n key: string\n /** Context component name used by internal endpoints (`form`). */\n component: string\n actions: ActionSchema[]\n operation?: Operation\n /**\n * Dashboard filters with `live()` fields: the server stores the filters during the live\n * refresh, and the renderer reloads the page's widgets once it is merged.\n */\n liveFilters?: boolean\n /**\n * The form is a wizard (`HasWizard` Create pages): its buttons show on the wizard's last\n * step only.\n */\n wizard?: boolean\n}\n\nexport interface InfolistBlock {\n type: 'Infolist'\n key: string\n components: SchemaComponent[]\n}\n\nexport interface SchemaBlock {\n type: 'Schema'\n key: string\n components: SchemaComponent[]\n}\n\nexport interface LinksBlock {\n type: 'Links'\n key: string\n links: Array<{ label: string; url: string }>\n}\n\n/** Response of the schema refresh endpoint. */\nexport type SchemaRefreshResponse = FormPayload | PartialFormPayload\n\nexport function isPartialFormPayload(\n payload: SchemaRefreshResponse,\n): payload is PartialFormPayload {\n return (payload as PartialFormPayload).partial === true\n}\n\n/** Response of the action endpoint for a field action. */\nexport interface FieldActionResponse {\n status: 'success' | 'halted' | 'cancelled'\n result?: unknown\n closeModal?: boolean\n redirect?: string | null\n /** The owning form after the action ran (partial when fingerprints were sent). */\n form?: SchemaRefreshResponse\n /** Notifications the action sent (field actions answer with JSON, not a page visit). */\n notifications?: NotificationSchema[]\n}\n\n/**\n * Response of the step validation endpoint when a step hook halted (`throw new Halt`):\n * the wizard stays on the step and shows the notifications the hook sent. Steps that\n * pass answer 204 (no body).\n */\nexport interface StepValidationHaltedResponse {\n halted: true\n notifications?: NotificationSchema[]\n}\n\nexport interface SelectOptionsResponse {\n options?: Array<{ value: string; label: string }>\n labels?: Record<string, string>\n}\n"],"mappings":";AA8EA,SAAgB,qBACd,SAC+B;CAC/B,OAAQ,QAA+B,YAAY;AACrD"}
1
+ {"version":3,"file":"form.js","names":[],"sources":["../../src/schema/form.ts"],"sourcesContent":["import type { ActionSchema } from './actions'\nimport type { Breakpoints, Operation } from './common'\nimport type { SchemaComponent } from './components'\nimport type { NotificationSchema } from './notifications'\n\n/** `Schema::toPayload()` — a component tree plus its state. */\nexport interface FormPayload {\n components: SchemaComponent[]\n state: Record<string, unknown>\n columns?: Breakpoints\n /**\n * Component fingerprints (index path → `own:subtree` hashes), sent for forms with live\n * fields or field actions. The store sends them back so a refresh answers with only\n * what changed (`PartialFormPayload`).\n */\n fingerprints?: Record<string, string>\n}\n\n/** A component replaced by a partial refresh, at its index path (`0.2` = `components[0].schema[2]`). */\nexport interface SchemaPatch {\n path: string\n component: SchemaComponent\n}\n\n/** A refresh answered with only the components and state keys that changed. */\nexport interface PartialFormPayload {\n partial: true\n patches: SchemaPatch[]\n fingerprints: Record<string, string>\n columns?: Breakpoints\n /** With `partialState`, only the top-level keys that differ from the state that was sent. */\n state: Record<string, unknown> | unknown[]\n partialState?: boolean\n /** Top-level keys that were sent but no longer exist (fields that became hidden). */\n removedState?: string[]\n}\n\n/** A page-level form block, including its submit actions. */\nexport interface FormBlock extends FormPayload {\n type: 'Form'\n key: string\n /** Context component name used by internal endpoints (`form`). */\n component: string\n actions: ActionSchema[]\n operation?: Operation\n /**\n * Dashboard filters with `live()` fields: the server stores the filters during the live\n * refresh, and the renderer reloads the page's widgets once it is merged.\n */\n liveFilters?: boolean\n /**\n * The form is a wizard (`HasWizard` Create pages): its buttons show on the wizard's last\n * step only.\n */\n wizard?: boolean\n}\n\nexport interface InfolistBlock {\n type: 'Infolist'\n key: string\n components: SchemaComponent[]\n /** The infolist's `columns()` (one column on the profile page's security part). */\n columns?: Breakpoints\n}\n\nexport interface SchemaBlock {\n type: 'Schema'\n key: string\n components: SchemaComponent[]\n}\n\nexport interface LinksBlock {\n type: 'Links'\n key: string\n links: Array<{ label: string; url: string }>\n}\n\n/** Response of the schema refresh endpoint. */\nexport type SchemaRefreshResponse = FormPayload | PartialFormPayload\n\nexport function isPartialFormPayload(\n payload: SchemaRefreshResponse,\n): payload is PartialFormPayload {\n return (payload as PartialFormPayload).partial === true\n}\n\n/** Response of the action endpoint for a field action. */\nexport interface FieldActionResponse {\n status: 'success' | 'halted' | 'cancelled'\n result?: unknown\n closeModal?: boolean\n redirect?: string | null\n /** A file the handler returned: a signed, one-time link to save it from. */\n download?: string | null\n /** The owning form after the action ran (partial when fingerprints were sent). */\n form?: SchemaRefreshResponse\n /** Notifications the action sent (field actions answer with JSON, not a page visit). */\n notifications?: NotificationSchema[]\n}\n\n/**\n * Response of the step validation endpoint when a step hook halted (`throw new Halt`):\n * the wizard stays on the step and shows the notifications the hook sent. Steps that\n * pass answer 204 (no body).\n */\nexport interface StepValidationHaltedResponse {\n halted: true\n notifications?: NotificationSchema[]\n}\n\nexport interface SelectOptionsResponse {\n options?: Array<{ value: string; label: string }>\n labels?: Record<string, string>\n}\n"],"mappings":";AAgFA,SAAgB,qBACd,SAC+B;CAC/B,OAAQ,QAA+B,YAAY;AACrD"}
@@ -621,6 +621,8 @@ export interface AlfakitPageProps {
621
621
  status: 'success' | 'halted' | 'cancelled';
622
622
  closeModal?: boolean;
623
623
  deselectRecords?: boolean | null;
624
+ /** A file the handler returned: a signed, one-time link to save it from. */
625
+ download?: string;
624
626
  };
625
627
  [key: string]: unknown;
626
628
  };
@@ -1 +1 @@
1
- {"version":3,"file":"panel.d.ts","names":[],"sources":["../../src/schema/panel.ts"],"mappings":"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"}
1
+ {"version":3,"file":"panel.d.ts","names":[],"sources":["../../src/schema/panel.ts"],"mappings":";;;;;;;;;;;;;;;iBAeiB;;EAEf;;EAEA;EACA,OAAO;;;;;EAKP,aAAa;EACb;EACA;EACA;EACA;EACA,aAAa;EACb;;EAEA;;EAEA;;EAEA,kBAAkB;EAClB,WAAW;;iBAGI;EACf;EACA,OAAO;EACP;EACA;EACA,OAAO;;EAEP,yBAAyB;;EAEzB,wBAAwB;;;iBAIT;EACf;EACA,aAAa;EACb;;;;;;iBAOe;;EAEf;;EAEA,SAAS,eAAe;;;;iBAKT;;EAEf;;EAEA,WAAW;;iBAGI;;EAEf;;EAEA;EACA;;EAEA,QAAQ;;;;;;;EAOR,WAAW;;EAEX,UAAU;;;;;;;iBAQK;;EAEf;;EAEA;IAAW;IAAuB;;;EAElC;IAAkB;IAAe;;;EAEjC;IACE,UAAU;IACV,SAAS;IACT;;IAEA;IACA;;;;;;;EAOF;IAAa;IAAe,SAAS;;;EAErC,gBAAgB;;;;;;EAMhB;IAAY;IAAe;;;;iBAIZ;EACf;EACA,QAAQ;;;;;;;iBAQO;EACf;EACA,OAAO;EACP;EACA;EACA,QAAQ;EACR;EACA,SAAS;;EAET;;;qBAIW;qBACA;iBAEI;EACf,IAAI;EACJ;EACA;EACA;;iBAGe;EACf,IAAI;;EAEJ;;EAEA;EACA;EACA;;EAEA;;;iBAIe;EACf;;EAEA;EACA;EACA;EACA;EACA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA,QAAQ;;;;;EAKR,QAAQ;;iBAGO;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;EAMA;;;;;;;;;YAUU;EACR;EAAc;;EAAmB;EAAmB,WAAW;;EAC7D;EAAgB,OAAO,eAAe,gBAAgB;;;YAGhD;;iBAGK;;EAEf;;EAEA;;EAEA;EACA;;;iBAIe,2BAA2B;EAC1C;;EAEA;;EAEA;;EAEA;;EAEA;;;;;EAKA,mBAAmB;;EAEnB,SAAS;;YAGC;iBAEK;EACf;EACA;EACA;EACA;;EAEA;;EAEA;EACA;EACA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;EACA;;EAEA;;EAEA;EACA;EACA;;EAEA;EACA;;EAEA;;EAEA;;EAEA;;EAEA;EACA;EACA;EACA;EACA;;;YAIU;;iBAIK;;EAEf;EACA;;EAEA;;;;;;;iBAQe;EACf;EACA;EACA,OAAO;EACP;EACA;;;YAIU,2BAA2B,eAAe;iBAErC;EACf;;;;;EAKA;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA;EACA;;;;;EAKA,SAAS;;;;;EAKT;EACA;IACE;IACA;;IAEA;;IAEA;;;EAGF;EACA;EACA;EACA;EACA,kBAAkB;EAClB;EACA;;EAEA;;EAEA;EACA;;EAEA,4BAA4B;;EAE5B;;EAEA;;;;;;EAMA,qBAAqB;EACrB,OAAO;;EAEP,QAAQ,eAAe;;;;;EAKvB,YAAY;;;;;EAKZ,kBAAkB;;;;;;EAMlB;EACA,OAAO;EACP;IACE,OAAO;IACP;IACA;;IAEA,UAAU;;IAEV,SAAS;;;;;IAKT;;EAEF;IACE,UAAU;IACV,SAAS;IACT;IACA;;IAEA;;IAEA;;IAEA,eAAe;;IAEf,UAAU;IACV,OAAO;;IAEP;;IAEA;;EAEF;IACE;IACA;;;;;IAKA;;EAEF;IACE;IACA;;IAEA;;IAEA;;IAEA;;;;;IAKA;;EAEF,WAAW,QAAQ;IAAoB;;;EAEvC;EACA;IAAQ;IAAgB;IAAmB;;EAC3C;;EAEA,gBAAgB;;;;;EAKhB,WAAW;;EAEX,gBAAgB;;EAEhB,iBAAiB;;EAEjB,oBAAoB;;EAEpB,MAAM;EACN,cAAc;EACd;EACA,cAAc;;iBAGC;EACf;EACA;;YAGU,eACR,YACA,gBACA,cACA,aACA,wBACA,eACA;EACE;EAAc;GAAc;;YAEtB;;iBAGK;EACf;EACA,QAAQ;EACR;EACA;EACA;EACA,cAAc;EACd,kBAAkB;;EAElB;IAAe;IAAiB;;;EAEhC,gBAAgB;EAChB,gBAAgB;;EAEhB;;EAEA,sBAAsB;EACtB,SAAS;;EAET;EACA,SAAS;EACT;IAAS;IAAmB,OAAO;;;;;;EAKnC,gBAAgB;;;;;;EAMhB,qBAAqB;;EAErB,WAAW;;EAEX,YAAY;;;iBAIG;EACf,QAAQ;;EAER;EACA,SAAS;EACT,YAAY;;;;;;YAOF,mBAAmB,eAAe,eAAe,eAAe;;iBAG3D;EACf,SAAS;EACT,OAAO;;EAEP,cAAc;;;;;EAKd,cAAc;;EAEd,mBAAmB;;;;;EAKnB,0BAA0B,eAAe;EACzC;;EAEA;;;;;EAKA,oBAAoB;;;;;;EAMpB,iBAAiB;;;;;;EAMjB,eAAe;;;;;EAKf,kBAAkB;EAClB;IACE,uBAAuB;IACvB;MACE;MACA;MACA;MACA;;MAEA;;KAED;;EAEH,SAAS;GACR"}