@potok-web-framework/core 0.1.0 → 0.2.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.
Files changed (94) hide show
  1. package/dist/block.d.ts +17 -0
  2. package/dist/bootstrap-app.d.ts +8 -0
  3. package/dist/client-only.d.ts +3 -0
  4. package/dist/client.mjs +133 -0
  5. package/dist/constants-BOAOReQ3.mjs +26 -0
  6. package/dist/constants.d.ts +2 -0
  7. package/dist/context.d.ts +12 -0
  8. package/dist/detect-child.d.ts +6 -0
  9. package/dist/error-boundary.d.ts +5 -0
  10. package/dist/exports/client.d.ts +1 -0
  11. package/dist/exports/hmr.d.ts +1 -0
  12. package/dist/exports/index.d.ts +14 -0
  13. package/dist/exports/jsx-runtime.d.ts +4 -0
  14. package/dist/exports/server.d.ts +1 -0
  15. package/dist/fragment-BahmURhz.mjs +17 -0
  16. package/dist/fragment.d.ts +4 -0
  17. package/dist/hmr/hmr-dev.d.ts +9 -0
  18. package/dist/hmr/register-component.d.ts +2 -0
  19. package/dist/hmr/registered-component.d.ts +23 -0
  20. package/dist/hmr/registry.d.ts +12 -0
  21. package/dist/hmr/types.d.ts +4 -0
  22. package/dist/hmr/utils.d.ts +3 -0
  23. package/dist/hmr.mjs +42 -0
  24. package/dist/html-element-Cm0RtMkT.mjs +42 -0
  25. package/dist/html-element.d.ts +6 -0
  26. package/dist/index.mjs +199 -0
  27. package/dist/jsx-runtime.mjs +10 -0
  28. package/dist/jsx-types.d.ts +11 -0
  29. package/dist/lazy.d.ts +7 -0
  30. package/dist/lib-context-reader.d.ts +5 -0
  31. package/dist/lib-scripts.d.ts +2 -0
  32. package/dist/lifecycle-4vjEuXGy.mjs +57 -0
  33. package/dist/lifecycle.d.ts +8 -0
  34. package/dist/list.d.ts +9 -0
  35. package/dist/portal-CbcYOHLv.mjs +44 -0
  36. package/dist/portal.d.ts +10 -0
  37. package/dist/prop-types.d.ts +939 -0
  38. package/dist/ref.d.ts +6 -0
  39. package/dist/render-to-dom.d.ts +8 -0
  40. package/dist/render-to-string.d.ts +2 -0
  41. package/dist/server-node.d.ts +10 -0
  42. package/dist/server.mjs +1192 -0
  43. package/dist/show.d.ts +6 -0
  44. package/dist/signals.d.ts +32 -0
  45. package/dist/store.d.ts +26 -0
  46. package/dist/text.d.ts +5 -0
  47. package/dist/types.d.ts +39 -0
  48. package/dist/utils-CAe_kbSH.mjs +345 -0
  49. package/dist/utils.d.ts +11 -0
  50. package/package.json +7 -2
  51. package/CHANGELOG.md +0 -7
  52. package/bun.lock +0 -25
  53. package/src/block.ts +0 -102
  54. package/src/bootstrap-app.ts +0 -115
  55. package/src/client-only.ts +0 -17
  56. package/src/constants.ts +0 -27
  57. package/src/context.ts +0 -85
  58. package/src/detect-child.ts +0 -21
  59. package/src/error-boundary.ts +0 -51
  60. package/src/exports/client.ts +0 -1
  61. package/src/exports/hmr.ts +0 -1
  62. package/src/exports/index.ts +0 -21
  63. package/src/exports/jsx-runtime.ts +0 -4
  64. package/src/exports/server.ts +0 -1
  65. package/src/fragment.ts +0 -28
  66. package/src/global.dev.d.ts +0 -12
  67. package/src/hmr/hmr-dev.ts +0 -10
  68. package/src/hmr/register-component.ts +0 -109
  69. package/src/hmr/registered-component.ts +0 -59
  70. package/src/hmr/registry.ts +0 -78
  71. package/src/hmr/types.ts +0 -6
  72. package/src/hmr/utils.ts +0 -20
  73. package/src/html-element.ts +0 -95
  74. package/src/jsx-types.ts +0 -13
  75. package/src/lazy.ts +0 -44
  76. package/src/lib-context-reader.ts +0 -33
  77. package/src/lib-scripts.ts +0 -8
  78. package/src/lifecycle.ts +0 -44
  79. package/src/list.ts +0 -175
  80. package/src/portal.ts +0 -101
  81. package/src/prop-types.ts +0 -1165
  82. package/src/ref.ts +0 -11
  83. package/src/render-to-dom.ts +0 -325
  84. package/src/render-to-string.ts +0 -65
  85. package/src/server-node.ts +0 -98
  86. package/src/show.ts +0 -46
  87. package/src/signals.ts +0 -323
  88. package/src/store.ts +0 -68
  89. package/src/text.ts +0 -35
  90. package/src/types.ts +0 -69
  91. package/src/utils.ts +0 -118
  92. package/tests/signals.test.ts +0 -403
  93. package/tsconfig.json +0 -17
  94. package/vite.config.ts +0 -21
package/src/ref.ts DELETED
@@ -1,11 +0,0 @@
1
- import { createSignal } from './signals'
2
-
3
- export type LibHTMLElementReference<Element extends HTMLElement> = {
4
- element: Element | null
5
- }
6
-
7
- export function createElementReference<Element extends HTMLElement>() {
8
- return createSignal({
9
- element: null as Element | null,
10
- })
11
- }
@@ -1,325 +0,0 @@
1
- import { HTML_ELEMENT_STYLE_PX_PROPERTIES } from './constants'
2
- import type { LibHTMLElementEventMap } from './prop-types'
3
- import { createEffect, createSignal, deepTrack, untrack } from './signals'
4
- import type { LibContext, LibNode, PotokElement, WithChildren } from './types'
5
- import { objectKeys } from './utils'
6
-
7
- type RenderToDOMOptions = {
8
- app: () => PotokElement
9
- needToHydrate?: boolean
10
- root?: Element
11
- }
12
-
13
- export function renderToDOM(options: RenderToDOMOptions) {
14
- const rootNode = options.root ?? document
15
- const libNodeToDOMNodeMap = new Map<LibNode, Node>()
16
-
17
- const signal = createSignal({
18
- portals: {} as Record<string, WithChildren<{}>['children']>,
19
- listeners: {} as LibContext['listeners'],
20
- isHydrating: options.needToHydrate ?? false,
21
- })
22
-
23
- function addDocumentListener(eventType: keyof LibHTMLElementEventMap) {
24
- const normalizedEventType = eventType.replace(/^on([A-Z])/, (_, letter) =>
25
- letter.toLowerCase(),
26
- ) as keyof DocumentEventMap
27
-
28
- document.addEventListener(normalizedEventType, (event) => {
29
- let isBubbleCancelled = false
30
- let node = event.target as HTMLElement | null
31
-
32
- let originalStopPropagation = event.stopPropagation.bind(event)
33
- let originalStopImmediatePropagation =
34
- event.stopImmediatePropagation.bind(event)
35
-
36
- event.stopPropagation = () => {
37
- isBubbleCancelled = true
38
- originalStopPropagation()
39
- }
40
-
41
- event.stopImmediatePropagation = () => {
42
- isBubbleCancelled = true
43
- originalStopImmediatePropagation()
44
- }
45
-
46
- while (node) {
47
- const eventListeningNodes = signal.listeners[eventType]
48
-
49
- const handler = eventListeningNodes?.get(node)
50
-
51
- if (handler) {
52
- Object.defineProperty(event, 'currentTarget', {
53
- configurable: true,
54
- enumerable: true,
55
- get: () => node,
56
- })
57
-
58
- handler(event as any)
59
-
60
- if (isBubbleCancelled) {
61
- break
62
- }
63
- }
64
-
65
- node = node.parentElement
66
- }
67
- })
68
- }
69
-
70
- const listenedEventTypes = new Set<keyof LibHTMLElementEventMap>()
71
-
72
- createEffect(() => {
73
- deepTrack(signal.listeners, 1)
74
-
75
- untrack(() => {
76
- objectKeys(signal.listeners).forEach((eventType) => {
77
- if (listenedEventTypes.has(eventType)) {
78
- return
79
- }
80
-
81
- addDocumentListener(eventType)
82
-
83
- listenedEventTypes.add(eventType)
84
- })
85
- })
86
- }, true)
87
-
88
- const insertDomNode = (
89
- parentDomNode: Node,
90
- domNode: Node,
91
- afterDomNode: Node | null,
92
- ) =>
93
- parentDomNode.insertBefore(
94
- domNode,
95
- afterDomNode ? afterDomNode.nextSibling : parentDomNode.firstChild,
96
- )
97
-
98
- const isHTMLElementNode = (node: Node): node is HTMLElement =>
99
- node instanceof HTMLElement
100
-
101
- if (!options.needToHydrate) {
102
- while (rootNode.firstChild) {
103
- rootNode.removeChild(rootNode.firstChild)
104
- }
105
- }
106
-
107
- options.app()({
108
- parentBlock: null,
109
- index: 0,
110
- portals: signal.portals,
111
- contexts: {},
112
- listeners: signal.listeners,
113
- isServer: false,
114
- promises: [],
115
- get isHydrating() {
116
- return signal.isHydrating
117
- },
118
- insertNode(parent, node, after) {
119
- if (signal.isHydrating) {
120
- if (parent === null) {
121
- libNodeToDOMNodeMap.set(node, document.querySelector('html')!)
122
- } else {
123
- const parentNode = libNodeToDOMNodeMap.get(parent)
124
-
125
- if (!parentNode) {
126
- throw new Error('Ошибка гидрации')
127
- }
128
-
129
- let childNode: Node | null = null
130
-
131
- if (after) {
132
- const node = libNodeToDOMNodeMap.get(after)
133
-
134
- if (!node) {
135
- throw new Error('Ошибка гидрации')
136
- }
137
-
138
- childNode = node.nextSibling
139
- } else {
140
- childNode = parentNode.firstChild
141
- }
142
-
143
- while (true) {
144
- if (!childNode) {
145
- throw new Error('Ошибка гидрации')
146
- }
147
-
148
- if (
149
- (node.type === 'text' &&
150
- String(node.props.text) === childNode.textContent) ||
151
- (node.type === 'html-element' &&
152
- isHTMLElementNode(childNode) &&
153
- node.props.tag === childNode.tagName.toLowerCase())
154
- ) {
155
- libNodeToDOMNodeMap.set(node, childNode)
156
-
157
- break
158
- } else {
159
- const oldChildNode = childNode
160
- childNode = childNode.nextSibling
161
- oldChildNode.parentElement?.removeChild(oldChildNode)
162
- }
163
- }
164
- }
165
-
166
- return
167
- }
168
-
169
- if (parent && !libNodeToDOMNodeMap.has(parent)) {
170
- libNodeToDOMNodeMap.set(
171
- parent,
172
- document.createElement(parent.props.tag),
173
- )
174
- }
175
-
176
- const parentDomNode = parent ? libNodeToDOMNodeMap.get(parent)! : rootNode
177
-
178
- const afterDomNode = (after && libNodeToDOMNodeMap.get(after)) ?? null
179
-
180
- if (node.type === 'text') {
181
- const domNode = document.createTextNode(String(node.props.text))
182
- libNodeToDOMNodeMap.set(node, domNode)
183
-
184
- this.updateTextNode(node)
185
-
186
- insertDomNode(parentDomNode, domNode, afterDomNode)
187
- } else if (node.type === 'html-element') {
188
- if (!libNodeToDOMNodeMap.has(node)) {
189
- libNodeToDOMNodeMap.set(node, document.createElement(node.props.tag))
190
- }
191
-
192
- for (const [key, descriptor] of Object.entries(
193
- Object.getOwnPropertyDescriptors(node.props),
194
- )) {
195
- if (['tag', 'children', 'ref'].includes(key)) {
196
- continue
197
- }
198
-
199
- let value = descriptor.get?.() ?? descriptor.value
200
- this.updateHtmlElementNodeProp(node, key, value)
201
- }
202
-
203
- const domNode = libNodeToDOMNodeMap.get(node)! as HTMLElement
204
-
205
- insertDomNode(parentDomNode, domNode, afterDomNode)
206
-
207
- if (node.props.ref) {
208
- node.props.ref.element = domNode
209
- }
210
- } else {
211
- let _: never = node
212
- throw new Error('Неверный тип ноды')
213
- }
214
- },
215
- updateTextNode(node) {
216
- const value = node.props.text
217
- const domNode = libNodeToDOMNodeMap.get(node)
218
-
219
- if (!domNode) {
220
- return
221
- }
222
-
223
- domNode.textContent = String(value)
224
- },
225
- updateHtmlElementNodeProp(node, key, value) {
226
- const domNode = libNodeToDOMNodeMap.get(node)
227
-
228
- if (!domNode) {
229
- return
230
- }
231
-
232
- const element = domNode as HTMLElement
233
-
234
- const isEventTypeKey = (
235
- key: string,
236
- ): key is keyof LibHTMLElementEventMap => key.startsWith('on')
237
-
238
- if (isEventTypeKey(key)) {
239
- if (value) {
240
- this.listeners[key] ??= new Map()
241
-
242
- this.listeners[key].set(
243
- element,
244
- value as LibHTMLElementEventMap[keyof LibHTMLElementEventMap],
245
- )
246
- } else {
247
- this.listeners[key]?.delete(element)
248
- }
249
-
250
- return
251
- }
252
-
253
- if (key.startsWith('aria')) {
254
- const name = key.toLowerCase().replace('aria', 'aria-')
255
-
256
- if (value) {
257
- element.setAttribute(name, value as string)
258
- } else {
259
- element.removeAttribute(name)
260
- }
261
-
262
- return
263
- }
264
-
265
- if (key === 'className') {
266
- if (value) {
267
- element.className = value as string
268
- } else {
269
- element.removeAttribute('class')
270
- }
271
-
272
- return
273
- }
274
-
275
- if (key === 'style') {
276
- if (value) {
277
- Object.keys(value).forEach((key) => {
278
- const keyValue = value[key as keyof typeof value]
279
- if (keyValue !== undefined) {
280
- const normalizedValue = String(
281
- HTML_ELEMENT_STYLE_PX_PROPERTIES.has(key) &&
282
- typeof keyValue === 'number'
283
- ? `${keyValue}px`
284
- : keyValue,
285
- )
286
-
287
- element.style.setProperty(key, normalizedValue)
288
- } else {
289
- element.style.removeProperty(key)
290
- }
291
- })
292
- } else {
293
- element.removeAttribute('style')
294
- }
295
-
296
- return
297
- }
298
-
299
- if (value !== undefined && value !== null) {
300
- element.setAttribute(key, String(value))
301
- } else {
302
- element.removeAttribute(key)
303
- }
304
- },
305
- removeNode(node) {
306
- const domNode = libNodeToDOMNodeMap.get(node)
307
-
308
- if (!domNode) {
309
- return
310
- }
311
-
312
- libNodeToDOMNodeMap.delete(node)
313
-
314
- if (isHTMLElementNode(domNode)) {
315
- domNode.remove()
316
- } else {
317
- domNode.parentElement?.removeChild(domNode)
318
- }
319
- },
320
- })
321
-
322
- if (options.needToHydrate) {
323
- signal.isHydrating = false
324
- }
325
- }
@@ -1,65 +0,0 @@
1
- import { ServerNode } from './server-node'
2
- import { createSignal } from './signals'
3
- import type { LibNode, LibContext, PotokElement } from './types'
4
-
5
- export async function renderToString(creator: PotokElement) {
6
- const signal = createSignal({
7
- portals: {} as Record<string, PotokElement[]>,
8
- listeners: {} as LibContext['listeners'],
9
- })
10
-
11
- let libNodeToServerNodeMap = new Map<LibNode, ServerNode>()
12
- let rootNode: ServerNode | undefined
13
-
14
- let promises: Promise<void>[] = []
15
-
16
- creator({
17
- parentBlock: null,
18
- index: 0,
19
- portals: signal.portals,
20
- contexts: {},
21
- listeners: signal.listeners,
22
- isServer: true,
23
- promises,
24
- isHydrating: false,
25
- insertNode(parent, libNode, after) {
26
- if (parent && !libNodeToServerNodeMap.has(parent)) {
27
- libNodeToServerNodeMap.set(parent, new ServerNode(parent))
28
- }
29
-
30
- if (!libNodeToServerNodeMap.has(libNode)) {
31
- libNodeToServerNodeMap.set(libNode, new ServerNode(libNode))
32
- }
33
-
34
- const serverNode = libNodeToServerNodeMap.get(libNode)!
35
-
36
- libNodeToServerNodeMap.set(libNode, serverNode)
37
-
38
- if (parent === null) {
39
- rootNode = serverNode
40
- } else {
41
- const afterServerNode =
42
- after && libNodeToServerNodeMap.has(after)
43
- ? libNodeToServerNodeMap.get(after)!
44
- : null
45
-
46
- libNodeToServerNodeMap
47
- .get(parent)
48
- ?.addChild(serverNode, afterServerNode)
49
- }
50
- },
51
- updateTextNode() {},
52
- updateHtmlElementNodeProp() {},
53
- removeNode(node) {
54
- libNodeToServerNodeMap.get(node)?.remove()
55
- },
56
- })
57
-
58
- await Promise.all(promises)
59
-
60
- if (!rootNode) {
61
- throw new Error('Корневая нода не найдена')
62
- }
63
-
64
- return rootNode.stringify()
65
- }
@@ -1,98 +0,0 @@
1
- import type { LibNode } from './types'
2
-
3
- export class ServerNode {
4
- libNode: LibNode
5
- parent: ServerNode | null = null
6
- children: ServerNode[] = []
7
-
8
- constructor(libNode: LibNode) {
9
- this.libNode = libNode
10
- }
11
-
12
- addChild(node: ServerNode, after: ServerNode | null) {
13
- if (after) {
14
- const afterIndex = this.children.indexOf(after)
15
- this.children.splice(afterIndex + 1, 0, node)
16
- } else {
17
- this.children.push(node)
18
- }
19
-
20
- node.parent = this
21
- }
22
-
23
- remove() {
24
- if (this.parent) {
25
- this.parent.children.splice(this.parent.children.indexOf(this), 1)
26
- }
27
- }
28
-
29
- stringify(): string {
30
- if (this.libNode.type === 'text') {
31
- const parentTagName =
32
- this.libNode.context.parentBlock?.nearestParentElement?.props.tag
33
- if (parentTagName && ['title', 'script'].includes(parentTagName)) {
34
- return String(this.libNode.props.text)
35
- }
36
-
37
- return `<!-- -->${this.libNode.props.text}`
38
- } else if (this.libNode.type === 'html-element') {
39
- let result = `<${this.libNode.props.tag}`
40
-
41
- for (const [key, descriptor] of Object.entries(
42
- Object.getOwnPropertyDescriptors(this.libNode.props)
43
- )) {
44
- if (['tag', 'children', 'ref'].includes(key)) {
45
- continue
46
- }
47
-
48
- if (key.startsWith('on')) {
49
- continue
50
- }
51
-
52
- let value = descriptor.get?.() ?? descriptor.value
53
-
54
- if (!value) {
55
- continue
56
- }
57
-
58
- if (key === 'style') {
59
- let styleStr = ''
60
- Object.entries(value as CSSStyleDeclaration).forEach(
61
- ([key, value]) => {
62
- styleStr += `${key
63
- .replace(/([A-Z])/g, '-$1')
64
- .toLowerCase()}:${value};`
65
- }
66
- )
67
-
68
- result += ` style="${styleStr}"`
69
- continue
70
- }
71
-
72
- if (key.startsWith('aria')) {
73
- result += ` ${key.toLowerCase().replace('aria', 'aria-')}="${value}"`
74
- continue
75
- }
76
-
77
- if (key === 'className') {
78
- result += ` class="${value}"`
79
- continue
80
- }
81
-
82
- result += ` ${key}="${value}"`
83
- }
84
-
85
- result += '>'
86
-
87
- this.children.forEach((child) => {
88
- result += child.stringify()
89
- })
90
-
91
- result += `</${this.libNode.props.tag}>`
92
-
93
- return result
94
- }
95
-
96
- throw new Error('Not implemented')
97
- }
98
- }
package/src/show.ts DELETED
@@ -1,46 +0,0 @@
1
- import { LibBlock } from './block'
2
- import { createEffect, untrack } from './signals'
3
- import type { LibContext, PotokElement, WithChildren } from './types'
4
- import { mergeContext, normalizeChildren } from './utils'
5
-
6
- type ShowProps = WithChildren<{
7
- when: boolean
8
- }>
9
-
10
- class ShowClass<Props extends ShowProps> extends LibBlock {
11
- constructor(
12
- readonly props: Props,
13
- readonly context: LibContext,
14
- ) {
15
- super()
16
-
17
- const normalizedChildren = normalizeChildren(props.children)
18
-
19
- this.addEffect(
20
- createEffect(() => {
21
- if (props.when) {
22
- untrack(() => {
23
- normalizedChildren.forEach((childCreator, index) => {
24
- this.children.push(
25
- childCreator(
26
- mergeContext(context, {
27
- parentBlock: this,
28
- index,
29
- }),
30
- ),
31
- )
32
- })
33
- })
34
- } else {
35
- this.unmountChildren()
36
- }
37
- }, true),
38
- )
39
- }
40
- }
41
-
42
- export function Show(props: ShowProps): PotokElement {
43
- return function (context: LibContext) {
44
- return new ShowClass(props, context)
45
- }
46
- }