@ankhorage/zora 20.0.2 → 20.1.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/CHANGELOG.md +12 -0
- package/dist/cli/commands/create.d.ts +14 -0
- package/dist/cli/commands/create.d.ts.map +1 -0
- package/dist/cli/commands/create.js +61 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/index.d.ts +18 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +33 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/features/tree-view/adapters/inbound/TreeItem.d.ts +1 -5
- package/dist/features/tree-view/adapters/inbound/TreeItem.d.ts.map +1 -1
- package/dist/features/tree-view/adapters/inbound/TreeItem.js +16 -9
- package/dist/features/tree-view/adapters/inbound/TreeItem.js.map +1 -1
- package/dist/features/tree-view/adapters/inbound/TreeView.d.ts +1 -5
- package/dist/features/tree-view/adapters/inbound/TreeView.d.ts.map +1 -1
- package/dist/features/tree-view/adapters/inbound/TreeView.js +6 -9
- package/dist/features/tree-view/adapters/inbound/TreeView.js.map +1 -1
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.d.ts +15 -0
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.d.ts.map +1 -0
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.js +121 -0
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.js.map +1 -0
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.d.ts +32 -0
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.d.ts.map +1 -0
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.js +24 -0
- package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.js.map +1 -0
- package/dist/features/tree-view/utils/toggleExpandedIds.d.ts +3 -0
- package/dist/features/tree-view/utils/toggleExpandedIds.d.ts.map +1 -0
- package/dist/features/tree-view/utils/toggleExpandedIds.js +7 -0
- package/dist/features/tree-view/utils/toggleExpandedIds.js.map +1 -0
- package/dist/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.d.ts +4 -0
- package/dist/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.d.ts.map +1 -0
- package/dist/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.js +20 -0
- package/dist/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.js.map +1 -0
- package/dist/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.d.ts +7 -0
- package/dist/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.d.ts.map +1 -0
- package/dist/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.js +2 -0
- package/dist/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.js.map +1 -0
- package/dist/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.d.ts +16 -0
- package/dist/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.d.ts.map +1 -0
- package/dist/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.js +42 -0
- package/dist/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.js.map +1 -0
- package/dist/features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync.d.ts +4 -0
- package/dist/features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync.d.ts.map +1 -0
- package/dist/features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync.js +7 -0
- package/dist/features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync.js.map +1 -0
- package/package.json +18 -5
- package/src/cli/commands/create.ts +96 -0
- package/src/cli/index.test.ts +18 -0
- package/src/cli/index.ts +50 -0
- package/src/features/tree-view/adapters/inbound/TreeItem.tsx +33 -27
- package/src/features/tree-view/adapters/inbound/TreeView.tsx +6 -9
- package/src/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.tsx +197 -0
- package/src/features/tree-view/adapters/inbound/web-artifact/TreeView.test.tsx +28 -0
- package/src/features/tree-view/adapters/inbound/web-artifact/TreeView.tsx +91 -0
- package/src/features/tree-view/utils/toggleExpandedIds.test.ts +12 -0
- package/src/features/tree-view/utils/toggleExpandedIds.ts +9 -0
- package/src/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.ts +22 -0
- package/src/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.ts +6 -0
- package/src/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.test.ts +84 -0
- package/src/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.ts +83 -0
- package/src/features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync.ts +16 -0
- package/src/platformAcceptance.test.ts +1 -1
- package/src/structureOwnership.test.ts +2 -2
- package/web-dist/tree-view/TreeView.d.ts +32 -0
- package/web-dist/tree-view/TreeView.js +219 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*** Toggle one tree node id while preserving immutable expansion state. */
|
|
2
|
+
export function toggleExpandedIds(expandedIds, id) {
|
|
3
|
+
return expandedIds.includes(id)
|
|
4
|
+
? expandedIds.filter((expandedId) => expandedId !== id)
|
|
5
|
+
: [...expandedIds, id];
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=toggleExpandedIds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toggleExpandedIds.js","sourceRoot":"","sources":["../../../../src/features/tree-view/utils/toggleExpandedIds.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB,CAC/B,WAA2B,EAC3B,EAAO;IAEP,OAAO,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,KAAK,EAAE,CAAC;QACvD,CAAC,CAAC,CAAC,GAAG,WAAW,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC","sourcesContent":["/*** Toggle one tree node id while preserving immutable expansion state. */\nexport function toggleExpandedIds<TId extends string>(\n expandedIds: readonly TId[],\n id: TId,\n): readonly TId[] {\n return expandedIds.includes(id)\n ? expandedIds.filter((expandedId) => expandedId !== id)\n : [...expandedIds, id];\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { WebComponentArtifactFileSystemPort } from '../../../application/ports/outbound/WebComponentArtifactFileSystemPort';
|
|
2
|
+
/*** Create the Node filesystem adapter used by ZORA web-component materialization. */
|
|
3
|
+
export declare function createNodeWebComponentArtifactFileSystem(): WebComponentArtifactFileSystemPort;
|
|
4
|
+
//# sourceMappingURL=createNodeWebComponentArtifactFileSystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createNodeWebComponentArtifactFileSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,wEAAwE,CAAC;AAEjI,sFAAsF;AACtF,wBAAgB,wCAAwC,IAAI,kCAAkC,CAe7F"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/*** Create the Node filesystem adapter used by ZORA web-component materialization. */
|
|
4
|
+
export function createNodeWebComponentArtifactFileSystem() {
|
|
5
|
+
return {
|
|
6
|
+
joinPath(...parts) {
|
|
7
|
+
return join(...parts);
|
|
8
|
+
},
|
|
9
|
+
async ensureDirectoryAsync(path) {
|
|
10
|
+
await mkdir(path, { recursive: true });
|
|
11
|
+
},
|
|
12
|
+
async readTextFileAsync(path) {
|
|
13
|
+
return await readFile(path, 'utf8');
|
|
14
|
+
},
|
|
15
|
+
async writeTextFileAsync(path, content) {
|
|
16
|
+
await writeFile(path, content, 'utf8');
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=createNodeWebComponentArtifactFileSystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createNodeWebComponentArtifactFileSystem.js","sourceRoot":"","sources":["../../../../../../src/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,sFAAsF;AACtF,MAAM,UAAU,wCAAwC;IACtD,OAAO;QACL,QAAQ,CAAC,GAAG,KAAK;YACf,OAAO,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,KAAK,CAAC,oBAAoB,CAAC,IAAI;YAC7B,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,CAAC,iBAAiB,CAAC,IAAI;YAC1B,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;QACD,KAAK,CAAC,kBAAkB,CAAC,IAAI,EAAE,OAAO;YACpC,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport type { WebComponentArtifactFileSystemPort } from '../../../application/ports/outbound/WebComponentArtifactFileSystemPort';\n\n/*** Create the Node filesystem adapter used by ZORA web-component materialization. */\nexport function createNodeWebComponentArtifactFileSystem(): WebComponentArtifactFileSystemPort {\n return {\n joinPath(...parts) {\n return join(...parts);\n },\n async ensureDirectoryAsync(path) {\n await mkdir(path, { recursive: true });\n },\n async readTextFileAsync(path) {\n return await readFile(path, 'utf8');\n },\n async writeTextFileAsync(path, content) {\n await writeFile(path, content, 'utf8');\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface WebComponentArtifactFileSystemPort {
|
|
2
|
+
joinPath(...parts: readonly string[]): string;
|
|
3
|
+
ensureDirectoryAsync(path: string): Promise<void>;
|
|
4
|
+
readTextFileAsync(path: string): Promise<string>;
|
|
5
|
+
writeTextFileAsync(path: string, content: string): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=WebComponentArtifactFileSystemPort.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebComponentArtifactFileSystemPort.d.ts","sourceRoot":"","sources":["../../../../../../src/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,GAAG,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC;IAC9C,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebComponentArtifactFileSystemPort.js","sourceRoot":"","sources":["../../../../../../src/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.ts"],"names":[],"mappings":"","sourcesContent":["export interface WebComponentArtifactFileSystemPort {\n joinPath(...parts: readonly string[]): string;\n ensureDirectoryAsync(path: string): Promise<void>;\n readTextFileAsync(path: string): Promise<string>;\n writeTextFileAsync(path: string, content: string): Promise<void>;\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { WebComponentArtifactFileSystemPort } from '../ports/outbound/WebComponentArtifactFileSystemPort';
|
|
2
|
+
export interface MaterializeWebComponentArtifactInput {
|
|
3
|
+
readonly component: string;
|
|
4
|
+
readonly outputDirectory: string;
|
|
5
|
+
readonly packageRoot: string;
|
|
6
|
+
readonly packageVersion: string;
|
|
7
|
+
}
|
|
8
|
+
export interface MaterializeWebComponentArtifactResult {
|
|
9
|
+
readonly component: string;
|
|
10
|
+
readonly createdFiles: readonly string[];
|
|
11
|
+
readonly outputDirectory: string;
|
|
12
|
+
readonly platform: 'web';
|
|
13
|
+
}
|
|
14
|
+
/*** Materialize one replaceable web-only component artifact from the published ZORA build. */
|
|
15
|
+
export declare function materializeWebComponentArtifactAsync(input: MaterializeWebComponentArtifactInput, fileSystem: WebComponentArtifactFileSystemPort): Promise<MaterializeWebComponentArtifactResult>;
|
|
16
|
+
//# sourceMappingURL=materializeWebComponentArtifactAsync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializeWebComponentArtifactAsync.d.ts","sourceRoot":"","sources":["../../../../../src/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,sDAAsD,CAAC;AAE/G,MAAM,WAAW,oCAAoC;IACnD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,qCAAqC;IACpD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;CAC1B;AAED,8FAA8F;AAC9F,wBAAsB,oCAAoC,CACxD,KAAK,EAAE,oCAAoC,EAC3C,UAAU,EAAE,kCAAkC,GAC7C,OAAO,CAAC,qCAAqC,CAAC,CAwChD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*** Materialize one replaceable web-only component artifact from the published ZORA build. */
|
|
2
|
+
export async function materializeWebComponentArtifactAsync(input, fileSystem) {
|
|
3
|
+
const artifact = resolveWebArtifact(input.component);
|
|
4
|
+
const sourceDirectory = fileSystem.joinPath(input.packageRoot, 'web-dist', artifact.directory);
|
|
5
|
+
await fileSystem.ensureDirectoryAsync(input.outputDirectory);
|
|
6
|
+
const createdFiles = await Promise.all(artifact.files.map(async (fileName) => {
|
|
7
|
+
const sourcePath = fileSystem.joinPath(sourceDirectory, fileName);
|
|
8
|
+
const targetPath = fileSystem.joinPath(input.outputDirectory, fileName);
|
|
9
|
+
const source = await fileSystem.readTextFileAsync(sourcePath);
|
|
10
|
+
await fileSystem.writeTextFileAsync(targetPath, createGeneratedSource(input.packageVersion, source));
|
|
11
|
+
return targetPath;
|
|
12
|
+
}));
|
|
13
|
+
const metadataPath = fileSystem.joinPath(input.outputDirectory, 'zora-artifact.json');
|
|
14
|
+
await fileSystem.writeTextFileAsync(metadataPath, `${JSON.stringify({
|
|
15
|
+
generated: true,
|
|
16
|
+
owner: '@ankhorage/zora',
|
|
17
|
+
version: input.packageVersion,
|
|
18
|
+
component: input.component,
|
|
19
|
+
platform: 'web',
|
|
20
|
+
}, null, 2)}\n`);
|
|
21
|
+
return {
|
|
22
|
+
component: input.component,
|
|
23
|
+
createdFiles: [...createdFiles, metadataPath],
|
|
24
|
+
outputDirectory: input.outputDirectory,
|
|
25
|
+
platform: 'web',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/*** Resolve the canonical packaged web artifact for a requested component. */
|
|
29
|
+
function resolveWebArtifact(component) {
|
|
30
|
+
if (component === 'tree-view') {
|
|
31
|
+
return {
|
|
32
|
+
directory: 'tree-view',
|
|
33
|
+
files: ['TreeView.js', 'TreeView.d.ts'],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`Unsupported ZORA web component: ${component}`);
|
|
37
|
+
}
|
|
38
|
+
/*** Add a generated-file marker without changing the compiled artifact semantics. */
|
|
39
|
+
function createGeneratedSource(packageVersion, source) {
|
|
40
|
+
return `// Generated by @ankhorage/zora v${packageVersion}. Do not edit manually.\n${source}`;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=materializeWebComponentArtifactAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializeWebComponentArtifactAsync.js","sourceRoot":"","sources":["../../../../../src/features/web-component-artifact/application/use-cases/materializeWebComponentArtifactAsync.ts"],"names":[],"mappings":"AAgBA,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,oCAAoC,CACxD,KAA2C,EAC3C,UAA8C;IAE9C,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,eAAe,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/F,MAAM,UAAU,CAAC,oBAAoB,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAE7D,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CACpC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QACpC,MAAM,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;QAClE,MAAM,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;QACxE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,UAAU,CAAC,kBAAkB,CACjC,UAAU,EACV,qBAAqB,CAAC,KAAK,CAAC,cAAc,EAAE,MAAM,CAAC,CACpD,CAAC;QACF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC;IACtF,MAAM,UAAU,CAAC,kBAAkB,CACjC,YAAY,EACZ,GAAG,IAAI,CAAC,SAAS,CACf;QACE,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,iBAAiB;QACxB,OAAO,EAAE,KAAK,CAAC,cAAc;QAC7B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK;KAChB,EACD,IAAI,EACJ,CAAC,CACF,IAAI,CACN,CAAC;IAEF,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,YAAY,EAAE,CAAC,GAAG,YAAY,EAAE,YAAY,CAAC;QAC7C,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,QAAQ,EAAE,KAAK;KAChB,CAAC;AACJ,CAAC;AAOD,8EAA8E;AAC9E,SAAS,kBAAkB,CAAC,SAAiB;IAC3C,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;QAC9B,OAAO;YACL,SAAS,EAAE,WAAW;YACtB,KAAK,EAAE,CAAC,aAAa,EAAE,eAAe,CAAC;SACxC,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,mCAAmC,SAAS,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,qFAAqF;AACrF,SAAS,qBAAqB,CAAC,cAAsB,EAAE,MAAc;IACnE,OAAO,oCAAoC,cAAc,4BAA4B,MAAM,EAAE,CAAC;AAChG,CAAC","sourcesContent":["import type { WebComponentArtifactFileSystemPort } from '../ports/outbound/WebComponentArtifactFileSystemPort';\n\nexport interface MaterializeWebComponentArtifactInput {\n readonly component: string;\n readonly outputDirectory: string;\n readonly packageRoot: string;\n readonly packageVersion: string;\n}\n\nexport interface MaterializeWebComponentArtifactResult {\n readonly component: string;\n readonly createdFiles: readonly string[];\n readonly outputDirectory: string;\n readonly platform: 'web';\n}\n\n/*** Materialize one replaceable web-only component artifact from the published ZORA build. */\nexport async function materializeWebComponentArtifactAsync(\n input: MaterializeWebComponentArtifactInput,\n fileSystem: WebComponentArtifactFileSystemPort,\n): Promise<MaterializeWebComponentArtifactResult> {\n const artifact = resolveWebArtifact(input.component);\n const sourceDirectory = fileSystem.joinPath(input.packageRoot, 'web-dist', artifact.directory);\n await fileSystem.ensureDirectoryAsync(input.outputDirectory);\n\n const createdFiles = await Promise.all(\n artifact.files.map(async (fileName) => {\n const sourcePath = fileSystem.joinPath(sourceDirectory, fileName);\n const targetPath = fileSystem.joinPath(input.outputDirectory, fileName);\n const source = await fileSystem.readTextFileAsync(sourcePath);\n await fileSystem.writeTextFileAsync(\n targetPath,\n createGeneratedSource(input.packageVersion, source),\n );\n return targetPath;\n }),\n );\n\n const metadataPath = fileSystem.joinPath(input.outputDirectory, 'zora-artifact.json');\n await fileSystem.writeTextFileAsync(\n metadataPath,\n `${JSON.stringify(\n {\n generated: true,\n owner: '@ankhorage/zora',\n version: input.packageVersion,\n component: input.component,\n platform: 'web',\n },\n null,\n 2,\n )}\\n`,\n );\n\n return {\n component: input.component,\n createdFiles: [...createdFiles, metadataPath],\n outputDirectory: input.outputDirectory,\n platform: 'web',\n };\n}\n\ninterface WebArtifactDefinition {\n readonly directory: string;\n readonly files: readonly string[];\n}\n\n/*** Resolve the canonical packaged web artifact for a requested component. */\nfunction resolveWebArtifact(component: string): WebArtifactDefinition {\n if (component === 'tree-view') {\n return {\n directory: 'tree-view',\n files: ['TreeView.js', 'TreeView.d.ts'],\n };\n }\n\n throw new Error(`Unsupported ZORA web component: ${component}`);\n}\n\n/*** Add a generated-file marker without changing the compiled artifact semantics. */\nfunction createGeneratedSource(packageVersion: string, source: string): string {\n return `// Generated by @ankhorage/zora v${packageVersion}. Do not edit manually.\\n${source}`;\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type MaterializeWebComponentArtifactInput, type MaterializeWebComponentArtifactResult } from '../application/use-cases/materializeWebComponentArtifactAsync';
|
|
2
|
+
/*** Compose the Node filesystem adapter with the web-component materialization use case. */
|
|
3
|
+
export declare function materializeWebComponentArtifactWithNodeAsync(input: MaterializeWebComponentArtifactInput): Promise<MaterializeWebComponentArtifactResult>;
|
|
4
|
+
//# sourceMappingURL=materializeWebComponentArtifactWithNodeAsync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializeWebComponentArtifactWithNodeAsync.d.ts","sourceRoot":"","sources":["../../../../src/features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,oCAAoC,EACzC,KAAK,qCAAqC,EAC3C,MAAM,+DAA+D,CAAC;AAEvE,4FAA4F;AAC5F,wBAAsB,4CAA4C,CAChE,KAAK,EAAE,oCAAoC,GAC1C,OAAO,CAAC,qCAAqC,CAAC,CAKhD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createNodeWebComponentArtifactFileSystem } from '../adapters/outbound/node/createNodeWebComponentArtifactFileSystem';
|
|
2
|
+
import { materializeWebComponentArtifactAsync, } from '../application/use-cases/materializeWebComponentArtifactAsync';
|
|
3
|
+
/*** Compose the Node filesystem adapter with the web-component materialization use case. */
|
|
4
|
+
export async function materializeWebComponentArtifactWithNodeAsync(input) {
|
|
5
|
+
return await materializeWebComponentArtifactAsync(input, createNodeWebComponentArtifactFileSystem());
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=materializeWebComponentArtifactWithNodeAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializeWebComponentArtifactWithNodeAsync.js","sourceRoot":"","sources":["../../../../src/features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wCAAwC,EAAE,MAAM,oEAAoE,CAAC;AAC9H,OAAO,EACL,oCAAoC,GAGrC,MAAM,+DAA+D,CAAC;AAEvE,4FAA4F;AAC5F,MAAM,CAAC,KAAK,UAAU,4CAA4C,CAChE,KAA2C;IAE3C,OAAO,MAAM,oCAAoC,CAC/C,KAAK,EACL,wCAAwC,EAAE,CAC3C,CAAC;AACJ,CAAC","sourcesContent":["import { createNodeWebComponentArtifactFileSystem } from '../adapters/outbound/node/createNodeWebComponentArtifactFileSystem';\nimport {\n materializeWebComponentArtifactAsync,\n type MaterializeWebComponentArtifactInput,\n type MaterializeWebComponentArtifactResult,\n} from '../application/use-cases/materializeWebComponentArtifactAsync';\n\n/*** Compose the Node filesystem adapter with the web-component materialization use case. */\nexport async function materializeWebComponentArtifactWithNodeAsync(\n input: MaterializeWebComponentArtifactInput,\n): Promise<MaterializeWebComponentArtifactResult> {\n return await materializeWebComponentArtifactAsync(\n input,\n createNodeWebComponentArtifactFileSystem(),\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/zora",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "20.
|
|
4
|
+
"version": "20.1.1",
|
|
5
5
|
"description": "Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/zora#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"files": [
|
|
51
51
|
"dist",
|
|
52
|
+
"web-dist",
|
|
52
53
|
"src",
|
|
53
54
|
"package.json",
|
|
54
55
|
"README.md",
|
|
@@ -92,13 +93,18 @@
|
|
|
92
93
|
"import": "./dist/features/theme/public.js",
|
|
93
94
|
"default": "./dist/features/theme/public.js"
|
|
94
95
|
},
|
|
95
|
-
"./package.json": "./package.json"
|
|
96
|
+
"./package.json": "./package.json",
|
|
97
|
+
"./cli": {
|
|
98
|
+
"types": "./dist/cli/index.d.ts",
|
|
99
|
+
"import": "./dist/cli/index.js",
|
|
100
|
+
"default": "./dist/cli/index.js"
|
|
101
|
+
}
|
|
96
102
|
},
|
|
97
103
|
"publishConfig": {
|
|
98
104
|
"access": "public"
|
|
99
105
|
},
|
|
100
106
|
"scripts": {
|
|
101
|
-
"build": "rm -rf dist tsconfig.tsbuildinfo && bun x tsc -p tsconfig.json",
|
|
107
|
+
"build": "rm -rf dist web-dist tsconfig.tsbuildinfo && bun x tsc -p tsconfig.json && bun scripts/build-web-components.ts",
|
|
102
108
|
"changeset": "ankhorage-changeset",
|
|
103
109
|
"changeset:status": "ankhorage-changeset status --since=origin/main",
|
|
104
110
|
"docs": "paradox",
|
|
@@ -115,7 +121,7 @@
|
|
|
115
121
|
"version-packages": "ankhorage-changeset version"
|
|
116
122
|
},
|
|
117
123
|
"devDependencies": {
|
|
118
|
-
"@ankhorage/devtools": "^1.
|
|
124
|
+
"@ankhorage/devtools": "^1.17.0",
|
|
119
125
|
"@ankhorage/paradox": "^0.1.26",
|
|
120
126
|
"@react-native-vector-icons/fontawesome": "^13.1.3",
|
|
121
127
|
"@react-native-vector-icons/fontawesome5": "^13.1.3",
|
|
@@ -138,5 +144,12 @@
|
|
|
138
144
|
"react-native-worklets": "0.10.1",
|
|
139
145
|
"typescript": "~6.0.3"
|
|
140
146
|
},
|
|
141
|
-
"packageManager": "bun@1.4.2"
|
|
147
|
+
"packageManager": "bun@1.4.2",
|
|
148
|
+
"ankh": {
|
|
149
|
+
"category": "zora",
|
|
150
|
+
"provider": "./dist/cli/index.js",
|
|
151
|
+
"capabilities": [
|
|
152
|
+
"zora.create"
|
|
153
|
+
]
|
|
154
|
+
}
|
|
142
155
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
import { materializeWebComponentArtifactWithNodeAsync } from '../../features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync';
|
|
6
|
+
|
|
7
|
+
interface ZoraCreateCommandRequest {
|
|
8
|
+
readonly argv: readonly string[];
|
|
9
|
+
readonly context: {
|
|
10
|
+
readonly cwd: string;
|
|
11
|
+
writeStderr(text: string): void;
|
|
12
|
+
writeStdout(text: string): void;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/*** Materialize a canonical ZORA component for a platform-specific consumer. */
|
|
17
|
+
export async function create(
|
|
18
|
+
request: ZoraCreateCommandRequest,
|
|
19
|
+
): Promise<{ readonly exitCode: number }> {
|
|
20
|
+
try {
|
|
21
|
+
const options = parseCreateArguments(request.argv);
|
|
22
|
+
const packageJsonPath = resolve(
|
|
23
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
24
|
+
'../../../package.json',
|
|
25
|
+
);
|
|
26
|
+
const packageRoot = dirname(packageJsonPath);
|
|
27
|
+
const packageVersion = await readPackageVersionAsync(packageJsonPath);
|
|
28
|
+
const outputDirectory =
|
|
29
|
+
options.outputDirectory === undefined
|
|
30
|
+
? resolve(request.context.cwd, 'src', 'generated', 'zora', options.component)
|
|
31
|
+
: resolve(request.context.cwd, options.outputDirectory);
|
|
32
|
+
|
|
33
|
+
const result = await materializeWebComponentArtifactWithNodeAsync({
|
|
34
|
+
component: options.component,
|
|
35
|
+
outputDirectory,
|
|
36
|
+
packageRoot,
|
|
37
|
+
packageVersion,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
request.context.writeStdout(
|
|
41
|
+
[
|
|
42
|
+
`Created ZORA ${result.component} for ${result.platform} at ${result.outputDirectory}`,
|
|
43
|
+
...result.createdFiles.map((filePath) => ` ${filePath}`),
|
|
44
|
+
'',
|
|
45
|
+
].join('\n'),
|
|
46
|
+
);
|
|
47
|
+
return { exitCode: 0 };
|
|
48
|
+
} catch (error) {
|
|
49
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
50
|
+
request.context.writeStderr(`ZORA create failed: ${message}\n`);
|
|
51
|
+
return { exitCode: 1 };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface CreateOptions {
|
|
56
|
+
readonly component: string;
|
|
57
|
+
readonly outputDirectory?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/*** Parse the intentionally small first web-materialization command surface. */
|
|
61
|
+
function parseCreateArguments(argv: readonly string[]): CreateOptions {
|
|
62
|
+
const [component, platformFlag, outputFlag, outputDirectory] = argv;
|
|
63
|
+
const hasDefaultOutput = argv.length === 2 && platformFlag === '--web';
|
|
64
|
+
const hasCustomOutput =
|
|
65
|
+
argv.length === 4 &&
|
|
66
|
+
platformFlag === '--web' &&
|
|
67
|
+
outputFlag === '--out' &&
|
|
68
|
+
outputDirectory !== undefined &&
|
|
69
|
+
outputDirectory.trim() !== '';
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
component === undefined ||
|
|
73
|
+
component.trim() === '' ||
|
|
74
|
+
(!hasDefaultOutput && !hasCustomOutput)
|
|
75
|
+
) {
|
|
76
|
+
throw new Error('Usage: ankh zora create <component> --web [--out <directory>]');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
component,
|
|
81
|
+
...(hasCustomOutput ? { outputDirectory } : {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/*** Read the installed package version used to stamp generated artifacts. */
|
|
86
|
+
async function readPackageVersionAsync(packageJsonPath: string): Promise<string> {
|
|
87
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as {
|
|
88
|
+
readonly version?: unknown;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (typeof packageJson.version !== 'string' || packageJson.version.trim() === '') {
|
|
92
|
+
throw new Error('ZORA package.json must define a non-empty version.');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return packageJson.version;
|
|
96
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import provider from './index';
|
|
4
|
+
|
|
5
|
+
test('publishes the ZORA create command through the Ankh provider', () => {
|
|
6
|
+
expect(provider.id).toBe('@ankhorage/zora');
|
|
7
|
+
expect(provider.category).toBe('zora');
|
|
8
|
+
expect(provider.capabilities).toEqual(['zora.create']);
|
|
9
|
+
expect(provider.commands).toEqual([
|
|
10
|
+
{
|
|
11
|
+
path: ['create'],
|
|
12
|
+
capability: 'zora.create',
|
|
13
|
+
summary: 'Materialize a canonical ZORA component for a target platform.',
|
|
14
|
+
},
|
|
15
|
+
]);
|
|
16
|
+
expect(provider.handlers).toHaveLength(1);
|
|
17
|
+
expect(provider.handlers[0]?.path).toEqual(['create']);
|
|
18
|
+
});
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
import type { AnkhCapabilityId, AnkhCommandProviderManifest } from '@ankhorage/contracts/cli';
|
|
6
|
+
|
|
7
|
+
import { create } from './commands/create';
|
|
8
|
+
|
|
9
|
+
const CREATE_CAPABILITY = 'zora.create' satisfies AnkhCapabilityId;
|
|
10
|
+
const CREATE_COMMAND = {
|
|
11
|
+
path: ['create'],
|
|
12
|
+
capability: CREATE_CAPABILITY,
|
|
13
|
+
summary: 'Materialize a canonical ZORA component for a target platform.',
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
interface ZoraRuntimeProvider extends AnkhCommandProviderManifest {
|
|
17
|
+
readonly handlers: readonly {
|
|
18
|
+
readonly path: readonly string[];
|
|
19
|
+
readonly handler: typeof create;
|
|
20
|
+
}[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const provider = {
|
|
24
|
+
id: '@ankhorage/zora',
|
|
25
|
+
category: 'zora',
|
|
26
|
+
version: readPackageVersion(),
|
|
27
|
+
capabilities: [CREATE_CAPABILITY],
|
|
28
|
+
commands: [CREATE_COMMAND],
|
|
29
|
+
handlers: [
|
|
30
|
+
{
|
|
31
|
+
path: CREATE_COMMAND.path,
|
|
32
|
+
handler: create,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
} satisfies ZoraRuntimeProvider;
|
|
36
|
+
|
|
37
|
+
export default provider;
|
|
38
|
+
|
|
39
|
+
/*** Read the installed ZORA version for the Ankh provider manifest. */
|
|
40
|
+
function readPackageVersion(): string {
|
|
41
|
+
const packageJson = JSON.parse(
|
|
42
|
+
readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'), 'utf8'),
|
|
43
|
+
) as { readonly version?: unknown };
|
|
44
|
+
|
|
45
|
+
if (typeof packageJson.version !== 'string' || packageJson.version.trim() === '') {
|
|
46
|
+
throw new Error('ZORA package.json must define a non-empty version.');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return packageJson.version;
|
|
50
|
+
}
|
|
@@ -3,6 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import type { ZoraBaseProps } from '../../../../types/base';
|
|
4
4
|
import type { TreeItemNode, TreeItemRenderProps } from '../../../../types/tree-view';
|
|
5
5
|
import { IconButton } from '../../../button/public';
|
|
6
|
+
import { Icon } from '../../../icon/public';
|
|
6
7
|
import { View } from '../../../layout/public';
|
|
7
8
|
import { ListItem } from '../../../list/public';
|
|
8
9
|
import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';
|
|
@@ -17,6 +18,7 @@ interface TreeItemProps<TId extends string = string> extends ZoraBaseProps {
|
|
|
17
18
|
renderItem?: (props: TreeItemRenderProps<TId>) => React.ReactNode;
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/*** Render one recursive themed tree row and keep row selection separate from expansion controls. */
|
|
20
22
|
function TreeItemInner<TId extends string = string>({
|
|
21
23
|
themeId: _themeId,
|
|
22
24
|
mode: _mode,
|
|
@@ -45,28 +47,36 @@ function TreeItemInner<TId extends string = string>({
|
|
|
45
47
|
});
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
50
|
+
const trailing =
|
|
51
|
+
node.actions !== undefined || hasChildren ? (
|
|
52
|
+
<View direction="row" gap="xs" align="center">
|
|
53
|
+
{node.actions}
|
|
54
|
+
{hasChildren ? (
|
|
55
|
+
<IconButton
|
|
56
|
+
icon={{ name: isExpanded ? 'chevron-down-outline' : 'chevron-forward-outline' }}
|
|
57
|
+
interactionPolicy={interactionPolicy}
|
|
58
|
+
label={isExpanded ? 'Collapse' : 'Expand'}
|
|
59
|
+
onPress={() => onToggleExpand(node.id)}
|
|
60
|
+
size="s"
|
|
61
|
+
variant="ghost"
|
|
62
|
+
/>
|
|
63
|
+
) : null}
|
|
64
|
+
</View>
|
|
65
|
+
) : undefined;
|
|
66
|
+
|
|
67
|
+
const listItemProps = {
|
|
68
|
+
title: node.label,
|
|
69
|
+
leading: node.icon === undefined ? undefined : <Icon {...node.icon} size="s" />,
|
|
70
|
+
meta: node.meta,
|
|
71
|
+
disabled: node.disabled,
|
|
72
|
+
selected: isSelected,
|
|
73
|
+
trailing,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return onSelect === undefined ? (
|
|
77
|
+
<ListItem {...listItemProps} />
|
|
78
|
+
) : (
|
|
79
|
+
<ListItem {...listItemProps} onPress={() => onSelect(node.id)} />
|
|
70
80
|
);
|
|
71
81
|
};
|
|
72
82
|
|
|
@@ -94,9 +104,5 @@ function TreeItemInner<TId extends string = string>({
|
|
|
94
104
|
);
|
|
95
105
|
}
|
|
96
106
|
|
|
97
|
-
/***
|
|
98
|
-
* Single tree node row used within `TreeView`.
|
|
99
|
-
*
|
|
100
|
-
|
|
101
|
-
*/
|
|
107
|
+
/*** Single tree node row used within `TreeView`. */
|
|
102
108
|
export const TreeItem = withZoraThemeScope(TreeItemInner);
|
|
@@ -3,8 +3,10 @@ import React from 'react';
|
|
|
3
3
|
import type { TreeViewProps } from '../../../../types/tree-view';
|
|
4
4
|
import { View } from '../../../layout/public';
|
|
5
5
|
import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';
|
|
6
|
+
import { toggleExpandedIds } from '../../utils/toggleExpandedIds';
|
|
6
7
|
import { TreeItem } from './TreeItem';
|
|
7
8
|
|
|
9
|
+
/*** Render the themed TreeView while supporting controlled or internal expansion state. */
|
|
8
10
|
function TreeViewInner<TId extends string = string>({
|
|
9
11
|
themeId: _themeId,
|
|
10
12
|
mode: _mode,
|
|
@@ -27,13 +29,12 @@ function TreeViewInner<TId extends string = string>({
|
|
|
27
29
|
|
|
28
30
|
const handleToggleExpand = (id: TId) => {
|
|
29
31
|
if (interactionPolicy === 'passive') return;
|
|
30
|
-
const
|
|
31
|
-
const newIds = isExpanded ? expandedIds.filter((eid) => eid !== id) : [...expandedIds, id];
|
|
32
|
+
const nextExpandedIds = toggleExpandedIds(expandedIds, id);
|
|
32
33
|
|
|
33
34
|
if (!isControlled) {
|
|
34
|
-
setInternalExpandedIds(
|
|
35
|
+
setInternalExpandedIds(nextExpandedIds);
|
|
35
36
|
}
|
|
36
|
-
onExpandedChange?.(
|
|
37
|
+
onExpandedChange?.(nextExpandedIds);
|
|
37
38
|
};
|
|
38
39
|
|
|
39
40
|
return (
|
|
@@ -55,9 +56,5 @@ function TreeViewInner<TId extends string = string>({
|
|
|
55
56
|
);
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
/***
|
|
59
|
-
* Tree view pattern for hierarchical navigation and expandable lists.
|
|
60
|
-
*
|
|
61
|
-
|
|
62
|
-
*/
|
|
59
|
+
/*** Tree view pattern for hierarchical navigation and expandable lists. */
|
|
63
60
|
export const TreeView = withZoraThemeScope(TreeViewInner);
|