@stacksjs/components 0.2.176 → 0.2.177

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 (109) hide show
  1. package/dist/{Accordion-pt8j917s.stx → Accordion-8tv78bh9.stx} +4 -4
  2. package/dist/{AccordionItem-hbhzx63p.stx → AccordionItem-7bd3ga36.stx} +3 -3
  3. package/dist/{Audio-hjywk3qc.stx → Audio-y0sgq50z.stx} +3 -3
  4. package/dist/{Avatar-h3jmwcq0.stx → Avatar-rjvwnskf.stx} +2 -2
  5. package/dist/{Badge-k8dy3d53.stx → Badge-k52qmxcm.stx} +1 -1
  6. package/dist/{Breadcrumb-7f7s4d02.stx → Breadcrumb-sy5taqsn.stx} +7 -7
  7. package/dist/{Button-1vknasy3.stx → Button-wrwmnfpf.stx} +2 -2
  8. package/dist/{Calendar-reny0et7.stx → Calendar-gjjhhfnt.stx} +8 -8
  9. package/dist/{Card-c1g1fd1w.stx → Card-473a02fy.stx} +3 -3
  10. package/dist/{Checkbox-aqmq4cqv.stx → Checkbox-2s2a7n4h.stx} +4 -4
  11. package/dist/{Checkout-agt0ngpw.stx → Checkout-22wh3s22.stx} +1 -1
  12. package/dist/{ComboboxOption-hmxt3gte.stx → ComboboxOption-6yh7xk7q.stx} +2 -2
  13. package/dist/{CommandPaletteItem-mvk6q7a2.stx → CommandPaletteItem-chdw0070.stx} +1 -1
  14. package/dist/{DefaultPaymentMethod-shhf6aap.stx → DefaultPaymentMethod-6qrem3sg.stx} +8 -8
  15. package/dist/{DialogDescription-76prd1m2.stx → DialogDescription-gth4c2kx.stx} +1 -1
  16. package/dist/{Drawer-hrz7qcyp.stx → Drawer-jgepqr9j.stx} +1 -1
  17. package/dist/{DropdownItem-c7rz08e5.stx → DropdownItem-d8ht2bp5.stx} +1 -1
  18. package/dist/{Form-bpnpbymb.stx → Form-vbag14t1.stx} +1 -1
  19. package/dist/{ListboxOption-e0dtv1gc.stx → ListboxOption-4j070101.stx} +2 -2
  20. package/dist/{Login-gepemsth.stx → Login-2cp65d41.stx} +40 -22
  21. package/dist/{Navigator-rk2a5wvk.stx → Navigator-smpa7my4.stx} +12 -12
  22. package/dist/{NumberInput-g41gmd2c.stx → NumberInput-j9p5bm5y.stx} +7 -7
  23. package/dist/{Pagination-wtgxmzey.stx → Pagination-jbcjrfcs.stx} +3 -3
  24. package/dist/{PasswordInput-4rsq1gwb.stx → PasswordInput-4qykq1dz.stx} +8 -8
  25. package/dist/{PaymentMethods-x4vrx9yb.stx → PaymentMethods-2xy66bwk.stx} +11 -11
  26. package/dist/{Progress-9dhakbh4.stx → Progress-4h7dytq5.stx} +9 -9
  27. package/dist/{Radio-djtb5dpc.stx → Radio-ccm07b2m.stx} +4 -4
  28. package/dist/RadioGroup-eerw9gq7.stx +138 -0
  29. package/dist/{RadioGroupDescription-yej78fak.stx → RadioGroupDescription-z34r9avr.stx} +1 -1
  30. package/dist/{RadioGroupOption-s1d6r221.stx → RadioGroupOption-7pq7rw84.stx} +1 -1
  31. package/dist/{Select-1vnd0brz.stx → Select-zt72gg1e.stx} +4 -4
  32. package/dist/{SidebarItem-2a6n0be3.stx → SidebarItem-5v8atp7p.stx} +2 -2
  33. package/dist/{SidebarPinned-tvj28bm0.stx → SidebarPinned-rq05nrtd.stx} +3 -3
  34. package/dist/{Signup-hxm5hwkr.stx → Signup-cbncrtvd.stx} +29 -19
  35. package/dist/{Skeleton-v1pwa8nr.stx → Skeleton-wtwb97xd.stx} +1 -1
  36. package/dist/{Spinner-7dahavkd.stx → Spinner-ypya5tt2.stx} +8 -8
  37. package/dist/{StepperStep-wxgembat.stx → StepperStep-3ahq4d9m.stx} +3 -3
  38. package/dist/{SubscriptionCheckout-zy2ycrmw.stx → SubscriptionCheckout-7fdkwf04.stx} +40 -34
  39. package/dist/{Switch-p1bcr9ks.stx → Switch-hdta55a8.stx} +1 -1
  40. package/dist/{Table-6cx8az9h.stx → Table-0mc3fdek.stx} +1 -1
  41. package/dist/{TableBody-wf6t13j9.stx → TableBody-drxyz5jh.stx} +1 -1
  42. package/dist/{TableCell-ntx0edbn.stx → TableCell-8swtcq8s.stx} +1 -1
  43. package/dist/{TableHead-3k4hnm2k.stx → TableHead-e9xvjx2j.stx} +1 -1
  44. package/dist/{TableHeader-0eyzbqpz.stx → TableHeader-sxc77b4d.stx} +2 -2
  45. package/dist/{TableRow-z09p2ebf.stx → TableRow-xd542nvb.stx} +1 -1
  46. package/dist/{Tabs-79brys99.stx → Tabs-b4xsba1w.stx} +6 -6
  47. package/dist/{TextInput-g0vaz0pe.stx → TextInput-cefyyprt.stx} +9 -9
  48. package/dist/{Textarea-96kawv5c.stx → Textarea-xcdym703.stx} +6 -6
  49. package/dist/{TwoFactorChallenge-y5m3nk79.stx → TwoFactorChallenge-y7n4yrk9.stx} +8 -8
  50. package/dist/{Video-84j4pv6h.stx → Video-a0aeyexv.stx} +1 -1
  51. package/dist/{VirtualTable-f9crbfjr.stx → VirtualTable-jvm1784g.stx} +6 -6
  52. package/dist/index.d.ts +2 -0
  53. package/dist/index.js +89 -55
  54. package/dist/theme/index.d.ts +92 -0
  55. package/package.json +3 -3
  56. package/src/index.ts +2 -0
  57. package/src/theme/index.ts +130 -0
  58. package/src/ui/accordion/Accordion.stx +4 -4
  59. package/src/ui/accordion/AccordionItem.stx +3 -3
  60. package/src/ui/audio/Audio.stx +3 -3
  61. package/src/ui/auth/Login.stx +40 -22
  62. package/src/ui/auth/Signup.stx +29 -19
  63. package/src/ui/auth/TwoFactorChallenge.stx +8 -8
  64. package/src/ui/avatar/Avatar.stx +2 -2
  65. package/src/ui/badge/Badge.stx +1 -1
  66. package/src/ui/breadcrumb/Breadcrumb.stx +7 -7
  67. package/src/ui/button/Button.stx +2 -2
  68. package/src/ui/calendar/Calendar.stx +8 -8
  69. package/src/ui/card/Card.stx +3 -3
  70. package/src/ui/checkbox/Checkbox.stx +4 -4
  71. package/src/ui/combobox/ComboboxOption.stx +2 -2
  72. package/src/ui/command-palette/CommandPaletteItem.stx +1 -1
  73. package/src/ui/dialog/DialogDescription.stx +1 -1
  74. package/src/ui/drawer/Drawer.stx +1 -1
  75. package/src/ui/dropdown/DropdownItem.stx +1 -1
  76. package/src/ui/form/Form.stx +1 -1
  77. package/src/ui/input/NumberInput.stx +7 -7
  78. package/src/ui/input/PasswordInput.stx +8 -8
  79. package/src/ui/input/TextInput.stx +9 -9
  80. package/src/ui/listbox/ListboxOption.stx +2 -2
  81. package/src/ui/navigator/Navigator.stx +12 -12
  82. package/src/ui/pagination/Pagination.stx +3 -3
  83. package/src/ui/payment/Checkout.stx +1 -1
  84. package/src/ui/payment/DefaultPaymentMethod.stx +8 -8
  85. package/src/ui/payment/PaymentMethods.stx +11 -11
  86. package/src/ui/payment/SubscriptionCheckout.stx +40 -34
  87. package/src/ui/progress/Progress.stx +9 -9
  88. package/src/ui/radio/Radio.stx +4 -4
  89. package/src/ui/radio-group/RadioGroup.stx +79 -1
  90. package/src/ui/radio-group/RadioGroupDescription.stx +1 -1
  91. package/src/ui/radio-group/RadioGroupOption.stx +1 -1
  92. package/src/ui/select/Select.stx +4 -4
  93. package/src/ui/sidebar/SidebarItem.stx +2 -2
  94. package/src/ui/sidebar/SidebarPinned.stx +3 -3
  95. package/src/ui/skeleton/Skeleton.stx +1 -1
  96. package/src/ui/spinner/Spinner.stx +8 -8
  97. package/src/ui/stepper/StepperStep.stx +3 -3
  98. package/src/ui/switch/Switch.stx +1 -1
  99. package/src/ui/table/Table.stx +1 -1
  100. package/src/ui/table/TableBody.stx +1 -1
  101. package/src/ui/table/TableCell.stx +1 -1
  102. package/src/ui/table/TableHead.stx +1 -1
  103. package/src/ui/table/TableHeader.stx +2 -2
  104. package/src/ui/table/TableRow.stx +1 -1
  105. package/src/ui/tabs/Tabs.stx +6 -6
  106. package/src/ui/textarea/Textarea.stx +6 -6
  107. package/src/ui/video/Video.stx +1 -1
  108. package/src/ui/virtual-table/VirtualTable.stx +6 -6
  109. package/dist/RadioGroup-qxmnm3xm.stx +0 -60
@@ -19,17 +19,17 @@ const sizeClasses = { sm: 'px-3 py-1.5 text-sm h-8', md: 'px-4 py-2 text-base h-
19
19
  const baseClasses = 'block w-full border-0 rounded-md shadow-sm ring-1 ring-inset transition-colors duration-200 focus:ring-2 focus:ring-inset dark:bg-blue-gray-700 dark:text-gray-100'
20
20
  const stateClasses = error
21
21
  ? 'ring-red-300 dark:ring-red-600 text-red-900 dark:text-red-300 placeholder-red-300 dark:placeholder-red-500 focus:ring-red-500 dark:focus:ring-red-400'
22
- : 'ring-gray-300 dark:ring-gray-600 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-indigo-600 dark:focus:ring-indigo-400'
22
+ : 'ring-line-strong text-fg placeholder-fg-subtle focus:ring-accent'
23
23
  const disabledClasses = disabled
24
- ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
24
+ ? 'opacity-50 cursor-not-allowed bg-surface'
25
25
  : readonly
26
- ? 'bg-gray-50 dark:bg-gray-800 cursor-default'
26
+ ? 'bg-surface cursor-default'
27
27
  : 'bg-white dark:bg-blue-gray-700'
28
28
  const paddingClasses = showControls ? 'pr-10' : ''
29
29
 
30
30
  export const inputClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${paddingClasses} ${inputClassName}`.trim()
31
- export const labelClasses = `block text-sm font-medium leading-6 mb-2 ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'}`.trim()
32
- export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
31
+ export const labelClasses = `block text-sm font-medium leading-6 mb-2 ${error ? 'text-danger' : 'text-fg'}`.trim()
32
+ export const helperClasses = `mt-2 text-sm ${error ? 'text-danger' : 'text-fg-soft'}`.trim()
33
33
  </script>
34
34
 
35
35
  <script client>
@@ -97,7 +97,7 @@ defineExpose({ value: inputValue, increment, decrement })
97
97
  <button
98
98
  type="button"
99
99
  @click="increment()"
100
- class="flex items-center justify-center w-8 h-1/2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none border-b border-gray-300 dark:border-gray-600"
100
+ class="flex items-center justify-center w-8 h-1/2 text-fg-subtle hover:text-fg-muted focus:outline-none border-b border-line-strong"
101
101
  aria-label="Increment"
102
102
  >
103
103
  <svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -107,7 +107,7 @@ defineExpose({ value: inputValue, increment, decrement })
107
107
  <button
108
108
  type="button"
109
109
  @click="decrement()"
110
- class="flex items-center justify-center w-8 h-1/2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none"
110
+ class="flex items-center justify-center w-8 h-1/2 text-fg-subtle hover:text-fg-muted focus:outline-none"
111
111
  aria-label="Decrement"
112
112
  >
113
113
  <svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -7,9 +7,9 @@ export const showPrevNext = $props.showPrevNext ?? true
7
7
  export const className = $props.className || ''
8
8
 
9
9
  export const paginationClasses = `flex items-center gap-1 ${className}`.trim()
10
- export const buttonClasses = `px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-white dark:disabled:hover:bg-gray-800 transition-colors duration-150`.trim()
11
- export const activeButtonClasses = `px-3 py-2 text-sm font-medium text-white bg-blue-600 dark:bg-blue-500 border border-blue-600 dark:border-blue-500 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900`.trim()
12
- export const ellipsisClasses = `px-3 py-2 text-sm font-medium text-gray-400 dark:text-gray-600`.trim()
10
+ export const buttonClasses = `px-3 py-2 text-sm font-medium text-fg-strong bg-white dark:bg-gray-800 border border-line-strong rounded-md hover:bg-surface focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-white dark:disabled:hover:bg-gray-800 transition-colors duration-150`.trim()
11
+ export const activeButtonClasses = `px-3 py-2 text-sm font-medium text-white bg-info-solid border border-info rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900`.trim()
12
+ export const ellipsisClasses = `px-3 py-2 text-sm font-medium text-fg-subtle`.trim()
13
13
  export const iconClasses = `w-5 h-5`.trim()
14
14
  </script>
15
15
 
@@ -18,16 +18,16 @@ const iconSizeClasses = { sm: 'h-4 w-4', md: 'h-5 w-5', lg: 'h-6 w-6' }
18
18
  const baseClasses = 'block w-full border-0 rounded-md shadow-sm ring-1 ring-inset transition-colors duration-200 focus:ring-2 focus:ring-inset dark:bg-blue-gray-700 dark:text-gray-100 pr-10'
19
19
  const stateClasses = error
20
20
  ? 'ring-red-300 dark:ring-red-600 text-red-900 dark:text-red-300 placeholder-red-300 dark:placeholder-red-500 focus:ring-red-500 dark:focus:ring-red-400'
21
- : 'ring-gray-300 dark:ring-gray-600 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-indigo-600 dark:focus:ring-indigo-400'
21
+ : 'ring-line-strong text-fg placeholder-fg-subtle focus:ring-accent'
22
22
  const disabledClasses = disabled
23
- ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
23
+ ? 'opacity-50 cursor-not-allowed bg-surface'
24
24
  : readonly
25
- ? 'bg-gray-50 dark:bg-gray-800 cursor-default'
25
+ ? 'bg-surface cursor-default'
26
26
  : 'bg-white dark:bg-blue-gray-700'
27
27
 
28
28
  export const inputClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${inputClassName}`.trim()
29
- export const labelClasses = `block text-sm font-medium leading-6 mb-2 ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'}`.trim()
30
- export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
29
+ export const labelClasses = `block text-sm font-medium leading-6 mb-2 ${error ? 'text-danger' : 'text-fg'}`.trim()
30
+ export const helperClasses = `mt-2 text-sm ${error ? 'text-danger' : 'text-fg-soft'}`.trim()
31
31
  export const iconClasses = iconSizeClasses[size]
32
32
  </script>
33
33
 
@@ -105,7 +105,7 @@ defineExpose({ value: inputValue })
105
105
  <button
106
106
  type="button"
107
107
  @click="toggleVisibility()"
108
- class="text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none"
108
+ class="text-fg-subtle hover:text-fg-muted focus:outline-none"
109
109
  :aria-label="toggleAriaLabel()"
110
110
  >
111
111
  <svg :show="showPassword()" class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -122,10 +122,10 @@ defineExpose({ value: inputValue })
122
122
  @if(showStrength)
123
123
  <div :show="inputValue().length > 0" class="mt-2">
124
124
  <div class="flex items-center justify-between mb-1">
125
- <span class="text-xs text-gray-600 dark:text-gray-400">Password strength</span>
125
+ <span class="text-xs text-fg-muted">Password strength</span>
126
126
  <span class="text-xs font-medium" :class="strengthLabelColor()" x-text="strengthText()"></span>
127
127
  </div>
128
- <div class="w-full h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
128
+ <div class="w-full h-1.5 bg-surface-sunken rounded-full overflow-hidden">
129
129
  <div
130
130
  class="h-full transition-all duration-300 rounded-full"
131
131
  :class="strengthColor()"
@@ -33,25 +33,25 @@ function onDelete(methodId) {
33
33
  <div class="{{ containerClasses }}">
34
34
  @if(isLoading)
35
35
  <div class="animate-pulse">
36
- <div class="h-24 bg-gray-200 dark:bg-gray-700 rounded-lg"></div>
36
+ <div class="h-24 bg-surface-sunken rounded-lg"></div>
37
37
  </div>
38
38
  @else
39
39
  @if(paymentMethods.length > 0)
40
40
  <ul role="list" class="grid grid-cols-1 gap-6 lg:grid-cols-1 sm:grid-cols-1">
41
41
  @foreach(method in paymentMethods)
42
- <li class="col-span-1 border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-blue-gray-800 shadow divide-y divide-gray-200 dark:divide-gray-700">
42
+ <li class="col-span-1 border border-line rounded-lg bg-white dark:bg-blue-gray-800 shadow divide-y divide-line">
43
43
  <div class="w-full p-3">
44
44
  <div class="flex items-center justify-between">
45
45
  <div class="flex items-center space-x-4">
46
- <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center bg-gray-100 dark:bg-gray-700 rounded-md">
46
+ <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center bg-surface-raised rounded-md">
47
47
  <span class="text-2xl">{{ brandIcons[method.brand.toLowerCase()] || brandIcons.default }}</span>
48
48
  </div>
49
49
 
50
50
  <div>
51
- <h2 class="text-sm text-gray-600 dark:text-gray-300">
51
+ <h2 class="text-sm text-fg-muted">
52
52
  {{ method.brand }} •••• {{ method.last_four }}
53
53
  </h2>
54
- <span class="text-xs text-gray-500 dark:text-gray-400 italic">
54
+ <span class="text-xs text-fg-soft italic">
55
55
  Expires {{ method.exp_month }} / {{ method.exp_year }}
56
56
  </span>
57
57
  </div>
@@ -61,7 +61,7 @@ function onDelete(methodId) {
61
61
  @if(showMakeDefault)
62
62
  <button
63
63
  type="button"
64
- class="border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-blue-gray-700 px-2 py-1 text-sm text-gray-700 dark:text-gray-300 font-semibold shadow-sm hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
64
+ class="border border-line-strong rounded-md bg-white dark:bg-blue-gray-700 px-2 py-1 text-sm text-fg-strong font-semibold shadow-sm hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
65
65
  @click="onMakeDefault('{{ method.id }}')"
66
66
  title="Make default"
67
67
  >
@@ -74,7 +74,7 @@ function onDelete(methodId) {
74
74
  @if(showDelete)
75
75
  <button
76
76
  type="button"
77
- class="border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-blue-gray-700 px-2 py-1 text-sm text-red-600 dark:text-red-400 font-semibold shadow-sm hover:bg-red-50 dark:hover:bg-red-900/20 focus-visible:outline-2 focus-visible:outline-red-600 focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
77
+ class="border border-line-strong rounded-md bg-white dark:bg-blue-gray-700 px-2 py-1 text-sm text-danger font-semibold shadow-sm hover:bg-red-50 dark:hover:bg-red-900/20 focus-visible:outline-2 focus-visible:outline-red-600 focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
78
78
  @click="onDelete('{{ method.id }}')"
79
79
  title="Delete payment method"
80
80
  >
@@ -90,12 +90,12 @@ function onDelete(methodId) {
90
90
  @endforeach
91
91
  </ul>
92
92
  @else
93
- <div class="text-center py-12 bg-white dark:bg-blue-gray-800 rounded-lg border border-gray-200 dark:border-gray-700">
94
- <svg class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
93
+ <div class="text-center py-12 bg-white dark:bg-blue-gray-800 rounded-lg border border-line">
94
+ <svg class="mx-auto h-12 w-12 text-fg-subtle" fill="none" viewBox="0 0 24 24" stroke="currentColor">
95
95
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
96
96
  </svg>
97
- <h3 class="mt-2 text-sm text-gray-900 dark:text-gray-100 font-medium">No payment methods</h3>
98
- <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
97
+ <h3 class="mt-2 text-sm text-fg font-medium">No payment methods</h3>
98
+ <p class="mt-1 text-sm text-fg-soft">
99
99
  You haven't added any payment methods yet.
100
100
  </p>
101
101
  </div>
@@ -11,11 +11,11 @@ export const className = $props.className || ''
11
11
  const linearSizeClasses = { sm: 'h-1', md: 'h-2', lg: 'h-3' }
12
12
  const circularSizeClasses = { sm: 'w-12 h-12', md: 'w-16 h-16', lg: 'w-24 h-24' }
13
13
  const colorClasses = {
14
- primary: 'bg-blue-600 dark:bg-blue-500',
14
+ primary: 'bg-info-solid',
15
15
  secondary: 'bg-purple-600 dark:bg-purple-500',
16
- success: 'bg-green-600 dark:bg-green-500',
16
+ success: 'bg-success-solid',
17
17
  warning: 'bg-yellow-600 dark:bg-yellow-500',
18
- danger: 'bg-red-600 dark:bg-red-500',
18
+ danger: 'bg-danger-solid',
19
19
  info: 'bg-cyan-600 dark:bg-cyan-500',
20
20
  }
21
21
 
@@ -28,16 +28,16 @@ export const containerClasses = variant === 'linear'
28
28
  ? `w-full ${className}`.trim()
29
29
  : `inline-flex items-center justify-center ${className}`.trim()
30
30
 
31
- export const linearTrackClasses = `w-full ${linearSizeClasses[size]} bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden`.trim()
31
+ export const linearTrackClasses = `w-full ${linearSizeClasses[size]} bg-surface-sunken rounded-full overflow-hidden`.trim()
32
32
  export const linearBarClasses = `h-full ${colorClasses[color]} transition-all duration-300 ease-in-out ${indeterminate ? 'animate-progress-indeterminate' : ''}`.trim()
33
33
  export const circularSizeClass = circularSizeClasses[size]
34
- export const labelClasses = `text-sm font-medium text-gray-700 dark:text-gray-300 mb-2`.trim()
34
+ export const labelClasses = `text-sm font-medium text-fg-strong mb-2`.trim()
35
35
  export const circularTrackColor = 'stroke-gray-200 dark:stroke-gray-700'
36
- export const circularBarColor = color === 'primary' ? 'stroke-blue-600 dark:stroke-blue-500'
36
+ export const circularBarColor = color === 'primary' ? 'stroke-info'
37
37
  : color === 'secondary' ? 'stroke-purple-600 dark:stroke-purple-500'
38
- : color === 'success' ? 'stroke-green-600 dark:stroke-green-500'
38
+ : color === 'success' ? 'stroke-success'
39
39
  : color === 'warning' ? 'stroke-yellow-600 dark:stroke-yellow-500'
40
- : color === 'danger' ? 'stroke-red-600 dark:stroke-red-500'
40
+ : color === 'danger' ? 'stroke-danger'
41
41
  : 'stroke-cyan-600 dark:stroke-cyan-500'
42
42
  </script>
43
43
 
@@ -112,7 +112,7 @@ defineExpose({ value, setValue: (v) => value.set(v) })
112
112
 
113
113
  @if(showLabel)
114
114
  <div class="absolute inset-0 flex items-center justify-center">
115
- <span class="text-sm font-semibold text-gray-700 dark:text-gray-300" x-text="percentLabel()"></span>
115
+ <span class="text-sm font-semibold text-fg-strong" x-text="percentLabel()"></span>
116
116
  </div>
117
117
  @endif
118
118
  </div>
@@ -11,13 +11,13 @@ export const name = $props.name || ''
11
11
  export const className = $props.className || ''
12
12
 
13
13
  const sizeClasses = { sm: 'h-4 w-4', md: 'h-5 w-5', lg: 'h-6 w-6' }
14
- const baseClasses = 'border-gray-300 dark:border-gray-600 text-indigo-600 dark:text-indigo-500 focus:ring-indigo-600 dark:focus:ring-indigo-500 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 transition-colors'
15
- const stateClasses = error ? 'border-red-300 dark:border-red-600 text-red-600 dark:text-red-500 focus:ring-red-500 dark:focus:ring-red-400' : ''
14
+ const baseClasses = 'border-line-strong text-accent focus:ring-accent focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 transition-colors'
15
+ const stateClasses = error ? 'border-red-300 dark:border-red-600 text-danger focus:ring-red-500 dark:focus:ring-red-400' : ''
16
16
  const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'
17
17
 
18
18
  export const radioClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses}`.trim()
19
- export const labelClasses = `text-sm font-medium ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'} ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`.trim()
20
- export const descriptionClasses = `text-sm ${error ? 'text-red-500 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
19
+ export const labelClasses = `text-sm font-medium ${error ? 'text-danger' : 'text-fg'} ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`.trim()
20
+ export const descriptionClasses = `text-sm ${error ? 'text-red-500 dark:text-red-400' : 'text-fg-soft'}`.trim()
21
21
  export const inputId = `radio-${value || label}`
22
22
  </script>
23
23
 
@@ -0,0 +1,138 @@
1
+ <script server>
2
+ export const value = $props.value
3
+ export const className = $props.className || ''
4
+ export const as = $props.as || 'div'
5
+
6
+ /*
7
+ * Prop-array mode, alongside the slot API (stacksjs/stx#1930).
8
+ *
9
+ * `<RadioGroup :options="[{ label: 'A', value: 'a' }]" />` used to emit a
10
+ * hydration shell and nothing else: the labels reached the page only inside
11
+ * `data-stx-props`, so the choices were invisible without JavaScript and to a
12
+ * crawler. Every comparable component here — Tabs, Accordion, Select, Navigator,
13
+ * Breadcrumb — server-renders its content from a prop array, so this was the
14
+ * odd one out rather than a deliberate choice.
15
+ *
16
+ * The options are rendered here rather than delegated to <RadioGroupOption>
17
+ * because a loop variable cannot cross a component boundary as a `:` binding.
18
+ * Interpolating it would stringify the value — `1` and `"1"` would stop being
19
+ * distinguishable — and the group compares values by identity. Emitting the
20
+ * option markup directly keeps `data-option-value` exact JSON, which is what
21
+ * `syncOptionStates` already reads.
22
+ */
23
+ export const options = Array.isArray($props.options) ? $props.options : []
24
+ export const hasPropOptions = options.length > 0
25
+
26
+ const optionBaseClasses = 'relative flex cursor-pointer rounded-lg px-5 py-4 shadow-md focus:outline-none transition-all bg-white dark:bg-neutral-800 text-fg focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-60 focus-visible:ring-offset-2 focus-visible:ring-offset-blue-300 dark:focus-visible:ring-offset-blue-700'
27
+ export const optionClasses = optionBaseClasses
28
+ export const optionDisabledClasses = `${optionBaseClasses} opacity-50 cursor-not-allowed`
29
+
30
+ const baseClasses = 'w-full'
31
+ export const groupClasses = `${baseClasses} ${className}`.trim()
32
+ export const radioGroupInstanceId = `stx-rg-${Math.random().toString(36).slice(2, 11)}`
33
+ </script>
34
+
35
+ <script client>
36
+ const emit = defineEmits()
37
+ const radioGroupInstanceId = {{ radioGroupInstanceId }}
38
+ const initialValue = {{ value === undefined ? 'null' : value }}
39
+ const selected = state(initialValue)
40
+ let rootEl = null
41
+
42
+ function selectValue(v) {
43
+ selected.set(v)
44
+ syncOptionStates()
45
+ emit('change', v)
46
+ }
47
+
48
+ function syncOptionStates() {
49
+ if (!rootEl) return
50
+ const options = rootEl.querySelectorAll('[data-stx-radio-option]')
51
+ for (const opt of options) {
52
+ const raw = opt.dataset.optionValue
53
+ let v
54
+ try { v = JSON.parse(raw ?? 'null') }
55
+ catch { v = raw }
56
+ const checked = selected() === v
57
+ opt.setAttribute('aria-checked', checked ? 'true' : 'false')
58
+ opt.setAttribute('data-checked', checked ? 'true' : 'false')
59
+ }
60
+ }
61
+
62
+ function onSelect(event) {
63
+ event.stopPropagation()
64
+ selectValue(event.detail)
65
+ }
66
+
67
+ // Options rendered from the `options` prop have no <RadioGroupOption> behind
68
+ // them to dispatch stx:radio-select, so the group claims them by delegation.
69
+ // One listener on the root rather than a handler per option, which also means
70
+ // options added later are picked up with no re-binding.
71
+ function optionValueOf(el) {
72
+ try { return JSON.parse(el.dataset.optionValue ?? 'null') }
73
+ catch { return el.dataset.optionValue }
74
+ }
75
+
76
+ function onDelegatedActivate(event) {
77
+ const option = event.target.closest?.('[data-stx-radio-option]')
78
+ if (!option || !rootEl || !rootEl.contains(option)) return
79
+ if (option.getAttribute('aria-disabled') === 'true') return
80
+ // A <RadioGroupOption> dispatches its own event; claiming its click too would
81
+ // select twice and emit two change events.
82
+ if (option.dataset.stxRadioDelegated !== 'true') return
83
+ if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return
84
+ event.preventDefault()
85
+ selectValue(optionValueOf(option))
86
+ }
87
+
88
+ onMount(() => {
89
+ rootEl = document.querySelector(`[data-radio-group-id="${radioGroupInstanceId}"]`)
90
+ if (rootEl) {
91
+ rootEl.addEventListener('click', onDelegatedActivate)
92
+ rootEl.addEventListener('keydown', onDelegatedActivate)
93
+ }
94
+ syncOptionStates()
95
+ })
96
+
97
+ onDestroy(() => {
98
+ if (!rootEl) return
99
+ rootEl.removeEventListener('click', onDelegatedActivate)
100
+ rootEl.removeEventListener('keydown', onDelegatedActivate)
101
+ })
102
+
103
+ defineExpose({ selected, selectValue })
104
+ </script>
105
+
106
+ <component
107
+ :is="{{ as }}"
108
+ class="{{ groupClasses }}"
109
+ data-stx-radio-group
110
+ data-radio-group-id="{{ radioGroupInstanceId }}"
111
+ role="radiogroup"
112
+ @stx:radio-select="onSelect($event)"
113
+ >
114
+ @if(hasPropOptions)
115
+ @foreach(option in options)
116
+ <div
117
+ data-stx-radio-option
118
+ data-stx-radio-delegated="true"
119
+ data-option-value="{{ JSON.stringify(option.value === undefined ? null : option.value) }}"
120
+ role="radio"
121
+ aria-checked="{{ option.value === value ? 'true' : 'false' }}"
122
+ data-checked="{{ option.value === value ? 'true' : 'false' }}"
123
+ aria-disabled="{{ option.disabled ? 'true' : 'false' }}"
124
+ tabindex="{{ option.disabled ? '-1' : '0' }}"
125
+ class="{{ option.disabled ? optionDisabledClasses : optionClasses }}"
126
+ >
127
+ <span class="flex flex-col">
128
+ <span class="text-sm font-medium">{{ option.label }}</span>
129
+ @if(option.description)
130
+ <span class="text-sm opacity-70">{{ option.description }}</span>
131
+ @endif
132
+ </span>
133
+ </div>
134
+ @endforeach
135
+ @else
136
+ <slot />
137
+ @endif
138
+ </component>
@@ -2,7 +2,7 @@
2
2
  export const className = $props.className || ''
3
3
  export const as = $props.as || 'span'
4
4
 
5
- const baseClasses = 'inline text-sm text-neutral-500 dark:text-neutral-400'
5
+ const baseClasses = 'inline text-sm text-fg-soft'
6
6
  const descriptionClasses = `${baseClasses} ${className}`.trim()
7
7
  </script>
8
8
 
@@ -4,7 +4,7 @@ export const disabled = $props.disabled || false
4
4
  export const className = $props.className || ''
5
5
  export const as = $props.as || 'div'
6
6
 
7
- const baseClasses = 'relative flex cursor-pointer rounded-lg px-5 py-4 shadow-md focus:outline-none transition-all bg-white dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-60 focus-visible:ring-offset-2 focus-visible:ring-offset-blue-300 dark:focus-visible:ring-offset-blue-700'
7
+ const baseClasses = 'relative flex cursor-pointer rounded-lg px-5 py-4 shadow-md focus:outline-none transition-all bg-white dark:bg-neutral-800 text-fg focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-60 focus-visible:ring-offset-2 focus-visible:ring-offset-blue-300 dark:focus-visible:ring-offset-blue-700'
8
8
  const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : ''
9
9
  export const optionClasses = `${baseClasses} ${disabledClasses} ${className}`.trim()
10
10
  export const valueJson = JSON.stringify(value === undefined ? null : value)
@@ -14,14 +14,14 @@ const sizeClasses = { sm: 'px-3 py-1.5 text-sm h-8', md: 'px-4 py-2 text-base h-
14
14
  const baseClasses = 'block w-full border-0 rounded-md shadow-sm ring-1 ring-inset transition-colors duration-200 focus:ring-2 focus:ring-inset dark:bg-blue-gray-700 dark:text-gray-100'
15
15
  const stateClasses = error
16
16
  ? 'ring-red-300 dark:ring-red-600 text-red-900 dark:text-red-300 placeholder-red-300 dark:placeholder-red-500 focus:ring-red-500 dark:focus:ring-red-400'
17
- : 'ring-gray-300 dark:ring-gray-600 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-indigo-600 dark:focus:ring-indigo-400'
17
+ : 'ring-line-strong text-fg placeholder-fg-subtle focus:ring-accent'
18
18
  const disabledClasses = disabled
19
- ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
19
+ ? 'opacity-50 cursor-not-allowed bg-surface'
20
20
  : 'bg-white dark:bg-blue-gray-700 cursor-pointer hover:ring-gray-400 dark:hover:ring-gray-500'
21
21
 
22
22
  export const selectClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${className}`.trim()
23
- export const labelClasses = `block text-sm font-medium leading-6 ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'}`.trim()
24
- export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
23
+ export const labelClasses = `block text-sm font-medium leading-6 ${error ? 'text-danger' : 'text-fg'}`.trim()
24
+ export const helperClasses = `mt-2 text-sm ${error ? 'text-danger' : 'text-fg-soft'}`.trim()
25
25
  export const selectId = `select-${value}`
26
26
  </script>
27
27
 
@@ -53,7 +53,7 @@ export const isLink = Boolean(href) && !disabled
53
53
  @if(indentStyle)style="{{ indentStyle }}"@endif
54
54
  >
55
55
  @if(isLink)
56
- <a href="{{ href }}" data-sidebar-item data-label="{{ label }}" class="{{ rowClasses }}" @if(active)data-active="true" aria-current="page"@endif>
56
+ <StxLink to="{{ href }}" data-sidebar-item data-label="{{ label }}" class="{{ rowClasses }}" :data-active="active ? 'true' : null" :aria-current="active ? 'page' : null">
57
57
  <span class="{{ disclosureClasses }}" @if(expandable)data-sidebar-disclosure role="button" aria-label="Toggle {{ label }}"@endif>
58
58
  @if(expandable)
59
59
  <span data-sidebar-chevron class="{{ chevronClasses }}" aria-hidden="true"></span>
@@ -68,7 +68,7 @@ export const isLink = Boolean(href) && !disabled
68
68
  @if(count !== '' && count !== null && count !== undefined)
69
69
  <span data-sidebar-count class="{{ countClasses }}">{{ count }}</span>
70
70
  @endif
71
- </a>
71
+ </StxLink>
72
72
  @else
73
73
  <button type="button" data-sidebar-item data-label="{{ label }}" class="{{ rowClasses }}" @if(active)data-active="true" aria-current="page"@endif @if(disabled)data-disabled disabled aria-disabled="true"@endif>
74
74
  <span class="{{ disclosureClasses }}" @if(expandable)data-sidebar-disclosure role="button" aria-label="Toggle {{ label }}"@endif>
@@ -51,8 +51,8 @@ function onPinnedClick(event) {
51
51
  >
52
52
  @foreach(items as item)
53
53
  @if(item.href)
54
- <a
55
- href="{{ item.href }}"
54
+ <StxLink
55
+ to="{{ item.href }}"
56
56
  data-space-pinned-item
57
57
  data-pinned-id="{{ item.id }}"
58
58
  class="{{ tileClasses }}"
@@ -65,7 +65,7 @@ function onPinnedClick(event) {
65
65
  @else
66
66
  <span class="{{ item.icon }} h-[20px] w-[20px]" @if(item.iconStyle)style="{{ item.iconStyle }}"@endif aria-hidden="true"></span>
67
67
  @endif
68
- </a>
68
+ </StxLink>
69
69
  @else
70
70
  <button
71
71
  type="button"
@@ -9,6 +9,14 @@ export const containerClasses = `min-h-full flex flex-col justify-center py-12 l
9
9
  <script client>
10
10
  const emit = defineEmits()
11
11
 
12
+ // The social buttons used to be `<a href="#">` — a link that navigates
13
+ // nowhere and that a host app had no way to wire (#1930). They are not
14
+ // navigation, so they are real buttons now, and the provider is emitted so
15
+ // the app can start its own OAuth flow.
16
+ function onSocial(provider) {
17
+ emit('social', { provider })
18
+ }
19
+
12
20
  function onSubmit(event) {
13
21
  event.preventDefault()
14
22
  const formData = new FormData(event.target)
@@ -33,7 +41,7 @@ function onSubmit(event) {
33
41
 
34
42
  <div class="{{ containerClasses }}">
35
43
  <div class="sm:mx-auto sm:max-w-md sm:w-full">
36
- <h2 class="mt-6 text-center text-2xl text-gray-900 dark:text-gray-100 font-bold leading-9 tracking-tight">
44
+ <h2 class="mt-6 text-center text-2xl text-fg font-bold leading-9 tracking-tight">
37
45
  {{ headingText }}
38
46
  </h2>
39
47
  </div>
@@ -42,7 +50,7 @@ function onSubmit(event) {
42
50
  <div class="bg-white dark:bg-blue-gray-800 px-6 py-12 shadow sm:rounded-lg sm:px-12">
43
51
  <form class="space-y-6" @submit="onSubmit($event)">
44
52
  <div>
45
- <label for="name" class="block text-sm text-gray-900 dark:text-gray-100 font-medium leading-6">
53
+ <label for="name" class="block text-sm text-fg font-medium leading-6">
46
54
  Full Name
47
55
  </label>
48
56
  <div class="mt-2">
@@ -52,13 +60,13 @@ function onSubmit(event) {
52
60
  type="text"
53
61
  autocomplete="name"
54
62
  required
55
- class="block w-full border-0 rounded-md p-2 py-1.5 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset sm:text-sm placeholder:text-gray-400 dark:placeholder:text-gray-500 sm:leading-6 focus:ring-2 focus:ring-teal-600 focus:ring-inset dark:bg-blue-gray-700"
63
+ class="block w-full border-0 rounded-md p-2 py-1.5 text-fg shadow-sm ring-1 ring-line-strong ring-inset sm:text-sm placeholder:text-fg-subtle sm:leading-6 focus:ring-2 focus:ring-teal-600 focus:ring-inset dark:bg-blue-gray-700"
56
64
  />
57
65
  </div>
58
66
  </div>
59
67
 
60
68
  <div>
61
- <label for="email" class="block text-sm text-gray-900 dark:text-gray-100 font-medium leading-6">
69
+ <label for="email" class="block text-sm text-fg font-medium leading-6">
62
70
  Email address
63
71
  </label>
64
72
  <div class="mt-2">
@@ -68,13 +76,13 @@ function onSubmit(event) {
68
76
  type="email"
69
77
  autocomplete="email"
70
78
  required
71
- class="block w-full border-0 rounded-md p-2 py-1.5 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset sm:text-sm placeholder:text-gray-400 dark:placeholder:text-gray-500 sm:leading-6 focus:ring-2 focus:ring-teal-600 focus:ring-inset dark:bg-blue-gray-700"
79
+ class="block w-full border-0 rounded-md p-2 py-1.5 text-fg shadow-sm ring-1 ring-line-strong ring-inset sm:text-sm placeholder:text-fg-subtle sm:leading-6 focus:ring-2 focus:ring-teal-600 focus:ring-inset dark:bg-blue-gray-700"
72
80
  />
73
81
  </div>
74
82
  </div>
75
83
 
76
84
  <div>
77
- <label for="confirm_email" class="block text-sm text-gray-900 dark:text-gray-100 font-medium leading-6">
85
+ <label for="confirm_email" class="block text-sm text-fg font-medium leading-6">
78
86
  Confirm Email
79
87
  </label>
80
88
  <div class="mt-2">
@@ -84,13 +92,13 @@ function onSubmit(event) {
84
92
  type="email"
85
93
  autocomplete="email"
86
94
  required
87
- class="block w-full border-0 rounded-md p-2 py-1.5 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset sm:text-sm placeholder:text-gray-400 dark:placeholder:text-gray-500 sm:leading-6 focus:ring-2 focus:ring-teal-600 focus:ring-inset dark:bg-blue-gray-700"
95
+ class="block w-full border-0 rounded-md p-2 py-1.5 text-fg shadow-sm ring-1 ring-line-strong ring-inset sm:text-sm placeholder:text-fg-subtle sm:leading-6 focus:ring-2 focus:ring-teal-600 focus:ring-inset dark:bg-blue-gray-700"
88
96
  />
89
97
  </div>
90
98
  </div>
91
99
 
92
100
  <div>
93
- <label for="password" class="block text-sm text-gray-900 dark:text-gray-100 font-medium leading-6">
101
+ <label for="password" class="block text-sm text-fg font-medium leading-6">
94
102
  Password
95
103
  </label>
96
104
  <div class="mt-2">
@@ -100,7 +108,7 @@ function onSubmit(event) {
100
108
  type="password"
101
109
  autocomplete="new-password"
102
110
  required
103
- class="block w-full border-0 rounded-md p-2 py-1.5 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset sm:text-sm placeholder:text-gray-400 dark:placeholder:text-gray-500 sm:leading-6 focus:ring-2 focus:ring-teal-600 focus:ring-inset dark:bg-blue-gray-700"
111
+ class="block w-full border-0 rounded-md p-2 py-1.5 text-fg shadow-sm ring-1 ring-line-strong ring-inset sm:text-sm placeholder:text-fg-subtle sm:leading-6 focus:ring-2 focus:ring-teal-600 focus:ring-inset dark:bg-blue-gray-700"
104
112
  />
105
113
  </div>
106
114
  </div>
@@ -119,19 +127,20 @@ function onSubmit(event) {
119
127
  <div>
120
128
  <div class="relative mt-10">
121
129
  <div class="absolute inset-0 flex items-center" aria-hidden="true">
122
- <div class="w-full border-t border-gray-200 dark:border-gray-600"></div>
130
+ <div class="w-full border-t border-line"></div>
123
131
  </div>
124
132
  <div class="relative flex justify-center text-sm font-medium leading-6">
125
- <span class="bg-white dark:bg-blue-gray-800 px-6 text-gray-900 dark:text-gray-100">
133
+ <span class="bg-white dark:bg-blue-gray-800 px-6 text-fg">
126
134
  Or signup with
127
135
  </span>
128
136
  </div>
129
137
  </div>
130
138
 
131
139
  <div class="grid grid-cols-2 mt-6 gap-4">
132
- <a
133
- href="#"
134
- class="w-full flex items-center justify-center gap-3 rounded-md bg-white dark:bg-blue-gray-700 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 font-semibold shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:ring-transparent"
140
+ <button
141
+ type="button"
142
+ @click="onSocial('google')"
143
+ class="w-full flex items-center justify-center gap-3 rounded-md bg-white dark:bg-blue-gray-700 px-3 py-2 text-sm text-fg font-semibold shadow-sm ring-1 ring-line-strong ring-inset hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:ring-transparent"
135
144
  >
136
145
  <svg class="h-5 w-5" viewBox="0 0 24 24" aria-hidden="true">
137
146
  <path d="M12.0003 4.75C13.7703 4.75 15.3553 5.36002 16.6053 6.54998L20.0303 3.125C17.9502 1.19 15.2353 0 12.0003 0C7.31028 0 3.25527 2.69 1.28027 6.60998L5.27028 9.70498C6.21525 6.86002 8.87028 4.75 12.0003 4.75Z" fill="#EA4335" />
@@ -140,17 +149,18 @@ function onSubmit(event) {
140
149
  <path d="M12.0004 24.0001C15.2404 24.0001 17.9654 22.935 19.9454 21.095L16.0804 18.095C15.0054 18.82 13.6204 19.245 12.0004 19.245C8.8704 19.245 6.21537 17.135 5.2654 14.29L1.27539 17.385C3.25539 21.31 7.3104 24.0001 12.0004 24.0001Z" fill="#34A853" />
141
150
  </svg>
142
151
  <span class="text-sm font-semibold leading-6">Google</span>
143
- </a>
152
+ </button>
144
153
 
145
- <a
146
- href="#"
147
- class="w-full flex items-center justify-center gap-3 rounded-md bg-white dark:bg-blue-gray-700 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 font-semibold shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:ring-transparent"
154
+ <button
155
+ type="button"
156
+ @click="onSocial('github')"
157
+ class="w-full flex items-center justify-center gap-3 rounded-md bg-white dark:bg-blue-gray-700 px-3 py-2 text-sm text-fg font-semibold shadow-sm ring-1 ring-line-strong ring-inset hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:ring-transparent"
148
158
  >
149
159
  <svg class="h-5 w-5 fill-[#24292F] dark:fill-white" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
150
160
  <path fill-rule="evenodd" d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z" clip-rule="evenodd" />
151
161
  </svg>
152
162
  <span class="text-sm font-semibold leading-6">GitHub</span>
153
- </a>
163
+ </button>
154
164
  </div>
155
165
  </div>
156
166
  @endif
@@ -33,7 +33,7 @@ if (height) {
33
33
  styleString += `height: ${typeof height === 'number' ? height + 'px' : height};`
34
34
  }
35
35
 
36
- export const skeletonClasses = `bg-gray-200 dark:bg-gray-700 ${baseClasses} ${animationClasses} ${className}`.trim()
36
+ export const skeletonClasses = `bg-surface-sunken ${baseClasses} ${animationClasses} ${className}`.trim()
37
37
  export const containerClasses = count > 1 ? 'space-y-3' : ''
38
38
  </script>
39
39