duckfn-docs-kit 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.
Files changed (65) hide show
  1. package/AGENTS.md +689 -0
  2. package/LICENSE +21 -0
  3. package/README.md +107 -0
  4. package/dist/dom.d.ts +69 -0
  5. package/dist/home/DfkFeatures.d.ts +20 -0
  6. package/dist/home/DfkHero.d.ts +25 -0
  7. package/dist/home/DfkNextSteps.d.ts +16 -0
  8. package/dist/home/styles.d.ts +8 -0
  9. package/dist/index.d.ts +50 -0
  10. package/dist/index.js +2 -0
  11. package/dist/register-DKLiYs-F.js +2324 -0
  12. package/dist/register.d.ts +10 -0
  13. package/dist/remark.d.ts +21 -0
  14. package/dist/remark.js +15 -0
  15. package/dist/runtimeConfig-Bokbb8VH.js +106 -0
  16. package/dist/sql/DfkSql.d.ts +7 -0
  17. package/dist/sql/PreviewTabs.d.ts +37 -0
  18. package/dist/sql/client.d.ts +1 -0
  19. package/dist/sql/client.js +4 -0
  20. package/dist/sql/editor.d.ts +16 -0
  21. package/dist/sql/extensions.d.ts +108 -0
  22. package/dist/sql/extensions.js +198 -0
  23. package/dist/sql/remark.d.ts +88 -0
  24. package/dist/sql/remark.js +69 -0
  25. package/dist/sql/renderers.d.ts +44 -0
  26. package/dist/sql/runtime.d.ts +105 -0
  27. package/dist/sql/runtimeConfig.d.ts +80 -0
  28. package/dist/sql/styles.d.ts +6 -0
  29. package/dist/toc-toggle/TocToggle.d.ts +46 -0
  30. package/dist/toc-toggle/TocToggle.js +69 -0
  31. package/dist/toc-toggle/client.d.ts +1 -0
  32. package/dist/toc-toggle/client.js +9 -0
  33. package/dist/toc-toggle/plugin.d.ts +36 -0
  34. package/dist/toc-toggle/plugin.js +13 -0
  35. package/dist/types.d.ts +42 -0
  36. package/package.json +73 -0
  37. package/src/dom.ts +109 -0
  38. package/src/home/DfkFeatures.ts +78 -0
  39. package/src/home/DfkHero.ts +128 -0
  40. package/src/home/DfkNextSteps.ts +73 -0
  41. package/src/home/home.css +520 -0
  42. package/src/home/styles.ts +28 -0
  43. package/src/index.ts +59 -0
  44. package/src/kit.css +19 -0
  45. package/src/register.ts +39 -0
  46. package/src/remark.ts +60 -0
  47. package/src/sql/DfkSql.css +226 -0
  48. package/src/sql/DfkSql.ts +620 -0
  49. package/src/sql/PreviewTabs.ts +169 -0
  50. package/src/sql/client.ts +16 -0
  51. package/src/sql/editor.ts +75 -0
  52. package/src/sql/extensions.ts +470 -0
  53. package/src/sql/remark.ts +213 -0
  54. package/src/sql/renderers.ts +916 -0
  55. package/src/sql/runtime.ts +348 -0
  56. package/src/sql/runtimeConfig.ts +249 -0
  57. package/src/sql/sql.css +397 -0
  58. package/src/sql/styles.ts +24 -0
  59. package/src/theme/tokens.css +75 -0
  60. package/src/toc-toggle/TocToggle.css +69 -0
  61. package/src/toc-toggle/TocToggle.ts +172 -0
  62. package/src/toc-toggle/client.ts +20 -0
  63. package/src/toc-toggle/plugin.ts +54 -0
  64. package/src/types.ts +47 -0
  65. package/src/vite-env.d.ts +8 -0
@@ -0,0 +1,520 @@
1
+ /**
2
+ * Styles for the `dfk-*` home-page custom elements.
3
+ *
4
+ * This file is *not* part of the site's global stylesheet: Vite inlines it into
5
+ * the bundle (`styles.ts`, `?inline`) and each component adopts it as a
6
+ * constructed stylesheet on its shadow root. The site's own CSS cannot reach
7
+ * these rules, and these rules cannot leak out — which is why the class names
8
+ * still carry the `dfk-` prefix (it keeps the shadow trees self-describing and
9
+ * greppable, not because they could collide with the host page).
10
+ *
11
+ * Theme colours cross the shadow boundary through inheritance: the `--duckfn-*`
12
+ * tokens from `theme/tokens.css` and the site's `--ifm-*` variables are custom
13
+ * properties declared on `:root` / `[data-theme]`, and custom properties
14
+ * inherit into shadow trees, so dark mode works without a single `[data-theme]`
15
+ * selector in this file.
16
+ *
17
+ * Motion rules, deliberately:
18
+ *
19
+ * - all animations live inside `@media (prefers-reduced-motion: no-preference)`
20
+ * and no static declaration sets `opacity: 0`, so a reader who disabled
21
+ * animation sees the page complete rather than blank;
22
+ * - entrance animations fill `backwards` instead of `forwards`. The delay then
23
+ * holds the start frame, but once the animation ends the element goes back to
24
+ * its normal styles — which is what lets the `:hover` transforms on the cards
25
+ * work. With `forwards` the finished animation would keep overriding them.
26
+ */
27
+
28
+ /* --------------------------------------------------------------- host */
29
+
30
+ /* A custom element is `display: inline` by default; the shadow content is a
31
+ full-width section, so the host has to be a block box. */
32
+ :host {
33
+ display: block;
34
+ }
35
+
36
+ /* The shadow-scoped box-sizing reset. The host page's universal selector
37
+ (Infima's `* { box-sizing: border-box }`) does not match into a shadow tree,
38
+ so without this every padded box in the components silently switches to
39
+ content-box — which is wide enough to push the feature grid from three
40
+ columns to four at the 72rem cap. The rules below are written against
41
+ border-box, so it is re-established here. */
42
+ *,
43
+ *::before,
44
+ *::after {
45
+ box-sizing: border-box;
46
+ }
47
+
48
+ /* --------------------------------------------------------------- hero */
49
+
50
+ .dfk-hero {
51
+ position: relative;
52
+ /* Contains the glow pseudo-elements below without needing a z-index race, and
53
+ clips them on the horizontal axis only: their offsets (the 52rem circle centred
54
+ with `left: 50%`, and the warm one at `right: -10rem`) reach past the viewport,
55
+ which would otherwise widen the page and add a scrollbar.
56
+ `clip`, not `hidden`. Both keep the page narrow, but `hidden` also made this
57
+ section a scroll container and clipped the vertical axis, slicing the warm glow
58
+ in half along this section's bottom edge. `clip` leaves the other axis visible,
59
+ so the glow fades out over the next section instead of ending on a straight
60
+ line. It is also what makes the clip invisible: the horizontal cut lands on the
61
+ viewport edge, where there is nothing to see anyway. */
62
+ isolation: isolate;
63
+ overflow-x: clip;
64
+ padding: 4.5rem 1.5rem 4rem;
65
+ text-align: center;
66
+ }
67
+
68
+ /* Two soft pools of light: brand blue from above, a hint of the logo's beak
69
+ yellow from the lower right. Purely decorative. */
70
+ .dfk-hero::before,
71
+ .dfk-hero::after {
72
+ content: '';
73
+ position: absolute;
74
+ z-index: -1;
75
+ border-radius: 50%;
76
+ pointer-events: none;
77
+ }
78
+
79
+ .dfk-hero::before {
80
+ top: -18rem;
81
+ left: 50%;
82
+ width: 52rem;
83
+ height: 52rem;
84
+ transform: translateX(-50%);
85
+ background: radial-gradient(circle, var(--duckfn-glow), transparent 70%);
86
+ }
87
+
88
+ .dfk-hero::after {
89
+ right: -10rem;
90
+ bottom: -14rem;
91
+ width: 34rem;
92
+ height: 34rem;
93
+ background: radial-gradient(circle, var(--duckfn-glow-warm), transparent 70%);
94
+ }
95
+
96
+ .dfk-hero-inner {
97
+ max-width: 46rem;
98
+ margin: 0 auto;
99
+ }
100
+
101
+ .dfk-logo-stage {
102
+ display: inline-block;
103
+ line-height: 0;
104
+ }
105
+
106
+ /* The logo is a vector, so this stays sharp at any density. */
107
+ .dfk-logo {
108
+ display: block;
109
+ width: clamp(7rem, 16vw, 10rem);
110
+ height: auto;
111
+ filter: drop-shadow(0 14px 28px var(--duckfn-glow));
112
+ }
113
+
114
+ .dfk-title {
115
+ margin: 1.5rem 0 0;
116
+ font-size: clamp(2.25rem, 5vw, 3.25rem);
117
+ font-weight: 700;
118
+ letter-spacing: -0.02em;
119
+ line-height: 1.1;
120
+ /* The plain colour is the fallback for the gradient below: without
121
+ `background-clip: text` a `transparent` colour would hide the name. */
122
+ color: var(--duckfn-blue);
123
+ }
124
+
125
+ @supports (-webkit-background-clip: text) or (background-clip: text) {
126
+ .dfk-title {
127
+ background-image: linear-gradient(
128
+ 120deg,
129
+ var(--duckfn-blue-deep),
130
+ var(--duckfn-blue-bright)
131
+ );
132
+ -webkit-background-clip: text;
133
+ background-clip: text;
134
+ color: transparent;
135
+ /* Room for descenders, which the tight line box would otherwise clip. */
136
+ padding-bottom: 0.06em;
137
+ }
138
+ }
139
+
140
+ /* The only yellow on this page, and it carries no text: a short rule under the
141
+ name that echoes the beak. See the note on the token in theme/tokens.css. */
142
+ .dfk-title::after {
143
+ content: '';
144
+ display: block;
145
+ width: 3rem;
146
+ height: 0.25rem;
147
+ margin: 1rem auto 0;
148
+ border-radius: 999px;
149
+ background-color: var(--duckfn-yellow);
150
+ }
151
+
152
+ .dfk-tagline {
153
+ max-width: 34rem;
154
+ margin: 1.25rem auto 0;
155
+ font-size: clamp(1.05rem, 2.2vw, 1.25rem);
156
+ line-height: 1.65;
157
+ color: var(--ifm-color-emphasis-700);
158
+ }
159
+
160
+ .dfk-actions {
161
+ display: flex;
162
+ flex-wrap: wrap;
163
+ justify-content: center;
164
+ gap: 0.75rem 1rem;
165
+ margin-top: 2.25rem;
166
+ }
167
+
168
+ .dfk-button-primary,
169
+ .dfk-button-secondary {
170
+ display: inline-flex;
171
+ align-items: center;
172
+ justify-content: center;
173
+ gap: 0.5rem;
174
+ padding: 0.7rem 1.6rem;
175
+ border: 1px solid transparent;
176
+ border-radius: 999px;
177
+ font-size: 1rem;
178
+ font-weight: 600;
179
+ line-height: 1.4;
180
+ text-decoration: none;
181
+ transition: background-color 0.2s var(--ifm-transition-timing-default),
182
+ border-color 0.2s var(--ifm-transition-timing-default),
183
+ color 0.2s var(--ifm-transition-timing-default),
184
+ box-shadow 0.2s var(--ifm-transition-timing-default);
185
+ }
186
+
187
+ .dfk-button-primary {
188
+ background-color: var(--duckfn-btn-bg);
189
+ border-color: var(--duckfn-btn-bg);
190
+ color: var(--duckfn-btn-fg);
191
+ }
192
+
193
+ .dfk-button-primary:hover,
194
+ .dfk-button-primary:focus-visible {
195
+ background-color: var(--duckfn-btn-bg-hover);
196
+ border-color: var(--duckfn-btn-bg-hover);
197
+ color: var(--duckfn-btn-fg);
198
+ box-shadow: var(--duckfn-shadow);
199
+ text-decoration: none;
200
+ }
201
+
202
+ .dfk-button-secondary {
203
+ background-color: transparent;
204
+ border-color: var(--duckfn-outline-border);
205
+ color: var(--duckfn-blue);
206
+ }
207
+
208
+ .dfk-button-secondary:hover,
209
+ .dfk-button-secondary:focus-visible {
210
+ background-color: var(--duckfn-blue-soft);
211
+ border-color: var(--duckfn-blue);
212
+ color: var(--duckfn-blue);
213
+ text-decoration: none;
214
+ }
215
+
216
+ /* ------------------------------------------------------------ icons */
217
+
218
+ /* Icons are official `<iconify-icon>` web components: the glyph is fetched from
219
+ the public Iconify API and painted with `currentColor`, so these rules only
220
+ set the size (and, where needed, the colour the glyph inherits).
221
+ Size with `font-size`, not `width`/`height`: the component renders an inner
222
+ `<svg width="1em" height="1em">`, so the glyph follows the host's font-size.
223
+ A CSS `width`/`height` only grows the empty host box and leaves the glyph at
224
+ the inherited font-size. */
225
+ .dfk-button-icon {
226
+ font-size: 1.125rem;
227
+ }
228
+
229
+ .dfk-badges {
230
+ display: flex;
231
+ flex-wrap: wrap;
232
+ align-items: center;
233
+ justify-content: center;
234
+ gap: 0.5rem;
235
+ margin-top: 2rem;
236
+ }
237
+
238
+ .dfk-badge {
239
+ display: inline-flex;
240
+ }
241
+
242
+ .dfk-badge-image {
243
+ display: block;
244
+ width: auto;
245
+ height: 20px;
246
+ }
247
+
248
+ /* ------------------------------------------------------------ sections */
249
+
250
+ .dfk-section {
251
+ padding: 4.5rem 0;
252
+ }
253
+
254
+ .dfk-section-inner {
255
+ max-width: 72rem;
256
+ margin: 0 auto;
257
+ padding: 0 1.5rem;
258
+ }
259
+
260
+ .dfk-section-title {
261
+ margin-bottom: 0;
262
+ text-align: center;
263
+ font-size: clamp(1.5rem, 3vw, 2rem);
264
+ letter-spacing: -0.01em;
265
+ }
266
+
267
+ /* ------------------------------------------------------------ features */
268
+
269
+ .dfk-feature-grid {
270
+ display: grid;
271
+ /* min(17rem, 100%) rather than a bare 17rem: a track can then never be wider
272
+ than the viewport, which is what keeps the narrowest phones from scrolling
273
+ sideways. */
274
+ grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
275
+ gap: 1.25rem;
276
+ margin-top: 2.75rem;
277
+ }
278
+
279
+ .dfk-feature-card {
280
+ display: flex;
281
+ flex-direction: column;
282
+ padding: 1.5rem;
283
+ border: 1px solid var(--duckfn-card-border);
284
+ border-radius: 1rem;
285
+ background-color: var(--duckfn-card-bg);
286
+ transition: border-color 0.2s var(--ifm-transition-timing-default),
287
+ box-shadow 0.2s var(--ifm-transition-timing-default);
288
+ }
289
+
290
+ .dfk-feature-card:hover {
291
+ border-color: var(--duckfn-blue);
292
+ box-shadow: var(--duckfn-shadow);
293
+ }
294
+
295
+ .dfk-feature-icon-chip {
296
+ display: inline-flex;
297
+ align-items: center;
298
+ justify-content: center;
299
+ width: 2.5rem;
300
+ height: 2.5rem;
301
+ margin-bottom: 1rem;
302
+ border-radius: 0.75rem;
303
+ background-color: var(--duckfn-blue-soft);
304
+ color: var(--duckfn-blue);
305
+ }
306
+
307
+ .dfk-feature-icon {
308
+ font-size: 1.375rem;
309
+ }
310
+
311
+ .dfk-feature-title {
312
+ margin-bottom: 0.5rem;
313
+ font-size: 1.0625rem;
314
+ font-weight: 600;
315
+ }
316
+
317
+ .dfk-feature-details {
318
+ margin-bottom: 0;
319
+ font-size: 0.9375rem;
320
+ line-height: 1.7;
321
+ color: var(--ifm-color-emphasis-700);
322
+ }
323
+
324
+ /* ---------------------------------------------------------- next steps */
325
+
326
+ .dfk-next-grid {
327
+ display: grid;
328
+ grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
329
+ gap: 1rem;
330
+ max-width: 54rem;
331
+ margin: 2.75rem auto 0;
332
+ }
333
+
334
+ .dfk-next-card {
335
+ display: flex;
336
+ align-items: center;
337
+ gap: 1rem;
338
+ padding: 1.25rem 1.375rem;
339
+ border: 1px solid var(--duckfn-card-border);
340
+ border-radius: 0.875rem;
341
+ background-color: var(--duckfn-card-bg);
342
+ /* The card is the link, so it must not pick up the anchor colour. */
343
+ color: inherit;
344
+ text-decoration: none;
345
+ transition: border-color 0.2s var(--ifm-transition-timing-default),
346
+ box-shadow 0.2s var(--ifm-transition-timing-default);
347
+ }
348
+
349
+ .dfk-next-card:hover,
350
+ .dfk-next-card:focus-visible {
351
+ border-color: var(--duckfn-blue);
352
+ box-shadow: var(--duckfn-shadow);
353
+ color: inherit;
354
+ text-decoration: none;
355
+ }
356
+
357
+ .dfk-next-card-body {
358
+ display: flex;
359
+ flex: 1;
360
+ flex-direction: column;
361
+ gap: 0.25rem;
362
+ min-width: 0;
363
+ }
364
+
365
+ .dfk-next-card-title {
366
+ font-size: 1rem;
367
+ font-weight: 600;
368
+ color: var(--duckfn-blue);
369
+ }
370
+
371
+ .dfk-next-card-details {
372
+ font-size: 0.9rem;
373
+ line-height: 1.6;
374
+ color: var(--ifm-color-emphasis-700);
375
+ }
376
+
377
+ .dfk-next-card-arrow {
378
+ flex-shrink: 0;
379
+ font-size: 1.25rem;
380
+ color: var(--ifm-color-emphasis-500);
381
+ transition: color 0.2s var(--ifm-transition-timing-default);
382
+ }
383
+
384
+ .dfk-next-card:hover .dfk-next-card-arrow,
385
+ .dfk-next-card:focus-visible .dfk-next-card-arrow {
386
+ color: var(--duckfn-blue);
387
+ }
388
+
389
+ /* -------------------------------------------------------------- motion */
390
+
391
+ @media (prefers-reduced-motion: no-preference) {
392
+ .dfk-logo-stage,
393
+ .dfk-title,
394
+ .dfk-tagline,
395
+ .dfk-actions,
396
+ .dfk-badges {
397
+ animation: dfk-rise 0.6s var(--ifm-transition-timing-default) backwards;
398
+ }
399
+
400
+ .dfk-title {
401
+ animation-delay: 0.06s;
402
+ }
403
+
404
+ .dfk-tagline {
405
+ animation-delay: 0.12s;
406
+ }
407
+
408
+ .dfk-actions {
409
+ animation-delay: 0.18s;
410
+ }
411
+
412
+ .dfk-badges {
413
+ animation-delay: 0.24s;
414
+ }
415
+
416
+ /* Two elements on purpose: `rise` plays once on the stage, `float` loops on
417
+ the image. One element cannot run two animations that both set transform. */
418
+ .dfk-logo {
419
+ animation: dfk-float 7s ease-in-out infinite;
420
+ will-change: transform;
421
+ }
422
+
423
+ .dfk-feature-card,
424
+ .dfk-next-card {
425
+ animation: dfk-rise 0.5s var(--ifm-transition-timing-default) backwards;
426
+ }
427
+
428
+ /* Cards arrive in reading order. Filling backwards keeps them invisible during
429
+ their delay and hands the element back to `:hover` when the animation ends. */
430
+ .dfk-feature-card:nth-child(2),
431
+ .dfk-next-card:nth-child(2) {
432
+ animation-delay: 0.06s;
433
+ }
434
+
435
+ .dfk-feature-card:nth-child(3),
436
+ .dfk-next-card:nth-child(3) {
437
+ animation-delay: 0.12s;
438
+ }
439
+
440
+ .dfk-feature-card:nth-child(4),
441
+ .dfk-next-card:nth-child(4) {
442
+ animation-delay: 0.18s;
443
+ }
444
+
445
+ .dfk-feature-card:nth-child(5) {
446
+ animation-delay: 0.24s;
447
+ }
448
+
449
+ .dfk-feature-card:nth-child(6) {
450
+ animation-delay: 0.3s;
451
+ }
452
+
453
+ .dfk-feature-card,
454
+ .dfk-next-card,
455
+ .dfk-next-card-arrow {
456
+ transition: transform 0.2s var(--ifm-transition-timing-default),
457
+ border-color 0.2s var(--ifm-transition-timing-default),
458
+ box-shadow 0.2s var(--ifm-transition-timing-default),
459
+ color 0.2s var(--ifm-transition-timing-default);
460
+ }
461
+
462
+ .dfk-feature-card:hover {
463
+ transform: translateY(-4px);
464
+ }
465
+
466
+ .dfk-next-card:hover {
467
+ transform: translateY(-2px);
468
+ }
469
+
470
+ .dfk-next-card:hover .dfk-next-card-arrow {
471
+ transform: translateX(4px);
472
+ }
473
+ }
474
+
475
+ @keyframes dfk-rise {
476
+ from {
477
+ opacity: 0;
478
+ transform: translateY(14px);
479
+ }
480
+
481
+ to {
482
+ opacity: 1;
483
+ transform: translateY(0);
484
+ }
485
+ }
486
+
487
+ @keyframes dfk-float {
488
+ 0%,
489
+ 100% {
490
+ transform: translateY(-4px);
491
+ }
492
+
493
+ 50% {
494
+ transform: translateY(4px);
495
+ }
496
+ }
497
+
498
+ /* -------------------------------------------------------- breakpoints */
499
+
500
+ @media screen and (max-width: 996px) {
501
+ .dfk-hero {
502
+ padding: 3rem 1.5rem;
503
+ }
504
+
505
+ .dfk-section {
506
+ padding: 3.5rem 0;
507
+ }
508
+ }
509
+
510
+ @media screen and (max-width: 576px) {
511
+ .dfk-section-inner {
512
+ padding: 0 1rem;
513
+ }
514
+
515
+ /* Full-width buttons stack better than two pills on a phone. */
516
+ .dfk-actions {
517
+ flex-direction: column;
518
+ align-items: stretch;
519
+ }
520
+ }
@@ -0,0 +1,28 @@
1
+ // The home components' CSS as an inline string, bundled into the JS by Vite's
2
+ // `?inline` import (see `vite.config.ts`). The components inject it into their
3
+ // shadow roots, so a consuming site never imports `home.css` — the only CSS
4
+ // files that stay global source are `theme/tokens.css` (the `--duckfn-*`
5
+ // palette, which must live on `:root` / `[data-theme]`) and
6
+ // `toc-toggle/TocToggle.css` (light-DOM rules that have to sit inside
7
+ // `@layer docusaurus.theme-classic`).
8
+ //
9
+ // The type declaration lives in `vite-env.d.ts`; `tsc` never resolves the
10
+ // `?inline` suffix, so the module graph stays buildable without Vite running.
11
+ import homeCss from './home.css?inline';
12
+
13
+ let sheet: CSSStyleSheet | null = null;
14
+
15
+ /**
16
+ * The one parsed stylesheet shared by every `dfk-*` shadow root.
17
+ *
18
+ * Created lazily: Docusaurus imports this module into Node during
19
+ * prerendering, where `CSSStyleSheet` does not exist — only the browser ever
20
+ * calls this.
21
+ */
22
+ export function homeStyles(): CSSStyleSheet {
23
+ if (!sheet) {
24
+ sheet = new CSSStyleSheet();
25
+ sheet.replaceSync(homeCss);
26
+ }
27
+ return sheet;
28
+ }
package/src/index.ts ADDED
@@ -0,0 +1,59 @@
1
+ import type {HTMLAttributes} from 'react';
2
+
3
+ /**
4
+ * Browser entry for duckfn-docs-kit: the home-page custom elements and the
5
+ * value types their `set*` methods accept.
6
+ *
7
+ * The components are retained-mode (build once, then mutate held nodes) and
8
+ * expose named setters such as `setTitle()` / `setBadges()`. They render into
9
+ * shadow roots and inject their own stylesheet, so the consuming site imports
10
+ * only the global CSS the kit cannot host in a shadow (`src/kit.css`: brand
11
+ * tokens + TOC toggle, imported as `duckfn-docs-kit/src/kit.css`). Icons are
12
+ * rendered by the official `<iconify-icon>`
13
+ * web component, which `registerDfkElements()` registers as a side effect, so
14
+ * this package ships no icon data.
15
+ *
16
+ * `TocToggle` and the remark plugin keep their own subpaths
17
+ * (`duckfn-docs-kit/toc-toggle/TocToggle`, `duckfn-docs-kit/remark`) instead of
18
+ * being merged here: a Docusaurus config file must never pull browser code into
19
+ * Node, and a site that only wants the TOC collapse button should not pay for
20
+ * the bundled `iconify-icon`.
21
+ */
22
+ export {DfkFeatures} from './home/DfkFeatures';
23
+ export {DfkHero} from './home/DfkHero';
24
+ export {DfkNextSteps} from './home/DfkNextSteps';
25
+ export {DfkSql} from './sql/DfkSql';
26
+ export {registerDfkElements} from './register';
27
+ export type {RunnableSqlConfig} from './sql/remark';
28
+ export type {
29
+ FeatureItem,
30
+ HeroAction,
31
+ HeroBadge,
32
+ HeroLink,
33
+ NextStepItem,
34
+ } from './types';
35
+
36
+ /**
37
+ * Props accepted by the `dfk-*` tags when they are created from React.
38
+ *
39
+ * The content is *not* passed as a prop — an object prop would never reach the
40
+ * component through hydration (React only reconciles strings onto custom
41
+ * elements). The caller mounts the element and drives it through its setters
42
+ * from a callback ref, so all React needs to know about is `ref`.
43
+ *
44
+ * The alias is exported (rather than written inline) because the emitted `.d.ts`
45
+ * for a module augmentation can only name types that are themselves reachable
46
+ * from the declaration file.
47
+ */
48
+ export type DfkElementProps = HTMLAttributes<HTMLElement>;
49
+
50
+ declare module 'react' {
51
+ namespace JSX {
52
+ interface IntrinsicElements {
53
+ 'dfk-hero': DfkElementProps;
54
+ 'dfk-features': DfkElementProps;
55
+ 'dfk-next-steps': DfkElementProps;
56
+ 'dfk-sql': DfkElementProps;
57
+ }
58
+ }
59
+ }
package/src/kit.css ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * One-line entry point for the CSS that must stay global: brand tokens + TOC
3
+ * toggle.
4
+ *
5
+ * The home components' CSS is deliberately *not* imported here. The `dfk-*`
6
+ * components render into shadow roots and inject their own styles from the JS
7
+ * bundle (see `home/styles.ts`), so a site that consumes the components gets
8
+ * their styles for free. What remains here is the CSS a shadow boundary cannot
9
+ * host: the `--duckfn-*` tokens (they must be declared on `:root` /
10
+ * `[data-theme]` so they can inherit *into* the shadow trees) and the TOC
11
+ * toggle (light-DOM rules that must sit inside
12
+ * `@layer docusaurus.theme-classic`).
13
+ *
14
+ * Each stylesheet lives in the feature folder it belongs to; this file only
15
+ * aggregates them for the consuming site's one-line `@import`.
16
+ */
17
+ @import './theme/tokens.css';
18
+ @import './toc-toggle/TocToggle.css';
19
+ @import './sql/sql.css';
@@ -0,0 +1,39 @@
1
+ // Side-effect import: registers the official `<iconify-icon>` custom element,
2
+ // which the `dfk-*` components use for every glyph. It loads icon data on
3
+ // demand from the public Iconify API, so this package ships no icon sets.
4
+ import 'iconify-icon';
5
+ import {DfkFeatures} from './home/DfkFeatures';
6
+ import {DfkHero} from './home/DfkHero';
7
+ import {DfkNextSteps} from './home/DfkNextSteps';
8
+ import {DfkSql} from './sql/DfkSql';
9
+
10
+ const TAGS = {
11
+ hero: 'dfk-hero',
12
+ features: 'dfk-features',
13
+ nextSteps: 'dfk-next-steps',
14
+ sql: 'dfk-sql',
15
+ } as const;
16
+
17
+ /**
18
+ * Defines the `dfk-*` custom elements. Idempotent and SSR-safe: it is a no-op
19
+ * outside the browser, and re-running it never throws
20
+ * "already been registered with the custom element registry".
21
+ *
22
+ * Call it once at module scope in the docs site (and anywhere else that uses
23
+ * the components); importing the classes alone does not register anything.
24
+ */
25
+ export function registerDfkElements(): void {
26
+ if (typeof customElements === 'undefined') {
27
+ return;
28
+ }
29
+ for (const [name, ctor] of Object.entries({
30
+ [TAGS.hero]: DfkHero,
31
+ [TAGS.features]: DfkFeatures,
32
+ [TAGS.nextSteps]: DfkNextSteps,
33
+ [TAGS.sql]: DfkSql,
34
+ })) {
35
+ if (!customElements.get(name)) {
36
+ customElements.define(name, ctor);
37
+ }
38
+ }
39
+ }