@pragma-sh/scratchpad 0.1.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,454 @@
1
+ // src/styles.ts
2
+ var SCRATCHPAD_STYLE_ELEMENT_ID = "pragma-scratchpad-styles";
3
+ var SCRATCHPAD_STYLES = `
4
+ .pragma-card {
5
+ display: grid;
6
+ gap: 0.75rem;
7
+ margin: 1rem 0;
8
+ padding: 0.875rem 1rem;
9
+ border: 1px solid var(--border, #3f3f46);
10
+ border-radius: var(--radius-lg, 10px);
11
+ background: var(--card, #18181b);
12
+ color: var(--card-foreground, #fafafa);
13
+ box-shadow: var(--shadow-raised, 0 1px 2px rgb(0 0 0 / 0.3));
14
+ font-family: var(--font-sans, system-ui, sans-serif);
15
+ font-size: 0.8125rem;
16
+ line-height: 1.55;
17
+ }
18
+ .pragma-card > :first-child { margin-top: 0; }
19
+ .pragma-card > :last-child { margin-bottom: 0; }
20
+
21
+ .pragma-eyebrow {
22
+ font-size: 0.6875rem;
23
+ font-weight: 600;
24
+ letter-spacing: 0.06em;
25
+ text-transform: uppercase;
26
+ color: var(--muted-foreground, #a1a1aa);
27
+ }
28
+ .pragma-title {
29
+ font-size: 0.9375rem;
30
+ font-weight: 600;
31
+ line-height: 1.4;
32
+ color: var(--card-foreground, #fafafa);
33
+ }
34
+ .pragma-hint { font-size: 0.75rem; color: var(--muted-foreground, #a1a1aa); }
35
+ .pragma-stack { display: grid; gap: 0.5rem; }
36
+ .pragma-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
37
+ .pragma-row--between { justify-content: space-between; }
38
+ .pragma-row--end { justify-content: flex-end; }
39
+ .pragma-empty {
40
+ padding: 0.75rem;
41
+ border: 1px dashed var(--border, #3f3f46);
42
+ border-radius: var(--radius-md, 8px);
43
+ font-size: 0.75rem;
44
+ color: var(--muted-foreground, #a1a1aa);
45
+ text-align: center;
46
+ }
47
+ .pragma-chip {
48
+ padding: 0.0625rem 0.375rem;
49
+ border-radius: var(--radius-sm, 6px);
50
+ background: var(--muted, #27272a);
51
+ color: var(--muted-foreground, #a1a1aa);
52
+ font-family: var(--font-mono, ui-monospace, monospace);
53
+ font-size: 0.6875rem;
54
+ }
55
+
56
+ .pragma-button {
57
+ display: inline-flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ gap: 0.375rem;
61
+ min-height: 2rem;
62
+ padding: 0 0.75rem;
63
+ border: 1px solid transparent;
64
+ border-radius: var(--radius-md, 8px);
65
+ font-family: inherit;
66
+ font-size: 0.8125rem;
67
+ font-weight: 500;
68
+ line-height: 1;
69
+ cursor: pointer;
70
+ white-space: nowrap;
71
+ transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
72
+ }
73
+ .pragma-button:focus-visible { outline: 2px solid var(--ring, #22d3ee); outline-offset: 2px; }
74
+ .pragma-button:disabled { cursor: not-allowed; opacity: 0.5; }
75
+ .pragma-button--sm { min-height: 1.75rem; padding: 0 0.5rem; font-size: 0.75rem; }
76
+ .pragma-button--primary {
77
+ background: var(--primary, #2563eb);
78
+ color: var(--primary-foreground, #fafafa);
79
+ }
80
+ .pragma-button--primary:hover:not(:disabled) { background: var(--primary-hover, #1d4ed8); }
81
+ .pragma-button--secondary {
82
+ background: var(--secondary, #27272a);
83
+ color: var(--secondary-foreground, #fafafa);
84
+ }
85
+ .pragma-button--secondary:hover:not(:disabled) { background: var(--accent, #3f3f46); }
86
+ .pragma-button--outline {
87
+ border-color: var(--input, #3f3f46);
88
+ background: transparent;
89
+ color: var(--foreground, #fafafa);
90
+ }
91
+ .pragma-button--outline:hover:not(:disabled) {
92
+ background: var(--accent, #27272a);
93
+ color: var(--accent-foreground, #fafafa);
94
+ }
95
+ .pragma-button--ghost { background: transparent; color: var(--muted-foreground, #a1a1aa); }
96
+ .pragma-button--ghost:hover:not(:disabled) {
97
+ background: var(--accent, #27272a);
98
+ color: var(--accent-foreground, #fafafa);
99
+ }
100
+ .pragma-button--danger {
101
+ background: var(--destructive, #ef4444);
102
+ color: var(--destructive-foreground, #fafafa);
103
+ }
104
+ .pragma-button--danger:hover:not(:disabled) { filter: brightness(1.08); }
105
+
106
+ .pragma-input,
107
+ .pragma-textarea {
108
+ width: 100%;
109
+ padding: 0.4375rem 0.625rem;
110
+ border: 1px solid var(--input, #3f3f46);
111
+ border-radius: var(--radius-md, 8px);
112
+ background: var(--background, #09090b);
113
+ color: var(--foreground, #fafafa);
114
+ font-family: inherit;
115
+ font-size: 0.8125rem;
116
+ line-height: 1.5;
117
+ transition: border-color 0.12s ease;
118
+ }
119
+ .pragma-input::placeholder,
120
+ .pragma-textarea::placeholder { color: var(--muted-foreground, #71717a); }
121
+ .pragma-input:focus-visible,
122
+ .pragma-textarea:focus-visible {
123
+ border-color: var(--ring, #22d3ee);
124
+ outline: 2px solid var(--ring, #22d3ee);
125
+ outline-offset: -1px;
126
+ }
127
+ .pragma-input:disabled,
128
+ .pragma-textarea:disabled { cursor: not-allowed; opacity: 0.5; }
129
+ .pragma-textarea { min-height: 5rem; resize: vertical; }
130
+
131
+ /*
132
+ * Choice list shared by every AskQuestion shape: a circular radio for a single
133
+ * answer, a square checkbox for multi-select. The native control is restyled
134
+ * (\`appearance: none\`) rather than replaced, so keyboard roving, labels and
135
+ * form semantics keep working inside the sandboxed frame.
136
+ */
137
+ .pragma-choices { display: grid; gap: 0.25rem; }
138
+ .pragma-choice {
139
+ display: flex;
140
+ align-items: center;
141
+ gap: 0.5rem;
142
+ padding: 0.4375rem 0.5rem;
143
+ border: 1px solid transparent;
144
+ border-radius: var(--radius-md, 8px);
145
+ cursor: pointer;
146
+ transition: background-color 0.12s ease, border-color 0.12s ease;
147
+ }
148
+ .pragma-choice:hover { background: var(--accent, #27272a); }
149
+ .pragma-choice--checked {
150
+ border-color: color-mix(in oklab, var(--primary, #2563eb) 45%, transparent);
151
+ background: color-mix(in oklab, var(--primary, #2563eb) 10%, transparent);
152
+ }
153
+ .pragma-choice:has(:disabled) { cursor: not-allowed; opacity: 0.5; }
154
+ .pragma-choice:has(:disabled):hover { background: transparent; }
155
+ .pragma-choice__control {
156
+ appearance: none;
157
+ -webkit-appearance: none;
158
+ display: grid;
159
+ place-content: center;
160
+ flex: none;
161
+ width: 1rem;
162
+ height: 1rem;
163
+ margin: 0;
164
+ border: 1px solid var(--input, #3f3f46);
165
+ background: var(--background, #09090b);
166
+ cursor: inherit;
167
+ transition: background-color 0.12s ease, border-color 0.12s ease;
168
+ }
169
+ .pragma-choice__control--radio { border-radius: 999px; }
170
+ .pragma-choice__control--check { border-radius: var(--radius-sm, 6px); }
171
+ .pragma-choice__control:focus-visible { outline: 2px solid var(--ring, #22d3ee); outline-offset: 2px; }
172
+ .pragma-choice__control:checked { border-color: var(--primary, #2563eb); }
173
+ .pragma-choice__control--radio:checked::after {
174
+ content: "";
175
+ width: 0.5rem;
176
+ height: 0.5rem;
177
+ border-radius: 999px;
178
+ background: var(--primary, #2563eb);
179
+ }
180
+ .pragma-choice__control--check:checked { background: var(--primary, #2563eb); }
181
+ .pragma-choice__control--check:checked::after {
182
+ content: "";
183
+ width: 0.3125rem;
184
+ height: 0.5625rem;
185
+ margin-top: -0.125rem;
186
+ border: solid var(--primary-foreground, #fafafa);
187
+ border-width: 0 2px 2px 0;
188
+ transform: rotate(45deg);
189
+ }
190
+ .pragma-choice__label { flex: 1; min-width: 0; font-size: 0.8125rem; }
191
+ /* The "Other" row swaps its text for this field, so it has to sit on the row. */
192
+ .pragma-choice__other {
193
+ padding: 0.125rem 0.375rem;
194
+ font-size: 0.8125rem;
195
+ cursor: text;
196
+ }
197
+
198
+ .pragma-progress {
199
+ appearance: none;
200
+ width: 100%;
201
+ height: 0.375rem;
202
+ border: 0;
203
+ border-radius: 999px;
204
+ overflow: hidden;
205
+ background: var(--muted, #27272a);
206
+ color: var(--pragma-tone, var(--primary, #22d3ee));
207
+ }
208
+ .pragma-progress::-webkit-progress-bar { background: var(--muted, #27272a); border-radius: 999px; }
209
+ .pragma-progress::-webkit-progress-value {
210
+ background: var(--pragma-tone, var(--primary, #22d3ee));
211
+ border-radius: 999px;
212
+ transition: width 0.25s ease;
213
+ }
214
+ .pragma-progress::-moz-progress-bar {
215
+ background: var(--pragma-tone, var(--primary, #22d3ee));
216
+ border-radius: 999px;
217
+ }
218
+
219
+ .pragma-badge {
220
+ display: inline-flex;
221
+ align-items: center;
222
+ gap: 0.25rem;
223
+ padding: 0.0625rem 0.4375rem;
224
+ border: 1px solid currentColor;
225
+ border-radius: 999px;
226
+ background: transparent;
227
+ color: var(--muted-foreground, #a1a1aa);
228
+ font-size: 0.6875rem;
229
+ font-weight: 500;
230
+ line-height: 1.5;
231
+ }
232
+ .pragma-badge--primary { color: var(--primary, #22d3ee); }
233
+ .pragma-badge--success { color: var(--success, #22c55e); }
234
+ .pragma-badge--warning { color: var(--warning, #eab308); }
235
+ .pragma-badge--danger { color: var(--destructive, #ef4444); }
236
+
237
+ .pragma-whiteboard__open {
238
+ display: block;
239
+ width: 100%;
240
+ padding: 0;
241
+ border: 0;
242
+ border-radius: var(--radius-md, 8px);
243
+ background: transparent;
244
+ cursor: pointer;
245
+ }
246
+ .pragma-whiteboard__open:focus-visible {
247
+ outline: 2px solid var(--ring, #22d3ee);
248
+ outline-offset: 2px;
249
+ }
250
+ .pragma-whiteboard__open:hover .pragma-whiteboard__image {
251
+ border-color: var(--primary, #22d3ee);
252
+ }
253
+ .pragma-whiteboard__image {
254
+ display: block;
255
+ width: 100%;
256
+ height: auto;
257
+ max-height: 36rem;
258
+ object-fit: contain;
259
+ border: 1px solid var(--border, #3f3f46);
260
+ border-radius: var(--radius-md, 8px);
261
+ background: var(--background, #09090b);
262
+ transition: border-color 0.15s ease;
263
+ }
264
+ .pragma-whiteboard__error {
265
+ margin: 0;
266
+ color: var(--destructive, #ef4444);
267
+ font-size: 0.75rem;
268
+ }
269
+
270
+ /*
271
+ * Side-by-side diff modelled on the desktop's \`@codemirror/merge\` view: one
272
+ * scroll container so both panes stay row-aligned, a line-number gutter per
273
+ * pane, whole-line tinting for inserted/deleted lines and a stronger tint on
274
+ * the words that actually changed (the equivalent of \`cm-changedText\`).
275
+ */
276
+ .pragma-diff {
277
+ display: grid;
278
+ grid-template-columns: repeat(2, minmax(0, 1fr));
279
+ max-height: 24rem;
280
+ overflow-y: auto;
281
+ border: 1px solid var(--border, #3f3f46);
282
+ border-radius: var(--radius-md, 8px);
283
+ background: var(--background, #09090b);
284
+ font-family: var(--font-mono, ui-monospace, monospace);
285
+ font-size: 0.75rem;
286
+ line-height: 1.6;
287
+ --pragma-diff-added: var(--diff-added, #22c55e);
288
+ --pragma-diff-removed: var(--diff-removed, #ef4444);
289
+ }
290
+ @media (max-width: 34rem) { .pragma-diff { grid-template-columns: minmax(0, 1fr); } }
291
+ .pragma-diff__pane { min-width: 0; overflow-x: auto; }
292
+ .pragma-diff__pane--after { border-left: 1px solid var(--border, #3f3f46); }
293
+ @media (max-width: 34rem) {
294
+ .pragma-diff__pane--after {
295
+ border-left: 0;
296
+ border-top: 1px solid var(--border, #3f3f46);
297
+ }
298
+ }
299
+ .pragma-diff__label {
300
+ display: flex;
301
+ justify-content: space-between;
302
+ gap: 0.5rem;
303
+ padding: 0.25rem 0.625rem;
304
+ border-bottom: 1px solid var(--border, #3f3f46);
305
+ background: var(--card, #18181b);
306
+ font-family: var(--font-sans, system-ui, sans-serif);
307
+ font-size: 0.6875rem;
308
+ font-weight: 600;
309
+ letter-spacing: 0.06em;
310
+ text-transform: uppercase;
311
+ }
312
+ .pragma-diff__pane--before .pragma-diff__label { color: var(--pragma-diff-removed); }
313
+ .pragma-diff__pane--after .pragma-diff__label { color: var(--pragma-diff-added); }
314
+
315
+ .pragma-diff__lines { display: grid; padding: 0.25rem 0; min-width: max-content; }
316
+ .pragma-diff__line {
317
+ display: grid;
318
+ grid-template-columns: 2.75rem minmax(0, 1fr);
319
+ min-height: 1.6em;
320
+ white-space: pre;
321
+ }
322
+ .pragma-diff__gutter {
323
+ padding-right: 0.625rem;
324
+ color: var(--muted-foreground, #71717a);
325
+ opacity: 0.7;
326
+ text-align: right;
327
+ user-select: none;
328
+ }
329
+ .pragma-diff__text { padding-right: 0.75rem; font: inherit; }
330
+ .pragma-diff__line--removed {
331
+ background: color-mix(in oklab, var(--pragma-diff-removed) 12%, transparent);
332
+ }
333
+ .pragma-diff__line--added {
334
+ background: color-mix(in oklab, var(--pragma-diff-added) 12%, transparent);
335
+ }
336
+ .pragma-diff__pane--before .pragma-diff__line--changed {
337
+ background: color-mix(in oklab, var(--pragma-diff-removed) 12%, transparent);
338
+ }
339
+ .pragma-diff__pane--after .pragma-diff__line--changed {
340
+ background: color-mix(in oklab, var(--pragma-diff-added) 12%, transparent);
341
+ }
342
+ .pragma-diff__line--spacer { background: var(--muted, #27272a); opacity: 0.35; }
343
+ .pragma-diff__pane--before .pragma-diff__changed {
344
+ background: color-mix(in oklab, var(--pragma-diff-removed) 30%, transparent);
345
+ }
346
+ .pragma-diff__pane--after .pragma-diff__changed {
347
+ background: color-mix(in oklab, var(--pragma-diff-added) 30%, transparent);
348
+ }
349
+
350
+ .pragma-progress-row { display: grid; gap: 0.3125rem; }
351
+ .pragma-progress-row + .pragma-progress-row {
352
+ padding-top: 0.625rem;
353
+ border-top: 1px solid var(--border, #3f3f46);
354
+ }
355
+ .pragma-progress-row__name {
356
+ min-width: 0;
357
+ overflow: hidden;
358
+ font-weight: 500;
359
+ text-overflow: ellipsis;
360
+ white-space: nowrap;
361
+ }
362
+ `;
363
+ function ensureScratchpadStyles() {
364
+ if (typeof document === "undefined")
365
+ return;
366
+ if (document.getElementById(SCRATCHPAD_STYLE_ELEMENT_ID))
367
+ return;
368
+ const element = document.createElement("style");
369
+ element.id = SCRATCHPAD_STYLE_ELEMENT_ID;
370
+ element.textContent = SCRATCHPAD_STYLES;
371
+ document.head.append(element);
372
+ }
373
+
374
+ // src/primitives.tsx
375
+ import { jsx } from "react/jsx-runtime";
376
+ var TONE_VARIABLE = {
377
+ neutral: "var(--muted-foreground)",
378
+ primary: "var(--primary)",
379
+ success: "var(--success)",
380
+ warning: "var(--warning)",
381
+ danger: "var(--destructive)"
382
+ };
383
+ function classNames(...values) {
384
+ return values.filter(Boolean).join(" ");
385
+ }
386
+ function Button({
387
+ className,
388
+ size = "md",
389
+ type = "button",
390
+ variant = "secondary",
391
+ ...rest
392
+ }) {
393
+ ensureScratchpadStyles();
394
+ return /* @__PURE__ */ jsx("button", {
395
+ ...rest,
396
+ className: classNames("pragma-button", `pragma-button--${variant}`, size === "sm" && "pragma-button--sm", className),
397
+ type
398
+ });
399
+ }
400
+ function Input({
401
+ className,
402
+ ...rest
403
+ }) {
404
+ ensureScratchpadStyles();
405
+ return /* @__PURE__ */ jsx("input", {
406
+ ...rest,
407
+ className: classNames("pragma-input", className)
408
+ });
409
+ }
410
+ function Textarea({
411
+ className,
412
+ ...rest
413
+ }) {
414
+ ensureScratchpadStyles();
415
+ return /* @__PURE__ */ jsx("textarea", {
416
+ ...rest,
417
+ className: classNames("pragma-textarea", className)
418
+ });
419
+ }
420
+ function Progress({
421
+ className,
422
+ style,
423
+ tone = "primary",
424
+ ...rest
425
+ }) {
426
+ ensureScratchpadStyles();
427
+ return /* @__PURE__ */ jsx("progress", {
428
+ ...rest,
429
+ className: classNames("pragma-progress", className),
430
+ style: { ["--pragma-tone"]: TONE_VARIABLE[tone], ...style }
431
+ });
432
+ }
433
+ function Card({ className, ...rest }) {
434
+ ensureScratchpadStyles();
435
+ return /* @__PURE__ */ jsx("section", {
436
+ ...rest,
437
+ className: classNames("pragma-card", className)
438
+ });
439
+ }
440
+ function Badge({ className, tone = "neutral", ...rest }) {
441
+ ensureScratchpadStyles();
442
+ return /* @__PURE__ */ jsx("span", {
443
+ ...rest,
444
+ className: classNames("pragma-badge", tone !== "neutral" && `pragma-badge--${tone}`, className)
445
+ });
446
+ }
447
+ export {
448
+ Textarea,
449
+ Progress,
450
+ Input,
451
+ Card,
452
+ Button,
453
+ Badge
454
+ };