@xyd-js/foo 0.1.0-xyd.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.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @xyd-js/foo
2
+
3
+ `foo` is a package that does components headless things.
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export const test = "test"
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@xyd-js/foo",
3
+ "version": "0.1.0-xyd.0",
4
+ "description": "",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ "./package.json": "./package.json",
10
+ "./index.css": "./dist/index.css",
11
+ ".": {
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./renderoll": {
15
+ "import": "./dist/renderoll.js"
16
+ }
17
+ },
18
+ "dependencies": {
19
+ "react": "^18.3.1"
20
+ },
21
+ "devDependencies": {
22
+ "postcss-import": "^16.1.0"
23
+ },
24
+ "scripts": {
25
+ "clean": "rimraf build",
26
+ "prebuild": "pnpm clean",
27
+ "build": "rollup -c rollup.config.js"
28
+ }
29
+ }
@@ -0,0 +1,3 @@
1
+ export {
2
+ renderoll
3
+ } from "./renderoll"
@@ -0,0 +1,189 @@
1
+ import React, {createContext, lazy, useContext, useEffect, useRef, useState, Suspense} from "react";
2
+ import type {RefObject} from "react";
3
+ import {css} from "@linaria/core";
4
+
5
+ const styles = {
6
+ loader: {
7
+ host: css`
8
+ z-index: 999999;
9
+ position: absolute;
10
+ left: 0;
11
+ top: 0;
12
+ right: 0;
13
+ bottom: 0;
14
+
15
+ background: white; // TODO: customization
16
+ `
17
+ },
18
+ serveComponent: {
19
+ host: css`
20
+ opacity: 0;
21
+ position: absolute;
22
+ height: 100%;
23
+ z-index: 999999;
24
+ `
25
+ },
26
+ content: {
27
+ host: css`
28
+ opacity: 0;
29
+ transition: opacity 0.3s;
30
+ `,
31
+ host$$active: css`
32
+ opacity: 1;
33
+ `
34
+ }
35
+ }
36
+
37
+ export interface RenderollOptions {
38
+ decorator?: (props: { children: React.ReactNode }) => React.ReactNode
39
+ }
40
+
41
+ export function renderoll(
42
+ async: () => Promise<any>,
43
+ options?: RenderollOptions
44
+ ) {
45
+ const [once, setOnce] = useState(false)
46
+ const [inited, setInited] = useState(false)
47
+
48
+ useEffect(() => {
49
+ setInited(true)
50
+ }, []);
51
+
52
+ const $RenderLazyComponent = $Lazy(async, options)
53
+
54
+ return ({children}) => {
55
+ return <$LazyContext.Provider value={{
56
+ onFinish: () => {
57
+ if (once) {
58
+ return
59
+ }
60
+ setOnce(true)
61
+ }
62
+ }}>
63
+ {
64
+ !once && <div className={inited ? styles.serveComponent.host : ""}>
65
+ {children}
66
+ </div>
67
+ }
68
+
69
+ {!once && <$Loader/>}
70
+
71
+ <Suspense fallback={<$Loader/>}>
72
+ <$RenderLazyComponent>
73
+ {children}
74
+ </$RenderLazyComponent>
75
+ </Suspense>
76
+ </$LazyContext.Provider>
77
+ }
78
+ }
79
+
80
+ // TODO: better api for `onFinish` because this does not match pixel perferct server component
81
+ const $LazyContext = createContext({
82
+ onFinish: () => {
83
+ }
84
+ })
85
+
86
+ function $Loader() {
87
+ return <div className={styles.loader.host}/>
88
+ }
89
+
90
+ // TODO: in the future different method than data-slug
91
+ // custom observer logic instead not pixel perfect threshold
92
+ function historyPushStateScroller() {
93
+ const elements = document.querySelectorAll('[data-slug]');
94
+
95
+ if (!elements.length) {
96
+ console.warn("No elements with [data-slug] found.");
97
+ return;
98
+ }
99
+
100
+ const observer = new IntersectionObserver((entries) => {
101
+ entries.forEach(entry => {
102
+ if (!entry.isIntersecting) {
103
+ return
104
+ }
105
+
106
+ const slug = entry.target.getAttribute("data-slug");
107
+
108
+ window.history.pushState(null, "", `${slug}`);
109
+
110
+ const event = new CustomEvent("xyd.history.pushState", {
111
+ detail: {
112
+ url: slug,
113
+ }
114
+ });
115
+ window.dispatchEvent(event);
116
+ });
117
+ }, {threshold: 0.3});
118
+
119
+ elements.forEach(element => observer.observe(element));
120
+
121
+ return observer
122
+ }
123
+
124
+ function $Lazy(
125
+ async: () => Promise<any>,
126
+ options?: RenderollOptions
127
+ ) {
128
+ return lazy(async () => {
129
+ const [Prev, Next] = await async()
130
+
131
+ return {
132
+ default: ({children}) => {
133
+ const [count, setCount] = useState(0)
134
+ const serverContent = useRef<Element>(null);
135
+ const {onFinish} = useContext($LazyContext)
136
+
137
+ useEffect(() => {
138
+ const observer = historyPushStateScroller()
139
+
140
+ if (!observer) {
141
+ return
142
+ }
143
+
144
+ return () => {
145
+ observer.disconnect();
146
+ };
147
+ }, []);
148
+
149
+ useEffect(() => {
150
+ if (serverContent?.current) {
151
+ // TODO: below mechanism does not match perfect - do we need to compare with server view position?
152
+ serverContent?.current.scrollIntoView?.();
153
+
154
+ onFinish()
155
+ }
156
+ }, [serverContent]);
157
+
158
+ function onLoaded() {
159
+ setCount(count + 1)
160
+ }
161
+
162
+ const loaded = !!count
163
+
164
+ const tree = <>
165
+ <Prev onLoaded={onLoaded}/>
166
+
167
+ <div ref={serverContent as RefObject<HTMLDivElement>}>
168
+ {children}
169
+ </div>
170
+
171
+ <Next onLoaded={onLoaded}/>
172
+ </>
173
+
174
+ const content = options?.decorator
175
+ ? options?.decorator?.({children: tree})
176
+ : tree
177
+
178
+ return <div
179
+ className={`
180
+ ${styles.content.host}
181
+ ${loaded && styles.content.host$$active}
182
+ `}>
183
+
184
+ {content}
185
+ </div>
186
+ }
187
+ }
188
+ })
189
+ }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ plugins: {
3
+ autoprefixer: {},
4
+ },
5
+ }
@@ -0,0 +1,89 @@
1
+ import {fileURLToPath} from 'url';
2
+ import {dirname} from 'path';
3
+
4
+ import resolve from '@rollup/plugin-node-resolve';
5
+ import commonjs from '@rollup/plugin-commonjs';
6
+ import typescript from '@rollup/plugin-typescript';
7
+ import dts from 'rollup-plugin-dts';
8
+ import {terser} from 'rollup-plugin-terser';
9
+ import babel from '@rollup/plugin-babel';
10
+ import postcss from 'rollup-plugin-postcss';
11
+ import wyw from '@wyw-in-js/rollup';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+
16
+ import {createRequire} from 'module';
17
+
18
+ const require = createRequire(import.meta.url);
19
+ const {dependencies} = require('./package.json', {assert: {type: 'json'}});
20
+
21
+ const external = Object.keys(dependencies);
22
+
23
+ export default [
24
+ {
25
+ input: {
26
+ index: 'index.ts',
27
+ renderoll: 'packages/renderoll/index.ts'
28
+ },
29
+ output: [
30
+ {
31
+ dir: 'dist',
32
+ format: 'esm',
33
+ sourcemap: false,
34
+ entryFileNames: '[name].js'
35
+ }
36
+ ],
37
+ plugins: [
38
+ wyw({
39
+ include: ['**/*.{ts,tsx}'],
40
+ babelOptions: {
41
+ presets: [
42
+ '@babel/preset-typescript',
43
+ '@babel/preset-react'
44
+ ],
45
+ },
46
+ }),
47
+ postcss({
48
+ extract: true,
49
+ plugins: [
50
+ require('postcss-import'),
51
+ require('autoprefixer')
52
+ ]
53
+ }),
54
+ resolve(),
55
+ commonjs(),
56
+ typescript({
57
+ tsconfig: './tsconfig.json',
58
+ }),
59
+ babel({
60
+ babelHelpers: 'bundled',
61
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
62
+ presets: [
63
+ '@babel/preset-env',
64
+ '@babel/preset-react'
65
+ ],
66
+ }),
67
+ terser(),
68
+ ],
69
+ external
70
+ },
71
+ {
72
+ input: 'index.ts',
73
+ output: {
74
+ file: 'dist/index.d.ts',
75
+ format: 'es',
76
+ },
77
+ plugins: [dts()],
78
+ external
79
+ },
80
+ {
81
+ input: 'packages/renderoll/index.ts',
82
+ output: {
83
+ file: 'dist/renderoll.d.ts',
84
+ format: 'es',
85
+ },
86
+ plugins: [dts()],
87
+ external
88
+ }
89
+ ];
File without changes
File without changes
package/tsconfig.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "esnext",
4
+ "esModuleInterop": true,
5
+ "moduleResolution": "node",
6
+ "target": "ES6",
7
+ "lib": [
8
+ "dom",
9
+ "dom.iterable",
10
+ "esnext"
11
+ ],
12
+ "allowJs": true,
13
+ "skipLibCheck": true,
14
+ "strict": false,
15
+ "noEmit": true,
16
+ "incremental": false,
17
+ "resolveJsonModule": true,
18
+ "isolatedModules": true,
19
+ "jsx": "react",
20
+ "plugins": [
21
+ {
22
+ "name": "next"
23
+ }
24
+ ],
25
+ "strictNullChecks": true
26
+ },
27
+ "include": [
28
+ "next-env.d.ts",
29
+ "**/*.ts",
30
+ "**/*.tsx",
31
+ ".next/types/**/*.ts"
32
+ ],
33
+ "exclude": [
34
+ "node_modules"
35
+ ]
36
+ }