@almadar/ui 2.51.0 → 2.53.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.
@@ -4063,6 +4063,26 @@ var CodeBlock = React114__default.memo(
4063
4063
  const codeRef = useRef(null);
4064
4064
  const savedScrollLeftRef = useRef(0);
4065
4065
  const [copied, setCopied] = useState(false);
4066
+ const [editableValue, setEditableValue] = useState(code);
4067
+ const [editableTextareaKey, setEditableTextareaKey] = useState(0);
4068
+ const lastPropCodeRef = useRef(code);
4069
+ const editableTextareaRef = useRef(null);
4070
+ const editableOverlayRef = useRef(null);
4071
+ useEffect(() => {
4072
+ if (code !== lastPropCodeRef.current) {
4073
+ lastPropCodeRef.current = code;
4074
+ setEditableValue(code);
4075
+ setEditableTextareaKey((k) => k + 1);
4076
+ }
4077
+ }, [code]);
4078
+ const handleEditableScroll = useCallback(() => {
4079
+ const ta = editableTextareaRef.current;
4080
+ const ov = editableOverlayRef.current;
4081
+ if (ta && ov) {
4082
+ ov.scrollTop = ta.scrollTop;
4083
+ ov.scrollLeft = ta.scrollLeft;
4084
+ }
4085
+ }, []);
4066
4086
  const isFoldable = foldableProp ?? (language === "orb" || language === "json");
4067
4087
  const [collapsed, setCollapsed] = useState(() => /* @__PURE__ */ new Set());
4068
4088
  const foldRegions = useMemo(
@@ -4223,33 +4243,106 @@ var CodeBlock = React114__default.memo(
4223
4243
  }
4224
4244
  ),
4225
4245
  editable ? (
4226
- /* GAP-51: editable mode composes the Textarea atom. Plain text editing,
4227
- no Prism highlighting overlay (follow-up). The textarea is uncontrolled
4228
- on the value side: we pass `code` as the initial value and forward
4229
- every keystroke via onChange the consumer is responsible for
4230
- debouncing and re-deriving `code` only after the user stops typing
4231
- so the cursor doesn't fight a re-render. */
4232
- /* @__PURE__ */ jsx(
4233
- Textarea,
4246
+ /* GAP-77: editable mode = transparent Textarea on top + Prism-highlighted
4247
+ overlay underneath. The textarea is uncontrolled (defaultValue + key)
4248
+ to avoid cursor jumps; the overlay reads `editableValue` which is
4249
+ mirrored from the textarea via onChange. Both elements share IDENTICAL
4250
+ font / line-height / padding so the highlighted text aligns with the
4251
+ textarea's invisible glyphs.
4252
+
4253
+ Scroll sync: the overlay has `pointer-events: none` and the textarea
4254
+ scrolls; `handleEditableScroll` keeps the overlay's scroll matched. */
4255
+ /* @__PURE__ */ jsxs(
4256
+ Box,
4234
4257
  {
4235
- defaultValue: code,
4236
- onChange: (e) => onChange?.(e.target.value),
4237
- spellCheck: false,
4238
4258
  style: {
4239
- fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
4240
- fontSize: "13px",
4241
- lineHeight: "1.5",
4259
+ position: "relative",
4242
4260
  backgroundColor: "#1e1e1e",
4243
- color: "#e6e6e6",
4244
4261
  borderRadius: hasHeader ? "0 0 0.5rem 0.5rem" : "0.5rem",
4245
- border: "none",
4246
- padding: "1rem",
4247
- resize: "none",
4248
4262
  minHeight: "160px",
4249
4263
  maxHeight,
4250
- width: "100%",
4251
- outline: "none"
4252
- }
4264
+ overflow: "hidden"
4265
+ },
4266
+ children: [
4267
+ /* @__PURE__ */ jsx(
4268
+ "div",
4269
+ {
4270
+ ref: editableOverlayRef,
4271
+ "aria-hidden": true,
4272
+ style: {
4273
+ position: "absolute",
4274
+ inset: 0,
4275
+ overflow: "hidden",
4276
+ pointerEvents: "none",
4277
+ maxHeight
4278
+ },
4279
+ children: /* @__PURE__ */ jsx(
4280
+ SyntaxHighlighter,
4281
+ {
4282
+ PreTag: "div",
4283
+ language,
4284
+ style: activeStyle,
4285
+ customStyle: {
4286
+ backgroundColor: "transparent",
4287
+ borderRadius: 0,
4288
+ padding: "1rem",
4289
+ margin: 0,
4290
+ whiteSpace: "pre",
4291
+ minWidth: "100%",
4292
+ minHeight: "160px",
4293
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
4294
+ fontSize: "13px",
4295
+ lineHeight: "1.5"
4296
+ },
4297
+ codeTagProps: {
4298
+ style: {
4299
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
4300
+ fontSize: "13px",
4301
+ lineHeight: "1.5"
4302
+ }
4303
+ },
4304
+ children: editableValue || " "
4305
+ }
4306
+ )
4307
+ }
4308
+ ),
4309
+ /* @__PURE__ */ jsx(
4310
+ Textarea,
4311
+ {
4312
+ ref: editableTextareaRef,
4313
+ defaultValue: code,
4314
+ onChange: (e) => {
4315
+ setEditableValue(e.target.value);
4316
+ onChange?.(e.target.value);
4317
+ },
4318
+ onScroll: handleEditableScroll,
4319
+ spellCheck: false,
4320
+ style: {
4321
+ position: "relative",
4322
+ zIndex: 1,
4323
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
4324
+ fontSize: "13px",
4325
+ lineHeight: "1.5",
4326
+ backgroundColor: "transparent",
4327
+ color: "transparent",
4328
+ caretColor: "#e6e6e6",
4329
+ borderRadius: hasHeader ? "0 0 0.5rem 0.5rem" : "0.5rem",
4330
+ border: "none",
4331
+ padding: "1rem",
4332
+ resize: "none",
4333
+ minHeight: "160px",
4334
+ maxHeight,
4335
+ width: "100%",
4336
+ height: "100%",
4337
+ outline: "none",
4338
+ whiteSpace: "pre",
4339
+ overflowWrap: "normal",
4340
+ overflow: "auto"
4341
+ }
4342
+ },
4343
+ editableTextareaKey
4344
+ )
4345
+ ]
4253
4346
  }
4254
4347
  )
4255
4348
  ) : /* @__PURE__ */ jsx(
@@ -10028,6 +10028,26 @@ var CodeBlock = React114__namespace.default.memo(
10028
10028
  const codeRef = React114.useRef(null);
10029
10029
  const savedScrollLeftRef = React114.useRef(0);
10030
10030
  const [copied, setCopied] = React114.useState(false);
10031
+ const [editableValue, setEditableValue] = React114.useState(code);
10032
+ const [editableTextareaKey, setEditableTextareaKey] = React114.useState(0);
10033
+ const lastPropCodeRef = React114.useRef(code);
10034
+ const editableTextareaRef = React114.useRef(null);
10035
+ const editableOverlayRef = React114.useRef(null);
10036
+ React114.useEffect(() => {
10037
+ if (code !== lastPropCodeRef.current) {
10038
+ lastPropCodeRef.current = code;
10039
+ setEditableValue(code);
10040
+ setEditableTextareaKey((k) => k + 1);
10041
+ }
10042
+ }, [code]);
10043
+ const handleEditableScroll = React114.useCallback(() => {
10044
+ const ta = editableTextareaRef.current;
10045
+ const ov = editableOverlayRef.current;
10046
+ if (ta && ov) {
10047
+ ov.scrollTop = ta.scrollTop;
10048
+ ov.scrollLeft = ta.scrollLeft;
10049
+ }
10050
+ }, []);
10031
10051
  const isFoldable = foldableProp ?? (language === "orb" || language === "json");
10032
10052
  const [collapsed, setCollapsed] = React114.useState(() => /* @__PURE__ */ new Set());
10033
10053
  const foldRegions = React114.useMemo(
@@ -10188,33 +10208,106 @@ var CodeBlock = React114__namespace.default.memo(
10188
10208
  }
10189
10209
  ),
10190
10210
  editable ? (
10191
- /* GAP-51: editable mode composes the Textarea atom. Plain text editing,
10192
- no Prism highlighting overlay (follow-up). The textarea is uncontrolled
10193
- on the value side: we pass `code` as the initial value and forward
10194
- every keystroke via onChange the consumer is responsible for
10195
- debouncing and re-deriving `code` only after the user stops typing
10196
- so the cursor doesn't fight a re-render. */
10197
- /* @__PURE__ */ jsxRuntime.jsx(
10198
- Textarea,
10211
+ /* GAP-77: editable mode = transparent Textarea on top + Prism-highlighted
10212
+ overlay underneath. The textarea is uncontrolled (defaultValue + key)
10213
+ to avoid cursor jumps; the overlay reads `editableValue` which is
10214
+ mirrored from the textarea via onChange. Both elements share IDENTICAL
10215
+ font / line-height / padding so the highlighted text aligns with the
10216
+ textarea's invisible glyphs.
10217
+
10218
+ Scroll sync: the overlay has `pointer-events: none` and the textarea
10219
+ scrolls; `handleEditableScroll` keeps the overlay's scroll matched. */
10220
+ /* @__PURE__ */ jsxRuntime.jsxs(
10221
+ Box,
10199
10222
  {
10200
- defaultValue: code,
10201
- onChange: (e) => onChange?.(e.target.value),
10202
- spellCheck: false,
10203
10223
  style: {
10204
- fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
10205
- fontSize: "13px",
10206
- lineHeight: "1.5",
10224
+ position: "relative",
10207
10225
  backgroundColor: "#1e1e1e",
10208
- color: "#e6e6e6",
10209
10226
  borderRadius: hasHeader ? "0 0 0.5rem 0.5rem" : "0.5rem",
10210
- border: "none",
10211
- padding: "1rem",
10212
- resize: "none",
10213
10227
  minHeight: "160px",
10214
10228
  maxHeight,
10215
- width: "100%",
10216
- outline: "none"
10217
- }
10229
+ overflow: "hidden"
10230
+ },
10231
+ children: [
10232
+ /* @__PURE__ */ jsxRuntime.jsx(
10233
+ "div",
10234
+ {
10235
+ ref: editableOverlayRef,
10236
+ "aria-hidden": true,
10237
+ style: {
10238
+ position: "absolute",
10239
+ inset: 0,
10240
+ overflow: "hidden",
10241
+ pointerEvents: "none",
10242
+ maxHeight
10243
+ },
10244
+ children: /* @__PURE__ */ jsxRuntime.jsx(
10245
+ SyntaxHighlighter__default.default,
10246
+ {
10247
+ PreTag: "div",
10248
+ language,
10249
+ style: activeStyle,
10250
+ customStyle: {
10251
+ backgroundColor: "transparent",
10252
+ borderRadius: 0,
10253
+ padding: "1rem",
10254
+ margin: 0,
10255
+ whiteSpace: "pre",
10256
+ minWidth: "100%",
10257
+ minHeight: "160px",
10258
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
10259
+ fontSize: "13px",
10260
+ lineHeight: "1.5"
10261
+ },
10262
+ codeTagProps: {
10263
+ style: {
10264
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
10265
+ fontSize: "13px",
10266
+ lineHeight: "1.5"
10267
+ }
10268
+ },
10269
+ children: editableValue || " "
10270
+ }
10271
+ )
10272
+ }
10273
+ ),
10274
+ /* @__PURE__ */ jsxRuntime.jsx(
10275
+ Textarea,
10276
+ {
10277
+ ref: editableTextareaRef,
10278
+ defaultValue: code,
10279
+ onChange: (e) => {
10280
+ setEditableValue(e.target.value);
10281
+ onChange?.(e.target.value);
10282
+ },
10283
+ onScroll: handleEditableScroll,
10284
+ spellCheck: false,
10285
+ style: {
10286
+ position: "relative",
10287
+ zIndex: 1,
10288
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
10289
+ fontSize: "13px",
10290
+ lineHeight: "1.5",
10291
+ backgroundColor: "transparent",
10292
+ color: "transparent",
10293
+ caretColor: "#e6e6e6",
10294
+ borderRadius: hasHeader ? "0 0 0.5rem 0.5rem" : "0.5rem",
10295
+ border: "none",
10296
+ padding: "1rem",
10297
+ resize: "none",
10298
+ minHeight: "160px",
10299
+ maxHeight,
10300
+ width: "100%",
10301
+ height: "100%",
10302
+ outline: "none",
10303
+ whiteSpace: "pre",
10304
+ overflowWrap: "normal",
10305
+ overflow: "auto"
10306
+ }
10307
+ },
10308
+ editableTextareaKey
10309
+ )
10310
+ ]
10218
10311
  }
10219
10312
  )
10220
10313
  ) : /* @__PURE__ */ jsxRuntime.jsx(
@@ -9983,6 +9983,26 @@ var CodeBlock = React114__default.memo(
9983
9983
  const codeRef = useRef(null);
9984
9984
  const savedScrollLeftRef = useRef(0);
9985
9985
  const [copied, setCopied] = useState(false);
9986
+ const [editableValue, setEditableValue] = useState(code);
9987
+ const [editableTextareaKey, setEditableTextareaKey] = useState(0);
9988
+ const lastPropCodeRef = useRef(code);
9989
+ const editableTextareaRef = useRef(null);
9990
+ const editableOverlayRef = useRef(null);
9991
+ useEffect(() => {
9992
+ if (code !== lastPropCodeRef.current) {
9993
+ lastPropCodeRef.current = code;
9994
+ setEditableValue(code);
9995
+ setEditableTextareaKey((k) => k + 1);
9996
+ }
9997
+ }, [code]);
9998
+ const handleEditableScroll = useCallback(() => {
9999
+ const ta = editableTextareaRef.current;
10000
+ const ov = editableOverlayRef.current;
10001
+ if (ta && ov) {
10002
+ ov.scrollTop = ta.scrollTop;
10003
+ ov.scrollLeft = ta.scrollLeft;
10004
+ }
10005
+ }, []);
9986
10006
  const isFoldable = foldableProp ?? (language === "orb" || language === "json");
9987
10007
  const [collapsed, setCollapsed] = useState(() => /* @__PURE__ */ new Set());
9988
10008
  const foldRegions = useMemo(
@@ -10143,33 +10163,106 @@ var CodeBlock = React114__default.memo(
10143
10163
  }
10144
10164
  ),
10145
10165
  editable ? (
10146
- /* GAP-51: editable mode composes the Textarea atom. Plain text editing,
10147
- no Prism highlighting overlay (follow-up). The textarea is uncontrolled
10148
- on the value side: we pass `code` as the initial value and forward
10149
- every keystroke via onChange the consumer is responsible for
10150
- debouncing and re-deriving `code` only after the user stops typing
10151
- so the cursor doesn't fight a re-render. */
10152
- /* @__PURE__ */ jsx(
10153
- Textarea,
10166
+ /* GAP-77: editable mode = transparent Textarea on top + Prism-highlighted
10167
+ overlay underneath. The textarea is uncontrolled (defaultValue + key)
10168
+ to avoid cursor jumps; the overlay reads `editableValue` which is
10169
+ mirrored from the textarea via onChange. Both elements share IDENTICAL
10170
+ font / line-height / padding so the highlighted text aligns with the
10171
+ textarea's invisible glyphs.
10172
+
10173
+ Scroll sync: the overlay has `pointer-events: none` and the textarea
10174
+ scrolls; `handleEditableScroll` keeps the overlay's scroll matched. */
10175
+ /* @__PURE__ */ jsxs(
10176
+ Box,
10154
10177
  {
10155
- defaultValue: code,
10156
- onChange: (e) => onChange?.(e.target.value),
10157
- spellCheck: false,
10158
10178
  style: {
10159
- fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
10160
- fontSize: "13px",
10161
- lineHeight: "1.5",
10179
+ position: "relative",
10162
10180
  backgroundColor: "#1e1e1e",
10163
- color: "#e6e6e6",
10164
10181
  borderRadius: hasHeader ? "0 0 0.5rem 0.5rem" : "0.5rem",
10165
- border: "none",
10166
- padding: "1rem",
10167
- resize: "none",
10168
10182
  minHeight: "160px",
10169
10183
  maxHeight,
10170
- width: "100%",
10171
- outline: "none"
10172
- }
10184
+ overflow: "hidden"
10185
+ },
10186
+ children: [
10187
+ /* @__PURE__ */ jsx(
10188
+ "div",
10189
+ {
10190
+ ref: editableOverlayRef,
10191
+ "aria-hidden": true,
10192
+ style: {
10193
+ position: "absolute",
10194
+ inset: 0,
10195
+ overflow: "hidden",
10196
+ pointerEvents: "none",
10197
+ maxHeight
10198
+ },
10199
+ children: /* @__PURE__ */ jsx(
10200
+ SyntaxHighlighter,
10201
+ {
10202
+ PreTag: "div",
10203
+ language,
10204
+ style: activeStyle,
10205
+ customStyle: {
10206
+ backgroundColor: "transparent",
10207
+ borderRadius: 0,
10208
+ padding: "1rem",
10209
+ margin: 0,
10210
+ whiteSpace: "pre",
10211
+ minWidth: "100%",
10212
+ minHeight: "160px",
10213
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
10214
+ fontSize: "13px",
10215
+ lineHeight: "1.5"
10216
+ },
10217
+ codeTagProps: {
10218
+ style: {
10219
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
10220
+ fontSize: "13px",
10221
+ lineHeight: "1.5"
10222
+ }
10223
+ },
10224
+ children: editableValue || " "
10225
+ }
10226
+ )
10227
+ }
10228
+ ),
10229
+ /* @__PURE__ */ jsx(
10230
+ Textarea,
10231
+ {
10232
+ ref: editableTextareaRef,
10233
+ defaultValue: code,
10234
+ onChange: (e) => {
10235
+ setEditableValue(e.target.value);
10236
+ onChange?.(e.target.value);
10237
+ },
10238
+ onScroll: handleEditableScroll,
10239
+ spellCheck: false,
10240
+ style: {
10241
+ position: "relative",
10242
+ zIndex: 1,
10243
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Courier New", monospace',
10244
+ fontSize: "13px",
10245
+ lineHeight: "1.5",
10246
+ backgroundColor: "transparent",
10247
+ color: "transparent",
10248
+ caretColor: "#e6e6e6",
10249
+ borderRadius: hasHeader ? "0 0 0.5rem 0.5rem" : "0.5rem",
10250
+ border: "none",
10251
+ padding: "1rem",
10252
+ resize: "none",
10253
+ minHeight: "160px",
10254
+ maxHeight,
10255
+ width: "100%",
10256
+ height: "100%",
10257
+ outline: "none",
10258
+ whiteSpace: "pre",
10259
+ overflowWrap: "normal",
10260
+ overflow: "auto"
10261
+ }
10262
+ },
10263
+ editableTextareaKey
10264
+ )
10265
+ ]
10173
10266
  }
10174
10267
  )
10175
10268
  ) : /* @__PURE__ */ jsx(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "2.51.0",
3
+ "version": "2.53.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "main": "./dist/components/index.js",