@pindoba/core-code 0.0.0-alpha-20260829223243 → 0.0.0-alpha-20261008173743
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/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/src/connect-code.d.ts +19 -2
- package/dist/src/connect-code.d.ts.map +1 -1
- package/dist/src/connect-code.js +156 -6
- package/dist/src/connect-code.js.map +1 -1
- package/dist/src/types.d.ts +87 -5
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +9 -7
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { CodeApi, CodeBaseProps, CodeFeedback, CodeLine, CodeLineItem, CodePassThrough, CodeSize, CodeSlotPassThrough, CodeSlots, CodeToken, CodeTokenItem, ConnectCodeOptions, ElementAttributes, PanelElement, PanelRootProps } from "./src/types.js";
|
|
2
|
-
import { codeDefaults, connectCode } from "./src/connect-code.js";
|
|
3
|
-
export { type CodeApi, type CodeBaseProps, type CodeFeedback, type CodeLine, type CodeLineItem, type CodePassThrough, type CodeSize, type CodeSlotPassThrough, type CodeSlots, type CodeToken, type CodeTokenItem, type ConnectCodeOptions, type ElementAttributes, type PanelElement, type PanelRootProps, codeDefaults, connectCode };
|
|
1
|
+
import { CodeApi, CodeBaseProps, CodeCardChrome, CodeCardDefaults, CodeCardFrameNodes, CodeCardProps, CodeFeedback, CodeLine, CodeLineItem, CodePassThrough, CodeResolvedCardFrame, CodeSize, CodeSlotPassThrough, CodeSlots, CodeToken, CodeTokenItem, ConnectCodeOptions, ElementAttributes, PanelElement, PanelRootProps } from "./src/types.js";
|
|
2
|
+
import { codeDefaults, connectCode, resolveCodeCardFrame } from "./src/connect-code.js";
|
|
3
|
+
export { type CodeApi, type CodeBaseProps, type CodeCardChrome, type CodeCardDefaults, type CodeCardFrameNodes, type CodeCardProps, type CodeFeedback, type CodeLine, type CodeLineItem, type CodePassThrough, type CodeResolvedCardFrame, type CodeSize, type CodeSlotPassThrough, type CodeSlots, type CodeToken, type CodeTokenItem, type ConnectCodeOptions, type ElementAttributes, type PanelElement, type PanelRootProps, codeDefaults, connectCode, resolveCodeCardFrame };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { codeDefaults, connectCode } from "./src/connect-code.js";
|
|
2
|
-
export { codeDefaults, connectCode };
|
|
1
|
+
import { codeDefaults, connectCode, resolveCodeCardFrame } from "./src/connect-code.js";
|
|
2
|
+
export { codeDefaults, connectCode, resolveCodeCardFrame };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { CodeApi, ConnectCodeOptions } from "./types.js";
|
|
1
|
+
import { CodeApi, CodeCardChrome, CodeCardFrameNodes, CodeResolvedCardFrame, ConnectCodeOptions } from "./types.js";
|
|
2
|
+
import { CardFrameProps } from "@pindoba/core-card";
|
|
2
3
|
//#region src/connect-code.d.ts
|
|
3
4
|
declare const codeDefaults: {
|
|
4
5
|
readonly size: "sm";
|
|
@@ -27,6 +28,22 @@ declare const codeDefaults: {
|
|
|
27
28
|
* rather than empty.
|
|
28
29
|
*/
|
|
29
30
|
declare function connectCode(options?: ConnectCodeOptions): CodeApi;
|
|
31
|
+
/**
|
|
32
|
+
* Resolve a framed block's Card: the consumer's `card` prop over the block's
|
|
33
|
+
* own defaults (`api.cardChrome`), with the framework's chrome appended AFTER
|
|
34
|
+
* the consumer's slots — the copy button into the header's trailing slot, the
|
|
35
|
+
* expand button into the footer's trailing slot. The same call in all four
|
|
36
|
+
* frameworks; they differ only in their slot type (Svelte snippets, React /
|
|
37
|
+
* Vue nodes; Astro fills `chrome-*` slots and passes none).
|
|
38
|
+
*
|
|
39
|
+
* - `card.heading` / `card.eyebrow` win over `title` / `lang`.
|
|
40
|
+
* - `card.content` merges over the block's `padding: "none"` default, so
|
|
41
|
+
* `{ contentBackground }` keeps the code edge to edge on an inset panel.
|
|
42
|
+
* - `card.passThrough` merges over `passThrough.card` and the frame styles.
|
|
43
|
+
* - `data-card-kind` (root) and the clamp markers (content) are re-applied
|
|
44
|
+
* last: nothing overrides them.
|
|
45
|
+
*/
|
|
46
|
+
declare function resolveCodeCardFrame<TSlot>(card: CardFrameProps<TSlot> | false | undefined, chrome: CodeCardChrome, nodes?: CodeCardFrameNodes<TSlot>): CodeResolvedCardFrame<TSlot>;
|
|
30
47
|
//#endregion
|
|
31
|
-
export { codeDefaults, connectCode };
|
|
48
|
+
export { codeDefaults, connectCode, resolveCodeCardFrame };
|
|
32
49
|
//# sourceMappingURL=connect-code.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect-code.d.ts","names":[],"sources":["../../src/connect-code.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"connect-code.d.ts","names":[],"sources":["../../src/connect-code.ts"],"mappings":";;;cAwBa;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyDG,YAAY,UAAS,qBAA0B;;;;;;;;;;;;;;;;iBAmZ/C,qBAAqB,OACnC,MAAM,eAAe,4BACrB,QAAQ,gBACR,QAAO,mBAAmB,SACzB,sBAAsB"}
|
package/dist/src/connect-code.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { css, cx } from "@pindoba/styled-system/css";
|
|
2
2
|
import { connectPanel } from "@pindoba/core-panel";
|
|
3
|
+
import { resolveCardContentSurface, resolveCardFrame } from "@pindoba/core-card";
|
|
3
4
|
import { defineConnect } from "@pindoba/normalize-props";
|
|
4
5
|
import { codeStyles } from "@pindoba/styles-code";
|
|
5
6
|
//#region src/connect-code.ts
|
|
@@ -42,15 +43,27 @@ function sourceFromLines(lines) {
|
|
|
42
43
|
* rather than empty.
|
|
43
44
|
*/
|
|
44
45
|
function connectCode(options = {}) {
|
|
45
|
-
const { lines, code = "", lang, size = codeDefaults.size, feedback = codeDefaults.feedback, wrap = codeDefaults.wrap, showLineNumbers = codeDefaults.showLineNumbers, startLine = codeDefaults.startLine, highlightLines, maxLines, collapsible = codeDefaults.collapsible, expanded = codeDefaults.expanded, copyable = codeDefaults.copyable, copied = codeDefaults.copied, label = codeDefaults.label, as = "div", background = codeDefaults.background, emphasis = codeDefaults.emphasis, translucent, padding = codeDefaults.padding, radius = codeDefaults.radius, radiusTop, radiusBottom, radiusLeft, radiusRight, border = codeDefaults.border, borderInteract, borderActive, reserveBorderSpace, shadow = codeDefaults.shadow, interactive, active, activeEmphasis, reactive, passThrough, class: className, ...rest } = options;
|
|
46
|
+
const { lines, code = "", lang, size = codeDefaults.size, feedback = codeDefaults.feedback, wrap = codeDefaults.wrap, showLineNumbers = codeDefaults.showLineNumbers, startLine = codeDefaults.startLine, highlightLines, maxLines, collapsible = codeDefaults.collapsible, expanded = codeDefaults.expanded, copyable = codeDefaults.copyable, copied = codeDefaults.copied, label = codeDefaults.label, title, card, as = "div", background = codeDefaults.background, emphasis = codeDefaults.emphasis, translucent, padding = codeDefaults.padding, radius = codeDefaults.radius, radiusTop, radiusBottom, radiusLeft, radiusRight, border = codeDefaults.border, borderInteract, borderActive, reserveBorderSpace, shadow = codeDefaults.shadow, interactive, active, activeEmphasis, reactive, passThrough, class: className, ...rest } = options;
|
|
46
47
|
const resolvedLines = lines ?? (code ? linesFromSource(code) : []);
|
|
47
48
|
const lineCount = resolvedLines.length;
|
|
48
49
|
const overflowable = maxLines != null && maxLines > 0 && lineCount > maxLines;
|
|
49
50
|
const clamped = overflowable && !expanded;
|
|
51
|
+
const framed = card != null && card !== false;
|
|
52
|
+
const frameInput = framed ? card : {};
|
|
53
|
+
const cardContent = {
|
|
54
|
+
padding: "none",
|
|
55
|
+
...frameInput.content
|
|
56
|
+
};
|
|
57
|
+
const { inset, surface: contentSurface } = resolveCardContentSurface(cardContent, frameInput.contentBackground);
|
|
58
|
+
const surfaceBackground = inset ? contentSurface.background : frameInput.background ?? background;
|
|
50
59
|
const classes = codeStyles.raw({
|
|
51
60
|
size,
|
|
52
61
|
wrap,
|
|
53
|
-
showLineNumbers
|
|
62
|
+
showLineNumbers,
|
|
63
|
+
...framed ? {
|
|
64
|
+
framed: true,
|
|
65
|
+
fadeSurface: surfaceBackground
|
|
66
|
+
} : null
|
|
54
67
|
});
|
|
55
68
|
const highlighted = new Set(highlightLines ?? []);
|
|
56
69
|
const items = resolvedLines.map((line, index) => {
|
|
@@ -85,7 +98,7 @@ function connectCode(options = {}) {
|
|
|
85
98
|
};
|
|
86
99
|
});
|
|
87
100
|
const copyText = lines ? sourceFromLines(lines) : code;
|
|
88
|
-
const showToolbar = Boolean(lang) || copyable;
|
|
101
|
+
const showToolbar = Boolean(lang) || copyable || Boolean(title);
|
|
89
102
|
const showExpand = Boolean(collapsible && overflowable);
|
|
90
103
|
const panelApi = connectPanel({
|
|
91
104
|
as,
|
|
@@ -123,6 +136,52 @@ function connectCode(options = {}) {
|
|
|
123
136
|
class: className,
|
|
124
137
|
...rest
|
|
125
138
|
});
|
|
139
|
+
const rootId = "id" in rest ? rest.id : void 0;
|
|
140
|
+
const cardPassThrough = passThrough?.card ?? {};
|
|
141
|
+
const invariantContentProps = {
|
|
142
|
+
"data-code-body": "",
|
|
143
|
+
"data-lang": lang ?? "",
|
|
144
|
+
"data-clamped": clamped ? "true" : "false",
|
|
145
|
+
...maxLines != null ? { style: `--code-max-lines:${maxLines}` } : {}
|
|
146
|
+
};
|
|
147
|
+
const cardDefaults = {
|
|
148
|
+
size,
|
|
149
|
+
background,
|
|
150
|
+
feedback,
|
|
151
|
+
emphasis,
|
|
152
|
+
...translucent !== void 0 ? { translucent } : null,
|
|
153
|
+
radius,
|
|
154
|
+
border,
|
|
155
|
+
shadow,
|
|
156
|
+
...inset ? null : { divided: true },
|
|
157
|
+
content: { padding: "none" }
|
|
158
|
+
};
|
|
159
|
+
const cardChrome = {
|
|
160
|
+
heading: title || void 0,
|
|
161
|
+
eyebrow: lang || void 0,
|
|
162
|
+
headingId: typeof rootId === "string" && rootId !== "" ? `${rootId}-heading` : void 0,
|
|
163
|
+
defaults: cardDefaults,
|
|
164
|
+
rootProps: {
|
|
165
|
+
"data-card-flushable": "",
|
|
166
|
+
...rest,
|
|
167
|
+
...passThrough?.root?.props
|
|
168
|
+
},
|
|
169
|
+
invariantRootProps: { "data-card-kind": "code" },
|
|
170
|
+
invariantContentProps,
|
|
171
|
+
passThrough: {
|
|
172
|
+
...cardPassThrough,
|
|
173
|
+
...passThrough?.root?.style || cardPassThrough.root ? { root: {
|
|
174
|
+
...cardPassThrough.root,
|
|
175
|
+
style: css.raw(passThrough?.root?.style, cardPassThrough.root?.style)
|
|
176
|
+
} } : null,
|
|
177
|
+
content: {
|
|
178
|
+
...cardPassThrough.content,
|
|
179
|
+
style: css.raw(classes.frameContent, cardPassThrough.content?.style)
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
class: className != null ? String(className) : void 0
|
|
183
|
+
};
|
|
184
|
+
const { card: _cardPassThrough, ...slotPassThrough } = passThrough ?? {};
|
|
126
185
|
return {
|
|
127
186
|
...defineConnect({
|
|
128
187
|
slots: {
|
|
@@ -131,6 +190,10 @@ function connectCode(options = {}) {
|
|
|
131
190
|
"data-code-toolbar": "",
|
|
132
191
|
class: css(classes.toolbar, passThrough?.toolbar?.style)
|
|
133
192
|
},
|
|
193
|
+
title: {
|
|
194
|
+
"data-code-title": "",
|
|
195
|
+
class: css(classes.title, passThrough?.title?.style)
|
|
196
|
+
},
|
|
134
197
|
language: {
|
|
135
198
|
"data-code-language": "",
|
|
136
199
|
class: css(classes.language, passThrough?.language?.style)
|
|
@@ -177,13 +240,16 @@ function connectCode(options = {}) {
|
|
|
177
240
|
size: "xs",
|
|
178
241
|
"aria-expanded": expanded ? "true" : "false",
|
|
179
242
|
class: css(classes.expandButton, passThrough?.expandButton?.style)
|
|
180
|
-
}
|
|
243
|
+
},
|
|
244
|
+
frameContent: { class: css(classes.frameContent) }
|
|
181
245
|
},
|
|
182
246
|
passThrough: {
|
|
183
|
-
...
|
|
247
|
+
...slotPassThrough,
|
|
184
248
|
root: void 0
|
|
185
249
|
}
|
|
186
250
|
}),
|
|
251
|
+
frame: framed ? "card" : "bare",
|
|
252
|
+
cardChrome,
|
|
187
253
|
rootProps: panelApi.rootProps,
|
|
188
254
|
element: panelApi.element,
|
|
189
255
|
items,
|
|
@@ -194,7 +260,91 @@ function connectCode(options = {}) {
|
|
|
194
260
|
lineCount
|
|
195
261
|
};
|
|
196
262
|
}
|
|
263
|
+
/** Merge one card slot's passThrough: `over` wins (styles merged, props spread). */
|
|
264
|
+
function mergeCardSlot(base, over) {
|
|
265
|
+
if (!base) return over;
|
|
266
|
+
if (!over) return base;
|
|
267
|
+
return {
|
|
268
|
+
style: css.raw(base.style, over.style),
|
|
269
|
+
props: {
|
|
270
|
+
...base.props,
|
|
271
|
+
...over.props
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function slotOf(bag, key) {
|
|
276
|
+
if (!bag) return void 0;
|
|
277
|
+
const entry = Reflect.get(bag, key);
|
|
278
|
+
return typeof entry === "object" && entry !== null ? entry : void 0;
|
|
279
|
+
}
|
|
280
|
+
/** Merge two card passThrough bags slot by slot (`over` wins). */
|
|
281
|
+
function mergeCardPassThrough(base, over) {
|
|
282
|
+
const merged = {};
|
|
283
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(base), ...Object.keys(over ?? {})]);
|
|
284
|
+
for (const key of keys) merged[key] = mergeCardSlot(slotOf(base, key), slotOf(over, key));
|
|
285
|
+
return merged;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Resolve a framed block's Card: the consumer's `card` prop over the block's
|
|
289
|
+
* own defaults (`api.cardChrome`), with the framework's chrome appended AFTER
|
|
290
|
+
* the consumer's slots — the copy button into the header's trailing slot, the
|
|
291
|
+
* expand button into the footer's trailing slot. The same call in all four
|
|
292
|
+
* frameworks; they differ only in their slot type (Svelte snippets, React /
|
|
293
|
+
* Vue nodes; Astro fills `chrome-*` slots and passes none).
|
|
294
|
+
*
|
|
295
|
+
* - `card.heading` / `card.eyebrow` win over `title` / `lang`.
|
|
296
|
+
* - `card.content` merges over the block's `padding: "none"` default, so
|
|
297
|
+
* `{ contentBackground }` keeps the code edge to edge on an inset panel.
|
|
298
|
+
* - `card.passThrough` merges over `passThrough.card` and the frame styles.
|
|
299
|
+
* - `data-card-kind` (root) and the clamp markers (content) are re-applied
|
|
300
|
+
* last: nothing overrides them.
|
|
301
|
+
*/
|
|
302
|
+
function resolveCodeCardFrame(card, chrome, nodes = {}) {
|
|
303
|
+
const frame = card || {};
|
|
304
|
+
const eyebrow = frame.eyebrow ?? chrome.eyebrow;
|
|
305
|
+
const resolved = resolveCardFrame({
|
|
306
|
+
...frame,
|
|
307
|
+
...eyebrow !== void 0 ? { eyebrow } : null,
|
|
308
|
+
content: {
|
|
309
|
+
...chrome.defaults.content,
|
|
310
|
+
...frame.content
|
|
311
|
+
},
|
|
312
|
+
passThrough: mergeCardPassThrough(chrome.passThrough, frame.passThrough)
|
|
313
|
+
}, {
|
|
314
|
+
heading: chrome.heading,
|
|
315
|
+
headingId: chrome.headingId,
|
|
316
|
+
defaults: chrome.defaults,
|
|
317
|
+
rootProps: chrome.rootProps,
|
|
318
|
+
trailing: nodes.copy,
|
|
319
|
+
footerTrailing: nodes.expand
|
|
320
|
+
});
|
|
321
|
+
const passThrough = resolved.cardProps.passThrough;
|
|
322
|
+
return {
|
|
323
|
+
...resolved,
|
|
324
|
+
cardProps: {
|
|
325
|
+
...resolved.cardProps,
|
|
326
|
+
passThrough: {
|
|
327
|
+
...passThrough,
|
|
328
|
+
root: {
|
|
329
|
+
...passThrough.root,
|
|
330
|
+
props: {
|
|
331
|
+
...passThrough.root?.props,
|
|
332
|
+
...chrome.invariantRootProps
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
content: {
|
|
336
|
+
...passThrough.content,
|
|
337
|
+
props: {
|
|
338
|
+
...passThrough.content?.props,
|
|
339
|
+
...chrome.invariantContentProps
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
...chrome.class !== void 0 ? { class: chrome.class } : null
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
197
347
|
//#endregion
|
|
198
|
-
export { codeDefaults, connectCode };
|
|
348
|
+
export { codeDefaults, connectCode, resolveCodeCardFrame };
|
|
199
349
|
|
|
200
350
|
//# sourceMappingURL=connect-code.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect-code.js","names":[],"sources":["../../src/connect-code.ts"],"sourcesContent":["import { css, cx } from \"@pindoba/styled-system/css\";\nimport { connectPanel } from \"@pindoba/core-panel\";\nimport { defineConnect } from \"@pindoba/normalize-props\";\nimport { codeStyles } from \"@pindoba/styles-code\";\nimport type {\n CodeApi,\n CodeBaseProps,\n CodeLine,\n CodeLineItem,\n CodeToken,\n ConnectCodeOptions,\n} from \"./types.js\";\n\nexport const codeDefaults = {\n size: \"sm\",\n feedback: \"neutral\",\n wrap: false,\n showLineNumbers: false,\n startLine: 1,\n collapsible: false,\n expanded: false,\n copyable: false,\n copied: false,\n label: \"Code block\",\n // --- Panel surface defaults ---\n // The root is a Panel; these reproduce the surface the recipe used to paint\n // by hand (`colorPalette.surface.hill` + a 1px muted border + an `sm`\n // corner). `padding: \"none\"` because the block's inset lives on the toolbar /\n // scroller, not the root — so no `--panel-out-padding` republish is needed.\n emphasis: \"secondary\",\n background: \"surface.hill\",\n padding: \"none\",\n radius: \"sm\",\n border: \"muted\",\n shadow: \"none\",\n} as const satisfies Partial<CodeBaseProps>;\n\n/** Split raw source into single-token lines — the unhighlighted fallback. */\nfunction linesFromSource(code: string): CodeLine[] {\n // A trailing newline is a line terminator, not an empty final line; keeping\n // it would render a stray blank row under every file.\n const body = code.endsWith(\"\\n\") ? code.slice(0, -1) : code;\n return body.split(\"\\n\").map((text) => ({ tokens: [{ text }] }));\n}\n\n/** A token's per-instance theme styling, as an inline CSS string. */\nfunction tokenStyle(token: CodeToken): string {\n return [\n token.color != null ? `color:${token.color}` : \"\",\n token.fontStyle != null ? `font-style:${token.fontStyle}` : \"\",\n ]\n .filter(Boolean)\n .join(\";\");\n}\n\n/** Reconstruct the plain text of tokenized lines, for the clipboard. */\nfunction sourceFromLines(lines: CodeLine[]): string {\n return lines\n .map((line) => line.tokens.map((t) => t.text).join(\"\"))\n .join(\"\\n\");\n}\n\n/**\n * Connect Contract v1.1 — the `Code` bags.\n *\n * Highlighting is somebody else's job: this takes already-tokenized `lines` and\n * turns them into spreadable bags. With no `lines` it falls back to rendering\n * `code` as plain text, so a block without a highlighter is still readable\n * rather than empty.\n */\nexport function connectCode(options: ConnectCodeOptions = {}): CodeApi {\n const {\n lines,\n code = \"\",\n lang,\n size = codeDefaults.size,\n feedback = codeDefaults.feedback,\n wrap = codeDefaults.wrap,\n showLineNumbers = codeDefaults.showLineNumbers,\n startLine = codeDefaults.startLine,\n highlightLines,\n maxLines,\n collapsible = codeDefaults.collapsible,\n expanded = codeDefaults.expanded,\n copyable = codeDefaults.copyable,\n copied = codeDefaults.copied,\n label = codeDefaults.label,\n // --- Panel surface axes (delegated to connectPanel) ---\n as = \"div\",\n background = codeDefaults.background,\n emphasis = codeDefaults.emphasis,\n translucent,\n padding = codeDefaults.padding,\n radius = codeDefaults.radius,\n radiusTop,\n radiusBottom,\n radiusLeft,\n radiusRight,\n border = codeDefaults.border,\n borderInteract,\n borderActive,\n reserveBorderSpace,\n shadow = codeDefaults.shadow,\n interactive,\n active,\n activeEmphasis,\n reactive,\n passThrough,\n class: className,\n ...rest\n } = options;\n\n const resolvedLines: CodeLine[] =\n lines ?? (code ? linesFromSource(code) : []);\n const lineCount = resolvedLines.length;\n\n // Clamp only when there is genuinely more than fits — a `maxLines` larger\n // than the content must not paint a fade over nothing.\n const overflowable = maxLines != null && maxLines > 0 && lineCount > maxLines;\n const clamped = overflowable && !expanded;\n\n const classes = codeStyles.raw({\n size,\n wrap,\n showLineNumbers,\n });\n const highlighted = new Set(highlightLines ?? []);\n\n const items: CodeLineItem[] = resolvedLines.map((line, index) => {\n const number = startLine + index;\n const isHighlighted = highlighted.has(number);\n return {\n id: `line-${number}`,\n number,\n marker: line.marker,\n lineProps: {\n \"data-line\": String(number),\n \"data-highlighted\": isHighlighted ? \"true\" : \"false\",\n class: css(classes.line, passThrough?.line?.style),\n },\n lineNumberProps: {\n // The number is decoration duplicated by `data-line`; announcing it\n // before every line would bury the code itself.\n \"aria-hidden\": \"true\",\n class: css(classes.lineNumber, passThrough?.lineNumber?.style),\n },\n lineContentProps: {\n class: css(classes.lineContent, passThrough?.lineContent?.style),\n },\n ...(line.marker != null\n ? {\n markerProps: {\n \"aria-hidden\": \"true\",\n class: css(classes.marker, passThrough?.marker?.style),\n },\n }\n : {}),\n tokens: line.tokens.map((token, tokenIndex) => ({\n id: `line-${number}-token-${tokenIndex}`,\n text: token.text,\n tokenProps: {\n // Theme colour arrives per token and is inherently per-instance, so\n // it stays an inline style (which the contract allowlists) rather\n // than becoming an unbounded set of generated classes.\n //\n // A **string**, not an object: that is what connect bags emit\n // (`reactProps` converts it for React; Vue accepts either), and\n // Svelte drops most properties of a spread style object.\n ...(tokenStyle(token) ? { style: tokenStyle(token) } : {}),\n class: cx(\n css(classes.token, passThrough?.token?.style),\n token.className,\n ),\n },\n })),\n };\n });\n\n const copyText = lines ? sourceFromLines(lines) : code;\n const showToolbar = Boolean(lang) || copyable;\n const showExpand = Boolean(collapsible && overflowable);\n\n // The root's surface (background / border / corner) belongs to Panel; the\n // recipe keeps only layout + typography and rides the `inheritedStyle`\n // channel, so the compose order stays panel recipe → code recipe → consumer\n // `passThrough.root.style` → literal `class`. `feedback` reaches the recipe's\n // `colorPalette.*` reads through the panel's own feedback variant.\n const panelApi = connectPanel({\n as,\n dataComponent: \"code\",\n background,\n emphasis,\n feedback,\n translucent,\n padding,\n radius,\n radiusTop,\n radiusBottom,\n radiusLeft,\n radiusRight,\n border,\n borderInteract,\n borderActive,\n reserveBorderSpace,\n shadow,\n interactive,\n active,\n activeEmphasis,\n reactive,\n inheritedStyle: classes.root,\n passThrough: {\n root: {\n style: passThrough?.root?.style,\n props: {\n // The consumer's overrides go FIRST so everything below stays an\n // invariant, exactly as when these were baked after the rest spread:\n // the Astro boot script keys its copy/expand wiring off\n // `data-component=\"code\"` + `data-clamped`, and the recipe reads the\n // clamp height from the inline `--code-max-lines`. Extra root styling\n // belongs on `passThrough.root.style` (the Panda channel), which is\n // merged into the class rather than fighting this attribute.\n ...passThrough?.root?.props,\n \"data-component\": \"code\",\n \"data-lang\": lang ?? \"\",\n \"data-clamped\": clamped ? \"true\" : \"false\",\n ...(maxLines != null\n ? { style: `--code-max-lines:${maxLines}` }\n : {}),\n },\n },\n },\n class: className,\n ...rest,\n });\n\n const api = defineConnect({\n slots: {\n // Placeholder: the panel owns the real root bag (including its\n // `passThrough.root` merge, where the invariants sit ON TOP of the\n // consumer's props). `defineConnect`'s slot map is keyed by the recipe's\n // slot union so `root` has to be present, but the value below is\n // discarded — `rootProps` is replaced with `panelApi.rootProps` in the\n // returned api. `passThrough.root` is withheld here so the consumer's\n // props are not re-applied last and allowed to clobber the markers.\n root: { class: \"\" },\n toolbar: {\n \"data-code-toolbar\": \"\",\n class: css(classes.toolbar, passThrough?.toolbar?.style),\n },\n language: {\n \"data-code-language\": \"\",\n class: css(classes.language, passThrough?.language?.style),\n },\n copyButton: {\n \"data-code-copy\": \"\",\n type: \"button\",\n emphasis: \"ghost\" as const,\n size: \"xs\" as const,\n // The label carries the state, so a screen reader hears the result of\n // the press rather than a button whose name never changes.\n \"aria-label\": copied ? \"Copied\" : \"Copy code\",\n \"data-copied\": copied ? \"true\" : \"false\",\n class: css(classes.copyButton, passThrough?.copyButton?.style),\n },\n scroller: {\n \"data-code-scroller\": \"\",\n // A horizontally scrollable region must be keyboard-reachable, or the\n // overflow is unreadable without a pointer.\n tabindex: 0,\n role: \"region\",\n \"aria-label\": label,\n class: css(classes.scroller, passThrough?.scroller?.style),\n },\n pre: {\n class: css(classes.pre, passThrough?.pre?.style),\n },\n codeEl: {\n ...(lang ? { \"data-language\": lang } : {}),\n class: css(classes.codeEl, passThrough?.codeEl?.style),\n },\n lineNumbers: {\n \"aria-hidden\": \"true\",\n class: css(classes.lineNumbers, passThrough?.lineNumbers?.style),\n },\n line: {\n class: css(classes.line, passThrough?.line?.style),\n },\n lineNumber: {\n class: css(classes.lineNumber, passThrough?.lineNumber?.style),\n },\n lineContent: {\n class: css(classes.lineContent, passThrough?.lineContent?.style),\n },\n token: {\n class: css(classes.token, passThrough?.token?.style),\n },\n marker: {\n class: css(classes.marker, passThrough?.marker?.style),\n },\n overflowFade: {\n \"data-code-fade\": \"\",\n \"aria-hidden\": \"true\",\n class: css(classes.overflowFade, passThrough?.overflowFade?.style),\n },\n expandButton: {\n \"data-code-expand\": \"\",\n type: \"button\",\n emphasis: \"secondary\" as const,\n size: \"xs\" as const,\n \"aria-expanded\": expanded ? \"true\" : \"false\",\n class: css(classes.expandButton, passThrough?.expandButton?.style),\n },\n },\n passThrough: { ...passThrough, root: undefined },\n });\n\n return {\n ...api,\n rootProps: panelApi.rootProps,\n element: panelApi.element,\n items,\n copyText,\n showToolbar,\n showExpand,\n overflowable,\n lineCount,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"connect-code.js","names":[],"sources":["../../src/connect-code.ts"],"sourcesContent":["import { css, cx } from \"@pindoba/styled-system/css\";\nimport { connectPanel } from \"@pindoba/core-panel\";\nimport {\n resolveCardContentSurface,\n resolveCardFrame,\n type CardFrameProps,\n type CardPassThrough,\n type CardSlotPassThrough,\n} from \"@pindoba/core-card\";\nimport { defineConnect } from \"@pindoba/normalize-props\";\nimport { codeStyles } from \"@pindoba/styles-code\";\nimport type {\n CodeApi,\n CodeBaseProps,\n CodeCardChrome,\n CodeCardDefaults,\n CodeCardFrameNodes,\n CodeResolvedCardFrame,\n CodeLine,\n CodeLineItem,\n CodeToken,\n ConnectCodeOptions,\n} from \"./types.js\";\n\nexport const codeDefaults = {\n size: \"sm\",\n feedback: \"neutral\",\n wrap: false,\n showLineNumbers: false,\n startLine: 1,\n collapsible: false,\n expanded: false,\n copyable: false,\n copied: false,\n label: \"Code block\",\n // --- Panel surface defaults ---\n // The root is a Panel; these reproduce the surface the recipe used to paint\n // by hand (`colorPalette.surface.hill` + a 1px muted border + an `sm`\n // corner). `padding: \"none\"` because the block's inset lives on the toolbar /\n // scroller, not the root — so no `--panel-out-padding` republish is needed.\n emphasis: \"secondary\",\n background: \"surface.hill\",\n padding: \"none\",\n radius: \"sm\",\n border: \"muted\",\n shadow: \"none\",\n} as const satisfies Partial<CodeBaseProps>;\n\n/** Split raw source into single-token lines — the unhighlighted fallback. */\nfunction linesFromSource(code: string): CodeLine[] {\n // A trailing newline is a line terminator, not an empty final line; keeping\n // it would render a stray blank row under every file.\n const body = code.endsWith(\"\\n\") ? code.slice(0, -1) : code;\n return body.split(\"\\n\").map((text) => ({ tokens: [{ text }] }));\n}\n\n/** A token's per-instance theme styling, as an inline CSS string. */\nfunction tokenStyle(token: CodeToken): string {\n return [\n token.color != null ? `color:${token.color}` : \"\",\n token.fontStyle != null ? `font-style:${token.fontStyle}` : \"\",\n ]\n .filter(Boolean)\n .join(\";\");\n}\n\n/** Reconstruct the plain text of tokenized lines, for the clipboard. */\nfunction sourceFromLines(lines: CodeLine[]): string {\n return lines\n .map((line) => line.tokens.map((t) => t.text).join(\"\"))\n .join(\"\\n\");\n}\n\n/**\n * Connect Contract v1.1 — the `Code` bags.\n *\n * Highlighting is somebody else's job: this takes already-tokenized `lines` and\n * turns them into spreadable bags. With no `lines` it falls back to rendering\n * `code` as plain text, so a block without a highlighter is still readable\n * rather than empty.\n */\nexport function connectCode(options: ConnectCodeOptions = {}): CodeApi {\n const {\n lines,\n code = \"\",\n lang,\n size = codeDefaults.size,\n feedback = codeDefaults.feedback,\n wrap = codeDefaults.wrap,\n showLineNumbers = codeDefaults.showLineNumbers,\n startLine = codeDefaults.startLine,\n highlightLines,\n maxLines,\n collapsible = codeDefaults.collapsible,\n expanded = codeDefaults.expanded,\n copyable = codeDefaults.copyable,\n copied = codeDefaults.copied,\n label = codeDefaults.label,\n title,\n card,\n // --- Panel surface axes (delegated to connectPanel) ---\n as = \"div\",\n background = codeDefaults.background,\n emphasis = codeDefaults.emphasis,\n translucent,\n padding = codeDefaults.padding,\n radius = codeDefaults.radius,\n radiusTop,\n radiusBottom,\n radiusLeft,\n radiusRight,\n border = codeDefaults.border,\n borderInteract,\n borderActive,\n reserveBorderSpace,\n shadow = codeDefaults.shadow,\n interactive,\n active,\n activeEmphasis,\n reactive,\n passThrough,\n class: className,\n ...rest\n } = options;\n\n const resolvedLines: CodeLine[] =\n lines ?? (code ? linesFromSource(code) : []);\n const lineCount = resolvedLines.length;\n\n // Clamp only when there is genuinely more than fits — a `maxLines` larger\n // than the content must not paint a fade over nothing.\n const overflowable = maxLines != null && maxLines > 0 && lineCount > maxLines;\n const clamped = overflowable && !expanded;\n\n // Card-optional: bare unless a card object is passed. The bare path must\n // stay byte-identical to the pre-card block, so the card-only recipe\n // variants are added ONLY when framed.\n const framed = card != null && card !== false;\n const frameInput: CardFrameProps = framed ? card : {};\n const cardContent = { padding: \"none\" as const, ...frameInput.content };\n const { inset, surface: contentSurface } = resolveCardContentSurface(\n cardContent,\n frameInput.contentBackground,\n );\n const surfaceBackground = inset\n ? contentSurface.background\n : (frameInput.background ?? background);\n\n const classes = codeStyles.raw({\n size,\n wrap,\n showLineNumbers,\n ...(framed ? { framed: true, fadeSurface: surfaceBackground } : null),\n });\n const highlighted = new Set(highlightLines ?? []);\n\n const items: CodeLineItem[] = resolvedLines.map((line, index) => {\n const number = startLine + index;\n const isHighlighted = highlighted.has(number);\n return {\n id: `line-${number}`,\n number,\n marker: line.marker,\n lineProps: {\n \"data-line\": String(number),\n \"data-highlighted\": isHighlighted ? \"true\" : \"false\",\n class: css(classes.line, passThrough?.line?.style),\n },\n lineNumberProps: {\n // The number is decoration duplicated by `data-line`; announcing it\n // before every line would bury the code itself.\n \"aria-hidden\": \"true\",\n class: css(classes.lineNumber, passThrough?.lineNumber?.style),\n },\n lineContentProps: {\n class: css(classes.lineContent, passThrough?.lineContent?.style),\n },\n ...(line.marker != null\n ? {\n markerProps: {\n \"aria-hidden\": \"true\",\n class: css(classes.marker, passThrough?.marker?.style),\n },\n }\n : {}),\n tokens: line.tokens.map((token, tokenIndex) => ({\n id: `line-${number}-token-${tokenIndex}`,\n text: token.text,\n tokenProps: {\n // Theme colour arrives per token and is inherently per-instance, so\n // it stays an inline style (which the contract allowlists) rather\n // than becoming an unbounded set of generated classes.\n //\n // A **string**, not an object: that is what connect bags emit\n // (`reactProps` converts it for React; Vue accepts either), and\n // Svelte drops most properties of a spread style object.\n ...(tokenStyle(token) ? { style: tokenStyle(token) } : {}),\n class: cx(\n css(classes.token, passThrough?.token?.style),\n token.className,\n ),\n },\n })),\n };\n });\n\n const copyText = lines ? sourceFromLines(lines) : code;\n const showToolbar = Boolean(lang) || copyable || Boolean(title);\n const showExpand = Boolean(collapsible && overflowable);\n\n // The root's surface (background / border / corner) belongs to Panel; the\n // recipe keeps only layout + typography and rides the `inheritedStyle`\n // channel, so the compose order stays panel recipe → code recipe → consumer\n // `passThrough.root.style` → literal `class`. `feedback` reaches the recipe's\n // `colorPalette.*` reads through the panel's own feedback variant.\n const panelApi = connectPanel({\n as,\n dataComponent: \"code\",\n background,\n emphasis,\n feedback,\n translucent,\n padding,\n radius,\n radiusTop,\n radiusBottom,\n radiusLeft,\n radiusRight,\n border,\n borderInteract,\n borderActive,\n reserveBorderSpace,\n shadow,\n interactive,\n active,\n activeEmphasis,\n reactive,\n inheritedStyle: classes.root,\n passThrough: {\n root: {\n style: passThrough?.root?.style,\n props: {\n // The consumer's overrides go FIRST so everything below stays an\n // invariant, exactly as when these were baked after the rest spread:\n // the Astro boot script keys its copy/expand wiring off\n // `data-component=\"code\"` + `data-clamped`, and the recipe reads the\n // clamp height from the inline `--code-max-lines`. Extra root styling\n // belongs on `passThrough.root.style` (the Panda channel), which is\n // merged into the class rather than fighting this attribute.\n ...passThrough?.root?.props,\n \"data-component\": \"code\",\n \"data-lang\": lang ?? \"\",\n \"data-clamped\": clamped ? \"true\" : \"false\",\n ...(maxLines != null\n ? { style: `--code-max-lines:${maxLines}` }\n : {}),\n },\n },\n },\n class: className,\n ...rest,\n });\n\n // --- Card frame input (used only when `frame === \"card\"`) ---------------\n const rootId: unknown = \"id\" in rest ? rest.id : undefined;\n const cardPassThrough: CardPassThrough = passThrough?.card ?? {};\n // The clamp host: in card mode the content region wraps the scroller + fade,\n // so the markers the bare root carries (and the recipe's `[data-clamped]\n // > &` rules and the Astro boot read) move here. Invariant — a consumer's\n // `card.passThrough.content.props` must not unclamp the block.\n const invariantContentProps: Record<string, unknown> = {\n \"data-code-body\": \"\",\n \"data-lang\": lang ?? \"\",\n \"data-clamped\": clamped ? \"true\" : \"false\",\n ...(maxLines != null ? { style: `--code-max-lines:${maxLines}` } : {}),\n };\n const cardDefaults: CodeCardDefaults = {\n size,\n background,\n feedback,\n emphasis,\n ...(translucent !== undefined ? { translucent } : null),\n radius,\n border,\n shadow,\n // A hairline under the header / over the footer stands in for the old\n // toolbar's bottom border. An inset card separates by its panel instead.\n ...(inset ? null : { divided: true }),\n content: { padding: \"none\" },\n };\n const cardChrome: CodeCardChrome = {\n heading: title || undefined,\n eyebrow: lang || undefined,\n headingId:\n typeof rootId === \"string\" && rootId !== \"\"\n ? `${rootId}-heading`\n : undefined,\n defaults: cardDefaults,\n rootProps: {\n \"data-card-flushable\": \"\",\n ...rest,\n ...passThrough?.root?.props,\n },\n invariantRootProps: { \"data-card-kind\": \"code\" },\n invariantContentProps,\n passThrough: {\n ...cardPassThrough,\n ...(passThrough?.root?.style || cardPassThrough.root\n ? {\n root: {\n ...cardPassThrough.root,\n style: css.raw(\n passThrough?.root?.style,\n cardPassThrough.root?.style,\n ),\n },\n }\n : null),\n content: {\n ...cardPassThrough.content,\n style: css.raw(classes.frameContent, cardPassThrough.content?.style),\n },\n },\n class: className != null ? String(className) : undefined,\n };\n\n // `passThrough.card` is the Card's, not a Code slot's.\n const { card: _cardPassThrough, ...slotPassThrough } = passThrough ?? {};\n\n const api = defineConnect({\n slots: {\n // Placeholder: the panel owns the real root bag (including its\n // `passThrough.root` merge, where the invariants sit ON TOP of the\n // consumer's props). `defineConnect`'s slot map is keyed by the recipe's\n // slot union so `root` has to be present, but the value below is\n // discarded — `rootProps` is replaced with `panelApi.rootProps` in the\n // returned api. `passThrough.root` is withheld here so the consumer's\n // props are not re-applied last and allowed to clobber the markers.\n root: { class: \"\" },\n toolbar: {\n \"data-code-toolbar\": \"\",\n class: css(classes.toolbar, passThrough?.toolbar?.style),\n },\n title: {\n \"data-code-title\": \"\",\n class: css(classes.title, passThrough?.title?.style),\n },\n language: {\n \"data-code-language\": \"\",\n class: css(classes.language, passThrough?.language?.style),\n },\n copyButton: {\n \"data-code-copy\": \"\",\n type: \"button\",\n emphasis: \"ghost\" as const,\n size: \"xs\" as const,\n // The label carries the state, so a screen reader hears the result of\n // the press rather than a button whose name never changes.\n \"aria-label\": copied ? \"Copied\" : \"Copy code\",\n \"data-copied\": copied ? \"true\" : \"false\",\n class: css(classes.copyButton, passThrough?.copyButton?.style),\n },\n scroller: {\n \"data-code-scroller\": \"\",\n // A horizontally scrollable region must be keyboard-reachable, or the\n // overflow is unreadable without a pointer.\n tabindex: 0,\n role: \"region\",\n \"aria-label\": label,\n class: css(classes.scroller, passThrough?.scroller?.style),\n },\n pre: {\n class: css(classes.pre, passThrough?.pre?.style),\n },\n codeEl: {\n ...(lang ? { \"data-language\": lang } : {}),\n class: css(classes.codeEl, passThrough?.codeEl?.style),\n },\n lineNumbers: {\n \"aria-hidden\": \"true\",\n class: css(classes.lineNumbers, passThrough?.lineNumbers?.style),\n },\n line: {\n class: css(classes.line, passThrough?.line?.style),\n },\n lineNumber: {\n class: css(classes.lineNumber, passThrough?.lineNumber?.style),\n },\n lineContent: {\n class: css(classes.lineContent, passThrough?.lineContent?.style),\n },\n token: {\n class: css(classes.token, passThrough?.token?.style),\n },\n marker: {\n class: css(classes.marker, passThrough?.marker?.style),\n },\n overflowFade: {\n \"data-code-fade\": \"\",\n \"aria-hidden\": \"true\",\n class: css(classes.overflowFade, passThrough?.overflowFade?.style),\n },\n expandButton: {\n \"data-code-expand\": \"\",\n type: \"button\",\n emphasis: \"secondary\" as const,\n size: \"xs\" as const,\n \"aria-expanded\": expanded ? \"true\" : \"false\",\n class: css(classes.expandButton, passThrough?.expandButton?.style),\n },\n // Card mode only: the frame styles ride `cardChrome.passThrough.content`\n // into the Card's content bag; nothing spreads this one directly.\n frameContent: {\n class: css(classes.frameContent),\n },\n },\n passThrough: { ...slotPassThrough, root: undefined },\n });\n\n return {\n ...api,\n frame: framed ? \"card\" : \"bare\",\n cardChrome,\n rootProps: panelApi.rootProps,\n element: panelApi.element,\n items,\n copyText,\n showToolbar,\n showExpand,\n overflowable,\n lineCount,\n };\n}\n\n/** Merge one card slot's passThrough: `over` wins (styles merged, props spread). */\nfunction mergeCardSlot(\n base: CardSlotPassThrough | undefined,\n over: CardSlotPassThrough | undefined,\n): CardSlotPassThrough | undefined {\n if (!base) return over;\n if (!over) return base;\n return {\n style: css.raw(base.style, over.style),\n props: { ...base.props, ...over.props },\n };\n}\n\nfunction slotOf(\n bag: CardPassThrough | undefined,\n key: string,\n): CardSlotPassThrough | undefined {\n if (!bag) return undefined;\n const entry: unknown = Reflect.get(bag, key);\n return typeof entry === \"object\" && entry !== null ? entry : undefined;\n}\n\n/** Merge two card passThrough bags slot by slot (`over` wins). */\nfunction mergeCardPassThrough(\n base: CardPassThrough,\n over: CardPassThrough | undefined,\n): CardPassThrough {\n const merged: Record<string, CardSlotPassThrough | undefined> = {};\n const keys = new Set([...Object.keys(base), ...Object.keys(over ?? {})]);\n for (const key of keys) {\n merged[key] = mergeCardSlot(slotOf(base, key), slotOf(over, key));\n }\n return merged;\n}\n\n/**\n * Resolve a framed block's Card: the consumer's `card` prop over the block's\n * own defaults (`api.cardChrome`), with the framework's chrome appended AFTER\n * the consumer's slots — the copy button into the header's trailing slot, the\n * expand button into the footer's trailing slot. The same call in all four\n * frameworks; they differ only in their slot type (Svelte snippets, React /\n * Vue nodes; Astro fills `chrome-*` slots and passes none).\n *\n * - `card.heading` / `card.eyebrow` win over `title` / `lang`.\n * - `card.content` merges over the block's `padding: \"none\"` default, so\n * `{ contentBackground }` keeps the code edge to edge on an inset panel.\n * - `card.passThrough` merges over `passThrough.card` and the frame styles.\n * - `data-card-kind` (root) and the clamp markers (content) are re-applied\n * last: nothing overrides them.\n */\nexport function resolveCodeCardFrame<TSlot>(\n card: CardFrameProps<TSlot> | false | undefined,\n chrome: CodeCardChrome,\n nodes: CodeCardFrameNodes<TSlot> = {},\n): CodeResolvedCardFrame<TSlot> {\n const frame: CardFrameProps<TSlot> = card || {};\n const eyebrow = frame.eyebrow ?? chrome.eyebrow;\n const resolved = resolveCardFrame<TSlot>(\n {\n ...frame,\n ...(eyebrow !== undefined ? { eyebrow } : null),\n content: { ...chrome.defaults.content, ...frame.content },\n passThrough: mergeCardPassThrough(chrome.passThrough, frame.passThrough),\n },\n {\n heading: chrome.heading,\n headingId: chrome.headingId,\n defaults: chrome.defaults,\n rootProps: chrome.rootProps,\n trailing: nodes.copy,\n footerTrailing: nodes.expand,\n },\n );\n const passThrough = resolved.cardProps.passThrough;\n return {\n ...resolved,\n cardProps: {\n ...resolved.cardProps,\n passThrough: {\n ...passThrough,\n root: {\n ...passThrough.root,\n props: { ...passThrough.root?.props, ...chrome.invariantRootProps },\n },\n content: {\n ...passThrough.content,\n props: {\n ...passThrough.content?.props,\n ...chrome.invariantContentProps,\n },\n },\n },\n ...(chrome.class !== undefined ? { class: chrome.class } : null),\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PanelElement, PanelElement as PanelElement$1, PanelInheritedProps, PanelRootProps, PanelRootProps as PanelRootProps$1 } from "@pindoba/core-panel";
|
|
2
|
+
import { CardFrameProps, CardFrameSlotInput, CardPassThrough, ResolvedCardFrame } from "@pindoba/core-card";
|
|
2
3
|
import { ConnectReturn } from "@pindoba/normalize-props";
|
|
3
4
|
import { CodeSlots, CodeStyleProps } from "@pindoba/styles-code";
|
|
4
5
|
import { SystemStyleObject } from "@pindoba/styled-system/types";
|
|
@@ -40,8 +41,22 @@ interface CodeSlotPassThrough<T = ElementAttributes> {
|
|
|
40
41
|
style?: SystemStyleObject;
|
|
41
42
|
props?: T;
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
/** Recipe slots that are card-mode styling hooks, not consumer-addressable elements. */
|
|
45
|
+
type CodeInternalSlots = "frameContent";
|
|
46
|
+
type CodePassThrough<RootElementAttributes = ElementAttributes> = { [K in Exclude<CodeSlots, CodeInternalSlots>]?: CodeSlotPassThrough<K extends "root" ? RootElementAttributes : ElementAttributes>; } & {
|
|
47
|
+
/**
|
|
48
|
+
* Card mode: passThrough forwarded to the Card (`root`, `header`, `content`,
|
|
49
|
+
* `footer`, …). Merged under `card.passThrough`. In card mode
|
|
50
|
+
* `passThrough.root` still reaches the Card root.
|
|
51
|
+
*/
|
|
52
|
+
card?: CardPassThrough;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* The `card` prop: frame the block in a Card. Every Card frame prop is
|
|
56
|
+
* accepted; `heading` defaults to `title` and `eyebrow` to `lang`.
|
|
57
|
+
*/
|
|
58
|
+
type CodeCardProps<TSlot = unknown> = CardFrameProps<TSlot>;
|
|
59
|
+
interface CodeBaseProps<RootElementAttributes = ElementAttributes, TSlot = unknown> extends Omit<PanelInheritedProps<RootElementAttributes>, "passThrough"> {
|
|
45
60
|
/**
|
|
46
61
|
* Pre-tokenized lines from a highlighter. When omitted, `code` is rendered
|
|
47
62
|
* as unhighlighted plain text — so the component degrades to a readable
|
|
@@ -56,11 +71,26 @@ interface CodeBaseProps<RootElementAttributes = ElementAttributes> extends Omit<
|
|
|
56
71
|
*/
|
|
57
72
|
code?: string;
|
|
58
73
|
/**
|
|
59
|
-
* Language label shown in the toolbar
|
|
60
|
-
* does no highlighting of its own.
|
|
74
|
+
* Language label shown in the toolbar (the card eyebrow when framed).
|
|
75
|
+
* Purely presentational — the component does no highlighting of its own.
|
|
61
76
|
* @group Content
|
|
62
77
|
*/
|
|
63
78
|
lang?: string;
|
|
79
|
+
/**
|
|
80
|
+
* A title for the block, e.g. its filename. Bare: the toolbar's leading
|
|
81
|
+
* text, before the language label. Framed (`card`): the card heading.
|
|
82
|
+
* @group Content
|
|
83
|
+
*/
|
|
84
|
+
title?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Frame the block in a Card. Unset or `false` renders the bare block (the
|
|
87
|
+
* default). With an object, `title` becomes the card heading, `lang` the
|
|
88
|
+
* eyebrow, the copy button moves to the header's trailing slot, the expand
|
|
89
|
+
* button to the footer, and the scroller is the card content
|
|
90
|
+
* (`content.padding: "none"`; set `contentBackground` for an inset panel).
|
|
91
|
+
* @group Appearance
|
|
92
|
+
*/
|
|
93
|
+
card?: CodeCardProps<TSlot> | false;
|
|
64
94
|
/**
|
|
65
95
|
* Type scale of the block. `xs` and `sm` currently render at the same font
|
|
66
96
|
* size — the scale's smallest step is `xs`, so separating them means moving
|
|
@@ -158,7 +188,59 @@ interface CodeLineItem {
|
|
|
158
188
|
markerProps?: Record<string, unknown>;
|
|
159
189
|
tokens: CodeTokenItem[];
|
|
160
190
|
}
|
|
191
|
+
/** The card defaults the block derives from its own surface props. */
|
|
192
|
+
type CodeCardDefaults = Pick<CardFrameProps, "size" | "background" | "feedback" | "emphasis" | "translucent" | "radius" | "border" | "shadow" | "divided" | "content">;
|
|
193
|
+
/**
|
|
194
|
+
* Everything `connectCode` resolves for the block's Card frame except the
|
|
195
|
+
* framework's own chrome nodes (copy / expand buttons). Feed it to
|
|
196
|
+
* `resolveCodeCardFrame(card, api.cardChrome, nodes)`.
|
|
197
|
+
*/
|
|
198
|
+
interface CodeCardChrome {
|
|
199
|
+
/** The card heading the block derives itself — its `title`. */
|
|
200
|
+
heading: string | undefined;
|
|
201
|
+
/** The card eyebrow the block derives itself — its `lang`. */
|
|
202
|
+
eyebrow: string | undefined;
|
|
203
|
+
/** Deterministic heading id (`${id}-heading`) when the block has an `id`. */
|
|
204
|
+
headingId: string | undefined;
|
|
205
|
+
/** The block's surface as card defaults (under the consumer's `card`). */
|
|
206
|
+
defaults: CodeCardDefaults;
|
|
207
|
+
/** Card root attributes: flush marker, the block's HTML attributes, `passThrough.root.props`. */
|
|
208
|
+
rootProps: Record<string, unknown>;
|
|
209
|
+
/** Card root attributes nothing may override (`data-card-kind`). */
|
|
210
|
+
invariantRootProps: Record<string, unknown>;
|
|
211
|
+
/**
|
|
212
|
+
* Card content attributes nothing may override: the clamp host markers
|
|
213
|
+
* (`data-code-body`, `data-lang`, `data-clamped`, `--code-max-lines`).
|
|
214
|
+
*/
|
|
215
|
+
invariantContentProps: Record<string, unknown>;
|
|
216
|
+
/** `passThrough.card` + the block's frame styles (`passThrough.root.style` included). */
|
|
217
|
+
passThrough: CardPassThrough;
|
|
218
|
+
/** The consumer's `class`, merged onto the card root. */
|
|
219
|
+
class: string | undefined;
|
|
220
|
+
}
|
|
221
|
+
/** The chrome a framework relocates into the block's Card. */
|
|
222
|
+
interface CodeCardFrameNodes<TSlot> {
|
|
223
|
+
/** The copy button → header trailing (after the consumer's `card.trailing`). */
|
|
224
|
+
copy?: CardFrameSlotInput<TSlot>;
|
|
225
|
+
/** The expand button → footer trailing (after the consumer's `card.footer.trailing`). */
|
|
226
|
+
expand?: CardFrameSlotInput<TSlot>;
|
|
227
|
+
}
|
|
228
|
+
/** `resolveCodeCardFrame()` — a resolved card frame whose root also carries the block's `class`. */
|
|
229
|
+
type CodeResolvedCardFrame<TSlot> = ResolvedCardFrame<TSlot> & {
|
|
230
|
+
cardProps: {
|
|
231
|
+
class?: string;
|
|
232
|
+
};
|
|
233
|
+
};
|
|
161
234
|
type CodeApi = ConnectReturn<CodeSlots> & {
|
|
235
|
+
/**
|
|
236
|
+
* `"bare"` (default, and `card={false}`) — render the block root
|
|
237
|
+
* `<element {...rootProps}>` with its toolbar. `"card"` (`card={{…}}`) —
|
|
238
|
+
* render `<CardFrame>` from `resolveCodeCardFrame(card, cardChrome, nodes)`
|
|
239
|
+
* with the scroller + fade as its content.
|
|
240
|
+
*/
|
|
241
|
+
frame: "card" | "bare";
|
|
242
|
+
/** The card frame input (card mode). See {@link CodeCardChrome}. */
|
|
243
|
+
cardChrome: CodeCardChrome;
|
|
162
244
|
/** The panel-produced root bag (`data-component="code"` + the nest hook). */
|
|
163
245
|
rootProps: PanelRootProps$1;
|
|
164
246
|
/** Resolved root tag from `as` — templates render this element. */
|
|
@@ -181,5 +263,5 @@ type CodeApi = ConnectReturn<CodeSlots> & {
|
|
|
181
263
|
lineCount: number;
|
|
182
264
|
};
|
|
183
265
|
//#endregion
|
|
184
|
-
export { CodeApi, CodeBaseProps, CodeFeedback, CodeLine, CodeLineItem, CodePassThrough, CodeSize, CodeSlotPassThrough, type CodeSlots, CodeToken, CodeTokenItem, ConnectCodeOptions, ElementAttributes, type PanelElement, type PanelRootProps };
|
|
266
|
+
export { CodeApi, CodeBaseProps, CodeCardChrome, CodeCardDefaults, CodeCardFrameNodes, CodeCardProps, CodeFeedback, CodeLine, CodeLineItem, CodePassThrough, CodeResolvedCardFrame, CodeSize, CodeSlotPassThrough, type CodeSlots, CodeToken, CodeTokenItem, ConnectCodeOptions, ElementAttributes, type PanelElement, type PanelRootProps };
|
|
185
267
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/types.ts"],"mappings":";;;;;;;KAmBY,oBAAoB,QAAQ;KAE5B,WAAW,YAAY;KACvB,eAAe,YAAY;;;;;;;;;;;;;;;UAkBtB;EACf;;EAEA;;EAEA;;EAEA;;;UAIe;EACf,QAAQ;;EAER;;UAKe,oBAAoB,IAAI;EACvC,QAAQ;EACR,QAAQ;;;KAIL;KAEO,gBAAgB,wBAAwB,wBACjD,KAAK,QAAQ,WAAW,sBAAsB,oBAC7C,mBAAmB,wBAAwB;;;;;;EAQ7C,OAAO;;;;;;KASG,cAAc,mBAAmB,eAAe;UAE3C,cACf,wBAAwB,mBACxB,yBAOQ,KAAK,oBAAoB;;;;;;;EAOjC,QAAQ;;;;;;EAMR;;;;;;EAMA;;;;;;EAMA;;;;;;;;;EASA,OAAO,cAAc;;;;;;;;EAQrB,OAAO;;;;;;EAMP;;;;;;EAMA;;;;;;;EAOA;;;;;EAKA;;;;;EAKA;;;;;;EAMA;;;;;;;EAOA;;;;;;EAMA;;;;;;;EAOA;;;;;;EAMA;;;;;EAKA,cAAc,gBAAgB;;UAKf,2BAA2B,QAC1C,cAAc;EAEd;GACC;;;UAIc;EACf;EACA;EACA,YAAY;;;UAIG;EACf;;EAEA;EACA;EACA,WAAW;EACX,iBAAiB;EACjB,kBAAkB;EAClB,cAAc;EACd,QAAQ;;;KAIE,mBAAmB,KAC7B;;;;;;UAkBe;;EAEf;;EAEA;;EAEA;;EAEA,UAAU;;EAEV,WAAW;;EAEX,oBAAoB;;;;;EAKpB,uBAAuB;;EAEvB,aAAa;;EAEb;;;UAIe,mBAAmB;;EAElC,OAAO,mBAAmB;;EAE1B,SAAS,mBAAmB;;;KAIlB,sBAAsB,SAAS,kBAAkB;EAC3D;IAAa;;;KAGH,UAAU,cAAc;;;;;;;EAOlC;;EAEA,YAAY;;EAEZ,WAAW;;EAEX,SAAS;;EAET,OAAO;;EAEP;;EAEA;;EAEA;;;;;;EAMA;;EAEA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pindoba/core-code",
|
|
3
|
-
"version": "0.0.0-alpha-
|
|
3
|
+
"version": "0.0.0-alpha-20261008173743",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -17,14 +17,16 @@
|
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
-
"dist"
|
|
20
|
+
"dist",
|
|
21
|
+
"!dist/**/__test__"
|
|
21
22
|
],
|
|
22
23
|
"dependencies": {
|
|
23
|
-
"@pindoba/core-
|
|
24
|
-
"@pindoba/
|
|
25
|
-
"@pindoba/
|
|
26
|
-
"@pindoba/
|
|
27
|
-
"@pindoba/styles-
|
|
24
|
+
"@pindoba/core-card": "0.0.0-alpha-20261008173743",
|
|
25
|
+
"@pindoba/core-panel": "0.0.0-alpha-20261008173743",
|
|
26
|
+
"@pindoba/normalize-props": "0.0.0-alpha-20261008173743",
|
|
27
|
+
"@pindoba/styled-system": "0.0.0-alpha-20261008173743",
|
|
28
|
+
"@pindoba/styles-code": "0.0.0-alpha-20261008173743",
|
|
29
|
+
"@pindoba/styles-panel": "0.0.0-alpha-20261008173743"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
32
|
"@pindoba/typescript-config": "0.0.0-alpha-20260320034942",
|