@wallarm-org/design-system 1.30.0 → 1.31.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.
Files changed (123) hide show
  1. package/dist/components/CodeEditor/CodeEditorContent.d.ts +17 -0
  2. package/dist/components/CodeEditor/CodeEditorContent.js +197 -0
  3. package/dist/components/CodeEditor/CodeEditorContext.d.ts +17 -0
  4. package/dist/components/CodeEditor/CodeEditorContext.js +8 -0
  5. package/dist/components/CodeEditor/CodeEditorRoot.d.ts +77 -0
  6. package/dist/components/CodeEditor/CodeEditorRoot.js +203 -0
  7. package/dist/components/CodeEditor/classes.d.ts +21 -0
  8. package/dist/components/CodeEditor/classes.js +41 -0
  9. package/dist/components/CodeEditor/engine/SearchPanel.d.ts +13 -0
  10. package/dist/components/CodeEditor/engine/SearchPanel.js +201 -0
  11. package/dist/components/CodeEditor/engine/adapterPainter.d.ts +23 -0
  12. package/dist/components/CodeEditor/engine/adapterPainter.js +110 -0
  13. package/dist/components/CodeEditor/engine/babelSyntax.d.ts +15 -0
  14. package/dist/components/CodeEditor/engine/babelSyntax.js +54 -0
  15. package/dist/components/CodeEditor/engine/completion.d.ts +17 -0
  16. package/dist/components/CodeEditor/engine/completion.js +129 -0
  17. package/dist/components/CodeEditor/engine/contentAttributes.d.ts +12 -0
  18. package/dist/components/CodeEditor/engine/contentAttributes.js +24 -0
  19. package/dist/components/CodeEditor/engine/diagnostics.d.ts +73 -0
  20. package/dist/components/CodeEditor/engine/diagnostics.js +327 -0
  21. package/dist/components/CodeEditor/engine/diff.d.ts +37 -0
  22. package/dist/components/CodeEditor/engine/diff.js +145 -0
  23. package/dist/components/CodeEditor/engine/folds.d.ts +25 -0
  24. package/dist/components/CodeEditor/engine/folds.js +458 -0
  25. package/dist/components/CodeEditor/engine/gutters.d.ts +22 -0
  26. package/dist/components/CodeEditor/engine/gutters.js +160 -0
  27. package/dist/components/CodeEditor/engine/index.d.ts +12 -0
  28. package/dist/components/CodeEditor/engine/index.js +387 -0
  29. package/dist/components/CodeEditor/engine/languages/http/index.d.ts +20 -0
  30. package/dist/components/CodeEditor/engine/languages/http/index.js +69 -0
  31. package/dist/components/CodeEditor/engine/languages/http/parser.d.ts +2 -0
  32. package/dist/components/CodeEditor/engine/languages/http/parser.js +31 -0
  33. package/dist/components/CodeEditor/engine/languages/http/parser.terms.d.ts +1 -0
  34. package/dist/components/CodeEditor/engine/languages/http/parser.terms.js +2 -0
  35. package/dist/components/CodeEditor/engine/languages/index.d.ts +8 -0
  36. package/dist/components/CodeEditor/engine/languages/index.js +41 -0
  37. package/dist/components/CodeEditor/engine/languages/json.d.ts +8 -0
  38. package/dist/components/CodeEditor/engine/languages/json.js +11 -0
  39. package/dist/components/CodeEditor/engine/languages/jsonPointers.d.ts +47 -0
  40. package/dist/components/CodeEditor/engine/languages/jsonPointers.js +125 -0
  41. package/dist/components/CodeEditor/engine/languages/yaml.d.ts +4 -0
  42. package/dist/components/CodeEditor/engine/languages/yaml.js +11 -0
  43. package/dist/components/CodeEditor/engine/lines.d.ts +22 -0
  44. package/dist/components/CodeEditor/engine/lines.js +131 -0
  45. package/dist/components/CodeEditor/engine/luaSyntax.d.ts +14 -0
  46. package/dist/components/CodeEditor/engine/luaSyntax.js +36 -0
  47. package/dist/components/CodeEditor/engine/positions.d.ts +19 -0
  48. package/dist/components/CodeEditor/engine/positions.js +22 -0
  49. package/dist/components/CodeEditor/engine/schema/complete.d.ts +12 -0
  50. package/dist/components/CodeEditor/engine/schema/complete.js +211 -0
  51. package/dist/components/CodeEditor/engine/schema/hover.d.ts +12 -0
  52. package/dist/components/CodeEditor/engine/schema/hover.js +73 -0
  53. package/dist/components/CodeEditor/engine/schema/loadSchema.d.ts +19 -0
  54. package/dist/components/CodeEditor/engine/schema/loadSchema.js +32 -0
  55. package/dist/components/CodeEditor/engine/schema/validate.d.ts +9 -0
  56. package/dist/components/CodeEditor/engine/schema/validate.js +67 -0
  57. package/dist/components/CodeEditor/engine/search.d.ts +13 -0
  58. package/dist/components/CodeEditor/engine/search.js +84 -0
  59. package/dist/components/CodeEditor/engine/searchMatches.d.ts +8 -0
  60. package/dist/components/CodeEditor/engine/searchMatches.js +15 -0
  61. package/dist/components/CodeEditor/engine/theme.d.ts +8 -0
  62. package/dist/components/CodeEditor/engine/theme.js +89 -0
  63. package/dist/components/CodeEditor/engine/types.d.ts +44 -0
  64. package/dist/components/CodeEditor/engine/types.js +0 -0
  65. package/dist/components/CodeEditor/hooks/useCodeEditor.d.ts +6 -0
  66. package/dist/components/CodeEditor/hooks/useCodeEditor.js +3 -0
  67. package/dist/components/CodeEditor/index.d.ts +6 -0
  68. package/dist/components/CodeEditor/index.js +5 -0
  69. package/dist/components/CodeEditor/lib/PortalOutlet.d.ts +11 -0
  70. package/dist/components/CodeEditor/lib/PortalOutlet.js +11 -0
  71. package/dist/components/CodeEditor/lib/httpCompletions.d.ts +7 -0
  72. package/dist/components/CodeEditor/lib/httpCompletions.js +102 -0
  73. package/dist/components/CodeEditor/lib/httpCompletionsData.d.ts +29 -0
  74. package/dist/components/CodeEditor/lib/httpCompletionsData.js +650 -0
  75. package/dist/components/CodeEditor/lib/keyboardHint.d.ts +5 -0
  76. package/dist/components/CodeEditor/lib/keyboardHint.js +2 -0
  77. package/dist/components/CodeEditor/lib/loadEngine.d.ts +7 -0
  78. package/dist/components/CodeEditor/lib/loadEngine.js +9 -0
  79. package/dist/components/CodeEditor/lib/portalRegistry.d.ts +20 -0
  80. package/dist/components/CodeEditor/lib/portalRegistry.js +47 -0
  81. package/dist/components/CodeEditor/lib/splitContentProps.d.ts +12 -0
  82. package/dist/components/CodeEditor/lib/splitContentProps.js +28 -0
  83. package/dist/components/CodeEditor/types.d.ts +72 -0
  84. package/dist/components/CodeEditor/types.js +0 -0
  85. package/dist/components/CodeSnippet/CodeSnippetCode.js +6 -23
  86. package/dist/components/CodeSnippet/CodeSnippetCopyButton.js +4 -3
  87. package/dist/components/CodeSnippet/CodeSnippetFrameContext.d.ts +25 -0
  88. package/dist/components/CodeSnippet/CodeSnippetFrameContext.js +3 -0
  89. package/dist/components/CodeSnippet/CodeSnippetFullscreenButton.js +2 -2
  90. package/dist/components/CodeSnippet/CodeSnippetRoot.d.ts +3 -5
  91. package/dist/components/CodeSnippet/CodeSnippetRoot.js +56 -50
  92. package/dist/components/CodeSnippet/CodeSnippetShowMoreButton.js +7 -5
  93. package/dist/components/CodeSnippet/CodeSnippetWrapButton.js +2 -2
  94. package/dist/components/CodeSnippet/adapters/highlightjs.js +1 -0
  95. package/dist/components/CodeSnippet/adapters/prism.js +3 -1
  96. package/dist/components/CodeSnippet/adapters/shiki.js +1 -0
  97. package/dist/components/CodeSnippet/adapters/types.d.ts +3 -3
  98. package/dist/components/CodeSnippet/classes.d.ts +3 -0
  99. package/dist/components/CodeSnippet/classes.js +14 -0
  100. package/dist/components/CodeSnippet/hooks/index.d.ts +1 -0
  101. package/dist/components/CodeSnippet/hooks/index.js +1 -0
  102. package/dist/components/CodeSnippet/hooks/useCodeSnippetFrame.d.ts +2 -0
  103. package/dist/components/CodeSnippet/hooks/useCodeSnippetFrame.js +8 -0
  104. package/dist/components/CodeSnippet/index.d.ts +2 -1
  105. package/dist/components/CodeSnippet/index.js +1 -1
  106. package/dist/components/CodeSnippet/internal/CodeSnippetFrame.d.ts +22 -0
  107. package/dist/components/CodeSnippet/internal/CodeSnippetFrame.js +81 -0
  108. package/dist/components/CodeSnippet/internal/CodeToken.d.ts +2 -1
  109. package/dist/components/CodeSnippet/internal/CodeToken.js +1 -1
  110. package/dist/components/CodeSnippet/internal/FoldSummary.d.ts +11 -0
  111. package/dist/components/CodeSnippet/internal/FoldSummary.js +27 -0
  112. package/dist/components/CodeSnippet/internal/FoldToggle.d.ts +2 -0
  113. package/dist/components/CodeSnippet/internal/FoldToggle.js +2 -1
  114. package/dist/components/CodeSnippet/internal/index.d.ts +1 -0
  115. package/dist/components/CodeSnippet/internal/index.js +1 -0
  116. package/dist/components/CodeSnippet/lib/foldUtils.d.ts +9 -2
  117. package/dist/components/CodeSnippet/lib/foldUtils.js +2 -2
  118. package/dist/components/CodeSnippet/lib/showMore.d.ts +7 -0
  119. package/dist/components/CodeSnippet/lib/showMore.js +7 -0
  120. package/dist/components/Copyable/Copyable.d.ts +5 -2
  121. package/dist/components/Copyable/Copyable.js +1 -1
  122. package/dist/metadata/components.json +1235 -5
  123. package/package.json +24 -1
@@ -6,6 +6,7 @@ export { CodeSnippetCode, type CodeSnippetCodeProps } from './CodeSnippetCode';
6
6
  export { CodeSnippetContent, type CodeSnippetContentProps } from './CodeSnippetContent';
7
7
  export { type CodeSnippetContextValue, type CodeSnippetSize, type LineColor, type LineConfig, type LineRange, type LineTextStyle, } from './CodeSnippetContext';
8
8
  export { CodeSnippetCopyButton, type CodeSnippetCopyButtonProps } from './CodeSnippetCopyButton';
9
+ export { type CodeSnippetFrameContextValue } from './CodeSnippetFrameContext';
9
10
  export { CodeSnippetFullscreenButton, type CodeSnippetFullscreenButtonProps, } from './CodeSnippetFullscreenButton';
10
11
  export { CodeSnippetHeader, type CodeSnippetHeaderProps } from './CodeSnippetHeader';
11
12
  export { CodeSnippetLineNumbers, type CodeSnippetLineNumbersProps } from './CodeSnippetLineNumbers';
@@ -15,7 +16,7 @@ export { CodeSnippetTab, type CodeSnippetTabProps } from './CodeSnippetTab';
15
16
  export { CodeSnippetTabs, type CodeSnippetTabsProps } from './CodeSnippetTabs';
16
17
  export { CodeSnippetTitle, type CodeSnippetTitleProps } from './CodeSnippetTitle';
17
18
  export { CodeSnippetWrapButton, type CodeSnippetWrapButtonProps } from './CodeSnippetWrapButton';
18
- export { useAdapter, useCodeSnippet } from './hooks';
19
+ export { useAdapter, useCodeSnippet, useCodeSnippetFrame } from './hooks';
19
20
  export { InlineCodeSnippet, type InlineCodeSnippetProps } from './InlineCodeSnippet';
20
21
  export { type FoldButtonProps, type FoldRegion } from './lib/foldUtils';
21
22
  export { getHttpFolds, HTTP_FOLD_ID, type HttpFoldOptions, type HttpFoldSectionOptions, } from './lib/httpFolds';
@@ -13,6 +13,6 @@ export { CodeSnippetTab } from "./CodeSnippetTab.js";
13
13
  export { CodeSnippetTabs } from "./CodeSnippetTabs.js";
14
14
  export { CodeSnippetTitle } from "./CodeSnippetTitle.js";
15
15
  export { CodeSnippetWrapButton } from "./CodeSnippetWrapButton.js";
16
- export { useAdapter, useCodeSnippet } from "./hooks/index.js";
16
+ export { useAdapter, useCodeSnippet, useCodeSnippetFrame } from "./hooks/index.js";
17
17
  export { InlineCodeSnippet } from "./InlineCodeSnippet.js";
18
18
  export { HTTP_FOLD_ID, getHttpFolds } from "./lib/httpFolds.js";
@@ -0,0 +1,22 @@
1
+ import type { FC, HTMLAttributes, ReactNode, Ref } from 'react';
2
+ export interface CodeSnippetFrameProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
3
+ ref?: Ref<HTMLDivElement>;
4
+ isFullscreen: boolean;
5
+ setIsFullscreen: (fullscreen: boolean) => void;
6
+ children: ReactNode;
7
+ }
8
+ /**
9
+ * Frame shell shared by CodeSnippetRoot and CodeEditorRoot.
10
+ *
11
+ * The root `<div>` (with every consumer prop, `className` and `ref`) is always
12
+ * rendered through `createPortal` into one persistent host element. Entering or
13
+ * leaving fullscreen only moves that host between an inline placeholder and
14
+ * `document.body`, so the subtree is never remounted (child state, focus
15
+ * targets, editor instances survive). Fullscreen classes are merged into the
16
+ * consumer `className`, not substituted.
17
+ *
18
+ * SSR: on the server (and during the hydration pass) the root renders inline
19
+ * inside the placeholder; the client switches to the portal right after
20
+ * hydration (a one-time remount at mount, never on fullscreen toggle).
21
+ */
22
+ export declare const CodeSnippetFrame: FC<CodeSnippetFrameProps>;
@@ -0,0 +1,81 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { cn } from "../../../utils/cn.js";
5
+ import { useTestId } from "../../../utils/testId.js";
6
+ const FULLSCREEN_CLASSES = 'fixed inset-16 z-50 m-0 w-auto h-auto min-w-0 min-h-0 max-w-[none] max-h-[none]';
7
+ const BACKDROP_CLASSES = 'fixed inset-0 z-40 backdrop-blur-xs bg-component-dialog-overlay';
8
+ const HOST_CLASSES = 'contents';
9
+ const noop = ()=>{};
10
+ const subscribeNoop = ()=>noop;
11
+ const getClientSnapshot = ()=>true;
12
+ const getServerSnapshot = ()=>false;
13
+ const createHost = ()=>{
14
+ if ("u" < typeof document) return null;
15
+ const host = document.createElement('div');
16
+ host.className = HOST_CLASSES;
17
+ return host;
18
+ };
19
+ const CodeSnippetFrame = ({ ref, isFullscreen, setIsFullscreen, className, children, ...props })=>{
20
+ const backdropTestId = useTestId('backdrop');
21
+ const placeholderRef = useRef(null);
22
+ const [host] = useState(createHost);
23
+ const canPortal = useSyncExternalStore(subscribeNoop, getClientSnapshot, getServerSnapshot);
24
+ const portalReady = canPortal && null !== host;
25
+ useLayoutEffect(()=>{
26
+ if (!host) return;
27
+ return ()=>host.remove();
28
+ }, [
29
+ host
30
+ ]);
31
+ useLayoutEffect(()=>{
32
+ if (!portalReady || !host) return;
33
+ const target = isFullscreen ? document.body : placeholderRef.current;
34
+ if (!target || host.parentNode === target) return;
35
+ const active = document.activeElement;
36
+ const refocus = active instanceof HTMLElement && host.contains(active) ? active : null;
37
+ target.appendChild(host);
38
+ if (refocus && !refocus.isSameNode(document.activeElement)) refocus.focus({
39
+ preventScroll: true
40
+ });
41
+ }, [
42
+ portalReady,
43
+ host,
44
+ isFullscreen
45
+ ]);
46
+ useEffect(()=>{
47
+ if (!isFullscreen) return;
48
+ const handleKeyDown = (event)=>{
49
+ if ('Escape' === event.key && !event.defaultPrevented) setIsFullscreen(false);
50
+ };
51
+ document.addEventListener('keydown', handleKeyDown);
52
+ return ()=>document.removeEventListener('keydown', handleKeyDown);
53
+ }, [
54
+ isFullscreen,
55
+ setIsFullscreen
56
+ ]);
57
+ const frame = /*#__PURE__*/ jsxs(Fragment, {
58
+ children: [
59
+ isFullscreen ? /*#__PURE__*/ jsx("div", {
60
+ "aria-hidden": "true",
61
+ "data-testid": backdropTestId,
62
+ className: BACKDROP_CLASSES,
63
+ onClick: ()=>setIsFullscreen(false)
64
+ }) : null,
65
+ /*#__PURE__*/ jsx("div", {
66
+ ...props,
67
+ ref: ref,
68
+ className: cn(className, isFullscreen && FULLSCREEN_CLASSES),
69
+ children: children
70
+ })
71
+ ]
72
+ });
73
+ return /*#__PURE__*/ jsx("div", {
74
+ ref: placeholderRef,
75
+ "data-slot": "code-snippet-frame",
76
+ className: HOST_CLASSES,
77
+ children: portalReady && host ? /*#__PURE__*/ createPortal(frame, host) : frame
78
+ });
79
+ };
80
+ CodeSnippetFrame.displayName = 'CodeSnippetFrame';
81
+ export { CodeSnippetFrame };
@@ -1,5 +1,6 @@
1
1
  import type { FC } from 'react';
2
- import type { Token } from '../adapters/types';
2
+ import type { Token, TokenType } from '../adapters/types';
3
+ export declare const TOKEN_CLASSES: Record<TokenType, string>;
3
4
  export type CodeTokenProps = {
4
5
  token: Token;
5
6
  colorClass?: string;
@@ -23,4 +23,4 @@ const CodeToken = ({ token, colorClass, rangeColorClass })=>/*#__PURE__*/ jsx("s
23
23
  className: rangeColorClass ?? colorClass ?? token.className ?? TOKEN_CLASSES[token.type],
24
24
  children: token.content
25
25
  });
26
- export { CodeToken };
26
+ export { CodeToken, TOKEN_CLASSES };
@@ -0,0 +1,11 @@
1
+ import type { FC } from 'react';
2
+ import type { FoldRegion } from '../lib/foldUtils';
3
+ export interface FoldSummaryProps {
4
+ fold: FoldRegion;
5
+ lineCount: number;
6
+ onToggle: () => void;
7
+ /** Default `data-testid`; `fold.summaryProps['data-testid']` still wins. */
8
+ testId?: string;
9
+ }
10
+ /** Collapsed-fold summary button. Shared by CodeSnippetCode and the CodeEditor fold widget. */
11
+ export declare const FoldSummary: FC<FoldSummaryProps>;
@@ -0,0 +1,27 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../../utils/cn.js";
3
+ import { getFoldSummaryLabel } from "../lib/foldUtils.js";
4
+ const FoldSummary = ({ fold, lineCount, onToggle, testId })=>{
5
+ const label = getFoldSummaryLabel(fold, lineCount);
6
+ const { className, onClick, ...summaryProps } = fold.summaryProps ?? {};
7
+ const handleClick = (event)=>{
8
+ onToggle();
9
+ onClick?.(event);
10
+ };
11
+ return /*#__PURE__*/ jsx("button", {
12
+ type: "button",
13
+ className: cn('inline-flex items-center cursor-pointer select-none', className),
14
+ "aria-expanded": false,
15
+ "aria-label": `Collapsed region: ${label}, ${lineCount} lines`,
16
+ "data-slot": "code-snippet-fold-summary",
17
+ "data-testid": testId,
18
+ ...summaryProps,
19
+ onClick: handleClick,
20
+ children: /*#__PURE__*/ jsx("span", {
21
+ className: "inline-flex items-center italic text-text-secondary hover:text-text-primary transition-colors",
22
+ children: label
23
+ })
24
+ });
25
+ };
26
+ FoldSummary.displayName = 'FoldSummary';
27
+ export { FoldSummary };
@@ -4,4 +4,6 @@ export declare const FoldToggle: FC<{
4
4
  fold: FoldRegion;
5
5
  isCollapsed: boolean;
6
6
  onToggle: () => void;
7
+ /** Default `data-testid`; `fold.toggleProps['data-testid']` still wins. */
8
+ testId?: string;
7
9
  }>;
@@ -3,7 +3,7 @@ import { ChevronDown } from "../../../icons/ChevronDown.js";
3
3
  import { ChevronRight } from "../../../icons/ChevronRight.js";
4
4
  import { cn } from "../../../utils/cn.js";
5
5
  import { getFoldSummaryLabel } from "../lib/foldUtils.js";
6
- const FoldToggle = ({ fold, isCollapsed, onToggle })=>{
6
+ const FoldToggle = ({ fold, isCollapsed, onToggle, testId })=>{
7
7
  const lineCount = fold.endLine - fold.startLine + 1;
8
8
  const label = getFoldSummaryLabel(fold, lineCount);
9
9
  const ariaLabel = isCollapsed ? `Expand ${label}` : `Collapse ${label}`;
@@ -17,6 +17,7 @@ const FoldToggle = ({ fold, isCollapsed, onToggle })=>{
17
17
  className: cn('flex items-center justify-center w-16 h-16 rounded-2 text-text-secondary hover:text-text-primary hover:bg-bg-secondary-hover transition-colors cursor-pointer', className),
18
18
  "aria-expanded": !isCollapsed,
19
19
  "aria-label": ariaLabel,
20
+ "data-testid": testId,
20
21
  ...toggleProps,
21
22
  onClick: handleClick,
22
23
  children: isCollapsed ? /*#__PURE__*/ jsx(ChevronRight, {}) : /*#__PURE__*/ jsx(ChevronDown, {})
@@ -2,5 +2,6 @@ export { CodeContent, type CodeContentProps } from './CodeContent';
2
2
  export { CodeLine, type CodeLineProps } from './CodeLine';
3
3
  export { CodeToken, type CodeTokenProps } from './CodeToken';
4
4
  export { ColorStickColumn } from './ColorStickColumn';
5
+ export { FoldSummary, type FoldSummaryProps } from './FoldSummary';
5
6
  export { PrefixColumn } from './PrefixColumn';
6
7
  export { TokenizedCodeLine, type TokenizedCodeLineProps } from './TokenizedCodeLine';
@@ -2,5 +2,6 @@ export { CodeContent } from "./CodeContent.js";
2
2
  export { CodeLine } from "./CodeLine.js";
3
3
  export { CodeToken } from "./CodeToken.js";
4
4
  export { ColorStickColumn } from "./ColorStickColumn.js";
5
+ export { FoldSummary } from "./FoldSummary.js";
5
6
  export { PrefixColumn } from "./PrefixColumn.js";
6
7
  export { TokenizedCodeLine } from "./TokenizedCodeLine.js";
@@ -1,5 +1,8 @@
1
1
  import type { ButtonHTMLAttributes } from 'react';
2
- export type FoldButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'>;
2
+ export type FoldButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'> & {
3
+ /** Hyphenated `data-*` attributes (e.g. `data-analytics-id`) are not part of the DOM typings. */
4
+ [dataAttribute: `data-${string}`]: string | number | boolean | undefined;
5
+ };
3
6
  export type FoldRegion = {
4
7
  /** Unique identifier for this fold region */
5
8
  id: string;
@@ -26,9 +29,13 @@ export type DisplayItem = {
26
29
  lineCount: number;
27
30
  };
28
31
  export declare function getFoldSummaryLabel(fold: FoldRegion, lineCount: number): string;
32
+ export type ValidateFoldsOptions = {
33
+ /** Log dev warnings for skipped folds. Default: true */
34
+ warn?: boolean;
35
+ };
29
36
  /**
30
37
  * Validates fold regions and returns a clean, sorted list.
31
38
  * Dev: logs warnings for invalid folds. Prod: silently filters them out.
32
39
  */
33
- export declare function validateFolds(folds: FoldRegion[], totalLines: number, startingLineNumber?: number): FoldRegion[];
40
+ export declare function validateFolds(folds: readonly FoldRegion[], totalLines: number, startingLineNumber?: number, options?: ValidateFoldsOptions): FoldRegion[];
34
41
  export declare function buildDisplayItems(totalLines: number, folds: FoldRegion[], collapsedFolds: Set<string>, startingLineNumber: number): DisplayItem[];
@@ -1,8 +1,8 @@
1
1
  function getFoldSummaryLabel(fold, lineCount) {
2
2
  return fold.label ?? `${lineCount} lines`;
3
3
  }
4
- function validateFolds(folds, totalLines, startingLineNumber = 1) {
5
- const isDev = 'production' !== process.env.NODE_ENV;
4
+ function validateFolds(folds, totalLines, startingLineNumber = 1, options) {
5
+ const isDev = options?.warn !== false && 'production' !== process.env.NODE_ENV;
6
6
  const valid = [];
7
7
  const seenIds = new Set();
8
8
  const lastLine = startingLineNumber + totalLines - 1;
@@ -0,0 +1,7 @@
1
+ import { type ReactNode } from 'react';
2
+ /** True when a direct child is a `CodeSnippetShowMoreButton` (root then skips the auto-rendered one). */
3
+ export declare const hasExplicitShowMoreButton: (children: ReactNode) => boolean;
4
+ /** Rows beyond `maxLines`, independent of the expanded state. 0 when `maxLines <= 0`. */
5
+ export declare const getHiddenLineCount: (totalRows: number, maxLines: number) => number;
6
+ /** Whether content is currently clipped to `maxLines`. */
7
+ export declare const isClamped: (hiddenLineCount: number, isExpanded: boolean) => boolean;
@@ -0,0 +1,7 @@
1
+ import { Children, isValidElement } from "react";
2
+ import { MIN_HIDDEN_LINES_THRESHOLD } from "../CodeSnippetContext.js";
3
+ const SHOW_MORE_BUTTON_DISPLAY_NAME = 'CodeSnippetShowMoreButton';
4
+ const hasExplicitShowMoreButton = (children)=>Children.toArray(children).some((child)=>isValidElement(child) && 'string' != typeof child.type && child.type.displayName === SHOW_MORE_BUTTON_DISPLAY_NAME);
5
+ const getHiddenLineCount = (totalRows, maxLines)=>maxLines > 0 ? Math.max(0, totalRows - maxLines) : 0;
6
+ const isClamped = (hiddenLineCount, isExpanded)=>hiddenLineCount >= MIN_HIDDEN_LINES_THRESHOLD && !isExpanded;
7
+ export { getHiddenLineCount, hasExplicitShowMoreButton, isClamped };
@@ -1,7 +1,10 @@
1
1
  import { type FC, type ReactNode } from 'react';
2
2
  export interface CopyableProps {
3
- /** The text to copy to the clipboard. */
4
- text: string;
3
+ /**
4
+ * The text to copy to the clipboard. Pass a function to read the text
5
+ * lazily at click time (e.g. the live document of an editor).
6
+ */
7
+ text: string | (() => string);
5
8
  /**
6
9
  * Show a tooltip with copy feedback.
7
10
  *
@@ -11,7 +11,7 @@ const Copyable = ({ text, tooltip, onCopied, resetDelay = 2000, children })=>{
11
11
  const keepOpenTimerRef = useRef(void 0);
12
12
  const tooltipOpen = hovering || keepOpen;
13
13
  const handleClick = useCallback((_event)=>{
14
- copy(text);
14
+ copy('function' == typeof text ? text() : text);
15
15
  onCopied?.();
16
16
  if (tooltip) {
17
17
  setKeepOpen(true);