duckfn-docs-kit 0.3.0 → 0.4.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.
Files changed (47) hide show
  1. package/AGENTS.md +326 -234
  2. package/README.md +10 -6
  3. package/dist/IconButton.d.ts +22 -0
  4. package/dist/codemirror.d.ts +29 -0
  5. package/dist/download.d.ts +51 -0
  6. package/dist/index.d.ts +28 -7
  7. package/dist/index.js +2 -2
  8. package/dist/mermaid/DfkMermaid.d.ts +25 -0
  9. package/dist/mermaid/config.d.ts +48 -0
  10. package/dist/mermaid/remark.d.ts +40 -0
  11. package/dist/mermaid/remark.js +32 -0
  12. package/dist/mermaid/render.d.ts +92 -0
  13. package/dist/mermaid/styles.d.ts +6 -0
  14. package/dist/panzoom-view.d.ts +17 -0
  15. package/dist/{register-CALCwFBv.js → register-wdwf0LC4.js} +1365 -738
  16. package/dist/remark.d.ts +1 -1
  17. package/dist/source-dialog.d.ts +35 -0
  18. package/dist/sql/PreviewTabs.d.ts +39 -23
  19. package/dist/sql/SvgViewer.d.ts +53 -0
  20. package/dist/sql/client.js +1 -1
  21. package/dist/sql/harness.js +1 -1
  22. package/dist/sql/remark.d.ts +6 -1
  23. package/dist/sql/renderers.d.ts +9 -0
  24. package/package.json +6 -2
  25. package/src/IconButton.ts +50 -0
  26. package/src/codemirror.ts +97 -0
  27. package/src/download.ts +169 -0
  28. package/src/index.ts +31 -7
  29. package/src/mermaid/DfkMermaid.css +326 -0
  30. package/src/mermaid/DfkMermaid.ts +411 -0
  31. package/src/mermaid/config.ts +74 -0
  32. package/src/mermaid/remark.ts +98 -0
  33. package/src/mermaid/render.ts +172 -0
  34. package/src/mermaid/styles.ts +24 -0
  35. package/src/panzoom-view.ts +235 -0
  36. package/src/register.ts +3 -0
  37. package/src/remark.ts +1 -1
  38. package/src/source-dialog.ts +126 -0
  39. package/src/sql/DfkSql.css +13 -10
  40. package/src/sql/DfkSql.ts +60 -51
  41. package/src/sql/PreviewTabs.ts +98 -52
  42. package/src/sql/SvgViewer.ts +155 -0
  43. package/src/sql/remark.ts +6 -1
  44. package/src/sql/renderers.ts +433 -159
  45. package/src/sql/sql.css +189 -19
  46. package/dist/sql/editor.d.ts +0 -16
  47. package/src/sql/editor.ts +0 -75
package/src/sql/sql.css CHANGED
@@ -191,12 +191,13 @@ dfk-sql:not(:defined) {
191
191
 
192
192
  /* --- Result tabs --------------------------------------------------------- */
193
193
 
194
- /* The strip is a row holding the scrolling tab list and the corner button
195
- (the fullscreen toggle, owned by `<dfk-sql>`). */
194
+ /* The strip is a row holding the scrolling tab list and, at its right end, the
195
+ chrome that acts on the result as a whole: `[the active tab's own controls]
196
+ [download] [fullscreen]`. The corner never scrolls with the list and never
197
+ shrinks, so those buttons stay put however many tabs there are. */
196
198
  .dfk-sql-tabs {
197
199
  display: flex;
198
200
  align-items: center;
199
- padding-right: 0.3rem;
200
201
  border-bottom: 1px solid var(--ifm-global-border-color, #e0e0e0);
201
202
  background: var(--ifm-color-emphasis-100, #f5f5f5);
202
203
  }
@@ -210,6 +211,63 @@ dfk-sql:not(:defined) {
210
211
  overflow-x: auto;
211
212
  }
212
213
 
214
+ .dfk-sql-tab-corner {
215
+ display: flex;
216
+ flex-shrink: 0;
217
+ align-items: center;
218
+ gap: 0.15rem;
219
+ padding-right: 0.3rem;
220
+ }
221
+
222
+ /* One tab's own controls — a table's search and view switches, a figure's zoom
223
+ and edit buttons. Written by the renderers (and by an embedded
224
+ `<dfk-mermaid>`); only the active tab's container is shown. */
225
+ .dfk-sql-tab-actions {
226
+ display: flex;
227
+ align-items: center;
228
+ gap: 0.15rem;
229
+ }
230
+
231
+ .dfk-sql-tab-actions[hidden] {
232
+ display: none;
233
+ }
234
+
235
+ /* The search box opens in place rather than as a popover over the canvas: the
236
+ table is as wide as the page, and a popover would cover the cells the reader
237
+ is searching. */
238
+ .dfk-sql-search-input {
239
+ width: 9rem;
240
+ padding: 0.1rem 0.4rem;
241
+ border: 1px solid var(--ifm-global-border-color, #e0e0e0);
242
+ border-radius: var(--ifm-global-radius, 0.25rem);
243
+ background: var(--ifm-background-surface-color, #fff);
244
+ color: var(--ifm-font-color-base, #181818);
245
+ font-family: inherit;
246
+ font-size: 0.75rem;
247
+ line-height: 1.5;
248
+ }
249
+
250
+ .dfk-sql-search-input:focus-visible {
251
+ outline: 2px solid var(--ifm-color-primary, #14459b);
252
+ outline-offset: -1px;
253
+ }
254
+
255
+ .dfk-sql-search-input[hidden] {
256
+ display: none;
257
+ }
258
+
259
+ .dfk-sql-search-count {
260
+ min-width: 2.2rem;
261
+ color: var(--ifm-color-emphasis-700, #666);
262
+ font-size: 0.7rem;
263
+ font-variant-numeric: tabular-nums;
264
+ text-align: center;
265
+ }
266
+
267
+ .dfk-sql-search-count[hidden] {
268
+ display: none;
269
+ }
270
+
213
271
  .dfk-sql-tab {
214
272
  padding: 0.15rem 0.65rem;
215
273
  border: 1px solid transparent;
@@ -237,11 +295,13 @@ dfk-sql:not(:defined) {
237
295
 
238
296
  /* --- Icon buttons and their tooltips ------------------------------------- */
239
297
 
240
- /* The same rules (and the `[data-tip]` tooltip below) are declared in
241
- `DfkSql.css`, because the buttons are split across the shadow boundary: the
242
- code-block actions live in the shadow tree, the fullscreen toggle lives in
243
- this light-DOM tab strip. Keep the two copies in sync. */
244
- .dfk-sql-icon-button {
298
+ /* The class names are written by the shared `IconButton` widget
299
+ (`src/IconButton.ts`). The same rules (and the `[data-tip]` tooltip below) are
300
+ declared in `DfkSql.css` and `DfkMermaid.css`, because the buttons are split
301
+ across shadow boundaries: the code-block actions live in `<dfk-sql>`'s tree,
302
+ a diagram's cluster in `<dfk-mermaid>`'s, and the fullscreen toggle in this
303
+ light-DOM tab strip. Keep the copies in sync. */
304
+ .dfk-icon-button {
245
305
  position: relative;
246
306
  display: inline-flex;
247
307
  align-items: center;
@@ -257,27 +317,27 @@ dfk-sql:not(:defined) {
257
317
  transition: background 0.12s ease, color 0.12s ease;
258
318
  }
259
319
 
260
- .dfk-sql-icon-button:hover:not(:disabled),
261
- .dfk-sql-icon-button:focus-visible {
320
+ .dfk-icon-button:hover:not(:disabled),
321
+ .dfk-icon-button:focus-visible {
262
322
  background: var(--ifm-color-emphasis-200, #e6e6e6);
263
323
  color: var(--ifm-color-primary, #14459b);
264
324
  }
265
325
 
266
- .dfk-sql-icon-button:disabled {
326
+ .dfk-icon-button:disabled {
267
327
  opacity: 0.45;
268
328
  cursor: progress;
269
329
  }
270
330
 
271
- .dfk-sql-icon-button[hidden] {
331
+ .dfk-icon-button[hidden] {
272
332
  display: none;
273
333
  }
274
334
 
275
335
  /* A sticky state, e.g. the wrap toggle while wrapping is on. */
276
- .dfk-sql-icon-on {
336
+ .dfk-icon-on {
277
337
  color: var(--ifm-color-primary, #14459b);
278
338
  }
279
339
 
280
- .dfk-sql-icon {
340
+ .dfk-icon {
281
341
  font-size: 1rem;
282
342
  }
283
343
 
@@ -315,11 +375,16 @@ dfk-sql:not(:defined) {
315
375
  bottom of the table from continuing into the page scroll (the page lurches
316
376
  upward and the example leaves the screen). It is not inherited, so it is
317
377
  declared on every scrolling box, including VTable's inner scroll containers
318
- under `.dfk-sql-table`. */
319
- .dfk-sql-panel,
378
+ under `.dfk-sql-table`.
379
+ The panel is contained **only while the result is expanded**: `contain` applies
380
+ to any box with a non-visible `overflow`, and a panel is a scroll container
381
+ whether or not it has anything to scroll — so, inline, it would swallow the
382
+ wheel that should have gone to the page (a figure is a picture there, not a
383
+ viewport: see `DfkMermaid.css`). Expanded, the panel really does scroll, and
384
+ without this the wheel would move the page *behind* the overlay instead. */
320
385
  .dfk-sql-table,
321
386
  .dfk-sql-table *,
322
- .dfk-sql-svg {
387
+ .dfk-sql-result-expanded .dfk-sql-panel {
323
388
  overscroll-behavior: contain;
324
389
  }
325
390
 
@@ -345,18 +410,37 @@ dfk-sql:not(:defined) {
345
410
  background: #fff;
346
411
  }
347
412
 
413
+ /* The `svg` result is a pan/zoom viewport (the shared `PanZoomView`), with the
414
+ SVG in its content box. It draws no frame: the result panel is the frame, and
415
+ stacking a second one behind the tab strip is what made a two-box look. The
416
+ `overflow: hidden` clips a zoomed figure instead of letting it spill over the
417
+ page, and is also what panzoom expects of a pan element's parent. */
348
418
  .dfk-sql-svg {
349
419
  width: var(--dfk-sql-preview-width, 100%);
350
420
  height: var(--dfk-sql-preview-height, auto);
351
421
  padding: 0.5rem;
352
- overflow: auto;
422
+ overflow: hidden;
353
423
  }
354
424
 
355
- .dfk-sql-svg > svg {
425
+ .dfk-sql-svg-content > svg {
426
+ display: block;
427
+ margin: 0 auto;
356
428
  max-width: 100%;
357
429
  height: auto;
358
430
  }
359
431
 
432
+ /* The cursor says what a drag will actually do, so it follows the zoom state
433
+ rather than being set once (`PanZoomView` writes the two state classes).
434
+ `cursor` is inherited, so it reaches the figure and every label in it. The
435
+ same two rules live in `DfkMermaid.css`. */
436
+ .dfk-sql-svg.dfk-panzoom-zoomed {
437
+ cursor: grab;
438
+ }
439
+
440
+ .dfk-sql-svg.dfk-panzoom-zoomed.dfk-panzoom-grabbing {
441
+ cursor: grabbing;
442
+ }
443
+
360
444
  /* --- Fullscreen ---------------------------------------------------------- */
361
445
 
362
446
  /* Also carries `.dfk-sql-result`, so `overflow` and the radius are re-declared
@@ -394,4 +478,90 @@ dfk-sql:not(:defined) {
394
478
  panel is one full-height scroll area rather than a strip. */
395
479
  .dfk-sql-result-expanded .dfk-sql-svg {
396
480
  height: 100%;
481
+ }
482
+
483
+ /* --- Source dialog ------------------------------------------------------- */
484
+
485
+ /* The `svg` viewer's source editor (`SourceDialog`). The dialog itself is
486
+ modal — it renders in the top layer, so its position needs no help — but the
487
+ class names are written by the shared widget, which `<dfk-mermaid>` uses
488
+ inside its shadow root; these rules are that sheet's `.dfk-source-dialog*`
489
+ block, in the light DOM, and the two are kept in sync by hand. */
490
+ .dfk-source-dialog {
491
+ width: min(56rem, 92vw);
492
+ max-width: none;
493
+ padding: 0;
494
+ border: 1px solid var(--ifm-global-border-color, #e0e0e0);
495
+ border-radius: var(--ifm-global-radius, 0.4rem);
496
+ background: var(--ifm-background-surface-color, #fff);
497
+ color: var(--ifm-font-color-base, #181818);
498
+ }
499
+
500
+ .dfk-source-dialog::backdrop {
501
+ background: rgb(0 0 0 / 45%);
502
+ }
503
+
504
+ .dfk-source-dialog-body {
505
+ display: flex;
506
+ flex-direction: column;
507
+ gap: 0.5rem;
508
+ padding: 0.75rem;
509
+ }
510
+
511
+ .dfk-source-dialog-title {
512
+ margin: 0;
513
+ font-size: 0.95rem;
514
+ font-weight: 600;
515
+ }
516
+
517
+ .dfk-source-dialog-editor {
518
+ border: 1px solid var(--ifm-global-border-color, #e0e0e0);
519
+ border-radius: var(--ifm-global-radius, 0.4rem);
520
+ overflow: hidden;
521
+ background: var(--ifm-background-surface-color, #fff);
522
+ font-size: var(--ifm-code-font-size, 95%);
523
+ }
524
+
525
+ .dfk-source-dialog-editor .cm-editor {
526
+ outline: none;
527
+ }
528
+
529
+ .dfk-source-dialog-editor .cm-scroller {
530
+ max-height: 55vh;
531
+ font-family: var(--ifm-font-family-monospace, ui-monospace, SFMono-Regular,
532
+ Menlo, monospace);
533
+ line-height: 1.6;
534
+ }
535
+
536
+ .dfk-source-dialog-footer {
537
+ display: flex;
538
+ justify-content: flex-end;
539
+ gap: 0.5rem;
540
+ }
541
+
542
+ .dfk-source-dialog-button {
543
+ padding: 0.3rem 0.9rem;
544
+ border: 1px solid var(--ifm-global-border-color, #e0e0e0);
545
+ border-radius: var(--ifm-global-radius, 0.25rem);
546
+ background: var(--ifm-background-surface-color, #fff);
547
+ color: var(--ifm-font-color-base, #181818);
548
+ font-family: inherit;
549
+ font-size: 0.85rem;
550
+ cursor: pointer;
551
+ }
552
+
553
+ .dfk-source-dialog-button:hover {
554
+ border-color: var(--ifm-color-primary, #14459b);
555
+ color: var(--ifm-color-primary, #14459b);
556
+ }
557
+
558
+ .dfk-source-dialog-apply {
559
+ border-color: var(--ifm-color-primary, #14459b);
560
+ background: var(--ifm-color-primary, #14459b);
561
+ color: var(--ifm-button-color, #fff);
562
+ }
563
+
564
+ .dfk-source-dialog-apply:hover {
565
+ color: var(--ifm-button-color, #fff);
566
+ filter: brightness(1.1);
397
567
  }
@@ -1,16 +0,0 @@
1
- /**
2
- * The CodeMirror 6 editor that *is* the code view of a runnable SQL block.
3
- *
4
- * Every CodeMirror module arrives through dynamic `import()` inside
5
- * {@link mountSqlEditor}: a page full of SQL examples pays nothing for the
6
- * editor on its critical path, and Docusaurus' Node prerender never evaluates
7
- * any of it.
8
- */
9
- export interface SqlEditor {
10
- getValue(): string;
11
- setValue(value: string): void;
12
- /** Soft-wraps long lines, or stops wrapping them (the block's wrap toggle). */
13
- setWrap(wrapped: boolean): void;
14
- destroy(): void;
15
- }
16
- export declare function mountSqlEditor(container: HTMLElement, value: string, onChange: (value: string) => void): Promise<SqlEditor>;
package/src/sql/editor.ts DELETED
@@ -1,75 +0,0 @@
1
- /**
2
- * The CodeMirror 6 editor that *is* the code view of a runnable SQL block.
3
- *
4
- * Every CodeMirror module arrives through dynamic `import()` inside
5
- * {@link mountSqlEditor}: a page full of SQL examples pays nothing for the
6
- * editor on its critical path, and Docusaurus' Node prerender never evaluates
7
- * any of it.
8
- */
9
-
10
- export interface SqlEditor {
11
- getValue(): string;
12
- setValue(value: string): void;
13
- /** Soft-wraps long lines, or stops wrapping them (the block's wrap toggle). */
14
- setWrap(wrapped: boolean): void;
15
- destroy(): void;
16
- }
17
-
18
- export async function mountSqlEditor(
19
- container: HTMLElement,
20
- value: string,
21
- onChange: (value: string) => void,
22
- ): Promise<SqlEditor> {
23
- const [
24
- {basicSetup},
25
- {sql},
26
- {EditorView, keymap},
27
- {defaultKeymap, historyKeymap},
28
- {Compartment},
29
- ] = await Promise.all([
30
- import('codemirror'),
31
- import('@codemirror/lang-sql'),
32
- import('@codemirror/view'),
33
- import('@codemirror/commands'),
34
- import('@codemirror/state'),
35
- ]);
36
-
37
- // Wrapping is toggled from the outside, and reconfiguring it must not disturb
38
- // the document or the undo history — that is exactly what a compartment is
39
- // for, so the extension is swapped in place rather than rebuilt.
40
- const wrap = new Compartment();
41
-
42
- const view = new EditorView({
43
- doc: value,
44
- extensions: [
45
- basicSetup,
46
- sql(),
47
- keymap.of([...defaultKeymap, ...historyKeymap]),
48
- wrap.of([]),
49
- EditorView.updateListener.of((update) => {
50
- if (update.docChanged) {
51
- onChange(update.state.doc.toString());
52
- }
53
- }),
54
- ],
55
- parent: container,
56
- // `root` is left to CodeMirror's own `getRoot(container)`. The container sits
57
- // in `<dfk-sql>`'s shadow root, so style-mod mounts the base theme into that
58
- // same shadow root — exactly where the `.cm-*` rules are needed. Pinning it
59
- // to `document` would put them outside the editor's tree instead, where a
60
- // shadow boundary stops them.
61
- });
62
-
63
- return {
64
- getValue: () => view.state.doc.toString(),
65
- setValue: (next: string) =>
66
- view.dispatch({
67
- changes: {from: 0, to: view.state.doc.length, insert: next},
68
- }),
69
- setWrap: (wrapped: boolean) =>
70
- view.dispatch({
71
- effects: wrap.reconfigure(wrapped ? EditorView.lineWrapping : []),
72
- }),
73
- destroy: () => view.destroy(),
74
- };
75
- }