@aglyn/shared-ui-jsx-forms 1.0.0-beta.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +7 -0
- package/package.json +52 -0
- package/src/index.d.ts +17 -0
- package/src/index.js +18 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/color-picker-tokens.d.ts +135 -0
- package/src/lib/components/color-picker-tokens.js +431 -0
- package/src/lib/components/color-picker-tokens.js.map +1 -0
- package/src/lib/components/color-picker.component.d.ts +64 -0
- package/src/lib/components/color-picker.component.js +322 -0
- package/src/lib/components/color-picker.component.js.map +1 -0
- package/src/lib/components/create-artifact-drawer.component.d.ts +100 -0
- package/src/lib/components/create-artifact-drawer.component.js +184 -0
- package/src/lib/components/create-artifact-drawer.component.js.map +1 -0
- package/src/lib/components/grid-form-template.component.d.ts +21 -0
- package/src/lib/components/grid-form-template.component.js +81 -0
- package/src/lib/components/grid-form-template.component.js.map +1 -0
- package/src/lib/components/icon-select.component.d.ts +52 -0
- package/src/lib/components/icon-select.component.js +453 -0
- package/src/lib/components/icon-select.component.js.map +1 -0
- package/src/lib/components/select.component.d.ts +58 -0
- package/src/lib/components/select.component.js +107 -0
- package/src/lib/components/select.component.js.map +1 -0
- package/src/lib/components/switch.component.d.ts +38 -0
- package/src/lib/components/switch.component.js +76 -0
- package/src/lib/components/switch.component.js.map +1 -0
- package/src/lib/components/text-field.component.d.ts +45 -0
- package/src/lib/components/text-field.component.js +77 -0
- package/src/lib/components/text-field.component.js.map +1 -0
- package/src/lib/components/textarea.component.d.ts +45 -0
- package/src/lib/components/textarea.component.js +61 -0
- package/src/lib/components/textarea.component.js.map +1 -0
- package/src/lib/components/toggle-button.component.d.ts +27 -0
- package/src/lib/components/toggle-button.component.js +116 -0
- package/src/lib/components/toggle-button.component.js.map +1 -0
- package/src/lib/constants/component-mappers.d.ts +42 -0
- package/src/lib/constants/component-mappers.js +70 -0
- package/src/lib/constants/component-mappers.js.map +1 -0
- package/src/lib/constants/dynamic-fields.d.ts +45 -0
- package/src/lib/constants/dynamic-fields.js +65 -0
- package/src/lib/constants/dynamic-fields.js.map +1 -0
- package/src/lib/constants/field-configurations.d.ts +53 -0
- package/src/lib/constants/field-configurations.js +121 -0
- package/src/lib/constants/field-configurations.js.map +1 -0
- package/src/lib/constants/flags.d.ts +72 -0
- package/src/lib/constants/flags.js +69 -0
- package/src/lib/constants/flags.js.map +1 -0
- package/src/lib/hocs/with-grid-item.d.ts +25 -0
- package/src/lib/hocs/with-grid-item.js +48 -0
- package/src/lib/hocs/with-grid-item.js.map +1 -0
- package/src/lib/jsx-forms.d.ts +41 -0
- package/src/lib/jsx-forms.js +42 -0
- package/src/lib/jsx-forms.js.map +1 -0
- package/src/lib/mapper/breakpoint-span.d.ts +73 -0
- package/src/lib/mapper/breakpoint-span.js +346 -0
- package/src/lib/mapper/breakpoint-span.js.map +1 -0
- package/src/lib/mapper/checkbox.d.ts +43 -0
- package/src/lib/mapper/checkbox.js +111 -0
- package/src/lib/mapper/checkbox.js.map +1 -0
- package/src/lib/mapper/css-border.d.ts +113 -0
- package/src/lib/mapper/css-border.js +410 -0
- package/src/lib/mapper/css-border.js.map +1 -0
- package/src/lib/mapper/css-dimension.d.ts +89 -0
- package/src/lib/mapper/css-dimension.js +327 -0
- package/src/lib/mapper/css-dimension.js.map +1 -0
- package/src/lib/mapper/css-gradient.d.ts +110 -0
- package/src/lib/mapper/css-gradient.js +720 -0
- package/src/lib/mapper/css-gradient.js.map +1 -0
- package/src/lib/mapper/data-table.d.ts +23 -0
- package/src/lib/mapper/data-table.js +296 -0
- package/src/lib/mapper/data-table.js.map +1 -0
- package/src/lib/mapper/date-picker.d.ts +26 -0
- package/src/lib/mapper/date-picker.js +69 -0
- package/src/lib/mapper/date-picker.js.map +1 -0
- package/src/lib/mapper/dual-list-select.d.ts +115 -0
- package/src/lib/mapper/dual-list-select.js +353 -0
- package/src/lib/mapper/dual-list-select.js.map +1 -0
- package/src/lib/mapper/field-array.d.ts +71 -0
- package/src/lib/mapper/field-array.js +326 -0
- package/src/lib/mapper/field-array.js.map +1 -0
- package/src/lib/mapper/form-field-grid.d.ts +155 -0
- package/src/lib/mapper/form-field-grid.js +194 -0
- package/src/lib/mapper/form-field-grid.js.map +1 -0
- package/src/lib/mapper/index.d.ts +50 -0
- package/src/lib/mapper/index.js +49 -0
- package/src/lib/mapper/index.js.map +1 -0
- package/src/lib/mapper/multiple-choice-list.d.ts +32 -0
- package/src/lib/mapper/multiple-choice-list.js +105 -0
- package/src/lib/mapper/multiple-choice-list.js.map +1 -0
- package/src/lib/mapper/plain-text.d.ts +31 -0
- package/src/lib/mapper/plain-text.js +48 -0
- package/src/lib/mapper/plain-text.js.map +1 -0
- package/src/lib/mapper/preset-choice.d.ts +106 -0
- package/src/lib/mapper/preset-choice.js +267 -0
- package/src/lib/mapper/preset-choice.js.map +1 -0
- package/src/lib/mapper/radio.d.ts +40 -0
- package/src/lib/mapper/radio.js +122 -0
- package/src/lib/mapper/radio.js.map +1 -0
- package/src/lib/mapper/select.d.ts +60 -0
- package/src/lib/mapper/select.js +203 -0
- package/src/lib/mapper/select.js.map +1 -0
- package/src/lib/mapper/slider.d.ts +45 -0
- package/src/lib/mapper/slider.js +119 -0
- package/src/lib/mapper/slider.js.map +1 -0
- package/src/lib/mapper/stored-field-value.d.ts +23 -0
- package/src/lib/mapper/stored-field-value.js +29 -0
- package/src/lib/mapper/stored-field-value.js.map +1 -0
- package/src/lib/mapper/sub-form.d.ts +39 -0
- package/src/lib/mapper/sub-form.js +108 -0
- package/src/lib/mapper/sub-form.js.map +1 -0
- package/src/lib/mapper/switch.d.ts +47 -0
- package/src/lib/mapper/switch.js +93 -0
- package/src/lib/mapper/switch.js.map +1 -0
- package/src/lib/mapper/tabs.d.ts +34 -0
- package/src/lib/mapper/tabs.js +64 -0
- package/src/lib/mapper/tabs.js.map +1 -0
- package/src/lib/mapper/text-field.d.ts +33 -0
- package/src/lib/mapper/text-field.js +88 -0
- package/src/lib/mapper/text-field.js.map +1 -0
- package/src/lib/mapper/textarea.d.ts +31 -0
- package/src/lib/mapper/textarea.js +68 -0
- package/src/lib/mapper/textarea.js.map +1 -0
- package/src/lib/mapper/theme-scale.d.ts +79 -0
- package/src/lib/mapper/theme-scale.js +162 -0
- package/src/lib/mapper/theme-scale.js.map +1 -0
- package/src/lib/mapper/time-picker.d.ts +26 -0
- package/src/lib/mapper/time-picker.js +69 -0
- package/src/lib/mapper/time-picker.js.map +1 -0
- package/src/lib/mapper/types.d.ts +43 -0
- package/src/lib/mapper/types.js +22 -0
- package/src/lib/mapper/types.js.map +1 -0
- package/src/lib/mapper/validation-error.d.ts +24 -0
- package/src/lib/mapper/validation-error.js +24 -0
- package/src/lib/mapper/validation-error.js.map +1 -0
- package/src/lib/mapper/wizard.d.ts +21 -0
- package/src/lib/mapper/wizard.js +203 -0
- package/src/lib/mapper/wizard.js.map +1 -0
- package/src/lib/types.d.ts +19 -0
- package/src/lib/types.js +18 -0
- package/src/lib/types.js.map +1 -0
- package/src/lib/utils/option-is-equal-to-value.d.ts +20 -0
- package/src/lib/utils/option-is-equal-to-value.js +21 -0
- package/src/lib/utils/option-is-equal-to-value.js.map +1 -0
- package/src/lib/utils/validation-message.d.ts +22 -0
- package/src/lib/utils/validation-message.js +24 -0
- package/src/lib/utils/validation-message.js.map +1 -0
- package/src/lib/vendor/data-driven-forms.d.ts +33 -0
- package/src/lib/vendor/data-driven-forms.js +29 -0
- package/src/lib/vendor/data-driven-forms.js.map +1 -0
|
@@ -0,0 +1,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
|