@pihanga2/codemirror 0.0.0-stage → 0.2.7

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/README.md CHANGED
@@ -1,3 +1,57 @@
1
- # Temporary Holding Version
1
+ # @pihanga2/codemirror
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Pihanga CodeMirror card — code editor with StreamLanguage plugin extension mechanism
4
+
5
+ Part of the [pihanga-shadcn](https://github.com/ivcap-works/pihanga-shadcn) card library.
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ npm install @pihanga2/codemirror
11
+ ```
12
+
13
+ Peer dependencies (already in your project if you use pihanga-shadcn):
14
+ ```sh
15
+ npm install react react-dom @pihanga2/core
16
+ ```
17
+
18
+ The following card-specific packages are installed automatically as dependencies:
19
+
20
+ - `@codemirror/language`
21
+ - `@codemirror/state`
22
+ - `@uiw/react-codemirror`
23
+ - `tailwind-merge`
24
+ - `clsx`
25
+ - `class-variance-authority`
26
+
27
+ ---
28
+
29
+ ## Tailwind CSS
30
+
31
+ This package ships TypeScript source with Tailwind utility classes. Add it to
32
+ your Tailwind content scan so the classes are included in your generated CSS.
33
+
34
+ **Tailwind v4 (`tailwind.css`)**:
35
+ ```css
36
+ @source "../../node_modules/@pihanga2/codemirror/dist-lib-codemirror";
37
+ ```
38
+
39
+ **Tailwind v3 (`tailwind.config.js`)**:
40
+ ```js
41
+ module.exports = {
42
+ content: ["./node_modules/@pihanga2/codemirror/dist-lib-codemirror/**/*.{js,jsx}"],
43
+ };
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Usage
49
+
50
+ ```ts
51
+ import "@pihanga2/codemirror/cards/codeMirror";
52
+ ```
53
+
54
+ ---
55
+
56
+ - Repository: <https://github.com/ivcap-works/pihanga-shadcn>
57
+ - shadcn registry: <https://ivcap-works.github.io/pihanga-shadcn/r>
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+ import { PiCardProps } from '@pihanga2/core';
3
+ import { CodeMirrorCardProps, CodeMirrorCardEvents } from './codeMirror.types';
4
+ export declare const CodeMirrorComponent: (props: PiCardProps<CodeMirrorCardProps, CodeMirrorCardEvents>) => React.ReactNode;
@@ -0,0 +1,41 @@
1
+ import { resolveExtensions as e, resolveStreamParser as t } from "./codeMirror.types.js";
2
+ import { useMemo as n } from "react";
3
+ import r from "@uiw/react-codemirror";
4
+ import { StreamLanguage as i } from "@codemirror/language";
5
+ import { jsx as a } from "react/jsx-runtime";
6
+ //#region src/cards/codeMirror/codeMirror.component.tsx
7
+ var o = (o) => {
8
+ let { value: s = "", readOnly: c = !1, streamLanguage: l, extensionsKey: u, theme: d = "light", lineNumbers: f = !0, foldGutter: p = !0, dropCursor: m = !0, allowMultipleSelections: h = !0, indentOnInput: g = !0, height: _ = "auto", minHeight: v, maxHeight: y, className: b, cardName: x, _cls: S, onChanged: C } = o, w = n(() => {
9
+ let n = u ? [...e(u) ?? []] : [];
10
+ if (l) {
11
+ let e = t(l);
12
+ e && n.push(i.define(e));
13
+ }
14
+ return n;
15
+ }, [l, u]), T = n(() => d === "dark" ? "dark" : d === "light" ? "light" : e(d) || (console.warn(`[shad/codeMirror] Unknown theme "${d}". Register it with registerExtensions() or use "light" / "dark". Falling back to "light".`), "light"), [d]);
16
+ return /* @__PURE__ */ a("div", {
17
+ className: S("root", b),
18
+ "data-pihanga": x,
19
+ children: /* @__PURE__ */ a(r, {
20
+ value: s,
21
+ height: _,
22
+ minHeight: v,
23
+ maxHeight: y,
24
+ readOnly: c,
25
+ theme: T,
26
+ extensions: w,
27
+ basicSetup: {
28
+ lineNumbers: f,
29
+ foldGutter: p,
30
+ dropCursor: m,
31
+ allowMultipleSelections: h,
32
+ indentOnInput: g
33
+ },
34
+ onChange: (e) => C?.({ value: e })
35
+ })
36
+ });
37
+ };
38
+ //#endregion
39
+ export { o as CodeMirrorComponent };
40
+
41
+ //# sourceMappingURL=codeMirror.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeMirror.component.js","names":[],"sources":["../../../src/cards/codeMirror/codeMirror.component.tsx"],"sourcesContent":["import React, {useMemo} from \"react\";\nimport type {PiCardProps} from \"@pihanga2/core\";\nimport CodeMirror from \"@uiw/react-codemirror\";\nimport {StreamLanguage} from \"@codemirror/language\";\nimport type {Extension} from \"@codemirror/state\";\n\nimport type {\n CodeMirrorCardProps,\n CodeMirrorCardEvents,\n} from \"./codeMirror.types\";\nimport {resolveStreamParser, resolveExtensions} from \"./codeMirror.types\";\n\nexport const CodeMirrorComponent = (\n props: PiCardProps<CodeMirrorCardProps, CodeMirrorCardEvents>,\n): React.ReactNode => {\n const {\n value = \"\",\n readOnly = false,\n streamLanguage,\n extensionsKey,\n theme = \"light\",\n lineNumbers = true,\n foldGutter = true,\n dropCursor = true,\n allowMultipleSelections = true,\n indentOnInput = true,\n height = \"auto\",\n minHeight,\n maxHeight,\n className,\n cardName,\n _cls,\n onChanged,\n } = props;\n\n /**\n * Build the effective extension list once per unique combination of keys.\n * Complex values (StreamParser, Extension[]) are looked up from the\n * module-level registries — never stored in Redux-serialised card props.\n */\n const extensions = useMemo<Extension[]>(() => {\n const ext: Extension[] = extensionsKey\n ? [...(resolveExtensions(extensionsKey) ?? [])]\n : [];\n if (streamLanguage) {\n const parser = resolveStreamParser(streamLanguage);\n if (parser) ext.push(StreamLanguage.define(parser));\n }\n return ext;\n }, [streamLanguage, extensionsKey]);\n\n /**\n * \"light\" / \"dark\" are built in. Any other value must be a theme bundle\n * registered with registerExtensions(); the bundle is applied as an\n * extension and the built-in light theme is suppressed.\n */\n const themeProp = useMemo<\n \"light\" | \"dark\" | \"none\" | Extension | Extension[]\n >(() => {\n if (theme === \"dark\") return \"dark\";\n if (theme === \"light\") return \"light\";\n const themeExt = resolveExtensions(theme);\n if (themeExt) return themeExt;\n console.warn(\n `[shad/codeMirror] Unknown theme \"${theme}\". Register it with registerExtensions() or use \"light\" / \"dark\". Falling back to \"light\".`,\n );\n return \"light\";\n }, [theme]);\n\n return (\n <div className={_cls(\"root\", className)} data-pihanga={cardName}>\n <CodeMirror\n value={value}\n height={height}\n minHeight={minHeight}\n maxHeight={maxHeight}\n readOnly={readOnly}\n theme={themeProp}\n extensions={extensions}\n basicSetup={{\n lineNumbers,\n foldGutter,\n dropCursor,\n allowMultipleSelections,\n indentOnInput,\n }}\n onChange={(val: string) => onChanged?.({value: val})}\n />\n </div>\n );\n};\n"],"mappings":";;;;;;AAYA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,WAAQ,IACR,cAAW,IACX,mBACA,kBACA,WAAQ,SACR,iBAAc,IACd,gBAAa,IACb,gBAAa,IACb,6BAA0B,IAC1B,mBAAgB,IAChB,YAAS,QACT,cACA,cACA,cACA,aACA,SACA,iBACE,GAOE,IAAa,QAA2B;EAC5C,IAAM,IAAmB,IACrB,CAAC,GAAI,EAAkB,CAAa,KAAK,CAAC,CAAE,IAC5C,CAAC;EACL,IAAI,GAAgB;GAClB,IAAM,IAAS,EAAoB,CAAc;GACjD,AAAI,KAAQ,EAAI,KAAK,EAAe,OAAO,CAAM,CAAC;EACpD;EACA,OAAO;CACT,GAAG,CAAC,GAAgB,CAAa,CAAC,GAO5B,IAAY,QAGZ,MAAU,SAAe,SACzB,MAAU,UAAgB,UACb,EAAkB,CAC/B,MACJ,QAAQ,KACN,oCAAoC,EAAM,2FAC5C,GACO,UACN,CAAC,CAAK,CAAC;CAEV,OACE,kBAAC,OAAD;EAAK,WAAW,EAAK,QAAQ,CAAS;EAAG,gBAAc;YACrD,kBAAC,GAAD;GACS;GACC;GACG;GACA;GACD;GACV,OAAO;GACK;GACZ,YAAY;IACV;IACA;IACA;IACA;IACA;GACF;GACA,WAAW,MAAgB,IAAY,EAAC,OAAO,EAAG,CAAC;EACpD,CAAA;CACE,CAAA;AAET"}
@@ -0,0 +1,104 @@
1
+ import { Extension } from '@codemirror/state';
2
+ import { StreamParser } from '@codemirror/language';
3
+ export declare const CODE_MIRROR_CARD = "code-mirror";
4
+ export declare const CodeMirror: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<CodeMirrorCardProps, S, CodeMirrorCardEvents>) => import('@pihanga2/core').PiCardDef;
5
+ /** @deprecated Use {@link CodeMirror} instead. */
6
+ export declare const CodeMirrorCard: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<CodeMirrorCardProps, S, CodeMirrorCardEvents>) => import('@pihanga2/core').PiCardDef;
7
+ export declare const CODE_MIRROR_ACTION: {
8
+ CHANGED: string;
9
+ };
10
+ export declare const onCodeMirrorChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
11
+ cardID: string;
12
+ } & ChangedEvent>) => void;
13
+ /**
14
+ * Register a StreamParser under a caller-chosen key.
15
+ * Call this once at app initialisation time, before the card is first rendered.
16
+ *
17
+ * @example
18
+ * import { python } from "@codemirror/legacy-modes/mode/python";
19
+ * import { registerStreamParser } from "@pihanga2/codemirror/cards/codeMirror";
20
+ * registerStreamParser("python", python);
21
+ */
22
+ export declare function registerStreamParser(key: string, parser: StreamParser<unknown>): void;
23
+ /** @internal — used by the component only. */
24
+ export declare function resolveStreamParser(key: string): StreamParser<unknown> | undefined;
25
+ /**
26
+ * Register a bundle of CodeMirror 6 extensions (themes, linters, keymaps, …)
27
+ * under a caller-chosen key.
28
+ * Call this once at app initialisation time, before the card is first rendered.
29
+ *
30
+ * @example
31
+ * import { oneDark } from "@codemirror/theme-one-dark";
32
+ * import { registerExtensions } from "@pihanga2/codemirror/cards/codeMirror";
33
+ * registerExtensions("oneDark", [oneDark]);
34
+ */
35
+ export declare function registerExtensions(key: string, exts: Extension[]): void;
36
+ /** @internal — used by the component only. */
37
+ export declare function resolveExtensions(key: string): Extension[] | undefined;
38
+ export type CodeMirrorCardProps = {
39
+ /** The code content to display or edit. */
40
+ value?: string;
41
+ /** When true the editor is read-only. Default: false. */
42
+ readOnly?: boolean;
43
+ /**
44
+ * Key of a StreamParser previously registered with `registerStreamParser()`.
45
+ * Props must be JSON-serialisable — pass the string key, not the parser itself.
46
+ *
47
+ * @example
48
+ * import { python } from "@codemirror/legacy-modes/mode/python";
49
+ * registerStreamParser("python", python);
50
+ * CodeMirror({ streamLanguage: "python", value: "print('hello')" });
51
+ */
52
+ streamLanguage?: string;
53
+ /**
54
+ * Key of an Extension bundle previously registered with `registerExtensions()`.
55
+ * Props must be JSON-serialisable — pass the string key, not the Extension objects.
56
+ *
57
+ * @example
58
+ * import { oneDark } from "@codemirror/theme-one-dark";
59
+ * registerExtensions("oneDark", [oneDark]);
60
+ * CodeMirror({ extensionsKey: "oneDark", ... });
61
+ *
62
+ * Note: `theme` looks up keys in this same registry, so a bundle registered
63
+ * here can also be used as a theme.
64
+ */
65
+ extensionsKey?: string;
66
+ /**
67
+ * CodeMirror editor theme: "light", "dark", or the key of a theme bundle
68
+ * registered with `registerExtensions()` (e.g. "dracula"). Default: "light".
69
+ *
70
+ * @example
71
+ * import { draculaInit } from "@uiw/codemirror-theme-dracula";
72
+ * registerExtensions("dracula", [draculaInit()]);
73
+ * CodeMirror({ theme: "dracula", ... });
74
+ */
75
+ theme?: "light" | "dark" | (string & {});
76
+ /** Show line numbers in the gutter. Default: true. */
77
+ lineNumbers?: boolean;
78
+ /** Show the fold gutter (code folding). Default: true. */
79
+ foldGutter?: boolean;
80
+ /** Show a drop cursor while dragging text. Default: true. */
81
+ dropCursor?: boolean;
82
+ /** Allow multiple selection ranges. Default: true. */
83
+ allowMultipleSelections?: boolean;
84
+ /** Re-indent the current line as you type. Default: true. */
85
+ indentOnInput?: boolean;
86
+ /**
87
+ * CSS height of the editor. Use "auto" to grow with content or a fixed
88
+ * value such as "400px". Default: "auto".
89
+ */
90
+ height?: string;
91
+ /** CSS minimum height of the editor, e.g. "120px". */
92
+ minHeight?: string;
93
+ /** CSS maximum height of the editor, e.g. "600px". Scrolls beyond this. */
94
+ maxHeight?: string;
95
+ /** Additional CSS class applied to the outer wrapper div. */
96
+ className?: string;
97
+ };
98
+ export type ChangedEvent = {
99
+ /** The updated editor content after each change. */
100
+ value: string;
101
+ };
102
+ export type CodeMirrorCardEvents = {
103
+ onChanged: ChangedEvent;
104
+ };
@@ -0,0 +1,20 @@
1
+ import { createCardDeclaration as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
2
+ //#region src/cards/codeMirror/codeMirror.types.ts
3
+ var r = "code-mirror", i = e(r), a = i, o = n(r, ["changed"]), s = t(o.CHANGED), c = /* @__PURE__ */ new Map();
4
+ function l(e, t) {
5
+ c.set(e, t);
6
+ }
7
+ function u(e) {
8
+ return c.get(e);
9
+ }
10
+ var d = /* @__PURE__ */ new Map();
11
+ function f(e, t) {
12
+ d.set(e, t);
13
+ }
14
+ function p(e) {
15
+ return d.get(e);
16
+ }
17
+ //#endregion
18
+ export { o as CODE_MIRROR_ACTION, r as CODE_MIRROR_CARD, i as CodeMirror, a as CodeMirrorCard, s as onCodeMirrorChanged, f as registerExtensions, l as registerStreamParser, p as resolveExtensions, u as resolveStreamParser };
19
+
20
+ //# sourceMappingURL=codeMirror.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeMirror.types.js","names":[],"sources":["../../../src/cards/codeMirror/codeMirror.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\nimport type {Extension} from \"@codemirror/state\";\nimport type {StreamParser} from \"@codemirror/language\";\n\nexport const CODE_MIRROR_CARD = \"code-mirror\";\n\nexport const CodeMirror = createCardDeclaration<\n CodeMirrorCardProps,\n CodeMirrorCardEvents\n>(CODE_MIRROR_CARD);\n\n/** @deprecated Use {@link CodeMirror} instead. */\nexport const CodeMirrorCard = CodeMirror;\n\nexport const CODE_MIRROR_ACTION = registerActions(CODE_MIRROR_CARD, [\n \"changed\",\n]);\n\nexport const onCodeMirrorChanged = createOnAction<ChangedEvent>(\n CODE_MIRROR_ACTION.CHANGED,\n);\n\n// ── StreamParser registry ────────────────────────────────────────────────────\n// Props must only contain JSON-serialisable primitives. Complex third-party\n// types (StreamParser, Extension) are stored here and referenced by string key.\n\nconst _streamParserRegistry = new Map<string, StreamParser<unknown>>();\n\n/**\n * Register a StreamParser under a caller-chosen key.\n * Call this once at app initialisation time, before the card is first rendered.\n *\n * @example\n * import { python } from \"@codemirror/legacy-modes/mode/python\";\n * import { registerStreamParser } from \"@pihanga2/codemirror/cards/codeMirror\";\n * registerStreamParser(\"python\", python);\n */\nexport function registerStreamParser(\n key: string,\n parser: StreamParser<unknown>,\n): void {\n _streamParserRegistry.set(key, parser);\n}\n\n/** @internal — used by the component only. */\nexport function resolveStreamParser(\n key: string,\n): StreamParser<unknown> | undefined {\n return _streamParserRegistry.get(key);\n}\n\n// ── Extension registry ───────────────────────────────────────────────────────\n\nconst _extensionsRegistry = new Map<string, Extension[]>();\n\n/**\n * Register a bundle of CodeMirror 6 extensions (themes, linters, keymaps, …)\n * under a caller-chosen key.\n * Call this once at app initialisation time, before the card is first rendered.\n *\n * @example\n * import { oneDark } from \"@codemirror/theme-one-dark\";\n * import { registerExtensions } from \"@pihanga2/codemirror/cards/codeMirror\";\n * registerExtensions(\"oneDark\", [oneDark]);\n */\nexport function registerExtensions(key: string, exts: Extension[]): void {\n _extensionsRegistry.set(key, exts);\n}\n\n/** @internal — used by the component only. */\nexport function resolveExtensions(key: string): Extension[] | undefined {\n return _extensionsRegistry.get(key);\n}\n\n// ── Card Props ───────────────────────────────────────────────────────────────\n\nexport type CodeMirrorCardProps = {\n /** The code content to display or edit. */\n value?: string;\n\n /** When true the editor is read-only. Default: false. */\n readOnly?: boolean;\n\n /**\n * Key of a StreamParser previously registered with `registerStreamParser()`.\n * Props must be JSON-serialisable — pass the string key, not the parser itself.\n *\n * @example\n * import { python } from \"@codemirror/legacy-modes/mode/python\";\n * registerStreamParser(\"python\", python);\n * CodeMirror({ streamLanguage: \"python\", value: \"print('hello')\" });\n */\n streamLanguage?: string;\n\n /**\n * Key of an Extension bundle previously registered with `registerExtensions()`.\n * Props must be JSON-serialisable — pass the string key, not the Extension objects.\n *\n * @example\n * import { oneDark } from \"@codemirror/theme-one-dark\";\n * registerExtensions(\"oneDark\", [oneDark]);\n * CodeMirror({ extensionsKey: \"oneDark\", ... });\n *\n * Note: `theme` looks up keys in this same registry, so a bundle registered\n * here can also be used as a theme.\n */\n extensionsKey?: string;\n\n /**\n * CodeMirror editor theme: \"light\", \"dark\", or the key of a theme bundle\n * registered with `registerExtensions()` (e.g. \"dracula\"). Default: \"light\".\n *\n * @example\n * import { draculaInit } from \"@uiw/codemirror-theme-dracula\";\n * registerExtensions(\"dracula\", [draculaInit()]);\n * CodeMirror({ theme: \"dracula\", ... });\n */\n theme?: \"light\" | \"dark\" | (string & {});\n\n /** Show line numbers in the gutter. Default: true. */\n lineNumbers?: boolean;\n\n /** Show the fold gutter (code folding). Default: true. */\n foldGutter?: boolean;\n\n /** Show a drop cursor while dragging text. Default: true. */\n dropCursor?: boolean;\n\n /** Allow multiple selection ranges. Default: true. */\n allowMultipleSelections?: boolean;\n\n /** Re-indent the current line as you type. Default: true. */\n indentOnInput?: boolean;\n\n /**\n * CSS height of the editor. Use \"auto\" to grow with content or a fixed\n * value such as \"400px\". Default: \"auto\".\n */\n height?: string;\n\n /** CSS minimum height of the editor, e.g. \"120px\". */\n minHeight?: string;\n\n /** CSS maximum height of the editor, e.g. \"600px\". Scrolls beyond this. */\n maxHeight?: string;\n\n /** Additional CSS class applied to the outer wrapper div. */\n className?: string;\n};\n\nexport type ChangedEvent = {\n /** The updated editor content after each change. */\n value: string;\n};\n\nexport type CodeMirrorCardEvents = {\n onChanged: ChangedEvent;\n};\n"],"mappings":";;AAQA,IAAa,IAAmB,eAEnB,IAAa,EAGxB,CAAgB,GAGL,IAAiB,GAEjB,IAAqB,EAAgB,GAAkB,CAClE,SACF,CAAC,GAEY,IAAsB,EACjC,EAAmB,OACrB,GAMM,oBAAwB,IAAI,IAAmC;AAWrE,SAAgB,EACd,GACA,GACM;CACN,EAAsB,IAAI,GAAK,CAAM;AACvC;AAGA,SAAgB,EACd,GACmC;CACnC,OAAO,EAAsB,IAAI,CAAG;AACtC;AAIA,IAAM,oBAAsB,IAAI,IAAyB;AAYzD,SAAgB,EAAmB,GAAa,GAAyB;CACvE,EAAoB,IAAI,GAAK,CAAI;AACnC;AAGA,SAAgB,EAAkB,GAAsC;CACtE,OAAO,EAAoB,IAAI,CAAG;AACpC"}
@@ -0,0 +1 @@
1
+ export * from './codeMirror.types';
@@ -0,0 +1,13 @@
1
+ import { CODE_MIRROR_ACTION as e, CODE_MIRROR_CARD as t, CodeMirror as n, CodeMirrorCard as r, onCodeMirrorChanged as i, registerExtensions as a, registerStreamParser as o, resolveExtensions as s, resolveStreamParser as c } from "./codeMirror.types.js";
2
+ import { CodeMirrorComponent as l } from "./codeMirror.component.js";
3
+ import { actionTypesToEvents as u, registerCardComponent as d } from "@pihanga2/core";
4
+ //#region src/cards/codeMirror/index.ts
5
+ d({
6
+ name: t,
7
+ component: l,
8
+ events: u(e)
9
+ });
10
+ //#endregion
11
+ export { e as CODE_MIRROR_ACTION, t as CODE_MIRROR_CARD, n as CodeMirror, r as CodeMirrorCard, i as onCodeMirrorChanged, a as registerExtensions, o as registerStreamParser, s as resolveExtensions, c as resolveStreamParser };
12
+
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/codeMirror/index.ts"],"sourcesContent":["import {registerCardComponent, actionTypesToEvents} from \"@pihanga2/core\";\n\nimport {CODE_MIRROR_CARD, CODE_MIRROR_ACTION} from \"./codeMirror.types\";\nimport {CodeMirrorComponent} from \"./codeMirror.component\";\n\nexport * from \"./codeMirror.types\";\n\nregisterCardComponent({\n name: CODE_MIRROR_CARD,\n component: CodeMirrorComponent,\n events: actionTypesToEvents(CODE_MIRROR_ACTION),\n});\n"],"mappings":";;;;AAOA,EAAsB;CACpB,MAAM;CACN,WAAW;CACX,QAAQ,EAAoB,CAAkB;AAChD,CAAC"}
@@ -0,0 +1,49 @@
1
+ import * as React from "react";
2
+ /**
3
+ * Convert a user-supplied breakpoint selector string into a CSS media-query
4
+ * string suitable for `window.matchMedia`.
5
+ *
6
+ * Supported selector formats
7
+ * ──────────────────────────
8
+ * Named (Tailwind) │ `sm` `md` `lg` `xl` `2xl`
9
+ * Min-width │ `640px` `>=640px`
10
+ * Exclusive min │ `>640px` (≡ min-width: 641px)
11
+ * Max-width │ `<=1024px`
12
+ * Exclusive max │ `<1024px` (≡ max-width: 1023px)
13
+ */
14
+ export declare function selectorToMediaQuery(selector: string): string;
15
+ /**
16
+ * Convert a breakpoint selector string into a predicate that tests a pixel
17
+ * width directly. Used by `useContainerBreakpoint` to evaluate the selector
18
+ * against an element's `contentRect.width` rather than the viewport.
19
+ *
20
+ * Returns `() => true` for unrecognised selectors (fail-open).
21
+ */
22
+ export declare function selectorToWidthTest(selector: string): (width: number) => boolean;
23
+ /**
24
+ * Returns `true` when the **viewport** matches the given breakpoint selector,
25
+ * and reactively updates on resize via `window.matchMedia`.
26
+ *
27
+ * When `selector` is `undefined` the hook always returns `true` (no restriction).
28
+ *
29
+ * @param selector A breakpoint name (`sm` | `md` | `lg` | `xl` | `2xl`),
30
+ * a pixel expression (`>400px`, `>=640px`, `<768px`,
31
+ * `<=1024px`, `400px`), or `undefined`.
32
+ */
33
+ export declare function useBreakpoint(selector: string | undefined): boolean;
34
+ /**
35
+ * Returns `true` when the width of the element referenced by `ref` matches
36
+ * the given breakpoint selector. Uses `ResizeObserver` so it reacts to
37
+ * any layout change — not just window resize.
38
+ *
39
+ * When `selector` is `undefined` the hook always returns `true`.
40
+ *
41
+ * **Note:** The caller must attach `ref` to a DOM element. A thin wrapper
42
+ * `<div ref={ref} style={{ width: "100%" }}>` whose width equals its parent's
43
+ * content width is the canonical usage pattern, allowing the breakpoint to be
44
+ * evaluated against the **enclosing container** rather than the viewport.
45
+ *
46
+ * @param selector Same format as {@link useBreakpoint}.
47
+ * @param ref A React ref attached to the element whose width is measured.
48
+ */
49
+ export declare function useContainerBreakpoint(selector: string | undefined, ref: React.RefObject<HTMLElement | null>): boolean;
@@ -0,0 +1 @@
1
+ export declare function useIsTouchDevice(): boolean;
@@ -0,0 +1,4 @@
1
+ export declare const useTheme: () => {
2
+ theme: import('./theme-provider.types').Theme;
3
+ setTheme: (theme: import('./theme-provider.types').Theme) => void;
4
+ };
@@ -0,0 +1,2 @@
1
+ import { ThemeProviderProps } from './theme-provider.types';
2
+ export declare function ThemeProvider({ children, defaultTheme, storageKey, ...props }: ThemeProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
1
+ export type Theme = "dark" | "light" | "system";
2
+ export type ThemeProviderProps = {
3
+ children: React.ReactNode;
4
+ defaultTheme?: Theme;
5
+ storageKey?: string;
6
+ };
7
+ type ThemeProviderState = {
8
+ theme: Theme;
9
+ setTheme: (theme: Theme) => void;
10
+ };
11
+ export declare const ThemeProviderContext: import('react').Context<ThemeProviderState>;
12
+ export {};
package/lib/utils.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { ClassValue } from 'clsx';
2
+ export declare function cn(...inputs: ClassValue[]): string;
3
+ /**
4
+ * Returns "#000000" or "#ffffff" for maximum contrast against the given background color (hex or rgb).
5
+ *
6
+ * Based on WCAG relative luminance, which models human visual perception:
7
+ * L = 0.2126·R + 0.7152·G + 0.0722·B
8
+ *
9
+ * The weights reflect how sensitive our eyes are to each channel —
10
+ * green contributes 71% of perceived brightness, red ~21%, blue only 7%.
11
+ * This means a vivid red like #c0392b is perceptually *dim* (L≈0.11), so
12
+ * white text (contrast 8.7:1) beats black text (2.4:1) against it.
13
+ *
14
+ * The threshold L > 0.179 is the luminance midpoint where both black and
15
+ * white achieve ~4.5:1 contrast — the WCAG AA minimum.
16
+ */
17
+ export declare function contrastColor(bg: string, threshold?: number): "#000000" | "#ffffff";
package/package.json CHANGED
@@ -1,6 +1,43 @@
1
1
  {
2
2
  "name": "@pihanga2/codemirror",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.7",
4
+ "description": "Pihanga CodeMirror card — code editor with StreamLanguage plugin extension mechanism",
5
+ "type": "module",
6
+ "exports": {
7
+ "./cards/codeMirror": {
8
+ "import": "./cards/codeMirror/index.js",
9
+ "types": "./cards/codeMirror/index.d.ts"
10
+ }
11
+ },
12
+ "sideEffects": [
13
+ "./cards/codeMirror/index.js"
14
+ ],
15
+ "license": "MIT",
16
+ "homepage": "https://ivcap-works.github.io/pihanga-shadcn",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/ivcap-works/pihanga-shadcn.git"
20
+ },
21
+ "keywords": [
22
+ "pihanga",
23
+ "shadcn",
24
+ "radix-ui",
25
+ "react",
26
+ "ui",
27
+ "cards",
28
+ "codemirror"
29
+ ],
30
+ "peerDependencies": {
31
+ "react": "^19.1.0",
32
+ "react-dom": "^19.1.0",
33
+ "@pihanga2/core": "^0.3.40"
34
+ },
35
+ "dependencies": {
36
+ "@codemirror/language": "^6.12.4",
37
+ "@codemirror/state": "^6.7.1",
38
+ "@uiw/react-codemirror": "^4.25.11",
39
+ "class-variance-authority": "^0.7.1",
40
+ "clsx": "^2.1.1",
41
+ "tailwind-merge": "^3.3.0"
42
+ }
43
+ }