@judo/components 0.1.0

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 (133) hide show
  1. package/LICENSE +277 -0
  2. package/README.md +200 -0
  3. package/dist/FlexRenderer-0KCxU9QU.js +1612 -0
  4. package/dist/FlexRenderer-0KCxU9QU.js.map +1 -0
  5. package/dist/FormContainerRenderer-B8H4kyz0.js +67 -0
  6. package/dist/FormContainerRenderer-B8H4kyz0.js.map +1 -0
  7. package/dist/FormContainerRenderer-CtuXP8jP.js +3 -0
  8. package/dist/TableContainerRenderer-gKBlsD4S.js +127 -0
  9. package/dist/TableContainerRenderer-gKBlsD4S.js.map +1 -0
  10. package/dist/TableContainerRenderer-qbzKI1Cd.js +2 -0
  11. package/dist/ViewContainerRenderer-7Cx4fcLp.js +3 -0
  12. package/dist/ViewContainerRenderer-DCRaE_dq.js +132 -0
  13. package/dist/ViewContainerRenderer-DCRaE_dq.js.map +1 -0
  14. package/dist/containers/FormContainerRenderer.d.ts +11 -0
  15. package/dist/containers/FormContainerRenderer.d.ts.map +1 -0
  16. package/dist/containers/PageRenderer.d.ts +9 -0
  17. package/dist/containers/PageRenderer.d.ts.map +1 -0
  18. package/dist/containers/TableContainerRenderer.d.ts +11 -0
  19. package/dist/containers/TableContainerRenderer.d.ts.map +1 -0
  20. package/dist/containers/ViewContainerRenderer.d.ts +12 -0
  21. package/dist/containers/ViewContainerRenderer.d.ts.map +1 -0
  22. package/dist/dialogs/LinkSelectorDialog.d.ts +21 -0
  23. package/dist/dialogs/LinkSelectorDialog.d.ts.map +1 -0
  24. package/dist/errors/ContainerErrorBoundary.d.ts +42 -0
  25. package/dist/errors/ContainerErrorBoundary.d.ts.map +1 -0
  26. package/dist/errors/index.d.ts +2 -0
  27. package/dist/errors/index.d.ts.map +1 -0
  28. package/dist/find-on-init-action-C5CqxQaH.js +7727 -0
  29. package/dist/find-on-init-action-C5CqxQaH.js.map +1 -0
  30. package/dist/hooks/use-file-handling.d.ts +79 -0
  31. package/dist/hooks/use-file-handling.d.ts.map +1 -0
  32. package/dist/hooks/use-page-title.d.ts +23 -0
  33. package/dist/hooks/use-page-title.d.ts.map +1 -0
  34. package/dist/hooks/use-table-data.d.ts +77 -0
  35. package/dist/hooks/use-table-data.d.ts.map +1 -0
  36. package/dist/index.css +2 -0
  37. package/dist/index.d.ts +44 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +296 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/inputs/BinaryInputComponent.d.ts +15 -0
  42. package/dist/inputs/BinaryInputComponent.d.ts.map +1 -0
  43. package/dist/inputs/CheckboxComponent.d.ts +14 -0
  44. package/dist/inputs/CheckboxComponent.d.ts.map +1 -0
  45. package/dist/inputs/DateInputComponent.d.ts +14 -0
  46. package/dist/inputs/DateInputComponent.d.ts.map +1 -0
  47. package/dist/inputs/DateTimeInputComponent.d.ts +14 -0
  48. package/dist/inputs/DateTimeInputComponent.d.ts.map +1 -0
  49. package/dist/inputs/EnumerationComboComponent.d.ts +20 -0
  50. package/dist/inputs/EnumerationComboComponent.d.ts.map +1 -0
  51. package/dist/inputs/EnumerationRadioComponent.d.ts +22 -0
  52. package/dist/inputs/EnumerationRadioComponent.d.ts.map +1 -0
  53. package/dist/inputs/EnumerationToggleButtonbarComponent.d.ts +23 -0
  54. package/dist/inputs/EnumerationToggleButtonbarComponent.d.ts.map +1 -0
  55. package/dist/inputs/InputRenderer.d.ts +11 -0
  56. package/dist/inputs/InputRenderer.d.ts.map +1 -0
  57. package/dist/inputs/NumericInputComponent.d.ts +14 -0
  58. package/dist/inputs/NumericInputComponent.d.ts.map +1 -0
  59. package/dist/inputs/PasswordInputComponent.d.ts +14 -0
  60. package/dist/inputs/PasswordInputComponent.d.ts.map +1 -0
  61. package/dist/inputs/SwitchComponent.d.ts +14 -0
  62. package/dist/inputs/SwitchComponent.d.ts.map +1 -0
  63. package/dist/inputs/TextAreaComponent.d.ts +14 -0
  64. package/dist/inputs/TextAreaComponent.d.ts.map +1 -0
  65. package/dist/inputs/TextInputComponent.d.ts +19 -0
  66. package/dist/inputs/TextInputComponent.d.ts.map +1 -0
  67. package/dist/inputs/TimeInputComponent.d.ts +14 -0
  68. package/dist/inputs/TimeInputComponent.d.ts.map +1 -0
  69. package/dist/renderers/ButtonGroupRenderer.d.ts +10 -0
  70. package/dist/renderers/ButtonGroupRenderer.d.ts.map +1 -0
  71. package/dist/renderers/FlexRenderer.d.ts +13 -0
  72. package/dist/renderers/FlexRenderer.d.ts.map +1 -0
  73. package/dist/renderers/FormattedRenderer.d.ts +12 -0
  74. package/dist/renderers/FormattedRenderer.d.ts.map +1 -0
  75. package/dist/renderers/FrameRenderer.d.ts +17 -0
  76. package/dist/renderers/FrameRenderer.d.ts.map +1 -0
  77. package/dist/renderers/IconRenderer.d.ts +41 -0
  78. package/dist/renderers/IconRenderer.d.ts.map +1 -0
  79. package/dist/renderers/InlineButtonGroupRenderer.d.ts +22 -0
  80. package/dist/renderers/InlineButtonGroupRenderer.d.ts.map +1 -0
  81. package/dist/renderers/LinkRenderer.d.ts +17 -0
  82. package/dist/renderers/LinkRenderer.d.ts.map +1 -0
  83. package/dist/renderers/PageHeader.d.ts +13 -0
  84. package/dist/renderers/PageHeader.d.ts.map +1 -0
  85. package/dist/renderers/RowActionCell.d.ts +28 -0
  86. package/dist/renderers/RowActionCell.d.ts.map +1 -0
  87. package/dist/renderers/StandaloneButtonRenderer.d.ts +16 -0
  88. package/dist/renderers/StandaloneButtonRenderer.d.ts.map +1 -0
  89. package/dist/renderers/SubThemeWrapper.d.ts +22 -0
  90. package/dist/renderers/SubThemeWrapper.d.ts.map +1 -0
  91. package/dist/renderers/TabControllerRenderer.d.ts +10 -0
  92. package/dist/renderers/TabControllerRenderer.d.ts.map +1 -0
  93. package/dist/renderers/TableRenderer.d.ts +10 -0
  94. package/dist/renderers/TableRenderer.d.ts.map +1 -0
  95. package/dist/renderers/TableToolbar.d.ts +47 -0
  96. package/dist/renderers/TableToolbar.d.ts.map +1 -0
  97. package/dist/renderers/VisualElementRenderer.d.ts +17 -0
  98. package/dist/renderers/VisualElementRenderer.d.ts.map +1 -0
  99. package/dist/utils/alignment-mappers.d.ts +17 -0
  100. package/dist/utils/alignment-mappers.d.ts.map +1 -0
  101. package/dist/utils/build-mask-string.d.ts +31 -0
  102. package/dist/utils/build-mask-string.d.ts.map +1 -0
  103. package/dist/utils/build-query-customizer.d.ts +35 -0
  104. package/dist/utils/build-query-customizer.d.ts.map +1 -0
  105. package/dist/utils/destructive-action-utils.d.ts +17 -0
  106. package/dist/utils/destructive-action-utils.d.ts.map +1 -0
  107. package/dist/utils/find-action-by-definition.d.ts +26 -0
  108. package/dist/utils/find-action-by-definition.d.ts.map +1 -0
  109. package/dist/utils/find-on-init-action.d.ts +12 -0
  110. package/dist/utils/find-on-init-action.d.ts.map +1 -0
  111. package/dist/utils/find-visual-element.d.ts +18 -0
  112. package/dist/utils/find-visual-element.d.ts.map +1 -0
  113. package/dist/utils/flex-layout.d.ts +104 -0
  114. package/dist/utils/flex-layout.d.ts.map +1 -0
  115. package/dist/utils/get-visible-buttons.d.ts +33 -0
  116. package/dist/utils/get-visible-buttons.d.ts.map +1 -0
  117. package/dist/utils/icon-adornment.d.ts +13 -0
  118. package/dist/utils/icon-adornment.d.ts.map +1 -0
  119. package/dist/utils/mdi-alias-map.d.ts +44 -0
  120. package/dist/utils/mdi-alias-map.d.ts.map +1 -0
  121. package/dist/utils/mdi-alias-map.generated.d.ts +10 -0
  122. package/dist/utils/mdi-alias-map.generated.d.ts.map +1 -0
  123. package/dist/utils/resolve-container-type.d.ts +11 -0
  124. package/dist/utils/resolve-container-type.d.ts.map +1 -0
  125. package/dist/utils/singleton-access.d.ts +25 -0
  126. package/dist/utils/singleton-access.d.ts.map +1 -0
  127. package/dist/utils/table-column-utils.d.ts +75 -0
  128. package/dist/utils/table-column-utils.d.ts.map +1 -0
  129. package/dist/utils/table-filter-utils.d.ts +14 -0
  130. package/dist/utils/table-filter-utils.d.ts.map +1 -0
  131. package/dist/utils/table-sort-utils.d.ts +24 -0
  132. package/dist/utils/table-sort-utils.d.ts.map +1 -0
  133. package/package.json +84 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlexRenderer-0KCxU9QU.js","names":["min: string | undefined","max: string | undefined","min: string | undefined","max: string | undefined","columns: GridColDef[]","queryCustomizer: Record<string, unknown>","parts: string[]","queryCustomizer: Record<string, unknown>","result: Record<string, (typeof visibleButtons)[number]>","result: typeof visibleButtons"],"sources":["../src/utils/alignment-mappers.ts","../src/utils/flex-layout.ts","../src/renderers/FrameRenderer.tsx","../src/inputs/BinaryInputComponent.tsx","../src/inputs/CheckboxComponent.tsx","../src/utils/icon-adornment.tsx","../src/inputs/DateInputComponent.tsx","../src/inputs/DateTimeInputComponent.tsx","../src/inputs/EnumerationComboComponent.tsx","../src/inputs/EnumerationRadioComponent.tsx","../src/inputs/EnumerationToggleButtonbarComponent.tsx","../src/inputs/NumericInputComponent.tsx","../src/inputs/PasswordInputComponent.tsx","../src/inputs/SwitchComponent.tsx","../src/inputs/TextAreaComponent.tsx","../src/inputs/TextInputComponent.tsx","../src/inputs/TimeInputComponent.tsx","../src/inputs/InputRenderer.tsx","../src/renderers/FormattedRenderer.tsx","../src/renderers/InlineButtonGroupRenderer.tsx","../src/dialogs/LinkSelectorDialog.tsx","../src/utils/build-mask-string.ts","../src/renderers/LinkRenderer.tsx","../src/renderers/StandaloneButtonRenderer.tsx","../src/renderers/SubThemeWrapper.tsx","../src/renderers/TabControllerRenderer.tsx","../src/renderers/VisualElementRenderer.tsx","../src/renderers/FlexRenderer.tsx"],"sourcesContent":["import { Alignment, CrossAxisAlignment, MainAxisAlignment } from \"@judo/model-api\";\n\n/**\n * Map MainAxisAlignment enum to CSS justify-content value.\n */\nexport function mapMainAxisAlignment(alignment: MainAxisAlignment | undefined): string {\n\tswitch (alignment) {\n\t\tcase MainAxisAlignment.START:\n\t\t\treturn \"flex-start\";\n\t\tcase MainAxisAlignment.END:\n\t\t\treturn \"flex-end\";\n\t\tcase MainAxisAlignment.CENTER:\n\t\t\treturn \"center\";\n\t\tcase MainAxisAlignment.SPACEBETWEEN:\n\t\t\treturn \"space-between\";\n\t\tcase MainAxisAlignment.SPACEAROUND:\n\t\t\treturn \"space-around\";\n\t\tcase MainAxisAlignment.SPACEEVENLY:\n\t\t\treturn \"space-evenly\";\n\t\tdefault:\n\t\t\treturn \"flex-start\";\n\t}\n}\n\n/**\n * Map CrossAxisAlignment enum to CSS align-items value.\n */\nexport function mapCrossAxisAlignment(alignment: CrossAxisAlignment | undefined): string {\n\tswitch (alignment) {\n\t\tcase CrossAxisAlignment.START:\n\t\t\treturn \"flex-start\";\n\t\tcase CrossAxisAlignment.END:\n\t\t\treturn \"flex-end\";\n\t\tcase CrossAxisAlignment.CENTER:\n\t\t\treturn \"center\";\n\t\tcase CrossAxisAlignment.STRETCH:\n\t\t\treturn \"stretch\";\n\t\tcase CrossAxisAlignment.BASELINE:\n\t\t\treturn \"baseline\";\n\t\tdefault:\n\t\t\treturn \"stretch\";\n\t}\n}\n\n/**\n * Map Alignment enum to CSS position properties.\n */\nexport function mapAlignment(alignment: Alignment | undefined): {\n\tjustifyContent: string;\n\talignItems: string;\n} {\n\tswitch (alignment) {\n\t\tcase Alignment.TOP_LEFT:\n\t\t\treturn { justifyContent: \"flex-start\", alignItems: \"flex-start\" };\n\t\tcase Alignment.TOP_CENTER:\n\t\t\treturn { justifyContent: \"center\", alignItems: \"flex-start\" };\n\t\tcase Alignment.TOP_RIGHT:\n\t\t\treturn { justifyContent: \"flex-end\", alignItems: \"flex-start\" };\n\t\tcase Alignment.CENTER_LEFT:\n\t\t\treturn { justifyContent: \"flex-start\", alignItems: \"center\" };\n\t\tcase Alignment.CENTER:\n\t\t\treturn { justifyContent: \"center\", alignItems: \"center\" };\n\t\tcase Alignment.CENTER_RIGHT:\n\t\t\treturn { justifyContent: \"flex-end\", alignItems: \"center\" };\n\t\tcase Alignment.BOTTOM_LEFT:\n\t\t\treturn { justifyContent: \"flex-start\", alignItems: \"flex-end\" };\n\t\tcase Alignment.BOTTOM_CENTER:\n\t\t\treturn { justifyContent: \"center\", alignItems: \"flex-end\" };\n\t\tcase Alignment.BOTTOM_RIGHT:\n\t\t\treturn { justifyContent: \"flex-end\", alignItems: \"flex-end\" };\n\t\tdefault:\n\t\t\treturn { justifyContent: \"flex-start\", alignItems: \"flex-start\" };\n\t}\n}\n","/**\n * Pure utility functions for flex layout calculations.\n * These functions implement the legacy code generator's calculateSize logic\n * and determine responsive grid sizing for MUI Grid2 components.\n */\n\nimport { Axis } from \"@judo/model-api\";\n\n/** Default column span for visual elements (from EMF meta-model) */\nexport const DEFAULT_COL = 4;\n\n/** Full grid width (12-column system) */\nexport const FULL_GRID_WIDTH = 12;\n\n/**\n * Grid size configuration for responsive breakpoints.\n * - xs: extra small screens (mobile)\n * - sm: small screens (tablets)\n * - md: medium screens and above (desktop)\n */\nexport interface GridSize {\n\txs: number;\n\tsm: number;\n\tmd?: number;\n}\n\n/**\n * Calculate the scaled size for a child element based on parent's column span.\n *\n * **Legacy calculateSize logic:**\n * - If parent spans full 12 columns: use child's col value as-is\n * - If parent spans less than 12: scale proportionally (12 / parentCol) × childCol\n *\n * @param parentCol - Parent Flex container's column span (1-12)\n * @param childCol - Child element's column span (1-12)\n * @returns Calculated size (may exceed 12 if child is larger than parent)\n *\n * @example\n * ```ts\n * calculateScaledSize(12, 6); // 6 - parent full width, child uses col as-is\n * calculateScaledSize(6, 3); // 6 - (12/6) × 3 = 6\n * calculateScaledSize(6, 6); // 12 - (12/6) × 6 = 12 (full width)\n * calculateScaledSize(4, 2); // 6 - (12/4) × 2 = 6\n * ```\n */\nexport function calculateScaledSize(parentCol: number, childCol: number): number {\n\tif (parentCol === FULL_GRID_WIDTH) {\n\t\treturn childCol;\n\t}\n\treturn (FULL_GRID_WIDTH / parentCol) * childCol;\n}\n\n/**\n * Calculate responsive grid size for horizontal flex layouts.\n *\n * **Responsive behavior:**\n * - xs/sm breakpoints: always full width (12 columns) for mobile/tablet\n * - md breakpoint: use calculated size for desktop\n * - Optimization: omit md property if calculated size equals 12\n *\n * @param parentCol - Parent Flex container's column span\n * @param childCol - Child element's column span\n * @returns GridSize object with responsive breakpoint configuration\n *\n * @example\n * ```ts\n * calculateHorizontalGridSize(12, 6); // { xs: 12, sm: 12, md: 6 }\n * calculateHorizontalGridSize(6, 6); // { xs: 12, sm: 12 } - omits md:12\n * calculateHorizontalGridSize(8, 4); // { xs: 12, sm: 12, md: 6 }\n * ```\n */\nexport function calculateHorizontalGridSize(parentCol: number, childCol: number): GridSize {\n\tconst calculatedSize = calculateScaledSize(parentCol, childCol);\n\n\t// Optimization: if calculated size is full width, omit md breakpoint\n\tif (calculatedSize === FULL_GRID_WIDTH) {\n\t\treturn { xs: FULL_GRID_WIDTH, sm: FULL_GRID_WIDTH };\n\t}\n\n\treturn {\n\t\txs: FULL_GRID_WIDTH,\n\t\tsm: FULL_GRID_WIDTH,\n\t\tmd: calculatedSize,\n\t};\n}\n\n/**\n * Calculate grid size for vertical flex layouts (Stack-based).\n *\n * **Vertical layout behavior:**\n * - Always returns full width (12 columns) for all breakpoints\n * - The `force-full-width` CSS class enforces 100% width on Stack children\n * - No md breakpoint needed since width is always 100%\n *\n * @returns GridSize object with full width at all breakpoints\n *\n * @example\n * ```ts\n * calculateVerticalGridSize(); // { xs: 12, sm: 12 }\n * ```\n */\nexport function calculateVerticalGridSize(): GridSize {\n\treturn { xs: FULL_GRID_WIDTH, sm: FULL_GRID_WIDTH };\n}\n\n/**\n * Determine if a Flex container uses vertical layout direction.\n *\n * @param direction - Axis enum value from Flex element\n * @returns true if vertical, false if horizontal\n */\nexport function isVerticalLayout(direction?: Axis): boolean {\n\treturn direction === Axis.VERTICAL;\n}\n\n/**\n * Calculate grid size for a child element based on parent's layout direction.\n *\n * **Decision logic:**\n * - Vertical layouts: always full width (Stack + force-full-width CSS)\n * - Horizontal layouts: responsive sizing with calculated md breakpoint\n *\n * @param direction - Parent Flex container's direction\n * @param parentCol - Parent Flex container's column span\n * @param childCol - Child element's column span\n * @returns GridSize object with appropriate responsive configuration\n *\n * @example\n * ```ts\n * // Vertical layout - always full width\n * calculateChildGridSize('VERTICAL', 12, 6); // { xs: 12, sm: 12 }\n * calculateChildGridSize('VERTICAL', 6, 3); // { xs: 12, sm: 12 }\n *\n * // Horizontal layout - responsive sizing\n * calculateChildGridSize('HORIZONTAL', 12, 6); // { xs: 12, sm: 12, md: 6 }\n * calculateChildGridSize('HORIZONTAL', 6, 3); // { xs: 12, sm: 12, md: 6 }\n * ```\n */\nexport function calculateChildGridSize(direction: Axis | undefined, parentCol: number, childCol: number): GridSize {\n\tif (isVerticalLayout(direction)) {\n\t\treturn calculateVerticalGridSize();\n\t}\n\treturn calculateHorizontalGridSize(parentCol, childCol);\n}\n","import type { Frame, Icon } from \"@judo/model-api\";\nimport { Box, Paper, Typography } from \"@mui/material\";\nimport type { ReactNode } from \"react\";\nimport { IconRenderer } from \"./IconRenderer\";\n\nexport interface FrameRendererProps {\n\tframe: Frame;\n\tchildren: ReactNode;\n\t/** Optional label for the card header */\n\tlabel?: string;\n\t/** Optional icon for the card header */\n\ticon?: Icon;\n}\n\n/**\n * Renderer for Frame (card/panel) styling.\n * Renders a Paper with optional header containing icon and label.\n * Includes subtle hover lift effect and fade-in entrance animation.\n */\nexport function FrameRenderer({ frame, children, label, icon }: FrameRendererProps) {\n\tconst hasHeader = label || icon;\n\n\treturn (\n\t\t<Paper\n\t\t\tsx={{\n\t\t\t\tp: 2,\n\t\t\t\tanimation: \"judoFadeInUp 0.35s cubic-bezier(0.4,0,0.2,1) both\",\n\t\t\t\t\"&:hover\": {\n\t\t\t\t\tborderColor: \"rgba(0, 0, 0, 0.15)\",\n\t\t\t\t\tboxShadow: (theme) =>\n\t\t\t\t\t\ttheme.palette.mode === \"light\" ? \"0 4px 20px rgba(0,0,0,0.06)\" : \"0 4px 20px rgba(0,0,0,0.3)\",\n\t\t\t\t\ttransform: \"translateY(-1px)\",\n\t\t\t\t},\n\t\t\t}}\n\t\t\tdata-testid={`frame::${frame[\"xmi:id\"]}`}\n\t\t>\n\t\t\t{hasHeader && (\n\t\t\t\t<Box\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\tgap: 1,\n\t\t\t\t\t\tmb: 2,\n\t\t\t\t\t\tpl: 1.5,\n\t\t\t\t\t\tborderLeft: 3,\n\t\t\t\t\t\tborderColor: \"primary.main\",\n\t\t\t\t\t}}\n\t\t\t\t\tdata-testid={`frame::${frame[\"xmi:id\"]}::header`}\n\t\t\t\t>\n\t\t\t\t\t{icon && <IconRenderer icon={icon} />}\n\t\t\t\t\t{label && (\n\t\t\t\t\t\t<Typography variant=\"h6\" component=\"h3\">\n\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t)}\n\t\t\t\t</Box>\n\t\t\t)}\n\t\t\t{children}\n\t\t</Paper>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { BinaryTypeInput, Input } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport DeleteIcon from \"@mui/icons-material/Delete\";\nimport UploadIcon from \"@mui/icons-material/Upload\";\nimport { Box, Button, IconButton, Typography } from \"@mui/material\";\nimport { useState } from \"react\";\n\nexport interface BinaryInputComponentProps {\n\telement: BinaryTypeInput | Input;\n\treadOnly?: boolean;\n\tvalue?: string | null; // Base64 encoded or URL\n\tonChange?: (value: string | null) => void;\n\terror?: string;\n\tdisabled?: boolean;\n\tfileName?: string;\n}\n\n/**\n * Binary/file input component.\n */\nexport function BinaryInputComponent({\n\telement,\n\treadOnly,\n\tvalue: _value,\n\tonChange,\n\terror,\n\tdisabled,\n\tfileName,\n}: BinaryInputComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst [currentFileName, setCurrentFileName] = useState(fileName ?? \"\");\n\n\tconst handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst file = e.target.files?.[0];\n\t\tif (file) {\n\t\t\tsetCurrentFileName(file.name);\n\t\t\tconst reader = new FileReader();\n\t\t\treader.addEventListener(\"load\", () => {\n\t\t\t\tconst base64 = (reader.result as string).split(\",\")[1];\n\t\t\t\tonChange?.(base64);\n\t\t\t});\n\t\t\treader.readAsDataURL(file);\n\t\t}\n\t};\n\n\tconst handleClear = () => {\n\t\tsetCurrentFileName(\"\");\n\t\tonChange?.(null);\n\t};\n\n\tconst isDisabled = disabled ?? element.disabled;\n\tconst isReadOnly = readOnly ?? element.isReadOnly;\n\n\treturn (\n\t\t<Box data-testid={testId}>\n\t\t\t<Typography variant=\"body2\" gutterBottom>\n\t\t\t\t{label}\n\t\t\t\t{element.required && \" *\"}\n\t\t\t</Typography>\n\t\t\t<Box display=\"flex\" alignItems=\"center\" gap={1}>\n\t\t\t\t<Button component=\"label\" variant=\"outlined\" startIcon={<UploadIcon />} disabled={isDisabled || isReadOnly}>\n\t\t\t\t\tUpload\n\t\t\t\t\t<input type=\"file\" hidden onChange={handleFileSelect} data-testid={`${testId}::file-input`} />\n\t\t\t\t</Button>\n\t\t\t\t{currentFileName && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<Typography variant=\"body2\" sx={{ flexGrow: 1 }}>\n\t\t\t\t\t\t\t{currentFileName}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t{!isReadOnly && (\n\t\t\t\t\t\t\t<IconButton onClick={handleClear} disabled={isDisabled} size=\"small\" data-testid={`${testId}::clear`}>\n\t\t\t\t\t\t\t\t<DeleteIcon />\n\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</Box>\n\t\t\t{error && (\n\t\t\t\t<Typography variant=\"caption\" color=\"error\">\n\t\t\t\t\t{error}\n\t\t\t\t</Typography>\n\t\t\t)}\n\t\t</Box>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { Checkbox as CheckboxElement, Input } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { Checkbox, FormControl, FormControlLabel, FormHelperText } from \"@mui/material\";\n\nexport interface CheckboxComponentProps {\n\telement: CheckboxElement | Input;\n\treadOnly?: boolean;\n\tvalue?: boolean;\n\tonChange?: (value: boolean) => void;\n\terror?: string;\n\tdisabled?: boolean;\n}\n\n/**\n * Checkbox input component.\n */\nexport function CheckboxComponent({\n\telement,\n\treadOnly,\n\tvalue = false,\n\tonChange,\n\terror,\n\tdisabled,\n}: CheckboxComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label: modelLabel } = useModelLabel(element);\n\n\tconst label = `${modelLabel}${element.required ? \" *\" : \"\"}`;\n\n\treturn (\n\t\t<FormControl error={!!error} disabled={disabled ?? element.disabled} required={element.required}>\n\t\t\t<FormControlLabel\n\t\t\t\tcontrol={\n\t\t\t\t\t<Checkbox\n\t\t\t\t\t\tchecked={value}\n\t\t\t\t\t\tonChange={(e) => onChange?.(e.target.checked)}\n\t\t\t\t\t\tdisabled={readOnly ?? element.isReadOnly}\n\t\t\t\t\t\tdata-testid={testId}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\tlabel={label}\n\t\t\t/>\n\t\t\t{error && <FormHelperText>{error}</FormHelperText>}\n\t\t</FormControl>\n\t);\n}\n","import type { Icon } from \"@judo/model-api\";\nimport InputAdornment from \"@mui/material/InputAdornment\";\nimport { IconRenderer } from \"../renderers/IconRenderer\";\n\n/**\n * Build a MUI `startAdornment` for a TextField-based input if the model element\n * has an icon defined. Returns `undefined` when no icon is present so that callers\n * can spread the result into slotProps without conditional logic.\n *\n * @example\n * ```tsx\n * <TextField slotProps={{ input: { startAdornment: buildIconAdornment(element.icon) } }} />\n * ```\n */\nexport function buildIconAdornment(icon: Icon | undefined): React.ReactNode | undefined {\n\tif (!icon?.iconName) return undefined;\n\n\treturn (\n\t\t<InputAdornment position=\"start\">\n\t\t\t<IconRenderer icon={icon} size=\"small\" color=\"action\" />\n\t\t</InputAdornment>\n\t);\n}\n","import { useDateValidationProps } from \"@judo/core\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { DateInput, Input } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { TextField } from \"@mui/material\";\nimport { buildIconAdornment } from \"../utils/icon-adornment\";\n\n/**\n * Format a Date to YYYY-MM-DD string for native date input min/max attributes.\n */\nfunction formatDateForInput(date: Date): string {\n\tconst y = date.getFullYear();\n\tconst m = String(date.getMonth() + 1).padStart(2, \"0\");\n\tconst d = String(date.getDate()).padStart(2, \"0\");\n\treturn `${y}-${m}-${d}`;\n}\n\nexport interface DateInputComponentProps {\n\telement: DateInput | Input;\n\treadOnly?: boolean;\n\tvalue?: Date | string | null;\n\tonChange?: (value: Date | null) => void;\n\terror?: string;\n\tdisabled?: boolean;\n}\n\n/**\n * Parse a date input string (YYYY-MM-DD) to a local-timezone Date.\n * Uses local date components to avoid timezone shift issues.\n */\nfunction parseDateInputValue(value: string): Date {\n\tconst [y, m, d] = value.split(\"-\").map(Number);\n\treturn new Date(y, m - 1, d);\n}\n\n/**\n * Format a Date or string value for the native date input element.\n * Handles Date objects (local date extraction) and string pass-through.\n */\nfunction toInputValue(value: Date | string | null | undefined): string {\n\tif (value == null) return \"\";\n\tif (value instanceof Date) return formatDateForInput(value);\n\treturn value;\n}\n\n/**\n * Date input component.\n */\nexport function DateInputComponent({ element, readOnly, value, onChange, error, disabled }: DateInputComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst dateValidation = useDateValidationProps(element[\"xmi:id\"]);\n\tconst startAdornment = buildIconAdornment(element.icon);\n\n\t// Resolve min/max from DateValidationProps\n\tlet min: string | undefined;\n\tlet max: string | undefined;\n\tif (dateValidation) {\n\t\tconst today = new Date();\n\t\tif (dateValidation.disablePast) min = formatDateForInput(today);\n\t\tif (dateValidation.minDate) min = formatDateForInput(dateValidation.minDate);\n\t\tif (dateValidation.disableFuture) max = formatDateForInput(today);\n\t\tif (dateValidation.maxDate) max = formatDateForInput(dateValidation.maxDate);\n\t}\n\n\treturn (\n\t\t<TextField\n\t\t\ttype=\"date\"\n\t\t\tlabel={label}\n\t\t\tvalue={toInputValue(value)}\n\t\t\tonChange={(e) => {\n\t\t\t\tconst str = e.target.value;\n\t\t\t\tonChange?.(str ? parseDateInputValue(str) : null);\n\t\t\t}}\n\t\t\terror={!!error}\n\t\t\thelperText={error}\n\t\t\tdisabled={disabled ?? element.disabled}\n\t\t\trequired={element.required}\n\t\t\tfullWidth\n\t\t\tdata-testid={testId}\n\t\t\tslotProps={{\n\t\t\t\tinput: {\n\t\t\t\t\treadOnly: readOnly ?? element.isReadOnly,\n\t\t\t\t\tstartAdornment,\n\t\t\t\t\t...(min !== undefined || max !== undefined\n\t\t\t\t\t\t? { inputProps: { ...(min !== undefined && { min }), ...(max !== undefined && { max }) } }\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t\tinputLabel: {\n\t\t\t\t\tshrink: true,\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import { useDateValidationProps } from \"@judo/core\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { DateTimeInput, Input } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { TextField } from \"@mui/material\";\nimport { format, parseISO } from \"date-fns\";\nimport { buildIconAdornment } from \"../utils/icon-adornment\";\n\nexport interface DateTimeInputComponentProps {\n\telement: DateTimeInput | Input;\n\treadOnly?: boolean;\n\tvalue?: Date | string | null;\n\tonChange?: (value: Date | null) => void;\n\terror?: string;\n\tdisabled?: boolean;\n}\n\n/**\n * Convert ISO datetime string to datetime-local format using date-fns.\n * Input: \"2026-02-03T03:33:31.89319Z\" (ISO 8601 with timezone)\n * Output: \"2026-02-03T03:33\" (datetime-local format for HTML input)\n */\nfunction toDateTimeLocalFormat(isoString: string | null | undefined): string {\n\tif (!isoString) return \"\";\n\n\ttry {\n\t\tconst date = parseISO(isoString);\n\t\tif (Number.isNaN(date.getTime())) return \"\";\n\n\t\t// Format as YYYY-MM-DDTHH:mm (datetime-local format)\n\t\treturn format(date, \"yyyy-MM-dd'T'HH:mm\");\n\t} catch {\n\t\treturn \"\";\n\t}\n}\n\n/**\n * Format a Date to datetime-local string for native input min/max attributes.\n */\nfunction formatDateTimeForInput(date: Date): string {\n\tconst y = date.getFullYear();\n\tconst mo = String(date.getMonth() + 1).padStart(2, \"0\");\n\tconst d = String(date.getDate()).padStart(2, \"0\");\n\tconst h = String(date.getHours()).padStart(2, \"0\");\n\tconst mi = String(date.getMinutes()).padStart(2, \"0\");\n\treturn `${y}-${mo}-${d}T${h}:${mi}`;\n}\n\n/**\n * DateTime input component.\n */\nexport function DateTimeInputComponent({\n\telement,\n\treadOnly,\n\tvalue,\n\tonChange,\n\terror,\n\tdisabled,\n}: DateTimeInputComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst dateValidation = useDateValidationProps(element[\"xmi:id\"]);\n\tconst startAdornment = buildIconAdornment(element.icon);\n\n\t// Convert value to datetime-local format for display\n\tconst displayValue = value instanceof Date ? formatDateTimeForInput(value) : toDateTimeLocalFormat(value);\n\n\t// Resolve min/max from DateValidationProps\n\tlet min: string | undefined;\n\tlet max: string | undefined;\n\tif (dateValidation) {\n\t\tconst today = new Date();\n\t\tif (dateValidation.disablePast) min = formatDateTimeForInput(today);\n\t\tif (dateValidation.minDate) min = formatDateTimeForInput(dateValidation.minDate);\n\t\tif (dateValidation.disableFuture) max = formatDateTimeForInput(today);\n\t\tif (dateValidation.maxDate) max = formatDateTimeForInput(dateValidation.maxDate);\n\t}\n\n\treturn (\n\t\t<TextField\n\t\t\ttype=\"datetime-local\"\n\t\t\tlabel={label}\n\t\t\tvalue={displayValue}\n\t\t\tonChange={(e) => {\n\t\t\t\tconst str = e.target.value;\n\t\t\t\tif (!str) {\n\t\t\t\t\tonChange?.(null);\n\t\t\t\t} else {\n\t\t\t\t\t// datetime-local string (\"YYYY-MM-DDTHH:mm\") → local Date\n\t\t\t\t\tconst parsed = parseISO(str);\n\t\t\t\t\tonChange?.(Number.isNaN(parsed.getTime()) ? null : parsed);\n\t\t\t\t}\n\t\t\t}}\n\t\t\terror={!!error}\n\t\t\thelperText={error}\n\t\t\tdisabled={disabled ?? element.disabled}\n\t\t\trequired={element.required}\n\t\t\tfullWidth\n\t\t\tdata-testid={testId}\n\t\t\tslotProps={{\n\t\t\t\tinput: {\n\t\t\t\t\treadOnly: readOnly ?? element.isReadOnly,\n\t\t\t\t\tstartAdornment,\n\t\t\t\t\t...(min !== undefined || max !== undefined\n\t\t\t\t\t\t? { inputProps: { ...(min !== undefined && { min }), ...(max !== undefined && { max }) } }\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t\tinputLabel: {\n\t\t\t\t\tshrink: true,\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { EnumerationCombo, Input } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { FormControl, FormHelperText, InputLabel, MenuItem, Select } from \"@mui/material\";\n\nexport interface EnumerationComboComponentProps {\n\telement: EnumerationCombo | Input;\n\treadOnly?: boolean;\n\tvalue?: string;\n\tonChange?: (value: string) => void;\n\terror?: string;\n\tdisabled?: boolean;\n\toptions?: Array<{ value: string; label: string }>;\n\t/** When true, allows empty selection and shows a clear option. @default false */\n\tnullable?: boolean;\n}\n\n/**\n * Enumeration combo (select) component.\n */\nexport function EnumerationComboComponent({\n\telement,\n\treadOnly,\n\tvalue = \"\",\n\tonChange,\n\terror,\n\tdisabled,\n\toptions = [],\n\tnullable = false,\n}: EnumerationComboComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst labelId = `${testId}-label`;\n\n\treturn (\n\t\t<FormControl fullWidth error={!!error} disabled={disabled ?? element.disabled} required={element.required}>\n\t\t\t<InputLabel id={labelId} shrink>\n\t\t\t\t{label}\n\t\t\t</InputLabel>\n\t\t\t<Select\n\t\t\t\tlabelId={labelId}\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => onChange?.(e.target.value)}\n\t\t\t\tlabel={label}\n\t\t\t\treadOnly={readOnly ?? element.isReadOnly}\n\t\t\t\tdata-testid={testId}\n\t\t\t\tdisplayEmpty={nullable}\n\t\t\t>\n\t\t\t\t{nullable && (\n\t\t\t\t\t<MenuItem value=\"\">\n\t\t\t\t\t\t<em>—</em>\n\t\t\t\t\t</MenuItem>\n\t\t\t\t)}\n\t\t\t\t{options.map((option) => (\n\t\t\t\t\t<MenuItem key={option.value} value={option.value}>\n\t\t\t\t\t\t{option.label}\n\t\t\t\t\t</MenuItem>\n\t\t\t\t))}\n\t\t\t</Select>\n\t\t\t{error && <FormHelperText>{error}</FormHelperText>}\n\t\t</FormControl>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { EnumerationRadio, Input } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { FormControl, FormControlLabel, FormHelperText, FormLabel, Radio, RadioGroup } from \"@mui/material\";\n\nexport interface EnumerationRadioComponentProps {\n\telement: EnumerationRadio | Input;\n\treadOnly?: boolean;\n\tvalue?: string;\n\tonChange?: (value: string) => void;\n\terror?: string;\n\tdisabled?: boolean;\n\toptions?: Array<{ value: string; label: string }>;\n\t/** Layout orientation of radio buttons. @default \"vertical\" */\n\torientation?: \"horizontal\" | \"vertical\";\n\t/** When true, allows de-selection by clicking a selected radio. @default false */\n\tnullable?: boolean;\n}\n\n/**\n * Enumeration radio group component.\n */\nexport function EnumerationRadioComponent({\n\telement,\n\treadOnly,\n\tvalue = \"\",\n\tonChange,\n\terror,\n\tdisabled,\n\toptions = [],\n\torientation = \"vertical\",\n\tnullable = false,\n}: EnumerationRadioComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\n\tconst handleRadioClick = (optionValue: string) => {\n\t\t// If nullable and clicking the already-selected option, deselect it\n\t\tif (nullable && value === optionValue) {\n\t\t\tonChange?.(\"\");\n\t\t} else {\n\t\t\tonChange?.(optionValue);\n\t\t}\n\t};\n\n\treturn (\n\t\t<FormControl error={!!error} disabled={disabled ?? element.disabled} required={element.required}>\n\t\t\t<FormLabel>{label}</FormLabel>\n\t\t\t<RadioGroup value={value} row={orientation === \"horizontal\"} data-testid={testId}>\n\t\t\t\t{options.map((option) => (\n\t\t\t\t\t<FormControlLabel\n\t\t\t\t\t\tkey={option.value}\n\t\t\t\t\t\tvalue={option.value}\n\t\t\t\t\t\tcontrol={<Radio disabled={readOnly ?? element.isReadOnly} onClick={() => handleRadioClick(option.value)} />}\n\t\t\t\t\t\tlabel={option.label}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</RadioGroup>\n\t\t\t{error && <FormHelperText>{error}</FormHelperText>}\n\t\t</FormControl>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { EnumerationToggleButtonbar, Input } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { FormControl, FormHelperText, InputLabel, ToggleButton, ToggleButtonGroup } from \"@mui/material\";\n\nexport interface EnumerationToggleButtonbarComponentProps {\n\telement: EnumerationToggleButtonbar | Input;\n\treadOnly?: boolean;\n\tvalue?: string;\n\tonChange?: (value: string) => void;\n\terror?: string;\n\tdisabled?: boolean;\n\toptions?: Array<{ value: string; label: string }>;\n\t/** Layout orientation of toggle buttons. @default \"horizontal\" */\n\torientation?: \"horizontal\" | \"vertical\";\n\t/** When true, allows de-selection by clicking a selected toggle. @default false */\n\tnullable?: boolean;\n}\n\n/**\n * Enumeration toggle button bar component.\n * Renders a MUI ToggleButtonGroup with exclusive selection.\n */\nexport function EnumerationToggleButtonbarComponent({\n\telement,\n\treadOnly,\n\tvalue = \"\",\n\tonChange,\n\terror,\n\tdisabled,\n\toptions = [],\n\torientation = \"horizontal\",\n\tnullable = false,\n}: EnumerationToggleButtonbarComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst isDisabled = disabled ?? element.disabled;\n\tconst isReadOnly = readOnly ?? element.isReadOnly;\n\n\tconst handleChange = (_event: React.MouseEvent<HTMLElement>, newValue: string | null) => {\n\t\tif (isReadOnly) return;\n\t\tif (newValue === null) {\n\t\t\t// Deselection: only allow if nullable\n\t\t\tif (nullable) {\n\t\t\t\tonChange?.(\"\");\n\t\t\t}\n\t\t} else {\n\t\t\tonChange?.(newValue);\n\t\t}\n\t};\n\n\treturn (\n\t\t<FormControl error={!!error} disabled={isDisabled} required={element.required}>\n\t\t\t<InputLabel shrink>{label}</InputLabel>\n\t\t\t<ToggleButtonGroup\n\t\t\t\tvalue={value || null}\n\t\t\t\texclusive\n\t\t\t\tonChange={handleChange}\n\t\t\t\torientation={orientation}\n\t\t\t\tdata-testid={testId}\n\t\t\t\tdisabled={isDisabled || isReadOnly}\n\t\t\t\tsx={{ mt: 1.25 }}\n\t\t\t>\n\t\t\t\t{options.map((option) => (\n\t\t\t\t\t<ToggleButton key={option.value} value={option.value}>\n\t\t\t\t\t\t{option.label}\n\t\t\t\t\t</ToggleButton>\n\t\t\t\t))}\n\t\t\t</ToggleButtonGroup>\n\t\t\t{error && <FormHelperText>{error}</FormHelperText>}\n\t\t</FormControl>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { Input, NumericInput } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { TextField } from \"@mui/material\";\nimport { buildIconAdornment } from \"../utils/icon-adornment\";\n\nexport interface NumericInputComponentProps {\n\telement: NumericInput | Input;\n\treadOnly?: boolean;\n\tvalue?: number | null;\n\tonChange?: (value: number | null) => void;\n\terror?: string;\n\tdisabled?: boolean;\n}\n\n/**\n * Numeric input component.\n */\nexport function NumericInputComponent({\n\telement,\n\treadOnly,\n\tvalue,\n\tonChange,\n\terror,\n\tdisabled,\n}: NumericInputComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst numericElement = element as NumericInput;\n\tconst startAdornment = buildIconAdornment(element.icon);\n\n\tconst handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst val = e.target.value;\n\t\tif (val === \"\") {\n\t\t\tonChange?.(null);\n\t\t} else {\n\t\t\tconst num = Number.parseFloat(val);\n\t\t\tif (!Number.isNaN(num)) {\n\t\t\t\tonChange?.(num);\n\t\t\t}\n\t\t}\n\t};\n\n\treturn (\n\t\t<TextField\n\t\t\ttype=\"number\"\n\t\t\tlabel={label}\n\t\t\tvalue={value ?? \"\"}\n\t\t\tonChange={handleChange}\n\t\t\terror={!!error}\n\t\t\thelperText={error}\n\t\t\tdisabled={disabled ?? element.disabled}\n\t\t\trequired={element.required}\n\t\t\tfullWidth\n\t\t\tdata-testid={testId}\n\t\t\tslotProps={{\n\t\t\t\tinput: {\n\t\t\t\t\treadOnly: readOnly ?? element.isReadOnly,\n\t\t\t\t\tstartAdornment,\n\t\t\t\t},\n\t\t\t\thtmlInput: {\n\t\t\t\t\tstep: numericElement.scale ? 10 ** -numericElement.scale : undefined,\n\t\t\t\t},\n\t\t\t\tinputLabel: {\n\t\t\t\t\tshrink: true,\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { Input, PasswordInput } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport VisibilityIcon from \"@mui/icons-material/Visibility\";\nimport VisibilityOffIcon from \"@mui/icons-material/VisibilityOff\";\nimport { IconButton, InputAdornment, TextField } from \"@mui/material\";\nimport { useState } from \"react\";\nimport { buildIconAdornment } from \"../utils/icon-adornment\";\n\nexport interface PasswordInputComponentProps {\n\telement: PasswordInput | Input;\n\treadOnly?: boolean;\n\tvalue?: string;\n\tonChange?: (value: string) => void;\n\terror?: string;\n\tdisabled?: boolean;\n}\n\n/**\n * Password input component with visibility toggle.\n */\nexport function PasswordInputComponent({\n\telement,\n\treadOnly,\n\tvalue = \"\",\n\tonChange,\n\terror,\n\tdisabled,\n}: PasswordInputComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst [showPassword, setShowPassword] = useState(false);\n\tconst startAdornment = buildIconAdornment(element.icon);\n\n\treturn (\n\t\t<TextField\n\t\t\ttype={showPassword ? \"text\" : \"password\"}\n\t\t\tlabel={label}\n\t\t\tvalue={value}\n\t\t\tonChange={(e) => onChange?.(e.target.value)}\n\t\t\terror={!!error}\n\t\t\thelperText={error}\n\t\t\tdisabled={disabled ?? element.disabled}\n\t\t\trequired={element.required}\n\t\t\tfullWidth\n\t\t\tdata-testid={testId}\n\t\t\tslotProps={{\n\t\t\t\tinput: {\n\t\t\t\t\treadOnly: readOnly ?? element.isReadOnly,\n\t\t\t\t\tstartAdornment,\n\t\t\t\t\tendAdornment: (\n\t\t\t\t\t\t<InputAdornment position=\"end\">\n\t\t\t\t\t\t\t<IconButton\n\t\t\t\t\t\t\t\tonClick={() => setShowPassword(!showPassword)}\n\t\t\t\t\t\t\t\tedge=\"end\"\n\t\t\t\t\t\t\t\tdata-testid={`${testId}::toggle-visibility`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{showPassword ? <VisibilityOffIcon /> : <VisibilityIcon />}\n\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t</InputAdornment>\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\tinputLabel: {\n\t\t\t\t\tshrink: true,\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { Input, Switch as SwitchElement } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { FormControl, FormControlLabel, FormHelperText, Switch } from \"@mui/material\";\n\nexport interface SwitchComponentProps {\n\telement: SwitchElement | Input;\n\treadOnly?: boolean;\n\tvalue?: boolean;\n\tonChange?: (value: boolean) => void;\n\terror?: string;\n\tdisabled?: boolean;\n}\n\n/**\n * Switch input component.\n */\nexport function SwitchComponent({ element, readOnly, value = false, onChange, error, disabled }: SwitchComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label: modelLabel } = useModelLabel(element);\n\n\tconst label = `${modelLabel}${element.required ? \" *\" : \"\"}`;\n\n\treturn (\n\t\t<FormControl error={!!error} disabled={disabled ?? element.disabled} required={element.required}>\n\t\t\t<FormControlLabel\n\t\t\t\tcontrol={\n\t\t\t\t\t<Switch\n\t\t\t\t\t\tchecked={value}\n\t\t\t\t\t\tonChange={(e) => onChange?.(e.target.checked)}\n\t\t\t\t\t\tdisabled={readOnly ?? element.isReadOnly}\n\t\t\t\t\t\tdata-testid={testId}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\tlabel={label}\n\t\t\t/>\n\t\t\t{error && <FormHelperText>{error}</FormHelperText>}\n\t\t</FormControl>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { Input, TextArea } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { TextField } from \"@mui/material\";\nimport { buildIconAdornment } from \"../utils/icon-adornment\";\n\nexport interface TextAreaComponentProps {\n\telement: TextArea | Input;\n\treadOnly?: boolean;\n\tvalue?: string;\n\tonChange?: (value: string) => void;\n\terror?: string;\n\tdisabled?: boolean;\n}\n\n/**\n * TextArea component.\n */\nexport function TextAreaComponent({\n\telement,\n\treadOnly,\n\tvalue = \"\",\n\tonChange,\n\terror,\n\tdisabled,\n}: TextAreaComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst textAreaElement = element as TextArea;\n\tconst startAdornment = buildIconAdornment(element.icon);\n\n\treturn (\n\t\t<TextField\n\t\t\tmultiline\n\t\t\tminRows={textAreaElement.lines}\n\t\t\tmaxRows={20}\n\t\t\tlabel={label}\n\t\t\tvalue={value}\n\t\t\tonChange={(e) => onChange?.(e.target.value)}\n\t\t\terror={!!error}\n\t\t\thelperText={\n\t\t\t\terror ??\n\t\t\t\t(textAreaElement.countCharacters\n\t\t\t\t\t? `${value.length}${textAreaElement.maxLength ? `/${textAreaElement.maxLength}` : \"\"}`\n\t\t\t\t\t: undefined)\n\t\t\t}\n\t\t\tdisabled={disabled ?? element.disabled}\n\t\t\trequired={element.required}\n\t\t\tfullWidth\n\t\t\tdata-testid={testId}\n\t\t\tslotProps={{\n\t\t\t\tinput: {\n\t\t\t\t\treadOnly: readOnly ?? element.isReadOnly,\n\t\t\t\t\tstartAdornment,\n\t\t\t\t},\n\t\t\t\thtmlInput: {\n\t\t\t\t\tmaxLength: textAreaElement.maxLength,\n\t\t\t\t},\n\t\t\t\tinputLabel: {\n\t\t\t\t\tshrink: true,\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import { useDebouncedCallback, useTypeaheadProvider } from \"@judo/core\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { Input, TextInput } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { Autocomplete, CircularProgress, TextField } from \"@mui/material\";\nimport { useState } from \"react\";\nimport { buildIconAdornment } from \"../utils/icon-adornment\";\n\nexport interface TextInputComponentProps {\n\telement: TextInput | Input;\n\treadOnly?: boolean;\n\tvalue?: string;\n\tonChange?: (value: string) => void;\n\terror?: string;\n\tdisabled?: boolean;\n}\n\n/**\n * Text input component.\n *\n * When the model element has `isTypeAheadField: true` and a matching\n * typeahead provider is registered in CustomizationsConfig, renders\n * as a MUI Autocomplete with freeSolo mode for suggestion support.\n * Otherwise, renders a plain TextField.\n */\nexport function TextInputComponent({\n\telement,\n\treadOnly,\n\tvalue = \"\",\n\tonChange,\n\terror,\n\tdisabled,\n}: TextInputComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst textInputElement = element as TextInput;\n\tconst startAdornment = buildIconAdornment(element.icon);\n\n\tconst isTypeAhead = String(textInputElement.isTypeAheadField) === \"true\";\n\tconst typeaheadProvider = useTypeaheadProvider(isTypeAhead ? element[\"xmi:id\"] : undefined);\n\n\tif (typeaheadProvider) {\n\t\treturn (\n\t\t\t<TypeaheadInput\n\t\t\t\tlabel={label}\n\t\t\t\ttestId={testId}\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={onChange}\n\t\t\t\terror={error}\n\t\t\t\tdisabled={disabled ?? element.disabled}\n\t\t\t\trequired={element.required}\n\t\t\t\treadOnly={readOnly ?? element.isReadOnly}\n\t\t\t\tmaxLength={textInputElement.maxLength}\n\t\t\t\tregexp={textInputElement.regexp}\n\t\t\t\tprovider={typeaheadProvider}\n\t\t\t\tstartAdornment={startAdornment}\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<TextField\n\t\t\tlabel={label}\n\t\t\tvalue={value}\n\t\t\tonChange={(e) => onChange?.(e.target.value)}\n\t\t\terror={!!error}\n\t\t\thelperText={error}\n\t\t\tdisabled={disabled ?? element.disabled}\n\t\t\trequired={element.required}\n\t\t\tfullWidth\n\t\t\tdata-testid={testId}\n\t\t\tslotProps={{\n\t\t\t\tinput: {\n\t\t\t\t\treadOnly: readOnly ?? element.isReadOnly,\n\t\t\t\t\tstartAdornment,\n\t\t\t\t},\n\t\t\t\thtmlInput: {\n\t\t\t\t\tmaxLength: textInputElement.maxLength,\n\t\t\t\t\tpattern: textInputElement.regexp,\n\t\t\t\t},\n\t\t\t\tinputLabel: {\n\t\t\t\t\tshrink: true,\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n}\n\n// ============================================\n// TYPEAHEAD SUB-COMPONENT\n// ============================================\n\ninterface TypeaheadInputProps {\n\tlabel: string;\n\ttestId: string;\n\tvalue: string;\n\tonChange?: (value: string) => void;\n\terror?: string;\n\tdisabled?: boolean;\n\trequired?: boolean;\n\treadOnly?: boolean;\n\tmaxLength?: number;\n\tregexp?: string;\n\tprovider: (text: string) => Promise<string[]>;\n\tstartAdornment?: React.ReactNode;\n}\n\nfunction TypeaheadInput({\n\tlabel,\n\ttestId,\n\tvalue,\n\tonChange,\n\terror,\n\tdisabled,\n\trequired,\n\treadOnly,\n\tmaxLength,\n\tregexp,\n\tprovider,\n\tstartAdornment,\n}: TypeaheadInputProps) {\n\tconst [options, setOptions] = useState<string[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\n\t// Fetch suggestions with built-in debounce (default 300ms)\n\tconst fetchSuggestions = useDebouncedCallback(async (text: string) => {\n\t\tsetLoading(true);\n\t\ttry {\n\t\t\tconst results = await provider(text);\n\t\t\tsetOptions(results);\n\t\t} catch {\n\t\t\tsetOptions([]);\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t});\n\n\treturn (\n\t\t<Autocomplete\n\t\t\tfreeSolo\n\t\t\toptions={options}\n\t\t\tloading={loading}\n\t\t\tvalue={value}\n\t\t\tinputValue={value}\n\t\t\tonInputChange={(_event, newInputValue, reason) => {\n\t\t\t\tif (reason === \"input\") {\n\t\t\t\t\tonChange?.(newInputValue);\n\t\t\t\t\tfetchSuggestions(newInputValue);\n\t\t\t\t}\n\t\t\t}}\n\t\t\tonChange={(_event, newValue) => {\n\t\t\t\t// newValue is string | null in freeSolo mode\n\t\t\t\tonChange?.(typeof newValue === \"string\" ? newValue : \"\");\n\t\t\t}}\n\t\t\tdisabled={disabled}\n\t\t\treadOnly={readOnly}\n\t\t\tfullWidth\n\t\t\tdata-testid={testId}\n\t\t\trenderInput={(params) => (\n\t\t\t\t<TextField\n\t\t\t\t\t{...params}\n\t\t\t\t\tlabel={label}\n\t\t\t\t\terror={!!error}\n\t\t\t\t\thelperText={error}\n\t\t\t\t\trequired={required}\n\t\t\t\t\tslotProps={{\n\t\t\t\t\t\tinput: {\n\t\t\t\t\t\t\t...params.InputProps,\n\t\t\t\t\t\t\treadOnly,\n\t\t\t\t\t\t\tstartAdornment: startAdornment ? (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t{startAdornment}\n\t\t\t\t\t\t\t\t\t{params.InputProps.startAdornment}\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\tparams.InputProps.startAdornment\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tendAdornment: (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t{loading && <CircularProgress color=\"inherit\" size={20} data-testid={`${testId}::loading`} />}\n\t\t\t\t\t\t\t\t\t{params.InputProps.endAdornment}\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t\thtmlInput: {\n\t\t\t\t\t\t\t...params.inputProps,\n\t\t\t\t\t\t\tmaxLength,\n\t\t\t\t\t\t\tpattern: regexp,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinputLabel: {\n\t\t\t\t\t\t\tshrink: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t)}\n\t\t/>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { Input, TimeInput } from \"@judo/model-api\";\nimport { getInputTestId } from \"@judo/test-ids\";\nimport { TextField } from \"@mui/material\";\nimport { buildIconAdornment } from \"../utils/icon-adornment\";\n\nexport interface TimeInputComponentProps {\n\telement: TimeInput | Input;\n\treadOnly?: boolean;\n\tvalue?: string | null;\n\tonChange?: (value: string | null) => void;\n\terror?: string;\n\tdisabled?: boolean;\n}\n\n/**\n * Time input component.\n */\nexport function TimeInputComponent({ element, readOnly, value, onChange, error, disabled }: TimeInputComponentProps) {\n\tconst testId = getInputTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst startAdornment = buildIconAdornment(element.icon);\n\n\treturn (\n\t\t<TextField\n\t\t\ttype=\"time\"\n\t\t\tlabel={label}\n\t\t\tvalue={value ?? \"\"}\n\t\t\tonChange={(e) => onChange?.(e.target.value || null)}\n\t\t\terror={!!error}\n\t\t\thelperText={error}\n\t\t\tdisabled={disabled ?? element.disabled}\n\t\t\trequired={element.required}\n\t\t\tfullWidth\n\t\t\tdata-testid={testId}\n\t\t\tslotProps={{\n\t\t\t\tinput: {\n\t\t\t\t\treadOnly: readOnly ?? element.isReadOnly,\n\t\t\t\t\tstartAdornment,\n\t\t\t\t},\n\t\t\t\tinputLabel: {\n\t\t\t\t\tshrink: true,\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import { useEnumOptionFilter, useVisualBinding } from \"@judo/core\";\nimport type { EnumerationCombo, EnumerationRadio, EnumerationToggleButtonbar, Input } from \"@judo/model-api\";\nimport { BinaryInputComponent } from \"./BinaryInputComponent\";\nimport { CheckboxComponent } from \"./CheckboxComponent\";\nimport { DateInputComponent } from \"./DateInputComponent\";\nimport { DateTimeInputComponent } from \"./DateTimeInputComponent\";\nimport { EnumerationComboComponent } from \"./EnumerationComboComponent\";\nimport { EnumerationRadioComponent } from \"./EnumerationRadioComponent\";\nimport { EnumerationToggleButtonbarComponent } from \"./EnumerationToggleButtonbarComponent\";\nimport { NumericInputComponent } from \"./NumericInputComponent\";\nimport { PasswordInputComponent } from \"./PasswordInputComponent\";\nimport { SwitchComponent } from \"./SwitchComponent\";\nimport { TextAreaComponent } from \"./TextAreaComponent\";\nimport { TextInputComponent } from \"./TextInputComponent\";\nimport { TimeInputComponent } from \"./TimeInputComponent\";\n\n/**\n * Converts model Option[] to component options format.\n * Uses enumerationMember.name as value and label/name as display.\n */\nfunction convertEnumOptions(\n\telement: EnumerationCombo | EnumerationRadio | EnumerationToggleButtonbar\n): Array<{ value: string; label: string }> {\n\treturn (element.options ?? []).map((opt) => ({\n\t\tvalue: opt.enumerationMember?.name ?? opt.name,\n\t\tlabel: opt.label ?? opt.enumerationMember?.name ?? opt.name,\n\t}));\n}\n\nexport interface InputRendererProps {\n\telement: Input;\n\treadOnly?: boolean;\n}\n\n/**\n * Dispatcher to specific input components based on element type.\n * Connects data binding via useVisualBinding hook.\n */\nexport function InputRenderer({ element, readOnly }: InputRendererProps) {\n\t// Connect to data store via visual binding\n\tconst binding = useVisualBinding(element);\n\n\t// Enum option filter (called unconditionally per rules of hooks)\n\tconst enumOptionFilter = useEnumOptionFilter(element[\"xmi:id\"]);\n\n\t// If element is hidden (via hiddenBy, static hidden, or customization override), don't render\n\tif (binding.hidden) {\n\t\treturn null;\n\t}\n\n\t// Merge readOnly from props, element, and binding\n\tconst isReadOnly = readOnly ?? binding.readOnly ?? element.isReadOnly ?? false;\n\n\t// Build effective element with visual property overrides applied.\n\t// binding.label already includes visual property override from VisualPropertiesProvider.\n\t// For required: merge binding.required (includes visual override) with element-level required\n\t// (element.required || attributeType.isRequired) for data-level 1..1 cardinality.\n\tconst elementRequired = element.required === true || element.attributeType?.isRequired === true;\n\tconst effectiveRequired = binding.required || elementRequired;\n\tconst effectiveElement = {\n\t\t...element,\n\t\tlabel: binding.label || element.label,\n\t\trequired: effectiveRequired,\n\t};\n\n\t// Common props from binding\n\tconst commonProps = {\n\t\tvalue: binding.value as any, // Type depends on input type, will be validated by component\n\t\tonChange: binding.onChange,\n\t\terror: binding.error ?? undefined,\n\t\tdisabled: binding.disabled,\n\t};\n\n\t// Dispatch to specific input component\n\tswitch (element[\"@type\"]) {\n\t\tcase \"TextInput\":\n\t\t\treturn <TextInputComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tcase \"NumericInput\":\n\t\t\treturn <NumericInputComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tcase \"DateInput\":\n\t\t\treturn <DateInputComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tcase \"DateTimeInput\":\n\t\t\treturn <DateTimeInputComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tcase \"TimeInput\":\n\t\t\treturn <TimeInputComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tcase \"TextArea\":\n\t\t\treturn <TextAreaComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tcase \"Checkbox\":\n\t\t\treturn <CheckboxComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tcase \"Switch\":\n\t\t\treturn <SwitchComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tcase \"EnumerationCombo\": {\n\t\t\tconst enumElement = effectiveElement as EnumerationCombo;\n\t\t\t// Nullable when not required (either by visual element or underlying attribute)\n\t\t\tconst isNullable = !enumElement.required && !enumElement.attributeType?.isRequired;\n\t\t\tconst comboOptions = convertEnumOptions(enumElement);\n\t\t\treturn (\n\t\t\t\t<EnumerationComboComponent\n\t\t\t\t\telement={effectiveElement}\n\t\t\t\t\treadOnly={isReadOnly}\n\t\t\t\t\toptions={enumOptionFilter ? enumOptionFilter(comboOptions) : comboOptions}\n\t\t\t\t\tnullable={isNullable}\n\t\t\t\t\t{...commonProps}\n\t\t\t\t/>\n\t\t\t);\n\t\t}\n\n\t\tcase \"EnumerationRadio\": {\n\t\t\tconst enumElement = effectiveElement as EnumerationRadio;\n\t\t\t// Nullable when not required (either by visual element or underlying attribute)\n\t\t\tconst isNullable = !enumElement.required && !enumElement.attributeType?.isRequired;\n\t\t\t// Orientation based on stretch property: HORIZONTAL stretch = horizontal layout\n\t\t\tconst orientation =\n\t\t\t\tenumElement.stretch === \"HORIZONTAL\" || enumElement.stretch === \"BOTH\" ? \"horizontal\" : \"vertical\";\n\t\t\tconst radioOptions = convertEnumOptions(enumElement);\n\t\t\treturn (\n\t\t\t\t<EnumerationRadioComponent\n\t\t\t\t\telement={effectiveElement}\n\t\t\t\t\treadOnly={isReadOnly}\n\t\t\t\t\toptions={enumOptionFilter ? enumOptionFilter(radioOptions) : radioOptions}\n\t\t\t\t\tnullable={isNullable}\n\t\t\t\t\torientation={orientation}\n\t\t\t\t\t{...commonProps}\n\t\t\t\t/>\n\t\t\t);\n\t\t}\n\n\t\tcase \"EnumerationToggleButtonbar\": {\n\t\t\tconst enumElement = effectiveElement as EnumerationToggleButtonbar;\n\t\t\t// Nullable when not required (either by visual element or underlying attribute)\n\t\t\tconst isNullable = !enumElement.required && !enumElement.attributeType?.isRequired;\n\t\t\t// Orientation based on stretch property: HORIZONTAL stretch = horizontal layout\n\t\t\tconst orientation = enumElement.stretch === \"VERTICAL\" ? \"vertical\" : \"horizontal\";\n\t\t\tconst toggleOptions = convertEnumOptions(enumElement);\n\t\t\treturn (\n\t\t\t\t<EnumerationToggleButtonbarComponent\n\t\t\t\t\telement={effectiveElement}\n\t\t\t\t\treadOnly={isReadOnly}\n\t\t\t\t\toptions={enumOptionFilter ? enumOptionFilter(toggleOptions) : toggleOptions}\n\t\t\t\t\tnullable={isNullable}\n\t\t\t\t\torientation={orientation}\n\t\t\t\t\t{...commonProps}\n\t\t\t\t/>\n\t\t\t);\n\t\t}\n\n\t\tcase \"BinaryTypeInput\":\n\t\t\treturn <BinaryInputComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tcase \"PasswordInput\":\n\t\t\treturn <PasswordInputComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\n\t\tdefault:\n\t\t\t// Fallback to text input\n\t\t\treturn <TextInputComponent element={effectiveElement} readOnly={isReadOnly} {...commonProps} />;\n\t}\n}\n","import { useVisualBinding } from \"@judo/core\";\nimport type { Formatted } from \"@judo/model-api\";\nimport Typography from \"@mui/material/Typography\";\n\nexport interface FormattedRendererProps {\n\telement: Formatted;\n\treadOnly?: boolean;\n}\n\n/**\n * Apply sprintf-style format string to a value.\n * Supports %s (string), %d (integer), %f (float), and %% (literal %).\n * Falls back to String(value) if format is not provided.\n */\nfunction applyFormat(format: string | undefined, value: unknown): string {\n\tif (value == null) {\n\t\treturn \"\";\n\t}\n\n\tif (!format) {\n\t\treturn String(value);\n\t}\n\n\t// Replace format specifiers with the value\n\treturn format.replace(/%([%sdf])/g, (match, specifier) => {\n\t\tif (specifier === \"%\") {\n\t\t\treturn \"%\";\n\t\t}\n\t\tif (specifier === \"d\") {\n\t\t\tconst num = Number(value);\n\t\t\treturn Number.isNaN(num) ? String(value) : String(Math.trunc(num));\n\t\t}\n\t\tif (specifier === \"f\") {\n\t\t\tconst num = Number(value);\n\t\t\treturn Number.isNaN(num) ? String(value) : String(num);\n\t\t}\n\t\t// %s - string\n\t\treturn String(value);\n\t});\n}\n\n/**\n * Renderer for Formatted visual elements.\n * Displays attribute value using a sprintf-style format string.\n * Uses useVisualBinding to read from the data store.\n */\nexport function FormattedRenderer({ element }: FormattedRendererProps) {\n\tconst binding = useVisualBinding(element);\n\n\tif (binding.hidden) {\n\t\treturn null;\n\t}\n\n\tconst formatted = applyFormat(element.format, binding.value);\n\tconst testId = `formatted::${element.sourceId ?? element[\"xmi:id\"]}`;\n\n\tif (element.isMultiLine) {\n\t\treturn (\n\t\t\t<Typography component=\"div\" data-testid={testId} sx={{ whiteSpace: \"pre-wrap\", wordBreak: \"break-word\" }}>\n\t\t\t\t{formatted}\n\t\t\t</Typography>\n\t\t);\n\t}\n\n\treturn <Typography data-testid={testId}>{formatted}</Typography>;\n}\n","import type { Action } from \"@judo/actions\";\nimport {\n\tuseDispatchOptional,\n\tuseEditMode,\n\tuseElementDisabled,\n\tuseElementVisibility,\n\tusePageContextOptional,\n} from \"@judo/core\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { Button as ButtonElement, ButtonGroup as ButtonGroupElement, PageDefinition } from \"@judo/model-api\";\nimport { getButtonGroupTestId, getButtonTestId } from \"@judo/test-ids\";\nimport KeyboardArrowDownIcon from \"@mui/icons-material/KeyboardArrowDown\";\nimport { Button, ButtonGroup, ListItemIcon, ListItemText, Menu, MenuItem } from \"@mui/material\";\nimport { useState } from \"react\";\nimport { findActionByDefinition } from \"../utils/find-action-by-definition\";\nimport { getVisibleButtons } from \"../utils/get-visible-buttons\";\nimport { IconRenderer } from \"./IconRenderer\";\n\nexport interface InlineButtonGroupRendererProps {\n\telement: ButtonGroupElement;\n\t/** Optional page override (uses context if not provided) */\n\tpage?: PageDefinition;\n\teditMode?: boolean;\n\t/** Optional dispatch override (uses context if not provided) */\n\tonDispatch?: (action: Action) => Promise<unknown>;\n}\n\n/**\n * Renderer for inline ButtonGroup elements (within forms/views).\n *\n * Supports `featuredActions` — when set to a number > 0, that many buttons\n * are \"extracted\" from the dropdown and rendered as inline buttons to the left\n * of the dropdown trigger. Featured buttons and the dropdown are rendered\n * within a single MUI ButtonGroup.\n *\n * When featuredActions is 0 (default), all buttons appear inside a dropdown menu.\n */\nexport function InlineButtonGroupRenderer({\n\telement,\n\tpage: pageProp,\n\teditMode,\n\tonDispatch: onDispatchProp,\n}: InlineButtonGroupRendererProps) {\n\t// Check group-level visibility (hiddenBy dynamic data, static hidden, customization overrides)\n\tconst groupHidden = useElementVisibility(element);\n\n\t// Use props if provided, otherwise fall back to context\n\tconst pageContext = usePageContextOptional();\n\tconst dispatchContext = useDispatchOptional();\n\tconst { isEditMode: derivedEditMode } = useEditMode();\n\n\tconst page = pageProp ?? pageContext?.pageDefinition;\n\tconst onDispatch = onDispatchProp ?? dispatchContext?.dispatch;\n\n\t// Resolve edit mode: use prop if provided, otherwise derive from hook.\n\t// When in edit mode, inline buttons are disabled (not hidden).\n\tconst resolvedEditMode = editMode ?? derivedEditMode;\n\n\tconst [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n\tconst open = Boolean(anchorEl);\n\n\tconst handleDropdownClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n\t\tsetAnchorEl(event.currentTarget);\n\t};\n\n\tconst handleClose = () => {\n\t\tsetAnchorEl(null);\n\t};\n\n\tconst dispatchButtonAction = (button: ButtonElement) => {\n\t\tconst action = page ? findActionByDefinition(page, button.actionDefinition) : undefined;\n\n\t\tif (action && onDispatch) {\n\t\t\tonDispatch(action as Action).catch((error) => {\n\t\t\t\tconsole.error(\"Button action failed:\", error);\n\t\t\t});\n\t\t}\n\t};\n\n\tconst handleButtonClick = (button: ButtonElement) => {\n\t\tdispatchButtonAction(button);\n\t};\n\n\tconst handleMenuItemClick = (button: ButtonElement) => {\n\t\thandleClose();\n\t\tdispatchButtonAction(button);\n\t};\n\n\t// Filter buttons to only show those with matching page actions.\n\t// Inline button groups always keep non-edit buttons visible — edit mode\n\t// controls disabling (greyed out) rather than visibility.\n\tconst visibleButtons = getVisibleButtons(element.buttons, page?.actions);\n\n\t// Don't render empty button group\n\tif (groupHidden || visibleButtons.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst groupTestId = getButtonGroupTestId(element);\n\tconst { label: dropdownLabel } = useModelLabel(element);\n\tconst featuredCount = element.featuredActions ?? 0;\n\n\t// Split into featured (inline buttons) and overflow (dropdown menu items)\n\tconst featuredButtons = featuredCount > 0 ? visibleButtons.slice(0, featuredCount) : [];\n\tconst overflowButtons = featuredCount > 0 ? visibleButtons.slice(featuredCount) : visibleButtons;\n\n\treturn (\n\t\t<>\n\t\t\t<ButtonGroup data-testid={groupTestId}>\n\t\t\t\t{featuredButtons.map((button) => (\n\t\t\t\t\t<InlineFeaturedButton\n\t\t\t\t\t\tkey={button[\"xmi:id\"]}\n\t\t\t\t\t\tbutton={button}\n\t\t\t\t\t\tonClick={() => handleButtonClick(button)}\n\t\t\t\t\t\tdisabled={button.disabled === true || resolvedEditMode === true}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t\t{overflowButtons.length > 0 && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\tonClick={handleDropdownClick}\n\t\t\t\t\t\tdisabled={resolvedEditMode === true}\n\t\t\t\t\t\tdata-testid={`${groupTestId}::dropdown`}\n\t\t\t\t\t\tstartIcon={element.icon ? <IconRenderer icon={element.icon} /> : undefined}\n\t\t\t\t\t\tendIcon={<KeyboardArrowDownIcon />}\n\t\t\t\t\t\taria-controls={open ? `${groupTestId}-menu` : undefined}\n\t\t\t\t\t\taria-haspopup=\"true\"\n\t\t\t\t\t\taria-expanded={open ? \"true\" : undefined}\n\t\t\t\t\t>\n\t\t\t\t\t\t{dropdownLabel}\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t</ButtonGroup>\n\t\t\t{overflowButtons.length > 0 && (\n\t\t\t\t<Menu\n\t\t\t\t\tid={`${groupTestId}-menu`}\n\t\t\t\t\tanchorEl={anchorEl}\n\t\t\t\t\topen={open}\n\t\t\t\t\tonClose={handleClose}\n\t\t\t\t\tMenuListProps={{\n\t\t\t\t\t\t\"aria-labelledby\": `${groupTestId}::dropdown`,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{overflowButtons.map((button) => (\n\t\t\t\t\t\t<InlineOverflowItem\n\t\t\t\t\t\t\tkey={button[\"xmi:id\"]}\n\t\t\t\t\t\t\tbutton={button}\n\t\t\t\t\t\t\tonClick={() => handleMenuItemClick(button)}\n\t\t\t\t\t\t\tdisabled={button.disabled === true || resolvedEditMode === true}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</Menu>\n\t\t\t)}\n\t\t</>\n\t);\n}\n\n/** Featured inline button with translated label. Handles hiddenBy and enabledBy. */\nfunction InlineFeaturedButton({\n\tbutton,\n\tonClick,\n\tdisabled,\n}: {\n\tbutton: ButtonElement;\n\tonClick: () => void;\n\tdisabled: boolean;\n}) {\n\tconst hidden = useElementVisibility(button);\n\tconst dynamicDisabled = useElementDisabled(button);\n\tconst { label } = useModelLabel(button);\n\tconst buttonTestId = getButtonTestId(button);\n\n\tif (hidden) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Button\n\t\t\tvariant=\"outlined\"\n\t\t\tonClick={onClick}\n\t\t\tdisabled={disabled || dynamicDisabled}\n\t\t\tdata-testid={buttonTestId}\n\t\t\tstartIcon={button.icon ? <IconRenderer icon={button.icon} /> : undefined}\n\t\t>\n\t\t\t{label}\n\t\t</Button>\n\t);\n}\n\n/** Overflow menu item with translated label. Handles hiddenBy and enabledBy. */\nfunction InlineOverflowItem({\n\tbutton,\n\tonClick,\n\tdisabled,\n}: {\n\tbutton: ButtonElement;\n\tonClick: () => void;\n\tdisabled: boolean;\n}) {\n\tconst hidden = useElementVisibility(button);\n\tconst dynamicDisabled = useElementDisabled(button);\n\tconst { label } = useModelLabel(button);\n\tconst buttonTestId = getButtonTestId(button);\n\n\tif (hidden) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<MenuItem onClick={onClick} disabled={disabled || dynamicDisabled} data-testid={buttonTestId}>\n\t\t\t{button.icon && (\n\t\t\t\t<ListItemIcon>\n\t\t\t\t\t<IconRenderer icon={button.icon} />\n\t\t\t\t</ListItemIcon>\n\t\t\t)}\n\t\t\t<ListItemText>{label}</ListItemText>\n\t\t</MenuItem>\n\t);\n}\n","import type { TransferStored, JudoRestApi } from \"@judo/actions\";\nimport { useMuiProOptional } from \"@judo/core\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { Column, Link, RelationType } from \"@judo/model-api\";\nimport { getLinkTestId } from \"@judo/test-ids\";\nimport { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField } from \"@mui/material\";\nimport { DataGrid, type GridColDef, type GridPaginationModel, type GridRowSelectionModel } from \"@mui/x-data-grid\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\ntype OptionRecord = Record<string, unknown>;\n\nexport interface LinkSelectorDialogProps {\n\topen: boolean;\n\telement: Link;\n\trelationType: RelationType;\n\tapi: JudoRestApi;\n\ttransfer?: OptionRecord;\n\tonConfirm: (selected: OptionRecord) => void;\n\tonCancel: () => void;\n}\n\n/**\n * A selector dialog for Link components.\n *\n * Shows a DataGrid table with the available relation range,\n * supports text filtering, pagination, and single-row selection.\n */\nexport function LinkSelectorDialog({\n\topen,\n\telement,\n\trelationType,\n\tapi,\n\ttransfer,\n\tonConfirm,\n\tonCancel,\n}: LinkSelectorDialogProps) {\n\tconst testId = `${getLinkTestId(element)}::selector`;\n\tconst { label } = useModelLabel(element);\n\n\t// MUI Pro detection — use DataGridPro when available for advanced features\n\tconst muiPro = useMuiProOptional();\n\tconst DataGridComponent = muiPro?.getComponent(\"DataGrid\") ?? DataGrid;\n\n\t// State\n\tconst [rows, setRows] = useState<OptionRecord[]>([]);\n\tconst [loading, setLoading] = useState(false);\n\tconst [rowCount, setRowCount] = useState(0);\n\tconst [filterText, setFilterText] = useState(\"\");\n\tconst [selectedRow, setSelectedRow] = useState<OptionRecord | null>(null);\n\tconst [paginationModel, setPaginationModel] = useState<GridPaginationModel>({\n\t\tpage: 0,\n\t\tpageSize: element.selectorRowsPerPage ?? 10,\n\t});\n\n\t// Guard against multiple initial loads\n\tconst _initialLoadDone = useRef(false);\n\n\t// Determine the first string attribute name on the target type for filtering\n\tconst filterAttributeName = useMemo(() => {\n\t\tif (!relationType?.target?.attributes) return undefined;\n\t\tconst stringAttr = relationType.target.attributes.find((attr) => attr.dataType?.[\"@type\"] === \"StringType\");\n\t\treturn stringAttr?.name;\n\t}, [relationType]);\n\n\t// Build columns from element.parts\n\tconst columns: GridColDef[] = useMemo(() => {\n\t\treturn element.parts.map((col: Column) => ({\n\t\t\tfield: col.attributeType?.name ?? col.name,\n\t\t\theaderName: col.label ?? col.name,\n\t\t\trenderHeader: () => <TranslatedColumnHeader column={col} />,\n\t\t\twidth: col.width ? Number.parseInt(col.width, 10) : 150,\n\t\t\tsortable: true,\n\t\t\tfilterable: false,\n\t\t}));\n\t}, [element.parts]);\n\n\t// Fetch data from backend\n\tconst fetchData = useCallback(\n\t\tasync (pageNum: number, pageSize: number, filter: string) => {\n\t\t\tsetLoading(true);\n\t\t\ttry {\n\t\t\t\tconst queryCustomizer: Record<string, unknown> = {\n\t\t\t\t\t_seek: { limit: pageSize, offset: pageNum * pageSize },\n\t\t\t\t};\n\n\t\t\t\t// Apply text filter on the first string attribute\n\t\t\t\tif (filter && filterAttributeName) {\n\t\t\t\t\tqueryCustomizer[filterAttributeName] = [{ operator: \"like\", value: `%${filter}%` }];\n\t\t\t\t}\n\n\t\t\t\tconst response = await api.getRelationRange(\n\t\t\t\t\trelationType,\n\t\t\t\t\ttransfer as TransferStored | undefined,\n\t\t\t\t\tqueryCustomizer as any\n\t\t\t\t);\n\n\t\t\t\tsetRows(response.data as OptionRecord[]);\n\t\t\t\t// If response includes count, use it\n\t\t\t\tif (typeof (response as any).totalCount === \"number\") {\n\t\t\t\t\tsetRowCount((response as any).totalCount);\n\t\t\t\t} else {\n\t\t\t\t\t// Estimate: if we got a full page, there might be more\n\t\t\t\t\tsetRowCount(\n\t\t\t\t\t\tresponse.data.length < pageSize ? pageNum * pageSize + response.data.length : (pageNum + 1) * pageSize + 1\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Failed to fetch selector data:\", error);\n\t\t\t\tsetRows([]);\n\t\t\t\tsetRowCount(0);\n\t\t\t} finally {\n\t\t\t\tsetLoading(false);\n\t\t\t}\n\t\t},\n\t\t[api, relationType, transfer, filterAttributeName]\n\t);\n\n\t// Initial load and on pagination/filter change\n\tuseEffect(() => {\n\t\tif (!open) return;\n\t\tfetchData(paginationModel.page, paginationModel.pageSize, filterText);\n\t}, [open, paginationModel.page, paginationModel.pageSize, filterText, fetchData]);\n\n\t// Handle filter input with debounce\n\tconst debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\tconst handleFilterChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst value = event.target.value;\n\t\tif (debounceRef.current) {\n\t\t\tclearTimeout(debounceRef.current);\n\t\t}\n\t\tdebounceRef.current = setTimeout(() => {\n\t\t\tsetFilterText(value);\n\t\t\tsetPaginationModel((prev) => ({ ...prev, page: 0 }));\n\t\t}, 300);\n\t}, []);\n\n\t// Handle row selection\n\tconst handleRowSelectionChange = useCallback(\n\t\t(model: GridRowSelectionModel) => {\n\t\t\tconst selectedIds = model.type === \"include\" ? Array.from(model.ids) : [];\n\t\t\tif (selectedIds.length > 0) {\n\t\t\t\tconst selected = rows.find(\n\t\t\t\t\t(row) => (row.__signedIdentifier ?? row.__identifier ?? row.__tempId ?? (row as any).id) === selectedIds[0]\n\t\t\t\t);\n\t\t\t\tsetSelectedRow(selected ?? null);\n\t\t\t} else {\n\t\t\t\tsetSelectedRow(null);\n\t\t\t}\n\t\t},\n\t\t[rows]\n\t);\n\n\t// Handle confirm\n\tconst handleConfirm = useCallback(() => {\n\t\tif (selectedRow) {\n\t\t\tonConfirm(selectedRow);\n\t\t}\n\t}, [selectedRow, onConfirm]);\n\n\t// Page size options\n\tconst pageSizeOptions = useMemo(() => {\n\t\tconst defaultOptions = [5, 10, 25, 50];\n\t\tconst modeledPageSize = element.selectorRowsPerPage ?? 10;\n\t\tif (!defaultOptions.includes(modeledPageSize)) {\n\t\t\treturn [...defaultOptions, modeledPageSize].toSorted((a, b) => a - b);\n\t\t}\n\t\treturn defaultOptions;\n\t}, [element.selectorRowsPerPage]);\n\n\treturn (\n\t\t<Dialog open={open} onClose={onCancel} maxWidth=\"md\" fullWidth data-testid={testId}>\n\t\t\t<DialogTitle data-testid={`${testId}::title`}>{label}</DialogTitle>\n\t\t\t<DialogContent>\n\t\t\t\t<Box sx={{ mb: 2, mt: 1 }}>\n\t\t\t\t\t<TextField\n\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\tplaceholder={`Filter by ${filterAttributeName ?? \"name\"}...`}\n\t\t\t\t\t\tonChange={handleFilterChange}\n\t\t\t\t\t\tdata-testid={`${testId}::filter`}\n\t\t\t\t\t\tslotProps={{\n\t\t\t\t\t\t\tinputLabel: { shrink: true },\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</Box>\n\t\t\t\t<Box sx={{ height: 400 }}>\n\t\t\t\t\t<DataGridComponent\n\t\t\t\t\t\tcolumns={columns}\n\t\t\t\t\t\trows={rows}\n\t\t\t\t\t\trowCount={rowCount}\n\t\t\t\t\t\tloading={loading}\n\t\t\t\t\t\tpaginationModel={paginationModel}\n\t\t\t\t\t\tonPaginationModelChange={setPaginationModel}\n\t\t\t\t\t\tpaginationMode=\"server\"\n\t\t\t\t\t\tpageSizeOptions={pageSizeOptions}\n\t\t\t\t\t\tgetRowId={(row: any) => row.__signedIdentifier ?? row.__identifier ?? row.__tempId ?? row.id}\n\t\t\t\t\t\tonRowSelectionModelChange={handleRowSelectionChange}\n\t\t\t\t\t\tdata-testid={`${testId}::grid`}\n\t\t\t\t\t\tsx={{ height: \"100%\" }}\n\t\t\t\t\t/>\n\t\t\t\t</Box>\n\t\t\t</DialogContent>\n\t\t\t<DialogActions>\n\t\t\t\t<Button onClick={onCancel} data-testid={`${testId}::cancel`}>\n\t\t\t\t\tCancel\n\t\t\t\t</Button>\n\t\t\t\t<Button onClick={handleConfirm} variant=\"contained\" disabled={!selectedRow} data-testid={`${testId}::confirm`}>\n\t\t\t\t\tConfirm\n\t\t\t\t</Button>\n\t\t\t</DialogActions>\n\t\t</Dialog>\n\t);\n}\n\n/** Translated column header component for selector DataGrid. */\nfunction TranslatedColumnHeader({ column }: { column: Column }) {\n\tconst { label } = useModelLabel(column);\n\treturn <>{label}</>;\n}\n","import type { AttributeType, RelationType } from \"@judo/model-api\";\n\n/**\n * Build a JUDO mask string from attributes and relations.\n *\n * The mask format wraps comma-separated entries in curly braces.\n * Plain attributes are listed by name, while relations include their\n * target attributes in nested braces.\n *\n * @example\n * // Attributes only\n * buildMaskString({ attributes: [{ name: \"born\" }, { name: \"name\" }] })\n * // => \"{born,name}\"\n *\n * @example\n * // Attributes + relations\n * buildMaskString({\n * attributes: [{ name: \"born\" }, { name: \"name\" }],\n * relations: [{ name: \"messages\", target: { attributes: [{ name: \"message\" }] } }],\n * })\n * // => \"{born,name,messages{message}}\"\n *\n * @example\n * // Empty produces \"{}\"\n * buildMaskString({ attributes: [] })\n * // => \"{}\"\n */\nexport function buildMaskString(params: { attributes?: AttributeType[]; relations?: RelationType[] }): string {\n\tconst { attributes = [], relations = [] } = params;\n\n\tconst parts: string[] = [];\n\n\t// Add attribute names\n\tfor (const attr of attributes) {\n\t\tif (attr.name) {\n\t\t\tparts.push(attr.name);\n\t\t}\n\t}\n\n\t// Add relation masks with nested target attributes\n\tfor (const rel of relations) {\n\t\tif (rel.name) {\n\t\t\tconst targetAttrs = (rel.target?.attributes ?? []).map((a) => a.name).filter(Boolean);\n\t\t\tif (targetAttrs.length > 0) {\n\t\t\t\tparts.push(`${rel.name}{${targetAttrs.join(\",\")}}`);\n\t\t\t} else {\n\t\t\t\tparts.push(`${rel.name}{}`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn `{${parts.join(\",\")}}`;\n}\n","import { getActionHandler, useActionDispatcher, useApi } from \"@judo/actions\";\nimport type { Action } from \"@judo/actions\";\nimport {\n\tuseDebouncedCallback,\n\tuseApplication,\n\tuseDataSelector,\n\tuseDataStore,\n\tuseNavigation,\n\tusePageContextOptional,\n\tuseResolvedPageActionOverrides,\n\tuseRuntimeConfigOptional,\n} from \"@judo/core\";\nimport { useConfirmation, useNotifications } from \"@judo/feedback\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { Button as ButtonElement, Column, Link, PageDefinition, RelationType } from \"@judo/model-api\";\nimport { getButtonTestId, getLinkTestId } from \"@judo/test-ids\";\nimport {\n\tAutocomplete,\n\tBox,\n\tClickAwayListener,\n\tGrow,\n\tIconButton,\n\tMenuItem,\n\tMenuList,\n\tPaper,\n\tPopper,\n\tTextField,\n\tTooltip,\n} from \"@mui/material\";\nimport ArrowDropDownIcon from \"@mui/icons-material/ArrowDropDown\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport { LinkSelectorDialog } from \"../dialogs/LinkSelectorDialog\";\nimport { buildMaskString } from \"../utils/build-mask-string\";\nimport { getDestructiveConfirmationOptions } from \"../utils/destructive-action-utils\";\nimport { findActionByDefinition } from \"../utils/find-action-by-definition\";\nimport { getVisibleButtons } from \"../utils/get-visible-buttons\";\nimport { buildIconAdornment } from \"../utils/icon-adornment\";\nimport { IconRenderer } from \"./IconRenderer\";\n\nexport interface LinkRendererProps {\n\telement: Link;\n\tpage?: PageDefinition;\n\treadOnly?: boolean;\n}\n\ntype OptionRecord = Record<string, unknown>;\n\n/**\n * Renderer for Link (autocomplete/relation) elements.\n *\n * Supports:\n * - Typeahead autocomplete with backend fetch (getRelationRange)\n * - Action buttons: View, Set (selector dialog), Unset, Create, Delete\n * - Selector dialog with DataGrid, filtering, pagination\n * - Read-only mode\n */\nexport function LinkRenderer({ element, page: pageProp, readOnly }: LinkRendererProps) {\n\tconst testId = getLinkTestId(element);\n\tconst { label } = useModelLabel(element);\n\tconst startAdornment = buildIconAdornment(element.icon);\n\n\t// Contexts\n\tconst pageContext = usePageContextOptional();\n\tconst page = pageProp ?? pageContext?.pageDefinition;\n\tconst navigation = useNavigation();\n\tconst dataStore = useDataStore();\n\tconst application = useApplication();\n\tconst api = useApi();\n\tconst notifications = useNotifications();\n\tconst { confirm } = useConfirmation();\n\tconst runtimeConfig = useRuntimeConfigOptional();\n\n\tconst density = runtimeConfig?.config?.density ?? \"compact\";\n\n\t// Density-aware margin mapping for the link actions box.\n\t// Each density level needs different margins to align with the Autocomplete's OutlinedInput.\n\tconst densityMargins = useMemo(() => {\n\t\tconst mapping = {\n\t\t\tcompact: { top: 1.33333334, bottom: 0.66666667 },\n\t\t\tcomfortable: { top: 0, bottom: 0 },\n\t\t\tstandard: { top: 1.63333332, bottom: 0.8 },\n\t\t};\n\t\treturn mapping[density] ?? mapping.comfortable;\n\t}, [density]);\n\n\t// Local state\n\tconst [options, setOptions] = useState<OptionRecord[]>([]);\n\tconst [autocompleteLoading, setAutocompleteLoading] = useState(false);\n\tconst [selectorOpen, setSelectorOpen] = useState(false);\n\n\t// Resolve the relation type from element.dataElement\n\tconst relationType = useMemo(() => {\n\t\tif (\n\t\t\telement.dataElement &&\n\t\t\ttypeof element.dataElement === \"object\" &&\n\t\t\telement.dataElement[\"@type\"] === \"RelationType\"\n\t\t) {\n\t\t\treturn element.dataElement as RelationType;\n\t\t}\n\t\treturn undefined;\n\t}, [element.dataElement]);\n\n\t// Subscribe to the current relation value from the DataStore\n\tconst relationValue = useDataSelector(\n\t\tuseCallback(\n\t\t\t(state) => {\n\t\t\t\tconst transferId = pageContext?.transferId;\n\t\t\t\tif (!transferId) return null;\n\t\t\t\tconst transferState = state.transfers.get(transferId);\n\t\t\t\tif (!transferState?.data) return null;\n\t\t\t\treturn (transferState.data[element.relationName] as OptionRecord) ?? null;\n\t\t\t},\n\t\t\t[pageContext?.transferId, element.relationName]\n\t\t)\n\t);\n\n\t// Subscribe to loading state\n\tconst _isLoading = useDataSelector(\n\t\tuseCallback(\n\t\t\t(state) => {\n\t\t\t\tconst transferId = pageContext?.transferId;\n\t\t\t\tif (!transferId) return false;\n\t\t\t\treturn state.transfers.get(transferId)?.isLoading ?? false;\n\t\t\t},\n\t\t\t[pageContext?.transferId]\n\t\t)\n\t);\n\n\t// Get current transfer data for action context\n\tconst storedTransfer = useDataSelector(\n\t\tuseCallback(\n\t\t\t(state) => {\n\t\t\t\tconst transferId = pageContext?.transferId;\n\t\t\t\treturn transferId ? state.transfers.get(transferId)?.data : undefined;\n\t\t\t},\n\t\t\t[pageContext?.transferId]\n\t\t)\n\t);\n\n\t// Build transfer for action context (with signedIdentifier)\n\tconst transfer = useMemo(() => {\n\t\tconst signedIdentifier = pageContext?.params?.signedIdentifier as string | undefined;\n\t\tif (signedIdentifier && pageContext?.transferId) {\n\t\t\treturn {\n\t\t\t\t__identifier: pageContext.transferId,\n\t\t\t\t__signedIdentifier: signedIdentifier,\n\t\t\t};\n\t\t}\n\t\tif (storedTransfer) {\n\t\t\treturn storedTransfer;\n\t\t}\n\t\treturn undefined;\n\t}, [storedTransfer, pageContext?.transferId, pageContext?.params]);\n\n\t// Effective readOnly: from prop, element, or relation\n\tconst isReadOnly = readOnly ?? element.isReadOnly ?? relationType?.isReadOnly ?? false;\n\n\t// Get resolved page action overrides from customizations\n\tconst actionOverrides = useResolvedPageActionOverrides();\n\n\t// Action dispatcher setup (following TableRenderer pattern)\n\tconst dispatcherContext = useMemo(\n\t\t() =>\n\t\t\t({\n\t\t\t\tnavigation,\n\t\t\t\tdata: dataStore,\n\t\t\t\tregistry: application,\n\t\t\t\tapi,\n\t\t\t\ttransfer,\n\t\t\t\tnotifications,\n\t\t\t\tactionOverrides,\n\t\t\t\tadditionalContext: {\n\t\t\t\t\tisEager: element.isEager,\n\t\t\t\t\trelationName: element.relationName,\n\t\t\t\t\tpageTransferId: pageContext?.transferId,\n\t\t\t\t\t// For eager links, pass parentTransferId so View/Create dialogs\n\t\t\t\t\t// get the eager context (matching the TableRenderer pattern)\n\t\t\t\t\t...(element.isEager && {\n\t\t\t\t\t\tparentTransferId: pageContext?.transferId,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t}) as unknown as Parameters<typeof useActionDispatcher>[0],\n\t\t[\n\t\t\tnavigation,\n\t\t\tdataStore,\n\t\t\tapplication,\n\t\t\tapi,\n\t\t\ttransfer,\n\t\t\tnotifications,\n\t\t\telement.isEager,\n\t\t\telement.relationName,\n\t\t\tpageContext?.transferId,\n\t\t\tactionOverrides,\n\t\t]\n\t);\n\n\tconst { dispatch } = useActionDispatcher(dispatcherContext);\n\n\t// Get display label from parts\n\tconst getOptionLabel = useCallback(\n\t\t(option: OptionRecord): string => {\n\t\t\tif (!option) return \"\";\n\t\t\treturn element.parts\n\t\t\t\t.map((p: Column) => option[p.name])\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(\" \");\n\t\t},\n\t\t[element.parts]\n\t);\n\n\t// Determine the first string attribute name on the target type for filtering\n\tconst filterAttributeName = useMemo(() => {\n\t\tif (!relationType?.target?.attributes) return undefined;\n\t\tconst stringAttr = relationType.target.attributes.find((attr) => attr.dataType?.[\"@type\"] === \"StringType\");\n\t\treturn stringAttr?.name;\n\t}, [relationType]);\n\n\t// Fetch relation range from backend\n\tconst fetchRange = useCallback(\n\t\tasync (filterValue?: string) => {\n\t\t\tif (!relationType || !api) return;\n\n\t\t\tsetAutocompleteLoading(true);\n\t\t\ttry {\n\t\t\t\tconst queryCustomizer: Record<string, unknown> = {\n\t\t\t\t\t_seek: { limit: element.autoCompleteRows ?? 10 },\n\t\t\t\t\t_mask: buildMaskString({\n\t\t\t\t\t\tattributes: [...(relationType.target.attributes ?? []), ...(element.additionalMaskAttributes ?? [])],\n\t\t\t\t\t\trelations: element.additionalMaskRelations,\n\t\t\t\t\t}),\n\t\t\t\t};\n\n\t\t\t\tif (filterValue && filterAttributeName) {\n\t\t\t\t\tqueryCustomizer[filterAttributeName] = [{ operator: \"like\", value: `%${filterValue}%` }];\n\t\t\t\t}\n\n\t\t\t\t// Use storedTransfer (backend data with correct __identifier UUID) rather than the\n\t\t\t\t// constructed transfer which may have the frontend store key as __identifier.\n\t\t\t\tconst response = await api.getRelationRange(\n\t\t\t\t\trelationType,\n\t\t\t\t\t(storedTransfer ?? transfer) as any,\n\t\t\t\t\tqueryCustomizer as any\n\t\t\t\t);\n\t\t\t\tsetOptions(response.data as OptionRecord[]);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Failed to load autocomplete options:\", error);\n\t\t\t\tsetOptions([]);\n\t\t\t} finally {\n\t\t\t\tsetAutocompleteLoading(false);\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\telement.autoCompleteRows,\n\t\t\telement.additionalMaskAttributes,\n\t\t\telement.additionalMaskRelations,\n\t\t\trelationType,\n\t\t\tapi,\n\t\t\tstoredTransfer,\n\t\t\ttransfer,\n\t\t\tfilterAttributeName,\n\t\t]\n\t);\n\n\t// Fetch initial (unfiltered) range when dropdown opens\n\tconst handleOpen = useCallback(() => {\n\t\tfetchRange();\n\t}, [fetchRange]);\n\n\t// Debounced fetch for autocomplete input typing\n\tconst debouncedFetchRange = useDebouncedCallback((value: string) => {\n\t\tfetchRange(value);\n\t});\n\n\t// Handle autocomplete input change — fetch range with built-in debounce\n\tconst handleInputChange = useCallback(\n\t\t(_event: unknown, value: string, reason: string) => {\n\t\t\tif (reason !== \"input\") return;\n\n\t\t\tif (!element.autocompleteRangeActionDefinition || !relationType) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tdebouncedFetchRange(value);\n\t\t},\n\t\t[element.autocompleteRangeActionDefinition, relationType, debouncedFetchRange]\n\t);\n\n\t// Ensure the current relationValue is always available in the options list\n\t// so MUI Autocomplete can match value → options for display\n\tconst mergedOptions = useMemo(() => {\n\t\tif (!relationValue) return options;\n\t\tconst alreadyPresent = options.some((opt) => {\n\t\t\t// Prefer __identifier (stable UUID) for dedup since __signedIdentifier\n\t\t\t// may differ between DataStore value and fresh range response\n\t\t\tif (opt.__identifier && relationValue.__identifier) {\n\t\t\t\treturn opt.__identifier === relationValue.__identifier;\n\t\t\t}\n\t\t\tif (opt.__signedIdentifier && relationValue.__signedIdentifier) {\n\t\t\t\treturn opt.__signedIdentifier === relationValue.__signedIdentifier;\n\t\t\t}\n\t\t\treturn opt === relationValue;\n\t\t});\n\t\tif (alreadyPresent) return options;\n\t\treturn [relationValue, ...options];\n\t}, [options, relationValue]);\n\n\t// Handle autocomplete selection\n\tconst handleChange = useCallback(\n\t\tasync (_event: unknown, value: OptionRecord | null) => {\n\t\t\t// Clear button clicked → unset the relation\n\t\t\tif (!value) {\n\t\t\t\tif (element.isEager && pageContext?.transferId) {\n\t\t\t\t\t// Eager: just clear the DataStore field, no REST call\n\t\t\t\t\tdataStore.updateTransferField(pageContext.transferId, element.relationName, null);\n\t\t\t\t} else {\n\t\t\t\t\t// Lazy: dispatch the unset REST action\n\t\t\t\t\tconst unsetActionDef = element.actionButtonGroup?.buttons?.find(\n\t\t\t\t\t\t(b) => b.actionDefinition?.[\"@type\"] === \"UnsetActionDefinition\"\n\t\t\t\t\t)?.actionDefinition;\n\t\t\t\t\tconst unsetAction = unsetActionDef ? findActionByDefinition(page!, unsetActionDef) : undefined;\n\n\t\t\t\t\tif (unsetAction) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst handlerHook = getActionHandler(unsetAction as Action);\n\t\t\t\t\t\t\tif (handlerHook) {\n\t\t\t\t\t\t\t\tconst handlerFn = handlerHook(unsetAction as Action);\n\t\t\t\t\t\t\t\tawait handlerFn({\n\t\t\t\t\t\t\t\t\tnavigation,\n\t\t\t\t\t\t\t\t\tdata: dataStore,\n\t\t\t\t\t\t\t\t\tregistry: application,\n\t\t\t\t\t\t\t\t\tapi,\n\t\t\t\t\t\t\t\t\ttransfer: relationValue ?? transfer,\n\t\t\t\t\t\t\t\t\tnotifications,\n\t\t\t\t\t\t\t\t\t...dispatcherContext.additionalContext,\n\t\t\t\t\t\t\t\t} as any);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconsole.error(\"Failed to unset autocomplete value:\", error);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst setAction = element.autocompleteSetActionDefinition\n\t\t\t\t? findActionByDefinition(page!, element.autocompleteSetActionDefinition)\n\t\t\t\t: undefined;\n\n\t\t\tif (setAction) {\n\t\t\t\ttry {\n\t\t\t\t\tawait dispatch(setAction as Action, { selectedItem: value });\n\n\t\t\t\t\t// For eager relations, update the parent transfer field to trigger edit mode\n\t\t\t\t\tif (element.isEager && pageContext?.transferId) {\n\t\t\t\t\t\tdataStore.updateTransferField(pageContext.transferId, element.relationName, value);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(\"Failed to set autocomplete value:\", error);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\telement.autocompleteSetActionDefinition,\n\t\t\telement.actionButtonGroup,\n\t\t\telement.isEager,\n\t\t\telement.relationName,\n\t\t\tpage,\n\t\t\tdispatch,\n\t\t\tdataStore,\n\t\t\tpageContext?.transferId,\n\t\t\tnavigation,\n\t\t\tapplication,\n\t\t\tapi,\n\t\t\ttransfer,\n\t\t\trelationValue,\n\t\t\tnotifications,\n\t\t\tdispatcherContext.additionalContext,\n\t\t]\n\t);\n\n\t// Resolve visible action buttons\n\tconst visibleButtons = useMemo(() => {\n\t\tconst allButtons = element.actionButtonGroup?.buttons ?? [];\n\t\treturn getVisibleButtons(allButtons, page?.actions);\n\t}, [element.actionButtonGroup, page?.actions]);\n\n\t// Categorize buttons by action type\n\tconst buttonsByType = useMemo(() => {\n\t\tconst result: Record<string, (typeof visibleButtons)[number]> = {};\n\t\tfor (const button of visibleButtons) {\n\t\t\tconst actionType = button.actionDefinition?.[\"@type\"];\n\t\t\tif (actionType) {\n\t\t\t\tresult[actionType] = button;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}, [visibleButtons]);\n\n\t// Cardinality check: isOptional defaults to true; when false the relation is required\n\tconst isOptional = relationType?.isOptional !== false;\n\n\t// Resolve individual buttons from the model\n\tconst viewButton = buttonsByType.OpenPageActionDefinition ?? buttonsByType.RowOpenPageActionDefinition ?? undefined;\n\tconst setButton = !isReadOnly ? buttonsByType.OpenSetSelectorActionDefinition : undefined;\n\tconst unsetButton = !isReadOnly && isOptional ? buttonsByType.UnsetActionDefinition : undefined;\n\tconst createButton = !isReadOnly ? (buttonsByType.OpenCreateFormActionDefinition ?? undefined) : undefined;\n\tconst deleteButton = isOptional ? buttonsByType.RowDeleteActionDefinition : undefined;\n\n\t// ── Button group layout logic ──\n\t// When a value IS set:\n\t// Primary: View only\n\t// Dropdown: Set, Unset, Create, Delete (filtered by guards)\n\t// When NO value is set:\n\t// Primary: Set + Create (if model allows)\n\t// No dropdown\n\tconst hasValue = !!relationValue;\n\n\tconst primaryButtons = useMemo(() => {\n\t\tif (hasValue) {\n\t\t\t// Value present → View is the primary action\n\t\t\treturn viewButton ? [viewButton] : [];\n\t\t}\n\t\t// No value → Set and Create are primary actions\n\t\tconst result: typeof visibleButtons = [];\n\t\tif (setButton) result.push(setButton);\n\t\tif (createButton) result.push(createButton);\n\t\treturn result;\n\t}, [hasValue, viewButton, setButton, createButton]);\n\n\tconst dropdownButtons = useMemo(() => {\n\t\tif (!hasValue) return [];\n\t\t// Value present → everything except View goes in the dropdown, filtered by guards\n\t\tconst result: typeof visibleButtons = [];\n\t\tif (setButton) result.push(setButton);\n\t\tif (unsetButton && relationValue) result.push(unsetButton);\n\t\tif (createButton) result.push(createButton);\n\t\tif (deleteButton && relationValue?.__deleteable === true) result.push(deleteButton);\n\t\treturn result;\n\t}, [hasValue, setButton, unsetButton, createButton, deleteButton, relationValue]);\n\n\t// Dropdown menu state (Popper-based, like original template)\n\tconst [dropdownOpen, setDropdownOpen] = useState(false);\n\tconst anchorRef = useRef<HTMLDivElement>(null);\n\n\tconst handleDropdownToggle = useCallback(() => {\n\t\tsetDropdownOpen((prev) => !prev);\n\t}, []);\n\n\tconst handleDropdownClose = useCallback((event: Event | React.SyntheticEvent) => {\n\t\tif (anchorRef.current?.contains(event.target as HTMLElement)) {\n\t\t\treturn;\n\t\t}\n\t\tsetDropdownOpen(false);\n\t}, []);\n\n\t// Helper: dispatch a button's action\n\tconst dispatchButtonAction = useCallback(\n\t\tasync (button: (typeof visibleButtons)[number], contextOverrides?: Record<string, unknown>) => {\n\t\t\tconst action = page ? findActionByDefinition(page, button.actionDefinition) : undefined;\n\t\t\tif (!action) return;\n\n\t\t\ttry {\n\t\t\t\tconst handlerHook = getActionHandler(action as Action);\n\t\t\t\tif (!handlerHook) {\n\t\t\t\t\tthrow new Error(`No handler for action type: ${button.actionDefinition?.[\"@type\"]}`);\n\t\t\t\t}\n\t\t\t\tconst handlerFn = handlerHook(action as Action);\n\t\t\t\tconst rowContext = {\n\t\t\t\t\tnavigation,\n\t\t\t\t\tdata: dataStore,\n\t\t\t\t\tregistry: application,\n\t\t\t\t\tapi,\n\t\t\t\t\ttransfer: contextOverrides?.transfer ?? relationValue ?? transfer,\n\t\t\t\t\tnotifications,\n\t\t\t\t\t...dispatcherContext.additionalContext,\n\t\t\t\t\t...contextOverrides,\n\t\t\t\t};\n\t\t\t\tawait handlerFn(rowContext as any);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Button action failed:\", error);\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\tpage,\n\t\t\tnavigation,\n\t\t\tdataStore,\n\t\t\tapplication,\n\t\t\tapi,\n\t\t\ttransfer,\n\t\t\trelationValue,\n\t\t\tnotifications,\n\t\t\tdispatcherContext.additionalContext,\n\t\t]\n\t);\n\n\t// Handle View button\n\tconst handleView = useCallback(() => {\n\t\tif (viewButton && relationValue) {\n\t\t\tdispatchButtonAction(viewButton, { transfer: relationValue });\n\t\t}\n\t}, [viewButton, relationValue, dispatchButtonAction]);\n\n\t// Handle Set button → open selector dialog\n\tconst handleOpenSelector = useCallback(() => {\n\t\tsetSelectorOpen(true);\n\t}, []);\n\n\t// Handle Unset button\n\tconst handleUnset = useCallback(async () => {\n\t\tif (unsetButton) {\n\t\t\tconst confirmed = await confirm(getDestructiveConfirmationOptions(\"UnsetActionDefinition\"));\n\t\t\tif (!confirmed) return;\n\t\t\tif (element.isEager && pageContext?.transferId) {\n\t\t\t\t// Eager: just clear the DataStore field, no REST call\n\t\t\t\tdataStore.updateTransferField(pageContext.transferId, element.relationName, null);\n\t\t\t} else {\n\t\t\t\t// Lazy: dispatch the unset REST action\n\t\t\t\tdispatchButtonAction(unsetButton);\n\t\t\t}\n\t\t}\n\t}, [\n\t\tunsetButton,\n\t\tdispatchButtonAction,\n\t\telement.isEager,\n\t\telement.relationName,\n\t\tdataStore,\n\t\tpageContext?.transferId,\n\t\tconfirm,\n\t]);\n\n\t// Handle Create button\n\tconst handleCreate = useCallback(() => {\n\t\tif (createButton) {\n\t\t\tdispatchButtonAction(createButton);\n\t\t}\n\t}, [createButton, dispatchButtonAction]);\n\n\t// Handle Delete button\n\tconst handleDelete = useCallback(async () => {\n\t\tif (deleteButton && relationValue) {\n\t\t\tconst confirmed = await confirm(getDestructiveConfirmationOptions(\"RowDeleteActionDefinition\"));\n\t\t\tif (!confirmed) return;\n\t\t\tdispatchButtonAction(deleteButton, { transfer: relationValue });\n\t\t}\n\t}, [deleteButton, relationValue, dispatchButtonAction, confirm]);\n\n\t// Map button to its click handler\n\tconst getButtonHandler = useCallback(\n\t\t(button: (typeof visibleButtons)[number]) => {\n\t\t\tconst actionType = button.actionDefinition?.[\"@type\"];\n\t\t\tswitch (actionType) {\n\t\t\t\tcase \"OpenPageActionDefinition\":\n\t\t\t\tcase \"RowOpenPageActionDefinition\":\n\t\t\t\t\treturn handleView;\n\t\t\t\tcase \"OpenSetSelectorActionDefinition\":\n\t\t\t\t\treturn handleOpenSelector;\n\t\t\t\tcase \"UnsetActionDefinition\":\n\t\t\t\t\treturn handleUnset;\n\t\t\t\tcase \"OpenCreateFormActionDefinition\":\n\t\t\t\t\treturn handleCreate;\n\t\t\t\tcase \"RowDeleteActionDefinition\":\n\t\t\t\t\treturn handleDelete;\n\t\t\t\tdefault:\n\t\t\t\t\treturn () => {};\n\t\t\t}\n\t\t},\n\t\t[handleView, handleOpenSelector, handleUnset, handleCreate, handleDelete]\n\t);\n\n\t// Map button to its default label\n\tconst _getButtonDefaultLabel = useCallback((button: (typeof visibleButtons)[number]) => {\n\t\tconst actionType = button.actionDefinition?.[\"@type\"];\n\t\tswitch (actionType) {\n\t\t\tcase \"OpenPageActionDefinition\":\n\t\t\tcase \"RowOpenPageActionDefinition\":\n\t\t\t\treturn \"View\";\n\t\t\tcase \"OpenSetSelectorActionDefinition\":\n\t\t\t\treturn \"Set\";\n\t\t\tcase \"UnsetActionDefinition\":\n\t\t\t\treturn \"Unset\";\n\t\t\tcase \"OpenCreateFormActionDefinition\":\n\t\t\t\treturn \"Create\";\n\t\t\tcase \"RowDeleteActionDefinition\":\n\t\t\t\treturn \"Delete\";\n\t\t\tdefault:\n\t\t\t\treturn \"Action\";\n\t\t}\n\t}, []);\n\n\t// Handle selector dialog confirm\n\tconst handleSelectorConfirm = useCallback(\n\t\tasync (selected: OptionRecord) => {\n\t\t\tsetSelectorOpen(false);\n\n\t\t\tif (!setButton) return;\n\n\t\t\tconst action = page ? findActionByDefinition(page, setButton.actionDefinition) : undefined;\n\t\t\tif (action) {\n\t\t\t\ttry {\n\t\t\t\t\tawait dispatch(action as Action, { selectedItem: selected });\n\n\t\t\t\t\t// For eager relations, update the parent transfer field to trigger edit mode\n\t\t\t\t\tif (element.isEager && pageContext?.transferId) {\n\t\t\t\t\t\tdataStore.updateTransferField(pageContext.transferId, element.relationName, selected);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(\"Failed to set from selector:\", error);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[setButton, page, dispatch, element.isEager, element.relationName, dataStore, pageContext?.transferId]\n\t);\n\n\t// Handle selector dialog cancel\n\tconst handleSelectorCancel = useCallback(() => {\n\t\tsetSelectorOpen(false);\n\t}, []);\n\n\t// Check option equality by __signedIdentifier or __identifier\n\t// Prefer __identifier (stable UUID) over __signedIdentifier (JWT that may\n\t// change between DataStore value and fresh range response), consistent with\n\t// the mergedOptions dedup logic.\n\tconst isOptionEqualToValue = useCallback((option: OptionRecord, value: OptionRecord) => {\n\t\tif (option.__identifier && value.__identifier) {\n\t\t\treturn option.__identifier === value.__identifier;\n\t\t}\n\t\tif (option.__signedIdentifier && value.__signedIdentifier) {\n\t\t\treturn option.__signedIdentifier === value.__signedIdentifier;\n\t\t}\n\t\treturn option === value;\n\t}, []);\n\n\tconst hasActionButtons = primaryButtons.length > 0 || dropdownButtons.length > 0;\n\n\treturn (\n\t\t<Box data-testid={testId} sx={{ display: \"flex\", alignItems: \"stretch\" }}>\n\t\t\t<Box sx={{ flexGrow: 1 }}>\n\t\t\t\t<Autocomplete\n\t\t\t\t\tvalue={relationValue}\n\t\t\t\t\tonChange={handleChange}\n\t\t\t\t\tonInputChange={handleInputChange}\n\t\t\t\t\tonOpen={handleOpen}\n\t\t\t\t\toptions={mergedOptions}\n\t\t\t\t\tgetOptionLabel={getOptionLabel}\n\t\t\t\t\tfilterOptions={(x) => x}\n\t\t\t\t\tisOptionEqualToValue={isOptionEqualToValue}\n\t\t\t\t\tloading={autocompleteLoading}\n\t\t\t\t\tdisabled={isReadOnly}\n\t\t\t\t\tfreeSolo={false}\n\t\t\t\t\tdata-testid={`${testId}::autocomplete`}\n\t\t\t\t\t{...(hasActionButtons && {\n\t\t\t\t\t\tsx: {\n\t\t\t\t\t\t\t\"& .MuiOutlinedInput-root\": {\n\t\t\t\t\t\t\t\tborderTopRightRadius: 0,\n\t\t\t\t\t\t\t\tborderBottomRightRadius: 0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t})}\n\t\t\t\t\trenderOption={({ key: _muiKey, ...optionProps }, option) => {\n\t\t\t\t\t\tconst key = String(option.__identifier ?? option.__signedIdentifier ?? getOptionLabel(option));\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<li {...optionProps} key={key}>\n\t\t\t\t\t\t\t\t{getOptionLabel(option)}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t);\n\t\t\t\t\t}}\n\t\t\t\t\trenderInput={({ inputProps: autoHtmlInputProps, InputProps: autoInputProps, ...restParams }) => (\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t{...restParams}\n\t\t\t\t\t\t\tlabel={label}\n\t\t\t\t\t\t\trequired={!isOptional}\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\tslotProps={{\n\t\t\t\t\t\t\t\tinput: {\n\t\t\t\t\t\t\t\t\t...autoInputProps,\n\t\t\t\t\t\t\t\t\tstartAdornment: startAdornment ? (\n\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t{startAdornment}\n\t\t\t\t\t\t\t\t\t\t\t{autoInputProps.startAdornment}\n\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\tautoInputProps.startAdornment\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tinputLabel: { shrink: true },\n\t\t\t\t\t\t\t\thtmlInput: {\n\t\t\t\t\t\t\t\t\t...autoHtmlInputProps,\n\t\t\t\t\t\t\t\t\t\"data-testid\": `${testId}::autocomplete::input`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t</Box>\n\n\t\t\t{hasActionButtons && (\n\t\t\t\t<Box\n\t\t\t\t\tref={anchorRef}\n\t\t\t\t\tdata-testid={`${testId}::actions`}\n\t\t\t\t\taria-label=\"link actions\"\n\t\t\t\t\trole=\"group\"\n\t\t\t\t\tsx={(theme) => {\n\t\t\t\t\t\tconst radius = theme.shape.borderRadius;\n\t\t\t\t\t\t// Match MuiOutlinedInput.notchedOutline borderColor from judo-theme-factory\n\t\t\t\t\t\tconst borderColor = theme.palette.mode === \"light\" ? \"rgba(0, 0, 0, 0.15)\" : \"rgba(255, 255, 255, 0.15)\";\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\t\tmarginTop: densityMargins.top,\n\t\t\t\t\t\t\tmarginBottom: densityMargins.bottom,\n\t\t\t\t\t\t\tborder: `1px solid ${borderColor}`,\n\t\t\t\t\t\t\tborderLeft: \"none\",\n\t\t\t\t\t\t\tborderRadius: `0 ${radius}px ${radius}px 0`,\n\t\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\t\tborderColor: theme.palette.text.primary,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{primaryButtons.map((button) => (\n\t\t\t\t\t\t<LinkActionButton key={button[\"xmi:id\"]} button={button} onClick={getButtonHandler(button)} />\n\t\t\t\t\t))}\n\t\t\t\t\t{dropdownButtons.length > 0 && (\n\t\t\t\t\t\t<IconButton\n\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\tonClick={handleDropdownToggle}\n\t\t\t\t\t\t\tdata-testid={`${testId}::actions::dropdown`}\n\t\t\t\t\t\t\taria-label=\"more actions\"\n\t\t\t\t\t\t\tsx={{ borderRadius: 0, px: 0.5 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<ArrowDropDownIcon fontSize=\"small\" />\n\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t)}\n\t\t\t\t</Box>\n\t\t\t)}\n\n\t\t\t<Popper\n\t\t\t\topen={dropdownOpen}\n\t\t\t\tanchorEl={anchorRef.current}\n\t\t\t\ttransition\n\t\t\t\tplacement=\"bottom-end\"\n\t\t\t\tsx={{ zIndex: 1 }}\n\t\t\t\tdata-testid={`${testId}::actions::menu`}\n\t\t\t>\n\t\t\t\t{({ TransitionProps, placement }) => (\n\t\t\t\t\t<Grow\n\t\t\t\t\t\t{...TransitionProps}\n\t\t\t\t\t\tstyle={{ transformOrigin: placement === \"bottom-end\" ? \"right top\" : \"right bottom\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Paper>\n\t\t\t\t\t\t\t<ClickAwayListener onClickAway={handleDropdownClose}>\n\t\t\t\t\t\t\t\t<MenuList autoFocusItem={dropdownOpen}>\n\t\t\t\t\t\t\t\t\t{dropdownButtons.map((button) => (\n\t\t\t\t\t\t\t\t\t\t<LinkDropdownItem\n\t\t\t\t\t\t\t\t\t\t\tkey={button[\"xmi:id\"]}\n\t\t\t\t\t\t\t\t\t\t\tbutton={button}\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetDropdownOpen(false);\n\t\t\t\t\t\t\t\t\t\t\t\tgetButtonHandler(button)();\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</MenuList>\n\t\t\t\t\t\t\t</ClickAwayListener>\n\t\t\t\t\t\t</Paper>\n\t\t\t\t\t</Grow>\n\t\t\t\t)}\n\t\t\t</Popper>\n\n\t\t\t{selectorOpen && relationType && (\n\t\t\t\t<LinkSelectorDialog\n\t\t\t\t\topen={selectorOpen}\n\t\t\t\t\telement={element}\n\t\t\t\t\trelationType={relationType}\n\t\t\t\t\tapi={api}\n\t\t\t\t\ttransfer={transfer}\n\t\t\t\t\tonConfirm={handleSelectorConfirm}\n\t\t\t\t\tonCancel={handleSelectorCancel}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</Box>\n\t);\n}\n\n/** Link action button rendered as a compact icon button matching Autocomplete indicator size. */\nfunction LinkActionButton({ button, onClick }: { button: ButtonElement; onClick: () => void }) {\n\tconst { label } = useModelLabel(button);\n\treturn (\n\t\t<Tooltip title={label}>\n\t\t\t<IconButton\n\t\t\t\tsize=\"small\"\n\t\t\t\tonClick={onClick}\n\t\t\t\tdata-testid={getButtonTestId(button)}\n\t\t\t\taria-label={label}\n\t\t\t\tsx={{ borderRadius: 0, px: 1 }}\n\t\t\t>\n\t\t\t\t{button.icon ? <IconRenderer icon={button.icon} /> : <span style={{ fontSize: \"0.875rem\" }}>{label}</span>}\n\t\t\t</IconButton>\n\t\t</Tooltip>\n\t);\n}\n\n/** Link dropdown menu item with translated label. */\nfunction LinkDropdownItem({ button, onClick }: { button: ButtonElement; onClick: () => void }) {\n\tconst { label } = useModelLabel(button);\n\treturn (\n\t\t<MenuItem onClick={onClick} data-testid={getButtonTestId(button)}>\n\t\t\t{button.icon && <IconRenderer icon={button.icon} />}\n\t\t\t<span style={{ marginLeft: button.icon ? 8 : 0 }}>{label}</span>\n\t\t</MenuItem>\n\t);\n}\n","import type { Action } from \"@judo/actions\";\nimport { useDispatchOptional, useElementDisabled, useElementVisibility, usePageContextOptional } from \"@judo/core\";\nimport { useConfirmation } from \"@judo/feedback\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { Button as ButtonElement, PageDefinition } from \"@judo/model-api\";\nimport { getButtonTestId } from \"@judo/test-ids\";\nimport { Button } from \"@mui/material\";\nimport { getDestructiveConfirmationOptions, isDestructiveAction } from \"../utils/destructive-action-utils\";\nimport { findActionByDefinition } from \"../utils/find-action-by-definition\";\nimport { IconRenderer } from \"./IconRenderer\";\n\nexport interface StandaloneButtonRendererProps {\n\telement: ButtonElement;\n\t/** Optional page override (uses context if not provided) */\n\tpage?: PageDefinition;\n\t/** Optional dispatch override (uses context if not provided) */\n\tonDispatch?: (action: Action) => Promise<unknown>;\n}\n\n/**\n * Renderer for standalone Button elements (direct children of Flex containers).\n * These are typically relation navigation buttons like \"View Matter Table\".\n * The button's actionDefinition is matched against page.actions to find the Action to dispatch.\n */\nexport function StandaloneButtonRenderer({\n\telement,\n\tpage: pageProp,\n\tonDispatch: onDispatchProp,\n}: StandaloneButtonRendererProps) {\n\t// Check element visibility (hiddenBy dynamic data, static hidden, customization overrides)\n\tconst hidden = useElementVisibility(element);\n\t// Check element disabled state (enabledBy dynamic data, static disabled, customization overrides)\n\tconst disabled = useElementDisabled(element);\n\n\t// Use props if provided, otherwise fall back to context\n\tconst pageContext = usePageContextOptional();\n\tconst dispatchContext = useDispatchOptional();\n\n\tconst page = pageProp ?? pageContext?.pageDefinition;\n\tconst onDispatch = onDispatchProp ?? dispatchContext?.dispatch;\n\tconst { confirm } = useConfirmation();\n\n\tconst handleClick = async () => {\n\t\t// Find the corresponding Action from page.actions by matching actionDefinition\n\t\tconst action = page ? findActionByDefinition(page, element.actionDefinition) : undefined;\n\n\t\tif (action && onDispatch) {\n\t\t\tconst actionType = element.actionDefinition?.[\"@type\"];\n\t\t\tif (isDestructiveAction(actionType)) {\n\t\t\t\tconst confirmed = await confirm(getDestructiveConfirmationOptions(actionType!));\n\t\t\t\tif (!confirmed) return;\n\t\t\t}\n\t\t\tonDispatch(action as Action).catch((error) => {\n\t\t\t\tconsole.error(\"Button action failed:\", error);\n\t\t\t});\n\t\t}\n\t};\n\n\tconst testId = getButtonTestId(element);\n\tconst { label } = useModelLabel(element);\n\n\tif (hidden) {\n\t\treturn null;\n\t}\n\n\t// Map button style to MUI variant\n\tconst getVariant = (): \"contained\" | \"outlined\" | \"text\" => {\n\t\tconst style = element.buttonStyle;\n\t\tif (style === \"outlined\") return \"outlined\";\n\t\tif (style === \"text\") return \"text\";\n\t\treturn \"contained\";\n\t};\n\n\treturn (\n\t\t<Button\n\t\t\tvariant={getVariant()}\n\t\t\tonClick={handleClick}\n\t\t\tdisabled={disabled}\n\t\t\tdata-testid={testId}\n\t\t\tstartIcon={element.icon ? <IconRenderer icon={element.icon} /> : undefined}\n\t\t>\n\t\t\t{label}\n\t\t</Button>\n\t);\n}\n","import { useSubThemeProvider } from \"@judo/core\";\nimport type { VisualElement } from \"@judo/model-api\";\nimport { ThemeProvider, createTheme } from \"@mui/material/styles\";\nimport type { ReactNode } from \"react\";\n\nexport interface SubThemeWrapperProps {\n\t/** The visual element that may have a subTheme property */\n\telement: VisualElement;\n\t/** Optional transfer data passed to the sub-theme hook */\n\tdata?: Record<string, unknown>;\n\t/** Child elements to render within the scoped theme */\n\tchildren: ReactNode;\n}\n\n/**\n * Wraps children in a scoped MUI ThemeProvider when the element has a `subTheme` set\n * and a matching provider is registered in `CustomizationsConfig.subThemeProviders`.\n *\n * Sub-themes nest naturally: a child element's sub-theme is deep-merged on top of\n * the parent's sub-theme, giving inner themes higher precedence.\n *\n * If `element.subTheme` is not set or no matching provider is found, renders\n * children directly without any wrapper.\n */\nexport function SubThemeWrapper({ element, data, children }: SubThemeWrapperProps) {\n\tconst subThemeHook = useSubThemeProvider(element);\n\n\tif (!subThemeHook) {\n\t\treturn <>{children}</>;\n\t}\n\n\treturn (\n\t\t<ThemeProvider theme={(parentTheme) => createTheme(parentTheme, subThemeHook(parentTheme, data))}>\n\t\t\t{children}\n\t\t</ThemeProvider>\n\t);\n}\n","import { useModelLabel } from \"@judo/i18n\";\nimport type { TabController, Tab as TabElement } from \"@judo/model-api\";\nimport { getTabControllerTestId, getTabListTestId, getTabPanelTestId, getTabTestId } from \"@judo/test-ids\";\nimport { Box, Tab, Tabs } from \"@mui/material\";\nimport { useState } from \"react\";\nimport { VisualElementRenderer } from \"./VisualElementRenderer\";\n\nexport interface TabControllerRendererProps {\n\telement: TabController;\n\treadOnly?: boolean;\n}\n\n/**\n * Renderer for TabController elements.\n */\nexport function TabControllerRenderer({ element, readOnly }: TabControllerRendererProps) {\n\tconst [activeTab, setActiveTab] = useState(0);\n\n\tconst controllerTestId = getTabControllerTestId(element);\n\tconst controllerId = element.sourceId ?? element[\"xmi:id\"] ?? \"unknown\";\n\tconst tabListTestId = getTabListTestId(controllerId);\n\n\treturn (\n\t\t<Box data-testid={controllerTestId}>\n\t\t\t<Tabs\n\t\t\t\tvalue={activeTab}\n\t\t\t\tonChange={(_, v) => setActiveTab(v)}\n\t\t\t\torientation={element.orientation === \"VERTICAL\" ? \"vertical\" : \"horizontal\"}\n\t\t\t\tdata-testid={tabListTestId}\n\t\t\t>\n\t\t\t\t{element.tabs.map((tab, index) => {\n\t\t\t\t\tconst tabTestId = getTabTestId(controllerId, tab, index);\n\t\t\t\t\treturn <TranslatedTab key={tab[\"xmi:id\"] ?? index} tab={tab} testId={tabTestId} />;\n\t\t\t\t})}\n\t\t\t</Tabs>\n\n\t\t\t{element.tabs.map((tab, index) => {\n\t\t\t\tconst panelTestId = getTabPanelTestId(controllerId, tab, index);\n\t\t\t\treturn (\n\t\t\t\t\t<Box\n\t\t\t\t\t\tkey={tab[\"xmi:id\"] ?? index}\n\t\t\t\t\t\trole=\"tabpanel\"\n\t\t\t\t\t\thidden={activeTab !== index}\n\t\t\t\t\t\tp={2}\n\t\t\t\t\t\tdata-testid={panelTestId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{activeTab === index && tab.element && <VisualElementRenderer element={tab.element} readOnly={readOnly} />}\n\t\t\t\t\t</Box>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Box>\n\t);\n}\n\n/** Tab with translated label via useModelLabel. */\nfunction TranslatedTab({ tab, testId }: { tab: TabElement; testId: string }) {\n\tconst { label } = useModelLabel(tab);\n\treturn <Tab label={label} data-testid={testId} />;\n}\n","import {\n\tuseComponentInterceptor,\n\tuseComponentOverride,\n\tuseElementVisibility,\n\tusePageContextOptional,\n} from \"@judo/core\";\nimport type {\n\tButton as ButtonElement,\n\tButtonGroup as ButtonGroupElement,\n\tFlex,\n\tFormatted,\n\tInput,\n\tLink,\n\tTabController,\n\tTable,\n\tVisualElement,\n} from \"@judo/model-api\";\nimport { InputRenderer } from \"../inputs/InputRenderer\";\nimport { FlexRenderer } from \"./FlexRenderer\";\nimport { FormattedRenderer } from \"./FormattedRenderer\";\nimport { InlineButtonGroupRenderer } from \"./InlineButtonGroupRenderer\";\nimport { LinkRenderer } from \"./LinkRenderer\";\nimport { StandaloneButtonRenderer } from \"./StandaloneButtonRenderer\";\nimport { SubThemeWrapper } from \"./SubThemeWrapper\";\nimport { TabControllerRenderer } from \"./TabControllerRenderer\";\nimport { TableRenderer } from \"./TableRenderer\";\n\nexport interface VisualElementRendererProps {\n\telement: VisualElement;\n\treadOnly?: boolean;\n}\n\n/**\n * Dispatcher for all visual element types.\n * Checks for overrides in priority order:\n * 1. sourceId-based override (CustomizationsConfig.components)\n * 2. type-based interceptor (CustomizationsConfig.componentInterceptors)\n * 3. Default rendering by @type\n *\n * When the element has a `subTheme` set and a matching provider is registered,\n * the rendered output is wrapped in a scoped MUI ThemeProvider via SubThemeWrapper.\n */\nexport function VisualElementRenderer({ element, readOnly }: VisualElementRendererProps) {\n\t// Check element visibility (hiddenBy dynamic data, static hidden, customization overrides)\n\tconst hidden = useElementVisibility(element);\n\tif (hidden) {\n\t\treturn null;\n\t}\n\n\t// 1. Check for sourceId-based custom component override (highest priority)\n\tconst CustomComponent = useComponentOverride(element);\n\tconst pageContext = usePageContextOptional();\n\tif (CustomComponent) {\n\t\tconst page = pageContext?.pageDefinition;\n\t\tif (!page) return null;\n\t\treturn (\n\t\t\t<SubThemeWrapper element={element}>\n\t\t\t\t<CustomComponent element={element} page={page} />\n\t\t\t</SubThemeWrapper>\n\t\t);\n\t}\n\n\t// 2. Check for type-based interceptor\n\tconst InterceptedComponent = useComponentInterceptor(element);\n\tif (InterceptedComponent) {\n\t\tconst page = pageContext?.pageDefinition;\n\t\tif (!page) return null;\n\t\treturn (\n\t\t\t<SubThemeWrapper element={element}>\n\t\t\t\t<InterceptedComponent element={element} page={page} />\n\t\t\t</SubThemeWrapper>\n\t\t);\n\t}\n\n\t// 3. Default rendering by @type\n\tconst content = renderByType(element, readOnly);\n\tif (!content) return null;\n\n\treturn <SubThemeWrapper element={element}>{content}</SubThemeWrapper>;\n}\n\n/**\n * Default rendering dispatch by element @type.\n */\nfunction renderByType(element: VisualElement, readOnly?: boolean): React.ReactNode {\n\tswitch (element[\"@type\"]) {\n\t\tcase \"Flex\":\n\t\tcase \"PageContainer\":\n\t\t\treturn <FlexRenderer element={element as Flex} readOnly={readOnly} />;\n\n\t\tcase \"Table\":\n\t\t\treturn <TableRenderer element={element as Table} />;\n\n\t\tcase \"Link\":\n\t\t\treturn <LinkRenderer element={element as Link} readOnly={readOnly} />;\n\n\t\tcase \"ButtonGroup\":\n\t\t\treturn <InlineButtonGroupRenderer element={element as ButtonGroupElement} />;\n\n\t\tcase \"Button\":\n\t\t\t// Standalone buttons (e.g., relation navigation buttons like \"View Matter Table\")\n\t\t\treturn <StandaloneButtonRenderer element={element as ButtonElement} />;\n\n\t\tcase \"TabController\":\n\t\t\treturn <TabControllerRenderer element={element as TabController} readOnly={readOnly} />;\n\n\t\t// Input types\n\t\tcase \"TextInput\":\n\t\tcase \"NumericInput\":\n\t\tcase \"DateInput\":\n\t\tcase \"DateTimeInput\":\n\t\tcase \"TimeInput\":\n\t\tcase \"EnumerationCombo\":\n\t\tcase \"EnumerationRadio\":\n\t\tcase \"EnumerationToggleButtonbar\":\n\t\tcase \"Checkbox\":\n\t\tcase \"Switch\":\n\t\tcase \"TrinaryLogicCombo\":\n\t\tcase \"TextArea\":\n\t\tcase \"BinaryTypeInput\":\n\t\tcase \"PasswordInput\":\n\t\t\treturn <InputRenderer element={element as Input} readOnly={readOnly} />;\n\n\t\tcase \"Spacer\":\n\t\t\treturn <div style={{ flex: 1 }} data-testid={`spacer::${element[\"xmi:id\"]}`} />;\n\n\t\tcase \"Divider\":\n\t\t\treturn <hr data-testid={`divider::${element[\"xmi:id\"]}`} />;\n\n\t\tcase \"Formatted\":\n\t\t\treturn <FormattedRenderer element={element as Formatted} />;\n\n\t\tdefault:\n\t\t\tconsole.warn(`Unknown element type: ${element[\"@type\"]}`);\n\t\t\treturn null;\n\t}\n}\n","import { useElementVisibility } from \"@judo/core\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { Flex, VisualElement } from \"@judo/model-api\";\nimport Grid from \"@mui/material/Grid\";\nimport Stack from \"@mui/material/Stack\";\nimport { mapCrossAxisAlignment, mapMainAxisAlignment } from \"../utils/alignment-mappers\";\nimport { DEFAULT_COL, type GridSize, calculateChildGridSize, isVerticalLayout } from \"../utils/flex-layout\";\nimport { FrameRenderer } from \"./FrameRenderer\";\nimport { VisualElementRenderer } from \"./VisualElementRenderer\";\nimport \"../styles.css\";\n\nexport interface FlexRendererProps {\n\telement: Flex;\n\treadOnly?: boolean;\n}\n\n/**\n * Renderer for Flex layout containers.\n * - Horizontal layouts: Use MUI Grid2 for responsive 12-column grid layout\n * - Vertical layouts: Use MUI Stack with force-full-width class\n * Each child's `col` property (1-12) is scaled based on parent's column span.\n */\nexport function FlexRenderer({ element, readOnly }: FlexRendererProps) {\n\tconst isVertical = isVerticalLayout(element.direction);\n\tconst justifyContent = mapMainAxisAlignment(element.mainAxisAlignment);\n\tconst alignItems = mapCrossAxisAlignment(element.crossAxisAlignment);\n\n\t// Get parent's column span for size calculation\n\tconst parentCol = element.col ?? DEFAULT_COL;\n\n\t// Common size constraints\n\tconst sizeStyles = {\n\t\twidth: element.size?.width ?? \"100%\",\n\t\theight: element.size?.height,\n\t\tminWidth: element.sizeConstraint?.minWidth,\n\t\tminHeight: element.sizeConstraint?.minHeight,\n\t\tmaxWidth: element.sizeConstraint?.maxWidth ?? \"100%\",\n\t\tmaxHeight: element.sizeConstraint?.maxHeight,\n\t};\n\n\t// Render children with Grid wrappers (using FlexChild to handle hiddenBy without Grid gaps)\n\tconst children = element.children?.map((child) => {\n\t\tconst childCol = child.col ?? DEFAULT_COL;\n\t\tconst gridSize = calculateChildGridSize(element.direction, parentCol, childCol);\n\n\t\treturn <FlexChild key={child[\"xmi:id\"]} child={child} gridSize={gridSize} readOnly={readOnly} />;\n\t});\n\n\tconst content = isVertical ? (\n\t\t<Stack\n\t\t\tspacing={2}\n\t\t\tclassName=\"force-full-width\"\n\t\t\tdata-testid={`flex::${element.sourceId ?? element[\"xmi:id\"]}`}\n\t\t\tsx={sizeStyles}\n\t\t>\n\t\t\t{children}\n\t\t</Stack>\n\t) : (\n\t\t<Grid\n\t\t\tcontainer\n\t\t\tjustifyContent={justifyContent}\n\t\t\talignItems={alignItems}\n\t\t\tspacing={2}\n\t\t\tdata-testid={`flex::${element.sourceId ?? element[\"xmi:id\"]}`}\n\t\t\tsx={sizeStyles}\n\t\t>\n\t\t\t{children}\n\t\t</Grid>\n\t);\n\n\t// Wrap in frame if specified, passing label and icon for header\n\tif (element.frame) {\n\t\treturn <TranslatedFrame element={element}>{content}</TranslatedFrame>;\n\t}\n\n\treturn content;\n}\n\n/** Frame wrapper that translates the label via useModelLabel. */\nfunction TranslatedFrame({ element, children }: { element: Flex; children: React.ReactNode }) {\n\tconst { label } = useModelLabel(element);\n\treturn (\n\t\t<FrameRenderer frame={element.frame!} label={label} icon={element.icon}>\n\t\t\t{children}\n\t\t</FrameRenderer>\n\t);\n}\n\n/**\n * Wrapper component for Flex children that handles visibility.\n * When a child element is hidden (via hiddenBy), both the Grid wrapper\n * and the element are removed from the layout to avoid empty grid gaps.\n */\nfunction FlexChild({ child, gridSize, readOnly }: { child: VisualElement; gridSize: GridSize; readOnly?: boolean }) {\n\tconst hidden = useElementVisibility(child);\n\tif (hidden) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Grid size={gridSize} sx={{ minWidth: 0 }}>\n\t\t\t<VisualElementRenderer element={child} readOnly={readOnly} />\n\t\t</Grid>\n\t);\n}\n"],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { t as FlexRenderer } from "./FlexRenderer-0KCxU9QU.js";
2
+ import { s as PageHeader, t as findOnInitAction } from "./find-on-init-action-C5CqxQaH.js";
3
+ import { Box } from "@mui/material";
4
+ import { useEffect, useMemo, useRef } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { useActionDispatcher, useApi } from "@judo/actions";
7
+ import { DispatchProvider, useApplication, useDataStore, useNavigation, usePageContext, useResolvedPageActionOverrides } from "@judo/core";
8
+ import { useNotifications } from "@judo/feedback";
9
+ function FormContainerRenderer({ page: v }) {
10
+ let y = v.container, b = usePageContext(), x = useNavigation(), S = useDataStore(), C = useApplication(), w = useApi(), T = useNotifications(), E = useResolvedPageActionOverrides(), D = useMemo(() => findOnInitAction(v, y), [v, y]), O = b?.params?.isCreate === !0, k = b?.params?.isEager === !0, A = b?.params?.relation, j = b?.params?.ownerTransfer, M = b?.params?.parentTransferId, N = b?.params?.relationName, { dispatch: P } = useActionDispatcher(useMemo(() => ({
11
+ navigation: x,
12
+ data: S,
13
+ registry: C,
14
+ api: w,
15
+ notifications: T,
16
+ additionalContext: {
17
+ pageTransferId: b?.transferId,
18
+ pageType: "FORM",
19
+ isEditMode: !0,
20
+ isEager: k,
21
+ createDialog: O ? {
22
+ relation: A,
23
+ ownerTransfer: j,
24
+ isEager: k,
25
+ parentTransferId: M,
26
+ relationName: N
27
+ } : void 0
28
+ },
29
+ actionOverrides: E
30
+ }), [
31
+ x,
32
+ S,
33
+ C,
34
+ w,
35
+ T,
36
+ b?.transferId,
37
+ O,
38
+ k,
39
+ A,
40
+ j,
41
+ M,
42
+ N,
43
+ E
44
+ ])), F = useRef(!1), I = useRef(P);
45
+ I.current = P, useEffect(() => {
46
+ F.current || D && (F.current = !0, I.current(D).catch((n) => {
47
+ console.error("[FormContainerRenderer] Error dispatching onInit action:", n);
48
+ }));
49
+ }, [D]);
50
+ let L = y.children?.[0], R = !b?.isDialog;
51
+ return /* @__PURE__ */ jsx(DispatchProvider, {
52
+ dispatch: P,
53
+ children: /* @__PURE__ */ jsxs(Box, {
54
+ "data-testid": `form-container::${y.name ?? y["xmi:id"]}`,
55
+ sx: { animation: "judoFadeInUp 0.4s cubic-bezier(0.4,0,0.2,1) both" },
56
+ children: [R && /* @__PURE__ */ jsx(PageHeader, {
57
+ page: v,
58
+ onDispatch: P
59
+ }), L && /* @__PURE__ */ jsx(FlexRenderer, {
60
+ element: L,
61
+ readOnly: !1
62
+ })]
63
+ })
64
+ });
65
+ }
66
+ var FormContainerRenderer_default = FormContainerRenderer;
67
+ export { FormContainerRenderer_default as n, FormContainerRenderer as t };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormContainerRenderer-B8H4kyz0.js","names":[],"sources":["../src/containers/FormContainerRenderer.tsx"],"sourcesContent":["import { useActionDispatcher, useApi } from \"@judo/actions\";\nimport {\n\tDispatchProvider,\n\tuseApplication,\n\tuseDataStore,\n\tuseNavigation,\n\tusePageContext,\n\tuseResolvedPageActionOverrides,\n} from \"@judo/core\";\nimport { useNotifications } from \"@judo/feedback\";\nimport type { Flex, PageContainer, PageDefinition } from \"@judo/model-api\";\nimport { Box } from \"@mui/material\";\nimport { useEffect, useMemo, useRef } from \"react\";\nimport { FlexRenderer } from \"../renderers/FlexRenderer\";\nimport { PageHeader } from \"../renderers/PageHeader\";\nimport { findOnInitAction } from \"../utils/find-on-init-action\";\n\nexport interface FormContainerRendererProps {\n\tpage: PageDefinition;\n}\n\n/**\n * Renderer for FORM type containers.\n * Handles onInit action (GetTemplate) on mount to fetch default values for new transfers.\n */\nexport function FormContainerRenderer({ page }: FormContainerRendererProps) {\n\tconst container = page.container as PageContainer;\n\n\t// Get page context to access transfer ID and params\n\tconst pageContext = usePageContext();\n\n\t// Get required contexts for action dispatcher\n\tconst navigation = useNavigation();\n\tconst dataStore = useDataStore();\n\tconst application = useApplication();\n\tconst api = useApi();\n\tconst notifications = useNotifications();\n\n\t// Get resolved page action overrides from customizations\n\tconst actionOverrides = useResolvedPageActionOverrides();\n\n\t// Find the onInit action\n\tconst onInitAction = useMemo(() => findOnInitAction(page, container), [page, container]);\n\n\t// Extract create dialog context from page params\n\tconst isCreate = pageContext?.params?.isCreate === true;\n\tconst isEager = pageContext?.params?.isEager === true;\n\tconst relation = pageContext?.params?.relation;\n\tconst ownerTransfer = pageContext?.params?.ownerTransfer;\n\t// For eager creates, extract parent context to know where to add created transfer\n\tconst parentTransferId = pageContext?.params?.parentTransferId as string | undefined;\n\tconst relationName = pageContext?.params?.relationName as string | undefined;\n\n\t// Memoize dispatcher context\n\tconst dispatcherContext = useMemo(\n\t\t() =>\n\t\t\t({\n\t\t\t\tnavigation,\n\t\t\t\tdata: dataStore,\n\t\t\t\tregistry: application,\n\t\t\t\tapi,\n\t\t\t\tnotifications,\n\t\t\t\tadditionalContext: {\n\t\t\t\t\tpageTransferId: pageContext?.transferId,\n\t\t\t\t\tpageType: \"FORM\",\n\t\t\t\t\tisEditMode: true,\n\t\t\t\t\tisEager,\n\t\t\t\t\t// Pass create dialog context for CreateActionHandler\n\t\t\t\t\tcreateDialog: isCreate\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\trelation,\n\t\t\t\t\t\t\t\townerTransfer,\n\t\t\t\t\t\t\t\tisEager,\n\t\t\t\t\t\t\t\t// For eager creates, include parent context\n\t\t\t\t\t\t\t\tparentTransferId,\n\t\t\t\t\t\t\t\trelationName,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\tactionOverrides,\n\t\t\t}) as unknown as Parameters<typeof useActionDispatcher>[0],\n\t\t[\n\t\t\tnavigation,\n\t\t\tdataStore,\n\t\t\tapplication,\n\t\t\tapi,\n\t\t\tnotifications,\n\t\t\tpageContext?.transferId,\n\t\t\tisCreate,\n\t\t\tisEager,\n\t\t\trelation,\n\t\t\townerTransfer,\n\t\t\tparentTransferId,\n\t\t\trelationName,\n\t\t\tactionOverrides,\n\t\t]\n\t);\n\n\t// Initialize action dispatcher\n\tconst { dispatch } = useActionDispatcher(dispatcherContext);\n\n\t// Use ref to track if onInit has been dispatched (avoid duplicate calls on strict mode re-renders)\n\tconst hasDispatchedOnInit = useRef(false);\n\t// Use ref to store dispatch function to avoid it changing in effect deps\n\tconst dispatchRef = useRef(dispatch);\n\tdispatchRef.current = dispatch;\n\n\t// Call onInit (GetTemplate) when form mounts to fetch default values\n\tuseEffect(() => {\n\t\tif (hasDispatchedOnInit.current) return;\n\n\t\tif (onInitAction) {\n\t\t\thasDispatchedOnInit.current = true;\n\n\t\t\t// Dispatch the GetTemplate action to fetch default values\n\t\t\tdispatchRef.current(onInitAction).catch((error) => {\n\t\t\t\tconsole.error(\"[FormContainerRenderer] Error dispatching onInit action:\", error);\n\t\t\t});\n\t\t}\n\t}, [onInitAction]);\n\n\tconst firstChild = container.children?.[0] as Flex | undefined;\n\n\t// Don't render PageHeader in dialogs - dialog handles its own title and actions\n\tconst showPageHeader = !pageContext?.isDialog;\n\n\treturn (\n\t\t<DispatchProvider dispatch={dispatch}>\n\t\t\t<Box\n\t\t\t\tdata-testid={`form-container::${container.name ?? container[\"xmi:id\"]}`}\n\t\t\t\tsx={{ animation: \"judoFadeInUp 0.4s cubic-bezier(0.4,0,0.2,1) both\" }}\n\t\t\t>\n\t\t\t\t{showPageHeader && <PageHeader page={page} onDispatch={dispatch} />}\n\n\t\t\t\t{/* Form content - render children from visual model */}\n\t\t\t\t{firstChild && <FlexRenderer element={firstChild} readOnly={false} />}\n\t\t\t</Box>\n\t\t</DispatchProvider>\n\t);\n}\n\nexport default FormContainerRenderer;\n"],"mappings":";;;;;;;;AAyBA,SAAgB,sBAAsB,EAAE,WAAoC;CAC3E,IAAM,IAAY,EAAK,WAGjB,IAAc,gBAAgB,EAG9B,IAAa,eAAe,EAC5B,IAAY,cAAc,EAC1B,IAAc,gBAAgB,EAC9B,IAAM,QAAQ,EACd,IAAgB,kBAAkB,EAGlC,IAAkB,gCAAgC,EAGlD,IAAe,cAAc,iBAAiB,GAAM,EAAU,EAAE,CAAC,GAAM,EAAU,CAAC,EAGlF,IAAW,GAAa,QAAQ,aAAa,IAC7C,IAAU,GAAa,QAAQ,YAAY,IAC3C,IAAW,GAAa,QAAQ,UAChC,IAAgB,GAAa,QAAQ,eAErC,IAAmB,GAAa,QAAQ,kBACxC,IAAe,GAAa,QAAQ,cAgDpC,EAAE,gBAAa,oBA7CK,eAEvB;EACA;EACA,MAAM;EACN,UAAU;EACV;EACA;EACA,mBAAmB;GAClB,gBAAgB,GAAa;GAC7B,UAAU;GACV,YAAY;GACZ;GAEA,cAAc,IACX;IACA;IACA;IACA;IAEA;IACA;IACA,GACA,KAAA;GACH;EACD;EACA,GACF;EACC;EACA;EACA;EACA;EACA;EACA,GAAa;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA,CACD,CAG0D,EAGrD,IAAsB,OAAO,GAAM,EAEnC,IAAc,OAAO,EAAS;AAIpC,CAHA,EAAY,UAAU,GAGtB,gBAAgB;AACX,IAAoB,WAEpB,MACH,EAAoB,UAAU,IAG9B,EAAY,QAAQ,EAAa,CAAC,OAAO,MAAU;AAClD,WAAQ,MAAM,4DAA4D,EAAM;IAC/E;IAED,CAAC,EAAa,CAAC;CAElB,IAAM,IAAa,EAAU,WAAW,IAGlC,IAAiB,CAAC,GAAa;AAErC,QACC,oBAAC,kBAAA;EAA2B;YAC3B,qBAAC,KAAA;GACA,eAAa,mBAAmB,EAAU,QAAQ,EAAU;GAC5D,IAAI,EAAE,WAAW,oDAAoD;cAEpE,KAAkB,oBAAC,YAAA;IAAiB;IAAM,YAAY;KAAY,EAGlE,KAAc,oBAAC,cAAA;IAAa,SAAS;IAAY,UAAU;KAAS,CAAA;IAChE;GACY;;AAIrB,IAAA,gCAAe"}
@@ -0,0 +1,3 @@
1
+ import "./FlexRenderer-0KCxU9QU.js";
2
+ import { n as FormContainerRenderer_default, t as FormContainerRenderer } from "./FormContainerRenderer-B8H4kyz0.js";
3
+ export { FormContainerRenderer, FormContainerRenderer_default as default };
@@ -0,0 +1,127 @@
1
+ import { n as TableRenderer, s as PageHeader, t as findOnInitAction } from "./find-on-init-action-C5CqxQaH.js";
2
+ import { Box } from "@mui/material";
3
+ import { useEffect, useMemo, useRef } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { useActionDispatcher, useApi } from "@judo/actions";
6
+ import { DispatchProvider, useApplication, useDataStore, useNavigation, usePageContext, useResolvedPageActionOverrides, useRuntimeConfigOptional } from "@judo/core";
7
+ import { useNotifications } from "@judo/feedback";
8
+ function findVisualElementByType(e, v) {
9
+ let y = Array.isArray(e) ? e : [e];
10
+ for (let e of y) {
11
+ if (e["@type"] === v) return e;
12
+ if (hasChildren(e)) {
13
+ let y = findVisualElementByType(e.children, v);
14
+ if (y) return y;
15
+ }
16
+ }
17
+ }
18
+ function findVisualElementById(e, v) {
19
+ let y = Array.isArray(e) ? e : [e];
20
+ for (let e of y) {
21
+ if (e["xmi:id"] === v) return e;
22
+ if (hasChildren(e)) {
23
+ let y = findVisualElementById(e.children, v);
24
+ if (y) return y;
25
+ }
26
+ }
27
+ }
28
+ function findVisualElementBySourceId(e, v) {
29
+ let y = Array.isArray(e) ? e : [e];
30
+ for (let e of y) {
31
+ if (e.sourceId === v) return e;
32
+ if (hasChildren(e)) {
33
+ let y = findVisualElementBySourceId(e.children, v);
34
+ if (y) return y;
35
+ }
36
+ }
37
+ }
38
+ function flattenVisualElements(e) {
39
+ let v = Array.isArray(e) ? e : [e], y = [];
40
+ for (let e of v) y.push(e), hasChildren(e) && y.push(...flattenVisualElements(e.children));
41
+ return y;
42
+ }
43
+ function hasChildren(e) {
44
+ return "children" in e && Array.isArray(e.children);
45
+ }
46
+ function TableContainerRenderer({ page: b }) {
47
+ let x = b.container, S = usePageContext(), C = useNavigation(), w = useDataStore(), T = useApplication(), E = useApi(), D = useNotifications(), O = findVisualElementByType(x.children, "Table"), k = O?.rowsPerPage && O.rowsPerPage > 0 ? O.rowsPerPage : 10, A = useResolvedPageActionOverrides(), j = useMemo(() => {
48
+ let e = findOnInitAction(b, x);
49
+ if (e && e.actionDefinition["@type"] === "RefreshActionDefinition" && !e.actionDefinition.targetType) {
50
+ let v = b.dataElement || x.dataElement;
51
+ if (v) {
52
+ let y;
53
+ y = v["@type"] === "RelationType" ? v.target : v, y ? e.actionDefinition.targetType = y : console.error("[TableContainerRenderer] Failed to set valid targetType - could not derive from dataElement");
54
+ }
55
+ }
56
+ return e;
57
+ }, [b, x]), M = useRuntimeConfigOptional(), N = useMemo(() => !O?.isEager && (M?.config.features?.forceShowTotalCountForLazyTables ?? !1) ? !0 : O?.showTotalCount ?? !1, [
58
+ O?.isEager,
59
+ O?.showTotalCount,
60
+ M
61
+ ]), P = String(b.isSelector) === "true", F = S?.params?.ownerTransfer, I = S?.params?.isOperationInput === !0, L = useMemo(() => {
62
+ let e = S?.transferId, v = S?.params?.signedIdentifier;
63
+ if (!(!e || !v)) return {
64
+ __identifier: e,
65
+ __signedIdentifier: v
66
+ };
67
+ }, [S?.transferId, S?.params]), { dispatch: R } = useActionDispatcher(useMemo(() => ({
68
+ navigation: C,
69
+ data: w,
70
+ registry: T,
71
+ api: E,
72
+ transfer: L,
73
+ notifications: D,
74
+ actionOverrides: A,
75
+ additionalContext: {
76
+ pageTransferId: S.transferId,
77
+ rowsPerPage: k,
78
+ ...P ? {
79
+ isSelector: !0,
80
+ ownerTransfer: F,
81
+ ...I ? { isOperationInput: !0 } : {}
82
+ } : {}
83
+ }
84
+ }), [
85
+ C,
86
+ w,
87
+ T,
88
+ E,
89
+ L,
90
+ D,
91
+ S.transferId,
92
+ k,
93
+ A,
94
+ P,
95
+ F,
96
+ I
97
+ ])), z = useRef(!1), B = useRef(R);
98
+ if (B.current = R, useEffect(() => {
99
+ z.current || j && (z.current = !0, B.current({
100
+ ...j,
101
+ ...N ? { countRecords: !0 } : {}
102
+ }).catch((e) => {
103
+ console.error("[TableContainerRenderer] Error dispatching onInit action:", e);
104
+ }));
105
+ }, [j, N]), !O) return /* @__PURE__ */ jsx(Box, {
106
+ p: 2,
107
+ "data-testid": "table-container::no-table",
108
+ children: "No table element found in container"
109
+ });
110
+ let V = !S?.isDialog;
111
+ return /* @__PURE__ */ jsx(DispatchProvider, {
112
+ dispatch: R,
113
+ children: /* @__PURE__ */ jsxs(Box, {
114
+ "data-testid": `table-container::${x.name ?? x["xmi:id"]}`,
115
+ sx: { animation: "judoFadeInUp 0.4s cubic-bezier(0.4,0,0.2,1) both" },
116
+ children: [V && /* @__PURE__ */ jsx(PageHeader, {
117
+ page: b,
118
+ onDispatch: R
119
+ }), /* @__PURE__ */ jsx(TableRenderer, {
120
+ element: O,
121
+ page: b
122
+ })]
123
+ })
124
+ });
125
+ }
126
+ var TableContainerRenderer_default = TableContainerRenderer;
127
+ export { findVisualElementByType as a, findVisualElementBySourceId as i, TableContainerRenderer_default as n, flattenVisualElements as o, findVisualElementById as r, TableContainerRenderer as t };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TableContainerRenderer-gKBlsD4S.js","names":["result: VisualElement[]","targetType: ClassType | undefined"],"sources":["../src/utils/find-visual-element.ts","../src/containers/TableContainerRenderer.tsx"],"sourcesContent":["import type { Container, VisualElement } from \"@judo/model-api\";\n\n/**\n * Find visual element by its @type property.\n */\nexport function findVisualElementByType<T extends VisualElement = VisualElement>(\n\telements: VisualElement | VisualElement[],\n\ttype: string\n): T | undefined {\n\tconst elementArray = Array.isArray(elements) ? elements : [elements];\n\n\tfor (const element of elementArray) {\n\t\tif (element[\"@type\"] === type) {\n\t\t\treturn element as T;\n\t\t}\n\t\t// Recursively search children if this is a container\n\t\tif (hasChildren(element)) {\n\t\t\tconst found = findVisualElementByType<T>(element.children, type);\n\t\t\tif (found) {\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Find visual element by its xmi:id.\n */\nexport function findVisualElementById<T extends VisualElement = VisualElement>(\n\telements: VisualElement | VisualElement[],\n\tid: string\n): T | undefined {\n\tconst elementArray = Array.isArray(elements) ? elements : [elements];\n\n\tfor (const element of elementArray) {\n\t\tif (element[\"xmi:id\"] === id) {\n\t\t\treturn element as T;\n\t\t}\n\t\t// Recursively search children\n\t\tif (hasChildren(element)) {\n\t\t\tconst found = findVisualElementById<T>(element.children, id);\n\t\t\tif (found) {\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Find visual element by its sourceId.\n */\nexport function findVisualElementBySourceId<T extends VisualElement = VisualElement>(\n\telements: VisualElement | VisualElement[],\n\tsourceId: string\n): T | undefined {\n\tconst elementArray = Array.isArray(elements) ? elements : [elements];\n\n\tfor (const element of elementArray) {\n\t\tif (element.sourceId === sourceId) {\n\t\t\treturn element as T;\n\t\t}\n\t\t// Recursively search children\n\t\tif (hasChildren(element)) {\n\t\t\tconst found = findVisualElementBySourceId<T>(element.children, sourceId);\n\t\t\tif (found) {\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Flatten visual element tree to array.\n */\nexport function flattenVisualElements(elements: VisualElement | VisualElement[]): VisualElement[] {\n\tconst elementArray = Array.isArray(elements) ? elements : [elements];\n\tconst result: VisualElement[] = [];\n\n\tfor (const element of elementArray) {\n\t\tresult.push(element);\n\t\tif (hasChildren(element)) {\n\t\t\tresult.push(...flattenVisualElements(element.children));\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Type guard to check if element has children.\n */\nfunction hasChildren(element: VisualElement): element is Container {\n\treturn \"children\" in element && Array.isArray((element as Container).children);\n}\n","import { useActionDispatcher, useApi } from \"@judo/actions\";\nimport {\n\tDispatchProvider,\n\tuseApplication,\n\tuseDataStore,\n\tuseNavigation,\n\tusePageContext,\n\tuseResolvedPageActionOverrides,\n\tuseRuntimeConfigOptional,\n} from \"@judo/core\";\nimport { useNotifications } from \"@judo/feedback\";\nimport type { ClassType, PageContainer, PageDefinition, RelationType, Table } from \"@judo/model-api\";\nimport { Box } from \"@mui/material\";\nimport { useEffect, useMemo, useRef } from \"react\";\nimport { PageHeader } from \"../renderers/PageHeader\";\nimport { TableRenderer } from \"../renderers/TableRenderer\";\nimport { findOnInitAction } from \"../utils/find-on-init-action\";\nimport { findVisualElementByType } from \"../utils/find-visual-element\";\n\nexport interface TableContainerRendererProps {\n\tpage: PageDefinition;\n}\n\n/**\n * Renderer for TABLE type containers.\n * Fetches table data on mount via onInit action (Refresh).\n */\nexport function TableContainerRenderer({ page }: TableContainerRendererProps) {\n\t// Container is already resolved in page\n\tconst container = page.container as PageContainer;\n\n\t// Get page context to access transfer ID\n\tconst pageContext = usePageContext();\n\n\t// Get required contexts for action dispatcher\n\tconst navigation = useNavigation();\n\tconst dataStore = useDataStore();\n\tconst application = useApplication();\n\tconst api = useApi();\n\tconst notifications = useNotifications();\n\n\t// Find Table visual element in container children\n\tconst tableElement = findVisualElementByType<Table>(container.children, \"Table\");\n\n\t// Get rowsPerPage (defaults to 10 if not specified or invalid)\n\tconst rowsPerPage = tableElement?.rowsPerPage && tableElement.rowsPerPage > 0 ? tableElement.rowsPerPage : 10;\n\n\t// Get resolved page action overrides from customizations\n\tconst actionOverrides = useResolvedPageActionOverrides();\n\n\t// Find the onInit action (Refresh action for loading table data)\n\tconst onInitAction = useMemo(() => {\n\t\tconst action = findOnInitAction(page, container);\n\n\t\t// If action exists and has a RefreshActionDefinition, ensure targetType is set\n\t\tif (action && action.actionDefinition[\"@type\"] === \"RefreshActionDefinition\") {\n\t\t\tconst existingTargetType = action.actionDefinition.targetType;\n\n\t\t\t// If no targetType is set, derive it from the dataElement\n\t\t\tif (!existingTargetType) {\n\t\t\t\t// Prefer page.dataElement, fallback to container.dataElement\n\t\t\t\tconst dataElement = page.dataElement || container.dataElement;\n\n\t\t\t\tif (dataElement) {\n\t\t\t\t\t// For RelationType (relation tables), use the target ClassType\n\t\t\t\t\t// For ClassType, use it directly\n\t\t\t\t\tlet targetType: ClassType | undefined;\n\n\t\t\t\t\tif (dataElement[\"@type\"] === \"RelationType\") {\n\t\t\t\t\t\tconst relation = dataElement as RelationType;\n\t\t\t\t\t\ttargetType = relation.target;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttargetType = dataElement as ClassType;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Mutate the action definition to add targetType (parser should do this, but doesn't)\n\t\t\t\t\tif (targetType) {\n\t\t\t\t\t\taction.actionDefinition.targetType = targetType;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t\"[TableContainerRenderer] Failed to set valid targetType - could not derive from dataElement\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn action;\n\t}, [page, container]);\n\n\t// Get runtime config to check for forceShowTotalCountForLazyTables\n\tconst runtimeConfig = useRuntimeConfigOptional();\n\n\t// Compute effective showTotalCount for the onInit dispatch\n\t// This mirrors the logic in TableRenderer.effectiveShowTotalCount\n\tconst effectiveShowTotalCount = useMemo(() => {\n\t\tconst isLazyTable = !tableElement?.isEager;\n\t\tconst forceEnabled = runtimeConfig?.config.features?.forceShowTotalCountForLazyTables ?? false;\n\t\tif (isLazyTable && forceEnabled) return true;\n\t\treturn tableElement?.showTotalCount ?? false;\n\t}, [tableElement?.isEager, tableElement?.showTotalCount, runtimeConfig]);\n\n\t// Detect selector pages (opened via Add/Set selector actions)\n\tconst isSelector = String(page.isSelector) === \"true\";\n\tconst ownerTransfer = pageContext?.params?.ownerTransfer as Record<string, unknown> | undefined;\n\n\t// Detect operation input selector pages (opened via OpenOperationInputSelectorAction)\n\tconst isOperationInput = pageContext?.params?.isOperationInput === true;\n\n\t// Get transfer from page context for relation tables\n\t// Relation tables need the parent transfer's signedIdentifier to know which relations to load\n\tconst transfer = useMemo(() => {\n\t\tconst transferId = pageContext?.transferId;\n\t\tconst signedIdentifier = pageContext?.params?.signedIdentifier as string | undefined;\n\n\t\tif (!transferId || !signedIdentifier) return undefined;\n\n\t\treturn {\n\t\t\t__identifier: transferId,\n\t\t\t__signedIdentifier: signedIdentifier,\n\t\t};\n\t}, [pageContext?.transferId, pageContext?.params]);\n\n\t// Memoize dispatcher context - include pageTransferId and rowsPerPage in additionalContext\n\tconst dispatcherContext = useMemo(\n\t\t() =>\n\t\t\t({\n\t\t\t\tnavigation,\n\t\t\t\tdata: dataStore,\n\t\t\t\tregistry: application,\n\t\t\t\tapi,\n\t\t\t\ttransfer,\n\t\t\t\tnotifications,\n\t\t\t\tactionOverrides,\n\t\t\t\tadditionalContext: {\n\t\t\t\t\tpageTransferId: pageContext.transferId,\n\t\t\t\t\trowsPerPage,\n\t\t\t\t\t// Pass selector context so RefreshActionHandler can call getRelationRange / getOperationInputRange\n\t\t\t\t\t...(isSelector\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tisSelector: true,\n\t\t\t\t\t\t\t\townerTransfer,\n\t\t\t\t\t\t\t\t...(isOperationInput ? { isOperationInput: true } : {}),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t}) as unknown as Parameters<typeof useActionDispatcher>[0],\n\t\t[\n\t\t\tnavigation,\n\t\t\tdataStore,\n\t\t\tapplication,\n\t\t\tapi,\n\t\t\ttransfer,\n\t\t\tnotifications,\n\t\t\tpageContext.transferId,\n\t\t\trowsPerPage,\n\t\t\tactionOverrides,\n\t\t\tisSelector,\n\t\t\townerTransfer,\n\t\t\tisOperationInput,\n\t\t]\n\t);\n\n\t// Initialize action dispatcher\n\tconst { dispatch } = useActionDispatcher(dispatcherContext);\n\n\t// Use ref to track if onInit has been dispatched (avoid duplicate calls on strict mode re-renders)\n\tconst hasDispatchedOnInit = useRef(false);\n\t// Use ref to store dispatch function to avoid it changing in effect deps\n\tconst dispatchRef = useRef(dispatch);\n\tdispatchRef.current = dispatch;\n\n\t// Call onInit (Refresh) when table container mounts\n\tuseEffect(() => {\n\t\tif (hasDispatchedOnInit.current) return;\n\n\t\tif (onInitAction) {\n\t\t\thasDispatchedOnInit.current = true;\n\n\t\t\t// Dispatch the refresh action to load table data\n\t\t\t// Include countRecords when showTotalCount is effective (needed for pagination)\n\t\t\tdispatchRef\n\t\t\t\t.current({\n\t\t\t\t\t...onInitAction,\n\t\t\t\t\t...(effectiveShowTotalCount ? { countRecords: true } : {}),\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tconsole.error(\"[TableContainerRenderer] Error dispatching onInit action:\", error);\n\t\t\t\t});\n\t\t}\n\t}, [onInitAction, effectiveShowTotalCount]);\n\n\tif (!tableElement) {\n\t\treturn (\n\t\t\t<Box p={2} data-testid=\"table-container::no-table\">\n\t\t\t\tNo table element found in container\n\t\t\t</Box>\n\t\t);\n\t}\n\n\t// Don't render PageHeader in dialogs - dialog handles its own title and actions\n\tconst showPageHeader = !pageContext?.isDialog;\n\n\treturn (\n\t\t<DispatchProvider dispatch={dispatch}>\n\t\t\t<Box\n\t\t\t\tdata-testid={`table-container::${container.name ?? container[\"xmi:id\"]}`}\n\t\t\t\tsx={{ animation: \"judoFadeInUp 0.4s cubic-bezier(0.4,0,0.2,1) both\" }}\n\t\t\t>\n\t\t\t\t{showPageHeader && <PageHeader page={page} onDispatch={dispatch} />}\n\t\t\t\t<TableRenderer element={tableElement} page={page} />\n\t\t\t</Box>\n\t\t</DispatchProvider>\n\t);\n}\n\nexport default TableContainerRenderer;\n"],"mappings":"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"}