kireji 0.6.7 → 0.6.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kireji",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
4
4
  "description": "A web framework for stateful, entropy-perfect, multi-origin web applications. Currently in alpha. Expect breaking changes for version 0. Use with caution!",
5
5
  "files": [
6
6
  "src/",
@@ -28,17 +28,11 @@ declare interface IKirejiAppTabGroup
28
28
  readonly permutationSizes: bigint[]
29
29
  readonly payloadCardinality: bigint
30
30
  readonly payloadSizes: bigint[]
31
- /** *Client-only*
32
- *
33
- * The tab group's main HTML element. */
31
+ /** The tab group's main HTML element. @remarks Client-only */
34
32
  readonly container: HTMLElement
35
- /** *Client-only*
36
- *
37
- * The most recent tab model, as determined while populating the view (not when propagating the route ID). */
33
+ /** The most recent tab model, as determined while populating the view (not when propagating the route ID). @remarks Client-only */
38
34
  readonly viewedActiveTab?: IKirejiAppTabGroupTab
39
- /** *Client-only*
40
- *
41
- * The most recent preview tab model, as determined while populating the view (not when propagating the route ID). */
35
+ /** The most recent preview tab model, as determined while populating the view (not when propagating the route ID). @remarks Client-only */
42
36
  readonly viewedPreviewTab?: IKirejiAppTabGroupTab
43
37
  /** The most recent permutation route ID, used to quickly determine if the tab arrangement has changed since the last view population. */
44
38
  readonly viewedPermutationRouteID?: bigint
@@ -70,17 +64,11 @@ declare interface IKirejiAppTabGroupTab {
70
64
  }
71
65
 
72
66
  declare const tabGroup: IKirejiAppTabGroup
73
- /** The index of the tab to render.
74
- *
75
- * *Only available in `close`, `point` and `renderTabHTML` methods.* */
67
+ /** The index of the tab to render. @remarks Only in `close`, `point` and `renderTabHTML` methods. */
76
68
  declare const TAB_INDEX: number
77
- /** The host part of the given tab.
78
- *
79
- * *Only available in `renderTabHTML` method.* */
69
+ /** The host part of the given tab. @remarks Only in `renderTabHTML` method. */
80
70
  declare const TAB_PART: IPartAny
81
- /** The filename of the given tab.
82
- *
83
- * *Only available in `renderTabHTML` method.* */
71
+ /** The filename of the given tab. @remarks Only in `renderTabHTML` method. */
84
72
  declare const TAB_FILENAME: string
85
73
  declare const activeTab: IKirejiAppTabGroupTab
86
74
  declare const activePart: IPartAny
@@ -14,9 +14,7 @@ declare interface IKirejiAppSidebar
14
14
  readonly "view.html": string
15
15
  /** The part outliner currently assigned to the sidebar (resolves to a view even when the sidebar is hidden). */
16
16
  readonly "view": IPartOutliner<IKirejiAppSidebar>
17
- /** *Client Only*
18
- *
19
- * Opens any closed parent folders of and scrolls (if necessary) to the element corresponding to the currently active tab. Does nothing if the sidebar is closed or there are no tabs open. */
17
+ /** Opens any closed parent folders of and scrolls (if necessary) to the element corresponding to the currently active tab. Does nothing if the sidebar is closed or there are no tabs open. @remarks Client-only */
20
18
  readonly frameActiveTab(): void
21
19
 
22
20
  // Runtime Properties.
@@ -65,9 +65,7 @@
65
65
  "IMAGE_NAME"
66
66
  ],
67
67
  "loop-distribute": [],
68
- "loop": [
69
- "TIME"
70
- ],
68
+ "loop": [],
71
69
  "attr-point": [
72
70
  "METHOD_NAME = 'point'",
73
71
  "...ARGS"
@@ -43,7 +43,7 @@ declare interface IPart<TOwner, TSubpart>
43
43
  readonly notify(EVENT_TYPE: string): void
44
44
  /** Computes the cardinality of the part from its subparts and defines any other necessary properties. */
45
45
  readonly build(): void
46
- /** Calls loop on the part and then propagates the call leafward to all subparts. */
46
+ /** Calls `loop()` on the part and then propagates the call leafward to all subparts. */
47
47
  readonly distributeLoop(): void
48
48
  /** Returns the subparts that meet the condition provided by FILTER_FUNCTION. */
49
49
  readonly filter(FILTER_FUNCTION: (subpart: TSubpart, index: number, part: IPart<TOwner, TSubpart>) => TSubpart): TSubpart[]
@@ -53,7 +53,7 @@ declare interface IPart<TOwner, TSubpart>
53
53
  readonly includes(SUBPART: TSubpart): boolean
54
54
  readonly reduce(REDUCE_FUNCTION: (result: TResult, subpart: TSubpart, index: number, part: IPart<TOwner, TSubpart>) => TResult, INITIAL_VALUE: TResult): TResult
55
55
  /** If defined, the per-frame update method for the part. Useful for implementing game features. */
56
- readonly loop?(TIME: DOMHighResTimeStamp): void
56
+ readonly loop?(): void
57
57
  /** Performs MAP_FUNCTION on every subpart of the part and returns an array of the results. */
58
58
  readonly map(MAP_FUNCTION: (subpart: TSubpart, index: number, part: IPart<TOwner, TSubpart>) => TResult): TResult[]
59
59
  /** Converts the given model to a routeID without modifying the state of the part. */
@@ -158,9 +158,7 @@ declare interface IPart<TOwner, TSubpart>
158
158
  /** The previous route of the part, changed at the last call to distributeRouteID or collectRouteID. */
159
159
  readonly previousRouteID: bigint
160
160
  readonly Property: typeof Property
161
- /** The part's prototype part.
162
- *
163
- * *Note: The part `part.abstract.parts` does not have a prototype part.* */
161
+ /** The part's prototype part. @remarks The part `part.abstract.parts` does not have a prototype part. */
164
162
  readonly prototype?: IPartAny
165
163
  /** The current route of the part expressed as a bigint index in the virtual array of all of its routes. */
166
164
  readonly routeID: bigint
@@ -227,13 +225,9 @@ declare function base(...args): any
227
225
  declare function recurse(...args): any
228
226
  /** Sets the current ecosystem route ID and host application as the undo point (the state the back button will return to). */
229
227
  declare function setUndoPoint(): void
230
- /** The current incoming route ID argument.
231
- *
232
- * *Available within distributeRouteID, setRouteID and updateRouteID methods only.* */
228
+ /** The current incoming route ID argument. @remarks Available within distributeRouteID, setRouteID and updateRouteID methods only. */
233
229
  declare const ROUTE_ID: bigint
234
- /** The part on which an event occurred.*
235
- *
236
- * **where available as an argument passed to a part listener callback.* */
230
+ /** The part on which an event occurred. @remarks Where available as an argument passed to a part listener callback. */
237
231
  declare const SENDER: IPartAny
238
232
  /** If on the client, returns whether or not the server-rendered view has been taken over by the client-side MVC framework. */
239
233
  declare const hydrated: boolean | null
@@ -33,24 +33,16 @@ declare interface IPermutation<TOwner, TInstance, TModel, TSubject>
33
33
  readonly supersetSize: bigint
34
34
  /** The maximum number of instances that can exist at one time. */
35
35
  readonly maxInstanceCount: bigint
36
-
37
36
  /** A subindex representing which permutation of k instances is assigned. */
38
37
  readonly permutationRouteID: bigint
39
- /** *Client-only*
40
- *
41
- * The most recent permutation route ID, used to quickly determine if the instance arrangement has changed since the last view population. */
38
+ /** The most recent permutation route ID, used to quickly determine if the instance arrangement has changed since the last view population. @remarks Client-only */
42
39
  readonly viewedPermutationRouteID?: bigint
43
-
44
40
  /** A subindex representing the combined per-instance payload data for the k instances. */
45
41
  readonly payloadRouteID: bigint
46
-
47
42
  /** The distributed instance data. */
48
43
  readonly instances: TInstance[]
49
- /** *Client-only*
50
- *
51
- * The set of viewed instance objects corresponding to the current `part.viewedPermutationRouteID`. */
44
+ /** The set of viewed instance objects corresponding to the current `part.viewedPermutationRouteID`. @remarks Client-only */
52
45
  readonly viewedInstances: TInstance[]
53
-
54
46
  /** A Fenwick tree that allows performant ranking and unranking of permutation indices. */
55
47
  readonly tree: FenwickTree
56
48
  }
@@ -3,91 +3,82 @@ await Promise.all([
3
3
  worker.takeControlAsync()
4
4
  ])
5
5
 
6
- logScope(0, "Finalizing Hydration", log => {
7
- if (+_.haltHydration && !production)
8
- warn('Intentionally blocked hydration.')
9
- else {
10
-
11
- // To preview FOUC
12
- if (_.hangHydration > 0 && !production)
13
- logScope(0, `Intentionally hanging the main thread for ${_.hangHydration} milliseconds.`, log => {
14
- const start = _.now
15
- let iteration = -1, elapsedMilliseconds, remainingMilliseconds
16
- do {
17
- elapsedMilliseconds = Math.trunc(_.now - start)
18
- const newRemainingMilliseconds = _.hangHydration - elapsedMilliseconds
19
- Math.sin(iteration++)
20
- if (Math.trunc(newRemainingMilliseconds / 100) !== Math.trunc(remainingMilliseconds / 100))
21
- log("t: -" + newRemainingMilliseconds)
22
- remainingMilliseconds = newRemainingMilliseconds
23
- } while (remainingMilliseconds > 0)
24
- log(`Main thread hang finished at iteration ${iteration}.`)
25
- })
26
-
27
- log("Defining Client-Only Methods, Globals and Default Listeners")
28
- if (environment === "client") {
29
- Object.assign(globalThis, {
30
- Q(...args) {
31
- return document.querySelector(...args)
32
- },
33
- inRect(pointerEvent, boundingClientRect) {
34
- return pointerEvent.clientX >= boundingClientRect.left
35
- && pointerEvent.clientX <= boundingClientRect.right
36
- && pointerEvent.clientY >= boundingClientRect.top
37
- && pointerEvent.clientY <= boundingClientRect.bottom
38
- },
39
- setUndoPoint() {
40
- _.parts.core.addressBar.setUndoPoint()
41
- },
42
- pointer: _.parts.core.pointer,
43
- client: _.parts.core.client
44
- })
6
+ if (!production) {
45
7
 
46
- // Clean up preview operations upon going back.
47
- // TODO: fix bugs here.
48
- window.addEventListener("pageshow", pageTransitionEvent => {
49
- log("Setting Initial State")
50
- addressBar.useRoute()
51
-
52
- log("Activating Body")
53
- document.body.classList.remove("unhydrated")
8
+ // To debug FOUC.
9
+ if (+_.haltHydration) {
10
+ warn('Intentionally blocked hydration.')
11
+ return
12
+ }
54
13
 
55
- debug('remove these preview classes', document.querySelectorAll(`[class^="preview-"]`))
56
- })
14
+ // To simulate slow loading time.
15
+ if (+_.hangHydration > 0) {
16
+ warn(`Intentionally hanging the main thread for ${_.hangHydration} milliseconds.`)
17
+ const start = _.now
18
+ while (_.hangHydration - (_.now - start) > 0)
19
+ Math.sin(Math.random())
20
+ }
21
+ }
57
22
 
58
- // Prevent normal click events to ensure the pointerdown event always takes precedence.
59
- document.addEventListener("click", pointerEvent => {
60
- pointerEvent.preventDefault()
61
- pointerEvent.stopPropagation()
62
- }, { capture: true })
23
+ logScope(0, "Finalizing Hydration", log => {
63
24
 
64
- // Listen for history popstate, which is called if bfcache is not employed.
65
- globalThis.addEventListener("popstate", () => {
66
- log("Setting Initial State")
67
- addressBar.useRoute()
25
+ log("Defining Client-Only Methods, Globals and Default Listeners")
26
+ Object.assign(globalThis, {
27
+ Q(...args) {
28
+ return document.querySelector(...args)
29
+ },
30
+ inRect(pointerEvent, boundingClientRect) {
31
+ return pointerEvent.clientX >= boundingClientRect.left
32
+ && pointerEvent.clientX <= boundingClientRect.right
33
+ && pointerEvent.clientY >= boundingClientRect.top
34
+ && pointerEvent.clientY <= boundingClientRect.bottom
35
+ },
36
+ setUndoPoint() {
37
+ _.parts.core.addressBar.setUndoPoint()
38
+ },
39
+ pointer: _.parts.core.pointer,
40
+ client: _.parts.core.client
41
+ })
68
42
 
69
- log("Activating Body")
70
- document.body.classList.remove("unhydrated")
43
+ // Handle navigation. TODO: fix bugs here.
44
+ window.addEventListener("pageshow", pageTransitionEvent => {
45
+ log("Setting Initial State")
46
+ addressBar.useRoute()
71
47
 
72
- debug('remove these preview classes', document.querySelectorAll(`[class^="preview-"]`))
73
- })
74
- }
48
+ log("Activating Body")
49
+ document.body.classList.remove("unhydrated")
75
50
 
51
+ debug('remove these preview classes', document.querySelectorAll(`[class^="preview-"]`))
52
+ })
53
+ globalThis.addEventListener("popstate", () => {
76
54
  log("Setting Initial State")
77
55
  addressBar.useRoute()
78
56
 
79
57
  log("Activating Body")
80
58
  document.body.classList.remove("unhydrated")
81
59
 
82
- // Make ecosystem available to HTML event handlers.
83
- globalThis._ = _
60
+ debug('remove these preview classes', document.querySelectorAll(`[class^="preview-"]`))
61
+ })
84
62
 
85
- log("Starting Engine Loop")
86
- _.define({
87
- frameRequest: { value: requestAnimationFrame(() => _.distributeLoop()), writable: true },
88
- })
63
+ // Prevent normal click events to ensure the pointerdown event always takes precedence.
64
+ document.addEventListener("click", pointerEvent => {
65
+ pointerEvent.preventDefault()
66
+ pointerEvent.stopPropagation()
67
+ }, { capture: true })
89
68
 
90
- log("Client hydration complete.")
91
- client.hydrated = true
92
- }
69
+ log("Setting Initial State")
70
+ // Propagate the initial state (matched to the snapshot exactly).
71
+ addressBar.useRoute()
72
+
73
+ log("Activating Interaction")
74
+ // Enable HTML event listeners.
75
+ globalThis._ = _
76
+ // Disable pre-hydration presentation.
77
+ document.body.classList.remove("unhydrated")
78
+ // Switch to post-hydration state propagation.
79
+ client.hydrated = true
80
+
81
+ log("Starting Engine Loop")
82
+ // One-frame lag to capture refresh-rate-specific initial timestamp.
83
+ requestAnimationFrame(now => client.requestLoop(now))
93
84
  })
@@ -1,3 +1,7 @@
1
- facet.define({
2
- hydrated: { value: false, writable: true }
1
+ client.define({
2
+ hydrated: { value: false, writable: true },
3
+ fps: { value: 60, writable: true },
4
+ now: { value: null, writable: true },
5
+ deltaTime: { value: null, writable: true },
6
+ meanFrameTime: { value: 1000 / 60, writable: true },
3
7
  })
@@ -0,0 +1,10 @@
1
+ requestAnimationFrame(now => {
2
+ const deltaTime = now - REQUEST_TIME
3
+ // Use 60fps delta if returning to tab or heavy lag.
4
+ client.deltaTime = deltaTime > 100 ? (1000 / 60) : deltaTime
5
+ client.meanFrameTime += (client.deltaTime - client.meanFrameTime) / 20
6
+ client.fps = Math.round(1000 / client.meanFrameTime)
7
+ client.now = now
8
+ _.distributeLoop()
9
+ recurse(now)
10
+ })
@@ -1,3 +1,8 @@
1
1
  {
2
- "extends": "facet"
2
+ "extends": "facet",
3
+ "methods": {
4
+ "loop-request": [
5
+ "REQUEST_TIME"
6
+ ]
7
+ }
3
8
  }
@@ -1,10 +1,24 @@
1
1
  declare interface IClient
2
2
  extends IFacet<ICore> {
3
3
 
4
+ // Serialized Properties.
5
+ /** Requests an animation frame that distributes the loop function throughout the ecosystem and calls itself again. @remarks Can only be run on the client. */
6
+ readonly requestLoop(REQUEST_TIME: DOMHighResTimeStamp): void
7
+
4
8
  // Runtime Properties.
5
- /** Whether or not the server-rendered page has been fully "taken over" by the client-side framework. */
9
+ /** Whether or not the server-rendered page has been fully "taken over" by the client-side framework. @remarks Can only become true in the client environment. */
6
10
  readonly hydrated: boolean
11
+ /** The averaged framerate of the application over a certain time window. @remarks Defaults to `60` before the first loop and when not in the client environment. */
12
+ readonly fps?: number
13
+ /** The current session time, aligned to the client refresh rate by `requestAnimationFrame`. @remarks Defaults to 'null' on first loop and when not in the client environment.*/
14
+ readonly now: number
15
+ /** The difference between the session time of the current frame and the session time of the previous frame. @remarks Defaults to `1000 / 60` before the first loop and when not in the client environment. */
16
+ readonly deltaTime: number
17
+ /** The average length of time each frame is on screen in milliseconds. @remarks Defaults to `1000 / 60` before the first loop and when not in the client environment. */
18
+ readonly meanFrameTime?: number
7
19
  }
8
20
 
9
- /** A facet which helps toggle the page style between a locked loading state (before hydration) and a fully-interactive state (after hydration). */
10
- declare const client: IClient
21
+ /** A facet which helps toggle the page style between a locked loading state (before hydration) and a fully-interactive state (after hydration). It also starts and continues the engine loop. */
22
+ declare const client: IClient
23
+ /** The animation frame timestamp when the method was called. @remarks Only available in `client.requestLoop()`. */
24
+ declare const REQUEST_TIME: DOMHighResTimeStamp
@@ -36,13 +36,9 @@ declare interface IPointerConfig {
36
36
  doubleClick: (pointerEvent: PointerEvent) => void,
37
37
  /** The action that should finally execute whenever the user's pointer action is complete (whether successfully or through a native pointer event cancellation). */
38
38
  reset: () => void,
39
- /** **REQUIRED**
40
- *
41
- * The pointerdown event responsible for launching the pointer session. */
39
+ /** The pointerdown event responsible for launching the pointer session. @remarks Required for all pointer handling. */
42
40
  readonly POINTER_EVENT: PointerEvent,
43
- /** **REQUIRED**
44
- *
45
- * The target HTML element whose pointerdown listener responsible for launching the pointer session. */
41
+ /** The target HTML element whose pointerdown listener responsible for launching the pointer session. @remarks Required for all pointer handling. */
46
42
  readonly TARGET_ELEMENT: HTMLElement,
47
43
  /** Optional helper that can automate calling TARGET_ELEMENT.focus() during the pointer session. */
48
44
  readonly focus?: "none" | "down" | "click",
@@ -51,11 +47,7 @@ declare interface IPointerConfig {
51
47
  declare const pointer: IPointer
52
48
 
53
49
  declare const POINTER_CONFIG: IPointerConfig
54
- /** The pointerdown event that the current listener is reacting to.
55
- *
56
- * *Available only in pointerdown event listeners.* */
50
+ /** The pointerdown event that the current listener is reacting to. @remarks Only in pointerdown event listeners. */
57
51
  declare const POINTER_EVENT: PointerEvent
58
- /** The element that the current pointerdown event is reacting to.
59
- *
60
- * *Available only in pointerdown event listeners.* */
52
+ /** The element that the current pointerdown event is reacting to. @remarks Only in pointerdown event listeners. */
61
53
  declare const TARGET_ELEMENT: HTMLElement
@@ -1 +1,4 @@
1
- return stats.fps
1
+ if (environment === "client")
2
+ return client.fps
3
+
4
+ return 60
@@ -1,3 +1 @@
1
- stats.fps = Math.round(1000 / (stats.meanFrameTime += (TIME - (stats.mark ?? TIME) - stats.meanFrameTime) / 20))
2
- stats.mark = TIME
3
- stats.element.textContent = stats.fps
1
+ stats.element.textContent = client.fps
@@ -1,13 +1,6 @@
1
1
  declare interface IStats
2
2
  extends ITrayItem {
3
3
 
4
- // Runtime Properties.
5
- /** If in the client environment, the computed framerate of the application. Null otherwise. */
6
- readonly fps?: number
7
- /** If in the client environment, the time (taken from _.now) of the last loop evaluation. Null otherwise. */
8
- readonly mark?: DOMHighResTimeStamp
9
- /** If in the client environment, the average length of time each frame is on screen in milliseconds. Null otherwise. */
10
- readonly meanFrameTime?: number
11
4
  }
12
5
 
13
6
  /** The framerate monitor, which sits in the taskbar tray. */
@@ -23,9 +23,7 @@ declare interface IDesktopWindowModel {
23
23
  readonly height: number
24
24
  }
25
25
 
26
- /** The host of the application to render.
27
- *
28
- * *Only available in `renderTaskHTML` methods.* */
26
+ /** The host of the application to render. @remarks Only in `renderTaskHTML` methods. */
29
27
  declare const APPLICATION_HOST: string
30
28
  declare const INSTANCES: IDesktopWindow[]
31
29
  declare const INSTANCE: IDesktopWindow
package/src/type.d.ts CHANGED
@@ -50,9 +50,7 @@ declare interface IEcosystem
50
50
  readonly setRoute(REQUEST_URL: string): void
51
51
  /** Performs automated build-time unit tests to validate the state of the build. */
52
52
  readonly validate(): void
53
- /** *Client-only*
54
- *
55
- * Navigates to the given host by setting the current location. An undo point is automatically set by the browser. */
53
+ /** Navigates to the given host by setting the current location. An undo point is automatically set by the browser. @remarks Client-only */
56
54
  readonly gotoApplication(HOST: string): void
57
55
 
58
56
  // Runtime Properties.
@@ -68,15 +66,11 @@ declare interface IEcosystem
68
66
  readonly landingModel: string
69
67
  /** The routeID of the desired landing page, as computed from data parameters during the initial boot process. */
70
68
  readonly landingRouteID: bigint
71
- /** If in the client environment, an integer ID representing the application frame loop's current pending frame request. Null, otherwise. */
72
- readonly frameRequest: number | null
73
69
  /** A boolean that is set to `true` as soon as the route ID is set for the first time. */
74
70
  readonly initialized: undefined | true
75
71
  }
76
72
 
77
- /** The root part. When JSON stringified, it should inline all information compiled from the git repo in node by the build process.
78
- *
79
- * The serialized version should not include any values that are added during or after recursively hydrating the part tree. */
73
+ /** This is the root part of the ecosystem, considered the ecosystem itself. @remarks When JSON stringified, it should inline all information compiled from the git repo in node by the build process. The serialized version should not include any values that are added during or after recursively hydrating the part tree. This means that all runtime values should be non-enumerable and defined using the `define()` method. */
80
74
  declare const _: IEcosystem
81
75
  /** A shorthand for document.querySelector */
82
76
  declare const Q: typeof document.querySelector
@@ -261,9 +255,7 @@ declare class MethodConstant {
261
255
  /** Idempotent function that ensures that the constant and all its recursive dependencies (`requirements`) are declared (added to the source file output). Marks the constant as used. */
262
256
  ensureDeclarationAndDependencies(): void
263
257
  }
264
- /** The incoming request url string.
265
- *
266
- * Available only in _.setRoute(). */
258
+ /** The incoming request url string. @remarks Only in _.setRoute(). */
267
259
  declare const REQUEST_URL: string
268
260
  /** A host-keyed map of all parts in the ecosystem. */
269
261
  declare const partsByHost: Record<string, IPartAny>
@@ -1,2 +0,0 @@
1
- base()
2
- _.frameRequest = requestAnimationFrame(() => _.distributeLoop(_.now))
@@ -1,5 +0,0 @@
1
- stats.define({
2
- fps: { value: 60, writable: true },
3
- mark: { value: null, writable: true },
4
- meanFrameTime: { value: 1000 / 60, writable: true }
5
- })