@kudzujs/core 0.8.6 → 0.8.7
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 +1 -1
- package/RELEASES.md +24 -0
- package/framework/build.mjs +47 -16
- package/framework/core.d.ts +1 -1
- package/framework/core.mjs +10 -4
- package/framework/list-runtime.js +36 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Kudzu compiles ordinary React-shaped TypeScript and TSX into complete static HTM
|
|
|
10
10
|
|
|
11
11
|
> Experimental `0.8.x`: the compiler API and supported TSX surface may change.
|
|
12
12
|
|
|
13
|
-
**Latest release: 0.8.
|
|
13
|
+
**Latest release: 0.8.7 - Reactive keyed row selection.** Flat keyed rows may combine their current item or index with direct primitive parent state in pure text and attribute expressions, enabling selected classes and ARIA state without remounting rows. Read the [release notes](./RELEASES.md#087---reactive-keyed-row-selection) or open the [release page](https://kudzujs.cloud/releases/0.8.7).
|
|
14
14
|
|
|
15
15
|
- [Documentation](https://kudzujs.cloud/docs)
|
|
16
16
|
- [Installation guide](https://kudzujs.cloud/docs#install)
|
package/RELEASES.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Kudzu Releases
|
|
2
2
|
|
|
3
|
+
## 0.8.7 - Reactive keyed row selection
|
|
4
|
+
|
|
5
|
+
Kudzu 0.8.7 lets a flat keyed row combine its current item or index with direct primitive parent state in pure text and attribute expressions.
|
|
6
|
+
|
|
7
|
+
### New in 0.8.7
|
|
8
|
+
|
|
9
|
+
- Selected-row classes, `aria-current`, `aria-selected`, and similar pure expressions update directly after parent-state commits.
|
|
10
|
+
- Retained rows reevaluate only their expression text and attributes; list structure, handlers, and DOM identity remain untouched.
|
|
11
|
+
- Initial static HTML evaluates the same expression with build-time state values.
|
|
12
|
+
- Calculated SVG coverage verifies focus, Space, click, insertion, reorder, latest handlers, selected classes, ARIA state, and retained node identity.
|
|
13
|
+
- A React Notes migration restores its ordinary `activeId === note.id` selected-row source without imperative DOM code.
|
|
14
|
+
- Object/array parent state, arbitrary captures, nested-row parent state, structural conditions, mutation, and arbitrary calls remain diagnosed.
|
|
15
|
+
- The complete suite passes 134/134 tests.
|
|
16
|
+
|
|
17
|
+
### Boundary
|
|
18
|
+
|
|
19
|
+
This support is limited to pure flat keyed-row text and attribute expressions over the current item/index plus direct primitive parent state. It adds no component rerenderer, VDOM, hydration, or general capture runtime.
|
|
20
|
+
|
|
21
|
+
### Upgrade
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @kudzujs/core@^0.8.7
|
|
25
|
+
```
|
|
26
|
+
|
|
3
27
|
## 0.8.6 - Responsive list reversals
|
|
4
28
|
|
|
5
29
|
Kudzu 0.8.6 fixes stale keyed-list bookkeeping after reverse and one-item removal fast paths.
|
package/framework/build.mjs
CHANGED
|
@@ -303,6 +303,7 @@ export async function build({ quiet = false, minify = true } = {}) {
|
|
|
303
303
|
.replace("function fillListItem(root, item, nested = false, index = 0)", "function fillListItem(root, item, nested = false)")
|
|
304
304
|
.replace("fillListParts(root, parts, item, revision, index, previous)", "fillListParts(root, parts, item, revision, previous)")
|
|
305
305
|
.replace("function fillListParts(root, parts, item, revision, index = 0, previous)", "function fillListParts(root, parts, item, revision, previous)")
|
|
306
|
+
.replace("fillListExpressions(root, parts, item, revision, index)", "fillListExpressions(root, parts, item, revision)")
|
|
306
307
|
.replaceAll('value?.type === "list-item" ? serializeItem(item) : value?.type === "list-index" ? index : value', 'value?.type === "list-item" ? serializeItem(item) : value')
|
|
307
308
|
.replaceAll("evaluate(descriptor, item, index)", "evaluate(descriptor, item)")
|
|
308
309
|
.replaceAll("evaluate({ module, handler }, item, index)", "evaluate({ module, handler }, item)")
|
|
@@ -311,6 +312,7 @@ export async function build({ quiet = false, minify = true } = {}) {
|
|
|
311
312
|
.replace("fillListParts(marker, listItemParts(fragment), item, revision, index)", "fillListParts(marker, listItemParts(fragment), item, revision)")
|
|
312
313
|
.replace("function evaluate(descriptor, item, index)", "function evaluate(descriptor, item)")
|
|
313
314
|
.replace("exports[descriptor.handler](item, index)", "exports[descriptor.handler](item)")
|
|
315
|
+
.replace("exports[descriptor.handler](item, index, {", "exports[descriptor.handler](item, undefined, {")
|
|
314
316
|
if (!hasCollectionSelectors) listRuntime = listRuntime.replaceAll(" && !list.descriptor.selector", "")
|
|
315
317
|
if (!hasListIndexes) listRuntime = listRuntime
|
|
316
318
|
.replaceAll(" && !list.descriptor.indexed", "")
|
|
@@ -3899,11 +3901,11 @@ function createKudzuTransformer(nativeHandlers, effectHandlers, reactiveBindings
|
|
|
3899
3901
|
}
|
|
3900
3902
|
|
|
3901
3903
|
if (ts.isJsxExpression(node) && node.expression && listValues.has(node.expression)) {
|
|
3902
|
-
return factory.updateJsxExpression(node, compileListValue(node.expression, listValues.get(node.expression), factory, listExpressions, handlerUrl))
|
|
3904
|
+
return factory.updateJsxExpression(node, compileListValue(node.expression, listValues.get(node.expression), factory, context, listExpressions, handlerUrl))
|
|
3903
3905
|
}
|
|
3904
3906
|
|
|
3905
3907
|
if (ts.isJsxAttribute(node) && node.initializer && ts.isJsxExpression(node.initializer) && node.initializer.expression && listValues.has(node.initializer.expression)) {
|
|
3906
|
-
return factory.updateJsxAttribute(node, node.name, factory.createJsxExpression(undefined, compileListValue(node.initializer.expression, listValues.get(node.initializer.expression), factory, listExpressions, handlerUrl)))
|
|
3908
|
+
return factory.updateJsxAttribute(node, node.name, factory.createJsxExpression(undefined, compileListValue(node.initializer.expression, listValues.get(node.initializer.expression), factory, context, listExpressions, handlerUrl)))
|
|
3907
3909
|
}
|
|
3908
3910
|
|
|
3909
3911
|
if (ts.isJsxExpression(node) && node.initializer === undefined && node.expression && (ts.isJsxElement(node.parent) || ts.isJsxFragment(node.parent))) {
|
|
@@ -4509,9 +4511,12 @@ function validateKeyedList(parts, sourceFile, listValues, listEventItems, listCo
|
|
|
4509
4511
|
return
|
|
4510
4512
|
}
|
|
4511
4513
|
if (referencesIdentifier(expression, item) || parts.index && referencesIdentifier(expression, parts.index)) {
|
|
4512
|
-
|
|
4514
|
+
const states = referencedStateNames(expression, setters)
|
|
4515
|
+
for (const rowState of rowStates) states.delete(rowState.state)
|
|
4516
|
+
if (parts.nested && states.size) fail(node, "Nested keyed list item expressions cannot read parent state")
|
|
4517
|
+
validateListExpression(expression, item, node, fail, parts.index, states)
|
|
4513
4518
|
if (ts.isJsxAttribute(node.parent) && ["ref", "dangerouslysetinnerhtml"].includes(node.parent.name.text.toLowerCase())) fail(node, `Keyed list item ${node.parent.name.text} is not supported`)
|
|
4514
|
-
listValues.set(node.expression, { item, index: parts.index })
|
|
4519
|
+
listValues.set(node.expression, { item, index: parts.index, states })
|
|
4515
4520
|
return
|
|
4516
4521
|
}
|
|
4517
4522
|
}
|
|
@@ -4983,7 +4988,7 @@ const assignmentOperators = new Set([
|
|
|
4983
4988
|
ts.SyntaxKind.QuestionQuestionEqualsToken
|
|
4984
4989
|
])
|
|
4985
4990
|
|
|
4986
|
-
function validateListExpression(expression, item, source, fail, index) {
|
|
4991
|
+
function validateListExpression(expression, item, source, fail, index, states = new Set()) {
|
|
4987
4992
|
const visit = node => {
|
|
4988
4993
|
if (ts.isTypeNode(node)) return
|
|
4989
4994
|
if (ts.isElementAccessExpression(node) && referencesIdentifier(node.expression, item)) {
|
|
@@ -5014,7 +5019,7 @@ function validateListExpression(expression, item, source, fail, index) {
|
|
|
5014
5019
|
fail(source, "Derived keyed list item expressions cannot call arbitrary functions")
|
|
5015
5020
|
}
|
|
5016
5021
|
}
|
|
5017
|
-
if (ts.isIdentifier(node) && isReferenceIdentifier(node) && !isJsxSyntaxIdentifier(node) && node.text !== item && node.text !== index && !pureListGlobals.has(node.text)) {
|
|
5022
|
+
if (ts.isIdentifier(node) && isReferenceIdentifier(node) && !isJsxSyntaxIdentifier(node) && node.text !== item && node.text !== index && !states.has(node.text) && !pureListGlobals.has(node.text)) {
|
|
5018
5023
|
fail(source, `Derived keyed list item expression identifier "${node.text}" is not allowed`)
|
|
5019
5024
|
}
|
|
5020
5025
|
ts.forEachChild(node, visit)
|
|
@@ -5032,10 +5037,12 @@ function containsJsx(root) {
|
|
|
5032
5037
|
return found
|
|
5033
5038
|
}
|
|
5034
5039
|
|
|
5035
|
-
function compileListExpression(read, expression, item, factory, listExpressions, handlerUrl, index) {
|
|
5040
|
+
function compileListExpression(read, expression, item, factory, listExpressions, handlerUrl, index, states = new Set()) {
|
|
5036
5041
|
const exportName = `listExpression${listExpressions.length}`
|
|
5037
|
-
listExpressions.push({ exportName, expression, item, index })
|
|
5038
|
-
|
|
5042
|
+
listExpressions.push({ exportName, expression, item, index, states })
|
|
5043
|
+
const arguments_ = [read, factory.createStringLiteral(handlerUrl), factory.createStringLiteral(exportName)]
|
|
5044
|
+
if (states.size) arguments_.push(factory.createArrayLiteralExpression([...states].map(name => factory.createArrayLiteralExpression([factory.createStringLiteral(name), factory.createIdentifier(name)]))))
|
|
5045
|
+
return factory.createCallExpression(factory.createIdentifier("__kListExpression"), undefined, arguments_)
|
|
5039
5046
|
}
|
|
5040
5047
|
|
|
5041
5048
|
function compileListConditional(entry, factory, listExpressions, handlerUrl) {
|
|
@@ -5048,11 +5055,17 @@ function compileListConditional(entry, factory, listExpressions, handlerUrl) {
|
|
|
5048
5055
|
])
|
|
5049
5056
|
}
|
|
5050
5057
|
|
|
5051
|
-
function compileListValue(expression, entry, factory, listExpressions, handlerUrl) {
|
|
5052
|
-
const
|
|
5058
|
+
function compileListValue(expression, entry, factory, context, listExpressions, handlerUrl) {
|
|
5059
|
+
const rewrite = node => {
|
|
5060
|
+
if (ts.isShorthandPropertyAssignment(node) && entry.states?.has(node.name.text)) return factory.createPropertyAssignment(node.name, factory.createPropertyAccessExpression(node.name, "value"))
|
|
5061
|
+
if (ts.isIdentifier(node) && entry.states?.has(node.text) && isReferenceIdentifier(node)) return factory.createPropertyAccessExpression(node, "value")
|
|
5062
|
+
return ts.visitEachChild(node, rewrite, context)
|
|
5063
|
+
}
|
|
5064
|
+
const initial = entry.states?.size ? ts.visitNode(expression, rewrite) : expression
|
|
5065
|
+
const read = factory.createArrowFunction(undefined, undefined, [], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), initial)
|
|
5053
5066
|
return entry.field
|
|
5054
5067
|
? factory.createCallExpression(factory.createIdentifier("__kListField"), undefined, [read, factory.createStringLiteral(entry.field)])
|
|
5055
|
-
: compileListExpression(read, expression, entry.item, factory, listExpressions, handlerUrl, entry.index)
|
|
5068
|
+
: compileListExpression(read, expression, entry.item, factory, listExpressions, handlerUrl, entry.index, entry.states)
|
|
5056
5069
|
}
|
|
5057
5070
|
|
|
5058
5071
|
function directProperty(expression, objectName) {
|
|
@@ -6307,17 +6320,35 @@ function printReactiveBinding({ exportName, expression, captures, states }) {
|
|
|
6307
6320
|
}
|
|
6308
6321
|
}
|
|
6309
6322
|
|
|
6310
|
-
function printListExpression({ exportName, expression, item, index }) {
|
|
6323
|
+
function printListExpression({ exportName, expression, item, index, states = new Set() }) {
|
|
6324
|
+
const factory = ts.factory
|
|
6325
|
+
const transformer = context => root => {
|
|
6326
|
+
const visitor = node => {
|
|
6327
|
+
if (ts.isShorthandPropertyAssignment(node) && states.has(node.name.text)) {
|
|
6328
|
+
return factory.createPropertyAssignment(node.name, factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "get"), undefined, [factory.createStringLiteral(node.name.text)]))
|
|
6329
|
+
}
|
|
6330
|
+
if (ts.isIdentifier(node) && states.has(node.text) && isReferenceIdentifier(node) && !isShadowedByParameter(node, expression)) {
|
|
6331
|
+
return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("__k"), "get"), undefined, [factory.createStringLiteral(node.text)])
|
|
6332
|
+
}
|
|
6333
|
+
return ts.visitEachChild(node, visitor, context)
|
|
6334
|
+
}
|
|
6335
|
+
return ts.visitNode(root, visitor)
|
|
6336
|
+
}
|
|
6337
|
+
const transformed = ts.transform(expression, [transformer])
|
|
6311
6338
|
const declaration = ts.factory.createFunctionDeclaration(
|
|
6312
6339
|
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
6313
6340
|
undefined,
|
|
6314
6341
|
exportName,
|
|
6315
6342
|
undefined,
|
|
6316
|
-
[ts.factory.createParameterDeclaration(undefined, undefined, item), ts.factory.createParameterDeclaration(undefined, undefined, index ?? "__kIndex")],
|
|
6343
|
+
[ts.factory.createParameterDeclaration(undefined, undefined, item), ts.factory.createParameterDeclaration(undefined, undefined, index ?? "__kIndex"), ts.factory.createParameterDeclaration(undefined, undefined, "__k")],
|
|
6317
6344
|
undefined,
|
|
6318
|
-
ts.factory.createBlock([ts.factory.createReturnStatement(
|
|
6345
|
+
ts.factory.createBlock([ts.factory.createReturnStatement(transformed.transformed[0])], true)
|
|
6319
6346
|
)
|
|
6320
|
-
|
|
6347
|
+
try {
|
|
6348
|
+
return ts.createPrinter().printNode(ts.EmitHint.Unspecified, declaration, expression.getSourceFile())
|
|
6349
|
+
} finally {
|
|
6350
|
+
transformed.dispose()
|
|
6351
|
+
}
|
|
6321
6352
|
}
|
|
6322
6353
|
|
|
6323
6354
|
function scopeRead(factory, name) {
|
package/framework/core.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export function bindingValue(value: unknown): unknown
|
|
|
38
38
|
export function conditional(kind: "and" | "ternary", value: unknown, truthy: () => unknown, falsy: () => unknown, module: string, handler: string, states: Array<[string, unknown]>, scope: Array<[string, unknown]>): unknown
|
|
39
39
|
export function list(items: unknown, keyField: string | null, render: (item: unknown, index: number) => unknown, ownerField?: string, selector?: unknown[], indexed?: boolean, selectorStates?: Array<[string, unknown]>, staticCollection?: boolean): unknown
|
|
40
40
|
export function listField(read: () => unknown, field: string): unknown
|
|
41
|
-
export function listExpression(read: () => unknown, module: string, handler: string): unknown
|
|
41
|
+
export function listExpression(read: () => unknown, module: string, handler: string, states?: Array<[string, unknown]>): unknown
|
|
42
42
|
export function listItem(): unknown
|
|
43
43
|
export function listIndex(): unknown
|
|
44
44
|
export function listConditional(kind: "and" | "ternary", read: () => unknown, truthy: () => unknown, falsy: () => unknown, module: string, handler: string): unknown
|
package/framework/core.mjs
CHANGED
|
@@ -324,11 +324,17 @@ export function listField(read, field) {
|
|
|
324
324
|
return { [listFieldMarker]: true, field, value: renderContext?.listTemplate ? undefined : read() }
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
-
export function listExpression(read, module, handler) {
|
|
327
|
+
export function listExpression(read, module, handler, states = []) {
|
|
328
328
|
renderContext?.handlerModules.add(module)
|
|
329
|
+
const stateMap = Object.fromEntries(states.map(([name, state]) => {
|
|
330
|
+
if (!state?.[signalMarker] || !validEffectDependency(state.value)) throw new Error(`Derived keyed list item expression state ${JSON.stringify(name)} must be primitive Kudzu state`)
|
|
331
|
+
return [name, state.id]
|
|
332
|
+
}))
|
|
333
|
+
const owner = renderContext?.listRoot ?? renderContext?.listRowRoot
|
|
334
|
+
if (owner && states.length) owner.descriptor.expressionStates = [...new Set([...(owner.descriptor.expressionStates ?? []), ...Object.values(stateMap)])]
|
|
329
335
|
const value = renderContext?.listTemplate ? undefined : read()
|
|
330
336
|
if (value && typeof value.then === "function") throw new Error("Derived keyed list item expressions must return synchronous values")
|
|
331
|
-
return { [listExpressionMarker]: true, module, handler, value }
|
|
337
|
+
return { [listExpressionMarker]: true, module, handler, states: stateMap, value }
|
|
332
338
|
}
|
|
333
339
|
|
|
334
340
|
export function listItem() {
|
|
@@ -659,7 +665,7 @@ async function renderNode(node, namespace, selectValue = noSelectValue) {
|
|
|
659
665
|
return `<template${marker}></template>${escapeHtml(node.value ?? "")}<template data-k-list-text-end></template>`
|
|
660
666
|
}
|
|
661
667
|
if (node?.[listExpressionMarker]) {
|
|
662
|
-
const descriptor = { module: node.module, handler: node.handler }
|
|
668
|
+
const descriptor = { module: node.module, handler: node.handler, ...(Object.keys(node.states).length ? { states: node.states } : {}) }
|
|
663
669
|
const marker = renderContext.listTemplate || renderContext.listInitialMarkers || renderContext.listConditionalBranch ? ` data-k-list-expression='${escapeJsonAttribute(descriptor)}'` : ""
|
|
664
670
|
return `<template${marker}></template>${escapeHtml(node.value ?? "")}<template data-k-list-expression-end></template>`
|
|
665
671
|
}
|
|
@@ -812,7 +818,7 @@ async function renderNode(node, namespace, selectValue = noSelectValue) {
|
|
|
812
818
|
}
|
|
813
819
|
if (value?.[listExpressionMarker]) {
|
|
814
820
|
attributes += renderAttribute(name, value.value)
|
|
815
|
-
listExpressionAttributes.push([name, value.module, value.handler])
|
|
821
|
+
listExpressionAttributes.push([name, value.module, value.handler, ...(Object.keys(value.states).length ? [value.states] : [])])
|
|
816
822
|
if (name === "style") renderContext.hasListStyles = true
|
|
817
823
|
continue
|
|
818
824
|
}
|
|
@@ -25,7 +25,10 @@ function commitLists(id) {
|
|
|
25
25
|
if (!lists) return
|
|
26
26
|
for (const list of lists) {
|
|
27
27
|
if (!list.start.isConnected) unregisterList(list.start)
|
|
28
|
-
else
|
|
28
|
+
else {
|
|
29
|
+
if (list.updateStates.has(id)) updateList(list)
|
|
30
|
+
if (list.expressionStates.has(id)) updateListExpressions(list)
|
|
31
|
+
}
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
|
|
@@ -76,6 +79,8 @@ function mountLists(root) {
|
|
|
76
79
|
...(__KUDZU_LIST_STABLE_FAST_PATHS__ ? { orderedRoots: roots } : {}),
|
|
77
80
|
values: new Map(),
|
|
78
81
|
items: undefined,
|
|
82
|
+
updateStates: new Set(),
|
|
83
|
+
expressionStates: new Set(descriptor.expressionStates ?? []),
|
|
79
84
|
container: roots[0]?.parentNode,
|
|
80
85
|
boundary: end,
|
|
81
86
|
...(__KUDZU_NESTED_LISTS__ && descriptor.ownerField ? { owner: nested.owner } : {})
|
|
@@ -93,20 +98,19 @@ function mountLists(root) {
|
|
|
93
98
|
loadListEvaluator(descriptor.source).then(evaluator => {
|
|
94
99
|
if (listLoads.get(start) !== load || !start.isConnected) return
|
|
95
100
|
list.sourceEvaluator = evaluator
|
|
96
|
-
const
|
|
101
|
+
const updateStates = [...new Set([...evaluator.stateIds, ...(__KUDZU_COLLECTION_SELECTORS__ ? Object.values(descriptor.selectorStates ?? {}) : [])])]
|
|
102
|
+
const states = [...new Set([...updateStates, ...list.expressionStates])]
|
|
103
|
+
list.updateStates = new Set(updateStates)
|
|
97
104
|
for (const state of states) register(listTargets, state, list)
|
|
98
105
|
listRegistrations.set(start, { states, list })
|
|
99
106
|
updateList(list)
|
|
100
107
|
}).catch(error => console.error(error))
|
|
101
108
|
} else {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
register(listTargets, descriptor.state, list)
|
|
108
|
-
listRegistrations.set(start, { state: descriptor.state, list })
|
|
109
|
-
}
|
|
109
|
+
const updateStates = [descriptor.state, ...(__KUDZU_COLLECTION_SELECTORS__ ? Object.values(descriptor.selectorStates ?? {}) : [])]
|
|
110
|
+
const states = [...new Set([...updateStates, ...list.expressionStates])]
|
|
111
|
+
list.updateStates = new Set(updateStates)
|
|
112
|
+
for (const state of states) register(listTargets, state, list)
|
|
113
|
+
listRegistrations.set(start, { states, list })
|
|
110
114
|
}
|
|
111
115
|
if (!descriptor.source) updateList(list)
|
|
112
116
|
}
|
|
@@ -125,7 +129,7 @@ function unregisterList(start) {
|
|
|
125
129
|
if (lists?.get(registration.list.descriptor.id) === registration.list) lists.delete(registration.list.descriptor.id)
|
|
126
130
|
if (!lists?.size) ownedLists.delete(registration.owner)
|
|
127
131
|
} else {
|
|
128
|
-
if (
|
|
132
|
+
if (registration.states) {
|
|
129
133
|
for (const state of registration.states) {
|
|
130
134
|
const lists = listTargets.get(state)
|
|
131
135
|
lists?.delete(registration.list)
|
|
@@ -647,6 +651,17 @@ function fillListParts(root, parts, item, revision, index = 0, previous) {
|
|
|
647
651
|
}
|
|
648
652
|
}
|
|
649
653
|
}
|
|
654
|
+
fillListExpressions(root, parts, item, revision, index)
|
|
655
|
+
if (__KUDZU_LIST_CONDITIONS__) {
|
|
656
|
+
for (const [marker, descriptor] of parts.conditions) {
|
|
657
|
+
evaluate(descriptor, item, index).then(value => {
|
|
658
|
+
if (revisions.get(root) === revision && marker.isConnected) updateListCondition(marker, descriptor.kind, value, item, index)
|
|
659
|
+
}).catch(error => console.error(error))
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function fillListExpressions(root, parts, item, revision, index) {
|
|
650
665
|
if (__KUDZU_LIST_EXPRESSIONS__) {
|
|
651
666
|
for (const [marker, descriptor] of parts.expressions) {
|
|
652
667
|
evaluate(descriptor, item, index).then(value => {
|
|
@@ -656,19 +671,20 @@ function fillListParts(root, parts, item, revision, index = 0, previous) {
|
|
|
656
671
|
}
|
|
657
672
|
if (__KUDZU_LIST_EXPRESSION_ATTRIBUTES__) {
|
|
658
673
|
for (const [node, attributes] of parts.expressionAttributes) {
|
|
659
|
-
for (const [target, module, handler] of attributes) {
|
|
660
|
-
evaluate({ module, handler }, item, index).then(value => {
|
|
674
|
+
for (const [target, module, handler, states] of attributes) {
|
|
675
|
+
evaluate({ module, handler, states }, item, index).then(value => {
|
|
661
676
|
if (revisions.get(root) === revision && node.isConnected) patchBinding(node, target, value)
|
|
662
677
|
}).catch(error => console.error(error))
|
|
663
678
|
}
|
|
664
679
|
}
|
|
665
680
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function updateListExpressions(list) {
|
|
684
|
+
for (const root of list.roots.values()) {
|
|
685
|
+
const revision = (revisions.get(root) ?? 0) + 1
|
|
686
|
+
revisions.set(root, revision)
|
|
687
|
+
fillListExpressions(root, listItemParts(root, list.descriptor.nested), listItems.get(root), revision, __KUDZU_LIST_INDEXES__ ? listIndexes.get(root) ?? 0 : 0)
|
|
672
688
|
}
|
|
673
689
|
}
|
|
674
690
|
|
|
@@ -999,7 +1015,7 @@ function evaluate(descriptor, item, index) {
|
|
|
999
1015
|
imports.set(descriptor.module, module)
|
|
1000
1016
|
}
|
|
1001
1017
|
return module.then(exports => {
|
|
1002
|
-
const value = exports[descriptor.handler](item, index)
|
|
1018
|
+
const value = exports[descriptor.handler](item, index, { get: name => browserState.get(descriptor.states?.[name]) })
|
|
1003
1019
|
if (value && typeof value.then === "function") throw new Error("Derived keyed list item expressions must return synchronous values")
|
|
1004
1020
|
return value
|
|
1005
1021
|
})
|