@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,113 @@
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
+ * CssBorder (AGL-2486): a thickness box plus a line-style picker for anything
21
+ * holding a CSS border shorthand.
22
+ *
23
+ * The alternative is a raw shorthand text box — `Border` and the four per-side
24
+ * fields each wanting `1px solid`, `Outline` wanting `2px solid`. A border is
25
+ * two obvious choices (how thick, what kind of line) plus a colour, and a text
26
+ * box turns them into a grammar exercise for an author who does not write CSS.
27
+ * A mom-and-pop shop owner is one of Aglyn's three stated ICPs.
28
+ *
29
+ * **The persisted value is unchanged: still one CSS shorthand string**
30
+ * (`"1px solid"`, `"2px dashed"`, `"none"`, `""`). This is purely an input
31
+ * affordance, so renderers, published documents and existing nodes stay
32
+ * untouched, and it composes with the responsive/scheme pipeline exactly as
33
+ * the free-text box did.
34
+ *
35
+ * **Colour deliberately stays its own field.** MUI declares `border` with
36
+ * `borderTransform`, which only turns a bare NUMBER into `${n}px solid` and
37
+ * otherwise passes the string through verbatim — so a palette token inside
38
+ * the shorthand would not resolve, and the panel's per-scheme colour scoping
39
+ * (`SCHEME_SCOPED_STYLE_FIELDS`) is keyed on `borderColor`. Folding the
40
+ * colour in here would have cost both. The group instead places Border
41
+ * Color immediately beside this control so the three choices read as one
42
+ * row.
43
+ *
44
+ * **The escape hatch is the same one `CssDimension` uses.** A value this
45
+ * editor cannot model — `thin solid`, `1px solid #f00`, `calc()` in a
46
+ * width, a `{{token}}` binding — falls back to a plain text box holding the
47
+ * raw string rather than being clobbered, and flips back to the structured
48
+ * controls the moment the text becomes a plain `<width> <style>` again. The
49
+ * mode is DERIVED from the value, never remembered in a flag that can go
50
+ * stale.
51
+ */
52
+ /**
53
+ * The line styles offered.
54
+ *
55
+ * `none` is on the list and is a real value, not the absence of one: it
56
+ * removes a border a component or the theme is drawing, which is different
57
+ * from clearing the field (that hands the decision back to the theme). The
58
+ * long tail CSS also has — `groove`, `ridge`, `inset`, `outset` — is
59
+ * deliberately absent: they are bevel effects nobody has asked for, and an
60
+ * author who wants one still has the raw text box.
61
+ */
62
+ export declare const CSS_BORDER_STYLES: readonly ["solid", "dashed", "dotted", "double", "none"];
63
+ export type CssBorderStyle = (typeof CSS_BORDER_STYLES)[number];
64
+ /** Plain-English name for each line style — no CSS vocabulary required. */
65
+ export declare const CSS_BORDER_STYLE_LABELS: Record<CssBorderStyle, string>;
66
+ /**
67
+ * What the CLOSED picker shows, which is not what the menu shows.
68
+ *
69
+ * The picker is an `endAdornment` inside a half-width field, so its width
70
+ * comes straight out of the box the author types the thickness into — and
71
+ * out of the room the field's own label needs. "Dashed line" collides with
72
+ * `Border Bottom`; "Dashed" does not. The menu, which has the whole popover
73
+ * to itself, keeps the sentence.
74
+ */
75
+ export declare const CSS_BORDER_STYLE_SHORT_LABELS: Record<CssBorderStyle, string>;
76
+ /** Draft state: what the two controls show, before serialization. */
77
+ export interface BorderDraft {
78
+ /** Thickness in pixels as typed (or the whole raw string in custom mode). */
79
+ width: string;
80
+ /** Selected line style, `''` when none is chosen. */
81
+ style: CssBorderStyle | '';
82
+ /** The value is not `<width>px <style>` — the text box holds it verbatim. */
83
+ custom: boolean;
84
+ }
85
+ /**
86
+ * Reads a stored shorthand into the two controls.
87
+ *
88
+ * Accepts exactly the shapes this editor can put back together — a pixel
89
+ * width, a known style, or both in either CSS order — and marks everything
90
+ * else `custom` so the raw text survives untouched. `0` is a legitimate
91
+ * width (it is how an author removes a border while keeping its box), and
92
+ * `strictNullChecks` is off repo-wide, so emptiness is spelled out rather
93
+ * than left to a falsy test.
94
+ */
95
+ export declare const seedBorderDraft: (value: unknown) => BorderDraft;
96
+ /**
97
+ * Serializes the two controls back into one shorthand.
98
+ *
99
+ * `none` is the whole value — a width in front of it is meaningless CSS and
100
+ * would read as a thickness the author cannot see the effect of.
101
+ */
102
+ export declare const serializeBorderDraft: (draft: BorderDraft) => string;
103
+ export interface CssBorderProps extends BaseFieldProps {
104
+ placeholder?: string;
105
+ /** Offer the reset-to-unset affordance (AGL-2486). */
106
+ clearable?: boolean;
107
+ FormFieldGridProps?: FormFieldGridProps;
108
+ }
109
+ export declare const CssBorderField: {
110
+ (props: CssBorderProps): import("react").JSX.Element;
111
+ displayName: string;
112
+ };
113
+ export default CssBorderField;
@@ -0,0 +1,410 @@
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, Fragment as _Fragment } 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, InputAdornment, MenuItem, Select, TextField as MuiTextField, Typography } from "@mui/material";
20
+ import { useCallback, useEffect, useRef, 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
+ /**
25
+ * CssBorder (AGL-2486): a thickness box plus a line-style picker for anything
26
+ * holding a CSS border shorthand.
27
+ *
28
+ * The alternative is a raw shorthand text box — `Border` and the four per-side
29
+ * fields each wanting `1px solid`, `Outline` wanting `2px solid`. A border is
30
+ * two obvious choices (how thick, what kind of line) plus a colour, and a text
31
+ * box turns them into a grammar exercise for an author who does not write CSS.
32
+ * A mom-and-pop shop owner is one of Aglyn's three stated ICPs.
33
+ *
34
+ * **The persisted value is unchanged: still one CSS shorthand string**
35
+ * (`"1px solid"`, `"2px dashed"`, `"none"`, `""`). This is purely an input
36
+ * affordance, so renderers, published documents and existing nodes stay
37
+ * untouched, and it composes with the responsive/scheme pipeline exactly as
38
+ * the free-text box did.
39
+ *
40
+ * **Colour deliberately stays its own field.** MUI declares `border` with
41
+ * `borderTransform`, which only turns a bare NUMBER into `${n}px solid` and
42
+ * otherwise passes the string through verbatim — so a palette token inside
43
+ * the shorthand would not resolve, and the panel's per-scheme colour scoping
44
+ * (`SCHEME_SCOPED_STYLE_FIELDS`) is keyed on `borderColor`. Folding the
45
+ * colour in here would have cost both. The group instead places Border
46
+ * Color immediately beside this control so the three choices read as one
47
+ * row.
48
+ *
49
+ * **The escape hatch is the same one `CssDimension` uses.** A value this
50
+ * editor cannot model — `thin solid`, `1px solid #f00`, `calc()` in a
51
+ * width, a `{{token}}` binding — falls back to a plain text box holding the
52
+ * raw string rather than being clobbered, and flips back to the structured
53
+ * controls the moment the text becomes a plain `<width> <style>` again. The
54
+ * mode is DERIVED from the value, never remembered in a flag that can go
55
+ * stale.
56
+ */ /**
57
+ * The line styles offered.
58
+ *
59
+ * `none` is on the list and is a real value, not the absence of one: it
60
+ * removes a border a component or the theme is drawing, which is different
61
+ * from clearing the field (that hands the decision back to the theme). The
62
+ * long tail CSS also has — `groove`, `ridge`, `inset`, `outset` — is
63
+ * deliberately absent: they are bevel effects nobody has asked for, and an
64
+ * author who wants one still has the raw text box.
65
+ */ export const CSS_BORDER_STYLES = [
66
+ 'solid',
67
+ 'dashed',
68
+ 'dotted',
69
+ 'double',
70
+ 'none'
71
+ ];
72
+ /** Plain-English name for each line style — no CSS vocabulary required. */ export const CSS_BORDER_STYLE_LABELS = {
73
+ solid: 'Solid line',
74
+ dashed: 'Dashed line',
75
+ dotted: 'Dotted line',
76
+ double: 'Double line',
77
+ none: 'No line'
78
+ };
79
+ /**
80
+ * What the CLOSED picker shows, which is not what the menu shows.
81
+ *
82
+ * The picker is an `endAdornment` inside a half-width field, so its width
83
+ * comes straight out of the box the author types the thickness into — and
84
+ * out of the room the field's own label needs. "Dashed line" collides with
85
+ * `Border Bottom`; "Dashed" does not. The menu, which has the whole popover
86
+ * to itself, keeps the sentence.
87
+ */ export const CSS_BORDER_STYLE_SHORT_LABELS = {
88
+ solid: 'Solid',
89
+ dashed: 'Dashed',
90
+ dotted: 'Dotted',
91
+ double: 'Double',
92
+ none: 'None'
93
+ };
94
+ /** A bare pixel thickness: `1`, `1px`, `0.5px`. Units other than px are raw. */ const BORDER_WIDTH_PATTERN = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(?:px)?$/i;
95
+ /**
96
+ * Reads a stored shorthand into the two controls.
97
+ *
98
+ * Accepts exactly the shapes this editor can put back together — a pixel
99
+ * width, a known style, or both in either CSS order — and marks everything
100
+ * else `custom` so the raw text survives untouched. `0` is a legitimate
101
+ * width (it is how an author removes a border while keeping its box), and
102
+ * `strictNullChecks` is off repo-wide, so emptiness is spelled out rather
103
+ * than left to a falsy test.
104
+ */ export const seedBorderDraft = (value)=>{
105
+ // A bare NUMBER is what MUI's own `borderTransform` reads as `${n}px
106
+ // solid`, so the controls must show exactly that rather than blanking.
107
+ if (typeof value === 'number' && Number.isFinite(value)) {
108
+ return {
109
+ width: `${value}`,
110
+ style: 'solid',
111
+ custom: false
112
+ };
113
+ }
114
+ const text = typeof value === 'string' ? value.trim() : '';
115
+ if (text === '') return {
116
+ width: '',
117
+ style: '',
118
+ custom: false
119
+ };
120
+ const parts = text.split(/\s+/);
121
+ if (parts.length > 2) return {
122
+ width: text,
123
+ style: '',
124
+ custom: true
125
+ };
126
+ let width = '';
127
+ let style = '';
128
+ for (const part of parts){
129
+ const lower = part.toLowerCase();
130
+ if (!style && CSS_BORDER_STYLES.includes(lower)) {
131
+ style = lower;
132
+ continue;
133
+ }
134
+ const matched = BORDER_WIDTH_PATTERN.exec(part);
135
+ if (width === '' && matched) {
136
+ width = matched[1];
137
+ continue;
138
+ }
139
+ // Anything the pair cannot account for (a colour, `thin`, `2rem`)
140
+ // makes the whole value raw — a partial parse would silently drop it.
141
+ return {
142
+ width: text,
143
+ style: '',
144
+ custom: true
145
+ };
146
+ }
147
+ return {
148
+ width,
149
+ style,
150
+ custom: false
151
+ };
152
+ };
153
+ /**
154
+ * Serializes the two controls back into one shorthand.
155
+ *
156
+ * `none` is the whole value — a width in front of it is meaningless CSS and
157
+ * would read as a thickness the author cannot see the effect of.
158
+ */ export const serializeBorderDraft = (draft)=>{
159
+ if (draft.custom) return draft.width;
160
+ if (draft.style === 'none') return 'none';
161
+ const width = draft.width.trim();
162
+ const parts = [];
163
+ if (width !== '') parts.push(`${width}px`);
164
+ if (draft.style) parts.push(draft.style);
165
+ return parts.join(' ');
166
+ };
167
+ export const CssBorderField = (props)=>{
168
+ var _input_value;
169
+ const _useFieldApi = useFieldApi(props), { input, isReadOnly, isDisabled, isRequired, label, placeholder, helperText, description, validateOnMount, meta, help, clearable, FormFieldGridProps = {}, // Free-text leftovers from the schema these fields were authored with
170
+ // as TEXT_FIELDs; they must never reach the DOM.
171
+ inputProps: _inputProps, InputProps: _InputProps, multiline: _multiline, type: _type, options: _options } = _useFieldApi, rest = _object_without_properties_loose(_useFieldApi, [
172
+ "input",
173
+ "isReadOnly",
174
+ "isDisabled",
175
+ "isRequired",
176
+ "label",
177
+ "placeholder",
178
+ "helperText",
179
+ "description",
180
+ "validateOnMount",
181
+ "meta",
182
+ "help",
183
+ "clearable",
184
+ "FormFieldGridProps",
185
+ "inputProps",
186
+ "InputProps",
187
+ "multiline",
188
+ "type",
189
+ "options"
190
+ ]);
191
+ const invalid = validationError(meta, validateOnMount);
192
+ const value = typeof input.value === 'number' ? `${input.value}` : `${(_input_value = input.value) != null ? _input_value : ''}`;
193
+ const [draft, setDraft] = useState(()=>seedBorderDraft(input.value));
194
+ // Re-seed only when the value changed OUTSIDE this field (a different
195
+ // node selected, an undo, a breakpoint switch). Re-seeding from our own
196
+ // emits would round a half-typed decimal out from under the caret — the
197
+ // same hazard `CssDimension` documents.
198
+ const emittedRef = useRef(serializeBorderDraft(seedBorderDraft(input.value)));
199
+ useEffect(()=>{
200
+ var _input_value;
201
+ const incoming = `${(_input_value = input.value) != null ? _input_value : ''}`;
202
+ if (incoming === emittedRef.current) return;
203
+ emittedRef.current = incoming;
204
+ setDraft(seedBorderDraft(input.value));
205
+ }, [
206
+ input.value
207
+ ]);
208
+ const commit = useCallback((next)=>{
209
+ const serialized = serializeBorderDraft(next);
210
+ emittedRef.current = serialized;
211
+ // A raw value the author edited back into a plain `<width> <style>`
212
+ // gets the structured controls back immediately, so the escape hatch
213
+ // is never a one-way door.
214
+ const reseeded = seedBorderDraft(serialized);
215
+ setDraft(next.custom && !reseeded.custom ? reseeded : next);
216
+ input.onChange(serialized);
217
+ }, [
218
+ input
219
+ ]);
220
+ const clear = buildFieldClear({
221
+ clearable,
222
+ label,
223
+ hasValue: value !== '',
224
+ locked: Boolean(isDisabled || isReadOnly),
225
+ // Clearing drops the STYLE as well as the thickness. Emptying the
226
+ // number alone would leave `solid` selected and the next keystroke
227
+ // would silently re-adopt it, which is the trap AGL-2486 fixed for
228
+ // lengths and units.
229
+ onClear: ()=>commit({
230
+ width: '',
231
+ style: '',
232
+ custom: false
233
+ })
234
+ });
235
+ const handleWidthChange = useCallback((event)=>{
236
+ const width = event.target.value;
237
+ // Typing a thickness with no line style yet means a solid line —
238
+ // a bare `1px` draws nothing at all, which is the silent no-op that
239
+ // made the free-text version feel broken.
240
+ const style = !draft.custom && !draft.style && width.trim() !== '' ? 'solid' : draft.style;
241
+ commit(_extends({}, draft, {
242
+ width,
243
+ style
244
+ }));
245
+ }, [
246
+ commit,
247
+ draft
248
+ ]);
249
+ const handleStyleChange = useCallback((event)=>{
250
+ const style = event.target.value || '';
251
+ // "No line" IS the whole value, so the thickness goes away with it
252
+ // and comes back when a drawn style is picked again.
253
+ commit(_extends({}, draft, {
254
+ style,
255
+ width: style === 'none' ? '' : draft.width
256
+ }));
257
+ }, [
258
+ commit,
259
+ draft
260
+ ]);
261
+ const noLine = !draft.custom && draft.style === 'none';
262
+ const styleSelect = /*#__PURE__*/ _jsx(InputAdornment, {
263
+ position: "end",
264
+ sx: {
265
+ ml: 0
266
+ },
267
+ children: /*#__PURE__*/ _jsxs(Select, {
268
+ value: draft.custom ? '' : draft.style,
269
+ onChange: handleStyleChange,
270
+ disabled: isDisabled || isReadOnly || draft.custom,
271
+ variant: "standard",
272
+ disableUnderline: true,
273
+ // Without displayEmpty an unset style renders nothing at all, which
274
+ // reads as a broken control rather than "no line chosen yet".
275
+ displayEmpty: true,
276
+ renderValue: (selected)=>draft.custom ? 'custom' : selected ? CSS_BORDER_STYLE_SHORT_LABELS[selected] : // Picker on a length field. The words "line style" here read
277
+ // as help but behave as layout: they push the adornment over
278
+ // the field's own label on every per-side border.
279
+ '—',
280
+ inputProps: {
281
+ 'aria-label': 'Line style'
282
+ },
283
+ sx: {
284
+ '& .MuiSelect-select': {
285
+ pr: '20px !important',
286
+ py: 0,
287
+ textOverflow: 'ellipsis'
288
+ },
289
+ fontSize: '0.8125rem',
290
+ color: 'text.secondary',
291
+ minWidth: 0,
292
+ maxWidth: 96
293
+ },
294
+ children: [
295
+ /*#__PURE__*/ _jsx(MenuItem, {
296
+ value: "",
297
+ children: /*#__PURE__*/ _jsx("em", {
298
+ children: 'not set'
299
+ })
300
+ }),
301
+ CSS_BORDER_STYLES.map((style)=>/*#__PURE__*/ _jsx(MenuItem, {
302
+ value: style,
303
+ children: /*#__PURE__*/ _jsxs(Box, {
304
+ sx: {
305
+ display: 'flex',
306
+ alignItems: 'center',
307
+ gap: 1,
308
+ width: '100%'
309
+ },
310
+ children: [
311
+ /*#__PURE__*/ _jsx(Box, {
312
+ "aria-hidden": true,
313
+ sx: {
314
+ width: 34,
315
+ flexShrink: 0,
316
+ borderTopWidth: style === 'double' ? 3 : 2,
317
+ borderTopStyle: style === 'none' ? 'solid' : style,
318
+ borderTopColor: style === 'none' ? 'transparent' : 'text.primary'
319
+ }
320
+ }),
321
+ /*#__PURE__*/ _jsx(Typography, {
322
+ variant: "body2",
323
+ noWrap: true,
324
+ children: CSS_BORDER_STYLE_LABELS[style]
325
+ })
326
+ ]
327
+ })
328
+ }, style))
329
+ ]
330
+ })
331
+ });
332
+ return /*#__PURE__*/ _jsx(FormFieldGrid, _extends({
333
+ help: help,
334
+ clear: clear
335
+ }, FormFieldGridProps, {
336
+ children: /*#__PURE__*/ _jsx(MuiTextField, _extends({}, rest, {
337
+ name: input.name,
338
+ value: noLine ? '' : draft.width,
339
+ onChange: handleWidthChange,
340
+ onBlur: input.onBlur,
341
+ onFocus: input.onFocus,
342
+ fullWidth: true,
343
+ error: !!invalid,
344
+ helperText: invalid || (meta.touched || validateOnMount) && meta.warning || helperText || description,
345
+ disabled: isDisabled,
346
+ label: label,
347
+ placeholder: noLine ? 'no line' : placeholder,
348
+ required: isRequired,
349
+ type: draft.custom || noLine ? 'text' : 'number',
350
+ slotProps: {
351
+ /**
352
+ * The label is ALWAYS pinned above the box, never floating
353
+ * inside it (AGL-2486).
354
+ *
355
+ * Two reasons, and they point the same way. `Border Bottom` is
356
+ * thirteen characters and the box is a half column with a
357
+ * picker parked in its right-hand end, so an un-shrunk label
358
+ * runs straight into the adornment and the two print on top of
359
+ * each other. And "No line" is shown through the PLACEHOLDER,
360
+ * which MUI hides
361
+ * behind CSS while the label is un-shrunk, so the field would
362
+ * print its label over an empty box on a node that demonstrably
363
+ * has a value.
364
+ *
365
+ * It also settles the group's rhythm: Border Color, Corner
366
+ * Radius and Shadow all sit under a pinned label, so the six
367
+ * border editors match the group they are in.
368
+ */ inputLabel: {
369
+ shrink: true
370
+ },
371
+ input: {
372
+ readOnly: isReadOnly || noLine,
373
+ endAdornment: /*#__PURE__*/ _jsxs(_Fragment, {
374
+ children: [
375
+ draft.custom || noLine || draft.width.trim() === '' ? null : /*#__PURE__*/ _jsx(InputAdornment, {
376
+ position: "end",
377
+ sx: {
378
+ ml: 0,
379
+ mr: 0.5,
380
+ '& .MuiTypography-root': {
381
+ fontSize: '0.8125rem',
382
+ color: 'text.secondary'
383
+ }
384
+ },
385
+ children: 'px'
386
+ }),
387
+ styleSelect
388
+ ]
389
+ })
390
+ },
391
+ htmlInput: {
392
+ inputMode: 'decimal',
393
+ min: 0,
394
+ step: 1,
395
+ // The VALUE is never the control that gets squeezed: the style
396
+ // picker is a fixed-width adornment sibling, so without a floor
397
+ // the number box is whatever is left in a narrow docked panel.
398
+ style: {
399
+ minWidth: '4.5ch'
400
+ },
401
+ 'aria-label': typeof label === 'string' ? `${label} thickness` : undefined
402
+ }
403
+ }
404
+ }))
405
+ }));
406
+ };
407
+ CssBorderField.displayName = 'AglynCssBorderField';
408
+ export default CssBorderField;
409
+
410
+ //# sourceMappingURL=css-border.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx-forms/src/lib/mapper/css-border.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 InputAdornment,\n MenuItem,\n Select,\n TextField as MuiTextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useRef, 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 * CssBorder (AGL-2486): a thickness box plus a line-style picker for anything\n * holding a CSS border shorthand.\n *\n * The alternative is a raw shorthand text box — `Border` and the four per-side\n * fields each wanting `1px solid`, `Outline` wanting `2px solid`. A border is\n * two obvious choices (how thick, what kind of line) plus a colour, and a text\n * box turns them into a grammar exercise for an author who does not write CSS.\n * A mom-and-pop shop owner is one of Aglyn's three stated ICPs.\n *\n * **The persisted value is unchanged: still one CSS shorthand string**\n * (`\"1px solid\"`, `\"2px dashed\"`, `\"none\"`, `\"\"`). This is purely an input\n * affordance, so renderers, published documents and existing nodes stay\n * untouched, and it composes with the responsive/scheme pipeline exactly as\n * the free-text box did.\n *\n * **Colour deliberately stays its own field.** MUI declares `border` with\n * `borderTransform`, which only turns a bare NUMBER into `${n}px solid` and\n * otherwise passes the string through verbatim — so a palette token inside\n * the shorthand would not resolve, and the panel's per-scheme colour scoping\n * (`SCHEME_SCOPED_STYLE_FIELDS`) is keyed on `borderColor`. Folding the\n * colour in here would have cost both. The group instead places Border\n * Color immediately beside this control so the three choices read as one\n * row.\n *\n * **The escape hatch is the same one `CssDimension` uses.** A value this\n * editor cannot model — `thin solid`, `1px solid #f00`, `calc()` in a\n * width, a `{{token}}` binding — falls back to a plain text box holding the\n * raw string rather than being clobbered, and flips back to the structured\n * controls the moment the text becomes a plain `<width> <style>` again. The\n * mode is DERIVED from the value, never remembered in a flag that can go\n * stale.\n */\n\n/**\n * The line styles offered.\n *\n * `none` is on the list and is a real value, not the absence of one: it\n * removes a border a component or the theme is drawing, which is different\n * from clearing the field (that hands the decision back to the theme). The\n * long tail CSS also has — `groove`, `ridge`, `inset`, `outset` — is\n * deliberately absent: they are bevel effects nobody has asked for, and an\n * author who wants one still has the raw text box.\n */\nexport const CSS_BORDER_STYLES = [\n 'solid',\n 'dashed',\n 'dotted',\n 'double',\n 'none',\n] as const\n\nexport type CssBorderStyle = (typeof CSS_BORDER_STYLES)[number]\n\n/** Plain-English name for each line style — no CSS vocabulary required. */\nexport const CSS_BORDER_STYLE_LABELS: Record<CssBorderStyle, string> = {\n solid: 'Solid line',\n dashed: 'Dashed line',\n dotted: 'Dotted line',\n double: 'Double line',\n none: 'No line',\n}\n\n/**\n * What the CLOSED picker shows, which is not what the menu shows.\n *\n * The picker is an `endAdornment` inside a half-width field, so its width\n * comes straight out of the box the author types the thickness into — and\n * out of the room the field's own label needs. \"Dashed line\" collides with\n * `Border Bottom`; \"Dashed\" does not. The menu, which has the whole popover\n * to itself, keeps the sentence.\n */\nexport const CSS_BORDER_STYLE_SHORT_LABELS: Record<CssBorderStyle, string> = {\n solid: 'Solid',\n dashed: 'Dashed',\n dotted: 'Dotted',\n double: 'Double',\n none: 'None',\n}\n\n/** Draft state: what the two controls show, before serialization. */\nexport interface BorderDraft {\n /** Thickness in pixels as typed (or the whole raw string in custom mode). */\n width: string\n /** Selected line style, `''` when none is chosen. */\n style: CssBorderStyle | ''\n /** The value is not `<width>px <style>` — the text box holds it verbatim. */\n custom: boolean\n}\n\n/** A bare pixel thickness: `1`, `1px`, `0.5px`. Units other than px are raw. */\nconst BORDER_WIDTH_PATTERN = /^([+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+))(?:px)?$/i\n\n/**\n * Reads a stored shorthand into the two controls.\n *\n * Accepts exactly the shapes this editor can put back together — a pixel\n * width, a known style, or both in either CSS order — and marks everything\n * else `custom` so the raw text survives untouched. `0` is a legitimate\n * width (it is how an author removes a border while keeping its box), and\n * `strictNullChecks` is off repo-wide, so emptiness is spelled out rather\n * than left to a falsy test.\n */\nexport const seedBorderDraft = (value: unknown): BorderDraft => {\n // A bare NUMBER is what MUI's own `borderTransform` reads as `${n}px\n // solid`, so the controls must show exactly that rather than blanking.\n if (typeof value === 'number' && Number.isFinite(value)) {\n return { width: `${value}`, style: 'solid', custom: false }\n }\n const text = typeof value === 'string' ? value.trim() : ''\n if (text === '') return { width: '', style: '', custom: false }\n\n const parts = text.split(/\\s+/)\n if (parts.length > 2) return { width: text, style: '', custom: true }\n\n let width = ''\n let style: CssBorderStyle | '' = ''\n for (const part of parts) {\n const lower = part.toLowerCase()\n if (!style && (CSS_BORDER_STYLES as readonly string[]).includes(lower)) {\n style = lower as CssBorderStyle\n continue\n }\n const matched = BORDER_WIDTH_PATTERN.exec(part)\n if (width === '' && matched) {\n width = matched[1]\n continue\n }\n // Anything the pair cannot account for (a colour, `thin`, `2rem`)\n // makes the whole value raw — a partial parse would silently drop it.\n return { width: text, style: '', custom: true }\n }\n return { width, style, custom: false }\n}\n\n/**\n * Serializes the two controls back into one shorthand.\n *\n * `none` is the whole value — a width in front of it is meaningless CSS and\n * would read as a thickness the author cannot see the effect of.\n */\nexport const serializeBorderDraft = (draft: BorderDraft): string => {\n if (draft.custom) return draft.width\n if (draft.style === 'none') return 'none'\n const width = draft.width.trim()\n const parts: string[] = []\n if (width !== '') parts.push(`${width}px`)\n if (draft.style) parts.push(draft.style)\n return parts.join(' ')\n}\n\nexport interface CssBorderProps extends BaseFieldProps {\n placeholder?: string\n /** Offer the reset-to-unset affordance (AGL-2486). */\n clearable?: boolean\n FormFieldGridProps?: FormFieldGridProps\n}\n\nexport const CssBorderField = (props: CssBorderProps) => {\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 clearable,\n FormFieldGridProps = {},\n // Free-text leftovers from the schema these fields were authored with\n // as TEXT_FIELDs; they must never reach the DOM.\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 value =\n typeof input.value === 'number' ? `${input.value}` : `${input.value ?? ''}`\n\n const [draft, setDraft] = useState<BorderDraft>(() =>\n seedBorderDraft(input.value),\n )\n // Re-seed only when the value changed OUTSIDE this field (a different\n // node selected, an undo, a breakpoint switch). Re-seeding from our own\n // emits would round a half-typed decimal out from under the caret — the\n // same hazard `CssDimension` documents.\n const emittedRef = useRef(serializeBorderDraft(seedBorderDraft(input.value)))\n useEffect(() => {\n const incoming = `${input.value ?? ''}`\n if (incoming === emittedRef.current) return\n emittedRef.current = incoming\n setDraft(seedBorderDraft(input.value))\n }, [input.value])\n\n const commit = useCallback(\n (next: BorderDraft) => {\n const serialized = serializeBorderDraft(next)\n emittedRef.current = serialized\n // A raw value the author edited back into a plain `<width> <style>`\n // gets the structured controls back immediately, so the escape hatch\n // is never a one-way door.\n const reseeded = seedBorderDraft(serialized)\n setDraft(next.custom && !reseeded.custom ? reseeded : next)\n input.onChange(serialized)\n },\n [input],\n )\n\n const clear = buildFieldClear({\n clearable,\n label,\n hasValue: value !== '',\n locked: Boolean(isDisabled || isReadOnly),\n // Clearing drops the STYLE as well as the thickness. Emptying the\n // number alone would leave `solid` selected and the next keystroke\n // would silently re-adopt it, which is the trap AGL-2486 fixed for\n // lengths and units.\n onClear: () => commit({ width: '', style: '', custom: false }),\n })\n\n const handleWidthChange = useCallback(\n (event: { target: { value: string } }) => {\n const width = event.target.value\n // Typing a thickness with no line style yet means a solid line —\n // a bare `1px` draws nothing at all, which is the silent no-op that\n // made the free-text version feel broken.\n const style =\n !draft.custom && !draft.style && width.trim() !== ''\n ? ('solid' as CssBorderStyle)\n : draft.style\n commit({ ...draft, width, style })\n },\n [commit, draft],\n )\n\n const handleStyleChange = useCallback(\n (event: { target: { value: unknown } }) => {\n const style = (event.target.value || '') as CssBorderStyle | ''\n // \"No line\" IS the whole value, so the thickness goes away with it\n // and comes back when a drawn style is picked again.\n commit({\n ...draft,\n style,\n width: style === 'none' ? '' : draft.width,\n })\n },\n [commit, draft],\n )\n\n const noLine = !draft.custom && draft.style === 'none'\n\n const styleSelect = (\n <InputAdornment position=\"end\" sx={{ ml: 0 }}>\n <Select\n value={draft.custom ? '' : draft.style}\n onChange={handleStyleChange}\n disabled={isDisabled || isReadOnly || draft.custom}\n variant=\"standard\"\n disableUnderline\n // Without displayEmpty an unset style renders nothing at all, which\n // reads as a broken control rather than \"no line chosen yet\".\n displayEmpty\n renderValue={(selected) =>\n draft.custom\n ? 'custom'\n : selected\n ? CSS_BORDER_STYLE_SHORT_LABELS[selected as CssBorderStyle]\n : // An unset picker is one em-dash wide, exactly like the unit\n // Picker on a length field. The words \"line style\" here read\n // as help but behave as layout: they push the adornment over\n // the field's own label on every per-side border.\n '—'\n }\n inputProps={{ 'aria-label': 'Line style' }}\n sx={{\n '& .MuiSelect-select': {\n pr: '20px !important',\n py: 0,\n textOverflow: 'ellipsis',\n },\n fontSize: '0.8125rem',\n color: 'text.secondary',\n minWidth: 0,\n maxWidth: 96,\n }}\n >\n <MenuItem value=\"\">\n <em>{'not set'}</em>\n </MenuItem>\n {CSS_BORDER_STYLES.map((style) => (\n <MenuItem key={style} value={style}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n width: '100%',\n }}\n >\n {/* The line itself, drawn in the style it names — the whole\n point of retiring the shorthand is that the choice can be\n made by looking. */}\n <Box\n aria-hidden\n sx={{\n width: 34,\n flexShrink: 0,\n borderTopWidth: style === 'double' ? 3 : 2,\n borderTopStyle: style === 'none' ? 'solid' : style,\n borderTopColor:\n style === 'none' ? 'transparent' : 'text.primary',\n }}\n />\n <Typography variant=\"body2\" noWrap>\n {CSS_BORDER_STYLE_LABELS[style]}\n </Typography>\n </Box>\n </MenuItem>\n ))}\n </Select>\n </InputAdornment>\n )\n\n return (\n <FormFieldGrid help={help} clear={clear} {...FormFieldGridProps}>\n <MuiTextField\n {...rest}\n name={input.name}\n value={noLine ? '' : draft.width}\n onChange={handleWidthChange}\n onBlur={input.onBlur}\n onFocus={input.onFocus}\n fullWidth\n error={!!invalid}\n helperText={\n invalid ||\n ((meta.touched || validateOnMount) && meta.warning) ||\n helperText ||\n description\n }\n disabled={isDisabled}\n label={label}\n placeholder={noLine ? 'no line' : placeholder}\n required={isRequired}\n type={draft.custom || noLine ? 'text' : 'number'}\n slotProps={{\n /**\n * The label is ALWAYS pinned above the box, never floating\n * inside it (AGL-2486).\n *\n * Two reasons, and they point the same way. `Border Bottom` is\n * thirteen characters and the box is a half column with a\n * picker parked in its right-hand end, so an un-shrunk label\n * runs straight into the adornment and the two print on top of\n * each other. And \"No line\" is shown through the PLACEHOLDER,\n * which MUI hides\n * behind CSS while the label is un-shrunk, so the field would\n * print its label over an empty box on a node that demonstrably\n * has a value.\n *\n * It also settles the group's rhythm: Border Color, Corner\n * Radius and Shadow all sit under a pinned label, so the six\n * border editors match the group they are in.\n */\n inputLabel: { shrink: true },\n input: {\n readOnly: isReadOnly || noLine,\n endAdornment: (\n <>\n {/* The unit is STATED, not asked for — that is the whole\n point of retiring the shorthand. It is hidden in raw\n mode, where the text is not a pixel thickness, and on\n \"no line\", where there is no thickness at all. */}\n {/* The unit is only stated once there is a number to put it\n after. On an empty field it is pure width, and width is\n what pushes the label into the adornments. */}\n {draft.custom || noLine || draft.width.trim() === '' ? null : (\n <InputAdornment\n position=\"end\"\n sx={{\n ml: 0,\n mr: 0.5,\n '& .MuiTypography-root': {\n fontSize: '0.8125rem',\n color: 'text.secondary',\n },\n }}\n >\n {'px'}\n </InputAdornment>\n )}\n {styleSelect}\n </>\n ),\n },\n htmlInput: {\n inputMode: 'decimal',\n min: 0,\n step: 1,\n // The VALUE is never the control that gets squeezed: the style\n // picker is a fixed-width adornment sibling, so without a floor\n // the number box is whatever is left in a narrow docked panel.\n style: { minWidth: '4.5ch' },\n 'aria-label':\n typeof label === 'string' ? `${label} thickness` : undefined,\n },\n }}\n />\n </FormFieldGrid>\n )\n}\nCssBorderField.displayName = 'AglynCssBorderField'\n\nexport default CssBorderField\n"],"names":["Box","InputAdornment","MenuItem","Select","TextField","MuiTextField","Typography","useCallback","useEffect","useRef","useState","useFieldApi","FormFieldGrid","buildFieldClear","validationError","CSS_BORDER_STYLES","CSS_BORDER_STYLE_LABELS","solid","dashed","dotted","double","none","CSS_BORDER_STYLE_SHORT_LABELS","BORDER_WIDTH_PATTERN","seedBorderDraft","value","Number","isFinite","width","style","custom","text","trim","parts","split","length","part","lower","toLowerCase","includes","matched","exec","serializeBorderDraft","draft","push","join","CssBorderField","props","input","isReadOnly","isDisabled","isRequired","label","placeholder","helperText","description","validateOnMount","meta","help","clearable","FormFieldGridProps","inputProps","_inputProps","InputProps","_InputProps","multiline","_multiline","type","_type","options","_options","rest","invalid","setDraft","emittedRef","incoming","current","commit","next","serialized","reseeded","onChange","clear","hasValue","locked","Boolean","onClear","handleWidthChange","event","target","handleStyleChange","noLine","styleSelect","position","sx","ml","disabled","variant","disableUnderline","displayEmpty","renderValue","selected","pr","py","textOverflow","fontSize","color","minWidth","maxWidth","em","map","display","alignItems","gap","aria-hidden","flexShrink","borderTopWidth","borderTopStyle","borderTopColor","noWrap","name","onBlur","onFocus","fullWidth","error","touched","warning","required","slotProps","inputLabel","shrink","readOnly","endAdornment","mr","htmlInput","inputMode","min","step","undefined","displayName"],"mappings":"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"}