@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,322 @@
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 2023 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 { ColorPicker as AglynColorPicker } from "@aglyn/shared-ui-color-picker";
20
+ import { styled } from "@aglyn/shared-ui-theme";
21
+ import { FormFieldGrid, validationError } from "../mapper/index.js";
22
+ // Deep import rather than through the barrel: this is a sibling module in
23
+ // the same lib and the barrel is edited by everything.
24
+ import { buildFieldClear } from "../mapper/form-field-grid.js";
25
+ import { useFieldApi } from "@data-driven-forms/react-form-renderer";
26
+ import { Button, ClickAwayListener, IconButton, InputAdornment, Paper, Popper, TextField as MuiTextField } from "@mui/material";
27
+ import { forwardRef, useCallback, useId, useMemo, useRef, useState } from "react";
28
+ import { paletteTokenToAlphaCssVar, parsePaletteTokenAlphaCssVar } from "@aglyn/shared-data-enums";
29
+ import { ColorTokenGrid, rgbColorToCss, TokenSwatch, useColorPickerTokenOptions } from "./color-picker-tokens.js";
30
+ /**
31
+ * Solid swatch for a literal colour, geometrically identical to
32
+ * {@link TokenSwatch}: same box, same hairline ring, so a field showing a
33
+ * token, a field showing a hex and an EMPTY field differ only in what fills
34
+ * the circle. The ring is the element's own border rather than a wrapper's,
35
+ * which is what keeps it concentric — a wrapper sized by its content rounds
36
+ * its radius against its own padded box and reads as an off-centre ellipse
37
+ * at this size.
38
+ *
39
+ * An unset field paints nothing and is the ring alone; `transparent` spells
40
+ * that out so the declaration is never emitted with an empty value.
41
+ */ const Swatch = styled('span', {
42
+ shouldForwardProp: (propName)=>propName !== 'color'
43
+ })(({ theme, color })=>({
44
+ width: 22,
45
+ height: 22,
46
+ flexShrink: 0,
47
+ display: 'inline-flex',
48
+ backgroundColor: color || 'transparent',
49
+ borderRadius: '50%',
50
+ border: `1px solid ${theme.palette.divider}`
51
+ }));
52
+ const TextFieldColorSwatch = /*#__PURE__*/ forwardRef((props, ref)=>{
53
+ const { color, token, tokenAlpha, IconButtonProps } = props, rest = _object_without_properties_loose(props, [
54
+ "color",
55
+ "token",
56
+ "tokenAlpha",
57
+ "IconButtonProps"
58
+ ]);
59
+ return /*#__PURE__*/ _jsx(InputAdornment, _extends({
60
+ ref: ref,
61
+ position: 'start'
62
+ }, rest, {
63
+ children: /*#__PURE__*/ _jsx(IconButton, _extends({
64
+ ref: ref,
65
+ edge: "start"
66
+ }, IconButtonProps, {
67
+ children: token ? /*#__PURE__*/ _jsx(TokenSwatch, {
68
+ light: token.light,
69
+ dark: token.dark,
70
+ alpha: tokenAlpha
71
+ }) : /*#__PURE__*/ _jsx(Swatch, {
72
+ color: color
73
+ })
74
+ }))
75
+ }));
76
+ });
77
+ TextFieldColorSwatch.displayName = 'AglynTextFieldColorSwatch';
78
+ export const ColorPickerComponent = /*#__PURE__*/ forwardRef((props, ref)=>{
79
+ var _ref, _activeToken_light;
80
+ const _useFieldApi = useFieldApi(props), { input, isReadOnly, isDisabled, placeholder, isRequired, label, helperText, description, // Every other field forwards `help` to FormFieldGrid, which renders
81
+ // the tip. This one used to swallow it into `...rest`, so a colour
82
+ // field given a help tip rendered nothing at all and gave no clue
83
+ // why — found while adding tips to the styles panel (AGL-1220).
84
+ help, validateOnMount, meta, defaultValue, onChange, onBlur, onFocus, inputProps, InputProps, presetColors, clearable, FormFieldGridProps, FormControlProps, ColorPickerProps, PopperProps } = _useFieldApi, rest = _object_without_properties_loose(_useFieldApi, [
85
+ "input",
86
+ "isReadOnly",
87
+ "isDisabled",
88
+ "placeholder",
89
+ "isRequired",
90
+ "label",
91
+ "helperText",
92
+ "description",
93
+ "help",
94
+ "validateOnMount",
95
+ "meta",
96
+ "defaultValue",
97
+ "onChange",
98
+ "onBlur",
99
+ "onFocus",
100
+ "inputProps",
101
+ "InputProps",
102
+ "presetColors",
103
+ "clearable",
104
+ "FormFieldGridProps",
105
+ "FormControlProps",
106
+ "ColorPickerProps",
107
+ "PopperProps"
108
+ ]);
109
+ const id = `color-picker-${useId()}`;
110
+ const invalid = validationError(meta, validateOnMount);
111
+ const hasError = Boolean(invalid);
112
+ const value = (input == null ? void 0 : input.value) || defaultValue || '';
113
+ const handleChange = useCallback((value, e)=>{
114
+ const val = rgbColorToCss(value || '') || '';
115
+ (input == null ? void 0 : input.onChange) && (input == null ? void 0 : input.onChange(val));
116
+ (inputProps == null ? void 0 : inputProps.onChange) && (inputProps == null ? void 0 : inputProps.onChange(e, val));
117
+ onChange && onChange(e, val);
118
+ }, [
119
+ input,
120
+ inputProps,
121
+ onChange
122
+ ]);
123
+ const handleTextChange = useCallback((e)=>{
124
+ handleChange(e.target.value, e);
125
+ }, [
126
+ handleChange
127
+ ]);
128
+ const handleColorChange = useCallback((color, e)=>{
129
+ handleChange(color.rgb, e);
130
+ }, [
131
+ handleChange
132
+ ]);
133
+ const popperRef = useRef(null);
134
+ const [fieldRef, setFieldRef] = useState(null);
135
+ const [open, setOpen] = useState(false);
136
+ // Two-stage picking (AGL-588): theme token references first, the
137
+ // raw color picker behind an explicit "Custom color" step. A stored
138
+ // token path re-opens on the token stage with its swatch selected; a
139
+ // hex/rgb value re-opens on the custom stage. `stage` only tracks an
140
+ // explicit in-session choice — it resets whenever the popper opens.
141
+ const tokenOptions = useColorPickerTokenOptions();
142
+ // A token carrying an author-chosen opacity (AGL-2486). It is stored as
143
+ // `rgba(var(--mui-palette-primary-mainChannel, 31 41 55) / 0.12)` — still
144
+ // a REFERENCE, so the site palette keeps driving it — and reading it back
145
+ // here is what makes the picker re-open on the token with its slider at
146
+ // 12% instead of on the custom stage showing an opaque string.
147
+ const alphaToken = useMemo(()=>parsePaletteTokenAlphaCssVar(value), [
148
+ value
149
+ ]);
150
+ const tokenPath = alphaToken ? alphaToken.path : value;
151
+ const tokenAlpha = alphaToken ? alphaToken.alpha : 1;
152
+ const activeToken = useMemo(()=>tokenOptions.find((option)=>option.value === tokenPath), [
153
+ tokenOptions,
154
+ tokenPath
155
+ ]);
156
+ /**
157
+ * The value a token + opacity pair is STORED as. A fully opaque token
158
+ * stays the bare palette path (`primary.main`) — MUI's own sx resolution
159
+ * handles it, and nothing about the shipped format changes for the
160
+ * overwhelmingly common case. Only a real alpha reaches for the channel
161
+ * form.
162
+ */ const writeToken = useCallback((path, opacity)=>{
163
+ var _option_light;
164
+ if (!(opacity < 1)) return path;
165
+ const option = tokenOptions.find((entry)=>entry.value === path);
166
+ // The literal fallback: what the token resolves to today, so a render
167
+ // path that skips substitution still paints the right colour at the
168
+ // right opacity.
169
+ return paletteTokenToAlphaCssVar(path, opacity, option ? (_option_light = option.light) != null ? _option_light : option.dark : undefined);
170
+ }, [
171
+ tokenOptions
172
+ ]);
173
+ const [stage, setStage] = useState();
174
+ const effectiveStage = stage != null ? stage : !tokenOptions.length || value && !activeToken ? 'custom' : 'tokens';
175
+ const handleClickAway = useCallback((e)=>setOpen(false), []);
176
+ const handleFocus = useCallback((e)=>{
177
+ setStage(undefined);
178
+ setOpen(true);
179
+ onFocus && onFocus(e);
180
+ }, [
181
+ onFocus
182
+ ]);
183
+ const handleTokenSelect = useCallback((picked, e)=>{
184
+ // Keeps the opacity across a token change: an author dialling a wash
185
+ // to 12% and then trying it in secondary is adjusting ONE decision.
186
+ handleChange(writeToken(picked, tokenAlpha), e);
187
+ setOpen(false);
188
+ }, [
189
+ handleChange,
190
+ writeToken,
191
+ tokenAlpha
192
+ ]);
193
+ // Dragging the slider must not close the popper — this is the one control
194
+ // in the picker an author adjusts continuously, so it commits live like
195
+ // every other field in the styles panel and leaves the palette open.
196
+ const handleOpacityChange = useCallback((opacity)=>{
197
+ if (!activeToken) return;
198
+ handleChange(writeToken(activeToken.value, opacity), undefined);
199
+ }, [
200
+ activeToken,
201
+ handleChange,
202
+ writeToken
203
+ ]);
204
+ const startAdornment = useMemo(()=>/*#__PURE__*/ _jsx(TextFieldColorSwatch, {
205
+ color: value,
206
+ token: activeToken,
207
+ tokenAlpha: tokenAlpha,
208
+ IconButtonProps: {
209
+ onClick: ()=>{
210
+ setStage(undefined);
211
+ setOpen((prev)=>!prev);
212
+ }
213
+ }
214
+ }), [
215
+ value,
216
+ activeToken,
217
+ tokenAlpha
218
+ ]);
219
+ // The way back to "no colour" (AGL-2486). A colour picker has no empty
220
+ // swatch and the text box re-parses whatever is left in it, so before
221
+ // this there was no click anywhere in the panel that took a colour off
222
+ // again — only another colour.
223
+ const clear = buildFieldClear({
224
+ clearable,
225
+ label,
226
+ hasValue: value !== '' && value !== undefined && value !== null,
227
+ locked: Boolean(isDisabled || isReadOnly),
228
+ onClear: ()=>{
229
+ setOpen(false);
230
+ handleChange('', undefined);
231
+ }
232
+ });
233
+ return /*#__PURE__*/ _jsx(FormFieldGrid, _extends({
234
+ ref: ref,
235
+ help: help,
236
+ clear: clear
237
+ }, FormFieldGridProps, {
238
+ children: /*#__PURE__*/ _jsx(ClickAwayListener, {
239
+ onClickAway: handleClickAway,
240
+ children: /*#__PURE__*/ _jsxs("div", {
241
+ children: [
242
+ /*#__PURE__*/ _jsx(MuiTextField, _extends({}, input, {
243
+ fullWidth: true,
244
+ error: hasError,
245
+ helperText: invalid || (meta.touched || validateOnMount) && meta.warning || helperText || description,
246
+ disabled: isDisabled,
247
+ label: label,
248
+ placeholder: placeholder || 'default',
249
+ required: isRequired,
250
+ onChange: handleTextChange,
251
+ onFocus: handleFocus,
252
+ value: value,
253
+ slotProps: {
254
+ htmlInput: _extends({}, inputProps, {
255
+ readOnly: isReadOnly
256
+ }),
257
+ input: _extends({
258
+ startAdornment,
259
+ ref: setFieldRef
260
+ }, InputProps)
261
+ }
262
+ }, rest)),
263
+ /*#__PURE__*/ _jsx(Popper, _extends({
264
+ id: id,
265
+ ref: popperRef,
266
+ open: Boolean(fieldRef && open),
267
+ anchorEl: fieldRef,
268
+ sx: {
269
+ zIndex: 'tooltip',
270
+ maxWidth: 280
271
+ },
272
+ disablePortal: true
273
+ }, PopperProps, {
274
+ children: effectiveStage === 'tokens' ? /*#__PURE__*/ _jsx(ColorTokenGrid, {
275
+ options: tokenOptions,
276
+ value: tokenPath,
277
+ onSelect: handleTokenSelect,
278
+ onCustom: ()=>setStage('custom'),
279
+ // Only once a token is picked: there is nothing to make
280
+ // translucent while the field is empty, and an opacity on a
281
+ // literal is already expressible through the custom
282
+ // picker's own alpha channel.
283
+ opacity: tokenAlpha,
284
+ onOpacityChange: activeToken ? handleOpacityChange : undefined,
285
+ // The picker itself offers the way back, not just the
286
+ // field's corner (AGL-2486): an author who opened the
287
+ // palette to change a colour is exactly the author who
288
+ // wants to take it off.
289
+ onClear: clear && !clear.hidden ? clear.onClear : undefined
290
+ }) : /*#__PURE__*/ _jsxs(Paper, {
291
+ sx: {
292
+ p: 0.5
293
+ },
294
+ children: [
295
+ tokenOptions.length ? /*#__PURE__*/ _jsx(Button, {
296
+ size: "small",
297
+ fullWidth: true,
298
+ sx: {
299
+ mb: 0.5
300
+ },
301
+ onClick: ()=>setStage('tokens'),
302
+ children: "‹ Theme colors"
303
+ }) : null,
304
+ /*#__PURE__*/ _jsx(AglynColorPicker, _extends({}, ColorPickerProps, {
305
+ // A token path is not parseable by the picker; seed it
306
+ // with the token's resolved color instead.
307
+ color: activeToken ? (_ref = (_activeToken_light = activeToken.light) != null ? _activeToken_light : activeToken.dark) != null ? _ref : '' : value,
308
+ onChange: handleColorChange,
309
+ presetColors: presetColors
310
+ }))
311
+ ]
312
+ })
313
+ }))
314
+ ]
315
+ })
316
+ })
317
+ }));
318
+ });
319
+ ColorPickerComponent.displayName = 'ColorPickerComponent';
320
+ export default ColorPickerComponent;
321
+
322
+ //# sourceMappingURL=color-picker.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx-forms/src/lib/components/color-picker.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2023 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ColorPicker as AglynColorPicker,\n type ColorPickerProps as AglynColorPickerProps,\n} from '@aglyn/shared-ui-color-picker'\nimport { styled } from '@aglyn/shared-ui-theme'\nimport {\n type ExtendedFieldMeta,\n FormFieldGrid,\n type FormFieldGridProps,\n validationError,\n} from '../mapper'\n// Deep import rather than through the barrel: this is a sibling module in\n// the same lib and the barrel is edited by everything.\nimport { buildFieldClear } from '../mapper/form-field-grid'\nimport {\n useFieldApi,\n type UseFieldApiComponentConfig,\n} from '@data-driven-forms/react-form-renderer'\nimport {\n Button,\n ClickAwayListener,\n type FormControlProps as MuiFormControlProps,\n type GridProps,\n IconButton,\n type IconButtonProps,\n InputAdornment,\n type InputAdornmentProps,\n Paper,\n Popper,\n type PopperProps,\n TextField as MuiTextField,\n type TextFieldProps,\n} from '@mui/material'\nimport {\n type FocusEvent,\n forwardRef,\n useCallback,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport {\n paletteTokenToAlphaCssVar,\n parsePaletteTokenAlphaCssVar,\n} from '@aglyn/shared-data-enums'\nimport {\n ColorTokenGrid,\n type ColorPickerTokenOption,\n rgbColorToCss,\n type RgbColorValue,\n TokenSwatch,\n useColorPickerTokenOptions,\n} from './color-picker-tokens'\n\ninterface TextFieldColorSwatchProps extends Partial<InputAdornmentProps> {\n color: string\n /** Set when the value is a theme token — renders the split swatch. */\n token?: ColorPickerTokenOption\n /** Opacity the token carries, 0–1 (AGL-2486). */\n tokenAlpha?: number\n IconButtonProps?: Partial<IconButtonProps>\n}\n\n/**\n * Solid swatch for a literal colour, geometrically identical to\n * {@link TokenSwatch}: same box, same hairline ring, so a field showing a\n * token, a field showing a hex and an EMPTY field differ only in what fills\n * the circle. The ring is the element's own border rather than a wrapper's,\n * which is what keeps it concentric — a wrapper sized by its content rounds\n * its radius against its own padded box and reads as an off-centre ellipse\n * at this size.\n *\n * An unset field paints nothing and is the ring alone; `transparent` spells\n * that out so the declaration is never emitted with an empty value.\n */\nconst Swatch = styled('span', {\n shouldForwardProp: (propName) => propName !== 'color',\n})<{ color: string }>(({ theme, color }) => ({\n width: 22,\n height: 22,\n flexShrink: 0,\n display: 'inline-flex',\n backgroundColor: color || 'transparent',\n borderRadius: '50%',\n border: `1px solid ${theme.palette.divider}`,\n}))\n\nconst TextFieldColorSwatch = forwardRef<any, TextFieldColorSwatchProps>(\n (props, ref) => {\n const { color, token, tokenAlpha, IconButtonProps, ...rest } = props\n\n return (\n <InputAdornment ref={ref} position={'start'} {...rest}>\n <IconButton ref={ref} edge=\"start\" {...IconButtonProps}>\n {token ? (\n <TokenSwatch\n light={token.light}\n dark={token.dark}\n alpha={tokenAlpha}\n />\n ) : (\n <Swatch color={color} />\n )}\n </IconButton>\n </InputAdornment>\n )\n },\n)\nTextFieldColorSwatch.displayName = 'AglynTextFieldColorSwatch'\n\ntype InternalColorPickerProps = Partial<TextFieldProps> & {\n /** Contextual help tooltip, same contract as every other field. */\n help?: FormFieldGridProps['help']\n FormFieldGridProps?: Partial<GridProps>\n ColorPickerProps?: Partial<AglynColorPickerProps>\n FormControlProps?: Partial<MuiFormControlProps>\n PopperProps?: Partial<PopperProps>\n presetColors?: string[]\n /** Offer the reset-to-unset affordance (AGL-2486). */\n clearable?: boolean\n}\n\nexport type ColorPickerProps = InternalColorPickerProps &\n UseFieldApiComponentConfig\n\ntype RGBColor = RgbColorValue\n\nexport const ColorPickerComponent = forwardRef<any, ColorPickerProps>(\n (props, ref) => {\n const {\n input,\n isReadOnly,\n isDisabled,\n placeholder,\n isRequired,\n label,\n helperText,\n description,\n // Every other field forwards `help` to FormFieldGrid, which renders\n // the tip. This one used to swallow it into `...rest`, so a colour\n // field given a help tip rendered nothing at all and gave no clue\n // why — found while adding tips to the styles panel (AGL-1220).\n help,\n validateOnMount,\n meta,\n defaultValue,\n onChange,\n onBlur,\n onFocus,\n inputProps,\n InputProps,\n presetColors,\n clearable,\n FormFieldGridProps,\n FormControlProps,\n ColorPickerProps,\n PopperProps,\n ...rest\n } = useFieldApi(props as any)\n\n const id = `color-picker-${useId()}`\n const invalid = validationError(meta as ExtendedFieldMeta, validateOnMount)\n const hasError = Boolean(invalid)\n\n const value = input?.value || defaultValue || ''\n\n const handleChange = useCallback(\n (value: RGBColor | string, e: any) => {\n const val = rgbColorToCss(value || '') || ''\n input?.onChange && input?.onChange(val)\n inputProps?.onChange && inputProps?.onChange(e, val)\n onChange && onChange(e, val)\n },\n [input, inputProps, onChange],\n )\n\n const handleTextChange = useCallback(\n (e: any) => {\n handleChange(e.target.value, e)\n },\n [handleChange],\n )\n\n const handleColorChange = useCallback(\n (color: any, e: any) => {\n handleChange(color.rgb, e)\n },\n [handleChange],\n )\n\n const popperRef = useRef<HTMLDivElement | null>(null)\n const [fieldRef, setFieldRef] = useState<HTMLDivElement | null>(null)\n const [open, setOpen] = useState(false)\n\n // Two-stage picking (AGL-588): theme token references first, the\n // raw color picker behind an explicit \"Custom color\" step. A stored\n // token path re-opens on the token stage with its swatch selected; a\n // hex/rgb value re-opens on the custom stage. `stage` only tracks an\n // explicit in-session choice — it resets whenever the popper opens.\n const tokenOptions = useColorPickerTokenOptions()\n // A token carrying an author-chosen opacity (AGL-2486). It is stored as\n // `rgba(var(--mui-palette-primary-mainChannel, 31 41 55) / 0.12)` — still\n // a REFERENCE, so the site palette keeps driving it — and reading it back\n // here is what makes the picker re-open on the token with its slider at\n // 12% instead of on the custom stage showing an opaque string.\n const alphaToken = useMemo(\n () => parsePaletteTokenAlphaCssVar(value),\n [value],\n )\n const tokenPath = alphaToken ? alphaToken.path : value\n const tokenAlpha = alphaToken ? alphaToken.alpha : 1\n const activeToken = useMemo(\n () => tokenOptions.find((option) => option.value === tokenPath),\n [tokenOptions, tokenPath],\n )\n\n /**\n * The value a token + opacity pair is STORED as. A fully opaque token\n * stays the bare palette path (`primary.main`) — MUI's own sx resolution\n * handles it, and nothing about the shipped format changes for the\n * overwhelmingly common case. Only a real alpha reaches for the channel\n * form.\n */\n const writeToken = useCallback(\n (path: string, opacity: number) => {\n if (!(opacity < 1)) return path\n const option = tokenOptions.find((entry) => entry.value === path)\n // The literal fallback: what the token resolves to today, so a render\n // path that skips substitution still paints the right colour at the\n // right opacity.\n return paletteTokenToAlphaCssVar(\n path,\n opacity,\n option ? (option.light ?? option.dark) : undefined,\n )\n },\n [tokenOptions],\n )\n const [stage, setStage] = useState<'tokens' | 'custom' | undefined>()\n const effectiveStage =\n stage ??\n (!tokenOptions.length || (value && !activeToken) ? 'custom' : 'tokens')\n\n const handleClickAway = useCallback(\n (e: MouseEvent | TouchEvent) => setOpen(false),\n [],\n )\n const handleFocus = useCallback(\n (e: FocusEvent<HTMLInputElement>) => {\n setStage(undefined)\n setOpen(true)\n onFocus && onFocus(e)\n },\n [onFocus],\n )\n\n const handleTokenSelect = useCallback(\n (picked: string, e: any) => {\n // Keeps the opacity across a token change: an author dialling a wash\n // to 12% and then trying it in secondary is adjusting ONE decision.\n handleChange(writeToken(picked, tokenAlpha), e)\n setOpen(false)\n },\n [handleChange, writeToken, tokenAlpha],\n )\n\n // Dragging the slider must not close the popper — this is the one control\n // in the picker an author adjusts continuously, so it commits live like\n // every other field in the styles panel and leaves the palette open.\n const handleOpacityChange = useCallback(\n (opacity: number) => {\n if (!activeToken) return\n handleChange(writeToken(activeToken.value, opacity), undefined)\n },\n [activeToken, handleChange, writeToken],\n )\n\n const startAdornment = useMemo(\n () => (\n <TextFieldColorSwatch\n color={value}\n token={activeToken}\n tokenAlpha={tokenAlpha}\n IconButtonProps={{\n onClick: () => {\n setStage(undefined)\n setOpen((prev) => !prev)\n },\n }}\n />\n ),\n [value, activeToken, tokenAlpha],\n )\n\n // The way back to \"no colour\" (AGL-2486). A colour picker has no empty\n // swatch and the text box re-parses whatever is left in it, so before\n // this there was no click anywhere in the panel that took a colour off\n // again — only another colour.\n const clear = buildFieldClear({\n clearable,\n label,\n hasValue: value !== '' && value !== undefined && value !== null,\n locked: Boolean(isDisabled || isReadOnly),\n onClear: () => {\n setOpen(false)\n handleChange('', undefined)\n },\n })\n\n return (\n <FormFieldGrid\n ref={ref}\n help={help}\n clear={clear}\n {...FormFieldGridProps}\n >\n <ClickAwayListener onClickAway={handleClickAway}>\n <div>\n <MuiTextField\n {...input}\n fullWidth\n error={hasError}\n helperText={\n invalid ||\n ((meta.touched || validateOnMount) && meta.warning) ||\n helperText ||\n description\n }\n disabled={isDisabled}\n label={label}\n placeholder={placeholder || 'default'}\n required={isRequired}\n onChange={handleTextChange}\n onFocus={handleFocus}\n value={value}\n slotProps={{\n htmlInput: {\n ...inputProps,\n readOnly: isReadOnly,\n },\n input: {\n startAdornment,\n ref: setFieldRef,\n ...InputProps,\n },\n }}\n {...rest}\n />\n <Popper\n id={id}\n ref={popperRef}\n open={Boolean(fieldRef && open)}\n anchorEl={fieldRef}\n sx={{ zIndex: 'tooltip', maxWidth: 280 }}\n disablePortal\n {...PopperProps}\n >\n {effectiveStage === 'tokens' ? (\n <ColorTokenGrid\n options={tokenOptions}\n value={tokenPath}\n onSelect={handleTokenSelect}\n onCustom={() => setStage('custom')}\n // Only once a token is picked: there is nothing to make\n // translucent while the field is empty, and an opacity on a\n // literal is already expressible through the custom\n // picker's own alpha channel.\n opacity={tokenAlpha}\n onOpacityChange={\n activeToken ? handleOpacityChange : undefined\n }\n // The picker itself offers the way back, not just the\n // field's corner (AGL-2486): an author who opened the\n // palette to change a colour is exactly the author who\n // wants to take it off.\n onClear={clear && !clear.hidden ? clear.onClear : undefined}\n />\n ) : (\n <Paper sx={{ p: 0.5 }}>\n {tokenOptions.length ? (\n <Button\n size=\"small\"\n fullWidth\n sx={{ mb: 0.5 }}\n onClick={() => setStage('tokens')}\n >\n ‹ Theme colors\n </Button>\n ) : null}\n <AglynColorPicker\n {...ColorPickerProps}\n // A token path is not parseable by the picker; seed it\n // with the token's resolved color instead.\n color={\n activeToken\n ? (activeToken.light ?? activeToken.dark ?? '')\n : value\n }\n onChange={handleColorChange}\n presetColors={presetColors}\n />\n </Paper>\n )}\n </Popper>\n </div>\n </ClickAwayListener>\n </FormFieldGrid>\n )\n },\n)\nColorPickerComponent.displayName = 'ColorPickerComponent'\n\nexport default ColorPickerComponent\n"],"names":["ColorPicker","AglynColorPicker","styled","FormFieldGrid","validationError","buildFieldClear","useFieldApi","Button","ClickAwayListener","IconButton","InputAdornment","Paper","Popper","TextField","MuiTextField","forwardRef","useCallback","useId","useMemo","useRef","useState","paletteTokenToAlphaCssVar","parsePaletteTokenAlphaCssVar","ColorTokenGrid","rgbColorToCss","TokenSwatch","useColorPickerTokenOptions","Swatch","shouldForwardProp","propName","theme","color","width","height","flexShrink","display","backgroundColor","borderRadius","border","palette","divider","TextFieldColorSwatch","props","ref","token","tokenAlpha","IconButtonProps","rest","position","edge","light","dark","alpha","displayName","ColorPickerComponent","activeToken","input","isReadOnly","isDisabled","placeholder","isRequired","label","helperText","description","help","validateOnMount","meta","defaultValue","onChange","onBlur","onFocus","inputProps","InputProps","presetColors","clearable","FormFieldGridProps","FormControlProps","ColorPickerProps","PopperProps","id","invalid","hasError","Boolean","value","handleChange","e","val","handleTextChange","target","handleColorChange","rgb","popperRef","fieldRef","setFieldRef","open","setOpen","tokenOptions","alphaToken","tokenPath","path","find","option","writeToken","opacity","entry","undefined","stage","setStage","effectiveStage","length","handleClickAway","handleFocus","handleTokenSelect","picked","handleOpacityChange","startAdornment","onClick","prev","clear","hasValue","locked","onClear","onClickAway","div","fullWidth","error","touched","warning","disabled","required","slotProps","htmlInput","readOnly","anchorEl","sx","zIndex","maxWidth","disablePortal","options","onSelect","onCustom","onOpacityChange","hidden","p","size","mb"],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type FormTemplateRenderProps } from '../vendor/data-driven-forms';
3
+ /**
4
+ * THE naming step in front of Create (AGL-700), shared by every console list
5
+ * surface that creates a record.
6
+ *
7
+ * ## Why it lives in a library
8
+ *
9
+ * It began in `apps/console`, which put it out of reach of the console pages
10
+ * that plugins ship — a plugin's console card cannot import from the app that
11
+ * renders it. So a plugin adding a create button had two options, both bad:
12
+ * an inline form stacked above its table, or a second drawer that looks
13
+ * almost but not quite like this one. Both are how a console comes to have
14
+ * three ways of creating a record.
15
+ *
16
+ * The console keeps a thin wrapper at its old path so its four existing call
17
+ * sites are untouched; it passes its own auth form template through
18
+ * {@link CreateArtifactDrawerProps.FormTemplate}.
19
+ *
20
+ * A drawer rather than a dialog on purpose: creating is a drawer, picking is
21
+ * a dialog (AGL-699). Editing is neither — it is the record's own page.
22
+ */
23
+ export interface CreateArtifactDrawerProps {
24
+ open: boolean;
25
+ onClose: () => void;
26
+ /** Drawer heading, e.g. "Create new component". */
27
+ title: string;
28
+ /** Receives the collected field values; closing is the caller's job. */
29
+ onSubmit: (values: Record<string, any>) => void | Promise<void>;
30
+ /** Extra fields appended after name and description. */
31
+ extraFields?: any[];
32
+ /** Rendered under the form when a submit fails. */
33
+ errorSlot?: ReactNode;
34
+ /**
35
+ * Whether to offer the shared Description box (AGL-2498).
36
+ *
37
+ * True for every artifact whose document stores one. Content collections do
38
+ * not: `/api/hosts/collections` filters `data` through a per-kind allowlist
39
+ * of `displayName` + `slug`, so a description typed here would be dropped
40
+ * without a word. A field the writer silently discards is worse than a field
41
+ * that was never offered.
42
+ */
43
+ includeDescription?: boolean;
44
+ /**
45
+ * The form's own chrome — the submit button and how the fields are laid out.
46
+ *
47
+ * Injectable because the console's version renders an auth-aware template
48
+ * that lives in the app and depends on the console's session hook. Defaults
49
+ * to {@link ArtifactFormTemplate}, which is the same layout without that
50
+ * dependency.
51
+ */
52
+ FormTemplate?: any;
53
+ /** Label on the submit button. */
54
+ submitLabel?: string;
55
+ }
56
+ /**
57
+ * The default chrome: the fields in a grid and one submit button.
58
+ *
59
+ * No Cancel button of its own — the drawer's app bar already carries one, and
60
+ * a second Cancel inside the form is the shape a reader has to think about.
61
+ */
62
+ export declare const ArtifactFormTemplate: import("react").ForwardRefExoticComponent<Omit<FormTemplateRenderProps, "ref"> & import("react").RefAttributes<any>>;
63
+ export declare function CreateArtifactDrawer(props: CreateArtifactDrawerProps): import("react").JSX.Element;
64
+ export declare namespace CreateArtifactDrawer {
65
+ var displayName: string;
66
+ }
67
+ /**
68
+ * Same shape and limits the layouts drawer has used since AGL-473, so the
69
+ * creates across the console validate identically.
70
+ */
71
+ export declare const BASE_FIELDS: ({
72
+ component: string;
73
+ name: string;
74
+ helperText: string;
75
+ type: string;
76
+ label: string;
77
+ isRequired: boolean;
78
+ validate: ({
79
+ type: string;
80
+ message: string;
81
+ threshold?: undefined;
82
+ } | {
83
+ type: string;
84
+ threshold: number;
85
+ message: string;
86
+ })[];
87
+ } | {
88
+ component: string;
89
+ name: string;
90
+ label: string;
91
+ helperText: string;
92
+ validate: {
93
+ type: string;
94
+ threshold: number;
95
+ message: string;
96
+ }[];
97
+ type?: undefined;
98
+ isRequired?: undefined;
99
+ })[];
100
+ export default CreateArtifactDrawer;
@@ -0,0 +1,184 @@
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
+ */ 'use client';
17
+ import { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
19
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
20
+ import { ICON_VARIANT_CLOSE } from "@aglyn/shared-data-enums";
21
+ import { Container, MdiIcon, SrOnly } from "@aglyn/shared-ui-jsx";
22
+ import { NavigationDrawerComponent } from "@aglyn/shared-ui-jsx/components/navigation-drawer.component";
23
+ import { Box, Button, FormControl, Grid, IconButton, Typography } from "@mui/material";
24
+ import { forwardRef } from "react";
25
+ import { FormRenderer, FormSpy, useFormApi } from "../vendor/data-driven-forms.js";
26
+ import { simpleComponentMapper } from "../constants/component-mappers.js";
27
+ /**
28
+ * The default chrome: the fields in a grid and one submit button.
29
+ *
30
+ * No Cancel button of its own — the drawer's app bar already carries one, and
31
+ * a second Cancel inside the form is the shape a reader has to think about.
32
+ */ export const ArtifactFormTemplate = /*#__PURE__*/ forwardRef((props, ref)=>{
33
+ const { formFields, schema } = props, rest = _object_without_properties_loose(props, [
34
+ "formFields",
35
+ "schema"
36
+ ]);
37
+ const { handleSubmit } = useFormApi();
38
+ return /*#__PURE__*/ _jsxs("form", _extends({
39
+ ref: ref,
40
+ onSubmit: handleSubmit,
41
+ noValidate: true
42
+ }, rest, {
43
+ children: [
44
+ schema.title,
45
+ /*#__PURE__*/ _jsx(Grid, {
46
+ spacing: 2,
47
+ container: true,
48
+ children: formFields
49
+ }),
50
+ /*#__PURE__*/ _jsx(FormSpy, {
51
+ children: ({ submitting })=>{
52
+ var _schema_submitLabel;
53
+ return /*#__PURE__*/ _jsx(Box, {
54
+ sx: {
55
+ mt: 2
56
+ },
57
+ children: /*#__PURE__*/ _jsx(FormControl, {
58
+ margin: "normal",
59
+ fullWidth: true,
60
+ children: /*#__PURE__*/ _jsx(Button, {
61
+ color: "primary",
62
+ disabled: submitting,
63
+ type: "submit",
64
+ variant: "contained",
65
+ fullWidth: true,
66
+ children: (_schema_submitLabel = schema.submitLabel) != null ? _schema_submitLabel : 'Next'
67
+ })
68
+ })
69
+ });
70
+ }
71
+ })
72
+ ]
73
+ }));
74
+ });
75
+ ArtifactFormTemplate.displayName = 'ArtifactFormTemplate';
76
+ ArtifactFormTemplate.aglyn = true;
77
+ export function CreateArtifactDrawer(props) {
78
+ const { open, onClose, title, onSubmit, extraFields, errorSlot, includeDescription = true, FormTemplate = ArtifactFormTemplate, submitLabel } = props;
79
+ const schema = _extends({
80
+ fields: [
81
+ ...includeDescription ? BASE_FIELDS : BASE_FIELDS.filter((field)=>field.name !== 'description'),
82
+ ...extraFields != null ? extraFields : []
83
+ ]
84
+ }, submitLabel ? {
85
+ submitLabel
86
+ } : {});
87
+ return /*#__PURE__*/ _jsx(NavigationDrawerComponent, {
88
+ open: open,
89
+ anchor: "right",
90
+ variant: "temporary",
91
+ onClose: onClose,
92
+ AppBarProps: {
93
+ color: 'surface'
94
+ },
95
+ appBarLeft: /*#__PURE__*/ _jsxs(_Fragment, {
96
+ children: [
97
+ /*#__PURE__*/ _jsxs(IconButton, {
98
+ color: "inherit",
99
+ edge: "start",
100
+ onClick: onClose,
101
+ sx: {
102
+ mr: 2
103
+ },
104
+ children: [
105
+ /*#__PURE__*/ _jsx(MdiIcon, {
106
+ path: ICON_VARIANT_CLOSE.path
107
+ }),
108
+ /*#__PURE__*/ _jsx(SrOnly, {
109
+ children: "close drawer"
110
+ })
111
+ ]
112
+ }),
113
+ /*#__PURE__*/ _jsx(Typography, {
114
+ variant: "h6",
115
+ component: "div",
116
+ children: title
117
+ })
118
+ ]
119
+ }),
120
+ appBarRight: /*#__PURE__*/ _jsx(Button, {
121
+ variant: "outlined",
122
+ color: "inherit",
123
+ onClick: onClose,
124
+ children: 'Cancel'
125
+ }),
126
+ children: /*#__PURE__*/ _jsxs(Container, {
127
+ gutterY: true,
128
+ children: [
129
+ /*#__PURE__*/ _jsx(FormRenderer, {
130
+ FormTemplate: FormTemplate,
131
+ componentMapper: simpleComponentMapper,
132
+ onSubmit: onSubmit,
133
+ schema: schema,
134
+ subscription: {
135
+ values: true
136
+ },
137
+ clearOnUnmount: true
138
+ }),
139
+ errorSlot
140
+ ]
141
+ })
142
+ });
143
+ }
144
+ /**
145
+ * Same shape and limits the layouts drawer has used since AGL-473, so the
146
+ * creates across the console validate identically.
147
+ */ export const BASE_FIELDS = [
148
+ {
149
+ component: 'text-field',
150
+ name: 'displayName',
151
+ helperText: 'Friendly name for internal reference',
152
+ type: 'text',
153
+ label: 'Display name',
154
+ isRequired: true,
155
+ validate: [
156
+ {
157
+ type: 'required',
158
+ message: 'Provide a display name'
159
+ },
160
+ {
161
+ type: 'max-length',
162
+ threshold: 25,
163
+ message: 'Must not exceed 25 characters'
164
+ }
165
+ ]
166
+ },
167
+ {
168
+ component: 'textarea',
169
+ name: 'description',
170
+ label: 'Description',
171
+ helperText: 'Brief description for internal reference',
172
+ validate: [
173
+ {
174
+ type: 'max-length',
175
+ threshold: 80,
176
+ message: 'Must not exceed 80 characters'
177
+ }
178
+ ]
179
+ }
180
+ ];
181
+ CreateArtifactDrawer.displayName = 'CreateArtifactDrawer';
182
+ export default CreateArtifactDrawer;
183
+
184
+ //# sourceMappingURL=create-artifact-drawer.component.js.map