react-input-material 0.0.433 → 0.0.435

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,585 +0,0 @@
1
- // #!/usr/bin/env babel-node
2
- // -*- coding: utf-8 -*-
3
- /** @module Inputs */
4
- 'use strict'
5
- /* !
6
- region header
7
- [Project page](https://torben.website/react-material-input)
8
-
9
- Copyright Torben Sickert (info["~at~"]torben.website) 16.12.2012
10
-
11
- License
12
- -------
13
-
14
- This library written by Torben Sickert stand under a creative commons
15
- naming 3.0 unported license.
16
- See https://creativecommons.org/licenses/by/3.0/deed.de
17
- endregion
18
- */
19
- // region imports
20
- import Tools from 'clientnode'
21
- import {Mapping} from 'clientnode/type'
22
- import {
23
- createRef,
24
- ForwardedRef,
25
- forwardRef,
26
- memo as memorize,
27
- MutableRefObject,
28
- ReactElement,
29
- useImperativeHandle,
30
- useEffect,
31
- useState
32
- } from 'react'
33
- import {ComponentAdapter} from 'web-component-wrapper/type'
34
- import {IconButton} from '@rmwc/icon-button'
35
-
36
- import GenericInput from './GenericInput'
37
- /*
38
- "namedExport" version of css-loader:
39
-
40
- import {
41
- inputsAddButtonClassName,
42
- inputsAddClassName,
43
- inputsClassName,
44
- inputsItemClassName,
45
- inputsItemDisabledClassName,
46
- inputsItemInputClassName,
47
- inputsItemRemoveClassName
48
- } from './Inputs.module'
49
- */
50
- import cssClassNames from './Inputs.module'
51
- import WrapConfigurations from './WrapConfigurations'
52
- import {
53
- createDummyStateSetter,
54
- determineInitialValue,
55
- getConsolidatedProperties,
56
- mapPropertiesIntoModel,
57
- translateKnownSymbols,
58
- triggerCallbackIfExists
59
- } from '../helper'
60
- import {
61
- defaultInputsProperties,
62
- DefaultInputsProperties,
63
- defaultProperties,
64
- GenericEvent,
65
- inputsPropertyTypes as propertyTypes,
66
- inputsRenderProperties as renderProperties,
67
- InputProps,
68
- InputsAdapter as Adapter,
69
- InputsAdapterWithReferences as AdapterWithReferences,
70
- InputsComponent,
71
- InputsModel as Model,
72
- InputsModelState as ModelState,
73
- InputsProperties,
74
- InputsPropertiesItem,
75
- InputsProps
76
- } from '../type'
77
- // endregion
78
- const CSS_CLASS_NAMES:Mapping = cssClassNames as Mapping
79
- // region helper
80
- const getPrototype = function<T, P extends InputsPropertiesItem<T>>(
81
- properties:InputsProperties<T, P>
82
- ):Partial<P> {
83
- return {
84
- ...defaultProperties as unknown as Partial<P>,
85
- className: CSS_CLASS_NAMES.inputs__item__input,
86
- ...(properties.default && properties.default.length > 0 ?
87
- properties.default[properties.default.length - 1] :
88
- {}
89
- )
90
- } as Partial<P>
91
- }
92
- const inputPropertiesToValues = function<
93
- T, P extends InputsPropertiesItem<T>
94
- >(inputProperties:Array<P>|null):Array<T|null|undefined>|null {
95
- return Array.isArray(inputProperties) ?
96
- inputProperties.map(({model, value}):null|T|undefined =>
97
- typeof value === undefined ? model?.value : value
98
- ) :
99
- inputProperties
100
- }
101
- const getModelState = function<T, P extends InputsPropertiesItem<T>>(
102
- inputsProperties:InputsProperties<T, P>
103
- ):ModelState {
104
- const properties:Array<P> = inputsProperties.value || []
105
-
106
- const unpack = (name:string, defaultValue = false) =>
107
- (properties:P) =>
108
- properties[name as keyof P] as unknown as boolean ?? defaultValue
109
-
110
- const validMaximumNumber:boolean =
111
- inputsProperties.maximumNumber >= properties.length
112
- const validMinimumNumber:boolean =
113
- inputsProperties.minimumNumber <= properties.length
114
-
115
- const valid:boolean = validMaximumNumber && validMinimumNumber
116
-
117
- return {
118
- dirty: properties.some(unpack('dirty')),
119
- focused: properties.some(unpack('focused')),
120
- invalid: !valid || properties.some(unpack('invalid', true)),
121
- invalidMaximumNumber: !validMaximumNumber,
122
- invalidMinimumNumber: !validMinimumNumber,
123
- invalidRequired: properties.some(unpack('invalidRequired')),
124
- pristine: properties.every(unpack('pristine', true)),
125
- touched: properties.some(unpack('touched')),
126
- untouched: properties.every(unpack('untouched', true)),
127
- valid: valid && properties.every(unpack('valid')),
128
- visited: properties.some(unpack('visited'))
129
- }
130
- }
131
- const getExternalProperties = function<T, P extends InputsPropertiesItem<T>>(
132
- properties:InputsProperties<T, P>
133
- ):InputsProperties<T, P> {
134
- const modelState:ModelState = getModelState<T, P>(properties)
135
-
136
- return {
137
- ...properties,
138
- ...modelState,
139
- model: {
140
- ...(properties.model || {}),
141
- state: modelState,
142
- value: properties.value
143
- }
144
- }
145
- }
146
- // endregion
147
- /**
148
- * Generic inputs wrapper component.
149
- * @property static:displayName - Descriptive name for component to show in web
150
- * developer tools.
151
- * @param props - Given components properties.
152
- * @param reference - Reference object to forward internal state.
153
- *
154
- * @returns React elements.
155
- */
156
- export const InputsInner = function<
157
- T = unknown,
158
- P extends InputsPropertiesItem<T> = InputProps<T>,
159
- State = Mapping<unknown>
160
- >(
161
- props:InputsProps<T, P>, reference?:ForwardedRef<Adapter<T, P>>
162
- ):ReactElement {
163
- // region consolidate properties
164
- const givenProps:InputsProps<T, P> =
165
- translateKnownSymbols(props) as InputsProps<T, P>
166
- /*
167
- Normalize value property (providing only value instead of props is
168
- allowed also).
169
- */
170
- if (Array.isArray(givenProps.value))
171
- for (let index = 0; index < givenProps.value.length; index += 1)
172
- if (
173
- givenProps.value[index] === null ||
174
- typeof givenProps.value[index] !== 'object'
175
- )
176
- givenProps.value[index] =
177
- {value: givenProps.value[index] as T} as Partial<P>
178
- /*
179
- NOTE: Extend default properties with given properties while letting
180
- default property object untouched for unchanged usage in other
181
- instances.
182
- */
183
- const givenProperties:InputsProps<T, P> = Tools.extend<InputsProps<T, P>>(
184
- true,
185
- Tools.copy<InputsProps<T, P>>(
186
- Inputs.defaultProperties as InputsProps<T, P>
187
- ),
188
- givenProps
189
- )
190
- // endregion
191
- // region consolidate state
192
- const [newInputState, setNewInputState] =
193
- useState<'added'|'rendered'|'stabilized'>('stabilized')
194
- useEffect(():void => {
195
- if (newInputState === 'added')
196
- setNewInputState('rendered')
197
- else if (newInputState === 'rendered') {
198
- setNewInputState('stabilized')
199
- triggerOnChange(inputPropertiesToValues<T, P>(properties.value))
200
- }
201
- })
202
-
203
- let [values, setValues] = useState<Array<null|T|undefined>|null>(
204
- inputPropertiesToValues<T, P>(
205
- determineInitialValue<Array<P>>(
206
- givenProps,
207
- Tools.copy(Inputs.defaultProperties.model?.default) as
208
- Array<P>|null|undefined
209
- ) ||
210
- null
211
- )
212
- )
213
- /*
214
- NOTE: Sometimes we need real given properties or derived (default
215
- extended) "given" properties.
216
- */
217
- const controlled:boolean =
218
- !givenProperties.enforceUncontrolled &&
219
- (
220
- (
221
- Array.isArray(givenProps.model?.value) ||
222
- givenProps.model?.value === null
223
- ) &&
224
- (Array.isArray(givenProps.value) || givenProps.value === null)
225
- ) &&
226
- Boolean(givenProperties.onChange || givenProperties.onChangeValue)
227
- // endregion
228
- // region prepare environment
229
- /*
230
- NOTE: Avoid writing into mutable model object properties. So project
231
- value to properties directly.
232
- */
233
- if (
234
- givenProperties.model!.value !== undefined &&
235
- givenProperties.value === undefined
236
- )
237
- givenProperties.value = givenProperties.model!.value
238
- if (givenProperties.value === undefined)
239
- // NOTE: Indicates to be filled later from state.
240
- givenProperties.value = []
241
-
242
- const references:Array<MutableRefObject<ComponentAdapter<P, State>|null>> =
243
- []
244
-
245
- const properties:InputsProperties<T, P> =
246
- getConsolidatedProperties<InputsProps<T, P>, InputsProperties<T, P>>(
247
- mapPropertiesIntoModel<
248
- InputsProps<T, P>,
249
- DefaultInputsProperties<T, P>
250
- >(
251
- givenProperties,
252
- Inputs.defaultProperties.model as unknown as Model<T, P>
253
- )
254
- )
255
-
256
- const triggerOnChange = (
257
- values:Array<null|T|undefined>|null,
258
- event?:GenericEvent,
259
- inputProperties?:Partial<P>,
260
- index?:number
261
- ):void => {
262
- if (values)
263
- properties.value = values.map((
264
- _:null|T|undefined, index:number
265
- ):P =>
266
- references[index]?.current?.properties ||
267
- (properties.value as Array<P>)[index]
268
- )
269
-
270
- if (!properties.value)
271
- properties.value = []
272
-
273
- if (inputProperties)
274
- if (typeof index === 'number')
275
- properties.value[index] = inputProperties as P
276
- else
277
- properties.value.push(inputProperties as P)
278
- else if (inputProperties === undefined && typeof index === 'number')
279
- properties.value.splice(index, 1)
280
-
281
- if (
282
- properties.emptyEqualsNull &&
283
- (!properties.value || properties.value.length === 0)
284
- )
285
- properties.value = null
286
-
287
- triggerCallbackIfExists<InputsProperties<T, P>>(
288
- properties,
289
- 'change',
290
- controlled,
291
- getExternalProperties<T, P>(properties),
292
- event,
293
- properties
294
- )
295
- }
296
- const triggerOnChangeValue = (
297
- values:Array<null|T|undefined>|null,
298
- event?:GenericEvent,
299
- value?:null|T,
300
- index?:number
301
- ):Array<null|T|undefined>|null => {
302
- if (values === null)
303
- values = []
304
-
305
- if (typeof index === 'number')
306
- if (value === undefined)
307
- values.splice(index, 1)
308
- else
309
- values[index] = value
310
- else
311
- values.push(value)
312
-
313
- values = [...values]
314
-
315
- if (properties.emptyEqualsNull && values.length === 0)
316
- values = null
317
-
318
- triggerCallbackIfExists<InputsProperties<T, P>>(
319
- properties,
320
- 'changeValue',
321
- controlled,
322
- values,
323
- event,
324
- properties
325
- )
326
-
327
- return values
328
- }
329
-
330
- for (let index = 0; index < Math.max(
331
- properties.model?.value?.length || 0,
332
- properties.value?.length || 0,
333
- !controlled && values?.length || 0
334
- ); index += 1) {
335
- /*
336
- NOTE: We cannot use "useRef" here since the number of calls would
337
- be variable und therefor break the rules of hooks.
338
- */
339
- const reference:MutableRefObject<ComponentAdapter<P, State>|null> =
340
- createRef<ComponentAdapter<P, State>>()
341
- references.push(reference)
342
-
343
- if (!properties.value)
344
- properties.value = []
345
- if (index >= properties.value.length)
346
- properties.value.push({} as P)
347
-
348
- properties.value[index] = Tools.extend<P>(
349
- true,
350
- {
351
- ...properties.createItem({
352
- index,
353
- item: Tools.copy(getPrototype<T, P>(properties)),
354
- properties,
355
- values
356
- }),
357
- ...properties.value[index],
358
- onChange: (inputProperties:P, event?:GenericEvent):void =>
359
- triggerOnChange(
360
- inputPropertiesToValues<T, P>(properties.value),
361
- event,
362
- inputProperties,
363
- index
364
- ),
365
- onChangeValue: (value:null|T, event?:GenericEvent):void =>
366
- setValues((
367
- values:Array<null|T|undefined>|null
368
- ):Array<null|T|undefined>|null =>
369
- triggerOnChangeValue(values, event, value, index)
370
- ),
371
- ref: reference
372
- },
373
- (
374
- properties.model?.value &&
375
- properties.model.value.length > index &&
376
- properties.model.value[index].model ?
377
- {model: properties.model.value[index].model} :
378
- {}
379
- ) as P,
380
- (
381
- properties.value && properties.value.length > index ?
382
- {value: (properties.value)[index].value} :
383
- {}
384
- ) as P,
385
- (
386
- !controlled && values && values.length > index ?
387
- {value: values[index]} :
388
- {}
389
- ) as P
390
- )
391
- }
392
-
393
- if (
394
- properties.emptyEqualsNull &&
395
- (!properties.value || properties.value.length === 0)
396
- )
397
- properties.value = values = null
398
- else
399
- values = inputPropertiesToValues<T, P>(properties.value)
400
-
401
- if (controlled)
402
- /*
403
- NOTE: We act as a controlled component by overwriting internal
404
- state setter.
405
- */
406
- setValues =
407
- createDummyStateSetter<Array<null|T|undefined>|null>(values)
408
-
409
- properties.invalidMaximumNumber =
410
- properties.model.state.invalidMaximumNumber =
411
- properties.maximumNumber < (properties.value?.length || 0)
412
- properties.invalidMinimumNumber =
413
- properties.model.state.invalidMinimumNumber =
414
- properties.minimumNumber > (properties.value?.length || 0)
415
-
416
- useImperativeHandle(
417
- reference,
418
- ():AdapterWithReferences<T, P> => ({
419
- properties: properties,
420
- references,
421
- state: controlled ?
422
- {} :
423
- {value: inputPropertiesToValues(properties.value)}
424
- })
425
- )
426
-
427
- const add = (event?:GenericEvent):void => setValues((
428
- values:Array<null|T|undefined>|null
429
- ):Array<null|T|undefined> => {
430
- const newProperties:Partial<P> = properties.createPrototype({
431
- index: values?.length || 0,
432
- item: getPrototype<T, P>(properties),
433
- lastValue: values?.length ? values[values.length - 1] : null,
434
- properties,
435
- values
436
- })
437
-
438
- triggerOnChange(values, event, newProperties)
439
-
440
- const result:Array<null|T|undefined> = triggerOnChangeValue(
441
- values,
442
- event,
443
- newProperties.value ?? newProperties.model?.value ?? null
444
- ) as Array<null|T|undefined>
445
-
446
- /**
447
- * NOTE: new Properties are not yet consolidated by nested input
448
- * component. So save that info for further rendering.
449
- */
450
- setNewInputState('added')
451
-
452
- return result
453
- })
454
- const createRemove = (index:number) => (event?:GenericEvent):void =>
455
- setValues((
456
- values:Array<null|T|undefined>|null
457
- ):Array<null|T|undefined>|null => {
458
- values = triggerOnChangeValue(values, event, undefined, index)
459
- triggerOnChange(values, event, undefined, index)
460
- return values
461
- })
462
- // endregion
463
- // region render
464
- const addButton:ReactElement = <IconButton
465
- className={CSS_CLASS_NAMES.inputs__add__button}
466
- icon={properties.addIcon}
467
- onClick={add}
468
- />
469
- const renderInput = (
470
- inputProperties:Partial<P>, index:number
471
- ):ReactElement =>
472
- Tools.isFunction(properties.children) ?
473
- properties.children({
474
- index,
475
- inputsProperties: properties,
476
- properties: inputProperties
477
- }) :
478
- <GenericInput
479
- {...inputProperties as InputProps<T>}
480
- name={`${properties.name}-${index + 1}`}
481
- />
482
-
483
- return <WrapConfigurations
484
- strict={Inputs.strict}
485
- themeConfiguration={properties.themeConfiguration}
486
- >
487
- <div
488
- className={
489
- [CSS_CLASS_NAMES.inputs]
490
- .concat(properties.className ?? [])
491
- .join(' ')
492
- }
493
- data-name={properties.name}
494
- style={properties.styles}
495
- >
496
- {properties.value ?
497
- (properties.value).map((
498
- inputProperties:P, index:number
499
- ):ReactElement =>
500
- <div className={CSS_CLASS_NAMES.inputs__item} key={index}>
501
- {renderInput(inputProperties, index)}
502
-
503
- {properties.disabled ?
504
- '' :
505
- <IconButton
506
- className={
507
- CSS_CLASS_NAMES.inputs__item__remove
508
- }
509
- icon={properties.removeIcon}
510
- onClick={createRemove(index)}
511
- />
512
- }
513
- </div>
514
- ) :
515
- <div className={[
516
- CSS_CLASS_NAMES.inputs__item,
517
- CSS_CLASS_NAMES['inputs__item--disabled']
518
- ].join(' ')}>
519
- {renderInput(
520
- properties.createPrototype({
521
- index: 0,
522
- item: {
523
- ...getPrototype<T, P>(properties),
524
- disabled: true
525
- },
526
- lastValue: null,
527
- properties,
528
- values
529
- }),
530
- 0
531
- )}
532
-
533
- {0 < properties.maximumNumber ? addButton : null}
534
- </div>
535
- }
536
-
537
- {(
538
- properties.disabled ||
539
- properties.invalidMaximumNumber ||
540
- !properties.value ||
541
- properties.maximumNumber <= properties.value.length ||
542
- properties.value.some(({model, value}):boolean =>
543
- [null, undefined].includes(value as null) &&
544
- [null, undefined].includes(model?.value as null)
545
- )
546
- ) ?
547
- '' :
548
- <div className={CSS_CLASS_NAMES.inputs__add}>{addButton}</div>
549
- }
550
- </div>
551
- </WrapConfigurations>
552
- // endregion
553
- }
554
- // NOTE: This is useful in react dev tools.
555
- InputsInner.displayName = 'Inputs'
556
- /**
557
- * Wrapping web component compatible react component.
558
- * @property static:defaultProperties - Initial property configuration.
559
- * @property static:propTypes - Triggers reacts runtime property value checks.
560
- * @property static:strict - Indicates whether we should wrap render output in
561
- * reacts strict component.
562
- * @property static:wrapped - Wrapped component.
563
- *
564
- * @param props - Given components properties.
565
- * @param reference - Reference object to forward internal state.
566
- *
567
- * @returns React elements.
568
- */
569
- export const Inputs:InputsComponent =
570
- memorize(forwardRef(InputsInner)) as unknown as InputsComponent
571
- // region static properties
572
- /// region web-component hints
573
- Inputs.wrapped = InputsInner
574
- Inputs.webComponentAdapterWrapped = 'react'
575
- /// endregion
576
- Inputs.defaultProperties = defaultInputsProperties
577
- Inputs.propTypes = propertyTypes
578
- Inputs.renderProperties = renderProperties
579
- Inputs.strict = false
580
- // endregion
581
- export default Inputs
582
- // region vim modline
583
- // vim: set tabstop=4 shiftwidth=4 expandtab:
584
- // vim: foldmethod=marker foldmarker=region,endregion:
585
- // endregion