@lexriver/dome 2.0.2 → 2.0.4

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.
Files changed (43) hide show
  1. package/out/index.cjs +994 -0
  2. package/out/index.mjs +2164 -0
  3. package/out/src/AnimatedArray.d.ts +29 -0
  4. package/out/src/AnimatedTable.d.mts +2 -1
  5. package/out/src/AnimatedTable.d.ts +39 -0
  6. package/out/src/AnimatedTable.mjs +2 -1
  7. package/out/src/AnimatedText.d.mts +1 -1
  8. package/out/src/AnimatedText.d.ts +13 -0
  9. package/out/src/AnimatedText.mjs +1 -1
  10. package/out/src/Animation.d.ts +4 -0
  11. package/out/src/Dome.d.ts +9 -0
  12. package/out/src/Dome.mjs +1 -1
  13. package/out/src/DomeComponent.d.ts +25 -0
  14. package/out/src/DomeManipulator.d.ts +52 -0
  15. package/out/src/DomeRouter.d.ts +32 -0
  16. package/out/src/LongestCommonSubsequence.d.ts +15 -0
  17. package/out/src/index.d.mts +5 -1
  18. package/out/src/index.d.ts +15 -0
  19. package/out/src/index.mjs +5 -1
  20. package/package.json +21 -3
  21. package/out/src/DomeRouter.console-test.d.mts +0 -1
  22. package/out/src/DomeRouter.console-test.mjs +0 -44
  23. package/out/src/concurrent-updates.test.d.mts +0 -1
  24. package/out/src/concurrent-updates.test.mjs +0 -203
  25. package/out/src/temp-test.d.mts +0 -1
  26. package/out/src/temp-test.mjs +0 -20
  27. package/out/vitest.config.d.ts +0 -2
  28. package/out/vitest.config.js +0 -9
  29. package/src/AnimatedArray.mts +0 -74
  30. package/src/AnimatedTable.mts +0 -120
  31. package/src/AnimatedText.mts +0 -30
  32. package/src/Animation.mts +0 -4
  33. package/src/Dome.mts +0 -346
  34. package/src/DomeComponent.mts +0 -84
  35. package/src/DomeManipulator.mts +0 -391
  36. package/src/DomeRouter.console-test.mts +0 -52
  37. package/src/DomeRouter.mts +0 -287
  38. package/src/LongestCommonSubsequence.mts +0 -201
  39. package/src/concurrent-updates.test.mts +0 -252
  40. package/src/index.mts +0 -12
  41. package/src/temp-test.mts +0 -23
  42. package/tsconfig.json +0 -59
  43. package/vitest.config.ts +0 -10
@@ -1,391 +0,0 @@
1
- import { Async } from "@lexriver/async"
2
- import { DataTypes } from "@lexriver/data-types"
3
- import { ObservableVariable, checkIfObservable } from "@lexriver/observable"
4
- import { Animation } from './Animation.mjs'
5
-
6
-
7
- export type CssClass = {[key:string]:boolean|ObservableVariable<boolean>} | string[] | string
8
-
9
- const replacementPromiseByElement = new WeakMap<Element, Promise<void>>()
10
-
11
- export namespace DomeManipulator {
12
-
13
- export async function hideElementAsync(element: Element, animation?:Animation) {
14
- if(!element) throw new Error('hideElementAsync failed, no element')
15
- if((element as HTMLElement).hidden) return
16
- if(animation){
17
- await addCssClassAsync(element, animation.cssClassName, animation.timeMs)
18
- }
19
- (element as HTMLElement).style.display = 'none'; //TODO: remove this?
20
- (element as HTMLElement).hidden = true
21
-
22
- }
23
-
24
- export async function unhideElementAsync(element: Element, animation?:Animation) {
25
- if(!element) throw new Error('unhideElementAsync failed, no element')
26
- if(!(element as HTMLElement).hidden) return
27
- (element as HTMLElement).style.display = ''; //TODO: remove this?
28
- (element as HTMLElement).hidden = false
29
- if(animation){
30
- await addCssClassAsync(element, animation.cssClassName, animation.timeMs)
31
- }
32
- }
33
-
34
- export async function insertAsFirstChildAsync(elementToInsert: Element, parentElement: Element | DocumentFragment, animation?:Animation) {
35
- parentElement.insertBefore(elementToInsert, parentElement.firstChild)
36
- if(animation){
37
- await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs)
38
- }
39
-
40
- }
41
-
42
- export async function insertBeforeAsync(elementToInsert: Element, refElement: Element | null, parentElement: Element | DocumentFragment, animation?:Animation) {
43
- parentElement.insertBefore(elementToInsert, refElement)
44
- if(animation){
45
- await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs)
46
- }
47
-
48
- }
49
-
50
- export async function insertAfterAsync(elementToInsert: Element, refElement: Element | null | undefined, parentElement: Element | DocumentFragment, animation?:Animation) {
51
- if (refElement) {
52
- parentElement.insertBefore(elementToInsert, refElement.nextSibling)
53
- } else {
54
- parentElement.appendChild(elementToInsert)
55
- }
56
- if(animation){
57
- await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs)
58
- }
59
-
60
- }
61
-
62
- export async function insertByIndexAsync(elementToInsert: Element, index: number, parentElement: Element | DocumentFragment, animation?:Animation) {
63
- if (index == 0) {
64
- parentElement.appendChild(elementToInsert)
65
- if(animation){
66
- await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs)
67
- }
68
- return
69
- }
70
-
71
- await insertAfterAsync(elementToInsert, parentElement.children[index], parentElement, animation)
72
-
73
- }
74
-
75
-
76
- export async function replaceAsync(oldElement: Element, newElement: Element, animationHide?:Animation, animationShow?:Animation) {
77
- if(!oldElement.parentNode){
78
- // almost impossible if in DOM
79
- console.error('replaceAsync() failed, no parentNode.', 'oldElement=', oldElement)
80
- throw new Error('no parent node for replaceAsync')
81
- }
82
-
83
- // hide
84
- if(animationHide){
85
- await addCssClassAsync(oldElement, animationHide.cssClassName, animationHide.timeMs)
86
- }
87
-
88
- // replace
89
- const parent = oldElement.parentNode
90
- if (!parent) {
91
- //TODO: do not throw error here?
92
- console.error('replaceAsync() failed, no parent. Probably node was deleted while hide animation.', 'oldElement=', oldElement, 'type=', typeof oldElement, 'parent=', oldElement.parentElement, oldElement.parentNode)
93
- throw new Error('no parent for replaceAsync()')
94
- }
95
- parent.replaceChild(newElement, oldElement)
96
-
97
- // show
98
- if(animationShow){
99
- await addCssClassAsync(newElement, animationShow.cssClassName, animationShow.timeMs)
100
- }
101
-
102
- return newElement
103
-
104
- }
105
-
106
- export async function removeElementAsync(element: Element, animation?:Animation) {
107
- //console.log('#dome', 'removeELementAsync', element)
108
- if(animation){
109
- //console.log('#dome', 'add animation', animation.cssClassName, animation.timeMs, element)
110
- await addCssClassAsync(element, animation.cssClassName, animation.timeMs)
111
- }
112
- //console.log('#dome', 'removing from dom', element)
113
- element.remove()
114
- }
115
-
116
- export function forEachChildrenOf(element:Element, action:(child:ChildNode)=>void){
117
- for(let i=0;i<element.childNodes.length;i++){
118
- action(element.childNodes[i])
119
- }
120
- }
121
-
122
-
123
- export async function removeAllChildrenAsync(element: Element, animation?:Animation) {
124
- // await Promise.all( //TODO: this doesn't remove text nodes
125
- // Array.from(element.children).map(child => removeElementAsync(child, animation))
126
- // )
127
-
128
- if(!animation){
129
- while (element.firstChild) {
130
- //element.removeChild(element.firstChild);
131
- element.firstChild.remove()
132
- }
133
- //return
134
- } else {
135
- //console.log('##', 'assign remove animation for each children', element.childNodes)
136
- forEachChildrenOf(element, (child) => child.nodeType == Node.ELEMENT_NODE && (child as Element).classList.add(animation.cssClassName))
137
- //console.log('##', 'wait ms', animation.timeMs)
138
- await Async.waitMsAsync(animation.timeMs)
139
- // Take a snapshot because childNodes is live and shrinks as nodes are removed.
140
- Array.from(element.childNodes).forEach(child => child.remove())
141
- //console.log('##', 'done')
142
- }
143
-
144
- // if(element.children.length>0) {
145
- // console.error('DomeManipulator: removeAllChildrenAsync() failed', 'length=', element.children.length, 'children=', element.children, 'animation=', animation, 'element=', element)
146
- // throw new Error()
147
- // }
148
-
149
- }
150
-
151
- export async function appendChildAsync(containerElement:Element, child:Element, animation?:Animation){
152
- containerElement.appendChild(child)
153
- if(animation){
154
- await addCssClassAsync(child, animation.cssClassName, animation.timeMs)
155
- }
156
- }
157
-
158
- export async function appendChildrenAsync(containerElement:Element, children:Element | Element[] | DocumentFragment | Text | string | null | undefined, animation?:Animation){
159
- //console.log('DomeManipulator: appendChildrenAsync', 'containerELement=', containerElement, 'children=', children, 'animation=', animation)
160
- if (DataTypes.isString(children)) {
161
- // no animation for text?
162
- containerElement.appendChild(document.createTextNode(children as string))
163
-
164
- } else if (DataTypes.isArray(children)) {
165
- await Promise.all(
166
- (children as Element[]).map(child => appendChildAsync(containerElement, child, animation))
167
- )
168
-
169
- } else if (children) {
170
- await appendChildAsync(containerElement, children as Element, animation)
171
-
172
- }
173
-
174
- }
175
-
176
-
177
- /**
178
- * Replacements for the same container run in call order. A rejected replacement does
179
- * not block the queue, and replacements for different containers remain independent.
180
- */
181
- export async function replaceAllChildrenAsync(
182
- containerElement: Element,
183
- childrenToInsert: Element | Element[] | DocumentFragment | Text | string | null | undefined,
184
- animationForHide?:Animation,
185
- animationForShow?:Animation
186
- ) {
187
- const previousReplacement = replacementPromiseByElement.get(containerElement)
188
- const replacement = (previousReplacement ?? Promise.resolve())
189
- .catch(() => undefined)
190
- .then(async () => {
191
- if(containerElement.childNodes.length>0){
192
- await removeAllChildrenAsync(containerElement, animationForHide)
193
- }
194
- await appendChildrenAsync(containerElement, childrenToInsert, animationForShow)
195
- })
196
-
197
- replacementPromiseByElement.set(containerElement, replacement)
198
-
199
- try {
200
- await replacement
201
- } finally {
202
- if(replacementPromiseByElement.get(containerElement) === replacement){
203
- replacementPromiseByElement.delete(containerElement)
204
- }
205
- }
206
- }
207
-
208
-
209
-
210
- export function isInDom(el: Element | undefined) {
211
- if (!el) return false
212
- return document.body.contains(el)
213
- }
214
-
215
- export function isOnScreen(el:Element|undefined){
216
- if(!el) return false
217
- var rect = el.getBoundingClientRect()
218
- var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight)
219
- return !(rect.bottom < 0 || rect.top - viewHeight >= 0)
220
- }
221
-
222
- export async function addCssClassAsync(element: Element, cssClassName: string, removeAfterMs?:number) {
223
- if(element.nodeType !== Node.ELEMENT_NODE) return
224
- element.classList.add(cssClassName)
225
- if(removeAfterMs && removeAfterMs>0){
226
- await Async.waitMsAsync(removeAfterMs)
227
- element.classList.remove(cssClassName)
228
- }
229
-
230
- }
231
-
232
- export async function addCssClassesAsync(element: Element, cssClassNames: string[], removeAfterMs?:number) {
233
- await Promise.all(cssClassNames.map(cssClassName => addCssClassAsync(element, cssClassName, removeAfterMs)))
234
- }
235
-
236
- export function removeCssClass(element: Element, cssClassName: string) {
237
- element.classList.remove(cssClassName)
238
- }
239
-
240
- export function removeCssClasses(element: Element, cssClassNames: string[]) {
241
- for (let cssClassName of cssClassNames) {
242
- element.classList.remove(cssClassName)
243
- }
244
-
245
-
246
- }
247
-
248
-
249
- /**
250
- * set css classes by array ['class1', 'class2'] or
251
- * by object {class1:true, class2:false} or
252
- * by Observable<boolean> {class1:true, class2:myVarO} or
253
- * by string
254
- * this function will replace class attribute so all classes that are not in params will be removed
255
- * @param value
256
- * @param element
257
- */
258
- export function setCssClasses(element: Element, value: CssClass) {
259
-
260
- if (!value) return // skip empty
261
- if (DataTypes.isArray(value)) {
262
- //console.log('setCssClasses', 'data is array', value)
263
- setAttribute(element, 'class', (value as string[]).join(' '))
264
-
265
- } else if (DataTypes.isObjectWithKeys(value)) {
266
- //console.log('setCssClasses', 'data is object with keys', value)
267
- let classNameArray: Array<string> = []
268
- for (let [k, v] of Object.entries(value)) {
269
- if (checkIfObservable(v)) {
270
- if ((v as ObservableVariable<boolean>).get()) {
271
- classNameArray.push(k)
272
- }
273
- } else if (v) {
274
- classNameArray.push(k)
275
- }
276
- }
277
- setAttribute(element, 'class', classNameArray.join(' '))
278
-
279
- } else {
280
- //console.log('setCssClasses', 'data is unknown', value)
281
- setAttribute(element, 'class', value)
282
-
283
- }
284
-
285
- }
286
-
287
- export function setAttribute(element: Element, name: string, value: any) {
288
- if (value === undefined || value === null) {
289
- return
290
- }
291
-
292
- // Naive support for xlink namespace
293
- // Full list: https://github.com/facebook/react/blob/1843f87/src/renderers/dom/shared/SVGDOMPropertyConfig.js#L258-L264
294
- if (/^xlink[AHRST]/.test(name)) {
295
- element.setAttributeNS('http://www.w3.org/1999/xlink', name.replace('xlink', 'xlink:').toLowerCase(), value)
296
- } else {
297
- element.setAttribute(name, value)
298
- }
299
- }
300
-
301
- export function hasFocus(el: Element):boolean {
302
- return document.activeElement == el
303
- }
304
-
305
- export function scrollIntoView(element: Element, paddingFromTop:number = 100) {
306
- if(isOnScreen(element)) {
307
- return // no need to scroll
308
- }
309
- //const positionBefore = getCurrentScrollPosition()
310
- //element.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
311
- //const positionAfter = getCurrentScrollPosition()
312
- //console.log('before=', positionBefore, 'after=', positionAfter)
313
- let expectedPosition = element.getBoundingClientRect().top + window.pageYOffset;
314
- expectedPosition -= paddingFromTop
315
- window.scrollTo({top: expectedPosition, behavior: 'smooth'});
316
-
317
-
318
-
319
- }
320
-
321
- // https://stackoverflow.com/questions/15935318/smooth-scroll-to-top/55926067
322
- export const scrollToTop = () => {
323
- //console.log('scrollToTop')
324
- let position = getCurrentScrollPosition()
325
-
326
- if (position > 0) {
327
- window.requestAnimationFrame(scrollToTop);
328
- if (position < 20) {
329
- window.scrollTo(0, 0)
330
- } else {
331
- window.scrollTo(0, position - position / 9)
332
- }
333
- }
334
- }
335
-
336
- export function getCurrentScrollPosition(){
337
- return document.documentElement.scrollTop || document.body.scrollTop;
338
- }
339
-
340
- export async function scrollToAsync(p:{
341
- pxFromTop?:number,
342
- pxFromLeft?:number,
343
- smooth?:boolean,
344
- msStep?:number,
345
- maxMsToWait?:number
346
- }){
347
- //console.log('scrollToAsync', p)
348
- const msStep = p.msStep ?? 50
349
- const maxMsToWait = p.maxMsToWait ?? 5000
350
-
351
- let scrollOptions:ScrollToOptions = {
352
- }
353
-
354
- if(p.pxFromTop){
355
- scrollOptions.top = p.pxFromTop
356
- }
357
- if(p.pxFromLeft){
358
- scrollOptions.left = p.pxFromLeft
359
- }
360
- if(p.smooth){
361
- scrollOptions.behavior = 'smooth'
362
- }
363
-
364
-
365
- try {
366
- if(p.pxFromLeft || p.pxFromTop){
367
- await Async.waitForFunctionToReturnTrueAsync(() => {
368
- if(p.pxFromTop){
369
- return document.body.scrollHeight >= p.pxFromTop
370
- }
371
- if(p.pxFromLeft){
372
- return document.body.scrollWidth >= p.pxFromLeft
373
- }
374
- return false
375
- }, msStep, maxMsToWait)
376
- }
377
-
378
- } catch(error){
379
- // ignore error
380
-
381
- }
382
- //console.log('scrollToY', pxFromTop, 'height=', document.body.clientHeight)
383
- //console.log('scrollToAsync now', scrollOptions)
384
- window.scrollTo(scrollOptions)
385
- }
386
-
387
-
388
-
389
-
390
-
391
- }
@@ -1,52 +0,0 @@
1
-
2
- // //import { DomeRouter } from "./DomeRouter"
3
- // function getRouteSlices(route:string){
4
- // return route.split('/').filter(x => x.length>0)
5
- // }
6
-
7
- // function checkUrlMatchRouteAndGetParameters(url:string, route:string, exactMatch:boolean = true):Map<string,string>|undefined{
8
- // // this function is purely for export
9
-
10
- // const urlSlices = getRouteSlices(url)
11
- // const routeSlices = getRouteSlices(route)
12
- // if(exactMatch && routeSlices.length !== urlSlices.length) return undefined
13
- // // all routeSlices must match for !exactMatch
14
- // const extractedParameters = new Map<string,string>()
15
- // for(let i=0;i<routeSlices.length;i++){
16
- // let cRouteSlice = routeSlices[i]
17
- // let cUrlSlice = urlSlices[i] // could be undefined
18
- // //console.info('\t\t cRouteSlice=', cRouteSlice, 'cUrlSlice=', cUrlSlice)
19
-
20
- // if(cRouteSlice.startsWith(':')){
21
- // // we have a param name
22
- // if(cUrlSlice === undefined){
23
- // return undefined
24
- // }
25
- // // we have some variable, save it
26
- // extractedParameters.set(cRouteSlice.substring(1), cUrlSlice)
27
-
28
- // } else {
29
- // // no param name
30
- // if(cRouteSlice !== cUrlSlice){
31
- // return undefined
32
- // }
33
- // }
34
- // }
35
- // return extractedParameters
36
- // }
37
-
38
-
39
- // DomeRouter.onRoute('/', true, ()=>{ console.log('exact /')})
40
- // DomeRouter.onRoute('/', false, ()=>{ console.log('notexact /')})
41
- // DomeRouter.onRoute('/test', true, ()=>{ console.log('exact /test')})
42
- // DomeRouter.onRoute('/test/:id', true, (p)=>{ console.log('exact /test/:id', 'params=', p)})
43
- // DomeRouter.onRoute('/test/:id', false, (p)=>{ console.log('notexact /test/:id', 'params=', p)})
44
- // DomeRouter.onRoute('/test', false, ()=>{ console.log('notexact /test')})
45
- // DomeRouter.onRoute('/test/:id/:id2', true, (p)=>{ console.log('exact /test/:id/:id2', 'params=', p)})
46
-
47
- // let testRoute = '//test/34/st'
48
- // console.log('** testing route:', testRoute)
49
- // DomeRouter.execute(testRoute)
50
- // //expect(!true).toBeTruthy()
51
-
52
- //console.log(checkUrlMatchRouteAndGetParameters('/get-product/123', '/get-product/:id/:id2', false))