@treenity/react 3.0.4 → 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.d.ts.map +1 -1
- package/dist/App.js +9 -8
- package/dist/App.js.map +1 -1
- 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.css +54 -0
- 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.css +91 -0
- package/dist/Tree.js +3 -3
- package/dist/Treenity.d.ts +0 -1
- package/dist/Treenity.d.ts.map +1 -1
- package/dist/Treenity.js +1 -1
- package/dist/Treenity.js.map +1 -1
- 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/lib/minimd.css +28 -0
- 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/editor-ui.css +174 -0
- 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/dist/root.css +117 -0
- package/dist/trpc.d.ts +8 -0
- package/dist/trpc.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/App.tsx +3 -2
- package/src/ComponentSection.tsx +1 -1
- package/src/Inspector.tsx +2 -2
- package/src/NodeEditor.tsx +3 -2
- package/src/Treenity.tsx +1 -1
- 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/dist/root.css
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/* Tailwind disabled — using CDN in index.html to avoid cross-package conflict */
|
|
2
|
+
/* @import 'tailwindcss'; */
|
|
3
|
+
/* @source "."; */
|
|
4
|
+
/* @source "../../src/mods"; */
|
|
5
|
+
|
|
6
|
+
/* Local fonts */
|
|
7
|
+
@font-face { font-family: 'Manrope'; src: url('/fonts/Manrope-Light.ttf'); font-weight: 300; font-display: swap; }
|
|
8
|
+
@font-face { font-family: 'Manrope'; src: url('/fonts/Manrope-Regular.ttf'); font-weight: 400; font-display: swap; }
|
|
9
|
+
@font-face { font-family: 'Manrope'; src: url('/fonts/Manrope-Medium.ttf'); font-weight: 500; font-display: swap; }
|
|
10
|
+
@font-face { font-family: 'Manrope'; src: url('/fonts/Manrope-SemiBold.ttf'); font-weight: 600; font-display: swap; }
|
|
11
|
+
|
|
12
|
+
/* shadcn/ui theme tokens — now in CDN (index.html), kept here for reference */
|
|
13
|
+
/* @theme inline extend { ... } — see index.html <style type="text/tailwindcss"> */
|
|
14
|
+
|
|
15
|
+
/* Tailwind theme tokens — unlayered :root beats CDN's layered output */
|
|
16
|
+
:root {
|
|
17
|
+
--color-background: #0d1117;
|
|
18
|
+
--color-foreground: #e6edf3;
|
|
19
|
+
--color-card: #161b22;
|
|
20
|
+
--color-card-foreground: #e6edf3;
|
|
21
|
+
--color-popover: #161b22;
|
|
22
|
+
--color-popover-foreground: #e6edf3;
|
|
23
|
+
--color-primary: #2ecc71;
|
|
24
|
+
--color-primary-foreground: #ffffff;
|
|
25
|
+
--color-secondary: #21262d;
|
|
26
|
+
--color-secondary-foreground: #e6edf3;
|
|
27
|
+
--color-muted: #161b22;
|
|
28
|
+
--color-muted-foreground: #7d8590;
|
|
29
|
+
--color-accent: rgba(46, 204, 113, 0.15);
|
|
30
|
+
--color-accent-foreground: #2ecc71;
|
|
31
|
+
--color-destructive: #f85149;
|
|
32
|
+
--color-destructive-foreground: #e6edf3;
|
|
33
|
+
--color-border: #30363d;
|
|
34
|
+
--color-input: #30363d;
|
|
35
|
+
--color-ring: #2ecc71;
|
|
36
|
+
--radius-sm: 4px;
|
|
37
|
+
--radius-md: 6px;
|
|
38
|
+
--radius-lg: 8px;
|
|
39
|
+
|
|
40
|
+
/* Legacy aliases */
|
|
41
|
+
--bg: var(--color-background);
|
|
42
|
+
--surface: var(--color-card);
|
|
43
|
+
--surface-2: var(--color-secondary);
|
|
44
|
+
--surface-3: var(--color-border);
|
|
45
|
+
--border: var(--color-border);
|
|
46
|
+
--border-subtle: var(--color-border);
|
|
47
|
+
--text: var(--color-foreground);
|
|
48
|
+
--text-2: var(--color-muted-foreground);
|
|
49
|
+
--text-3: color-mix(in srgb, var(--color-muted-foreground) 60%, transparent);
|
|
50
|
+
--accent: var(--color-primary);
|
|
51
|
+
--accent-subtle: var(--color-accent);
|
|
52
|
+
--danger: var(--color-destructive);
|
|
53
|
+
--danger-subtle: color-mix(in srgb, var(--color-destructive) 15%, transparent);
|
|
54
|
+
--success: #3fb950;
|
|
55
|
+
--success-subtle: rgba(63, 185, 80, 0.15);
|
|
56
|
+
--warning: #d29922;
|
|
57
|
+
--radius: var(--radius-md);
|
|
58
|
+
--radius-lg: var(--radius-lg);
|
|
59
|
+
--font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
60
|
+
--mono: 'SF Mono', SFMono-Regular, 'Cascadia Code', 'Fira Code', Consolas, monospace;
|
|
61
|
+
--transition: 0.15s ease;
|
|
62
|
+
}
|
|
63
|
+
@layer base {
|
|
64
|
+
*,
|
|
65
|
+
::before,
|
|
66
|
+
::after {
|
|
67
|
+
margin: 0;
|
|
68
|
+
padding: 0;
|
|
69
|
+
box-sizing: border-box;
|
|
70
|
+
border-color: var(--color-border);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
html,
|
|
74
|
+
body {
|
|
75
|
+
height: 100%;
|
|
76
|
+
font-family: var(--font);
|
|
77
|
+
}
|
|
78
|
+
body {
|
|
79
|
+
background: var(--bg);
|
|
80
|
+
color: var(--text);
|
|
81
|
+
font-size: 14px;
|
|
82
|
+
line-height: 1.5;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@layer base {
|
|
86
|
+
input,
|
|
87
|
+
textarea,
|
|
88
|
+
select {
|
|
89
|
+
width: 100%;
|
|
90
|
+
padding: 4px 8px;
|
|
91
|
+
background: var(--bg);
|
|
92
|
+
border: 1px solid var(--border);
|
|
93
|
+
border-radius: var(--radius);
|
|
94
|
+
color: var(--text);
|
|
95
|
+
font-size: 12px;
|
|
96
|
+
font-family: var(--mono);
|
|
97
|
+
outline: none;
|
|
98
|
+
transition: border-color var(--transition);
|
|
99
|
+
}
|
|
100
|
+
input:focus,
|
|
101
|
+
textarea:focus,
|
|
102
|
+
select:focus {
|
|
103
|
+
border-color: var(--accent);
|
|
104
|
+
}
|
|
105
|
+
input:read-only {
|
|
106
|
+
color: var(--text-2);
|
|
107
|
+
cursor: default;
|
|
108
|
+
}
|
|
109
|
+
input:read-only:focus {
|
|
110
|
+
border-color: var(--border);
|
|
111
|
+
}
|
|
112
|
+
textarea {
|
|
113
|
+
min-height: 80px;
|
|
114
|
+
resize: vertical;
|
|
115
|
+
line-height: 1.5;
|
|
116
|
+
}
|
|
117
|
+
}
|
package/dist/trpc.d.ts
CHANGED
|
@@ -174,6 +174,14 @@ export declare const trpc: import("@trpc/client").TRPCClient<import("@trpc/serve
|
|
|
174
174
|
};
|
|
175
175
|
meta: object;
|
|
176
176
|
}>;
|
|
177
|
+
devLogin: import("@trpc/server").TRPCMutationProcedure<{
|
|
178
|
+
input: void;
|
|
179
|
+
output: {
|
|
180
|
+
token: string;
|
|
181
|
+
userId: string;
|
|
182
|
+
};
|
|
183
|
+
meta: object;
|
|
184
|
+
}>;
|
|
177
185
|
streamAction: import("@trpc/server/unstable-core-do-not-import").LegacyObservableSubscriptionProcedure<{
|
|
178
186
|
input: {
|
|
179
187
|
path: string;
|
package/dist/trpc.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trpc.d.ts","sourceRoot":"","sources":["../src/trpc.ts"],"names":[],"mappings":"AAIA,wBAAgB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAExC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,QAErC;AAED,wBAAgB,UAAU,SAEzB;AAED,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAUtD,eAAO,MAAQ,IAAI
|
|
1
|
+
{"version":3,"file":"trpc.d.ts","sourceRoot":"","sources":["../src/trpc.ts"],"names":[],"mappings":"AAIA,wBAAgB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAExC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,QAErC;AAED,wBAAgB,UAAU,SAEzB;AAED,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAUtD,eAAO,MAAQ,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAiE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treenity/react",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.7",
|
|
4
4
|
"description": "React binding for Treenity — reactive hooks, admin UI, and context-based component rendering.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"README.md"
|
|
81
81
|
],
|
|
82
82
|
"scripts": {
|
|
83
|
-
"build": "tsc -p tsconfig.build.json",
|
|
83
|
+
"build": "tsc -p tsconfig.build.json && fix-hash-imports --copy-assets",
|
|
84
84
|
"prepack": "npm run build",
|
|
85
85
|
"test": "tsx --conditions development --test src/**/*.test.ts",
|
|
86
86
|
"dev": "vite"
|
package/src/App.tsx
CHANGED
|
@@ -42,7 +42,8 @@ export function App() {
|
|
|
42
42
|
const token = getToken();
|
|
43
43
|
if (!token) {
|
|
44
44
|
try {
|
|
45
|
-
const
|
|
45
|
+
const login = import.meta.env.VITE_DEV_LOGIN ? trpc.devLogin : trpc.anonLogin;
|
|
46
|
+
const { token: anonToken, userId } = await login.mutate();
|
|
46
47
|
setToken(anonToken);
|
|
47
48
|
setAuthed(userId);
|
|
48
49
|
setAuthChecked(true);
|
|
@@ -439,7 +440,7 @@ export function App() {
|
|
|
439
440
|
if (!authed) return <LoginScreen onLogin={(uid) => setAuthed(uid)} />;
|
|
440
441
|
|
|
441
442
|
const isAnon = authed.startsWith('anon:');
|
|
442
|
-
const needsLogin =
|
|
443
|
+
const needsLogin = showLoginModal;
|
|
443
444
|
if (mode === 'view') return <NavigateProvider value={navigate}><ViewPage path={viewPath} /></NavigateProvider>;
|
|
444
445
|
if (mode === 'preview') return <NavigateProvider value={navigate}><ViewPage path={viewPath} editorLink /></NavigateProvider>;
|
|
445
446
|
|
package/src/ComponentSection.tsx
CHANGED
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
|
)}
|
package/src/Treenity.tsx
CHANGED
|
@@ -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)
|