-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Body definition: more explicit structure, expand support to repeats…
… and evidently partial support for outputs as well(!) As anticipated by an earlier comment, the original view child class has been supplanted by a set of different types corresponding to their various body child usage scenarios. While this is large, hopefully it’s relatively self-explanatory.
- Loading branch information
1 parent
b976533
commit 6a82c5d
Showing
51 changed files
with
1,667 additions
and
523 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { beforeEach, describe, expect, it } from 'vitest'; | ||
import { getScopeChildBySelector } from './compatibility'; | ||
|
||
describe('DOM compatibility library functions', () => { | ||
describe('querying direct children of an element', () => { | ||
let root: Element; | ||
let child: Element; | ||
let descendant: Element; | ||
|
||
beforeEach(() => { | ||
const domParser = new DOMParser(); | ||
const { documentElement } = domParser.parseFromString( | ||
/* xml */ ` | ||
<root> | ||
<child> | ||
<descendant /> | ||
</child> | ||
</root> | ||
`.trim(), | ||
'text/xml' | ||
); | ||
|
||
root = documentElement; | ||
child = root.firstElementChild!; | ||
descendant = child.firstElementChild!; | ||
}); | ||
|
||
it('gets a direct child matching a selector', () => { | ||
const result = getScopeChildBySelector(root, ':scope > child', 'child'); | ||
|
||
expect(result).toBe(child); | ||
}); | ||
|
||
it('does not get a descendant matching the selector', () => { | ||
const result = getScopeChildBySelector(root, ':scope > descendant', 'descendant'); | ||
|
||
expect(result).not.toBe(descendant); | ||
expect(result).toBe(null); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
const SUPPORTS_SCOPE_CHILD_SELECTOR = (() => { | ||
const parent = document.createElement('parent'); | ||
const child1 = document.createElement('child1'); | ||
const child2 = document.createElement('child2'); | ||
|
||
child2.append(child1); | ||
parent.append(child2); | ||
|
||
return ( | ||
parent.querySelector(':scope > child1') === child1 && | ||
parent.querySelector(':scope > child2') !== child2 | ||
); | ||
})(); | ||
|
||
type ScopedSelector = `:scope > ${string}`; | ||
|
||
type UnscopedSelector<Selector extends ScopedSelector> = | ||
Selector extends `:scope > ${infer Unscoped}` ? Unscoped : never; | ||
|
||
type GetScopeChildBySelector = <Selector extends ScopedSelector>( | ||
element: Element, | ||
scopedSelector: Selector, | ||
unscopedSelector: UnscopedSelector<Selector> | ||
) => Element | null; | ||
|
||
/** | ||
* Provides compatibility for `ParentNode.querySelector(':scope > $SELECTOR')` | ||
* in environments where the `:scope > ` prefix is ignored (e.g. | ||
* {@link https://github.com/jsdom/jsdom/issues/3067 | jsdom}). | ||
* | ||
* Both the scoped and unscoped selector should be provided, to avoid a common | ||
* deoptimization caused by producing selectors dynamically. | ||
*/ | ||
export const getScopeChildBySelector = (() => { | ||
if (SUPPORTS_SCOPE_CHILD_SELECTOR) { | ||
return ((element, scopedSelector) => { | ||
return element.querySelector(scopedSelector); | ||
}) satisfies GetScopeChildBySelector; | ||
// ^ Note `satisfies` here (and below) allows TypeScript to infer the | ||
// literal type rather than referencing it by name, which is generally | ||
// easier to work with from a call site. | ||
} | ||
|
||
// `scopedSelector` isn't used for this compatibility fallback, but it's | ||
// included here as part of the inferred function signature. | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-ignore | ||
return ((element, scopedSelector, unscopedSelector) => { | ||
const children = Array.from(element.children); | ||
const result = children.find((child) => child.matches(unscopedSelector)); | ||
|
||
return result ?? null; | ||
}) satisfies GetScopeChildBySelector; | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
const { COMMENT_NODE, ELEMENT_NODE, TEXT_NODE } = Node; | ||
|
||
export const isCommentNode = (node: Node): node is Comment => node.nodeType === COMMENT_NODE; | ||
|
||
export const isElementNode = (node: Node): node is Element => node.nodeType === ELEMENT_NODE; | ||
|
||
export const isTextNode = (node: Node): node is Text => node.nodeType === TEXT_NODE; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
packages/odk-web-forms/fixtures/xforms/computations-demo/8-outputs.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<?xml version="1.0"?> | ||
<h:html xmlns="http://www.w3.org/2002/xforms" | ||
xmlns:ev="http://www.w3.org/2001/xml-events" | ||
xmlns:h="http://www.w3.org/1999/xhtml" | ||
xmlns:jr="http://openrosa.org/javarosa" | ||
xmlns:orx="http://openrosa.org/xforms/" | ||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | ||
<h:head> | ||
<h:title>Outputs</h:title> | ||
<model> | ||
<instance> | ||
<root id="outputs"> | ||
<a /> | ||
<b>default value of /root/b!</b> | ||
<c>defualt value of c</c> | ||
<d>10</d> | ||
<e /> | ||
<meta> | ||
<instanceID/> | ||
</meta> | ||
</root> | ||
</instance> | ||
<bind nodeset="/root/a" /> | ||
<bind nodeset="/root/b" /> | ||
<bind nodeset="/root/c" /> | ||
<bind nodeset="/root/d" /> | ||
<bind nodeset="/root/e" calculate="/root/d * 2" /> | ||
</model> | ||
</h:head> | ||
<h:body> | ||
<input ref="/root/a"> | ||
<label> | ||
1. Whoops, accidentally built part of output functionality! | ||
<output value="/root/b" /> | ||
</label> | ||
</input> | ||
<input ref="/root/c"> | ||
<label> | ||
2. Wonder if calculate also works... | ||
d: <output value="/root/d" />, e (d * 2): <output value="/root/e" /> | ||
</label> | ||
</input> | ||
</h:body> | ||
</h:html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,7 @@ | |
<instance> | ||
<root id="repeat-basic"> | ||
<rep> | ||
<a /> | ||
<a>default value</a> | ||
</rep> | ||
<meta> | ||
<instanceID/> | ||
|
35 changes: 35 additions & 0 deletions
35
packages/odk-web-forms/fixtures/xforms/repeats/02-repeat-grouped.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?xml version="1.0"?> | ||
<h:html xmlns="http://www.w3.org/2002/xforms" | ||
xmlns:ev="http://www.w3.org/2001/xml-events" | ||
xmlns:h="http://www.w3.org/1999/xhtml" | ||
xmlns:jr="http://openrosa.org/javarosa" | ||
xmlns:orx="http://openrosa.org/xforms/" | ||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | ||
<h:head> | ||
<h:title>Repeat (grouped)</h:title> | ||
<model> | ||
<instance> | ||
<root id="repeat-grouped"> | ||
<rep> | ||
<a>default value</a> | ||
</rep> | ||
<meta> | ||
<instanceID/> | ||
</meta> | ||
</root> | ||
</instance> | ||
<bind nodeset="/root/rep/a"/> | ||
<bind nodeset="/root/meta/instanceID" type="string"/> | ||
</model> | ||
</h:head> | ||
<h:body> | ||
<group ref="/root/rep"> | ||
<label>Repeat group</label> | ||
<repeat nodeset="/root/rep"> | ||
<input ref="/root/rep/a"> | ||
<label>Repeat input a</label> | ||
</input> | ||
</repeat> | ||
</group> | ||
</h:body> | ||
</h:html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
packages/odk-web-forms/src/components/XForm/XFormBodyElement.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Match, Switch } from 'solid-js'; | ||
import type { XFormEntry } from '../../lib/xform/XFormEntry.ts'; | ||
import { | ||
controlElementDefinition, | ||
groupElementDefinition, | ||
type AnyBodyElementDefinition, | ||
} from '../../lib/xform/body/BodyDefinition.ts'; | ||
import { XFormGroup } from './containers/XFormGroup.tsx'; | ||
import { XFormControl } from './controls/XFormControl.tsx'; | ||
|
||
interface XFormUnknownElementProps { | ||
readonly entry: XFormEntry; | ||
readonly element: AnyBodyElementDefinition; | ||
} | ||
|
||
const XFormUnknownElement = (props: XFormUnknownElementProps) => { | ||
props; | ||
return <></>; | ||
}; | ||
|
||
export interface XFormBodyElementProps { | ||
readonly entry: XFormEntry; | ||
readonly element: AnyBodyElementDefinition; | ||
} | ||
|
||
export const XFormBodyElement = (props: XFormBodyElementProps) => { | ||
return ( | ||
<Switch fallback={<XFormUnknownElement {...props} />}> | ||
<Match when={groupElementDefinition(props.element)} keyed={true}> | ||
{(groupElement) => { | ||
return <XFormGroup entry={props.entry} group={groupElement} />; | ||
}} | ||
</Match> | ||
<Match when={controlElementDefinition(props.element)} keyed={true}> | ||
{(controlElement) => { | ||
return <XFormControl entry={props.entry} control={controlElement} />; | ||
}} | ||
</Match> | ||
</Switch> | ||
); | ||
}; |
43 changes: 0 additions & 43 deletions
43
packages/odk-web-forms/src/components/XForm/XFormControl.tsx
This file was deleted.
Oops, something went wrong.
17 changes: 13 additions & 4 deletions
17
packages/odk-web-forms/src/components/XForm/XFormLabel.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
packages/odk-web-forms/src/components/XForm/XFormQuestionList.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { For } from 'solid-js'; | ||
import type { XFormEntry } from '../../lib/xform/XFormEntry.ts'; | ||
import type { BodyElementDefinitionArray } from '../../lib/xform/body/BodyDefinition.ts'; | ||
import { XFormBodyElement } from './XFormBodyElement.tsx'; | ||
import { XFormControlStack } from './XFormControlStack.tsx'; | ||
|
||
interface XFormQuestionListProps { | ||
readonly entry: XFormEntry; | ||
readonly elements: BodyElementDefinitionArray; | ||
} | ||
|
||
export const XFormQuesetionList = (props: XFormQuestionListProps) => { | ||
return ( | ||
<XFormControlStack> | ||
<For each={props.elements}> | ||
{(element) => { | ||
return <XFormBodyElement entry={props.entry} element={element} />; | ||
}} | ||
</For> | ||
</XFormControlStack> | ||
); | ||
}; |
Oops, something went wrong.