decap-cms-widget-list 3.2.2 → 3.3.0
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/CHANGELOG.md +6 -0
- package/dist/decap-cms-widget-list.js +3 -3
- package/dist/decap-cms-widget-list.js.map +1 -1
- package/dist/esm/ListControl.js +188 -149
- package/dist/esm/index.js +9 -16
- package/dist/esm/schema.js +1 -7
- package/dist/esm/typedListHelpers.js +7 -17
- package/package.json +2 -2
- package/src/ListControl.js +83 -24
- package/src/__tests__/__snapshots__/ListControl.spec.js.snap +5 -6
package/dist/esm/index.js
CHANGED
|
@@ -1,30 +1,23 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = exports.DecapCmsWidgetList = void 0;
|
|
7
|
-
var _decapCmsWidgetObject = _interopRequireDefault(require("decap-cms-widget-object"));
|
|
8
|
-
var _ListControl = _interopRequireDefault(require("./ListControl"));
|
|
9
|
-
var _schema = _interopRequireDefault(require("./schema"));
|
|
10
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
1
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
12
2
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
13
3
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
14
4
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
|
|
15
5
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
16
|
-
|
|
6
|
+
import DecapCmsWidgetObject from 'decap-cms-widget-object';
|
|
7
|
+
import controlComponent from './ListControl';
|
|
8
|
+
import schema from './schema';
|
|
9
|
+
const previewComponent = DecapCmsWidgetObject.previewComponent;
|
|
17
10
|
function Widget(opts = {}) {
|
|
18
11
|
return _objectSpread({
|
|
19
12
|
name: 'list',
|
|
20
|
-
controlComponent
|
|
13
|
+
controlComponent,
|
|
21
14
|
previewComponent,
|
|
22
|
-
schema
|
|
15
|
+
schema
|
|
23
16
|
}, opts);
|
|
24
17
|
}
|
|
25
|
-
const DecapCmsWidgetList =
|
|
18
|
+
export const DecapCmsWidgetList = {
|
|
26
19
|
Widget,
|
|
27
|
-
controlComponent
|
|
20
|
+
controlComponent,
|
|
28
21
|
previewComponent
|
|
29
22
|
};
|
|
30
|
-
|
|
23
|
+
export default DecapCmsWidgetList;
|
package/dist/esm/schema.js
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
});
|
|
6
|
-
exports.TYPE_KEY = exports.TYPES_KEY = exports.DEFAULT_TYPE_KEY = void 0;
|
|
7
|
-
exports.getErrorMessageForTypedFieldAndValue = getErrorMessageForTypedFieldAndValue;
|
|
8
|
-
exports.getTypedFieldForValue = getTypedFieldForValue;
|
|
9
|
-
exports.resolveFieldKeyType = resolveFieldKeyType;
|
|
10
|
-
exports.resolveFunctionForTypedField = resolveFunctionForTypedField;
|
|
11
|
-
const TYPES_KEY = exports.TYPES_KEY = 'types';
|
|
12
|
-
const TYPE_KEY = exports.TYPE_KEY = 'typeKey';
|
|
13
|
-
const DEFAULT_TYPE_KEY = exports.DEFAULT_TYPE_KEY = 'type';
|
|
14
|
-
function getTypedFieldForValue(field, value) {
|
|
1
|
+
export const TYPES_KEY = 'types';
|
|
2
|
+
export const TYPE_KEY = 'typeKey';
|
|
3
|
+
export const DEFAULT_TYPE_KEY = 'type';
|
|
4
|
+
export function getTypedFieldForValue(field, value) {
|
|
15
5
|
const typeKey = resolveFieldKeyType(field);
|
|
16
6
|
const types = field.get(TYPES_KEY);
|
|
17
7
|
const valueType = value.get(typeKey);
|
|
18
8
|
return types.find(type => type.get('name') === valueType);
|
|
19
9
|
}
|
|
20
|
-
function resolveFunctionForTypedField(field) {
|
|
10
|
+
export function resolveFunctionForTypedField(field) {
|
|
21
11
|
const typeKey = resolveFieldKeyType(field);
|
|
22
12
|
const types = field.get(TYPES_KEY);
|
|
23
13
|
return value => {
|
|
@@ -25,10 +15,10 @@ function resolveFunctionForTypedField(field) {
|
|
|
25
15
|
return types.find(type => type.get('name') === valueType);
|
|
26
16
|
};
|
|
27
17
|
}
|
|
28
|
-
function resolveFieldKeyType(field) {
|
|
18
|
+
export function resolveFieldKeyType(field) {
|
|
29
19
|
return field.get(TYPE_KEY, DEFAULT_TYPE_KEY);
|
|
30
20
|
}
|
|
31
|
-
function getErrorMessageForTypedFieldAndValue(field, value) {
|
|
21
|
+
export function getErrorMessageForTypedFieldAndValue(field, value) {
|
|
32
22
|
const keyType = resolveFieldKeyType(field);
|
|
33
23
|
const type = value.get(keyType);
|
|
34
24
|
let errorMessage;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "decap-cms-widget-list",
|
|
3
3
|
"description": "Widget for editing lists in Decap CMS.",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.3.0",
|
|
5
5
|
"homepage": "https://www.decapcms.org/docs/widgets/#list",
|
|
6
6
|
"repository": "https://github.com/decaporg/decap-cms/tree/main/packages/decap-cms-widget-list",
|
|
7
7
|
"bugs": "https://github.com/decaporg/decap-cms/issues",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"react": "^18.2.0",
|
|
38
38
|
"react-immutable-proptypes": "^2.1.0"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "e2165450e5963b2a8d76d4cf331319bf91f05d45"
|
|
41
41
|
}
|
package/src/ListControl.js
CHANGED
|
@@ -171,7 +171,7 @@ function LabelComponent({ field, isActive, hasErrors, uniqueFieldId, isFieldOpti
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
export default class ListControl extends React.Component {
|
|
174
|
-
|
|
174
|
+
childRefs = {};
|
|
175
175
|
|
|
176
176
|
static propTypes = {
|
|
177
177
|
metadata: ImmutablePropTypes.map,
|
|
@@ -365,16 +365,18 @@ export default class ListControl extends React.Component {
|
|
|
365
365
|
processControlRef = ref => {
|
|
366
366
|
if (!ref) return;
|
|
367
367
|
const {
|
|
368
|
-
validate,
|
|
369
368
|
props: { validationKey: key },
|
|
370
369
|
} = ref;
|
|
371
|
-
this.
|
|
370
|
+
this.childRefs[key] = ref;
|
|
371
|
+
this.props.controlRef?.(this);
|
|
372
372
|
};
|
|
373
373
|
|
|
374
374
|
validate = () => {
|
|
375
|
-
if
|
|
376
|
-
|
|
377
|
-
|
|
375
|
+
// First validate child widgets if this is a complex list
|
|
376
|
+
const hasChildWidgets = this.getValueType() && Object.keys(this.childRefs).length > 0;
|
|
377
|
+
if (hasChildWidgets) {
|
|
378
|
+
Object.values(this.childRefs).forEach(widget => {
|
|
379
|
+
widget?.validate?.();
|
|
378
380
|
});
|
|
379
381
|
} else {
|
|
380
382
|
this.props.validate();
|
|
@@ -431,7 +433,17 @@ export default class ListControl extends React.Component {
|
|
|
431
433
|
handleRemove = (index, event) => {
|
|
432
434
|
event.preventDefault();
|
|
433
435
|
const { itemsCollapsed } = this.state;
|
|
434
|
-
const {
|
|
436
|
+
const {
|
|
437
|
+
value,
|
|
438
|
+
metadata,
|
|
439
|
+
onChange,
|
|
440
|
+
field,
|
|
441
|
+
clearFieldErrors,
|
|
442
|
+
onValidateObject,
|
|
443
|
+
forID,
|
|
444
|
+
fieldsErrors,
|
|
445
|
+
} = this.props;
|
|
446
|
+
|
|
435
447
|
const collectionName = field.get('name');
|
|
436
448
|
const isSingleField = this.getValueType() === valueTypes.SINGLE;
|
|
437
449
|
|
|
@@ -441,17 +453,41 @@ export default class ListControl extends React.Component {
|
|
|
441
453
|
? { [collectionName]: metadata.removeIn(metadataRemovePath) }
|
|
442
454
|
: metadata;
|
|
443
455
|
|
|
456
|
+
// Get the key of the item being removed
|
|
457
|
+
const removedKey = this.state.keys[index];
|
|
458
|
+
|
|
459
|
+
// Update state while preserving keys for remaining items
|
|
460
|
+
const newKeys = [...this.state.keys];
|
|
461
|
+
newKeys.splice(index, 1);
|
|
444
462
|
itemsCollapsed.splice(index, 1);
|
|
445
|
-
// clear validations
|
|
446
|
-
this.validations = [];
|
|
447
463
|
|
|
448
464
|
this.setState({
|
|
449
465
|
itemsCollapsed: [...itemsCollapsed],
|
|
450
|
-
keys:
|
|
466
|
+
keys: newKeys,
|
|
451
467
|
});
|
|
452
468
|
|
|
453
|
-
|
|
454
|
-
|
|
469
|
+
// Clear the ref for the removed item
|
|
470
|
+
delete this.childRefs[removedKey];
|
|
471
|
+
|
|
472
|
+
const newValue = value.delete(index);
|
|
473
|
+
|
|
474
|
+
// Clear errors for the removed item and its children
|
|
475
|
+
if (fieldsErrors) {
|
|
476
|
+
Object.entries(fieldsErrors.toJS()).forEach(([fieldId, errors]) => {
|
|
477
|
+
if (errors.some(err => err.parentIds?.includes(removedKey))) {
|
|
478
|
+
clearFieldErrors(fieldId);
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// If list is empty, mark it as valid
|
|
484
|
+
if (newValue.size === 0) {
|
|
485
|
+
clearFieldErrors(forID);
|
|
486
|
+
onValidateObject(forID, []);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Update the value last to ensure all error states are cleared
|
|
490
|
+
onChange(newValue, parsedMetadata);
|
|
455
491
|
};
|
|
456
492
|
|
|
457
493
|
handleItemCollapseToggle = (index, event) => {
|
|
@@ -527,7 +563,7 @@ export default class ListControl extends React.Component {
|
|
|
527
563
|
}
|
|
528
564
|
|
|
529
565
|
onSortEnd = ({ oldIndex, newIndex }) => {
|
|
530
|
-
const { value
|
|
566
|
+
const { value } = this.props;
|
|
531
567
|
const { itemsCollapsed, keys } = this.state;
|
|
532
568
|
|
|
533
569
|
// Update value
|
|
@@ -541,18 +577,13 @@ export default class ListControl extends React.Component {
|
|
|
541
577
|
const updatedItemsCollapsed = [...itemsCollapsed];
|
|
542
578
|
updatedItemsCollapsed.splice(newIndex, 0, collapsed);
|
|
543
579
|
|
|
544
|
-
//
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
return key;
|
|
550
|
-
});
|
|
551
|
-
this.setState({ itemsCollapsed: updatedItemsCollapsed, keys: updatedKeys });
|
|
580
|
+
// Move keys to maintain relationships
|
|
581
|
+
const movedKey = keys[oldIndex];
|
|
582
|
+
const updatedKeys = [...keys];
|
|
583
|
+
updatedKeys.splice(oldIndex, 1);
|
|
584
|
+
updatedKeys.splice(newIndex, 0, movedKey);
|
|
552
585
|
|
|
553
|
-
|
|
554
|
-
clearFieldErrors();
|
|
555
|
-
this.validations = this.validations.filter(item => updatedKeys.includes(item.key));
|
|
586
|
+
this.setState({ itemsCollapsed: updatedItemsCollapsed, keys: updatedKeys });
|
|
556
587
|
};
|
|
557
588
|
|
|
558
589
|
hasError = index => {
|
|
@@ -564,6 +595,34 @@ export default class ListControl extends React.Component {
|
|
|
564
595
|
}
|
|
565
596
|
};
|
|
566
597
|
|
|
598
|
+
focus(path) {
|
|
599
|
+
const [index, ...remainingPath] = path.split('.');
|
|
600
|
+
|
|
601
|
+
if (this.state.listCollapsed || this.state.itemsCollapsed[index]) {
|
|
602
|
+
const newItemsCollapsed = [...this.state.itemsCollapsed];
|
|
603
|
+
newItemsCollapsed[index] = false;
|
|
604
|
+
this.setState(
|
|
605
|
+
{
|
|
606
|
+
listCollapsed: false,
|
|
607
|
+
itemsCollapsed: newItemsCollapsed,
|
|
608
|
+
},
|
|
609
|
+
() => {
|
|
610
|
+
const key = this.state.keys[index];
|
|
611
|
+
const control = this.childRefs[key];
|
|
612
|
+
if (control?.focus) {
|
|
613
|
+
control.focus(remainingPath.join('.'));
|
|
614
|
+
}
|
|
615
|
+
},
|
|
616
|
+
);
|
|
617
|
+
} else {
|
|
618
|
+
const key = this.state.keys[index];
|
|
619
|
+
const control = this.childRefs[key];
|
|
620
|
+
if (control?.focus) {
|
|
621
|
+
control.focus(remainingPath.join('.'));
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
567
626
|
// eslint-disable-next-line react/display-name
|
|
568
627
|
renderItem = (item, index) => {
|
|
569
628
|
const {
|
|
@@ -724,13 +724,12 @@ exports[`ListControl should remove from list when remove button is clicked 2`] =
|
|
|
724
724
|
<div>
|
|
725
725
|
<div
|
|
726
726
|
class="emotion-15 emotion-16"
|
|
727
|
-
style="transition: transform 0ms linear;"
|
|
728
727
|
>
|
|
729
728
|
<mock-list-item-top-bar
|
|
730
729
|
classname="css-1e1b0lr-StyledListItemTopBar e11zrb3c1"
|
|
731
730
|
collapsed="true"
|
|
732
|
-
data-testid="styled-list-item-top-bar-
|
|
733
|
-
id="
|
|
731
|
+
data-testid="styled-list-item-top-bar-1"
|
|
732
|
+
id="1"
|
|
734
733
|
>
|
|
735
734
|
<button>
|
|
736
735
|
Remove
|
|
@@ -744,12 +743,12 @@ exports[`ListControl should remove from list when remove button is clicked 2`] =
|
|
|
744
743
|
<mock-object-control
|
|
745
744
|
classnamewrapper="classNameWrapper css-1pznrxi"
|
|
746
745
|
collapsed="true"
|
|
747
|
-
data-testid="object-control-
|
|
746
|
+
data-testid="object-control-1"
|
|
748
747
|
field="Map { \\"name\\": \\"list\\", \\"label\\": \\"List\\", \\"collapsed\\": false, \\"minimize_collapsed\\": true, \\"fields\\": List [ Map { \\"label\\": \\"String\\", \\"name\\": \\"string\\", \\"widget\\": \\"string\\" } ] }"
|
|
749
748
|
fieldserrors="Map {}"
|
|
750
749
|
forlist="true"
|
|
751
|
-
parentids="forID,
|
|
752
|
-
validationkey="
|
|
750
|
+
parentids="forID,1"
|
|
751
|
+
validationkey="1"
|
|
753
752
|
value="Map { \\"string\\": \\"item 2\\" }"
|
|
754
753
|
/>
|
|
755
754
|
</div>
|