@cosense-toolbox/tailwind 0.1.0-beta.2

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.
package/dist/index.mjs ADDED
@@ -0,0 +1,696 @@
1
+ import plugin from "tailwindcss/plugin";
2
+ //#region src/modifiers.ts
3
+ const MODIFIERS = [
4
+ {
5
+ name: "title",
6
+ target: ".title",
7
+ notation: "タイトル (1 行目)"
8
+ },
9
+ {
10
+ name: "line",
11
+ target: ".line",
12
+ notation: "各行"
13
+ },
14
+ {
15
+ name: "heading",
16
+ target: ".decoration[data-size-level]",
17
+ notation: "`[** 見出し]` などの大きな文字"
18
+ },
19
+ {
20
+ name: "strong",
21
+ target: "strong",
22
+ notation: "`[[太字]]` `[* 太字]`"
23
+ },
24
+ {
25
+ name: "em",
26
+ target: "em",
27
+ notation: "`[/ 斜体]`"
28
+ },
29
+ {
30
+ name: "s",
31
+ target: "s",
32
+ notation: "`[- 打ち消し]`"
33
+ },
34
+ {
35
+ name: "u",
36
+ target: "u",
37
+ notation: "`[_ 下線]`"
38
+ },
39
+ {
40
+ name: "link",
41
+ target: ".link",
42
+ notation: "リンクすべて (`[ページ]` `[https://…]` `[/project/ページ]`)"
43
+ },
44
+ {
45
+ name: "link-external",
46
+ target: ".link-external",
47
+ notation: "外部リンク `[https://…]`"
48
+ },
49
+ {
50
+ name: "link-project",
51
+ target: ".link-project",
52
+ notation: "別プロジェクトへのリンク `[/project/ページ]`"
53
+ },
54
+ {
55
+ name: "hashtag",
56
+ target: ".hashtag",
57
+ notation: "`#タグ`"
58
+ },
59
+ {
60
+ name: "code",
61
+ target: ".code",
62
+ notation: "`` `コード` ``"
63
+ },
64
+ {
65
+ name: "code-block",
66
+ target: ".code-block > code",
67
+ notation: "`code:ファイル名` のブロックの各行"
68
+ },
69
+ {
70
+ name: "code-filename",
71
+ target: ".code-block-start",
72
+ notation: "`code:ファイル名` のファイル名"
73
+ },
74
+ {
75
+ name: "quote",
76
+ target: ".quote",
77
+ notation: "`>` で始まる引用"
78
+ },
79
+ {
80
+ name: "table",
81
+ target: ".table",
82
+ notation: "`table:名前` の表"
83
+ },
84
+ {
85
+ name: "td",
86
+ target: ".table td",
87
+ notation: "表のセル"
88
+ },
89
+ {
90
+ name: "image",
91
+ target: ".image",
92
+ notation: "画像"
93
+ },
94
+ {
95
+ name: "icon",
96
+ target: ".icon",
97
+ notation: "`[ユーザー名.icon]`"
98
+ },
99
+ {
100
+ name: "formula",
101
+ target: ".formula",
102
+ notation: "`[$ 数式]`"
103
+ }
104
+ ];
105
+ //#endregion
106
+ //#region src/styles.generated.ts
107
+ const styles = {
108
+ "root": {
109
+ "font-family": "var(--cosense-font, \"Open Sans\", Helvetica, Arial, \"Hiragino Sans\", sans-serif)",
110
+ "font-size": "var(--cosense-font-size, 15px)",
111
+ "line-height": "var(--cosense-line-height, 1.87)",
112
+ "color": "var(--cosense-text, var(--page-text-color, #4a4a4a))",
113
+ "background": "var(--cosense-bg, var(--page-bg, #fefefe))",
114
+ "text-align": "left",
115
+ "word-wrap": "break-word"
116
+ },
117
+ "rules": [
118
+ {
119
+ "selector": {
120
+ "body": ".title",
121
+ "pseudo": ""
122
+ },
123
+ "declarations": {
124
+ "margin": "0 0 0.77em",
125
+ "font-size": "1.73em",
126
+ "font-weight": "700",
127
+ "line-height": "1.62",
128
+ "color": "var(--cosense-title, var(--line-title-color, var(--page-text-color, #4a4a4a)))"
129
+ }
130
+ },
131
+ {
132
+ "selector": {
133
+ "body": ".line",
134
+ "pseudo": ""
135
+ },
136
+ "declarations": {
137
+ "position": "relative",
138
+ "min-height": "1em",
139
+ "font-variant-ligatures": "no-common-ligatures"
140
+ }
141
+ },
142
+ {
143
+ "selector": {
144
+ "body": ".indent-mark",
145
+ "pseudo": ""
146
+ },
147
+ "declarations": {
148
+ "position": "absolute",
149
+ "left": "0",
150
+ "top": "0",
151
+ "height": "1em",
152
+ "color": "transparent"
153
+ }
154
+ },
155
+ {
156
+ "selector": {
157
+ "body": ".pad",
158
+ "pseudo": ""
159
+ },
160
+ "declarations": {
161
+ "display": "inline-block",
162
+ "width": "var(--cosense-indent, 1.5em)",
163
+ "height": "1em",
164
+ "overflow": "hidden"
165
+ }
166
+ },
167
+ {
168
+ "selector": {
169
+ "body": ".dot",
170
+ "pseudo": ""
171
+ },
172
+ "declarations": {
173
+ "position": "absolute",
174
+ "right": "0.65em",
175
+ "top": "0.7em",
176
+ "width": "6px",
177
+ "height": "6px",
178
+ "border-radius": "50%",
179
+ "background": "var(--cosense-text, var(--page-text-color, #555))"
180
+ }
181
+ },
182
+ {
183
+ "selector": {
184
+ "body": ".link",
185
+ "pseudo": ""
186
+ },
187
+ "declarations": {
188
+ "color": "var(--cosense-link, var(--page-link-color, #3d72f5))",
189
+ "text-decoration": "none",
190
+ "-webkit-tap-highlight-color": "rgba(0, 0, 0, 0.2)"
191
+ }
192
+ },
193
+ {
194
+ "selector": {
195
+ "body": ".hashtag",
196
+ "pseudo": ""
197
+ },
198
+ "declarations": {
199
+ "color": "var(--cosense-link, var(--page-link-color, #3d72f5))",
200
+ "text-decoration": "none",
201
+ "-webkit-tap-highlight-color": "rgba(0, 0, 0, 0.2)"
202
+ }
203
+ },
204
+ {
205
+ "selector": {
206
+ "body": ".code",
207
+ "pseudo": ""
208
+ },
209
+ "declarations": {
210
+ "font-family": "var(--cosense-code-font, ui-monospace, SFMono-Regular, Menlo, monospace)",
211
+ "color": "var(--cosense-code-text, var(--code-color, #342d9c))"
212
+ }
213
+ },
214
+ {
215
+ "selector": {
216
+ "body": ".code-start",
217
+ "pseudo": ""
218
+ },
219
+ "declarations": {
220
+ "font-family": "var(--cosense-code-font, ui-monospace, SFMono-Regular, Menlo, monospace)",
221
+ "color": "var(--cosense-code-text, var(--code-color, #342d9c))"
222
+ }
223
+ },
224
+ {
225
+ "selector": {
226
+ "body": ".code-body",
227
+ "pseudo": ""
228
+ },
229
+ "declarations": {
230
+ "font-family": "var(--cosense-code-font, ui-monospace, SFMono-Regular, Menlo, monospace)",
231
+ "color": "var(--cosense-code-text, var(--code-color, #342d9c))"
232
+ }
233
+ },
234
+ {
235
+ "selector": {
236
+ "body": ".monospace",
237
+ "pseudo": ""
238
+ },
239
+ "declarations": {
240
+ "font-family": "var(--cosense-code-font, ui-monospace, SFMono-Regular, Menlo, monospace)",
241
+ "color": "var(--cosense-code-text, var(--code-color, #342d9c))"
242
+ }
243
+ },
244
+ {
245
+ "selector": {
246
+ "body": ".code",
247
+ "pseudo": ""
248
+ },
249
+ "declarations": {
250
+ "padding": "0 0.2em",
251
+ "border-radius": "4px",
252
+ "font-size": "90%",
253
+ "word-wrap": "break-word",
254
+ "background": "var(--cosense-code-bg, var(--code-bg, rgba(0, 0, 0, 0.04)))"
255
+ }
256
+ },
257
+ {
258
+ "selector": {
259
+ "body": ".monospace",
260
+ "pseudo": ""
261
+ },
262
+ "declarations": {
263
+ "padding": "0 0.2em",
264
+ "border-radius": "4px",
265
+ "font-size": "90%",
266
+ "word-wrap": "break-word",
267
+ "background": "var(--cosense-code-bg, var(--code-bg, rgba(0, 0, 0, 0.04)))"
268
+ }
269
+ },
270
+ {
271
+ "selector": {
272
+ "body": ".code-block-start",
273
+ "pseudo": ""
274
+ },
275
+ "declarations": {
276
+ "padding": "1px 2px",
277
+ "font-size": "0.95em",
278
+ "color": "var(--cosense-badge-text, #342d9c)",
279
+ "background": "var(--cosense-badge-bg, #ffcfc6)"
280
+ }
281
+ },
282
+ {
283
+ "selector": {
284
+ "body": ".quote",
285
+ "pseudo": ""
286
+ },
287
+ "declarations": {
288
+ "display": "block",
289
+ "margin": "0",
290
+ "padding-left": "3px",
291
+ "border-left": "solid 1px #a0a0a0",
292
+ "background": "var(--cosense-quote-bg, var(--quote-bg-color, rgba(0, 0, 0, 0.05)))"
293
+ }
294
+ },
295
+ {
296
+ "selector": {
297
+ "body": ".table",
298
+ "pseudo": ""
299
+ },
300
+ "declarations": {
301
+ "margin": "0",
302
+ "border-collapse": "collapse",
303
+ "caption-side": "top"
304
+ }
305
+ },
306
+ {
307
+ "selector": {
308
+ "body": ".image",
309
+ "pseudo": ""
310
+ },
311
+ "declarations": {
312
+ "display": "inline-block",
313
+ "max-width": "100%",
314
+ "max-height": "300px",
315
+ "vertical-align": "bottom"
316
+ }
317
+ },
318
+ {
319
+ "selector": {
320
+ "body": ".formula",
321
+ "pseudo": ""
322
+ },
323
+ "declarations": {
324
+ "margin": "auto 6px",
325
+ "font-family": "var(--cosense-code-font, ui-monospace, SFMono-Regular, Menlo, monospace)",
326
+ "font-style": "italic"
327
+ }
328
+ },
329
+ {
330
+ "selector": {
331
+ "body": ".table caption",
332
+ "pseudo": ""
333
+ },
334
+ "declarations": {
335
+ "padding": "1px 2px",
336
+ "text-align": "center",
337
+ "font-size": "0.9em",
338
+ "color": "var(--cosense-badge-text, #342d9c)",
339
+ "background": "var(--cosense-badge-bg, #ffcfc6)"
340
+ }
341
+ },
342
+ {
343
+ "selector": {
344
+ "body": ".table td",
345
+ "pseudo": ""
346
+ },
347
+ "declarations": {
348
+ "padding": "0 2px 0 8px",
349
+ "white-space": "nowrap"
350
+ }
351
+ },
352
+ {
353
+ "selector": {
354
+ "body": "img.icon",
355
+ "pseudo": ""
356
+ },
357
+ "declarations": {
358
+ "display": "inline-block",
359
+ "position": "relative",
360
+ "top": "-0.3em",
361
+ "height": "1.3em",
362
+ "max-width": "100%",
363
+ "vertical-align": "baseline"
364
+ }
365
+ },
366
+ {
367
+ "selector": {
368
+ "body": ".line[data-indent=\"1\"]",
369
+ "pseudo": ""
370
+ },
371
+ "declarations": { "--cosense-depth": "1" }
372
+ },
373
+ {
374
+ "selector": {
375
+ "body": ".line[data-indent=\"2\"]",
376
+ "pseudo": ""
377
+ },
378
+ "declarations": { "--cosense-depth": "2" }
379
+ },
380
+ {
381
+ "selector": {
382
+ "body": ".line[data-indent=\"3\"]",
383
+ "pseudo": ""
384
+ },
385
+ "declarations": { "--cosense-depth": "3" }
386
+ },
387
+ {
388
+ "selector": {
389
+ "body": ".line[data-indent=\"4\"]",
390
+ "pseudo": ""
391
+ },
392
+ "declarations": { "--cosense-depth": "4" }
393
+ },
394
+ {
395
+ "selector": {
396
+ "body": ".line[data-indent=\"5\"]",
397
+ "pseudo": ""
398
+ },
399
+ "declarations": { "--cosense-depth": "5" }
400
+ },
401
+ {
402
+ "selector": {
403
+ "body": ".line[data-indent=\"6\"]",
404
+ "pseudo": ""
405
+ },
406
+ "declarations": { "--cosense-depth": "6" }
407
+ },
408
+ {
409
+ "selector": {
410
+ "body": ".line[data-indent=\"7\"]",
411
+ "pseudo": ""
412
+ },
413
+ "declarations": { "--cosense-depth": "7" }
414
+ },
415
+ {
416
+ "selector": {
417
+ "body": ".line[data-indent=\"8\"]",
418
+ "pseudo": ""
419
+ },
420
+ "declarations": { "--cosense-depth": "8" }
421
+ },
422
+ {
423
+ "selector": {
424
+ "body": ".line[data-indent=\"9\"]",
425
+ "pseudo": ""
426
+ },
427
+ "declarations": { "--cosense-depth": "9" }
428
+ },
429
+ {
430
+ "selector": {
431
+ "body": ".line[data-indent=\"10\"]",
432
+ "pseudo": ""
433
+ },
434
+ "declarations": { "--cosense-depth": "10" }
435
+ },
436
+ {
437
+ "selector": {
438
+ "body": ".line[data-indent]",
439
+ "pseudo": ""
440
+ },
441
+ "declarations": { "padding-left": "calc(var(--cosense-indent, 1.5em) * var(--cosense-depth, 0))" }
442
+ },
443
+ {
444
+ "selector": {
445
+ "body": ".link:hover",
446
+ "pseudo": ""
447
+ },
448
+ "declarations": { "color": "var(--cosense-link-hover, var(--page-link-hover-color, #0d4ff3))" }
449
+ },
450
+ {
451
+ "selector": {
452
+ "body": ".hashtag:hover",
453
+ "pseudo": ""
454
+ },
455
+ "declarations": { "color": "var(--cosense-link-hover, var(--page-link-hover-color, #0d4ff3))" }
456
+ },
457
+ {
458
+ "selector": {
459
+ "body": ".image[data-large]",
460
+ "pseudo": ""
461
+ },
462
+ "declarations": {
463
+ "margin": "3px 0",
464
+ "max-width": "95%",
465
+ "max-height": "none"
466
+ }
467
+ },
468
+ {
469
+ "selector": {
470
+ "body": ".decoration[data-size-level=\"1\"]",
471
+ "pseudo": ""
472
+ },
473
+ "declarations": { "font-size": "1.2em" }
474
+ },
475
+ {
476
+ "selector": {
477
+ "body": ".decoration[data-size-level=\"2\"]",
478
+ "pseudo": ""
479
+ },
480
+ "declarations": { "font-size": "1.44em" }
481
+ },
482
+ {
483
+ "selector": {
484
+ "body": ".decoration[data-size-level=\"3\"]",
485
+ "pseudo": ""
486
+ },
487
+ "declarations": { "font-size": "1.73em" }
488
+ },
489
+ {
490
+ "selector": {
491
+ "body": ".decoration[data-size-level=\"4\"]",
492
+ "pseudo": ""
493
+ },
494
+ "declarations": { "font-size": "2.07em" }
495
+ },
496
+ {
497
+ "selector": {
498
+ "body": ".decoration[data-size-level]",
499
+ "pseudo": ""
500
+ },
501
+ "declarations": {
502
+ "display": "inline-block",
503
+ "line-height": "1.6"
504
+ }
505
+ },
506
+ {
507
+ "selector": {
508
+ "body": ".line[data-indent]",
509
+ "pseudo": "::before"
510
+ },
511
+ "declarations": {
512
+ "content": "\"\"",
513
+ "position": "absolute",
514
+ "top": "0.7em",
515
+ "left": "calc(var(--cosense-indent, 1.5em) * var(--cosense-depth, 0) - 1.05em)",
516
+ "width": "6px",
517
+ "height": "6px",
518
+ "border-radius": "50%",
519
+ "background": "var(--cosense-text, var(--page-text-color, #555))"
520
+ }
521
+ },
522
+ {
523
+ "selector": {
524
+ "body": ".line:has(> .indent-mark)",
525
+ "pseudo": "::before"
526
+ },
527
+ "declarations": { "content": "none" }
528
+ },
529
+ {
530
+ "selector": {
531
+ "body": ".line.code-block > code",
532
+ "pseudo": ""
533
+ },
534
+ "declarations": {
535
+ "display": "block",
536
+ "min-height": "1.7em",
537
+ "line-height": "1.7em",
538
+ "tab-size": "4",
539
+ "background": "var(--cosense-code-bg, var(--code-bg, rgba(0, 0, 0, 0.04)))"
540
+ }
541
+ },
542
+ {
543
+ "selector": {
544
+ "body": ".table td:nth-child(odd)",
545
+ "pseudo": ""
546
+ },
547
+ "declarations": { "background": "rgba(0, 0, 0, 0.04)" }
548
+ },
549
+ {
550
+ "selector": {
551
+ "body": ".table td:nth-child(even)",
552
+ "pseudo": ""
553
+ },
554
+ "declarations": { "background": "rgba(0, 0, 0, 0.06)" }
555
+ },
556
+ {
557
+ "selector": {
558
+ "body": ".line.code-block > .code-body",
559
+ "pseudo": ""
560
+ },
561
+ "declarations": {
562
+ "margin-left": "calc(var(--cosense-indent, 1.5em) * -1)",
563
+ "padding-left": "var(--cosense-indent, 1.5em)",
564
+ "white-space": "pre-wrap"
565
+ }
566
+ },
567
+ {
568
+ "selector": {
569
+ "body": ".line.code-block[data-line-digits=\"1\"]",
570
+ "pseudo": ""
571
+ },
572
+ "declarations": { "--cosense-line-digits": "1" }
573
+ },
574
+ {
575
+ "selector": {
576
+ "body": ".line.code-block[data-line-digits=\"2\"]",
577
+ "pseudo": ""
578
+ },
579
+ "declarations": { "--cosense-line-digits": "2" }
580
+ },
581
+ {
582
+ "selector": {
583
+ "body": ".line.code-block[data-line-digits=\"3\"]",
584
+ "pseudo": ""
585
+ },
586
+ "declarations": { "--cosense-line-digits": "3" }
587
+ },
588
+ {
589
+ "selector": {
590
+ "body": ".line.code-block[data-line-digits=\"4\"]",
591
+ "pseudo": ""
592
+ },
593
+ "declarations": { "--cosense-line-digits": "4" }
594
+ },
595
+ {
596
+ "selector": {
597
+ "body": ".line.code-block[data-line-digits=\"5\"]",
598
+ "pseudo": ""
599
+ },
600
+ "declarations": { "--cosense-line-digits": "5" }
601
+ },
602
+ {
603
+ "selector": {
604
+ "body": ".line.code-block:not(:has(> .code-start))",
605
+ "pseudo": "::before"
606
+ },
607
+ "declarations": { "content": "none" }
608
+ },
609
+ {
610
+ "selector": {
611
+ "body": ".line.code-block[data-line]",
612
+ "pseudo": "::before"
613
+ },
614
+ "declarations": {
615
+ "content": "attr(data-line)",
616
+ "top": "0",
617
+ "left": "calc(var(--cosense-indent, 1.5em) * (var(--cosense-depth, 1) - 1))",
618
+ "width": "calc(0.6em + var(--cosense-line-digits, 5) * 1ch)",
619
+ "height": "auto",
620
+ "display": "flex",
621
+ "justify-content": "flex-end",
622
+ "white-space": "nowrap",
623
+ "border-radius": "0",
624
+ "background": "none",
625
+ "font-family": "var(--cosense-code-font, ui-monospace, SFMono-Regular, Menlo, monospace)",
626
+ "line-height": "1.7em",
627
+ "color": "var(--cosense-line-number, rgba(0, 0, 0, 0.35))"
628
+ }
629
+ },
630
+ {
631
+ "selector": {
632
+ "body": ".line.code-block[data-line] > .code-body",
633
+ "pseudo": ""
634
+ },
635
+ "declarations": { "padding-left": "calc(0.6em + (var(--cosense-line-digits, 5) + 1) * 1ch)" }
636
+ }
637
+ ]
638
+ };
639
+ //#endregion
640
+ //#region src/index.ts
641
+ /**
642
+ * `@cosense-toolbox/tailwind` — `class="cosense"` を付けた要素の中に、Cosense 記法の既定の見た目を当てる。
643
+ * typography の `prose` と同じ使い方をする。
644
+ *
645
+ * ```css
646
+ * @import "tailwindcss";
647
+ * @plugin "@cosense-toolbox/tailwind";
648
+ * ```
649
+ *
650
+ * 当てるスタイルは `@cosense-toolbox/style` の style.css と同じもの。`cosense-link:underline` のような
651
+ * modifier で、記事の中の特定の記法にだけ utility を当てられる。
652
+ */
653
+ /** 生成したデータは readonly なので、Tailwind の可変の型に合わせる (中身は書き換えない)。 */
654
+ const mutable = (declarations) => declarations;
655
+ /**
656
+ * `not-{className}` を付けた要素とその中を除く条件。`:where()` の中なので詳細度を増やさない。
657
+ */
658
+ const outside = (className) => `:not(:where([class~="not-${className}"],[class~="not-${className}"] *))`;
659
+ /**
660
+ * 1 つのルールのセレクタ。本文を `:where()` で包み、どのルールも `.cosense` と同じ詳細度にする。
661
+ * 除く条件は擬似要素より前に付ける。
662
+ *
663
+ * 詳細度を揃えるので、ルールどうしの勝ち負けは並び順だけで決まる。生成したデータは元の詳細度の
664
+ * 低い順に並んでいるので、style.css と同じ勝ち負けになる。後ろに出る `cosense-link:` などの
665
+ * modifier や、同じ詳細度の utility が既定のスタイルに勝てるのは、このため。
666
+ */
667
+ const selectorOf = ({ selector }, className) => `& :where(${selector.body})${outside(className)}${selector.pseudo}`;
668
+ /**
669
+ * ルールごとに別のオブジェクトにする。1 つのオブジェクトのキーにすると、同じセレクタのルールが
670
+ * 後のもので上書きされてしまうため。Tailwind は並べた順のまま `.cosense` の中に出す。
671
+ */
672
+ const componentsOf = (className) => [{ [`.${className}`]: mutable(styles.root) }, ...styles.rules.map((rule) => ({ [`.${className}`]: { [selectorOf(rule, className)]: mutable(rule.declarations) } }))];
673
+ /** `cosense-link:` なら `.cosense-link\:underline :is(…)` のように、中の対象だけに当てる。 */
674
+ const modifierOf = (modifier, className) => `& :is(:where(${modifier.target})${outside(className)})`;
675
+ /** class 名に使えない記号を、CSS のセレクタ用にエスケープする。 */
676
+ const escapeClassChar = (char) => /[A-Za-z0-9_-]/.test(char) ? char : `\\${char}`;
677
+ /**
678
+ * `cosense-deco-[|]:` の `[...]` に書いた記号の装飾。`toHtml` は装飾を
679
+ * `<span class="decoration deco-|">` のように記号ごとの class で出すので、それを選ぶ。
680
+ * 記号を並べると (`[-/]`)、それらをすべて持つ装飾に当たる。
681
+ *
682
+ * Tailwind は `[...]` の中の `_` を空白に変える。下線の記号 `_` は `[\_]` と書く (Tailwind の決まり)。
683
+ */
684
+ const decorationOf = (markers, className) => {
685
+ return `& :is(:where(.decoration${[...new Set(markers)].map((marker) => `.deco-${escapeClassChar(marker)}`).join("")})${outside(className)})`;
686
+ };
687
+ const cosense = plugin.withOptions((options) => ({ addComponents, addVariant, matchVariant }) => {
688
+ const className = options?.className ?? "cosense";
689
+ addComponents(componentsOf(className));
690
+ for (const modifier of MODIFIERS) addVariant(`${className}-${modifier.name}`, modifierOf(modifier, className));
691
+ matchVariant(`${className}-deco`, (markers) => decorationOf(markers, className));
692
+ });
693
+ //#endregion
694
+ export { cosense as default };
695
+
696
+ //# sourceMappingURL=index.mjs.map