@uniweb/kit 0.7.1 → 0.7.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/README.md CHANGED
@@ -47,14 +47,6 @@ function Hero({ content }) {
47
47
  }
48
48
  ```
49
49
 
50
- ## Exports Overview
51
-
52
- | Import Path | Purpose |
53
- |-------------|---------|
54
- | `@uniweb/kit` | Core components, hooks, and utilities |
55
- | `@uniweb/kit/styled` | Pre-styled components (Section, SidebarLayout, etc.) |
56
- | `@uniweb/kit/search` | Search client and hooks (requires Fuse.js) |
57
-
58
50
  ---
59
51
 
60
52
  ## Components
@@ -395,7 +387,7 @@ function ThemedComponent({ block }) {
395
387
 
396
388
  ---
397
389
 
398
- ## Search (`@uniweb/kit/search`)
390
+ ## Search
399
391
 
400
392
  Full-text search powered by Fuse.js. Requires `fuse.js` as a peer dependency in your foundation.
401
393
 
@@ -408,7 +400,7 @@ npm install fuse.js
408
400
  Main search hook with debouncing and state management.
409
401
 
410
402
  ```jsx
411
- import { useSearch } from '@uniweb/kit/search'
403
+ import { useSearch, useWebsite } from '@uniweb/kit'
412
404
 
413
405
  function SearchComponent() {
414
406
  const { website } = useWebsite()
@@ -433,7 +425,7 @@ function SearchComponent() {
433
425
  Intent-based preloading — loads search index on hover/focus instead of page load.
434
426
 
435
427
  ```jsx
436
- import { useSearchWithIntent, useSearchShortcut } from '@uniweb/kit/search'
428
+ import { useSearchWithIntent, useSearchShortcut } from '@uniweb/kit'
437
429
 
438
430
  function SearchButton({ onClick }) {
439
431
  const { website } = useWebsite()
@@ -460,7 +452,7 @@ This saves bandwidth — the search index only loads when users show intent to s
460
452
  Keyboard shortcut for opening search.
461
453
 
462
454
  ```jsx
463
- import { useSearchShortcut } from '@uniweb/kit/search'
455
+ import { useSearchShortcut } from '@uniweb/kit'
464
456
 
465
457
  // Simple
466
458
  useSearchShortcut(() => setSearchOpen(true))
@@ -477,7 +469,7 @@ useSearchShortcut({
477
469
  Low-level search client for advanced use.
478
470
 
479
471
  ```jsx
480
- import { createSearchClient } from '@uniweb/kit/search'
472
+ import { createSearchClient } from '@uniweb/kit'
481
473
 
482
474
  const client = createSearchClient(website, {
483
475
  fuseOptions: { threshold: 0.3 },
@@ -497,12 +489,12 @@ client.getIndexUrl()
497
489
 
498
490
  ---
499
491
 
500
- ## Styled Components (`@uniweb/kit/styled`)
492
+ ## Styled Components
501
493
 
502
- Pre-styled components with Tailwind CSS. Import separately to keep core kit dependency-free.
494
+ Pre-styled components with Tailwind CSS.
503
495
 
504
496
  ```jsx
505
- import { Section, SidebarLayout, Disclaimer } from '@uniweb/kit/styled'
497
+ import { Section, SidebarLayout, Disclaimer } from '@uniweb/kit'
506
498
 
507
499
  <Section width="lg" padding="md" className="bg-gray-50">
508
500
  <h1>Welcome</h1>
package/package.json CHANGED
@@ -1,16 +1,10 @@
1
1
  {
2
2
  "name": "@uniweb/kit",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Standard component library for Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./src/index.js",
8
- "./styled": "./src/styled/index.js",
9
- "./styles": {
10
- "style": "./src/styles/index.css",
11
- "default": "./src/styles/index.css"
12
- },
13
- "./search": "./src/search/index.js",
14
8
  "./theme-tokens.css": {
15
9
  "style": "./src/theme-tokens.css",
16
10
  "default": "./src/theme-tokens.css"
@@ -46,7 +40,7 @@
46
40
  "fuse.js": "^7.0.0",
47
41
  "shiki": "^3.0.0",
48
42
  "tailwind-merge": "^2.6.0",
49
- "@uniweb/core": "0.5.2"
43
+ "@uniweb/core": "0.5.4"
50
44
  },
51
45
  "peerDependencies": {
52
46
  "react": "^18.0.0 || ^19.0.0",
package/src/index.js CHANGED
@@ -2,26 +2,14 @@
2
2
  * @uniweb/kit
3
3
  *
4
4
  * Standard component library for Uniweb foundations.
5
- *
6
- * For pre-styled components (Section, SidebarLayout, Disclaimer, etc.),
7
- * import from '@uniweb/kit/styled'.
5
+ * All components, hooks, and utilities are exported from this single entry point.
8
6
  *
9
7
  * @example
10
- * import { Link, Image, useWebsite } from '@uniweb/kit'
11
- *
12
- * function MyComponent() {
13
- * const { localize } = useWebsite()
14
- * return (
15
- * <Link to="/about">
16
- * <Image src="/logo.png" alt="Logo" />
17
- * {localize({ en: 'About', fr: 'À propos' })}
18
- * </Link>
19
- * )
20
- * }
8
+ * import { Link, Image, Section, Render, useWebsite, cn } from '@uniweb/kit'
21
9
  */
22
10
 
23
11
  // ============================================================================
24
- // Components (Primitives - no Tailwind dependency)
12
+ // Components (Primitives)
25
13
  // ============================================================================
26
14
 
27
15
  // Navigation
@@ -38,12 +26,12 @@ export {
38
26
  PlainText
39
27
  } from './components/Text/index.js'
40
28
 
41
- // Media (plain version - for styled facade, use @uniweb/kit/tailwind)
29
+ // Media
42
30
  export { Media } from './components/Media/index.js'
43
31
  export { FileLogo } from './components/FileLogo/index.js'
44
32
  export { MediaIcon } from './components/MediaIcon/index.js'
45
33
 
46
- // Files (plain version - for styled card, use @uniweb/kit/tailwind)
34
+ // Files
47
35
  export { Asset } from './components/Asset/index.js'
48
36
 
49
37
  // Data loading
@@ -99,7 +87,30 @@ export {
99
87
  isFileUrl,
100
88
  detectMediaType,
101
89
  parseIconRef,
90
+ // Runtime utilities (getChildBlockRenderer is internal — use ChildBlocks)
91
+ getChildBlockRenderer,
92
+ ChildBlocks,
102
93
  // Locale utilities
103
94
  LOCALE_DISPLAY_NAMES,
104
95
  getLocaleLabel
105
96
  } from './utils/index.js'
97
+
98
+ // ============================================================================
99
+ // Styled Components (Tailwind-based)
100
+ // ============================================================================
101
+
102
+ export { SidebarLayout } from './styled/SidebarLayout/index.js'
103
+ export { Section, Render } from './styled/Section/index.js'
104
+ export { Prose } from './styled/Prose/index.jsx'
105
+ export { Article } from './styled/Article/index.jsx'
106
+ export { Code, Alert, Warning, Table, Details, Divider } from './styled/Section/renderers/index.js'
107
+ export { Disclaimer } from './styled/Disclaimer/index.js'
108
+ export { Visual } from './styled/Visual/index.jsx'
109
+
110
+ // ============================================================================
111
+ // Search
112
+ // ============================================================================
113
+
114
+ export { createSearchClient, loadSearchIndex, clearSearchCache } from './search/client.js'
115
+ export { buildSnippet, highlightMatches, escapeHtml } from './search/snippets.js'
116
+ export { useSearch, useSearchIndex, useSearchShortcut, useSearchWithIntent } from './search/hooks.js'
@@ -4,10 +4,10 @@
4
4
  * Provides helpers for implementing search functionality in foundations.
5
5
  * Uses Fuse.js for fuzzy search (peer dependency - must be installed by foundation).
6
6
  *
7
- * @module @uniweb/kit/search
7
+ * @module @uniweb/kit (search)
8
8
  *
9
9
  * @example
10
- * import { createSearchClient, buildSnippet } from '@uniweb/kit/search'
10
+ * import { createSearchClient, buildSnippet } from '@uniweb/kit (search)'
11
11
  *
12
12
  * // Create a search client for your site
13
13
  * const search = createSearchClient(website)
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import React from 'react'
11
- import { cn } from '../../utils/index.js'
11
+ import { cn, getChildBlockRenderer } from '../../utils/index.js'
12
12
  import { SafeHtml } from '../../components/SafeHtml/index.js'
13
13
  import { Image } from '../../components/Image/index.js'
14
14
  import { Media } from '../../components/Media/index.js'
@@ -239,17 +239,15 @@ function RenderNode({ node, block, ...props }) {
239
239
  return <Divider type={attrs?.type} className="my-6" />
240
240
  }
241
241
 
242
- case 'inline_child_placeholder': {
242
+ case 'inset_placeholder': {
243
243
  const refId = attrs?.refId
244
244
  if (!block || !refId) return null
245
245
 
246
- const childBlock = block.getInlineChild(refId)
247
- if (!childBlock) return null
246
+ const insetBlock = block.getInset(refId)
247
+ if (!insetBlock) return null
248
248
 
249
- const ChildBlocks = childBlock.getChildBlockRenderer()
250
- if (!ChildBlocks) return null
251
-
252
- return <ChildBlocks blocks={[childBlock]} as="div" />
249
+ const InsetRenderer = getChildBlockRenderer()
250
+ return <InsetRenderer blocks={[insetBlock]} as="div" />
253
251
  }
254
252
 
255
253
  case 'button': {
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Visual Component
3
+ *
4
+ * Renders the first non-empty visual from the given candidates.
5
+ * Resolution order: inset > video > image. Only tries what's passed.
6
+ *
7
+ * @module @uniweb/kit/styled/Visual
8
+ */
9
+
10
+ import React from 'react'
11
+ import { Media } from '../../components/Media/Media.jsx'
12
+ import { Image } from '../../components/Image/index.js'
13
+ import { getChildBlockRenderer } from '../../utils/index.js'
14
+
15
+ /**
16
+ * Renders the first non-empty visual from the given candidates.
17
+ *
18
+ * @param {Object} props
19
+ * @param {Object} [props.inset] - Inset Block instance (from block.insets or block.getInset())
20
+ * @param {Object} [props.video] - Video object with src property
21
+ * @param {Object} [props.image] - Image object with src and alt properties
22
+ * @param {string} [props.className] - CSS classes for the visual container
23
+ * @param {React.ReactNode} [props.fallback] - Fallback when no visual is found
24
+ *
25
+ * @example
26
+ * // Try inset first, fall back to video, then image
27
+ * <Visual inset={block.insets[0]} video={content.videos[0]} image={content.imgs[0]} />
28
+ *
29
+ * @example
30
+ * // Specific inset only
31
+ * <Visual inset={block.getInset('chart')} className="rounded-lg" />
32
+ *
33
+ * @example
34
+ * // Image only
35
+ * <Visual image={content.imgs[1]} className="aspect-video" />
36
+ */
37
+ export function Visual({ inset, video, image, className, fallback = null }) {
38
+ if (inset) {
39
+ const Renderer = getChildBlockRenderer()
40
+ return <Renderer blocks={[inset]} as="div" extra={{ className }} />
41
+ }
42
+
43
+ if (video) {
44
+ return <Media src={video.src || video} className={className} />
45
+ }
46
+
47
+ if (image) {
48
+ return <Image src={image.src || image} alt={image.alt} className={className} />
49
+ }
50
+
51
+ return fallback
52
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @uniweb/kit/styled
2
+ * @uniweb/kit (styled)
3
3
  *
4
4
  * Pre-styled components from the kit.
5
5
  *
@@ -7,7 +7,7 @@
7
7
  * For unstyled primitives, use the main '@uniweb/kit' export.
8
8
  *
9
9
  * @example
10
- * import { SidebarLayout, Section, Media } from '@uniweb/kit/styled'
10
+ * import { SidebarLayout, Section, Media } from '@uniweb/kit (styled)'
11
11
  */
12
12
 
13
13
  // ============================================================================
@@ -39,6 +39,9 @@ export { Code, Alert, Warning, Table, Details, Divider } from './Section/rendere
39
39
  // Disclaimer - Modal dialog for legal disclaimers
40
40
  export { Disclaimer } from './Disclaimer/index.js'
41
41
 
42
+ // Visual - Unified visual renderer (inset > video > image)
43
+ export { Visual } from './Visual/index.jsx'
44
+
42
45
  // Media - Video player with styled play button facade
43
46
  export { Media } from './Media/index.js'
44
47
 
@@ -133,6 +133,36 @@ export function parseIconRef(ref) {
133
133
  return null
134
134
  }
135
135
 
136
+ // ─────────────────────────────────────────────────────────────────
137
+ // Runtime Utilities
138
+ // ─────────────────────────────────────────────────────────────────
139
+
140
+ /**
141
+ * Get the child block renderer component from the runtime.
142
+ * Internal — used by Visual and Render. Components should use ChildBlocks instead.
143
+ */
144
+ export function getChildBlockRenderer() {
145
+ return globalThis.uniweb.childBlockRenderer
146
+ }
147
+
148
+ /**
149
+ * Renders child blocks or insets. Wrapper that defers runtime lookup to render time.
150
+ *
151
+ * @param {Object} props
152
+ * @param {Object} props.from - Parent block (renders block.childBlocks)
153
+ * @param {Array} props.blocks - Explicit array of blocks to render
154
+ *
155
+ * @example
156
+ * import { ChildBlocks } from '@uniweb/kit'
157
+ *
158
+ * <ChildBlocks from={block} />
159
+ * <ChildBlocks blocks={block.insets} />
160
+ */
161
+ export function ChildBlocks(props) {
162
+ const Renderer = globalThis.uniweb.childBlockRenderer
163
+ return Renderer(props)
164
+ }
165
+
136
166
  // ─────────────────────────────────────────────────────────────────
137
167
  // Class / String Utilities
138
168
  // ─────────────────────────────────────────────────────────────────