rasti 4.0.0-alpha.8 → 4.0.0
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 +11 -5
- package/dist/rasti.js +228 -85
- package/dist/rasti.js.map +1 -1
- package/dist/rasti.min.js +1 -1
- package/dist/rasti.min.js.map +1 -1
- package/es/Component.js +141 -51
- package/es/Component.js.map +1 -1
- package/es/View.js +46 -22
- package/es/View.js.map +1 -1
- package/es/utils/dev.js +1 -0
- package/es/utils/dev.js.map +1 -1
- package/es/utils/formatTemplateSource.js +1 -1
- package/es/utils/formatTemplateSource.js.map +1 -1
- package/es/utils/replaceNode.js +28 -11
- package/es/utils/replaceNode.js.map +1 -1
- package/lib/Component.cjs +141 -51
- package/lib/Component.cjs.map +1 -1
- package/lib/View.cjs +46 -22
- package/lib/View.cjs.map +1 -1
- package/lib/utils/dev.cjs +1 -0
- package/lib/utils/dev.cjs.map +1 -1
- package/lib/utils/formatTemplateSource.cjs +1 -1
- package/lib/utils/formatTemplateSource.cjs.map +1 -1
- package/lib/utils/replaceNode.cjs +28 -11
- package/lib/utils/replaceNode.cjs.map +1 -1
- package/package.json +3 -4
- package/src/Component.js +141 -51
- package/src/View.js +46 -22
- package/src/utils/dev.js +1 -0
- package/src/utils/formatTemplateSource.js +1 -1
- package/src/utils/replaceNode.js +28 -11
- /package/{LICENSE.md → LICENSE} +0 -0
package/lib/Component.cjs
CHANGED
|
@@ -37,21 +37,37 @@ require('./utils/padStart.cjs');
|
|
|
37
37
|
*/
|
|
38
38
|
const getExpressionResult = (expression, context, meta) => {
|
|
39
39
|
try {
|
|
40
|
-
|
|
40
|
+
if (typeof expression !== 'function') return expression;
|
|
41
|
+
// In development, detect uninstantiated Component classes and provide a helpful error.
|
|
42
|
+
// This typically happens when a component tag is malformed and not properly expanded.
|
|
43
|
+
if (utils_dev && expression.prototype instanceof Component) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Received uninstantiated Component class "${expression.name || 'Anonymous'}". ` +
|
|
46
|
+
'This usually happens when a component tag is malformed (e.g., missing closing tag or typo). ' +
|
|
47
|
+
'If that\'s not the case, make sure to instantiate child components using a component tag, mount(), or new.'
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return expression.call(context, context);
|
|
41
52
|
} catch (error) {
|
|
42
|
-
if (meta && !error.
|
|
53
|
+
if (meta && !error._rasti) {
|
|
43
54
|
let message;
|
|
44
55
|
|
|
45
56
|
if (utils_dev) {
|
|
46
57
|
const formattedSource = utils_formatTemplateSource(context.source, expression);
|
|
47
|
-
message = utils_createDevelopmentErrorMessage(
|
|
58
|
+
message = utils_createDevelopmentErrorMessage(
|
|
59
|
+
`Error in ${context.constructor.name}#${context.uid} (${meta})\n${error.message}\n\nTemplate source:\n\n${formattedSource}`
|
|
60
|
+
);
|
|
48
61
|
} else {
|
|
49
62
|
message = utils_createProductionErrorMessage(`Error in ${context.constructor.name}#${context.uid} expression`);
|
|
50
63
|
}
|
|
64
|
+
|
|
51
65
|
const enhancedError = new Error(message, { cause : error });
|
|
52
|
-
enhancedError.
|
|
66
|
+
enhancedError._rasti = true;
|
|
67
|
+
|
|
53
68
|
throw enhancedError;
|
|
54
69
|
}
|
|
70
|
+
|
|
55
71
|
throw error;
|
|
56
72
|
}
|
|
57
73
|
};
|
|
@@ -72,7 +88,9 @@ const isComponent = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_
|
|
|
72
88
|
* @return {boolean} True if the element contains a component.
|
|
73
89
|
* @private
|
|
74
90
|
*/
|
|
75
|
-
const containsElement = (el) => !!(
|
|
91
|
+
const containsElement = (el) => !!(
|
|
92
|
+
el && ((el.dataset && el.dataset[Component.DATASET_ELEMENT]) || (el.querySelector && el.querySelector(`[${Component.ATTRIBUTE_ELEMENT}]`)))
|
|
93
|
+
);
|
|
76
94
|
|
|
77
95
|
/**
|
|
78
96
|
* Generate string with placeholders for interpolated expressions.
|
|
@@ -215,8 +233,8 @@ const expandComponents = (main, expressions, skipNormalization = false) => {
|
|
|
215
233
|
}
|
|
216
234
|
// Match component tags with backreference to ensure correct pairing.
|
|
217
235
|
return main.replace(
|
|
218
|
-
new RegExp(`<(${PH})([^>]*)
|
|
219
|
-
(match,
|
|
236
|
+
new RegExp(`<(${PH})([^>]*)/>|<(${PH})([^>]*)>([\\s\\S]*?)</\\4>`,'g'),
|
|
237
|
+
(match, selfClosingTag, selfClosingIdx, selfClosingAttrs, openTag, openIdx, nonVoidAttrs, inner) => {
|
|
220
238
|
let tag, attributesStr, innerList;
|
|
221
239
|
|
|
222
240
|
if (openTag) {
|
|
@@ -246,7 +264,7 @@ const expandComponents = (main, expressions, skipNormalization = false) => {
|
|
|
246
264
|
// Add `renderChildren` function to options.
|
|
247
265
|
if (innerList) {
|
|
248
266
|
// Evaluate items in parent context and create Partial.
|
|
249
|
-
options.renderChildren = () => new core_Partial(innerList.map(item => getExpressionResult(item, this)));
|
|
267
|
+
options.renderChildren = () => new core_Partial(innerList.map(item => getExpressionResult(item, this, 'children')));
|
|
250
268
|
}
|
|
251
269
|
// Mount component.
|
|
252
270
|
return tag.mount(options);
|
|
@@ -463,7 +481,7 @@ const parseAttributes = (attributesStr, expressions) => {
|
|
|
463
481
|
const PH = Component.PLACEHOLDER('(\\d+)');
|
|
464
482
|
const attributes = [];
|
|
465
483
|
// Parse attributes string with support for placeholders in both names and values.
|
|
466
|
-
const regExp = new RegExp(`(?:${PH}|([\\w-]+))(?:=(["']?)(?:${PH}|((?:.?(?!["']?\\s+(?:\\S+)=|\\s
|
|
484
|
+
const regExp = new RegExp(`(?:${PH}|([\\w-]+))(?:=(["']?)(?:${PH}|((?:.?(?!["']?\\s+(?:\\S+)=|\\s*/>|\\s*[>"']))+.))?\\3)?`, 'g');
|
|
467
485
|
|
|
468
486
|
let attributeMatch;
|
|
469
487
|
while ((attributeMatch = regExp.exec(attributesStr)) !== null) {
|
|
@@ -491,7 +509,7 @@ const parseAttributes = (attributesStr, expressions) => {
|
|
|
491
509
|
/*
|
|
492
510
|
* These option keys will be extended on the component instance.
|
|
493
511
|
*/
|
|
494
|
-
const componentOptions = ['key', 'state', 'onCreate', 'onChange', 'onHydrate', 'onRecycle', 'onUpdate'];
|
|
512
|
+
const componentOptions = ['key', 'state', 'onCreate', 'onChange', 'onHydrate', 'onBeforeRecycle', 'onRecycle', 'onBeforeUpdate', 'onUpdate'];
|
|
495
513
|
|
|
496
514
|
/**
|
|
497
515
|
* @lends module:Component
|
|
@@ -664,22 +682,34 @@ class Component extends View {
|
|
|
664
682
|
/**
|
|
665
683
|
* Used internally on the render process.
|
|
666
684
|
* Reuse a `Component` by replacing the placeholder comment with the real nodes.
|
|
667
|
-
*
|
|
668
|
-
* @param parent {node} The parent node.
|
|
669
|
-
* @param props {object} The props to set on the recycled component.
|
|
685
|
+
* Calls `onBeforeRecycle` lifecycle method at the beginning, before any recycling operations occur.
|
|
686
|
+
* @param parent {node} The parent node. If not provided, the node is already in the correct position and won't be moved.
|
|
670
687
|
* @return {Component} The component instance.
|
|
671
688
|
* @private
|
|
672
689
|
*/
|
|
673
|
-
recycle(parent
|
|
690
|
+
recycle(parent) {
|
|
691
|
+
// Call `onBeforeRecycle` lifecycle method.
|
|
692
|
+
this.onBeforeRecycle.call(this);
|
|
693
|
+
// No parent means the node is already in the correct position. So we don't need to replace it.
|
|
674
694
|
if (parent) {
|
|
675
695
|
// Locate the placeholder comment and replace it with the real nodes
|
|
676
696
|
const placeholder = utils_findComment(parent, Component.MARKER_RECYCLED(this.uid), isComponent);
|
|
677
697
|
utils_replaceNode(placeholder, this.el);
|
|
678
698
|
}
|
|
679
|
-
//
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
699
|
+
// Return `this` for chaining.
|
|
700
|
+
return this;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Update the component's props.
|
|
705
|
+
* Sets the props and calls the `onRecycle` lifecycle method.
|
|
706
|
+
* @param props {object} The props to set on the component.
|
|
707
|
+
* @return {Component} The component instance.
|
|
708
|
+
* @private
|
|
709
|
+
*/
|
|
710
|
+
updateProps(props) {
|
|
711
|
+
// Set the props.
|
|
712
|
+
this.props.set(props);
|
|
683
713
|
// Call `onRecycle` lifecycle method.
|
|
684
714
|
this.onRecycle.call(this);
|
|
685
715
|
// Return `this` for chaining.
|
|
@@ -710,7 +740,7 @@ class Component extends View {
|
|
|
710
740
|
* import { Component } from 'rasti';
|
|
711
741
|
* // Create a Title component.
|
|
712
742
|
* const Title = Component.create`
|
|
713
|
-
* <h1>${({ props }) => props.
|
|
743
|
+
* <h1>${({ props }) => props.renderChildren()}</h1>
|
|
714
744
|
* `;
|
|
715
745
|
* // Create Main component.
|
|
716
746
|
* const Main = Component.create`
|
|
@@ -844,14 +874,42 @@ class Component extends View {
|
|
|
844
874
|
}
|
|
845
875
|
|
|
846
876
|
/**
|
|
847
|
-
* Render the `Component`.
|
|
848
|
-
*
|
|
849
|
-
*
|
|
850
|
-
*
|
|
851
|
-
*
|
|
852
|
-
*
|
|
853
|
-
*
|
|
854
|
-
*
|
|
877
|
+
* Render the `Component`.
|
|
878
|
+
*
|
|
879
|
+
* **First render (when `this.el` is not present):**
|
|
880
|
+
* This is the initial render call. The component will be rendered as a string inside a `DocumentFragment` and hydrated,
|
|
881
|
+
* making `this.el` available. `this.el` is the root DOM element of the component that can be applied to the DOM.
|
|
882
|
+
* The `onHydrate` lifecycle method will be called.
|
|
883
|
+
*
|
|
884
|
+
* **Note:** Typically, you don't need to call `render()` directly for the first render. The static method `Component.mount()`
|
|
885
|
+
* handles this process automatically, creating the component instance, rendering it, and appending it to the DOM.
|
|
886
|
+
*
|
|
887
|
+
* **Update render (when `this.el` is present):**
|
|
888
|
+
* This indicates the component is being updated. The method will:
|
|
889
|
+
* - Update only the attributes of the root element and child elements
|
|
890
|
+
* - Update only the content of interpolations (the dynamic parts of the template)
|
|
891
|
+
* - For container components (components that render a single child component), update the single interpolation
|
|
892
|
+
*
|
|
893
|
+
* The `onBeforeUpdate` lifecycle method will be called at the beginning, followed by the `onUpdate` lifecycle method at the end.
|
|
894
|
+
*
|
|
895
|
+
* **Child component handling:**
|
|
896
|
+
* When rendering child components, they can be either recreated or recycled:
|
|
897
|
+
*
|
|
898
|
+
* - **Recreation:** A new component instance is created, running the constructor again. This happens when no matching component
|
|
899
|
+
* is found for recycling.
|
|
900
|
+
*
|
|
901
|
+
* - **Recycling:** The same component instance is reused. Recycling happens in two ways:
|
|
902
|
+
* - Components with a `key` are recycled if a previous child with the same key exists
|
|
903
|
+
* - Unkeyed components are recycled if they have the same type and position in the template or partial
|
|
904
|
+
*
|
|
905
|
+
* When a component is recycled:
|
|
906
|
+
* - The `onBeforeRecycle` lifecycle method is called when recycling starts
|
|
907
|
+
* - The component's `this.props` is updated with the new props from the parent
|
|
908
|
+
* - The `onRecycle` lifecycle method is called after props are updated
|
|
909
|
+
*
|
|
910
|
+
* A recycled component may not use props at all and remain unchanged, or it may be subscribed to a different model
|
|
911
|
+
* (or even the same model as the parent) and update independently in subsequent render cycles.
|
|
912
|
+
*
|
|
855
913
|
* @return {Component} The component instance.
|
|
856
914
|
*/
|
|
857
915
|
render() {
|
|
@@ -863,14 +921,16 @@ class Component extends View {
|
|
|
863
921
|
this.hydrate(fragment);
|
|
864
922
|
return this;
|
|
865
923
|
}
|
|
924
|
+
// Call `onBeforeUpdate` lifecycle method.
|
|
925
|
+
this.onBeforeUpdate.call(this);
|
|
866
926
|
// Clear event listeners.
|
|
867
927
|
this.eventsManager.reset();
|
|
868
|
-
// Update elements.
|
|
869
|
-
this.template.elements.forEach(element => element.update());
|
|
870
928
|
// Store previous children.
|
|
871
929
|
const previousChildren = this.children;
|
|
872
930
|
// Clear current children.
|
|
873
931
|
this.children = [];
|
|
932
|
+
// Store props to update.
|
|
933
|
+
const propsQueue = [];
|
|
874
934
|
// Update interpolations.
|
|
875
935
|
this.template.interpolations.forEach(interpolation => {
|
|
876
936
|
// Reset the tracker.
|
|
@@ -914,8 +974,10 @@ class Component extends View {
|
|
|
914
974
|
const rendered = this.renderTemplatePart(interpolation.expression, addChild, tracker);
|
|
915
975
|
|
|
916
976
|
const recycle = ([recycled, discarded], fragment) => {
|
|
917
|
-
//
|
|
918
|
-
|
|
977
|
+
// Store props to update.
|
|
978
|
+
propsQueue.push([recycled, discarded.props.toJSON()]);
|
|
979
|
+
// Add child and recycle (move to new position if needed).
|
|
980
|
+
this.addChild(recycled).recycle(fragment);
|
|
919
981
|
// Destroy discarded component.
|
|
920
982
|
discarded.destroy();
|
|
921
983
|
};
|
|
@@ -944,10 +1006,17 @@ class Component extends View {
|
|
|
944
1006
|
previousChildren.forEach(prev => {
|
|
945
1007
|
if (this.children.indexOf(prev) < 0) prev.destroy();
|
|
946
1008
|
});
|
|
947
|
-
//
|
|
1009
|
+
// Update recycled children props.
|
|
1010
|
+
propsQueue.forEach(([recycled, props]) => {
|
|
1011
|
+
recycled.updateProps(props);
|
|
1012
|
+
});
|
|
1013
|
+
// If this component is a container, set el to the child element.
|
|
1014
|
+
// Otherwise, update elements attributes and delegate events.
|
|
948
1015
|
if (this.isContainer()) {
|
|
949
1016
|
this.el = this.children[0].el;
|
|
950
1017
|
} else {
|
|
1018
|
+
// Update elements attributes.
|
|
1019
|
+
this.template.elements.forEach(element => element.update());
|
|
951
1020
|
// If there are pending event types, delegate events again.
|
|
952
1021
|
if (this.eventsManager.hasPendingTypes()) {
|
|
953
1022
|
this.delegateEvents();
|
|
@@ -974,7 +1043,7 @@ class Component extends View {
|
|
|
974
1043
|
* This method can be extended with custom logic.
|
|
975
1044
|
* Maybe comparing new attributes with previous ones and calling
|
|
976
1045
|
* render when needed.
|
|
977
|
-
* @param model {
|
|
1046
|
+
* @param model {Model} The model that emitted the event.
|
|
978
1047
|
* @param changed {object} Object containing keys and values that has changed.
|
|
979
1048
|
* @param [...args] {any} Any extra arguments passed to set method.
|
|
980
1049
|
*/
|
|
@@ -989,6 +1058,19 @@ class Component extends View {
|
|
|
989
1058
|
*/
|
|
990
1059
|
onHydrate() {}
|
|
991
1060
|
|
|
1061
|
+
/**
|
|
1062
|
+
* Lifecycle method. Called before the component is recycled and reused between renders.
|
|
1063
|
+
* This method is called at the beginning of the `recycle` method, before any recycling operations occur.
|
|
1064
|
+
*
|
|
1065
|
+
* A component is recycled when:
|
|
1066
|
+
* - It has a `key` and a previous child with the same key exists
|
|
1067
|
+
* - It doesn't have a `key` but has the same type and position in the template or partial
|
|
1068
|
+
*
|
|
1069
|
+
* Use this method to perform operations that need to happen before the component is recycled,
|
|
1070
|
+
* such as storing previous state or preparing for the recycling.
|
|
1071
|
+
*/
|
|
1072
|
+
onBeforeRecycle() {}
|
|
1073
|
+
|
|
992
1074
|
/**
|
|
993
1075
|
* Lifecycle method. Called when the component is recycled and reused between renders.
|
|
994
1076
|
*
|
|
@@ -1001,6 +1083,14 @@ class Component extends View {
|
|
|
1001
1083
|
*/
|
|
1002
1084
|
onRecycle() {}
|
|
1003
1085
|
|
|
1086
|
+
/**
|
|
1087
|
+
* Lifecycle method. Called before the component is updated or re-rendered.
|
|
1088
|
+
* This method is called at the beginning of the `render` method when the component's state, model, or props change and trigger a re-render.
|
|
1089
|
+
* Use this method to perform operations that need to happen before the component is updated,
|
|
1090
|
+
* such as saving previous state or preparing for the update.
|
|
1091
|
+
*/
|
|
1092
|
+
onBeforeUpdate() {}
|
|
1093
|
+
|
|
1004
1094
|
/**
|
|
1005
1095
|
* Lifecycle method. Called when the component is updated or re-rendered.
|
|
1006
1096
|
* This method is called when the component's state, model, or props change and trigger a re-render.
|
|
@@ -1122,7 +1212,7 @@ class Component extends View {
|
|
|
1122
1212
|
* ```javascript
|
|
1123
1213
|
* const Button = Component.create`
|
|
1124
1214
|
* <button class="${({ props }) => props.className}">
|
|
1125
|
-
* ${({ props }) => props.
|
|
1215
|
+
* ${({ props }) => props.renderChildren()}
|
|
1126
1216
|
* </button>
|
|
1127
1217
|
* `;
|
|
1128
1218
|
* ```
|
|
@@ -1168,14 +1258,14 @@ class Component extends View {
|
|
|
1168
1258
|
* // Create a button component.
|
|
1169
1259
|
* const Button = Component.create`
|
|
1170
1260
|
* <button class="button">
|
|
1171
|
-
* ${({ props }) => props.
|
|
1261
|
+
* ${({ props }) => props.renderChildren()}
|
|
1172
1262
|
* </button>
|
|
1173
1263
|
* `;
|
|
1174
1264
|
* // Create a navigation component. Add buttons as children. Iterate over items.
|
|
1175
1265
|
* const Navigation = Component.create`
|
|
1176
1266
|
* <nav>
|
|
1177
1267
|
* ${({ props }) => props.items.map(
|
|
1178
|
-
* item => Button.mount({
|
|
1268
|
+
* item => Button.mount({ renderChildren : () => item.label })
|
|
1179
1269
|
* )}
|
|
1180
1270
|
* </nav>
|
|
1181
1271
|
* `;
|
|
@@ -1191,7 +1281,7 @@ class Component extends View {
|
|
|
1191
1281
|
* // Create a button component.
|
|
1192
1282
|
* const Button = Component.create`
|
|
1193
1283
|
* <button class="button">
|
|
1194
|
-
* ${({ props }) => props.
|
|
1284
|
+
* ${({ props }) => props.renderChildren()}
|
|
1195
1285
|
* </button>
|
|
1196
1286
|
* `;
|
|
1197
1287
|
* // Create a navigation component. Add buttons as children. Iterate over items.
|
|
@@ -1214,7 +1304,7 @@ class Component extends View {
|
|
|
1214
1304
|
* // Create a button component.
|
|
1215
1305
|
* const Button = Component.create`
|
|
1216
1306
|
* <button class="${({ props }) => props.className}">
|
|
1217
|
-
* ${({ props }) => props.
|
|
1307
|
+
* ${({ props }) => props.renderChildren()}
|
|
1218
1308
|
* </button>
|
|
1219
1309
|
* `;
|
|
1220
1310
|
* // Create a container that renders a Button component.
|
|
@@ -1224,7 +1314,7 @@ class Component extends View {
|
|
|
1224
1314
|
* // Create a container that renders a Button component, using a function.
|
|
1225
1315
|
* const ButtonCancel = Component.create(() => Button.mount({
|
|
1226
1316
|
* className : 'cancel',
|
|
1227
|
-
*
|
|
1317
|
+
* renderChildren : () => 'Cancel'
|
|
1228
1318
|
* }));
|
|
1229
1319
|
* ```
|
|
1230
1320
|
* @static
|
|
@@ -1286,25 +1376,25 @@ class Component extends View {
|
|
|
1286
1376
|
/*
|
|
1287
1377
|
* Attributes used to identify elements and events.
|
|
1288
1378
|
*/
|
|
1289
|
-
Component.ATTRIBUTE_ELEMENT = 'data-
|
|
1290
|
-
Component.ATTRIBUTE_EVENT = (type, uid) => `data-
|
|
1379
|
+
Component.ATTRIBUTE_ELEMENT = 'data-rst-el';
|
|
1380
|
+
Component.ATTRIBUTE_EVENT = (type, uid) => `data-rst-on-${type}-${uid}`;
|
|
1291
1381
|
|
|
1292
1382
|
/*
|
|
1293
1383
|
* Dataset attribute used to identify elements.
|
|
1294
1384
|
*/
|
|
1295
|
-
Component.DATASET_ELEMENT = '
|
|
1385
|
+
Component.DATASET_ELEMENT = 'rstEl';
|
|
1296
1386
|
|
|
1297
1387
|
/*
|
|
1298
1388
|
* Placeholders used to temporarily replace expressions in the template.
|
|
1299
1389
|
*/
|
|
1300
|
-
Component.PLACEHOLDER = (idx) => `
|
|
1390
|
+
Component.PLACEHOLDER = (idx) => `__RASTI_PLACEHOLDER_${idx}__`;
|
|
1301
1391
|
|
|
1302
1392
|
/*
|
|
1303
1393
|
* Markers used to identify interpolation and recycled components.
|
|
1304
1394
|
*/
|
|
1305
|
-
Component.MARKER_RECYCLED = (uid) => `
|
|
1306
|
-
Component.MARKER_START = (uid) => `
|
|
1307
|
-
Component.MARKER_END = (uid) => `
|
|
1395
|
+
Component.MARKER_RECYCLED = (uid) => `rst-r-${uid}`;
|
|
1396
|
+
Component.MARKER_START = (uid) => `rst-s-${uid}`;
|
|
1397
|
+
Component.MARKER_END = (uid) => `rst-e-${uid}`;
|
|
1308
1398
|
|
|
1309
1399
|
/**
|
|
1310
1400
|
* Components are a special kind of `View` that is designed to be easily composable,
|
|
@@ -1314,11 +1404,11 @@ Component.MARKER_END = (uid) => `rasti-e-${uid}`;
|
|
|
1314
1404
|
* Components are defined with the {@link #module_component_create Component.create} static method, which takes a tagged template string or a function that returns another component.
|
|
1315
1405
|
* @module
|
|
1316
1406
|
* @extends View
|
|
1317
|
-
* @param {object} options Object containing options. The following keys will be merged to `this`: model, state, key, onDestroy, onHydrate, onRecycle, onUpdate, onCreate, onChange. Any additional options not in the component or view options list will be automatically extracted as props and stored as `this.props`.
|
|
1407
|
+
* @param {object} options Object containing options. The following keys will be merged to `this`: model, state, key, onDestroy, onHydrate, onBeforeRecycle, onRecycle, onBeforeUpdate, onUpdate, onCreate, onChange. Any additional options not in the component or view options list will be automatically extracted as props and stored as `this.props`.
|
|
1318
1408
|
* @property {string} [key] A unique key to identify the component. Components with keys are recycled when the same key is found in the previous render. Unkeyed components are recycled based on type and position.
|
|
1319
|
-
* @property {
|
|
1320
|
-
* @property {
|
|
1321
|
-
* @property {
|
|
1409
|
+
* @property {Model} [model] A `Model` or any emitter object containing data and business logic. The component will listen to `change` events and call `onChange` lifecycle method.
|
|
1410
|
+
* @property {Model} [state] A `Model` or any emitter object containing data and business logic, to be used as internal state. The component will listen to `change` events and call `onChange` lifecycle method.
|
|
1411
|
+
* @property {Model} [props] Automatically created from any options not merged to the component instance. Contains props passed from parent component as a `Model`. The component will listen to `change` events on props and call `onChange` lifecycle method. When a component with a `key` is recycled during parent re-render, new props are automatically updated and any changes trigger a re-render.
|
|
1322
1412
|
* @see {@link #module_component_create Component.create}
|
|
1323
1413
|
* @example
|
|
1324
1414
|
* import { Component, Model } from 'rasti';
|
|
@@ -1329,7 +1419,7 @@ Component.MARKER_END = (uid) => `rasti-e-${uid}`;
|
|
|
1329
1419
|
* </div>
|
|
1330
1420
|
* `;
|
|
1331
1421
|
* // Create model to store seconds.
|
|
1332
|
-
* const model = new Model({ seconds: 0 });
|
|
1422
|
+
* const model = new Model({ seconds : 0 });
|
|
1333
1423
|
* // Mount timer on body.
|
|
1334
1424
|
* Timer.mount({ model }, document.body);
|
|
1335
1425
|
* // Increment `model.seconds` every second.
|