@codesuma/baseline 1.0.2 → 1.0.5
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 +1 -1
- package/components/advanced/page.module.css +8 -5
- package/components/advanced/page.ts +14 -1
- package/index.ts +2 -1
- package/lib/idb.ts +105 -93
- package/lib/router.ts +4 -0
- package/package.json +1 -1
- package/utils/appender.ts +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
.page {
|
|
2
|
-
position:
|
|
2
|
+
position: fixed;
|
|
3
3
|
display: flex;
|
|
4
|
-
|
|
5
|
-
justify-content: center;
|
|
4
|
+
flex-direction: column;
|
|
6
5
|
top: 0;
|
|
7
6
|
left: 0;
|
|
8
7
|
right: 0;
|
|
9
8
|
bottom: 0;
|
|
9
|
+
width: 100%;
|
|
10
|
+
height: 100%;
|
|
11
|
+
padding-left: 60px;
|
|
10
12
|
padding-top: env(safe-area-inset-top);
|
|
11
13
|
padding-bottom: env(safe-area-inset-bottom);
|
|
12
14
|
background-color: #fff;
|
|
@@ -15,6 +17,7 @@
|
|
|
15
17
|
transition: opacity 0.16s ease, transform 0.16s ease;
|
|
16
18
|
transform: translateY(60px);
|
|
17
19
|
pointer-events: none;
|
|
20
|
+
opacity: 0;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
/* Forward enter: from bottom */
|
|
@@ -47,11 +50,11 @@
|
|
|
47
50
|
|
|
48
51
|
/* Initial hidden states for stacking */
|
|
49
52
|
.page.hiddenBelow {
|
|
50
|
-
transform: translateY(
|
|
53
|
+
transform: translateY(60px);
|
|
51
54
|
opacity: 0;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
.page.hiddenAbove {
|
|
55
|
-
transform: translateY(60px);
|
|
58
|
+
transform: translateY(-60px);
|
|
56
59
|
opacity: 0;
|
|
57
60
|
}
|
|
@@ -10,10 +10,20 @@ const TRANSITION_DURATION = 160
|
|
|
10
10
|
export const Page = () => {
|
|
11
11
|
const base = Div()
|
|
12
12
|
base.addClass(styles.page) // Initial state is hidden below (in CSS)
|
|
13
|
+
base.el.setAttribute('aria-hidden', 'true')
|
|
13
14
|
|
|
14
15
|
// Enter: direction based on isBack flag
|
|
15
16
|
base.on('enter', async ({ isBack }: IRouteEvent) => {
|
|
16
|
-
|
|
17
|
+
// Pre-position correctly before entering to ensure correct transition direction
|
|
18
|
+
if (isBack) {
|
|
19
|
+
base.addClass(styles.hiddenAbove)
|
|
20
|
+
base.removeClass(styles.hiddenBelow)
|
|
21
|
+
} else {
|
|
22
|
+
base.addClass(styles.hiddenBelow)
|
|
23
|
+
base.removeClass(styles.hiddenAbove)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
await waitFor(200)
|
|
17
27
|
// Clear all state classes
|
|
18
28
|
base.removeClass(
|
|
19
29
|
styles.exitUp,
|
|
@@ -23,6 +33,7 @@ export const Page = () => {
|
|
|
23
33
|
)
|
|
24
34
|
// Add enter class (same visual result, but positioned correctly before)
|
|
25
35
|
base.addClass(isBack ? styles.enterDown : styles.enterUp)
|
|
36
|
+
base.el.setAttribute('aria-hidden', 'false')
|
|
26
37
|
})
|
|
27
38
|
|
|
28
39
|
// Exit: direction based on isBack flag
|
|
@@ -37,6 +48,8 @@ export const Page = () => {
|
|
|
37
48
|
}
|
|
38
49
|
await waitFor(TRANSITION_DURATION)
|
|
39
50
|
|
|
51
|
+
base.el.setAttribute('aria-hidden', 'true')
|
|
52
|
+
|
|
40
53
|
// Position for next enter
|
|
41
54
|
if (isBack) {
|
|
42
55
|
// After exiting down, position below for next forward enter
|
package/index.ts
CHANGED
|
@@ -25,7 +25,7 @@ export { Page } from './components/advanced/page'
|
|
|
25
25
|
export { default as router, IRouteEvent } from './lib/router'
|
|
26
26
|
export { default as http } from './lib/http'
|
|
27
27
|
export { default as ldb } from './lib/ldb'
|
|
28
|
-
export { default as
|
|
28
|
+
export { default as idb } from './lib/idb'
|
|
29
29
|
export { default as state } from './lib/state'
|
|
30
30
|
|
|
31
31
|
// Utilities
|
|
@@ -33,3 +33,4 @@ export { createEmitter, emitter, IEmitter } from './utils/emitter'
|
|
|
33
33
|
export { createStyler, injectCSS, IStyler } from './utils/styler'
|
|
34
34
|
export { waitFor } from './utils/wait'
|
|
35
35
|
export { withRipple } from './utils/ripple'
|
|
36
|
+
export { nextId, shortUUID, uuidv4 } from './utils/id'
|
package/lib/idb.ts
CHANGED
|
@@ -36,100 +36,112 @@ const withStore = async <T>(
|
|
|
36
36
|
})
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
opts.indices!.forEach(idx => store.createIndex(idx, idx))
|
|
58
|
-
}
|
|
39
|
+
// Get database info
|
|
40
|
+
async function info(dbName: string): Promise<{ version: number; objectStoreNames: DOMStringList }> {
|
|
41
|
+
const db = await openDB(dbName)
|
|
42
|
+
const result = { version: db.version, objectStoreNames: db.objectStoreNames }
|
|
43
|
+
db.close()
|
|
44
|
+
return result
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Create or upgrade store
|
|
48
|
+
async function createStore(dbName: string, name: string, version: number, options: StoreOptions = {}) {
|
|
49
|
+
const opts = { keyPath: 'id', autoIncrement: true, indices: [], ...options }
|
|
50
|
+
return new Promise<void>((resolve, reject) => {
|
|
51
|
+
const req = indexedDB.open(dbName, version)
|
|
52
|
+
req.onupgradeneeded = (e) => {
|
|
53
|
+
const db = (e.target as IDBOpenDBRequest).result
|
|
54
|
+
if (!db.objectStoreNames.contains(name)) {
|
|
55
|
+
const store = db.createObjectStore(name, { keyPath: opts.keyPath, autoIncrement: opts.autoIncrement })
|
|
56
|
+
opts.indices!.forEach(idx => store.createIndex(idx, idx))
|
|
59
57
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
58
|
+
}
|
|
59
|
+
req.onsuccess = () => { req.result.close(); resolve() }
|
|
60
|
+
req.onerror = () => reject(req.error)
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// CRUD operations
|
|
65
|
+
async function save<T>(dbName: string, store: string, data: T | T[]): Promise<T | T[]> {
|
|
66
|
+
const items = Array.isArray(data) ? data : [data]
|
|
67
|
+
await withStore(dbName, store, 'readwrite', (s) => {
|
|
68
|
+
items.forEach(item => s.add(item))
|
|
69
|
+
})
|
|
70
|
+
return data
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function get<T>(dbName: string, store: string, id: any): Promise<T | undefined> {
|
|
74
|
+
return withStore(dbName, store, 'readonly', s => s.get(id))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function all<T>(dbName: string, store: string): Promise<T[]> {
|
|
78
|
+
return withStore(dbName, store, 'readonly', s => s.getAll())
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function update<T>(dbName: string, store: string, data: T): Promise<T> {
|
|
82
|
+
await withStore(dbName, store, 'readwrite', s => s.put(data))
|
|
83
|
+
return data
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function del(dbName: string, store: string, id: any): Promise<void> {
|
|
87
|
+
await withStore(dbName, store, 'readwrite', s => s.delete(id))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function clear(dbName: string, store: string): Promise<void> {
|
|
91
|
+
await withStore(dbName, store, 'readwrite', s => s.clear())
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function count(dbName: string, store: string): Promise<number> {
|
|
95
|
+
return withStore(dbName, store, 'readonly', s => s.count())
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Query with options
|
|
99
|
+
async function find<T>(dbName: string, store: string, options: {
|
|
100
|
+
index?: string
|
|
101
|
+
value?: any
|
|
102
|
+
limit?: number
|
|
103
|
+
reverse?: boolean
|
|
104
|
+
} = {}): Promise<T[]> {
|
|
105
|
+
const { index, value, limit = 1000, reverse = false } = options
|
|
106
|
+
const db = await openDB(dbName)
|
|
107
|
+
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
if (!db.objectStoreNames.contains(store)) {
|
|
110
|
+
db.close()
|
|
111
|
+
return resolve([])
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const tx = db.transaction(store, 'readonly')
|
|
115
|
+
const s = tx.objectStore(store)
|
|
116
|
+
const source = index ? s.index(index) : s
|
|
117
|
+
const range = value !== undefined ? IDBKeyRange.only(value) : undefined
|
|
118
|
+
const req = source.openCursor(range, reverse ? 'prev' : 'next')
|
|
119
|
+
|
|
120
|
+
const results: T[] = []
|
|
121
|
+
req.onsuccess = () => {
|
|
122
|
+
const cursor = req.result
|
|
123
|
+
if (cursor && results.length < limit) {
|
|
124
|
+
results.push(cursor.value)
|
|
125
|
+
cursor.continue()
|
|
126
|
+
} else {
|
|
111
127
|
db.close()
|
|
112
|
-
|
|
128
|
+
resolve(results)
|
|
113
129
|
}
|
|
130
|
+
}
|
|
131
|
+
tx.onerror = () => { db.close(); reject(tx.error) }
|
|
132
|
+
})
|
|
133
|
+
}
|
|
114
134
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
db.close()
|
|
129
|
-
resolve(results)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
tx.onerror = () => { db.close(); reject(tx.error) }
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
})
|
|
135
|
+
|
|
136
|
+
export default {
|
|
137
|
+
info,
|
|
138
|
+
createStore,
|
|
139
|
+
save,
|
|
140
|
+
get,
|
|
141
|
+
all,
|
|
142
|
+
update,
|
|
143
|
+
delete: del,
|
|
144
|
+
clear,
|
|
145
|
+
count,
|
|
146
|
+
find
|
|
147
|
+
}
|
package/lib/router.ts
CHANGED
|
@@ -11,6 +11,7 @@ export interface IRouteEvent {
|
|
|
11
11
|
from: string
|
|
12
12
|
data?: any
|
|
13
13
|
isBack?: boolean // True if navigating via back button
|
|
14
|
+
to?: string
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
interface RouteConfig {
|
|
@@ -82,6 +83,7 @@ const navigate = async (to: string, data?: any) => {
|
|
|
82
83
|
params: {},
|
|
83
84
|
query: getQuery(),
|
|
84
85
|
from: currentPath,
|
|
86
|
+
to: path,
|
|
85
87
|
data,
|
|
86
88
|
isBack
|
|
87
89
|
})
|
|
@@ -112,6 +114,7 @@ const navigate = async (to: string, data?: any) => {
|
|
|
112
114
|
params: match.params,
|
|
113
115
|
query: getQuery(),
|
|
114
116
|
from,
|
|
117
|
+
to: path,
|
|
115
118
|
data,
|
|
116
119
|
isBack
|
|
117
120
|
})
|
|
@@ -121,6 +124,7 @@ const navigate = async (to: string, data?: any) => {
|
|
|
121
124
|
params: match.params,
|
|
122
125
|
query: getQuery(),
|
|
123
126
|
from,
|
|
127
|
+
to: path,
|
|
124
128
|
data,
|
|
125
129
|
isBack
|
|
126
130
|
})
|
package/package.json
CHANGED
package/utils/appender.ts
CHANGED
|
@@ -118,10 +118,10 @@ export function createAppender(base: AnyComponent): IAppender {
|
|
|
118
118
|
if (base.parent) {
|
|
119
119
|
base.parent.setChildren(base.parent.getChildren().filter(c => c !== base))
|
|
120
120
|
}
|
|
121
|
+
base.emit('unmounted')
|
|
121
122
|
base.removeAllListeners()
|
|
122
123
|
pendingRoots.delete(base)
|
|
123
124
|
base.el.remove()
|
|
124
|
-
base.emit('unmounted')
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
}
|