@wtfalch/design 0.11.0 → 0.13.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/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
  }
@@ -2814,8 +2831,10 @@ input[type='radio']:active:not(:disabled) {
2814
2831
  }
2815
2832
 
2816
2833
  /* Only where there is something to pick. A row without `row-hit` is not a
2817
- choice, and lighting it up on hover promises something that does not happen. */
2818
- .rows-pick > .rows-row:has(.row-hit):hover {
2834
+ choice, and lighting it up on hover promises something that does not happen.
2835
+ Nor is a row whose hit is disabled: a waiting row lit up under its own
2836
+ `not-allowed` cursor, and `disabled` would have made that permanent. */
2837
+ .rows-pick > .rows-row:has(.row-hit:enabled):hover {
2819
2838
  border-color: var(--accent);
2820
2839
  background: var(--panel-2);
2821
2840
  }
@@ -2867,9 +2886,16 @@ input[type='radio']:active:not(:disabled) {
2867
2886
  /* And nothing else can be chosen while it happens: picking a second model
2868
2887
  mid-load queues a second load, which is how a machine ends up swapping two
2869
2888
  sets of weights it cannot hold at once. */
2870
- .rows-pick > .rows-row.is-waiting { opacity: 0.5; }
2889
+ .rows-pick > .rows-row.is-waiting,
2890
+ .rows-pick > .rows-row.is-disabled { opacity: 0.5; }
2871
2891
 
2872
- .rows-pick > .rows-row.is-waiting .row-hit { cursor: not-allowed; }
2892
+ .rows-pick > .rows-row.is-waiting .row-hit,
2893
+ .rows-pick > .rows-row.is-disabled .row-hit { cursor: not-allowed; }
2894
+
2895
+ /* Dimmed once. `.row-hit:disabled` dims the button as well, and under the
2896
+ row's own opacity the hint of a disabled row, the line saying why it cannot
2897
+ be chosen, came out at a quarter strength. */
2898
+ .rows-pick > .rows-row.is-disabled > .row-hit:disabled { opacity: 1; }
2873
2899
 
2874
2900
  @media (prefers-reduced-motion: reduce) {
2875
2901
  /* The border still says which one, without the breathing. */
@@ -2921,7 +2947,7 @@ input[type='radio']:active:not(:disabled) {
2921
2947
  margin-bottom: calc(var(--space-2) * -1);
2922
2948
  }
2923
2949
 
2924
- .rows-pick > .rows-row.is-picked:has(.row-hit):hover {
2950
+ .rows-pick > .rows-row.is-picked:has(.row-hit:enabled):hover {
2925
2951
  background: color-mix(in srgb, var(--accent) 13%, var(--panel));
2926
2952
  }
2927
2953
 
@@ -2980,7 +3006,7 @@ input[type='radio']:active:not(:disabled) {
2980
3006
  border-radius: var(--radius-sm);
2981
3007
  }
2982
3008
 
2983
- .row-hit:hover .truncate { color: var(--accent); }
3009
+ .row-hit:enabled:hover .truncate { color: var(--accent); }
2984
3010
 
2985
3011
  .row-hit:focus-visible { outline: none; box-shadow: var(--focus-ring); }
2986
3012
  }
@@ -4965,6 +4991,100 @@ body.splitting * { cursor: inherit !important; }
4965
4991
  .ident-remove:hover { background: var(--panel); color: var(--text); }
4966
4992
  .ident-remove:focus-visible { outline: none; box-shadow: var(--focus-ring); }
4967
4993
  }
4994
+
4995
+ /* Prose and the surface it is written on, added in 0.8.0. Last, because
4996
+ `.prose` styles the elements the reset in `base.css` flattened and has to
4997
+ win over it, and because the editor's box sits over nothing. */
4998
+ /* ---- ./richtext.css ---- */
4999
+ @layer components {
5000
+ /* Prose: one class, and the elements it styles are ones nobody wrote.
5001
+ *
5002
+ * That is the whole reason a class exists here rather than utilities. Inside
5003
+ * the editor the paragraphs, headings and lists are ProseMirror's, built
5004
+ * from the document — there is no JSX to hang a utility on, so the choice is
5005
+ * descendant rules behind one class or an arbitrary variant per element,
5006
+ * which is the same selector spelled worse. `Markdown` has the same problem
5007
+ * for the same reason and answers it the same way, as `.md` in `base.css`.
5008
+ *
5009
+ * The editor and the view share the class on purpose. They have to look
5010
+ * identical and one set of rules is what guarantees it; two sets maintained
5011
+ * separately is precisely how a what-you-see-is-what-you-get editor stops
5012
+ * being one. Everything the components *do* render — the box, the toolbar,
5013
+ * the writing surface's own padding and focus ring — is utilities in the
5014
+ * component, where it belongs.
5015
+ *
5016
+ * `.rich-text` and not `.prose`: this package's classes ship unprefixed into
5017
+ * other people's stylesheets, and `.prose` is the one name in CSS most
5018
+ * likely to already be taken — Tailwind's typography plugin defines exactly
5019
+ * it. A consumer with that plugin and this package would have had two sets
5020
+ * of margins fighting, and it would have read as a theming bug.
5021
+ *
5022
+ * Every value here is a token. The vertical rhythm is `--space-*`, four
5023
+ * pixels a step and scaling with `--density`; the type steps are `--text-*`,
5024
+ * scaling with `--font-size`. A heading two sizes apart from its body at one
5025
+ * density is two sizes apart at every density.
5026
+ */
5027
+
5028
+ .rich-text > * {
5029
+ margin: 0;
5030
+ }
5031
+
5032
+ .rich-text > * + * {
5033
+ margin-top: var(--space-3);
5034
+ }
5035
+
5036
+ .rich-text h2 {
5037
+ font-size: var(--text-lg);
5038
+ font-weight: var(--weight-strong);
5039
+ letter-spacing: -0.01em;
5040
+ }
5041
+
5042
+ .rich-text h3 {
5043
+ font-size: var(--text-md);
5044
+ font-weight: var(--weight-strong);
5045
+ }
5046
+
5047
+ /* A heading after prose needs more room above it than below: the space
5048
+ belongs to the section it opens, not to the paragraph it follows. */
5049
+ .rich-text > * + :is(h2, h3) {
5050
+ margin-top: var(--space-6);
5051
+ }
5052
+
5053
+ .rich-text :is(ul, ol) {
5054
+ padding-left: var(--space-5);
5055
+ }
5056
+
5057
+ .rich-text li + li {
5058
+ margin-top: var(--space-1);
5059
+ }
5060
+
5061
+ .rich-text a {
5062
+ color: var(--accent);
5063
+ text-decoration: underline;
5064
+ text-underline-offset: 2px;
5065
+ }
5066
+
5067
+ .rich-text strong {
5068
+ font-weight: var(--weight-strong);
5069
+ }
5070
+
5071
+ /* An empty editor says what goes in it. The placeholder extension puts the
5072
+ words on the empty node as `data-placeholder` and marks it, so `attr()` is
5073
+ reading an attribute of the element it is drawn on — which is the part a
5074
+ hand-rolled rule got wrong twice: a rule on the paragraph cannot reach an
5075
+ attribute on the box, and ProseMirror's empty paragraph holds a trailing
5076
+ `<br>` so `:empty` never matches it either. `pointer-events: none` so a
5077
+ click on the words still lands in the text.
5078
+
5079
+ Harmless on the view, which never produces the class. */
5080
+ .rich-text p.is-editor-empty:first-child::before {
5081
+ content: attr(data-placeholder);
5082
+ float: left;
5083
+ height: 0;
5084
+ color: var(--muted);
5085
+ pointer-events: none;
5086
+ }
5087
+ }
4968
5088
  /* ---- valet: the themes ---- */
4969
5089
  :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
5090
  :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.11.0",
3
+ "version": "0.13.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
  }