@scrawl-board/board 0.1.0-beta.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,297 @@
1
+ [data-scrawl-root],
2
+ [data-scrawl-portal] {
3
+ --scrawl-color-surface: #ffffff;
4
+ --scrawl-color-surface-raised: #f7f7f4;
5
+ --scrawl-color-surface-muted: #ecece7;
6
+ --scrawl-color-text: #1c1c1a;
7
+ --scrawl-color-text-muted: #62625c;
8
+ --scrawl-color-edge: #d4d4cc;
9
+ --scrawl-color-focus: #1856a3;
10
+ --scrawl-color-selection: #d9e8f7;
11
+ --scrawl-color-danger: #a3302b;
12
+ --scrawl-color-warning: #805400;
13
+ --scrawl-color-success: #28633b;
14
+ --scrawl-font-ui: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
15
+ --scrawl-font-data: ui-monospace, SFMono-Regular, monospace;
16
+ --scrawl-font-size: 14px;
17
+ --scrawl-font-weight: 400;
18
+ --scrawl-font-weight-strong: 650;
19
+ --scrawl-radius-control: 6px;
20
+ --scrawl-radius-panel: 10px;
21
+ --scrawl-elevation-low: 0 2px 3px rgba(28, 28, 26, 0.12);
22
+ --scrawl-elevation-high: 0 8px 20px rgba(28, 28, 26, 0.18);
23
+ --scrawl-motion-duration: 140ms;
24
+ --scrawl-motion-easing: cubic-bezier(0.2, 0, 0, 1);
25
+ --scrawl-density: comfortable;
26
+ box-sizing: border-box;
27
+ color: var(--scrawl-color-text);
28
+ font-family: var(--scrawl-font-ui);
29
+ font-size: var(--scrawl-font-size);
30
+ font-weight: var(--scrawl-font-weight);
31
+ line-height: 1.4;
32
+ }
33
+
34
+ [data-scrawl-root] {
35
+ background: var(--scrawl-color-surface);
36
+ block-size: 100%;
37
+ inline-size: 100%;
38
+ isolation: isolate;
39
+ min-block-size: 12rem;
40
+ min-inline-size: 16rem;
41
+ overflow: visible;
42
+ position: relative;
43
+ }
44
+
45
+ [data-scrawl-root] *, [data-scrawl-root] *::before, [data-scrawl-root] *::after,
46
+ [data-scrawl-portal] *, [data-scrawl-portal] *::before, [data-scrawl-portal] *::after { box-sizing: border-box; }
47
+
48
+ [data-scrawl-root] button, [data-scrawl-root] input, [data-scrawl-root] select, [data-scrawl-root] textarea,
49
+ [data-scrawl-portal] button, [data-scrawl-portal] input, [data-scrawl-portal] select, [data-scrawl-portal] textarea {
50
+ color: inherit;
51
+ font: inherit;
52
+ line-height: 1.4;
53
+ }
54
+
55
+ [data-scrawl-root] button, [data-scrawl-root] [role="button"],
56
+ [data-scrawl-portal] button, [data-scrawl-portal] [role="button"] { min-block-size: 44px; min-inline-size: 44px; }
57
+
58
+ [data-scrawl-root] :focus-visible, [data-scrawl-portal] :focus-visible {
59
+ outline: 3px solid var(--scrawl-color-focus);
60
+ outline-offset: 2px;
61
+ }
62
+
63
+ [data-scrawl-root] [data-scrawl-canvas], [data-scrawl-root] .scrawl-board__content {
64
+ block-size: 100%;
65
+ inline-size: 100%;
66
+ min-block-size: inherit;
67
+ min-inline-size: inherit;
68
+ position: relative;
69
+ }
70
+
71
+ [data-scrawl-root] [data-scrawl-canvas] { overflow: clip; }
72
+
73
+ [data-scrawl-root] .scrawl-board__canvas {
74
+ block-size: 100%;
75
+ display: block;
76
+ inline-size: 100%;
77
+ touch-action: none;
78
+ }
79
+
80
+ [data-scrawl-root] .scrawl-board__portal-layer, [data-scrawl-portal] {
81
+ color: var(--scrawl-color-text);
82
+ font-family: var(--scrawl-font-ui);
83
+ line-height: 1.4;
84
+ overflow: visible;
85
+ position: relative;
86
+ z-index: 20;
87
+ }
88
+
89
+ [data-scrawl-root] .scrawl-board__portal-layer {
90
+ inset: 0;
91
+ pointer-events: none;
92
+ position: absolute;
93
+ }
94
+
95
+ [data-scrawl-root] [data-scrawl-default-ui] {
96
+ inset: 0;
97
+ pointer-events: none;
98
+ position: absolute;
99
+ z-index: 10;
100
+ }
101
+
102
+ [data-scrawl-root] .scrawl-board__actions,
103
+ [data-scrawl-root] .scrawl-board__tools,
104
+ [data-scrawl-root] .scrawl-board__view,
105
+ [data-scrawl-root] .scrawl-board__style-shelf {
106
+ align-items: center;
107
+ background: var(--scrawl-color-surface-raised);
108
+ border: 1px solid color-mix(in srgb, var(--scrawl-color-surface-raised), var(--scrawl-color-text) 12%);
109
+ border-radius: var(--scrawl-radius-panel);
110
+ display: flex;
111
+ gap: 2px;
112
+ padding: 4px;
113
+ pointer-events: auto;
114
+ position: absolute;
115
+ }
116
+
117
+ [data-scrawl-root] .scrawl-board__actions { inset-block-start: 12px; inset-inline-end: 12px; }
118
+ [data-scrawl-root] .scrawl-board__tools { inset-block-end: 12px; inset-inline-start: 50%; max-inline-size: calc(100% - 24px); transform: translateX(-50%); }
119
+ [data-scrawl-root] .scrawl-board__view { inset-block-end: 12px; inset-inline-end: 12px; }
120
+ [data-scrawl-root] .scrawl-board__style-shelf {
121
+ gap: 12px;
122
+ inset-block-end: 68px;
123
+ inset-inline-start: 50%;
124
+ max-inline-size: calc(100% - 24px);
125
+ overflow-x: auto;
126
+ transform: translateX(-50%);
127
+ }
128
+ [data-scrawl-root] .scrawl-board__style-group { align-items: center; display: flex; gap: 6px; white-space: nowrap; }
129
+ [data-scrawl-root] .scrawl-board__style-group > span:first-child { color: var(--scrawl-color-text-muted); font-size: 0.75rem; font-weight: var(--scrawl-font-weight-strong); text-transform: uppercase; }
130
+ [data-scrawl-root] .scrawl-board__style-group button { align-items: center; display: flex; justify-content: center; padding: 6px 10px; }
131
+ [data-scrawl-root] .scrawl-board__style-group button span[aria-hidden] { block-size: 18px; border-radius: 50%; inline-size: 18px; }
132
+
133
+ [data-scrawl-root] [data-scrawl-default-ui] button,
134
+ [data-scrawl-root] [data-scrawl-default-ui] select,
135
+ [data-scrawl-portal] .scrawl-board__panel button,
136
+ [data-scrawl-portal] .scrawl-board__panel input {
137
+ background: transparent;
138
+ border: 0;
139
+ border-radius: var(--scrawl-radius-control);
140
+ color: var(--scrawl-color-text);
141
+ }
142
+
143
+ [data-scrawl-root] [data-scrawl-default-ui] button,
144
+ [data-scrawl-portal] .scrawl-board__panel button {
145
+ cursor: pointer;
146
+ padding: 8px 10px;
147
+ }
148
+
149
+ [data-scrawl-root] [data-scrawl-default-ui] button:hover,
150
+ [data-scrawl-portal] .scrawl-board__panel button:hover { background: var(--scrawl-color-surface-muted); }
151
+
152
+ [data-scrawl-root] [data-scrawl-default-ui] button[aria-pressed="true"],
153
+ [data-scrawl-portal] .scrawl-board__panel button[aria-pressed="true"] {
154
+ background: var(--scrawl-color-selection);
155
+ font-weight: var(--scrawl-font-weight-strong);
156
+ }
157
+
158
+ [data-scrawl-root] [data-scrawl-default-ui] button:disabled,
159
+ [data-scrawl-root] [data-scrawl-default-ui] select:disabled { color: var(--scrawl-color-text-muted); cursor: not-allowed; }
160
+
161
+ [data-scrawl-root] .scrawl-board__tool-select {
162
+ align-items: center;
163
+ display: flex;
164
+ min-block-size: 44px;
165
+ }
166
+
167
+ [data-scrawl-root] .scrawl-board__tool-select > span { block-size: 1px; clip: rect(0, 0, 0, 0); inline-size: 1px; overflow: hidden; position: absolute; }
168
+ [data-scrawl-root] .scrawl-board__tool-select select {
169
+ -webkit-appearance: none;
170
+ appearance: none;
171
+ /* Chevron drawn from two gradient triangles rather than an embedded asset
172
+ reference (disallowed by this stylesheet's policy, see styles.test.ts),
173
+ and currentColor keeps it Theme-aware where a bitmap/SVG asset would
174
+ need its own colour. */
175
+ background-image:
176
+ linear-gradient(45deg, transparent 50%, currentColor 50%),
177
+ linear-gradient(135deg, currentColor 50%, transparent 50%);
178
+ background-position: right 14px center, right 9px center;
179
+ background-repeat: no-repeat;
180
+ background-size: 5px 5px, 5px 5px;
181
+ min-block-size: 44px;
182
+ padding-inline: 8px 24px;
183
+ }
184
+
185
+ [data-scrawl-root] .scrawl-board__ink-sample,
186
+ [data-scrawl-portal] .scrawl-board__ink-options span {
187
+ border: 1px solid color-mix(in srgb, currentColor, transparent 72%);
188
+ border-radius: 50%;
189
+ block-size: 18px;
190
+ display: inline-block;
191
+ inline-size: 18px;
192
+ margin-inline-end: 6px;
193
+ vertical-align: middle;
194
+ }
195
+
196
+ [data-scrawl-root] .scrawl-board__file-input { block-size: 1px; clip: rect(0, 0, 0, 0); inline-size: 1px; overflow: hidden; position: absolute; }
197
+
198
+ [data-scrawl-portal] .scrawl-board__modal-layer {
199
+ inset: 0;
200
+ pointer-events: auto;
201
+ position: absolute;
202
+ z-index: 30;
203
+ }
204
+
205
+ [data-scrawl-portal] .scrawl-board__panel {
206
+ background: var(--scrawl-color-surface-raised);
207
+ border: 1px solid color-mix(in srgb, var(--scrawl-color-surface-raised), var(--scrawl-color-text) 14%);
208
+ border-radius: var(--scrawl-radius-panel);
209
+ box-shadow: var(--scrawl-elevation-high);
210
+ color: var(--scrawl-color-text);
211
+ inline-size: min(28rem, calc(100vw - 32px));
212
+ inset-block-end: 68px;
213
+ inset-inline-start: 50%;
214
+ max-block-size: min(32rem, calc(100vh - 96px));
215
+ overflow: auto;
216
+ padding: 12px;
217
+ pointer-events: auto;
218
+ position: absolute;
219
+ transform: translateX(-50%);
220
+ z-index: 1;
221
+ }
222
+
223
+ [data-scrawl-portal] .scrawl-board__panel-heading { align-items: center; display: flex; justify-content: space-between; margin-block-end: 10px; }
224
+ [data-scrawl-portal] .scrawl-board__panel-heading h2 { font-size: 1rem; line-height: 1.4; margin: 0; }
225
+ [data-scrawl-portal] .scrawl-board__ink-options,
226
+ [data-scrawl-portal] .scrawl-board__export-options { display: grid; gap: 4px; grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr)); }
227
+ [data-scrawl-portal] .scrawl-board__ink-options button,
228
+ [data-scrawl-portal] .scrawl-board__export-options button { text-align: start; }
229
+
230
+ [data-scrawl-portal] [data-scrawl-search] label { display: grid; font-weight: var(--scrawl-font-weight-strong); gap: 6px; }
231
+ [data-scrawl-portal] [data-scrawl-search] input { background: var(--scrawl-color-surface); border: 1px solid var(--scrawl-color-edge); min-block-size: 44px; padding: 8px 10px; }
232
+ [data-scrawl-portal] [data-scrawl-search-results] { display: grid; gap: 4px; margin-block-start: 8px; }
233
+ [data-scrawl-portal] [data-scrawl-search-results] button { display: grid; gap: 2px; text-align: start; }
234
+ [data-scrawl-portal] [data-scrawl-search-results] span { color: var(--scrawl-color-text-muted); }
235
+
236
+ [data-scrawl-portal] .scrawl-board__inline-editor {
237
+ background: var(--scrawl-color-surface);
238
+ border: 1px solid var(--scrawl-color-focus);
239
+ border-radius: var(--scrawl-radius-control);
240
+ box-shadow: var(--scrawl-elevation-high);
241
+ min-block-size: 32px;
242
+ padding: 6px 8px;
243
+ pointer-events: auto;
244
+ position: absolute;
245
+ resize: none;
246
+ white-space: pre-wrap;
247
+ word-break: break-word;
248
+ z-index: 25;
249
+ }
250
+
251
+ [data-scrawl-portal] .scrawl-board__inline-editor--table-cell {
252
+ pointer-events: auto;
253
+ position: absolute;
254
+ z-index: 25;
255
+ }
256
+ [data-scrawl-portal] .scrawl-board__inline-editor--table-cell .scrawl-board__inline-editor { inset: 0; block-size: 100%; inline-size: 100%; position: absolute; }
257
+
258
+ [data-scrawl-portal] .scrawl-board__inline-editor-actions {
259
+ align-items: center;
260
+ background: var(--scrawl-color-surface-raised);
261
+ border-radius: var(--scrawl-radius-control);
262
+ box-shadow: var(--scrawl-elevation-low);
263
+ display: flex;
264
+ font-size: 0.75rem;
265
+ gap: 6px;
266
+ inset-block-end: calc(100% + 4px);
267
+ inset-inline-start: 0;
268
+ padding: 2px 6px;
269
+ position: absolute;
270
+ white-space: nowrap;
271
+ }
272
+ [data-scrawl-portal] .scrawl-board__inline-editor-actions button { min-block-size: auto; min-inline-size: auto; padding: 2px 6px; }
273
+
274
+ @media (max-width: 60rem) {
275
+ [data-scrawl-root] .scrawl-board__actions,
276
+ [data-scrawl-root] .scrawl-board__tools { inline-size: calc(100% - 24px); overflow-x: auto; }
277
+ [data-scrawl-root] .scrawl-board__actions { justify-content: flex-end; }
278
+ [data-scrawl-root] .scrawl-board__tools { flex-wrap: nowrap; inset-inline-start: 12px; transform: none; }
279
+ [data-scrawl-root] .scrawl-board__tools :focus-visible { outline-offset: -3px; }
280
+ [data-scrawl-root] .scrawl-board__view { inset-block-end: 84px; }
281
+ }
282
+
283
+ [data-scrawl-root] .scrawl-board__status, [data-scrawl-portal] .scrawl-board__status {
284
+ block-size: 1px;
285
+ border: 0;
286
+ clip: rect(0, 0, 0, 0);
287
+ inline-size: 1px;
288
+ margin: -1px;
289
+ overflow: hidden;
290
+ padding: 0;
291
+ position: absolute;
292
+ white-space: nowrap;
293
+ }
294
+
295
+ @media (prefers-reduced-motion: reduce) {
296
+ [data-scrawl-root], [data-scrawl-portal] { --scrawl-motion-duration: 0ms !important; }
297
+ }
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@scrawl-board/board",
3
+ "version": "0.1.0-beta.0",
4
+ "description": "The Scrawl Board SDK: an embeddable, collaborative infinite-canvas whiteboard for React and vanilla JS/TS apps.",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/purelogiclimited/scrawl-board-sdk.git",
9
+ "directory": "packages/board"
10
+ },
11
+ "homepage": "https://github.com/purelogiclimited/scrawl-board-sdk/tree/main/packages/board#readme",
12
+ "bugs": "https://github.com/purelogiclimited/scrawl-board-sdk/issues",
13
+ "publishConfig": {
14
+ "access": "public",
15
+ "tag": "beta"
16
+ },
17
+ "type": "module",
18
+ "sideEffects": [
19
+ "./dist/styles.css"
20
+ ],
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "LICENSE",
25
+ "NOTICE"
26
+ ],
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js"
31
+ },
32
+ "./core": {
33
+ "types": "./dist/core.d.ts",
34
+ "import": "./dist/core.js"
35
+ },
36
+ "./browser": {
37
+ "types": "./dist/browser.d.ts",
38
+ "import": "./dist/browser.js"
39
+ },
40
+ "./react": {
41
+ "types": "./dist/react.d.ts",
42
+ "import": "./dist/react.js"
43
+ },
44
+ "./styles.css": "./dist/styles.css"
45
+ },
46
+ "scripts": {
47
+ "build": "node ./scripts/build.mjs",
48
+ "prepack": "npm run build",
49
+ "license-check": "node ./scripts/check-license-allowlist.mjs",
50
+ "notice": "node ./scripts/generate-notice.mjs",
51
+ "sbom": "node ./scripts/generate-sbom.mjs",
52
+ "size": "size-limit",
53
+ "lint:pack": "publint . && attw --pack . --exclude-entrypoints ./styles.css --profile esm-only",
54
+ "api-report": "node ./scripts/generate-api-docs.mjs"
55
+ },
56
+ "peerDependencies": {
57
+ "react": ">=18 <20",
58
+ "react-dom": ">=18 <20"
59
+ },
60
+ "devDependencies": {
61
+ "@arethetypeswrong/cli": "^0.18.5",
62
+ "@cyclonedx/cyclonedx-npm": "^6.0.1",
63
+ "@microsoft/api-extractor": "^7.59.0",
64
+ "@size-limit/file": "^13.0.3",
65
+ "@types/react": "^19",
66
+ "@types/ws": "^8.18.1",
67
+ "publint": "^0.3.24",
68
+ "size-limit": "^13.0.3",
69
+ "vite": "^8.1.4",
70
+ "ws": "^8.21.3"
71
+ }
72
+ }