@emdash-cms/plugin-color 0.0.1

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/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@emdash-cms/plugin-color",
3
+ "version": "0.0.1",
4
+ "description": "Color picker field widget for EmDash CMS",
5
+ "type": "module",
6
+ "main": "src/index.ts",
7
+ "exports": {
8
+ ".": "./src/index.ts",
9
+ "./admin": "./src/admin.tsx"
10
+ },
11
+ "files": [
12
+ "src"
13
+ ],
14
+ "keywords": [
15
+ "emdash",
16
+ "cms",
17
+ "plugin",
18
+ "color",
19
+ "picker",
20
+ "field-widget"
21
+ ],
22
+ "author": "Matt Kane",
23
+ "license": "MIT",
24
+ "peerDependencies": {
25
+ "react": "^18.0.0 || ^19.0.0",
26
+ "emdash": "0.0.1"
27
+ },
28
+ "devDependencies": {
29
+ "@types/react": "19.2.14"
30
+ },
31
+ "scripts": {
32
+ "typecheck": "tsgo --noEmit"
33
+ }
34
+ }
package/src/admin.tsx ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Color picker admin component.
3
+ *
4
+ * Exports a `fields` map with a "picker" widget that renders a color
5
+ * input with hex value display and preview swatch.
6
+ */
7
+
8
+ import * as React from "react";
9
+
10
+ interface FieldWidgetProps {
11
+ value: unknown;
12
+ onChange: (value: unknown) => void;
13
+ label: string;
14
+ id: string;
15
+ required?: boolean;
16
+ options?: Record<string, unknown>;
17
+ minimal?: boolean;
18
+ }
19
+
20
+ /** Named CSS colors for the preset palette */
21
+ const PRESETS = [
22
+ "#ef4444",
23
+ "#f97316",
24
+ "#eab308",
25
+ "#22c55e",
26
+ "#06b6d4",
27
+ "#3b82f6",
28
+ "#8b5cf6",
29
+ "#ec4899",
30
+ "#000000",
31
+ "#ffffff",
32
+ ];
33
+
34
+ const VALID_HEX_PATTERN = /^#[\da-f]{6}$/i;
35
+
36
+ function ColorPicker({ value, onChange, label, id, required, minimal }: FieldWidgetProps) {
37
+ const rawColor = typeof value === "string" && value ? value : "#000000";
38
+ // Only pass valid 6-digit hex to the native color input and preview;
39
+ // partial input while typing would produce invalid color values.
40
+ const color = VALID_HEX_PATTERN.test(rawColor) ? rawColor : "#000000";
41
+
42
+ const handleHexChange = (e: React.ChangeEvent<HTMLInputElement>) => {
43
+ const v = e.target.value;
44
+ // Allow partial input while typing
45
+ onChange(v);
46
+ };
47
+
48
+ return (
49
+ <div data-testid="color-picker-widget">
50
+ {!minimal && (
51
+ <label htmlFor={id} className="text-sm font-medium leading-none mb-1.5 block">
52
+ {label}
53
+ {required && <span className="text-destructive ml-0.5">*</span>}
54
+ </label>
55
+ )}
56
+ <div className="flex items-center gap-3">
57
+ <input
58
+ type="color"
59
+ id={id}
60
+ value={color}
61
+ onChange={(e) => onChange(e.target.value)}
62
+ className="h-10 w-10 cursor-pointer rounded border border-input p-0.5"
63
+ data-testid="color-input"
64
+ />
65
+ <input
66
+ type="text"
67
+ value={typeof value === "string" ? value : ""}
68
+ onChange={handleHexChange}
69
+ placeholder="#000000"
70
+ className="flex h-10 w-28 rounded-md border border-input bg-transparent px-3 py-2 text-sm font-mono ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
71
+ data-testid="color-hex-input"
72
+ />
73
+ <div
74
+ className="h-10 flex-1 rounded-md border border-input"
75
+ style={{ backgroundColor: color }}
76
+ data-testid="color-preview"
77
+ />
78
+ </div>
79
+ <div className="mt-2 flex gap-1" data-testid="color-presets">
80
+ {PRESETS.map((preset) => (
81
+ <button
82
+ key={preset}
83
+ type="button"
84
+ onClick={() => onChange(preset)}
85
+ className="h-6 w-6 rounded-sm border border-input transition-transform hover:scale-110"
86
+ style={{ backgroundColor: preset }}
87
+ title={preset}
88
+ data-testid={`color-preset-${preset.slice(1)}`}
89
+ />
90
+ ))}
91
+ </div>
92
+ </div>
93
+ );
94
+ }
95
+
96
+ export const fields = {
97
+ picker: ColorPicker,
98
+ };
package/src/index.ts ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Color Picker Plugin for EmDash CMS
3
+ *
4
+ * Provides a color picker field widget that replaces the default
5
+ * string input with a visual color selector. Demonstrates the
6
+ * field widget plugin capability.
7
+ *
8
+ * Usage:
9
+ * 1. Add the plugin to your emdash config
10
+ * 2. Create a field with type "string" and widget "color:picker"
11
+ * 3. The admin editor will show a color picker instead of a text input
12
+ *
13
+ * The color value is stored as a hex string (e.g., "#ff6600").
14
+ */
15
+
16
+ import type { PluginDescriptor } from "emdash";
17
+ import { definePlugin } from "emdash";
18
+
19
+ /**
20
+ * Create the color picker plugin instance.
21
+ * Called by the virtual module system at runtime.
22
+ */
23
+ export function createPlugin() {
24
+ return definePlugin({
25
+ id: "color",
26
+ version: "0.0.1",
27
+
28
+ admin: {
29
+ entry: "@emdash-cms/plugin-color/admin",
30
+ fieldWidgets: [
31
+ {
32
+ name: "picker",
33
+ label: "Color Picker",
34
+ fieldTypes: ["string"],
35
+ },
36
+ ],
37
+ },
38
+ });
39
+ }
40
+
41
+ export default createPlugin;
42
+
43
+ /**
44
+ * Create a plugin descriptor for use in emdash config.
45
+ */
46
+ export function colorPlugin(): PluginDescriptor {
47
+ return {
48
+ id: "color",
49
+ version: "0.0.1",
50
+ entrypoint: "@emdash-cms/plugin-color",
51
+ options: {},
52
+ adminEntry: "@emdash-cms/plugin-color/admin",
53
+ };
54
+ }