@prototyp/skeletor 1.0.4 → 1.0.6
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/README.md +7 -1
- package/lib/module/components/InputFocusScrollView/InputFocusScrollView.js +5 -13
- package/lib/module/components/InputFocusScrollView/InputFocusScrollView.js.map +1 -1
- package/lib/module/hooks/useForm.js +30 -15
- package/lib/module/hooks/useForm.js.map +1 -1
- package/lib/module/models/Border.js +1 -1
- package/lib/module/models/Size.js +1 -1
- package/lib/module/models/Spacing.js +1 -1
- package/lib/typescript/lib/module/components/Block/Block.d.ts +1 -1
- package/lib/typescript/lib/module/components/InputFocusScrollView/InputFocusScrollView.d.ts +1 -1
- package/lib/typescript/lib/module/components/InputFocusScrollView/InputFocusScrollView.d.ts.map +1 -1
- package/lib/typescript/lib/module/components/Text/Text.d.ts +1 -1
- package/lib/typescript/lib/module/hooks/useAnimation.d.ts +1 -1
- package/lib/typescript/lib/module/hooks/useForm.d.ts.map +1 -1
- package/lib/typescript/lib/module/models/Border.d.ts +1 -0
- package/lib/typescript/lib/module/models/Size.d.ts +1 -0
- package/lib/typescript/lib/module/models/Spacing.d.ts +1 -0
- package/lib/typescript/lib/module/models/index.d.ts +3 -0
- package/lib/typescript/src/components/InputFocusScrollView/InputFocusScrollView.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useForm.d.ts +7 -7
- package/lib/typescript/src/hooks/useForm.d.ts.map +1 -1
- package/lib/typescript/src/models/Border.d.ts +6 -5
- package/lib/typescript/src/models/Border.d.ts.map +1 -1
- package/lib/typescript/src/models/Size.d.ts +7 -6
- package/lib/typescript/src/models/Size.d.ts.map +1 -1
- package/lib/typescript/src/models/Spacing.d.ts +15 -14
- package/lib/typescript/src/models/Spacing.d.ts.map +1 -1
- package/package.json +10 -7
- package/src/components/InputFocusScrollView/InputFocusScrollView.tsx +10 -15
- package/src/hooks/useForm.ts +47 -29
- package/src/models/Border.ts +7 -5
- package/src/models/Size.ts +8 -6
- package/src/models/Spacing.ts +16 -14
package/README.md
CHANGED
|
@@ -252,6 +252,12 @@ Flexible in its function, supports multiple validation approaches through callba
|
|
|
252
252
|
2. To trigger standalone validation, use `validate("prop")`
|
|
253
253
|
3. Validate entire form with `validateForm()`
|
|
254
254
|
|
|
255
|
+
The order of importance when it comes to validating fields is:
|
|
256
|
+
|
|
257
|
+
1. Custom validation rule - will get the value as-is for your rule to validate it fully. The configuration rule receives the current value, state and optional flag values for you to validate against.
|
|
258
|
+
2. If there is no custom validation rule and the primitive value check returns false (there is no value), check if the field is optional. If optional, the validation result is `true`, otherwise it is `false`;
|
|
259
|
+
3. If all previous checks have not been triggered, return the primitive "has value" check result. This will return `false` for values such as: `null | undefined | NaN | "" | Invalid Date`. This will return `true` if you have a complex value type such as `object | Array`, <b>so in case you have a complex value type use a custom validation rule to get what you need</b>.
|
|
260
|
+
|
|
255
261
|
#### Example 1: Simple use case with standalone validation on blur:
|
|
256
262
|
|
|
257
263
|
```javascript
|
|
@@ -321,7 +327,7 @@ const { state, validation, update, validate } = useForm(
|
|
|
321
327
|
optional: ["middleName"],
|
|
322
328
|
// validation.lastName is invalid if lastName is <3 characters long
|
|
323
329
|
// state can be used to compare with other values (ie repeat password)
|
|
324
|
-
rules: { lastName: (value, state) => value.length >= 3,
|
|
330
|
+
rules: { lastName: (value, state, optional) => value.length >= 3,
|
|
325
331
|
}
|
|
326
332
|
```
|
|
327
333
|
|
|
@@ -21,13 +21,11 @@ export const InputFocusScrollView = _ref => {
|
|
|
21
21
|
} = _ref;
|
|
22
22
|
const screenHeight = useRef(Dimensions.get("screen").height).current;
|
|
23
23
|
const ref = useRef(null);
|
|
24
|
-
const [scrollTarget, setScrollTarget] = useState();
|
|
25
24
|
/** Cached scroll position to keep focus on input if layout shifts. */
|
|
26
|
-
const [scrollPosition, setScrollPosition] = useState();
|
|
25
|
+
const [scrollPosition, setScrollPosition] = useState(null);
|
|
26
|
+
const [scrollTarget, setScrollTarget] = useState(null);
|
|
27
27
|
function onInputFocus(e) {
|
|
28
|
-
if (Platform.OS !== "ios" || !scrollTarget)
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
28
|
+
if (Platform.OS !== "ios" || !scrollTarget) return;
|
|
31
29
|
e.currentTarget.measureLayout(scrollTarget, (nope, top, nuuh, elementHeight) => {
|
|
32
30
|
var _ref$current;
|
|
33
31
|
let scrollY = top - elementHeight;
|
|
@@ -43,12 +41,6 @@ export const InputFocusScrollView = _ref => {
|
|
|
43
41
|
});
|
|
44
42
|
}, () => console.error("failed to measure layout"));
|
|
45
43
|
}
|
|
46
|
-
function onScrollViewLayout(e) {
|
|
47
|
-
if (Platform.OS !== "ios") {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
setScrollTarget(e.nativeEvent.target);
|
|
51
|
-
}
|
|
52
44
|
|
|
53
45
|
/** Handle layout shifts by programmatically scrolling to the same input position without animation. */
|
|
54
46
|
function onContentSizeChange() {
|
|
@@ -60,7 +52,7 @@ export const InputFocusScrollView = _ref => {
|
|
|
60
52
|
y: scrollPosition,
|
|
61
53
|
animated: false
|
|
62
54
|
});
|
|
63
|
-
setScrollPosition(
|
|
55
|
+
setScrollPosition(null);
|
|
64
56
|
}
|
|
65
57
|
const containerStyles = StyleSheet.flatten([styles[height], margins, style]);
|
|
66
58
|
const contentStyles = StyleSheet.flatten([styles.content, {
|
|
@@ -70,7 +62,7 @@ export const InputFocusScrollView = _ref => {
|
|
|
70
62
|
ref: ref,
|
|
71
63
|
scrollToOverflowEnabled: true,
|
|
72
64
|
scrollEventThrottle: 16,
|
|
73
|
-
onLayout:
|
|
65
|
+
onLayout: e => setScrollTarget(e.currentTarget),
|
|
74
66
|
onContentSizeChange: onContentSizeChange,
|
|
75
67
|
showsVerticalScrollIndicator: false,
|
|
76
68
|
showsHorizontalScrollIndicator: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useRef","useState","Platform","ScrollView","StyleSheet","Dimensions","InputFocusScrollView","children","style","contentContainerStyle","height","focusPositionOffset","margins","paddings","rest","screenHeight","get","current","ref","
|
|
1
|
+
{"version":3,"names":["React","useRef","useState","Platform","ScrollView","StyleSheet","Dimensions","InputFocusScrollView","children","style","contentContainerStyle","height","focusPositionOffset","margins","paddings","rest","screenHeight","get","current","ref","scrollPosition","setScrollPosition","scrollTarget","setScrollTarget","onInputFocus","e","OS","currentTarget","measureLayout","nope","top","nuuh","elementHeight","scrollY","undefined","scrollTo","y","console","error","onContentSizeChange","animated","containerStyles","flatten","styles","contentStyles","content","create","full","auto","flexGrow","paddingBottom"],"sourceRoot":"../../src","sources":["InputFocusScrollView.tsx"],"mappings":"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"}
|
|
@@ -108,32 +108,47 @@ export function useForm(values, config) {
|
|
|
108
108
|
/** Helper hook to validate form state outside of the scope of useForm. */
|
|
109
109
|
export function useFormUtils(config) {
|
|
110
110
|
function doesValueExist(value) {
|
|
111
|
-
if (value ===
|
|
111
|
+
if (value === undefined || value === null) {
|
|
112
112
|
return false;
|
|
113
113
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
if (typeof value === "string") {
|
|
115
|
+
return value !== "";
|
|
116
|
+
}
|
|
117
|
+
if (typeof value === "number") {
|
|
118
|
+
return value >= 0 || value < 0 || !isNaN(value);
|
|
119
|
+
}
|
|
120
|
+
if (value instanceof Date) {
|
|
121
|
+
return !isNaN(value.valueOf());
|
|
121
122
|
}
|
|
122
|
-
// else return true because we know the value exists already.
|
|
123
123
|
return true;
|
|
124
124
|
}
|
|
125
125
|
function isOptional(key) {
|
|
126
126
|
var _config$optional;
|
|
127
|
-
return config === null || config === void 0 ? void 0 : (_config$optional = config.optional) === null || _config$optional === void 0 ? void 0 : _config$optional.includes(key);
|
|
127
|
+
return (config === null || config === void 0 ? void 0 : (_config$optional = config.optional) === null || _config$optional === void 0 ? void 0 : _config$optional.includes(key)) || false;
|
|
128
128
|
}
|
|
129
|
+
|
|
130
|
+
/** Validate by custom validation rule. If the rule does not exist, returns undefined. */
|
|
131
|
+
function validateByRule(key, value, state) {
|
|
132
|
+
var _config$rules, _config$rules$key;
|
|
133
|
+
return config === null || config === void 0 ? void 0 : (_config$rules = config.rules) === null || _config$rules === void 0 ? void 0 : (_config$rules$key = _config$rules[key]) === null || _config$rules$key === void 0 ? void 0 : _config$rules$key.call(_config$rules, value, state, isOptional(key));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Handles validation for a specific form field.
|
|
137
|
+
* Order of priority:
|
|
138
|
+
* 1. If there is a custom validation rule, always use that to preserve all possible type values
|
|
139
|
+
* 2. If there is no value (is a falsy value), check if the field is optional
|
|
140
|
+
* 3. Fallback to simple truthy value check if all other checks are not triggered. */
|
|
129
141
|
function fieldValidation(key, value, state) {
|
|
142
|
+
var _config$rules2;
|
|
130
143
|
const hasValue = doesValueExist(value);
|
|
131
144
|
const optional = isOptional(key);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
145
|
+
|
|
146
|
+
// If form has custom validation rule, always trigger only that.
|
|
147
|
+
if (!!(config !== null && config !== void 0 && (_config$rules2 = config.rules) !== null && _config$rules2 !== void 0 && _config$rules2[key])) return validateByRule(key, value, state);
|
|
148
|
+
// If value does not exist (is null, undefined or other falsy value), check if field is optional.
|
|
149
|
+
if (!hasValue) return !!optional;
|
|
150
|
+
// Fallback, simple check if value exists
|
|
151
|
+
return hasValue;
|
|
137
152
|
}
|
|
138
153
|
function stateValidation(state) {
|
|
139
154
|
const keys = Object.keys(state).map(key => key);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useEffect","useState","useForm","values","config","keys","Object","validation","setValidation","initialState","setInitialState","state","setState","fieldValidation","stateValidation","isOptional","useFormUtils","changed","filter","key","length","updatedState","forEach","update","value","shouldValidate","s","undefined","validate","validateForm","formValidationState","valid","isFormValid","some","resetState","resetInitialValues","resetValidation","clearForm","doesValueExist","
|
|
1
|
+
{"version":3,"names":["useEffect","useState","useForm","values","config","keys","Object","validation","setValidation","initialState","setInitialState","state","setState","fieldValidation","stateValidation","isOptional","useFormUtils","changed","filter","key","length","updatedState","forEach","update","value","shouldValidate","s","undefined","validate","validateForm","formValidationState","valid","isFormValid","some","resetState","resetInitialValues","resetValidation","clearForm","doesValueExist","isNaN","Date","valueOf","optional","includes","validateByRule","rules","hasValue","map"],"sourceRoot":"../../src","sources":["useForm.ts"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
|
2
2
|
//# sourceMappingURL=Border.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
|
2
2
|
//# sourceMappingURL=Size.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
|
2
2
|
//# sourceMappingURL=Spacing.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export function Block(_ref2: any): React.FunctionComponentElement<any> | React.CElement<import("react-native").ScrollViewProps, ScrollView>;
|
|
2
2
|
import React from "react";
|
|
3
|
-
import { ScrollView } from "react-native";
|
|
3
|
+
import { ScrollView } from "react-native/Libraries/Components/ScrollView/ScrollView";
|
|
4
4
|
//# sourceMappingURL=Block.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export function InputFocusScrollView(_ref: any): React.CElement<import("react-native").ScrollViewProps, ScrollView>;
|
|
2
|
-
import { ScrollView } from "react-native";
|
|
2
|
+
import { ScrollView } from "react-native/Libraries/Components/ScrollView/ScrollView";
|
|
3
3
|
import React from "react";
|
|
4
4
|
//# sourceMappingURL=InputFocusScrollView.d.ts.map
|
package/lib/typescript/lib/module/components/InputFocusScrollView/InputFocusScrollView.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputFocusScrollView.d.ts","sourceRoot":"","sources":["../../../../../module/components/InputFocusScrollView/InputFocusScrollView.js"],"names":[],"mappings":"AAUO,
|
|
1
|
+
{"version":3,"file":"InputFocusScrollView.d.ts","sourceRoot":"","sources":["../../../../../module/components/InputFocusScrollView/InputFocusScrollView.js"],"names":[],"mappings":"AAUO,oHA6DN"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export function Text(_ref: any): React.CElement<import("react-native").TextProps, RNText>;
|
|
2
|
-
import { Text as RNText } from "react-native";
|
|
2
|
+
import { Text as RNText } from "react-native/Libraries/Text/Text";
|
|
3
3
|
import React from "react";
|
|
4
4
|
//# sourceMappingURL=Text.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../module/hooks/useForm.js"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AACH;;;;;;;;;;;EA+FC;AAED,0EAA0E;AAC1E;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../module/hooks/useForm.js"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AACH;;;;;;;;;;;EA+FC;AAED,0EAA0E;AAC1E;;;;;;;;;EAgEC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputFocusScrollView.d.ts","sourceRoot":"","sources":["../../../../../src/components/InputFocusScrollView/InputFocusScrollView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAChD,OAAO,EAGL,oBAAoB,EAEpB,eAAe,EAEf,uBAAuB,
|
|
1
|
+
{"version":3,"file":"InputFocusScrollView.d.ts","sourceRoot":"","sources":["../../../../../src/components/InputFocusScrollView/InputFocusScrollView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAChD,OAAO,EAGL,oBAAoB,EAEpB,eAAe,EAEf,uBAAuB,EAKxB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,WAAW,yBACf,SAAQ,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,EACvC,OAAO;IACT,4LAA4L;IAC5L,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,EAAE,CACR,YAAY,EAAE,CAAC,CAAC,EAAE,oBAAoB,CAAC,uBAAuB,CAAC,KAAK,IAAI,KACrE,KAAK,CAAC,SAAS,CAAC;CACtB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAqEpE,CAAC"}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
declare type Validation<T> = {
|
|
1
|
+
export declare type Validation<T> = {
|
|
2
2
|
[K in keyof Partial<T>]?: boolean;
|
|
3
3
|
};
|
|
4
4
|
declare type Rules<T> = {
|
|
5
|
-
[K in keyof T]?: (value: T[K], state: T) => boolean | undefined;
|
|
5
|
+
[K in keyof T]?: (value: T[K], state: T, optional: boolean) => boolean | undefined;
|
|
6
6
|
};
|
|
7
|
-
declare type Values<T> = {
|
|
7
|
+
export declare type Values<T> = {
|
|
8
8
|
[K in keyof T]: T[K];
|
|
9
9
|
};
|
|
10
10
|
export declare type FormConfig<R> = {
|
|
11
11
|
/** List of optional properties. Optional properties will be marked as valid if left empty. */
|
|
12
12
|
optional?: Array<keyof R>;
|
|
13
|
-
/** Validation rules by specified property name. If you define a validation rule function here, the field will be validated against it. If no rule is set, a crude value check will be used instead (Boolean(value)) */
|
|
13
|
+
/** Validation rules by specified property name. If you define a validation rule function here, the field will be validated against it. If no rule is set, a crude value check will be used instead (optional || Boolean(value)). Note: For complex value types (objects, arrays, dates etc) it is best to use a custom validation rule. */
|
|
14
14
|
rules?: Rules<R>;
|
|
15
15
|
/** Will compare key/value pairs instead of just top level JSON.stringify on complex objects/arrays */
|
|
16
16
|
deepCompare?: boolean;
|
|
@@ -39,10 +39,10 @@ export declare function useForm<T>(values: Values<T>, config?: FormConfig<T>): {
|
|
|
39
39
|
};
|
|
40
40
|
/** Helper hook to validate form state outside of the scope of useForm. */
|
|
41
41
|
export declare function useFormUtils<T>(config?: FormConfig<T>): {
|
|
42
|
-
doesValueExist: (value: T[keyof T]
|
|
42
|
+
doesValueExist: (value: T[keyof T]) => value is Exclude<T[keyof T], null | undefined>;
|
|
43
43
|
validateByRule: <K extends keyof T>(key: K, value: T[K], state: Values<T>) => boolean | undefined;
|
|
44
|
-
isOptional: (key: keyof T) => boolean
|
|
45
|
-
fieldValidation: (key: keyof T, value: T[keyof T]
|
|
44
|
+
isOptional: (key: keyof T) => boolean;
|
|
45
|
+
fieldValidation: (key: keyof T, value: T[keyof T], state: Values<T>) => boolean | undefined;
|
|
46
46
|
stateValidation: (state: Values<T>) => {
|
|
47
47
|
valid: boolean;
|
|
48
48
|
validation: Validation<T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useForm.ts"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useForm.ts"],"names":[],"mappings":"AAEA,oBAAY,UAAU,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO;CAAE,CAAC;AAClE,aAAK,KAAK,CAAC,CAAC,IAAI;KACb,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CACf,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EACX,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,OAAO,KACd,OAAO,GAAG,SAAS;CACzB,CAAC;AAEF,oBAAY,MAAM,CAAC,CAAC,IAAI;KACrB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACrB,CAAC;AAEF,oBAAY,UAAU,CAAC,CAAC,IAAI;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1B,2UAA2U;IAC3U,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,sGAAsG;IACtG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;;;8EA2B/C,OAAO;;wBAmBD,OAAO;;;;;;EAgDjC;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;4BAE3C,CAAC,CAAC,MAAM,CAAC,CAAC;oEA6BV,OAAO,CAAC,CAAC;sBARO,MAAM,CAAC;2BAkBF,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,OAAO,CAAC,CAAC;6BAY1C,OAAO,CAAC,CAAC;;;;EAuB1C"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AnimatableNumericValue } from "react-native/types";
|
|
1
2
|
export interface Border {
|
|
2
3
|
border?: {
|
|
3
4
|
borderWidth?: number;
|
|
@@ -6,11 +7,11 @@ export interface Border {
|
|
|
6
7
|
borderLeftWidth?: number;
|
|
7
8
|
borderRightWidth?: number;
|
|
8
9
|
borderColor?: string;
|
|
9
|
-
borderRadius?:
|
|
10
|
-
borderTopLeftRadius?:
|
|
11
|
-
borderTopRightRadius?:
|
|
12
|
-
borderBottomLeftRadius?:
|
|
13
|
-
borderBottomRightRadius?:
|
|
10
|
+
borderRadius?: AnimatableNumericValue;
|
|
11
|
+
borderTopLeftRadius?: AnimatableNumericValue;
|
|
12
|
+
borderTopRightRadius?: AnimatableNumericValue;
|
|
13
|
+
borderBottomLeftRadius?: AnimatableNumericValue;
|
|
14
|
+
borderBottomRightRadius?: AnimatableNumericValue;
|
|
14
15
|
};
|
|
15
16
|
}
|
|
16
17
|
//# sourceMappingURL=Border.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Border.d.ts","sourceRoot":"","sources":["../../../../src/models/Border.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,MAAM,CAAC,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"Border.d.ts","sourceRoot":"","sources":["../../../../src/models/Border.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,WAAW,MAAM;IACrB,MAAM,CAAC,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,sBAAsB,CAAC;QACtC,mBAAmB,CAAC,EAAE,sBAAsB,CAAC;QAC7C,oBAAoB,CAAC,EAAE,sBAAsB,CAAC;QAC9C,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;QAChD,uBAAuB,CAAC,EAAE,sBAAsB,CAAC;KAClD,CAAC;CACH"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { DimensionValue } from "react-native/types";
|
|
1
2
|
export interface Size {
|
|
2
|
-
width?:
|
|
3
|
-
height?:
|
|
4
|
-
minHeight?:
|
|
5
|
-
minWidth?:
|
|
6
|
-
maxHeight?:
|
|
7
|
-
maxWidth?:
|
|
3
|
+
width?: DimensionValue;
|
|
4
|
+
height?: DimensionValue;
|
|
5
|
+
minHeight?: DimensionValue;
|
|
6
|
+
minWidth?: DimensionValue;
|
|
7
|
+
maxHeight?: DimensionValue;
|
|
8
|
+
maxWidth?: DimensionValue;
|
|
8
9
|
flex?: number;
|
|
9
10
|
}
|
|
10
11
|
//# sourceMappingURL=Size.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Size.d.ts","sourceRoot":"","sources":["../../../../src/models/Size.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,KAAK,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"Size.d.ts","sourceRoot":"","sources":["../../../../src/models/Size.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,WAAW,IAAI;IACnB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
+
import { DimensionValue } from "react-native/types";
|
|
1
2
|
export interface Spacing {
|
|
2
3
|
margins?: {
|
|
3
|
-
marginTop?:
|
|
4
|
-
marginBottom?:
|
|
5
|
-
marginLeft?:
|
|
6
|
-
marginRight?:
|
|
7
|
-
marginHorizontal?:
|
|
8
|
-
marginVertical?:
|
|
9
|
-
margin?:
|
|
4
|
+
marginTop?: DimensionValue;
|
|
5
|
+
marginBottom?: DimensionValue;
|
|
6
|
+
marginLeft?: DimensionValue;
|
|
7
|
+
marginRight?: DimensionValue;
|
|
8
|
+
marginHorizontal?: DimensionValue;
|
|
9
|
+
marginVertical?: DimensionValue;
|
|
10
|
+
margin?: DimensionValue;
|
|
10
11
|
};
|
|
11
12
|
paddings?: {
|
|
12
|
-
paddingTop?:
|
|
13
|
-
paddingBottom?:
|
|
14
|
-
paddingLeft?:
|
|
15
|
-
paddingRight?:
|
|
16
|
-
paddingHorizontal?:
|
|
17
|
-
paddingVertical?:
|
|
18
|
-
padding?:
|
|
13
|
+
paddingTop?: DimensionValue;
|
|
14
|
+
paddingBottom?: DimensionValue;
|
|
15
|
+
paddingLeft?: DimensionValue;
|
|
16
|
+
paddingRight?: DimensionValue;
|
|
17
|
+
paddingHorizontal?: DimensionValue;
|
|
18
|
+
paddingVertical?: DimensionValue;
|
|
19
|
+
padding?: DimensionValue;
|
|
19
20
|
};
|
|
20
21
|
}
|
|
21
22
|
//# sourceMappingURL=Spacing.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Spacing.d.ts","sourceRoot":"","sources":["../../../../src/models/Spacing.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"Spacing.d.ts","sourceRoot":"","sources":["../../../../src/models/Spacing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,cAAc,CAAC;QAC3B,YAAY,CAAC,EAAE,cAAc,CAAC;QAC9B,UAAU,CAAC,EAAE,cAAc,CAAC;QAC5B,WAAW,CAAC,EAAE,cAAc,CAAC;QAC7B,gBAAgB,CAAC,EAAE,cAAc,CAAC;QAClC,cAAc,CAAC,EAAE,cAAc,CAAC;QAChC,MAAM,CAAC,EAAE,cAAc,CAAC;KACzB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,cAAc,CAAC;QAC5B,aAAa,CAAC,EAAE,cAAc,CAAC;QAC/B,WAAW,CAAC,EAAE,cAAc,CAAC;QAC7B,YAAY,CAAC,EAAE,cAAc,CAAC;QAC9B,iBAAiB,CAAC,EAAE,cAAc,CAAC;QACnC,eAAe,CAAC,EAAE,cAAc,CAAC;QACjC,OAAO,CAAC,EAAE,cAAc,CAAC;KAC1B,CAAC;CACH"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@prototyp/skeletor",
|
|
3
3
|
"description": "React-Native UI and functional toolkit",
|
|
4
4
|
"author": "Luka Buljan <luka@prototyp.digital>",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.6",
|
|
6
6
|
"types": "lib/typescript/src/index.d.ts",
|
|
7
7
|
"main": "lib/module/index.js",
|
|
8
8
|
"react-native": "src/index.ts",
|
|
@@ -16,18 +16,21 @@
|
|
|
16
16
|
"prepack": "bob build"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@tsconfig/react-native": "
|
|
19
|
+
"@tsconfig/react-native": "^3.0.0",
|
|
20
20
|
"@types/jest": "29.4.0",
|
|
21
|
-
"@types/react
|
|
21
|
+
"@types/react": "^18.0.24",
|
|
22
|
+
"@react-native-community/eslint-config": "3.2.0",
|
|
23
|
+
"@react-native/eslint-config": "^0.72.2",
|
|
24
|
+
"@react-native/metro-config": "^0.72.9",
|
|
22
25
|
"jest": "29.4.2",
|
|
23
|
-
"react": "18.
|
|
24
|
-
"react-native": "0.
|
|
26
|
+
"react": "^18.2.0",
|
|
27
|
+
"react-native": "^0.72.0",
|
|
25
28
|
"react-native-builder-bob": "0.20.3",
|
|
26
|
-
"typescript": "4.8.
|
|
29
|
+
"typescript": "4.8.4"
|
|
27
30
|
},
|
|
28
31
|
"peerDependencies": {
|
|
29
32
|
"react": ">=16",
|
|
30
|
-
"react-native": ">=0.
|
|
33
|
+
"react-native": ">=0.72.0"
|
|
31
34
|
},
|
|
32
35
|
"publishConfig": {
|
|
33
36
|
"access": "public"
|
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
StyleSheet,
|
|
9
9
|
TextInputFocusEventData,
|
|
10
10
|
Dimensions,
|
|
11
|
+
UIManager,
|
|
12
|
+
findNodeHandle,
|
|
13
|
+
TextInput,
|
|
11
14
|
} from "react-native";
|
|
12
15
|
import { Spacing } from "../../models";
|
|
13
16
|
|
|
@@ -41,15 +44,14 @@ export const InputFocusScrollView: React.FC<InputFocusScrollViewProps> = ({
|
|
|
41
44
|
}) => {
|
|
42
45
|
const screenHeight = useRef(Dimensions.get("screen").height).current;
|
|
43
46
|
const ref = useRef<ScrollView>(null);
|
|
44
|
-
const [scrollTarget, setScrollTarget] = useState<number | null>();
|
|
45
47
|
/** Cached scroll position to keep focus on input if layout shifts. */
|
|
46
|
-
const [scrollPosition, setScrollPosition] = useState<number | null>();
|
|
48
|
+
const [scrollPosition, setScrollPosition] = useState<number | null>(null);
|
|
49
|
+
const [scrollTarget, setScrollTarget] = useState<number | null>(null);
|
|
47
50
|
|
|
48
51
|
function onInputFocus(e: NativeSyntheticEvent<TextInputFocusEventData>) {
|
|
49
|
-
if (Platform.OS !== "ios" || !scrollTarget)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
e.currentTarget.measureLayout(
|
|
52
|
+
if (Platform.OS !== "ios" || !scrollTarget) return;
|
|
53
|
+
|
|
54
|
+
(e.currentTarget as unknown as TextInput).measureLayout(
|
|
53
55
|
scrollTarget,
|
|
54
56
|
(nope, top, nuuh, elementHeight) => {
|
|
55
57
|
let scrollY = top - elementHeight;
|
|
@@ -66,20 +68,13 @@ export const InputFocusScrollView: React.FC<InputFocusScrollViewProps> = ({
|
|
|
66
68
|
);
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
function onScrollViewLayout(e: LayoutChangeEvent) {
|
|
70
|
-
if (Platform.OS !== "ios") {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
setScrollTarget(e.nativeEvent.target);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
71
|
/** Handle layout shifts by programmatically scrolling to the same input position without animation. */
|
|
77
72
|
function onContentSizeChange() {
|
|
78
73
|
if (Platform.OS !== "ios" || !scrollPosition) {
|
|
79
74
|
return;
|
|
80
75
|
}
|
|
81
76
|
ref.current?.scrollTo({ y: scrollPosition, animated: false });
|
|
82
|
-
setScrollPosition(
|
|
77
|
+
setScrollPosition(null);
|
|
83
78
|
}
|
|
84
79
|
|
|
85
80
|
const containerStyles = StyleSheet.flatten([styles[height], margins, style]);
|
|
@@ -95,7 +90,7 @@ export const InputFocusScrollView: React.FC<InputFocusScrollViewProps> = ({
|
|
|
95
90
|
ref={ref}
|
|
96
91
|
scrollToOverflowEnabled
|
|
97
92
|
scrollEventThrottle={16}
|
|
98
|
-
onLayout={
|
|
93
|
+
onLayout={(e) => setScrollTarget(e.currentTarget)}
|
|
99
94
|
onContentSizeChange={onContentSizeChange}
|
|
100
95
|
showsVerticalScrollIndicator={false}
|
|
101
96
|
showsHorizontalScrollIndicator={false}
|
package/src/hooks/useForm.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
|
|
3
|
-
type Validation<T> = { [K in keyof Partial<T>]?: boolean };
|
|
3
|
+
export type Validation<T> = { [K in keyof Partial<T>]?: boolean };
|
|
4
4
|
type Rules<T> = {
|
|
5
|
-
[K in keyof T]?: (
|
|
5
|
+
[K in keyof T]?: (
|
|
6
|
+
value: T[K],
|
|
7
|
+
state: T,
|
|
8
|
+
optional: boolean
|
|
9
|
+
) => boolean | undefined;
|
|
6
10
|
};
|
|
7
11
|
|
|
8
|
-
type Values<T> = {
|
|
12
|
+
export type Values<T> = {
|
|
9
13
|
[K in keyof T]: T[K];
|
|
10
14
|
};
|
|
11
15
|
|
|
12
16
|
export type FormConfig<R> = {
|
|
13
17
|
/** List of optional properties. Optional properties will be marked as valid if left empty. */
|
|
14
18
|
optional?: Array<keyof R>;
|
|
15
|
-
/** Validation rules by specified property name. If you define a validation rule function here, the field will be validated against it. If no rule is set, a crude value check will be used instead (Boolean(value)) */
|
|
19
|
+
/** Validation rules by specified property name. If you define a validation rule function here, the field will be validated against it. If no rule is set, a crude value check will be used instead (optional || Boolean(value)). Note: For complex value types (objects, arrays, dates etc) it is best to use a custom validation rule. */
|
|
16
20
|
rules?: Rules<R>;
|
|
17
21
|
/** Will compare key/value pairs instead of just top level JSON.stringify on complex objects/arrays */
|
|
18
22
|
deepCompare?: boolean;
|
|
@@ -55,7 +59,7 @@ export function useForm<T>(values: Values<T>, config?: FormConfig<T>) {
|
|
|
55
59
|
function update<K extends keyof T>(
|
|
56
60
|
key: K,
|
|
57
61
|
value: Values<T>[K],
|
|
58
|
-
shouldValidate?: boolean
|
|
62
|
+
shouldValidate?: boolean
|
|
59
63
|
) {
|
|
60
64
|
setState((s) => ({ ...s, [key]: value }));
|
|
61
65
|
setValidation((s) => ({
|
|
@@ -84,7 +88,7 @@ export function useForm<T>(values: Values<T>, config?: FormConfig<T>) {
|
|
|
84
88
|
* Only use when validating fields separately, has no value when valiating on form submit. */
|
|
85
89
|
function isFormValid() {
|
|
86
90
|
return !keys.some((key) =>
|
|
87
|
-
isOptional(key) ? validation[key] === false : !validation[key]
|
|
91
|
+
isOptional(key) ? validation[key] === false : !validation[key]
|
|
88
92
|
);
|
|
89
93
|
}
|
|
90
94
|
|
|
@@ -126,42 +130,56 @@ export function useForm<T>(values: Values<T>, config?: FormConfig<T>) {
|
|
|
126
130
|
|
|
127
131
|
/** Helper hook to validate form state outside of the scope of useForm. */
|
|
128
132
|
export function useFormUtils<T>(config?: FormConfig<T>) {
|
|
129
|
-
function doesValueExist(
|
|
130
|
-
|
|
133
|
+
function doesValueExist(
|
|
134
|
+
value: T[keyof T]
|
|
135
|
+
): value is Exclude<T[keyof T], null | undefined> {
|
|
136
|
+
if (value === undefined || value === null) {
|
|
131
137
|
return false;
|
|
132
138
|
}
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
value: T[K],
|
|
139
|
-
state: Values<T>,
|
|
140
|
-
) {
|
|
141
|
-
// If rule exists, validate with rule
|
|
142
|
-
if (config?.rules && config.rules[key]) {
|
|
143
|
-
return config.rules[key]?.(value, state);
|
|
140
|
+
if (typeof value === "string") {
|
|
141
|
+
return value !== "";
|
|
144
142
|
}
|
|
145
|
-
|
|
143
|
+
|
|
144
|
+
if (typeof value === "number") {
|
|
145
|
+
return value >= 0 || value < 0 || !isNaN(value);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (value instanceof Date) {
|
|
149
|
+
return !isNaN(value.valueOf());
|
|
150
|
+
}
|
|
151
|
+
|
|
146
152
|
return true;
|
|
147
153
|
}
|
|
148
154
|
|
|
149
155
|
function isOptional(key: keyof T) {
|
|
150
|
-
return config?.optional?.includes(key);
|
|
156
|
+
return config?.optional?.includes(key) || false;
|
|
151
157
|
}
|
|
152
158
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
159
|
+
/** Validate by custom validation rule. If the rule does not exist, returns undefined. */
|
|
160
|
+
function validateByRule<K extends keyof T>(
|
|
161
|
+
key: K,
|
|
162
|
+
value: T[K],
|
|
163
|
+
state: Values<T>
|
|
157
164
|
) {
|
|
165
|
+
return config?.rules?.[key]?.(value, state, isOptional(key));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Handles validation for a specific form field.
|
|
169
|
+
* Order of priority:
|
|
170
|
+
* 1. If there is a custom validation rule, always use that to preserve all possible type values
|
|
171
|
+
* 2. If there is no value (is a falsy value), check if the field is optional
|
|
172
|
+
* 3. Fallback to simple truthy value check if all other checks are not triggered. */
|
|
173
|
+
function fieldValidation(key: keyof T, value: T[keyof T], state: Values<T>) {
|
|
158
174
|
const hasValue = doesValueExist(value);
|
|
159
175
|
const optional = isOptional(key);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
176
|
+
|
|
177
|
+
// If form has custom validation rule, always trigger only that.
|
|
178
|
+
if (!!config?.rules?.[key]) return validateByRule(key, value, state);
|
|
179
|
+
// If value does not exist (is null, undefined or other falsy value), check if field is optional.
|
|
180
|
+
if (!hasValue) return !!optional;
|
|
181
|
+
// Fallback, simple check if value exists
|
|
182
|
+
return hasValue;
|
|
165
183
|
}
|
|
166
184
|
|
|
167
185
|
function stateValidation(state: Values<T>) {
|
package/src/models/Border.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AnimatableNumericValue } from "react-native/types";
|
|
2
|
+
|
|
1
3
|
export interface Border {
|
|
2
4
|
border?: {
|
|
3
5
|
borderWidth?: number;
|
|
@@ -6,10 +8,10 @@ export interface Border {
|
|
|
6
8
|
borderLeftWidth?: number;
|
|
7
9
|
borderRightWidth?: number;
|
|
8
10
|
borderColor?: string;
|
|
9
|
-
borderRadius?:
|
|
10
|
-
borderTopLeftRadius?:
|
|
11
|
-
borderTopRightRadius?:
|
|
12
|
-
borderBottomLeftRadius?:
|
|
13
|
-
borderBottomRightRadius?:
|
|
11
|
+
borderRadius?: AnimatableNumericValue;
|
|
12
|
+
borderTopLeftRadius?: AnimatableNumericValue;
|
|
13
|
+
borderTopRightRadius?: AnimatableNumericValue;
|
|
14
|
+
borderBottomLeftRadius?: AnimatableNumericValue;
|
|
15
|
+
borderBottomRightRadius?: AnimatableNumericValue;
|
|
14
16
|
};
|
|
15
17
|
}
|
package/src/models/Size.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { DimensionValue } from "react-native/types";
|
|
2
|
+
|
|
1
3
|
export interface Size {
|
|
2
|
-
width?:
|
|
3
|
-
height?:
|
|
4
|
-
minHeight?:
|
|
5
|
-
minWidth?:
|
|
6
|
-
maxHeight?:
|
|
7
|
-
maxWidth?:
|
|
4
|
+
width?: DimensionValue;
|
|
5
|
+
height?: DimensionValue;
|
|
6
|
+
minHeight?: DimensionValue;
|
|
7
|
+
minWidth?: DimensionValue;
|
|
8
|
+
maxHeight?: DimensionValue;
|
|
9
|
+
maxWidth?: DimensionValue;
|
|
8
10
|
flex?: number;
|
|
9
11
|
}
|
package/src/models/Spacing.ts
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
+
import { DimensionValue } from "react-native/types";
|
|
2
|
+
|
|
1
3
|
export interface Spacing {
|
|
2
4
|
margins?: {
|
|
3
|
-
marginTop?:
|
|
4
|
-
marginBottom?:
|
|
5
|
-
marginLeft?:
|
|
6
|
-
marginRight?:
|
|
7
|
-
marginHorizontal?:
|
|
8
|
-
marginVertical?:
|
|
9
|
-
margin?:
|
|
5
|
+
marginTop?: DimensionValue;
|
|
6
|
+
marginBottom?: DimensionValue;
|
|
7
|
+
marginLeft?: DimensionValue;
|
|
8
|
+
marginRight?: DimensionValue;
|
|
9
|
+
marginHorizontal?: DimensionValue;
|
|
10
|
+
marginVertical?: DimensionValue;
|
|
11
|
+
margin?: DimensionValue;
|
|
10
12
|
};
|
|
11
13
|
paddings?: {
|
|
12
|
-
paddingTop?:
|
|
13
|
-
paddingBottom?:
|
|
14
|
-
paddingLeft?:
|
|
15
|
-
paddingRight?:
|
|
16
|
-
paddingHorizontal?:
|
|
17
|
-
paddingVertical?:
|
|
18
|
-
padding?:
|
|
14
|
+
paddingTop?: DimensionValue;
|
|
15
|
+
paddingBottom?: DimensionValue;
|
|
16
|
+
paddingLeft?: DimensionValue;
|
|
17
|
+
paddingRight?: DimensionValue;
|
|
18
|
+
paddingHorizontal?: DimensionValue;
|
|
19
|
+
paddingVertical?: DimensionValue;
|
|
20
|
+
padding?: DimensionValue;
|
|
19
21
|
};
|
|
20
22
|
}
|