1 | ;
|
2 |
|
3 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
4 |
|
5 | Object.defineProperty(exports, "__esModule", {
|
6 | value: true
|
7 | });
|
8 | exports.Children = exports.default = void 0;
|
9 |
|
10 | var _react = _interopRequireDefault(require("react"));
|
11 |
|
12 | var _makeRequirable = require("./makeRequirable");
|
13 |
|
14 | /*
|
15 | * The MIT License (MIT)
|
16 | *
|
17 | * Copyright (c) 2015 - present Instructure, Inc.
|
18 | *
|
19 | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
20 | * of this software and associated documentation files (the "Software"), to deal
|
21 | * in the Software without restriction, including without limitation the rights
|
22 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
23 | * copies of the Software, and to permit persons to whom the Software is
|
24 | * furnished to do so, subject to the following conditions:
|
25 | *
|
26 | * The above copyright notice and this permission notice shall be included in all
|
27 | * copies or substantial portions of the Software.
|
28 | *
|
29 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
30 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
31 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
32 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
33 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
34 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
35 | * SOFTWARE.
|
36 | */
|
37 | var Children = {
|
38 | /**
|
39 | * Validate that the children of a component are one of the specified types.
|
40 | *
|
41 | * ```js
|
42 | * import { Children } from '@instructure/ui-prop-types'
|
43 | *
|
44 | * class Example extends Component {
|
45 | * static propTypes = {
|
46 | * children: Children.oneOf([Foo, Bar, Baz])
|
47 | * }
|
48 | *
|
49 | * render () {
|
50 | * return <div>{this.props.children}</div>
|
51 | * }
|
52 | * }
|
53 | * ```
|
54 | *
|
55 | * This will allow children such as:
|
56 | *
|
57 | * ```jsx
|
58 | * <Example>
|
59 | * <Foo />
|
60 | * </Example>
|
61 | * ```
|
62 | *
|
63 | * OR
|
64 | *
|
65 | * ```jsx
|
66 | * <Example>
|
67 | * <Bar />
|
68 | * <Foo />
|
69 | * </Example>
|
70 | * ```
|
71 | *
|
72 | * But will fail on something like:
|
73 | *
|
74 | * ```jsx
|
75 | * <Example>
|
76 | * <h1>Example</h1>
|
77 | * <Foo />
|
78 | * </Example>
|
79 | * ```
|
80 | * @returns {Error} if validation failed
|
81 | */
|
82 | oneOf: function oneOf(validTypes) {
|
83 | function validator(props, propName, componentName) {
|
84 | var children = _react.default.Children.toArray(props[propName]);
|
85 |
|
86 | var validTypeNames = validTypes.map(function (type) {
|
87 | return type ? getDisplayName(type) : type;
|
88 | });
|
89 |
|
90 | for (var i = 0; i < children.length; i++) {
|
91 | var child = children[i];
|
92 |
|
93 | if (child && child.type) {
|
94 | var childName = getDisplayName(child.type);
|
95 |
|
96 | if (validTypeNames.indexOf(childName) < 0) {
|
97 | return new Error("Expected one of ".concat(validTypeNames.join(', '), " in ").concat(componentName, " but found '").concat(childName, "'"));
|
98 | }
|
99 | } else if (child) {
|
100 | return new Error("Expected one of ".concat(validTypeNames.join(', '), " in ").concat(componentName, " but found an element with unknown type: ").concat(child));
|
101 | }
|
102 | }
|
103 | }
|
104 |
|
105 | validator.isRequired = (0, _makeRequirable.makeRequirable)(validator);
|
106 | return validator;
|
107 | },
|
108 |
|
109 | /**
|
110 | * Ensures that there is exactly one of each specified child
|
111 | *
|
112 | * ```js
|
113 | * import { Children } from '@instructure/ui-prop-types'
|
114 | *
|
115 | * class Example extends Component {
|
116 | * static propTypes = {
|
117 | * children: Children.oneOfEach([Foo, Bar, Baz])
|
118 | * }
|
119 | *
|
120 | * render () {
|
121 | * return <div>{this.props.children}</div>
|
122 | * }
|
123 | * }
|
124 | * ```
|
125 | *
|
126 | * This will enforce the following:
|
127 | *
|
128 | * ```jsx
|
129 | * <Example>
|
130 | * <Foo />
|
131 | * <Bar />
|
132 | * <Baz />
|
133 | * </Example>
|
134 | * ```
|
135 | * An error will be thrown
|
136 | * - If any of the children are not provided (ex. Foo, Bar, but missing Baz)
|
137 | * - If multiple children of the same type are provided (ex. Foo, Foo, Bar, and Baz)
|
138 | *
|
139 | * @param {Array} validTypes - Array of child types
|
140 | * @returns {Error} if validation failed
|
141 | */
|
142 | oneOfEach: function oneOfEach(validTypes) {
|
143 | return function (props, propName, componentName) {
|
144 | var children = _react.default.Children.toArray(props[propName]);
|
145 |
|
146 | var instanceCount = {};
|
147 | var validTypeNames = validTypes.map(function (type) {
|
148 | var typeName = getDisplayName(type);
|
149 | instanceCount[typeName] = 0;
|
150 | return typeName;
|
151 | });
|
152 |
|
153 | for (var i = 0; i < children.length; i++) {
|
154 | var child = children[i];
|
155 |
|
156 | if (child && child.type) {
|
157 | var childName = getDisplayName(child.type);
|
158 |
|
159 | if (validTypeNames.indexOf(childName) < 0) {
|
160 | return new Error("Expected one of ".concat(validTypeNames.join(', '), " in ").concat(componentName, " but found '").concat(childName, "'"));
|
161 | }
|
162 |
|
163 | instanceCount[childName] = (instanceCount[childName] || 0) + 1;
|
164 | } else if (child) {
|
165 | return new Error("Expected one of ".concat(validTypeNames.join(', '), " in ").concat(componentName, " but found an element of unknown type: ").concat(child));
|
166 | }
|
167 | }
|
168 |
|
169 | var errors = [];
|
170 | Object.keys(instanceCount).forEach(function (childName) {
|
171 | if (instanceCount[childName] > 1) {
|
172 | errors.push("".concat(instanceCount[childName], " children of type ").concat(childName));
|
173 | }
|
174 |
|
175 | if (instanceCount[childName] === 0) {
|
176 | errors.push("0 children of type ".concat(childName));
|
177 | }
|
178 | });
|
179 |
|
180 | if (errors.length > 0) {
|
181 | return new Error("Expected exactly one of each ".concat(validTypeNames.join(', '), " in ").concat(componentName, " but found:\n ").concat(errors.join('\n')));
|
182 | }
|
183 | };
|
184 | },
|
185 |
|
186 | /**
|
187 | * Validate the type and order of children for a component.
|
188 | *
|
189 | * ```js
|
190 | * import { Children } from '@instructure/ui-prop-types'
|
191 | *
|
192 | * class Example extends Component {
|
193 | * static propTypes = {
|
194 | * children: Children.enforceOrder([Foo, Bar, Baz])
|
195 | * }
|
196 | *
|
197 | * render () {
|
198 | * return <div>{this.props.children}</div>
|
199 | * }
|
200 | * }
|
201 | * ```
|
202 | *
|
203 | * This will enforce the following:
|
204 | *
|
205 | * ```jsx
|
206 | * <Example>
|
207 | * <Foo />
|
208 | * <Bar />
|
209 | * <Baz />
|
210 | * </Example>
|
211 | * ```
|
212 | *
|
213 | * This validator will also allow various permutations of the order.
|
214 | *
|
215 | * ```js
|
216 | * import { Children } from '@instructure/ui-prop-types'
|
217 | *
|
218 | * class Example extends Component {
|
219 | * static propTypes = {
|
220 | * children: Children.enforceOrder(
|
221 | * [Foo, Bar, Baz],
|
222 | * [Foo, Bar],
|
223 | * [Bar, Baz],
|
224 | * )
|
225 | * }
|
226 | *
|
227 | * render () {
|
228 | * return <div>{this.props.children}</div>
|
229 | * }
|
230 | * }
|
231 | * ```
|
232 | *
|
233 | * This will enforce one of the following:
|
234 | *
|
235 | * ```jsx
|
236 | * <Example>
|
237 | * <Foo />
|
238 | * <Bar />
|
239 | * <Baz />
|
240 | * </Example>
|
241 | * ```
|
242 | *
|
243 | * OR
|
244 | *
|
245 | * ```jsx
|
246 | * <Example>
|
247 | * <Foo />
|
248 | * <Bar />
|
249 | * </Example>
|
250 | * ```
|
251 | *
|
252 | * OR
|
253 | *
|
254 | * ```jsx
|
255 | * <Example>
|
256 | * <Bar />
|
257 | * <Baz />
|
258 | * </Example>
|
259 | * ```
|
260 | *
|
261 | * @param {...Array} validTypeGroups One or more Arrays of valid types
|
262 | * @returns {Error} if validation failed
|
263 | */
|
264 | enforceOrder: function enforceOrder() {
|
265 | for (var _len = arguments.length, validTypeGroups = new Array(_len), _key = 0; _key < _len; _key++) {
|
266 | validTypeGroups[_key] = arguments[_key];
|
267 | }
|
268 |
|
269 | function validateTypes(childNames, typeNames) {
|
270 | for (var i = 0; i < childNames.length; i++) {
|
271 | if (childNames[i] !== typeNames[i]) {
|
272 | return false;
|
273 | }
|
274 | }
|
275 |
|
276 | return true;
|
277 | }
|
278 |
|
279 | function formatGroupTypes(componentName, typeGroups) {
|
280 | return typeGroups.map(function (types) {
|
281 | return formatTypes(componentName, types);
|
282 | }).join('\n\n');
|
283 | }
|
284 |
|
285 | function formatTypes(componentName, types) {
|
286 | var children = types.map(function (type) {
|
287 | if (type) {
|
288 | return getDisplayName(type);
|
289 | } else {
|
290 | return '??';
|
291 | }
|
292 | }).map(function (name) {
|
293 | return " <".concat(name, " />");
|
294 | }).join('\n');
|
295 | return "<".concat(componentName, ">\n").concat(children, "\n</").concat(componentName, ">");
|
296 | }
|
297 |
|
298 | function validator(props, propName, componentName) {
|
299 | var childNames = _react.default.Children.toArray(props[propName]).map(function (child) {
|
300 | if (child && child.type) {
|
301 | return getDisplayName(child.type);
|
302 | } else if (child) {
|
303 | return null;
|
304 | }
|
305 | }); // Validate each group, if any of them are valid we're done
|
306 |
|
307 |
|
308 | for (var i = 0; i < validTypeGroups.length; i++) {
|
309 | var validTypeNames = validTypeGroups[i].map(function (type) {
|
310 | if (type) {
|
311 | return getDisplayName(type);
|
312 | } else {
|
313 | return '??';
|
314 | }
|
315 | });
|
316 |
|
317 | if (validateTypes(childNames, validTypeNames)) {
|
318 | return;
|
319 | }
|
320 | } // If we make it through the loop then children are not valid
|
321 |
|
322 |
|
323 | return new Error("Expected children of ".concat(componentName, " in one of the following formats:\n ").concat(formatGroupTypes(componentName, validTypeGroups), "\n\n\n Instead of:\n ").concat(formatTypes(componentName, childNames)));
|
324 | }
|
325 |
|
326 | validator.isRequired = (0, _makeRequirable.makeRequirable)(validator);
|
327 | return validator;
|
328 | }
|
329 | }; // TODO: Remove when we further break up ui-utils and bringing this in no longer creates
|
330 | // a circular dep
|
331 |
|
332 | exports.Children = Children;
|
333 |
|
334 | var getDisplayName = function getDisplayName(Component) {
|
335 | return typeof Component === 'string' ? Component : Component.displayName || Component.name;
|
336 | };
|
337 |
|
338 | var _default = Children;
|
339 | exports.default = _default; |
\ | No newline at end of file |