lit-rdf 0.3.3 → 0.3.4
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/CHANGELOG.md +6 -0
- package/package.json +9 -5
- package/skills/lit-rdf/SKILL.md +30 -0
- package/skills/lit-rdf/agents/openai.yaml +4 -0
- package/skills/lit-rdf/assets/people-demo.ts +100 -0
- package/skills/lit-rdf/references/binding.md +101 -0
- package/skills/lit-rdf/references/patterns.md +100 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lit-rdf",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"
|
|
6
|
+
"postinstall": "skills experimental_sync -y",
|
|
7
|
+
"prepare": "husky && patch-package",
|
|
7
8
|
"lint": "eslint . --quiet",
|
|
9
|
+
"lint:skills": "skill-check check skills --no-security-scan --fail-on-warning",
|
|
8
10
|
"storybook": "storybook dev -p 6006",
|
|
9
11
|
"build-storybook": "storybook build",
|
|
10
12
|
"test:storybook": "vitest --project=storybook",
|
|
@@ -17,6 +19,7 @@
|
|
|
17
19
|
"release": "changeset publish"
|
|
18
20
|
},
|
|
19
21
|
"files": [
|
|
22
|
+
"skills/lit-rdf/",
|
|
20
23
|
"CHANGELOG.md",
|
|
21
24
|
"custom-elements.json",
|
|
22
25
|
"src/**/*.js",
|
|
@@ -41,7 +44,7 @@
|
|
|
41
44
|
"@rdfjs/data-model": "^2.1.1",
|
|
42
45
|
"@rdfjs/dataset": "^2.0.3",
|
|
43
46
|
"@rdfjs/types": "^2",
|
|
44
|
-
"@zazuko/env": "^3.0.
|
|
47
|
+
"@zazuko/env": "^3.0.6",
|
|
45
48
|
"clownface": "^2.0.3",
|
|
46
49
|
"clownface-shacl-path": "^2.4.0",
|
|
47
50
|
"is-url": "^1.2.4",
|
|
@@ -60,8 +63,8 @@
|
|
|
60
63
|
"@eslint/js": "^10",
|
|
61
64
|
"@lit-labs/ssr": "^4.1.0",
|
|
62
65
|
"@open-wc/testing": "^5.0.0",
|
|
63
|
-
"@rollup/plugin-commonjs": "^29.0.3",
|
|
64
66
|
"@rolldown/plugin-node-polyfills": "^1.0.3",
|
|
67
|
+
"@rollup/plugin-commonjs": "^29.0.3",
|
|
65
68
|
"@storybook/addon-docs": "^10.6.6",
|
|
66
69
|
"@storybook/addon-vitest": "^10.6.6",
|
|
67
70
|
"@storybook/web-components-vite": "^10.6.6",
|
|
@@ -86,10 +89,11 @@
|
|
|
86
89
|
"eslint-plugin-storybook": "^10.5.7",
|
|
87
90
|
"husky": "^9.1.7",
|
|
88
91
|
"lint-staged": "^17.3.0",
|
|
89
|
-
"skills": "^1.7.6",
|
|
90
92
|
"patch-package": "^8.0.1",
|
|
91
93
|
"playwright": "^1.65.0",
|
|
92
94
|
"sinon": "^22.1.0",
|
|
95
|
+
"skill-check": "^1.2.0",
|
|
96
|
+
"skills": "^1.7.6",
|
|
93
97
|
"storybook": "^10.6.6",
|
|
94
98
|
"string-to-stream": "^3.0.1",
|
|
95
99
|
"typescript": "^5",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lit-rdf
|
|
3
|
+
description: Use when building or explaining RDF-driven Lit interfaces with lit-rdf, including dataset binding, focus-node context, graph traversal, filtering, sorting, and custom reactive components. Covers lit-rdf examples and integrations; excludes generic RDF processing and unrelated Lit components.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build with lit-rdf
|
|
7
|
+
|
|
8
|
+
Use the library's context providers and Clownface pointers to compose views. Preserve RDF terms and datasets through the binding layer instead of converting the graph into unrelated JSON models.
|
|
9
|
+
|
|
10
|
+
## Choose the example
|
|
11
|
+
|
|
12
|
+
- For initial setup, data sources, selecting resources, labels, links, and traversal, read [binding.md](references/binding.md).
|
|
13
|
+
- For repeated cards or tables, filters, sorting, custom controllers, and application updates, read [patterns.md](references/patterns.md).
|
|
14
|
+
- For a complete starting point, adapt [people-demo.ts](assets/people-demo.ts). It supplies its own RDF/JS fixture and renders a sorted, filtered list with per-person context. Import it from a browser TypeScript entrypoint with bare-module resolution, then place `<rdf-people-demo></rdf-people-demo>` in the page. It needs `lit`, `lit-rdf`, and `@zazuko/env`; it is not a standalone browser script.
|
|
15
|
+
|
|
16
|
+
## Binding contract
|
|
17
|
+
|
|
18
|
+
The usual hierarchy is `rdf-environment` → `rdf-dataset` → `target-node` → optional `filter-node` → a view consuming `FocusNode`. Contributing `rdf-graph` elements belong beneath the dataset. A custom view iterates `FocusNode.array` and wraps each item in `<focus-node .focusNode=${item}>` so nested resource elements consume that item.
|
|
19
|
+
|
|
20
|
+
`target-node`, `filter-node`, and `focus-node` provide context; they do not stamp one copy of their children per resource. Use an explicit renderer for collections. Traversal offers rendering callbacks, but those callbacks also need per-item `focus-node` wrappers when rendering nested resource elements.
|
|
21
|
+
|
|
22
|
+
Use attributes for serialized IRIs and paths, and Lit property bindings for objects and functions. Examples: `target-class="schema:Person"`, `.targetClass=${rdf.ns.schema.Person}`, `.value=${dataset}`, `.filter=${callback}`, `.focusNode=${pointer}`. Attribute converters do not run for property bindings.
|
|
23
|
+
|
|
24
|
+
Import `lit-rdf` for element registration; import controllers from `lit-rdf/controllers.js` and the environment mixin from `lit-rdf/mixins.js`. The root entrypoint does not export controller classes. Avoid private `src/` imports in consumer examples.
|
|
25
|
+
|
|
26
|
+
## Demonstrate the binding
|
|
27
|
+
|
|
28
|
+
Use the public exports supported by the installed version of `lit-rdf`.
|
|
29
|
+
|
|
30
|
+
Examples should include data matching their vocabulary, every required import, and a real collection renderer when multiple nodes are selected. Explain the expected visible output and how the dataset, focus, and nested bindings connect. These are display bindings; implement input-to-RDF writes explicitly when requested.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { html, LitElement } from 'lit'
|
|
2
|
+
import type { GraphPointer } from 'clownface'
|
|
3
|
+
import type { NamedNode } from '@rdfjs/types'
|
|
4
|
+
import rdf from '@zazuko/env/web.js'
|
|
5
|
+
import { FocusNode } from 'lit-rdf/controllers.js'
|
|
6
|
+
import 'lit-rdf'
|
|
7
|
+
|
|
8
|
+
const alice = rdf.namedNode('https://example.org/alice')
|
|
9
|
+
const bob = rdf.namedNode('https://example.org/bob')
|
|
10
|
+
const carol = rdf.namedNode('https://example.org/carol')
|
|
11
|
+
const people: [NamedNode, string, number][] = [
|
|
12
|
+
[alice, 'Alice', 32], [bob, 'Bob', 16], [carol, 'Carol', 24],
|
|
13
|
+
]
|
|
14
|
+
const graph = rdf.dataset([
|
|
15
|
+
...people.flatMap(
|
|
16
|
+
([person, name, age]) => {
|
|
17
|
+
return [
|
|
18
|
+
rdf.quad(person, rdf.ns.rdf.type, rdf.ns.schema.Person),
|
|
19
|
+
rdf.quad(person, rdf.ns.schema.name, rdf.literal(String(name))),
|
|
20
|
+
rdf.quad(person, rdf.ns.foaf.age,
|
|
21
|
+
rdf.literal(String(age), rdf.ns.xsd.integer)),
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
),
|
|
25
|
+
rdf.quad(alice, rdf.ns.schema.knows, carol),
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
class RdfPeopleCards extends LitElement {
|
|
29
|
+
private readonly focusController = new FocusNode(this)
|
|
30
|
+
|
|
31
|
+
render() {
|
|
32
|
+
const people = this.focusController.array ?? []
|
|
33
|
+
if (!people.length) return html`<p>No matching people</p>`
|
|
34
|
+
|
|
35
|
+
return people.map(person => html`
|
|
36
|
+
<focus-node .focusNode=${person}>
|
|
37
|
+
<article>
|
|
38
|
+
<h2><resource-label predicate="schema:name"></resource-label></h2>
|
|
39
|
+
<p>Age: ${person.out(rdf.ns.foaf.age).value}</p>
|
|
40
|
+
<resource-link>Resource URI</resource-link>
|
|
41
|
+
<p>Friends: ${person.out(rdf.ns.schema.knows).toArray().map(friend => html`
|
|
42
|
+
<focus-node .focusNode=${friend}>
|
|
43
|
+
<resource-label predicate="schema:name"></resource-label>
|
|
44
|
+
</focus-node>
|
|
45
|
+
`)}</p>
|
|
46
|
+
</article>
|
|
47
|
+
</focus-node>
|
|
48
|
+
`)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
customElements.define('rdf-people-cards', RdfPeopleCards)
|
|
52
|
+
|
|
53
|
+
class RdfPeopleDemo extends LitElement {
|
|
54
|
+
static properties = {
|
|
55
|
+
minimumAge: { type: Number },
|
|
56
|
+
direction: { type: String },
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
declare minimumAge: number
|
|
60
|
+
declare direction: 'asc' | 'desc'
|
|
61
|
+
|
|
62
|
+
constructor() {
|
|
63
|
+
super()
|
|
64
|
+
this.minimumAge = 18
|
|
65
|
+
this.direction = 'asc'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
render() {
|
|
69
|
+
return html`
|
|
70
|
+
<label>Minimum age
|
|
71
|
+
<input type="number" .value=${String(this.minimumAge)}
|
|
72
|
+
@input=${(event: Event) => {
|
|
73
|
+
this.minimumAge = (event.target as HTMLInputElement).valueAsNumber
|
|
74
|
+
}}>
|
|
75
|
+
</label>
|
|
76
|
+
<button @click=${() => {
|
|
77
|
+
this.direction = this.direction === 'asc' ? 'desc' : 'asc'
|
|
78
|
+
}}>Reverse name order</button>
|
|
79
|
+
<rdf-environment>
|
|
80
|
+
<rdf-dataset>
|
|
81
|
+
<rdf-graph .value=${graph}></rdf-graph>
|
|
82
|
+
<target-node target-class="schema:Person"
|
|
83
|
+
order-by="schema:name" order-dir=${this.direction}>
|
|
84
|
+
<filter-node .filter=${(person: GraphPointer) => {
|
|
85
|
+
const age = person.out(rdf.ns.foaf.age).value
|
|
86
|
+
return age !== undefined && Number(age) >= this.minimumAge
|
|
87
|
+
}}>
|
|
88
|
+
<rdf-people-cards></rdf-people-cards>
|
|
89
|
+
</filter-node>
|
|
90
|
+
</target-node>
|
|
91
|
+
</rdf-dataset>
|
|
92
|
+
</rdf-environment>
|
|
93
|
+
`
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
customElements.define('rdf-people-demo', RdfPeopleDemo)
|
|
97
|
+
|
|
98
|
+
// Initially: Alice (32, friend Carol), then Carol (24).
|
|
99
|
+
// Minimum age 0 includes Bob (16); 100 displays “No matching people”.
|
|
100
|
+
// Reversing order changes the initial list to Carol, then Alice.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Declarative binding
|
|
2
|
+
|
|
3
|
+
## Supply data and select one resource
|
|
4
|
+
|
|
5
|
+
This is a complete Lit render function for a browser application with package imports resolved by its build tool:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { html, render } from 'lit'
|
|
9
|
+
import rdf from '@zazuko/env/web.js'
|
|
10
|
+
import 'lit-rdf'
|
|
11
|
+
|
|
12
|
+
const alice = rdf.namedNode('https://example.org/alice')
|
|
13
|
+
const dataset = rdf.dataset([
|
|
14
|
+
rdf.quad(alice, rdf.ns.rdf.type, rdf.ns.schema.Person),
|
|
15
|
+
rdf.quad(alice, rdf.ns.schema.name, rdf.literal('Alice')),
|
|
16
|
+
rdf.quad(alice, rdf.ns.schema.url, rdf.namedNode('https://alice.example.org/')),
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
render(html`
|
|
20
|
+
<rdf-environment>
|
|
21
|
+
<rdf-dataset .value=${dataset}>
|
|
22
|
+
<target-node target-node="https://example.org/alice">
|
|
23
|
+
<h2><resource-label predicate="schema:name"></resource-label></h2>
|
|
24
|
+
<resource-link property="schema:url">Homepage</resource-link>
|
|
25
|
+
</target-node>
|
|
26
|
+
</rdf-dataset>
|
|
27
|
+
</rdf-environment>
|
|
28
|
+
`, document.body)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Expected output: a heading “Alice” and a “Homepage” anchor linking to `https://alice.example.org/`. The environment supplies RDF factories; the dataset supplies the graph; the target supplies a Clownface pointer; resource elements consume that pointer.
|
|
32
|
+
|
|
33
|
+
`resource-label` defaults to `rdfs:label`. Specify `predicate="schema:name"` for schema names; there is no automatic fallback across arbitrary label predicates. `resource-link` uses the focus URI when `property` is absent or resolves no value. Supply its visible content in the default slot. `resource-value` displays the current pointer's raw `.value`; it has no predicate lookup or datatype formatting API.
|
|
34
|
+
|
|
35
|
+
## Compose graph sources
|
|
36
|
+
|
|
37
|
+
Use either a dataset bound directly to `rdf-dataset.value`, as above, or child graph contributions:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
html`
|
|
41
|
+
<rdf-environment>
|
|
42
|
+
<rdf-dataset>
|
|
43
|
+
<rdf-graph .value=${peopleDataset}></rdf-graph>
|
|
44
|
+
<rdf-graph .value=${labelsDataset}
|
|
45
|
+
graph="https://example.org/graphs/labels"></rdf-graph>
|
|
46
|
+
<!-- Put selection and view components here. -->
|
|
47
|
+
</rdf-dataset>
|
|
48
|
+
</rdf-environment>
|
|
49
|
+
`
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Here `peopleDataset` and `labelsDataset` are RDF/JS DatasetCore objects, not strings. Graph contributions are merged; without a `graph` override their existing quad graph terms are preserved. Setting `graph` rewrites all contributed quads to that named graph. Graph contribution updates rebuild `rdf-dataset.value`, so avoid treating its direct value binding as an additional independently merged source.
|
|
53
|
+
|
|
54
|
+
`rdf-graph` has no `src` URL loader or inline Turtle parser. Fetch/parse RDF in application code, then bind the resulting dataset. Its `window.graphs` lookup is an optional preloaded factory mechanism keyed by `data-graph` or `id`, not a network loader. The current update hook watches `value`; changing only `graph` does not resubmit the contribution.
|
|
55
|
+
|
|
56
|
+
## Select focus nodes
|
|
57
|
+
|
|
58
|
+
| Attribute | Property binding type | Meaning |
|
|
59
|
+
|----------------------|---------------------------------|-----------------------------------|
|
|
60
|
+
| `target-node` | `.targetNode` = NamedNode | Explicit resource |
|
|
61
|
+
| `target-class` | `.targetClass` = NamedNode | Subjects with matching `rdf:type` |
|
|
62
|
+
| `target-subjects-of` | `.targetSubjectsOf` = NamedNode | Subjects of a predicate |
|
|
63
|
+
| `target-objects-of` | `.targetObjectsOf` = NamedNode | Objects of a predicate |
|
|
64
|
+
|
|
65
|
+
Use one selector per element. If several are set, the implementation chooses in the table's order; it does not combine them. Prefixed attributes use the library's known prefixes. Use a full IRI or a NamedNode property binding for application vocabularies; declaring a prefix in Turtle does not register it with attribute converters.
|
|
66
|
+
|
|
67
|
+
## Traverse from a single resource
|
|
68
|
+
|
|
69
|
+
Inside a per-resource focus, a single-valued property can be displayed as:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
html`
|
|
73
|
+
<traverse-graph property-path="foaf:age">
|
|
74
|
+
<resource-value></resource-value>
|
|
75
|
+
<span slot="empty">Age unknown</span>
|
|
76
|
+
</traverse-graph>
|
|
77
|
+
`
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`property-path` is parsed as a SPARQL/SHACL path. For example, `schema:knows/schema:name` follows friends to their names, and `^schema:knows` follows incoming relationships. A `.propertyPath` binding expects the parsed SHACL path object, not the serialized string.
|
|
81
|
+
|
|
82
|
+
For multiple results, choose a callback rather than relying on the `.value` of a multi-pointer:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import type { GraphPointer } from 'clownface'
|
|
86
|
+
|
|
87
|
+
html`
|
|
88
|
+
<traverse-graph property-path="schema:knows"
|
|
89
|
+
.renderObjectNode=${(friend: GraphPointer) => html`
|
|
90
|
+
<focus-node .focusNode=${friend}>
|
|
91
|
+
<p><resource-label predicate="schema:name"></resource-label></p>
|
|
92
|
+
</focus-node>
|
|
93
|
+
`}>
|
|
94
|
+
<p slot="empty">No friends listed</p>
|
|
95
|
+
</traverse-graph>
|
|
96
|
+
`
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The default slot receives the entire resulting pointer, not one scoped pointer per child. `.renderObjectNodes` receives the whole multi-pointer and takes precedence over `.renderObjectNode`. Neither callback applies the ambient sort automatically.
|
|
100
|
+
|
|
101
|
+
Current implementation caveat: `traverse-graph.willUpdate` checks a `focusNode` changed-property key, while its controller calls `requestUpdate()` without that key. Initial property-path rendering is supported, but a later focus-only change may leave traversal stale. For dynamic views, derive related values directly from the current `GraphPointer` inside the collection renderer, as the demo does, or verify a library fix before relying on reactive traversal.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Collection and application patterns
|
|
2
|
+
|
|
3
|
+
## Consume a collection, then scope each item
|
|
4
|
+
|
|
5
|
+
Use [people-demo.ts](../assets/people-demo.ts) for the complete version of this pattern:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { html, LitElement } from 'lit'
|
|
9
|
+
import { FocusNode } from 'lit-rdf/controllers.js'
|
|
10
|
+
import 'lit-rdf'
|
|
11
|
+
|
|
12
|
+
class ResourceCards extends LitElement {
|
|
13
|
+
private readonly focusController = new FocusNode(this)
|
|
14
|
+
|
|
15
|
+
render() {
|
|
16
|
+
const items = this.focusController.array ?? []
|
|
17
|
+
return items.length ? items.map(item => html`
|
|
18
|
+
<focus-node .focusNode=${item}>
|
|
19
|
+
<article>
|
|
20
|
+
<resource-link>
|
|
21
|
+
<resource-label predicate="schema:name"></resource-label>
|
|
22
|
+
</resource-link>
|
|
23
|
+
</article>
|
|
24
|
+
</focus-node>
|
|
25
|
+
`) : html`<p>No matching resources</p>`
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
customElements.define('resource-cards', ResourceCards)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Place `<resource-cards>` under a target and optional filter. `FocusNode.pointer` is the entire selection. `FocusNode.array` returns per-node pointers and applies ambient sorting. The controller requests host updates when focus or sorting changes. Handle its initially undefined pointer; context becomes available through element connection.
|
|
32
|
+
|
|
33
|
+
For a table, put a `focus-node` inside each cell that needs a resource component, or scope custom row components internally. Do not insert a `focus-node` wrapper between native `table`/`tbody`/`tr` elements in parsed HTML: table parsing can relocate invalid children. For keyed collections, use a stable key appropriate to the data and ensure relation displays update when that key retains an existing component.
|
|
34
|
+
|
|
35
|
+
## Filter and sort
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import type { GraphPointer } from 'clownface'
|
|
39
|
+
import rdf from '@zazuko/env/web.js'
|
|
40
|
+
|
|
41
|
+
const minimumAge = 18
|
|
42
|
+
html`
|
|
43
|
+
<target-node target-class="schema:Person"
|
|
44
|
+
order-by="schema:name" order-dir="asc">
|
|
45
|
+
<filter-node .filter=${(person: GraphPointer) => {
|
|
46
|
+
const age = person.out(rdf.ns.foaf.age).value
|
|
47
|
+
return age !== undefined && Number(age) >= minimumAge
|
|
48
|
+
}}>
|
|
49
|
+
<resource-cards></resource-cards>
|
|
50
|
+
</filter-node>
|
|
51
|
+
</target-node>
|
|
52
|
+
`
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The filter is a Clownface callback passed as a property. An omitted callback passes the current selection through. For interactive thresholds, keep the threshold in reactive host state and create a new callback in `render()` so `.filter` changes when the threshold changes. A stable callback closing over mutable state alone does not notify `filter-node` to recompute.
|
|
56
|
+
|
|
57
|
+
`order-by` converts a predicate IRI to a key extractor. For a custom key use `.orderBy=${(person: GraphPointer) => person.out(rdf.ns.schema.name).value?.toLowerCase()}`. Consumers must use `FocusNode.array` to honor that sort context. Merely wrapping arbitrary slotted markup in `target-node` does not reorder it.
|
|
58
|
+
|
|
59
|
+
Sorting converts RDF literals to comparable JS values. Use typed numeric/date literals for numeric/date ordering; plain string literals sort as strings. Missing keys sort last in both directions.
|
|
60
|
+
|
|
61
|
+
## Supply an existing pointer
|
|
62
|
+
|
|
63
|
+
If the host already has a Clownface pointer, bind it directly with `<focus-node .focusNode=${pointer}>`. Descendant resource elements can consume it without `target-node`. Keep `rdf-environment` and `rdf-dataset` ancestors when other descendants require those contexts. Do not pass a bare IRI or a dataset as `.focusNode`.
|
|
64
|
+
|
|
65
|
+
## Custom context consumers and providers
|
|
66
|
+
|
|
67
|
+
Public imports:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { Dataset, Environment, FocusNode } from 'lit-rdf/controllers.js'
|
|
71
|
+
import { provideEnvironment } from 'lit-rdf/mixins.js'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- `new Environment(this)` consumes an ancestor environment; `.value` throws if no provider exists. Access it after connection, rather than assuming availability in the host constructor.
|
|
75
|
+
- `new Dataset(this, dataset => { /* update host state */ })` consumes dataset changes and exposes `.value` and a Clownface `.pointer`. Update reactive host state or request an update in the callback if the host renders dataset-derived values.
|
|
76
|
+
- `new FocusNode(this)` consumes focus and sorting, exposes `.pointer` and sorted `.array`, and requests updates automatically. `.onChange` can recompute derived state.
|
|
77
|
+
- `class Host extends provideEnvironment(LitElement)` supplies an environment after assigning its public `rdf` property. `rdf-environment` already provides the default web environment and is simpler for ordinary templates.
|
|
78
|
+
|
|
79
|
+
`lit-rdf/context.js` and `lit-rdf/controllers/FocusNode.js` are not exported package paths in this version. Use the public controller barrel rather than inventing context imports for consumers.
|
|
80
|
+
|
|
81
|
+
## Updates and editing
|
|
82
|
+
|
|
83
|
+
The library displays RDF data; it does not provide form-to-RDF two-way binding. To implement editing, explicitly add/delete RDF quads in application code and publish a new dataset reference through `rdf-dataset.value` or `rdf-graph.value`. In-place changes to a DatasetCore do not themselves trigger Lit property updates or context delivery. With contributed graphs, update the contribution rather than overwriting the parent's aggregate.
|
|
84
|
+
|
|
85
|
+
Example after removing a value in application code:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
const next = rdf.dataset([...current])
|
|
89
|
+
next.delete(oldQuad)
|
|
90
|
+
next.add(replacementQuad)
|
|
91
|
+
// Assign next to reactive application state bound as .value=${...}.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Keep these current limits in mind for demos involving live data:
|
|
95
|
+
|
|
96
|
+
- `target-node.setFocusNode()` only publishes selections with at least one term; a transition from matches to no matches can retain the previous focus. Do not promise that switching to an absent class clears the view without checking/fixing this behavior.
|
|
97
|
+
- `filter-node` can publish an empty pointer, so it is suitable for demonstrating a working zero-results state.
|
|
98
|
+
- For focus-only traversal updates, see the caveat in [binding.md](binding.md). The asset reads ages and friends from each current pointer in the custom renderer instead.
|
|
99
|
+
|
|
100
|
+
Prefer showing a limitation precisely to adding a broad workaround or silently changing library behavior as part of an example.
|