round-core 0.1.8 → 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.
- package/README.md +74 -0
- package/package.json +1 -1
- package/src/cli.js +1 -1
- package/src/runtime/router.js +41 -4
package/README.md
CHANGED
|
@@ -115,6 +115,80 @@ export default function App() {
|
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
+
## Markdown rendering with `@round-core/markdown`
|
|
119
|
+
|
|
120
|
+
Round includes an optional companion package for markdown rendering with
|
|
121
|
+
syntax highlighting and rich code blocks.
|
|
122
|
+
|
|
123
|
+
Install it alongside `round-core`:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm install @round-core/markdown
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
or with Bun:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
bun add @round-core/markdown
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Then use it in a `.round` file or JSX component:
|
|
136
|
+
|
|
137
|
+
```jsx
|
|
138
|
+
import { createElement } from 'round-core';
|
|
139
|
+
import { Markdown, defaultMarkdownStyles as markdown } from '@round-core/markdown';
|
|
140
|
+
import '@round-core/markdown/styles.css';
|
|
141
|
+
|
|
142
|
+
export default function App() {
|
|
143
|
+
const content = `
|
|
144
|
+
# Markdown with code blocks
|
|
145
|
+
|
|
146
|
+
You can render fenced code blocks with syntax highlighting:
|
|
147
|
+
|
|
148
|
+
\`\`\`javascript
|
|
149
|
+
const value = signal(0);
|
|
150
|
+
\`\`\`
|
|
151
|
+
`;
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<div>
|
|
155
|
+
<Markdown content={content}/>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
You can also theme the markdown surface (background/text) and accents via
|
|
162
|
+
`options.theme`:
|
|
163
|
+
|
|
164
|
+
```jsx
|
|
165
|
+
<Markdown
|
|
166
|
+
content={content}
|
|
167
|
+
options={{
|
|
168
|
+
theme: {
|
|
169
|
+
// Dark card-like surface
|
|
170
|
+
markdownBackground: '#020617',
|
|
171
|
+
markdownText: '#e5e7eb',
|
|
172
|
+
primaryColor: '#e5e7eb',
|
|
173
|
+
secondaryColor: '#38bdf8',
|
|
174
|
+
},
|
|
175
|
+
}}
|
|
176
|
+
/>
|
|
177
|
+
|
|
178
|
+
<Markdown
|
|
179
|
+
content={content}
|
|
180
|
+
options={{
|
|
181
|
+
theme: {
|
|
182
|
+
// Light mode
|
|
183
|
+
markdownBackground: '#ffffff',
|
|
184
|
+
markdownText: '#0f172a',
|
|
185
|
+
primaryColor: '#0f172a',
|
|
186
|
+
secondaryColor: '#2563eb',
|
|
187
|
+
},
|
|
188
|
+
}}
|
|
189
|
+
/>
|
|
190
|
+
```
|
|
191
|
+
|
|
118
192
|
## Core API & Examples
|
|
119
193
|
|
|
120
194
|
### `signal(initialValue)`
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
package/src/runtime/router.js
CHANGED
|
@@ -17,6 +17,10 @@ let hasMatchForPath = false;
|
|
|
17
17
|
const pathHasMatch = signal(false);
|
|
18
18
|
const pathEvalReady = signal(true);
|
|
19
19
|
|
|
20
|
+
// Per-path scroll positions so each route can keep its own scroll offset.
|
|
21
|
+
const scrollPositions = hasWindow ? new Map() : null;
|
|
22
|
+
let lastScrollPath = hasWindow ? window.location.pathname : '/';
|
|
23
|
+
|
|
20
24
|
let defaultNotFoundComponent = null;
|
|
21
25
|
let autoNotFoundMounted = false;
|
|
22
26
|
let userProvidedNotFound = false;
|
|
@@ -30,7 +34,26 @@ function ensureListener() {
|
|
|
30
34
|
mountAutoNotFound();
|
|
31
35
|
|
|
32
36
|
window.addEventListener('popstate', () => {
|
|
33
|
-
|
|
37
|
+
const rawPrev = lastScrollPath;
|
|
38
|
+
const rawNext = window.location.pathname;
|
|
39
|
+
|
|
40
|
+
const prevPath = normalizePathname(rawPrev);
|
|
41
|
+
const nextPath = normalizePathname(rawNext);
|
|
42
|
+
|
|
43
|
+
if (scrollPositions) {
|
|
44
|
+
// Save scroll for the route we are leaving
|
|
45
|
+
const y = window.scrollY ?? window.pageYOffset ?? 0;
|
|
46
|
+
scrollPositions.set(prevPath, y);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
lastScrollPath = rawNext;
|
|
50
|
+
currentPath(rawNext);
|
|
51
|
+
|
|
52
|
+
if (scrollPositions) {
|
|
53
|
+
// Restore scroll for the route we are entering (or default to top)
|
|
54
|
+
const saved = scrollPositions.get(nextPath) ?? 0;
|
|
55
|
+
window.scrollTo(0, saved);
|
|
56
|
+
}
|
|
34
57
|
});
|
|
35
58
|
}
|
|
36
59
|
|
|
@@ -76,7 +99,6 @@ export function useRouteReady() {
|
|
|
76
99
|
export function getIsNotFound() {
|
|
77
100
|
const pathname = normalizePathname(currentPath());
|
|
78
101
|
if (pathname === '/') return false;
|
|
79
|
-
if (!(Boolean(pathEvalReady()) && lastPathEvaluated === pathname)) return false;
|
|
80
102
|
return !Boolean(pathHasMatch());
|
|
81
103
|
}
|
|
82
104
|
|
|
@@ -84,7 +106,8 @@ export function useIsNotFound() {
|
|
|
84
106
|
return () => {
|
|
85
107
|
const pathname = normalizePathname(currentPath());
|
|
86
108
|
if (pathname === '/') return false;
|
|
87
|
-
|
|
109
|
+
// Mirror getIsNotFound: react immediately to the current path and
|
|
110
|
+
// the latest match flag, instead of waiting for pathEvalReady.
|
|
88
111
|
return !Boolean(pathHasMatch());
|
|
89
112
|
};
|
|
90
113
|
}
|
|
@@ -136,12 +159,26 @@ export function navigate(to, options = {}) {
|
|
|
136
159
|
if (!hasWindow) return;
|
|
137
160
|
ensureListener();
|
|
138
161
|
|
|
162
|
+
const fromPath = normalizePathname(currentPath());
|
|
163
|
+
if (scrollPositions) {
|
|
164
|
+
const y = window.scrollY ?? window.pageYOffset ?? 0;
|
|
165
|
+
scrollPositions.set(fromPath, y);
|
|
166
|
+
}
|
|
167
|
+
|
|
139
168
|
const normalizedTo = normalizeTo(to);
|
|
140
169
|
const replace = Boolean(options.replace);
|
|
141
170
|
if (replace) window.history.replaceState({}, '', normalizedTo);
|
|
142
171
|
else window.history.pushState({}, '', normalizedTo);
|
|
143
172
|
|
|
144
|
-
|
|
173
|
+
const rawNext = window.location.pathname;
|
|
174
|
+
lastScrollPath = rawNext;
|
|
175
|
+
currentPath(rawNext);
|
|
176
|
+
|
|
177
|
+
if (scrollPositions) {
|
|
178
|
+
const nextPath = normalizePathname(rawNext);
|
|
179
|
+
const saved = scrollPositions.get(nextPath) ?? 0;
|
|
180
|
+
window.scrollTo(0, saved);
|
|
181
|
+
}
|
|
145
182
|
}
|
|
146
183
|
|
|
147
184
|
function applyHead({ title, meta, links, icon, favicon }) {
|