uniweb 1.13.1 → 1.13.3
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 +7 -7
- package/partials/agents.md +23 -5
- package/src/commands/doctor.js +91 -8
- package/src/framework-index.json +8 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.3",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,15 +41,15 @@
|
|
|
41
41
|
"js-yaml": "^4.1.0",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
|
-
"@uniweb/
|
|
44
|
+
"@uniweb/core": "~1.3.0",
|
|
45
|
+
"@uniweb/semantic-parser": "~1.12.2",
|
|
45
46
|
"@uniweb/schemas": "~1.5.0",
|
|
46
|
-
"@uniweb/
|
|
47
|
-
"@uniweb/core": "~1.3.0"
|
|
47
|
+
"@uniweb/content-writer": "~1.3.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@uniweb/
|
|
51
|
-
"@uniweb/
|
|
52
|
-
"@uniweb/
|
|
50
|
+
"@uniweb/build": "~1.5.2",
|
|
51
|
+
"@uniweb/content-reader": "~1.5.4",
|
|
52
|
+
"@uniweb/semantic-parser": "~1.12.2"
|
|
53
53
|
},
|
|
54
54
|
"peerDependenciesMeta": {
|
|
55
55
|
"@uniweb/build": {
|
package/partials/agents.md
CHANGED
|
@@ -1098,7 +1098,7 @@ import { Section, Prose } from '@uniweb/kit'
|
|
|
1098
1098
|
|
|
1099
1099
|
`Prose` renders from the parsed sequence — headings, paragraphs, images, snippets, lists — with prose typography. Tagged data blocks are **skipped**; access them via `content.data` for custom rendering. Pass `content` (needs `.sequence`), and `block` too if the content uses insets. Also works as a pure typography wrapper: `<Prose>{children}</Prose>`.
|
|
1100
1100
|
|
|
1101
|
-
`Article` is
|
|
1101
|
+
`Article` is `Prose` in a semantic `<article>` element — the same rendering, for content that is a self-contained document.
|
|
1102
1102
|
|
|
1103
1103
|
### The Kit, by use case
|
|
1104
1104
|
|
|
@@ -1111,13 +1111,13 @@ Names only — for signatures and props, read the package: it's on disk at `node
|
|
|
1111
1111
|
**Header/layout:** `useScrolled(threshold)`, `useMobileMenu()`, `useAppearance()`
|
|
1112
1112
|
**Overlays:** `Overlay` (modals, palettes, drawers, toasts — portals out of the layout, contains focus; read the note below before hand-rolling one)
|
|
1113
1113
|
**Keyboard:** `useShortcut('mod+k', fn)`, `useShortcuts({…})`, `useShortcutLabel('mod+k')` — `mod` is Cmd on Apple platforms and Ctrl elsewhere, and the label renders per-platform so a hint never shows the wrong key
|
|
1114
|
-
**Long-form prose:** `<Prose>` and the container you put `<Render>` output in both use
|
|
1114
|
+
**Long-form prose:** `<Prose>` and the container you put `<Render>` output in both use kit's `prose` classes. One line in the foundation's `styles.css` supplies the rules, colored by the section's theme:
|
|
1115
1115
|
|
|
1116
1116
|
```css
|
|
1117
|
-
@import "@uniweb/kit/prose-tokens.css"; /*
|
|
1117
|
+
@import "@uniweb/kit/prose-tokens.css"; /* kit's prose layer, wired to theme.yml */
|
|
1118
1118
|
```
|
|
1119
1119
|
|
|
1120
|
-
Nothing to install
|
|
1120
|
+
Nothing to install. **Skip the import and prose is completely unstyled** — lists lose their bullets and numbers, and text its typography — while the markup looks right. The foundation build warns about it, and `uniweb doctor` flags it. `size` picks a step (`prose-sm` … `prose-2xl`) of the site's reading size, which `theme.yml` sets under `vars:` — `prose-size`, `prose-leading`, `prose-measure`, `prose-flow`, `prose-h1` … `prose-h4`; spread `proseVars` from `@uniweb/kit/prose-vars` into `main.js`'s `vars` to declare them. `<Prose>` and `<Article>` fill their box (`max-w-none`), so `prose-measure` reaches only a `prose` element written without it — set their width on the box around them. A utility class or an element variant (`prose-headings:tracking-tight`, `prose-a:no-underline`) overrides any rule; `prose-a:` leaves a content button its own look. There are no palette modifiers and no `prose-invert` — the colors are already the theme's, light and dark.
|
|
1121
1121
|
|
|
1122
1122
|
**Documentation shells:** `useHeadings()` (the page's headings + the one being read, derived from content so it prerenders), `website.getBranchHierarchy({ route, for })` (the page tree for one branch). Kit ships no ready-made layout — a layout is your foundation's design; write it in `src/layouts/` and use these for the behaviour.
|
|
1123
1123
|
**Layout helpers:** `useGridLayout(columns, { gap })`, `useAccordion({ multiple, defaultOpen })`
|
|
@@ -1860,7 +1860,7 @@ const page = website.activePage
|
|
|
1860
1860
|
| `block.childBlocks` / `block.insets` | Child sections / inline `@Component` references |
|
|
1861
1861
|
| `block.getInset(refId)` | Lookup an inset by refId |
|
|
1862
1862
|
| `block.properties` | Raw frontmatter |
|
|
1863
|
-
| `block.rawContent` | ProseMirror document —
|
|
1863
|
+
| `block.rawContent` | The section's ProseMirror document, before parsing — what a content handler reads |
|
|
1864
1864
|
| `block.themeName` | `"light"`, `"medium"`, `"dark"` |
|
|
1865
1865
|
| `block.stableId` / `block.key` | Stable ID from filename or `id:` / unique key across pages — use as React key |
|
|
1866
1866
|
| `block.path` | Page route this block belongs to |
|
|
@@ -2566,6 +2566,24 @@ await writer.remove(itemId)
|
|
|
2566
2566
|
first; a retry would succeed by overwriting a change nobody looked at. Tell the
|
|
2567
2567
|
person.
|
|
2568
2568
|
|
|
2569
|
+
### Translated fields
|
|
2570
|
+
|
|
2571
|
+
A `localized` field holds `{ en: '…', fr: '…' }`, or one plain value that is every
|
|
2572
|
+
language, and a read answers it in the page's language. ⛔ **Never write that one value
|
|
2573
|
+
back as the whole field** — it becomes the value in every language. To edit one:
|
|
2574
|
+
|
|
2575
|
+
```jsx
|
|
2576
|
+
const { entity } = useEntity({ schema: '@/profile', uuid, languages: 'all' }) // every language, as stored
|
|
2577
|
+
await writer.update(item.id, { ...item.data, bio: 'Bonjour' }, { language: 'fr' }) // one language, merged
|
|
2578
|
+
```
|
|
2579
|
+
|
|
2580
|
+
- **`update` with `{ language }`** merges each translated field you name into the languages
|
|
2581
|
+
the item holds, and keeps a translated field you leave out. On a site with more than one
|
|
2582
|
+
language, an update without it that writes a plain value over a translated field read in
|
|
2583
|
+
the page's language is refused.
|
|
2584
|
+
- **`languagesOf`, `inLanguage` and `withLanguage`** read and set one language of a value
|
|
2585
|
+
yourself, its `@` metadata kept.
|
|
2586
|
+
|
|
2569
2587
|
### ⛔ Permissions are the SERVER'S, and your UI is only a courtesy
|
|
2570
2588
|
|
|
2571
2589
|
Gate your controls on what the viewer may do — a record's own `can_edit` from a
|
package/src/commands/doctor.js
CHANGED
|
@@ -190,6 +190,38 @@ export function rendersKitProse(dir) {
|
|
|
190
190
|
)
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Does a stylesheet load Tailwind Typography itself? A line commented out loads
|
|
195
|
+
* nothing. ⛔ Until 2026-10-19 one was read as loaded, so the first step of
|
|
196
|
+
* removing the plugin drew a warning to remove it.
|
|
197
|
+
*/
|
|
198
|
+
export function loadsTypographyPlugin(styles) {
|
|
199
|
+
const css = String(styles || '').replace(/\/\*[\s\S]*?\*\//g, '')
|
|
200
|
+
return /@plugin\s+["']@tailwindcss\/typography["']/.test(css)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Tailwind Typography's palette modifiers and `prose-invert`, wherever a
|
|
205
|
+
* foundation's source names one in a class list — `dark:prose-invert` included,
|
|
206
|
+
* and marked important either way (`!prose-invert`, `prose-invert!`). Comments
|
|
207
|
+
* are skipped, since a comment warning against one names it too. What it reads
|
|
208
|
+
* is the source's text, so the same word in a sentence a component renders is
|
|
209
|
+
* read as a class as well.
|
|
210
|
+
*
|
|
211
|
+
* @returns {{ file: string, modifiers: string[] }[]}
|
|
212
|
+
*/
|
|
213
|
+
export function inertProseModifiers(dir) {
|
|
214
|
+
const MODIFIER =
|
|
215
|
+
/(?:^|[\s"'`:!])(prose-(?:gray|slate|zinc|neutral|stone|invert|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose))(?=$|[\s"'`!])/gm
|
|
216
|
+
const found = []
|
|
217
|
+
forEachSourceFile(dir, (text, file) => {
|
|
218
|
+
const code = text.replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:])\/\/.*$/gm, '$1')
|
|
219
|
+
const modifiers = [...new Set([...code.matchAll(MODIFIER)].map((m) => m[1]))]
|
|
220
|
+
if (modifiers.length) found.push({ file, modifiers })
|
|
221
|
+
})
|
|
222
|
+
return found
|
|
223
|
+
}
|
|
224
|
+
|
|
193
225
|
function sourceMatches(dir, pattern) {
|
|
194
226
|
let found = false
|
|
195
227
|
forEachSourceFile(dir, (text) => {
|
|
@@ -1200,13 +1232,14 @@ export async function doctor(args = []) {
|
|
|
1200
1232
|
|
|
1201
1233
|
// Prose without the tokens — a silent, total loss of styling.
|
|
1202
1234
|
//
|
|
1203
|
-
// `@uniweb/kit/prose-tokens.css`
|
|
1204
|
-
//
|
|
1205
|
-
//
|
|
1206
|
-
//
|
|
1207
|
-
//
|
|
1208
|
-
//
|
|
1209
|
-
//
|
|
1235
|
+
// `@uniweb/kit/prose-tokens.css` is kit's prose layer, which answers to the
|
|
1236
|
+
// site's theme.yml. A foundation that writes `prose` (or renders
|
|
1237
|
+
// <Prose>/<Article>, which emit it) and does NOT import that file gets the
|
|
1238
|
+
// class and no rules behind it: correct markup, zero styling, and nothing
|
|
1239
|
+
// reported anywhere. Measured 2026-07-30 on a foundation missing only the
|
|
1240
|
+
// rules — every paragraph `margin-top: 0px`, no warning from Vite, Tailwind or
|
|
1241
|
+
// the browser. (Then the rules were Tailwind Typography's; kit's own since
|
|
1242
|
+
// 2026-10-19.)
|
|
1210
1243
|
//
|
|
1211
1244
|
// kit closes this for anyone who imports the file; this closes it for anyone
|
|
1212
1245
|
// who does not, which is the case kit cannot reach.
|
|
@@ -1237,13 +1270,63 @@ export async function doctor(args = []) {
|
|
|
1237
1270
|
})
|
|
1238
1271
|
warn(`[${id}] ${f.name} ${reason}, with no prose styling behind it`)
|
|
1239
1272
|
log(
|
|
1240
|
-
`
|
|
1273
|
+
` kit's prose layer supplies the rules and it is not imported, so the ` +
|
|
1241
1274
|
`markup is correct and completely unstyled — silently.`
|
|
1242
1275
|
)
|
|
1243
1276
|
log(` Add to ${f.folderName}/styles.css:`)
|
|
1244
1277
|
log(` ${colors.dim}@import "@uniweb/kit/prose-tokens.css";${colors.reset}`)
|
|
1245
1278
|
}
|
|
1246
1279
|
|
|
1280
|
+
// A modifier kit's prose layer does not have — `prose-slate`, `prose-invert`
|
|
1281
|
+
// and the rest of Tailwind Typography's palettes. Since 2026-10-19 the layer
|
|
1282
|
+
// takes every color from the section's theme tokens, so a class list still
|
|
1283
|
+
// naming one styles nothing and says a design the page does not have.
|
|
1284
|
+
// Only where the foundation imports kit's layer and does not load the plugin
|
|
1285
|
+
// itself — with its own `@plugin`, the modifier still means what it says.
|
|
1286
|
+
for (const f of foundations) {
|
|
1287
|
+
const stylesPath = join(f.path, 'styles.css')
|
|
1288
|
+
if (!existsSync(stylesPath)) continue
|
|
1289
|
+
const styles = readFileSync(stylesPath, 'utf8')
|
|
1290
|
+
if (!styles.includes('@uniweb/kit/prose-tokens.css')) continue
|
|
1291
|
+
if (loadsTypographyPlugin(styles)) {
|
|
1292
|
+
// Both: the plugin's rules sit in a layer above kit's and win, so prose is
|
|
1293
|
+
// the plugin's again — its own greys, and none of the --prose-* variables.
|
|
1294
|
+
const id = 'prose-plugin-alongside'
|
|
1295
|
+
issues.push({
|
|
1296
|
+
id,
|
|
1297
|
+
type: 'warning',
|
|
1298
|
+
foundation: f.name,
|
|
1299
|
+
message: `${f.name} loads Tailwind Typography as well as kit's prose layer`
|
|
1300
|
+
})
|
|
1301
|
+
warn(`[${id}] ${f.name} loads Tailwind Typography as well as kit's prose layer`)
|
|
1302
|
+
log(
|
|
1303
|
+
` The plugin's rules sit above kit's and win: prose takes the plugin's greys, not the ` +
|
|
1304
|
+
`theme's colors, and the --prose-* variables reach nothing.`
|
|
1305
|
+
)
|
|
1306
|
+
log(` Remove the @plugin line from ${f.folderName}/styles.css to use kit's layer alone.`)
|
|
1307
|
+
continue
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
const found = inertProseModifiers(f.path)
|
|
1311
|
+
if (found.length === 0) continue
|
|
1312
|
+
|
|
1313
|
+
const id = 'prose-modifier-inert'
|
|
1314
|
+
const names = [...new Set(found.flatMap((x) => x.modifiers))]
|
|
1315
|
+
issues.push({
|
|
1316
|
+
id,
|
|
1317
|
+
type: 'warning',
|
|
1318
|
+
foundation: f.name,
|
|
1319
|
+
message: `${f.name} names ${names.join(', ')}, which kit's prose layer does not have`
|
|
1320
|
+
})
|
|
1321
|
+
warn(`[${id}] ${f.name} names ${names.join(', ')} — they no longer do anything`)
|
|
1322
|
+
for (const { file, modifiers } of found.slice(0, 6)) log(` ${file}: ${modifiers.join(', ')}`)
|
|
1323
|
+
log(
|
|
1324
|
+
` Prose takes its colors from the section's theme tokens, so it already follows ` +
|
|
1325
|
+
`theme.yml and the visitor's scheme. Remove these; to change what prose looks like, ` +
|
|
1326
|
+
`set the theme's colors, or the --prose-* variables.`
|
|
1327
|
+
)
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1247
1330
|
// ⛔ SAY WHEN A CHECK DID NOT RUN. Every foundation check below reads the
|
|
1248
1331
|
// BUILT `dist/meta/schema.json` — what a consumer actually receives — and
|
|
1249
1332
|
// returns silently when there is none. In a workspace with a site, "Foundation
|
package/src/framework-index.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-19T18:20:17.536Z",
|
|
4
4
|
"packages": {
|
|
5
5
|
"@uniweb/api": {
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.6.0"
|
|
7
7
|
},
|
|
8
8
|
"@uniweb/build": {
|
|
9
|
-
"version": "1.5.
|
|
9
|
+
"version": "1.5.2"
|
|
10
10
|
},
|
|
11
11
|
"@uniweb/content-reader": {
|
|
12
|
-
"version": "1.5.
|
|
12
|
+
"version": "1.5.4"
|
|
13
13
|
},
|
|
14
14
|
"@uniweb/content-writer": {
|
|
15
15
|
"version": "1.3.0"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"version": "1.0.4"
|
|
25
25
|
},
|
|
26
26
|
"@uniweb/kit": {
|
|
27
|
-
"version": "1.
|
|
27
|
+
"version": "1.5.1"
|
|
28
28
|
},
|
|
29
29
|
"@uniweb/loom": {
|
|
30
30
|
"version": "1.1.0"
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"version": "1.1.4"
|
|
37
37
|
},
|
|
38
38
|
"@uniweb/runtime": {
|
|
39
|
-
"version": "1.1.
|
|
39
|
+
"version": "1.1.10"
|
|
40
40
|
},
|
|
41
41
|
"@uniweb/scene": {
|
|
42
42
|
"version": "1.0.1"
|
|
@@ -48,13 +48,13 @@
|
|
|
48
48
|
"version": "1.1.0"
|
|
49
49
|
},
|
|
50
50
|
"@uniweb/semantic-parser": {
|
|
51
|
-
"version": "1.12.
|
|
51
|
+
"version": "1.12.2"
|
|
52
52
|
},
|
|
53
53
|
"@uniweb/snapshot": {
|
|
54
54
|
"version": "1.1.0"
|
|
55
55
|
},
|
|
56
56
|
"@uniweb/templates": {
|
|
57
|
-
"version": "1.1.
|
|
57
|
+
"version": "1.1.3"
|
|
58
58
|
},
|
|
59
59
|
"@uniweb/theming": {
|
|
60
60
|
"version": "1.2.0"
|