@akinon/akiform-builder 1.0.0 → 1.0.1

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 (33) hide show
  1. package/dist/cjs/__tests__/akiform-builder.test.js +257 -83
  2. package/dist/cjs/__tests__/field-builder.test.js +48 -3
  3. package/dist/cjs/index.css +10 -0
  4. package/dist/cjs/src/akiform-builder.d.ts.map +1 -1
  5. package/dist/cjs/src/akiform-builder.js +230 -63
  6. package/dist/cjs/src/field-builder.d.ts +22 -5
  7. package/dist/cjs/src/field-builder.d.ts.map +1 -1
  8. package/dist/cjs/src/field-builder.js +81 -22
  9. package/dist/cjs/src/i18n/translations/en.d.ts +7 -0
  10. package/dist/cjs/src/i18n/translations/en.d.ts.map +1 -1
  11. package/dist/cjs/src/i18n/translations/en.js +8 -1
  12. package/dist/cjs/src/i18n/translations/tr.d.ts +7 -0
  13. package/dist/cjs/src/i18n/translations/tr.d.ts.map +1 -1
  14. package/dist/cjs/src/i18n/translations/tr.js +8 -1
  15. package/dist/cjs/src/types.d.ts +27 -5
  16. package/dist/cjs/src/types.d.ts.map +1 -1
  17. package/dist/esm/__tests__/akiform-builder.test.js +257 -83
  18. package/dist/esm/__tests__/field-builder.test.js +48 -3
  19. package/dist/esm/index.css +10 -0
  20. package/dist/esm/src/akiform-builder.d.ts.map +1 -1
  21. package/dist/esm/src/akiform-builder.js +231 -64
  22. package/dist/esm/src/field-builder.d.ts +22 -5
  23. package/dist/esm/src/field-builder.d.ts.map +1 -1
  24. package/dist/esm/src/field-builder.js +81 -22
  25. package/dist/esm/src/i18n/translations/en.d.ts +7 -0
  26. package/dist/esm/src/i18n/translations/en.d.ts.map +1 -1
  27. package/dist/esm/src/i18n/translations/en.js +8 -1
  28. package/dist/esm/src/i18n/translations/tr.d.ts +7 -0
  29. package/dist/esm/src/i18n/translations/tr.d.ts.map +1 -1
  30. package/dist/esm/src/i18n/translations/tr.js +8 -1
  31. package/dist/esm/src/types.d.ts +27 -5
  32. package/dist/esm/src/types.d.ts.map +1 -1
  33. package/package.json +19 -16
@@ -120,10 +120,54 @@ describe('FieldBuilder', () => {
120
120
  render: renderFn
121
121
  });
122
122
  });
123
+ it('should build row and col fields', () => {
124
+ const customField = (0, field_builder_1.field)()
125
+ .type('row')
126
+ .key('mainrow')
127
+ .rowProps({
128
+ align: 'middle'
129
+ })
130
+ .columnFields([
131
+ (0, field_builder_1.field)()
132
+ .type('column')
133
+ .key('col1')
134
+ .columnProps({
135
+ span: 24
136
+ })
137
+ .fields([
138
+ (0, field_builder_1.field)().type('text').key('test1').label('Text label').build()
139
+ ])
140
+ .build()
141
+ ])
142
+ .build();
143
+ expect(customField).toEqual({
144
+ type: 'row',
145
+ key: 'mainrow',
146
+ rowProps: {
147
+ align: 'middle'
148
+ },
149
+ columnFields: [
150
+ {
151
+ type: 'column',
152
+ key: 'col1',
153
+ columnProps: {
154
+ span: 24
155
+ },
156
+ fields: [
157
+ {
158
+ type: 'text',
159
+ key: 'test1',
160
+ label: 'Text label'
161
+ }
162
+ ]
163
+ }
164
+ ]
165
+ });
166
+ });
123
167
  it('should throw an error if required properties are missing', () => {
124
- expect(() => (0, field_builder_1.field)().build()).toThrow('Field must have at least a key, label, and type');
125
- expect(() => (0, field_builder_1.field)().key('test').build()).toThrow('Field must have at least a key, label, and type');
126
- expect(() => (0, field_builder_1.field)().key('test').label('Test').build()).toThrow('Field must have at least a key, label, and type');
168
+ expect(() => (0, field_builder_1.field)().build()).toThrow('Field must have at least a key and type');
169
+ expect(() => (0, field_builder_1.field)().key('test').build()).toThrow('Field must have at least a key and type');
170
+ expect(() => (0, field_builder_1.field)().type('text').build()).toThrow('Field must have at least a key and type');
127
171
  });
128
172
  it('should only allow options for select fields', () => {
129
173
  const selectField = (0, field_builder_1.field)()
@@ -238,6 +282,7 @@ describe('FieldBuilder', () => {
238
282
  .key('name')
239
283
  .label('Name')
240
284
  .type('text')
285
+ // @ts-expect-error : We are explicitly waiting .fields to throw an error.
241
286
  .fields([(0, field_builder_1.field)().key('invalid').label('Invalid').type('text').build()])
242
287
  .build();
243
288
  expect(textField).toEqual({
@@ -5,3 +5,13 @@
5
5
  .akiform-builder-field-array {
6
6
  padding-bottom: 1rem;
7
7
  }
8
+
9
+ .akiform-builder-form-actions {
10
+ display: flex;
11
+ align-items: center;
12
+ gap: 0.5rem;
13
+ }
14
+
15
+ .akiform-builder-action-icon {
16
+ cursor: pointer;
17
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"akiform-builder.d.ts","sourceRoot":"","sources":["../../../src/akiform-builder.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAErB,OAAO,EAKL,WAAW,EAMZ,MAAM,iBAAiB,CAAC;AAWzB,OAAO,KAWN,MAAM,OAAO,CAAC;AAGf,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EAMlB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,cAAc,MAAM,CAAC;AAgJlC,eAAO,MAAM,cAAc,yHAwS1B,CAAC"}
1
+ {"version":3,"file":"akiform-builder.d.ts","sourceRoot":"","sources":["../../../src/akiform-builder.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAErB,OAAO,EAML,WAAW,EAMZ,MAAM,iBAAiB,CAAC;AAczB,OAAO,KAWN,MAAM,OAAO,CAAC;AAGf,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EAQlB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,cAAc,MAAM,CAAC;AA6WlC,eAAO,MAAM,cAAc,yHA+V1B,CAAC"}
@@ -15,35 +15,120 @@ exports.AkiformBuilder = exports.THROTTLE_DELAY = void 0;
15
15
  require("./index.css");
16
16
  const akiform_1 = require("@akinon/akiform");
17
17
  const akival_1 = require("@akinon/akival");
18
+ const icons_1 = require("@akinon/icons");
18
19
  const ui_button_1 = require("@akinon/ui-button");
19
20
  const ui_checkbox_1 = require("@akinon/ui-checkbox");
20
21
  const ui_collapse_1 = require("@akinon/ui-collapse");
21
22
  const ui_date_picker_1 = require("@akinon/ui-date-picker");
23
+ const ui_divider_1 = require("@akinon/ui-divider");
22
24
  const ui_input_1 = require("@akinon/ui-input");
23
25
  const ui_input_number_1 = require("@akinon/ui-input-number");
26
+ const ui_layout_1 = require("@akinon/ui-layout");
24
27
  const ui_select_1 = require("@akinon/ui-select");
25
- const ui_space_1 = require("@akinon/ui-space");
26
28
  const ui_typography_1 = require("@akinon/ui-typography");
29
+ const clsx_1 = require("clsx");
27
30
  const react_1 = require("react");
28
31
  const i18n_1 = require("./i18n");
29
32
  exports.THROTTLE_DELAY = 300; // ms
33
+ const checkIsDisabled = ({ field, formValues }) => {
34
+ var _a;
35
+ const configDisabledProperty = (_a = field.config) === null || _a === void 0 ? void 0 : _a.disabled;
36
+ return typeof configDisabledProperty === 'function'
37
+ ? configDisabledProperty(formValues)
38
+ : !!configDisabledProperty;
39
+ };
40
+ const checkIsVisible = ({ field, formValues }) => {
41
+ var _a;
42
+ const configVisibleProperty = (_a = field.config) === null || _a === void 0 ? void 0 : _a.visible;
43
+ return typeof configVisibleProperty === 'function'
44
+ ? configVisibleProperty(formValues)
45
+ : configVisibleProperty !== false;
46
+ };
30
47
  const SectionComponent = ({ field, control, formValues, formState, layout, layoutOptions }) => {
31
- return (react_1.default.createElement(ui_collapse_1.Collapse, { defaultActiveKey: field.defaultExpanded ? [field.key] : [], items: [
32
- {
33
- label: field.label,
34
- key: field.key,
35
- children: field.fields.map(nestedField => {
36
- var _a, _b;
37
- const isVisible = typeof ((_a = nestedField.config) === null || _a === void 0 ? void 0 : _a.visible) === 'function'
38
- ? nestedField.config.visible(formValues)
39
- : ((_b = nestedField.config) === null || _b === void 0 ? void 0 : _b.visible) !== false;
40
- if (!isVisible) {
41
- return null;
42
- }
43
- return (react_1.default.createElement(akiform_1.FormItem, { key: nestedField.key, control: control, name: nestedField.key, label: nestedField.label }, renderField(nestedField, control, formValues, formState, layout, layoutOptions)));
44
- })
45
- }
46
- ] }));
48
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
+ const { errors } = formState;
50
+ if (field.collapsible) {
51
+ return (react_1.default.createElement(ui_collapse_1.Collapse, { defaultActiveKey: field.defaultExpanded ? [field.key] : [], expandIcon: panelProps => ({
52
+ name: 'circle-down',
53
+ style: {
54
+ color: 'var(--color-azure-500)',
55
+ transform: panelProps.isActive ? 'rotate(-180deg)' : 'rotate(0deg)',
56
+ transition: 'transform 0.3s'
57
+ },
58
+ size: 20
59
+ }), items: [
60
+ {
61
+ label: (react_1.default.createElement("div", { className: "akiform-builder-form-actions" },
62
+ react_1.default.createElement(ui_typography_1.Text, { strong: true }, field.label),
63
+ Object.keys(errors).length > 0 ? (react_1.default.createElement(ui_typography_1.Text, { strong: true, type: "danger" }, i18n_1.i18n.t('an_error_occurred'))) : null)),
64
+ key: field.key,
65
+ children: field.fields.map(nestedField => {
66
+ return renderFormItem({
67
+ field: nestedField,
68
+ control,
69
+ formValues,
70
+ formState,
71
+ layout,
72
+ layoutOptions
73
+ });
74
+ })
75
+ }
76
+ ] }));
77
+ }
78
+ else {
79
+ return (react_1.default.createElement(react_1.default.Fragment, null,
80
+ react_1.default.createElement(ui_divider_1.Divider, { orientation: "left", plain: true, plainOffset: 40 }, field.label),
81
+ field.fields.map(nestedField => {
82
+ return renderFormItem({
83
+ field: nestedField,
84
+ control,
85
+ formValues,
86
+ formState,
87
+ layout,
88
+ layoutOptions
89
+ });
90
+ })));
91
+ }
92
+ };
93
+ const RowComponent = ({ field, control, formValues, formState, layout, layoutOptions }) => {
94
+ const { columnFields, rowProps } = field;
95
+ if (!(columnFields === null || columnFields === void 0 ? void 0 : columnFields.length))
96
+ return;
97
+ return (react_1.default.createElement(ui_layout_1.Row, Object.assign({}, rowProps), columnFields.map(columnField => {
98
+ const { columnProps } = columnField;
99
+ const isVisible = checkIsVisible({
100
+ field: columnField,
101
+ formValues
102
+ });
103
+ if (!isVisible)
104
+ return null;
105
+ return (react_1.default.createElement(ui_layout_1.Col, Object.assign({ key: columnField.key, flex: "1" }, columnProps),
106
+ react_1.default.createElement(ColumnComponent, { field: columnField, control: control, formValues: formValues, formState: formState, layout: layout, layoutOptions: layoutOptions })));
107
+ })));
108
+ };
109
+ const ColumnComponent = ({ field, control, formValues, formState, layout, layoutOptions }) => {
110
+ const { fields } = field;
111
+ if (!(fields === null || fields === void 0 ? void 0 : fields.length))
112
+ return;
113
+ return fields.map(rowField => {
114
+ const isVisible = checkIsVisible({
115
+ field: rowField,
116
+ formValues
117
+ });
118
+ if (!isVisible)
119
+ return null;
120
+ const isRowField = rowField.type === 'row';
121
+ return isRowField
122
+ ? renderField(rowField, control, formValues, formState, layout, layoutOptions)
123
+ : renderFormItem({
124
+ field: rowField,
125
+ control,
126
+ formValues,
127
+ formState,
128
+ layout,
129
+ layoutOptions
130
+ });
131
+ });
47
132
  };
48
133
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
134
  const renderField = (field, control, formValues,
@@ -63,7 +148,7 @@ formState, layout, layoutOptions) => {
63
148
  case 'checkbox':
64
149
  return (react_1.default.createElement(ui_checkbox_1.Checkbox, Object.assign({ checked: formValues[field.key] }, commonProps), field.label));
65
150
  case 'date':
66
- return (react_1.default.createElement(ui_date_picker_1.DatePicker, Object.assign({ placeholder: field.placeholder, size: "large" }, commonProps)));
151
+ return (react_1.default.createElement(ui_date_picker_1.DatePicker, Object.assign({ placeholder: field.placeholder, showTime: field.showTime }, commonProps)));
67
152
  case 'textarea':
68
153
  return react_1.default.createElement(ui_input_1.InputTextArea, Object.assign({ placeholder: field.placeholder }, commonProps));
69
154
  case 'fieldArray':
@@ -76,13 +161,32 @@ formState, layout, layoutOptions) => {
76
161
  return react_1.default.createElement(react_1.Fragment, null);
77
162
  case 'section':
78
163
  return (react_1.default.createElement(SectionComponent, { field: field, control: control, formValues: formValues, formState: formState, layout: layout, layoutOptions: layoutOptions }));
164
+ case 'row':
165
+ return (react_1.default.createElement(RowComponent, { field: field, control: control, formValues: formValues, formState: formState, layout: layout, layoutOptions: layoutOptions }));
166
+ case 'column':
167
+ return (react_1.default.createElement(ColumnComponent, { field: field, control: control, formValues: formValues, formState: formState, layout: layout, layoutOptions: layoutOptions }));
79
168
  default:
80
169
  return react_1.default.createElement(react_1.Fragment, null);
81
170
  }
82
171
  };
172
+ const renderFormItem = ({ field, control, formValues, formState, layout, layoutOptions, customVisibleCheck }) => {
173
+ const isVisible = customVisibleCheck
174
+ ? customVisibleCheck()
175
+ : checkIsVisible({
176
+ field,
177
+ formValues
178
+ });
179
+ if (!isVisible)
180
+ return null;
181
+ const isDisabled = checkIsDisabled({
182
+ field,
183
+ formValues
184
+ });
185
+ return (react_1.default.createElement(akiform_1.FormItem, { key: field.key, control: control, name: field.key, label: field.label, required: field.validation ? true : false, tooltip: field.tooltip, disabled: isDisabled, help: field.help, labelDescription: field.labelDescription }, renderField(field, control, formValues, formState, layout, layoutOptions)));
186
+ };
83
187
  exports.AkiformBuilder = (0, react_1.forwardRef)((_a, ref) => {
84
188
  var _b, _c;
85
- var { fields, onSubmit, layout = 'vertical', layoutOptions, showResetButton = false, onReset, controlled = false, values, onValueChange } = _a, rest = __rest(_a, ["fields", "onSubmit", "layout", "layoutOptions", "showResetButton", "onReset", "controlled", "values", "onValueChange"]);
189
+ var { fields, onSubmit, layout = 'vertical', layoutOptions, showResetButton = false, onReset, controlled = false, values, onValueChange, submitButtonProps, resetButtonProps } = _a, rest = __rest(_a, ["fields", "onSubmit", "layout", "layoutOptions", "showResetButton", "onReset", "controlled", "values", "onValueChange", "submitButtonProps", "resetButtonProps"]);
86
190
  const validationSchema = (0, react_1.useMemo)(() => {
87
191
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
88
192
  const schema = {};
@@ -112,6 +216,8 @@ exports.AkiformBuilder = (0, react_1.forwardRef)((_a, ref) => {
112
216
  const prevFormValuesRef = (0, react_1.useRef)(null);
113
217
  const isInitialRenderRef = (0, react_1.useRef)(true);
114
218
  const throttleTimeoutRef = (0, react_1.useRef)(null);
219
+ const hasSubmitButton = !!onSubmit;
220
+ const hasFormActions = hasSubmitButton || showResetButton;
115
221
  const handleValueChange = (0, react_1.useCallback)((values) => {
116
222
  if (!controlled) {
117
223
  if (throttleTimeoutRef.current) {
@@ -217,47 +323,78 @@ exports.AkiformBuilder = (0, react_1.forwardRef)((_a, ref) => {
217
323
  }
218
324
  }
219
325
  }));
326
+ const renderSubmitButton = () => {
327
+ const _a = submitButtonProps || {}, { children, block = false, className } = _a, otherSubmitButtonProps = __rest(_a, ["children", "block", "className"]);
328
+ const submitButtonClassName = (0, clsx_1.default)(className, {
329
+ 'w-full': block
330
+ });
331
+ return (react_1.default.createElement(ui_button_1.Button, Object.assign({ className: submitButtonClassName, type: "primary" }, otherSubmitButtonProps, { htmlType: "submit" }), children || i18n_1.i18n.t('submit')));
332
+ };
333
+ const renderShowResetButton = () => {
334
+ const _a = resetButtonProps || {}, { children, block = false, className, onClick } = _a, otherResetButtonProps = __rest(_a, ["children", "block", "className", "onClick"]);
335
+ const resetButtonClassName = (0, clsx_1.default)(className, {
336
+ 'w-full': block
337
+ });
338
+ const handleOnClickReset = event => {
339
+ handleReset(event);
340
+ if (onClick) {
341
+ onClick(event);
342
+ }
343
+ };
344
+ return (react_1.default.createElement(ui_button_1.Button
345
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
346
+ , Object.assign({
347
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
348
+ onClick: handleOnClickReset, className: resetButtonClassName, type: "default" }, otherResetButtonProps, { htmlType: "reset" }), children || i18n_1.i18n.t('reset')));
349
+ };
350
+ const renderFormActions = () => {
351
+ return (react_1.default.createElement("div", { className: "akiform-builder-form-actions" },
352
+ hasSubmitButton && renderSubmitButton(),
353
+ showResetButton && renderShowResetButton()));
354
+ };
220
355
  return (react_1.default.createElement("div", { className: "akiform-builder" },
221
- react_1.default.createElement(akiform_1.Akiform, Object.assign({ onFinish: handleSubmit(onSubmit), onReset: handleReset, layout: layout }, formItemLayout, rest, { "data-testid": "akiform-builder", role: "form", "aria-label": i18n_1.i18n.t('formLabel'), requiredMark: true }),
356
+ react_1.default.createElement(akiform_1.Akiform, Object.assign({}, (hasSubmitButton && { onFinish: handleSubmit(onSubmit) }), { onReset: handleReset, layout: layout }, formItemLayout, rest, { "data-testid": "akiform-builder", role: "form", "aria-label": i18n_1.i18n.t('formLabel'), requiredMark: true }),
222
357
  fields.map(field => {
223
- var _a, _b, _c, _d;
224
- const isDisabled = typeof ((_a = field.config) === null || _a === void 0 ? void 0 : _a.disabled) === 'function'
225
- ? field.config.disabled(formValues)
226
- : (_b = field.config) === null || _b === void 0 ? void 0 : _b.disabled;
227
- const isVisible = typeof ((_c = field.config) === null || _c === void 0 ? void 0 : _c.visible) === 'function'
228
- ? field.config.visible(formValues)
229
- : ((_d = field.config) === null || _d === void 0 ? void 0 : _d.visible) !== false;
358
+ const isVisible = checkIsVisible({
359
+ field,
360
+ formValues
361
+ });
230
362
  if (!isVisible) {
231
363
  return null;
232
364
  }
233
- if (field.type === 'section') {
234
- return (react_1.default.createElement(SectionComponent, { key: field.key, field: field, control: control, formValues: formValues, formState: formState, layout: layout, layoutOptions: layoutOptions }));
365
+ switch (field.type) {
366
+ case 'section':
367
+ return (react_1.default.createElement(SectionComponent, { key: field.key, field: field, control: control, formValues: formValues, formState: formState, layout: layout, layoutOptions: layoutOptions }));
368
+ case 'fieldArray':
369
+ return (react_1.default.createElement("div", { className: "akiform-builder-field-array", key: field.key },
370
+ react_1.default.createElement(ui_divider_1.Divider, { orientation: "left", plain: true, plainOffset: 40 },
371
+ react_1.default.createElement("span", { id: `${field.key}-label` }, field.label)),
372
+ renderField(field, control, formValues, formState, layout, layoutOptions)));
373
+ case 'row':
374
+ return renderField(field, control, formValues, formState, layout, layoutOptions);
375
+ default:
376
+ return renderFormItem({
377
+ field,
378
+ control,
379
+ formValues,
380
+ formState,
381
+ layout,
382
+ layoutOptions
383
+ });
235
384
  }
236
- if (field.type === 'fieldArray') {
237
- return (react_1.default.createElement("div", { className: "akiform-builder-field-array", key: field.key },
238
- react_1.default.createElement(ui_typography_1.Title, { level: 5 }, field.label),
239
- renderField(field, control, formValues, formState, layout, layoutOptions)));
240
- }
241
- return (react_1.default.createElement(akiform_1.FormItem, { key: field.key, control: control, name: field.key, label: field.label, disabled: isDisabled, required: field.validation ? true : false, tooltip: field.tooltip }, renderField(field, control, formValues, formState, layout, layoutOptions)));
242
385
  }),
243
- react_1.default.createElement(akiform_1.FormItem, { control: control, name: 'form_actions', wrapperCol: layout === 'horizontal'
386
+ hasFormActions && (react_1.default.createElement(akiform_1.FormItem, { control: control, name: 'form_actions', wrapperCol: layout === 'horizontal'
244
387
  ? {
245
388
  offset: (_b = formItemLayout.labelCol) === null || _b === void 0 ? void 0 : _b.span,
246
389
  span: (_c = formItemLayout.wrapperCol) === null || _c === void 0 ? void 0 : _c.span
247
390
  }
248
- : undefined },
249
- react_1.default.createElement(ui_space_1.Space, null,
250
- react_1.default.createElement(ui_button_1.Button, { type: "primary", htmlType: "submit" }, i18n_1.i18n.t('submit')),
251
- showResetButton && (react_1.default.createElement(ui_button_1.Button
252
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
253
- , {
254
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
255
- onClick: handleReset, type: "default", htmlType: "reset" }, i18n_1.i18n.t('reset'))))))));
391
+ : undefined }, renderFormActions())))));
256
392
  });
257
393
  exports.AkiformBuilder.displayName = 'AkiformBuilder';
258
394
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
259
395
  const FieldArrayComponent = ({ field, control, formValues, formState, layout, layoutOptions }) => {
260
- const { fields, append, remove } = (0, akiform_1.useFieldArray)({
396
+ const { errors } = formState;
397
+ const { fields, append, remove, insert } = (0, akiform_1.useFieldArray)({
261
398
  control,
262
399
  name: field.key
263
400
  });
@@ -270,22 +407,52 @@ const FieldArrayComponent = ({ field, control, formValues, formState, layout, la
270
407
  {});
271
408
  };
272
409
  return (react_1.default.createElement("div", { role: "group", "aria-labelledby": `${field.key}-label` },
273
- react_1.default.createElement("div", { id: `${field.key}-label`, className: "sr-only", "aria-hidden": true }, field.label),
274
- fields.map((item, index) => (react_1.default.createElement("div", { key: item.id },
275
- field.fields.map(nestedField => {
276
- var _a, _b;
277
- const isVisible = typeof ((_a = nestedField.config) === null || _a === void 0 ? void 0 : _a.visible) === 'function'
278
- ? nestedField.config.visible(((_b = formValues[field.key]) === null || _b === void 0 ? void 0 : _b[index]) || {})
279
- : true;
280
- if (!isVisible) {
281
- return null;
282
- }
283
- return (react_1.default.createElement(akiform_1.FormItem, { key: `${field.key}.${index}.${nestedField.key}`, control: control, name: `${field.key}.${index}.${nestedField.key}`, label: nestedField.label, required: nestedField.validation ? true : false }, renderField(Object.assign(Object.assign({}, nestedField), {
284
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
285
- key: `${field.key}.${index}.${nestedField.key}` }), control, formValues, formState, layout, layoutOptions)));
286
- }),
287
- react_1.default.createElement(ui_button_1.Button, { icon: "eksi", size: "small", danger: true, onClick: () => remove(index), "aria-label": `Remove ${field.label} ${index + 1}` }, "Remove")))),
288
- react_1.default.createElement(ui_button_1.Button, { icon: "arti", size: "small", type: "text",
289
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
290
- onClick: () => append(createInitialValue()), "aria-label": `Add ${field.label}` }, "Add")));
410
+ !fields.length && (react_1.default.createElement("div", { className: "akiform-builder-form-actions akiform-builder-action-icon", "data-testid": `${field.key}-add-button`, onClick: () => append(createInitialValue()) },
411
+ react_1.default.createElement(icons_1.Icon, { icon: "plus", size: 20, color: "var(--color-green-500)", "aria-label": i18n_1.i18n.t('add', { label: field.label }) }),
412
+ react_1.default.createElement(ui_typography_1.Text, { strong: true }, i18n_1.i18n.t('add', { label: field.label })))),
413
+ fields.map((item, index) => {
414
+ var _a;
415
+ return (react_1.default.createElement(react_1.Fragment, { key: item.id },
416
+ react_1.default.createElement(ui_collapse_1.Collapse, { collapsible: "icon", defaultActiveKey: field.defaultExpanded ? [item.id] : [], expandIcon: panelProps => ({
417
+ name: 'circle-down',
418
+ style: {
419
+ color: 'var(--color-azure-500)',
420
+ transform: panelProps.isActive
421
+ ? 'rotate(-180deg)'
422
+ : 'rotate(0deg)',
423
+ transition: 'transform 0.3s'
424
+ },
425
+ size: 20
426
+ }), items: [
427
+ {
428
+ label: (react_1.default.createElement("div", { className: "akiform-builder-form-actions" },
429
+ react_1.default.createElement(ui_typography_1.Text, { strong: true }, i18n_1.i18n.t('itemof', {
430
+ label: field.label,
431
+ count: index + 1,
432
+ ordinal: true
433
+ })),
434
+ react_1.default.createElement(icons_1.Icon, { className: "akiform-builder-action-icon", onClick: () => remove(index), icon: "minus", size: 20, color: "var(--color-red-500)", "aria-label": i18n_1.i18n.t('remove', { label: field.label }) }),
435
+ react_1.default.createElement(icons_1.Icon, { className: "akiform-builder-action-icon", onClick: () => insert(index + 1, createInitialValue()), icon: "plus", size: 20, color: "var(--color-green-500)", "aria-label": i18n_1.i18n.t('add', { label: field.label }) }),
436
+ ((_a = errors[field.key]) === null || _a === void 0 ? void 0 : _a[index]) ? (react_1.default.createElement(ui_typography_1.Text, { strong: true, type: "danger" }, i18n_1.i18n.t('an_error_occurred'))) : null)),
437
+ key: field.key,
438
+ children: field.fields.map(nestedField => {
439
+ return renderFormItem({
440
+ field: Object.assign(Object.assign({}, nestedField), { key: `${field.key}.${index}.${nestedField.key}` }),
441
+ control,
442
+ formValues,
443
+ formState,
444
+ layout,
445
+ layoutOptions,
446
+ customVisibleCheck: () => {
447
+ var _a, _b;
448
+ return typeof ((_a = nestedField.config) === null || _a === void 0 ? void 0 : _a.visible) === 'function'
449
+ ? nestedField.config.visible(((_b = formValues[field.key]) === null || _b === void 0 ? void 0 : _b[index]) || {})
450
+ : true;
451
+ }
452
+ });
453
+ })
454
+ }
455
+ ] }),
456
+ react_1.default.createElement(ui_divider_1.Divider, { plain: true })));
457
+ })));
291
458
  };
@@ -1,10 +1,11 @@
1
1
  import { FieldPath, FieldValues } from '@akinon/akiform';
2
2
  import { AnySchema } from '@akinon/akival';
3
+ import { ColProps, RowProps } from '@akinon/ui-layout';
3
4
  import { TooltipProps } from '@akinon/ui-tooltip';
4
5
  import { FieldConfig, FieldType, FormField } from './types';
5
- type FieldTypeToBuilder<T extends FieldType, TFieldValues extends FieldValues = FieldValues> = T extends 'select' ? SelectFieldBuilder<TFieldValues> : T extends 'custom' ? CustomFieldBuilder<TFieldValues> : T extends 'section' ? SectionFieldBuilder<TFieldValues> : BaseFieldBuilder<TFieldValues>;
6
+ type FieldTypeToBuilder<T extends FieldType, TFieldValues extends FieldValues = FieldValues> = T extends 'select' ? SelectFieldBuilder<TFieldValues> : T extends 'date' ? DateFieldBuilder<TFieldValues> : T extends 'custom' ? CustomFieldBuilder<TFieldValues> : T extends 'section' ? SectionFieldBuilder<TFieldValues> : T extends 'fieldArray' ? FieldArrayOrSectionFieldBuilder<TFieldValues> : T extends 'row' ? RowFieldBuilder<TFieldValues> : T extends 'column' ? ColumnFieldBuilder<TFieldValues> : BaseFieldBuilder<TFieldValues>;
6
7
  declare class BaseFieldBuilder<TFieldValues extends FieldValues = FieldValues> {
7
- protected field: Partial<FormField<TFieldValues>>;
8
+ field: Partial<FormField<TFieldValues>>;
8
9
  key(key: FieldPath<TFieldValues>): this;
9
10
  label(label: string): this;
10
11
  type<T extends FieldType>(type: T): FieldTypeToBuilder<T, TFieldValues>;
@@ -12,8 +13,9 @@ declare class BaseFieldBuilder<TFieldValues extends FieldValues = FieldValues> {
12
13
  defaultValue(value: any): this;
13
14
  validation(schema: AnySchema): this;
14
15
  config(config: FieldConfig<TFieldValues>): this;
15
- fields(fields: FormField<TFieldValues>[]): this;
16
16
  tooltip(tooltipProps: TooltipProps | string): this;
17
+ help(help: string): this;
18
+ labelDescription(labelDescription: string): this;
17
19
  build(): FormField<TFieldValues>;
18
20
  }
19
21
  declare class SelectFieldBuilder<TFieldValues extends FieldValues = FieldValues> extends BaseFieldBuilder<TFieldValues> {
@@ -22,6 +24,9 @@ declare class SelectFieldBuilder<TFieldValues extends FieldValues = FieldValues>
22
24
  label: string;
23
25
  }>): this;
24
26
  }
27
+ declare class DateFieldBuilder<TFieldValues extends FieldValues = FieldValues> extends BaseFieldBuilder<TFieldValues> {
28
+ showTime(showTime: boolean): this;
29
+ }
25
30
  declare class CustomFieldBuilder<TFieldValues extends FieldValues = FieldValues> extends BaseFieldBuilder<TFieldValues> {
26
31
  render(renderFn: (props: {
27
32
  field: FormField<TFieldValues>;
@@ -29,9 +34,21 @@ declare class CustomFieldBuilder<TFieldValues extends FieldValues = FieldValues>
29
34
  control: any;
30
35
  }) => React.ReactElement): this;
31
36
  }
32
- declare class SectionFieldBuilder<TFieldValues extends FieldValues = FieldValues> extends BaseFieldBuilder<TFieldValues> {
37
+ declare class FieldArrayOrSectionFieldBuilder<TFieldValues extends FieldValues = FieldValues> extends BaseFieldBuilder<TFieldValues> {
33
38
  defaultExpanded(expanded: boolean): this;
39
+ fields(fields: FormField<TFieldValues>[]): this;
40
+ }
41
+ declare class SectionFieldBuilder<TFieldValues extends FieldValues = FieldValues> extends FieldArrayOrSectionFieldBuilder<TFieldValues> {
42
+ collapsible(collapsible: boolean): this;
43
+ }
44
+ declare class RowFieldBuilder<TFieldValues extends FieldValues = FieldValues> extends BaseFieldBuilder<TFieldValues> {
45
+ columnFields(columnFields: FormField<TFieldValues>[]): this;
46
+ rowProps(rowProps: RowProps): this;
47
+ }
48
+ declare class ColumnFieldBuilder<TFieldValues extends FieldValues = FieldValues> extends BaseFieldBuilder<TFieldValues> {
49
+ fields(fields: FormField<TFieldValues>[]): this;
50
+ columnProps(columnProps: ColProps): this;
34
51
  }
35
- export declare function field<TFieldValues extends FieldValues = FieldValues>(): BaseFieldBuilder<TFieldValues> & SelectFieldBuilder<TFieldValues> & CustomFieldBuilder<TFieldValues> & SectionFieldBuilder<TFieldValues>;
52
+ export declare function field<TFieldValues extends FieldValues = FieldValues>(): BaseFieldBuilder<TFieldValues> & SelectFieldBuilder<TFieldValues> & DateFieldBuilder<TFieldValues> & CustomFieldBuilder<TFieldValues> & SectionFieldBuilder<TFieldValues> & FieldArrayOrSectionFieldBuilder<TFieldValues>;
36
53
  export {};
37
54
  //# sourceMappingURL=field-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"field-builder.d.ts","sourceRoot":"","sources":["../../../src/field-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAEL,WAAW,EACX,SAAS,EACT,SAAS,EAEV,MAAM,SAAS,CAAC;AAEjB,KAAK,kBAAkB,CACrB,CAAC,SAAS,SAAS,EACnB,YAAY,SAAS,WAAW,GAAG,WAAW,IAC5C,CAAC,SAAS,QAAQ,GAClB,kBAAkB,CAAC,YAAY,CAAC,GAChC,CAAC,SAAS,QAAQ,GAChB,kBAAkB,CAAC,YAAY,CAAC,GAChC,CAAC,SAAS,SAAS,GACjB,mBAAmB,CAAC,YAAY,CAAC,GACjC,gBAAgB,CAAC,YAAY,CAAC,CAAC;AAEvC,cAAM,gBAAgB,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW;IACnE,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAM;IAEvD,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,YAAY,CAAC,GAAG,IAAI;IAKvC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1B,IAAI,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE,CAAC,GAAG,kBAAkB,CAAC,CAAC,EAAE,YAAY,CAAC;IAKvE,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAMtC,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IAK9B,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAKnC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,YAAY,CAAC,GAAG,IAAI;IAM/C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,YAAY,CAAC,EAAE,GAAG,IAAI;IAa/C,OAAO,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI;IAKlD,KAAK,IAAI,SAAS,CAAC,YAAY,CAAC;CAMjC;AAED,cAAM,kBAAkB,CACtB,YAAY,SAAS,WAAW,GAAG,WAAW,CAC9C,SAAQ,gBAAgB,CAAC,YAAY,CAAC;IACtC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI;CAKzE;AAED,cAAM,kBAAkB,CACtB,YAAY,SAAS,WAAW,GAAG,WAAW,CAC9C,SAAQ,gBAAgB,CAAC,YAAY,CAAC;IACtC,MAAM,CACJ,QAAQ,EAAE,CAAC,KAAK,EAAE;QAChB,KAAK,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;QAC/B,UAAU,EAAE,YAAY,CAAC;QAEzB,OAAO,EAAE,GAAG,CAAC;KACd,KAAK,KAAK,CAAC,YAAY,GACvB,IAAI;CAKR;AAED,cAAM,mBAAmB,CACvB,YAAY,SAAS,WAAW,GAAG,WAAW,CAC9C,SAAQ,gBAAgB,CAAC,YAAY,CAAC;IACtC,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;CAIzC;AAED,wBAAgB,KAAK,CACnB,YAAY,SAAS,WAAW,GAAG,WAAW,KAC3C,gBAAgB,CAAC,YAAY,CAAC,GACjC,kBAAkB,CAAC,YAAY,CAAC,GAChC,kBAAkB,CAAC,YAAY,CAAC,GAChC,mBAAmB,CAAC,YAAY,CAAC,CAoBlC"}
1
+ {"version":3,"file":"field-builder.d.ts","sourceRoot":"","sources":["../../../src/field-builder.ts"],"names":[],"mappings":"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"}