uniweb 1.13.1 → 1.13.2

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": "uniweb",
3
- "version": "1.13.1",
3
+ "version": "1.13.2",
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/core": "~1.3.0",
45
+ "@uniweb/semantic-parser": "~1.12.1",
44
46
  "@uniweb/content-writer": "~1.3.0",
45
- "@uniweb/schemas": "~1.5.0",
46
- "@uniweb/semantic-parser": "~1.12.0",
47
- "@uniweb/core": "~1.3.0"
47
+ "@uniweb/schemas": "~1.5.0"
48
48
  },
49
49
  "peerDependencies": {
50
- "@uniweb/content-reader": "~1.5.2",
51
- "@uniweb/semantic-parser": "~1.12.0",
52
- "@uniweb/build": "~1.5.1"
50
+ "@uniweb/build": "~1.5.2",
51
+ "@uniweb/semantic-parser": "~1.12.1",
52
+ "@uniweb/content-reader": "~1.5.3"
53
53
  },
54
54
  "peerDependenciesMeta": {
55
55
  "@uniweb/build": {
@@ -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 an older alternative rendering from `block.rawContent` (raw ProseMirror), including data blocks. Prefer `Prose` for new components.
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 Tailwind Typography's `prose` classes. One line in the foundation's `styles.css` supplies them and points them at the site's theme:
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"; /* the plugin, wired to theme.yml */
1117
+ @import "@uniweb/kit/prose-tokens.css"; /* kit's prose layer, wired to theme.yml */
1118
1118
  ```
1119
1119
 
1120
- Nothing to install — the import brings the plugin with it. **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. Use **one** `prose` container per subtree — the `--tw-prose-*` variables are inherited, so a nested one silently resets them and the outer container goes on looking correct. The section that renders the document is usually the better owner; a layout should supply column width and padding.
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. A utility class or an element variant (`prose-headings:font-display`, `prose-a:no-underline`) overrides any rule. 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 — passed internally by `<Article block={block} />` |
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
@@ -190,6 +190,30 @@ export function rendersKitProse(dir) {
190
190
  )
191
191
  }
192
192
 
193
+ /** Does a stylesheet load Tailwind Typography itself? */
194
+ export function loadsTypographyPlugin(styles) {
195
+ return /@plugin\s+["']@tailwindcss\/typography["']/.test(String(styles || ''))
196
+ }
197
+
198
+ /**
199
+ * Tailwind Typography's palette modifiers and `prose-invert`, wherever a
200
+ * foundation's source names one in a class list — `dark:prose-invert` included.
201
+ * Comments are skipped, since a comment warning against one names it too.
202
+ *
203
+ * @returns {{ file: string, modifiers: string[] }[]}
204
+ */
205
+ export function inertProseModifiers(dir) {
206
+ const MODIFIER =
207
+ /(?:^|[\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
208
+ const found = []
209
+ forEachSourceFile(dir, (text, file) => {
210
+ const code = text.replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:])\/\/.*$/gm, '$1')
211
+ const modifiers = [...new Set([...code.matchAll(MODIFIER)].map((m) => m[1]))]
212
+ if (modifiers.length) found.push({ file, modifiers })
213
+ })
214
+ return found
215
+ }
216
+
193
217
  function sourceMatches(dir, pattern) {
194
218
  let found = false
195
219
  forEachSourceFile(dir, (text) => {
@@ -1200,13 +1224,14 @@ export async function doctor(args = []) {
1200
1224
 
1201
1225
  // Prose without the tokens — a silent, total loss of styling.
1202
1226
  //
1203
- // `@uniweb/kit/prose-tokens.css` brings Tailwind Typography with it and then
1204
- // points it at the site's theme.yml. A foundation that writes `prose` (or
1205
- // renders <Prose>/<Article>, which emit it) and does NOT import that file
1206
- // gets the class and no rules behind it: correct markup, zero styling, and
1207
- // nothing reported anywhere. Measured 2026-07-30 on a foundation missing only
1208
- // the plugin — every paragraph `margin-top: 0px`, no warning from Vite,
1209
- // Tailwind or the browser.
1227
+ // `@uniweb/kit/prose-tokens.css` is kit's prose layer, which answers to the
1228
+ // site's theme.yml. A foundation that writes `prose` (or renders
1229
+ // <Prose>/<Article>, which emit it) and does NOT import that file gets the
1230
+ // class and no rules behind it: correct markup, zero styling, and nothing
1231
+ // reported anywhere. Measured 2026-07-30 on a foundation missing only the
1232
+ // rules — every paragraph `margin-top: 0px`, no warning from Vite, Tailwind or
1233
+ // the browser. (Then the rules were Tailwind Typography's; kit's own since
1234
+ // 2026-10-19.)
1210
1235
  //
1211
1236
  // kit closes this for anyone who imports the file; this closes it for anyone
1212
1237
  // who does not, which is the case kit cannot reach.
@@ -1237,13 +1262,63 @@ export async function doctor(args = []) {
1237
1262
  })
1238
1263
  warn(`[${id}] ${f.name} ${reason}, with no prose styling behind it`)
1239
1264
  log(
1240
- ` Tailwind Typography supplies the rules and it is not loaded, so the ` +
1265
+ ` kit's prose layer supplies the rules and it is not imported, so the ` +
1241
1266
  `markup is correct and completely unstyled — silently.`
1242
1267
  )
1243
1268
  log(` Add to ${f.folderName}/styles.css:`)
1244
1269
  log(` ${colors.dim}@import "@uniweb/kit/prose-tokens.css";${colors.reset}`)
1245
1270
  }
1246
1271
 
1272
+ // A modifier kit's prose layer does not have — `prose-slate`, `prose-invert`
1273
+ // and the rest of Tailwind Typography's palettes. Since 2026-10-19 the layer
1274
+ // takes every color from the section's theme tokens, so a class list still
1275
+ // naming one styles nothing and says a design the page does not have.
1276
+ // Only where the foundation imports kit's layer and does not load the plugin
1277
+ // itself — with its own `@plugin`, the modifier still means what it says.
1278
+ for (const f of foundations) {
1279
+ const stylesPath = join(f.path, 'styles.css')
1280
+ if (!existsSync(stylesPath)) continue
1281
+ const styles = readFileSync(stylesPath, 'utf8')
1282
+ if (!styles.includes('@uniweb/kit/prose-tokens.css')) continue
1283
+ if (loadsTypographyPlugin(styles)) {
1284
+ // Both: the plugin's rules sit in a layer above kit's and win, so prose is
1285
+ // the plugin's again — its own greys, and none of the --prose-* variables.
1286
+ const id = 'prose-plugin-alongside'
1287
+ issues.push({
1288
+ id,
1289
+ type: 'warning',
1290
+ foundation: f.name,
1291
+ message: `${f.name} loads Tailwind Typography as well as kit's prose layer`
1292
+ })
1293
+ warn(`[${id}] ${f.name} loads Tailwind Typography as well as kit's prose layer`)
1294
+ log(
1295
+ ` The plugin's rules sit above kit's and win: prose takes the plugin's greys, not the ` +
1296
+ `theme's colors, and the --prose-* variables reach nothing.`
1297
+ )
1298
+ log(` Remove the @plugin line from ${f.folderName}/styles.css to use kit's layer alone.`)
1299
+ continue
1300
+ }
1301
+
1302
+ const found = inertProseModifiers(f.path)
1303
+ if (found.length === 0) continue
1304
+
1305
+ const id = 'prose-modifier-inert'
1306
+ const names = [...new Set(found.flatMap((x) => x.modifiers))]
1307
+ issues.push({
1308
+ id,
1309
+ type: 'warning',
1310
+ foundation: f.name,
1311
+ message: `${f.name} names ${names.join(', ')}, which kit's prose layer does not have`
1312
+ })
1313
+ warn(`[${id}] ${f.name} names ${names.join(', ')} — they no longer do anything`)
1314
+ for (const { file, modifiers } of found.slice(0, 6)) log(` ${file}: ${modifiers.join(', ')}`)
1315
+ log(
1316
+ ` Prose takes its colors from the section's theme tokens, so it already follows ` +
1317
+ `theme.yml and the visitor's scheme. Remove these; to change what prose looks like, ` +
1318
+ `set the theme's colors, or the --prose-* variables.`
1319
+ )
1320
+ }
1321
+
1247
1322
  // ⛔ SAY WHEN A CHECK DID NOT RUN. Every foundation check below reads the
1248
1323
  // BUILT `dist/meta/schema.json` — what a consumer actually receives — and
1249
1324
  // returns silently when there is none. In a workspace with a site, "Foundation
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-10-19T02:42:59.650Z",
3
+ "generatedAt": "2026-10-19T17:17:22.841Z",
4
4
  "packages": {
5
5
  "@uniweb/api": {
6
- "version": "1.5.2"
6
+ "version": "1.6.0"
7
7
  },
8
8
  "@uniweb/build": {
9
- "version": "1.5.1"
9
+ "version": "1.5.2"
10
10
  },
11
11
  "@uniweb/content-reader": {
12
- "version": "1.5.2"
12
+ "version": "1.5.3"
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.4.0"
27
+ "version": "1.5.0"
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.8"
39
+ "version": "1.1.9"
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.0"
51
+ "version": "1.12.1"
52
52
  },
53
53
  "@uniweb/snapshot": {
54
54
  "version": "1.1.0"
55
55
  },
56
56
  "@uniweb/templates": {
57
- "version": "1.1.1"
57
+ "version": "1.1.2"
58
58
  },
59
59
  "@uniweb/theming": {
60
60
  "version": "1.2.0"