@glyph-ui/textarea 0.1.0-alpha.2

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 ADDED
@@ -0,0 +1,22 @@
1
+ # @glyph-ui/textarea
2
+
3
+ Glyph UI's **GTextarea** component.
4
+
5
+ ```bash
6
+ npm install @glyph-ui/textarea
7
+ ```
8
+
9
+ Installing runs a postinstall step that copies these files into your own project (not into a runtime dependency):
10
+
11
+ - `src/components/glyph/GTextarea.tsx`
12
+ - `src/lib/utils.ts`
13
+
14
+ You'll also need: `clsx`, `tailwind-merge`.
15
+
16
+ Once the files land, **this package is done its job** — feel free to run:
17
+
18
+ ```bash
19
+ npm uninstall @glyph-ui/textarea
20
+ ```
21
+
22
+ Your project keeps the copied source either way; nothing at runtime ever imports from this package.
@@ -0,0 +1,45 @@
1
+ import { TextareaHTMLAttributes, forwardRef, useState } from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ interface Props extends TextareaHTMLAttributes<HTMLTextAreaElement> {
5
+ label?: string;
6
+ }
7
+
8
+ export const GTextarea = forwardRef<HTMLTextAreaElement, Props>(
9
+ ({ className, label, onFocus, onBlur, ...rest }, ref) => {
10
+ const [focused, setFocused] = useState(false);
11
+ return (
12
+ <label className="block w-full">
13
+ {label && (
14
+ <span className="label-mono text-muted block mb-2">{label}</span>
15
+ )}
16
+ <div
17
+ className={cn(
18
+ "relative rounded-[8px] border bg-surface transition-all duration-200",
19
+ focused
20
+ ? "border-signal [box-shadow:0_0_18px_hsl(var(--signal-glow)/var(--glow-soft)),inset_0_0_0_1px_hsl(var(--signal)/0.3)]"
21
+ : "border-[hsl(var(--border-subtle))]"
22
+ )}
23
+ >
24
+ <textarea
25
+ ref={ref}
26
+ onFocus={(e) => {
27
+ setFocused(true);
28
+ onFocus?.(e);
29
+ }}
30
+ onBlur={(e) => {
31
+ setFocused(false);
32
+ onBlur?.(e);
33
+ }}
34
+ className={cn(
35
+ "w-full bg-transparent px-3.5 py-2.5 min-h-[88px] text-sm text-foreground placeholder:text-muted/70 outline-none font-mono resize-y",
36
+ className
37
+ )}
38
+ {...rest}
39
+ />
40
+ </div>
41
+ </label>
42
+ );
43
+ }
44
+ );
45
+ GTextarea.displayName = "GTextarea";
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
package/manifest.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "component": "GTextarea",
3
+ "files": [
4
+ "src/components/glyph/GTextarea.tsx",
5
+ "src/lib/utils.ts"
6
+ ],
7
+ "dependencies": [
8
+ "clsx",
9
+ "tailwind-merge"
10
+ ]
11
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@glyph-ui/textarea",
3
+ "version": "0.1.0-alpha.2",
4
+ "description": "Glyph UI — GTextarea. Installing this copies its source into your project; it is not a runtime dependency and is safe to remove once copied.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "private": false,
8
+ "publishConfig": {
9
+ "tag": "alpha",
10
+ "access": "public"
11
+ },
12
+ "scripts": {
13
+ "postinstall": "node scripts/postinstall.mjs",
14
+ "prepublishOnly": "node scripts/check-alpha-version.mjs"
15
+ },
16
+ "files": [
17
+ "files",
18
+ "manifest.json",
19
+ "scripts",
20
+ "README.md"
21
+ ],
22
+ "peerDependencies": {
23
+ "react": ">=18",
24
+ "clsx": "*",
25
+ "tailwind-merge": "*"
26
+ },
27
+ "peerDependenciesMeta": {
28
+ "clsx": {
29
+ "optional": true
30
+ },
31
+ "tailwind-merge": {
32
+ "optional": true
33
+ }
34
+ },
35
+ "keywords": [
36
+ "react",
37
+ "ui",
38
+ "component",
39
+ "gtextarea"
40
+ ]
41
+ }
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Runs as "prepublishOnly" — a non-zero exit here aborts `npm publish`
4
+ * before anything reaches the registry. Refuses to publish unless the
5
+ * version is a proper alpha prerelease and publishConfig.tag is "alpha",
6
+ * so a stable/"latest" release can't happen by accident during the alpha
7
+ * phase. See the package's README for how to graduate out of alpha
8
+ * deliberately.
9
+ */
10
+ import { readFileSync } from "node:fs";
11
+ import { dirname, join } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8"));
16
+
17
+ const ALPHA_VERSION = /^\d+\.\d+\.\d+-alpha\.\d+$/;
18
+
19
+ if (!ALPHA_VERSION.test(pkg.version)) {
20
+ console.error(
21
+ `\nRefusing to publish: version "${pkg.version}" is not an alpha prerelease.\n` +
22
+ `Expected x.y.z-alpha.N, e.g. "0.1.0-alpha.2".\n` +
23
+ `Bump with: npm version prerelease --preid=alpha\n`
24
+ );
25
+ process.exit(1);
26
+ }
27
+
28
+ if (pkg.publishConfig?.tag !== "alpha") {
29
+ console.error(
30
+ `\nRefusing to publish: publishConfig.tag is "${pkg.publishConfig?.tag ?? "(unset)"}", expected "alpha".\n`
31
+ );
32
+ process.exit(1);
33
+ }
34
+
35
+ console.log(`\u2713 ${pkg.name}@${pkg.version} is a valid alpha prerelease.`);
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Runs automatically after `npm install` for this package. Copies this
4
+ * component's real source file(s) out of node_modules and into the
5
+ * consumer's own project, at the same relative path they'd have if they'd
6
+ * copy-pasted it by hand.
7
+ *
8
+ * npm sets INIT_CWD to the directory the user actually ran `npm install`
9
+ * from (their project root) — not this package's folder inside
10
+ * node_modules, which is what `process.cwd()` would give during a
11
+ * postinstall hook. That's the whole trick that makes this behave like
12
+ * shadcn's copy-paste model instead of a normal installed dependency.
13
+ */
14
+ import { cpSync, mkdirSync, existsSync, readFileSync } from "node:fs";
15
+ import { dirname, join } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+
18
+ const __dirname = dirname(fileURLToPath(import.meta.url));
19
+ const pkgRoot = join(__dirname, "..");
20
+ const pkg = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf8"));
21
+ const manifest = JSON.parse(readFileSync(join(pkgRoot, "manifest.json"), "utf8"));
22
+
23
+ const targetRoot = process.env.INIT_CWD || process.cwd();
24
+
25
+ // Guard against this ever running inside the glyph-ui monorepo itself
26
+ // (e.g. `npm install` at the repo root) and overwriting the source of
27
+ // truth these packages were generated from.
28
+ if (targetRoot.split(/[/\\]/).includes("packages")) {
29
+ process.exit(0);
30
+ }
31
+
32
+ console.log(`\nglyph-ui: ${pkg.name} \u2014 copying source into your project\n`);
33
+
34
+ let copied = 0;
35
+ for (const relPath of manifest.files) {
36
+ const src = join(pkgRoot, "files", relPath);
37
+ const dest = join(targetRoot, relPath);
38
+ if (!existsSync(src)) continue;
39
+ mkdirSync(dirname(dest), { recursive: true });
40
+ cpSync(src, dest);
41
+ console.log(` + ${relPath}`);
42
+ copied++;
43
+ }
44
+
45
+ console.log(`\n${copied} file(s) copied.`);
46
+ if (manifest.dependencies.length) {
47
+ console.log(`Make sure these are installed: ${manifest.dependencies.join(", ")}`);
48
+ }
49
+ console.log(`This package's job is done. It is safe to remove:`);
50
+ console.log(` npm uninstall ${pkg.name}\n`);