@wtfalch/design 0.10.2 → 0.12.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.
- package/README.md +36 -0
- package/dist/components/DangerZone.js +1 -1
- package/dist/components/Field.d.ts +8 -1
- package/dist/components/Field.js +2 -2
- package/dist/components/RichText.d.ts +24 -0
- package/dist/components/RichText.js +69 -0
- package/dist/components/RichTextEditor.d.ts +32 -0
- package/dist/components/RichTextEditor.js +163 -0
- package/dist/components/Toggle.d.ts +8 -1
- package/dist/components/Toggle.js +2 -2
- package/dist/editor.d.ts +16 -0
- package/dist/editor.js +16 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5 -0
- package/dist/rich-text/schema.d.ts +219 -0
- package/dist/rich-text/schema.js +88 -0
- package/dist/rich-text/value.d.ts +25 -0
- package/dist/rich-text/value.js +41 -0
- package/dist/rich-text.d.ts +11 -0
- package/dist/rich-text.js +11 -0
- package/dist/styles/index.css +132 -21
- package/dist/tf.css +132 -21
- package/dist/valet.css +132 -21
- package/package.json +44 -4
package/dist/tf.css
CHANGED
|
@@ -307,6 +307,7 @@
|
|
|
307
307
|
--text-2xs: var(--text-2xs);
|
|
308
308
|
--text-md: var(--text-md);
|
|
309
309
|
--font-weight-strong: var(--weight-strong);
|
|
310
|
+
--radius-DEFAULT: var(--radius);
|
|
310
311
|
--radius-pill: var(--radius-pill);
|
|
311
312
|
--color-text: var(--text);
|
|
312
313
|
--color-muted: var(--muted);
|
|
@@ -443,6 +444,9 @@
|
|
|
443
444
|
.min-h-0 {
|
|
444
445
|
min-height: 0px;
|
|
445
446
|
}
|
|
447
|
+
.min-h-\[calc\(var\(--space-15\)\*2\)\] {
|
|
448
|
+
min-height: calc(var(--space-15) * 2);
|
|
449
|
+
}
|
|
446
450
|
.min-h-screen {
|
|
447
451
|
min-height: 100vh;
|
|
448
452
|
}
|
|
@@ -583,6 +587,9 @@
|
|
|
583
587
|
.rounded {
|
|
584
588
|
border-radius: 0.25rem;
|
|
585
589
|
}
|
|
590
|
+
.rounded-\(--radius\) {
|
|
591
|
+
border-radius: var(--radius);
|
|
592
|
+
}
|
|
586
593
|
.rounded-full {
|
|
587
594
|
border-radius: calc(infinity * 1px);
|
|
588
595
|
}
|
|
@@ -732,6 +739,9 @@
|
|
|
732
739
|
.uppercase {
|
|
733
740
|
text-transform: uppercase;
|
|
734
741
|
}
|
|
742
|
+
.italic {
|
|
743
|
+
font-style: italic;
|
|
744
|
+
}
|
|
735
745
|
.tabular-nums {
|
|
736
746
|
--tw-numeric-spacing: tabular-nums;
|
|
737
747
|
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
|
|
@@ -778,9 +788,16 @@
|
|
|
778
788
|
.surface-bg {
|
|
779
789
|
background: var(--bg);
|
|
780
790
|
}
|
|
791
|
+
.surface-control {
|
|
792
|
+
background: var(--control);
|
|
793
|
+
}
|
|
781
794
|
.surface-panel {
|
|
782
795
|
background: var(--panel);
|
|
783
796
|
}
|
|
797
|
+
.focus-within\:shadow-\(--focus-ring\):focus-within {
|
|
798
|
+
--tw-shadow: var(--focus-ring);
|
|
799
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
800
|
+
}
|
|
784
801
|
.disabled\:cursor-default:disabled {
|
|
785
802
|
cursor: default;
|
|
786
803
|
}
|
|
@@ -1513,13 +1530,6 @@ select:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
|
1513
1530
|
to { transform: scaleX(0); }
|
|
1514
1531
|
}
|
|
1515
1532
|
|
|
1516
|
-
/* (The bordered head bar that used to live here is gone. It was a second
|
|
1517
|
-
`.card-head` -- same name, different thing -- and the only place it was ever
|
|
1518
|
-
used was the gallery page documenting it. A card that holds rows now takes
|
|
1519
|
-
`title` like any other, and the header the component draws is the one
|
|
1520
|
-
header.) */
|
|
1521
|
-
.row { display: flex; align-items: center; gap: var(--space-3); }
|
|
1522
|
-
|
|
1523
1533
|
.ctl-grow { flex: 1; min-width: 0; }
|
|
1524
1534
|
|
|
1525
1535
|
.mono { font-family: var(--font-mono); font-size: var(--text-sm); }
|
|
@@ -1780,13 +1790,6 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
1780
1790
|
template are allowed to diverge, and this is only saying that they have. */
|
|
1781
1791
|
.set-hint.drifted { color: var(--warn); }
|
|
1782
1792
|
|
|
1783
|
-
/* One applet, alone on the page, at `/applet/<id>`. Fills the window: there is
|
|
1784
|
-
no grid here to decide a height, and a screenshot of an applet letterboxed
|
|
1785
|
-
inside a page is mostly not the applet. */
|
|
1786
|
-
.bare { height: 100vh; display: flex; flex-direction: column; background: var(--bg); }
|
|
1787
|
-
|
|
1788
|
-
.bare > * { flex: 1; min-height: 0; }
|
|
1789
|
-
|
|
1790
1793
|
/* A round is in flight. On the button that asks for one, because that is where
|
|
1791
1794
|
you are looking when you have just pressed it -- and not in the foot, which
|
|
1792
1795
|
would flicker every thirty seconds on a tile that is working perfectly. */
|
|
@@ -2134,7 +2137,15 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
2134
2137
|
|
|
2135
2138
|
.danger-act > .set-hint + .set-hint { margin-top: var(--space-1); }
|
|
2136
2139
|
|
|
2137
|
-
.
|
|
2140
|
+
/* `display: flex` is here now. These rows carried `.row` as well, which is a
|
|
2141
|
+
class no component of this package renders -- it only ever reached them
|
|
2142
|
+
because a consumer's stylesheet happened to define it too. */
|
|
2143
|
+
.danger-row {
|
|
2144
|
+
display: flex;
|
|
2145
|
+
margin-top: var(--space-2);
|
|
2146
|
+
gap: var(--space-2);
|
|
2147
|
+
align-items: center;
|
|
2148
|
+
}
|
|
2138
2149
|
|
|
2139
2150
|
.danger-row > input { min-width: 0; }
|
|
2140
2151
|
|
|
@@ -2156,15 +2167,15 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
2156
2167
|
column-gap: var(--space-3);
|
|
2157
2168
|
}
|
|
2158
2169
|
|
|
2159
|
-
.field-row { align-items: flex-end; gap: var(--space-2); }
|
|
2170
|
+
.danger-field-row { align-items: flex-end; gap: var(--space-2); }
|
|
2160
2171
|
|
|
2161
|
-
.field-row > button { flex: none; }
|
|
2172
|
+
.danger-field-row > button { flex: none; }
|
|
2162
2173
|
|
|
2163
2174
|
/* Two forms one under the other, whose buttons say different words -- "Add"
|
|
2164
2175
|
and "Block". Sized to their text they came out different widths, and two
|
|
2165
2176
|
controls in the same column at the same indent that do not line up read as
|
|
2166
2177
|
an accident rather than as a pair. */
|
|
2167
|
-
.field-row > button { min-width: 9ch; }
|
|
2178
|
+
.danger-field-row > button { min-width: 9ch; }
|
|
2168
2179
|
}
|
|
2169
2180
|
|
|
2170
2181
|
/* ---- ./callout.css ---- */
|
|
@@ -2495,9 +2506,12 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
2495
2506
|
/* Sized to its words, for a switch that sits in a row of other controls rather
|
|
2496
2507
|
than owning a row of its own. `flex: 1` there would push the label away from
|
|
2497
2508
|
the switch by the whole width of the bar. */
|
|
2498
|
-
|
|
2509
|
+
/* `inRow`: a toggle beside other controls rather than in a column of
|
|
2510
|
+
settings. Was `.row > .switch-row`, which reached through `.row` -- a class
|
|
2511
|
+
no component here renders. */
|
|
2512
|
+
.switch-in-row { flex: none; padding-block: 0; }
|
|
2499
2513
|
|
|
2500
|
-
.
|
|
2514
|
+
.switch-in-row .switch-body { flex: none; }
|
|
2501
2515
|
|
|
2502
2516
|
/* The opposite case: a switch that *is* the row, with something small beside it
|
|
2503
2517
|
-- a tooltip, a state word. `.set-row` wraps, so a switch that does not grow
|
|
@@ -4086,7 +4100,10 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
4086
4100
|
/* Fields stacked down a form. Wider than the gap inside one field, so the
|
|
4087
4101
|
label of the next belongs to the input under it rather than to the error
|
|
4088
4102
|
above it. */
|
|
4089
|
-
|
|
4103
|
+
/* `inRow`: a field sharing a line with other controls rather than stacked in a
|
|
4104
|
+
column. Was `.field-row > .field`, which reached through a container class
|
|
4105
|
+
the caller had to write and this package does not hand out. */
|
|
4106
|
+
.field-in-row { flex: 1; min-width: 0; }
|
|
4090
4107
|
|
|
4091
4108
|
/* A password with an eye -- `Input type="password"`.
|
|
4092
4109
|
A grid rather than `position: absolute`: both children take the one cell, the
|
|
@@ -4961,6 +4978,100 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4961
4978
|
.ident-remove:hover { background: var(--panel); color: var(--text); }
|
|
4962
4979
|
.ident-remove:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
|
4963
4980
|
}
|
|
4981
|
+
|
|
4982
|
+
/* Prose and the surface it is written on, added in 0.8.0. Last, because
|
|
4983
|
+
`.prose` styles the elements the reset in `base.css` flattened and has to
|
|
4984
|
+
win over it, and because the editor's box sits over nothing. */
|
|
4985
|
+
/* ---- ./richtext.css ---- */
|
|
4986
|
+
@layer components {
|
|
4987
|
+
/* Prose: one class, and the elements it styles are ones nobody wrote.
|
|
4988
|
+
*
|
|
4989
|
+
* That is the whole reason a class exists here rather than utilities. Inside
|
|
4990
|
+
* the editor the paragraphs, headings and lists are ProseMirror's, built
|
|
4991
|
+
* from the document — there is no JSX to hang a utility on, so the choice is
|
|
4992
|
+
* descendant rules behind one class or an arbitrary variant per element,
|
|
4993
|
+
* which is the same selector spelled worse. `Markdown` has the same problem
|
|
4994
|
+
* for the same reason and answers it the same way, as `.md` in `base.css`.
|
|
4995
|
+
*
|
|
4996
|
+
* The editor and the view share the class on purpose. They have to look
|
|
4997
|
+
* identical and one set of rules is what guarantees it; two sets maintained
|
|
4998
|
+
* separately is precisely how a what-you-see-is-what-you-get editor stops
|
|
4999
|
+
* being one. Everything the components *do* render — the box, the toolbar,
|
|
5000
|
+
* the writing surface's own padding and focus ring — is utilities in the
|
|
5001
|
+
* component, where it belongs.
|
|
5002
|
+
*
|
|
5003
|
+
* `.rich-text` and not `.prose`: this package's classes ship unprefixed into
|
|
5004
|
+
* other people's stylesheets, and `.prose` is the one name in CSS most
|
|
5005
|
+
* likely to already be taken — Tailwind's typography plugin defines exactly
|
|
5006
|
+
* it. A consumer with that plugin and this package would have had two sets
|
|
5007
|
+
* of margins fighting, and it would have read as a theming bug.
|
|
5008
|
+
*
|
|
5009
|
+
* Every value here is a token. The vertical rhythm is `--space-*`, four
|
|
5010
|
+
* pixels a step and scaling with `--density`; the type steps are `--text-*`,
|
|
5011
|
+
* scaling with `--font-size`. A heading two sizes apart from its body at one
|
|
5012
|
+
* density is two sizes apart at every density.
|
|
5013
|
+
*/
|
|
5014
|
+
|
|
5015
|
+
.rich-text > * {
|
|
5016
|
+
margin: 0;
|
|
5017
|
+
}
|
|
5018
|
+
|
|
5019
|
+
.rich-text > * + * {
|
|
5020
|
+
margin-top: var(--space-3);
|
|
5021
|
+
}
|
|
5022
|
+
|
|
5023
|
+
.rich-text h2 {
|
|
5024
|
+
font-size: var(--text-lg);
|
|
5025
|
+
font-weight: var(--weight-strong);
|
|
5026
|
+
letter-spacing: -0.01em;
|
|
5027
|
+
}
|
|
5028
|
+
|
|
5029
|
+
.rich-text h3 {
|
|
5030
|
+
font-size: var(--text-md);
|
|
5031
|
+
font-weight: var(--weight-strong);
|
|
5032
|
+
}
|
|
5033
|
+
|
|
5034
|
+
/* A heading after prose needs more room above it than below: the space
|
|
5035
|
+
belongs to the section it opens, not to the paragraph it follows. */
|
|
5036
|
+
.rich-text > * + :is(h2, h3) {
|
|
5037
|
+
margin-top: var(--space-6);
|
|
5038
|
+
}
|
|
5039
|
+
|
|
5040
|
+
.rich-text :is(ul, ol) {
|
|
5041
|
+
padding-left: var(--space-5);
|
|
5042
|
+
}
|
|
5043
|
+
|
|
5044
|
+
.rich-text li + li {
|
|
5045
|
+
margin-top: var(--space-1);
|
|
5046
|
+
}
|
|
5047
|
+
|
|
5048
|
+
.rich-text a {
|
|
5049
|
+
color: var(--accent);
|
|
5050
|
+
text-decoration: underline;
|
|
5051
|
+
text-underline-offset: 2px;
|
|
5052
|
+
}
|
|
5053
|
+
|
|
5054
|
+
.rich-text strong {
|
|
5055
|
+
font-weight: var(--weight-strong);
|
|
5056
|
+
}
|
|
5057
|
+
|
|
5058
|
+
/* An empty editor says what goes in it. The placeholder extension puts the
|
|
5059
|
+
words on the empty node as `data-placeholder` and marks it, so `attr()` is
|
|
5060
|
+
reading an attribute of the element it is drawn on — which is the part a
|
|
5061
|
+
hand-rolled rule got wrong twice: a rule on the paragraph cannot reach an
|
|
5062
|
+
attribute on the box, and ProseMirror's empty paragraph holds a trailing
|
|
5063
|
+
`<br>` so `:empty` never matches it either. `pointer-events: none` so a
|
|
5064
|
+
click on the words still lands in the text.
|
|
5065
|
+
|
|
5066
|
+
Harmless on the view, which never produces the class. */
|
|
5067
|
+
.rich-text p.is-editor-empty:first-child::before {
|
|
5068
|
+
content: attr(data-placeholder);
|
|
5069
|
+
float: left;
|
|
5070
|
+
height: 0;
|
|
5071
|
+
color: var(--muted);
|
|
5072
|
+
pointer-events: none;
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
4964
5075
|
/* ---- tf: the themes ---- */
|
|
4965
5076
|
:root[data-theme='night']{--bg:#0f1115;--panel:#161a21;--panel-2:#1c222b;--border:#262d38;--text:#e6e9ef;--muted:#8b94a4;--accent:#5b9dff;--accent-dim:#2a4877;--app-bg:#0f1115;color-scheme:dark}
|
|
4966
5077
|
:root[data-theme='paper']{--bg:#f6f7f9;--panel:#ffffff;--panel-2:#f0f2f5;--border:#e4e8ec;--border-strong:#8792a1;--text:#191d23;--muted:#5d6773;--accent:#0e7872;--accent-dim:#7fbdb8;--on-accent:#ffffff;--good:#1c7a4a;--warn:#8a6216;--bad:#b3312c;--info:#216bc9;--shadow-1:0 4px 14px rgba(16, 24, 40, 0.08);--shadow-2:0 8px 24px rgba(16, 24, 40, 0.10);--shadow-3:0 12px 32px rgba(16, 24, 40, 0.12);--scrim:rgba(16, 24, 40, 0.32);color-scheme:light}
|
package/dist/valet.css
CHANGED
|
@@ -311,6 +311,7 @@
|
|
|
311
311
|
--text-2xs: var(--text-2xs);
|
|
312
312
|
--text-md: var(--text-md);
|
|
313
313
|
--font-weight-strong: var(--weight-strong);
|
|
314
|
+
--radius-DEFAULT: var(--radius);
|
|
314
315
|
--radius-pill: var(--radius-pill);
|
|
315
316
|
--color-text: var(--text);
|
|
316
317
|
--color-muted: var(--muted);
|
|
@@ -447,6 +448,9 @@
|
|
|
447
448
|
.min-h-0 {
|
|
448
449
|
min-height: 0px;
|
|
449
450
|
}
|
|
451
|
+
.min-h-\[calc\(var\(--space-15\)\*2\)\] {
|
|
452
|
+
min-height: calc(var(--space-15) * 2);
|
|
453
|
+
}
|
|
450
454
|
.min-h-screen {
|
|
451
455
|
min-height: 100vh;
|
|
452
456
|
}
|
|
@@ -587,6 +591,9 @@
|
|
|
587
591
|
.rounded {
|
|
588
592
|
border-radius: 0.25rem;
|
|
589
593
|
}
|
|
594
|
+
.rounded-\(--radius\) {
|
|
595
|
+
border-radius: var(--radius);
|
|
596
|
+
}
|
|
590
597
|
.rounded-full {
|
|
591
598
|
border-radius: calc(infinity * 1px);
|
|
592
599
|
}
|
|
@@ -736,6 +743,9 @@
|
|
|
736
743
|
.uppercase {
|
|
737
744
|
text-transform: uppercase;
|
|
738
745
|
}
|
|
746
|
+
.italic {
|
|
747
|
+
font-style: italic;
|
|
748
|
+
}
|
|
739
749
|
.tabular-nums {
|
|
740
750
|
--tw-numeric-spacing: tabular-nums;
|
|
741
751
|
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
|
|
@@ -782,9 +792,16 @@
|
|
|
782
792
|
.surface-bg {
|
|
783
793
|
background: var(--bg);
|
|
784
794
|
}
|
|
795
|
+
.surface-control {
|
|
796
|
+
background: var(--control);
|
|
797
|
+
}
|
|
785
798
|
.surface-panel {
|
|
786
799
|
background: var(--panel);
|
|
787
800
|
}
|
|
801
|
+
.focus-within\:shadow-\(--focus-ring\):focus-within {
|
|
802
|
+
--tw-shadow: var(--focus-ring);
|
|
803
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
804
|
+
}
|
|
788
805
|
.disabled\:cursor-default:disabled {
|
|
789
806
|
cursor: default;
|
|
790
807
|
}
|
|
@@ -1517,13 +1534,6 @@ select:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
|
1517
1534
|
to { transform: scaleX(0); }
|
|
1518
1535
|
}
|
|
1519
1536
|
|
|
1520
|
-
/* (The bordered head bar that used to live here is gone. It was a second
|
|
1521
|
-
`.card-head` -- same name, different thing -- and the only place it was ever
|
|
1522
|
-
used was the gallery page documenting it. A card that holds rows now takes
|
|
1523
|
-
`title` like any other, and the header the component draws is the one
|
|
1524
|
-
header.) */
|
|
1525
|
-
.row { display: flex; align-items: center; gap: var(--space-3); }
|
|
1526
|
-
|
|
1527
1537
|
.ctl-grow { flex: 1; min-width: 0; }
|
|
1528
1538
|
|
|
1529
1539
|
.mono { font-family: var(--font-mono); font-size: var(--text-sm); }
|
|
@@ -1784,13 +1794,6 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
1784
1794
|
template are allowed to diverge, and this is only saying that they have. */
|
|
1785
1795
|
.set-hint.drifted { color: var(--warn); }
|
|
1786
1796
|
|
|
1787
|
-
/* One applet, alone on the page, at `/applet/<id>`. Fills the window: there is
|
|
1788
|
-
no grid here to decide a height, and a screenshot of an applet letterboxed
|
|
1789
|
-
inside a page is mostly not the applet. */
|
|
1790
|
-
.bare { height: 100vh; display: flex; flex-direction: column; background: var(--bg); }
|
|
1791
|
-
|
|
1792
|
-
.bare > * { flex: 1; min-height: 0; }
|
|
1793
|
-
|
|
1794
1797
|
/* A round is in flight. On the button that asks for one, because that is where
|
|
1795
1798
|
you are looking when you have just pressed it -- and not in the foot, which
|
|
1796
1799
|
would flicker every thirty seconds on a tile that is working perfectly. */
|
|
@@ -2138,7 +2141,15 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
2138
2141
|
|
|
2139
2142
|
.danger-act > .set-hint + .set-hint { margin-top: var(--space-1); }
|
|
2140
2143
|
|
|
2141
|
-
.
|
|
2144
|
+
/* `display: flex` is here now. These rows carried `.row` as well, which is a
|
|
2145
|
+
class no component of this package renders -- it only ever reached them
|
|
2146
|
+
because a consumer's stylesheet happened to define it too. */
|
|
2147
|
+
.danger-row {
|
|
2148
|
+
display: flex;
|
|
2149
|
+
margin-top: var(--space-2);
|
|
2150
|
+
gap: var(--space-2);
|
|
2151
|
+
align-items: center;
|
|
2152
|
+
}
|
|
2142
2153
|
|
|
2143
2154
|
.danger-row > input { min-width: 0; }
|
|
2144
2155
|
|
|
@@ -2160,15 +2171,15 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
2160
2171
|
column-gap: var(--space-3);
|
|
2161
2172
|
}
|
|
2162
2173
|
|
|
2163
|
-
.field-row { align-items: flex-end; gap: var(--space-2); }
|
|
2174
|
+
.danger-field-row { align-items: flex-end; gap: var(--space-2); }
|
|
2164
2175
|
|
|
2165
|
-
.field-row > button { flex: none; }
|
|
2176
|
+
.danger-field-row > button { flex: none; }
|
|
2166
2177
|
|
|
2167
2178
|
/* Two forms one under the other, whose buttons say different words -- "Add"
|
|
2168
2179
|
and "Block". Sized to their text they came out different widths, and two
|
|
2169
2180
|
controls in the same column at the same indent that do not line up read as
|
|
2170
2181
|
an accident rather than as a pair. */
|
|
2171
|
-
.field-row > button { min-width: 9ch; }
|
|
2182
|
+
.danger-field-row > button { min-width: 9ch; }
|
|
2172
2183
|
}
|
|
2173
2184
|
|
|
2174
2185
|
/* ---- ./callout.css ---- */
|
|
@@ -2499,9 +2510,12 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
2499
2510
|
/* Sized to its words, for a switch that sits in a row of other controls rather
|
|
2500
2511
|
than owning a row of its own. `flex: 1` there would push the label away from
|
|
2501
2512
|
the switch by the whole width of the bar. */
|
|
2502
|
-
|
|
2513
|
+
/* `inRow`: a toggle beside other controls rather than in a column of
|
|
2514
|
+
settings. Was `.row > .switch-row`, which reached through `.row` -- a class
|
|
2515
|
+
no component here renders. */
|
|
2516
|
+
.switch-in-row { flex: none; padding-block: 0; }
|
|
2503
2517
|
|
|
2504
|
-
.
|
|
2518
|
+
.switch-in-row .switch-body { flex: none; }
|
|
2505
2519
|
|
|
2506
2520
|
/* The opposite case: a switch that *is* the row, with something small beside it
|
|
2507
2521
|
-- a tooltip, a state word. `.set-row` wraps, so a switch that does not grow
|
|
@@ -4090,7 +4104,10 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
4090
4104
|
/* Fields stacked down a form. Wider than the gap inside one field, so the
|
|
4091
4105
|
label of the next belongs to the input under it rather than to the error
|
|
4092
4106
|
above it. */
|
|
4093
|
-
|
|
4107
|
+
/* `inRow`: a field sharing a line with other controls rather than stacked in a
|
|
4108
|
+
column. Was `.field-row > .field`, which reached through a container class
|
|
4109
|
+
the caller had to write and this package does not hand out. */
|
|
4110
|
+
.field-in-row { flex: 1; min-width: 0; }
|
|
4094
4111
|
|
|
4095
4112
|
/* A password with an eye -- `Input type="password"`.
|
|
4096
4113
|
A grid rather than `position: absolute`: both children take the one cell, the
|
|
@@ -4965,6 +4982,100 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4965
4982
|
.ident-remove:hover { background: var(--panel); color: var(--text); }
|
|
4966
4983
|
.ident-remove:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
|
4967
4984
|
}
|
|
4985
|
+
|
|
4986
|
+
/* Prose and the surface it is written on, added in 0.8.0. Last, because
|
|
4987
|
+
`.prose` styles the elements the reset in `base.css` flattened and has to
|
|
4988
|
+
win over it, and because the editor's box sits over nothing. */
|
|
4989
|
+
/* ---- ./richtext.css ---- */
|
|
4990
|
+
@layer components {
|
|
4991
|
+
/* Prose: one class, and the elements it styles are ones nobody wrote.
|
|
4992
|
+
*
|
|
4993
|
+
* That is the whole reason a class exists here rather than utilities. Inside
|
|
4994
|
+
* the editor the paragraphs, headings and lists are ProseMirror's, built
|
|
4995
|
+
* from the document — there is no JSX to hang a utility on, so the choice is
|
|
4996
|
+
* descendant rules behind one class or an arbitrary variant per element,
|
|
4997
|
+
* which is the same selector spelled worse. `Markdown` has the same problem
|
|
4998
|
+
* for the same reason and answers it the same way, as `.md` in `base.css`.
|
|
4999
|
+
*
|
|
5000
|
+
* The editor and the view share the class on purpose. They have to look
|
|
5001
|
+
* identical and one set of rules is what guarantees it; two sets maintained
|
|
5002
|
+
* separately is precisely how a what-you-see-is-what-you-get editor stops
|
|
5003
|
+
* being one. Everything the components *do* render — the box, the toolbar,
|
|
5004
|
+
* the writing surface's own padding and focus ring — is utilities in the
|
|
5005
|
+
* component, where it belongs.
|
|
5006
|
+
*
|
|
5007
|
+
* `.rich-text` and not `.prose`: this package's classes ship unprefixed into
|
|
5008
|
+
* other people's stylesheets, and `.prose` is the one name in CSS most
|
|
5009
|
+
* likely to already be taken — Tailwind's typography plugin defines exactly
|
|
5010
|
+
* it. A consumer with that plugin and this package would have had two sets
|
|
5011
|
+
* of margins fighting, and it would have read as a theming bug.
|
|
5012
|
+
*
|
|
5013
|
+
* Every value here is a token. The vertical rhythm is `--space-*`, four
|
|
5014
|
+
* pixels a step and scaling with `--density`; the type steps are `--text-*`,
|
|
5015
|
+
* scaling with `--font-size`. A heading two sizes apart from its body at one
|
|
5016
|
+
* density is two sizes apart at every density.
|
|
5017
|
+
*/
|
|
5018
|
+
|
|
5019
|
+
.rich-text > * {
|
|
5020
|
+
margin: 0;
|
|
5021
|
+
}
|
|
5022
|
+
|
|
5023
|
+
.rich-text > * + * {
|
|
5024
|
+
margin-top: var(--space-3);
|
|
5025
|
+
}
|
|
5026
|
+
|
|
5027
|
+
.rich-text h2 {
|
|
5028
|
+
font-size: var(--text-lg);
|
|
5029
|
+
font-weight: var(--weight-strong);
|
|
5030
|
+
letter-spacing: -0.01em;
|
|
5031
|
+
}
|
|
5032
|
+
|
|
5033
|
+
.rich-text h3 {
|
|
5034
|
+
font-size: var(--text-md);
|
|
5035
|
+
font-weight: var(--weight-strong);
|
|
5036
|
+
}
|
|
5037
|
+
|
|
5038
|
+
/* A heading after prose needs more room above it than below: the space
|
|
5039
|
+
belongs to the section it opens, not to the paragraph it follows. */
|
|
5040
|
+
.rich-text > * + :is(h2, h3) {
|
|
5041
|
+
margin-top: var(--space-6);
|
|
5042
|
+
}
|
|
5043
|
+
|
|
5044
|
+
.rich-text :is(ul, ol) {
|
|
5045
|
+
padding-left: var(--space-5);
|
|
5046
|
+
}
|
|
5047
|
+
|
|
5048
|
+
.rich-text li + li {
|
|
5049
|
+
margin-top: var(--space-1);
|
|
5050
|
+
}
|
|
5051
|
+
|
|
5052
|
+
.rich-text a {
|
|
5053
|
+
color: var(--accent);
|
|
5054
|
+
text-decoration: underline;
|
|
5055
|
+
text-underline-offset: 2px;
|
|
5056
|
+
}
|
|
5057
|
+
|
|
5058
|
+
.rich-text strong {
|
|
5059
|
+
font-weight: var(--weight-strong);
|
|
5060
|
+
}
|
|
5061
|
+
|
|
5062
|
+
/* An empty editor says what goes in it. The placeholder extension puts the
|
|
5063
|
+
words on the empty node as `data-placeholder` and marks it, so `attr()` is
|
|
5064
|
+
reading an attribute of the element it is drawn on — which is the part a
|
|
5065
|
+
hand-rolled rule got wrong twice: a rule on the paragraph cannot reach an
|
|
5066
|
+
attribute on the box, and ProseMirror's empty paragraph holds a trailing
|
|
5067
|
+
`<br>` so `:empty` never matches it either. `pointer-events: none` so a
|
|
5068
|
+
click on the words still lands in the text.
|
|
5069
|
+
|
|
5070
|
+
Harmless on the view, which never produces the class. */
|
|
5071
|
+
.rich-text p.is-editor-empty:first-child::before {
|
|
5072
|
+
content: attr(data-placeholder);
|
|
5073
|
+
float: left;
|
|
5074
|
+
height: 0;
|
|
5075
|
+
color: var(--muted);
|
|
5076
|
+
pointer-events: none;
|
|
5077
|
+
}
|
|
5078
|
+
}
|
|
4968
5079
|
/* ---- valet: the themes ---- */
|
|
4969
5080
|
:root[data-theme='valet']{--bg:#f4f5f8;--panel:#ffffff;--panel-2:#eceef3;--border:#dcdfe7;--border-strong:#7b8597;--text:#171a21;--muted:#5b6474;--accent:#4f46e5;--accent-dim:#a9a4f0;--on-accent:#ffffff;--good:#1b7f4b;--warn:#8a5f0a;--bad:#bf3a31;--info:#0e6f8e;--app-bg:#f4f5f8;--shadow-1:0 4px 14px rgba(23, 26, 33, 0.08);--shadow-2:0 8px 24px rgba(23, 26, 33, 0.10);--shadow-3:0 12px 32px rgba(23, 26, 33, 0.12);--scrim:rgba(23, 26, 33, 0.32);color-scheme:light}
|
|
4970
5081
|
:root[data-theme='valet-night']{--bg:#0c0f14;--panel:#141820;--panel-2:#1b2029;--border:#262c37;--border-strong:#616b7d;--text:#e8eaf0;--muted:#9ba4b5;--accent:#8f88ff;--accent-dim:#3f3a8f;--on-accent:#0d0b2e;--good:#5fcb8f;--warn:#e2ae58;--bad:#f28b84;--info:#57c4e8;--app-bg:#0c0f14;--shadow-1:0 6px 20px rgba(0, 0, 0, 0.28);--shadow-2:0 8px 28px rgba(0, 0, 0, 0.34);--shadow-3:0 10px 34px rgba(0, 0, 0, 0.38);--scrim:rgba(0, 0, 0, 0.5);color-scheme:dark}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtfalch/design",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "wtfalch's design system: themeable components on a fixed token vocabulary.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design-system",
|
|
@@ -48,7 +48,15 @@
|
|
|
48
48
|
"default": "./dist/themes/index.js"
|
|
49
49
|
},
|
|
50
50
|
"./tokens.css": "./dist/tokens.css",
|
|
51
|
-
"./styles.css": "./dist/styles/index.css"
|
|
51
|
+
"./styles.css": "./dist/styles/index.css",
|
|
52
|
+
"./editor": {
|
|
53
|
+
"types": "./dist/editor.d.ts",
|
|
54
|
+
"default": "./dist/editor.js"
|
|
55
|
+
},
|
|
56
|
+
"./rich-text": {
|
|
57
|
+
"types": "./dist/rich-text.d.ts",
|
|
58
|
+
"default": "./dist/rich-text.js"
|
|
59
|
+
}
|
|
52
60
|
},
|
|
53
61
|
"sideEffects": ["*.css"],
|
|
54
62
|
"engines": {
|
|
@@ -61,8 +69,14 @@
|
|
|
61
69
|
"test": "vitest run"
|
|
62
70
|
},
|
|
63
71
|
"peerDependencies": {
|
|
72
|
+
"@tiptap/extension-link": "^3.31.0",
|
|
73
|
+
"@tiptap/extensions": "^3.31.0",
|
|
74
|
+
"@tiptap/pm": "^3.31.0",
|
|
75
|
+
"@tiptap/react": "^3.31.0",
|
|
76
|
+
"@tiptap/starter-kit": "^3.31.0",
|
|
64
77
|
"react": "^19.0.0",
|
|
65
|
-
"react-dom": "^19.0.0"
|
|
78
|
+
"react-dom": "^19.0.0",
|
|
79
|
+
"zod": "^4.0.0"
|
|
66
80
|
},
|
|
67
81
|
"dependencies": {
|
|
68
82
|
"@radix-ui/react-slot": "^1.3.3",
|
|
@@ -72,6 +86,11 @@
|
|
|
72
86
|
},
|
|
73
87
|
"devDependencies": {
|
|
74
88
|
"@tailwindcss/cli": "^4.3.3",
|
|
89
|
+
"@tiptap/extension-link": "^3.31.3",
|
|
90
|
+
"@tiptap/extensions": "^3.31.3",
|
|
91
|
+
"@tiptap/pm": "^3.31.3",
|
|
92
|
+
"@tiptap/react": "^3.31.3",
|
|
93
|
+
"@tiptap/starter-kit": "^3.31.3",
|
|
75
94
|
"@types/node": "^22",
|
|
76
95
|
"@types/react": "^19",
|
|
77
96
|
"@types/react-dom": "^19",
|
|
@@ -79,6 +98,27 @@
|
|
|
79
98
|
"react-dom": "^19",
|
|
80
99
|
"tailwindcss": "^4.3.3",
|
|
81
100
|
"typescript": "^5.9.0",
|
|
82
|
-
"vitest": "^4.1.6"
|
|
101
|
+
"vitest": "^4.1.6",
|
|
102
|
+
"zod": "^4.0.0"
|
|
103
|
+
},
|
|
104
|
+
"peerDependenciesMeta": {
|
|
105
|
+
"@tiptap/extension-link": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"@tiptap/extensions": {
|
|
109
|
+
"optional": true
|
|
110
|
+
},
|
|
111
|
+
"@tiptap/pm": {
|
|
112
|
+
"optional": true
|
|
113
|
+
},
|
|
114
|
+
"@tiptap/react": {
|
|
115
|
+
"optional": true
|
|
116
|
+
},
|
|
117
|
+
"@tiptap/starter-kit": {
|
|
118
|
+
"optional": true
|
|
119
|
+
},
|
|
120
|
+
"zod": {
|
|
121
|
+
"optional": true
|
|
122
|
+
}
|
|
83
123
|
}
|
|
84
124
|
}
|