@bettercms-ai/next 0.28.0 → 0.30.0
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/dist/blocks.js +1 -1
- package/dist/blocks.js.map +1 -1
- package/dist/draft-bridge.js +1 -1
- package/dist/draft-bridge.js.map +1 -1
- package/dist/elements.d.ts +51 -0
- package/dist/elements.js +130 -0
- package/dist/elements.js.map +1 -0
- package/dist/form.d.ts +1 -1
- package/dist/form.js +1 -1
- package/dist/form.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/search.js +1 -1
- package/dist/search.js.map +1 -1
- package/package.json +8 -3
package/dist/search.d.ts
CHANGED
package/dist/search.js
CHANGED
package/dist/search.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/search.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * <BcmsSearch> — an instant, typo-tolerant site-search box for React/Next.\n *\n * Debounced search-as-you-type against the public delivery search endpoint (via\n * `@bettercms-ai/sdk`'s `search`), rendering a dropdown of results under the input.\n * No API key — `project` (from the dashboard's Site Search settings) is the only\n * scope. All markup is unstyled and `bcms-search-*` class-driven, so the host\n * site owns the look. Mirrors <BcmsForm>.\n */\n\nimport { useEffect, useRef, useState, type ReactElement } from \"react\";\nimport { search, type SearchHit } from \"@bettercms-ai/sdk\";\n\nexport interface BcmsSearchProps {\n /** The project id (from Site Search settings). */\n project: string;\n /** API origin. Defaults to the SDK default (https://api.bettercms.ai). */\n apiBase?: string;\n /** Placeholder for the input. */\n placeholder?: string;\n /** Max results, 1–20 (default 8). */\n limit?: number;\n /** Debounce in ms (default 200). */\n debounceMs?: number;\n /** Class for the wrapper; inner elements use `bcms-search-*` classes. */\n className?: string;\n /** Called when a result is chosen; return false to suppress the default navigation. */\n onSelect?: (hit: SearchHit) => boolean | void;\n}\n\nexport function BcmsSearch({\n project,\n apiBase,\n placeholder = \"Search…\",\n limit,\n debounceMs = 200,\n className,\n onSelect,\n}: BcmsSearchProps): ReactElement {\n const [query, setQuery] = useState(\"\");\n const [hits, setHits] = useState<SearchHit[]>([]);\n const [open, setOpen] = useState(false);\n const [active, setActive] = useState(-1);\n const wrap = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const q = query.trim();\n if (q.length < 2) {\n setHits([]);\n setOpen(false);\n return;\n }\n const ctrl = new AbortController();\n const t = setTimeout(() => {\n search({ project, q, limit, baseUrl: apiBase, signal: ctrl.signal }).then((r) => {\n setHits(r);\n setActive(-1);\n setOpen(true);\n });\n }, debounceMs);\n return () => {\n clearTimeout(t);\n ctrl.abort();\n };\n }, [query, project, apiBase, limit, debounceMs]);\n\n // Close on outside click.\n useEffect(() => {\n const onClick = (e: MouseEvent) => {\n if (wrap.current && !wrap.current.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener(\"click\", onClick);\n return () => document.removeEventListener(\"click\", onClick);\n }, []);\n\n const choose = (hit: SearchHit) => {\n if (onSelect?.(hit) === false) return;\n window.location.href = hit.url;\n };\n\n const onKeyDown = (e: React.KeyboardEvent) => {\n if (!open || !hits.length) return;\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive((i) => (i + 1) % hits.length);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((i) => (i - 1 + hits.length) % hits.length);\n } else if (e.key === \"Enter\" && active >= 0) {\n e.preventDefault();\n choose(hits[active]);\n } else if (e.key === \"Escape\") {\n setOpen(false);\n }\n };\n\n return (\n <div ref={wrap} className={`bcms-search${className ? ` ${className}` : \"\"}`} style={{ position: \"relative\" }}>\n <input\n type=\"search\"\n className=\"bcms-search-input\"\n placeholder={placeholder}\n aria-label=\"Search this site\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n onFocus={() => hits.length && setOpen(true)}\n />\n {open && (\n <div className=\"bcms-search-results\" role=\"listbox\">\n {hits.length === 0 ? (\n <div className=\"bcms-search-empty\">No results</div>\n ) : (\n hits.map((hit, i) => (\n <a\n key={`${hit.type}:${hit.slug}`}\n href={hit.url}\n role=\"option\"\n aria-selected={i === active}\n className={`bcms-search-hit${i === active ? \" is-active\" : \"\"}`}\n onClick={(e) => {\n e.preventDefault();\n choose(hit);\n }}\n >\n <span className=\"bcms-search-title\">{hit.title}</span>\n {hit.snippet && (\n <span\n className=\"bcms-search-snippet\"\n dangerouslySetInnerHTML={{ __html: hit.snippet }}\n />\n )}\n </a>\n ))\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/search.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * <BcmsSearch> — an instant, typo-tolerant site-search box for React/Next.\n *\n * Debounced search-as-you-type against the public delivery search endpoint (via\n * `@bettercms-ai/sdk`'s `search`), rendering a dropdown of results under the input.\n * No API key — `project` (from the dashboard's Site Search settings) is the only\n * scope. All markup is unstyled and `bcms-search-*` class-driven, so the host\n * site owns the look. Mirrors <BcmsForm>.\n */\n\nimport { useEffect, useRef, useState, type ReactElement } from \"react\";\nimport { search, type SearchHit } from \"@bettercms-ai/sdk/read\";\n\nexport interface BcmsSearchProps {\n /** The project id (from Site Search settings). */\n project: string;\n /** API origin. Defaults to the SDK default (https://api.bettercms.ai). */\n apiBase?: string;\n /** Placeholder for the input. */\n placeholder?: string;\n /** Max results, 1–20 (default 8). */\n limit?: number;\n /** Debounce in ms (default 200). */\n debounceMs?: number;\n /** Class for the wrapper; inner elements use `bcms-search-*` classes. */\n className?: string;\n /** Called when a result is chosen; return false to suppress the default navigation. */\n onSelect?: (hit: SearchHit) => boolean | void;\n}\n\nexport function BcmsSearch({\n project,\n apiBase,\n placeholder = \"Search…\",\n limit,\n debounceMs = 200,\n className,\n onSelect,\n}: BcmsSearchProps): ReactElement {\n const [query, setQuery] = useState(\"\");\n const [hits, setHits] = useState<SearchHit[]>([]);\n const [open, setOpen] = useState(false);\n const [active, setActive] = useState(-1);\n const wrap = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const q = query.trim();\n if (q.length < 2) {\n setHits([]);\n setOpen(false);\n return;\n }\n const ctrl = new AbortController();\n const t = setTimeout(() => {\n search({ project, q, limit, baseUrl: apiBase, signal: ctrl.signal }).then((r) => {\n setHits(r);\n setActive(-1);\n setOpen(true);\n });\n }, debounceMs);\n return () => {\n clearTimeout(t);\n ctrl.abort();\n };\n }, [query, project, apiBase, limit, debounceMs]);\n\n // Close on outside click.\n useEffect(() => {\n const onClick = (e: MouseEvent) => {\n if (wrap.current && !wrap.current.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener(\"click\", onClick);\n return () => document.removeEventListener(\"click\", onClick);\n }, []);\n\n const choose = (hit: SearchHit) => {\n if (onSelect?.(hit) === false) return;\n window.location.href = hit.url;\n };\n\n const onKeyDown = (e: React.KeyboardEvent) => {\n if (!open || !hits.length) return;\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive((i) => (i + 1) % hits.length);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((i) => (i - 1 + hits.length) % hits.length);\n } else if (e.key === \"Enter\" && active >= 0) {\n e.preventDefault();\n choose(hits[active]);\n } else if (e.key === \"Escape\") {\n setOpen(false);\n }\n };\n\n return (\n <div ref={wrap} className={`bcms-search${className ? ` ${className}` : \"\"}`} style={{ position: \"relative\" }}>\n <input\n type=\"search\"\n className=\"bcms-search-input\"\n placeholder={placeholder}\n aria-label=\"Search this site\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n onFocus={() => hits.length && setOpen(true)}\n />\n {open && (\n <div className=\"bcms-search-results\" role=\"listbox\">\n {hits.length === 0 ? (\n <div className=\"bcms-search-empty\">No results</div>\n ) : (\n hits.map((hit, i) => (\n <a\n key={`${hit.type}:${hit.slug}`}\n href={hit.url}\n role=\"option\"\n aria-selected={i === active}\n className={`bcms-search-hit${i === active ? \" is-active\" : \"\"}`}\n onClick={(e) => {\n e.preventDefault();\n choose(hit);\n }}\n >\n <span className=\"bcms-search-title\">{hit.title}</span>\n {hit.snippet && (\n <span\n className=\"bcms-search-snippet\"\n dangerouslySetInnerHTML={{ __html: hit.snippet }}\n />\n )}\n </a>\n ))\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bettercms-ai/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The BetterCMS adapter for Next.js — typed, cache-aware content reads (getEntry/listEntries), draft preview, build-time content snapshot, and llms.txt generation for the App Router. The /blocks, /form, /field, /search and /visual-editing entries are framework-free React and work in any React app (see the React+TS starter), which is why `next` is an OPTIONAL peer.",
|
|
6
6
|
"bin": {
|
|
@@ -50,6 +50,11 @@
|
|
|
50
50
|
"types": "./dist/draft-bridge.d.ts",
|
|
51
51
|
"import": "./dist/draft-bridge.js",
|
|
52
52
|
"default": "./dist/draft-bridge.js"
|
|
53
|
+
},
|
|
54
|
+
"./elements": {
|
|
55
|
+
"types": "./dist/elements.d.ts",
|
|
56
|
+
"import": "./dist/elements.js",
|
|
57
|
+
"default": "./dist/elements.js"
|
|
53
58
|
}
|
|
54
59
|
},
|
|
55
60
|
"files": [
|
|
@@ -66,8 +71,8 @@
|
|
|
66
71
|
"@bettercms-ai/icons": "^0.3.0",
|
|
67
72
|
"@bettercms-ai/image-url": "^0.4.0",
|
|
68
73
|
"@bettercms-ai/richtext": "^0.12.0",
|
|
69
|
-
"@bettercms-ai/sdk": "^1.
|
|
70
|
-
"@bettercms-ai/types": "^1.
|
|
74
|
+
"@bettercms-ai/sdk": "^1.34.0",
|
|
75
|
+
"@bettercms-ai/types": "^1.50.2",
|
|
71
76
|
"@bettercms-ai/ui": "^0.20.0",
|
|
72
77
|
"react-phone-number-input": "^3.4.18"
|
|
73
78
|
},
|