@womp/kookie-ui 0.3.26 → 0.5.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 (204) hide show
  1. package/AUTHORS +27 -0
  2. package/LICENSE +29 -0
  3. package/README.md +21 -1
  4. package/components.css +472 -270
  5. package/dist/cjs/components/_internal/shell-bottom.js +1 -1
  6. package/dist/cjs/components/_internal/shell-bottom.js.map +3 -3
  7. package/dist/cjs/components/_internal/shell-inspector.js +1 -1
  8. package/dist/cjs/components/_internal/shell-inspector.js.map +3 -3
  9. package/dist/cjs/components/_internal/shell-sidebar.js +1 -1
  10. package/dist/cjs/components/_internal/shell-sidebar.js.map +3 -3
  11. package/dist/cjs/components/alert-dialog.js +1 -1
  12. package/dist/cjs/components/alert-dialog.js.map +3 -3
  13. package/dist/cjs/components/badge.js +1 -1
  14. package/dist/cjs/components/badge.js.map +3 -3
  15. package/dist/cjs/components/button.js +1 -1
  16. package/dist/cjs/components/button.js.map +3 -3
  17. package/dist/cjs/components/chatbar.js +2 -2
  18. package/dist/cjs/components/chatbar.js.map +3 -3
  19. package/dist/cjs/components/checkbox-cards.js +1 -1
  20. package/dist/cjs/components/checkbox-cards.js.map +3 -3
  21. package/dist/cjs/components/combobox.js +1 -1
  22. package/dist/cjs/components/combobox.js.map +3 -3
  23. package/dist/cjs/components/context-menu.js +1 -1
  24. package/dist/cjs/components/context-menu.js.map +3 -3
  25. package/dist/cjs/components/dialog.js +1 -1
  26. package/dist/cjs/components/dialog.js.map +3 -3
  27. package/dist/cjs/components/dropdown-menu.js +1 -1
  28. package/dist/cjs/components/dropdown-menu.js.map +3 -3
  29. package/dist/cjs/components/hover-card.js +1 -1
  30. package/dist/cjs/components/hover-card.js.map +3 -3
  31. package/dist/cjs/components/icon-button.js +2 -2
  32. package/dist/cjs/components/icon-button.js.map +3 -3
  33. package/dist/cjs/components/index.js +5 -5
  34. package/dist/cjs/components/index.js.map +3 -3
  35. package/dist/cjs/components/popover.js +1 -1
  36. package/dist/cjs/components/popover.js.map +3 -3
  37. package/dist/cjs/components/radio-cards.js +1 -1
  38. package/dist/cjs/components/radio-cards.js.map +3 -3
  39. package/dist/cjs/components/select.js +1 -1
  40. package/dist/cjs/components/select.js.map +3 -3
  41. package/dist/cjs/components/sheet.js +1 -1
  42. package/dist/cjs/components/sheet.js.map +3 -3
  43. package/dist/cjs/components/shell.js +1 -1
  44. package/dist/cjs/components/shell.js.map +3 -3
  45. package/dist/cjs/components/sidebar.js +1 -1
  46. package/dist/cjs/components/sidebar.js.map +3 -3
  47. package/dist/cjs/components/theme-panel.js +3 -3
  48. package/dist/cjs/components/theme-panel.js.map +3 -3
  49. package/dist/cjs/components/theme.d.ts +3 -0
  50. package/dist/cjs/components/theme.d.ts.map +1 -1
  51. package/dist/cjs/components/theme.js +1 -1
  52. package/dist/cjs/components/theme.js.map +3 -3
  53. package/dist/cjs/components/theme.props.d.ts +15 -1
  54. package/dist/cjs/components/theme.props.d.ts.map +1 -1
  55. package/dist/cjs/components/theme.props.js +1 -1
  56. package/dist/cjs/components/theme.props.js.map +2 -2
  57. package/dist/cjs/components/toggle-button.js +2 -2
  58. package/dist/cjs/components/toggle-button.js.map +3 -3
  59. package/dist/cjs/components/toggle-icon-button.js +3 -3
  60. package/dist/cjs/components/toggle-icon-button.js.map +3 -3
  61. package/dist/cjs/components/tooltip.js +1 -1
  62. package/dist/cjs/components/tooltip.js.map +3 -3
  63. package/dist/cjs/components/user-card.js +1 -1
  64. package/dist/cjs/components/user-card.js.map +3 -3
  65. package/dist/cjs/helpers/font-config.d.ts +84 -77
  66. package/dist/cjs/helpers/font-config.d.ts.map +1 -1
  67. package/dist/cjs/helpers/font-config.js +5 -2
  68. package/dist/cjs/helpers/font-config.js.map +3 -3
  69. package/dist/cjs/helpers/index.js +5 -2
  70. package/dist/cjs/helpers/index.js.map +3 -3
  71. package/dist/cjs/index.js +5 -5
  72. package/dist/cjs/index.js.map +3 -3
  73. package/dist/cjs/props/index.js +1 -1
  74. package/dist/cjs/props/index.js.map +2 -2
  75. package/dist/esm/{chunk-4CKDU6FY.js → chunk-2FYJTSOP.js} +2 -2
  76. package/dist/esm/{chunk-ICIGZ3N7.js → chunk-374ZYJUP.js} +2 -2
  77. package/dist/esm/{chunk-F2HYQ3ZR.js → chunk-6IGTK4JE.js} +2 -2
  78. package/dist/esm/chunk-6XGZPIUT.js +2 -0
  79. package/dist/esm/{chunk-T27QHMW7.js.map → chunk-6XGZPIUT.js.map} +2 -2
  80. package/dist/esm/{chunk-FLFAXVFB.js → chunk-A2RZGGMY.js} +2 -2
  81. package/dist/esm/{chunk-KKM6T5P7.js → chunk-AU3D6F42.js} +2 -2
  82. package/dist/esm/{chunk-O3CDWEZA.js → chunk-CVWCKOHO.js} +2 -2
  83. package/dist/esm/{chunk-JQQIPEGY.js → chunk-CWRNW44F.js} +2 -2
  84. package/dist/esm/{chunk-UVCH7QKO.js → chunk-DNHUQLXO.js} +2 -2
  85. package/dist/esm/{chunk-FOEZLQTW.js → chunk-FXUUI6Z2.js} +2 -2
  86. package/dist/esm/{chunk-WO43WW3A.js → chunk-IKSN4RNB.js} +2 -2
  87. package/dist/esm/{chunk-4IY2PR6N.js → chunk-K6QZMNCD.js} +2 -2
  88. package/dist/esm/{chunk-DL2O3GKG.js → chunk-KKBP2CRH.js} +2 -2
  89. package/dist/esm/{chunk-VLO7NXSP.js → chunk-M24UXMOQ.js} +2 -2
  90. package/dist/esm/{chunk-MRECKC4D.js → chunk-MK2R6DAU.js} +2 -2
  91. package/dist/esm/{chunk-5IBGFL6O.js → chunk-MOR3NSXQ.js} +2 -2
  92. package/dist/esm/{chunk-PQZXQ4ST.js → chunk-OSRJRBKP.js} +2 -2
  93. package/dist/esm/{chunk-WTYNFBFV.js → chunk-PLWXTEVE.js} +2 -2
  94. package/dist/esm/{chunk-U2X2CAW4.js → chunk-QEOAXJLN.js} +2 -2
  95. package/dist/esm/{chunk-36ZQVP7F.js → chunk-RMKXWYOV.js} +2 -2
  96. package/dist/esm/{chunk-BJYUPIXO.js → chunk-S56YSRHP.js} +2 -2
  97. package/dist/esm/{chunk-22HGLMPQ.js → chunk-TOLLPRMM.js} +2 -2
  98. package/dist/esm/{chunk-ETMLMDW4.js → chunk-UGD7Z3L4.js} +2 -2
  99. package/dist/esm/chunk-VA5A4MHU.js +6 -0
  100. package/dist/esm/chunk-VA5A4MHU.js.map +7 -0
  101. package/dist/esm/{chunk-4BBOHEF4.js → chunk-W7N7V5YD.js} +2 -2
  102. package/dist/esm/{chunk-D5N627TH.js → chunk-WFMYNZXZ.js} +2 -2
  103. package/dist/esm/{chunk-JR2YOGII.js → chunk-YEB3H7QN.js} +2 -2
  104. package/dist/esm/chunk-YUP6EICB.js +2 -0
  105. package/dist/esm/chunk-YUP6EICB.js.map +7 -0
  106. package/dist/esm/components/_internal/shell-bottom.js +1 -1
  107. package/dist/esm/components/_internal/shell-inspector.js +1 -1
  108. package/dist/esm/components/_internal/shell-sidebar.js +1 -1
  109. package/dist/esm/components/alert-dialog.js +1 -1
  110. package/dist/esm/components/badge.js +1 -1
  111. package/dist/esm/components/button.js +1 -1
  112. package/dist/esm/components/chatbar.js +1 -1
  113. package/dist/esm/components/checkbox-cards.js +1 -1
  114. package/dist/esm/components/combobox.js +1 -1
  115. package/dist/esm/components/context-menu.js +1 -1
  116. package/dist/esm/components/dialog.js +1 -1
  117. package/dist/esm/components/dropdown-menu.js +1 -1
  118. package/dist/esm/components/hover-card.js +1 -1
  119. package/dist/esm/components/icon-button.js +1 -1
  120. package/dist/esm/components/index.js +1 -1
  121. package/dist/esm/components/popover.js +1 -1
  122. package/dist/esm/components/radio-cards.js +1 -1
  123. package/dist/esm/components/select.js +1 -1
  124. package/dist/esm/components/sheet.js +1 -1
  125. package/dist/esm/components/shell.js +1 -1
  126. package/dist/esm/components/sidebar.js +1 -1
  127. package/dist/esm/components/theme-panel.js +1 -1
  128. package/dist/esm/components/theme.d.ts +3 -0
  129. package/dist/esm/components/theme.d.ts.map +1 -1
  130. package/dist/esm/components/theme.js +1 -1
  131. package/dist/esm/components/theme.props.d.ts +15 -1
  132. package/dist/esm/components/theme.props.d.ts.map +1 -1
  133. package/dist/esm/components/theme.props.js +1 -1
  134. package/dist/esm/components/toggle-button.js +1 -1
  135. package/dist/esm/components/toggle-icon-button.js +1 -1
  136. package/dist/esm/components/tooltip.js +1 -1
  137. package/dist/esm/components/user-card.js +1 -1
  138. package/dist/esm/helpers/font-config.d.ts +84 -77
  139. package/dist/esm/helpers/font-config.d.ts.map +1 -1
  140. package/dist/esm/helpers/font-config.js +1 -1
  141. package/dist/esm/helpers/index.js +1 -1
  142. package/dist/esm/index.js +1 -1
  143. package/dist/esm/props/index.js +1 -1
  144. package/fonts.css +8 -0
  145. package/package.json +17 -7
  146. package/src/components/_internal/base-card.css +5 -5
  147. package/src/components/_internal/base-checkbox.css +17 -3
  148. package/src/components/_internal/base-dialog.css +4 -4
  149. package/src/components/_internal/base-menu.css +3 -3
  150. package/src/components/accordion.css +5 -5
  151. package/src/components/callout.css +5 -5
  152. package/src/components/chatbar.css +6 -6
  153. package/src/components/checkbox-cards.css +30 -0
  154. package/src/components/heading.css +10 -3
  155. package/src/components/hover-card.css +3 -3
  156. package/src/components/popover.css +4 -4
  157. package/src/components/radio-cards.css +30 -0
  158. package/src/components/select.css +2 -2
  159. package/src/components/shell.css +1 -1
  160. package/src/components/table.css +5 -5
  161. package/src/components/text.css +10 -3
  162. package/src/components/theme.props.tsx +13 -1
  163. package/src/components/theme.tsx +18 -0
  164. package/src/components/tooltip.css +1 -1
  165. package/src/helpers/font-config.ts +130 -148
  166. package/src/styles/fonts.css +24 -29
  167. package/src/styles/index.css +0 -1
  168. package/src/styles/tokens/base.css +1 -0
  169. package/src/styles/tokens/font-family.css +263 -0
  170. package/src/styles/tokens/radius.css +47 -4
  171. package/src/styles/tokens/typography.css +2 -216
  172. package/styles.css +9094 -8884
  173. package/tokens/base.css +55 -28
  174. package/tokens.css +55 -28
  175. package/dist/esm/chunk-LOGJJF4I.js +0 -2
  176. package/dist/esm/chunk-LOGJJF4I.js.map +0 -7
  177. package/dist/esm/chunk-Q7P6BTVU.js +0 -3
  178. package/dist/esm/chunk-Q7P6BTVU.js.map +0 -7
  179. package/dist/esm/chunk-T27QHMW7.js +0 -2
  180. /package/dist/esm/{chunk-4CKDU6FY.js.map → chunk-2FYJTSOP.js.map} +0 -0
  181. /package/dist/esm/{chunk-ICIGZ3N7.js.map → chunk-374ZYJUP.js.map} +0 -0
  182. /package/dist/esm/{chunk-F2HYQ3ZR.js.map → chunk-6IGTK4JE.js.map} +0 -0
  183. /package/dist/esm/{chunk-FLFAXVFB.js.map → chunk-A2RZGGMY.js.map} +0 -0
  184. /package/dist/esm/{chunk-KKM6T5P7.js.map → chunk-AU3D6F42.js.map} +0 -0
  185. /package/dist/esm/{chunk-O3CDWEZA.js.map → chunk-CVWCKOHO.js.map} +0 -0
  186. /package/dist/esm/{chunk-JQQIPEGY.js.map → chunk-CWRNW44F.js.map} +0 -0
  187. /package/dist/esm/{chunk-UVCH7QKO.js.map → chunk-DNHUQLXO.js.map} +0 -0
  188. /package/dist/esm/{chunk-FOEZLQTW.js.map → chunk-FXUUI6Z2.js.map} +0 -0
  189. /package/dist/esm/{chunk-WO43WW3A.js.map → chunk-IKSN4RNB.js.map} +0 -0
  190. /package/dist/esm/{chunk-4IY2PR6N.js.map → chunk-K6QZMNCD.js.map} +0 -0
  191. /package/dist/esm/{chunk-DL2O3GKG.js.map → chunk-KKBP2CRH.js.map} +0 -0
  192. /package/dist/esm/{chunk-VLO7NXSP.js.map → chunk-M24UXMOQ.js.map} +0 -0
  193. /package/dist/esm/{chunk-MRECKC4D.js.map → chunk-MK2R6DAU.js.map} +0 -0
  194. /package/dist/esm/{chunk-5IBGFL6O.js.map → chunk-MOR3NSXQ.js.map} +0 -0
  195. /package/dist/esm/{chunk-PQZXQ4ST.js.map → chunk-OSRJRBKP.js.map} +0 -0
  196. /package/dist/esm/{chunk-WTYNFBFV.js.map → chunk-PLWXTEVE.js.map} +0 -0
  197. /package/dist/esm/{chunk-U2X2CAW4.js.map → chunk-QEOAXJLN.js.map} +0 -0
  198. /package/dist/esm/{chunk-36ZQVP7F.js.map → chunk-RMKXWYOV.js.map} +0 -0
  199. /package/dist/esm/{chunk-BJYUPIXO.js.map → chunk-S56YSRHP.js.map} +0 -0
  200. /package/dist/esm/{chunk-22HGLMPQ.js.map → chunk-TOLLPRMM.js.map} +0 -0
  201. /package/dist/esm/{chunk-ETMLMDW4.js.map → chunk-UGD7Z3L4.js.map} +0 -0
  202. /package/dist/esm/{chunk-4BBOHEF4.js.map → chunk-W7N7V5YD.js.map} +0 -0
  203. /package/dist/esm/{chunk-D5N627TH.js.map → chunk-WFMYNZXZ.js.map} +0 -0
  204. /package/dist/esm/{chunk-JR2YOGII.js.map → chunk-YEB3H7QN.js.map} +0 -0
@@ -73,11 +73,22 @@ const themePropDefs = {
73
73
  */
74
74
  scaling: { type: 'enum', values: scalings, default: '100%' },
75
75
  /**
76
- * Sets the font family for the theme.
76
+ * Sets the font family used for body text in the theme.
77
+ *
78
+ * Headings follow this unless `headingFontFamily` (or the `--font-heading`
79
+ * token) says otherwise.
77
80
  *
78
81
  * @default 'sans'
79
82
  */
80
83
  fontFamily: { type: 'enum', values: fontFamilies, default: 'sans' },
84
+ /**
85
+ * Sets the font family used for `Heading`, independently of body text.
86
+ *
87
+ * Deliberately has no default: when it is left unset no attribute is
88
+ * emitted and `--font-heading` keeps following `--font-body`, so a
89
+ * `--font-heading` override in your own CSS survives a `fontFamily` switch.
90
+ */
91
+ headingFontFamily: { type: 'enum', values: fontFamilies },
81
92
  } satisfies {
82
93
  hasBackground: PropDef<boolean>;
83
94
  appearance: PropDef<(typeof appearances)[number]>;
@@ -88,6 +99,7 @@ const themePropDefs = {
88
99
  radius: PropDef<(typeof radii)[number]>;
89
100
  scaling: PropDef<(typeof scalings)[number]>;
90
101
  fontFamily: PropDef<(typeof fontFamilies)[number]>;
102
+ headingFontFamily: PropDef<(typeof fontFamilies)[number]>;
91
103
  };
92
104
 
93
105
  type ThemeOwnProps = GetPropDefTypes<typeof themePropDefs & typeof asChildPropDef>;
@@ -23,6 +23,9 @@ type ThemePanelBackground = (typeof themePropDefs.panelBackground.values)[number
23
23
  type ThemeRadius = (typeof themePropDefs.radius.values)[number];
24
24
  type ThemeScaling = (typeof themePropDefs.scaling.values)[number];
25
25
  type ThemeFontFamily = (typeof themePropDefs.fontFamily.values)[number];
26
+ // Headings follow the body font until something sets this, so `undefined` is a
27
+ // meaningful value here rather than a missing one.
28
+ type ThemeHeadingFontFamily = ThemeFontFamily | undefined;
26
29
 
27
30
  interface ThemeChangeHandlers {
28
31
  onAppearanceChange: (appearance: ThemeAppearance) => void;
@@ -33,6 +36,7 @@ interface ThemeChangeHandlers {
33
36
  onRadiusChange: (radius: ThemeRadius) => void;
34
37
  onScalingChange: (scaling: ThemeScaling) => void;
35
38
  onFontFamilyChange: (fontFamily: ThemeFontFamily) => void;
39
+ onHeadingFontFamilyChange: (headingFontFamily: ThemeHeadingFontFamily) => void;
36
40
  }
37
41
 
38
42
  interface ThemeContextValue extends ThemeChangeHandlers {
@@ -45,6 +49,7 @@ interface ThemeContextValue extends ThemeChangeHandlers {
45
49
  radius: ThemeRadius;
46
50
  scaling: ThemeScaling;
47
51
  fontFamily: ThemeFontFamily;
52
+ headingFontFamily: ThemeHeadingFontFamily;
48
53
  }
49
54
  // Default theme values used when components render outside a Theme provider
50
55
  const defaultThemeContext: ThemeContextValue = {
@@ -57,6 +62,7 @@ const defaultThemeContext: ThemeContextValue = {
57
62
  radius: themePropDefs.radius.default,
58
63
  scaling: themePropDefs.scaling.default,
59
64
  fontFamily: themePropDefs.fontFamily.default,
65
+ headingFontFamily: undefined,
60
66
  onAppearanceChange: noop,
61
67
  onAccentColorChange: noop,
62
68
  onGrayColorChange: noop,
@@ -65,6 +71,7 @@ const defaultThemeContext: ThemeContextValue = {
65
71
  onRadiusChange: noop,
66
72
  onScalingChange: noop,
67
73
  onFontFamilyChange: noop,
74
+ onHeadingFontFamilyChange: noop,
68
75
  };
69
76
 
70
77
  const ThemeContext = React.createContext<ThemeContextValue | undefined>(undefined);
@@ -103,6 +110,7 @@ const ThemeRoot = React.forwardRef<ThemeImplElement, ThemeImplPublicProps>(
103
110
  radius: radiusProp = themePropDefs.radius.default,
104
111
  scaling: scalingProp = themePropDefs.scaling.default,
105
112
  fontFamily: fontFamilyProp = themePropDefs.fontFamily.default,
113
+ headingFontFamily: headingFontFamilyProp,
106
114
  hasBackground = themePropDefs.hasBackground.default,
107
115
  ...rootProps
108
116
  } = props;
@@ -128,6 +136,7 @@ const ThemeRoot = React.forwardRef<ThemeImplElement, ThemeImplPublicProps>(
128
136
  const [radius, setRadius] = usePropSyncedState(radiusProp);
129
137
  const [scaling, setScaling] = usePropSyncedState(scalingProp);
130
138
  const [fontFamily, setFontFamily] = usePropSyncedState(fontFamilyProp);
139
+ const [headingFontFamily, setHeadingFontFamily] = usePropSyncedState(headingFontFamilyProp);
131
140
 
132
141
  return (
133
142
  <ThemeImpl
@@ -144,6 +153,7 @@ const ThemeRoot = React.forwardRef<ThemeImplElement, ThemeImplPublicProps>(
144
153
  radius={radius}
145
154
  scaling={scaling}
146
155
  fontFamily={fontFamily}
156
+ headingFontFamily={headingFontFamily}
147
157
  //
148
158
  onAppearanceChange={setAppearance}
149
159
  onAccentColorChange={setAccentColor}
@@ -153,6 +163,7 @@ const ThemeRoot = React.forwardRef<ThemeImplElement, ThemeImplPublicProps>(
153
163
  onRadiusChange={setRadius}
154
164
  onScalingChange={setScaling}
155
165
  onFontFamilyChange={setFontFamily}
166
+ onHeadingFontFamilyChange={setHeadingFontFamily}
156
167
  />
157
168
  );
158
169
  },
@@ -193,6 +204,7 @@ const ThemeImpl = React.forwardRef<ThemeImplElement, ThemeImplProps>((props, for
193
204
  radius = props.radius ?? context?.radius ?? themePropDefs.radius.default,
194
205
  scaling = props.scaling ?? context?.scaling ?? themePropDefs.scaling.default,
195
206
  fontFamily = props.fontFamily ?? context?.fontFamily ?? themePropDefs.fontFamily.default,
207
+ headingFontFamily = props.headingFontFamily ?? context?.headingFontFamily,
196
208
  //
197
209
  onAppearanceChange = noop,
198
210
  onAccentColorChange = noop,
@@ -202,6 +214,7 @@ const ThemeImpl = React.forwardRef<ThemeImplElement, ThemeImplProps>((props, for
202
214
  onRadiusChange = noop,
203
215
  onScalingChange = noop,
204
216
  onFontFamilyChange = noop,
217
+ onHeadingFontFamilyChange = noop,
205
218
  //
206
219
  ...themeProps
207
220
  } = props;
@@ -243,6 +256,7 @@ const ThemeImpl = React.forwardRef<ThemeImplElement, ThemeImplProps>((props, for
243
256
  radius,
244
257
  scaling,
245
258
  fontFamily,
259
+ headingFontFamily,
246
260
  //
247
261
  onAppearanceChange,
248
262
  onAccentColorChange,
@@ -252,6 +266,7 @@ const ThemeImpl = React.forwardRef<ThemeImplElement, ThemeImplProps>((props, for
252
266
  onRadiusChange,
253
267
  onScalingChange,
254
268
  onFontFamilyChange,
269
+ onHeadingFontFamilyChange,
255
270
  }),
256
271
  [
257
272
  appearance,
@@ -263,6 +278,7 @@ const ThemeImpl = React.forwardRef<ThemeImplElement, ThemeImplProps>((props, for
263
278
  radius,
264
279
  scaling,
265
280
  fontFamily,
281
+ headingFontFamily,
266
282
  //
267
283
  onAppearanceChange,
268
284
  onAccentColorChange,
@@ -272,6 +288,7 @@ const ThemeImpl = React.forwardRef<ThemeImplElement, ThemeImplProps>((props, for
272
288
  onRadiusChange,
273
289
  onScalingChange,
274
290
  onFontFamilyChange,
291
+ onHeadingFontFamilyChange,
275
292
  ],
276
293
  )}
277
294
  >
@@ -286,6 +303,7 @@ const ThemeImpl = React.forwardRef<ThemeImplElement, ThemeImplProps>((props, for
286
303
  data-radius={radius}
287
304
  data-scaling={scaling}
288
305
  data-font-family={fontFamily}
306
+ data-heading-font-family={headingFontFamily}
289
307
  ref={composedRef}
290
308
  {...themeProps}
291
309
  className={classNames(
@@ -2,7 +2,7 @@
2
2
  box-sizing: border-box;
3
3
  padding: var(--space-1) var(--space-2);
4
4
  background-color: var(--gray-12);
5
- border-radius: var(--radius-1);
5
+ border-radius: var(--radius-surface-1);
6
6
  z-index: 300; /* Tooltips always on top - above dialogs (100) and menus (200) */
7
7
 
8
8
  transform-origin: var(--radix-tooltip-content-transform-origin);
@@ -1,194 +1,176 @@
1
1
  /**
2
- * Font configuration utilities for Kookie UI
2
+ * Runtime font configuration for Kookie UI.
3
3
  *
4
- * These utilities help users configure custom fonts through CSS variables
5
- * and provide type-safe font configuration options.
4
+ * This is a thin, typed wrapper over the CSS tokens in `styles/tokens/font-family.css` —
5
+ * it writes the same variables you would write by hand, and nothing else. Prefer plain CSS
6
+ * where you can; reach for this when the stacks are only known at runtime (a theme editor,
7
+ * a user-selectable typeface).
8
+ *
9
+ * Two tiers, matching the CSS:
10
+ *
11
+ * - `stacks` — which typefaces exist: `sans`, `mono`, `serif`. Written to `:root`.
12
+ * - `roles` — which stack each role uses: `body`, `heading`, `code`, `strong`, `em`,
13
+ * `quote`. Written to the theme element, since roles are per-theme.
6
14
  */
7
15
 
8
- /**
9
- * Font family configuration interface
10
- */
11
- export interface FontConfig {
12
- /** Sans-serif font stack for fontFamily="sans" */
16
+ /** Tier 1 — the typefaces available to the theme. */
17
+ export interface FontStacks {
18
+ /** Sans-serif stack. Backs `font="sans"` and, by default, body text. */
13
19
  sans?: string;
14
- /** Monospace font stack for fontFamily="mono" */
20
+ /** Monospace stack. Backs `font="mono"` and `Code`. */
15
21
  mono?: string;
16
- /** Serif font stack for fontFamily="serif" */
22
+ /** Serif stack. Backs `font="serif"`, `Em` and `Quote`. */
17
23
  serif?: string;
18
- /** Base Inter font replacement */
19
- inter?: string;
20
- /** Base JetBrains Mono font replacement */
21
- jetbrainsMono?: string;
22
- /** Base Playfair Display font replacement */
23
- playfairDisplay?: string;
24
24
  }
25
25
 
26
- /**
27
- * CSS variable names used by Kookie UI for fonts
28
- */
29
- export const FONT_CSS_VARIABLES = {
26
+ /** Tier 2 — which stack each role of text uses. */
27
+ export interface FontRoles {
28
+ /** Body text: `Text`, inputs, buttons, and anything that does not opt out. */
29
+ body?: string;
30
+ /** `Heading`. Follows `body` when left unset. */
31
+ heading?: string;
32
+ /** `Code`. */
33
+ code?: string;
34
+ /** `Strong`. */
35
+ strong?: string;
36
+ /** `Em`. */
37
+ em?: string;
38
+ /** `Quote`. */
39
+ quote?: string;
40
+ }
41
+
42
+ export interface FontConfig {
43
+ stacks?: FontStacks;
44
+ roles?: FontRoles;
45
+ }
46
+
47
+ /** CSS custom properties backing each stack. Declared on `:root`. */
48
+ export const FONT_STACK_VARIABLES = {
30
49
  sans: '--font-sans',
31
50
  mono: '--font-mono',
32
51
  serif: '--font-serif',
33
- inter: '--font-inter',
34
- jetbrainsMono: '--font-jetbrains-mono',
35
- playfairDisplay: '--font-playfair-display',
36
- defaultFamily: '--default-font-family',
37
- headingFamily: '--heading-font-family',
38
- strongFamily: '--strong-font-family',
39
- codeFamily: '--code-font-family',
40
- } as const;
52
+ } as const satisfies Record<keyof FontStacks, `--font-${string}`>;
53
+
54
+ /** CSS custom properties backing each role. Declared on the theme element. */
55
+ export const FONT_ROLE_VARIABLES = {
56
+ body: '--font-body',
57
+ heading: '--font-heading',
58
+ code: '--font-code',
59
+ strong: '--font-strong',
60
+ em: '--font-em',
61
+ quote: '--font-quote',
62
+ } as const satisfies Record<keyof FontRoles, `--font-${string}`>;
41
63
 
42
64
  /**
43
- * Popular font stacks for common use cases
65
+ * Ready-made stacks, each ending in a system fallback.
66
+ *
67
+ * The webfont entries assume the face is already loaded — via
68
+ * `import '@womp/kookie-ui/fonts.css'`, `next/font`, or your own `@font-face`.
69
+ * Kookie's core stylesheet deliberately loads none.
44
70
  */
45
71
  export const FONT_STACKS = {
46
- // Sans-serif options
47
- inter: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
48
- system: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif",
49
- poppins: "'Poppins', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
50
- openSans: "'Open Sans', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
51
-
52
- // Monospace options
53
- jetbrainsMono: "'JetBrains Mono', 'Fira Code', 'Consolas', 'Liberation Mono', monospace",
54
- firaCode: "'Fira Code', 'JetBrains Mono', 'Consolas', 'Liberation Mono', monospace",
55
- sourceCodePro: "'Source Code Pro', 'JetBrains Mono', 'Consolas', monospace",
56
- systemMono: "'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', 'Courier New', monospace",
57
-
58
- // Serif options
59
- playfair: "'Playfair Display', 'Times New Roman', 'Times', 'Georgia', 'Cambria', serif",
60
- times: "'Times New Roman', 'Times', 'Georgia', 'Cambria', serif",
72
+ // Sans
73
+ system: "-apple-system, BlinkMacSystemFont, 'Segoe UI (Custom)', Roboto, 'Helvetica Neue', system-ui, sans-serif",
74
+ inter: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI (Custom)', Roboto, system-ui, sans-serif",
75
+ poppins: "'Poppins', -apple-system, BlinkMacSystemFont, system-ui, sans-serif",
76
+ openSans: "'Open Sans (Custom)', -apple-system, BlinkMacSystemFont, system-ui, sans-serif",
77
+
78
+ // Mono
79
+ systemMono: "'Menlo', 'Consolas (Custom)', 'Bitstream Vera Sans Mono', monospace",
80
+ jetbrainsMono: "'JetBrains Mono', 'Menlo', 'Consolas (Custom)', monospace",
81
+ firaCode: "'Fira Code', 'Menlo', 'Consolas (Custom)', monospace",
82
+ sourceCodePro: "'Source Code Pro', 'Menlo', 'Consolas (Custom)', monospace",
83
+
84
+ // Serif
85
+ systemSerif: "'Times New Roman', 'Times', 'Georgia', 'Cambria', serif",
86
+ playfair: "'Playfair Display', 'Times New Roman', 'Georgia', serif",
61
87
  georgia: "'Georgia', 'Times New Roman', 'Times', serif",
62
- lora: "'Lora', 'Times New Roman', 'Times', serif",
88
+ lora: "'Lora', 'Georgia', 'Times New Roman', serif",
63
89
  } as const;
64
90
 
65
- /**
66
- * Apply font configuration to CSS variables
67
- *
68
- * @param config Font configuration object
69
- * @param target Target element (defaults to document.documentElement)
70
- *
71
- * @example
72
- * ```ts
73
- * // Use Google Fonts
74
- * applyFontConfig({
75
- * sans: FONT_STACKS.poppins,
76
- * mono: FONT_STACKS.firaCode
77
- * });
78
- *
79
- * // Use system fonts only
80
- * applyFontConfig({
81
- * sans: FONT_STACKS.system,
82
- * mono: FONT_STACKS.systemMono
83
- * });
84
- * ```
85
- */
86
- export function applyFontConfig(config: FontConfig, target: HTMLElement = document.documentElement): void {
87
- const style = target.style;
88
-
89
- if (config.sans) {
90
- style.setProperty(FONT_CSS_VARIABLES.sans, config.sans);
91
- }
92
-
93
- if (config.mono) {
94
- style.setProperty(FONT_CSS_VARIABLES.mono, config.mono);
95
- }
96
-
97
- if (config.serif) {
98
- style.setProperty(FONT_CSS_VARIABLES.serif, config.serif);
99
- }
100
-
101
- if (config.inter) {
102
- style.setProperty(FONT_CSS_VARIABLES.inter, config.inter);
103
- }
104
-
105
- if (config.jetbrainsMono) {
106
- style.setProperty(FONT_CSS_VARIABLES.jetbrainsMono, config.jetbrainsMono);
91
+ function write<K extends string>(target: HTMLElement, variables: Record<K, string>, values: Partial<Record<K, string>>) {
92
+ for (const key of Object.keys(variables) as K[]) {
93
+ const value = values[key];
94
+ if (value) target.style.setProperty(variables[key], value);
107
95
  }
96
+ }
108
97
 
109
- if (config.playfairDisplay) {
110
- style.setProperty(FONT_CSS_VARIABLES.playfairDisplay, config.playfairDisplay);
98
+ function clear(target: HTMLElement, variables: Record<string, string>) {
99
+ for (const variable of Object.values(variables)) {
100
+ target.style.removeProperty(variable);
111
101
  }
112
102
  }
113
103
 
114
104
  /**
115
- * Generate CSS string for font configuration
105
+ * Apply a font configuration.
116
106
  *
117
- * @param config Font configuration object
118
- * @returns CSS string that can be injected into a stylesheet
107
+ * Stacks land on `:root` and roles on `themeElement`, mirroring where the stylesheet
108
+ * declares them — writing a role to `:root` would not survive, because the theme
109
+ * element declares its own.
119
110
  *
120
111
  * @example
121
112
  * ```ts
122
- * const css = generateFontCSS({
123
- * sans: FONT_STACKS.poppins,
124
- * mono: FONT_STACKS.firaCode
113
+ * // Serif headings over a sans body
114
+ * applyFontConfig({
115
+ * stacks: { sans: FONT_STACKS.inter, serif: FONT_STACKS.playfair },
116
+ * roles: { heading: 'var(--font-serif)' },
125
117
  * });
126
- *
127
- * // Inject into document
128
- * const style = document.createElement('style');
129
- * style.textContent = css;
130
- * document.head.appendChild(style);
131
118
  * ```
132
119
  */
133
- export function generateFontCSS(config: FontConfig): string {
134
- const rules: string[] = [':root {'];
135
-
136
- if (config.sans) {
137
- rules.push(` ${FONT_CSS_VARIABLES.sans}: ${config.sans};`);
138
- }
139
-
140
- if (config.mono) {
141
- rules.push(` ${FONT_CSS_VARIABLES.mono}: ${config.mono};`);
142
- }
143
-
144
- if (config.serif) {
145
- rules.push(` ${FONT_CSS_VARIABLES.serif}: ${config.serif};`);
146
- }
120
+ export function applyFontConfig(
121
+ config: FontConfig,
122
+ { root = document.documentElement, themeElement = document.querySelector<HTMLElement>('.radix-themes') }: { root?: HTMLElement; themeElement?: HTMLElement | null } = {},
123
+ ): void {
124
+ if (config.stacks) write(root, FONT_STACK_VARIABLES, config.stacks);
125
+ if (config.roles && themeElement) write(themeElement, FONT_ROLE_VARIABLES, config.roles);
126
+ }
147
127
 
148
- if (config.inter) {
149
- rules.push(` ${FONT_CSS_VARIABLES.inter}: ${config.inter};`);
150
- }
128
+ /**
129
+ * Render a font configuration as a CSS string, for injecting into a stylesheet or
130
+ * emitting server-side.
131
+ */
132
+ export function generateFontCSS(config: FontConfig): string {
133
+ const blocks: string[] = [];
151
134
 
152
- if (config.jetbrainsMono) {
153
- rules.push(` ${FONT_CSS_VARIABLES.jetbrainsMono}: ${config.jetbrainsMono};`);
135
+ const stacks = Object.entries(config.stacks ?? {}).filter(([, value]) => value);
136
+ if (stacks.length) {
137
+ blocks.push([':root {', ...stacks.map(([key, value]) => ` ${FONT_STACK_VARIABLES[key as keyof FontStacks]}: ${value};`), '}'].join('\n'));
154
138
  }
155
139
 
156
- if (config.playfairDisplay) {
157
- rules.push(` ${FONT_CSS_VARIABLES.playfairDisplay}: ${config.playfairDisplay};`);
140
+ const roles = Object.entries(config.roles ?? {}).filter(([, value]) => value);
141
+ if (roles.length) {
142
+ blocks.push(['.radix-themes {', ...roles.map(([key, value]) => ` ${FONT_ROLE_VARIABLES[key as keyof FontRoles]}: ${value};`), '}'].join('\n'));
158
143
  }
159
144
 
160
- rules.push('}');
161
-
162
- return rules.join('\n');
145
+ return blocks.join('\n\n');
163
146
  }
164
147
 
165
- /**
166
- * Reset fonts to Kookie UI defaults
167
- */
168
- export function resetFonts(target: HTMLElement = document.documentElement): void {
169
- const style = target.style;
170
-
171
- // Remove custom font variables to fall back to defaults
172
- style.removeProperty(FONT_CSS_VARIABLES.sans);
173
- style.removeProperty(FONT_CSS_VARIABLES.mono);
174
- style.removeProperty(FONT_CSS_VARIABLES.serif);
175
- style.removeProperty(FONT_CSS_VARIABLES.inter);
176
- style.removeProperty(FONT_CSS_VARIABLES.jetbrainsMono);
177
- style.removeProperty(FONT_CSS_VARIABLES.playfairDisplay);
148
+ /** Drop every inline font override, falling back to the stylesheet's defaults. */
149
+ export function resetFonts({ root = document.documentElement, themeElement = document.querySelector<HTMLElement>('.radix-themes') }: { root?: HTMLElement; themeElement?: HTMLElement | null } = {}): void {
150
+ clear(root, FONT_STACK_VARIABLES);
151
+ if (themeElement) clear(themeElement, FONT_ROLE_VARIABLES);
178
152
  }
179
153
 
180
- /**
181
- * Get current font configuration from CSS variables
182
- */
183
- export function getCurrentFontConfig(target: HTMLElement = document.documentElement): FontConfig {
184
- const computedStyle = getComputedStyle(target);
154
+ /** Read the stacks and roles currently in effect. */
155
+ export function getCurrentFontConfig({ themeElement = document.querySelector<HTMLElement>('.radix-themes') }: { themeElement?: HTMLElement | null } = {}): Required<FontConfig> {
156
+ // Roles resolve against the theme element, so read both tiers from it — it inherits
157
+ // the stacks from `:root` and is the only place the roles are declared.
158
+ const computed = getComputedStyle(themeElement ?? document.documentElement);
159
+ const read = (variable: string) => computed.getPropertyValue(variable).trim() || undefined;
185
160
 
186
161
  return {
187
- sans: computedStyle.getPropertyValue(FONT_CSS_VARIABLES.sans).trim() || undefined,
188
- mono: computedStyle.getPropertyValue(FONT_CSS_VARIABLES.mono).trim() || undefined,
189
- serif: computedStyle.getPropertyValue(FONT_CSS_VARIABLES.serif).trim() || undefined,
190
- inter: computedStyle.getPropertyValue(FONT_CSS_VARIABLES.inter).trim() || undefined,
191
- jetbrainsMono: computedStyle.getPropertyValue(FONT_CSS_VARIABLES.jetbrainsMono).trim() || undefined,
192
- playfairDisplay: computedStyle.getPropertyValue(FONT_CSS_VARIABLES.playfairDisplay).trim() || undefined,
162
+ stacks: {
163
+ sans: read(FONT_STACK_VARIABLES.sans),
164
+ mono: read(FONT_STACK_VARIABLES.mono),
165
+ serif: read(FONT_STACK_VARIABLES.serif),
166
+ },
167
+ roles: {
168
+ body: read(FONT_ROLE_VARIABLES.body),
169
+ heading: read(FONT_ROLE_VARIABLES.heading),
170
+ code: read(FONT_ROLE_VARIABLES.code),
171
+ strong: read(FONT_ROLE_VARIABLES.strong),
172
+ em: read(FONT_ROLE_VARIABLES.em),
173
+ quote: read(FONT_ROLE_VARIABLES.quote),
174
+ },
193
175
  };
194
176
  }
@@ -1,35 +1,30 @@
1
- /* Inter, JetBrains Mono, and Playfair Display from Google Fonts */
1
+ /***************************************************************************************************
2
+ * *
3
+ * KOOKIE UI WEBFONTS — OPT-IN *
4
+ * *
5
+ * Kookie UI's core stylesheet ships no webfonts; it defaults to system stacks so that importing *
6
+ * the library costs zero network requests. Import this file alongside it to get Kookie's own *
7
+ * typefaces: *
8
+ * *
9
+ * import '@womp/kookie-ui/styles.css'; *
10
+ * import '@womp/kookie-ui/fonts.css'; *
11
+ * *
12
+ * This costs three render-blocking requests to Google Fonts. If you already load fonts yourself *
13
+ * (`next/font`, a self-hosted @font-face, a CDN), skip this file and point the stacks at your *
14
+ * own faces instead: *
15
+ * *
16
+ * :root { *
17
+ * --font-sans: var(--my-next-font), system-ui, sans-serif; *
18
+ * } *
19
+ * *
20
+ ***************************************************************************************************/
21
+
2
22
  @import url('https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,100..900;1,100..900&display=swap');
3
23
  @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
4
24
  @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap');
5
25
 
6
- /* Font Variables - Customize these to change fonts throughout your app */
7
26
  :root {
8
- /* Base font definitions - these are the actual font stacks */
9
- --font-inter: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
10
- --font-jetbrains-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', 'Liberation Mono', 'Courier New', monospace;
11
- --font-playfair-display: 'Playfair Display', 'Times New Roman', 'Times', 'Georgia', 'Cambria', serif;
12
-
13
- /* Theme font family overrides - change these to customize fonts globally */
14
- --font-sans: var(--font-inter); /* Override this for custom sans-serif */
15
- --font-mono: var(--font-jetbrains-mono); /* Override this for custom monospace */
16
- --font-serif: var(--font-playfair-display); /* Override this for custom serif */
17
-
18
- /* Force proper font weight rendering */
19
- font-synthesis: none; /* Prevent browser from synthesizing weights */
20
- }
21
-
22
- /* Radix Themes font weight enforcement */
23
- .radix-themes {
24
- font-synthesis: none;
25
- font-family: var(--default-font-family);
26
- }
27
-
28
- /* System font fallback for critical loading scenarios */
29
- @font-face {
30
- font-family: 'System Fallback';
31
- font-style: normal;
32
- font-weight: 100 900;
33
- font-display: block;
34
- src: local('-apple-system'), local('BlinkMacSystemFont'), local('Segoe UI'), local('Roboto');
27
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI (Custom)', Roboto, 'Helvetica Neue', system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
28
+ --font-mono: 'JetBrains Mono', 'Menlo', 'Consolas (Custom)', 'Liberation Mono', monospace, 'Apple Color Emoji', 'Segoe UI Emoji';
29
+ --font-serif: 'Playfair Display', 'Times New Roman', 'Times', 'Georgia', 'Cambria', serif;
35
30
  }
@@ -1,4 +1,3 @@
1
- @import './fonts.css';
2
1
  @import './tokens/index.css';
3
2
  @import './breakpoints.css';
4
3
  @import './scrollbar.css';
@@ -4,6 +4,7 @@
4
4
  @import './radius.css';
5
5
  @import './shadow.css';
6
6
  @import './transition.css';
7
+ @import './font-family.css';
7
8
  @import './typography.css';
8
9
  @import './blur.css';
9
10
  @import './opacity.css';