@_mustachio/openauth 0.6.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 (192) hide show
  1. package/dist/esm/client.js +186 -0
  2. package/dist/esm/css.d.js +0 -0
  3. package/dist/esm/error.js +73 -0
  4. package/dist/esm/index.js +14 -0
  5. package/dist/esm/issuer.js +558 -0
  6. package/dist/esm/jwt.js +16 -0
  7. package/dist/esm/keys.js +113 -0
  8. package/dist/esm/pkce.js +35 -0
  9. package/dist/esm/provider/apple.js +28 -0
  10. package/dist/esm/provider/arctic.js +43 -0
  11. package/dist/esm/provider/code.js +58 -0
  12. package/dist/esm/provider/cognito.js +16 -0
  13. package/dist/esm/provider/discord.js +15 -0
  14. package/dist/esm/provider/facebook.js +24 -0
  15. package/dist/esm/provider/github.js +15 -0
  16. package/dist/esm/provider/google.js +25 -0
  17. package/dist/esm/provider/index.js +3 -0
  18. package/dist/esm/provider/jumpcloud.js +15 -0
  19. package/dist/esm/provider/keycloak.js +15 -0
  20. package/dist/esm/provider/linkedin.js +15 -0
  21. package/dist/esm/provider/m2m.js +17 -0
  22. package/dist/esm/provider/microsoft.js +24 -0
  23. package/dist/esm/provider/oauth2.js +119 -0
  24. package/dist/esm/provider/oidc.js +69 -0
  25. package/dist/esm/provider/passkey.js +315 -0
  26. package/dist/esm/provider/password.js +306 -0
  27. package/dist/esm/provider/provider.js +10 -0
  28. package/dist/esm/provider/slack.js +15 -0
  29. package/dist/esm/provider/spotify.js +15 -0
  30. package/dist/esm/provider/twitch.js +15 -0
  31. package/dist/esm/provider/x.js +16 -0
  32. package/dist/esm/provider/yahoo.js +15 -0
  33. package/dist/esm/random.js +27 -0
  34. package/dist/esm/storage/aws.js +39 -0
  35. package/dist/esm/storage/cloudflare.js +42 -0
  36. package/dist/esm/storage/dynamo.js +116 -0
  37. package/dist/esm/storage/memory.js +88 -0
  38. package/dist/esm/storage/storage.js +36 -0
  39. package/dist/esm/subject.js +7 -0
  40. package/dist/esm/ui/base.js +407 -0
  41. package/dist/esm/ui/code.js +151 -0
  42. package/dist/esm/ui/form.js +43 -0
  43. package/dist/esm/ui/icon.js +92 -0
  44. package/dist/esm/ui/passkey.js +329 -0
  45. package/dist/esm/ui/password.js +338 -0
  46. package/dist/esm/ui/select.js +187 -0
  47. package/dist/esm/ui/theme.js +115 -0
  48. package/dist/esm/util.js +54 -0
  49. package/dist/types/client.d.ts +466 -0
  50. package/dist/types/client.d.ts.map +1 -0
  51. package/dist/types/error.d.ts +77 -0
  52. package/dist/types/error.d.ts.map +1 -0
  53. package/dist/types/index.d.ts +20 -0
  54. package/dist/types/index.d.ts.map +1 -0
  55. package/dist/types/issuer.d.ts +465 -0
  56. package/dist/types/issuer.d.ts.map +1 -0
  57. package/dist/types/jwt.d.ts +6 -0
  58. package/dist/types/jwt.d.ts.map +1 -0
  59. package/dist/types/keys.d.ts +18 -0
  60. package/dist/types/keys.d.ts.map +1 -0
  61. package/dist/types/pkce.d.ts +7 -0
  62. package/dist/types/pkce.d.ts.map +1 -0
  63. package/dist/types/provider/apple.d.ts +108 -0
  64. package/dist/types/provider/apple.d.ts.map +1 -0
  65. package/dist/types/provider/arctic.d.ts +16 -0
  66. package/dist/types/provider/arctic.d.ts.map +1 -0
  67. package/dist/types/provider/code.d.ts +74 -0
  68. package/dist/types/provider/code.d.ts.map +1 -0
  69. package/dist/types/provider/cognito.d.ts +64 -0
  70. package/dist/types/provider/cognito.d.ts.map +1 -0
  71. package/dist/types/provider/discord.d.ts +38 -0
  72. package/dist/types/provider/discord.d.ts.map +1 -0
  73. package/dist/types/provider/facebook.d.ts +74 -0
  74. package/dist/types/provider/facebook.d.ts.map +1 -0
  75. package/dist/types/provider/github.d.ts +38 -0
  76. package/dist/types/provider/github.d.ts.map +1 -0
  77. package/dist/types/provider/google.d.ts +74 -0
  78. package/dist/types/provider/google.d.ts.map +1 -0
  79. package/dist/types/provider/index.d.ts +4 -0
  80. package/dist/types/provider/index.d.ts.map +1 -0
  81. package/dist/types/provider/jumpcloud.d.ts +38 -0
  82. package/dist/types/provider/jumpcloud.d.ts.map +1 -0
  83. package/dist/types/provider/keycloak.d.ts +67 -0
  84. package/dist/types/provider/keycloak.d.ts.map +1 -0
  85. package/dist/types/provider/linkedin.d.ts +6 -0
  86. package/dist/types/provider/linkedin.d.ts.map +1 -0
  87. package/dist/types/provider/m2m.d.ts +34 -0
  88. package/dist/types/provider/m2m.d.ts.map +1 -0
  89. package/dist/types/provider/microsoft.d.ts +89 -0
  90. package/dist/types/provider/microsoft.d.ts.map +1 -0
  91. package/dist/types/provider/oauth2.d.ts +133 -0
  92. package/dist/types/provider/oauth2.d.ts.map +1 -0
  93. package/dist/types/provider/oidc.d.ts +91 -0
  94. package/dist/types/provider/oidc.d.ts.map +1 -0
  95. package/dist/types/provider/passkey.d.ts +143 -0
  96. package/dist/types/provider/passkey.d.ts.map +1 -0
  97. package/dist/types/provider/password.d.ts +210 -0
  98. package/dist/types/provider/password.d.ts.map +1 -0
  99. package/dist/types/provider/provider.d.ts +29 -0
  100. package/dist/types/provider/provider.d.ts.map +1 -0
  101. package/dist/types/provider/slack.d.ts +59 -0
  102. package/dist/types/provider/slack.d.ts.map +1 -0
  103. package/dist/types/provider/spotify.d.ts +38 -0
  104. package/dist/types/provider/spotify.d.ts.map +1 -0
  105. package/dist/types/provider/twitch.d.ts +38 -0
  106. package/dist/types/provider/twitch.d.ts.map +1 -0
  107. package/dist/types/provider/x.d.ts +38 -0
  108. package/dist/types/provider/x.d.ts.map +1 -0
  109. package/dist/types/provider/yahoo.d.ts +38 -0
  110. package/dist/types/provider/yahoo.d.ts.map +1 -0
  111. package/dist/types/random.d.ts +3 -0
  112. package/dist/types/random.d.ts.map +1 -0
  113. package/dist/types/storage/aws.d.ts +4 -0
  114. package/dist/types/storage/aws.d.ts.map +1 -0
  115. package/dist/types/storage/cloudflare.d.ts +34 -0
  116. package/dist/types/storage/cloudflare.d.ts.map +1 -0
  117. package/dist/types/storage/dynamo.d.ts +65 -0
  118. package/dist/types/storage/dynamo.d.ts.map +1 -0
  119. package/dist/types/storage/memory.d.ts +49 -0
  120. package/dist/types/storage/memory.d.ts.map +1 -0
  121. package/dist/types/storage/storage.d.ts +15 -0
  122. package/dist/types/storage/storage.d.ts.map +1 -0
  123. package/dist/types/subject.d.ts +122 -0
  124. package/dist/types/subject.d.ts.map +1 -0
  125. package/dist/types/ui/base.d.ts +5 -0
  126. package/dist/types/ui/base.d.ts.map +1 -0
  127. package/dist/types/ui/code.d.ts +104 -0
  128. package/dist/types/ui/code.d.ts.map +1 -0
  129. package/dist/types/ui/form.d.ts +6 -0
  130. package/dist/types/ui/form.d.ts.map +1 -0
  131. package/dist/types/ui/icon.d.ts +6 -0
  132. package/dist/types/ui/icon.d.ts.map +1 -0
  133. package/dist/types/ui/passkey.d.ts +5 -0
  134. package/dist/types/ui/passkey.d.ts.map +1 -0
  135. package/dist/types/ui/password.d.ts +139 -0
  136. package/dist/types/ui/password.d.ts.map +1 -0
  137. package/dist/types/ui/select.d.ts +55 -0
  138. package/dist/types/ui/select.d.ts.map +1 -0
  139. package/dist/types/ui/theme.d.ts +207 -0
  140. package/dist/types/ui/theme.d.ts.map +1 -0
  141. package/dist/types/util.d.ts +8 -0
  142. package/dist/types/util.d.ts.map +1 -0
  143. package/package.json +51 -0
  144. package/src/client.ts +749 -0
  145. package/src/css.d.ts +4 -0
  146. package/src/error.ts +120 -0
  147. package/src/index.ts +26 -0
  148. package/src/issuer.ts +1302 -0
  149. package/src/jwt.ts +17 -0
  150. package/src/keys.ts +139 -0
  151. package/src/pkce.ts +40 -0
  152. package/src/provider/apple.ts +127 -0
  153. package/src/provider/arctic.ts +66 -0
  154. package/src/provider/code.ts +227 -0
  155. package/src/provider/cognito.ts +74 -0
  156. package/src/provider/discord.ts +45 -0
  157. package/src/provider/facebook.ts +84 -0
  158. package/src/provider/github.ts +45 -0
  159. package/src/provider/google.ts +85 -0
  160. package/src/provider/index.ts +3 -0
  161. package/src/provider/jumpcloud.ts +45 -0
  162. package/src/provider/keycloak.ts +75 -0
  163. package/src/provider/linkedin.ts +12 -0
  164. package/src/provider/m2m.ts +56 -0
  165. package/src/provider/microsoft.ts +100 -0
  166. package/src/provider/oauth2.ts +297 -0
  167. package/src/provider/oidc.ts +179 -0
  168. package/src/provider/passkey.ts +655 -0
  169. package/src/provider/password.ts +672 -0
  170. package/src/provider/provider.ts +33 -0
  171. package/src/provider/slack.ts +67 -0
  172. package/src/provider/spotify.ts +45 -0
  173. package/src/provider/twitch.ts +45 -0
  174. package/src/provider/x.ts +46 -0
  175. package/src/provider/yahoo.ts +45 -0
  176. package/src/random.ts +24 -0
  177. package/src/storage/aws.ts +59 -0
  178. package/src/storage/cloudflare.ts +77 -0
  179. package/src/storage/dynamo.ts +193 -0
  180. package/src/storage/memory.ts +135 -0
  181. package/src/storage/storage.ts +46 -0
  182. package/src/subject.ts +130 -0
  183. package/src/ui/base.tsx +118 -0
  184. package/src/ui/code.tsx +215 -0
  185. package/src/ui/form.tsx +40 -0
  186. package/src/ui/icon.tsx +95 -0
  187. package/src/ui/passkey.tsx +321 -0
  188. package/src/ui/password.tsx +405 -0
  189. package/src/ui/select.tsx +221 -0
  190. package/src/ui/theme.ts +319 -0
  191. package/src/ui/ui.css +252 -0
  192. package/src/util.ts +58 -0
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Use one of the built-in themes.
3
+ *
4
+ * @example
5
+ *
6
+ * ```ts
7
+ * import { THEME_SST } from "@openauthjs/openauth/ui/theme"
8
+ *
9
+ * export default issuer({
10
+ * theme: THEME_SST,
11
+ * // ...
12
+ * })
13
+ * ```
14
+ *
15
+ * Or define your own.
16
+ *
17
+ * ```ts
18
+ * import type { Theme } from "@openauthjs/openauth/ui/theme"
19
+ *
20
+ * const MY_THEME: Theme = {
21
+ * title: "Acne",
22
+ * radius: "none",
23
+ * favicon: "https://www.example.com/favicon.svg",
24
+ * // ...
25
+ * }
26
+ *
27
+ * export default issuer({
28
+ * theme: MY_THEME,
29
+ * // ...
30
+ * })
31
+ * ```
32
+ *
33
+ * @packageDocumentation
34
+ */
35
+
36
+ /**
37
+ * A type to define values for light and dark mode.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * {
42
+ * light: "#FFF",
43
+ * dark: "#000"
44
+ * }
45
+ * ```
46
+ */
47
+ export interface ColorScheme {
48
+ /**
49
+ * The value for dark mode.
50
+ */
51
+ dark: string
52
+ /**
53
+ * The value for light mode.
54
+ */
55
+ light: string
56
+ }
57
+
58
+ /**
59
+ * A type to define your custom theme.
60
+ */
61
+ export interface Theme {
62
+ /**
63
+ * The name of your app. Also used as the title of the page.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * {
68
+ * title: "Acne"
69
+ * }
70
+ * ```
71
+ */
72
+ title?: string
73
+ /**
74
+ * A URL to the favicon of your app.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * {
79
+ * favicon: "https://www.example.com/favicon.svg"
80
+ * }
81
+ * ```
82
+ */
83
+ favicon?: string
84
+ /**
85
+ * The border radius of the UI elements.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * {
90
+ * radius: "none"
91
+ * }
92
+ * ```
93
+ */
94
+ radius?: "none" | "sm" | "md" | "lg" | "full"
95
+ /**
96
+ * The primary color of the theme.
97
+ *
98
+ * Takes a color or both light and dark colors.
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * {
103
+ * primary: "#FF5E00"
104
+ * }
105
+ * ```
106
+ */
107
+ primary: string | ColorScheme
108
+ /**
109
+ * The background color of the theme.
110
+ *
111
+ * Takes a color or both light and dark colors.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * {
116
+ * background: "#FFF"
117
+ * }
118
+ * ```
119
+ */
120
+ background?: string | ColorScheme
121
+ /**
122
+ * A URL to the logo of your app.
123
+ *
124
+ * Takes a single image or both light and dark mode versions.
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * {
129
+ * logo: "https://www.example.com/logo.svg"
130
+ * }
131
+ * ```
132
+ */
133
+ logo?: string | ColorScheme
134
+ /**
135
+ * The font family and scale of the theme.
136
+ */
137
+ font?: {
138
+ /**
139
+ * The font family of the theme.
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * {
144
+ * font: {
145
+ * family: "Geist Mono, monospace"
146
+ * }
147
+ * }
148
+ * ```
149
+ */
150
+ family?: string
151
+ /**
152
+ * The font scale of the theme. Can be used to increase or decrease the font sizes across
153
+ * the UI.
154
+ *
155
+ * @default "1"
156
+ * @example
157
+ * ```ts
158
+ * {
159
+ * font: {
160
+ * scale: "1.25"
161
+ * }
162
+ * }
163
+ * ```
164
+ */
165
+ scale?: string
166
+ }
167
+ /**
168
+ * Custom CSS that's added to the page in a `<style>` tag.
169
+ *
170
+ * This can be used to import custom fonts.
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * {
175
+ * css: `@import url('https://fonts.googleapis.com/css2?family=Rubik:wght@100;200;300;400;500;600;700;800;900&display=swap');`
176
+ * }
177
+ * ```
178
+ */
179
+ css?: string
180
+ }
181
+
182
+ /**
183
+ * Built-in default OpenAuth theme.
184
+ */
185
+ export const THEME_OPENAUTH: Theme = {
186
+ title: "OpenAuth",
187
+ radius: "none",
188
+ background: {
189
+ dark: "black",
190
+ light: "white",
191
+ },
192
+ primary: {
193
+ dark: "white",
194
+ light: "black",
195
+ },
196
+ font: {
197
+ family: "IBM Plex Sans, sans-serif",
198
+ },
199
+ css: `
200
+ @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@100;200;300;400;500;600;700&display=swap');
201
+ `,
202
+ }
203
+
204
+ /**
205
+ * Built-in theme based on [Terminal](https://terminal.shop).
206
+ */
207
+ export const THEME_TERMINAL: Theme = {
208
+ title: "terminal",
209
+ radius: "none",
210
+ favicon: "https://www.terminal.shop/favicon.svg",
211
+ logo: {
212
+ dark: "https://www.terminal.shop/images/logo-white.svg",
213
+ light: "https://www.terminal.shop/images/logo-black.svg",
214
+ },
215
+ primary: "#ff5e00",
216
+ background: {
217
+ dark: "rgb(0, 0, 0)",
218
+ light: "rgb(255, 255, 255)",
219
+ },
220
+ font: {
221
+ family: "Geist Mono, monospace",
222
+ },
223
+ css: `
224
+ @import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100;200;300;400;500;600;700;800;900&display=swap');
225
+ `,
226
+ }
227
+
228
+ /**
229
+ * Built-in theme based on [SST](https://sst.dev).
230
+ */
231
+ export const THEME_SST: Theme = {
232
+ title: "SST",
233
+ favicon: "https://sst.dev/favicon.svg",
234
+ logo: {
235
+ dark: "https://sst.dev/favicon.svg",
236
+ light: "https://sst.dev/favicon.svg",
237
+ },
238
+ background: {
239
+ dark: "#1a1a2d",
240
+ light: "rgb(255, 255, 255)",
241
+ },
242
+ primary: "#f3663f",
243
+ font: {
244
+ family: "Rubik, sans-serif",
245
+ },
246
+ css: `
247
+ @import url('https://fonts.googleapis.com/css2?family=Rubik:wght@100;200;300;400;500;600;700;800;900&display=swap');
248
+ `,
249
+ }
250
+
251
+ /**
252
+ * Built-in theme based on [Supabase](https://supabase.com).
253
+ */
254
+ export const THEME_SUPABASE: Theme = {
255
+ title: "Supabase",
256
+ logo: {
257
+ dark: "https://supabase.com/dashboard/_next/image?url=%2Fdashboard%2Fimg%2Fsupabase-dark.svg&w=128&q=75",
258
+ light:
259
+ "https://supabase.com/dashboard/_next/image?url=%2Fdashboard%2Fimg%2Fsupabase-light.svg&w=128&q=75",
260
+ },
261
+ background: {
262
+ dark: "#171717",
263
+ light: "#f8f8f8",
264
+ },
265
+ primary: {
266
+ dark: "#006239",
267
+ light: "#72e3ad",
268
+ },
269
+ font: {
270
+ family: "Varela Round, sans-serif",
271
+ },
272
+ css: `
273
+ @import url('https://fonts.googleapis.com/css2?family=Varela+Round:wght@100;200;300;400;500;600;700;800;900&display=swap');
274
+ `,
275
+ }
276
+
277
+ /**
278
+ * Built-in theme based on [Vercel](https://vercel.com).
279
+ */
280
+ export const THEME_VERCEL: Theme = {
281
+ title: "Vercel",
282
+ logo: {
283
+ dark: "https://vercel.com/mktng/_next/static/media/vercel-logotype-dark.e8c0a742.svg",
284
+ light:
285
+ "https://vercel.com/mktng/_next/static/media/vercel-logotype-light.700a8d26.svg",
286
+ },
287
+ background: {
288
+ dark: "black",
289
+ light: "white",
290
+ },
291
+ primary: {
292
+ dark: "white",
293
+ light: "black",
294
+ },
295
+ font: {
296
+ family: "Geist, sans-serif",
297
+ },
298
+ css: `
299
+ @import url('https://fonts.googleapis.com/css2?family=Geist:wght@100;200;300;400;500;600;700;800;900&display=swap');
300
+ `,
301
+ }
302
+
303
+ // i really don't wanna use async local storage for this so get over it
304
+
305
+ /**
306
+ * @internal
307
+ */
308
+ export function setTheme(value: Theme) {
309
+ // @ts-ignore
310
+ globalThis.OPENAUTH_THEME = value
311
+ }
312
+
313
+ /**
314
+ * @internal
315
+ */
316
+ export function getTheme() {
317
+ // @ts-ignore
318
+ return globalThis.OPENAUTH_THEME || THEME_OPENAUTH
319
+ }
package/src/ui/ui.css ADDED
@@ -0,0 +1,252 @@
1
+ @import url("https://unpkg.com/tailwindcss@3.4.15/src/css/preflight.css");
2
+
3
+ :root {
4
+ --color-background-dark: #0e0e11;
5
+ --color-background-light: #ffffff;
6
+ --color-primary-dark: #6772e5;
7
+ --color-primary-light: #6772e5;
8
+
9
+ --color-background-success-dark: oklch(0.3 0.04 172);
10
+ --color-background-success-light: oklch(from var(--color-background-success-dark) 0.83 c h);
11
+ --color-success-dark: oklch(from var(--color-background-success-dark) 0.92 c h);
12
+ --color-success-light: oklch(from var(--color-background-success-dark) 0.25 c h);
13
+
14
+ --color-background-error-dark: oklch(0.32 0.07 15);
15
+ --color-background-error-light: oklch(from var(--color-background-error-dark) 0.92 c h);
16
+ --color-error-dark: oklch(from var(--color-background-error-dark) 0.92 c h);
17
+ --color-error-light: oklch(from var(--color-background-error-dark) 0.25 c h);
18
+
19
+ --border-radius: 0;
20
+
21
+ --color-background: var(--color-background-dark);
22
+ --color-primary: var(--color-primary-dark);
23
+
24
+ --color-background-success: var(--color-background-success-dark);
25
+ --color-success: var(--color-success-dark);
26
+ --color-background-error: var(--color-background-error-dark);
27
+ --color-error: var(--color-error-dark);
28
+
29
+ @media (prefers-color-scheme: light) {
30
+ --color-background: var(--color-background-light);
31
+ --color-primary: var(--color-primary-light);
32
+
33
+ --color-background-success: var(--color-background-success-light);
34
+ --color-success: var(--color-success-light);
35
+ --color-background-error: var(--color-background-error-light);
36
+ --color-error: var(--color-error-light);
37
+ }
38
+
39
+ --color-high: oklch(
40
+ from var(--color-background) clamp(0, calc((l - 0.714) * -1000), 1) 0 0
41
+ );
42
+ --color-low: oklch(from var(--color-background) clamp(0, calc((l - 0.714) * 1000), 1) 0 0);
43
+ --lightness-high: color-mix(
44
+ in oklch,
45
+ var(--color-high) 0%,
46
+ oklch(var(--color-high) 0 0)
47
+ );
48
+ --lightness-low: color-mix(
49
+ in oklch,
50
+ var(--color-low) 0%,
51
+ oklch(var(--color-low) 0 0)
52
+ );
53
+ --font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
54
+ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
55
+ --font-scale: 1;
56
+
57
+ --font-size-xs: calc(0.75rem * var(--font-scale));
58
+ --font-size-sm: calc(0.875rem * var(--font-scale));
59
+ --font-size-md: calc(1rem * var(--font-scale));
60
+ --font-size-lg: calc(1.125rem * var(--font-scale));
61
+ --font-size-xl: calc(1.25rem * var(--font-scale));
62
+ --font-size-2xl: calc(1.5rem * var(--font-scale));
63
+ }
64
+
65
+ [data-component="root"] {
66
+ font-family: var(--font-family);
67
+ background-color: var(--color-background);
68
+ padding: 1rem;
69
+ color: white;
70
+ position: absolute;
71
+ inset: 0;
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ flex-direction: column;
76
+ user-select: none;
77
+ color: var(--color-high);
78
+ }
79
+
80
+ [data-component="center"] {
81
+ width: 380px;
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: 1.5rem;
85
+
86
+ &[data-size="small"] {
87
+ width: 300px;
88
+ }
89
+ }
90
+
91
+ [data-component="link"] {
92
+ text-decoration: underline;
93
+ text-underline-offset: 0.125rem;
94
+ font-weight: 600;
95
+ }
96
+
97
+ [data-component="label"] {
98
+ display: flex;
99
+ gap: 0.75rem;
100
+ flex-direction: column;
101
+ font-size: var(--font-size-xs);
102
+ }
103
+
104
+ [data-component="logo"] {
105
+ margin: 0 auto;
106
+ height: 2.5rem;
107
+ width: auto;
108
+ display: none;
109
+
110
+ @media (prefers-color-scheme: light) {
111
+ &[data-mode="light"] {
112
+ display: block;
113
+ }
114
+ }
115
+
116
+ @media (prefers-color-scheme: dark) {
117
+ &[data-mode="dark"] {
118
+ display: block;
119
+ }
120
+ }
121
+ }
122
+
123
+ [data-component="logo-default"] {
124
+ margin: 0 auto;
125
+ height: 2.5rem;
126
+ width: auto;
127
+
128
+ @media (prefers-color-scheme: light) {
129
+ color: var(--color-high);
130
+ }
131
+
132
+ @media (prefers-color-scheme: dark) {
133
+ color: var(--color-high);
134
+ }
135
+ }
136
+
137
+ [data-component="input"] {
138
+ width: 100%;
139
+ height: 2.5rem;
140
+ padding: 0 1rem;
141
+ border: 1px solid transparent;
142
+ --background: oklch(
143
+ from var(--color-background) calc(l + (-0.06 * clamp(0, calc((l - 0.714) * 1000), 1) + 0.03)) c h
144
+
145
+ );
146
+ background: var(--background);
147
+ border-color: oklch(
148
+ from var(--color-background)
149
+ calc(clamp(0.22, l + (-0.12 * clamp(0, calc((l - 0.714) * 1000), 1) + 0.06), 0.88)) c h
150
+ );
151
+ border-radius: calc(var(--border-radius) * 0.25rem);
152
+ font-size: var(--font-size-sm);
153
+ outline: none;
154
+
155
+ &:focus {
156
+ border-color: oklch(
157
+ from var(--color-background)
158
+ calc(clamp(0.3, l + (-0.2 * clamp(0, calc((l - 0.714) * 1000), 1) + 0.1), 0.7)) c h
159
+ );
160
+ }
161
+
162
+ &:user-invalid:not(:focus) {
163
+ border-color: oklch(0.4 0.09 7.91);
164
+ }
165
+ }
166
+
167
+ [data-component="button"] {
168
+ height: 2.5rem;
169
+ cursor: pointer;
170
+ border: 0;
171
+ font-weight: 500;
172
+ font-size: var(--font-size-sm);
173
+ border-radius: calc(var(--border-radius) * 0.25rem);
174
+ display: flex;
175
+ gap: 0.75rem;
176
+ align-items: center;
177
+ justify-content: center;
178
+ background: var(--color-primary);
179
+ color: oklch(from var(--color-primary) clamp(0, calc((l - 0.714) * -1000), 1) 0 0);
180
+
181
+ &[data-color="ghost"] {
182
+ background: transparent;
183
+ color: var(--color-high);
184
+ border: 1px solid
185
+ oklch(
186
+ from var(--color-background)
187
+ calc(clamp(0.22, l + (-0.12 * clamp(0, calc((l - 0.714) * 1000), 1) + 0.06), 0.88)) c h
188
+ );
189
+ }
190
+
191
+ [data-slot="icon"] {
192
+ width: 16px;
193
+ height: 16px;
194
+
195
+ svg {
196
+ width: 100%;
197
+ height: 100%;
198
+ }
199
+ }
200
+ }
201
+
202
+ [data-component="form"] {
203
+ max-width: 100%;
204
+ display: flex;
205
+ flex-direction: column;
206
+ gap: 1rem;
207
+ margin: 0;
208
+ }
209
+
210
+ [data-component="form-alert"] {
211
+ height: 2.5rem;
212
+ display: flex;
213
+ align-items: center;
214
+ padding: 0 1rem;
215
+ border-radius: calc(var(--border-radius) * 0.25rem);
216
+ background: var(--color-background-error);
217
+ color: var(--color-error);
218
+ text-align: left;
219
+ font-size: 0.75rem;
220
+ gap: 0.5rem;
221
+
222
+ &[data-color="success"] {
223
+ background: var(--color-background-success);
224
+ color: var(--color-success);
225
+
226
+ [data-slot="icon-success"] { display: block; }
227
+ [data-slot="icon-danger"] { display: none; }
228
+ }
229
+
230
+ &:has([data-slot="message"]:empty) {
231
+ display: none;
232
+ }
233
+
234
+ [data-slot="icon-success"],
235
+ [data-slot="icon-danger"] {
236
+ width: 1rem;
237
+ height: 1rem;
238
+ }
239
+ [data-slot="icon-success"] { display: none; }
240
+ }
241
+
242
+ [data-component="form-footer"] {
243
+ display: flex;
244
+ gap: 1rem;
245
+ font-size: 0.75rem;
246
+ align-items: center;
247
+ justify-content: center;
248
+
249
+ &:has(> :nth-child(2)) {
250
+ justify-content: space-between;
251
+ }
252
+ }
package/src/util.ts ADDED
@@ -0,0 +1,58 @@
1
+ import type { Context } from "hono"
2
+
3
+ export type Prettify<T> = {
4
+ [K in keyof T]: T[K]
5
+ }
6
+
7
+ export function getRelativeUrl(ctx: Context, path: string) {
8
+ const result = new URL(path, ctx.req.url)
9
+ result.host = ctx.req.header("x-forwarded-host") || result.host
10
+ result.protocol = ctx.req.header("x-forwarded-proto") || result.protocol
11
+ result.port = ctx.req.header("x-forwarded-port") || result.port
12
+ return result.toString()
13
+ }
14
+
15
+ const twoPartTlds = [
16
+ "co.uk",
17
+ "co.jp",
18
+ "co.kr",
19
+ "co.nz",
20
+ "co.za",
21
+ "co.in",
22
+ "com.au",
23
+ "com.br",
24
+ "com.cn",
25
+ "com.mx",
26
+ "com.tw",
27
+ "net.au",
28
+ "org.uk",
29
+ "ne.jp",
30
+ "ac.uk",
31
+ "gov.uk",
32
+ "edu.au",
33
+ "gov.au",
34
+ ]
35
+
36
+ export function isDomainMatch(a: string, b: string): boolean {
37
+ if (a === b) return true
38
+ const partsA = a.split(".")
39
+ const partsB = b.split(".")
40
+ const hasTwoPartTld = twoPartTlds.some(
41
+ (tld) => a.endsWith("." + tld) || b.endsWith("." + tld),
42
+ )
43
+ const numParts = hasTwoPartTld ? -3 : -2
44
+ const min = Math.min(partsA.length, partsB.length, numParts)
45
+ const tailA = partsA.slice(min).join(".")
46
+ const tailB = partsB.slice(min).join(".")
47
+ return tailA === tailB
48
+ }
49
+
50
+ export function lazy<T>(fn: () => T): () => T {
51
+ let value: T | undefined
52
+ return () => {
53
+ if (value === undefined) {
54
+ value = fn()
55
+ }
56
+ return value
57
+ }
58
+ }