@aglyn/shared-ui-jsx-forms 1.0.0-beta.143

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 (150) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +52 -0
  4. package/src/index.d.ts +17 -0
  5. package/src/index.js +18 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/color-picker-tokens.d.ts +135 -0
  8. package/src/lib/components/color-picker-tokens.js +431 -0
  9. package/src/lib/components/color-picker-tokens.js.map +1 -0
  10. package/src/lib/components/color-picker.component.d.ts +64 -0
  11. package/src/lib/components/color-picker.component.js +322 -0
  12. package/src/lib/components/color-picker.component.js.map +1 -0
  13. package/src/lib/components/create-artifact-drawer.component.d.ts +100 -0
  14. package/src/lib/components/create-artifact-drawer.component.js +184 -0
  15. package/src/lib/components/create-artifact-drawer.component.js.map +1 -0
  16. package/src/lib/components/grid-form-template.component.d.ts +21 -0
  17. package/src/lib/components/grid-form-template.component.js +81 -0
  18. package/src/lib/components/grid-form-template.component.js.map +1 -0
  19. package/src/lib/components/icon-select.component.d.ts +52 -0
  20. package/src/lib/components/icon-select.component.js +453 -0
  21. package/src/lib/components/icon-select.component.js.map +1 -0
  22. package/src/lib/components/select.component.d.ts +58 -0
  23. package/src/lib/components/select.component.js +107 -0
  24. package/src/lib/components/select.component.js.map +1 -0
  25. package/src/lib/components/switch.component.d.ts +38 -0
  26. package/src/lib/components/switch.component.js +76 -0
  27. package/src/lib/components/switch.component.js.map +1 -0
  28. package/src/lib/components/text-field.component.d.ts +45 -0
  29. package/src/lib/components/text-field.component.js +77 -0
  30. package/src/lib/components/text-field.component.js.map +1 -0
  31. package/src/lib/components/textarea.component.d.ts +45 -0
  32. package/src/lib/components/textarea.component.js +61 -0
  33. package/src/lib/components/textarea.component.js.map +1 -0
  34. package/src/lib/components/toggle-button.component.d.ts +27 -0
  35. package/src/lib/components/toggle-button.component.js +116 -0
  36. package/src/lib/components/toggle-button.component.js.map +1 -0
  37. package/src/lib/constants/component-mappers.d.ts +42 -0
  38. package/src/lib/constants/component-mappers.js +70 -0
  39. package/src/lib/constants/component-mappers.js.map +1 -0
  40. package/src/lib/constants/dynamic-fields.d.ts +45 -0
  41. package/src/lib/constants/dynamic-fields.js +65 -0
  42. package/src/lib/constants/dynamic-fields.js.map +1 -0
  43. package/src/lib/constants/field-configurations.d.ts +53 -0
  44. package/src/lib/constants/field-configurations.js +121 -0
  45. package/src/lib/constants/field-configurations.js.map +1 -0
  46. package/src/lib/constants/flags.d.ts +72 -0
  47. package/src/lib/constants/flags.js +69 -0
  48. package/src/lib/constants/flags.js.map +1 -0
  49. package/src/lib/hocs/with-grid-item.d.ts +25 -0
  50. package/src/lib/hocs/with-grid-item.js +48 -0
  51. package/src/lib/hocs/with-grid-item.js.map +1 -0
  52. package/src/lib/jsx-forms.d.ts +41 -0
  53. package/src/lib/jsx-forms.js +42 -0
  54. package/src/lib/jsx-forms.js.map +1 -0
  55. package/src/lib/mapper/breakpoint-span.d.ts +73 -0
  56. package/src/lib/mapper/breakpoint-span.js +346 -0
  57. package/src/lib/mapper/breakpoint-span.js.map +1 -0
  58. package/src/lib/mapper/checkbox.d.ts +43 -0
  59. package/src/lib/mapper/checkbox.js +111 -0
  60. package/src/lib/mapper/checkbox.js.map +1 -0
  61. package/src/lib/mapper/css-border.d.ts +113 -0
  62. package/src/lib/mapper/css-border.js +410 -0
  63. package/src/lib/mapper/css-border.js.map +1 -0
  64. package/src/lib/mapper/css-dimension.d.ts +89 -0
  65. package/src/lib/mapper/css-dimension.js +327 -0
  66. package/src/lib/mapper/css-dimension.js.map +1 -0
  67. package/src/lib/mapper/css-gradient.d.ts +110 -0
  68. package/src/lib/mapper/css-gradient.js +720 -0
  69. package/src/lib/mapper/css-gradient.js.map +1 -0
  70. package/src/lib/mapper/data-table.d.ts +23 -0
  71. package/src/lib/mapper/data-table.js +296 -0
  72. package/src/lib/mapper/data-table.js.map +1 -0
  73. package/src/lib/mapper/date-picker.d.ts +26 -0
  74. package/src/lib/mapper/date-picker.js +69 -0
  75. package/src/lib/mapper/date-picker.js.map +1 -0
  76. package/src/lib/mapper/dual-list-select.d.ts +115 -0
  77. package/src/lib/mapper/dual-list-select.js +353 -0
  78. package/src/lib/mapper/dual-list-select.js.map +1 -0
  79. package/src/lib/mapper/field-array.d.ts +71 -0
  80. package/src/lib/mapper/field-array.js +326 -0
  81. package/src/lib/mapper/field-array.js.map +1 -0
  82. package/src/lib/mapper/form-field-grid.d.ts +155 -0
  83. package/src/lib/mapper/form-field-grid.js +194 -0
  84. package/src/lib/mapper/form-field-grid.js.map +1 -0
  85. package/src/lib/mapper/index.d.ts +50 -0
  86. package/src/lib/mapper/index.js +49 -0
  87. package/src/lib/mapper/index.js.map +1 -0
  88. package/src/lib/mapper/multiple-choice-list.d.ts +32 -0
  89. package/src/lib/mapper/multiple-choice-list.js +105 -0
  90. package/src/lib/mapper/multiple-choice-list.js.map +1 -0
  91. package/src/lib/mapper/plain-text.d.ts +31 -0
  92. package/src/lib/mapper/plain-text.js +48 -0
  93. package/src/lib/mapper/plain-text.js.map +1 -0
  94. package/src/lib/mapper/preset-choice.d.ts +106 -0
  95. package/src/lib/mapper/preset-choice.js +267 -0
  96. package/src/lib/mapper/preset-choice.js.map +1 -0
  97. package/src/lib/mapper/radio.d.ts +40 -0
  98. package/src/lib/mapper/radio.js +122 -0
  99. package/src/lib/mapper/radio.js.map +1 -0
  100. package/src/lib/mapper/select.d.ts +60 -0
  101. package/src/lib/mapper/select.js +203 -0
  102. package/src/lib/mapper/select.js.map +1 -0
  103. package/src/lib/mapper/slider.d.ts +45 -0
  104. package/src/lib/mapper/slider.js +119 -0
  105. package/src/lib/mapper/slider.js.map +1 -0
  106. package/src/lib/mapper/stored-field-value.d.ts +23 -0
  107. package/src/lib/mapper/stored-field-value.js +29 -0
  108. package/src/lib/mapper/stored-field-value.js.map +1 -0
  109. package/src/lib/mapper/sub-form.d.ts +39 -0
  110. package/src/lib/mapper/sub-form.js +108 -0
  111. package/src/lib/mapper/sub-form.js.map +1 -0
  112. package/src/lib/mapper/switch.d.ts +47 -0
  113. package/src/lib/mapper/switch.js +93 -0
  114. package/src/lib/mapper/switch.js.map +1 -0
  115. package/src/lib/mapper/tabs.d.ts +34 -0
  116. package/src/lib/mapper/tabs.js +64 -0
  117. package/src/lib/mapper/tabs.js.map +1 -0
  118. package/src/lib/mapper/text-field.d.ts +33 -0
  119. package/src/lib/mapper/text-field.js +88 -0
  120. package/src/lib/mapper/text-field.js.map +1 -0
  121. package/src/lib/mapper/textarea.d.ts +31 -0
  122. package/src/lib/mapper/textarea.js +68 -0
  123. package/src/lib/mapper/textarea.js.map +1 -0
  124. package/src/lib/mapper/theme-scale.d.ts +79 -0
  125. package/src/lib/mapper/theme-scale.js +162 -0
  126. package/src/lib/mapper/theme-scale.js.map +1 -0
  127. package/src/lib/mapper/time-picker.d.ts +26 -0
  128. package/src/lib/mapper/time-picker.js +69 -0
  129. package/src/lib/mapper/time-picker.js.map +1 -0
  130. package/src/lib/mapper/types.d.ts +43 -0
  131. package/src/lib/mapper/types.js +22 -0
  132. package/src/lib/mapper/types.js.map +1 -0
  133. package/src/lib/mapper/validation-error.d.ts +24 -0
  134. package/src/lib/mapper/validation-error.js +24 -0
  135. package/src/lib/mapper/validation-error.js.map +1 -0
  136. package/src/lib/mapper/wizard.d.ts +21 -0
  137. package/src/lib/mapper/wizard.js +203 -0
  138. package/src/lib/mapper/wizard.js.map +1 -0
  139. package/src/lib/types.d.ts +19 -0
  140. package/src/lib/types.js +18 -0
  141. package/src/lib/types.js.map +1 -0
  142. package/src/lib/utils/option-is-equal-to-value.d.ts +20 -0
  143. package/src/lib/utils/option-is-equal-to-value.js +21 -0
  144. package/src/lib/utils/option-is-equal-to-value.js.map +1 -0
  145. package/src/lib/utils/validation-message.d.ts +22 -0
  146. package/src/lib/utils/validation-message.js +24 -0
  147. package/src/lib/utils/validation-message.js.map +1 -0
  148. package/src/lib/vendor/data-driven-forms.d.ts +33 -0
  149. package/src/lib/vendor/data-driven-forms.js +29 -0
  150. package/src/lib/vendor/data-driven-forms.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx-forms/src/lib/mapper/css-gradient.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ColorPicker as AglynColorPicker,\n type ColorPickerProps as AglynColorPickerProps,\n} from '@aglyn/shared-ui-color-picker'\nimport {\n buildCssGradient,\n type CssGradient,\n type CssGradientStop,\n type CssGradientType,\n parseCssGradient,\n parsePaletteTokenCssVar,\n paletteTokenToCssVar,\n} from '@aglyn/shared-data-enums'\nimport {\n Box,\n Button,\n ButtonBase,\n ClickAwayListener,\n FormHelperText,\n IconButton,\n MenuItem,\n Paper,\n Popper,\n Stack,\n TextField as MuiTextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport {\n ColorTokenGrid,\n type ColorPickerTokenOption,\n rgbColorToCss,\n TokenSwatch,\n useColorPickerTokenOptions,\n} from '../components/color-picker-tokens'\nimport { useFieldApi } from '../vendor/data-driven-forms'\nimport FormFieldGrid, {\n buildFieldClear,\n type FormFieldGridProps,\n} from './form-field-grid'\nimport type { BaseFieldProps } from './types'\nimport { type ExtendedFieldMeta, validationError } from './validation-error'\n\n/**\n * CssGradient (AGL-1331): the Background Fill editor.\n *\n * The Styles panel's Colors group offered *Text Color* and *Background\n * Color* and nothing else, so a gradient could not be authored at all —\n * and typing one into Background Color was accepted, stored as\n * `background-color: linear-gradient(…)`, and dropped by the CSS parser\n * with no error anywhere. This is the control that expresses the value,\n * and `describeCssColorProblem` is the guard that stops the silent store;\n * the two ship together on purpose.\n *\n * The PERSISTED value is ONE CSS string under `backgroundImage` — the same\n * contract as `CssDimensionField`, so nothing downstream has to know\n * this editor exists. A **Solid** fill writes the explicit keyword\n * `none`, which paints no image and leaves the neighbouring Background\n * Color field to do the job; the two never fight over one property.\n * **Default** writes `''`, which clears the property entirely.\n *\n * Solid and Default are two states, not one (AGL-1338). Solid shipped as\n * \"write nothing\" — and on a reusable-component INSTANCE, where the panel\n * edits an override slice, writing nothing IS \"no override\": the field\n * could not be used to take a gradient off one placement, because the\n * absence it produced was indistinguishable from never having touched it.\n * `none` is a value, so it merges over the component's gradient and wins.\n *\n * Stops bind to palette TOKENS or to literals, and a single gradient can\n * mix them: the marketing CTA's endpoints are `primary.main` /\n * `secondary.main` while its mid stop `#7A5CF0` has no token at all. A\n * token stop persists as `var(--mui-palette-primary-main, #00B0FF)` and is\n * substituted against the site theme by the node renderer\n * (`resolvePaletteVarsSx`) — see that module for why the reference is not\n * left to the browser.\n *\n * Anything the editor cannot model — `conic-gradient`, `to bottom right`,\n * a comma-stacked image list — falls back to a free-text box holding the\n * raw string, so no existing value is destroyed by an editor that cannot\n * show it. The stacked case reaches that box only because `parseCssGradient`\n * splits top-level layers first (AGL-1336); until it did, a tint over a\n * photo opened in the STOP editor and the author's first edit deleted the\n * photo.\n */\n\n/**\n * The CSS an explicit **Solid** fill persists — `background-image`'s own\n * initial value, so it renders identically to no declaration at all while\n * remaining a VALUE that can override an inherited one (AGL-1338).\n */\nexport const SOLID_FILL_VALUE = 'none'\n\n/**\n * What the fill-type switch offers. Three states, because \"no gradient\"\n * and \"no opinion\" are different answers on a component instance:\n *\n * - `''` — unset: the property is not written at all. On a plain node\n * that is the browser default; in an instance's override slice it is\n * how \"this instance does not override the fill\" is stored, so the\n * component's own fill keeps painting.\n * - `solid` — an explicit {@link SOLID_FILL_VALUE}: paint no image and\n * let Background Color show. A real value, so it beats a gradient the\n * component set.\n * - `linear` / `radial` — the gradient the stop editor builds.\n */\ntype GradientFillType = '' | 'solid' | CssGradientType\n\ninterface GradientDraft {\n fill: GradientFillType\n angle: string\n /** Radial centre, percent, as typed. Empty means CSS's default (centre). */\n positionX: string\n positionY: string\n stops: CssGradientStop[]\n /** The value is not a gradient this editor can model — held verbatim. */\n raw?: string\n}\n\nconst DEFAULT_ANGLE = 180\n\n/** No value at all — the property stays off the node. */\nconst emptyDraft: GradientDraft = {\n fill: '',\n angle: '',\n positionX: '',\n positionY: '',\n stops: [],\n}\n\n/** An explicit `background-image: none`. */\nconst solidDraft: GradientDraft = {\n fill: 'solid',\n angle: '',\n positionX: '',\n positionY: '',\n stops: [],\n}\n\nexport const seedGradientDraft = (value: unknown): GradientDraft => {\n const text = typeof value === 'string' ? value.trim() : ''\n if (!text) return emptyDraft\n // `none` is this control's own Solid value, not a background it cannot\n // model: reading it as raw CSS would strand the author in the text box\n // on a value the control itself wrote.\n if (text.toLowerCase() === SOLID_FILL_VALUE) return solidDraft\n const parsed = parseCssGradient(text)\n // A non-gradient background image (`url(…)`) is still someone's value.\n if (!parsed) return { ...emptyDraft, fill: 'linear', raw: text }\n if (parsed.raw !== undefined) {\n return {\n fill: parsed.type,\n angle: '',\n positionX: '',\n positionY: '',\n stops: [],\n raw: parsed.raw,\n }\n }\n return {\n fill: parsed.type,\n angle: parsed.angle === undefined ? '' : `${parsed.angle}`,\n positionX: parsed.position ? `${parsed.position.x}` : '',\n positionY: parsed.position ? `${parsed.position.y}` : '',\n stops: parsed.stops,\n }\n}\n\nexport const serializeGradientDraft = (draft: GradientDraft): string => {\n if (draft.raw !== undefined) return draft.raw\n if (draft.fill === '') return ''\n if (draft.fill === 'solid') return SOLID_FILL_VALUE\n const angle = draft.angle.trim()\n // Both boxes or neither: `at 50%` alone is a different CSS value (it\n // defaults Y to centre), and writing one while the author has only filled\n // the other would move the glow the moment they tabbed out of the first.\n const x = draft.positionX.trim()\n const y = draft.positionY.trim()\n const hasPosition = draft.fill === 'radial' && x !== '' && y !== ''\n const gradient: CssGradient = {\n type: draft.fill,\n angle: angle === '' ? undefined : Number(angle),\n position: hasPosition ? { x: Number(x), y: Number(y) } : undefined,\n stops: draft.stops,\n }\n return buildCssGradient(gradient)\n}\n\n/** The two stops a fresh gradient starts from — brand ends when available. */\nfunction defaultStops(options: ColorPickerTokenOption[]): CssGradientStop[] {\n const pick = (path: string) => options.find((option) => option.value === path)\n const start = pick('primary.main')\n const end = pick('secondary.main')\n return [\n {\n color: start\n ? paletteTokenToCssVar(start.value, start.light ?? start.dark)\n : '#ffffff',\n position: 0,\n },\n {\n color: end\n ? paletteTokenToCssVar(end.value, end.light ?? end.dark)\n : '#000000',\n position: 100,\n },\n ]\n}\n\n/** The token a stop is bound to, or undefined when it is a literal. */\nfunction stopToken(\n color: string,\n options: ColorPickerTokenOption[],\n): ColorPickerTokenOption | undefined {\n const ref = parsePaletteTokenCssVar(color)\n if (!ref) return undefined\n return options.find((option) => option.value === ref.path)\n}\n\n/**\n * A preview-safe copy of the value: token references resolve to the SITE\n * theme's colour rather than to whatever `--mui-palette-*` the surrounding\n * app happens to define (the console defines its own).\n */\nfunction previewGradient(\n draft: GradientDraft,\n options: ColorPickerTokenOption[],\n): string {\n const resolved = {\n ...draft,\n stops: draft.stops.map((stop) => {\n const ref = parsePaletteTokenCssVar(stop.color)\n if (!ref) return stop\n const token = options.find((option) => option.value === ref.path)\n const color = token?.light ?? token?.dark ?? ref.fallback ?? stop.color\n return { ...stop, color }\n }),\n }\n return serializeGradientDraft(resolved)\n}\n\n/** Swatch + label button that opens one stop's two-stage colour picker. */\nconst GradientStopColor = (props: {\n color: string\n label: string\n disabled?: boolean\n presetColors?: string[]\n ColorPickerProps?: Partial<AglynColorPickerProps>\n onChange: (color: string) => void\n}) => {\n const { color, label, disabled, presetColors, ColorPickerProps, onChange } =\n props\n const options = useColorPickerTokenOptions()\n const token = stopToken(color, options)\n const literal = parsePaletteTokenCssVar(color)?.fallback ?? color\n const [anchor, setAnchor] = useState<HTMLElement | null>(null)\n const [stage, setStage] = useState<'tokens' | 'custom'>('tokens')\n\n const handleOpen = useCallback(\n (event: { currentTarget: HTMLElement }) => {\n // Tokens first, exactly like the colour field's two-stage picker —\n // unless the theme offers none, in which case the token stage would\n // be an empty grid.\n setStage(options.length ? 'tokens' : 'custom')\n setAnchor((previous) => (previous ? null : event.currentTarget))\n },\n [options.length],\n )\n\n return (\n <ClickAwayListener onClickAway={() => setAnchor(null)}>\n <Box sx={{ flexGrow: 1, minWidth: 0 }}>\n <ButtonBase\n aria-label={label}\n disabled={disabled}\n onClick={handleOpen}\n sx={{\n width: '100%',\n justifyContent: 'flex-start',\n gap: 0.75,\n px: 1,\n py: 0.75,\n border: 1,\n borderColor: 'divider',\n borderRadius: 1,\n }}\n >\n {token ? (\n <TokenSwatch light={token.light} dark={token.dark} size={18} />\n ) : (\n <Box\n sx={{\n width: 18,\n height: 18,\n flexShrink: 0,\n borderRadius: '50%',\n border: 1,\n borderColor: 'divider',\n backgroundColor: literal,\n }}\n />\n )}\n <Typography variant=\"caption\" noWrap>\n {token ? token.label : literal}\n </Typography>\n </ButtonBase>\n <Popper\n open={Boolean(anchor)}\n anchorEl={anchor}\n sx={{ zIndex: 'tooltip', maxWidth: 280 }}\n disablePortal\n >\n {stage === 'tokens' && options.length ? (\n <ColorTokenGrid\n options={options}\n value={token?.value ?? ''}\n onSelect={(path) => {\n const picked = options.find((option) => option.value === path)\n onChange(\n paletteTokenToCssVar(path, picked?.light ?? picked?.dark),\n )\n setAnchor(null)\n }}\n onCustom={() => setStage('custom')}\n />\n ) : (\n <Paper sx={{ p: 0.5 }}>\n {options.length ? (\n <Button\n size=\"small\"\n fullWidth\n sx={{ mb: 0.5 }}\n onClick={() => setStage('tokens')}\n >\n {'‹ Theme colors'}\n </Button>\n ) : null}\n <AglynColorPicker\n {...ColorPickerProps}\n // A `var()` reference is not parseable by the picker; seed\n // it with the colour that reference resolves to.\n color={token?.light ?? token?.dark ?? literal}\n onChange={(picked: any) => onChange(rgbColorToCss(picked.rgb))}\n presetColors={presetColors}\n />\n </Paper>\n )}\n </Popper>\n </Box>\n </ClickAwayListener>\n )\n}\nGradientStopColor.displayName = 'AglynGradientStopColor'\n\nexport interface CssGradientProps extends BaseFieldProps {\n /** Swatches offered on the custom stage, same as the colour field. */\n presetColors?: string[]\n /**\n * What the unset choice is called (AGL-1338). Defaults to the panel's\n * usual `Default`; a caller editing a component instance's override\n * slice says so, because there \"unset\" means the component's own fill\n * keeps painting rather than nothing painting.\n */\n unsetLabel?: string\n /** Offer the reset-to-unset affordance (AGL-2486). */\n clearable?: boolean\n ColorPickerProps?: Partial<AglynColorPickerProps>\n FormFieldGridProps?: FormFieldGridProps\n}\n\nexport const CssGradientField = (props: CssGradientProps) => {\n const {\n input,\n isReadOnly,\n isDisabled,\n label,\n helperText,\n description,\n validateOnMount,\n meta,\n help,\n presetColors,\n unsetLabel = 'Default',\n clearable,\n ColorPickerProps,\n FormFieldGridProps = {},\n // Free-text leftovers from an attribute schema that must never reach\n // the DOM.\n inputProps: _inputProps,\n InputProps: _InputProps,\n multiline: _multiline,\n placeholder: _placeholder,\n ...rest\n } = useFieldApi(props)\n const invalid = validationError(meta as ExtendedFieldMeta, validateOnMount)\n const options = useColorPickerTokenOptions()\n const value = typeof input.value === 'string' ? input.value : ''\n const locked = Boolean(isDisabled || isReadOnly)\n\n const [draft, setDraft] = useState<GradientDraft>(() =>\n seedGradientDraft(value),\n )\n // Re-seed only when the value changed OUTSIDE this field (a different\n // node selected, an undo) — re-seeding from our own emits would fight\n // the caret in the angle and position boxes.\n const emittedRef = useRef(value)\n useEffect(() => {\n if (value === emittedRef.current) return\n emittedRef.current = value\n setDraft(seedGradientDraft(value))\n }, [value])\n\n const commit = useCallback(\n (next: GradientDraft) => {\n const serialized = serializeGradientDraft(next)\n emittedRef.current = serialized\n setDraft(next)\n input.onChange(serialized)\n },\n [input],\n )\n\n const handleFillChange = useCallback(\n (event: { target: { value: unknown } }) => {\n const fill = (event.target.value ?? '') as GradientFillType\n // Neither non-gradient choice keeps stops, but they persist\n // differently: Solid writes `none`, Default writes nothing.\n if (fill === '' || fill === 'solid') {\n commit({ ...emptyDraft, fill })\n return\n }\n // Switching INTO a gradient with nothing to show yet starts from the\n // brand ends, so the author sees a gradient immediately instead of an\n // empty stop list that serializes to nothing.\n const stops = draft.stops.length >= 2 ? draft.stops : defaultStops(options)\n const angle =\n fill === 'linear' ? draft.angle || `${DEFAULT_ANGLE}` : ''\n // Position belongs to radial; carried across a radial→radial change\n // (Solid and back) and dropped when the fill is no longer radial, so a\n // linear gradient cannot persist a centre no CSS would use.\n const positionX = fill === 'radial' ? draft.positionX : ''\n const positionY = fill === 'radial' ? draft.positionY : ''\n commit({ fill, angle, positionX, positionY, stops, raw: undefined })\n },\n [\n commit,\n draft.angle,\n draft.positionX,\n draft.positionY,\n draft.stops,\n options,\n ],\n )\n\n const handlePositionChange = useCallback(\n (axis: 'positionX' | 'positionY') =>\n (event: { target: { value: string } }) => {\n commit({ ...draft, [axis]: event.target.value })\n },\n [commit, draft],\n )\n\n const handleAngleChange = useCallback(\n (event: { target: { value: string } }) => {\n commit({ ...draft, angle: event.target.value })\n },\n [commit, draft],\n )\n\n const handleStopColor = useCallback(\n (index: number) => (color: string) => {\n const stops = draft.stops.map((stop, i) =>\n i === index ? { ...stop, color } : stop,\n )\n commit({ ...draft, stops })\n },\n [commit, draft],\n )\n\n const handleStopPosition = useCallback(\n (index: number) =>\n (event: { target: { value: string } }) => {\n const text = event.target.value.trim()\n const position = text === '' ? undefined : Number(text)\n const stops = draft.stops.map((stop, i) =>\n i === index ? { ...stop, position } : stop,\n )\n commit({ ...draft, stops })\n },\n [commit, draft],\n )\n\n const handleAddStop = useCallback(() => {\n const last = draft.stops[draft.stops.length - 1]\n const previous = draft.stops[draft.stops.length - 2]\n const between =\n typeof last?.position === 'number' && typeof previous?.position === 'number'\n ? Math.round((last.position + previous.position) / 2)\n : undefined\n const stop: CssGradientStop = {\n color: last?.color ?? '#ffffff',\n position: between,\n }\n // The new stop lands BEFORE the last one when it can be positioned\n // between the two — the CTA's mid stop is that shape.\n const stops =\n between === undefined\n ? [...draft.stops, stop]\n : [...draft.stops.slice(0, -1), stop, last]\n commit({ ...draft, stops })\n }, [commit, draft])\n\n const handleRemoveStop = useCallback(\n (index: number) => () => {\n commit({ ...draft, stops: draft.stops.filter((_, i) => i !== index) })\n },\n [commit, draft],\n )\n\n const handleRawChange = useCallback(\n (event: { target: { value: string } }) => {\n const text = event.target.value\n // Edited back into a gradient this editor CAN model? Take the\n // structured controls back rather than stranding the author in the\n // text box (the css-dimension rule).\n const reseeded = seedGradientDraft(text)\n commit(reseeded.raw === undefined && text.trim() !== ''\n ? reseeded\n : { ...draft, raw: text })\n },\n [commit, draft],\n )\n\n const preview = useMemo(\n () => previewGradient(draft, options),\n [draft, options],\n )\n\n // Back to unset in one click (AGL-2486) — including out of the raw-CSS\n // fallback, which the fill-type select cannot leave on its own because it\n // is disabled while a raw value is held.\n const clear = buildFieldClear({\n clearable,\n label,\n hasValue: value !== '',\n locked,\n onClear: () => commit({ ...emptyDraft, raw: undefined }),\n })\n\n return (\n <FormFieldGrid help={help} clear={clear} {...FormFieldGridProps}>\n <MuiTextField\n {...rest}\n select\n fullWidth\n size=\"small\"\n name={input.name}\n label={label}\n value={draft.raw !== undefined ? 'custom' : draft.fill}\n onChange={handleFillChange}\n disabled={locked || draft.raw !== undefined}\n error={!!invalid}\n helperText={\n invalid ||\n ((meta.touched || validateOnMount) && meta.warning) ||\n helperText ||\n description\n }\n slotProps={{\n htmlInput: { 'aria-label': 'Fill type' },\n // Without displayEmpty a MUI Select renders NOTHING for `''`,\n // which would show the unset state as a broken control.\n select: { displayEmpty: true },\n // …and `displayEmpty` alone prints the label ON TOP of the option\n // it just drew (AGL-2486). MUI shrinks a label when the input\n // reports itself FILLED, and an empty Select reports the\n // opposite no matter what it is rendering — so the unset choice\n // and the field name landed in the same few pixels and neither\n // could be read. A rendered option is content; say so.\n inputLabel: { shrink: true },\n }}\n >\n <MenuItem value=\"\">{unsetLabel}</MenuItem>\n <MenuItem value=\"solid\">Solid color</MenuItem>\n <MenuItem value=\"linear\">Linear gradient</MenuItem>\n <MenuItem value=\"radial\">Radial gradient</MenuItem>\n {draft.raw !== undefined ? (\n <MenuItem value=\"custom\">Custom CSS</MenuItem>\n ) : null}\n </MuiTextField>\n\n {draft.raw !== undefined ? (\n <>\n <MuiTextField\n fullWidth\n size=\"small\"\n multiline\n label=\"Background image\"\n value={draft.raw}\n onChange={handleRawChange}\n disabled={locked}\n sx={{ mt: 1 }}\n slotProps={{ htmlInput: { 'aria-label': 'Background image CSS' } }}\n />\n <FormHelperText>\n {'This background is richer than the stop editor can show — ' +\n 'stacked layers, a conic gradient, a direction keyword. It is ' +\n 'kept exactly as written; editing it back to a plain linear ' +\n 'or radial gradient brings the controls back.'}\n </FormHelperText>\n </>\n ) : draft.fill !== 'linear' && draft.fill !== 'radial' ? null : (\n <>\n <Box\n aria-label=\"Gradient preview\"\n sx={{\n mt: 1,\n height: 28,\n borderRadius: 1,\n border: 1,\n borderColor: 'divider',\n backgroundImage: preview || 'none',\n }}\n />\n {draft.fill === 'linear' ? (\n <MuiTextField\n fullWidth\n size=\"small\"\n type=\"number\"\n label=\"Angle\"\n value={draft.angle}\n onChange={handleAngleChange}\n disabled={locked}\n sx={{ mt: 1 }}\n slotProps={{\n htmlInput: { 'aria-label': 'Angle', inputMode: 'numeric' },\n input: { endAdornment: <Typography variant=\"caption\">deg</Typography> },\n }}\n />\n ) : null}\n {draft.fill === 'radial' ? (\n <Stack direction=\"row\" spacing={0.5} sx={{ mt: 1 }}>\n <MuiTextField\n fullWidth\n size=\"small\"\n type=\"number\"\n label=\"Center X\"\n value={draft.positionX}\n onChange={handlePositionChange('positionX')}\n disabled={locked}\n slotProps={{\n htmlInput: {\n 'aria-label': 'Center X',\n inputMode: 'numeric',\n },\n input: {\n endAdornment: <Typography variant=\"caption\">{'%'}</Typography>,\n },\n }}\n />\n <MuiTextField\n fullWidth\n size=\"small\"\n type=\"number\"\n label=\"Center Y\"\n value={draft.positionY}\n onChange={handlePositionChange('positionY')}\n disabled={locked}\n slotProps={{\n htmlInput: {\n 'aria-label': 'Center Y',\n inputMode: 'numeric',\n },\n input: {\n endAdornment: <Typography variant=\"caption\">{'%'}</Typography>,\n },\n }}\n />\n </Stack>\n ) : null}\n <Stack spacing={0.5} sx={{ mt: 1 }}>\n {draft.stops.map((stop, index) => (\n <Stack\n key={index}\n direction=\"row\"\n spacing={0.5}\n sx={{ alignItems: 'center' }}\n >\n <GradientStopColor\n color={stop.color}\n label={`Stop ${index + 1} color`}\n disabled={locked}\n presetColors={presetColors}\n ColorPickerProps={ColorPickerProps}\n onChange={handleStopColor(index)}\n />\n <MuiTextField\n size=\"small\"\n type=\"number\"\n value={stop.position ?? ''}\n onChange={handleStopPosition(index)}\n disabled={locked}\n sx={{ width: 88 }}\n slotProps={{\n htmlInput: {\n 'aria-label': `Stop ${index + 1} position`,\n inputMode: 'numeric',\n },\n input: {\n endAdornment: (\n <Typography variant=\"caption\">%</Typography>\n ),\n },\n }}\n />\n <IconButton\n size=\"small\"\n aria-label={`Remove stop ${index + 1}`}\n // A gradient needs two ends; the last two are not\n // removable, so the control can never serialize to a\n // value that silently clears the background.\n disabled={locked || draft.stops.length <= 2}\n onClick={handleRemoveStop(index)}\n >\n {'×'}\n </IconButton>\n </Stack>\n ))}\n </Stack>\n <Button\n size=\"small\"\n onClick={handleAddStop}\n disabled={locked}\n sx={{ mt: 0.5 }}\n >\n Add stop\n </Button>\n </>\n )}\n </FormFieldGrid>\n )\n}\n\nexport default CssGradientField\n"],"names":["ColorPicker","AglynColorPicker","buildCssGradient","parseCssGradient","parsePaletteTokenCssVar","paletteTokenToCssVar","Box","Button","ButtonBase","ClickAwayListener","FormHelperText","IconButton","MenuItem","Paper","Popper","Stack","TextField","MuiTextField","Typography","useCallback","useEffect","useMemo","useRef","useState","ColorTokenGrid","rgbColorToCss","TokenSwatch","useColorPickerTokenOptions","useFieldApi","FormFieldGrid","buildFieldClear","validationError","SOLID_FILL_VALUE","DEFAULT_ANGLE","emptyDraft","fill","angle","positionX","positionY","stops","solidDraft","seedGradientDraft","value","text","trim","toLowerCase","parsed","raw","undefined","type","position","x","y","serializeGradientDraft","draft","hasPosition","gradient","Number","defaultStops","options","start","end","pick","path","find","option","color","light","dark","stopToken","ref","previewGradient","resolved","map","stop","token","fallback","GradientStopColor","props","label","disabled","presetColors","ColorPickerProps","onChange","literal","anchor","setAnchor","stage","setStage","handleOpen","event","length","previous","currentTarget","onClickAway","sx","flexGrow","minWidth","aria-label","onClick","width","justifyContent","gap","px","py","border","borderColor","borderRadius","size","height","flexShrink","backgroundColor","variant","noWrap","open","Boolean","anchorEl","zIndex","maxWidth","disablePortal","onSelect","picked","onCustom","p","fullWidth","mb","rgb","displayName","CssGradientField","input","isReadOnly","isDisabled","helperText","description","validateOnMount","meta","help","unsetLabel","clearable","FormFieldGridProps","inputProps","_inputProps","InputProps","_InputProps","multiline","_multiline","placeholder","_placeholder","rest","invalid","locked","setDraft","emittedRef","current","commit","next","serialized","handleFillChange","target","handlePositionChange","axis","handleAngleChange","handleStopColor","index","i","handleStopPosition","handleAddStop","last","between","Math","round","slice","handleRemoveStop","filter","_","handleRawChange","reseeded","preview","clear","hasValue","onClear","select","name","error","touched","warning","slotProps","htmlInput","displayEmpty","inputLabel","shrink","mt","backgroundImage","inputMode","endAdornment","direction","spacing","alignItems"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type FormFieldGridProps } from './form-field-grid';
18
+ import type { BaseFieldProps } from './types';
19
+ export interface DataTableFieldProps extends BaseFieldProps {
20
+ FormFieldGridProps?: FormFieldGridProps;
21
+ }
22
+ export declare const DataTableField: (props: DataTableFieldProps) => import("react").JSX.Element;
23
+ export default DataTableField;
@@ -0,0 +1,296 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ /**
5
+ * @license
6
+ * Copyright 2026 Aglyn LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ import { parseDataTableRows, readDataTableAlignments, readPastedDataTable, serializeDataTable, withCellSet, withColumnAdded, withColumnRemoved, withRowAdded, withRowRemoved } from "@aglyn/shared-data-enums";
20
+ import { mdiFormatAlignCenter, mdiFormatAlignLeft, mdiFormatAlignRight, mdiPlus, mdiTrashCanOutline } from "@aglyn/shared-data-mdi";
21
+ import { MdiIcon } from "@aglyn/shared-ui-jsx";
22
+ import Box from "@mui/material/Box";
23
+ import Button from "@mui/material/Button";
24
+ import IconButton from "@mui/material/IconButton";
25
+ import Stack from "@mui/material/Stack";
26
+ import TextField from "@mui/material/TextField";
27
+ import ToggleButton from "@mui/material/ToggleButton";
28
+ import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
29
+ import { useCallback, useMemo } from "react";
30
+ import { useFieldApi } from "../vendor/data-driven-forms.js";
31
+ import FormFieldGrid from "./form-field-grid.js";
32
+ /**
33
+ * DataTable (AGL-2543): the row-and-column editor for the Table element.
34
+ *
35
+ * Without it the element would be a textarea of pipe syntax, which re-ships
36
+ * the complaint the issue was filed about — "a subscriber who wants to change
37
+ * one cell has to edit markdown pipe syntax, which is exactly the audience
38
+ * the besigner exists to avoid".
39
+ *
40
+ * The PERSISTED value is unchanged by this control existing: still ONE string
41
+ * in the syntax the element itself parses, via the same shared helpers, so
42
+ * renderers and published documents stay untouched. Same rule the CSS length,
43
+ * border and gradient fields follow.
44
+ *
45
+ * There is no local draft state, deliberately. The border and dimension
46
+ * fields need one because a half-typed decimal must not be rounded out from
47
+ * under the caret; a table cell has no such intermediate — every keystroke is
48
+ * already a valid cell value — so reading straight from the prop keeps the
49
+ * grid honest about what is stored and removes a whole class of re-seed bug.
50
+ */ const ALIGN_ICONS = {
51
+ left: mdiFormatAlignLeft.path,
52
+ center: mdiFormatAlignCenter.path,
53
+ right: mdiFormatAlignRight.path
54
+ };
55
+ export const DataTableField = (props)=>{
56
+ var _input_value, _ref;
57
+ var _rows_;
58
+ const _useFieldApi = useFieldApi(props), { input, isReadOnly, isDisabled, label, helperText, description, help, FormFieldGridProps = {}, // Free-text leftovers from the schema shape these fields share; they
59
+ // must never reach the DOM.
60
+ inputProps: _inputProps, InputProps: _InputProps, multiline: _multiline, type: _type, options: _options, meta: _meta, validateOnMount: _validateOnMount, isRequired: _isRequired, placeholder: _placeholder } = _useFieldApi, rest = _object_without_properties_loose(_useFieldApi, [
61
+ "input",
62
+ "isReadOnly",
63
+ "isDisabled",
64
+ "label",
65
+ "helperText",
66
+ "description",
67
+ "help",
68
+ "FormFieldGridProps",
69
+ "inputProps",
70
+ "InputProps",
71
+ "multiline",
72
+ "type",
73
+ "options",
74
+ "meta",
75
+ "validateOnMount",
76
+ "isRequired",
77
+ "placeholder"
78
+ ]);
79
+ const stored = `${(_input_value = input.value) != null ? _input_value : ''}`;
80
+ const rows = useMemo(()=>parseDataTableRows(stored), [
81
+ stored
82
+ ]);
83
+ const width = (_ref = (_rows_ = rows[0]) == null ? void 0 : _rows_.length) != null ? _ref : 0;
84
+ const alignments = useMemo(()=>readDataTableAlignments(stored, width), [
85
+ stored,
86
+ width
87
+ ]);
88
+ const commit = useCallback((nextRows, nextAlignments = alignments)=>{
89
+ input.onChange(serializeDataTable(nextRows, nextAlignments));
90
+ }, [
91
+ input,
92
+ alignments
93
+ ]);
94
+ /**
95
+ * Importing a markdown table by pasting it into a cell (AGL-2568).
96
+ *
97
+ * It replaces the whole grid rather than splicing at the cell, because what
98
+ * an author pastes is a table, not a range: the case this exists for is
99
+ * moving a comparison table off the Markdown workaround, where the grid it
100
+ * lands on is the two-row starter. Anything the paste is NOT a table —
101
+ * which includes every ordinary cell value — falls through to the browser
102
+ * and types itself into the cell, so this cannot cost anyone a paste.
103
+ */ const importPaste = useCallback((event)=>{
104
+ var _event_clipboardData;
105
+ const pasted = readPastedDataTable((_event_clipboardData = event.clipboardData) == null ? void 0 : _event_clipboardData.getData('text/plain'));
106
+ if (!pasted) return;
107
+ event.preventDefault();
108
+ commit(pasted.rows, pasted.alignments);
109
+ }, [
110
+ commit
111
+ ]);
112
+ const locked = isReadOnly || isDisabled;
113
+ // An empty value has no cell to click, so the grid cannot be typed into
114
+ // and the author is stuck. Offer the one action that unsticks it.
115
+ if (rows.length === 0) {
116
+ return /*#__PURE__*/ _jsx(FormFieldGrid, _extends({
117
+ help: help
118
+ }, FormFieldGridProps, {
119
+ children: /*#__PURE__*/ _jsxs(Stack, _extends({
120
+ spacing: 1
121
+ }, rest, {
122
+ children: [
123
+ /*#__PURE__*/ _jsx(Box, {
124
+ sx: {
125
+ color: 'text.secondary',
126
+ fontSize: 13
127
+ },
128
+ children: label != null ? label : 'Rows'
129
+ }),
130
+ /*#__PURE__*/ _jsx(Button, {
131
+ size: "small",
132
+ variant: "outlined",
133
+ disabled: locked,
134
+ startIcon: /*#__PURE__*/ _jsx(MdiIcon, {
135
+ path: mdiPlus.path
136
+ }),
137
+ onClick: ()=>commit([
138
+ [
139
+ 'Feature',
140
+ 'Us',
141
+ 'Them'
142
+ ],
143
+ [
144
+ '',
145
+ '',
146
+ ''
147
+ ]
148
+ ], [
149
+ 'left',
150
+ 'center',
151
+ 'center'
152
+ ]),
153
+ children: 'Start a table'
154
+ }),
155
+ /*#__PURE__*/ _jsx(Box, {
156
+ sx: {
157
+ color: 'text.secondary',
158
+ fontSize: 12
159
+ },
160
+ children: 'Then paste a markdown table into any cell to import one.'
161
+ })
162
+ ]
163
+ }))
164
+ }));
165
+ }
166
+ return /*#__PURE__*/ _jsx(FormFieldGrid, _extends({
167
+ help: help
168
+ }, FormFieldGridProps, {
169
+ children: /*#__PURE__*/ _jsxs(Stack, _extends({
170
+ spacing: 1
171
+ }, rest, {
172
+ children: [
173
+ label ? /*#__PURE__*/ _jsx(Box, {
174
+ sx: {
175
+ color: 'text.secondary',
176
+ fontSize: 13
177
+ },
178
+ children: label
179
+ }) : null,
180
+ /*#__PURE__*/ _jsx(Stack, {
181
+ direction: "row",
182
+ spacing: 0.5,
183
+ sx: {
184
+ pl: 0
185
+ },
186
+ children: alignments.map((alignment, columnIndex)=>/*#__PURE__*/ _jsxs(Box, {
187
+ sx: {
188
+ flex: 1,
189
+ minWidth: 0
190
+ },
191
+ children: [
192
+ /*#__PURE__*/ _jsx(ToggleButtonGroup, {
193
+ size: "small",
194
+ exclusive: true,
195
+ disabled: locked,
196
+ value: alignment,
197
+ onChange: (_event, next)=>{
198
+ if (!next) return;
199
+ const nextAlignments = alignments.map((current, index)=>index === columnIndex ? next : current);
200
+ commit(rows, nextAlignments);
201
+ },
202
+ "aria-label": `Column ${columnIndex + 1} alignment`,
203
+ children: Object.keys(ALIGN_ICONS).map((option)=>/*#__PURE__*/ _jsx(ToggleButton, {
204
+ value: option,
205
+ sx: {
206
+ px: 0.75
207
+ },
208
+ children: /*#__PURE__*/ _jsx(MdiIcon, {
209
+ path: ALIGN_ICONS[option],
210
+ size: 0.7
211
+ })
212
+ }, option))
213
+ }),
214
+ /*#__PURE__*/ _jsx(IconButton, {
215
+ size: "small",
216
+ disabled: locked || width <= 1,
217
+ "aria-label": `Remove column ${columnIndex + 1}`,
218
+ onClick: ()=>commit(withColumnRemoved(rows, columnIndex)),
219
+ children: /*#__PURE__*/ _jsx(MdiIcon, {
220
+ path: mdiTrashCanOutline.path,
221
+ size: 0.7
222
+ })
223
+ })
224
+ ]
225
+ }, columnIndex))
226
+ }),
227
+ rows.map((row, rowIndex)=>/*#__PURE__*/ _jsxs(Stack, {
228
+ direction: "row",
229
+ spacing: 0.5,
230
+ sx: {
231
+ alignItems: 'center'
232
+ },
233
+ children: [
234
+ row.map((cell, columnIndex)=>/*#__PURE__*/ _jsx(TextField, {
235
+ size: "small",
236
+ fullWidth: true,
237
+ disabled: locked,
238
+ value: cell,
239
+ onPaste: importPaste,
240
+ slotProps: {
241
+ htmlInput: {
242
+ 'aria-label': `Row ${rowIndex + 1} column ${columnIndex + 1}`
243
+ }
244
+ },
245
+ onChange: (event)=>commit(withCellSet(rows, rowIndex, columnIndex, event.target.value))
246
+ }, columnIndex)),
247
+ /*#__PURE__*/ _jsx(IconButton, {
248
+ size: "small",
249
+ disabled: locked || rows.length <= 1,
250
+ "aria-label": `Remove row ${rowIndex + 1}`,
251
+ onClick: ()=>commit(withRowRemoved(rows, rowIndex)),
252
+ children: /*#__PURE__*/ _jsx(MdiIcon, {
253
+ path: mdiTrashCanOutline.path,
254
+ size: 0.7
255
+ })
256
+ })
257
+ ]
258
+ }, rowIndex)),
259
+ /*#__PURE__*/ _jsxs(Stack, {
260
+ direction: "row",
261
+ spacing: 1,
262
+ children: [
263
+ /*#__PURE__*/ _jsx(Button, {
264
+ size: "small",
265
+ disabled: locked,
266
+ startIcon: /*#__PURE__*/ _jsx(MdiIcon, {
267
+ path: mdiPlus.path
268
+ }),
269
+ onClick: ()=>commit(withRowAdded(rows)),
270
+ children: 'Row'
271
+ }),
272
+ /*#__PURE__*/ _jsx(Button, {
273
+ size: "small",
274
+ disabled: locked,
275
+ startIcon: /*#__PURE__*/ _jsx(MdiIcon, {
276
+ path: mdiPlus.path
277
+ }),
278
+ onClick: ()=>commit(withColumnAdded(rows)),
279
+ children: 'Column'
280
+ })
281
+ ]
282
+ }),
283
+ helperText || description ? /*#__PURE__*/ _jsx(Box, {
284
+ sx: {
285
+ color: 'text.secondary',
286
+ fontSize: 12
287
+ },
288
+ children: helperText != null ? helperText : description
289
+ }) : null
290
+ ]
291
+ }))
292
+ }));
293
+ };
294
+ export default DataTableField;
295
+
296
+ //# sourceMappingURL=data-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx-forms/src/lib/mapper/data-table.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type DataTableAlignment,\n parseDataTableRows,\n readDataTableAlignments,\n readPastedDataTable,\n serializeDataTable,\n withCellSet,\n withColumnAdded,\n withColumnRemoved,\n withRowAdded,\n withRowRemoved,\n} from '@aglyn/shared-data-enums'\nimport {\n mdiFormatAlignCenter,\n mdiFormatAlignLeft,\n mdiFormatAlignRight,\n mdiPlus,\n mdiTrashCanOutline,\n} from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport IconButton from '@mui/material/IconButton'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\nimport ToggleButton from '@mui/material/ToggleButton'\nimport ToggleButtonGroup from '@mui/material/ToggleButtonGroup'\nimport type { ClipboardEvent } from 'react'\nimport { useCallback, useMemo } from 'react'\nimport { useFieldApi } from '../vendor/data-driven-forms'\nimport FormFieldGrid, { type FormFieldGridProps } from './form-field-grid'\nimport type { BaseFieldProps } from './types'\n\n/**\n * DataTable (AGL-2543): the row-and-column editor for the Table element.\n *\n * Without it the element would be a textarea of pipe syntax, which re-ships\n * the complaint the issue was filed about — \"a subscriber who wants to change\n * one cell has to edit markdown pipe syntax, which is exactly the audience\n * the besigner exists to avoid\".\n *\n * The PERSISTED value is unchanged by this control existing: still ONE string\n * in the syntax the element itself parses, via the same shared helpers, so\n * renderers and published documents stay untouched. Same rule the CSS length,\n * border and gradient fields follow.\n *\n * There is no local draft state, deliberately. The border and dimension\n * fields need one because a half-typed decimal must not be rounded out from\n * under the caret; a table cell has no such intermediate — every keystroke is\n * already a valid cell value — so reading straight from the prop keeps the\n * grid honest about what is stored and removes a whole class of re-seed bug.\n */\n\nconst ALIGN_ICONS: Record<DataTableAlignment, string> = {\n left: mdiFormatAlignLeft.path,\n center: mdiFormatAlignCenter.path,\n right: mdiFormatAlignRight.path,\n}\n\nexport interface DataTableFieldProps extends BaseFieldProps {\n FormFieldGridProps?: FormFieldGridProps\n}\n\nexport const DataTableField = (props: DataTableFieldProps) => {\n const {\n input,\n isReadOnly,\n isDisabled,\n label,\n helperText,\n description,\n help,\n FormFieldGridProps = {},\n // Free-text leftovers from the schema shape these fields share; they\n // must never reach the DOM.\n inputProps: _inputProps,\n InputProps: _InputProps,\n multiline: _multiline,\n type: _type,\n options: _options,\n meta: _meta,\n validateOnMount: _validateOnMount,\n isRequired: _isRequired,\n placeholder: _placeholder,\n ...rest\n } = useFieldApi(props)\n\n const stored = `${input.value ?? ''}`\n const rows = useMemo(() => parseDataTableRows(stored), [stored])\n const width = rows[0]?.length ?? 0\n const alignments = useMemo(\n () => readDataTableAlignments(stored, width),\n [stored, width],\n )\n\n const commit = useCallback(\n (nextRows: string[][], nextAlignments = alignments) => {\n input.onChange(serializeDataTable(nextRows, nextAlignments))\n },\n [input, alignments],\n )\n\n /**\n * Importing a markdown table by pasting it into a cell (AGL-2568).\n *\n * It replaces the whole grid rather than splicing at the cell, because what\n * an author pastes is a table, not a range: the case this exists for is\n * moving a comparison table off the Markdown workaround, where the grid it\n * lands on is the two-row starter. Anything the paste is NOT a table —\n * which includes every ordinary cell value — falls through to the browser\n * and types itself into the cell, so this cannot cost anyone a paste.\n */\n const importPaste = useCallback(\n (event: ClipboardEvent<HTMLElement>) => {\n const pasted = readPastedDataTable(\n event.clipboardData?.getData('text/plain'),\n )\n if (!pasted) return\n event.preventDefault()\n commit(pasted.rows, pasted.alignments)\n },\n [commit],\n )\n\n const locked = isReadOnly || isDisabled\n\n // An empty value has no cell to click, so the grid cannot be typed into\n // and the author is stuck. Offer the one action that unsticks it.\n if (rows.length === 0) {\n return (\n <FormFieldGrid help={help} {...FormFieldGridProps}>\n <Stack spacing={1} {...rest}>\n <Box sx={{ color: 'text.secondary', fontSize: 13 }}>\n {label ?? 'Rows'}\n </Box>\n <Button\n size=\"small\"\n variant=\"outlined\"\n disabled={locked}\n startIcon={<MdiIcon path={mdiPlus.path} />}\n onClick={() =>\n commit(\n [\n ['Feature', 'Us', 'Them'],\n ['', '', ''],\n ],\n ['left', 'center', 'center'],\n )\n }\n >\n {'Start a table'}\n </Button>\n {/* \"Then\", not \"or\": the import runs on a cell's paste handler, and\n an empty field has no cell to paste into. */}\n <Box sx={{ color: 'text.secondary', fontSize: 12 }}>\n {'Then paste a markdown table into any cell to import one.'}\n </Box>\n </Stack>\n </FormFieldGrid>\n )\n }\n\n return (\n <FormFieldGrid help={help} {...FormFieldGridProps}>\n <Stack spacing={1} {...rest}>\n {label ? (\n <Box sx={{ color: 'text.secondary', fontSize: 13 }}>{label}</Box>\n ) : null}\n\n {/* Per-column alignment. It sits above its column rather than in a\n separate field because it belongs to the column an author is\n looking at — and because a field editor only ever receives one\n prop, so it has to travel inside this same string. */}\n <Stack direction=\"row\" spacing={0.5} sx={{ pl: 0 }}>\n {alignments.map((alignment, columnIndex) => (\n <Box key={columnIndex} sx={{ flex: 1, minWidth: 0 }}>\n <ToggleButtonGroup\n size=\"small\"\n exclusive\n disabled={locked}\n value={alignment}\n onChange={(_event, next) => {\n if (!next) return\n const nextAlignments = alignments.map((current, index) =>\n index === columnIndex\n ? (next as DataTableAlignment)\n : current,\n )\n commit(rows, nextAlignments)\n }}\n aria-label={`Column ${columnIndex + 1} alignment`}\n >\n {(\n Object.keys(ALIGN_ICONS) as DataTableAlignment[]\n ).map((option) => (\n <ToggleButton key={option} value={option} sx={{ px: 0.75 }}>\n <MdiIcon path={ALIGN_ICONS[option]} size={0.7} />\n </ToggleButton>\n ))}\n </ToggleButtonGroup>\n <IconButton\n size=\"small\"\n disabled={locked || width <= 1}\n aria-label={`Remove column ${columnIndex + 1}`}\n onClick={() => commit(withColumnRemoved(rows, columnIndex))}\n >\n <MdiIcon path={mdiTrashCanOutline.path} size={0.7} />\n </IconButton>\n </Box>\n ))}\n </Stack>\n\n {rows.map((row, rowIndex) => (\n <Stack\n key={rowIndex}\n direction=\"row\"\n spacing={0.5}\n sx={{ alignItems: 'center' }}\n >\n {row.map((cell, columnIndex) => (\n <TextField\n key={columnIndex}\n size=\"small\"\n fullWidth\n disabled={locked}\n value={cell}\n onPaste={importPaste}\n slotProps={{\n htmlInput: {\n 'aria-label': `Row ${rowIndex + 1} column ${\n columnIndex + 1\n }`,\n },\n }}\n onChange={(event) =>\n commit(\n withCellSet(rows, rowIndex, columnIndex, event.target.value),\n )\n }\n />\n ))}\n <IconButton\n size=\"small\"\n disabled={locked || rows.length <= 1}\n aria-label={`Remove row ${rowIndex + 1}`}\n onClick={() => commit(withRowRemoved(rows, rowIndex))}\n >\n <MdiIcon path={mdiTrashCanOutline.path} size={0.7} />\n </IconButton>\n </Stack>\n ))}\n\n <Stack direction=\"row\" spacing={1}>\n <Button\n size=\"small\"\n disabled={locked}\n startIcon={<MdiIcon path={mdiPlus.path} />}\n onClick={() => commit(withRowAdded(rows))}\n >\n {'Row'}\n </Button>\n <Button\n size=\"small\"\n disabled={locked}\n startIcon={<MdiIcon path={mdiPlus.path} />}\n onClick={() => commit(withColumnAdded(rows))}\n >\n {'Column'}\n </Button>\n </Stack>\n\n {helperText || description ? (\n <Box sx={{ color: 'text.secondary', fontSize: 12 }}>\n {helperText ?? description}\n </Box>\n ) : null}\n </Stack>\n </FormFieldGrid>\n )\n}\n\nexport default DataTableField\n"],"names":["parseDataTableRows","readDataTableAlignments","readPastedDataTable","serializeDataTable","withCellSet","withColumnAdded","withColumnRemoved","withRowAdded","withRowRemoved","mdiFormatAlignCenter","mdiFormatAlignLeft","mdiFormatAlignRight","mdiPlus","mdiTrashCanOutline","MdiIcon","Box","Button","IconButton","Stack","TextField","ToggleButton","ToggleButtonGroup","useCallback","useMemo","useFieldApi","FormFieldGrid","ALIGN_ICONS","left","path","center","right","DataTableField","props","input","rows","isReadOnly","isDisabled","label","helperText","description","help","FormFieldGridProps","inputProps","_inputProps","InputProps","_InputProps","multiline","_multiline","type","_type","options","_options","meta","_meta","validateOnMount","_validateOnMount","isRequired","_isRequired","placeholder","_placeholder","rest","stored","value","width","length","alignments","commit","nextRows","nextAlignments","onChange","importPaste","event","pasted","clipboardData","getData","preventDefault","locked","spacing","sx","color","fontSize","size","variant","disabled","startIcon","onClick","direction","pl","map","alignment","columnIndex","flex","minWidth","exclusive","_event","next","current","index","aria-label","Object","keys","option","px","row","rowIndex","alignItems","cell","fullWidth","onPaste","slotProps","htmlInput","target"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type DatePickerProps as MuiDatePickerProps } from '@mui/x-date-pickers';
18
+ import { type FormFieldGridProps } from './form-field-grid';
19
+ import type { BaseFieldProps } from './types';
20
+ export interface DatePickerProps extends BaseFieldProps {
21
+ placeholder?: string;
22
+ FormFieldGridProps?: FormFieldGridProps;
23
+ DatePickerProps?: Omit<MuiDatePickerProps, 'value' | 'onChange' | 'disabled' | 'readOnly'>;
24
+ }
25
+ export declare const DatePicker: (props: DatePickerProps) => import("react").JSX.Element;
26
+ export default DatePicker;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /**
17
+ * Ported from `@data-driven-forms/mui-component-mapper` (Apache-2.0) and
18
+ * updated for the current @mui/x-date-pickers slots API.
19
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
20
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
21
+ import { jsx as _jsx } from "react/jsx-runtime";
22
+ import { DatePicker as MuiDatePicker } from "@mui/x-date-pickers";
23
+ import { useFieldApi } from "../vendor/data-driven-forms.js";
24
+ import FormFieldGrid from "./form-field-grid.js";
25
+ import { validationError } from "./validation-error.js";
26
+ export const DatePicker = (props)=>{
27
+ const _useFieldApi = useFieldApi(props), { input, isReadOnly, isDisabled, placeholder, isRequired, label, helperText, description, validateOnMount, meta, help, FormFieldGridProps = {}, DatePickerProps = {} } = _useFieldApi, rest = _object_without_properties_loose(_useFieldApi, [
28
+ "input",
29
+ "isReadOnly",
30
+ "isDisabled",
31
+ "placeholder",
32
+ "isRequired",
33
+ "label",
34
+ "helperText",
35
+ "description",
36
+ "validateOnMount",
37
+ "meta",
38
+ "help",
39
+ "FormFieldGridProps",
40
+ "DatePickerProps"
41
+ ]);
42
+ const invalid = validationError(meta, validateOnMount);
43
+ return /*#__PURE__*/ _jsx(FormFieldGrid, _extends({
44
+ help: help
45
+ }, FormFieldGridProps, {
46
+ children: /*#__PURE__*/ _jsx(MuiDatePicker, _extends({
47
+ slotProps: {
48
+ textField: {
49
+ fullWidth: true,
50
+ margin: 'normal',
51
+ label,
52
+ helperText: invalid || (meta.touched || validateOnMount) && meta.warning || helperText || description,
53
+ placeholder,
54
+ required: isRequired,
55
+ error: !!invalid,
56
+ onBlur: input.onBlur,
57
+ onFocus: input.onFocus
58
+ }
59
+ },
60
+ disabled: isDisabled || isReadOnly,
61
+ readOnly: isReadOnly
62
+ }, input, {
63
+ value: input.value || null
64
+ }, DatePickerProps, rest))
65
+ }));
66
+ };
67
+ export default DatePicker;
68
+
69
+ //# sourceMappingURL=date-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx-forms/src/lib/mapper/date-picker.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Ported from `@data-driven-forms/mui-component-mapper` (Apache-2.0) and\n * updated for the current @mui/x-date-pickers slots API.\n */\n\nimport type { TextFieldProps } from '@mui/material'\n\nimport {\n DatePicker as MuiDatePicker,\n type DatePickerProps as MuiDatePickerProps,\n} from '@mui/x-date-pickers'\n\nimport { useFieldApi } from '../vendor/data-driven-forms'\nimport FormFieldGrid, { type FormFieldGridProps } from './form-field-grid'\nimport type { BaseFieldProps } from './types'\nimport { type ExtendedFieldMeta, validationError } from './validation-error'\n\nexport interface DatePickerProps extends BaseFieldProps {\n placeholder?: string\n FormFieldGridProps?: FormFieldGridProps\n DatePickerProps?: Omit<\n MuiDatePickerProps,\n 'value' | 'onChange' | 'disabled' | 'readOnly'\n >\n}\n\nexport const DatePicker = (props: DatePickerProps) => {\n const {\n input,\n isReadOnly,\n isDisabled,\n placeholder,\n isRequired,\n label,\n helperText,\n description,\n validateOnMount,\n meta,\n help,\n FormFieldGridProps = {},\n DatePickerProps = {},\n ...rest\n } = useFieldApi(props)\n\n const invalid = validationError(meta as ExtendedFieldMeta, validateOnMount)\n\n return (\n <FormFieldGrid help={help} {...FormFieldGridProps}>\n <MuiDatePicker\n slotProps={{\n textField: {\n fullWidth: true,\n margin: 'normal',\n label,\n helperText:\n invalid ||\n ((meta.touched || validateOnMount) && meta.warning) ||\n helperText ||\n description,\n placeholder,\n required: isRequired,\n error: !!invalid,\n onBlur: input.onBlur,\n onFocus: input.onFocus,\n } as TextFieldProps,\n }}\n disabled={isDisabled || isReadOnly}\n readOnly={isReadOnly}\n {...input}\n value={input.value || null}\n {...DatePickerProps}\n {...rest}\n />\n </FormFieldGrid>\n )\n}\n\nexport default DatePicker\n"],"names":["DatePicker","MuiDatePicker","useFieldApi","FormFieldGrid","validationError","props","input","isReadOnly","isDisabled","placeholder","isRequired","label","helperText","description","validateOnMount","meta","help","FormFieldGridProps","DatePickerProps","rest","invalid","slotProps","textField","fullWidth","margin","touched","warning","required","error","onBlur","onFocus","disabled","readOnly","value"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;CAGC;;;AAID,SACEA,cAAcC,aAAa,QAEtB,sBAAqB;AAE5B,SAASC,WAAW,QAAQ,iCAA6B;AACzD,OAAOC,mBAAgD,uBAAmB;AAE1E,SAAiCC,eAAe,QAAQ,wBAAoB;AAW5E,OAAO,MAAMJ,aAAa,CAACK;IACzB,MAeIH,eAAAA,YAAYG,QAfV,EACJC,KAAK,EACLC,UAAU,EACVC,UAAU,EACVC,WAAW,EACXC,UAAU,EACVC,KAAK,EACLC,UAAU,EACVC,WAAW,EACXC,eAAe,EACfC,IAAI,EACJC,IAAI,EACJC,qBAAqB,CAAC,CAAC,EACvBC,kBAAkB,CAAC,CAAC,EAErB,GAAGhB,cADCiB,wCACDjB;;;;;;;;;;;;;;;IAEJ,MAAMkB,UAAUhB,gBAAgBW,MAA2BD;IAE3D,qBACE,KAACX;QAAca,MAAMA;OAAUC;kBAC7B,cAAA,KAAChB;YACCoB,WAAW;gBACTC,WAAW;oBACTC,WAAW;oBACXC,QAAQ;oBACRb;oBACAC,YACEQ,WACC,AAACL,CAAAA,KAAKU,OAAO,IAAIX,eAAc,KAAMC,KAAKW,OAAO,IAClDd,cACAC;oBACFJ;oBACAkB,UAAUjB;oBACVkB,OAAO,CAAC,CAACR;oBACTS,QAAQvB,MAAMuB,MAAM;oBACpBC,SAASxB,MAAMwB,OAAO;gBACxB;YACF;YACAC,UAAUvB,cAAcD;YACxByB,UAAUzB;WACND;YACJ2B,OAAO3B,MAAM2B,KAAK,IAAI;WAClBf,iBACAC;;AAIZ,EAAC;AAED,eAAenB,WAAU"}