@treenity/react 3.0.6 → 3.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AclEditor.js +3 -3
- package/dist/ActionCards.js +5 -5
- package/dist/App.js +6 -6
- package/dist/CLAUDE.md +16 -0
- package/dist/ComponentSection.js +4 -4
- package/dist/ComponentSection.js.map +1 -1
- package/dist/ErrorBoundary.js +1 -1
- package/dist/Inspector.js +9 -9
- package/dist/Inspector.js.map +1 -1
- package/dist/Login.js +4 -4
- package/dist/NodeEditor.d.ts.map +1 -1
- package/dist/NodeEditor.js +10 -9
- package/dist/NodeEditor.js.map +1 -1
- package/dist/Tree.js +3 -3
- package/dist/ViewPage.js +1 -1
- package/dist/bind/engine.js +2 -2
- package/dist/bind/hook.js +2 -2
- package/dist/components/ConfirmDialog.js +1 -1
- package/dist/components/ConfirmPopover.js +2 -2
- package/dist/components/PathBreadcrumb.js +1 -1
- package/dist/components/lib/utils.ts.bak +6 -0
- package/dist/components/ui/accordion.js +1 -1
- package/dist/components/ui/alert-dialog.js +2 -2
- package/dist/components/ui/badge.js +1 -1
- package/dist/components/ui/breadcrumb.js +1 -1
- package/dist/components/ui/button.js +1 -1
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/checkbox.js +1 -1
- package/dist/components/ui/command.js +2 -2
- package/dist/components/ui/dialog.js +2 -2
- package/dist/components/ui/drawer.js +1 -1
- package/dist/components/ui/dropdown-menu.js +1 -1
- package/dist/components/ui/form-field.js +1 -1
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/label.js +1 -1
- package/dist/components/ui/pagination.js +2 -2
- package/dist/components/ui/popover.js +1 -1
- package/dist/components/ui/progress.js +1 -1
- package/dist/components/ui/resizable.js +1 -1
- package/dist/components/ui/scroll-area.js +1 -1
- package/dist/components/ui/select.js +1 -1
- package/dist/components/ui/separator.js +1 -1
- package/dist/components/ui/sheet.js +1 -1
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/slider.js +1 -1
- package/dist/components/ui/switch.js +1 -1
- package/dist/components/ui/table.js +1 -1
- package/dist/components/ui/tabs.js +1 -1
- package/dist/components/ui/textarea.js +1 -1
- package/dist/components/ui/toggle-group.js +2 -2
- package/dist/components/ui/toggle.js +1 -1
- package/dist/components/ui/tooltip.js +1 -1
- package/dist/context/index.js +2 -2
- package/dist/mods/editor-ui/CLAUDE.md +3 -0
- package/dist/mods/editor-ui/DraftTextarea.d.ts +8 -0
- package/dist/mods/editor-ui/DraftTextarea.d.ts.map +1 -0
- package/dist/mods/editor-ui/DraftTextarea.js +23 -0
- package/dist/mods/editor-ui/DraftTextarea.js.map +1 -0
- package/dist/mods/editor-ui/FieldLabel.js +2 -2
- package/dist/mods/editor-ui/default-edit.js +3 -3
- package/dist/mods/editor-ui/default-view.js +4 -4
- package/dist/mods/editor-ui/dir-view.js +2 -2
- package/dist/mods/editor-ui/empty-placeholder.js +2 -2
- package/dist/mods/editor-ui/form-field.js +5 -5
- package/dist/mods/editor-ui/form-field.js.map +1 -1
- package/dist/mods/editor-ui/form-fields.d.ts.map +1 -1
- package/dist/mods/editor-ui/form-fields.js +17 -16
- package/dist/mods/editor-ui/form-fields.js.map +1 -1
- package/dist/mods/editor-ui/layout-view.js +2 -2
- package/dist/mods/editor-ui/list-items.js +1 -1
- package/dist/mods/editor-ui/node-utils.js +1 -1
- package/dist/mods/editor-ui/node-utils.js.map +1 -1
- package/dist/mods/editor-ui/type-picker.js +5 -5
- package/dist/mods/treenity/CLAUDE.md +7 -0
- package/dist/mods/treenity/groups/index.js +3 -3
- package/dist/mods/treenity/preview.js +2 -2
- package/dist/mods/treenity/ref-view.js +3 -3
- package/package.json +2 -2
- package/src/ComponentSection.tsx +1 -1
- package/src/Inspector.tsx +2 -2
- package/src/NodeEditor.tsx +3 -2
- package/src/mods/editor-ui/DraftTextarea.tsx +42 -0
- package/src/mods/editor-ui/form-field.tsx +4 -4
- package/src/mods/editor-ui/form-fields.tsx +11 -10
- package/src/mods/editor-ui/node-utils.ts +1 -1
- package/vite-plugin-treenity.ts +7 -1
package/src/Inspector.tsx
CHANGED
|
@@ -28,7 +28,7 @@ export function Inspector({ path, currentUserId, onDelete, onAddComponent, onSel
|
|
|
28
28
|
const node = usePath(path);
|
|
29
29
|
const [confirmDelete, setConfirmDelete] = useState(false);
|
|
30
30
|
const [editing, setEditing] = useState(false);
|
|
31
|
-
const [context, setContext] = useState('react');
|
|
31
|
+
const [context, setContext] = useState('react:layout');
|
|
32
32
|
|
|
33
33
|
// Reset context when path changes
|
|
34
34
|
const [prevPath, setPrevPath] = useState(path);
|
|
@@ -113,7 +113,7 @@ export function Inspector({ path, currentUserId, onDelete, onAddComponent, onSel
|
|
|
113
113
|
{/* Rendered view */}
|
|
114
114
|
<ScrollArea className="flex-1">
|
|
115
115
|
<div className="p-4">
|
|
116
|
-
<ErrorBoundary>
|
|
116
|
+
<ErrorBoundary key={node.$path}>
|
|
117
117
|
<RenderContext name={context}>
|
|
118
118
|
<div className="node-view">
|
|
119
119
|
<Render value={node} />
|
package/src/NodeEditor.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { Input } from '#components/ui/input';
|
|
|
7
7
|
import { ScrollArea } from '#components/ui/scroll-area';
|
|
8
8
|
import { Tabs, TabsList, TabsTrigger } from '#components/ui/tabs';
|
|
9
9
|
import { toPlain } from '#lib/to-plain';
|
|
10
|
+
import { DraftTextarea } from '#mods/editor-ui/DraftTextarea';
|
|
10
11
|
import { FieldLabel, RefEditor } from '#mods/editor-ui/FieldLabel';
|
|
11
12
|
import { getComponents, getPlainFields, getSchema } from '#mods/editor-ui/node-utils';
|
|
12
13
|
import { type ComponentData, type GroupPerm, isRef, type NodeData, resolve } from '@treenity/core';
|
|
@@ -272,9 +273,9 @@ export function NodeEditor({ node, open, onClose, currentUserId, toast, onAddCom
|
|
|
272
273
|
)}
|
|
273
274
|
</>
|
|
274
275
|
) : (
|
|
275
|
-
<
|
|
276
|
+
<DraftTextarea
|
|
276
277
|
value={snap.jsonText}
|
|
277
|
-
onChange={(
|
|
278
|
+
onChange={(text) => { st.jsonText = text; st.dirty = true; }}
|
|
278
279
|
spellCheck={false}
|
|
279
280
|
/>
|
|
280
281
|
)}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Uncontrolled textarea that preserves cursor position during external re-renders.
|
|
2
|
+
// Uses ref + defaultValue so React never touches the DOM value while user is editing.
|
|
3
|
+
|
|
4
|
+
import { Textarea } from '#components/ui/textarea';
|
|
5
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
|
|
6
|
+
|
|
7
|
+
type Props = Omit<React.ComponentProps<typeof Textarea>, 'value' | 'defaultValue' | 'onChange'> & {
|
|
8
|
+
value: string;
|
|
9
|
+
onChange: (text: string) => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const DraftTextarea = forwardRef<HTMLTextAreaElement, Props>(
|
|
13
|
+
({ value, onChange, ...props }, fwd) => {
|
|
14
|
+
const ref = useRef<HTMLTextAreaElement>(null);
|
|
15
|
+
const editing = useRef(false);
|
|
16
|
+
|
|
17
|
+
useImperativeHandle(fwd, () => ref.current!);
|
|
18
|
+
|
|
19
|
+
// Sync external value into DOM only when not focused
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!editing.current && ref.current && ref.current.value !== value) {
|
|
22
|
+
ref.current.value = value;
|
|
23
|
+
}
|
|
24
|
+
}, [value]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Textarea
|
|
28
|
+
ref={ref}
|
|
29
|
+
defaultValue={value}
|
|
30
|
+
onFocus={() => { editing.current = true; }}
|
|
31
|
+
onBlur={() => {
|
|
32
|
+
editing.current = false;
|
|
33
|
+
if (ref.current && ref.current.value !== value) {
|
|
34
|
+
ref.current.value = value;
|
|
35
|
+
}
|
|
36
|
+
}}
|
|
37
|
+
onChange={(e) => onChange(e.target.value)}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
},
|
|
42
|
+
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Button } from '#components/ui/button';
|
|
2
2
|
import { Input } from '#components/ui/input';
|
|
3
|
-
import {
|
|
3
|
+
import { DraftTextarea } from '#mods/editor-ui/DraftTextarea';
|
|
4
4
|
import { isRef, resolveExact } from '@treenity/core';
|
|
5
5
|
import { createElement, useState } from 'react';
|
|
6
6
|
import { FieldLabel, RefEditor } from './FieldLabel';
|
|
@@ -92,12 +92,12 @@ export function StringArrayField({
|
|
|
92
92
|
|
|
93
93
|
if (!isStrings) {
|
|
94
94
|
return (
|
|
95
|
-
<
|
|
95
|
+
<DraftTextarea
|
|
96
96
|
className="min-h-16 text-xs font-mono"
|
|
97
97
|
value={JSON.stringify(value, null, 2)}
|
|
98
|
-
onChange={(
|
|
98
|
+
onChange={(text) => {
|
|
99
99
|
try {
|
|
100
|
-
onChange(JSON.parse(
|
|
100
|
+
onChange(JSON.parse(text));
|
|
101
101
|
} catch {
|
|
102
102
|
/* typing */
|
|
103
103
|
}
|
|
@@ -5,6 +5,7 @@ import { tree as clientStore } from '#client';
|
|
|
5
5
|
// Covers: string, text, textarea, number, integer, boolean, array, object, image, uri, url, select, timestamp, path
|
|
6
6
|
import { Button } from '#components/ui/button';
|
|
7
7
|
import { Input } from '#components/ui/input';
|
|
8
|
+
import { DraftTextarea } from '#mods/editor-ui/DraftTextarea';
|
|
8
9
|
import { Popover, PopoverContent, PopoverTrigger } from '#components/ui/popover';
|
|
9
10
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '#components/ui/select';
|
|
10
11
|
import { Switch } from '#components/ui/switch';
|
|
@@ -281,13 +282,13 @@ function ObjectForm({ value, onChange }: FP) {
|
|
|
281
282
|
return (
|
|
282
283
|
<div className="rounded border border-border/50 bg-muted/30 p-2">
|
|
283
284
|
{modeToggle}
|
|
284
|
-
<
|
|
285
|
+
<DraftTextarea
|
|
285
286
|
className={`text-[11px] min-h-[60px] ${jsonError ? 'border-destructive' : ''}`}
|
|
286
287
|
value={jsonDraft}
|
|
287
|
-
onChange={(
|
|
288
|
-
setJsonDraft(
|
|
288
|
+
onChange={(text) => {
|
|
289
|
+
setJsonDraft(text);
|
|
289
290
|
try {
|
|
290
|
-
const parsed = JSON.parse(
|
|
291
|
+
const parsed = JSON.parse(text);
|
|
291
292
|
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
292
293
|
emit(parsed);
|
|
293
294
|
setJsonError(false);
|
|
@@ -334,12 +335,12 @@ function ObjectForm({ value, onChange }: FP) {
|
|
|
334
335
|
onChange={(e) => emit({ ...obj, [k]: e.target.value })}
|
|
335
336
|
/>
|
|
336
337
|
) : (
|
|
337
|
-
<
|
|
338
|
+
<DraftTextarea
|
|
338
339
|
className="flex-1 min-w-0 text-[11px] font-mono min-h-[40px]"
|
|
339
340
|
value={JSON.stringify(v, null, 2)}
|
|
340
|
-
onChange={(
|
|
341
|
+
onChange={(text) => {
|
|
341
342
|
try {
|
|
342
|
-
emit({ ...obj, [k]: JSON.parse(
|
|
343
|
+
emit({ ...obj, [k]: JSON.parse(text) });
|
|
343
344
|
} catch {
|
|
344
345
|
/* typing */
|
|
345
346
|
}
|
|
@@ -484,11 +485,11 @@ function ArrayForm({ value, onChange }: FP) {
|
|
|
484
485
|
|
|
485
486
|
// object/other — textarea fallback
|
|
486
487
|
return (
|
|
487
|
-
<
|
|
488
|
+
<DraftTextarea
|
|
488
489
|
value={JSON.stringify(arr, null, 2)}
|
|
489
|
-
onChange={(
|
|
490
|
+
onChange={(text) => {
|
|
490
491
|
try {
|
|
491
|
-
emit(JSON.parse(
|
|
492
|
+
emit(JSON.parse(text));
|
|
492
493
|
} catch {
|
|
493
494
|
/* let user keep typing */
|
|
494
495
|
}
|
package/vite-plugin-treenity.ts
CHANGED
|
@@ -189,7 +189,13 @@ export default function treenityPlugin(opts?: { modsDirs?: string[] }): Plugin {
|
|
|
189
189
|
// Resolve # imports via nearest package.json imports field
|
|
190
190
|
if (id.startsWith('#')) {
|
|
191
191
|
const pkg = readPkg(dirname(importer));
|
|
192
|
-
if (pkg?.imports)
|
|
192
|
+
if (pkg?.imports) {
|
|
193
|
+
// Inside node_modules: skip 'development' condition to stay in dist/
|
|
194
|
+
// (dist files use relative ./hooks, # must resolve to same dist files)
|
|
195
|
+
const isNm = importer.includes('/node_modules/');
|
|
196
|
+
const conds = isNm ? conditions.filter(c => c !== 'development') : conditions;
|
|
197
|
+
return matchPattern(id, pkg.imports, pkg.dir, conds);
|
|
198
|
+
}
|
|
193
199
|
}
|
|
194
200
|
|
|
195
201
|
// Resolve @treenity/* exports (Vite doesn't handle array conditions)
|