@particle-academy/react-fancy 4.14.0 → 4.15.0
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/README.md +1 -0
- package/dist/index.cjs +112 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -2
- package/dist/index.d.ts +55 -2
- package/dist/index.js +112 -21
- package/dist/index.js.map +1 -1
- package/docs/CodeView.md +64 -0
- package/docs/Editor.md +7 -5
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -163,6 +163,7 @@ npx vite build # Build demo app (verifies imports work)
|
|
|
163
163
|
| Composer | Chat-style message input composing textarea + actions | [docs](docs/Composer.md) |
|
|
164
164
|
| Chart | SVG-based Bar, Line, Area, Pie, Donut, and Sparkline charts | [docs](docs/Chart.md) |
|
|
165
165
|
| Editor | Toolbar chrome wrapper for contentEditable, with a Source toggle to edit raw HTML/Markdown | [docs](docs/Editor.md) |
|
|
166
|
+
| CodeView | Lightweight syntax-highlighted source view (HTML highlighted; fills height) | [docs](docs/CodeView.md) |
|
|
166
167
|
| Kanban | Drag-and-drop board with columns and cards | [docs](docs/Kanban.md) |
|
|
167
168
|
| Canvas | Interactive node canvas with pan, zoom, and connections | [docs](docs/Canvas.md) |
|
|
168
169
|
| Diagram | Entity-relationship diagram with draggable nodes and relation lines | [docs](docs/Diagram.md) |
|
package/dist/index.cjs
CHANGED
|
@@ -7,6 +7,7 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
7
7
|
var reactDom = require('react-dom');
|
|
8
8
|
var lucideReact = require('lucide-react');
|
|
9
9
|
var marked = require('marked');
|
|
10
|
+
var fancyFileCommons = require('@particle-academy/fancy-file-commons');
|
|
10
11
|
|
|
11
12
|
// src/components/Button/Button.tsx
|
|
12
13
|
function cn(...inputs) {
|
|
@@ -11388,7 +11389,7 @@ function EditorToolbar({
|
|
|
11388
11389
|
{
|
|
11389
11390
|
"data-react-fancy-editor-toolbar": "",
|
|
11390
11391
|
className: cn(
|
|
11391
|
-
"flex items-center gap-0.5 border-b border-zinc-200 px-2 py-1.5 dark:border-zinc-700",
|
|
11392
|
+
"flex shrink-0 items-center gap-0.5 border-b border-zinc-200 px-2 py-1.5 dark:border-zinc-700",
|
|
11392
11393
|
className
|
|
11393
11394
|
),
|
|
11394
11395
|
children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -11430,6 +11431,98 @@ function EditorToolbarSeparator() {
|
|
|
11430
11431
|
);
|
|
11431
11432
|
}
|
|
11432
11433
|
EditorToolbarSeparator.displayName = "EditorToolbarSeparator";
|
|
11434
|
+
function subscribeDark(callback) {
|
|
11435
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
11436
|
+
mq.addEventListener("change", callback);
|
|
11437
|
+
const observer = new MutationObserver(callback);
|
|
11438
|
+
observer.observe(document.documentElement, {
|
|
11439
|
+
attributes: true,
|
|
11440
|
+
attributeFilter: ["class"]
|
|
11441
|
+
});
|
|
11442
|
+
return () => {
|
|
11443
|
+
mq.removeEventListener("change", callback);
|
|
11444
|
+
observer.disconnect();
|
|
11445
|
+
};
|
|
11446
|
+
}
|
|
11447
|
+
function darkSnapshot() {
|
|
11448
|
+
return document.documentElement.classList.contains("dark") || window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
11449
|
+
}
|
|
11450
|
+
function useIsDark() {
|
|
11451
|
+
return react.useSyncExternalStore(subscribeDark, darkSnapshot, () => false);
|
|
11452
|
+
}
|
|
11453
|
+
var TEXT_METRICS = "m-0 p-3 font-mono text-xs leading-relaxed";
|
|
11454
|
+
function CodeView({
|
|
11455
|
+
value,
|
|
11456
|
+
onChange,
|
|
11457
|
+
language = "plaintext",
|
|
11458
|
+
readOnly = false,
|
|
11459
|
+
placeholder,
|
|
11460
|
+
minHeight = 120,
|
|
11461
|
+
maxHeight,
|
|
11462
|
+
className
|
|
11463
|
+
}) {
|
|
11464
|
+
const textareaRef = react.useRef(null);
|
|
11465
|
+
const isDark = useIsDark();
|
|
11466
|
+
const colors = isDark ? fancyFileCommons.DARK_COLORS : fancyFileCommons.LIGHT_COLORS;
|
|
11467
|
+
const highlighted = react.useMemo(() => {
|
|
11468
|
+
const tokens = language === "html" ? fancyFileCommons.tokenizeHtml(value) : [];
|
|
11469
|
+
return fancyFileCommons.highlightCode(value, tokens, colors);
|
|
11470
|
+
}, [value, language, colors]);
|
|
11471
|
+
react.useEffect(() => {
|
|
11472
|
+
const el = textareaRef.current;
|
|
11473
|
+
if (!el) return;
|
|
11474
|
+
el.style.height = "auto";
|
|
11475
|
+
el.style.height = `${el.scrollHeight}px`;
|
|
11476
|
+
}, [value]);
|
|
11477
|
+
const editable = !readOnly && !!onChange;
|
|
11478
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11479
|
+
"div",
|
|
11480
|
+
{
|
|
11481
|
+
"data-react-fancy-code-view": "",
|
|
11482
|
+
className: cn("relative overflow-auto", className),
|
|
11483
|
+
style: { backgroundColor: colors.background, color: colors.foreground, minHeight, maxHeight },
|
|
11484
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative min-h-full", children: [
|
|
11485
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11486
|
+
"pre",
|
|
11487
|
+
{
|
|
11488
|
+
"aria-hidden": "true",
|
|
11489
|
+
className: cn("pointer-events-none absolute inset-0 overflow-hidden border-none", TEXT_METRICS),
|
|
11490
|
+
style: { whiteSpace: "pre-wrap", overflowWrap: "break-word" },
|
|
11491
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("code", { dangerouslySetInnerHTML: { __html: highlighted + "\n" } })
|
|
11492
|
+
}
|
|
11493
|
+
),
|
|
11494
|
+
placeholder && value.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("pointer-events-none absolute left-0 top-0 opacity-40", TEXT_METRICS), children: placeholder }),
|
|
11495
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11496
|
+
"textarea",
|
|
11497
|
+
{
|
|
11498
|
+
ref: textareaRef,
|
|
11499
|
+
"data-react-fancy-code-view-input": "",
|
|
11500
|
+
value,
|
|
11501
|
+
onChange: editable ? (e) => onChange(e.target.value) : void 0,
|
|
11502
|
+
readOnly: !editable,
|
|
11503
|
+
spellCheck: false,
|
|
11504
|
+
autoComplete: "off",
|
|
11505
|
+
autoCorrect: "off",
|
|
11506
|
+
autoCapitalize: "off",
|
|
11507
|
+
"aria-label": placeholder,
|
|
11508
|
+
className: cn(
|
|
11509
|
+
"relative block w-full resize-none border-none bg-transparent text-transparent outline-none",
|
|
11510
|
+
TEXT_METRICS
|
|
11511
|
+
),
|
|
11512
|
+
style: {
|
|
11513
|
+
caretColor: colors.cursorColor,
|
|
11514
|
+
overflow: "hidden",
|
|
11515
|
+
whiteSpace: "pre-wrap",
|
|
11516
|
+
overflowWrap: "break-word",
|
|
11517
|
+
minHeight
|
|
11518
|
+
}
|
|
11519
|
+
}
|
|
11520
|
+
)
|
|
11521
|
+
] })
|
|
11522
|
+
}
|
|
11523
|
+
);
|
|
11524
|
+
}
|
|
11525
|
+
CodeView.displayName = "CodeView";
|
|
11433
11526
|
|
|
11434
11527
|
// src/components/Editor/editor.utils.ts
|
|
11435
11528
|
var proseClasses = [
|
|
@@ -11652,24 +11745,14 @@ function EditorContent({ className, maxHeight, sourceClassName }) {
|
|
|
11652
11745
|
);
|
|
11653
11746
|
if (showSource) {
|
|
11654
11747
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11655
|
-
|
|
11748
|
+
CodeView,
|
|
11656
11749
|
{
|
|
11657
|
-
"data-react-fancy-editor-source": "",
|
|
11658
11750
|
value: _sourceValue,
|
|
11659
|
-
onChange:
|
|
11660
|
-
|
|
11751
|
+
onChange: _onSourceInput,
|
|
11752
|
+
language: outputFormat === "html" ? "html" : "plaintext",
|
|
11661
11753
|
placeholder,
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
maxHeight: maxHeight ? `${maxHeight}px` : void 0
|
|
11665
|
-
},
|
|
11666
|
-
className: cn(
|
|
11667
|
-
"block min-h-[120px] w-full resize-y px-4 py-3 font-mono text-xs leading-relaxed outline-none",
|
|
11668
|
-
"bg-zinc-50 text-zinc-800 focus:outline-none dark:bg-zinc-900 dark:text-zinc-200",
|
|
11669
|
-
"placeholder:text-zinc-400",
|
|
11670
|
-
maxHeight && "overflow-y-auto",
|
|
11671
|
-
sourceClassName
|
|
11672
|
-
)
|
|
11754
|
+
maxHeight,
|
|
11755
|
+
className: cn("min-h-0 flex-auto", sourceClassName)
|
|
11673
11756
|
}
|
|
11674
11757
|
);
|
|
11675
11758
|
}
|
|
@@ -11687,9 +11770,8 @@ function EditorContent({ className, maxHeight, sourceClassName }) {
|
|
|
11687
11770
|
maxHeight: maxHeight ? `${maxHeight}px` : void 0
|
|
11688
11771
|
},
|
|
11689
11772
|
className: cn(
|
|
11690
|
-
"min-h-[120px] px-4 py-3 text-sm outline-none",
|
|
11773
|
+
"min-h-[120px] flex-auto overflow-y-auto px-4 py-3 text-sm outline-none",
|
|
11691
11774
|
"focus:outline-none",
|
|
11692
|
-
maxHeight && "overflow-y-auto",
|
|
11693
11775
|
proseClasses,
|
|
11694
11776
|
extClasses,
|
|
11695
11777
|
"empty:before:content-[attr(data-placeholder)] empty:before:text-zinc-400 empty:before:pointer-events-none",
|
|
@@ -11989,7 +12071,7 @@ function EditorRoot({
|
|
|
11989
12071
|
"data-react-fancy-editor": "",
|
|
11990
12072
|
"data-mode": "edit",
|
|
11991
12073
|
className: cn(
|
|
11992
|
-
"overflow-hidden rounded-xl border border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900",
|
|
12074
|
+
"flex flex-col overflow-hidden rounded-xl border border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900",
|
|
11993
12075
|
className
|
|
11994
12076
|
),
|
|
11995
12077
|
children
|
|
@@ -12963,6 +13045,7 @@ function TreeNode({ node, depth }) {
|
|
|
12963
13045
|
indentSize,
|
|
12964
13046
|
showIcons,
|
|
12965
13047
|
draggable,
|
|
13048
|
+
dragCursor,
|
|
12966
13049
|
dragState,
|
|
12967
13050
|
setDragState,
|
|
12968
13051
|
onNodeMove,
|
|
@@ -13093,7 +13176,12 @@ function TreeNode({ node, depth }) {
|
|
|
13093
13176
|
isSelected ? "bg-blue-500/15 text-blue-600 dark:text-blue-400" : "text-zinc-700 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800",
|
|
13094
13177
|
node.disabled && "pointer-events-none opacity-40",
|
|
13095
13178
|
isDragging && "opacity-50",
|
|
13096
|
-
|
|
13179
|
+
// Grab affordance. By default (`dragCursor="none"`) the row keeps its
|
|
13180
|
+
// normal click cursor on hover — no open-hand "move me" cursor before
|
|
13181
|
+
// any drag — and only shows the closed-hand `grabbing` cursor while a
|
|
13182
|
+
// drag is actually underway (mousedown/drag). `dragCursor="grab"` opts
|
|
13183
|
+
// back into the always-on grab cursor for whole-row drag handles (#14).
|
|
13184
|
+
canDrag && (dragCursor === "grab" ? "cursor-grab active:cursor-grabbing" : "active:cursor-grabbing"),
|
|
13097
13185
|
isDropTarget && dropPosition === "inside" && "bg-blue-500/10 ring-1 ring-blue-500/30 ring-inset"
|
|
13098
13186
|
),
|
|
13099
13187
|
style: { paddingLeft },
|
|
@@ -13149,6 +13237,7 @@ function TreeNavRoot({
|
|
|
13149
13237
|
defaultExpandAll = false,
|
|
13150
13238
|
indentSize = 16,
|
|
13151
13239
|
showIcons = true,
|
|
13240
|
+
dragCursor = "none",
|
|
13152
13241
|
className
|
|
13153
13242
|
}) {
|
|
13154
13243
|
const [internalExpanded, setInternalExpanded] = react.useState(() => {
|
|
@@ -13193,6 +13282,7 @@ function TreeNavRoot({
|
|
|
13193
13282
|
indentSize,
|
|
13194
13283
|
showIcons,
|
|
13195
13284
|
draggable,
|
|
13285
|
+
dragCursor,
|
|
13196
13286
|
dragState,
|
|
13197
13287
|
setDragState,
|
|
13198
13288
|
onNodeMove,
|
|
@@ -13210,6 +13300,7 @@ function TreeNavRoot({
|
|
|
13210
13300
|
indentSize,
|
|
13211
13301
|
showIcons,
|
|
13212
13302
|
draggable,
|
|
13303
|
+
dragCursor,
|
|
13213
13304
|
dragState,
|
|
13214
13305
|
onNodeMove,
|
|
13215
13306
|
acceptExternalDrops,
|
|
@@ -15986,6 +16077,7 @@ exports.Chart = Chart;
|
|
|
15986
16077
|
exports.ChatDrawer = ChatDrawer;
|
|
15987
16078
|
exports.Checkbox = Checkbox;
|
|
15988
16079
|
exports.CheckboxGroup = CheckboxGroup;
|
|
16080
|
+
exports.CodeView = CodeView;
|
|
15989
16081
|
exports.ColorPicker = ColorPicker;
|
|
15990
16082
|
exports.Command = Command;
|
|
15991
16083
|
exports.Composer = Composer;
|