@almadar/ui 5.146.0 → 5.146.2

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.
@@ -18412,8 +18412,10 @@ var init_CodeBlock = __esm({
18412
18412
  ref: editableTextareaRef,
18413
18413
  defaultValue: code,
18414
18414
  onChange: (e) => {
18415
- setEditableValue(e.target.value);
18416
- onChange?.(e.target.value);
18415
+ const v = e.target.value;
18416
+ lastPropCodeRef.current = v;
18417
+ setEditableValue(v);
18418
+ onChange?.(v);
18417
18419
  },
18418
18420
  onScroll: handleEditableScroll,
18419
18421
  spellCheck: false,
@@ -24234,6 +24236,7 @@ var init_CodeRunnerPanel = __esm({
24234
24236
  const [output, setOutput] = React94.useState(null);
24235
24237
  const [error, setError] = React94.useState(null);
24236
24238
  const [isRunning, setIsRunning] = React94.useState(false);
24239
+ const [copied, setCopied] = React94.useState(false);
24237
24240
  const handleRun = React94.useCallback(async () => {
24238
24241
  if (!onRun) return;
24239
24242
  setIsRunning(true);
@@ -24256,63 +24259,75 @@ var init_CodeRunnerPanel = __esm({
24256
24259
  setOutput(null);
24257
24260
  setError(null);
24258
24261
  }, [initialCode]);
24262
+ const handleCopy = React94.useCallback(async () => {
24263
+ try {
24264
+ await navigator.clipboard.writeText(code);
24265
+ setCopied(true);
24266
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
24267
+ setTimeout(() => setCopied(false), 2e3);
24268
+ } catch {
24269
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
24270
+ }
24271
+ }, [code, language, eventBus]);
24259
24272
  if (!runnable || !onRun) {
24260
24273
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className, children: /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { language, code }) });
24261
24274
  }
24262
24275
  const hasOutput = output !== null || error !== null;
24263
24276
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("space-y-3", className), children: [
24264
- /* @__PURE__ */ jsxRuntime.jsx(
24265
- CodeBlock,
24266
- {
24267
- language,
24268
- code,
24269
- editable: true,
24270
- onChange: setCode,
24271
- showLanguageBadge: true,
24272
- showCopyButton: true
24273
- }
24274
- ),
24275
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "between", children: [
24276
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
24277
- /* @__PURE__ */ jsxRuntime.jsx(
24278
- Button,
24279
- {
24280
- variant: "primary",
24281
- size: "sm",
24282
- onClick: handleRun,
24283
- disabled: isRunning,
24284
- className: "min-w-[5rem]",
24285
- children: isRunning ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
24286
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16, className: "animate-spin" }),
24287
- t("common.loading")
24288
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
24289
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Play, { size: 16 }),
24290
- "Run"
24291
- ] })
24292
- }
24293
- ),
24294
- /* @__PURE__ */ jsxRuntime.jsx(
24295
- Button,
24296
- {
24297
- variant: "secondary",
24298
- size: "sm",
24299
- onClick: handleReset,
24300
- disabled: isRunning,
24301
- children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
24302
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16 }),
24303
- "Reset"
24304
- ] })
24305
- }
24306
- )
24307
- ] }),
24308
- output && /* @__PURE__ */ jsxRuntime.jsxs(
24309
- Badge,
24277
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
24278
+ /* @__PURE__ */ jsxRuntime.jsx(
24279
+ CodeBlock,
24310
24280
  {
24311
- variant: output.exitCode === 0 ? "success" : "danger",
24312
- size: "sm",
24281
+ language,
24282
+ code,
24283
+ editable: true,
24284
+ onChange: setCode,
24285
+ showLanguageBadge: true,
24286
+ showCopyButton: false,
24287
+ maxHeight: "100%"
24288
+ }
24289
+ ),
24290
+ /* @__PURE__ */ jsxRuntime.jsxs(
24291
+ HStack,
24292
+ {
24293
+ gap: "xs",
24294
+ align: "center",
24295
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
24313
24296
  children: [
24314
- "Exit ",
24315
- output.exitCode
24297
+ /* @__PURE__ */ jsxRuntime.jsx(
24298
+ Button,
24299
+ {
24300
+ variant: "ghost",
24301
+ size: "sm",
24302
+ onClick: handleCopy,
24303
+ icon: copied ? LucideIcons2.Check : LucideIcons2.Copy,
24304
+ "aria-label": t("common.copy"),
24305
+ className: copied ? "text-success" : ""
24306
+ }
24307
+ ),
24308
+ /* @__PURE__ */ jsxRuntime.jsx(
24309
+ Button,
24310
+ {
24311
+ variant: "ghost",
24312
+ size: "sm",
24313
+ onClick: handleReset,
24314
+ disabled: isRunning,
24315
+ icon: LucideIcons2.RotateCcw,
24316
+ "aria-label": "Reset"
24317
+ }
24318
+ ),
24319
+ /* @__PURE__ */ jsxRuntime.jsx(
24320
+ Button,
24321
+ {
24322
+ variant: "primary",
24323
+ size: "sm",
24324
+ onClick: handleRun,
24325
+ disabled: isRunning,
24326
+ icon: isRunning ? LucideIcons2.RotateCcw : LucideIcons2.Play,
24327
+ className: isRunning ? "[&_svg]:animate-spin" : "",
24328
+ children: isRunning ? t("common.loading") : "Run"
24329
+ }
24330
+ )
24316
24331
  ]
24317
24332
  }
24318
24333
  )
@@ -24326,7 +24341,18 @@ var init_CodeRunnerPanel = __esm({
24326
24341
  className: "px-3 py-2 bg-card border-b border-border",
24327
24342
  children: [
24328
24343
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Terminal, { size: 16, className: "text-muted-foreground" }),
24329
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
24344
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
24345
+ output && /* @__PURE__ */ jsxRuntime.jsxs(
24346
+ Badge,
24347
+ {
24348
+ variant: output.exitCode === 0 ? "success" : "danger",
24349
+ size: "sm",
24350
+ children: [
24351
+ "Exit ",
24352
+ output.exitCode
24353
+ ]
24354
+ }
24355
+ )
24330
24356
  ]
24331
24357
  }
24332
24358
  ),
package/dist/avl/index.js CHANGED
@@ -18336,8 +18336,10 @@ var init_CodeBlock = __esm({
18336
18336
  ref: editableTextareaRef,
18337
18337
  defaultValue: code,
18338
18338
  onChange: (e) => {
18339
- setEditableValue(e.target.value);
18340
- onChange?.(e.target.value);
18339
+ const v = e.target.value;
18340
+ lastPropCodeRef.current = v;
18341
+ setEditableValue(v);
18342
+ onChange?.(v);
18341
18343
  },
18342
18344
  onScroll: handleEditableScroll,
18343
18345
  spellCheck: false,
@@ -24158,6 +24160,7 @@ var init_CodeRunnerPanel = __esm({
24158
24160
  const [output, setOutput] = useState(null);
24159
24161
  const [error, setError] = useState(null);
24160
24162
  const [isRunning, setIsRunning] = useState(false);
24163
+ const [copied, setCopied] = useState(false);
24161
24164
  const handleRun = useCallback(async () => {
24162
24165
  if (!onRun) return;
24163
24166
  setIsRunning(true);
@@ -24180,63 +24183,75 @@ var init_CodeRunnerPanel = __esm({
24180
24183
  setOutput(null);
24181
24184
  setError(null);
24182
24185
  }, [initialCode]);
24186
+ const handleCopy = useCallback(async () => {
24187
+ try {
24188
+ await navigator.clipboard.writeText(code);
24189
+ setCopied(true);
24190
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
24191
+ setTimeout(() => setCopied(false), 2e3);
24192
+ } catch {
24193
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
24194
+ }
24195
+ }, [code, language, eventBus]);
24183
24196
  if (!runnable || !onRun) {
24184
24197
  return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsx(CodeBlock, { language, code }) });
24185
24198
  }
24186
24199
  const hasOutput = output !== null || error !== null;
24187
24200
  return /* @__PURE__ */ jsxs(Box, { className: cn("space-y-3", className), children: [
24188
- /* @__PURE__ */ jsx(
24189
- CodeBlock,
24190
- {
24191
- language,
24192
- code,
24193
- editable: true,
24194
- onChange: setCode,
24195
- showLanguageBadge: true,
24196
- showCopyButton: true
24197
- }
24198
- ),
24199
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "between", children: [
24200
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
24201
- /* @__PURE__ */ jsx(
24202
- Button,
24203
- {
24204
- variant: "primary",
24205
- size: "sm",
24206
- onClick: handleRun,
24207
- disabled: isRunning,
24208
- className: "min-w-[5rem]",
24209
- children: isRunning ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
24210
- /* @__PURE__ */ jsx(RotateCcw, { size: 16, className: "animate-spin" }),
24211
- t("common.loading")
24212
- ] }) : /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
24213
- /* @__PURE__ */ jsx(Play, { size: 16 }),
24214
- "Run"
24215
- ] })
24216
- }
24217
- ),
24218
- /* @__PURE__ */ jsx(
24219
- Button,
24220
- {
24221
- variant: "secondary",
24222
- size: "sm",
24223
- onClick: handleReset,
24224
- disabled: isRunning,
24225
- children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
24226
- /* @__PURE__ */ jsx(RotateCcw, { size: 16 }),
24227
- "Reset"
24228
- ] })
24229
- }
24230
- )
24231
- ] }),
24232
- output && /* @__PURE__ */ jsxs(
24233
- Badge,
24201
+ /* @__PURE__ */ jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
24202
+ /* @__PURE__ */ jsx(
24203
+ CodeBlock,
24234
24204
  {
24235
- variant: output.exitCode === 0 ? "success" : "danger",
24236
- size: "sm",
24205
+ language,
24206
+ code,
24207
+ editable: true,
24208
+ onChange: setCode,
24209
+ showLanguageBadge: true,
24210
+ showCopyButton: false,
24211
+ maxHeight: "100%"
24212
+ }
24213
+ ),
24214
+ /* @__PURE__ */ jsxs(
24215
+ HStack,
24216
+ {
24217
+ gap: "xs",
24218
+ align: "center",
24219
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
24237
24220
  children: [
24238
- "Exit ",
24239
- output.exitCode
24221
+ /* @__PURE__ */ jsx(
24222
+ Button,
24223
+ {
24224
+ variant: "ghost",
24225
+ size: "sm",
24226
+ onClick: handleCopy,
24227
+ icon: copied ? Check : Copy,
24228
+ "aria-label": t("common.copy"),
24229
+ className: copied ? "text-success" : ""
24230
+ }
24231
+ ),
24232
+ /* @__PURE__ */ jsx(
24233
+ Button,
24234
+ {
24235
+ variant: "ghost",
24236
+ size: "sm",
24237
+ onClick: handleReset,
24238
+ disabled: isRunning,
24239
+ icon: RotateCcw,
24240
+ "aria-label": "Reset"
24241
+ }
24242
+ ),
24243
+ /* @__PURE__ */ jsx(
24244
+ Button,
24245
+ {
24246
+ variant: "primary",
24247
+ size: "sm",
24248
+ onClick: handleRun,
24249
+ disabled: isRunning,
24250
+ icon: isRunning ? RotateCcw : Play,
24251
+ className: isRunning ? "[&_svg]:animate-spin" : "",
24252
+ children: isRunning ? t("common.loading") : "Run"
24253
+ }
24254
+ )
24240
24255
  ]
24241
24256
  }
24242
24257
  )
@@ -24250,7 +24265,18 @@ var init_CodeRunnerPanel = __esm({
24250
24265
  className: "px-3 py-2 bg-card border-b border-border",
24251
24266
  children: [
24252
24267
  /* @__PURE__ */ jsx(Terminal, { size: 16, className: "text-muted-foreground" }),
24253
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
24268
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
24269
+ output && /* @__PURE__ */ jsxs(
24270
+ Badge,
24271
+ {
24272
+ variant: output.exitCode === 0 ? "success" : "danger",
24273
+ size: "sm",
24274
+ children: [
24275
+ "Exit ",
24276
+ output.exitCode
24277
+ ]
24278
+ }
24279
+ )
24254
24280
  ]
24255
24281
  }
24256
24282
  ),
@@ -11122,8 +11122,10 @@ var init_CodeBlock = __esm({
11122
11122
  ref: editableTextareaRef,
11123
11123
  defaultValue: code,
11124
11124
  onChange: (e) => {
11125
- setEditableValue(e.target.value);
11126
- onChange?.(e.target.value);
11125
+ const v = e.target.value;
11126
+ lastPropCodeRef.current = v;
11127
+ setEditableValue(v);
11128
+ onChange?.(v);
11127
11129
  },
11128
11130
  onScroll: handleEditableScroll,
11129
11131
  spellCheck: false,
@@ -19346,6 +19348,7 @@ var init_CodeRunnerPanel = __esm({
19346
19348
  const [output, setOutput] = React77.useState(null);
19347
19349
  const [error, setError] = React77.useState(null);
19348
19350
  const [isRunning, setIsRunning] = React77.useState(false);
19351
+ const [copied, setCopied] = React77.useState(false);
19349
19352
  const handleRun = React77.useCallback(async () => {
19350
19353
  if (!onRun) return;
19351
19354
  setIsRunning(true);
@@ -19368,63 +19371,75 @@ var init_CodeRunnerPanel = __esm({
19368
19371
  setOutput(null);
19369
19372
  setError(null);
19370
19373
  }, [initialCode]);
19374
+ const handleCopy = React77.useCallback(async () => {
19375
+ try {
19376
+ await navigator.clipboard.writeText(code);
19377
+ setCopied(true);
19378
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
19379
+ setTimeout(() => setCopied(false), 2e3);
19380
+ } catch {
19381
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
19382
+ }
19383
+ }, [code, language, eventBus]);
19371
19384
  if (!runnable || !onRun) {
19372
19385
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className, children: /* @__PURE__ */ jsxRuntime.jsx(exports.CodeBlock, { language, code }) });
19373
19386
  }
19374
19387
  const hasOutput = output !== null || error !== null;
19375
19388
  return /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: cn("space-y-3", className), children: [
19376
- /* @__PURE__ */ jsxRuntime.jsx(
19377
- exports.CodeBlock,
19378
- {
19379
- language,
19380
- code,
19381
- editable: true,
19382
- onChange: setCode,
19383
- showLanguageBadge: true,
19384
- showCopyButton: true
19385
- }
19386
- ),
19387
- /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", justify: "between", children: [
19388
- /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", children: [
19389
- /* @__PURE__ */ jsxRuntime.jsx(
19390
- exports.Button,
19391
- {
19392
- variant: "primary",
19393
- size: "sm",
19394
- onClick: handleRun,
19395
- disabled: isRunning,
19396
- className: "min-w-[5rem]",
19397
- children: isRunning ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
19398
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16, className: "animate-spin" }),
19399
- t("common.loading")
19400
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
19401
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Play, { size: 16 }),
19402
- "Run"
19403
- ] })
19404
- }
19405
- ),
19406
- /* @__PURE__ */ jsxRuntime.jsx(
19407
- exports.Button,
19408
- {
19409
- variant: "secondary",
19410
- size: "sm",
19411
- onClick: handleReset,
19412
- disabled: isRunning,
19413
- children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
19414
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16 }),
19415
- "Reset"
19416
- ] })
19417
- }
19418
- )
19419
- ] }),
19420
- output && /* @__PURE__ */ jsxRuntime.jsxs(
19421
- exports.Badge,
19389
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "group relative", style: { height: 360 }, children: [
19390
+ /* @__PURE__ */ jsxRuntime.jsx(
19391
+ exports.CodeBlock,
19422
19392
  {
19423
- variant: output.exitCode === 0 ? "success" : "danger",
19424
- size: "sm",
19393
+ language,
19394
+ code,
19395
+ editable: true,
19396
+ onChange: setCode,
19397
+ showLanguageBadge: true,
19398
+ showCopyButton: false,
19399
+ maxHeight: "100%"
19400
+ }
19401
+ ),
19402
+ /* @__PURE__ */ jsxRuntime.jsxs(
19403
+ exports.HStack,
19404
+ {
19405
+ gap: "xs",
19406
+ align: "center",
19407
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
19425
19408
  children: [
19426
- "Exit ",
19427
- output.exitCode
19409
+ /* @__PURE__ */ jsxRuntime.jsx(
19410
+ exports.Button,
19411
+ {
19412
+ variant: "ghost",
19413
+ size: "sm",
19414
+ onClick: handleCopy,
19415
+ icon: copied ? LucideIcons2.Check : LucideIcons2.Copy,
19416
+ "aria-label": t("common.copy"),
19417
+ className: copied ? "text-success" : ""
19418
+ }
19419
+ ),
19420
+ /* @__PURE__ */ jsxRuntime.jsx(
19421
+ exports.Button,
19422
+ {
19423
+ variant: "ghost",
19424
+ size: "sm",
19425
+ onClick: handleReset,
19426
+ disabled: isRunning,
19427
+ icon: LucideIcons2.RotateCcw,
19428
+ "aria-label": "Reset"
19429
+ }
19430
+ ),
19431
+ /* @__PURE__ */ jsxRuntime.jsx(
19432
+ exports.Button,
19433
+ {
19434
+ variant: "primary",
19435
+ size: "sm",
19436
+ onClick: handleRun,
19437
+ disabled: isRunning,
19438
+ icon: isRunning ? LucideIcons2.RotateCcw : LucideIcons2.Play,
19439
+ className: isRunning ? "[&_svg]:animate-spin" : "",
19440
+ children: isRunning ? t("common.loading") : "Run"
19441
+ }
19442
+ )
19428
19443
  ]
19429
19444
  }
19430
19445
  )
@@ -19438,7 +19453,18 @@ var init_CodeRunnerPanel = __esm({
19438
19453
  className: "px-3 py-2 bg-card border-b border-border",
19439
19454
  children: [
19440
19455
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Terminal, { size: 16, className: "text-muted-foreground" }),
19441
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
19456
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
19457
+ output && /* @__PURE__ */ jsxRuntime.jsxs(
19458
+ exports.Badge,
19459
+ {
19460
+ variant: output.exitCode === 0 ? "success" : "danger",
19461
+ size: "sm",
19462
+ children: [
19463
+ "Exit ",
19464
+ output.exitCode
19465
+ ]
19466
+ }
19467
+ )
19442
19468
  ]
19443
19469
  }
19444
19470
  ),
@@ -7,7 +7,7 @@ import { EventBusContext, useTraitScopeChain, useCurrentPagePath, useGameAudioCo
7
7
  export { GameAudioContext, GameAudioProvider, useGameAudioContext } from '@almadar/ui/providers';
8
8
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
9
9
  import * as LucideIcons2 from 'lucide-react';
10
- import { X, List, Printer, ChevronRight, ChevronLeft, RotateCcw, Play, Terminal, CheckCircle, XCircle, ChevronDown, Search, ChevronUp, MoreHorizontal, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ZoomIn, TrendingUp, TrendingDown, Minus, AlertCircle, Circle, Clock, CheckCircle2, Loader2, Code, FileText, WrapText, Check, Copy, HelpCircle, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, GitBranch, Plus, ArrowRight, Trash, ArrowLeft, Menu as Menu$1, AlertTriangle, Trash2, Eraser, ZoomOut, Download, Lightbulb, PauseCircle, Link2, Tag, User, DollarSign } from 'lucide-react';
10
+ import { X, List, Printer, ChevronRight, ChevronLeft, Check, Copy, RotateCcw, Play, Terminal, CheckCircle, XCircle, ChevronDown, Search, ChevronUp, MoreHorizontal, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ZoomIn, TrendingUp, TrendingDown, Minus, AlertCircle, Circle, Clock, CheckCircle2, Loader2, Code, FileText, WrapText, HelpCircle, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, GitBranch, Plus, ArrowRight, Trash, ArrowLeft, Menu as Menu$1, AlertTriangle, Trash2, Eraser, ZoomOut, Download, Lightbulb, PauseCircle, Link2, Tag, User, DollarSign } from 'lucide-react';
11
11
  import { useTranslate } from '@almadar/ui/hooks';
12
12
  import { useUISlots, useTheme } from '@almadar/ui/context';
13
13
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
@@ -11047,8 +11047,10 @@ var init_CodeBlock = __esm({
11047
11047
  ref: editableTextareaRef,
11048
11048
  defaultValue: code,
11049
11049
  onChange: (e) => {
11050
- setEditableValue(e.target.value);
11051
- onChange?.(e.target.value);
11050
+ const v = e.target.value;
11051
+ lastPropCodeRef.current = v;
11052
+ setEditableValue(v);
11053
+ onChange?.(v);
11052
11054
  },
11053
11055
  onScroll: handleEditableScroll,
11054
11056
  spellCheck: false,
@@ -19271,6 +19273,7 @@ var init_CodeRunnerPanel = __esm({
19271
19273
  const [output, setOutput] = useState(null);
19272
19274
  const [error, setError] = useState(null);
19273
19275
  const [isRunning, setIsRunning] = useState(false);
19276
+ const [copied, setCopied] = useState(false);
19274
19277
  const handleRun = useCallback(async () => {
19275
19278
  if (!onRun) return;
19276
19279
  setIsRunning(true);
@@ -19293,63 +19296,75 @@ var init_CodeRunnerPanel = __esm({
19293
19296
  setOutput(null);
19294
19297
  setError(null);
19295
19298
  }, [initialCode]);
19299
+ const handleCopy = useCallback(async () => {
19300
+ try {
19301
+ await navigator.clipboard.writeText(code);
19302
+ setCopied(true);
19303
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
19304
+ setTimeout(() => setCopied(false), 2e3);
19305
+ } catch {
19306
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
19307
+ }
19308
+ }, [code, language, eventBus]);
19296
19309
  if (!runnable || !onRun) {
19297
19310
  return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsx(CodeBlock, { language, code }) });
19298
19311
  }
19299
19312
  const hasOutput = output !== null || error !== null;
19300
19313
  return /* @__PURE__ */ jsxs(Box, { className: cn("space-y-3", className), children: [
19301
- /* @__PURE__ */ jsx(
19302
- CodeBlock,
19303
- {
19304
- language,
19305
- code,
19306
- editable: true,
19307
- onChange: setCode,
19308
- showLanguageBadge: true,
19309
- showCopyButton: true
19310
- }
19311
- ),
19312
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "between", children: [
19313
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
19314
- /* @__PURE__ */ jsx(
19315
- Button,
19316
- {
19317
- variant: "primary",
19318
- size: "sm",
19319
- onClick: handleRun,
19320
- disabled: isRunning,
19321
- className: "min-w-[5rem]",
19322
- children: isRunning ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
19323
- /* @__PURE__ */ jsx(RotateCcw, { size: 16, className: "animate-spin" }),
19324
- t("common.loading")
19325
- ] }) : /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
19326
- /* @__PURE__ */ jsx(Play, { size: 16 }),
19327
- "Run"
19328
- ] })
19329
- }
19330
- ),
19331
- /* @__PURE__ */ jsx(
19332
- Button,
19333
- {
19334
- variant: "secondary",
19335
- size: "sm",
19336
- onClick: handleReset,
19337
- disabled: isRunning,
19338
- children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
19339
- /* @__PURE__ */ jsx(RotateCcw, { size: 16 }),
19340
- "Reset"
19341
- ] })
19342
- }
19343
- )
19344
- ] }),
19345
- output && /* @__PURE__ */ jsxs(
19346
- Badge,
19314
+ /* @__PURE__ */ jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
19315
+ /* @__PURE__ */ jsx(
19316
+ CodeBlock,
19347
19317
  {
19348
- variant: output.exitCode === 0 ? "success" : "danger",
19349
- size: "sm",
19318
+ language,
19319
+ code,
19320
+ editable: true,
19321
+ onChange: setCode,
19322
+ showLanguageBadge: true,
19323
+ showCopyButton: false,
19324
+ maxHeight: "100%"
19325
+ }
19326
+ ),
19327
+ /* @__PURE__ */ jsxs(
19328
+ HStack,
19329
+ {
19330
+ gap: "xs",
19331
+ align: "center",
19332
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
19350
19333
  children: [
19351
- "Exit ",
19352
- output.exitCode
19334
+ /* @__PURE__ */ jsx(
19335
+ Button,
19336
+ {
19337
+ variant: "ghost",
19338
+ size: "sm",
19339
+ onClick: handleCopy,
19340
+ icon: copied ? Check : Copy,
19341
+ "aria-label": t("common.copy"),
19342
+ className: copied ? "text-success" : ""
19343
+ }
19344
+ ),
19345
+ /* @__PURE__ */ jsx(
19346
+ Button,
19347
+ {
19348
+ variant: "ghost",
19349
+ size: "sm",
19350
+ onClick: handleReset,
19351
+ disabled: isRunning,
19352
+ icon: RotateCcw,
19353
+ "aria-label": "Reset"
19354
+ }
19355
+ ),
19356
+ /* @__PURE__ */ jsx(
19357
+ Button,
19358
+ {
19359
+ variant: "primary",
19360
+ size: "sm",
19361
+ onClick: handleRun,
19362
+ disabled: isRunning,
19363
+ icon: isRunning ? RotateCcw : Play,
19364
+ className: isRunning ? "[&_svg]:animate-spin" : "",
19365
+ children: isRunning ? t("common.loading") : "Run"
19366
+ }
19367
+ )
19353
19368
  ]
19354
19369
  }
19355
19370
  )
@@ -19363,7 +19378,18 @@ var init_CodeRunnerPanel = __esm({
19363
19378
  className: "px-3 py-2 bg-card border-b border-border",
19364
19379
  children: [
19365
19380
  /* @__PURE__ */ jsx(Terminal, { size: 16, className: "text-muted-foreground" }),
19366
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
19381
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
19382
+ output && /* @__PURE__ */ jsxs(
19383
+ Badge,
19384
+ {
19385
+ variant: output.exitCode === 0 ? "success" : "danger",
19386
+ size: "sm",
19387
+ children: [
19388
+ "Exit ",
19389
+ output.exitCode
19390
+ ]
19391
+ }
19392
+ )
19367
19393
  ]
19368
19394
  }
19369
19395
  ),