@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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 20.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c9f2c5d: Emit web-only component artifacts with React's production JSX runtime so Next.js SSR consumers can prerender them safely.
|
|
8
|
+
|
|
9
|
+
## 20.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- e915d65: Add Ankh CLI web-only component materialization, starting with TreeView, and wire TreeView default-row selection and icons.
|
|
14
|
+
|
|
3
15
|
## 20.0.2
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface ZoraCreateCommandRequest {
|
|
2
|
+
readonly argv: readonly string[];
|
|
3
|
+
readonly context: {
|
|
4
|
+
readonly cwd: string;
|
|
5
|
+
writeStderr(text: string): void;
|
|
6
|
+
writeStdout(text: string): void;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/*** Materialize a canonical ZORA component for a platform-specific consumer. */
|
|
10
|
+
export declare function create(request: ZoraCreateCommandRequest): Promise<{
|
|
11
|
+
readonly exitCode: number;
|
|
12
|
+
}>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/create.ts"],"names":[],"mappings":"AAMA,UAAU,wBAAwB;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;KACjC,CAAC;CACH;AAED,gFAAgF;AAChF,wBAAsB,MAAM,CAC1B,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCxC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { materializeWebComponentArtifactWithNodeAsync } from '../../features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync';
|
|
5
|
+
/*** Materialize a canonical ZORA component for a platform-specific consumer. */
|
|
6
|
+
export async function create(request) {
|
|
7
|
+
try {
|
|
8
|
+
const options = parseCreateArguments(request.argv);
|
|
9
|
+
const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../../package.json');
|
|
10
|
+
const packageRoot = dirname(packageJsonPath);
|
|
11
|
+
const packageVersion = await readPackageVersionAsync(packageJsonPath);
|
|
12
|
+
const outputDirectory = options.outputDirectory === undefined
|
|
13
|
+
? resolve(request.context.cwd, 'src', 'generated', 'zora', options.component)
|
|
14
|
+
: resolve(request.context.cwd, options.outputDirectory);
|
|
15
|
+
const result = await materializeWebComponentArtifactWithNodeAsync({
|
|
16
|
+
component: options.component,
|
|
17
|
+
outputDirectory,
|
|
18
|
+
packageRoot,
|
|
19
|
+
packageVersion,
|
|
20
|
+
});
|
|
21
|
+
request.context.writeStdout([
|
|
22
|
+
`Created ZORA ${result.component} for ${result.platform} at ${result.outputDirectory}`,
|
|
23
|
+
...result.createdFiles.map((filePath) => ` ${filePath}`),
|
|
24
|
+
'',
|
|
25
|
+
].join('\n'));
|
|
26
|
+
return { exitCode: 0 };
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
request.context.writeStderr(`ZORA create failed: ${message}\n`);
|
|
31
|
+
return { exitCode: 1 };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/*** Parse the intentionally small first web-materialization command surface. */
|
|
35
|
+
function parseCreateArguments(argv) {
|
|
36
|
+
const [component, platformFlag, outputFlag, outputDirectory] = argv;
|
|
37
|
+
const hasDefaultOutput = argv.length === 2 && platformFlag === '--web';
|
|
38
|
+
const hasCustomOutput = argv.length === 4 &&
|
|
39
|
+
platformFlag === '--web' &&
|
|
40
|
+
outputFlag === '--out' &&
|
|
41
|
+
outputDirectory !== undefined &&
|
|
42
|
+
outputDirectory.trim() !== '';
|
|
43
|
+
if (component === undefined ||
|
|
44
|
+
component.trim() === '' ||
|
|
45
|
+
(!hasDefaultOutput && !hasCustomOutput)) {
|
|
46
|
+
throw new Error('Usage: ankh zora create <component> --web [--out <directory>]');
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
component,
|
|
50
|
+
...(hasCustomOutput ? { outputDirectory } : {}),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/*** Read the installed package version used to stamp generated artifacts. */
|
|
54
|
+
async function readPackageVersionAsync(packageJsonPath) {
|
|
55
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
|
|
56
|
+
if (typeof packageJson.version !== 'string' || packageJson.version.trim() === '') {
|
|
57
|
+
throw new Error('ZORA package.json must define a non-empty version.');
|
|
58
|
+
}
|
|
59
|
+
return packageJson.version;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/cli/commands/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,4CAA4C,EAAE,MAAM,gGAAgG,CAAC;AAW9J,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,OAAiC;IAEjC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,eAAe,GAAG,OAAO,CAC7B,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EACvC,uBAAuB,CACxB,CAAC;QACF,MAAM,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;QAC7C,MAAM,cAAc,GAAG,MAAM,uBAAuB,CAAC,eAAe,CAAC,CAAC;QACtE,MAAM,eAAe,GACnB,OAAO,CAAC,eAAe,KAAK,SAAS;YACnC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC;YAC7E,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;QAE5D,MAAM,MAAM,GAAG,MAAM,4CAA4C,CAAC;YAChE,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,eAAe;YACf,WAAW;YACX,cAAc;SACf,CAAC,CAAC;QAEH,OAAO,CAAC,OAAO,CAAC,WAAW,CACzB;YACE,gBAAgB,MAAM,CAAC,SAAS,QAAQ,MAAM,CAAC,QAAQ,OAAO,MAAM,CAAC,eAAe,EAAE;YACtF,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC;YACzD,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACF,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,uBAAuB,OAAO,IAAI,CAAC,CAAC;QAChE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAOD,gFAAgF;AAChF,SAAS,oBAAoB,CAAC,IAAuB;IACnD,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,CAAC,GAAG,IAAI,CAAC;IACpE,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,KAAK,OAAO,CAAC;IACvE,MAAM,eAAe,GACnB,IAAI,CAAC,MAAM,KAAK,CAAC;QACjB,YAAY,KAAK,OAAO;QACxB,UAAU,KAAK,OAAO;QACtB,eAAe,KAAK,SAAS;QAC7B,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAEhC,IACE,SAAS,KAAK,SAAS;QACvB,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE;QACvB,CAAC,CAAC,gBAAgB,IAAI,CAAC,eAAe,CAAC,EACvC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;IACnF,CAAC;IAED,OAAO;QACL,SAAS;QACT,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,KAAK,UAAU,uBAAuB,CAAC,eAAuB;IAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,CAErE,CAAC;IAEF,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,QAAQ,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,WAAW,CAAC,OAAO,CAAC;AAC7B,CAAC","sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { materializeWebComponentArtifactWithNodeAsync } from '../../features/web-component-artifact/composition/materializeWebComponentArtifactWithNodeAsync';\n\ninterface ZoraCreateCommandRequest {\n readonly argv: readonly string[];\n readonly context: {\n readonly cwd: string;\n writeStderr(text: string): void;\n writeStdout(text: string): void;\n };\n}\n\n/*** Materialize a canonical ZORA component for a platform-specific consumer. */\nexport async function create(\n request: ZoraCreateCommandRequest,\n): Promise<{ readonly exitCode: number }> {\n try {\n const options = parseCreateArguments(request.argv);\n const packageJsonPath = resolve(\n dirname(fileURLToPath(import.meta.url)),\n '../../../package.json',\n );\n const packageRoot = dirname(packageJsonPath);\n const packageVersion = await readPackageVersionAsync(packageJsonPath);\n const outputDirectory =\n options.outputDirectory === undefined\n ? resolve(request.context.cwd, 'src', 'generated', 'zora', options.component)\n : resolve(request.context.cwd, options.outputDirectory);\n\n const result = await materializeWebComponentArtifactWithNodeAsync({\n component: options.component,\n outputDirectory,\n packageRoot,\n packageVersion,\n });\n\n request.context.writeStdout(\n [\n `Created ZORA ${result.component} for ${result.platform} at ${result.outputDirectory}`,\n ...result.createdFiles.map((filePath) => ` ${filePath}`),\n '',\n ].join('\\n'),\n );\n return { exitCode: 0 };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n request.context.writeStderr(`ZORA create failed: ${message}\\n`);\n return { exitCode: 1 };\n }\n}\n\ninterface CreateOptions {\n readonly component: string;\n readonly outputDirectory?: string;\n}\n\n/*** Parse the intentionally small first web-materialization command surface. */\nfunction parseCreateArguments(argv: readonly string[]): CreateOptions {\n const [component, platformFlag, outputFlag, outputDirectory] = argv;\n const hasDefaultOutput = argv.length === 2 && platformFlag === '--web';\n const hasCustomOutput =\n argv.length === 4 &&\n platformFlag === '--web' &&\n outputFlag === '--out' &&\n outputDirectory !== undefined &&\n outputDirectory.trim() !== '';\n\n if (\n component === undefined ||\n component.trim() === '' ||\n (!hasDefaultOutput && !hasCustomOutput)\n ) {\n throw new Error('Usage: ankh zora create <component> --web [--out <directory>]');\n }\n\n return {\n component,\n ...(hasCustomOutput ? { outputDirectory } : {}),\n };\n}\n\n/*** Read the installed package version used to stamp generated artifacts. */\nasync function readPackageVersionAsync(packageJsonPath: string): Promise<string> {\n const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as {\n readonly version?: unknown;\n };\n\n if (typeof packageJson.version !== 'string' || packageJson.version.trim() === '') {\n throw new Error('ZORA package.json must define a non-empty version.');\n }\n\n return packageJson.version;\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { create } from './commands/create';
|
|
2
|
+
declare const provider: {
|
|
3
|
+
id: string;
|
|
4
|
+
category: string;
|
|
5
|
+
version: string;
|
|
6
|
+
capabilities: "zora.create"[];
|
|
7
|
+
commands: {
|
|
8
|
+
readonly path: readonly ["create"];
|
|
9
|
+
readonly capability: "zora.create";
|
|
10
|
+
readonly summary: "Materialize a canonical ZORA component for a target platform.";
|
|
11
|
+
}[];
|
|
12
|
+
handlers: {
|
|
13
|
+
path: readonly ["create"];
|
|
14
|
+
handler: typeof create;
|
|
15
|
+
}[];
|
|
16
|
+
};
|
|
17
|
+
export default provider;
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAgB3C,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;CAYiB,CAAC;AAEhC,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { create } from './commands/create';
|
|
5
|
+
const CREATE_CAPABILITY = 'zora.create';
|
|
6
|
+
const CREATE_COMMAND = {
|
|
7
|
+
path: ['create'],
|
|
8
|
+
capability: CREATE_CAPABILITY,
|
|
9
|
+
summary: 'Materialize a canonical ZORA component for a target platform.',
|
|
10
|
+
};
|
|
11
|
+
const provider = {
|
|
12
|
+
id: '@ankhorage/zora',
|
|
13
|
+
category: 'zora',
|
|
14
|
+
version: readPackageVersion(),
|
|
15
|
+
capabilities: [CREATE_CAPABILITY],
|
|
16
|
+
commands: [CREATE_COMMAND],
|
|
17
|
+
handlers: [
|
|
18
|
+
{
|
|
19
|
+
path: CREATE_COMMAND.path,
|
|
20
|
+
handler: create,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
export default provider;
|
|
25
|
+
/*** Read the installed ZORA version for the Ankh provider manifest. */
|
|
26
|
+
function readPackageVersion() {
|
|
27
|
+
const packageJson = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'), 'utf8'));
|
|
28
|
+
if (typeof packageJson.version !== 'string' || packageJson.version.trim() === '') {
|
|
29
|
+
throw new Error('ZORA package.json must define a non-empty version.');
|
|
30
|
+
}
|
|
31
|
+
return packageJson.version;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,iBAAiB,GAAG,aAAwC,CAAC;AACnE,MAAM,cAAc,GAAG;IACrB,IAAI,EAAE,CAAC,QAAQ,CAAC;IAChB,UAAU,EAAE,iBAAiB;IAC7B,OAAO,EAAE,+DAA+D;CAChE,CAAC;AASX,MAAM,QAAQ,GAAG;IACf,EAAE,EAAE,iBAAiB;IACrB,QAAQ,EAAE,MAAM;IAChB,OAAO,EAAE,kBAAkB,EAAE;IAC7B,YAAY,EAAE,CAAC,iBAAiB,CAAC;IACjC,QAAQ,EAAE,CAAC,cAAc,CAAC;IAC1B,QAAQ,EAAE;QACR;YACE,IAAI,EAAE,cAAc,CAAC,IAAI;YACzB,OAAO,EAAE,MAAM;SAChB;KACF;CAC4B,CAAC;AAEhC,eAAe,QAAQ,CAAC;AAExB,uEAAuE;AACvE,SAAS,kBAAkB;IACzB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,CAC3D,CAAC;IAEpC,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,QAAQ,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,WAAW,CAAC,OAAO,CAAC;AAC7B,CAAC","sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { AnkhCapabilityId, AnkhCommandProviderManifest } from '@ankhorage/contracts/cli';\n\nimport { create } from './commands/create';\n\nconst CREATE_CAPABILITY = 'zora.create' satisfies AnkhCapabilityId;\nconst CREATE_COMMAND = {\n path: ['create'],\n capability: CREATE_CAPABILITY,\n summary: 'Materialize a canonical ZORA component for a target platform.',\n} as const;\n\ninterface ZoraRuntimeProvider extends AnkhCommandProviderManifest {\n readonly handlers: readonly {\n readonly path: readonly string[];\n readonly handler: typeof create;\n }[];\n}\n\nconst provider = {\n id: '@ankhorage/zora',\n category: 'zora',\n version: readPackageVersion(),\n capabilities: [CREATE_CAPABILITY],\n commands: [CREATE_COMMAND],\n handlers: [\n {\n path: CREATE_COMMAND.path,\n handler: create,\n },\n ],\n} satisfies ZoraRuntimeProvider;\n\nexport default provider;\n\n/*** Read the installed ZORA version for the Ankh provider manifest. */\nfunction readPackageVersion(): string {\n const packageJson = JSON.parse(\n readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'), 'utf8'),\n ) as { readonly version?: unknown };\n\n if (typeof packageJson.version !== 'string' || packageJson.version.trim() === '') {\n throw new Error('ZORA package.json must define a non-empty version.');\n }\n\n return packageJson.version;\n}\n"]}
|
|
@@ -10,11 +10,7 @@ interface TreeItemProps<TId extends string = string> extends ZoraBaseProps {
|
|
|
10
10
|
onToggleExpand: (id: TId) => void;
|
|
11
11
|
renderItem?: (props: TreeItemRenderProps<TId>) => React.ReactNode;
|
|
12
12
|
}
|
|
13
|
-
/***
|
|
14
|
-
* Single tree node row used within `TreeView`.
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
*/
|
|
13
|
+
/*** Single tree node row used within `TreeView`. */
|
|
18
14
|
export declare const TreeItem: <TId extends string = string>(props: TreeItemProps<TId>) => React.ReactElement | null;
|
|
19
15
|
export {};
|
|
20
16
|
//# sourceMappingURL=TreeItem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeItem.d.ts","sourceRoot":"","sources":["../../../../../src/features/tree-view/adapters/inbound/TreeItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"TreeItem.d.ts","sourceRoot":"","sources":["../../../../../src/features/tree-view/adapters/inbound/TreeItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAOrF,UAAU,aAAa,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,aAAa;IACxE,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,WAAW,EAAE,SAAS,GAAG,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7B,cAAc,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IAClC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;CACnE;AAwFD,oDAAoD;AACpD,eAAO,MAAM,QAAQ,GAtFE,GAAG,SAAS,MAAM,kEAsFgB,CAAC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { IconButton } from '../../../button/public';
|
|
3
|
+
import { Icon } from '../../../icon/public';
|
|
3
4
|
import { View } from '../../../layout/public';
|
|
4
5
|
import { ListItem } from '../../../list/public';
|
|
5
6
|
import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';
|
|
7
|
+
/*** Render one recursive themed tree row and keep row selection separate from expansion controls. */
|
|
6
8
|
function TreeItemInner({ themeId: _themeId, mode: _mode, node, depth, selectedId, expandedIds, onSelect, onToggleExpand, renderItem, testID, interactionPolicy, }) {
|
|
7
9
|
const hasChildren = node.children !== undefined && node.children.length > 0;
|
|
8
10
|
const isExpanded = expandedIds.includes(node.id);
|
|
@@ -17,10 +19,19 @@ function TreeItemInner({ themeId: _themeId, mode: _mode, node, depth, selectedId
|
|
|
17
19
|
hasChildren,
|
|
18
20
|
});
|
|
19
21
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const trailing = node.actions !== undefined || hasChildren ? (<View direction="row" gap="xs" align="center">
|
|
23
|
+
{node.actions}
|
|
24
|
+
{hasChildren ? (<IconButton icon={{ name: isExpanded ? 'chevron-down-outline' : 'chevron-forward-outline' }} interactionPolicy={interactionPolicy} label={isExpanded ? 'Collapse' : 'Expand'} onPress={() => onToggleExpand(node.id)} size="s" variant="ghost"/>) : null}
|
|
25
|
+
</View>) : undefined;
|
|
26
|
+
const listItemProps = {
|
|
27
|
+
title: node.label,
|
|
28
|
+
leading: node.icon === undefined ? undefined : <Icon {...node.icon} size="s"/>,
|
|
29
|
+
meta: node.meta,
|
|
30
|
+
disabled: node.disabled,
|
|
31
|
+
selected: isSelected,
|
|
32
|
+
trailing,
|
|
33
|
+
};
|
|
34
|
+
return onSelect === undefined ? (<ListItem {...listItemProps}/>) : (<ListItem {...listItemProps} onPress={() => onSelect(node.id)}/>);
|
|
24
35
|
};
|
|
25
36
|
return (<View testID={testID}>
|
|
26
37
|
<View style={{ paddingLeft: depth * 16 }}>{renderContent()}</View>
|
|
@@ -29,10 +40,6 @@ function TreeItemInner({ themeId: _themeId, mode: _mode, node, depth, selectedId
|
|
|
29
40
|
</View>) : null}
|
|
30
41
|
</View>);
|
|
31
42
|
}
|
|
32
|
-
/***
|
|
33
|
-
* Single tree node row used within `TreeView`.
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
*/
|
|
43
|
+
/*** Single tree node row used within `TreeView`. */
|
|
37
44
|
export const TreeItem = withZoraThemeScope(TreeItemInner);
|
|
38
45
|
//# sourceMappingURL=TreeItem.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeItem.js","sourceRoot":"","sources":["../../../../../src/features/tree-view/adapters/inbound/TreeItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oDAAoD,CAAC;AAYxF,SAAS,aAAa,CAA8B,EAClD,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,IAAI,EACJ,KAAK,EACL,UAAU,EACV,WAAW,EACX,QAAQ,EACR,cAAc,EACd,UAAU,EACV,MAAM,EACN,iBAAiB,GACE;IACnB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5E,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,UAAU,KAAK,IAAI,CAAC,EAAE,CAAC;IAE1C,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,UAAU,CAAC;gBAChB,IAAI;gBACJ,KAAK;gBACL,QAAQ,EAAE,UAAU;gBACpB,QAAQ,EAAE,UAAU;gBACpB,WAAW;aACZ,CAAC,CAAC;QACL,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"TreeItem.js","sourceRoot":"","sources":["../../../../../src/features/tree-view/adapters/inbound/TreeItem.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\n\nimport type { ZoraBaseProps } from '../../../../types/base';\nimport type { TreeItemNode, TreeItemRenderProps } from '../../../../types/tree-view';\nimport { IconButton } from '../../../button/public';\nimport { Icon } from '../../../icon/public';\nimport { View } from '../../../layout/public';\nimport { ListItem } from '../../../list/public';\nimport { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';\n\ninterface TreeItemProps<TId extends string = string> extends ZoraBaseProps {\n node: TreeItemNode<TId>;\n depth: number;\n selectedId?: TId;\n expandedIds: readonly TId[];\n onSelect?: (id: TId) => void;\n onToggleExpand: (id: TId) => void;\n renderItem?: (props: TreeItemRenderProps<TId>) => React.ReactNode;\n}\n\n/*** Render one recursive themed tree row and keep row selection separate from expansion controls. */\nfunction TreeItemInner<TId extends string = string>({\n themeId: _themeId,\n mode: _mode,\n node,\n depth,\n selectedId,\n expandedIds,\n onSelect,\n onToggleExpand,\n renderItem,\n testID,\n interactionPolicy,\n}: TreeItemProps<TId>) {\n const hasChildren = node.children !== undefined && node.children.length > 0;\n const isExpanded = expandedIds.includes(node.id);\n const isSelected = selectedId === node.id;\n\n const renderContent = () => {\n if (renderItem) {\n return renderItem({\n node,\n depth,\n selected: isSelected,\n expanded: isExpanded,\n hasChildren,\n });\n }\n\n const trailing =\n node.actions !== undefined || hasChildren ? (\n <View direction=\"row\" gap=\"xs\" align=\"center\">\n {node.actions}\n {hasChildren ? (\n <IconButton\n icon={{ name: isExpanded ? 'chevron-down-outline' : 'chevron-forward-outline' }}\n interactionPolicy={interactionPolicy}\n label={isExpanded ? 'Collapse' : 'Expand'}\n onPress={() => onToggleExpand(node.id)}\n size=\"s\"\n variant=\"ghost\"\n />\n ) : null}\n </View>\n ) : undefined;\n\n const listItemProps = {\n title: node.label,\n leading: node.icon === undefined ? undefined : <Icon {...node.icon} size=\"s\" />,\n meta: node.meta,\n disabled: node.disabled,\n selected: isSelected,\n trailing,\n };\n\n return onSelect === undefined ? (\n <ListItem {...listItemProps} />\n ) : (\n <ListItem {...listItemProps} onPress={() => onSelect(node.id)} />\n );\n };\n\n return (\n <View testID={testID}>\n <View style={{ paddingLeft: depth * 16 }}>{renderContent()}</View>\n {hasChildren && isExpanded ? (\n <View>\n {node.children?.map((child) => (\n <TreeItem\n key={child.id}\n depth={depth + 1}\n expandedIds={expandedIds}\n interactionPolicy={interactionPolicy}\n node={child}\n onSelect={onSelect}\n onToggleExpand={onToggleExpand}\n renderItem={renderItem}\n selectedId={selectedId}\n />\n ))}\n </View>\n ) : null}\n </View>\n );\n}\n\n/*** Single tree node row used within `TreeView`. */\nexport const TreeItem = withZoraThemeScope(TreeItemInner);\n"]}
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { TreeViewProps } from '../../../../types/tree-view';
|
|
3
|
-
/***
|
|
4
|
-
* Tree view pattern for hierarchical navigation and expandable lists.
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
*/
|
|
3
|
+
/*** Tree view pattern for hierarchical navigation and expandable lists. */
|
|
8
4
|
export declare const TreeView: <TId extends string = string>(props: TreeViewProps<TId>) => React.ReactElement | null;
|
|
9
5
|
//# sourceMappingURL=TreeView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeView.d.ts","sourceRoot":"","sources":["../../../../../src/features/tree-view/adapters/inbound/TreeView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"TreeView.d.ts","sourceRoot":"","sources":["../../../../../src/features/tree-view/adapters/inbound/TreeView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAwDjE,2EAA2E;AAC3E,eAAO,MAAM,QAAQ,GAlDE,GAAG,SAAS,MAAM,kEAkDgB,CAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View } from '../../../layout/public';
|
|
3
3
|
import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';
|
|
4
|
+
import { toggleExpandedIds } from '../../utils/toggleExpandedIds';
|
|
4
5
|
import { TreeItem } from './TreeItem';
|
|
6
|
+
/*** Render the themed TreeView while supporting controlled or internal expansion state. */
|
|
5
7
|
function TreeViewInner({ themeId: _themeId, mode: _mode, nodes, selectedId, expandedIds: controlledExpandedIds, defaultExpandedIds, onSelect, onExpandedChange, renderItem, testID, interactionPolicy, }) {
|
|
6
8
|
const [internalExpandedIds, setInternalExpandedIds] = React.useState(defaultExpandedIds ?? []);
|
|
7
9
|
const isControlled = controlledExpandedIds !== undefined;
|
|
@@ -9,21 +11,16 @@ function TreeViewInner({ themeId: _themeId, mode: _mode, nodes, selectedId, expa
|
|
|
9
11
|
const handleToggleExpand = (id) => {
|
|
10
12
|
if (interactionPolicy === 'passive')
|
|
11
13
|
return;
|
|
12
|
-
const
|
|
13
|
-
const newIds = isExpanded ? expandedIds.filter((eid) => eid !== id) : [...expandedIds, id];
|
|
14
|
+
const nextExpandedIds = toggleExpandedIds(expandedIds, id);
|
|
14
15
|
if (!isControlled) {
|
|
15
|
-
setInternalExpandedIds(
|
|
16
|
+
setInternalExpandedIds(nextExpandedIds);
|
|
16
17
|
}
|
|
17
|
-
onExpandedChange?.(
|
|
18
|
+
onExpandedChange?.(nextExpandedIds);
|
|
18
19
|
};
|
|
19
20
|
return (<View gap="none" testID={testID}>
|
|
20
21
|
{nodes.map((node) => (<TreeItem key={node.id} depth={0} expandedIds={expandedIds} node={node} onSelect={onSelect} onToggleExpand={handleToggleExpand} renderItem={renderItem} selectedId={selectedId} interactionPolicy={interactionPolicy}/>))}
|
|
21
22
|
</View>);
|
|
22
23
|
}
|
|
23
|
-
/***
|
|
24
|
-
* Tree view pattern for hierarchical navigation and expandable lists.
|
|
25
|
-
*
|
|
26
|
-
|
|
27
|
-
*/
|
|
24
|
+
/*** Tree view pattern for hierarchical navigation and expandable lists. */
|
|
28
25
|
export const TreeView = withZoraThemeScope(TreeViewInner);
|
|
29
26
|
//# sourceMappingURL=TreeView.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeView.js","sourceRoot":"","sources":["../../../../../src/features/tree-view/adapters/inbound/TreeView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oDAAoD,CAAC;AACxF,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,SAAS,aAAa,CAA8B,EAClD,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,KAAK,EACL,UAAU,EACV,WAAW,EAAE,qBAAqB,EAClC,kBAAkB,EAClB,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,MAAM,EACN,iBAAiB,GACE;IACnB,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAClE,kBAAkB,IAAI,EAAE,CACzB,CAAC;IAEF,MAAM,YAAY,GAAG,qBAAqB,KAAK,SAAS,CAAC;IACzD,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,mBAAmB,CAAC;IAE/E,MAAM,kBAAkB,GAAG,CAAC,EAAO,EAAE,EAAE;QACrC,IAAI,iBAAiB,KAAK,SAAS;YAAE,OAAO;QAC5C,MAAM,
|
|
1
|
+
{"version":3,"file":"TreeView.js","sourceRoot":"","sources":["../../../../../src/features/tree-view/adapters/inbound/TreeView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oDAAoD,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,2FAA2F;AAC3F,SAAS,aAAa,CAA8B,EAClD,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,KAAK,EACL,UAAU,EACV,WAAW,EAAE,qBAAqB,EAClC,kBAAkB,EAClB,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,MAAM,EACN,iBAAiB,GACE;IACnB,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAClE,kBAAkB,IAAI,EAAE,CACzB,CAAC;IAEF,MAAM,YAAY,GAAG,qBAAqB,KAAK,SAAS,CAAC;IACzD,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,mBAAmB,CAAC;IAE/E,MAAM,kBAAkB,GAAG,CAAC,EAAO,EAAE,EAAE;QACrC,IAAI,iBAAiB,KAAK,SAAS;YAAE,OAAO;QAC5C,MAAM,eAAe,GAAG,iBAAiB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAE3D,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,sBAAsB,CAAC,eAAe,CAAC,CAAC;QAC1C,CAAC;QACD,gBAAgB,EAAE,CAAC,eAAe,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,OAAO,CACL,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAC9B;MAAA,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,CAAC,QAAQ,CACP,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CACb,KAAK,CAAC,CAAC,CAAC,CAAC,CACT,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,QAAQ,CAAC,CAAC,QAAQ,CAAC,CACnB,cAAc,CAAC,CAAC,kBAAkB,CAAC,CACnC,UAAU,CAAC,CAAC,UAAU,CAAC,CACvB,UAAU,CAAC,CAAC,UAAU,CAAC,CACvB,iBAAiB,CAAC,CAAC,iBAAiB,CAAC,EACrC,CACH,CAAC,CACJ;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,aAAa,CAAC,CAAC","sourcesContent":["import React from 'react';\n\nimport type { TreeViewProps } from '../../../../types/tree-view';\nimport { View } from '../../../layout/public';\nimport { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';\nimport { toggleExpandedIds } from '../../utils/toggleExpandedIds';\nimport { TreeItem } from './TreeItem';\n\n/*** Render the themed TreeView while supporting controlled or internal expansion state. */\nfunction TreeViewInner<TId extends string = string>({\n themeId: _themeId,\n mode: _mode,\n nodes,\n selectedId,\n expandedIds: controlledExpandedIds,\n defaultExpandedIds,\n onSelect,\n onExpandedChange,\n renderItem,\n testID,\n interactionPolicy,\n}: TreeViewProps<TId>) {\n const [internalExpandedIds, setInternalExpandedIds] = React.useState<readonly TId[]>(\n defaultExpandedIds ?? [],\n );\n\n const isControlled = controlledExpandedIds !== undefined;\n const expandedIds = isControlled ? controlledExpandedIds : internalExpandedIds;\n\n const handleToggleExpand = (id: TId) => {\n if (interactionPolicy === 'passive') return;\n const nextExpandedIds = toggleExpandedIds(expandedIds, id);\n\n if (!isControlled) {\n setInternalExpandedIds(nextExpandedIds);\n }\n onExpandedChange?.(nextExpandedIds);\n };\n\n return (\n <View gap=\"none\" testID={testID}>\n {nodes.map((node) => (\n <TreeItem\n key={node.id}\n depth={0}\n expandedIds={expandedIds}\n node={node}\n onSelect={onSelect}\n onToggleExpand={handleToggleExpand}\n renderItem={renderItem}\n selectedId={selectedId}\n interactionPolicy={interactionPolicy}\n />\n ))}\n </View>\n );\n}\n\n/*** Tree view pattern for hierarchical navigation and expandable lists. */\nexport const TreeView = withZoraThemeScope(TreeViewInner);\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { TreeItemNode, TreeItemRenderProps } from './TreeView';
|
|
3
|
+
/*** Render one recursive browser tree row while keeping selection and expansion independent. */
|
|
4
|
+
export declare function TreeItemRow<TId extends string>(props: TreeItemRowProps<TId>): React.JSX.Element;
|
|
5
|
+
interface TreeItemRowProps<TId extends string> {
|
|
6
|
+
readonly node: TreeItemNode<TId>;
|
|
7
|
+
readonly depth: number;
|
|
8
|
+
readonly selectedId?: TId;
|
|
9
|
+
readonly expandedIds: readonly TId[];
|
|
10
|
+
readonly onSelect?: (id: TId) => void;
|
|
11
|
+
readonly onToggleExpand: (id: TId) => void;
|
|
12
|
+
readonly renderItem?: (props: TreeItemRenderProps<TId>) => React.ReactNode;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=TreeItemRow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeItemRow.d.ts","sourceRoot":"","sources":["../../../../../../src/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE,gGAAgG;AAChG,wBAAgB,WAAW,CAAC,GAAG,SAAS,MAAM,EAAE,KAAK,EAAE,gBAAgB,CAAC,GAAG,CAAC,qBAqC3E;AAED,UAAU,gBAAgB,CAAC,GAAG,SAAS,MAAM;IAC3C,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,SAAS,GAAG,EAAE,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,cAAc,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;CAC5E"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/*** Render one recursive browser tree row while keeping selection and expansion independent. */
|
|
3
|
+
export function TreeItemRow(props) {
|
|
4
|
+
const { node } = props;
|
|
5
|
+
const hasChildren = node.children !== undefined && node.children.length > 0;
|
|
6
|
+
const expanded = props.expandedIds.includes(node.id);
|
|
7
|
+
const selected = props.selectedId === node.id;
|
|
8
|
+
const content = props.renderItem?.({
|
|
9
|
+
node,
|
|
10
|
+
depth: props.depth,
|
|
11
|
+
selected,
|
|
12
|
+
expanded,
|
|
13
|
+
hasChildren,
|
|
14
|
+
}) ?? <TreeItemDefaultContent node={node}/>;
|
|
15
|
+
return (<>
|
|
16
|
+
<div aria-disabled={node.disabled === true ? true : undefined} aria-expanded={hasChildren ? expanded : undefined} aria-selected={selected} onClick={() => selectNode(props)} onKeyDown={(event) => selectNodeFromKeyboard(event, props)} role="treeitem" tabIndex={node.disabled || props.onSelect === undefined ? undefined : 0} style={createRowStyle(props.depth, selected, node.disabled, props.onSelect !== undefined)}>
|
|
17
|
+
{content}
|
|
18
|
+
<TreeItemActions actions={node.actions}/>
|
|
19
|
+
<TreeItemExpander expanded={expanded} hasChildren={hasChildren} nodeId={node.id} onToggleExpand={props.onToggleExpand}/>
|
|
20
|
+
</div>
|
|
21
|
+
{hasChildren && expanded ? <TreeItemChildren {...props}/> : null}
|
|
22
|
+
</>);
|
|
23
|
+
}
|
|
24
|
+
/*** Render the default browser tree-row label, icon, and metadata. */
|
|
25
|
+
function TreeItemDefaultContent({ node, }) {
|
|
26
|
+
return (<>
|
|
27
|
+
{node.icon === undefined ? null : (<span aria-hidden="true" style={ICON_STYLE}>
|
|
28
|
+
{node.icon}
|
|
29
|
+
</span>)}
|
|
30
|
+
<span style={LABEL_STYLE}>{node.label}</span>
|
|
31
|
+
{node.meta === undefined ? null : <span style={META_STYLE}>{node.meta}</span>}
|
|
32
|
+
</>);
|
|
33
|
+
}
|
|
34
|
+
/*** Isolate optional row actions so their pointer events do not select the tree item. */
|
|
35
|
+
function TreeItemActions({ actions }) {
|
|
36
|
+
if (actions === undefined)
|
|
37
|
+
return null;
|
|
38
|
+
return (<span onClick={(event) => event.stopPropagation()} onKeyDown={(event) => event.stopPropagation()} style={INLINE_STYLE}>
|
|
39
|
+
{actions}
|
|
40
|
+
</span>);
|
|
41
|
+
}
|
|
42
|
+
/*** Render the independent expansion control for a tree row with children. */
|
|
43
|
+
function TreeItemExpander(props) {
|
|
44
|
+
if (!props.hasChildren)
|
|
45
|
+
return null;
|
|
46
|
+
return (<button aria-label={props.expanded ? 'Collapse' : 'Expand'} onClick={(event) => {
|
|
47
|
+
event.stopPropagation();
|
|
48
|
+
props.onToggleExpand(props.nodeId);
|
|
49
|
+
}} style={EXPANDER_STYLE} type="button">
|
|
50
|
+
{props.expanded ? '⌄' : '›'}
|
|
51
|
+
</button>);
|
|
52
|
+
}
|
|
53
|
+
/*** Render expanded descendants recursively. */
|
|
54
|
+
function TreeItemChildren(props) {
|
|
55
|
+
return (<div role="group">
|
|
56
|
+
{props.node.children?.map((child) => (<TreeItemRow {...props} key={child.id} depth={props.depth + 1} node={child}/>))}
|
|
57
|
+
</div>);
|
|
58
|
+
}
|
|
59
|
+
/*** Select a row from pointer activation when it is interactive. */
|
|
60
|
+
function selectNode(props) {
|
|
61
|
+
if (!props.node.disabled)
|
|
62
|
+
props.onSelect?.(props.node.id);
|
|
63
|
+
}
|
|
64
|
+
/*** Select a row from keyboard activation while preserving native navigation keys. */
|
|
65
|
+
function selectNodeFromKeyboard(event, props) {
|
|
66
|
+
if (props.node.disabled || (event.key !== 'Enter' && event.key !== ' '))
|
|
67
|
+
return;
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
props.onSelect?.(props.node.id);
|
|
70
|
+
}
|
|
71
|
+
/*** Resolve browser row presentation from the interaction state. */
|
|
72
|
+
function createRowStyle(depth, selected, disabled, selectable) {
|
|
73
|
+
return {
|
|
74
|
+
...ROW_STYLE,
|
|
75
|
+
background: selected ? 'color-mix(in srgb, currentColor 10%, transparent)' : 'transparent',
|
|
76
|
+
cursor: disabled ? 'default' : selectable ? 'pointer' : 'inherit',
|
|
77
|
+
opacity: disabled ? 0.5 : 1,
|
|
78
|
+
paddingLeft: depth * 16 + 6,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const ROW_STYLE = {
|
|
82
|
+
alignItems: 'center',
|
|
83
|
+
borderRadius: 6,
|
|
84
|
+
display: 'flex',
|
|
85
|
+
gap: 6,
|
|
86
|
+
minHeight: 28,
|
|
87
|
+
paddingRight: 4,
|
|
88
|
+
userSelect: 'none',
|
|
89
|
+
};
|
|
90
|
+
const INLINE_STYLE = {
|
|
91
|
+
display: 'inline-flex',
|
|
92
|
+
flexShrink: 0,
|
|
93
|
+
};
|
|
94
|
+
const ICON_STYLE = INLINE_STYLE;
|
|
95
|
+
const LABEL_STYLE = {
|
|
96
|
+
flex: 1,
|
|
97
|
+
minWidth: 0,
|
|
98
|
+
overflow: 'hidden',
|
|
99
|
+
textOverflow: 'ellipsis',
|
|
100
|
+
whiteSpace: 'nowrap',
|
|
101
|
+
};
|
|
102
|
+
const META_STYLE = {
|
|
103
|
+
flexShrink: 0,
|
|
104
|
+
opacity: 0.65,
|
|
105
|
+
};
|
|
106
|
+
const EXPANDER_STYLE = {
|
|
107
|
+
alignItems: 'center',
|
|
108
|
+
appearance: 'none',
|
|
109
|
+
background: 'transparent',
|
|
110
|
+
border: 0,
|
|
111
|
+
color: 'inherit',
|
|
112
|
+
cursor: 'pointer',
|
|
113
|
+
display: 'inline-flex',
|
|
114
|
+
flexShrink: 0,
|
|
115
|
+
font: 'inherit',
|
|
116
|
+
height: 24,
|
|
117
|
+
justifyContent: 'center',
|
|
118
|
+
padding: 0,
|
|
119
|
+
width: 24,
|
|
120
|
+
};
|
|
121
|
+
//# sourceMappingURL=TreeItemRow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeItemRow.js","sourceRoot":"","sources":["../../../../../../src/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\n\nimport type { TreeItemNode, TreeItemRenderProps } from './TreeView';\n\n/*** Render one recursive browser tree row while keeping selection and expansion independent. */\nexport function TreeItemRow<TId extends string>(props: TreeItemRowProps<TId>) {\n const { node } = props;\n const hasChildren = node.children !== undefined && node.children.length > 0;\n const expanded = props.expandedIds.includes(node.id);\n const selected = props.selectedId === node.id;\n const content = props.renderItem?.({\n node,\n depth: props.depth,\n selected,\n expanded,\n hasChildren,\n }) ?? <TreeItemDefaultContent node={node} />;\n\n return (\n <>\n <div\n aria-disabled={node.disabled === true ? true : undefined}\n aria-expanded={hasChildren ? expanded : undefined}\n aria-selected={selected}\n onClick={() => selectNode(props)}\n onKeyDown={(event) => selectNodeFromKeyboard(event, props)}\n role=\"treeitem\"\n tabIndex={node.disabled || props.onSelect === undefined ? undefined : 0}\n style={createRowStyle(props.depth, selected, node.disabled, props.onSelect !== undefined)}\n >\n {content}\n <TreeItemActions actions={node.actions} />\n <TreeItemExpander\n expanded={expanded}\n hasChildren={hasChildren}\n nodeId={node.id}\n onToggleExpand={props.onToggleExpand}\n />\n </div>\n {hasChildren && expanded ? <TreeItemChildren {...props} /> : null}\n </>\n );\n}\n\ninterface TreeItemRowProps<TId extends string> {\n readonly node: TreeItemNode<TId>;\n readonly depth: number;\n readonly selectedId?: TId;\n readonly expandedIds: readonly TId[];\n readonly onSelect?: (id: TId) => void;\n readonly onToggleExpand: (id: TId) => void;\n readonly renderItem?: (props: TreeItemRenderProps<TId>) => React.ReactNode;\n}\n\n/*** Render the default browser tree-row label, icon, and metadata. */\nfunction TreeItemDefaultContent<TId extends string>({\n node,\n}: {\n readonly node: TreeItemNode<TId>;\n}) {\n return (\n <>\n {node.icon === undefined ? null : (\n <span aria-hidden=\"true\" style={ICON_STYLE}>\n {node.icon}\n </span>\n )}\n <span style={LABEL_STYLE}>{node.label}</span>\n {node.meta === undefined ? null : <span style={META_STYLE}>{node.meta}</span>}\n </>\n );\n}\n\n/*** Isolate optional row actions so their pointer events do not select the tree item. */\nfunction TreeItemActions({ actions }: { readonly actions?: React.ReactNode }) {\n if (actions === undefined) return null;\n return (\n <span\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n style={INLINE_STYLE}\n >\n {actions}\n </span>\n );\n}\n\n/*** Render the independent expansion control for a tree row with children. */\nfunction TreeItemExpander<TId extends string>(props: {\n readonly expanded: boolean;\n readonly hasChildren: boolean;\n readonly nodeId: TId;\n readonly onToggleExpand: (id: TId) => void;\n}) {\n if (!props.hasChildren) return null;\n return (\n <button\n aria-label={props.expanded ? 'Collapse' : 'Expand'}\n onClick={(event) => {\n event.stopPropagation();\n props.onToggleExpand(props.nodeId);\n }}\n style={EXPANDER_STYLE}\n type=\"button\"\n >\n {props.expanded ? '⌄' : '›'}\n </button>\n );\n}\n\n/*** Render expanded descendants recursively. */\nfunction TreeItemChildren<TId extends string>(props: TreeItemRowProps<TId>) {\n return (\n <div role=\"group\">\n {props.node.children?.map((child) => (\n <TreeItemRow {...props} key={child.id} depth={props.depth + 1} node={child} />\n ))}\n </div>\n );\n}\n\n/*** Select a row from pointer activation when it is interactive. */\nfunction selectNode<TId extends string>(props: TreeItemRowProps<TId>) {\n if (!props.node.disabled) props.onSelect?.(props.node.id);\n}\n\n/*** Select a row from keyboard activation while preserving native navigation keys. */\nfunction selectNodeFromKeyboard<TId extends string>(\n event: React.KeyboardEvent<HTMLDivElement>,\n props: TreeItemRowProps<TId>,\n) {\n if (props.node.disabled || (event.key !== 'Enter' && event.key !== ' ')) return;\n event.preventDefault();\n props.onSelect?.(props.node.id);\n}\n\n/*** Resolve browser row presentation from the interaction state. */\nfunction createRowStyle(\n depth: number,\n selected: boolean,\n disabled: boolean | undefined,\n selectable: boolean,\n): React.CSSProperties {\n return {\n ...ROW_STYLE,\n background: selected ? 'color-mix(in srgb, currentColor 10%, transparent)' : 'transparent',\n cursor: disabled ? 'default' : selectable ? 'pointer' : 'inherit',\n opacity: disabled ? 0.5 : 1,\n paddingLeft: depth * 16 + 6,\n };\n}\n\nconst ROW_STYLE = {\n alignItems: 'center',\n borderRadius: 6,\n display: 'flex',\n gap: 6,\n minHeight: 28,\n paddingRight: 4,\n userSelect: 'none',\n} as const satisfies React.CSSProperties;\n\nconst INLINE_STYLE = {\n display: 'inline-flex',\n flexShrink: 0,\n} as const satisfies React.CSSProperties;\n\nconst ICON_STYLE = INLINE_STYLE;\n\nconst LABEL_STYLE = {\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n} as const satisfies React.CSSProperties;\n\nconst META_STYLE = {\n flexShrink: 0,\n opacity: 0.65,\n} as const satisfies React.CSSProperties;\n\nconst EXPANDER_STYLE = {\n alignItems: 'center',\n appearance: 'none',\n background: 'transparent',\n border: 0,\n color: 'inherit',\n cursor: 'pointer',\n display: 'inline-flex',\n flexShrink: 0,\n font: 'inherit',\n height: 24,\n justifyContent: 'center',\n padding: 0,\n width: 24,\n} as const satisfies React.CSSProperties;\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface TreeItemNode<TId extends string = string> {
|
|
3
|
+
readonly id: TId;
|
|
4
|
+
readonly label: React.ReactNode;
|
|
5
|
+
readonly icon?: React.ReactNode;
|
|
6
|
+
readonly children?: readonly TreeItemNode<TId>[];
|
|
7
|
+
readonly disabled?: boolean;
|
|
8
|
+
readonly meta?: React.ReactNode;
|
|
9
|
+
readonly actions?: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export interface TreeItemRenderProps<TId extends string = string> {
|
|
12
|
+
readonly node: TreeItemNode<TId>;
|
|
13
|
+
readonly depth: number;
|
|
14
|
+
readonly selected: boolean;
|
|
15
|
+
readonly expanded: boolean;
|
|
16
|
+
readonly hasChildren: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface TreeViewProps<TId extends string = string> {
|
|
19
|
+
readonly nodes: readonly TreeItemNode<TId>[];
|
|
20
|
+
readonly selectedId?: TId;
|
|
21
|
+
readonly expandedIds?: readonly TId[];
|
|
22
|
+
readonly defaultExpandedIds?: readonly TId[];
|
|
23
|
+
readonly onSelect?: (id: TId) => void;
|
|
24
|
+
readonly onExpandedChange?: (ids: readonly TId[]) => void;
|
|
25
|
+
readonly renderItem?: (props: TreeItemRenderProps<TId>) => React.ReactNode;
|
|
26
|
+
readonly className?: string;
|
|
27
|
+
readonly style?: React.CSSProperties;
|
|
28
|
+
readonly ariaLabel?: string;
|
|
29
|
+
}
|
|
30
|
+
/*** Render the standalone browser TreeView artifact without React Native runtime dependencies. */
|
|
31
|
+
export declare function TreeView<TId extends string = string>({ nodes, selectedId, expandedIds: controlledExpandedIds, defaultExpandedIds, onSelect, onExpandedChange, renderItem, className, style, ariaLabel, }: TreeViewProps<TId>): React.JSX.Element;
|
|
32
|
+
//# sourceMappingURL=TreeView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeView.d.ts","sourceRoot":"","sources":["../../../../../../src/features/tree-view/adapters/inbound/web-artifact/TreeView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,MAAM,WAAW,YAAY,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IACvD,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACjB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IAC9D,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,GAAG,EAAE,CAAC;IACtC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,GAAG,EAAE,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,GAAG,EAAE,KAAK,IAAI,CAAC;IAC1D,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAAE,EACpD,KAAK,EACL,UAAU,EACV,WAAW,EAAE,qBAAqB,EAClC,kBAAkB,EAClB,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,KAAK,EACL,SAAkB,GACnB,EAAE,aAAa,CAAC,GAAG,CAAC,qBAoCpB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { toggleExpandedIds } from '../../../utils/toggleExpandedIds';
|
|
3
|
+
import { TreeItemRow } from './TreeItemRow';
|
|
4
|
+
/*** Render the standalone browser TreeView artifact without React Native runtime dependencies. */
|
|
5
|
+
export function TreeView({ nodes, selectedId, expandedIds: controlledExpandedIds, defaultExpandedIds, onSelect, onExpandedChange, renderItem, className, style, ariaLabel = 'Tree', }) {
|
|
6
|
+
const [internalExpandedIds, setInternalExpandedIds] = React.useState(defaultExpandedIds ?? []);
|
|
7
|
+
const isControlled = controlledExpandedIds !== undefined;
|
|
8
|
+
const expandedIds = isControlled ? controlledExpandedIds : internalExpandedIds;
|
|
9
|
+
const handleToggleExpand = React.useCallback((id) => {
|
|
10
|
+
const nextExpandedIds = toggleExpandedIds(expandedIds, id);
|
|
11
|
+
if (!isControlled)
|
|
12
|
+
setInternalExpandedIds(nextExpandedIds);
|
|
13
|
+
onExpandedChange?.(nextExpandedIds);
|
|
14
|
+
}, [expandedIds, isControlled, onExpandedChange]);
|
|
15
|
+
return (<div aria-label={ariaLabel} className={className} role="tree" style={{ ...TREE_STYLE, ...style }}>
|
|
16
|
+
{nodes.map((node) => (<TreeItemRow key={node.id} depth={0} expandedIds={expandedIds} node={node} onSelect={onSelect} onToggleExpand={handleToggleExpand} renderItem={renderItem} selectedId={selectedId}/>))}
|
|
17
|
+
</div>);
|
|
18
|
+
}
|
|
19
|
+
const TREE_STYLE = {
|
|
20
|
+
display: 'flex',
|
|
21
|
+
flexDirection: 'column',
|
|
22
|
+
minWidth: 0,
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=TreeView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeView.js","sourceRoot":"","sources":["../../../../../../src/features/tree-view/adapters/inbound/web-artifact/TreeView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAiC5C,kGAAkG;AAClG,MAAM,UAAU,QAAQ,CAA8B,EACpD,KAAK,EACL,UAAU,EACV,WAAW,EAAE,qBAAqB,EAClC,kBAAkB,EAClB,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,KAAK,EACL,SAAS,GAAG,MAAM,GACC;IACnB,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAClE,kBAAkB,IAAI,EAAE,CACzB,CAAC;IACF,MAAM,YAAY,GAAG,qBAAqB,KAAK,SAAS,CAAC;IACzD,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,mBAAmB,CAAC;IAC/E,MAAM,kBAAkB,GAAG,KAAK,CAAC,WAAW,CAC1C,CAAC,EAAO,EAAE,EAAE;QACV,MAAM,eAAe,GAAG,iBAAiB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,YAAY;YAAE,sBAAsB,CAAC,eAAe,CAAC,CAAC;QAC3D,gBAAgB,EAAE,CAAC,eAAe,CAAC,CAAC;IACtC,CAAC,EACD,CAAC,WAAW,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAC9C,CAAC;IAEF,OAAO,CACL,CAAC,GAAG,CACF,UAAU,CAAC,CAAC,SAAS,CAAC,CACtB,SAAS,CAAC,CAAC,SAAS,CAAC,CACrB,IAAI,CAAC,MAAM,CACX,KAAK,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,GAAG,KAAK,EAAE,CAAC,CAEnC;MAAA,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,CAAC,WAAW,CACV,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CACb,KAAK,CAAC,CAAC,CAAC,CAAC,CACT,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,QAAQ,CAAC,CAAC,QAAQ,CAAC,CACnB,cAAc,CAAC,CAAC,kBAAkB,CAAC,CACnC,UAAU,CAAC,CAAC,UAAU,CAAC,CACvB,UAAU,CAAC,CAAC,UAAU,CAAC,EACvB,CACH,CAAC,CACJ;IAAA,EAAE,GAAG,CAAC,CACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,GAAG;IACjB,OAAO,EAAE,MAAM;IACf,aAAa,EAAE,QAAQ;IACvB,QAAQ,EAAE,CAAC;CAC2B,CAAC","sourcesContent":["import React from 'react';\n\nimport { toggleExpandedIds } from '../../../utils/toggleExpandedIds';\nimport { TreeItemRow } from './TreeItemRow';\n\nexport interface TreeItemNode<TId extends string = string> {\n readonly id: TId;\n readonly label: React.ReactNode;\n readonly icon?: React.ReactNode;\n readonly children?: readonly TreeItemNode<TId>[];\n readonly disabled?: boolean;\n readonly meta?: React.ReactNode;\n readonly actions?: React.ReactNode;\n}\n\nexport interface TreeItemRenderProps<TId extends string = string> {\n readonly node: TreeItemNode<TId>;\n readonly depth: number;\n readonly selected: boolean;\n readonly expanded: boolean;\n readonly hasChildren: boolean;\n}\n\nexport interface TreeViewProps<TId extends string = string> {\n readonly nodes: readonly TreeItemNode<TId>[];\n readonly selectedId?: TId;\n readonly expandedIds?: readonly TId[];\n readonly defaultExpandedIds?: readonly TId[];\n readonly onSelect?: (id: TId) => void;\n readonly onExpandedChange?: (ids: readonly TId[]) => void;\n readonly renderItem?: (props: TreeItemRenderProps<TId>) => React.ReactNode;\n readonly className?: string;\n readonly style?: React.CSSProperties;\n readonly ariaLabel?: string;\n}\n\n/*** Render the standalone browser TreeView artifact without React Native runtime dependencies. */\nexport function TreeView<TId extends string = string>({\n nodes,\n selectedId,\n expandedIds: controlledExpandedIds,\n defaultExpandedIds,\n onSelect,\n onExpandedChange,\n renderItem,\n className,\n style,\n ariaLabel = 'Tree',\n}: TreeViewProps<TId>) {\n const [internalExpandedIds, setInternalExpandedIds] = React.useState<readonly TId[]>(\n defaultExpandedIds ?? [],\n );\n const isControlled = controlledExpandedIds !== undefined;\n const expandedIds = isControlled ? controlledExpandedIds : internalExpandedIds;\n const handleToggleExpand = React.useCallback(\n (id: TId) => {\n const nextExpandedIds = toggleExpandedIds(expandedIds, id);\n if (!isControlled) setInternalExpandedIds(nextExpandedIds);\n onExpandedChange?.(nextExpandedIds);\n },\n [expandedIds, isControlled, onExpandedChange],\n );\n\n return (\n <div\n aria-label={ariaLabel}\n className={className}\n role=\"tree\"\n style={{ ...TREE_STYLE, ...style }}\n >\n {nodes.map((node) => (\n <TreeItemRow\n key={node.id}\n depth={0}\n expandedIds={expandedIds}\n node={node}\n onSelect={onSelect}\n onToggleExpand={handleToggleExpand}\n renderItem={renderItem}\n selectedId={selectedId}\n />\n ))}\n </div>\n );\n}\n\nconst TREE_STYLE = {\n display: 'flex',\n flexDirection: 'column',\n minWidth: 0,\n} as const satisfies React.CSSProperties;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toggleExpandedIds.d.ts","sourceRoot":"","sources":["../../../../src/features/tree-view/utils/toggleExpandedIds.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,GAAG,SAAS,MAAM,EAClD,WAAW,EAAE,SAAS,GAAG,EAAE,EAC3B,EAAE,EAAE,GAAG,GACN,SAAS,GAAG,EAAE,CAIhB"}
|