pawajs-continue 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Allisboy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # pawajs-continue
2
+
3
+ The **Continuity Rendering Model (CRM)** for [Pawajs](https://github.com/Allisboy/pawajs).
4
+
5
+ `pawajs-continue` handles the client-side hydration (resumption) of applications server-rendered with `pawa-ssr`. It picks up where the server left off, attaching event listeners and reactivity to the existing DOM without expensive re-renders.
6
+
7
+ ## Features
8
+
9
+ - **Resumability**: Hydrates components, state, and directives from server-rendered HTML.
10
+ - **Lightweight**: Only loads what is necessary to make the page interactive.
11
+ - **Seamless Integration**: Designed to work out-of-the-box with `pawajs` and `pawa-ssr`.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install pawajs-continue
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ In your client-side entry point (e.g., `main.js` or `app.js`), import `initiateResumer` and call it before starting the Pawajs app.
22
+
23
+ ```javascript
24
+ import { isServer } from "pawajs/server";
25
+ import { RegisterComponent, pawaStartApp } from "pawajs";
26
+ import { initiateResumer } from "pawajs-continue";
27
+ import { App } from "./App.js";
28
+
29
+ // Register your root component and others
30
+ RegisterComponent(App);
31
+
32
+ if (!isServer()) {
33
+ const app = document.getElementById('app');
34
+
35
+ // 1. Initialize the continuity engine
36
+ initiateResumer();
37
+
38
+ // 2. Start the app (hydrates the existing DOM)
39
+ pawaStartApp(app);
40
+ }
41
+ ```
42
+
43
+ ## How it Works
44
+
45
+ 1. **Server-Side**: `pawa-ssr` renders the HTML and embeds serialized data (props, state, context) into comments within the DOM.
46
+ 2. **Client-Side**: `pawajs-continue` scans the DOM during the `pawaStartApp` process.
47
+ 3. **Continuity**: Instead of creating new DOM elements, it continues by reading he markers or the serialized data, restores the state, and attaches reactive effects to the existing elements from the server rendering.
48
+
49
+ ## API
50
+
51
+ ### `initiateResumer()`
52
+
53
+ Initializes the hydration logic for attributes, text, loops (`for-each`), conditionals (`if`), and components. This must be called before `pawaStartApp` on the client.
54
+
55
+ ## Related Packages
56
+
57
+ - **pawajs**: The core reactive framework.
58
+ - **pawa-ssr**: The server-side rendering engine.
package/component.js ADDED
@@ -0,0 +1,250 @@
1
+ import { components,keepContext,render,getCurrentContext } from "pawajs/index.js"
2
+ import { PawaElement, PawaComment } from "pawajs/pawaElement.js"
3
+ import PawaComponent from "pawajs/pawaComponent.js"
4
+ import { createEffect } from "pawajs/reactive.js"
5
+ import { setProps } from "./utils.js"
6
+ import {propsValidator} from 'pawajs/utils.js'
7
+ export const resume_component=(el,attr,setStateContext,mapsPlugin,formerStateContext,
8
+ pawaContext,stateWatch,{comment,endComment,children,name,id,serialized})=>{
9
+ el.removeAttribute(attr.name)
10
+ el._running=true
11
+ let appContext={
12
+ _transportContext:{},
13
+ _formerContext:formerStateContext,
14
+ _reactiveProps:{},
15
+ _template:'',
16
+ _transportContext:{},
17
+ _elementContext:{},
18
+ _hasRun:false,
19
+ _static:[],
20
+ _serializedData:{}
21
+ }
22
+ /**
23
+ * @param {HTMLElement} node
24
+ */
25
+ try{
26
+ const oldState=getCurrentContext()
27
+
28
+ PawaComment.Element(comment)
29
+ const compo=components.get(name)
30
+ const binary = atob(serialized.replace(/-/g, '+'));
31
+ const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
32
+ const json = new TextDecoder('utf-8').decode(bytes);
33
+
34
+ const props = JSON.parse(json);
35
+ const prop={
36
+ children:props.children
37
+ }
38
+ /**
39
+ * @type {PawaElement | HTMLElement}
40
+ */
41
+ const element=document.createElement(name)
42
+ PawaElement.Element(element,el._context)
43
+ element._underControl=comment
44
+ comment._componentElement=element
45
+ comment._controlComponent=true
46
+ comment._endComment=endComment
47
+ if(props?.data){
48
+ Object.assign(element._context,props.data)
49
+ }
50
+ comment.data=`<${name}>`
51
+ endComment.data=`</${name}>`
52
+ if(!compo){
53
+
54
+ const fakeComponent=new PawaComponent(()=>null)
55
+ const stateContexts=setStateContext(fakeComponent)
56
+ stateContexts._resume=true
57
+ stateContexts._prop={children:'',...props._props}
58
+ stateContexts._static=[...stateContexts._static,...props.context]
59
+ if(props?.data){
60
+ Object.assign(element._context,props.data)
61
+ }
62
+ stateContexts._elementContext={...element._context}
63
+ const number={notRender:null,index:null}
64
+ children.forEach((value, index) => {
65
+ number.index=index
66
+ if(number.notRender && index <= number.notRender) return
67
+ render(value,element._context,number,attr.name)
68
+ })
69
+ stateContexts._hasRun=true
70
+ keepContext(stateContexts._formerContext)
71
+ return
72
+ }
73
+ // props setter
74
+ let isStatic=false
75
+ for (const [key,value] of Object.entries(props.props)) {
76
+ const attr={
77
+ name:key,
78
+ value:value
79
+ }
80
+ if(!isStatic){
81
+ const resStatic=setProps(el._context,attr,prop,element)
82
+ isStatic=resStatic.static
83
+ }
84
+ }
85
+ if(isStatic){
86
+ const fakeComponent=new PawaComponent(()=>null)
87
+ const stateContexts=setStateContext(fakeComponent)
88
+ stateContexts._resume=true
89
+ if(props?.data){
90
+ Object.assign(element._context,props.data)
91
+ }
92
+ stateContexts._prop={children:'',...props._props}
93
+ stateContexts._elementContext={...element._context}
94
+ stateContexts._static=[...stateContexts._static,...props.context]
95
+ const number={notRender:null,index:null}
96
+
97
+ children.forEach((value, index) => {
98
+ number.index=index
99
+ if(number.notRender && index <= number.notRender) return
100
+ render(value,element._context,number)
101
+ })
102
+ stateContexts._hasRun=true
103
+ keepContext(stateContexts._formerContext)
104
+ return
105
+ }
106
+ for (const [key,value] of Object.entries(props.slots)) {
107
+ prop[key]=()=>value
108
+ }
109
+ el._isKill=true
110
+ el._kill=()=>{
111
+ pawaWayRemover(comment,endComment)
112
+ comment.remove(),endComment.remove();
113
+ }
114
+ element._props=prop
115
+ let isIndex=0
116
+ //props setter
117
+ const validprops=element._component.validPropRule
118
+ let done=true
119
+ if(validprops && Object.entries(validprops).length > 0){
120
+ done= propsValidator(validprops,{...element._props},element._componentName,element._template,element)
121
+ }
122
+ element._componentTerminate=() => {
123
+ comment._terminateByComponent(endComment)
124
+ }
125
+ const apps={
126
+ children:prop.children,
127
+ ...element._props
128
+ }
129
+ const component =element._component
130
+ const stateContexts=setStateContext(component)
131
+ stateContexts._resume=true
132
+ stateContexts._prop={children:props.children,...element._props}
133
+ stateContexts._elementContext={...element._context}
134
+ stateContexts._name=element._componentName
135
+ stateContexts._template=element._template
136
+ stateContexts._recallEffect=()=>{
137
+
138
+ }
139
+ stateContexts._serializedData=props.data
140
+ let isAwait=false
141
+ if(done){
142
+ const compoCall=component.component(apps)
143
+ isAwait=compoCall instanceof Promise
144
+ if( isAwait){
145
+ const storeContext=stateContexts
146
+ compoCall.then((res)=>{
147
+ if (storeContext._hasRun) {
148
+ storeContext._hasRun = false
149
+ }
150
+ keepContext(storeContext)
151
+ if (storeContext?._insert) {
152
+ Object.assign(element._context,storeContext._insert)
153
+ }
154
+ childInsert()
155
+ lifeCircle()
156
+ storeContext._hasRun=true
157
+ })
158
+ }else{
159
+ Object.assign(element._context,stateContexts._insert)
160
+ }
161
+ }
162
+ if (component?._insert) {
163
+
164
+ Object.assign(element._context,component._insert)
165
+ // console.log(el,el._context)
166
+ }
167
+ const childInsert=()=>{
168
+ element._component?._hook?.beforeMount?.forEach((bfm) => {
169
+ const result= bfm(comment)
170
+ if (typeof result === 'function') {
171
+ element._unMountFunctions.push(result)
172
+ }
173
+ })
174
+
175
+ element._component?._hook?.isMount.forEach((hook) => {
176
+ element._MountFunctions.push(hook)
177
+ })
178
+ element._component?._hook?.isUnMount.forEach((hook) => {
179
+ element._unMountFunctions.push(hook)
180
+ })
181
+ const number={notRender:null,index:null}
182
+ children.forEach((value, index) => {
183
+ isIndex++
184
+ if(value.hasAttribute(attr.name)) value.removeAttribute(attr.name);
185
+ number.index=index
186
+ if(number.notRender && index <= number.notRender){
187
+ return
188
+ }
189
+ render(value,element._context,number,attr.name)
190
+ })
191
+ }
192
+ if(!isAwait){
193
+ childInsert()
194
+ }
195
+ const lifeCircle=()=>{
196
+ Promise.resolve().then(()=>{
197
+ element._component?._hook?.effect.forEach((hook) => {
198
+ if(hook?.done) return
199
+ hook.done=true
200
+ const result=stateWatch(hook.effect,hook.deps)
201
+ if (typeof result === 'function') {
202
+ element._unMountFunctions.push(result)
203
+ }
204
+ })
205
+
206
+ if (element._component?._hook?.reactiveEffect) {
207
+ element._component?._hook?.reactiveEffect.forEach((hook) => {
208
+ if(hook?.done) return
209
+ hook.done=true
210
+ const effect=hook.effect(comment)
211
+ if (hook.deps?.component) {
212
+ createEffect(() => {
213
+ return effect()
214
+ },element)
215
+ } else {
216
+ createEffect(() => {
217
+ return effect()
218
+ },hook.deps.value)
219
+ }
220
+ })
221
+ }
222
+ element._MountFunctions.forEach((func) => {
223
+ func.done=true
224
+ const result=func(comment)
225
+ if (typeof result === 'function') {
226
+ element._unMountFunctions.push(result)
227
+ }
228
+ })
229
+
230
+ })
231
+ }
232
+ if(!isAwait){
233
+ lifeCircle()
234
+ }
235
+ stateContexts._hasRun=true
236
+
237
+ keepContext(stateContexts._formerContext)
238
+ if (stateContexts._transportContext) {
239
+ let contextId = stateContexts._transportContext
240
+ delete pawaContext[contextId]
241
+ }
242
+ __pawaDev.totalComponent++
243
+
244
+
245
+ }catch(error){
246
+ console.log(error.message,error.stack)
247
+ console.error(error.message,error.stack)
248
+ }
249
+
250
+ }
package/index.js ADDED
@@ -0,0 +1,154 @@
1
+ import {setResumer} from 'pawajs/resumer.js'
2
+ import {resume_state} from './resume-directive.js'
3
+ import {resume_if} from './resumeIf.js'
4
+ import {resume_for} from './resumeFor.js'
5
+ import {resume_key} from './resumeKey.js'
6
+ import {resume_component} from './component.js'
7
+ import {createEffect} from 'pawajs/reactive.js'
8
+ import {checkKeywordsExistence,setPawaDevError} from 'pawajs/utils.js'
9
+ import { resume_switch } from './resumeSwitch.js'
10
+ export const resume_text=(el,attr,isName)=>{
11
+ if (el._running) {
12
+ return
13
+ }
14
+ el.removeAttribute('c-t')
15
+ el._checkStatic()
16
+ let textNodes
17
+ el.childNodes.forEach((value, index) => {
18
+ if(value.nodeType === 8 && value.data.startsWith('textEvaluator-')){
19
+ textNodes=value.data.slice(14)
20
+ }
21
+ })
22
+ const evaluate = () => {
23
+ try {
24
+ // Always use original content from map for evaluation
25
+ let value = textNodes
26
+ const regex = /@{([^}]*)}/g;
27
+ const keys = Object.keys(el._context);
28
+ const resolvePath = (path, obj) => {
29
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
30
+ };
31
+ const values = keys.map((key) => resolvePath(key, el._context));
32
+ if(!value)return
33
+ value = value.replace(regex, (match, expression) => {
34
+ if (checkKeywordsExistence(el._staticContext,expression)) {
35
+ return ''
36
+ }else{
37
+
38
+ el._textContent[expression]=value
39
+ const func = new Function(...keys, `return ${expression}`);
40
+ return String(func(...values));
41
+ }
42
+ });
43
+ if (el.tagName === 'TEXTAREA') {
44
+ el.value=value
45
+ }else{
46
+ el.textContent=value;
47
+ }
48
+
49
+
50
+ } catch (error) {
51
+ // console.warn(`error at ${el} textcontent`)
52
+ setPawaDevError({
53
+ message:`error at TextContent ${error.message}`,
54
+ error:error,
55
+ template:el._template
56
+ })
57
+ }
58
+ };
59
+
60
+ createEffect(() => {
61
+ evaluate();
62
+ },el);
63
+ }
64
+
65
+ export const resume_attribute=(el,attr,isName)=>{
66
+ if(el._running) return
67
+ // Store original attribute value
68
+
69
+ if (el._componentName) {
70
+ return
71
+ }
72
+ el.removeAttribute(attr.name)
73
+ const attrName=attr.name.slice(5)
74
+ const attrValue=attr.value
75
+ el._preRenderAvoid.push(attrName)
76
+ // A set of attributes that are treated as booleans and are best controlled via properties.
77
+ const booleanAttributes = new Set(['checked', 'selected', 'disabled', 'readonly', 'required', 'multiple']);
78
+ el._mainAttribute[attrName]=attr.value
79
+ el._checkStatic()
80
+ el.removeAttribute(attr.name)
81
+ const evaluate = () => {
82
+
83
+ try{
84
+ // Always use original value from map for evaluation
85
+ let value = attrValue;
86
+ let isBoolean
87
+ const regex = /@{([^}]*)}/g;
88
+ const keys = Object.keys(el._context);
89
+ const resolvePath = (path, obj) => {
90
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
91
+ };
92
+ const values = keys.map((key) => resolvePath(key, el._context));
93
+
94
+ value = value.replace(regex, (match, expression) => {
95
+ if(checkKeywordsExistence(el._staticContext,expression)){
96
+ return ''
97
+ }else{
98
+ const func = new Function(...keys, `return ${expression}`);
99
+ const result = func(...values);
100
+ isBoolean = result; // Assuming one expression for boolean attributes.
101
+ return result;
102
+ }
103
+ });
104
+
105
+ if (booleanAttributes.has(attrName)) {
106
+ // If there was no expression, the presence of the attribute means true, unless its value is 'false'.
107
+ const boolValue = regex.test(attrValue) ? !!isBoolean : attrValue.toLowerCase() !== 'false';
108
+ regex.lastIndex = 0; // Reset regex state after .test()
109
+
110
+ // Map attribute name to property name where they differ (e.g., 'readonly' -> 'readOnly')
111
+ const propName = attrName === 'readonly' ? 'readOnly' : attrName;
112
+
113
+ if (propName in el) {
114
+ el[propName] = boolValue;
115
+ }
116
+
117
+ // Also update the attribute for consistency and for CSS selectors.
118
+ if (boolValue) {
119
+ el.setAttribute(attrName, '');
120
+ } else {
121
+ el.removeAttribute(attrName);
122
+ }
123
+ } else if (attrName === 'value' && 'value' in el) {
124
+ el.value = value;
125
+ } else {
126
+ el.setAttribute(attrName, value);
127
+ }
128
+ }catch(error){
129
+ console.warn(`failed at attribute ${attrName}`,el)
130
+ setPawaDevError({
131
+ message:`error at attribute ${error.message}`,
132
+ error:error,
133
+ template:el._template
134
+ })
135
+ }
136
+ };
137
+
138
+ createEffect(()=>{
139
+ evaluate()
140
+ })
141
+ }
142
+
143
+ export const initiateResumer=()=>{
144
+ setResumer({
145
+ resume_attribute,
146
+ resume_text,
147
+ resume_state,
148
+ resume_if,
149
+ resume_for,
150
+ resume_switch,
151
+ resume_component,
152
+ resume_key
153
+ })
154
+ }
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "pawajs-continue",
3
+ "version": "1.0.0",
4
+ "description": "Pawajs continuity initializer library for ssr",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/Allisboy/pawajs-continue.git"
12
+ },
13
+ "keywords": [
14
+ "pawajs",
15
+ "pawa-ssr",
16
+ "continuity",
17
+ "ssr"
18
+ ],
19
+ "author": "Allwell oriso-owubo owupele",
20
+ "license": "MIT",
21
+ "bugs": {
22
+ "url": "https://github.com/Allisboy/pawajs-continue/issues"
23
+ },
24
+ "homepage": "https://github.com/Allisboy/pawajs-continue#readme",
25
+ "dependencies": {
26
+ "pawajs": "^1.3.8"
27
+ }
28
+ }
@@ -0,0 +1,32 @@
1
+ import {$state} from 'pawajs/index.js'
2
+
3
+
4
+ export const resume_state=(el,attr,isResume)=>{
5
+ if(el._running)return
6
+ const name=attr.name.split('-')[2]
7
+ el.removeAttribute(attr.name)
8
+ try{
9
+ const keys = Object.keys(el._context);
10
+ const resolvePath = (path, obj) => {
11
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
12
+ };
13
+ const values = keys.map((key) => resolvePath(key, el._context));
14
+ const val = new Function(...keys, `
15
+ try{
16
+ return ${attr.value}
17
+ }catch(error){
18
+ console.log(error.message,error.stack)
19
+ }
20
+ `)(...values)
21
+ el._context[name] = null
22
+ el._context[name] = $state(val)
23
+
24
+ el.removeAttribute(attr.name)
25
+ } catch (error) {
26
+ setPawaDevError({
27
+ message: `Error from State directive ${error.message}`,
28
+ error: error,
29
+ template: el._template
30
+ })
31
+ }
32
+ }
package/resumeFor.js ADDED
@@ -0,0 +1,82 @@
1
+ import { createEffect } from 'pawajs/reactive.js';
2
+ import { PawaComment, PawaElement } from 'pawajs/pawaElement.js';
3
+ import { processNode, pawaWayRemover, safeEval, getEvalValues, setPawaDevError, getComment,getEndComment, checkKeywordsExistence } from 'pawajs/utils.js';
4
+ import { merger_for } from 'pawajs/merger/for.js';
5
+ /**
6
+ * @param {HTMLElement | PawaElement} el
7
+ * @param {{value:string,name:string}} attr,
8
+ * @param {{...any}} stateContext
9
+ * @param {{comment:Comment,endComment:Comment,id:string,children:[],dataComment:Comment}} arg
10
+ */
11
+ export const resume_for=(el,attr,stateContext,{comment,endComment,id,children,dataElement})=>{
12
+ const element=dataElement.content.firstElementChild
13
+ if(checkKeywordsExistence(el._staticContext,element.getAttribute('for-each'))) return
14
+ PawaElement.Element(element,el._context)
15
+ element._out = true
16
+ const parent = endComment.parentElement
17
+ element._deCompositionElement = true
18
+ element._isKill = true
19
+ element._kill = () => {
20
+ pawaWayRemover(comment, endComment)
21
+ comment.remove(), endComment.remove();
22
+ }
23
+ const keyOrders=new Map()
24
+ PawaComment.Element(comment)
25
+ comment._setCoveringElement(element)
26
+ element._underControl = comment
27
+ const context = element._context
28
+ const insertIndex = new Map()
29
+ const elementArray = new Set()
30
+ let index=0
31
+ let isCurrentComment
32
+ PawaElement.Element(element,el._context)
33
+ const value=element.getAttribute('for-each')
34
+ const exp = new WeakMap()
35
+ const primitive = { key: value }
36
+ let firstEnter = true
37
+ const split = value.split(' in ')
38
+ const arrayName = split[1]
39
+ const arrayItems = split[0].split(',')
40
+ const arrayItem = arrayItems[0]
41
+ const indexes = arrayItems[1]
42
+ element._underControl = comment
43
+ el._deCompositionElement = true
44
+ element._isKill = true
45
+ element._kill = () => {
46
+ pawaWayRemover(comment, endComment)
47
+ comment.remove(), endComment.remove();
48
+ }
49
+
50
+ const getKeyComment=(comments)=>{
51
+ if(comments === endComment) return
52
+ const current=comments?.data?.split('@-$@-$@') || []
53
+ if(current[1] === id && current[0] === 'forKey'){
54
+ comments.data=`for-key ${current[2]}`
55
+ PawaComment.Element(comments)
56
+ comments._index = index
57
+ keyOrders.set(index,{comment:comments})
58
+ comments._setKey(current[2])
59
+ isCurrentComment=comments
60
+ elementArray.add(comments)
61
+ insertIndex.set(index, current[2])
62
+ index++
63
+ getKeyComment(comments.nextSibling)
64
+ }else if(current[0] === 'endForKey' && current[1] === id && isCurrentComment){
65
+ isCurrentComment._endComment = comments
66
+ comments.data=`end -for-key ${current[2]}`
67
+ getKeyComment(comments.nextSibling)
68
+ }else{
69
+ getKeyComment(comments.nextSibling)
70
+ }
71
+ }
72
+
73
+ const unique=id
74
+ let evalFunc
75
+ getKeyComment(comment)
76
+ const att={name:'for-each',value:element.getAttribute('for-each')}
77
+ const evaluate=merger_for(element,stateContext,att,arrayName,arrayItem,indexes,true,
78
+ {comment,endComment,unique,elementArray,insertIndex,keyOrders})
79
+ createEffect(()=>{
80
+ evaluate()
81
+ })
82
+ }
package/resumeIf.js ADDED
@@ -0,0 +1,70 @@
1
+ import { createEffect } from 'pawajs/reactive.js';
2
+ import { PawaComment, PawaElement } from 'pawajs/pawaElement.js';
3
+ import { pawaWayRemover, safeEval, getEvalValues, setPawaDevError } from 'pawajs/utils.js';
4
+ import { merger_if} from 'pawajs/merger/if.js'
5
+ export const resume_if=(el,attr,stateContext,{comment,endComment,id,children,number})=>{
6
+ const dataElement=document.querySelector(`[p\\:store-if="${id}"]`);
7
+ dataElement.remove()
8
+ const element=dataElement.content.firstElementChild
9
+ // console.log(id,element,el._attributes)
10
+ const chained=[{
11
+ exp:element.getAttribute('if'),
12
+ condition:'if',
13
+ element:element
14
+ }]
15
+ const nextSiblings=element.nextElementSibling || null
16
+ const chainMap=new Map()
17
+ chainMap.set(element.getAttribute('if'),{condition:'if',element:element})
18
+ const getChained=(nextSibling)=>{
19
+ if (nextSibling !== null) {
20
+ if (nextSibling && nextSibling.getAttribute('else') === '' || nextSibling.getAttribute('else-if')) {
21
+ // console.log(true,'it has',nextSibling.getAttribute('else'))
22
+ if (nextSibling.getAttribute('else-if')) {
23
+ chained.push({
24
+ exp:nextSibling.getAttribute('else-if'),
25
+ condition:'else-if',
26
+ element:nextSibling
27
+ })
28
+ chainMap.set(nextSibling.getAttribute('else-if'),{condition:'else-if',element:nextSibling})
29
+ getChained(nextSibling.nextElementSibling)
30
+ nextSibling.remove()
31
+ }else if (nextSibling.getAttribute('else') === '') {
32
+ chained.push({
33
+ exp:'false',
34
+ condition:'else',
35
+ element:nextSibling
36
+ })
37
+ chainMap.set('else',{condition:'else',element:nextSibling})
38
+ nextSibling.remove()
39
+ }
40
+ }
41
+ }
42
+ }
43
+ getChained(nextSiblings)
44
+
45
+ PawaElement.Element(element,el._context)
46
+ element._out = true
47
+ const parent = endComment.parentElement
48
+ element._deCompositionElement = true
49
+ element._isKill = true
50
+ element._kill = () => {
51
+ pawaWayRemover(comment, endComment)
52
+ comment.remove(), endComment.remove();
53
+ }
54
+ PawaComment.Element(comment)
55
+ comment._setCoveringElement(element)
56
+ element._underControl = comment
57
+ const context = element._context
58
+ comment._controlComponent = true
59
+ el.removeAttribute(attr.name)
60
+ /**
61
+ * endComment,comment,func(a function to set func),firstEnter,getFirst,stateContext
62
+ */
63
+ const evaluate=merger_if(element,attr,stateContext,true,
64
+ {comment,endComment,children,chained,chainMap}
65
+ )
66
+ createEffect(()=>{
67
+ evaluate()
68
+ },element)
69
+
70
+ }
package/resumeKey.js ADDED
@@ -0,0 +1,38 @@
1
+ import { createEffect } from 'pawajs/reactive.js';
2
+ import { PawaComment, PawaElement } from 'pawajs/pawaElement.js';
3
+ import { pawaWayRemover, safeEval, getEvalValues, setPawaDevError } from 'pawajs/utils.js';
4
+ import { merger_key } from 'pawajs/merger/key.js';
5
+ export const resume_key=(el,attr,stateContext,{comment,endComment,id,children})=>{
6
+ let dataElement
7
+ dataElement=document.querySelector(`[p\\:store-key="${id}"]`);
8
+ const element=dataElement.content.firstElementChild
9
+ dataElement.remove()
10
+ PawaElement.Element(element,el._context)
11
+ element._out = true
12
+ const parent = endComment.parentElement
13
+ element._deCompositionElement = true
14
+ element._isKill = true
15
+ element._kill = () => {
16
+ pawaWayRemover(comment, endComment)
17
+ comment.remove(), endComment.remove();
18
+ }
19
+ PawaComment.Element(comment)
20
+ comment._setCoveringElement(element)
21
+ element._underControl = comment
22
+ const context = element._context
23
+ comment._controlComponent = true
24
+ el.removeAttribute(attr.name)
25
+ const att={name:'key',value:element.getAttribute('key')}
26
+ let key
27
+ try {
28
+ key=new Function(`return ${attr.value}`)()
29
+ } catch (error) {
30
+ key=''
31
+ }
32
+
33
+ const evaluate=merger_key(element,att,stateContext,true,
34
+ {comment,endComment,children,old:key})
35
+ createEffect(()=>{
36
+ evaluate()
37
+ },element)
38
+ }
@@ -0,0 +1,73 @@
1
+ import { createEffect } from 'pawajs/reactive.js';
2
+ import { PawaComment, PawaElement } from 'pawajs/pawaElement.js';
3
+ import { pawaWayRemover, safeEval, getEvalValues, setPawaDevError } from 'pawajs/utils.js';
4
+ import { merger_switch } from 'pawajs/merger/switch.js';
5
+ export const resume_switch=(el,attr,stateContext,{comment,endComment,id,children})=>{
6
+ let dataElement
7
+ dataElement=document.querySelector(`[p\\:store-switch="${id}"]`);
8
+ const element=dataElement.content.firstElementChild
9
+ dataElement.remove()
10
+ const att={name:'switch',value:element.getAttribute('switch')}
11
+ element.removeAttribute('switch')
12
+ const chained=[{
13
+ exp:element.getAttribute('case'),
14
+ condition:'case',
15
+ element:element
16
+ }]
17
+ const nextSiblings=element.nextElementSibling || null
18
+ const chainMap=new Map()
19
+ chainMap.set(element.getAttribute('case'),{condition:'case',element:element})
20
+ const getChained=(nextSibling)=>{
21
+ if (nextSibling !== null) {
22
+ if (nextSibling && nextSibling.getAttribute('case') || nextSibling.getAttribute('default') === '') {
23
+ // console.log(true,'it has',nextSibling.getAttribute('else'))
24
+ if (nextSibling.getAttribute('case')) {
25
+ chained.push({
26
+ exp:nextSibling.getAttribute('case'),
27
+ condition:'case',
28
+ element:nextSibling
29
+ })
30
+ chainMap.set(nextSibling.getAttribute('case'),{condition:'case',element:nextSibling})
31
+ getChained(nextSibling.nextElementSibling)
32
+ nextSibling.remove()
33
+ }else if (nextSibling.getAttribute('default') === '') {
34
+ chained.push({
35
+ exp:'false',
36
+ condition:'default',
37
+ element:nextSibling
38
+ })
39
+ chainMap.set('default',{condition:'default',element:nextSibling})
40
+ nextSibling.remove()
41
+ }
42
+ }
43
+ }
44
+ }
45
+ getChained(nextSiblings)
46
+
47
+ PawaElement.Element(element,el._context)
48
+ element._out = true
49
+ const parent = endComment.parentElement
50
+ element._deCompositionElement = true
51
+ element._isKill = true
52
+ element._kill = () => {
53
+ pawaWayRemover(comment, endComment)
54
+ comment.remove(), endComment.remove();
55
+ }
56
+ PawaComment.Element(comment)
57
+ comment._setCoveringElement(element)
58
+ element._underControl = comment
59
+ const context = element._context
60
+ comment._controlComponent = true
61
+ el.removeAttribute(attr.name)
62
+ /**
63
+ * endComment,comment,func(a function to set func),firstEnter,getFirst,stateContext
64
+ */
65
+ const evaluate=merger_switch(element,att,stateContext,true,
66
+ {comment,endComment,children,chained,chainMap,caseValue:attr}
67
+ )
68
+
69
+ createEffect(()=>{
70
+ evaluate()
71
+ },element)
72
+
73
+ }
package/utils.js ADDED
@@ -0,0 +1,37 @@
1
+ import {setPawaDevError,replaceTemplateOperators,checkKeywordsExistence} from 'pawajs/utils.js'
2
+ export const setProps=(context,attr,props,el)=>{
3
+ if(checkKeywordsExistence(el._staticContext,attr.value)){
4
+ return {
5
+ static:true
6
+ }
7
+ }
8
+ try {
9
+ const keys = Object.keys(context);
10
+ const resolvePath = (path, obj) => {
11
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
12
+ };
13
+ const values = keys.map((key) => resolvePath(key, context));
14
+ if(attr.value === '') attr.value=true;
15
+ const value=new Function(...keys,`
16
+ return ()=>{
17
+ try{
18
+ const prop= ${replaceTemplateOperators(attr.value)};
19
+ if(prop === '')return prop
20
+ return prop
21
+ }catch(error){
22
+ console.error(error.message,error.stack)
23
+ }
24
+ }
25
+ `)(...values)
26
+ props[attr.name]=value
27
+ return {
28
+ static:false
29
+ }
30
+ } catch (error) {
31
+ setPawaDevError({
32
+ message:`error from ${el._componentName} prop :${attr.name} ${error.message}`,
33
+ error:error,
34
+ template:this._template
35
+ })
36
+ }
37
+ }