@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.
- package/LICENSE +201 -0
- package/README.md +7 -0
- package/package.json +52 -0
- package/src/index.d.ts +17 -0
- package/src/index.js +18 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/color-picker-tokens.d.ts +135 -0
- package/src/lib/components/color-picker-tokens.js +431 -0
- package/src/lib/components/color-picker-tokens.js.map +1 -0
- package/src/lib/components/color-picker.component.d.ts +64 -0
- package/src/lib/components/color-picker.component.js +322 -0
- package/src/lib/components/color-picker.component.js.map +1 -0
- package/src/lib/components/create-artifact-drawer.component.d.ts +100 -0
- package/src/lib/components/create-artifact-drawer.component.js +184 -0
- package/src/lib/components/create-artifact-drawer.component.js.map +1 -0
- package/src/lib/components/grid-form-template.component.d.ts +21 -0
- package/src/lib/components/grid-form-template.component.js +81 -0
- package/src/lib/components/grid-form-template.component.js.map +1 -0
- package/src/lib/components/icon-select.component.d.ts +52 -0
- package/src/lib/components/icon-select.component.js +453 -0
- package/src/lib/components/icon-select.component.js.map +1 -0
- package/src/lib/components/select.component.d.ts +58 -0
- package/src/lib/components/select.component.js +107 -0
- package/src/lib/components/select.component.js.map +1 -0
- package/src/lib/components/switch.component.d.ts +38 -0
- package/src/lib/components/switch.component.js +76 -0
- package/src/lib/components/switch.component.js.map +1 -0
- package/src/lib/components/text-field.component.d.ts +45 -0
- package/src/lib/components/text-field.component.js +77 -0
- package/src/lib/components/text-field.component.js.map +1 -0
- package/src/lib/components/textarea.component.d.ts +45 -0
- package/src/lib/components/textarea.component.js +61 -0
- package/src/lib/components/textarea.component.js.map +1 -0
- package/src/lib/components/toggle-button.component.d.ts +27 -0
- package/src/lib/components/toggle-button.component.js +116 -0
- package/src/lib/components/toggle-button.component.js.map +1 -0
- package/src/lib/constants/component-mappers.d.ts +42 -0
- package/src/lib/constants/component-mappers.js +70 -0
- package/src/lib/constants/component-mappers.js.map +1 -0
- package/src/lib/constants/dynamic-fields.d.ts +45 -0
- package/src/lib/constants/dynamic-fields.js +65 -0
- package/src/lib/constants/dynamic-fields.js.map +1 -0
- package/src/lib/constants/field-configurations.d.ts +53 -0
- package/src/lib/constants/field-configurations.js +121 -0
- package/src/lib/constants/field-configurations.js.map +1 -0
- package/src/lib/constants/flags.d.ts +72 -0
- package/src/lib/constants/flags.js +69 -0
- package/src/lib/constants/flags.js.map +1 -0
- package/src/lib/hocs/with-grid-item.d.ts +25 -0
- package/src/lib/hocs/with-grid-item.js +48 -0
- package/src/lib/hocs/with-grid-item.js.map +1 -0
- package/src/lib/jsx-forms.d.ts +41 -0
- package/src/lib/jsx-forms.js +42 -0
- package/src/lib/jsx-forms.js.map +1 -0
- package/src/lib/mapper/breakpoint-span.d.ts +73 -0
- package/src/lib/mapper/breakpoint-span.js +346 -0
- package/src/lib/mapper/breakpoint-span.js.map +1 -0
- package/src/lib/mapper/checkbox.d.ts +43 -0
- package/src/lib/mapper/checkbox.js +111 -0
- package/src/lib/mapper/checkbox.js.map +1 -0
- package/src/lib/mapper/css-border.d.ts +113 -0
- package/src/lib/mapper/css-border.js +410 -0
- package/src/lib/mapper/css-border.js.map +1 -0
- package/src/lib/mapper/css-dimension.d.ts +89 -0
- package/src/lib/mapper/css-dimension.js +327 -0
- package/src/lib/mapper/css-dimension.js.map +1 -0
- package/src/lib/mapper/css-gradient.d.ts +110 -0
- package/src/lib/mapper/css-gradient.js +720 -0
- package/src/lib/mapper/css-gradient.js.map +1 -0
- package/src/lib/mapper/data-table.d.ts +23 -0
- package/src/lib/mapper/data-table.js +296 -0
- package/src/lib/mapper/data-table.js.map +1 -0
- package/src/lib/mapper/date-picker.d.ts +26 -0
- package/src/lib/mapper/date-picker.js +69 -0
- package/src/lib/mapper/date-picker.js.map +1 -0
- package/src/lib/mapper/dual-list-select.d.ts +115 -0
- package/src/lib/mapper/dual-list-select.js +353 -0
- package/src/lib/mapper/dual-list-select.js.map +1 -0
- package/src/lib/mapper/field-array.d.ts +71 -0
- package/src/lib/mapper/field-array.js +326 -0
- package/src/lib/mapper/field-array.js.map +1 -0
- package/src/lib/mapper/form-field-grid.d.ts +155 -0
- package/src/lib/mapper/form-field-grid.js +194 -0
- package/src/lib/mapper/form-field-grid.js.map +1 -0
- package/src/lib/mapper/index.d.ts +50 -0
- package/src/lib/mapper/index.js +49 -0
- package/src/lib/mapper/index.js.map +1 -0
- package/src/lib/mapper/multiple-choice-list.d.ts +32 -0
- package/src/lib/mapper/multiple-choice-list.js +105 -0
- package/src/lib/mapper/multiple-choice-list.js.map +1 -0
- package/src/lib/mapper/plain-text.d.ts +31 -0
- package/src/lib/mapper/plain-text.js +48 -0
- package/src/lib/mapper/plain-text.js.map +1 -0
- package/src/lib/mapper/preset-choice.d.ts +106 -0
- package/src/lib/mapper/preset-choice.js +267 -0
- package/src/lib/mapper/preset-choice.js.map +1 -0
- package/src/lib/mapper/radio.d.ts +40 -0
- package/src/lib/mapper/radio.js +122 -0
- package/src/lib/mapper/radio.js.map +1 -0
- package/src/lib/mapper/select.d.ts +60 -0
- package/src/lib/mapper/select.js +203 -0
- package/src/lib/mapper/select.js.map +1 -0
- package/src/lib/mapper/slider.d.ts +45 -0
- package/src/lib/mapper/slider.js +119 -0
- package/src/lib/mapper/slider.js.map +1 -0
- package/src/lib/mapper/stored-field-value.d.ts +23 -0
- package/src/lib/mapper/stored-field-value.js +29 -0
- package/src/lib/mapper/stored-field-value.js.map +1 -0
- package/src/lib/mapper/sub-form.d.ts +39 -0
- package/src/lib/mapper/sub-form.js +108 -0
- package/src/lib/mapper/sub-form.js.map +1 -0
- package/src/lib/mapper/switch.d.ts +47 -0
- package/src/lib/mapper/switch.js +93 -0
- package/src/lib/mapper/switch.js.map +1 -0
- package/src/lib/mapper/tabs.d.ts +34 -0
- package/src/lib/mapper/tabs.js +64 -0
- package/src/lib/mapper/tabs.js.map +1 -0
- package/src/lib/mapper/text-field.d.ts +33 -0
- package/src/lib/mapper/text-field.js +88 -0
- package/src/lib/mapper/text-field.js.map +1 -0
- package/src/lib/mapper/textarea.d.ts +31 -0
- package/src/lib/mapper/textarea.js +68 -0
- package/src/lib/mapper/textarea.js.map +1 -0
- package/src/lib/mapper/theme-scale.d.ts +79 -0
- package/src/lib/mapper/theme-scale.js +162 -0
- package/src/lib/mapper/theme-scale.js.map +1 -0
- package/src/lib/mapper/time-picker.d.ts +26 -0
- package/src/lib/mapper/time-picker.js +69 -0
- package/src/lib/mapper/time-picker.js.map +1 -0
- package/src/lib/mapper/types.d.ts +43 -0
- package/src/lib/mapper/types.js +22 -0
- package/src/lib/mapper/types.js.map +1 -0
- package/src/lib/mapper/validation-error.d.ts +24 -0
- package/src/lib/mapper/validation-error.js +24 -0
- package/src/lib/mapper/validation-error.js.map +1 -0
- package/src/lib/mapper/wizard.d.ts +21 -0
- package/src/lib/mapper/wizard.js +203 -0
- package/src/lib/mapper/wizard.js.map +1 -0
- package/src/lib/types.d.ts +19 -0
- package/src/lib/types.js +18 -0
- package/src/lib/types.js.map +1 -0
- package/src/lib/utils/option-is-equal-to-value.d.ts +20 -0
- package/src/lib/utils/option-is-equal-to-value.js +21 -0
- package/src/lib/utils/option-is-equal-to-value.js.map +1 -0
- package/src/lib/utils/validation-message.d.ts +22 -0
- package/src/lib/utils/validation-message.js +24 -0
- package/src/lib/utils/validation-message.js.map +1 -0
- package/src/lib/vendor/data-driven-forms.d.ts +33 -0
- package/src/lib/vendor/data-driven-forms.js +29 -0
- package/src/lib/vendor/data-driven-forms.js.map +1 -0
|
@@ -0,0 +1,106 @@
|
|
|
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
|
+
/**
|
|
20
|
+
* PresetChoice (AGL-2486): a named-preset picker with a raw escape hatch, for
|
|
21
|
+
* the properties whose honest answer is "pick one of these five" but whose CSS
|
|
22
|
+
* is a grammar.
|
|
23
|
+
*
|
|
24
|
+
* Three fields in the styles panel have that shape. Corner Radius as a text
|
|
25
|
+
* box can only offer `8px, 50%, or a theme spacing number` — three value
|
|
26
|
+
* systems in one helper line. A Shadow select with no escape hatch has to send
|
|
27
|
+
* the author to the custom-CSS section for anything off the list. Font Family
|
|
28
|
+
* as free text can advise "prefer theme typography" and give no way to act
|
|
29
|
+
* on it.
|
|
30
|
+
*
|
|
31
|
+
* All three are built here as: **the theme's own answers first, then a short
|
|
32
|
+
* list of plain-English presets, then Custom…** — and the preset shows what it
|
|
33
|
+
* looks like rather than what to type.
|
|
34
|
+
*
|
|
35
|
+
* **The persisted value is whatever the property already stored** — a
|
|
36
|
+
* number for the theme-multiple properties, a CSS string otherwise. This is
|
|
37
|
+
* an input affordance, not a shape change.
|
|
38
|
+
*
|
|
39
|
+
* **A stored value that matches no preset opens the field in its custom
|
|
40
|
+
* state showing that value**, so a hand-authored `box-shadow` or font stack
|
|
41
|
+
* round-trips and keeps rendering. That is the rule for every editor in
|
|
42
|
+
* this panel: the mode is DERIVED from the value, never remembered in a
|
|
43
|
+
* flag, so an author who typed raw CSS last month is never told their value
|
|
44
|
+
* is gone.
|
|
45
|
+
*/
|
|
46
|
+
/** One offered preset. */
|
|
47
|
+
export interface PresetChoiceOption {
|
|
48
|
+
/**
|
|
49
|
+
* The value STORED.
|
|
50
|
+
*
|
|
51
|
+
* A NUMBER where the property's bare number is a theme multiple —
|
|
52
|
+
* `borderRadius: 2` renders 8px through `shape.borderRadius`, and the
|
|
53
|
+
* string `'2'` would reach CSS as `border-radius: 2` and be dropped. The
|
|
54
|
+
* panel's own `normalizeStyleValue` enforces the same rule one level up;
|
|
55
|
+
* emitting the number here means it never has to rescue this field.
|
|
56
|
+
*/
|
|
57
|
+
value: string | number;
|
|
58
|
+
/** The author's name for it (`Rounded`, `Soft shadow`, `Sans-serif`). */
|
|
59
|
+
label: string;
|
|
60
|
+
/** What it resolves to in this theme today (`8px`, `system default`). */
|
|
61
|
+
hint?: string;
|
|
62
|
+
/**
|
|
63
|
+
* CSS the menu row renders ITSELF with, so the choice is made by looking
|
|
64
|
+
* rather than by reading. See {@link PresetChoiceProps.previewKind}.
|
|
65
|
+
*/
|
|
66
|
+
preview?: string;
|
|
67
|
+
}
|
|
68
|
+
/** How a menu row shows what the preset does. */
|
|
69
|
+
export type PresetChoicePreview = 'none' | 'shadow' | 'radius' | 'font';
|
|
70
|
+
export interface PresetChoiceProps extends BaseFieldProps {
|
|
71
|
+
choices?: PresetChoiceOption[];
|
|
72
|
+
/**
|
|
73
|
+
* What the preview swatch on each row demonstrates. `font` renders the
|
|
74
|
+
* option's own label in that face — the only preview that tells a
|
|
75
|
+
* non-developer anything about a font stack. `shadow` and `radius` draw a
|
|
76
|
+
* small tile carrying the value.
|
|
77
|
+
*/
|
|
78
|
+
previewKind?: PresetChoicePreview;
|
|
79
|
+
/** Label of the escape-hatch entry; defaults to `Custom…`. */
|
|
80
|
+
customLabel?: string;
|
|
81
|
+
/** Helper shown while the raw text box is open. */
|
|
82
|
+
customHelperText?: string;
|
|
83
|
+
placeholder?: string;
|
|
84
|
+
/** Offer the reset-to-unset affordance (AGL-2486). */
|
|
85
|
+
clearable?: boolean;
|
|
86
|
+
FormFieldGridProps?: FormFieldGridProps;
|
|
87
|
+
}
|
|
88
|
+
/** Sentinel for the escape-hatch entry. Never a stored value. */
|
|
89
|
+
export declare const PRESET_CHOICE_CUSTOM = "__custom__";
|
|
90
|
+
/** The text a stored value shows in the raw box. */
|
|
91
|
+
export declare const presetChoiceValueToText: (value: unknown) => string;
|
|
92
|
+
/**
|
|
93
|
+
* The preset a stored value names, compared as TEXT.
|
|
94
|
+
*
|
|
95
|
+
* A stored `2` and an option whose value is the number `2` are the same
|
|
96
|
+
* choice, and so are a stored `'50%'` and the string option — but the form
|
|
97
|
+
* value round-trips through controls that can only hand back strings, so
|
|
98
|
+
* comparing by identity would show "Custom" for a value the author picked
|
|
99
|
+
* from this very menu one render ago.
|
|
100
|
+
*/
|
|
101
|
+
export declare const findPresetChoice: (choices: PresetChoiceOption[], value: unknown) => PresetChoiceOption | undefined;
|
|
102
|
+
export declare const PresetChoiceField: {
|
|
103
|
+
(props: PresetChoiceProps): import("react").JSX.Element;
|
|
104
|
+
displayName: string;
|
|
105
|
+
};
|
|
106
|
+
export default PresetChoiceField;
|
|
@@ -0,0 +1,267 @@
|
|
|
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 { Box, MenuItem, TextField as MuiTextField, Typography } from "@mui/material";
|
|
20
|
+
import { useCallback, useState } from "react";
|
|
21
|
+
import { useFieldApi } from "../vendor/data-driven-forms.js";
|
|
22
|
+
import FormFieldGrid, { buildFieldClear } from "./form-field-grid.js";
|
|
23
|
+
import { validationError } from "./validation-error.js";
|
|
24
|
+
/** Sentinel for the escape-hatch entry. Never a stored value. */ export const PRESET_CHOICE_CUSTOM = '__custom__';
|
|
25
|
+
/** The text a stored value shows in the raw box. */ export const presetChoiceValueToText = (value)=>{
|
|
26
|
+
if (value === undefined || value === null) return '';
|
|
27
|
+
if (typeof value === 'number') return Number.isFinite(value) ? `${value}` : '';
|
|
28
|
+
return `${value}`;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The preset a stored value names, compared as TEXT.
|
|
32
|
+
*
|
|
33
|
+
* A stored `2` and an option whose value is the number `2` are the same
|
|
34
|
+
* choice, and so are a stored `'50%'` and the string option — but the form
|
|
35
|
+
* value round-trips through controls that can only hand back strings, so
|
|
36
|
+
* comparing by identity would show "Custom" for a value the author picked
|
|
37
|
+
* from this very menu one render ago.
|
|
38
|
+
*/ export const findPresetChoice = (choices, value)=>{
|
|
39
|
+
const text = presetChoiceValueToText(value);
|
|
40
|
+
if (text === '') return undefined;
|
|
41
|
+
return choices.find((choice)=>presetChoiceValueToText(choice.value) === text);
|
|
42
|
+
};
|
|
43
|
+
/** The swatch that shows what a preset does, or null when it shows nothing. */ const PresetPreview = (props)=>{
|
|
44
|
+
var _option_preview;
|
|
45
|
+
const { kind, option } = props;
|
|
46
|
+
const preview = (_option_preview = option.preview) != null ? _option_preview : presetChoiceValueToText(option.value);
|
|
47
|
+
if (kind === 'none' || kind === 'font' || preview === '') return null;
|
|
48
|
+
return /*#__PURE__*/ _jsx(Box, {
|
|
49
|
+
"aria-hidden": true,
|
|
50
|
+
sx: _extends({
|
|
51
|
+
width: 26,
|
|
52
|
+
height: 18,
|
|
53
|
+
flexShrink: 0,
|
|
54
|
+
// A neutral tile the effect is applied TO. `background.paper`
|
|
55
|
+
// rather than a literal so the swatch stays legible in both
|
|
56
|
+
// schemes — the console chrome is theme-aware here.
|
|
57
|
+
backgroundColor: 'background.paper',
|
|
58
|
+
border: 1,
|
|
59
|
+
borderColor: 'divider'
|
|
60
|
+
}, kind === 'shadow' ? {
|
|
61
|
+
boxShadow: preview === 'none' ? 'none' : preview
|
|
62
|
+
} : {
|
|
63
|
+
borderRadius: preview
|
|
64
|
+
})
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
export const PresetChoiceField = (props)=>{
|
|
68
|
+
const _useFieldApi = useFieldApi(props), { input, isReadOnly, isDisabled, isRequired, label, placeholder, helperText, description, validateOnMount, meta, help, choices = [], previewKind = 'none', customLabel = 'Custom…', customHelperText, clearable, FormFieldGridProps = {}, // Schema leftovers from the TEXT_FIELD/SELECT these were authored as.
|
|
69
|
+
inputProps: _inputProps, InputProps: _InputProps, multiline: _multiline, type: _type, options: _options } = _useFieldApi, rest = _object_without_properties_loose(_useFieldApi, [
|
|
70
|
+
"input",
|
|
71
|
+
"isReadOnly",
|
|
72
|
+
"isDisabled",
|
|
73
|
+
"isRequired",
|
|
74
|
+
"label",
|
|
75
|
+
"placeholder",
|
|
76
|
+
"helperText",
|
|
77
|
+
"description",
|
|
78
|
+
"validateOnMount",
|
|
79
|
+
"meta",
|
|
80
|
+
"help",
|
|
81
|
+
"choices",
|
|
82
|
+
"previewKind",
|
|
83
|
+
"customLabel",
|
|
84
|
+
"customHelperText",
|
|
85
|
+
"clearable",
|
|
86
|
+
"FormFieldGridProps",
|
|
87
|
+
"inputProps",
|
|
88
|
+
"InputProps",
|
|
89
|
+
"multiline",
|
|
90
|
+
"type",
|
|
91
|
+
"options"
|
|
92
|
+
]);
|
|
93
|
+
const invalid = validationError(meta, validateOnMount);
|
|
94
|
+
const text = presetChoiceValueToText(input.value);
|
|
95
|
+
const matched = findPresetChoice(choices, input.value);
|
|
96
|
+
/**
|
|
97
|
+
* The raw box is open because the AUTHOR asked for it.
|
|
98
|
+
*
|
|
99
|
+
* The other reason it opens — a stored value that matches no preset — is
|
|
100
|
+
* DERIVED below rather than mirrored into this flag, and that distinction
|
|
101
|
+
* is load-bearing. `choices` come from the site theme, which resolves
|
|
102
|
+
* ASYNCHRONOUSLY: the styles panel mounts before `useHostThemeDocument`
|
|
103
|
+
* answers, so on first render every preset list is empty and every stored
|
|
104
|
+
* value "matches no preset". A remembered flag would latch that and every
|
|
105
|
+
* preset field would sit in its custom state showing a raw `2` for the
|
|
106
|
+
* rest of the session, with the real menu one render away and unreachable
|
|
107
|
+
* — a mutation test caught exactly this.
|
|
108
|
+
*
|
|
109
|
+
* Deriving instead makes the control self-healing: the moment the theme
|
|
110
|
+
* arrives and the value matches, the preset menu takes over on its own.
|
|
111
|
+
* The flag is only ever set by a click on Custom…, and cleared by
|
|
112
|
+
* choosing a preset or by clearing the field, so it can never disagree
|
|
113
|
+
* with a value it did not cause.
|
|
114
|
+
*/ const [customPicked, setCustomPicked] = useState(false);
|
|
115
|
+
const custom = customPicked || text !== '' && !matched;
|
|
116
|
+
const commit = useCallback((next)=>{
|
|
117
|
+
input.onChange(next);
|
|
118
|
+
}, [
|
|
119
|
+
input
|
|
120
|
+
]);
|
|
121
|
+
const clear = buildFieldClear({
|
|
122
|
+
clearable,
|
|
123
|
+
label,
|
|
124
|
+
hasValue: text !== '',
|
|
125
|
+
locked: Boolean(isDisabled || isReadOnly),
|
|
126
|
+
onClear: ()=>{
|
|
127
|
+
setCustomPicked(false);
|
|
128
|
+
commit('');
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
const handleSelect = useCallback((event)=>{
|
|
132
|
+
var _event_target_value;
|
|
133
|
+
const picked = `${(_event_target_value = event.target.value) != null ? _event_target_value : ''}`;
|
|
134
|
+
if (picked === PRESET_CHOICE_CUSTOM) {
|
|
135
|
+
// Opening the raw box must NOT clear what is already there: the
|
|
136
|
+
// commonest reason to open it is to tweak a preset by hand.
|
|
137
|
+
setCustomPicked(true);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
setCustomPicked(false);
|
|
141
|
+
const choice = choices.find((entry)=>presetChoiceValueToText(entry.value) === picked);
|
|
142
|
+
// The option's own `value` is emitted, not the select's string, so a
|
|
143
|
+
// numeric preset stays a NUMBER and keeps its theme-multiple meaning.
|
|
144
|
+
commit(choice ? choice.value : '');
|
|
145
|
+
}, [
|
|
146
|
+
choices,
|
|
147
|
+
commit
|
|
148
|
+
]);
|
|
149
|
+
const selectValue = custom ? PRESET_CHOICE_CUSTOM : matched ? presetChoiceValueToText(matched.value) : '';
|
|
150
|
+
return /*#__PURE__*/ _jsxs(FormFieldGrid, _extends({
|
|
151
|
+
help: help,
|
|
152
|
+
clear: clear
|
|
153
|
+
}, FormFieldGridProps, {
|
|
154
|
+
children: [
|
|
155
|
+
/*#__PURE__*/ _jsxs(MuiTextField, _extends({}, rest, {
|
|
156
|
+
select: true,
|
|
157
|
+
name: custom ? `${input.name}-preset` : input.name,
|
|
158
|
+
value: selectValue,
|
|
159
|
+
onChange: handleSelect,
|
|
160
|
+
fullWidth: true,
|
|
161
|
+
size: "small",
|
|
162
|
+
margin: "dense",
|
|
163
|
+
error: !!invalid && !custom,
|
|
164
|
+
helperText: custom ? undefined : invalid || (meta.touched || validateOnMount) && meta.warning || // Naming what the preset resolves to is what makes it
|
|
165
|
+
// checkable: `Rounded` means nothing until it says `8px`.
|
|
166
|
+
((matched == null ? void 0 : matched.hint) ? `${matched.label} — ${matched.hint}` : undefined) || helperText || description,
|
|
167
|
+
disabled: isDisabled,
|
|
168
|
+
label: label,
|
|
169
|
+
required: isRequired,
|
|
170
|
+
slotProps: {
|
|
171
|
+
select: {
|
|
172
|
+
displayEmpty: true
|
|
173
|
+
},
|
|
174
|
+
// `displayEmpty` renders "Not set" in the box while the value is
|
|
175
|
+
// empty, and MUI only floats a label once it thinks there IS a
|
|
176
|
+
// value — so the label sat ON the placeholder. Pinning it shrunk
|
|
177
|
+
// is the documented pairing for `displayEmpty` and is the same
|
|
178
|
+
// fix `CssDimension` carries for its keyword values (AGL-2486).
|
|
179
|
+
inputLabel: {
|
|
180
|
+
shrink: true
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
children: [
|
|
184
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
185
|
+
value: "",
|
|
186
|
+
children: /*#__PURE__*/ _jsx("em", {
|
|
187
|
+
children: 'Not set'
|
|
188
|
+
})
|
|
189
|
+
}),
|
|
190
|
+
choices.map((choice)=>{
|
|
191
|
+
var _choice_preview;
|
|
192
|
+
return /*#__PURE__*/ _jsx(MenuItem, {
|
|
193
|
+
value: presetChoiceValueToText(choice.value),
|
|
194
|
+
children: /*#__PURE__*/ _jsxs(Box, {
|
|
195
|
+
sx: {
|
|
196
|
+
display: 'flex',
|
|
197
|
+
alignItems: 'center',
|
|
198
|
+
gap: 1,
|
|
199
|
+
width: '100%',
|
|
200
|
+
minWidth: 0
|
|
201
|
+
},
|
|
202
|
+
children: [
|
|
203
|
+
/*#__PURE__*/ _jsx(PresetPreview, {
|
|
204
|
+
kind: previewKind,
|
|
205
|
+
option: choice
|
|
206
|
+
}),
|
|
207
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
208
|
+
variant: "body2",
|
|
209
|
+
noWrap: true,
|
|
210
|
+
sx: _extends({
|
|
211
|
+
flexGrow: 1,
|
|
212
|
+
minWidth: 0
|
|
213
|
+
}, previewKind === 'font' ? {
|
|
214
|
+
fontFamily: (_choice_preview = choice.preview) != null ? _choice_preview : presetChoiceValueToText(choice.value)
|
|
215
|
+
} : {}),
|
|
216
|
+
children: choice.label
|
|
217
|
+
}),
|
|
218
|
+
choice.hint ? /*#__PURE__*/ _jsx(Typography, {
|
|
219
|
+
variant: "caption",
|
|
220
|
+
color: "text.secondary",
|
|
221
|
+
noWrap: true,
|
|
222
|
+
children: choice.hint
|
|
223
|
+
}) : null
|
|
224
|
+
]
|
|
225
|
+
})
|
|
226
|
+
}, presetChoiceValueToText(choice.value));
|
|
227
|
+
}),
|
|
228
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
229
|
+
value: PRESET_CHOICE_CUSTOM,
|
|
230
|
+
children: /*#__PURE__*/ _jsx("em", {
|
|
231
|
+
children: customLabel
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
]
|
|
235
|
+
})),
|
|
236
|
+
custom ? /*#__PURE__*/ _jsx(MuiTextField, {
|
|
237
|
+
name: input.name,
|
|
238
|
+
value: text,
|
|
239
|
+
onChange: (event)=>commit(event.target.value),
|
|
240
|
+
onBlur: input.onBlur,
|
|
241
|
+
onFocus: input.onFocus,
|
|
242
|
+
fullWidth: true,
|
|
243
|
+
size: "small",
|
|
244
|
+
margin: "dense",
|
|
245
|
+
error: !!invalid,
|
|
246
|
+
helperText: invalid || (meta.touched || validateOnMount) && meta.warning || customHelperText || helperText || description,
|
|
247
|
+
disabled: isDisabled,
|
|
248
|
+
placeholder: placeholder,
|
|
249
|
+
slotProps: {
|
|
250
|
+
htmlInput: {
|
|
251
|
+
readOnly: isReadOnly,
|
|
252
|
+
// The visible label belongs to the SELECT — it names the
|
|
253
|
+
// field — so the raw box needs an accessible name of its
|
|
254
|
+
// own, or it is an unlabelled input that screen readers and
|
|
255
|
+
// tests both read as anonymous. Qualified rather than
|
|
256
|
+
// duplicated, because both are on screen at once.
|
|
257
|
+
'aria-label': typeof label === 'string' ? `${label} custom value` : `${input.name} custom value`
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}) : null
|
|
261
|
+
]
|
|
262
|
+
}));
|
|
263
|
+
};
|
|
264
|
+
PresetChoiceField.displayName = 'AglynPresetChoiceField';
|
|
265
|
+
export default PresetChoiceField;
|
|
266
|
+
|
|
267
|
+
//# sourceMappingURL=preset-choice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx-forms/src/lib/mapper/preset-choice.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 Box,\n MenuItem,\n TextField as MuiTextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useState } from 'react'\n\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 * PresetChoice (AGL-2486): a named-preset picker with a raw escape hatch, for\n * the properties whose honest answer is \"pick one of these five\" but whose CSS\n * is a grammar.\n *\n * Three fields in the styles panel have that shape. Corner Radius as a text\n * box can only offer `8px, 50%, or a theme spacing number` — three value\n * systems in one helper line. A Shadow select with no escape hatch has to send\n * the author to the custom-CSS section for anything off the list. Font Family\n * as free text can advise \"prefer theme typography\" and give no way to act\n * on it.\n *\n * All three are built here as: **the theme's own answers first, then a short\n * list of plain-English presets, then Custom…** — and the preset shows what it\n * looks like rather than what to type.\n *\n * **The persisted value is whatever the property already stored** — a\n * number for the theme-multiple properties, a CSS string otherwise. This is\n * an input affordance, not a shape change.\n *\n * **A stored value that matches no preset opens the field in its custom\n * state showing that value**, so a hand-authored `box-shadow` or font stack\n * round-trips and keeps rendering. That is the rule for every editor in\n * this panel: the mode is DERIVED from the value, never remembered in a\n * flag, so an author who typed raw CSS last month is never told their value\n * is gone.\n */\n\n/** One offered preset. */\nexport interface PresetChoiceOption {\n /**\n * The value STORED.\n *\n * A NUMBER where the property's bare number is a theme multiple —\n * `borderRadius: 2` renders 8px through `shape.borderRadius`, and the\n * string `'2'` would reach CSS as `border-radius: 2` and be dropped. The\n * panel's own `normalizeStyleValue` enforces the same rule one level up;\n * emitting the number here means it never has to rescue this field.\n */\n value: string | number\n /** The author's name for it (`Rounded`, `Soft shadow`, `Sans-serif`). */\n label: string\n /** What it resolves to in this theme today (`8px`, `system default`). */\n hint?: string\n /**\n * CSS the menu row renders ITSELF with, so the choice is made by looking\n * rather than by reading. See {@link PresetChoiceProps.previewKind}.\n */\n preview?: string\n}\n\n/** How a menu row shows what the preset does. */\nexport type PresetChoicePreview = 'none' | 'shadow' | 'radius' | 'font'\n\nexport interface PresetChoiceProps extends BaseFieldProps {\n choices?: PresetChoiceOption[]\n /**\n * What the preview swatch on each row demonstrates. `font` renders the\n * option's own label in that face — the only preview that tells a\n * non-developer anything about a font stack. `shadow` and `radius` draw a\n * small tile carrying the value.\n */\n previewKind?: PresetChoicePreview\n /** Label of the escape-hatch entry; defaults to `Custom…`. */\n customLabel?: string\n /** Helper shown while the raw text box is open. */\n customHelperText?: string\n placeholder?: string\n /** Offer the reset-to-unset affordance (AGL-2486). */\n clearable?: boolean\n FormFieldGridProps?: FormFieldGridProps\n}\n\n/** Sentinel for the escape-hatch entry. Never a stored value. */\nexport const PRESET_CHOICE_CUSTOM = '__custom__'\n\n/** The text a stored value shows in the raw box. */\nexport const presetChoiceValueToText = (value: unknown): string => {\n if (value === undefined || value === null) return ''\n if (typeof value === 'number') return Number.isFinite(value) ? `${value}` : ''\n return `${value}`\n}\n\n/**\n * The preset a stored value names, compared as TEXT.\n *\n * A stored `2` and an option whose value is the number `2` are the same\n * choice, and so are a stored `'50%'` and the string option — but the form\n * value round-trips through controls that can only hand back strings, so\n * comparing by identity would show \"Custom\" for a value the author picked\n * from this very menu one render ago.\n */\nexport const findPresetChoice = (\n choices: PresetChoiceOption[],\n value: unknown,\n): PresetChoiceOption | undefined => {\n const text = presetChoiceValueToText(value)\n if (text === '') return undefined\n return choices.find(\n (choice) => presetChoiceValueToText(choice.value) === text,\n )\n}\n\n/** The swatch that shows what a preset does, or null when it shows nothing. */\nconst PresetPreview = (props: {\n kind: PresetChoicePreview\n option: PresetChoiceOption\n}) => {\n const { kind, option } = props\n const preview = option.preview ?? presetChoiceValueToText(option.value)\n if (kind === 'none' || kind === 'font' || preview === '') return null\n return (\n <Box\n aria-hidden\n sx={{\n width: 26,\n height: 18,\n flexShrink: 0,\n // A neutral tile the effect is applied TO. `background.paper`\n // rather than a literal so the swatch stays legible in both\n // schemes — the console chrome is theme-aware here.\n backgroundColor: 'background.paper',\n border: 1,\n borderColor: 'divider',\n ...(kind === 'shadow'\n ? { boxShadow: preview === 'none' ? 'none' : preview }\n : { borderRadius: preview }),\n }}\n />\n )\n}\n\nexport const PresetChoiceField = (props: PresetChoiceProps) => {\n const {\n input,\n isReadOnly,\n isDisabled,\n isRequired,\n label,\n placeholder,\n helperText,\n description,\n validateOnMount,\n meta,\n help,\n choices = [],\n previewKind = 'none',\n customLabel = 'Custom…',\n customHelperText,\n clearable,\n FormFieldGridProps = {},\n // Schema leftovers from the TEXT_FIELD/SELECT these were authored as.\n inputProps: _inputProps,\n InputProps: _InputProps,\n multiline: _multiline,\n type: _type,\n options: _options,\n ...rest\n } = useFieldApi(props)\n\n const invalid = validationError(meta as ExtendedFieldMeta, validateOnMount)\n const text = presetChoiceValueToText(input.value)\n const matched = findPresetChoice(choices, input.value)\n\n /**\n * The raw box is open because the AUTHOR asked for it.\n *\n * The other reason it opens — a stored value that matches no preset — is\n * DERIVED below rather than mirrored into this flag, and that distinction\n * is load-bearing. `choices` come from the site theme, which resolves\n * ASYNCHRONOUSLY: the styles panel mounts before `useHostThemeDocument`\n * answers, so on first render every preset list is empty and every stored\n * value \"matches no preset\". A remembered flag would latch that and every\n * preset field would sit in its custom state showing a raw `2` for the\n * rest of the session, with the real menu one render away and unreachable\n * — a mutation test caught exactly this.\n *\n * Deriving instead makes the control self-healing: the moment the theme\n * arrives and the value matches, the preset menu takes over on its own.\n * The flag is only ever set by a click on Custom…, and cleared by\n * choosing a preset or by clearing the field, so it can never disagree\n * with a value it did not cause.\n */\n const [customPicked, setCustomPicked] = useState(false)\n const custom = customPicked || (text !== '' && !matched)\n\n const commit = useCallback(\n (next: string | number) => {\n input.onChange(next)\n },\n [input],\n )\n\n const clear = buildFieldClear({\n clearable,\n label,\n hasValue: text !== '',\n locked: Boolean(isDisabled || isReadOnly),\n onClear: () => {\n setCustomPicked(false)\n commit('')\n },\n })\n\n const handleSelect = useCallback(\n (event: { target: { value: unknown } }) => {\n const picked = `${event.target.value ?? ''}`\n if (picked === PRESET_CHOICE_CUSTOM) {\n // Opening the raw box must NOT clear what is already there: the\n // commonest reason to open it is to tweak a preset by hand.\n setCustomPicked(true)\n return\n }\n setCustomPicked(false)\n const choice = choices.find(\n (entry) => presetChoiceValueToText(entry.value) === picked,\n )\n // The option's own `value` is emitted, not the select's string, so a\n // numeric preset stays a NUMBER and keeps its theme-multiple meaning.\n commit(choice ? choice.value : '')\n },\n [choices, commit],\n )\n\n const selectValue = custom\n ? PRESET_CHOICE_CUSTOM\n : matched\n ? presetChoiceValueToText(matched.value)\n : ''\n\n return (\n <FormFieldGrid help={help} clear={clear} {...FormFieldGridProps}>\n <MuiTextField\n {...rest}\n select\n name={custom ? `${input.name}-preset` : input.name}\n value={selectValue}\n onChange={handleSelect}\n fullWidth\n size=\"small\"\n margin=\"dense\"\n error={!!invalid && !custom}\n helperText={\n custom\n ? undefined\n : invalid ||\n ((meta.touched || validateOnMount) && meta.warning) ||\n // Naming what the preset resolves to is what makes it\n // checkable: `Rounded` means nothing until it says `8px`.\n (matched?.hint\n ? `${matched.label} — ${matched.hint}`\n : undefined) ||\n helperText ||\n description\n }\n disabled={isDisabled}\n label={label}\n required={isRequired}\n slotProps={{\n select: { displayEmpty: true },\n // `displayEmpty` renders \"Not set\" in the box while the value is\n // empty, and MUI only floats a label once it thinks there IS a\n // value — so the label sat ON the placeholder. Pinning it shrunk\n // is the documented pairing for `displayEmpty` and is the same\n // fix `CssDimension` carries for its keyword values (AGL-2486).\n inputLabel: { shrink: true },\n }}\n >\n <MenuItem value=\"\">\n <em>{'Not set'}</em>\n </MenuItem>\n {choices.map((choice) => (\n <MenuItem\n key={presetChoiceValueToText(choice.value)}\n value={presetChoiceValueToText(choice.value)}\n >\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n width: '100%',\n minWidth: 0,\n }}\n >\n <PresetPreview kind={previewKind} option={choice} />\n <Typography\n variant=\"body2\"\n noWrap\n sx={{\n flexGrow: 1,\n minWidth: 0,\n // A font preset renders its own name in its own face —\n // the only preview that says anything useful about a\n // typeface to someone who cannot read a font stack.\n ...(previewKind === 'font'\n ? {\n fontFamily:\n choice.preview ??\n presetChoiceValueToText(choice.value),\n }\n : {}),\n }}\n >\n {choice.label}\n </Typography>\n {choice.hint ? (\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {choice.hint}\n </Typography>\n ) : null}\n </Box>\n </MenuItem>\n ))}\n <MenuItem value={PRESET_CHOICE_CUSTOM}>\n <em>{customLabel}</em>\n </MenuItem>\n </MuiTextField>\n {custom ? (\n <MuiTextField\n name={input.name}\n value={text}\n onChange={(event) => commit(event.target.value)}\n onBlur={input.onBlur}\n onFocus={input.onFocus}\n fullWidth\n size=\"small\"\n margin=\"dense\"\n error={!!invalid}\n helperText={\n invalid ||\n ((meta.touched || validateOnMount) && meta.warning) ||\n customHelperText ||\n helperText ||\n description\n }\n disabled={isDisabled}\n placeholder={placeholder}\n slotProps={{\n htmlInput: {\n readOnly: isReadOnly,\n // The visible label belongs to the SELECT — it names the\n // field — so the raw box needs an accessible name of its\n // own, or it is an unlabelled input that screen readers and\n // tests both read as anonymous. Qualified rather than\n // duplicated, because both are on screen at once.\n 'aria-label':\n typeof label === 'string'\n ? `${label} custom value`\n : `${input.name} custom value`,\n },\n }}\n />\n ) : null}\n </FormFieldGrid>\n )\n}\nPresetChoiceField.displayName = 'AglynPresetChoiceField'\n\nexport default PresetChoiceField\n"],"names":["Box","MenuItem","TextField","MuiTextField","Typography","useCallback","useState","useFieldApi","FormFieldGrid","buildFieldClear","validationError","PRESET_CHOICE_CUSTOM","presetChoiceValueToText","value","undefined","Number","isFinite","findPresetChoice","choices","text","find","choice","PresetPreview","props","option","kind","preview","aria-hidden","sx","width","height","flexShrink","backgroundColor","border","borderColor","boxShadow","borderRadius","PresetChoiceField","input","isReadOnly","isDisabled","isRequired","label","placeholder","helperText","description","validateOnMount","meta","help","previewKind","customLabel","customHelperText","clearable","FormFieldGridProps","inputProps","_inputProps","InputProps","_InputProps","multiline","_multiline","type","_type","options","_options","rest","invalid","matched","customPicked","setCustomPicked","custom","commit","next","onChange","clear","hasValue","locked","Boolean","onClear","handleSelect","event","picked","target","entry","selectValue","select","name","fullWidth","size","margin","error","touched","warning","hint","disabled","required","slotProps","displayEmpty","inputLabel","shrink","em","map","display","alignItems","gap","minWidth","variant","noWrap","flexGrow","fontFamily","color","onBlur","onFocus","htmlInput","readOnly","displayName"],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
/**
|
|
18
|
+
* Ported from `@data-driven-forms/mui-component-mapper` (Apache-2.0) and
|
|
19
|
+
* updated for the current MUI API (`slotProps` instead of `inputProps`).
|
|
20
|
+
*/
|
|
21
|
+
import { type FormControlLabelProps, type FormControlProps, type FormHelperTextProps, type FormLabelProps } from '@mui/material';
|
|
22
|
+
import { type FormFieldGridProps } from './form-field-grid';
|
|
23
|
+
import type { BaseFieldProps, OptionValue, SelectOption } from './types';
|
|
24
|
+
interface RadioFieldOptionProps {
|
|
25
|
+
inputProps?: Record<string, any>;
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
}
|
|
28
|
+
export interface RadioProps<T = OptionValue> extends BaseFieldProps {
|
|
29
|
+
options?: SelectOption<T>[];
|
|
30
|
+
/** Offer the reset-to-unset affordance (AGL-2486). */
|
|
31
|
+
clearable?: boolean;
|
|
32
|
+
FormFieldGridProps?: FormFieldGridProps;
|
|
33
|
+
FormControlProps?: FormControlProps;
|
|
34
|
+
FormLabelProps?: FormLabelProps;
|
|
35
|
+
FormHelperTextProps?: FormHelperTextProps;
|
|
36
|
+
FormControlLabelProps?: Partial<FormControlLabelProps>;
|
|
37
|
+
RadioProps?: RadioFieldOptionProps;
|
|
38
|
+
}
|
|
39
|
+
export declare function Radio<T = OptionValue>({ name, ...props }: RadioProps<T>): import("react").JSX.Element;
|
|
40
|
+
export default Radio;
|
|
@@ -0,0 +1,122 @@
|
|
|
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
|
+
*/ /**
|
|
20
|
+
* Ported from `@data-driven-forms/mui-component-mapper` (Apache-2.0) and
|
|
21
|
+
* updated for the current MUI API (`slotProps` instead of `inputProps`).
|
|
22
|
+
*/ import { FormControl, FormControlLabel, FormHelperText, FormLabel, Radio as MuiRadio } from "@mui/material";
|
|
23
|
+
import { styled } from "@mui/material/styles";
|
|
24
|
+
import { useFieldApi } from "../vendor/data-driven-forms.js";
|
|
25
|
+
import FormFieldGrid, { buildFieldClear } from "./form-field-grid.js";
|
|
26
|
+
import { useStoredFieldHasValue } from "./stored-field-value.js";
|
|
27
|
+
import { validationError } from "./validation-error.js";
|
|
28
|
+
const PREFIX = 'Radio';
|
|
29
|
+
const classes = {
|
|
30
|
+
grid: `${PREFIX}-grid`
|
|
31
|
+
};
|
|
32
|
+
const StyledFormFieldGrid = styled(FormFieldGrid)(()=>({
|
|
33
|
+
[`&.${classes.grid}`]: {
|
|
34
|
+
'&:first-of-type': {
|
|
35
|
+
marginTop: 8
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}));
|
|
39
|
+
function RadioOption(_0) {
|
|
40
|
+
let { name, option, isDisabled, isReadOnly, FormControlLabelProps, RadioProps: _ref = {} } = _0, { inputProps } = _ref, RadioProps = _object_without_properties_loose(_ref, [
|
|
41
|
+
"inputProps"
|
|
42
|
+
]), props = _object_without_properties_loose(_0, [
|
|
43
|
+
"name",
|
|
44
|
+
"option",
|
|
45
|
+
"isDisabled",
|
|
46
|
+
"isReadOnly",
|
|
47
|
+
"FormControlLabelProps",
|
|
48
|
+
"RadioProps"
|
|
49
|
+
]);
|
|
50
|
+
const { input } = useFieldApi({
|
|
51
|
+
name,
|
|
52
|
+
type: 'radio',
|
|
53
|
+
value: option.value
|
|
54
|
+
});
|
|
55
|
+
return /*#__PURE__*/ _jsx(FormControlLabel, _extends({
|
|
56
|
+
control: /*#__PURE__*/ _jsx(MuiRadio, _extends({}, input, {
|
|
57
|
+
name: name,
|
|
58
|
+
disabled: isDisabled || isReadOnly,
|
|
59
|
+
onChange: ()=>input.onChange(option.value),
|
|
60
|
+
slotProps: {
|
|
61
|
+
input: _extends({
|
|
62
|
+
readOnly: isReadOnly
|
|
63
|
+
}, inputProps)
|
|
64
|
+
}
|
|
65
|
+
}, RadioProps)),
|
|
66
|
+
label: option.label
|
|
67
|
+
}, FormControlLabelProps, props), `${name}-${String(option.value)}`);
|
|
68
|
+
}
|
|
69
|
+
export function Radio(_0) {
|
|
70
|
+
let { name } = _0, props = _object_without_properties_loose(_0, [
|
|
71
|
+
"name"
|
|
72
|
+
]);
|
|
73
|
+
const { options = [], isDisabled, label, isRequired, helperText, description, isReadOnly, meta, validateOnMount, help, clearable, input, FormFieldGridProps = {}, FormControlProps = {}, FormLabelProps = {}, FormHelperTextProps = {}, FormControlLabelProps = {}, RadioProps = {} } = useFieldApi(_extends({}, props, {
|
|
74
|
+
name,
|
|
75
|
+
type: 'radio'
|
|
76
|
+
}));
|
|
77
|
+
const invalid = validationError(meta, validateOnMount);
|
|
78
|
+
const text = invalid || (meta.touched || validateOnMount) && meta.warning || helperText || description;
|
|
79
|
+
const hasValue = useStoredFieldHasValue(name);
|
|
80
|
+
// Each option is its own radio input, so the group has no control that can
|
|
81
|
+
// be driven back to "nothing chosen" — the clear button is that way back.
|
|
82
|
+
const clear = buildFieldClear({
|
|
83
|
+
clearable,
|
|
84
|
+
label,
|
|
85
|
+
hasValue,
|
|
86
|
+
locked: Boolean(isDisabled || isReadOnly),
|
|
87
|
+
onClear: ()=>input.onChange(undefined)
|
|
88
|
+
});
|
|
89
|
+
return /*#__PURE__*/ _jsx(StyledFormFieldGrid, _extends({
|
|
90
|
+
className: classes.grid,
|
|
91
|
+
help: help,
|
|
92
|
+
clear: clear
|
|
93
|
+
}, FormFieldGridProps, {
|
|
94
|
+
children: /*#__PURE__*/ _jsxs(FormControl, _extends({
|
|
95
|
+
required: isRequired,
|
|
96
|
+
error: !!invalid,
|
|
97
|
+
component: "fieldset"
|
|
98
|
+
}, FormControlProps, {
|
|
99
|
+
children: [
|
|
100
|
+
/*#__PURE__*/ _jsx(FormLabel, _extends({
|
|
101
|
+
component: "legend"
|
|
102
|
+
}, FormLabelProps, {
|
|
103
|
+
children: label
|
|
104
|
+
})),
|
|
105
|
+
options.map((option)=>/*#__PURE__*/ _jsx(RadioOption, {
|
|
106
|
+
name: name || '',
|
|
107
|
+
option: option,
|
|
108
|
+
isDisabled: isDisabled,
|
|
109
|
+
isReadOnly: isReadOnly,
|
|
110
|
+
FormControlLabelProps: FormControlLabelProps,
|
|
111
|
+
RadioProps: RadioProps
|
|
112
|
+
}, String(option.value))),
|
|
113
|
+
text && /*#__PURE__*/ _jsx(FormHelperText, _extends({}, FormHelperTextProps, {
|
|
114
|
+
children: text
|
|
115
|
+
}))
|
|
116
|
+
]
|
|
117
|
+
}))
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
export default Radio;
|
|
121
|
+
|
|
122
|
+
//# sourceMappingURL=radio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx-forms/src/lib/mapper/radio.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 API (`slotProps` instead of `inputProps`).\n */\n\nimport {\n FormControl,\n type FormControlLabelProps,\n FormControlLabel,\n type FormControlProps,\n FormHelperText,\n type FormHelperTextProps,\n FormLabel,\n type FormLabelProps,\n Radio as MuiRadio,\n} from '@mui/material'\nimport { styled } from '@mui/material/styles'\n\nimport { useFieldApi } from '../vendor/data-driven-forms'\nimport FormFieldGrid, {\n buildFieldClear,\n type FormFieldGridProps,\n} from './form-field-grid'\nimport { useStoredFieldHasValue } from './stored-field-value'\nimport type { BaseFieldProps, OptionValue, SelectOption } from './types'\nimport { type ExtendedFieldMeta, validationError } from './validation-error'\n\nconst PREFIX = 'Radio'\n\nconst classes = {\n grid: `${PREFIX}-grid`,\n}\n\nconst StyledFormFieldGrid = styled(FormFieldGrid)(() => ({\n [`&.${classes.grid}`]: {\n '&:first-of-type': {\n marginTop: 8,\n },\n },\n}))\n\ninterface RadioFieldOptionProps {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n inputProps?: Record<string, any>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any\n}\n\ninterface RadioOptionProps<T = OptionValue> {\n name: string\n option: SelectOption<T>\n isDisabled?: boolean\n isReadOnly?: boolean\n FormControlLabelProps?: Partial<FormControlLabelProps>\n RadioProps?: RadioFieldOptionProps\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any\n}\n\nfunction RadioOption<T = OptionValue>({\n name,\n option,\n isDisabled,\n isReadOnly,\n FormControlLabelProps,\n RadioProps: { inputProps, ...RadioProps } = {},\n ...props\n}: RadioOptionProps<T>) {\n const { input } = useFieldApi({\n name,\n type: 'radio',\n value: option.value,\n })\n\n return (\n <FormControlLabel\n key={`${name}-${String(option.value)}`}\n control={\n <MuiRadio\n {...input}\n name={name}\n disabled={isDisabled || isReadOnly}\n onChange={() => input.onChange(option.value)}\n slotProps={{\n input: { readOnly: isReadOnly, ...inputProps },\n }}\n {...RadioProps}\n />\n }\n label={option.label}\n {...FormControlLabelProps}\n {...props}\n />\n )\n}\n\nexport interface RadioProps<T = OptionValue> extends BaseFieldProps {\n options?: SelectOption<T>[]\n /** Offer the reset-to-unset affordance (AGL-2486). */\n clearable?: boolean\n FormFieldGridProps?: FormFieldGridProps\n FormControlProps?: FormControlProps\n FormLabelProps?: FormLabelProps\n FormHelperTextProps?: FormHelperTextProps\n FormControlLabelProps?: Partial<FormControlLabelProps>\n RadioProps?: RadioFieldOptionProps\n}\n\nexport function Radio<T = OptionValue>({ name, ...props }: RadioProps<T>) {\n const {\n options = [],\n isDisabled,\n label,\n isRequired,\n helperText,\n description,\n isReadOnly,\n meta,\n validateOnMount,\n help,\n clearable,\n input,\n FormFieldGridProps = {},\n FormControlProps = {},\n FormLabelProps = {},\n FormHelperTextProps = {},\n FormControlLabelProps = {},\n RadioProps = {},\n } = useFieldApi({\n ...props,\n name,\n type: 'radio',\n })\n\n const invalid = validationError(meta as ExtendedFieldMeta, validateOnMount)\n const text =\n invalid ||\n ((meta.touched || validateOnMount) && meta.warning) ||\n helperText ||\n description\n const hasValue = useStoredFieldHasValue(name)\n // Each option is its own radio input, so the group has no control that can\n // be driven back to \"nothing chosen\" — the clear button is that way back.\n const clear = buildFieldClear({\n clearable,\n label,\n hasValue,\n locked: Boolean(isDisabled || isReadOnly),\n onClear: () => input.onChange(undefined),\n })\n\n return (\n <StyledFormFieldGrid\n className={classes.grid}\n help={help}\n clear={clear}\n {...FormFieldGridProps}\n >\n <FormControl\n required={isRequired}\n error={!!invalid}\n component=\"fieldset\"\n {...FormControlProps}\n >\n <FormLabel component=\"legend\" {...FormLabelProps}>\n {label}\n </FormLabel>\n {(options as SelectOption<T>[]).map((option) => (\n <RadioOption<T>\n key={String(option.value)}\n name={name || ''}\n option={option}\n isDisabled={isDisabled}\n isReadOnly={isReadOnly}\n FormControlLabelProps={FormControlLabelProps}\n RadioProps={RadioProps}\n />\n ))}\n {text && (\n <FormHelperText {...FormHelperTextProps}>{text}</FormHelperText>\n )}\n </FormControl>\n </StyledFormFieldGrid>\n )\n}\n\nexport default Radio\n"],"names":["FormControl","FormControlLabel","FormHelperText","FormLabel","Radio","MuiRadio","styled","useFieldApi","FormFieldGrid","buildFieldClear","useStoredFieldHasValue","validationError","PREFIX","classes","grid","StyledFormFieldGrid","marginTop","RadioOption","name","option","isDisabled","isReadOnly","FormControlLabelProps","RadioProps","inputProps","props","input","type","value","control","disabled","onChange","slotProps","readOnly","label","String","options","isRequired","helperText","description","meta","validateOnMount","help","clearable","FormFieldGridProps","FormControlProps","FormLabelProps","FormHelperTextProps","invalid","text","touched","warning","hasValue","clear","locked","Boolean","onClear","undefined","className","required","error","component","map"],"mappings":"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"}
|