oolib 2.49.0 → 2.49.2
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.
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export function TextInput(props: any): any;
|
|
2
|
-
export function PasswordInput({
|
|
2
|
+
export function PasswordInput({ ...props }: {
|
|
3
3
|
[x: string]: any;
|
|
4
|
-
enableValidation?: boolean;
|
|
5
4
|
}): any;
|
|
6
5
|
export function EmailInput({ passValidationErrorToFormValidation, ...props }: {
|
|
7
6
|
[x: string]: any;
|
|
@@ -94,31 +94,37 @@ var OKELink_1 = require("../OKELink");
|
|
|
94
94
|
var DisplayIcon = function (_a) {
|
|
95
95
|
var icon = _a.icon, onClick = _a.onClick, size = _a.size;
|
|
96
96
|
var IconComp = icons_1.icons[icon];
|
|
97
|
-
return (react_1.default.createElement("div", { style: { cursor: onClick ?
|
|
97
|
+
return (react_1.default.createElement("div", { style: { cursor: onClick ? "pointer" : "", display: "flex" }, onMouseDown: onClick || null }, IconComp && react_1.default.createElement(IconComp, { size: size, weight: "bold" })));
|
|
98
98
|
};
|
|
99
99
|
var TextInput = function (props) {
|
|
100
|
-
var id = props.id, invert = props.invert, disabled = props.disabled, icon = props.icon, type = props.type, _a = props.placeholder, placeholder = _a === void 0 ?
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
var
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
var id = props.id, invert = props.invert, disabled = props.disabled, icon = props.icon, type = props.type, _a = props.placeholder, placeholder = _a === void 0 ? "Enter Text..." : _a, _b = props.value, value = _b === void 0 ? "" : _b, onChange = props.onChange, onFocus = props.onFocus, onBlur = props.onBlur, readOnly = props.readOnly, iconOnClick = props.iconOnClick, eyeIcon = props.eyeIcon, S = props.S, handleValidation = props.handleValidation, validateOnMount = props.validateOnMount, actionBtn = props.actionBtn, clearBtn = props.clearBtn, className = props.className, maxLength = props.maxLength, DEPRECATED_maxNumLimiter = props.maxNumLimiter, forceFocus = props.forceFocus, //sometimes, when some other elem is clicked, we wanna trigger focus on the textinput. eg. when on mobile, the search icon is clicked on the listingpage
|
|
101
|
+
_c = props.validateOnlyOnBlur, //sometimes, when some other elem is clicked, we wanna trigger focus on the textinput. eg. when on mobile, the search icon is clicked on the listingpage
|
|
102
|
+
validateOnlyOnBlur = _c === void 0 ? false : _c, //for example, in the login form we want validation to only run, once the text input is blurred. else it can be irritating
|
|
103
|
+
_validationStatus = props.validationStatus;
|
|
104
|
+
var _d = (0, react_1.useState)(_validationStatus), validationStatus = _d[0], setValidationStatus = _d[1];
|
|
105
|
+
(0, react_1.useEffect)(function () {
|
|
106
|
+
setValidationStatus(_validationStatus);
|
|
107
|
+
}, [_validationStatus]);
|
|
108
|
+
var composition = icon && !eyeIcon ? "icon+text" : "textOnly";
|
|
109
|
+
var size = S ? "S" : "M";
|
|
110
|
+
var actionBtnEnabaled = !!value && (type !== "url" ? true : validationStatus.type === "success");
|
|
111
|
+
var clearBtnEnabled = !!value && (type !== "url" ? true : validationStatus.type === "success");
|
|
112
|
+
var handleValidate = function (e, onBlur) { return __awaiter(void 0, void 0, void 0, function () {
|
|
108
113
|
var value, res;
|
|
109
114
|
return __generator(this, function (_a) {
|
|
110
115
|
switch (_a.label) {
|
|
111
116
|
case 0:
|
|
117
|
+
onBlur && onBlur(e);
|
|
112
118
|
value = e.target.value;
|
|
113
119
|
if (!value)
|
|
114
120
|
return [2 /*return*/];
|
|
115
|
-
if (type ===
|
|
116
|
-
|
|
117
|
-
if (!
|
|
118
|
-
return [4 /*yield*/,
|
|
121
|
+
if (type === "url")
|
|
122
|
+
setValidationStatus("loading");
|
|
123
|
+
if (!handleValidation) return [3 /*break*/, 2];
|
|
124
|
+
return [4 /*yield*/, handleValidation(value)];
|
|
119
125
|
case 1:
|
|
120
126
|
res = _a.sent();
|
|
121
|
-
|
|
127
|
+
setValidationStatus(res);
|
|
122
128
|
_a.label = 2;
|
|
123
129
|
case 2: return [2 /*return*/];
|
|
124
130
|
}
|
|
@@ -131,72 +137,55 @@ var TextInput = function (props) {
|
|
|
131
137
|
}, [validateOnMount]);
|
|
132
138
|
var handleOnChange = function (e) {
|
|
133
139
|
onChange(id, e.target.value);
|
|
134
|
-
if (
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
if (!e.target.value)
|
|
141
|
+
setValidationStatus('');
|
|
142
|
+
if (!validateOnlyOnBlur) {
|
|
137
143
|
handleValidate(e);
|
|
138
144
|
}
|
|
145
|
+
else {
|
|
146
|
+
/**
|
|
147
|
+
* basically if an error has already been set then, run validation in realtime on change
|
|
148
|
+
*/
|
|
149
|
+
if (validationStatus) {
|
|
150
|
+
if (type === "url")
|
|
151
|
+
return setValidationStatus("");
|
|
152
|
+
handleValidate(e);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
139
155
|
};
|
|
140
156
|
var inputRef = (0, react_1.useRef)(null);
|
|
141
157
|
(0, react_1.useEffect)(function () {
|
|
142
|
-
forceFocus &&
|
|
143
|
-
inputRef.current &&
|
|
144
|
-
inputRef.current.focus();
|
|
158
|
+
forceFocus && inputRef.current && inputRef.current.focus();
|
|
145
159
|
}, [forceFocus]);
|
|
146
160
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
147
161
|
react_1.default.createElement("div", { className: className },
|
|
148
162
|
react_1.default.createElement(BlockLabel_1.BlockLabel, __assign({}, (0, _EXPORTS_1.getBlockLabelProps)(props))),
|
|
149
|
-
readOnly ? (react_1.default.createElement(Typo_1.SANS_3, { invert: invert }, type ===
|
|
150
|
-
react_1.default.createElement(index_styled_1.InputContainerStyled, { invert: invert, type: type, disabled: disabled, status:
|
|
163
|
+
readOnly ? (react_1.default.createElement(Typo_1.SANS_3, { invert: invert }, type === "password" ? "********" : value)) : (react_1.default.createElement(react_1.default.Fragment, null,
|
|
164
|
+
react_1.default.createElement(index_styled_1.InputContainerStyled, { invert: invert, type: type, disabled: disabled, status: validationStatus === null || validationStatus === void 0 ? void 0 : validationStatus.type, eyeIcon: eyeIcon, composition: composition, onClick: function () { return inputRef.current.focus(); } },
|
|
151
165
|
icon && (react_1.default.createElement(DisplayIcon, { icon: icon, size: S ? 15 : 20, onClick: iconOnClick || null })),
|
|
152
|
-
react_1.default.createElement(index_styled_1.InputStyled, { ref: inputRef, className: size ===
|
|
153
|
-
|
|
166
|
+
react_1.default.createElement(index_styled_1.InputStyled, { ref: inputRef, className: size === "S" ? "SANS_2" : "SANS_3", id: id, type: type, name: type, placeholder: placeholder, value: value, onChange: handleOnChange, maxLength: maxLength || DEPRECATED_maxNumLimiter, onBlur: validateOnlyOnBlur
|
|
167
|
+
? function (e) { return handleValidate(e, onBlur); }
|
|
168
|
+
: onBlur, onFocus: onFocus, size: size, autoComplete: "off" }),
|
|
169
|
+
validationStatus === "loading" && (react_1.default.createElement("div", null,
|
|
154
170
|
react_1.default.createElement(LoadersAndProgress_1.LoaderCircle, { S: true, invert: invert }))),
|
|
155
|
-
clearBtn && (react_1.default.createElement(Buttons_1.ButtonGhost, { M: true, value: clearBtn.text, invert: clearBtn.invert, onClick: function () { return onChange(props.id,
|
|
156
|
-
actionBtn && (react_1.default.createElement(Buttons_1.ButtonPrimary, { M: true, value: actionBtn.text, invert: actionBtn.invert, onClick: actionBtnEnabaled && actionBtn.onClick, disabled: !actionBtnEnabaled, style: { marginRight:
|
|
157
|
-
(
|
|
171
|
+
clearBtn && (react_1.default.createElement(Buttons_1.ButtonGhost, { M: true, value: clearBtn.text, invert: clearBtn.invert, onClick: function () { return onChange(props.id, ""); }, disabled: !clearBtnEnabled, style: { marginRight: actionBtn ? "-1rem" : "-2rem" }, icon: clearBtn.icon })),
|
|
172
|
+
actionBtn && (react_1.default.createElement(Buttons_1.ButtonPrimary, { M: true, value: actionBtn.text, invert: actionBtn.invert, onClick: actionBtnEnabaled && actionBtn.onClick, disabled: !actionBtnEnabaled, style: { marginRight: "-2rem" }, icon: actionBtn.icon }))),
|
|
173
|
+
(validationStatus === null || validationStatus === void 0 ? void 0 : validationStatus.msg) && (react_1.default.createElement(index_styled_1.MsgContainer, { invert: invert, status: validationStatus === null || validationStatus === void 0 ? void 0 : validationStatus.type },
|
|
158
174
|
react_1.default.createElement(Typo_1.SANS_3, null,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
react_1.default.createElement(OKELink_1.OKELink, { style: { marginLeft: '1rem' }, to: inputStatus.link.to }, inputStatus.link.text)))))))));
|
|
175
|
+
validationStatus.msg,
|
|
176
|
+
validationStatus.link && (react_1.default.createElement(OKELink_1.OKELink, { style: { marginLeft: "1rem" }, to: validationStatus.link.to }, validationStatus.link.text))))))))));
|
|
162
177
|
};
|
|
163
178
|
exports.TextInput = TextInput;
|
|
164
179
|
//passValidationErrorToFormValidation is not being handled by PasswordInput, cuz i dont think we will need it here..
|
|
165
180
|
var PasswordInput = function (_a) {
|
|
166
|
-
var
|
|
167
|
-
var
|
|
168
|
-
var icon = showPassword ?
|
|
181
|
+
var props = __rest(_a, []);
|
|
182
|
+
var _b = (0, react_1.useState)(false), showPassword = _b[0], setShowPassword = _b[1];
|
|
183
|
+
var icon = showPassword ? "Eye" : "EyeClosed";
|
|
169
184
|
var toggleShowPassword = function (e) {
|
|
170
185
|
e.preventDefault();
|
|
171
186
|
setShowPassword(function (prev) { return !prev; });
|
|
172
187
|
};
|
|
173
|
-
|
|
174
|
-
if (value.length < 8) {
|
|
175
|
-
return { type: 'error', msg: 'Password cannot be less than 8 characters' };
|
|
176
|
-
}
|
|
177
|
-
if (!/[A-Z]/g.test(value)) {
|
|
178
|
-
return {
|
|
179
|
-
type: 'error',
|
|
180
|
-
msg: 'Password must contain a uppercase character',
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
if (!/[\d]/g.test(value)) {
|
|
184
|
-
return {
|
|
185
|
-
type: 'error',
|
|
186
|
-
msg: 'Password must contain a digit',
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
if (!/[a-z]/g.test(value)) {
|
|
190
|
-
return {
|
|
191
|
-
type: 'error',
|
|
192
|
-
msg: 'Password must contain a lowercase character',
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
if (!/\W|_/g.test(value)) {
|
|
196
|
-
return { type: 'error', msg: 'Password must contain a special character' };
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
return (react_1.default.createElement(exports.TextInput, __assign({ placeholder: 'Enter password...', type: showPassword ? 'text' : 'password', iconOnClick: toggleShowPassword, eyeIcon: true, icon: icon, validateOnBlur: enableValidation && handleValidation }, props)));
|
|
188
|
+
return (react_1.default.createElement(exports.TextInput, __assign({ placeholder: "Enter password...", type: showPassword ? "text" : "password", iconOnClick: toggleShowPassword, eyeIcon: true, icon: icon }, props)));
|
|
200
189
|
};
|
|
201
190
|
exports.PasswordInput = PasswordInput;
|
|
202
191
|
var EmailInput = function (_a) {
|
|
@@ -204,14 +193,14 @@ var EmailInput = function (_a) {
|
|
|
204
193
|
var handleValidation = function (value) {
|
|
205
194
|
var regEx = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
206
195
|
var errorObj = regEx.test(value)
|
|
207
|
-
?
|
|
208
|
-
: { type:
|
|
196
|
+
? ""
|
|
197
|
+
: { type: "error", msg: "Enter a valid email address" };
|
|
209
198
|
if (passValidationErrorToFormValidation) {
|
|
210
|
-
passValidationErrorToFormValidation((errorObj === null || errorObj === void 0 ? void 0 : errorObj.type) ||
|
|
199
|
+
passValidationErrorToFormValidation((errorObj === null || errorObj === void 0 ? void 0 : errorObj.type) || "success");
|
|
211
200
|
}
|
|
212
201
|
return errorObj;
|
|
213
202
|
};
|
|
214
|
-
return (react_1.default.createElement(exports.TextInput, __assign({ type: "email", placeholder:
|
|
203
|
+
return (react_1.default.createElement(exports.TextInput, __assign({ type: "email", placeholder: "Enter email...", handleValidation: handleValidation }, props)));
|
|
215
204
|
};
|
|
216
205
|
exports.EmailInput = EmailInput;
|
|
217
206
|
var PhoneInput = function (_a) {
|
|
@@ -219,22 +208,22 @@ var PhoneInput = function (_a) {
|
|
|
219
208
|
var handleValidation = function (value) {
|
|
220
209
|
var errorObj;
|
|
221
210
|
if (isNaN(value)) {
|
|
222
|
-
errorObj = { type:
|
|
211
|
+
errorObj = { type: "error", msg: "Enter a valid phone number" };
|
|
223
212
|
if (passValidationErrorToFormValidation)
|
|
224
213
|
passValidationErrorToFormValidation(errorObj.type);
|
|
225
214
|
return errorObj;
|
|
226
215
|
}
|
|
227
216
|
if (value.length < 10) {
|
|
228
|
-
errorObj = { type:
|
|
217
|
+
errorObj = { type: "error", msg: "Enter a valid phone number" };
|
|
229
218
|
if (passValidationErrorToFormValidation)
|
|
230
219
|
passValidationErrorToFormValidation(errorObj.type);
|
|
231
220
|
return errorObj;
|
|
232
221
|
}
|
|
233
222
|
//else
|
|
234
223
|
if (passValidationErrorToFormValidation)
|
|
235
|
-
passValidationErrorToFormValidation(
|
|
224
|
+
passValidationErrorToFormValidation("success");
|
|
236
225
|
};
|
|
237
|
-
return (react_1.default.createElement(exports.TextInput, __assign({ type: "tel", placeholder:
|
|
226
|
+
return (react_1.default.createElement(exports.TextInput, __assign({ type: "tel", placeholder: "Enter Phone...", handleValidation: handleValidation, maxLength: 10 }, props)));
|
|
238
227
|
};
|
|
239
228
|
exports.PhoneInput = PhoneInput;
|
|
240
229
|
var URLInput = function (_a) {
|
|
@@ -246,7 +235,11 @@ var URLInput = function (_a) {
|
|
|
246
235
|
switch (_a.label) {
|
|
247
236
|
case 0:
|
|
248
237
|
if (!validationPlugin) return [3 /*break*/, 2];
|
|
249
|
-
return [4 /*yield*/, validationPlugin({
|
|
238
|
+
return [4 /*yield*/, validationPlugin({
|
|
239
|
+
value: value,
|
|
240
|
+
content: content,
|
|
241
|
+
passValidationErrorToFormValidation: passValidationErrorToFormValidation,
|
|
242
|
+
})];
|
|
250
243
|
case 1:
|
|
251
244
|
pluginResponse = _a.sent();
|
|
252
245
|
if (pluginResponse)
|
|
@@ -255,15 +248,15 @@ var URLInput = function (_a) {
|
|
|
255
248
|
case 2:
|
|
256
249
|
//else
|
|
257
250
|
//if routesAreValidInputs, then first validate for a route
|
|
258
|
-
if (routesAreValidInputs && value.substring(0, 1) ===
|
|
259
|
-
successObj = { type:
|
|
251
|
+
if (routesAreValidInputs && value.substring(0, 1) === "/") {
|
|
252
|
+
successObj = { type: "success", msg: "valid route" };
|
|
260
253
|
if (passValidationErrorToFormValidation)
|
|
261
254
|
passValidationErrorToFormValidation(successObj.type);
|
|
262
255
|
return [2 /*return*/, successObj];
|
|
263
256
|
}
|
|
264
257
|
//else validate for a url
|
|
265
258
|
if (!/^https?:\/\//i.test(value)) {
|
|
266
|
-
value =
|
|
259
|
+
value = "https://" + value;
|
|
267
260
|
}
|
|
268
261
|
_a.label = 3;
|
|
269
262
|
case 3:
|
|
@@ -272,20 +265,20 @@ var URLInput = function (_a) {
|
|
|
272
265
|
case 4:
|
|
273
266
|
response = _a.sent();
|
|
274
267
|
if (response.status !== 200)
|
|
275
|
-
throw new Error(
|
|
276
|
-
successObj = { type:
|
|
268
|
+
throw new Error("");
|
|
269
|
+
successObj = { type: "success", msg: "valid url" };
|
|
277
270
|
if (passValidationErrorToFormValidation)
|
|
278
271
|
passValidationErrorToFormValidation(successObj.type);
|
|
279
272
|
return [2 /*return*/, successObj];
|
|
280
273
|
case 5:
|
|
281
274
|
err_1 = _a.sent();
|
|
282
|
-
if (/[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/
|
|
283
|
-
successObj = { type:
|
|
275
|
+
if (/[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/gi.test(value)) {
|
|
276
|
+
successObj = { type: "success", msg: "valid url" };
|
|
284
277
|
if (passValidationErrorToFormValidation)
|
|
285
278
|
passValidationErrorToFormValidation(successObj.type);
|
|
286
279
|
return [2 /*return*/, successObj];
|
|
287
280
|
}
|
|
288
|
-
errorObj = { type:
|
|
281
|
+
errorObj = { type: "error", msg: "Enter a valid url..." };
|
|
289
282
|
if (passValidationErrorToFormValidation)
|
|
290
283
|
passValidationErrorToFormValidation(errorObj.type);
|
|
291
284
|
return [2 /*return*/, errorObj];
|
|
@@ -293,7 +286,7 @@ var URLInput = function (_a) {
|
|
|
293
286
|
}
|
|
294
287
|
});
|
|
295
288
|
}); };
|
|
296
|
-
return (react_1.default.createElement(exports.TextInput, __assign({ type: "url",
|
|
289
|
+
return (react_1.default.createElement(exports.TextInput, __assign({ type: "url", handleValidation: handleValidation, placeholder: "Enter a valid url..." }, props)));
|
|
297
290
|
};
|
|
298
291
|
exports.URLInput = URLInput;
|
|
299
292
|
var NumberInput = function (_a) {
|
|
@@ -302,31 +295,37 @@ var NumberInput = function (_a) {
|
|
|
302
295
|
var handleValidation = function (value) {
|
|
303
296
|
var errorObj;
|
|
304
297
|
if (isNaN(value)) {
|
|
305
|
-
errorObj = { type:
|
|
298
|
+
errorObj = { type: "error", msg: "Enter a number" };
|
|
306
299
|
if (passValidationErrorToFormValidation)
|
|
307
300
|
passValidationErrorToFormValidation(errorObj.type);
|
|
308
301
|
return errorObj;
|
|
309
302
|
}
|
|
310
303
|
if (min && value < min) {
|
|
311
|
-
errorObj = {
|
|
304
|
+
errorObj = {
|
|
305
|
+
type: "error",
|
|
306
|
+
msg: "Enter value greater than or equal to ".concat(min),
|
|
307
|
+
};
|
|
312
308
|
if (passValidationErrorToFormValidation)
|
|
313
309
|
passValidationErrorToFormValidation(errorObj.type);
|
|
314
310
|
return errorObj;
|
|
315
311
|
}
|
|
316
312
|
if (max && value > max) {
|
|
317
|
-
errorObj = {
|
|
313
|
+
errorObj = {
|
|
314
|
+
type: "error",
|
|
315
|
+
msg: "Enter value less than or equal to ".concat(max),
|
|
316
|
+
};
|
|
318
317
|
if (passValidationErrorToFormValidation)
|
|
319
318
|
passValidationErrorToFormValidation(errorObj.type);
|
|
320
319
|
return errorObj;
|
|
321
320
|
}
|
|
322
321
|
//else
|
|
323
322
|
if (passValidationErrorToFormValidation)
|
|
324
|
-
passValidationErrorToFormValidation(
|
|
323
|
+
passValidationErrorToFormValidation("success");
|
|
325
324
|
};
|
|
326
325
|
return (react_1.default.createElement(exports.TextInput
|
|
327
326
|
// type="number"
|
|
328
327
|
, __assign({
|
|
329
328
|
// type="number"
|
|
330
|
-
|
|
329
|
+
handleValidation: handleValidation, placeholder: "Enter Number..." }, props)));
|
|
331
330
|
};
|
|
332
331
|
exports.NumberInput = NumberInput;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oolib",
|
|
3
|
-
"version": "2.49.
|
|
3
|
+
"version": "2.49.2",
|
|
4
4
|
"description": " OKE Component Library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,9 +12,26 @@
|
|
|
12
12
|
"build": "npx tsc",
|
|
13
13
|
"prebuild": "rm -rf dist",
|
|
14
14
|
"postbuild": "npm run copy-files",
|
|
15
|
-
"semantic-release": "semantic-release
|
|
15
|
+
"semantic-release": "semantic-release",
|
|
16
16
|
"chromatic": "npx chromatic --project-token=0db95ae1f8d9"
|
|
17
17
|
},
|
|
18
|
+
"release": {
|
|
19
|
+
"branches": [
|
|
20
|
+
"main"
|
|
21
|
+
],
|
|
22
|
+
"plugins": [
|
|
23
|
+
"@semantic-release/commit-analyzer",
|
|
24
|
+
"@semantic-release/release-notes-generator",
|
|
25
|
+
"@semantic-release/npm",
|
|
26
|
+
[
|
|
27
|
+
"@semantic-release/github",
|
|
28
|
+
{
|
|
29
|
+
"successComment": false,
|
|
30
|
+
"failComment": false
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
]
|
|
34
|
+
},
|
|
18
35
|
"repository": {
|
|
19
36
|
"type": "git",
|
|
20
37
|
"url": "https://github.com/ooloi-labs/oolib.git"
|