@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @alfakit/core
2
2
 
3
+ ## 0.1.12
4
+
5
+ ### Patch Changes
6
+
7
+ - Starter kit sidebar items keyed by URL (language and tenant switches no longer leave links pointing at the old page or tenant); upload previews kept after a round trip; chart registries shared by a second copy of core under `npm run dev`; conflict banner finds forms inside relation-manager tabs; presence joins an already-subscribed channel; saved views and column changes count as mutations for Back; starter kit toasts reach the kit's toaster.
8
+
9
+ ## 0.1.11
10
+
11
+ ### Patch Changes
12
+
13
+ - A page restored by Back after a save is loaded fresh, so forms show the saved values. Actions that return a file download it (`startDownload()`); pages restored by Back after a save reload; lazy widgets that fail show a retry; toasts and the inspector follow the host page's side in right-to-left starter kits (`overlayPlacementDirection()`); icon replacements apply during server rendering; dark-mode danger text in starter kits.
14
+
3
15
  ## 0.1.10
4
16
 
5
17
  ### Patch Changes
package/components.css CHANGED
@@ -182,6 +182,13 @@
182
182
  .fc[data-slot='calendar'] .fc-day-other .fc-daygrid-day-number {
183
183
  color: var(--muted-foreground);
184
184
  }
185
+ /*
186
+ * FullCalendar fades other months' dates to 30% opacity, which fails WCAG AA contrast
187
+ * (W-V4-20); the muted colour alone sets them apart.
188
+ */
189
+ .fc[data-slot='calendar'] .fc-day-other .fc-daygrid-day-top {
190
+ opacity: 1;
191
+ }
185
192
  /* Today: a tinted cell (`--fc-today-bg-color`) and the date in a primary pill. */
186
193
  .fc[data-slot='calendar'] .fc-daygrid-day.fc-day-today .fc-daygrid-day-number {
187
194
  display: inline-flex;
@@ -345,3 +352,15 @@
345
352
  transition: none;
346
353
  }
347
354
  }
355
+
356
+ /* ------------------------------------------------------------------ Dev tools */
357
+
358
+ /*
359
+ * The floating debug-panel and schema-inspector buttons (local development) sit at the
360
+ * bottom end, over the helpdesk inbox's reply composer and its Send button: lift them
361
+ * above the composer while the inbox is on the page (W-S4-09).
362
+ */
363
+ body:has([data-slot='helpdesk-inbox']) [data-slot='dev-tools-toggle'],
364
+ body:has([data-slot='helpdesk-inbox']) [data-slot='starter-kit-debug-panel'] {
365
+ bottom: 14rem;
366
+ }
package/dist/actions.d.ts CHANGED
@@ -86,6 +86,12 @@ export interface ActionRunnerOptions {
86
86
  * Drives action buttons: plain links navigate, actions without a modal post straight to
87
87
  * the server, and actions with a modal fetch the modal schema first.
88
88
  */
89
+ /**
90
+ * Save a file an action handler returned. The action endpoint answers an Inertia visit (or
91
+ * JSON), which cannot carry a file, so the server keeps it behind a signed, one-time link
92
+ * served as an attachment: opening it saves the file and the page stays where it is.
93
+ */
94
+ export declare function startDownload(url: string): void;
89
95
  export declare class ActionRunner {
90
96
  private readonly options;
91
97
  readonly store: Store<ActionRunnerState>;
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","names":[],"sources":["../src/actions.ts"],"mappings":";;;;;;iBA6BiB;;EAEf;;EAEA;EACA,SAAS;;EAET,UAAU;;EAEV;EACA,YAAY;;;;;EAKZ;;;;;EAKA,OAAO;;iBAGQ;;EAEf;;;;;EAKA;;;qBAIW;;;;;wBAMG,mBACd,OAAO,yBACP,UAAU,yBACV,2CACC;iBAiBc;EACf,QAAQ;EACR,SAAS;EACT,OAAO;;EAEP,QAAQ;EACR;;EAEA,WAAW;;;;;EAKX;;iBAGe;;EAEf,QAAQ;;EAER;;;;;EAKA;;iBAGe;EACf;IAAa;IAAgB;;EAC7B,WAAW;;EAEX,aAAa,QAAQ,cAAc,SAAS;;;;;EAK5C,mBAAmB,eAAe;;;;;;qBAOvB;mBASkB;WARb,OAAO,MAAM;;mBAGZ;;mBAGA;EAEY,YAAA,SAAS;MAIlC,SAAS;;EAKb,uBACE,WAAW,eAAe;UAKpB;;EAOR,aAAa,WAAW,QAAQ;;;;;;EAShC,kBAAkB,QAAQ,cAAc,SAAS,eAAe,MAAM;;EAUtE,aAAa,SAAS,gBAAgB,MAAM;;;;;EAkB5C,YAAY,SAAS,gBAAgB,MAAM;;EAoBrC,QAAQ,QAAQ,cAAc,SAAS,gBAAgB;;;;;EA8DvD,SAAS,QAAQ,cAAc,SAAS,gBAAgB;;;;;EAkB9D,kBAAkB,QAAQ,cAAc,SAAS;;;;;EAqBjD,YAAY;;EAYZ,aAAa,SAAS,eAAe;EAY/B,UACJ,QAAQ,cACR,SAAS,eACT,WAAW,2BACV;UAyCK;;;;;EA0CF,WAAW,cAAc,WAAU,0BAA+B;;EAwCxE,UAAU,QAAQ,cAAc,SAAS;EAIzC,WAAW;;EAeX,QACE,QAAQ,cACR,SAAS,eACT,OAAM,yBACN,UAAS;;;;;EAmIL,YAAY,aAChB,QAAQ,cACR,SAAS,eACT,OAAM,0BACL,QAAQ;;;;;EAwCL,aACJ,QAAQ,cACR,SAAS,eACT,OAAM,0BACL;UAkFK;UAWA;;;;;;;wBAqBM,iBACd,QAAQ,KAAK,2CACb,SAAS,KAAK;;YAMJ;;;;;wBAMI,kBACd,MAAM,yBACN,WAAU,mBACT;;wBAiBa,eAAe,MAAM;iBAIpB;EACf;EACA;;;;;;wBAOc,uBAAuB,uCAAuC;;wBAa9D,mBAAmB,SAAS,oBAAoB;;;;;;wBAWhD,qBAAqB,QAAQ,aAAa;;wBAqB1C,qBACd,OAAO,KAAK;;;;;wBAkBE,cACd,8CACA;;;;;wBAiBc,wBACd,OAAO,KAAK,2CACZ;EAAQ;;;;;;wBASM,kBACd,OAAO,KAAK,2CACZ;EAAQ;sBACR;;;;;;wBAcc,iBACd,OAAO,KAAK,2CACZ;EAAQ;sBACR;;wBA8Bc,kBAAkB,eAAe,kCAAkC;;;;;wBAQnE,eAAe;EAAY;GAAkB,OAAO,MAAM;;wBAmB1D,gBACd,OAAO,mBACP,QAAQ,cACR,SAAS;;wBAMK,mBACd,OAAO,mBACP,QAAQ,cACR,SAAS;;;;;wBAmBK,eACd,kBACA,SAAS,KAAK,8BACd"}
1
+ {"version":3,"file":"actions.d.ts","names":[],"sources":["../src/actions.ts"],"mappings":";;;;;;iBA6BiB;;EAEf;;EAEA;EACA,SAAS;;EAET,UAAU;;EAEV;EACA,YAAY;;;;;EAKZ;;;;;EAKA,OAAO;;iBAGQ;;EAEf;;;;;EAKA;;;qBAIW;;;;;wBAMG,mBACd,OAAO,yBACP,UAAU,yBACV,2CACC;iBAiBc;EACf,QAAQ;EACR,SAAS;EACT,OAAO;;EAEP,QAAQ;EACR;;EAEA,WAAW;;;;;EAKX;;iBAGe;;EAEf,QAAQ;;EAER;;;;;EAKA;;iBAGe;EACf;IAAa;IAAgB;;EAC7B,WAAW;;EAEX,aAAa,QAAQ,cAAc,SAAS;;;;;EAK5C,mBAAmB,eAAe;;;;;;;;;;;wBAYpB,cAAc;qBAajB;mBASkB;WARb,OAAO,MAAM;;mBAGZ;;mBAGA;EAEY,YAAA,SAAS;MAIlC,SAAS;;EAKb,uBACE,WAAW,eAAe;UAKpB;;EAOR,aAAa,WAAW,QAAQ;;;;;;EAShC,kBAAkB,QAAQ,cAAc,SAAS,eAAe,MAAM;;EAUtE,aAAa,SAAS,gBAAgB,MAAM;;;;;EAkB5C,YAAY,SAAS,gBAAgB,MAAM;;EAoBrC,QAAQ,QAAQ,cAAc,SAAS,gBAAgB;;;;;EAgEvD,SAAS,QAAQ,cAAc,SAAS,gBAAgB;;;;;EAkB9D,kBAAkB,QAAQ,cAAc,SAAS;;;;;EAqBjD,YAAY;;EAYZ,aAAa,SAAS,eAAe;EAY/B,UACJ,QAAQ,cACR,SAAS,eACT,WAAW,2BACV;UAyCK;;;;;EA0CF,WAAW,cAAc,WAAU,0BAA+B;;EAwCxE,UAAU,QAAQ,cAAc,SAAS;EAIzC,WAAW;;EAeX,QACE,QAAQ,cACR,SAAS,eACT,OAAM,yBACN,UAAS;;;;;EAuIL,YAAY,aAChB,QAAQ,cACR,SAAS,eACT,OAAM,0BACL,QAAQ;;;;;EAwCL,aACJ,QAAQ,cACR,SAAS,eACT,OAAM,0BACL;UAsFK;UAWA;;;;;;;wBAqBM,iBACd,QAAQ,KAAK,2CACb,SAAS,KAAK;;YAMJ;;;;;wBAMI,kBACd,MAAM,yBACN,WAAU,mBACT;;wBAiBa,eAAe,MAAM;iBAIpB;EACf;EACA;;;;;;wBAOc,uBAAuB,uCAAuC;;wBAa9D,mBAAmB,SAAS,oBAAoB;;;;;;wBAWhD,qBAAqB,QAAQ,aAAa;;wBAqB1C,qBACd,OAAO,KAAK;;;;;wBAkBE,cACd,8CACA;;;;;wBAiBc,wBACd,OAAO,KAAK,2CACZ;EAAQ;;;;;;wBASM,kBACd,OAAO,KAAK,2CACZ;EAAQ;sBACR;;;;;;wBAcc,iBACd,OAAO,KAAK,2CACZ;EAAQ;sBACR;;wBA8Bc,kBAAkB,eAAe,kCAAkC;;;;;wBAQnE,eAAe;EAAY;GAAkB,OAAO,MAAM;;wBAmB1D,gBACd,OAAO,mBACP,QAAQ,cACR,SAAS;;wBAMK,mBACd,OAAO,mBACP,QAAQ,cACR,SAAS;;;;;wBAmBK,eACd,kBACA,SAAS,KAAK,8BACd"}
package/dist/actions.js CHANGED
@@ -28,6 +28,22 @@ function createAnotherState(fresh, previous, preserve) {
28
28
  * Drives action buttons: plain links navigate, actions without a modal post straight to
29
29
  * the server, and actions with a modal fetch the modal schema first.
30
30
  */
31
+ /**
32
+ * Save a file an action handler returned. The action endpoint answers an Inertia visit (or
33
+ * JSON), which cannot carry a file, so the server keeps it behind a signed, one-time link
34
+ * served as an attachment: opening it saves the file and the page stays where it is.
35
+ */
36
+ function startDownload(url) {
37
+ if (typeof document === "undefined") return;
38
+ const link = document.createElement("a");
39
+ link.href = url;
40
+ link.download = "";
41
+ link.rel = "noopener";
42
+ link.style.display = "none";
43
+ document.body.appendChild(link);
44
+ link.click();
45
+ link.remove();
46
+ }
31
47
  var ActionRunner = class {
32
48
  options;
33
49
  store;
@@ -106,7 +122,8 @@ var ActionRunner = class {
106
122
  return;
107
123
  }
108
124
  if (action.url && !action.hasAction && !action.hasModal) {
109
- if (action.openUrlInNewTab) window.open(action.url, "_blank", "noopener");
125
+ if (action.download) startDownload(action.url);
126
+ else if (action.openUrlInNewTab) window.open(action.url, "_blank", "noopener");
110
127
  else {
111
128
  const { router } = await import("@inertiajs/core");
112
129
  router.visit(action.url);
@@ -350,6 +367,7 @@ var ActionRunner = class {
350
367
  else this.execute(next, nextContext);
351
368
  }
352
369
  if (flash?.status === "success" && flash.closeModal === false && options.createAnother) this.resetModal(action.name, data);
370
+ if (flash?.status === "success" && flash.download) startDownload(flash.download);
353
371
  if (!flash || flash.status === "success") this.options.onSuccess?.(action, context);
354
372
  },
355
373
  onFinish: () => {
@@ -417,6 +435,7 @@ var ActionRunner = class {
417
435
  if (response.status === "cancelled" || response.closeModal !== false) this.closeModal(action.name);
418
436
  if (response.status === "success") {
419
437
  this.options.onSuccess?.(action, context);
438
+ if (response.download) startDownload(response.download);
420
439
  if (response.redirect) {
421
440
  const { router } = await import("@inertiajs/core");
422
441
  router.visit(response.redirect);
@@ -629,6 +648,6 @@ function actionEndpoint(endpoint, context, search = typeof window !== "undefined
629
648
  return endpoint + (endpoint.includes("?") ? "&" : "?") + search.replace(/^\?/, "");
630
649
  }
631
650
  //#endregion
632
- export { ActionRunner, CREATE_ANOTHER_ARGUMENT, actionEndpoint, bindsKeyBindings, confirmModalClose, createAnotherState, flattenActionGroup, groupMenuItems, guardModalUnload, iconButtonSize, isActionLoading, isActionProcessing, isModalHiddenByChild, menuActionContext, modalFooterAlignment, parseDropdownPlacement, resolveActionSize, shouldConfirmModalClose, slideOverSide };
651
+ export { ActionRunner, CREATE_ANOTHER_ARGUMENT, actionEndpoint, bindsKeyBindings, confirmModalClose, createAnotherState, flattenActionGroup, groupMenuItems, guardModalUnload, iconButtonSize, isActionLoading, isActionProcessing, isModalHiddenByChild, menuActionContext, modalFooterAlignment, parseDropdownPlacement, resolveActionSize, shouldConfirmModalClose, slideOverSide, startDownload };
633
652
 
634
653
  //# sourceMappingURL=actions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","names":[],"sources":["../src/actions.ts"],"sourcesContent":["import type { Page } from '@inertiajs/core'\nimport { revealAutofocusField } from './autofocus'\nimport {\n CONFLICT_ERROR_KEY,\n currentRecordVersion,\n markRecordSubmitted,\n RECORD_VERSION_INPUT,\n reportSaveConflict,\n} from './conflicts'\nimport { isFieldActionContext } from './field-actions'\nimport { pageFlash } from './flash'\nimport { isLeavingVisit, type FormStore } from './form'\nimport { HttpError, inertiaPost, requestJson, router } from './http'\nimport { ACTION_PATH_SEPARATOR, actionPath, PASSWORD_CONFIRMATION_INPUT } from './modal-actions'\nimport { openDatabaseNotifications } from './notifications'\nimport { submitFormById } from './page-actions'\nimport { currentPageQuery } from './page-query'\nimport type {\n ActionModalCancelledResponse,\n ActionModalSchema,\n ActionSchema,\n AnyActionSchema,\n} from './schema/actions'\nimport { isActionGroup } from './schema/actions'\nimport type { RecordKey, Size } from './schema/common'\nimport type { FieldActionResponse } from './schema/form'\nimport type { NotificationSchema } from './schema/notifications'\nimport { createStore, type Store } from './store'\n\nexport interface ActionContext {\n /** Encrypted page context token. */\n token: string\n /** `page`, `table`, `relationManager:Class`, `widget:Class`. */\n component?: string\n record?: RecordKey | null\n /** Selected record keys for bulk actions. */\n records?: RecordKey[]\n /** \"All filtered records\" bulk selection. */\n allRecords?: boolean\n arguments?: Record<string, unknown>\n /**\n * Names of the actions whose modals this action sits in, outermost first (actions in a\n * modal's footer). The server resolves the action by its path, `parent>child`.\n */\n parents?: string[]\n /**\n * Field actions (`component` = `field:{schema}::{key}`): the form the field belongs to.\n * Its state is sent with the action and the refreshed form is merged back into it.\n */\n form?: FormStore\n}\n\nexport interface ExecuteOptions {\n /** The current password, for actions with `requiresPasswordConfirmation()`. */\n password?: string\n /**\n * \"Create & create another\": run with the `another` argument and, when the server keeps\n * the modal open, reload it with a fresh form (keeping `preserveFormData` fields).\n */\n createAnother?: boolean\n}\n\n/** The argument `CreateAction` reads for \"Create & create another\". */\nexport const CREATE_ANOTHER_ARGUMENT = 'another'\n\n/**\n * The state of the fresh form after \"Create & create another\": the server's defaults,\n * plus the previous values of the fields `preserveFormData` names (all of them for `true`).\n */\nexport function createAnotherState(\n fresh: Record<string, unknown>,\n previous: Record<string, unknown>,\n preserve: boolean | string[] | undefined,\n): Record<string, unknown> {\n if (!preserve) {\n return fresh\n }\n\n const keys = preserve === true ? Object.keys(previous) : preserve\n const state = { ...fresh }\n\n for (const key of keys) {\n if (Object.prototype.hasOwnProperty.call(previous, key)) {\n state[key] = previous[key]\n }\n }\n\n return state\n}\n\nexport interface OpenModal {\n action: ActionSchema\n context: ActionContext\n modal: ActionModalSchema\n /** Current form values of the modal form. */\n errors: Record<string, string[]>\n processing: boolean\n /** Field actions: settles `runField()` with the action's result (undefined when closed). */\n resolve?: (result: unknown) => void\n /**\n * Bumped by `resetModal()` (\"Create & create another\"): the renderer focuses the form's\n * `autofocus()` field again (`focusAutofocusField()`) once the fresh form rendered.\n */\n refocus?: number\n}\n\nexport interface ActionRunnerState {\n /** Stack of open modals (nested modals are possible). */\n modals: OpenModal[]\n /** Name of the action currently loading its modal. */\n loading: string | null\n /**\n * Which run of it (component, action path and record): a table renders the same action\n * once per row, and only the clicked row's button is loading (`isActionLoading()`).\n */\n loadingKey?: string | null\n}\n\nexport interface ActionRunnerOptions {\n endpoints: { action: string; modal: string }\n onError?: (error: unknown) => void\n /** Called after a successful run so the UI can e.g. clear a table selection. */\n onSuccess?: (action: ActionSchema, context: ActionContext) => void\n /**\n * Shows notifications that arrive in JSON responses (a modal that `mountUsing()`\n * cancelled, field actions). Renderers can also set it with `setNotificationHandler()`.\n */\n onNotifications?: (notifications: NotificationSchema[]) => void\n}\n\n/**\n * Drives action buttons: plain links navigate, actions without a modal post straight to\n * the server, and actions with a modal fetch the modal schema first.\n */\nexport class ActionRunner {\n public readonly store: Store<ActionRunnerState>\n\n /** Runs in flight, so a double click or a repeated shortcut doesn't submit twice. */\n private readonly running = new Set<string>()\n\n /** The form of each open modal (registered by the renderer), by modal path. */\n private readonly modalForms = new Map<string, FormStore>()\n\n constructor(private readonly options: ActionRunnerOptions) {\n this.store = createStore<ActionRunnerState>({ modals: [], loading: null, loadingKey: null })\n }\n\n get state(): ActionRunnerState {\n return this.store.get()\n }\n\n /** Show notifications from JSON responses with this handler (e.g. the renderer's toasts). */\n setNotificationHandler(\n handler: ((notifications: NotificationSchema[]) => void) | undefined,\n ): void {\n this.options.onNotifications = handler\n }\n\n private notify(notifications: NotificationSchema[] | undefined): void {\n if (notifications && notifications.length > 0) {\n this.options.onNotifications?.(notifications)\n }\n }\n\n /** Point the runner at the current panel's endpoints (they change per tenant/panel). */\n setEndpoints(endpoints: Partial<ActionRunnerOptions['endpoints']>): void {\n Object.assign(this.options.endpoints, endpoints)\n }\n\n /**\n * The renderer registers the form of an open modal, so nested actions can send its state\n * (`$mountedActions`, `getRawData()`) and `fillData()` can write into it. Returns the\n * function that unregisters it.\n */\n registerModalForm(action: ActionSchema, context: ActionContext, form: FormStore): () => void {\n const key = actionPath(action, context)\n this.modalForms.set(key, form)\n\n return () => {\n if (this.modalForms.get(key) === form) this.modalForms.delete(key)\n }\n }\n\n /** The open modals of the actions a nested action sits in, outermost first. */\n parentModals(context: ActionContext): Array<OpenModal | undefined> {\n const parents = context.parents ?? []\n\n return parents.map((_, index) => {\n const path = parents.slice(0, index + 1).join(ACTION_PATH_SEPARATOR)\n\n return this.state.modals.find(\n (modal) =>\n modal.context.component === context.component &&\n actionPath(modal.action, modal.context) === path,\n )\n })\n }\n\n /**\n * The form state of the modals a nested action sits in, outermost first (undefined when\n * none of them has a form).\n */\n mountedData(context: ActionContext): Array<Record<string, unknown>> | undefined {\n const parents = context.parents ?? []\n\n if (parents.length === 0) {\n return undefined\n }\n\n const forms = parents.map((_, index) =>\n this.modalForms.get(parents.slice(0, index + 1).join(ACTION_PATH_SEPARATOR)),\n )\n\n // Parents without a form have nothing to send.\n if (forms.every((form) => !form)) {\n return undefined\n }\n\n return forms.map((form) => form?.state.values ?? {})\n }\n\n /** Entry point for a click on an action button. */\n async trigger(action: ActionSchema, context: ActionContext): Promise<void> {\n if (action.disabled) {\n return\n }\n\n // `openDatabaseNotifications()`: a client-side button.\n if (action.opensDatabaseNotifications) {\n openDatabaseNotifications()\n\n return\n }\n\n // `makeModalSubmitAction()`: submit the modal this button sits in, with its arguments.\n if (action.submitsModal) {\n this.submitParentModal(action, context)\n\n return\n }\n\n // `formId()`: the page form submits itself with its state, wherever the button is.\n if (submitFormById(action, context)) {\n return\n }\n\n // `postToUrl()`: a POST request to the URL (e.g. \"lock session\"), not a visit.\n if (action.url && action.postToUrl) {\n const { router } = await import('@inertiajs/core')\n router.post(action.url)\n\n return\n }\n\n if (action.url && !action.hasAction && !action.hasModal) {\n if (action.openUrlInNewTab) {\n window.open(action.url, '_blank', 'noopener')\n } else {\n const { router } = await import('@inertiajs/core')\n router.visit(action.url)\n }\n\n return\n }\n\n if (isFieldActionContext(context)) {\n await this.runField(action, context)\n\n return\n }\n\n if (action.hasModal) {\n await this.openModal(action, context)\n\n return\n }\n\n this.execute(action, context)\n }\n\n /**\n * Run a field action (opening its modal first, if it has one) and resolve with its\n * result once it ran, or with undefined when the modal is closed without running it.\n */\n async runField(action: ActionSchema, context: ActionContext): Promise<unknown> {\n if (action.disabled) {\n return undefined\n }\n\n if (action.hasModal) {\n return new Promise<unknown>((resolve) => {\n void this.openModal(action, context, resolve)\n })\n }\n\n return this.executeField(action, context)\n }\n\n /**\n * Run the action whose modal `button` sits in (a `makeModalSubmitAction()` button) with\n * that modal's form state and the button's arguments.\n */\n submitParentModal(button: ActionSchema, context: ActionContext): void {\n const parents = context.parents ?? []\n const open = this.parentModals(context).at(-1)\n\n if (!open || parents.length === 0) {\n return\n }\n\n const form = this.modalForms.get(parents.join(ACTION_PATH_SEPARATOR))\n\n this.execute(\n open.action,\n { ...open.context, arguments: { ...open.context.arguments, ...button.arguments } },\n form?.state.values ?? {},\n )\n }\n\n /**\n * Close a modal the user dismissed (cancel, Escape, clicking away, close button). With\n * `cancelParentActionsOnClose()` its parents close too.\n */\n cancelModal(name: string): void {\n const open = this.state.modals.find((modal) => modal.action.name === name)\n const cancel = open?.modal.cancelParentActionsOnClose\n\n this.closeModal(name)\n\n if (open && cancel) {\n this.closeParents(open.context, cancel)\n }\n }\n\n /** Close the modals `context` sits in: all of them, or up to and including `until`. */\n closeParents(context: ActionContext, until: true | string): void {\n const parents = [...(context.parents ?? [])].reverse()\n\n for (const parent of parents) {\n this.closeModal(parent)\n\n if (until !== true && parent === until) {\n break\n }\n }\n }\n\n async openModal(\n action: ActionSchema,\n context: ActionContext,\n resolve?: (result: unknown) => void,\n ): Promise<void> {\n const key = `modal:${runKey(action, context)}`\n\n if (this.running.has(key)) {\n resolve?.(undefined)\n\n return\n }\n\n this.running.add(key)\n this.store.update({ loading: action.name, loadingKey: runKey(action, context) })\n\n try {\n const modal = await this.fetchModal(action, context)\n\n // `mountUsing()` halted or cancelled the action: the modal stays closed.\n if (isCancelledModal(modal)) {\n this.store.update({ loading: null, loadingKey: null })\n this.notify(modal.notifications)\n resolve?.(undefined)\n\n return\n }\n\n this.store.set((state) => ({\n loading: null,\n loadingKey: null,\n modals: [\n ...state.modals,\n { action, context, modal, errors: {}, processing: false, resolve },\n ],\n }))\n } catch (error) {\n this.store.update({ loading: null, loadingKey: null })\n resolve?.(undefined)\n this.options.onError?.(error)\n } finally {\n this.running.delete(key)\n }\n }\n\n private fetchModal(\n action: ActionSchema,\n context: ActionContext,\n ): Promise<ActionModalSchema | ActionModalCancelledResponse> {\n // Bulk actions send their selection (and, for \"select all\", the page's table state), so\n // the server resolves the bulk action rather than a record action and fills `$records`.\n const records = context.records\n const isBulk = records !== undefined\n const params = {\n token: context.token,\n component: context.component,\n action: actionPath(action, context),\n record: context.record ?? undefined,\n records: records !== undefined && records.length > 0 ? records : undefined,\n allRecords: context.allRecords ? 1 : undefined,\n bulk: isBulk ? 1 : undefined,\n // The table state (active tab, filters, search) for record and bulk actions alike: a\n // record action on a non-default tab resolves its record through that tab's query.\n tableQuery: currentPageQuery(),\n arguments: context.arguments,\n }\n const mountedData = this.mountedData(context)\n\n // Field actions send the form state, and nested actions their parents' form state,\n // which needs a request body.\n if (isFieldActionContext(context)) {\n return requestJson<ActionModalSchema | ActionModalCancelledResponse>(\n this.options.endpoints.modal,\n { method: 'POST', body: { ...params, state: context.form?.state.values ?? {} } },\n )\n }\n\n return requestJson<ActionModalSchema | ActionModalCancelledResponse>(\n this.options.endpoints.modal,\n mountedData ? { method: 'POST', body: { ...params, mountedData } } : { query: params },\n )\n }\n\n /**\n * After \"Create & create another\": load the modal again so its form starts from the\n * server's defaults, keeping the `preserveFormData` fields from the values just sent.\n */\n async resetModal(name: string, previous: Record<string, unknown> = {}): Promise<void> {\n const open = this.state.modals.find((modal) => modal.action.name === name)\n\n if (!open) {\n return\n }\n\n try {\n const modal = await this.fetchModal(open.action, open.context)\n\n if (isCancelledModal(modal)) {\n this.notify(modal.notifications)\n this.closeModal(name)\n\n return\n }\n\n if (modal.form) {\n modal.form = {\n ...modal.form,\n // A wizard goes back to the step holding the `autofocus()` field.\n components: revealAutofocusField(modal.form.components),\n state: createAnotherState(modal.form.state, previous, modal.preserveFormData),\n }\n }\n\n this.store.set((state) => ({\n ...state,\n modals: state.modals.map((entry) =>\n entry === open || entry.action.name === name\n ? { ...entry, modal, errors: {}, refocus: (entry.refocus ?? 0) + 1 }\n : entry,\n ),\n }))\n } catch (error) {\n this.options.onError?.(error)\n }\n }\n\n /** Whether this action is currently being submitted for this context. */\n isRunning(action: ActionSchema, context: ActionContext): boolean {\n return this.running.has(runKey(action, context))\n }\n\n closeModal(name?: string): void {\n const modals = this.state.modals\n const remaining = name\n ? modals.filter((modal) => modal.action.name !== name)\n : modals.slice(0, -1)\n\n this.store.set((state) => ({ ...state, modals: remaining }))\n\n // A field action's caller learns that its modal closed without running.\n for (const modal of modals) {\n if (!remaining.includes(modal)) modal.resolve?.(undefined)\n }\n }\n\n /** Submit the topmost modal (or run a modal-less action) through Inertia. */\n execute(\n action: ActionSchema,\n context: ActionContext,\n data: Record<string, unknown> = {},\n options: ExecuteOptions = {},\n ): void {\n if (isFieldActionContext(context)) {\n void this.executeField(action, context, data)\n\n return\n }\n\n const key = runKey(action, context)\n\n if (this.running.has(key)) {\n return\n }\n\n this.running.add(key)\n this.setProcessing(action.name, true)\n\n // Edit pages (`detectConflicts()`): page actions send the version the form was loaded\n // from, so the server refuses to save over somebody else's changes.\n const version = context.component === 'page' ? currentRecordVersion() : null\n\n if (version !== null) markRecordSubmitted()\n\n inertiaPost(\n actionEndpoint(this.options.endpoints.action, context),\n {\n ...(version !== null ? { [RECORD_VERSION_INPUT]: version } : {}),\n token: context.token,\n component: context.component,\n action: actionPath(action, context),\n record: context.record ?? undefined,\n records: context.records,\n allRecords: context.allRecords ? 1 : undefined,\n bulk: context.records !== undefined ? 1 : undefined,\n arguments: options.createAnother\n ? { ...context.arguments, [CREATE_ANOTHER_ARGUMENT]: true }\n : context.arguments,\n tableQuery: currentPageQuery(),\n data,\n mountedData: this.mountedData(context),\n [PASSWORD_CONFIRMATION_INPUT]: options.password || undefined,\n },\n {\n onError: (errors) => {\n if (CONFLICT_ERROR_KEY in (errors as Record<string, unknown>)) reportSaveConflict()\n\n // A nested action without a modal of its own (e.g. `getValidatedData()` on its\n // parent failed): the parent's modal shows the errors.\n const hasModal = this.state.modals.some((modal) => modal.action.name === action.name)\n const parent = hasModal ? undefined : this.parentModals(context).at(-1)\n\n this.setErrors(\n parent ? parent.action.name : action.name,\n errors as Record<string, string>,\n )\n },\n onSuccess: (page) => {\n const flash = pageFlash(page as Page).alfakitAction\n\n // `fillData()`: values written into the parents' forms.\n for (const filled of flash?.parentData ?? []) {\n const parents = context.parents ?? []\n const index = parents.lastIndexOf(filled.name)\n const form =\n index >= 0\n ? this.modalForms.get(parents.slice(0, index + 1).join(ACTION_PATH_SEPARATOR))\n : undefined\n\n for (const [path, value] of Object.entries(filled.data)) {\n form?.setValue(path, value, { silent: true })\n }\n }\n\n if (\n !flash ||\n flash.status === 'cancelled' ||\n (flash.status === 'success' && flash.closeModal !== false)\n ) {\n this.closeModal(action.name)\n }\n\n // `cancelParentActions()`: the modals this nested action was opened from close too.\n if (flash?.status === 'success' && flash.cancelParentActions) {\n this.closeParents(\n context,\n typeof flash.cancelParentActions === 'string' ? flash.cancelParentActions : true,\n )\n }\n\n // `replaceMountedAction()`: the next action opens (or runs) in place of this one.\n const replacement = flash?.status === 'success' ? flash.replaceMountedAction : undefined\n\n if (replacement) {\n const next: ActionSchema = {\n type: 'Action',\n name: replacement.name,\n hasModal: replacement.hasModal || undefined,\n hasAction: true,\n }\n const nextContext: ActionContext = {\n ...context,\n arguments: replacement.arguments ?? undefined,\n }\n\n if (replacement.hasModal) {\n void this.openModal(next, nextContext)\n } else {\n this.execute(next, nextContext)\n }\n }\n\n if (flash?.status === 'success' && flash.closeModal === false && options.createAnother) {\n void this.resetModal(action.name, data)\n }\n\n if (!flash || flash.status === 'success') {\n this.options.onSuccess?.(action, context)\n }\n },\n onFinish: () => {\n this.running.delete(key)\n this.setProcessing(action.name, false)\n },\n },\n )\n }\n\n /**\n * Run an action and resolve with its JSON result (for callers that don't want an\n * Inertia visit, e.g. a custom widget).\n */\n async executeJson<T = unknown>(\n action: ActionSchema,\n context: ActionContext,\n data: Record<string, unknown> = {},\n ): Promise<T> {\n try {\n const response = await requestJson<{ result: T }>(\n actionEndpoint(this.options.endpoints.action, context),\n {\n method: 'POST',\n body: {\n token: context.token,\n component: context.component,\n action: actionPath(action, context),\n record: context.record ?? undefined,\n records: context.records,\n allRecords: context.allRecords ? 1 : undefined,\n bulk: context.records !== undefined ? 1 : undefined,\n arguments: context.arguments,\n tableQuery: currentPageQuery(),\n data,\n },\n },\n )\n\n return response.result\n } catch (error) {\n if (error instanceof HttpError && error.status === 422) {\n this.setErrors(\n action.name,\n Object.fromEntries(\n Object.entries(error.errors).map(([key, messages]) => [key, messages[0] ?? '']),\n ),\n )\n }\n\n throw error\n }\n }\n\n /**\n * Run a field action as JSON with its form's state; merge the refreshed form from the\n * response, settle the modal's `runField()` promise and close the modal.\n */\n async executeField(\n action: ActionSchema,\n context: ActionContext,\n data: Record<string, unknown> = {},\n ): Promise<unknown> {\n const key = runKey(action, context)\n\n if (this.running.has(key)) {\n return undefined\n }\n\n this.running.add(key)\n this.setProcessing(action.name, true)\n\n const form = context.form\n const sent = form?.state.values ?? {}\n\n try {\n const response = await requestJson<FieldActionResponse>(\n actionEndpoint(this.options.endpoints.action, context),\n {\n method: 'POST',\n body: {\n token: context.token,\n component: context.component,\n action: actionPath(action, context),\n record: context.record ?? undefined,\n arguments: context.arguments,\n // A field action inside a record action's modal on a list tab.\n tableQuery: currentPageQuery(),\n data,\n state: sent,\n fingerprints: form?.currentFingerprints,\n },\n },\n )\n\n // A partial response that doesn't fit the tree falls back to a full refresh.\n if (response.form && form && !form.applyResponse(response.form, sent)) {\n void form.refresh()\n }\n\n this.notify(response.notifications)\n\n if (response.status === 'halted') {\n return undefined\n }\n\n if (response.status === 'success') {\n const modal = this.state.modals.find((open) => open.action.name === action.name)\n modal?.resolve?.(response.result)\n }\n\n if (response.status === 'cancelled' || response.closeModal !== false) {\n this.closeModal(action.name)\n }\n\n if (response.status === 'success') {\n this.options.onSuccess?.(action, context)\n\n if (response.redirect) {\n const { router } = await import('@inertiajs/core')\n router.visit(response.redirect)\n }\n }\n\n return response.status === 'success' ? response.result : undefined\n } catch (error) {\n if (error instanceof HttpError && error.status === 422) {\n this.setErrors(\n action.name,\n Object.fromEntries(\n Object.entries(error.errors).map(([field, messages]) => [field, messages[0] ?? '']),\n ),\n )\n } else {\n this.options.onError?.(error)\n }\n\n return undefined\n } finally {\n this.running.delete(key)\n this.setProcessing(action.name, false)\n }\n }\n\n private setProcessing(name: string, processing: boolean): void {\n this.store.set((state) => ({\n ...state,\n modals: state.modals.map((modal) =>\n modal.action.name === name\n ? { ...modal, processing, errors: processing ? {} : modal.errors }\n : modal,\n ),\n }))\n }\n\n private setErrors(name: string, errors: Record<string, string>): void {\n const normalized: Record<string, string[]> = {}\n\n for (const [key, message] of Object.entries(errors)) {\n normalized[key] = [message]\n }\n\n this.store.set((state) => ({\n ...state,\n modals: state.modals.map((modal) =>\n modal.action.name === name ? { ...modal, errors: normalized } : modal,\n ),\n }))\n }\n}\n\n/**\n * Whether an action button should bind its key bindings globally. Record actions repeat\n * on every row, so a page-wide shortcut would run them once per record; they only bind\n * when rendered outside a record (header, page and bulk actions).\n */\nexport function bindsKeyBindings(\n action: Pick<ActionSchema, 'keyBindings' | 'disabled'>,\n context: Pick<ActionContext, 'record'>,\n): boolean {\n return Boolean(action.keyBindings?.length) && !action.disabled && context.record == null\n}\n\n/** Button sizes every renderer's shadcn `Button` understands. */\nexport type ActionButtonSize = 'xs' | 'sm' | 'default' | 'lg'\n\n/**\n * The button size for an action: its own `size()` wins over the size the surrounding\n * list asks for (`md` is the default button, `xl` the largest one).\n */\nexport function resolveActionSize(\n size: Size | null | undefined,\n fallback: ActionButtonSize = 'default',\n): ActionButtonSize {\n switch (size) {\n case 'xs':\n return 'xs'\n case 'sm':\n return 'sm'\n case 'md':\n return 'default'\n case 'lg':\n case 'xl':\n return 'lg'\n default:\n return fallback\n }\n}\n\n/** The square icon-only button that matches a button size. */\nexport function iconButtonSize(size: ActionButtonSize): 'icon-xs' | 'icon-sm' | 'icon' {\n return size === 'xs' ? 'icon-xs' : size === 'sm' ? 'icon-sm' : 'icon'\n}\n\nexport interface DropdownPlacement {\n side: 'top' | 'right' | 'bottom' | 'left'\n align: 'start' | 'center' | 'end'\n}\n\n/**\n * Parse an ActionGroup `dropdownPlacement()` (`bottom-start`, `top-end`, `left`, …) into the\n * side/align pair dropdown primitives take. Defaults to `bottom` / `end`.\n */\nexport function parseDropdownPlacement(placement: string | null | undefined): DropdownPlacement {\n const [side, align] = (placement ?? '').split('-')\n const sides = ['top', 'right', 'bottom', 'left'] as const\n const aligns = ['start', 'center', 'end'] as const\n\n const knownSide = sides.find((candidate) => candidate === side)\n const resolvedAlign =\n aligns.find((candidate) => candidate === align) ?? (knownSide && !align ? 'center' : 'end')\n\n return { side: knownSide ?? 'bottom', align: resolvedAlign }\n}\n\n/** Every action inside a group, nested groups flattened. */\nexport function flattenActionGroup(actions: AnyActionSchema[]): ActionSchema[] {\n return actions.flatMap((action) =>\n isActionGroup(action) ? flattenActionGroup(action.actions) : [action],\n )\n}\n\n/**\n * Whether an open modal is hidden because a nested modal was opened from it. Nested modals\n * hide their parents unless they opt into `overlayParentActions()`; a hidden parent shows\n * again when the child closes.\n */\nexport function isModalHiddenByChild(modals: OpenModal[], index: number): boolean {\n const modal = modals[index]\n\n if (!modal) {\n return false\n }\n\n const path = actionPath(modal.action, modal.context)\n\n return modals.slice(index + 1).some((child) => {\n if (child.modal.overlayParent === true) return false\n\n const parents = child.context.parents ?? []\n\n return parents.some(\n (_, position) => parents.slice(0, position + 1).join(ACTION_PATH_SEPARATOR) === path,\n )\n })\n}\n\n/** Justify class keyword for modal footer buttons: `footerActionsAlignment`, else `alignment`. */\nexport function modalFooterAlignment(\n modal: Pick<ActionModalSchema, 'alignment' | 'footerActionsAlignment'>,\n): 'start' | 'center' | 'end' | 'between' {\n const alignment = modal.footerActionsAlignment ?? modal.alignment\n\n switch (alignment) {\n case 'start':\n case 'center':\n case 'between':\n return alignment\n default:\n return 'end'\n }\n}\n\n/**\n * The physical side a slide-over enters from: `end` (default) is the right edge in\n * left-to-right documents and the left edge in right-to-left ones.\n */\nexport function slideOverSide(\n position: 'start' | 'end' | null | undefined,\n direction: 'ltr' | 'rtl' = 'ltr',\n): 'left' | 'right' {\n const atStart = position === 'start'\n\n return atStart === (direction === 'rtl') ? 'right' : 'left'\n}\n\nfunction isCancelledModal(\n modal: ActionModalSchema | ActionModalCancelledResponse,\n): modal is ActionModalCancelledResponse {\n return (modal as Partial<ActionModalCancelledResponse>).cancelled === true\n}\n\n/**\n * Whether closing a modal has to ask first: its form changed and the modal has\n * `unsavedChangesAlert` (the action's own setting or the panel's `unsavedChangesAlerts()`).\n */\nexport function shouldConfirmModalClose(\n modal: Pick<ActionModalSchema, 'unsavedChangesAlert'>,\n form: { isDirty: boolean } | null | undefined,\n): boolean {\n return Boolean(modal.unsavedChangesAlert && form?.isDirty)\n}\n\n/**\n * Ask whether to close a modal with unsaved changes (`window.confirm`); true when it may\n * close. Without changes (or the alert) it never asks.\n */\nexport function confirmModalClose(\n modal: Pick<ActionModalSchema, 'unsavedChangesAlert'>,\n form: { isDirty: boolean } | null | undefined,\n message: string,\n): boolean {\n if (!shouldConfirmModalClose(modal, form) || typeof window === 'undefined') {\n return true\n }\n\n return window.confirm(message)\n}\n\n/**\n * Warn before leaving the page (a reload, or an Inertia visit when `message` is given)\n * while a modal form with `unsavedChangesAlert` has unsaved changes. Returns a function\n * that removes the listeners.\n */\nexport function guardModalUnload(\n modal: Pick<ActionModalSchema, 'unsavedChangesAlert'>,\n form: { isDirty: boolean } | null | undefined,\n message?: string,\n): () => void {\n if (!modal.unsavedChangesAlert || !form || typeof window === 'undefined') {\n return () => {}\n }\n\n const listener = (event: BeforeUnloadEvent) => {\n if (form.isDirty) {\n event.preventDefault()\n event.returnValue = ''\n }\n }\n\n window.addEventListener('beforeunload', listener)\n\n const removeVisitGuard = message\n ? router.on('before', (event) => {\n if (form.isDirty && isLeavingVisit(event.detail.visit) && !window.confirm(message)) {\n event.preventDefault()\n }\n })\n : () => {}\n\n return () => {\n window.removeEventListener('beforeunload', listener)\n removeVisitGuard()\n }\n}\n\n/** The context of a user or tenant menu action: the page's token and the menu's component. */\nexport function menuActionContext(token: string, menu: 'userMenu' | 'tenantMenu'): ActionContext {\n return { token, component: menu }\n}\n\n/**\n * Split menu entries into their groups (`group` index, nested arrays in\n * `userMenuItems()`), in order; renderers draw a separator between groups.\n */\nexport function groupMenuItems<T extends { group?: number }>(items: T[]): T[][] {\n const groups: T[][] = []\n let current: number | null = null\n\n for (const item of items) {\n const group = item.group ?? 0\n\n if (current === null || group !== current) {\n groups.push([])\n current = group\n }\n\n groups[groups.length - 1]!.push(item)\n }\n\n return groups\n}\n\n/** Whether this button's run (this action for this record) is fetching its modal. */\nexport function isActionLoading(\n state: ActionRunnerState,\n action: ActionSchema,\n context: ActionContext,\n): boolean {\n return state.loadingKey === runKey(action, context)\n}\n\n/** Whether this button's run (this action for this record) has a modal that is submitting. */\nexport function isActionProcessing(\n state: ActionRunnerState,\n action: ActionSchema,\n context: ActionContext,\n): boolean {\n const key = runKey(action, context)\n\n return state.modals.some(\n (modal) => modal.processing && runKey(modal.action, modal.context) === key,\n )\n}\n\nfunction runKey(action: Pick<ActionSchema, 'name'>, context: ActionContext): string {\n return [context.component ?? 'page', actionPath(action, context), context.record ?? ''].join(\n '\\u0000',\n )\n}\n\n/**\n * The action endpoint for a run. \"All records\" bulk actions carry the page's query string\n * (filters, search, list tab), so the server selects exactly the records the table shows.\n */\nexport function actionEndpoint(\n endpoint: string,\n context: Pick<ActionContext, 'allRecords'>,\n search: string = typeof window !== 'undefined' ? window.location.search : '',\n): string {\n if (!context.allRecords || search.length <= 1) {\n return endpoint\n }\n\n return endpoint + (endpoint.includes('?') ? '&' : '?') + search.replace(/^\\?/, '')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"actions.js","names":[],"sources":["../src/actions.ts"],"sourcesContent":["import type { Page } from '@inertiajs/core'\nimport { revealAutofocusField } from './autofocus'\nimport {\n CONFLICT_ERROR_KEY,\n currentRecordVersion,\n markRecordSubmitted,\n RECORD_VERSION_INPUT,\n reportSaveConflict,\n} from './conflicts'\nimport { isFieldActionContext } from './field-actions'\nimport { pageFlash } from './flash'\nimport { isLeavingVisit, type FormStore } from './form'\nimport { HttpError, inertiaPost, requestJson, router } from './http'\nimport { ACTION_PATH_SEPARATOR, actionPath, PASSWORD_CONFIRMATION_INPUT } from './modal-actions'\nimport { openDatabaseNotifications } from './notifications'\nimport { submitFormById } from './page-actions'\nimport { currentPageQuery } from './page-query'\nimport type {\n ActionModalCancelledResponse,\n ActionModalSchema,\n ActionSchema,\n AnyActionSchema,\n} from './schema/actions'\nimport { isActionGroup } from './schema/actions'\nimport type { RecordKey, Size } from './schema/common'\nimport type { FieldActionResponse } from './schema/form'\nimport type { NotificationSchema } from './schema/notifications'\nimport { createStore, type Store } from './store'\n\nexport interface ActionContext {\n /** Encrypted page context token. */\n token: string\n /** `page`, `table`, `relationManager:Class`, `widget:Class`. */\n component?: string\n record?: RecordKey | null\n /** Selected record keys for bulk actions. */\n records?: RecordKey[]\n /** \"All filtered records\" bulk selection. */\n allRecords?: boolean\n arguments?: Record<string, unknown>\n /**\n * Names of the actions whose modals this action sits in, outermost first (actions in a\n * modal's footer). The server resolves the action by its path, `parent>child`.\n */\n parents?: string[]\n /**\n * Field actions (`component` = `field:{schema}::{key}`): the form the field belongs to.\n * Its state is sent with the action and the refreshed form is merged back into it.\n */\n form?: FormStore\n}\n\nexport interface ExecuteOptions {\n /** The current password, for actions with `requiresPasswordConfirmation()`. */\n password?: string\n /**\n * \"Create & create another\": run with the `another` argument and, when the server keeps\n * the modal open, reload it with a fresh form (keeping `preserveFormData` fields).\n */\n createAnother?: boolean\n}\n\n/** The argument `CreateAction` reads for \"Create & create another\". */\nexport const CREATE_ANOTHER_ARGUMENT = 'another'\n\n/**\n * The state of the fresh form after \"Create & create another\": the server's defaults,\n * plus the previous values of the fields `preserveFormData` names (all of them for `true`).\n */\nexport function createAnotherState(\n fresh: Record<string, unknown>,\n previous: Record<string, unknown>,\n preserve: boolean | string[] | undefined,\n): Record<string, unknown> {\n if (!preserve) {\n return fresh\n }\n\n const keys = preserve === true ? Object.keys(previous) : preserve\n const state = { ...fresh }\n\n for (const key of keys) {\n if (Object.prototype.hasOwnProperty.call(previous, key)) {\n state[key] = previous[key]\n }\n }\n\n return state\n}\n\nexport interface OpenModal {\n action: ActionSchema\n context: ActionContext\n modal: ActionModalSchema\n /** Current form values of the modal form. */\n errors: Record<string, string[]>\n processing: boolean\n /** Field actions: settles `runField()` with the action's result (undefined when closed). */\n resolve?: (result: unknown) => void\n /**\n * Bumped by `resetModal()` (\"Create & create another\"): the renderer focuses the form's\n * `autofocus()` field again (`focusAutofocusField()`) once the fresh form rendered.\n */\n refocus?: number\n}\n\nexport interface ActionRunnerState {\n /** Stack of open modals (nested modals are possible). */\n modals: OpenModal[]\n /** Name of the action currently loading its modal. */\n loading: string | null\n /**\n * Which run of it (component, action path and record): a table renders the same action\n * once per row, and only the clicked row's button is loading (`isActionLoading()`).\n */\n loadingKey?: string | null\n}\n\nexport interface ActionRunnerOptions {\n endpoints: { action: string; modal: string }\n onError?: (error: unknown) => void\n /** Called after a successful run so the UI can e.g. clear a table selection. */\n onSuccess?: (action: ActionSchema, context: ActionContext) => void\n /**\n * Shows notifications that arrive in JSON responses (a modal that `mountUsing()`\n * cancelled, field actions). Renderers can also set it with `setNotificationHandler()`.\n */\n onNotifications?: (notifications: NotificationSchema[]) => void\n}\n\n/**\n * Drives action buttons: plain links navigate, actions without a modal post straight to\n * the server, and actions with a modal fetch the modal schema first.\n */\n/**\n * Save a file an action handler returned. The action endpoint answers an Inertia visit (or\n * JSON), which cannot carry a file, so the server keeps it behind a signed, one-time link\n * served as an attachment: opening it saves the file and the page stays where it is.\n */\nexport function startDownload(url: string): void {\n if (typeof document === 'undefined') return\n\n const link = document.createElement('a')\n link.href = url\n link.download = ''\n link.rel = 'noopener'\n link.style.display = 'none'\n document.body.appendChild(link)\n link.click()\n link.remove()\n}\n\nexport class ActionRunner {\n public readonly store: Store<ActionRunnerState>\n\n /** Runs in flight, so a double click or a repeated shortcut doesn't submit twice. */\n private readonly running = new Set<string>()\n\n /** The form of each open modal (registered by the renderer), by modal path. */\n private readonly modalForms = new Map<string, FormStore>()\n\n constructor(private readonly options: ActionRunnerOptions) {\n this.store = createStore<ActionRunnerState>({ modals: [], loading: null, loadingKey: null })\n }\n\n get state(): ActionRunnerState {\n return this.store.get()\n }\n\n /** Show notifications from JSON responses with this handler (e.g. the renderer's toasts). */\n setNotificationHandler(\n handler: ((notifications: NotificationSchema[]) => void) | undefined,\n ): void {\n this.options.onNotifications = handler\n }\n\n private notify(notifications: NotificationSchema[] | undefined): void {\n if (notifications && notifications.length > 0) {\n this.options.onNotifications?.(notifications)\n }\n }\n\n /** Point the runner at the current panel's endpoints (they change per tenant/panel). */\n setEndpoints(endpoints: Partial<ActionRunnerOptions['endpoints']>): void {\n Object.assign(this.options.endpoints, endpoints)\n }\n\n /**\n * The renderer registers the form of an open modal, so nested actions can send its state\n * (`$mountedActions`, `getRawData()`) and `fillData()` can write into it. Returns the\n * function that unregisters it.\n */\n registerModalForm(action: ActionSchema, context: ActionContext, form: FormStore): () => void {\n const key = actionPath(action, context)\n this.modalForms.set(key, form)\n\n return () => {\n if (this.modalForms.get(key) === form) this.modalForms.delete(key)\n }\n }\n\n /** The open modals of the actions a nested action sits in, outermost first. */\n parentModals(context: ActionContext): Array<OpenModal | undefined> {\n const parents = context.parents ?? []\n\n return parents.map((_, index) => {\n const path = parents.slice(0, index + 1).join(ACTION_PATH_SEPARATOR)\n\n return this.state.modals.find(\n (modal) =>\n modal.context.component === context.component &&\n actionPath(modal.action, modal.context) === path,\n )\n })\n }\n\n /**\n * The form state of the modals a nested action sits in, outermost first (undefined when\n * none of them has a form).\n */\n mountedData(context: ActionContext): Array<Record<string, unknown>> | undefined {\n const parents = context.parents ?? []\n\n if (parents.length === 0) {\n return undefined\n }\n\n const forms = parents.map((_, index) =>\n this.modalForms.get(parents.slice(0, index + 1).join(ACTION_PATH_SEPARATOR)),\n )\n\n // Parents without a form have nothing to send.\n if (forms.every((form) => !form)) {\n return undefined\n }\n\n return forms.map((form) => form?.state.values ?? {})\n }\n\n /** Entry point for a click on an action button. */\n async trigger(action: ActionSchema, context: ActionContext): Promise<void> {\n if (action.disabled) {\n return\n }\n\n // `openDatabaseNotifications()`: a client-side button.\n if (action.opensDatabaseNotifications) {\n openDatabaseNotifications()\n\n return\n }\n\n // `makeModalSubmitAction()`: submit the modal this button sits in, with its arguments.\n if (action.submitsModal) {\n this.submitParentModal(action, context)\n\n return\n }\n\n // `formId()`: the page form submits itself with its state, wherever the button is.\n if (submitFormById(action, context)) {\n return\n }\n\n // `postToUrl()`: a POST request to the URL (e.g. \"lock session\"), not a visit.\n if (action.url && action.postToUrl) {\n const { router } = await import('@inertiajs/core')\n router.post(action.url)\n\n return\n }\n\n if (action.url && !action.hasAction && !action.hasModal) {\n if (action.download) {\n startDownload(action.url)\n } else if (action.openUrlInNewTab) {\n window.open(action.url, '_blank', 'noopener')\n } else {\n const { router } = await import('@inertiajs/core')\n router.visit(action.url)\n }\n\n return\n }\n\n if (isFieldActionContext(context)) {\n await this.runField(action, context)\n\n return\n }\n\n if (action.hasModal) {\n await this.openModal(action, context)\n\n return\n }\n\n this.execute(action, context)\n }\n\n /**\n * Run a field action (opening its modal first, if it has one) and resolve with its\n * result once it ran, or with undefined when the modal is closed without running it.\n */\n async runField(action: ActionSchema, context: ActionContext): Promise<unknown> {\n if (action.disabled) {\n return undefined\n }\n\n if (action.hasModal) {\n return new Promise<unknown>((resolve) => {\n void this.openModal(action, context, resolve)\n })\n }\n\n return this.executeField(action, context)\n }\n\n /**\n * Run the action whose modal `button` sits in (a `makeModalSubmitAction()` button) with\n * that modal's form state and the button's arguments.\n */\n submitParentModal(button: ActionSchema, context: ActionContext): void {\n const parents = context.parents ?? []\n const open = this.parentModals(context).at(-1)\n\n if (!open || parents.length === 0) {\n return\n }\n\n const form = this.modalForms.get(parents.join(ACTION_PATH_SEPARATOR))\n\n this.execute(\n open.action,\n { ...open.context, arguments: { ...open.context.arguments, ...button.arguments } },\n form?.state.values ?? {},\n )\n }\n\n /**\n * Close a modal the user dismissed (cancel, Escape, clicking away, close button). With\n * `cancelParentActionsOnClose()` its parents close too.\n */\n cancelModal(name: string): void {\n const open = this.state.modals.find((modal) => modal.action.name === name)\n const cancel = open?.modal.cancelParentActionsOnClose\n\n this.closeModal(name)\n\n if (open && cancel) {\n this.closeParents(open.context, cancel)\n }\n }\n\n /** Close the modals `context` sits in: all of them, or up to and including `until`. */\n closeParents(context: ActionContext, until: true | string): void {\n const parents = [...(context.parents ?? [])].reverse()\n\n for (const parent of parents) {\n this.closeModal(parent)\n\n if (until !== true && parent === until) {\n break\n }\n }\n }\n\n async openModal(\n action: ActionSchema,\n context: ActionContext,\n resolve?: (result: unknown) => void,\n ): Promise<void> {\n const key = `modal:${runKey(action, context)}`\n\n if (this.running.has(key)) {\n resolve?.(undefined)\n\n return\n }\n\n this.running.add(key)\n this.store.update({ loading: action.name, loadingKey: runKey(action, context) })\n\n try {\n const modal = await this.fetchModal(action, context)\n\n // `mountUsing()` halted or cancelled the action: the modal stays closed.\n if (isCancelledModal(modal)) {\n this.store.update({ loading: null, loadingKey: null })\n this.notify(modal.notifications)\n resolve?.(undefined)\n\n return\n }\n\n this.store.set((state) => ({\n loading: null,\n loadingKey: null,\n modals: [\n ...state.modals,\n { action, context, modal, errors: {}, processing: false, resolve },\n ],\n }))\n } catch (error) {\n this.store.update({ loading: null, loadingKey: null })\n resolve?.(undefined)\n this.options.onError?.(error)\n } finally {\n this.running.delete(key)\n }\n }\n\n private fetchModal(\n action: ActionSchema,\n context: ActionContext,\n ): Promise<ActionModalSchema | ActionModalCancelledResponse> {\n // Bulk actions send their selection (and, for \"select all\", the page's table state), so\n // the server resolves the bulk action rather than a record action and fills `$records`.\n const records = context.records\n const isBulk = records !== undefined\n const params = {\n token: context.token,\n component: context.component,\n action: actionPath(action, context),\n record: context.record ?? undefined,\n records: records !== undefined && records.length > 0 ? records : undefined,\n allRecords: context.allRecords ? 1 : undefined,\n bulk: isBulk ? 1 : undefined,\n // The table state (active tab, filters, search) for record and bulk actions alike: a\n // record action on a non-default tab resolves its record through that tab's query.\n tableQuery: currentPageQuery(),\n arguments: context.arguments,\n }\n const mountedData = this.mountedData(context)\n\n // Field actions send the form state, and nested actions their parents' form state,\n // which needs a request body.\n if (isFieldActionContext(context)) {\n return requestJson<ActionModalSchema | ActionModalCancelledResponse>(\n this.options.endpoints.modal,\n { method: 'POST', body: { ...params, state: context.form?.state.values ?? {} } },\n )\n }\n\n return requestJson<ActionModalSchema | ActionModalCancelledResponse>(\n this.options.endpoints.modal,\n mountedData ? { method: 'POST', body: { ...params, mountedData } } : { query: params },\n )\n }\n\n /**\n * After \"Create & create another\": load the modal again so its form starts from the\n * server's defaults, keeping the `preserveFormData` fields from the values just sent.\n */\n async resetModal(name: string, previous: Record<string, unknown> = {}): Promise<void> {\n const open = this.state.modals.find((modal) => modal.action.name === name)\n\n if (!open) {\n return\n }\n\n try {\n const modal = await this.fetchModal(open.action, open.context)\n\n if (isCancelledModal(modal)) {\n this.notify(modal.notifications)\n this.closeModal(name)\n\n return\n }\n\n if (modal.form) {\n modal.form = {\n ...modal.form,\n // A wizard goes back to the step holding the `autofocus()` field.\n components: revealAutofocusField(modal.form.components),\n state: createAnotherState(modal.form.state, previous, modal.preserveFormData),\n }\n }\n\n this.store.set((state) => ({\n ...state,\n modals: state.modals.map((entry) =>\n entry === open || entry.action.name === name\n ? { ...entry, modal, errors: {}, refocus: (entry.refocus ?? 0) + 1 }\n : entry,\n ),\n }))\n } catch (error) {\n this.options.onError?.(error)\n }\n }\n\n /** Whether this action is currently being submitted for this context. */\n isRunning(action: ActionSchema, context: ActionContext): boolean {\n return this.running.has(runKey(action, context))\n }\n\n closeModal(name?: string): void {\n const modals = this.state.modals\n const remaining = name\n ? modals.filter((modal) => modal.action.name !== name)\n : modals.slice(0, -1)\n\n this.store.set((state) => ({ ...state, modals: remaining }))\n\n // A field action's caller learns that its modal closed without running.\n for (const modal of modals) {\n if (!remaining.includes(modal)) modal.resolve?.(undefined)\n }\n }\n\n /** Submit the topmost modal (or run a modal-less action) through Inertia. */\n execute(\n action: ActionSchema,\n context: ActionContext,\n data: Record<string, unknown> = {},\n options: ExecuteOptions = {},\n ): void {\n if (isFieldActionContext(context)) {\n void this.executeField(action, context, data)\n\n return\n }\n\n const key = runKey(action, context)\n\n if (this.running.has(key)) {\n return\n }\n\n this.running.add(key)\n this.setProcessing(action.name, true)\n\n // Edit pages (`detectConflicts()`): page actions send the version the form was loaded\n // from, so the server refuses to save over somebody else's changes.\n const version = context.component === 'page' ? currentRecordVersion() : null\n\n if (version !== null) markRecordSubmitted()\n\n inertiaPost(\n actionEndpoint(this.options.endpoints.action, context),\n {\n ...(version !== null ? { [RECORD_VERSION_INPUT]: version } : {}),\n token: context.token,\n component: context.component,\n action: actionPath(action, context),\n record: context.record ?? undefined,\n records: context.records,\n allRecords: context.allRecords ? 1 : undefined,\n bulk: context.records !== undefined ? 1 : undefined,\n arguments: options.createAnother\n ? { ...context.arguments, [CREATE_ANOTHER_ARGUMENT]: true }\n : context.arguments,\n tableQuery: currentPageQuery(),\n data,\n mountedData: this.mountedData(context),\n [PASSWORD_CONFIRMATION_INPUT]: options.password || undefined,\n },\n {\n onError: (errors) => {\n if (CONFLICT_ERROR_KEY in (errors as Record<string, unknown>)) reportSaveConflict()\n\n // A nested action without a modal of its own (e.g. `getValidatedData()` on its\n // parent failed): the parent's modal shows the errors.\n const hasModal = this.state.modals.some((modal) => modal.action.name === action.name)\n const parent = hasModal ? undefined : this.parentModals(context).at(-1)\n\n this.setErrors(\n parent ? parent.action.name : action.name,\n errors as Record<string, string>,\n )\n },\n onSuccess: (page) => {\n const flash = pageFlash(page as Page).alfakitAction\n\n // `fillData()`: values written into the parents' forms.\n for (const filled of flash?.parentData ?? []) {\n const parents = context.parents ?? []\n const index = parents.lastIndexOf(filled.name)\n const form =\n index >= 0\n ? this.modalForms.get(parents.slice(0, index + 1).join(ACTION_PATH_SEPARATOR))\n : undefined\n\n for (const [path, value] of Object.entries(filled.data)) {\n form?.setValue(path, value, { silent: true })\n }\n }\n\n if (\n !flash ||\n flash.status === 'cancelled' ||\n (flash.status === 'success' && flash.closeModal !== false)\n ) {\n this.closeModal(action.name)\n }\n\n // `cancelParentActions()`: the modals this nested action was opened from close too.\n if (flash?.status === 'success' && flash.cancelParentActions) {\n this.closeParents(\n context,\n typeof flash.cancelParentActions === 'string' ? flash.cancelParentActions : true,\n )\n }\n\n // `replaceMountedAction()`: the next action opens (or runs) in place of this one.\n const replacement = flash?.status === 'success' ? flash.replaceMountedAction : undefined\n\n if (replacement) {\n const next: ActionSchema = {\n type: 'Action',\n name: replacement.name,\n hasModal: replacement.hasModal || undefined,\n hasAction: true,\n }\n const nextContext: ActionContext = {\n ...context,\n arguments: replacement.arguments ?? undefined,\n }\n\n if (replacement.hasModal) {\n void this.openModal(next, nextContext)\n } else {\n this.execute(next, nextContext)\n }\n }\n\n if (flash?.status === 'success' && flash.closeModal === false && options.createAnother) {\n void this.resetModal(action.name, data)\n }\n\n if (flash?.status === 'success' && flash.download) {\n startDownload(flash.download)\n }\n\n if (!flash || flash.status === 'success') {\n this.options.onSuccess?.(action, context)\n }\n },\n onFinish: () => {\n this.running.delete(key)\n this.setProcessing(action.name, false)\n },\n },\n )\n }\n\n /**\n * Run an action and resolve with its JSON result (for callers that don't want an\n * Inertia visit, e.g. a custom widget).\n */\n async executeJson<T = unknown>(\n action: ActionSchema,\n context: ActionContext,\n data: Record<string, unknown> = {},\n ): Promise<T> {\n try {\n const response = await requestJson<{ result: T }>(\n actionEndpoint(this.options.endpoints.action, context),\n {\n method: 'POST',\n body: {\n token: context.token,\n component: context.component,\n action: actionPath(action, context),\n record: context.record ?? undefined,\n records: context.records,\n allRecords: context.allRecords ? 1 : undefined,\n bulk: context.records !== undefined ? 1 : undefined,\n arguments: context.arguments,\n tableQuery: currentPageQuery(),\n data,\n },\n },\n )\n\n return response.result\n } catch (error) {\n if (error instanceof HttpError && error.status === 422) {\n this.setErrors(\n action.name,\n Object.fromEntries(\n Object.entries(error.errors).map(([key, messages]) => [key, messages[0] ?? '']),\n ),\n )\n }\n\n throw error\n }\n }\n\n /**\n * Run a field action as JSON with its form's state; merge the refreshed form from the\n * response, settle the modal's `runField()` promise and close the modal.\n */\n async executeField(\n action: ActionSchema,\n context: ActionContext,\n data: Record<string, unknown> = {},\n ): Promise<unknown> {\n const key = runKey(action, context)\n\n if (this.running.has(key)) {\n return undefined\n }\n\n this.running.add(key)\n this.setProcessing(action.name, true)\n\n const form = context.form\n const sent = form?.state.values ?? {}\n\n try {\n const response = await requestJson<FieldActionResponse>(\n actionEndpoint(this.options.endpoints.action, context),\n {\n method: 'POST',\n body: {\n token: context.token,\n component: context.component,\n action: actionPath(action, context),\n record: context.record ?? undefined,\n arguments: context.arguments,\n // A field action inside a record action's modal on a list tab.\n tableQuery: currentPageQuery(),\n data,\n state: sent,\n fingerprints: form?.currentFingerprints,\n },\n },\n )\n\n // A partial response that doesn't fit the tree falls back to a full refresh.\n if (response.form && form && !form.applyResponse(response.form, sent)) {\n void form.refresh()\n }\n\n this.notify(response.notifications)\n\n if (response.status === 'halted') {\n return undefined\n }\n\n if (response.status === 'success') {\n const modal = this.state.modals.find((open) => open.action.name === action.name)\n modal?.resolve?.(response.result)\n }\n\n if (response.status === 'cancelled' || response.closeModal !== false) {\n this.closeModal(action.name)\n }\n\n if (response.status === 'success') {\n this.options.onSuccess?.(action, context)\n\n if (response.download) {\n startDownload(response.download)\n }\n\n if (response.redirect) {\n const { router } = await import('@inertiajs/core')\n router.visit(response.redirect)\n }\n }\n\n return response.status === 'success' ? response.result : undefined\n } catch (error) {\n if (error instanceof HttpError && error.status === 422) {\n this.setErrors(\n action.name,\n Object.fromEntries(\n Object.entries(error.errors).map(([field, messages]) => [field, messages[0] ?? '']),\n ),\n )\n } else {\n this.options.onError?.(error)\n }\n\n return undefined\n } finally {\n this.running.delete(key)\n this.setProcessing(action.name, false)\n }\n }\n\n private setProcessing(name: string, processing: boolean): void {\n this.store.set((state) => ({\n ...state,\n modals: state.modals.map((modal) =>\n modal.action.name === name\n ? { ...modal, processing, errors: processing ? {} : modal.errors }\n : modal,\n ),\n }))\n }\n\n private setErrors(name: string, errors: Record<string, string>): void {\n const normalized: Record<string, string[]> = {}\n\n for (const [key, message] of Object.entries(errors)) {\n normalized[key] = [message]\n }\n\n this.store.set((state) => ({\n ...state,\n modals: state.modals.map((modal) =>\n modal.action.name === name ? { ...modal, errors: normalized } : modal,\n ),\n }))\n }\n}\n\n/**\n * Whether an action button should bind its key bindings globally. Record actions repeat\n * on every row, so a page-wide shortcut would run them once per record; they only bind\n * when rendered outside a record (header, page and bulk actions).\n */\nexport function bindsKeyBindings(\n action: Pick<ActionSchema, 'keyBindings' | 'disabled'>,\n context: Pick<ActionContext, 'record'>,\n): boolean {\n return Boolean(action.keyBindings?.length) && !action.disabled && context.record == null\n}\n\n/** Button sizes every renderer's shadcn `Button` understands. */\nexport type ActionButtonSize = 'xs' | 'sm' | 'default' | 'lg'\n\n/**\n * The button size for an action: its own `size()` wins over the size the surrounding\n * list asks for (`md` is the default button, `xl` the largest one).\n */\nexport function resolveActionSize(\n size: Size | null | undefined,\n fallback: ActionButtonSize = 'default',\n): ActionButtonSize {\n switch (size) {\n case 'xs':\n return 'xs'\n case 'sm':\n return 'sm'\n case 'md':\n return 'default'\n case 'lg':\n case 'xl':\n return 'lg'\n default:\n return fallback\n }\n}\n\n/** The square icon-only button that matches a button size. */\nexport function iconButtonSize(size: ActionButtonSize): 'icon-xs' | 'icon-sm' | 'icon' {\n return size === 'xs' ? 'icon-xs' : size === 'sm' ? 'icon-sm' : 'icon'\n}\n\nexport interface DropdownPlacement {\n side: 'top' | 'right' | 'bottom' | 'left'\n align: 'start' | 'center' | 'end'\n}\n\n/**\n * Parse an ActionGroup `dropdownPlacement()` (`bottom-start`, `top-end`, `left`, …) into the\n * side/align pair dropdown primitives take. Defaults to `bottom` / `end`.\n */\nexport function parseDropdownPlacement(placement: string | null | undefined): DropdownPlacement {\n const [side, align] = (placement ?? '').split('-')\n const sides = ['top', 'right', 'bottom', 'left'] as const\n const aligns = ['start', 'center', 'end'] as const\n\n const knownSide = sides.find((candidate) => candidate === side)\n const resolvedAlign =\n aligns.find((candidate) => candidate === align) ?? (knownSide && !align ? 'center' : 'end')\n\n return { side: knownSide ?? 'bottom', align: resolvedAlign }\n}\n\n/** Every action inside a group, nested groups flattened. */\nexport function flattenActionGroup(actions: AnyActionSchema[]): ActionSchema[] {\n return actions.flatMap((action) =>\n isActionGroup(action) ? flattenActionGroup(action.actions) : [action],\n )\n}\n\n/**\n * Whether an open modal is hidden because a nested modal was opened from it. Nested modals\n * hide their parents unless they opt into `overlayParentActions()`; a hidden parent shows\n * again when the child closes.\n */\nexport function isModalHiddenByChild(modals: OpenModal[], index: number): boolean {\n const modal = modals[index]\n\n if (!modal) {\n return false\n }\n\n const path = actionPath(modal.action, modal.context)\n\n return modals.slice(index + 1).some((child) => {\n if (child.modal.overlayParent === true) return false\n\n const parents = child.context.parents ?? []\n\n return parents.some(\n (_, position) => parents.slice(0, position + 1).join(ACTION_PATH_SEPARATOR) === path,\n )\n })\n}\n\n/** Justify class keyword for modal footer buttons: `footerActionsAlignment`, else `alignment`. */\nexport function modalFooterAlignment(\n modal: Pick<ActionModalSchema, 'alignment' | 'footerActionsAlignment'>,\n): 'start' | 'center' | 'end' | 'between' {\n const alignment = modal.footerActionsAlignment ?? modal.alignment\n\n switch (alignment) {\n case 'start':\n case 'center':\n case 'between':\n return alignment\n default:\n return 'end'\n }\n}\n\n/**\n * The physical side a slide-over enters from: `end` (default) is the right edge in\n * left-to-right documents and the left edge in right-to-left ones.\n */\nexport function slideOverSide(\n position: 'start' | 'end' | null | undefined,\n direction: 'ltr' | 'rtl' = 'ltr',\n): 'left' | 'right' {\n const atStart = position === 'start'\n\n return atStart === (direction === 'rtl') ? 'right' : 'left'\n}\n\nfunction isCancelledModal(\n modal: ActionModalSchema | ActionModalCancelledResponse,\n): modal is ActionModalCancelledResponse {\n return (modal as Partial<ActionModalCancelledResponse>).cancelled === true\n}\n\n/**\n * Whether closing a modal has to ask first: its form changed and the modal has\n * `unsavedChangesAlert` (the action's own setting or the panel's `unsavedChangesAlerts()`).\n */\nexport function shouldConfirmModalClose(\n modal: Pick<ActionModalSchema, 'unsavedChangesAlert'>,\n form: { isDirty: boolean } | null | undefined,\n): boolean {\n return Boolean(modal.unsavedChangesAlert && form?.isDirty)\n}\n\n/**\n * Ask whether to close a modal with unsaved changes (`window.confirm`); true when it may\n * close. Without changes (or the alert) it never asks.\n */\nexport function confirmModalClose(\n modal: Pick<ActionModalSchema, 'unsavedChangesAlert'>,\n form: { isDirty: boolean } | null | undefined,\n message: string,\n): boolean {\n if (!shouldConfirmModalClose(modal, form) || typeof window === 'undefined') {\n return true\n }\n\n return window.confirm(message)\n}\n\n/**\n * Warn before leaving the page (a reload, or an Inertia visit when `message` is given)\n * while a modal form with `unsavedChangesAlert` has unsaved changes. Returns a function\n * that removes the listeners.\n */\nexport function guardModalUnload(\n modal: Pick<ActionModalSchema, 'unsavedChangesAlert'>,\n form: { isDirty: boolean } | null | undefined,\n message?: string,\n): () => void {\n if (!modal.unsavedChangesAlert || !form || typeof window === 'undefined') {\n return () => {}\n }\n\n const listener = (event: BeforeUnloadEvent) => {\n if (form.isDirty) {\n event.preventDefault()\n event.returnValue = ''\n }\n }\n\n window.addEventListener('beforeunload', listener)\n\n const removeVisitGuard = message\n ? router.on('before', (event) => {\n if (form.isDirty && isLeavingVisit(event.detail.visit) && !window.confirm(message)) {\n event.preventDefault()\n }\n })\n : () => {}\n\n return () => {\n window.removeEventListener('beforeunload', listener)\n removeVisitGuard()\n }\n}\n\n/** The context of a user or tenant menu action: the page's token and the menu's component. */\nexport function menuActionContext(token: string, menu: 'userMenu' | 'tenantMenu'): ActionContext {\n return { token, component: menu }\n}\n\n/**\n * Split menu entries into their groups (`group` index, nested arrays in\n * `userMenuItems()`), in order; renderers draw a separator between groups.\n */\nexport function groupMenuItems<T extends { group?: number }>(items: T[]): T[][] {\n const groups: T[][] = []\n let current: number | null = null\n\n for (const item of items) {\n const group = item.group ?? 0\n\n if (current === null || group !== current) {\n groups.push([])\n current = group\n }\n\n groups[groups.length - 1]!.push(item)\n }\n\n return groups\n}\n\n/** Whether this button's run (this action for this record) is fetching its modal. */\nexport function isActionLoading(\n state: ActionRunnerState,\n action: ActionSchema,\n context: ActionContext,\n): boolean {\n return state.loadingKey === runKey(action, context)\n}\n\n/** Whether this button's run (this action for this record) has a modal that is submitting. */\nexport function isActionProcessing(\n state: ActionRunnerState,\n action: ActionSchema,\n context: ActionContext,\n): boolean {\n const key = runKey(action, context)\n\n return state.modals.some(\n (modal) => modal.processing && runKey(modal.action, modal.context) === key,\n )\n}\n\nfunction runKey(action: Pick<ActionSchema, 'name'>, context: ActionContext): string {\n return [context.component ?? 'page', actionPath(action, context), context.record ?? ''].join(\n '\\u0000',\n )\n}\n\n/**\n * The action endpoint for a run. \"All records\" bulk actions carry the page's query string\n * (filters, search, list tab), so the server selects exactly the records the table shows.\n */\nexport function actionEndpoint(\n endpoint: string,\n context: Pick<ActionContext, 'allRecords'>,\n search: string = typeof window !== 'undefined' ? window.location.search : '',\n): string {\n if (!context.allRecords || search.length <= 1) {\n return endpoint\n }\n\n return endpoint + (endpoint.includes('?') ? '&' : '?') + search.replace(/^\\?/, '')\n}\n"],"mappings":"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"}
@@ -183,6 +183,12 @@ export declare function pickerFilterFormOptions(owner: FormStore, path: string):
183
183
  * either side normalises the same way.
184
184
  */
185
185
  export declare function fileUploadPaths(value: unknown): string[];
186
+ /**
187
+ * The file entry of each path: the server's (`component.files`), or the one this session
188
+ * uploaded. A temporary upload comes back from the server without a `url` after a round trip,
189
+ * so the session's entry (with its local image preview) wins over it then (W-S2-02).
190
+ */
191
+ export declare function fileUploadEntries<T extends UploadedFile>(paths: readonly string[], serverFiles: readonly UploadedFile[], uploaded: readonly T[]): Array<T | UploadedFile>;
186
192
  /** The picker's `accept`: the accepted types plus the extensions of `mimeTypeMap()`. */
187
193
  export declare function fileUploadAccept(schema: Pick<FileUploadSchema, 'acceptedFileTypes' | 'mimeTypeMap'>): string | undefined;
188
194
  /** A `'2:1'` / `'16/9'` ratio as a CSS `aspect-ratio` value. */
@@ -1 +1 @@
1
- {"version":3,"file":"advanced-fields.d.ts","names":[],"sources":["../src/advanced-fields.ts"],"mappings":";;;;;;;wBAkBgB,aAAa,iBAAiB;;wBAY9B,kBACd,OAAO,oBACP,OAAO,oBACP,iBACC;;wBAQa,mBAAmB,OAAO,qBAAqB;;;;;wBAY/C,oBAAoB,UAAU,KAAK,wCACjD,QAAQ,KACR,gBACC;iBAYc,kBAAkB;;EAEjC;EACA,QAAQ;;;;;;wBAOM,mBAAmB,UAAU,KAAK,8BAChD,QAAQ,MACP,kBAAkB;;wBAgBL,mBACd,WAAW,KAAK,4BAChB,OAAO,KAAK,0CACZ,OAAO;;;;;;wBAaO,kBACd,WAAW,KAAK,oCAChB,OAAO,oBACP,gBACC;;wBAca,iBACd,WAAW,KAAK,oCAChB,OAAO,oBACP;;iBAWe;EACf;EACA;;;;;;;;wBASc,kBACd,aACA,iBACA,OAAO,qBACP;;wBAuDc,kBACd,kBACA,gBACA;;wBAcc,sBAAsB,kBAAkB;;wBAiBxC,aACd,gBACA,QAAQ,KAAK;;wBAoBC,YACd,kBACA,QAAQ,KAAK;iBAKE;EACf;;EAEA;;EAEA;;EAEA;;;;;;wBAOc,WACd,QAAQ,KAAK,oEACZ;KAoCE,cAAc,KAAK;;wBAqCR,cAAc,eAAe,QAAQ;;wBAkBrC,cAAc,iBAAiB,QAAQ,aAAa;;wBAkBpD,WAAW,eAAe,QAAQ;;wBAKlC,aACd,QAAQ,KAAK;;wBAQC,mBAAmB,QAAQ,KAAK,2BAA2B;;wBAK3D,kBAAkB,QAAQ,KAAK;;;;;wBAQ/B,mBACd,kBACA,QAAQ,KAAK,6BAA6B,cACzC;EAAQ;EAAe;;;wBAcV,gBACd;EAAW;EAAe;GAC1B;EAAW;EAAmB;EAAuB;IACpD;;wBAca,eAAe,QAAQ,KAAK,4BAA4B,IAAI;;wBAK5D,gBACd,QAAQ,KAAK,sBACb;;;;;wBASc,gBACd,QAAQ,aACR;EACG;EAAa;EAAa;EAAc;;;wBAc7B,kBAAkB,kBAAkB,QAAQ;;wBAO5C,oBAAoB,kBAAkB,QAAQ,aAAa;KAMtE,cAAc,cACjB,KAAK;;;;;;;wBAQS,iBACd,oBACA,gBACA,QAAQ;;;;;wBAyDM,YAAY,kBAAkB,eAAe,QAAQ;;;;;;wBAgBrD,qBACd,OAAO,cACP;EACE,OAAO;EACP;EACA,QAAQ;EACR;EACA;;EAEA;EACA,WAAW;EACX;;;;;;wBAsDY,gBACd,QAAQ,oBACR,QAAQ,KAAK;iBAWE;EACf;EACA;EACA;;;;;;wBAOc,WACd,eACA,wBACA,sBACA,iBACA,oBACC;;wBAyCa,kBACd,eACA,wBACA,uBACC;;wBAea,gBAAgB,oBAAoB,OAAO,aAAa;;;;;wBAgBxD,oBACd,oBACA,aACA,mBACA;;;;;;;wBAmBc,wBAAwB,OAAO,WAAW,eAAe;;;;;;wBAqBzD,gBAAgB;;wBAShB,iBACd,QAAQ,KAAK;;wBAYC,eAAe;;;;;wBAUf,mBACd,iBACA,aACA,QAAQ,KAAK,kCACb;;wBAQc,kBAAkB,MAAM,KAAK;EAC3C;EACA;;;;;;wBASc,mBAAmB,iBAAiB,GAAG,YAAY,QAAQ,OAAO,QAAQ;;wBAuB1E,mBAAmB,gBAAgB;iBAMlC;EACf;EACA;EACA;EACA;EACA;EACA;;;wBAIc,iBACd,YAAY,yCACX"}
1
+ {"version":3,"file":"advanced-fields.d.ts","names":[],"sources":["../src/advanced-fields.ts"],"mappings":";;;;;;;wBAkBgB,aAAa,iBAAiB;;wBAY9B,kBACd,OAAO,oBACP,OAAO,oBACP,iBACC;;wBAQa,mBAAmB,OAAO,qBAAqB;;;;;wBAY/C,oBAAoB,UAAU,KAAK,wCACjD,QAAQ,KACR,gBACC;iBAYc,kBAAkB;;EAEjC;EACA,QAAQ;;;;;;wBAOM,mBAAmB,UAAU,KAAK,8BAChD,QAAQ,MACP,kBAAkB;;wBAgBL,mBACd,WAAW,KAAK,4BAChB,OAAO,KAAK,0CACZ,OAAO;;;;;;wBAaO,kBACd,WAAW,KAAK,oCAChB,OAAO,oBACP,gBACC;;wBAca,iBACd,WAAW,KAAK,oCAChB,OAAO,oBACP;;iBAWe;EACf;EACA;;;;;;;;wBASc,kBACd,aACA,iBACA,OAAO,qBACP;;wBAuDc,kBACd,kBACA,gBACA;;wBAcc,sBAAsB,kBAAkB;;wBAiBxC,aACd,gBACA,QAAQ,KAAK;;wBAoBC,YACd,kBACA,QAAQ,KAAK;iBAKE;EACf;;EAEA;;EAEA;;EAEA;;;;;;wBAOc,WACd,QAAQ,KAAK,oEACZ;KAoCE,cAAc,KAAK;;wBAqCR,cAAc,eAAe,QAAQ;;wBAkBrC,cAAc,iBAAiB,QAAQ,aAAa;;wBAkBpD,WAAW,eAAe,QAAQ;;wBAKlC,aACd,QAAQ,KAAK;;wBAQC,mBAAmB,QAAQ,KAAK,2BAA2B;;wBAK3D,kBAAkB,QAAQ,KAAK;;;;;wBAQ/B,mBACd,kBACA,QAAQ,KAAK,6BAA6B,cACzC;EAAQ;EAAe;;;wBAcV,gBACd;EAAW;EAAe;GAC1B;EAAW;EAAmB;EAAuB;IACpD;;wBAca,eAAe,QAAQ,KAAK,4BAA4B,IAAI;;wBAK5D,gBACd,QAAQ,KAAK,sBACb;;;;;wBASc,gBACd,QAAQ,aACR;EACG;EAAa;EAAa;EAAc;;;wBAc7B,kBAAkB,kBAAkB,QAAQ;;wBAO5C,oBAAoB,kBAAkB,QAAQ,aAAa;KAMtE,cAAc,cACjB,KAAK;;;;;;;wBAQS,iBACd,oBACA,gBACA,QAAQ;;;;;wBAyDM,YAAY,kBAAkB,eAAe,QAAQ;;;;;;wBAgBrD,qBACd,OAAO,cACP;EACE,OAAO;EACP;EACA,QAAQ;EACR;EACA;;EAEA;EACA,WAAW;EACX;;;;;;wBAsDY,gBACd,QAAQ,oBACR,QAAQ,KAAK;iBAWE;EACf;EACA;EACA;;;;;;wBAOc,WACd,eACA,wBACA,sBACA,iBACA,oBACC;;wBAyCa,kBACd,eACA,wBACA,uBACC;;wBAea,gBAAgB,oBAAoB,OAAO,aAAa;;;;;wBAgBxD,oBACd,oBACA,aACA,mBACA;;;;;;;wBAmBc,wBAAwB,OAAO,WAAW,eAAe;;;;;;wBAqBzD,gBAAgB;;;;;;wBAahB,kBAAkB,UAAU,cAC1C,0BACA,sBAAsB,gBACtB,mBAAmB,MAClB,MAAM,IAAI;;wBAYG,iBACd,QAAQ,KAAK;;wBAYC,eAAe;;;;;wBAUf,mBACd,iBACA,aACA,QAAQ,KAAK,kCACb;;wBAQc,kBAAkB,MAAM,KAAK;EAC3C;EACA;;;;;;wBASc,mBAAmB,iBAAiB,GAAG,YAAY,QAAQ,OAAO,QAAQ;;wBAuB1E,mBAAmB,gBAAgB;iBAMlC;EACf;EACA;EACA;EACA;EACA;EACA;;;wBAIc,iBACd,YAAY,yCACX"}
@@ -475,6 +475,25 @@ function fileUploadPaths(value) {
475
475
  if (Array.isArray(value)) return value.filter((path) => typeof path === "string" && path !== "");
476
476
  return typeof value === "string" && value !== "" ? [value] : [];
477
477
  }
478
+ /**
479
+ * The file entry of each path: the server's (`component.files`), or the one this session
480
+ * uploaded. A temporary upload comes back from the server without a `url` after a round trip,
481
+ * so the session's entry (with its local image preview) wins over it then (W-S2-02).
482
+ */
483
+ function fileUploadEntries(paths, serverFiles, uploaded) {
484
+ return paths.map((path) => {
485
+ const server = serverFiles.find((file) => file.path === path);
486
+ const local = uploaded.find((file) => file.path === path);
487
+ if (local && !server?.url) return {
488
+ ...server,
489
+ ...local
490
+ };
491
+ return server ?? local ?? {
492
+ path,
493
+ name: path.replace(/^tmp:/, "")
494
+ };
495
+ });
496
+ }
478
497
  /** The picker's `accept`: the accepted types plus the extensions of `mimeTypeMap()`. */
479
498
  function fileUploadAccept(schema) {
480
499
  if (!schema.acceptedFileTypes || schema.acceptedFileTypes.length === 0) return void 0;
@@ -541,6 +560,6 @@ function modalTablePaging(pagination) {
541
560
  };
542
561
  }
543
562
  //#endregion
544
- export { builderBlockCounts, builderItemLabel, builderItemSchema, builderItems, builderPickerMove, canAddBuilderBlock, concurrencyLimiter, cssAspectRatio, fileUploadAccept, fileUploadPaths, filterBuilderBlocks, groupBuilderBlocks, indentCode, insertBuilderItem, insertUploadedFile, modalTablePaging, modalTableQuery, modalTableSelected, newlineWithIndent, pickerFilterFormOptions, sliderBehavior, sliderBlocksTap, sliderBounds, sliderDirection, sliderFillSections, sliderFillStyle, sliderFromPrimitive, sliderHasTooltips, sliderNextValues, sliderPercent, sliderPips, sliderPrimitive, sliderShift, sliderShowsTooltip, sliderSnap, sliderState, sliderToPrimitive, sliderValueAt, sliderValues, startSliderRangeDrag, toggleButtonsNext, toggleButtonsSelected, toggleModalTableKey, uploadedFileLinks };
563
+ export { builderBlockCounts, builderItemLabel, builderItemSchema, builderItems, builderPickerMove, canAddBuilderBlock, concurrencyLimiter, cssAspectRatio, fileUploadAccept, fileUploadEntries, fileUploadPaths, filterBuilderBlocks, groupBuilderBlocks, indentCode, insertBuilderItem, insertUploadedFile, modalTablePaging, modalTableQuery, modalTableSelected, newlineWithIndent, pickerFilterFormOptions, sliderBehavior, sliderBlocksTap, sliderBounds, sliderDirection, sliderFillSections, sliderFillStyle, sliderFromPrimitive, sliderHasTooltips, sliderNextValues, sliderPercent, sliderPips, sliderPrimitive, sliderShift, sliderShowsTooltip, sliderSnap, sliderState, sliderToPrimitive, sliderValueAt, sliderValues, startSliderRangeDrag, toggleButtonsNext, toggleButtonsSelected, toggleModalTableKey, uploadedFileLinks };
545
564
 
546
565
  //# sourceMappingURL=advanced-fields.js.map