@uniweb/kit 0.14.0 → 0.15.1

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.14.0",
3
+ "version": "0.15.1",
4
4
  "description": "Standard component library for Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
@@ -44,8 +44,8 @@
44
44
  "shiki": "^3.0.0",
45
45
  "tailwind-merge": "^3.6.0",
46
46
  "temml": "^0.13.2",
47
- "@uniweb/core": "^0.13.0",
48
- "@uniweb/semantic-parser": "^1.3.1",
47
+ "@uniweb/semantic-parser": "^1.4.0",
48
+ "@uniweb/core": "^0.15.0",
49
49
  "@uniweb/scene": "^0.1.3"
50
50
  },
51
51
  "peerDependencies": {
@@ -2,7 +2,7 @@ export { useWebsite, default } from './useWebsite.js'
2
2
  export { useFetched } from './useFetched.js'
3
3
  export { useCacheEntry } from './useCacheEntry.js'
4
4
  export { useEntityDetail } from './useEntityDetail.js'
5
- export { useCollectionQueryable } from './useCollectionQueryable.js'
5
+ export { useQueryable } from './useQueryable.js'
6
6
  export { useRouting } from './useRouting.js'
7
7
  export { useActiveRoute } from './useActiveRoute.js'
8
8
  export { useVersion } from './useVersion.js'
@@ -1,20 +1,20 @@
1
1
  /**
2
- * useEntityDetail — fetch the full record for a deferred-field collection.
2
+ * useEntityDetail — fetch the full record for a query with deferred fields.
3
3
  *
4
- * When a collection declares `deferred: [...]` in `site.yml`, the cascade
4
+ * When a query declares `deferred: [...]`, the cascade
5
5
  * payload omits the deferred fields. The full record (with deferred
6
6
  * fields included) lives somewhere — either at a per-record file the
7
7
  * build emits, or at an author-declared API endpoint. This hook fetches
8
8
  * that full record on demand.
9
9
  *
10
- * Two source patterns, picked automatically from the collection's
10
+ * Two source patterns, picked automatically from the query's
11
11
  * declaration:
12
12
  *
13
- * - Markdown-backed collections (declared with `path:` in site.yml).
14
- * The build emits `/data/<collection>/<slug>.json` per record. The
13
+ * - File-backed records (a query over `entities/{schema}/`).
14
+ * The build emits `/data/<query>/<slug>.json` per record. The
15
15
  * hook fetches that path.
16
16
  *
17
- * - API-backed collections (declared with `url:` in site.yml plus a
17
+ * - Remote sources (a query declaring `url:` plus a
18
18
  * `detailUrl:` pattern). The hook substitutes `{slug}` in the
19
19
  * pattern and fetches that URL.
20
20
  *
@@ -31,7 +31,7 @@
31
31
  * function ArticleCard({ article }) {
32
32
  * const [open, setOpen] = useState(false)
33
33
  * const { data: full, loading } = useEntityDetail(open ? article : null, {
34
- * collection: 'articles',
34
+ * query: 'articles',
35
35
  * })
36
36
  * return (
37
37
  * <div>
@@ -48,18 +48,18 @@ import { getUniweb, resolveFetchConfigs, buildDetailConfig } from '@uniweb/core'
48
48
  import { useFetched } from './useFetched.js'
49
49
 
50
50
  /**
51
- * @param {Object|null} record - A record from a cascade-delivered collection.
51
+ * @param {Object|null} record - A record from a cascade-delivered query.
52
52
  * Must have a `slug` field. Pass null/undefined to skip the fetch.
53
53
  * @param {Object} [options]
54
- * @param {string} options.collection - The collection name (e.g., 'articles').
55
- * Required when record is non-null. Used to look up the collection's
54
+ * @param {string} options.query - The query name (e.g., 'articles').
55
+ * Required when record is non-null. Used to look up the query's
56
56
  * `detailUrl:` (if declared) or fall back to the static-file default
57
57
  * `/data/<collection>/<slug>.json`.
58
58
  * @returns {{ data: any, error: string|null, loading: boolean }}
59
59
  */
60
60
  export function useEntityDetail(record, options = {}) {
61
- const collection = options?.collection
62
- const request = buildDetailRequest(record, collection)
61
+ const query = options?.query
62
+ const request = buildDetailRequest(record, query)
63
63
  const result = useFetched(request)
64
64
 
65
65
  // No separate detail source for this collection — nothing was stripped from
@@ -69,7 +69,7 @@ export function useEntityDetail(record, options = {}) {
69
69
  // guaranteed 404, because that file is only written for a `deferred:`
70
70
  // collection. `useFetched` is still called above — unconditionally, as the
71
71
  // rules of hooks require — and simply skips on a null request.
72
- if (record && collection && !request) {
72
+ if (record && query && !request) {
73
73
  return { data: record, error: null, loading: false }
74
74
  }
75
75
  return result
@@ -79,7 +79,7 @@ export function useEntityDetail(record, options = {}) {
79
79
  * Build the fetch request for one record's full payload.
80
80
  *
81
81
  * ⛔ THIS MUST NOT DECIDE THE ADDRESS ITSELF, and it used to. It read
82
- * `config.collections[name].detailUrl` directly and otherwise composed
82
+ * `config.queries[name].detailUrl` directly and otherwise composed
83
83
  * `/data/<name>/<slug>.json` by hand, which was wrong three ways: it 404'd on
84
84
  * any collection without `deferred:` (that file is only written for one), it
85
85
  * could not see a host's live record lane at all, and its hand-rolled `{slug}`
@@ -98,24 +98,24 @@ export function useEntityDetail(record, options = {}) {
98
98
  * Exported for tests only — not re-exported from the package index.
99
99
  *
100
100
  * @param {Object|null} record
101
- * @param {string} collection
101
+ * @param {string} query
102
102
  * @returns {{path?: string, url?: string, endpoint?: string, schema: string}|null}
103
103
  */
104
- export function buildDetailRequest(record, collection) {
104
+ export function buildDetailRequest(record, query) {
105
105
  const slug = record?.slug
106
- if (!slug || !collection) return null
106
+ if (!slug || !query) return null
107
107
 
108
108
  const website = getUniweb()?.activeWebsite
109
109
  const config = website?.config
110
110
 
111
111
  // One synthetic source, resolved by the shared rule — same inputs the
112
112
  // EntityStore passes, so the hook cannot disagree with the page it sits on.
113
- const resolved = resolveFetchConfigs([{ collection, schema: collection }], {
114
- collections: config?.collections ?? null,
113
+ const resolved = resolveFetchConfigs([{ query, schema: query }], {
114
+ queries: config?.queries ?? null,
115
115
  records: config?.records ?? null,
116
116
  locale: website?.getActiveLocale?.() ?? null,
117
117
  defaultLocale: website?.getDefaultLocale?.() ?? null,
118
- }).get(collection)
118
+ }).get(query)
119
119
 
120
120
  if (!resolved) return null
121
121
 
@@ -14,7 +14,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
14
14
  *
15
15
  * What it deliberately does NOT own is the rendering. Which control a `type`
16
16
  * maps to, how it looks, how an error reads — that is the foundation's design
17
- * and its whole reason for existing. Same split as `useCollectionQueryable`:
17
+ * and its whole reason for existing. Same split as `useQueryable`:
18
18
  * the kit hands over the metadata and the state, the foundation builds the
19
19
  * controls against them.
20
20
  *
@@ -1,25 +1,29 @@
1
1
  /**
2
- * useCollectionQueryable — read the queryable-surface metadata for a
3
- * collection.
2
+ * useQueryable — read the queryable-surface metadata for a named query.
4
3
  *
5
- * Authors declare the queryable surface of an entity in `site.yml`:
4
+ * ⛔ RENAMED FROM `useQueryable`. An earlier pass kept the old name to
5
+ * avoid breaking foundations — but nothing is published yet, and the word was
6
+ * hiding the conflation this whole change removes: `queryable:` is declared on a
7
+ * QUERY, and a query is not a set of files.
6
8
  *
7
- * collections:
8
- * members:
9
- * path: collections/members
10
- * queryable:
11
- * department:
12
- * type: enum
13
- * label: Department
14
- * options: [biology, physics, chemistry, geology]
15
- * tenured:
16
- * type: boolean
17
- * label: Tenured
18
- * start_year:
19
- * type: range
20
- * label: Start year
21
- * min: 1800
22
- * max: 2025
9
+ * Authors declare the queryable surface on a named QUERY, in `queries.yml`
10
+ * (or under `queries:` in `site.yml`):
11
+ *
12
+ * members:
13
+ * schema: '@std/person'
14
+ * queryable:
15
+ * department:
16
+ * type: enum
17
+ * label: Department
18
+ * options: [biology, physics, chemistry, geology]
19
+ * tenured:
20
+ * type: boolean
21
+ * label: Tenured
22
+ * start_year:
23
+ * type: range
24
+ * label: Start year
25
+ * min: 1800
26
+ * max: 2025
23
27
  *
24
28
  * Foundations consume this hook to render filter UIs and compose
25
29
  * where-objects from user interactions. The kit doesn't ship UI
@@ -29,7 +33,7 @@
29
33
  *
30
34
  * @example
31
35
  * function MemberFilters({ onChange }) {
32
- * const queryable = useCollectionQueryable('members')
36
+ * const queryable = useQueryable('members')
33
37
  * const [values, setValues] = useState({})
34
38
  * if (!queryable) return null
35
39
  * return (
@@ -53,22 +57,22 @@
53
57
  *
54
58
  * Returns null when the collection has no `queryable:` declared.
55
59
  *
56
- * @param {string} collectionName - Name of the collection to read queryable
60
+ * @param {string} queryName - Name of the collection to read queryable
57
61
  * metadata for. Pass null/undefined to skip (returns null).
58
62
  * @returns {Object|null} The queryable metadata object, or null.
59
63
  */
60
64
 
61
65
  import { getUniweb } from '@uniweb/core'
62
66
 
63
- export function useCollectionQueryable(collectionName) {
64
- if (!collectionName) return null
67
+ export function useQueryable(queryName) {
68
+ if (!queryName) return null
65
69
  const website = getUniweb()?.activeWebsite
66
70
  if (!website) return null
67
- const config = website.config?.collections?.[collectionName]
71
+ const config = website.config?.queries?.[queryName]
68
72
  if (!config || typeof config !== 'object') return null
69
73
  const queryable = config.queryable
70
74
  if (!queryable || typeof queryable !== 'object') return null
71
75
  return queryable
72
76
  }
73
77
 
74
- export default useCollectionQueryable
78
+ export default useQueryable
package/src/index.js CHANGED
@@ -58,7 +58,7 @@ export {
58
58
  useFetched,
59
59
  useCacheEntry,
60
60
  useEntityDetail,
61
- useCollectionQueryable,
61
+ useQueryable,
62
62
  useRouting,
63
63
  useActiveRoute,
64
64
  useVersion,
@@ -93,7 +93,7 @@ export const NOT_RENDERED = {
93
93
  'carry a component NAME and no refId, so there is nothing here to look up — ' +
94
94
  'and kit answering for the name is the shadowing the inset_block case ' +
95
95
  'refuses. Consequence worth knowing: a document rendered straight from ' +
96
- 'markdown without that build step (a collection record body, say) loses its ' +
96
+ 'markdown without that build step (a record body, say) loses its ' +
97
97
  'inline component references.',
98
98
  form: 'an editor node; its data reaches components as content.data[schemaId]',
99
99
  'card-group': 'an editor node, deprecated — maps to content.data[cardType]',