pretrunc 0.0.0-stage → 0.1.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 (52) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/DESIGN.md +235 -0
  3. package/LICENSE +21 -0
  4. package/README.md +200 -2
  5. package/dist/cut-D7qi2yZl.js +356 -0
  6. package/dist/cut-D7qi2yZl.js.map +1 -0
  7. package/dist/cut.d.ts +75 -0
  8. package/dist/dom-CPL0-qc3.js +52 -0
  9. package/dist/dom-CPL0-qc3.js.map +1 -0
  10. package/dist/dom.d.ts +22 -0
  11. package/dist/dom.js +1 -0
  12. package/dist/face-pICHAjvk.js +68 -0
  13. package/dist/face-pICHAjvk.js.map +1 -0
  14. package/dist/face.d.ts +46 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +3 -0
  17. package/dist/lines-DOj2DQLl.js +334 -0
  18. package/dist/lines-DOj2DQLl.js.map +1 -0
  19. package/dist/lines.d.ts +32 -0
  20. package/dist/lines.js +1 -0
  21. package/dist/metrics-C2jv4JVL.js +49 -0
  22. package/dist/metrics-C2jv4JVL.js.map +1 -0
  23. package/dist/metrics-cli.js +19 -0
  24. package/dist/metrics-cli.js.map +1 -0
  25. package/dist/metrics.d.ts +36 -0
  26. package/dist/metrics.js +73 -0
  27. package/dist/metrics.js.map +1 -0
  28. package/dist/react-CnQfjWyS.js +156 -0
  29. package/dist/react-CnQfjWyS.js.map +1 -0
  30. package/dist/react-lines.d.ts +27 -0
  31. package/dist/react-lines.js +74 -0
  32. package/dist/react-lines.js.map +1 -0
  33. package/dist/react.d.ts +81 -0
  34. package/dist/react.js +1 -0
  35. package/dist/solid-BWC32VMg.js +155 -0
  36. package/dist/solid-BWC32VMg.js.map +1 -0
  37. package/dist/solid-lines.d.ts +27 -0
  38. package/dist/solid-lines.js +90 -0
  39. package/dist/solid-lines.js.map +1 -0
  40. package/dist/solid.d.ts +77 -0
  41. package/dist/solid.js +1 -0
  42. package/package.json +145 -3
  43. package/src/cut.ts +596 -0
  44. package/src/dom.ts +59 -0
  45. package/src/face.ts +112 -0
  46. package/src/index.ts +15 -0
  47. package/src/lines.ts +585 -0
  48. package/src/metrics.ts +106 -0
  49. package/src/react-lines.ts +99 -0
  50. package/src/react.ts +251 -0
  51. package/src/solid-lines.tsx +89 -0
  52. package/src/solid.tsx +225 -0
@@ -0,0 +1,27 @@
1
+ import type { JSX } from "@solidjs/web";
2
+ import { type CutOptions, type Protect } from "./cut.js";
3
+ export interface ClampProps extends Omit<CutOptions, "tailGraphemes"> {
4
+ readonly text: string;
5
+ /** How many lines to keep. */
6
+ readonly lines: number;
7
+ readonly ellipsis?: string;
8
+ /**
9
+ * Painted after the text whenever it is cut or `expanded`, such as a "more" or
10
+ * "less" button. Its width is observed and kept free on the last line.
11
+ */
12
+ readonly after?: JSX.Element;
13
+ /** Show every line, with `after` following the last one, on its own if it doesn't fit. */
14
+ readonly expanded?: boolean;
15
+ /** The room in px. Left out, it is observed from the element. */
16
+ readonly width?: number;
17
+ /** A CSS font shorthand. Left out, it is read from the element's computed style. */
18
+ readonly font?: string;
19
+ /** CSS `letter-spacing` in px. Left out, it is read from the element's computed style. */
20
+ readonly letterSpacing?: number;
21
+ readonly protect?: Protect;
22
+ readonly whiteSpace?: "normal" | "pre-wrap";
23
+ readonly wordBreak?: "normal" | "keep-all";
24
+ readonly class?: string;
25
+ }
26
+ /** A paragraph cut to a number of lines at its end, start or middle. */
27
+ export declare function Clamp(props: ClampProps): JSX.Element;
@@ -0,0 +1,90 @@
1
+ import { l as truncated, r as head, s as tail } from "./cut-D7qi2yZl.js";
2
+ import { n as observe } from "./dom-CPL0-qc3.js";
3
+ import { n as prepareLines, t as clamp } from "./lines-DOj2DQLl.js";
4
+ import { r as createBox } from "./solid-BWC32VMg.js";
5
+ import { className, createComponent, effect, insert, memo, readShallow, ref, setStyleProperty, template } from "@solidjs/web";
6
+ import { Show, createMemo, createSignal, onSettled } from "solid-js";
7
+ //#region src/solid-lines.tsx
8
+ var _tmpl$ = /* @__PURE__ */ template(`<span style=display:inline-block>`);
9
+ var _tmpl$2 = /* @__PURE__ */ template(`<div style=overflow-wrap:break-word><!><!>`);
10
+ /** A paragraph cut to a number of lines at its end, start or middle. */
11
+ function Clamp(props) {
12
+ const box = createBox(props);
13
+ const [afterWidth, setAfterWidth] = createSignal(0);
14
+ let stop;
15
+ const watch = (element) => {
16
+ stop?.();
17
+ stop = observe(element, setAfterWidth);
18
+ };
19
+ onSettled(() => () => stop?.());
20
+ const prepared = createMemo(() => {
21
+ box.fonts();
22
+ const font = box.font();
23
+ if (font === void 0) return void 0;
24
+ return prepareLines(props.text, font, {
25
+ ...props.protect ? { protect: props.protect } : {},
26
+ ...props.whiteSpace ? { whiteSpace: props.whiteSpace } : {},
27
+ ...props.wordBreak ? { wordBreak: props.wordBreak } : {},
28
+ letterSpacing: box.spacing()
29
+ });
30
+ });
31
+ const cut = createMemo(() => {
32
+ const p = prepared();
33
+ const width = box.width();
34
+ const font = box.font();
35
+ if (p === void 0 || width === void 0 || font === void 0) return void 0;
36
+ return clamp(p, width, {
37
+ ...props,
38
+ after: props.after === void 0 ? 0 : afterWidth()
39
+ });
40
+ });
41
+ const cutNow = () => {
42
+ const c = cut();
43
+ return c !== void 0 && truncated(c);
44
+ };
45
+ const text = () => {
46
+ const p = prepared();
47
+ const c = cut();
48
+ if (props.expanded || p === void 0 || c === void 0 || !truncated(c)) return props.text;
49
+ return p.text.slice(0, head(c)) + (props.ellipsis ?? "…") + p.text.slice(tail(c));
50
+ };
51
+ var _el$ = _tmpl$2();
52
+ var _el$2 = _el$.firstChild;
53
+ var _el$4 = _el$2.nextSibling;
54
+ var _ref$ = box.ref;
55
+ typeof _ref$ === "function" || Array.isArray(_ref$) ? ref(() => {
56
+ return _ref$;
57
+ }, _el$) : box.ref = _el$;
58
+ insert(_el$, text, _el$2);
59
+ insert(_el$, createComponent(Show, {
60
+ get when() {
61
+ return memo(() => {
62
+ return props.after !== void 0;
63
+ })() && (props.expanded || cutNow());
64
+ },
65
+ get children() {
66
+ var _el$3 = _tmpl$();
67
+ ref(() => {
68
+ return watch;
69
+ }, _el$3);
70
+ insert(_el$3, () => {
71
+ return props.after;
72
+ });
73
+ return _el$3;
74
+ }
75
+ }), _el$4);
76
+ effect(() => {
77
+ return {
78
+ e: readShallow(props.class),
79
+ t: props.whiteSpace ?? "normal"
80
+ };
81
+ }, ({ e, t }, _p$) => {
82
+ className(_el$, e, _p$?.e);
83
+ t !== _p$?.t && setStyleProperty(_el$, "white-space", t);
84
+ });
85
+ return _el$;
86
+ }
87
+ //#endregion
88
+ export { Clamp };
89
+
90
+ //# sourceMappingURL=solid-lines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solid-lines.js","names":["ref={box.ref}","<div\n ref={box.ref}\n class={props.class}\n style={{ \"overflow-wrap\": \"break-word\", \"white-space\": props.whiteSpace ?? \"normal\" }}\n >\n {text()}\n <Show when={props.after !== undefined && (props.expanded || cutNow())}>\n <span ref={watch} style={{ display: \"inline-block\" }}>\n {props.after}\n </span>\n </Show>\n </div>","<Show when={props.after !== undefined && (props.expanded || cutNow())}>\n <span ref={watch} style={{ display: \"inline-block\" }}>\n {props.after}\n </span>\n </Show>","props.after !== undefined && (props.expanded || cutNow())","ref={watch}","<span ref={watch} style={{ display: \"inline-block\" }}>\n {props.after}\n </span>","\"white-space\": props.whiteSpace ?? \"normal\"","_$ref","_$createComponent","_$memo","_$readShallow","_$setStyleProperty"],"sources":["../src/solid-lines.tsx"],"sourcesContent":["import type { JSX } from \"@solidjs/web\";\nimport { createMemo, createSignal, onSettled, Show } from \"solid-js\";\nimport { type CutOptions, head, type Protect, tail, truncated } from \"./cut.ts\";\nimport { observe } from \"./dom.ts\";\nimport { clamp, prepareLines } from \"./lines.ts\";\nimport { createBox } from \"./solid.tsx\";\n\nexport interface ClampProps extends Omit<CutOptions, \"tailGraphemes\"> {\n readonly text: string;\n /** How many lines to keep. */\n readonly lines: number;\n readonly ellipsis?: string;\n /**\n * Painted after the text whenever it is cut or `expanded`, such as a \"more\" or\n * \"less\" button. Its width is observed and kept free on the last line.\n */\n readonly after?: JSX.Element;\n /** Show every line, with `after` following the last one, on its own if it doesn't fit. */\n readonly expanded?: boolean;\n /** The room in px. Left out, it is observed from the element. */\n readonly width?: number;\n /** A CSS font shorthand. Left out, it is read from the element's computed style. */\n readonly font?: string;\n /** CSS `letter-spacing` in px. Left out, it is read from the element's computed style. */\n readonly letterSpacing?: number;\n readonly protect?: Protect;\n readonly whiteSpace?: \"normal\" | \"pre-wrap\";\n readonly wordBreak?: \"normal\" | \"keep-all\";\n readonly class?: string;\n}\n\n/** A paragraph cut to a number of lines at its end, start or middle. */\nexport function Clamp(props: ClampProps): JSX.Element {\n const box = createBox(props);\n const [afterWidth, setAfterWidth] = createSignal(0);\n // `after` mounts only once the text is cut, so it is observed from its own ref.\n let stop: (() => void) | undefined;\n const watch = (element: Element) => {\n stop?.();\n stop = observe(element, setAfterWidth);\n };\n onSettled(() => () => stop?.());\n const prepared = createMemo(() => {\n box.fonts();\n const font = box.font();\n if (font === undefined) return undefined;\n return prepareLines(props.text, font, {\n ...(props.protect ? { protect: props.protect } : {}),\n ...(props.whiteSpace ? { whiteSpace: props.whiteSpace } : {}),\n ...(props.wordBreak ? { wordBreak: props.wordBreak } : {}),\n letterSpacing: box.spacing(),\n });\n });\n const cut = createMemo(() => {\n const p = prepared();\n const width = box.width();\n const font = box.font();\n if (p === undefined || width === undefined || font === undefined) return undefined;\n // `after` is an element here and a width to `clamp`, so it's always given as one.\n return clamp(p, width, {\n ...props,\n after: props.after === undefined ? 0 : afterWidth(),\n });\n });\n const cutNow = () => {\n const c = cut();\n return c !== undefined && truncated(c);\n };\n const text = () => {\n const p = prepared();\n const c = cut();\n if (props.expanded || p === undefined || c === undefined || !truncated(c)) return props.text;\n return p.text.slice(0, head(c)) + (props.ellipsis ?? \"…\") + p.text.slice(tail(c));\n };\n return (\n <div\n ref={box.ref}\n class={props.class}\n style={{ \"overflow-wrap\": \"break-word\", \"white-space\": props.whiteSpace ?? \"normal\" }}\n >\n {text()}\n <Show when={props.after !== undefined && (props.expanded || cutNow())}>\n <span ref={watch} style={{ display: \"inline-block\" }}>\n {props.after}\n </span>\n </Show>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAgCA,SAAgB,MAAM,OAAgC;CACpD,MAAM,MAAM,UAAU,KAAK;CAC3B,MAAM,CAAC,YAAY,iBAAiB,aAAa,CAAC;CAElD,IAAI;CACJ,MAAM,SAAS,YAAqB;EAClC,OAAO;EACP,OAAO,QAAQ,SAAS,aAAa;CACvC;CACA,sBAAsB,OAAO,CAAC;CAC9B,MAAM,WAAW,iBAAiB;EAChC,IAAI,MAAM;EACV,MAAM,OAAO,IAAI,KAAK;EACtB,IAAI,SAAS,KAAA,GAAW,OAAO,KAAA;EAC/B,OAAO,aAAa,MAAM,MAAM,MAAM;GACpC,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;GAClD,GAAI,MAAM,aAAa,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;GAC3D,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;GACxD,eAAe,IAAI,QAAQ;EAC7B,CAAC;CACH,CAAC;CACD,MAAM,MAAM,iBAAiB;EAC3B,MAAM,IAAI,SAAS;EACnB,MAAM,QAAQ,IAAI,MAAM;EACxB,MAAM,OAAO,IAAI,KAAK;EACtB,IAAI,MAAM,KAAA,KAAa,UAAU,KAAA,KAAa,SAAS,KAAA,GAAW,OAAO,KAAA;EAEzE,OAAO,MAAM,GAAG,OAAO;GACrB,GAAG;GACH,OAAO,MAAM,UAAU,KAAA,IAAY,IAAI,WAAW;EACpD,CAAC;CACH,CAAC;CACD,MAAM,eAAe;EACnB,MAAM,IAAI,IAAI;EACd,OAAO,MAAM,KAAA,KAAa,UAAU,CAAC;CACvC;CACA,MAAM,aAAa;EACjB,MAAM,IAAI,SAAS;EACnB,MAAM,IAAI,IAAI;EACd,IAAI,MAAM,YAAY,MAAM,KAAA,KAAa,MAAM,KAAA,KAAa,CAAC,UAAU,CAAC,GAAG,OAAO,MAAM;EACxF,OAAO,EAAE,KAAK,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,MAAM,YAAY,OAAO,EAAE,KAAK,MAAM,KAAK,CAAC,CAAC;CAClF;CAEE,IAAA,OAAA,QAWK;CAXL,IAAA,QAAA,KAAA;;CACE,IAAA,QAAK,IAAI;CAAT,OAAA,UAAA,cAAA,MAAA,QAAA,KAAY,IAAZA,UAAAA;;CAAY,GAAZA,IAAY,IAAZ,IAAS,MAATA;CADF,OAAA,MAKG,MALHC,KAWK;CAXL,OAAA,MAMEC,gBAAAA,MAAAA;EAAM,IAAA,OAAA;GAAMC,OAAAA,WAAAA;IAAM,OAAA,MAAA,UAAU,KAAA;GAAwC,CAAA,CAAC,CAAD,MAA1B,MAAM,YAAY,OAAO;EAAE;EAArE,IAAA,WAAA;GACE,IAAA,QAAA,OAEM;GAFA,UAAA;IAAK,OAAA;GAAK,GAAVC,KAAU;GAAhB,OAAA,aACE;IAAC,OAAA,MAAM;GAAK,CACR;GAHR,OACEC;EAGI;CAVRJ,CAAAA,GAAAA,KAWK;CATH,aAAA;;GAAO,GAAAS,YAAA,MAAM,KAAK;GACsBJ,GAAe,MAAM,cAAc;EADzD;CAAlB,IAAA,EAAA,GAAA,KAAA,QAAA;EAAkB,UAAA,MAAA,GAAA,KAAA,CAAA;EACsB,MAAA,KAAA,KAAAK,iBAAA,MAAA,eAAA,CAA0C;CADhE,CAAA;CAHtB,OACEV;AAaJ"}
@@ -0,0 +1,77 @@
1
+ import type { JSX } from "@solidjs/web";
2
+ import { type Accessor } from "solid-js";
3
+ import { type Cut, type CutOptions, type Prepared, type Protect } from "./cut.js";
4
+ export interface CutProps extends CutOptions {
5
+ readonly text: string;
6
+ /** The room in px. Left out, it is observed from the element. */
7
+ readonly width?: number;
8
+ /** A CSS font shorthand. Left out, it is read from the element's computed style. */
9
+ readonly font?: string;
10
+ /** CSS `letter-spacing` in px. Left out, it is read from the element's computed style. */
11
+ readonly letterSpacing?: number;
12
+ readonly protect?: Protect;
13
+ }
14
+ export interface CutHandle {
15
+ /** Give it the element whose width and font the cut follows. */
16
+ readonly ref: (element: Element) => void;
17
+ readonly prepared: Accessor<Prepared | undefined>;
18
+ /** Undefined until the width and font are known. */
19
+ readonly cut: Accessor<Cut | undefined>;
20
+ }
21
+ export interface Box {
22
+ /** Give it the element whose width and font the text follows. */
23
+ readonly ref: (element: Element) => void;
24
+ /** The width given, or the element's content width; undefined until observed. */
25
+ readonly width: Accessor<number | undefined>;
26
+ /** The font given, or the element's; undefined until it mounts. */
27
+ readonly font: Accessor<string | undefined>;
28
+ /** The letter spacing given, or the element's, in px. */
29
+ readonly spacing: Accessor<number>;
30
+ /** Changes whenever web fonts load: read it where text is prepared. */
31
+ readonly fonts: Accessor<number>;
32
+ }
33
+ export interface FontProviderProps {
34
+ /** A CSS font shorthand that every cut inside is in, unless it's given its own. */
35
+ readonly font?: string;
36
+ /** CSS `letter-spacing` in px for every cut inside, unless it's given its own. */
37
+ readonly letterSpacing?: number;
38
+ readonly children?: JSX.Element;
39
+ }
40
+ /**
41
+ * Gives every `Truncate`, `Clamp` and `createBox` inside the font and letter spacing
42
+ * their text renders in, once for a list. Each would otherwise read its element's
43
+ * computed style when it mounts: 5,000 rows take 4 to 5 ms of style reads. Cuts follow
44
+ * what's given, so give what the rows really render in.
45
+ */
46
+ export declare function FontProvider(props: FontProviderProps): JSX.Element;
47
+ /**
48
+ * The width and font text is cut to: the ones given, then a `FontProvider`'s, or an
49
+ * element's, observed. Whether to observe the width and read the font is decided once,
50
+ * when it settles.
51
+ */
52
+ export declare const createBox: (props: {
53
+ readonly width?: number;
54
+ readonly font?: string;
55
+ readonly letterSpacing?: number;
56
+ }) => Box;
57
+ export interface CreateCutProps extends CutProps {
58
+ /**
59
+ * The ellipsis is painted in an element of its own, so it is measured as a run of its
60
+ * own and no kerning across it counts. Read once.
61
+ */
62
+ readonly separateEllipsis?: boolean;
63
+ }
64
+ /** The cut of `props.text` for an element's width and font, or for the ones given. */
65
+ export declare const createCut: (props: CreateCutProps) => CutHandle;
66
+ export interface TruncateProps extends CutProps {
67
+ readonly ellipsis?: string;
68
+ /**
69
+ * "kept" (default) paints the kept text, with the whole text in `title` once cut.
70
+ * "full" paints all of it with the cut part collapsed to no width, so copy,
71
+ * find-in-page and screen readers get the whole text. Read once.
72
+ */
73
+ readonly render?: "kept" | "full";
74
+ readonly class?: string;
75
+ }
76
+ /** One line of text, cut to fit its box. */
77
+ export declare function Truncate(props: TruncateProps): JSX.Element;
package/dist/solid.js ADDED
@@ -0,0 +1 @@
1
+ export { t as FontProvider, n as Truncate, r as createBox, i as createCut } from "./solid-BWC32VMg.js";
package/package.json CHANGED
@@ -1,6 +1,148 @@
1
1
  {
2
2
  "name": "pretrunc",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "Cut text at its start, middle or end to fit a width, measured before it paints, never overflowing",
5
+ "keywords": [
6
+ "canvas",
7
+ "clamp",
8
+ "ellipsis",
9
+ "middle-ellipsis",
10
+ "pretext",
11
+ "react",
12
+ "solid",
13
+ "text",
14
+ "truncate"
15
+ ],
16
+ "homepage": "https://lewisalderman.github.io/pretrunc/",
17
+ "bugs": "https://github.com/LewisAlderman/pretrunc/issues",
18
+ "license": "MIT",
19
+ "author": "Lewis Alderman",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/LewisAlderman/pretrunc.git"
23
+ },
24
+ "bin": {
25
+ "pretrunc-metrics": "./dist/metrics-cli.js"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "src",
30
+ "!src/**/*.test.ts",
31
+ "!src/**/*.test.tsx",
32
+ "DESIGN.md",
33
+ "CHANGELOG.md"
34
+ ],
35
+ "type": "module",
36
+ "sideEffects": false,
37
+ "exports": {
38
+ ".": {
39
+ "solid": "./src/index.ts",
40
+ "types": "./dist/index.d.ts",
41
+ "default": "./dist/index.js"
42
+ },
43
+ "./dom": {
44
+ "solid": "./src/dom.ts",
45
+ "types": "./dist/dom.d.ts",
46
+ "default": "./dist/dom.js"
47
+ },
48
+ "./lines": {
49
+ "solid": "./src/lines.ts",
50
+ "types": "./dist/lines.d.ts",
51
+ "default": "./dist/lines.js"
52
+ },
53
+ "./metrics": {
54
+ "solid": "./src/metrics.ts",
55
+ "types": "./dist/metrics.d.ts",
56
+ "default": "./dist/metrics.js"
57
+ },
58
+ "./solid": {
59
+ "solid": "./src/solid.tsx",
60
+ "types": "./dist/solid.d.ts",
61
+ "default": "./dist/solid.js"
62
+ },
63
+ "./solid/lines": {
64
+ "solid": "./src/solid-lines.tsx",
65
+ "types": "./dist/solid-lines.d.ts",
66
+ "default": "./dist/solid-lines.js"
67
+ },
68
+ "./react": {
69
+ "types": "./dist/react.d.ts",
70
+ "default": "./dist/react.js"
71
+ },
72
+ "./react/lines": {
73
+ "types": "./dist/react-lines.d.ts",
74
+ "default": "./dist/react-lines.js"
75
+ },
76
+ "./package.json": "./package.json"
77
+ },
78
+ "devDependencies": {
79
+ "@changesets/cli": "3.0.3",
80
+ "@chenglou/pretext": "1.0.0",
81
+ "@effect/tsgo": "0.53.1",
82
+ "@effect/vitest": "4.0.5",
83
+ "@fontsource-variable/inter": "5.3.0",
84
+ "@shikijs/twoslash": "4.5.0",
85
+ "@solidjs/testing-library": "1.0.0-beta.3",
86
+ "@solidjs/vite-plugin": "3.0.0-next.50",
87
+ "@solidjs/web": "2.0.0-rc.15",
88
+ "@testing-library/dom": "10.4.2",
89
+ "@testing-library/react": "16.3.3",
90
+ "@types/fontkit": "2.0.9",
91
+ "@types/react": "19.3.0",
92
+ "@types/react-dom": "19.3.0",
93
+ "@vitest/browser-playwright": "5.0.4",
94
+ "effect": "4.0.5",
95
+ "eslint-plugin-solid": "0.18.1",
96
+ "fontkit": "2.0.4",
97
+ "knip": "6.39.0",
98
+ "playwright": "1.64.1",
99
+ "react": "19.3.0",
100
+ "react-dom": "19.3.0",
101
+ "shiki": "4.5.0",
102
+ "solid-js": "2.0.0-rc.15",
103
+ "twoslash": "0.3.9",
104
+ "typescript": "7.0.2",
105
+ "typescript-twoslash": "npm:typescript@5.9.3",
106
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.2.0",
107
+ "vite-plus": "1.2.0"
108
+ },
109
+ "peerDependencies": {
110
+ "@chenglou/pretext": "^1.0.0",
111
+ "@solidjs/web": "^2.0.0-rc.15",
112
+ "fontkit": "^2.0.4",
113
+ "react": "^19.0.0",
114
+ "solid-js": "^2.0.0-rc.15"
115
+ },
116
+ "peerDependenciesMeta": {
117
+ "@chenglou/pretext": {
118
+ "optional": true
119
+ },
120
+ "fontkit": {
121
+ "optional": true
122
+ },
123
+ "@solidjs/web": {
124
+ "optional": true
125
+ },
126
+ "react": {
127
+ "optional": true
128
+ },
129
+ "solid-js": {
130
+ "optional": true
131
+ }
132
+ },
133
+ "devEngines": {
134
+ "packageManager": {
135
+ "name": "pnpm",
136
+ "version": "12.11.2",
137
+ "onFail": "download"
138
+ },
139
+ "runtime": {
140
+ "name": "node",
141
+ "version": "26.12.0",
142
+ "onFail": "download"
143
+ }
144
+ },
145
+ "scripts": {
146
+ "setup": "vp config && effect-tsgo patch --oxlint"
147
+ }
6
148
  }