@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 +5 -4
- package/src/components/SectionBackground/SectionBackground.jsx +36 -0
- package/src/components/SectionBackground/index.js +1 -0
- package/src/hooks/useThemeData.js +14 -17
- package/src/index.js +4 -0
- package/src/styled/ChildGrid/index.jsx +74 -0
- package/src/styled/Render/index.jsx +6 -5
- package/src/styled/index.js +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/kit",
|
|
3
|
-
"version": "0.19.
|
|
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/
|
|
47
|
-
"@uniweb/
|
|
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/
|
|
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
|
-
*
|
|
92
|
+
* The color context a section renders in: `'light'`, `'medium'` or `'dark'`.
|
|
93
93
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
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 -
|
|
98
|
-
* @returns {
|
|
100
|
+
* @param {Object} block - The section's Block
|
|
101
|
+
* @returns {'light'|'medium'|'dark'}
|
|
99
102
|
*
|
|
100
103
|
* @example
|
|
101
|
-
* function
|
|
104
|
+
* function Logo({ block }) {
|
|
102
105
|
* const context = useColorContext(block)
|
|
103
|
-
* return <
|
|
106
|
+
* return <img src={context === 'dark' ? '/logo-light.svg' : '/logo.svg'} alt="" />
|
|
104
107
|
* }
|
|
105
108
|
*/
|
|
106
109
|
export function useColorContext(block) {
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
'
|
|
91
|
-
'
|
|
90
|
+
'the stored form of a leaf inset (``, `[@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
|
|
96
|
-
'
|
|
97
|
-
'
|
|
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',
|
package/src/styled/index.js
CHANGED
|
@@ -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
|
|