@uniweb/kit 0.19.7 → 0.19.9

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/kit",
3
- "version": "0.19.7",
3
+ "version": "0.19.9",
4
4
  "description": "Standard component library for Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
@@ -43,10 +43,11 @@
43
43
  "shiki": "^3.0.0",
44
44
  "tailwind-merge": "^3.6.0",
45
45
  "temml": "^0.13.2",
46
- "@uniweb/projections": "^0.7.6",
47
- "@uniweb/core": "^0.32.0",
46
+ "@uniweb/core": "^0.33.0",
47
+ "@uniweb/projections": "^0.7.9",
48
+ "@uniweb/semantic-parser": "^1.4.1",
48
49
  "@uniweb/scene": "^0.1.3",
49
- "@uniweb/semantic-parser": "^1.4.1"
50
+ "@uniweb/schemas": "^0.8.3"
50
51
  },
51
52
  "peerDependencies": {
52
53
  "react": "^19.0.0",
@@ -0,0 +1,36 @@
1
+ /**
2
+ * SectionBackground — the background the author set on a section, drawn by the runtime's own
3
+ * renderer, for a component that places it itself.
4
+ *
5
+ * The runtime draws a section's background behind every section, so most components need
6
+ * nothing. A component that paints its own — a hero with a built-in gradient, a background
7
+ * that belongs inside a card — declares `background: 'self'` in its `meta.js`, and the runtime
8
+ * then draws none. With this it can still draw what the author chose, wherever it wants,
9
+ * without rebuilding the image, video, gradient and overlay handling.
10
+ *
11
+ * It fills the nearest positioned ancestor (`position: absolute; inset: 0`), so place it inside
12
+ * an element with `position: relative`, before the content.
13
+ *
14
+ * @param {Object} props
15
+ * @param {Object} props.block - The section's block — its `block.background`, normalized by core
16
+ * @param {string} [props.className] - Classes on the background layer
17
+ *
18
+ * @example
19
+ * function Hero({ content, block }) {
20
+ * return (
21
+ * <section className="relative">
22
+ * <SectionBackground block={block} />
23
+ * <div className="relative z-10">…</div>
24
+ * </section>
25
+ * )
26
+ * }
27
+ */
28
+ export function SectionBackground({ block, className }) {
29
+ const background = block?.background
30
+ if (!background?.mode) return null
31
+ const Renderer = globalThis.uniweb?.backgroundRenderer
32
+ if (!Renderer) return null
33
+ return <Renderer {...background} className={className} />
34
+ }
35
+
36
+ export default SectionBackground
@@ -0,0 +1 @@
1
+ export { SectionBackground, default } from './SectionBackground.jsx'
@@ -89,31 +89,28 @@ export function useThemeData() {
89
89
  }
90
90
 
91
91
  /**
92
- * Get the current section's color context.
92
+ * The color context a section renders in: `'light'`, `'medium'` or `'dark'`.
93
93
  *
94
- * Note: This requires the component to receive the block prop.
95
- * For components that don't have block access, use a default or pass context explicitly.
94
+ * A section pinned with `theme:` renders in that context. One that follows the site — no
95
+ * `theme:` — renders in the site's current scheme, so on a dark-scheme site it is `'dark'`.
96
+ * This is how a component reads its context for its own logic, a light or dark logo say:
97
+ * `theme` is a setting of the section, never one of the component's params. ⛔ Until
98
+ * 2026-09-28 a section that follows the site read as `'light'` whatever the scheme.
96
99
  *
97
- * @param {Object} block - Block instance (optional)
98
- * @returns {string} Context name ('light', 'medium', or 'dark')
100
+ * @param {Object} block - The section's Block
101
+ * @returns {'light'|'medium'|'dark'}
99
102
  *
100
103
  * @example
101
- * function MyComponent({ block }) {
104
+ * function Logo({ block }) {
102
105
  * const context = useColorContext(block)
103
- * return <div className={`context-${context}`}>...</div>
106
+ * return <img src={context === 'dark' ? '/logo-light.svg' : '/logo.svg'} alt="" />
104
107
  * }
105
108
  */
106
109
  export function useColorContext(block) {
107
- // Get context from block's theme property
108
- const context = block?.themeName || block?.theme || 'light'
109
-
110
- // Validate context name
111
- const validContexts = ['light', 'medium', 'dark']
112
- if (validContexts.includes(context)) {
113
- return context
114
- }
115
-
116
- return 'light'
110
+ const { scheme } = useAppearance()
111
+ const pinned = block?.themeName
112
+ if (pinned === 'light' || pinned === 'medium' || pinned === 'dark') return pinned
113
+ return scheme === 'dark' ? 'dark' : 'light'
117
114
  }
118
115
 
119
116
  /**
package/src/index.js CHANGED
@@ -40,6 +40,9 @@ export { Asset } from './components/Asset/index.js'
40
40
  // Data loading
41
41
  export { DataPlaceholder } from './components/DataPlaceholder.jsx'
42
42
 
43
+ // A section's background, for a component that draws it itself (`background: 'self'`)
44
+ export { SectionBackground } from './components/SectionBackground/index.js'
45
+
43
46
  // Social
44
47
  export {
45
48
  SocialIcon,
@@ -158,6 +161,7 @@ export { Article } from './styled/Article/index.jsx'
158
161
  export { Code, Alert, Warning, Table, Details, Divider } from './styled/Section/renderers/index.js'
159
162
  export { Disclaimer } from './styled/Disclaimer/index.js'
160
163
  export { Visual } from './styled/Visual/index.jsx'
164
+ export { ChildGrid } from './styled/ChildGrid/index.jsx'
161
165
  export { Scene } from './styled/Scene/index.jsx'
162
166
 
163
167
  // ============================================================================
@@ -0,0 +1,74 @@
1
+ /**
2
+ * ChildGrid — a section's child sections, laid out in the columns its author chose.
3
+ *
4
+ * The author chooses with the section's reserved `grid:` key — `3` (equal columns) or
5
+ * `'40/60'` (relative widths) — one of the layouts the component offers in `meta.js`
6
+ * (`children: { grid: [2, 3, '40/60'] }`). A component opts in by rendering its
7
+ * children through this, so what a visual editor draws from the same value
8
+ * (`gridTemplate`, `@uniweb/schemas/grid`) is what renders.
9
+ *
10
+ * Narrow screens get one column; from the `md` breakpoint a layout of up to two
11
+ * columns applies as chosen and a wider one shows two equal columns; from `lg` the
12
+ * chosen layout applies whatever its width.
13
+ *
14
+ * ⭐ Each child renders as a section, in a `div`: its own `theme:` and `background:`
15
+ * apply, and it carries the `section-{id}` its theme rules select [2026-09-28]. ⛔ Until
16
+ * then the children rendered bare, and a child's theme and background did nothing.
17
+ *
18
+ * @module @uniweb/kit/styled/ChildGrid
19
+ */
20
+
21
+ import React from 'react'
22
+ import { parseGrid, gridTemplate } from '@uniweb/schemas/grid'
23
+ import { ChildBlocks, cn } from '../../utils/index.js'
24
+
25
+ const TWO_EQUAL = 'repeat(2, minmax(0, 1fr))'
26
+
27
+ /**
28
+ * @param {Object} props
29
+ * @param {Object} props.from - the section's Block; its `childBlocks` are laid out
30
+ * @param {number|string} [props.fallback] - the layout when the section chose none
31
+ * (or chose something that is not a layout) — the component's default
32
+ * @param {boolean} [props.headerRow] - the first child spans every column
33
+ * @param {string} [props.className] - classes on the grid, e.g. a gap (`gap-8` by default)
34
+ * @param {string} [props.cellClassName] - classes on each child's cell
35
+ *
36
+ * @example
37
+ * <ChildGrid from={block} fallback={3} headerRow={params.headerRow} className="gap-6" />
38
+ */
39
+ export function ChildGrid({ from: block, fallback = null, headerRow = false, className, cellClassName }) {
40
+ const children = block?.childBlocks || []
41
+ if (children.length === 0) return null
42
+
43
+ const choice = parseGrid(block.grid) ? block.grid : fallback
44
+ const layout = parseGrid(choice)
45
+ const style = layout
46
+ ? {
47
+ '--uniweb-grid-cols': gridTemplate(choice),
48
+ '--uniweb-grid-cols-md': layout.columns <= 2 ? gridTemplate(choice) : TWO_EQUAL,
49
+ }
50
+ : undefined
51
+
52
+ return (
53
+ <div
54
+ className={cn(
55
+ 'grid grid-cols-1 gap-8',
56
+ layout && 'md:grid-cols-[var(--uniweb-grid-cols-md)] lg:grid-cols-[var(--uniweb-grid-cols)]',
57
+ className
58
+ )}
59
+ style={style}
60
+ data-grid={layout ? String(choice) : undefined}
61
+ >
62
+ {children.map((child, index) => (
63
+ <div
64
+ key={child.id || index}
65
+ className={cn(headerRow && index === 0 && 'md:col-span-full', cellClassName)}
66
+ >
67
+ <ChildBlocks blocks={[child]} wrapAs="div" />
68
+ </div>
69
+ ))}
70
+ </div>
71
+ )
72
+ }
73
+
74
+ export default ChildGrid
@@ -87,14 +87,15 @@ export const NOT_RENDERED = {
87
87
  dataBlock:
88
88
  'structured data, not prose — a component reads it from content.data[tag]',
89
89
  inset_ref:
90
- 'a BUILD-TIME intermediate. The reader emits it for `![](@Component)`; the ' +
91
- 'build\'s content-collector extracts it into the section\'s insets and leaves ' +
90
+ 'the stored form of a leaf inset (`![](@Component)`, `[@key]`, `[#id]`). ' +
91
+ '@uniweb/core lifts it when it builds a Block — a placeholder in place, a ' +
92
+ 'Block in `block.insets` — so a section\'s content reaches this renderer as ' +
92
93
  'an `inset_placeholder`, which is what the `inset` case resolves. Its attrs ' +
93
94
  'carry a component NAME and no refId, so there is nothing here to look up — ' +
94
95
  'and kit answering for the name is the shadowing the inset_block case ' +
95
- 'refuses. Consequence worth knowing: a document rendered straight from ' +
96
- 'markdown without that build step (a record body, say) loses its ' +
97
- 'inline component references.',
96
+ 'refuses. Consequence worth knowing: a document rendered here WITHOUT a Block ' +
97
+ 'built over it (a record\'s body passed straight in, say) keeps its ' +
98
+ 'inset_ref nodes, and they render nothing.',
98
99
  form: 'an editor node; its data reaches components as content.data[schemaId]',
99
100
  'card-group': 'an editor node, deprecated — maps to content.data[cardType]',
100
101
  'document-group': 'an editor node — its documents reach content.links',
@@ -42,6 +42,9 @@ export { Disclaimer } from './Disclaimer/index.js'
42
42
  // Visual - Unified visual renderer (inset > video > image)
43
43
  export { Visual } from './Visual/index.jsx'
44
44
 
45
+ // ChildGrid - A section's child sections in the columns its `grid:` chose
46
+ export { ChildGrid } from './ChildGrid/index.jsx'
47
+
45
48
  // Media - Video player with styled play button facade
46
49
  export { Media } from './Media/index.js'
47
50