@principal-ai/file-city-react 0.5.39 → 0.5.41

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.
Files changed (59) hide show
  1. package/dist/components/FileCity3D/FileCity3D.d.ts +8 -2
  2. package/dist/components/FileCity3D/FileCity3D.d.ts.map +1 -1
  3. package/dist/components/FileCity3D/FileCity3D.js +129 -40
  4. package/dist/components/FileCityExplorer/AddToAreaModal.d.ts +14 -0
  5. package/dist/components/FileCityExplorer/AddToAreaModal.d.ts.map +1 -0
  6. package/dist/components/FileCityExplorer/AddToAreaModal.js +140 -0
  7. package/dist/components/FileCityExplorer/AddToScopeModal.d.ts +14 -0
  8. package/dist/components/FileCityExplorer/AddToScopeModal.d.ts.map +1 -0
  9. package/dist/components/FileCityExplorer/AddToScopeModal.js +176 -0
  10. package/dist/components/FileCityExplorer/FileCityExplorer.d.ts +30 -0
  11. package/dist/components/FileCityExplorer/FileCityExplorer.d.ts.map +1 -0
  12. package/dist/components/FileCityExplorer/FileCityExplorer.js +1045 -0
  13. package/dist/components/FileCityExplorer/ScopeInfoOverlay.d.ts +10 -0
  14. package/dist/components/FileCityExplorer/ScopeInfoOverlay.d.ts.map +1 -0
  15. package/dist/components/FileCityExplorer/ScopeInfoOverlay.js +73 -0
  16. package/dist/components/FileCityExplorer/index.d.ts +3 -0
  17. package/dist/components/FileCityExplorer/index.d.ts.map +1 -0
  18. package/dist/components/FileCityExplorer/index.js +1 -0
  19. package/dist/components/FileCityExplorer/layers.d.ts +16 -0
  20. package/dist/components/FileCityExplorer/layers.d.ts.map +1 -0
  21. package/dist/components/FileCityExplorer/layers.js +61 -0
  22. package/dist/components/FileCityExplorer/model.d.ts +32 -0
  23. package/dist/components/FileCityExplorer/model.d.ts.map +1 -0
  24. package/dist/components/FileCityExplorer/model.js +14 -0
  25. package/dist/components/FileCityExplorer/pathConversion.d.ts +19 -0
  26. package/dist/components/FileCityExplorer/pathConversion.d.ts.map +1 -0
  27. package/dist/components/FileCityExplorer/pathConversion.js +26 -0
  28. package/dist/components/FileCityExplorer/scopeTreePaths.d.ts +21 -0
  29. package/dist/components/FileCityExplorer/scopeTreePaths.d.ts.map +1 -0
  30. package/dist/components/FileCityExplorer/scopeTreePaths.js +42 -0
  31. package/dist/components/FileCityExplorer/styles.d.ts +9 -0
  32. package/dist/components/FileCityExplorer/styles.d.ts.map +1 -0
  33. package/dist/components/FileCityExplorer/styles.js +28 -0
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +2 -0
  37. package/dist/utils/folderElevatedPanels.d.ts +62 -0
  38. package/dist/utils/folderElevatedPanels.d.ts.map +1 -0
  39. package/dist/utils/folderElevatedPanels.js +130 -0
  40. package/package.json +2 -1
  41. package/src/components/FileCity3D/FileCity3D.tsx +200 -52
  42. package/src/components/FileCityExplorer/AddToAreaModal.tsx +273 -0
  43. package/src/components/FileCityExplorer/AddToScopeModal.tsx +320 -0
  44. package/src/components/FileCityExplorer/FileCityExplorer.tsx +1457 -0
  45. package/src/components/FileCityExplorer/ScopeInfoOverlay.tsx +229 -0
  46. package/src/components/FileCityExplorer/index.ts +2 -0
  47. package/src/components/FileCityExplorer/layers.ts +72 -0
  48. package/src/components/FileCityExplorer/model.ts +35 -0
  49. package/src/components/FileCityExplorer/pathConversion.ts +32 -0
  50. package/src/components/FileCityExplorer/scopeTreePaths.ts +52 -0
  51. package/src/components/FileCityExplorer/styles.ts +34 -0
  52. package/src/index.ts +8 -0
  53. package/src/stories/2D3DComparison.stories.tsx +13 -2
  54. package/src/stories/ElevatedScopePanels.stories.tsx +295 -0
  55. package/src/stories/FileCity3D.stories.tsx +24 -3
  56. package/src/stories/FileCityExplorer.stories.tsx +2474 -0
  57. package/src/stories/FileCityExplorerComponent.stories.tsx +59 -0
  58. package/src/utils/folderElevatedPanels.ts +176 -0
  59. package/src/stories/ScopeOverlay.stories.tsx +0 -1687
@@ -0,0 +1,176 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { useTheme } from '@principal-ade/industry-theme';
4
+ import { makeSectionLabelStyle } from './styles';
5
+ export const AddToScopeModal = ({ path, scopes, scopeId, namespaceName, onScopeIdChange, onNamespaceNameChange, onPickExisting, onSubmit, onClose, }) => {
6
+ const { theme } = useTheme();
7
+ const sectionLabelStyle = makeSectionLabelStyle(theme);
8
+ React.useEffect(() => {
9
+ const onKey = (e) => {
10
+ if (e.key === 'Escape')
11
+ onClose();
12
+ };
13
+ window.addEventListener('keydown', onKey);
14
+ return () => window.removeEventListener('keydown', onKey);
15
+ }, [onClose]);
16
+ const trimmedScope = scopeId.trim();
17
+ const trimmedNs = namespaceName.trim();
18
+ const canSubmit = trimmedScope.length > 0;
19
+ // Determine what the submit will do, for the action label.
20
+ const targetScope = scopes.find(s => s.id === trimmedScope);
21
+ const targetNs = trimmedNs
22
+ ? targetScope?.namespaces.find(n => n.name === trimmedNs) ?? null
23
+ : null;
24
+ const alreadyClaimed = trimmedNs
25
+ ? targetNs?.paths.includes(path) ?? false
26
+ : targetScope?.paths.includes(path) ?? false;
27
+ let actionLabel = 'Add';
28
+ if (alreadyClaimed)
29
+ actionLabel = 'Already added';
30
+ else if (!targetScope && !trimmedNs)
31
+ actionLabel = 'Create scope';
32
+ else if (!targetScope)
33
+ actionLabel = 'Create scope + namespace';
34
+ else if (!trimmedNs)
35
+ actionLabel = 'Add to scope';
36
+ else if (!targetNs)
37
+ actionLabel = 'Create namespace';
38
+ else
39
+ actionLabel = 'Add path';
40
+ const sectionDivider = `1px solid ${theme.colors.backgroundSecondary}`;
41
+ const inputStyle = {
42
+ padding: '8px 10px',
43
+ background: theme.colors.backgroundDark ?? theme.colors.background,
44
+ color: theme.colors.text,
45
+ border: `1px solid ${theme.colors.border}`,
46
+ borderRadius: theme.radii[2],
47
+ fontFamily: theme.fonts.monospace,
48
+ fontSize: theme.fontSizes[1],
49
+ };
50
+ return (_jsx("div", { onClick: onClose, style: {
51
+ position: 'fixed',
52
+ inset: 0,
53
+ background: 'rgba(0, 0, 0, 0.55)',
54
+ display: 'flex',
55
+ alignItems: 'center',
56
+ justifyContent: 'center',
57
+ zIndex: 1000,
58
+ fontFamily: theme.fonts.body,
59
+ }, children: _jsxs("div", { onClick: e => e.stopPropagation(), style: {
60
+ width: 520,
61
+ maxHeight: 'min(80vh, 700px)',
62
+ display: 'flex',
63
+ flexDirection: 'column',
64
+ background: theme.colors.background,
65
+ color: theme.colors.text,
66
+ borderRadius: theme.radii[4],
67
+ border: `1px solid ${theme.colors.border}`,
68
+ boxShadow: theme.shadows[4],
69
+ overflow: 'hidden',
70
+ }, children: [_jsxs("div", { style: {
71
+ padding: '14px 18px',
72
+ borderBottom: sectionDivider,
73
+ display: 'flex',
74
+ justifyContent: 'space-between',
75
+ alignItems: 'flex-start',
76
+ gap: theme.space[3],
77
+ }, children: [_jsxs("div", { children: [_jsx("div", { style: sectionLabelStyle, children: "Add to scope" }), _jsx("div", { style: {
78
+ fontFamily: theme.fonts.monospace,
79
+ fontSize: theme.fontSizes[0],
80
+ color: theme.colors.textMuted,
81
+ marginTop: 6,
82
+ wordBreak: 'break-all',
83
+ }, children: path })] }), _jsx("button", { onClick: onClose, style: {
84
+ background: 'transparent',
85
+ border: 'none',
86
+ color: theme.colors.textTertiary,
87
+ fontSize: theme.fontSizes[3],
88
+ cursor: 'pointer',
89
+ lineHeight: 1,
90
+ padding: 0,
91
+ }, "aria-label": "Close", children: "\u00D7" })] }), _jsxs("div", { style: {
92
+ padding: '14px 18px',
93
+ borderBottom: sectionDivider,
94
+ display: 'flex',
95
+ flexDirection: 'column',
96
+ gap: theme.space[3],
97
+ }, children: [_jsxs("label", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsx("span", { style: sectionLabelStyle, children: "Scope" }), _jsx("input", { type: "text", value: scopeId, list: "scope-id-options", autoFocus: true, placeholder: "e.g. principal-view.cli", onChange: e => onScopeIdChange(e.target.value), onKeyDown: e => {
98
+ if (e.key === 'Enter' && canSubmit && !alreadyClaimed)
99
+ onSubmit();
100
+ }, style: inputStyle }), _jsx("datalist", { id: "scope-id-options", children: scopes.map(s => (_jsx("option", { value: s.id }, s.id))) })] }), _jsxs("label", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsx("span", { style: sectionLabelStyle, children: "Namespace (optional)" }), _jsx("input", { type: "text", value: namespaceName, placeholder: "leave blank to add to scope itself", onChange: e => onNamespaceNameChange(e.target.value), onKeyDown: e => {
101
+ if (e.key === 'Enter' && canSubmit && !alreadyClaimed)
102
+ onSubmit();
103
+ }, style: inputStyle })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'flex-end', gap: theme.space[2] }, children: [_jsx("button", { onClick: onClose, style: {
104
+ padding: '8px 14px',
105
+ background: 'transparent',
106
+ color: theme.colors.textSecondary,
107
+ border: `1px solid ${theme.colors.border}`,
108
+ borderRadius: theme.radii[2],
109
+ cursor: 'pointer',
110
+ fontSize: theme.fontSizes[1],
111
+ }, children: "Cancel" }), _jsx("button", { onClick: onSubmit, disabled: !canSubmit || alreadyClaimed, style: {
112
+ padding: '8px 14px',
113
+ background: !canSubmit || alreadyClaimed
114
+ ? theme.colors.backgroundSecondary
115
+ : theme.colors.primary,
116
+ color: !canSubmit || alreadyClaimed
117
+ ? theme.colors.muted
118
+ : theme.colors.textOnPrimary,
119
+ border: `1px solid ${theme.colors.border}`,
120
+ borderRadius: theme.radii[2],
121
+ cursor: !canSubmit || alreadyClaimed ? 'not-allowed' : 'pointer',
122
+ fontSize: theme.fontSizes[1],
123
+ fontWeight: theme.fontWeights.medium,
124
+ }, children: actionLabel })] })] }), _jsxs("div", { style: {
125
+ padding: '14px 18px',
126
+ overflowY: 'auto',
127
+ flex: 1,
128
+ }, children: [_jsx("div", { style: sectionLabelStyle, children: "Existing scopes (click to prefill)" }), _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: theme.space[3], marginTop: theme.space[2] }, children: scopes.map(scope => (_jsxs("div", { children: [_jsx("div", { style: {
129
+ fontFamily: theme.fonts.monospace,
130
+ fontSize: theme.fontSizes[0],
131
+ color: theme.colors.textSecondary,
132
+ marginBottom: 6,
133
+ }, children: scope.id }), _jsxs("div", { style: { display: 'flex', flexWrap: 'wrap', gap: theme.space[1] }, children: [_jsxs("button", { onClick: () => onPickExisting(scope.id, ''), title: scope.paths.includes(path)
134
+ ? 'Scope already claims this path'
135
+ : 'Prefill (scope-level)', style: {
136
+ fontSize: theme.fontSizes[0],
137
+ padding: '3px 7px',
138
+ background: scope.paths.includes(path)
139
+ ? theme.colors.background
140
+ : theme.colors.backgroundSecondary,
141
+ color: scope.paths.includes(path)
142
+ ? theme.colors.muted
143
+ : theme.colors.textSecondary,
144
+ border: `1px dashed ${theme.colors.muted}`,
145
+ borderRadius: theme.radii[1],
146
+ cursor: 'pointer',
147
+ display: 'flex',
148
+ alignItems: 'center',
149
+ gap: 5,
150
+ fontStyle: 'italic',
151
+ opacity: scope.paths.includes(path) ? 0.6 : 1,
152
+ }, children: ["(scope-level)", scope.paths.includes(path) && (_jsx("span", { style: { marginLeft: theme.space[1], fontSize: theme.fontSizes[0] }, children: "\u2713" }))] }), scope.namespaces.map(ns => {
153
+ const claims = ns.paths.includes(path);
154
+ return (_jsxs("button", { onClick: () => onPickExisting(scope.id, ns.name), title: claims ? 'Already claims this path' : 'Prefill inputs', style: {
155
+ fontSize: theme.fontSizes[0],
156
+ padding: '3px 7px',
157
+ background: claims
158
+ ? theme.colors.background
159
+ : theme.colors.backgroundSecondary,
160
+ color: claims ? theme.colors.muted : theme.colors.text,
161
+ border: `1px solid ${theme.colors.border}`,
162
+ borderRadius: theme.radii[1],
163
+ cursor: 'pointer',
164
+ display: 'flex',
165
+ alignItems: 'center',
166
+ gap: 5,
167
+ opacity: claims ? 0.6 : 1,
168
+ }, children: [_jsx("span", { style: {
169
+ width: 8,
170
+ height: 8,
171
+ borderRadius: theme.radii[1],
172
+ background: ns.color,
173
+ flexShrink: 0,
174
+ } }), ns.name, claims && _jsx("span", { style: { marginLeft: theme.space[1], fontSize: theme.fontSizes[0] }, children: "\u2713" })] }, ns.name));
175
+ })] })] }, scope.id))) })] })] }) }));
176
+ };
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { type CityData } from '../FileCity3D';
3
+ import type { ProjectArea, Scope } from './model';
4
+ export interface FileCityExplorerProps {
5
+ /** City data to render in the 3D canvas. */
6
+ cityData: CityData;
7
+ /**
8
+ * Prefix that scopes/namespace paths are stripped of when read out of
9
+ * `cityData` (e.g. `'electron-app/'`). Pass `''` if the city data is already
10
+ * rooted at the project root.
11
+ */
12
+ packageRoot: string;
13
+ /** Initial scopes (used when no persisted state is found). */
14
+ initialScopes?: Scope[];
15
+ /** Initial areas (used when no persisted state is found). */
16
+ initialAreas?: ProjectArea[];
17
+ /**
18
+ * When set, scopes/areas round-trip through `localStorage` under
19
+ * `${persistKey}.scopes` and `${persistKey}.areas`. When omitted, state is
20
+ * purely in-memory.
21
+ */
22
+ persistKey?: string | null;
23
+ /**
24
+ * Initial focused directory (city path). Defaults to the city root derived
25
+ * from `packageRoot` (with trailing slash stripped).
26
+ */
27
+ initialFocusDirectory?: string | null;
28
+ }
29
+ export declare const FileCityExplorer: React.FC<FileCityExplorerProps>;
30
+ //# sourceMappingURL=FileCityExplorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileCityExplorer.d.ts","sourceRoot":"","sources":["../../../src/components/FileCityExplorer/FileCityExplorer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,OAAO,EAEL,KAAK,QAAQ,EAGd,MAAM,eAAe,CAAC;AAOvB,OAAO,KAAK,EAAa,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAuB7D,MAAM,WAAW,qBAAqB;IACpC,4CAA4C;IAC5C,QAAQ,EAAE,QAAQ,CAAC;IACnB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,KAAK,EAAE,CAAC;IACxB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAy2C5D,CAAC"}