vanilla-jui 1.5.3 → 1.5.5
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/dist/index.d.ts +3 -5
- package/dist/index.js +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +2 -7
- package/src/components/form.ts +150 -110
- package/src/components/modal.ts +56 -54
- package/src/index.ts +0 -1
- package/src/locales/index.ts +2 -0
- package/src/utilities/object.ts +16 -3
- package/src/utilities/function.ts +0 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanilla-jui",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A lightweight, reactive, and fully customizable vanilla JS UI library.",
|
|
6
6
|
"keywords": [
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"build": "vp pack",
|
|
56
|
-
"pack": "vp pack",
|
|
56
|
+
"pack": "vp check --fix && vp pack",
|
|
57
57
|
"dev": "vp dev",
|
|
58
58
|
"test": "vp test",
|
|
59
59
|
"check": "vp check",
|
|
@@ -61,8 +61,6 @@
|
|
|
61
61
|
"prepublishOnly": "vp run build"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@types/lodash-es": "^4.17.12",
|
|
65
|
-
"lodash-es": "^4.18.1",
|
|
66
64
|
"vanilla-create-storage": "latest",
|
|
67
65
|
"vanilla-signal": "^1.1.4",
|
|
68
66
|
"vanilla-signal-i18n": "latest"
|
|
@@ -73,9 +71,6 @@
|
|
|
73
71
|
"typescript": "latest",
|
|
74
72
|
"vite-plus": "latest"
|
|
75
73
|
},
|
|
76
|
-
"inlinedDependencies": {
|
|
77
|
-
"lodash-es": "4.18.1"
|
|
78
|
-
},
|
|
79
74
|
"registry": {
|
|
80
75
|
"type": "git",
|
|
81
76
|
"url": "git+https://github.com/WangShai123/vanilla-jui.git"
|
package/src/components/form.ts
CHANGED
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
} from '../utilities/types.ts';
|
|
24
24
|
import { createValidator } from '../validation/validator.ts';
|
|
25
25
|
import { createLoading } from '../primitives/loading.ts';
|
|
26
|
+
import { t } from 'vanilla-signal-i18n';
|
|
27
|
+
import locales from '../locales/index.ts';
|
|
26
28
|
|
|
27
29
|
type FormValue = string | number | boolean;
|
|
28
30
|
export type FieldOption = FormValue | FormOption;
|
|
@@ -99,7 +101,10 @@ export interface FormField {
|
|
|
99
101
|
label?: RenderableContent<Form> | false;
|
|
100
102
|
name?: string;
|
|
101
103
|
options?: readonly FieldOption[];
|
|
102
|
-
value?:
|
|
104
|
+
value?:
|
|
105
|
+
| FormDataEntryValue
|
|
106
|
+
| FormValue
|
|
107
|
+
| readonly (FormDataEntryValue | FormValue)[];
|
|
103
108
|
checked?: boolean;
|
|
104
109
|
required?: boolean;
|
|
105
110
|
placeholder?: string;
|
|
@@ -230,8 +235,18 @@ const DEFAULT_CLASS_NAMES: FormClassNames = {
|
|
|
230
235
|
};
|
|
231
236
|
|
|
232
237
|
const DEFAULT_BUTTONS: FormButton[] = [
|
|
233
|
-
{
|
|
234
|
-
|
|
238
|
+
{
|
|
239
|
+
type: 'submit',
|
|
240
|
+
text: t('Submit', locales),
|
|
241
|
+
theme: 'primary',
|
|
242
|
+
action: 'submit',
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
type: 'reset',
|
|
246
|
+
text: t('Reset', locales),
|
|
247
|
+
theme: 'ghost',
|
|
248
|
+
action: 'reset',
|
|
249
|
+
},
|
|
235
250
|
];
|
|
236
251
|
|
|
237
252
|
// Guard against malformed dynamic chains that never terminate.
|
|
@@ -688,96 +703,109 @@ export function createForm(input: FormProps = {}): Form {
|
|
|
688
703
|
};
|
|
689
704
|
|
|
690
705
|
const controlProps = <TExtra extends Record<string, unknown>>(
|
|
691
|
-
|
|
706
|
+
fieldAccessor: () => FormField,
|
|
692
707
|
id: string,
|
|
693
708
|
extra: TExtra
|
|
694
709
|
): TExtra & Record<string, unknown> => ({
|
|
695
710
|
...extra,
|
|
696
|
-
name:
|
|
711
|
+
name: () => fieldAccessor().name,
|
|
697
712
|
id,
|
|
698
|
-
placeholder:
|
|
699
|
-
required: !!
|
|
700
|
-
disabled: () => state.submitting || !!
|
|
701
|
-
readonly: !!
|
|
702
|
-
'data-form-field':
|
|
713
|
+
placeholder: () => fieldAccessor().placeholder || '',
|
|
714
|
+
required: () => !!fieldAccessor().required,
|
|
715
|
+
disabled: () => state.submitting || !!fieldAccessor().disabled,
|
|
716
|
+
readonly: () => !!fieldAccessor().readonly,
|
|
717
|
+
'data-form-field': () => fieldAccessor().name || id,
|
|
703
718
|
});
|
|
704
719
|
|
|
705
720
|
const choiceGroupView = (
|
|
706
|
-
|
|
721
|
+
fieldAccessor: () => FormField,
|
|
707
722
|
id: string,
|
|
708
723
|
type: 'checkbox' | 'radio'
|
|
709
724
|
): HTMLElement => {
|
|
710
|
-
const direction = field.vertical ? 'vertical' : 'horizontal';
|
|
711
|
-
const names = state.className;
|
|
712
725
|
return jsx('div', {
|
|
713
|
-
className:
|
|
714
|
-
|
|
715
|
-
direction
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
726
|
+
className: () => {
|
|
727
|
+
const field = fieldAccessor();
|
|
728
|
+
const direction = field.vertical ? 'vertical' : 'horizontal';
|
|
729
|
+
const names = state.className;
|
|
730
|
+
return joinClasses(
|
|
731
|
+
type === 'radio' ? names.radio : names.checkbox,
|
|
732
|
+
direction === 'vertical'
|
|
733
|
+
? names.choiceVertical
|
|
734
|
+
: names.choiceHorizontal,
|
|
735
|
+
field.group ? names.choiceGroup : '',
|
|
736
|
+
field.size ? `is-${field.size}` : ''
|
|
737
|
+
);
|
|
738
|
+
},
|
|
739
|
+
'data-form-choice-group': () => fieldAccessor().name || id,
|
|
722
740
|
'data-choice-type': type,
|
|
723
|
-
'data-choice-layout':
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
'
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
741
|
+
'data-choice-layout': () =>
|
|
742
|
+
fieldAccessor().vertical ? 'vertical' : 'horizontal',
|
|
743
|
+
children: () =>
|
|
744
|
+
(fieldAccessor().options || []).map((option, optionIndex) => {
|
|
745
|
+
const item = normalizeOption(option);
|
|
746
|
+
const optionId = `${id}_${optionIndex}`;
|
|
747
|
+
return jsx('label', {
|
|
748
|
+
className: () =>
|
|
749
|
+
type === 'radio' ? state.className.radioLabel : '',
|
|
750
|
+
'data-form-choice': () => fieldAccessor().name || id,
|
|
751
|
+
for: optionId,
|
|
752
|
+
children: [
|
|
753
|
+
jsx('input', {
|
|
754
|
+
type,
|
|
755
|
+
id: optionId,
|
|
756
|
+
name: () => fieldAccessor().name,
|
|
757
|
+
value: item.value ?? '',
|
|
758
|
+
checked: () =>
|
|
759
|
+
type === 'radio'
|
|
760
|
+
? isSelected(fieldAccessor().value, item.value)
|
|
761
|
+
: isChecked(
|
|
762
|
+
fieldAccessor().value,
|
|
763
|
+
item.value,
|
|
764
|
+
item.checked
|
|
765
|
+
),
|
|
766
|
+
disabled: () =>
|
|
767
|
+
state.submitting ||
|
|
768
|
+
!!item.disabled ||
|
|
769
|
+
!!fieldAccessor().disabled,
|
|
770
|
+
required: () => !!fieldAccessor().required,
|
|
771
|
+
onChange: (event: Event) => {
|
|
772
|
+
const target = event.currentTarget;
|
|
773
|
+
if (target instanceof HTMLInputElement) {
|
|
774
|
+
syncFieldValue(fieldAccessor(), target, type);
|
|
775
|
+
}
|
|
776
|
+
},
|
|
777
|
+
}),
|
|
778
|
+
jsx('span', {
|
|
779
|
+
className: () =>
|
|
780
|
+
type === 'radio' ? state.className.radioText : '',
|
|
781
|
+
'data-form-choice-text': '',
|
|
782
|
+
children: item.text ?? item.label ?? item.value ?? '',
|
|
783
|
+
}),
|
|
784
|
+
],
|
|
785
|
+
});
|
|
786
|
+
}),
|
|
759
787
|
}) as HTMLElement;
|
|
760
788
|
};
|
|
761
789
|
|
|
762
790
|
const controlView = (
|
|
763
|
-
|
|
764
|
-
|
|
791
|
+
itemAccessor: () => FormItem<FormField>,
|
|
792
|
+
fieldAccessor: () => FormField,
|
|
765
793
|
id: string,
|
|
766
|
-
|
|
767
|
-
item: FormItem<FormField>
|
|
794
|
+
indexAccessor: () => number
|
|
768
795
|
): RenderableContent<FormControlContext> => {
|
|
769
|
-
const
|
|
796
|
+
const type = itemAccessor().type;
|
|
770
797
|
if (type === 'textarea') {
|
|
771
798
|
return jsx(
|
|
772
799
|
'textarea',
|
|
773
|
-
controlProps(
|
|
774
|
-
className:
|
|
775
|
-
|
|
776
|
-
|
|
800
|
+
controlProps(fieldAccessor, id, {
|
|
801
|
+
className: () =>
|
|
802
|
+
fieldAccessor().className || state.className.textarea,
|
|
803
|
+
autocomplete: () => fieldAccessor().autocomplete,
|
|
804
|
+
value: () => fieldAccessor().value ?? '',
|
|
777
805
|
onInput: (event: Event) => {
|
|
778
806
|
const target = event.currentTarget;
|
|
779
807
|
if (target instanceof HTMLTextAreaElement) {
|
|
780
|
-
syncFieldValue(
|
|
808
|
+
syncFieldValue(fieldAccessor(), target, 'textarea');
|
|
781
809
|
}
|
|
782
810
|
},
|
|
783
811
|
})
|
|
@@ -786,84 +814,99 @@ export function createForm(input: FormProps = {}): Form {
|
|
|
786
814
|
if (type === 'select') {
|
|
787
815
|
return jsx(
|
|
788
816
|
'select',
|
|
789
|
-
controlProps(
|
|
790
|
-
className:
|
|
791
|
-
autocomplete:
|
|
792
|
-
multiple: !!
|
|
817
|
+
controlProps(fieldAccessor, id, {
|
|
818
|
+
className: () => fieldAccessor().className || state.className.select,
|
|
819
|
+
autocomplete: () => fieldAccessor().autocomplete || 'off',
|
|
820
|
+
multiple: () => !!fieldAccessor().multiple,
|
|
793
821
|
onChange: (event: Event) => {
|
|
794
822
|
const target = event.currentTarget;
|
|
795
823
|
if (target instanceof HTMLSelectElement) {
|
|
796
|
-
syncFieldValue(
|
|
824
|
+
syncFieldValue(fieldAccessor(), target, 'select');
|
|
797
825
|
}
|
|
798
826
|
},
|
|
799
|
-
children: (
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
827
|
+
children: () =>
|
|
828
|
+
(fieldAccessor().options || []).map((option) => {
|
|
829
|
+
const item = normalizeOption(option);
|
|
830
|
+
return jsx('option', {
|
|
831
|
+
value: item.value ?? '',
|
|
832
|
+
disabled: !!item.disabled,
|
|
833
|
+
selected: () => isSelected(fieldAccessor().value, item.value),
|
|
834
|
+
children: item.text ?? item.label ?? item.value ?? '',
|
|
835
|
+
});
|
|
836
|
+
}),
|
|
808
837
|
})
|
|
809
838
|
) as HTMLSelectElement;
|
|
810
839
|
}
|
|
811
|
-
if (type === 'radio') return choiceGroupView(
|
|
812
|
-
if (type === 'checkbox' && Array.isArray(
|
|
813
|
-
return choiceGroupView(
|
|
840
|
+
if (type === 'radio') return choiceGroupView(fieldAccessor, id, 'radio');
|
|
841
|
+
if (type === 'checkbox' && Array.isArray(fieldAccessor().options)) {
|
|
842
|
+
return choiceGroupView(fieldAccessor, id, 'checkbox');
|
|
814
843
|
}
|
|
815
844
|
if (type === 'switch') {
|
|
816
845
|
return jsx('label', {
|
|
817
|
-
className:
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
846
|
+
className: () => {
|
|
847
|
+
const field = fieldAccessor();
|
|
848
|
+
const names = state.className;
|
|
849
|
+
return joinClasses(
|
|
850
|
+
names.switch,
|
|
851
|
+
field.variant ? `is-${field.variant}` : names.switchDefault,
|
|
852
|
+
field.size ? `is-${field.size}` : names.switchSizeMd
|
|
853
|
+
);
|
|
854
|
+
},
|
|
855
|
+
'data-form-switch': () => fieldAccessor().name || id,
|
|
823
856
|
for: id,
|
|
824
857
|
children: [
|
|
825
858
|
jsx('input', {
|
|
826
859
|
type: 'checkbox',
|
|
827
860
|
id,
|
|
828
|
-
name:
|
|
829
|
-
value:
|
|
830
|
-
checked: !!
|
|
831
|
-
disabled: () => state.submitting || !!
|
|
832
|
-
required: !!
|
|
861
|
+
name: () => fieldAccessor().name,
|
|
862
|
+
value: () => fieldAccessor().value ?? '1',
|
|
863
|
+
checked: () => !!fieldAccessor().checked,
|
|
864
|
+
disabled: () => state.submitting || !!fieldAccessor().disabled,
|
|
865
|
+
required: () => !!fieldAccessor().required,
|
|
833
866
|
onChange: (event: Event) => {
|
|
834
867
|
const target = event.currentTarget;
|
|
835
868
|
if (target instanceof HTMLInputElement) {
|
|
836
|
-
syncFieldValue(
|
|
869
|
+
syncFieldValue(fieldAccessor(), target, 'switch');
|
|
837
870
|
}
|
|
838
871
|
},
|
|
839
872
|
}),
|
|
840
873
|
jsx('span', {
|
|
841
|
-
className:
|
|
874
|
+
className: () => state.className.switchSlider,
|
|
842
875
|
'data-form-switch-slider': '',
|
|
843
876
|
}),
|
|
844
877
|
],
|
|
845
878
|
}) as HTMLLabelElement;
|
|
846
879
|
}
|
|
847
880
|
if (type === 'custom') {
|
|
881
|
+
const field = fieldAccessor();
|
|
848
882
|
return typeof field.content === 'function'
|
|
849
|
-
? field.content({
|
|
883
|
+
? field.content({
|
|
884
|
+
form,
|
|
885
|
+
field,
|
|
886
|
+
index: indexAccessor(),
|
|
887
|
+
item: itemAccessor(),
|
|
888
|
+
})
|
|
850
889
|
: field.content;
|
|
851
890
|
}
|
|
852
891
|
const inputType = type || 'text';
|
|
853
892
|
return jsx('input', {
|
|
854
|
-
...controlProps(
|
|
893
|
+
...controlProps(fieldAccessor, id, {
|
|
855
894
|
type: inputType,
|
|
856
|
-
className:
|
|
857
|
-
autocomplete:
|
|
858
|
-
|
|
895
|
+
className: () => fieldAccessor().className || state.className.input,
|
|
896
|
+
autocomplete: () =>
|
|
897
|
+
fieldAccessor().autocomplete || autoComplete(inputType),
|
|
898
|
+
value: () => fieldAccessor().value ?? '',
|
|
859
899
|
onInput: (event: Event) => {
|
|
860
900
|
const target = event.currentTarget;
|
|
861
901
|
if (target instanceof HTMLInputElement) {
|
|
862
|
-
syncFieldValue(
|
|
902
|
+
syncFieldValue(fieldAccessor(), target, inputType);
|
|
863
903
|
}
|
|
864
904
|
},
|
|
865
905
|
}),
|
|
866
|
-
checked:
|
|
906
|
+
checked: () => {
|
|
907
|
+
const checked = fieldAccessor().checked;
|
|
908
|
+
return checked === undefined ? undefined : !!checked;
|
|
909
|
+
},
|
|
867
910
|
}) as HTMLInputElement;
|
|
868
911
|
};
|
|
869
912
|
|
|
@@ -871,11 +914,8 @@ export function createForm(input: FormProps = {}): Form {
|
|
|
871
914
|
itemAccessor: () => FormItem<FormField>,
|
|
872
915
|
indexAccessor: () => number
|
|
873
916
|
): HTMLElement => {
|
|
874
|
-
const item = itemAccessor();
|
|
875
|
-
const field = item.payload;
|
|
876
917
|
const fieldAccessor = (): FormField => itemAccessor().payload;
|
|
877
|
-
const
|
|
878
|
-
const id = resolveFieldId(field, index);
|
|
918
|
+
const id = resolveFieldId(fieldAccessor(), indexAccessor());
|
|
879
919
|
return jsx('div', {
|
|
880
920
|
className: () => state.className.item,
|
|
881
921
|
'data-form-item': () => fieldAccessor().name || String(indexAccessor()),
|
|
@@ -906,7 +946,7 @@ export function createForm(input: FormProps = {}): Form {
|
|
|
906
946
|
'data-form-control': () =>
|
|
907
947
|
fieldAccessor().name || String(indexAccessor()),
|
|
908
948
|
children: [
|
|
909
|
-
controlView(
|
|
949
|
+
controlView(itemAccessor, fieldAccessor, id, indexAccessor),
|
|
910
950
|
() => {
|
|
911
951
|
const current = fieldAccessor();
|
|
912
952
|
return current.help
|
package/src/components/modal.ts
CHANGED
|
@@ -685,34 +685,35 @@ export function createModal(input: ModalProps = {}): Modal {
|
|
|
685
685
|
...(props.style ? { style: props.style } : {}),
|
|
686
686
|
'data-mount': () => (motionVisible() ? 'true' : 'false'),
|
|
687
687
|
children: [
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
688
|
+
props.header
|
|
689
|
+
? jsx('div', {
|
|
690
|
+
className: props.className.header,
|
|
691
|
+
children: () =>
|
|
692
|
+
state.loading
|
|
693
|
+
? null
|
|
694
|
+
: [
|
|
695
|
+
jsx('div', {
|
|
696
|
+
className: props.className.title,
|
|
697
|
+
id: `${props.id}_title`,
|
|
698
|
+
'aria-label': props.text.title,
|
|
699
|
+
children: props.text.title,
|
|
700
|
+
}),
|
|
701
|
+
props.showClose
|
|
702
|
+
? jsx('button', {
|
|
703
|
+
type: 'button',
|
|
704
|
+
className: joinClasses(
|
|
705
|
+
props.className.button,
|
|
706
|
+
props.className.closeBtn
|
|
707
|
+
),
|
|
708
|
+
'data-action': 'close',
|
|
709
|
+
'aria-label': t('Close', locales),
|
|
710
|
+
disabled: isBusy,
|
|
711
|
+
children: icon('close'),
|
|
712
|
+
})
|
|
713
|
+
: null,
|
|
714
|
+
],
|
|
715
|
+
})
|
|
716
|
+
: null,
|
|
716
717
|
jsx('div', {
|
|
717
718
|
className: props.className.body,
|
|
718
719
|
'data-modal-body': '',
|
|
@@ -720,37 +721,38 @@ export function createModal(input: ModalProps = {}): Modal {
|
|
|
720
721
|
return resolvedContent().value;
|
|
721
722
|
},
|
|
722
723
|
}),
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
724
|
+
props.footer
|
|
725
|
+
? jsx('div', {
|
|
726
|
+
className: props.className.footer,
|
|
727
|
+
children: () =>
|
|
728
|
+
state.loading
|
|
729
|
+
? null
|
|
730
|
+
: [
|
|
731
|
+
props.showCancel
|
|
732
|
+
? jsx('button', {
|
|
733
|
+
type: 'button',
|
|
734
|
+
className: joinClasses(
|
|
735
|
+
props.className.button,
|
|
736
|
+
props.className.cancelBtn
|
|
737
|
+
),
|
|
738
|
+
'data-action': 'cancel',
|
|
739
|
+
disabled: isBusy,
|
|
740
|
+
children: props.text.cancel,
|
|
741
|
+
})
|
|
742
|
+
: null,
|
|
743
|
+
jsx('button', {
|
|
731
744
|
type: 'button',
|
|
732
745
|
className: joinClasses(
|
|
733
746
|
props.className.button,
|
|
734
|
-
props.className.
|
|
747
|
+
props.className.confirmBtn
|
|
735
748
|
),
|
|
736
|
-
'data-action': '
|
|
749
|
+
'data-action': 'confirm',
|
|
737
750
|
disabled: isBusy,
|
|
738
|
-
children: props.text.
|
|
739
|
-
})
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
className: joinClasses(
|
|
744
|
-
props.className.button,
|
|
745
|
-
props.className.confirmBtn
|
|
746
|
-
),
|
|
747
|
-
'data-action': 'confirm',
|
|
748
|
-
disabled: isBusy,
|
|
749
|
-
children: props.text.confirm,
|
|
750
|
-
}),
|
|
751
|
-
]
|
|
752
|
-
: null,
|
|
753
|
-
}),
|
|
751
|
+
children: props.text.confirm,
|
|
752
|
+
}),
|
|
753
|
+
],
|
|
754
|
+
})
|
|
755
|
+
: null,
|
|
754
756
|
],
|
|
755
757
|
}) as HTMLElement;
|
|
756
758
|
const root = createPopup({
|
package/src/index.ts
CHANGED
|
@@ -11,7 +11,6 @@ export * from './core/motion.ts';
|
|
|
11
11
|
export * from './utilities/object.ts';
|
|
12
12
|
export * from './utilities/timer.ts';
|
|
13
13
|
export * from './utilities/types.ts';
|
|
14
|
-
export * from './utilities/function.ts';
|
|
15
14
|
export * from './core/scheduler.ts';
|
|
16
15
|
export * from './utilities/state.ts';
|
|
17
16
|
export * from './utilities/refs.ts';
|
package/src/locales/index.ts
CHANGED
package/src/utilities/object.ts
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
const objectTag = '[object Object]';
|
|
2
|
+
const objectCtorString = Function.prototype.toString.call(Object);
|
|
2
3
|
|
|
3
|
-
export function isPlainObject(
|
|
4
|
-
|
|
4
|
+
export function isPlainObject(value: unknown): boolean {
|
|
5
|
+
if (value === null || typeof value !== 'object') return false;
|
|
6
|
+
if (Object.prototype.toString.call(value) !== objectTag) return false;
|
|
7
|
+
|
|
8
|
+
const proto = Object.getPrototypeOf(value);
|
|
9
|
+
if (proto === null) return true;
|
|
10
|
+
|
|
11
|
+
const ctor =
|
|
12
|
+
Object.prototype.hasOwnProperty.call(proto, 'constructor') &&
|
|
13
|
+
proto.constructor;
|
|
14
|
+
return (
|
|
15
|
+
typeof ctor === 'function' &&
|
|
16
|
+
Function.prototype.toString.call(ctor) === objectCtorString
|
|
17
|
+
);
|
|
5
18
|
}
|