@qoretechnologies/reqraft 0.10.2 → 0.10.4
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/design/COMPACT_ENGINE_REDESIGN.md +156 -0
- package/design/FORM_ENGINE_COMPACT_UX_PLAN.md +353 -0
- package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
- package/dist/components/form/engine/CompactRow.js +153 -94
- package/dist/components/form/engine/CompactRow.js.map +1 -1
- package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
- package/dist/components/form/engine/CompactToolbar.js +130 -94
- package/dist/components/form/engine/CompactToolbar.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +181 -45
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/compactRowStyles.d.ts +6 -3
- package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
- package/dist/components/form/engine/compactRowStyles.js +70 -48
- package/dist/components/form/engine/compactRowStyles.js.map +1 -1
- package/dist/components/form/engine/compactToolbarContext.d.ts +1 -0
- package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
- package/dist/components/form/engine/compactToolbarContext.js.map +1 -1
- package/dist/components/form/engine/readFirst.d.ts +19 -0
- package/dist/components/form/engine/readFirst.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.js +22 -1
- package/dist/components/form/engine/readFirst.js.map +1 -1
- package/dist/components/form/engine/variants/VariantCalmTable.d.ts +6 -0
- package/dist/components/form/engine/variants/VariantCalmTable.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantCalmTable.js +94 -0
- package/dist/components/form/engine/variants/VariantCalmTable.js.map +1 -0
- package/dist/components/form/engine/variants/VariantCards.d.ts +6 -0
- package/dist/components/form/engine/variants/VariantCards.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantCards.js +80 -0
- package/dist/components/form/engine/variants/VariantCards.js.map +1 -0
- package/dist/components/form/engine/variants/VariantFocus.d.ts +7 -0
- package/dist/components/form/engine/variants/VariantFocus.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantFocus.js +138 -0
- package/dist/components/form/engine/variants/VariantFocus.js.map +1 -0
- package/dist/components/form/engine/variants/VariantMinimal.d.ts +6 -0
- package/dist/components/form/engine/variants/VariantMinimal.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantMinimal.js +73 -0
- package/dist/components/form/engine/variants/VariantMinimal.js.map +1 -0
- package/dist/components/form/engine/variants/focusDemo.d.ts +13 -0
- package/dist/components/form/engine/variants/focusDemo.d.ts.map +1 -0
- package/dist/components/form/engine/variants/focusDemo.js +139 -0
- package/dist/components/form/engine/variants/focusDemo.js.map +1 -0
- package/dist/components/form/engine/variants/variantModel.d.ts +70 -0
- package/dist/components/form/engine/variants/variantModel.d.ts.map +1 -0
- package/dist/components/form/engine/variants/variantModel.js +133 -0
- package/dist/components/form/engine/variants/variantModel.js.map +1 -0
- package/dist/components/form/engine/variants/variantParts.d.ts +79 -0
- package/dist/components/form/engine/variants/variantParts.d.ts.map +1 -0
- package/dist/components/form/engine/variants/variantParts.js +191 -0
- package/dist/components/form/engine/variants/variantParts.js.map +1 -0
- package/dist/components/form/fields/auto/AutoFormField.d.ts +3 -0
- package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.js +2 -2
- package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
- package/package.json +1 -1
- package/src/components/form/engine/CompactRow.tsx +256 -234
- package/src/components/form/engine/CompactToolbar.tsx +108 -68
- package/src/components/form/engine/FormEngine.stories.tsx +127 -110
- package/src/components/form/engine/FormEngine.tsx +248 -67
- package/src/components/form/engine/compactRowStyles.ts +207 -134
- package/src/components/form/engine/compactToolbarContext.ts +1 -0
- package/src/components/form/engine/readFirst.ts +35 -0
- package/src/components/form/engine/variants/FormEngineVariants.stories.tsx +119 -0
- package/src/components/form/engine/variants/VariantCalmTable.tsx +242 -0
- package/src/components/form/engine/variants/VariantCards.tsx +212 -0
- package/src/components/form/engine/variants/VariantFocus.tsx +382 -0
- package/src/components/form/engine/variants/VariantMinimal.tsx +170 -0
- package/src/components/form/engine/variants/focusDemo.ts +145 -0
- package/src/components/form/engine/variants/variantModel.ts +216 -0
- package/src/components/form/engine/variants/variantParts.tsx +313 -0
- package/src/components/form/fields/auto/AutoFormField.tsx +5 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VARIANT 1 — "Calm Table"
|
|
3
|
+
*
|
|
4
|
+
* Direction: treat it like a clean data table. One status channel (segmented
|
|
5
|
+
* meter), one mark per row (a status dot), whitespace instead of borders/boxes.
|
|
6
|
+
* Errors are quiet inline text, not full-width red boxes. WHOLE-ROW hover.
|
|
7
|
+
* ONE unified description control (tap to reveal short+long inline). Click a row
|
|
8
|
+
* to edit it inline. Responsive: collapses to stacked label/value on phone.
|
|
9
|
+
*/
|
|
10
|
+
import { ReqoreIcon, ReqoreP } from '@qoretechnologies/reqore';
|
|
11
|
+
import { IQorusFormField, IQorusFormSchema } from '@qoretechnologies/ts-toolkit';
|
|
12
|
+
import styled from 'styled-components';
|
|
13
|
+
import {
|
|
14
|
+
InlineEdit,
|
|
15
|
+
StatusDot,
|
|
16
|
+
TVariantForm,
|
|
17
|
+
ValueView,
|
|
18
|
+
VariantToolbar,
|
|
19
|
+
useDisclosure,
|
|
20
|
+
useVariantColors,
|
|
21
|
+
useVariantForm,
|
|
22
|
+
} from './variantParts';
|
|
23
|
+
|
|
24
|
+
const Wrap = styled.div<{ $line: string; $hover: string; $muted: string; $faint: string }>`
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-flow: column;
|
|
27
|
+
gap: 22px;
|
|
28
|
+
font-size: 13px;
|
|
29
|
+
|
|
30
|
+
.vct-row {
|
|
31
|
+
display: grid;
|
|
32
|
+
grid-template-columns: minmax(180px, 320px) minmax(0, 1fr) auto;
|
|
33
|
+
align-items: center;
|
|
34
|
+
gap: 18px;
|
|
35
|
+
min-height: 40px;
|
|
36
|
+
padding: 6px 10px;
|
|
37
|
+
border-radius: 8px;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
transition: background 0.12s ease;
|
|
40
|
+
}
|
|
41
|
+
/* WHOLE-row hover (fixes: hover used to only tint the label cell) */
|
|
42
|
+
.vct-row:hover,
|
|
43
|
+
.vct-row:focus-within {
|
|
44
|
+
background: ${({ $hover }) => $hover};
|
|
45
|
+
}
|
|
46
|
+
.vct-label {
|
|
47
|
+
font-weight: 600;
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
gap: 6px;
|
|
51
|
+
min-width: 0;
|
|
52
|
+
}
|
|
53
|
+
.vct-actions {
|
|
54
|
+
display: inline-flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
gap: 10px;
|
|
57
|
+
opacity: 0.85;
|
|
58
|
+
}
|
|
59
|
+
.vct-desc {
|
|
60
|
+
grid-column: 1 / -1;
|
|
61
|
+
padding: 2px 2px 6px 0;
|
|
62
|
+
color: ${({ $muted }) => $muted};
|
|
63
|
+
}
|
|
64
|
+
.vct-reason {
|
|
65
|
+
font-size: 12px;
|
|
66
|
+
margin-left: 8px;
|
|
67
|
+
}
|
|
68
|
+
.vct-info {
|
|
69
|
+
background: none;
|
|
70
|
+
border: none;
|
|
71
|
+
color: ${({ $faint }) => $faint};
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
padding: 4px;
|
|
74
|
+
display: inline-flex;
|
|
75
|
+
border-radius: 6px;
|
|
76
|
+
}
|
|
77
|
+
.vct-info:hover {
|
|
78
|
+
color: ${({ $muted }) => $muted};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@media (max-width: 620px) {
|
|
82
|
+
.vct-row {
|
|
83
|
+
grid-template-columns: 1fr auto;
|
|
84
|
+
grid-template-areas: 'label actions' 'value value';
|
|
85
|
+
row-gap: 2px;
|
|
86
|
+
}
|
|
87
|
+
.vct-label {
|
|
88
|
+
grid-area: label;
|
|
89
|
+
}
|
|
90
|
+
.vct-value {
|
|
91
|
+
grid-area: value;
|
|
92
|
+
}
|
|
93
|
+
.vct-actions {
|
|
94
|
+
grid-area: actions;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
const Meter = ({ form }: { form: TVariantForm }) => {
|
|
100
|
+
const c = useVariantColors();
|
|
101
|
+
const s = form.summary;
|
|
102
|
+
const filtering = form.filter === 'attention';
|
|
103
|
+
return (
|
|
104
|
+
<div style={{ display: 'flex', flexFlow: 'column', gap: 8 }}>
|
|
105
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 12, fontSize: 12, color: c.muted }}>
|
|
106
|
+
<ReqoreP
|
|
107
|
+
size='small'
|
|
108
|
+
effect={{
|
|
109
|
+
uppercase: true,
|
|
110
|
+
spaced: 1,
|
|
111
|
+
weight: 'bold',
|
|
112
|
+
color: (s.attention ? c.warning : c.success) as never,
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
{s.attention ? 'Draft' : 'Ready'}
|
|
116
|
+
</ReqoreP>
|
|
117
|
+
<span>
|
|
118
|
+
{s.set} of {s.total} set
|
|
119
|
+
</span>
|
|
120
|
+
{s.attention ?
|
|
121
|
+
<button
|
|
122
|
+
type='button'
|
|
123
|
+
onClick={form.toggleAttention}
|
|
124
|
+
style={{
|
|
125
|
+
marginLeft: 'auto',
|
|
126
|
+
background: 'none',
|
|
127
|
+
border: 'none',
|
|
128
|
+
cursor: 'pointer',
|
|
129
|
+
color: c.warning,
|
|
130
|
+
fontSize: 12,
|
|
131
|
+
textDecoration: 'underline',
|
|
132
|
+
textUnderlineOffset: 3,
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
{filtering ? '← show all fields' : `${s.attention} need attention →`}
|
|
136
|
+
</button>
|
|
137
|
+
: <span style={{ color: c.success, marginLeft: 'auto' }}>All clear</span>}
|
|
138
|
+
</div>
|
|
139
|
+
<div style={{ display: 'flex', height: 6, borderRadius: 3, overflow: 'hidden', background: c.line }}>
|
|
140
|
+
<div style={{ width: `${(s.set / s.total) * 100}%`, background: c.success }} />
|
|
141
|
+
<div style={{ width: `${(s.attention / s.total) * 100}%`, background: c.warning }} />
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const VariantCalmTable = ({
|
|
148
|
+
options,
|
|
149
|
+
values,
|
|
150
|
+
}: {
|
|
151
|
+
options: IQorusFormSchema;
|
|
152
|
+
values: Record<string, IQorusFormField>;
|
|
153
|
+
}) => {
|
|
154
|
+
const c = useVariantColors();
|
|
155
|
+
const form = useVariantForm(options, values);
|
|
156
|
+
const disc = useDisclosure();
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<Wrap $line={c.line} $hover={c.hover} $muted={c.muted} $faint={c.faint}>
|
|
160
|
+
<Meter form={form} />
|
|
161
|
+
<VariantToolbar form={form} />
|
|
162
|
+
{form.visibleGroups.map((g) => (
|
|
163
|
+
<div key={g.name} style={{ display: 'flex', flexFlow: 'column', gap: 2 }}>
|
|
164
|
+
<div
|
|
165
|
+
style={{
|
|
166
|
+
display: 'flex',
|
|
167
|
+
alignItems: 'center',
|
|
168
|
+
gap: 10,
|
|
169
|
+
padding: '0 10px 6px',
|
|
170
|
+
borderBottom: `1px solid ${c.line}`,
|
|
171
|
+
marginBottom: 4,
|
|
172
|
+
}}
|
|
173
|
+
>
|
|
174
|
+
<ReqoreP effect={{ weight: 'bold' }}>{g.label}</ReqoreP>
|
|
175
|
+
<span style={{ color: c.faint, fontSize: 12 }}>{g.rows.length}</span>
|
|
176
|
+
</div>
|
|
177
|
+
{g.rows.map((r) => {
|
|
178
|
+
const hasDesc = !!(r.shortDesc || r.longDesc);
|
|
179
|
+
const open = disc.isOpen(r.name);
|
|
180
|
+
const editing = form.editing === r.name;
|
|
181
|
+
return (
|
|
182
|
+
<div
|
|
183
|
+
key={r.name}
|
|
184
|
+
className='vct-row'
|
|
185
|
+
role='button'
|
|
186
|
+
tabIndex={0}
|
|
187
|
+
aria-label={r.label}
|
|
188
|
+
onClick={() => !r.readOnly && form.startEdit(r.name)}
|
|
189
|
+
>
|
|
190
|
+
<span className='vct-label' style={{ color: c.text }}>
|
|
191
|
+
{r.label}
|
|
192
|
+
{r.required ?
|
|
193
|
+
<ReqoreIcon icon='Asterisk' size='9px' style={{ color: c.danger }} />
|
|
194
|
+
: null}
|
|
195
|
+
</span>
|
|
196
|
+
<span className='vct-value' style={{ minWidth: 0, color: c.muted }}>
|
|
197
|
+
<ValueView value={r.value} />
|
|
198
|
+
{r.status === 'invalid' || r.status === 'todo' ?
|
|
199
|
+
<span
|
|
200
|
+
className='vct-reason'
|
|
201
|
+
style={{ color: r.status === 'invalid' ? c.danger : c.warning }}
|
|
202
|
+
>
|
|
203
|
+
{r.reason}
|
|
204
|
+
</span>
|
|
205
|
+
: null}
|
|
206
|
+
</span>
|
|
207
|
+
<span className='vct-actions'>
|
|
208
|
+
<StatusDot status={r.status} />
|
|
209
|
+
{hasDesc ?
|
|
210
|
+
<button
|
|
211
|
+
type='button'
|
|
212
|
+
className='vct-info'
|
|
213
|
+
aria-label='Toggle description'
|
|
214
|
+
aria-expanded={open}
|
|
215
|
+
onClick={(e) => {
|
|
216
|
+
e.stopPropagation();
|
|
217
|
+
disc.toggle(r.name);
|
|
218
|
+
}}
|
|
219
|
+
>
|
|
220
|
+
<ReqoreIcon icon={open ? 'InformationFill' : 'InformationLine'} size='14px' />
|
|
221
|
+
</button>
|
|
222
|
+
: null}
|
|
223
|
+
</span>
|
|
224
|
+
{hasDesc && open ?
|
|
225
|
+
<div className='vct-desc'>
|
|
226
|
+
{r.shortDesc ? <div>{r.shortDesc}</div> : null}
|
|
227
|
+
{r.longDesc ?
|
|
228
|
+
<div style={{ opacity: 0.8, marginTop: r.shortDesc ? 4 : 0 }}>
|
|
229
|
+
{r.longDesc.replace(/[#`*]/g, '')}
|
|
230
|
+
</div>
|
|
231
|
+
: null}
|
|
232
|
+
</div>
|
|
233
|
+
: null}
|
|
234
|
+
{editing ? <InlineEdit row={r} onDone={form.stopEdit} /> : null}
|
|
235
|
+
</div>
|
|
236
|
+
);
|
|
237
|
+
})}
|
|
238
|
+
</div>
|
|
239
|
+
))}
|
|
240
|
+
</Wrap>
|
|
241
|
+
);
|
|
242
|
+
};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VARIANT 2 — "Cards / Stack"
|
|
3
|
+
*
|
|
4
|
+
* Direction: breathing room over density. Each field is a subtle card with a
|
|
5
|
+
* generous tap target (phone-friendly). Status is shown with a single left
|
|
6
|
+
* accent — but ONLY for genuinely invalid (touched) fields; to-dos get a calm
|
|
7
|
+
* amber label dot, unset fields stay neutral. The description control sits on
|
|
8
|
+
* the LEFT under the label (where the text appears). Click a card to edit inline.
|
|
9
|
+
*/
|
|
10
|
+
import { ReqoreIcon, ReqoreP } from '@qoretechnologies/reqore';
|
|
11
|
+
import { IQorusFormField, IQorusFormSchema } from '@qoretechnologies/ts-toolkit';
|
|
12
|
+
import styled from 'styled-components';
|
|
13
|
+
import {
|
|
14
|
+
InlineEdit,
|
|
15
|
+
STATUS_COLOR,
|
|
16
|
+
ValueView,
|
|
17
|
+
VariantToolbar,
|
|
18
|
+
useDisclosure,
|
|
19
|
+
useVariantColors,
|
|
20
|
+
useVariantForm,
|
|
21
|
+
} from './variantParts';
|
|
22
|
+
|
|
23
|
+
const Wrap = styled.div<{ $surface: string; $line: string; $hover: string }>`
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-flow: column;
|
|
26
|
+
gap: 26px;
|
|
27
|
+
font-size: 13px;
|
|
28
|
+
|
|
29
|
+
.vc-card {
|
|
30
|
+
position: relative;
|
|
31
|
+
display: grid;
|
|
32
|
+
grid-template-columns: minmax(200px, 0.7fr) minmax(0, 1.3fr);
|
|
33
|
+
gap: 18px;
|
|
34
|
+
padding: 14px 16px;
|
|
35
|
+
border-radius: 10px;
|
|
36
|
+
background: ${({ $surface }) => $surface};
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
transition: background 0.12s ease;
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
}
|
|
41
|
+
.vc-card:hover,
|
|
42
|
+
.vc-card:focus-within {
|
|
43
|
+
background: ${({ $hover }) => $hover};
|
|
44
|
+
}
|
|
45
|
+
.vc-accent {
|
|
46
|
+
position: absolute;
|
|
47
|
+
left: 0;
|
|
48
|
+
top: 0;
|
|
49
|
+
bottom: 0;
|
|
50
|
+
width: 3px;
|
|
51
|
+
}
|
|
52
|
+
.vc-name {
|
|
53
|
+
font-weight: 600;
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
gap: 7px;
|
|
57
|
+
}
|
|
58
|
+
.vc-descbtn {
|
|
59
|
+
background: none;
|
|
60
|
+
border: none;
|
|
61
|
+
padding: 0;
|
|
62
|
+
margin-top: 6px;
|
|
63
|
+
color: inherit;
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
display: inline-flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 5px;
|
|
68
|
+
font-size: 12px;
|
|
69
|
+
}
|
|
70
|
+
.vc-value {
|
|
71
|
+
align-self: center;
|
|
72
|
+
min-width: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@media (max-width: 620px) {
|
|
76
|
+
.vc-card {
|
|
77
|
+
grid-template-columns: 1fr;
|
|
78
|
+
gap: 8px;
|
|
79
|
+
padding: 14px;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
export const VariantCards = ({
|
|
85
|
+
options,
|
|
86
|
+
values,
|
|
87
|
+
}: {
|
|
88
|
+
options: IQorusFormSchema;
|
|
89
|
+
values: Record<string, IQorusFormField>;
|
|
90
|
+
}) => {
|
|
91
|
+
const c = useVariantColors();
|
|
92
|
+
const form = useVariantForm(options, values);
|
|
93
|
+
const s = form.summary;
|
|
94
|
+
const disc = useDisclosure();
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<Wrap $surface={c.surface} $line={c.line} $hover={c.hover}>
|
|
98
|
+
<div style={{ display: 'flex', flexFlow: 'column', gap: 10 }}>
|
|
99
|
+
<div style={{ display: 'flex', alignItems: 'baseline', gap: 12 }}>
|
|
100
|
+
<ReqoreP size='big' effect={{ weight: 'bold' }}>
|
|
101
|
+
{s.pct}% complete
|
|
102
|
+
</ReqoreP>
|
|
103
|
+
<span style={{ color: c.muted, fontSize: 12 }}>
|
|
104
|
+
{s.set}/{s.total} set
|
|
105
|
+
</span>
|
|
106
|
+
{s.attention ?
|
|
107
|
+
<button
|
|
108
|
+
type='button'
|
|
109
|
+
onClick={form.toggleAttention}
|
|
110
|
+
style={{
|
|
111
|
+
background: 'none',
|
|
112
|
+
border: 'none',
|
|
113
|
+
cursor: 'pointer',
|
|
114
|
+
color: c.warning,
|
|
115
|
+
fontSize: 12,
|
|
116
|
+
textDecoration: 'underline',
|
|
117
|
+
textUnderlineOffset: 3,
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{form.filter === 'attention' ? '← show all' : `${s.attention} need attention →`}
|
|
121
|
+
</button>
|
|
122
|
+
: null}
|
|
123
|
+
</div>
|
|
124
|
+
<div style={{ height: 4, borderRadius: 2, background: c.line, overflow: 'hidden' }}>
|
|
125
|
+
<div style={{ width: `${s.pct}%`, height: '100%', background: c.success }} />
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
<VariantToolbar form={form} />
|
|
129
|
+
|
|
130
|
+
{form.visibleGroups.map((g) => (
|
|
131
|
+
<div key={g.name} style={{ display: 'flex', flexFlow: 'column', gap: 10 }}>
|
|
132
|
+
<ReqoreP effect={{ weight: 'bold', uppercase: true, spaced: 1 }} size='small'>
|
|
133
|
+
{g.label}
|
|
134
|
+
</ReqoreP>
|
|
135
|
+
<div style={{ display: 'flex', flexFlow: 'column', gap: 8 }}>
|
|
136
|
+
{g.rows.map((r) => {
|
|
137
|
+
const hasDesc = !!(r.shortDesc || r.longDesc);
|
|
138
|
+
const open = disc.isOpen(r.name);
|
|
139
|
+
const editing = form.editing === r.name;
|
|
140
|
+
return (
|
|
141
|
+
<div
|
|
142
|
+
key={r.name}
|
|
143
|
+
className='vc-card'
|
|
144
|
+
role='button'
|
|
145
|
+
tabIndex={0}
|
|
146
|
+
onClick={() => !r.readOnly && form.startEdit(r.name)}
|
|
147
|
+
>
|
|
148
|
+
{r.status === 'invalid' ?
|
|
149
|
+
<span className='vc-accent' style={{ background: c.danger }} />
|
|
150
|
+
: null}
|
|
151
|
+
<div>
|
|
152
|
+
<span className='vc-name' style={{ color: c.text }}>
|
|
153
|
+
{r.status === 'todo' || r.status === 'invalid' ?
|
|
154
|
+
<span
|
|
155
|
+
aria-hidden
|
|
156
|
+
style={{
|
|
157
|
+
width: 6,
|
|
158
|
+
height: 6,
|
|
159
|
+
borderRadius: '50%',
|
|
160
|
+
background: STATUS_COLOR(r.status, c),
|
|
161
|
+
}}
|
|
162
|
+
/>
|
|
163
|
+
: null}
|
|
164
|
+
{r.label}
|
|
165
|
+
{r.required ?
|
|
166
|
+
<ReqoreIcon icon='Asterisk' size='9px' style={{ color: c.danger }} />
|
|
167
|
+
: null}
|
|
168
|
+
</span>
|
|
169
|
+
{hasDesc ?
|
|
170
|
+
<button
|
|
171
|
+
type='button'
|
|
172
|
+
className='vc-descbtn'
|
|
173
|
+
style={{ color: c.faint }}
|
|
174
|
+
aria-expanded={open}
|
|
175
|
+
onClick={(e) => {
|
|
176
|
+
e.stopPropagation();
|
|
177
|
+
disc.toggle(r.name);
|
|
178
|
+
}}
|
|
179
|
+
>
|
|
180
|
+
<ReqoreIcon icon={open ? 'ArrowUpSLine' : 'QuestionLine'} size='12px' />
|
|
181
|
+
{open ? 'Hide info' : 'Info'}
|
|
182
|
+
</button>
|
|
183
|
+
: null}
|
|
184
|
+
{open ?
|
|
185
|
+
<div style={{ color: c.muted, marginTop: 6, fontSize: 12, lineHeight: 1.5 }}>
|
|
186
|
+
{r.shortDesc ? <div>{r.shortDesc}</div> : null}
|
|
187
|
+
{r.longDesc ?
|
|
188
|
+
<div style={{ opacity: 0.85, marginTop: r.shortDesc ? 4 : 0 }}>
|
|
189
|
+
{r.longDesc.replace(/[#`*]/g, '')}
|
|
190
|
+
</div>
|
|
191
|
+
: null}
|
|
192
|
+
</div>
|
|
193
|
+
: null}
|
|
194
|
+
</div>
|
|
195
|
+
<div className='vc-value' style={{ color: c.muted }}>
|
|
196
|
+
<ValueView value={r.value} />
|
|
197
|
+
{r.status === 'invalid' ?
|
|
198
|
+
<div style={{ color: c.danger, fontSize: 12, marginTop: 4 }}>{r.reason}</div>
|
|
199
|
+
: r.status === 'todo' ?
|
|
200
|
+
<div style={{ color: c.warning, fontSize: 12, marginTop: 4 }}>{r.reason}</div>
|
|
201
|
+
: null}
|
|
202
|
+
</div>
|
|
203
|
+
{editing ? <InlineEdit row={r} onDone={form.stopEdit} /> : null}
|
|
204
|
+
</div>
|
|
205
|
+
);
|
|
206
|
+
})}
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
))}
|
|
210
|
+
</Wrap>
|
|
211
|
+
);
|
|
212
|
+
};
|