@codesuma/baseline 1.0.3 → 1.0.6

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,12 +1,14 @@
1
1
  .page {
2
- position: absolute;
2
+ position: fixed;
3
3
  display: flex;
4
- align-items: center;
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(-60px);
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
- await waitFor(10)
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 createDB } from './lib/idb'
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,133 @@ const withStore = async <T>(
36
36
  })
37
37
  }
38
38
 
39
- export default (dbName: string) => ({
40
- // Get database info
41
- async info(): Promise<{ version: number; objectStoreNames: DOMStringList }> {
42
- const db = await openDB(dbName)
43
- const result = { version: db.version, objectStoreNames: db.objectStoreNames }
44
- db.close()
45
- return result
46
- },
47
-
48
- // Create or upgrade store
49
- async createStore(name: string, version: number, options: StoreOptions = {}) {
50
- const opts = { keyPath: 'id', autoIncrement: true, indices: [], ...options }
51
- return new Promise<void>((resolve, reject) => {
52
- const req = indexedDB.open(dbName, version)
53
- req.onupgradeneeded = (e) => {
54
- const db = (e.target as IDBOpenDBRequest).result
55
- if (!db.objectStoreNames.contains(name)) {
56
- const store = db.createObjectStore(name, { keyPath: opts.keyPath, autoIncrement: opts.autoIncrement })
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
- req.onsuccess = () => { req.result.close(); resolve() }
61
- req.onerror = () => reject(req.error)
62
- })
63
- },
64
-
65
- // CRUD operations
66
- async save<T>(store: string, data: T | T[]): Promise<T | T[]> {
67
- const items = Array.isArray(data) ? data : [data]
68
- await withStore(dbName, store, 'readwrite', (s) => {
69
- items.forEach(item => s.add(item))
70
- })
71
- return data
72
- },
73
-
74
- async get<T>(store: string, id: any): Promise<T | undefined> {
75
- return withStore(dbName, store, 'readonly', s => s.get(id))
76
- },
77
-
78
- async all<T>(store: string): Promise<T[]> {
79
- return withStore(dbName, store, 'readonly', s => s.getAll())
80
- },
81
-
82
- async update<T>(store: string, data: T): Promise<T> {
83
- await withStore(dbName, store, 'readwrite', s => s.put(data))
84
- return data
85
- },
86
-
87
- async delete(store: string, id: any): Promise<void> {
88
- await withStore(dbName, store, 'readwrite', s => s.delete(id))
89
- },
90
-
91
- async clear(store: string): Promise<void> {
92
- await withStore(dbName, store, 'readwrite', s => s.clear())
93
- },
94
-
95
- async count(store: string): Promise<number> {
96
- return withStore(dbName, store, 'readonly', s => s.count())
97
- },
98
-
99
- // Query with options
100
- async find<T>(store: string, options: {
101
- index?: string
102
- value?: any
103
- limit?: number
104
- reverse?: boolean
105
- } = {}): Promise<T[]> {
106
- const { index, value, limit = 1000, reverse = false } = options
107
- const db = await openDB(dbName)
108
-
109
- return new Promise((resolve, reject) => {
110
- if (!db.objectStoreNames.contains(store)) {
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
- return resolve([])
128
+ resolve(results)
113
129
  }
130
+ }
131
+ tx.onerror = () => { db.close(); reject(tx.error) }
132
+ })
133
+ }
114
134
 
115
- const tx = db.transaction(store, 'readonly')
116
- const s = tx.objectStore(store)
117
- const source = index ? s.index(index) : s
118
- const range = value !== undefined ? IDBKeyRange.only(value) : undefined
119
- const req = source.openCursor(range, reverse ? 'prev' : 'next')
120
-
121
- const results: T[] = []
122
- req.onsuccess = () => {
123
- const cursor = req.result
124
- if (cursor && results.length < limit) {
125
- results.push(cursor.value)
126
- cursor.continue()
127
- } else {
128
- db.close()
129
- resolve(results)
130
- }
131
- }
132
- tx.onerror = () => { db.close(); reject(tx.error) }
133
- })
135
+ // Add this factory function at the end, before export default
136
+
137
+ function createDatabase(dbName: string) {
138
+ return {
139
+ info: () => info(dbName),
140
+ createStore: (name: string, version: number, options?: StoreOptions) =>
141
+ createStore(dbName, name, version, options),
142
+ save: <T>(store: string, data: T | T[]) => save<T>(dbName, store, data),
143
+ get: <T>(store: string, id: any) => get<T>(dbName, store, id),
144
+ all: <T>(store: string) => all<T>(dbName, store),
145
+ update: <T>(store: string, data: T) => update<T>(dbName, store, data),
146
+ delete: (store: string, id: any) => del(dbName, store, id),
147
+ clear: (store: string) => clear(dbName, store),
148
+ count: (store: string) => count(dbName, store),
149
+ find: <T>(store: string, options?: Parameters<typeof find>[2]) =>
150
+ find<T>(dbName, store, options),
134
151
  }
152
+ }
153
+
154
+ // Make the export callable AND have the raw methods
155
+ const idb = Object.assign(createDatabase, {
156
+ info,
157
+ createStore,
158
+ save,
159
+ get,
160
+ all,
161
+ update,
162
+ delete: del,
163
+ clear,
164
+ count,
165
+ find
135
166
  })
167
+
168
+ export default idb
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codesuma/baseline",
3
- "version": "1.0.3",
3
+ "version": "1.0.6",
4
4
  "description": "A minimal, imperative UI framework for building fast web apps. No virtual DOM, no magic, no dependencies.",
5
5
  "main": "index.ts",
6
6
  "types": "index.ts",
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
  }