@reiwuzen/blocky-react 1.0.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.
@@ -0,0 +1,257 @@
1
+ /* ─── Editor ─────────────────────────────────────────────────────────────────── */
2
+
3
+ .blocky-editor {
4
+ position: relative;
5
+ width: 100%;
6
+ max-width: 720px;
7
+ margin: 0 auto;
8
+ padding: 24px 16px;
9
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
10
+ font-size: 16px;
11
+ line-height: 1.6;
12
+ color: #1a1a1a;
13
+ }
14
+
15
+ .blocky-editor--readonly { pointer-events: none; }
16
+
17
+ /* ─── Block row ──────────────────────────────────────────────────────────────── */
18
+
19
+ .blocky-block-list { display: flex; flex-direction: column; gap: 2px; }
20
+
21
+ .blocky-block-row {
22
+ display: flex;
23
+ align-items: flex-start;
24
+ gap: 4px;
25
+ border-radius: 4px;
26
+ transition: background 0.1s;
27
+ }
28
+
29
+ .blocky-block-row:hover .blocky-gutter { opacity: 1; }
30
+ .blocky-block-row.blocky-drag-over { background: #f0f4ff; outline: 2px dashed #4f6ef7; }
31
+
32
+ /* ─── Gutter ─────────────────────────────────────────────────────────────────── */
33
+
34
+ .blocky-gutter {
35
+ display: flex;
36
+ align-items: center;
37
+ gap: 2px;
38
+ opacity: 0;
39
+ transition: opacity 0.15s;
40
+ padding-top: 3px;
41
+ flex-shrink: 0;
42
+ }
43
+
44
+ .blocky-drag-handle {
45
+ cursor: grab;
46
+ color: #aaa;
47
+ padding: 2px 4px;
48
+ border-radius: 3px;
49
+ }
50
+
51
+ .blocky-drag-handle:hover { color: #555; background: #f0f0f0; }
52
+ .blocky-drag-handle:active { cursor: grabbing; }
53
+
54
+ .blocky-type-btn {
55
+ background: none;
56
+ border: none;
57
+ cursor: pointer;
58
+ color: #aaa;
59
+ font-size: 14px;
60
+ padding: 2px 4px;
61
+ border-radius: 3px;
62
+ line-height: 1;
63
+ }
64
+
65
+ .blocky-type-btn:hover { color: #555; background: #f0f0f0; }
66
+
67
+ /* ─── Block content ──────────────────────────────────────────────────────────── */
68
+
69
+ .blocky-block-content { flex: 1; min-width: 0; position: relative; }
70
+
71
+ .blocky-block {
72
+ outline: none;
73
+ min-height: 1.6em;
74
+ word-break: break-word;
75
+ }
76
+
77
+ .blocky-block:empty::before {
78
+ content: attr(data-placeholder);
79
+ color: #bbb;
80
+ pointer-events: none;
81
+ }
82
+
83
+ /* ─── Block types ────────────────────────────────────────────────────────────── */
84
+
85
+ .blocky-paragraph { font-size: 16px; }
86
+ .blocky-h1 { font-size: 2em; font-weight: 700; margin: 8px 0 4px; }
87
+ .blocky-h2 { font-size: 1.5em; font-weight: 600; margin: 6px 0 3px; }
88
+ .blocky-h3 { font-size: 1.2em; font-weight: 600; margin: 4px 0 2px; }
89
+
90
+ /* ─── Lists ──────────────────────────────────────────────────────────────────── */
91
+
92
+ .blocky-list { display: flex; align-items: flex-start; gap: 8px; }
93
+ .blocky-list-content { flex: 1; outline: none; min-height: 1.6em; }
94
+
95
+ .blocky-bullet-marker { color: #555; font-size: 18px; line-height: 1.4; flex-shrink: 0; }
96
+ .blocky-number-marker { color: #555; font-size: 16px; line-height: 1.6; flex-shrink: 0; }
97
+
98
+ .blocky-todo-checkbox {
99
+ margin-top: 4px;
100
+ width: 16px;
101
+ height: 16px;
102
+ flex-shrink: 0;
103
+ cursor: pointer;
104
+ accent-color: #4f6ef7;
105
+ }
106
+
107
+ /* ─── Code block ─────────────────────────────────────────────────────────────── */
108
+
109
+ .blocky-code-block {
110
+ background: #f6f8fa;
111
+ border: 1px solid #e1e4e8;
112
+ border-radius: 6px;
113
+ padding: 12px 16px;
114
+ margin: 4px 0;
115
+ overflow-x: auto;
116
+ }
117
+
118
+ .blocky-code-content {
119
+ display: block;
120
+ outline: none;
121
+ font-family: "JetBrains Mono", "Fira Code", monospace;
122
+ font-size: 14px;
123
+ line-height: 1.6;
124
+ white-space: pre;
125
+ color: #24292e;
126
+ }
127
+
128
+ /* ─── Equation block ─────────────────────────────────────────────────────────── */
129
+
130
+ .blocky-equation-block {
131
+ display: flex;
132
+ align-items: center;
133
+ gap: 8px;
134
+ padding: 8px 12px;
135
+ background: #fafafa;
136
+ border-left: 3px solid #4f6ef7;
137
+ border-radius: 0 4px 4px 0;
138
+ margin: 4px 0;
139
+ }
140
+
141
+ .blocky-equation-label { color: #4f6ef7; font-weight: 600; font-family: monospace; }
142
+
143
+ .blocky-equation-content {
144
+ flex: 1;
145
+ outline: none;
146
+ font-family: monospace;
147
+ font-size: 15px;
148
+ }
149
+
150
+ /* ─── Inline formatting ──────────────────────────────────────────────────────── */
151
+
152
+ .blocky-highlight-yellow { background: #fff176; border-radius: 2px; padding: 0 1px; }
153
+ .blocky-highlight-green { background: #b9f6ca; border-radius: 2px; padding: 0 1px; }
154
+ .blocky-color-red { color: #e53935; }
155
+ .blocky-color-blue { color: #1e88e5; }
156
+ .blocky-color-green { color: #43a047; }
157
+
158
+ /* ─── Format toolbar ─────────────────────────────────────────────────────────── */
159
+
160
+ .blocky-format-toolbar {
161
+ position: absolute;
162
+ z-index: 100;
163
+ transform: translateX(-50%);
164
+ display: flex;
165
+ align-items: center;
166
+ gap: 2px;
167
+ padding: 4px 6px;
168
+ background: #1a1a1a;
169
+ border-radius: 6px;
170
+ box-shadow: 0 4px 12px rgba(0,0,0,0.25);
171
+ white-space: nowrap;
172
+ }
173
+
174
+ .blocky-toolbar-btn {
175
+ background: none;
176
+ border: none;
177
+ color: #fff;
178
+ cursor: pointer;
179
+ font-size: 13px;
180
+ font-weight: 600;
181
+ padding: 3px 7px;
182
+ border-radius: 4px;
183
+ line-height: 1;
184
+ transition: background 0.1s;
185
+ }
186
+
187
+ .blocky-toolbar-btn:hover { background: rgba(255,255,255,0.15); }
188
+ .blocky-toolbar-btn--italic { font-style: italic; }
189
+ .blocky-toolbar-btn--underline { text-decoration: underline; }
190
+ .blocky-toolbar-btn--strike { text-decoration: line-through; }
191
+ .blocky-toolbar-btn--highlight { background: #fff176; color: #1a1a1a; }
192
+ .blocky-toolbar-btn--red { color: #ff6b6b; }
193
+ .blocky-toolbar-btn--blue { color: #74b9ff; }
194
+
195
+ .blocky-toolbar-divider {
196
+ width: 1px;
197
+ height: 16px;
198
+ background: rgba(255,255,255,0.2);
199
+ margin: 0 2px;
200
+ }
201
+
202
+ /* ─── Block type switcher ────────────────────────────────────────────────────── */
203
+
204
+ .blocky-type-switcher {
205
+ position: absolute;
206
+ z-index: 100;
207
+ top: 100%;
208
+ left: 0;
209
+ display: flex;
210
+ flex-direction: column;
211
+ background: #fff;
212
+ border: 1px solid #e1e4e8;
213
+ border-radius: 6px;
214
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
215
+ padding: 4px;
216
+ min-width: 120px;
217
+ }
218
+
219
+ .blocky-type-option {
220
+ background: none;
221
+ border: none;
222
+ cursor: pointer;
223
+ text-align: left;
224
+ padding: 6px 10px;
225
+ font-size: 14px;
226
+ border-radius: 4px;
227
+ color: #1a1a1a;
228
+ transition: background 0.1s;
229
+ }
230
+
231
+ .blocky-type-option:hover { background: #f0f4ff; }
232
+ .blocky-type-option--active { background: #f0f4ff; color: #4f6ef7; font-weight: 600; }
233
+
234
+ /* ─── Updated structure ──────────────────────────────────────────────────────── */
235
+
236
+ .blocky-block-wrapper {
237
+ flex: 1;
238
+ min-width: 0;
239
+ position: relative;
240
+ display: flex;
241
+ align-items: flex-start;
242
+ gap: 8px;
243
+ }
244
+
245
+ /* .blocky-block-content IS now the contentEditable */
246
+ .blocky-block-content {
247
+ flex: 1;
248
+ outline: none;
249
+ min-height: 1.6em;
250
+ word-break: break-word;
251
+ }
252
+
253
+ .blocky-block-content:empty::before {
254
+ content: attr(data-placeholder);
255
+ color: #bbb;
256
+ pointer-events: none;
257
+ }
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@reiwuzen/blocky-react",
3
+ "version": "1.0.0",
4
+ "description": "React UI layer for @reiwuzen/blocky — composable block editor components.",
5
+ "author": "Rei WuZen",
6
+ "license": "ISC",
7
+ "type": "module",
8
+ "sideEffects": [
9
+ "./dist/styles.css"
10
+ ],
11
+ "main": "./dist/index.cjs",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js",
18
+ "require": "./dist/index.cjs"
19
+ },
20
+ "./styles.css": "./dist/styles.css"
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "peerDependencies": {
29
+ "react": ">=18",
30
+ "react-dom": ">=18"
31
+ },
32
+ "dependencies": {
33
+ "@reiwuzen/blocky": "^1.2.0",
34
+ "zustand": "^5.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@testing-library/jest-dom": "^6.0.0",
38
+ "@testing-library/react": "^16.0.0",
39
+ "@testing-library/user-event": "^14.0.0",
40
+ "@types/react": "^19.0.0",
41
+ "@types/react-dom": "^19.0.0",
42
+ "@vitest/coverage-v8": "^2.0.0",
43
+ "cpy-cli": "^7.0.0",
44
+ "jsdom": "^25.0.0",
45
+ "rimraf": "^6.0.1",
46
+ "tsup": "^8.5.1",
47
+ "typescript": "^5.9.3",
48
+ "vitest": "^2.0.0"
49
+ },
50
+ "keywords": [
51
+ "block-editor",
52
+ "rich-text",
53
+ "react",
54
+ "headless",
55
+ "notion-like"
56
+ ],
57
+ "scripts": {
58
+ "clean": "rimraf dist",
59
+ "build": "tsup",
60
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
61
+ "test": "vitest run",
62
+ "test:watch": "vitest"
63
+ }
64
+ }