@opencode/ui 2.0.22 → 2.0.24

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 (82) hide show
  1. package/dist/data-display/accordion/accordion.d.ts +3 -1
  2. package/dist/feedback/toast/toast.d.ts +3 -2
  3. package/dist/i18n/en.d.ts +5 -0
  4. package/dist/icons/catalog.d.ts +257 -0
  5. package/dist/icons/icon/additional-icons.d.ts +1 -0
  6. package/dist/icons/icon/icon.d.ts +1 -237
  7. package/package.json +5 -1
  8. package/src/actions/button/button.tsx +1 -0
  9. package/src/actions/icon-button/icon-button.tsx +1 -0
  10. package/src/actions/split-button/split-button.tsx +3 -0
  11. package/src/components/animated-number.tsx +13 -0
  12. package/src/components/app-icon.tsx +2 -0
  13. package/src/components/card.tsx +21 -0
  14. package/src/components/collapsible.tsx +1 -0
  15. package/src/components/context-menu.tsx +34 -0
  16. package/src/components/dock-surface.tsx +3 -0
  17. package/src/components/file-icon.tsx +12 -0
  18. package/src/components/image-preview.tsx +1 -0
  19. package/src/components/list.tsx +32 -0
  20. package/src/components/motion-spring.tsx +5 -0
  21. package/src/components/popover.tsx +12 -0
  22. package/src/components/provider-icon.tsx +1 -0
  23. package/src/components/resize-handle.tsx +8 -0
  24. package/src/components/scroll-view.tsx +39 -0
  25. package/src/components/spinner.tsx +2 -0
  26. package/src/components/text-field.tsx +6 -0
  27. package/src/components/text-reveal.tsx +19 -0
  28. package/src/components/text-strikethrough.tsx +8 -0
  29. package/src/components/typewriter.tsx +4 -0
  30. package/src/context/dialog.tsx +12 -0
  31. package/src/context/file.tsx +1 -0
  32. package/src/context/helper.tsx +4 -0
  33. package/src/context/i18n.tsx +20 -0
  34. package/src/context/index.ts +3 -0
  35. package/src/context/marked-base.tsx +7 -0
  36. package/src/context/marked-parser.tsx +7 -0
  37. package/src/context/marked.tsx +3 -0
  38. package/src/context/worker-pool.tsx +2 -0
  39. package/src/data-display/accordion/accordion.tsx +16 -2
  40. package/src/data-display/avatar/avatar.tsx +4 -0
  41. package/src/data-display/badge/badge.tsx +1 -0
  42. package/src/data-display/diff-changes/diff-changes.tsx +2 -0
  43. package/src/data-display/keybind/keybind.tsx +1 -0
  44. package/src/data-display/line-comment/line-comment.tsx +22 -0
  45. package/src/data-display/project-avatar/project-avatar.tsx +10 -0
  46. package/src/feedback/loader/loader.tsx +1 -0
  47. package/src/feedback/toast/description.ts +1 -0
  48. package/src/feedback/toast/toast.tsx +32 -6
  49. package/src/forms/checkbox/checkbox.tsx +1 -0
  50. package/src/forms/field/field.tsx +8 -0
  51. package/src/forms/inline-input/inline-input.tsx +4 -0
  52. package/src/forms/radio/radio.tsx +2 -0
  53. package/src/forms/select/select.tsx +11 -0
  54. package/src/forms/switch/switch.tsx +1 -0
  55. package/src/forms/text-input/text-input.tsx +3 -0
  56. package/src/hooks/create-auto-scroll.tsx +34 -0
  57. package/src/hooks/index.ts +1 -0
  58. package/src/hooks/use-filtered-list.tsx +14 -0
  59. package/src/i18n/en.ts +10 -0
  60. package/src/i18n/no.ts +1 -0
  61. package/src/icons/catalog.ts +273 -0
  62. package/src/icons/icon/additional-icons.ts +1 -0
  63. package/src/icons/icon/icon.tsx +10 -250
  64. package/src/layout/divider/divider.tsx +1 -0
  65. package/src/navigation/menu/menu.tsx +13 -0
  66. package/src/navigation/segmented-control/segmented-control.tsx +16 -0
  67. package/src/navigation/tab-state-indicator.tsx +1 -0
  68. package/src/navigation/tabs/tabs.css +6 -72
  69. package/src/navigation/tabs/tabs.tsx +18 -0
  70. package/src/overlays/dialog/dialog.tsx +3 -0
  71. package/src/overlays/tooltip/tooltip.tsx +15 -0
  72. package/src/storybook/scaffold.tsx +3 -0
  73. package/src/styles/theme.css +1 -1
  74. package/src/theme/color.ts +27 -0
  75. package/src/theme/context.tsx +58 -0
  76. package/src/theme/default-themes.ts +35 -0
  77. package/src/theme/index.ts +3 -0
  78. package/src/theme/loader.ts +11 -0
  79. package/src/theme/resolve.ts +28 -0
  80. package/src/theme/v2/foreground.ts +8 -0
  81. package/src/theme/v2/resolve.ts +10 -0
  82. package/src/typography/text-shimmer/text-shimmer.tsx +1 -0
@@ -1,6 +1,8 @@
1
1
  import { Content, Header, Item, Root, Trigger } from "@kobalte/core/accordion";
2
2
  import type { ComponentProps, ParentProps } from "solid-js";
3
- export interface AccordionProps extends ComponentProps<typeof Root> {
3
+ export interface AccordionProps extends Omit<ComponentProps<typeof Root>, "value"> {
4
+ /** Controlled expanded items. Kobalte reads this iterable into its own selection; it never mutates this array. */
5
+ value?: readonly string[];
4
6
  }
5
7
  export interface AccordionItemProps extends ComponentProps<typeof Item> {
6
8
  }
@@ -32,7 +32,7 @@ export declare const toaster: {
32
32
  duration?: number;
33
33
  persistent?: boolean;
34
34
  /** Reactive value the toast's height depends on; sonner re-measures when it changes. */
35
- resize?: () => unknown;
35
+ resize?: () => void;
36
36
  }): number;
37
37
  dismiss(toastId?: number): string | number | undefined;
38
38
  };
@@ -44,7 +44,8 @@ export interface ToastAction {
44
44
  export interface ToastOptions {
45
45
  title?: string;
46
46
  description?: string;
47
- icon?: JSX.Element;
47
+ /** An element, or a render function the toast calls under its own owner, for icons created from imperative code. */
48
+ icon?: JSX.Element | (() => JSX.Element);
48
49
  variant?: "default" | "success" | "error" | "loading";
49
50
  duration?: number;
50
51
  persistent?: boolean;
package/dist/i18n/en.d.ts CHANGED
@@ -98,6 +98,7 @@ declare const source: {
98
98
  "ui.messagePart.questions.dismissed": string;
99
99
  "ui.messagePart.compaction": string;
100
100
  "ui.messagePart.compaction.started": string;
101
+ "ui.messagePart.compaction.queued": string;
101
102
  "ui.messagePart.compaction.running": string;
102
103
  "ui.messagePart.compaction.failed": string;
103
104
  "ui.messagePart.compaction.cancelled": string;
@@ -219,12 +220,16 @@ declare const source: {
219
220
  "ui.message.copyMessage": string;
220
221
  "ui.message.forkMessage": string;
221
222
  "ui.message.revertMessage": string;
223
+ "ui.message.moveToQueue": string;
224
+ "ui.message.pending": string;
225
+ "ui.message.deletePending": string;
222
226
  "ui.message.copyResponse": string;
223
227
  "ui.message.copied": string;
224
228
  "ui.message.thought": string;
225
229
  "ui.message.duration.seconds": string;
226
230
  "ui.message.duration.minutesSeconds": string;
227
231
  "ui.message.interrupted": string;
232
+ "ui.message.modelVariant": string;
228
233
  "ui.sessionTimeline.notice.model": string;
229
234
  "ui.sessionTimeline.notice.modelSwitched": string;
230
235
  "ui.sessionTimeline.notice.agentChanged": string;
@@ -0,0 +1,257 @@
1
+ import { additionalIcons } from "./icon/additional-icons";
2
+ declare const icons: {
3
+ lock: {
4
+ viewBox: string;
5
+ body: string;
6
+ };
7
+ globe: {
8
+ viewBox: string;
9
+ body: string;
10
+ };
11
+ "select-element": {
12
+ viewBox: string;
13
+ body: string;
14
+ };
15
+ flask: {
16
+ viewBox: string;
17
+ body: string;
18
+ };
19
+ edit: {
20
+ viewBox: string;
21
+ body: string;
22
+ };
23
+ "folder-add-left": {
24
+ viewBox: string;
25
+ body: string;
26
+ };
27
+ folder: {
28
+ viewBox: string;
29
+ body: string;
30
+ };
31
+ branch: {
32
+ viewBox: string;
33
+ body: string;
34
+ };
35
+ "branch-out": {
36
+ viewBox: string;
37
+ body: string;
38
+ };
39
+ "grid-plus": {
40
+ viewBox: string;
41
+ body: string;
42
+ };
43
+ help: {
44
+ viewBox: string;
45
+ body: string;
46
+ };
47
+ info: {
48
+ viewBox: string;
49
+ body: string;
50
+ };
51
+ "circle-exclamation": {
52
+ viewBox: string;
53
+ body: string;
54
+ };
55
+ "circle-xmark": {
56
+ viewBox: string;
57
+ body: string;
58
+ };
59
+ "sidebar-right": {
60
+ viewBox: string;
61
+ body: string;
62
+ };
63
+ status: {
64
+ viewBox: string;
65
+ body: string;
66
+ };
67
+ "status-active": {
68
+ viewBox: string;
69
+ body: string;
70
+ };
71
+ "magnifying-glass": {
72
+ viewBox: string;
73
+ body: string;
74
+ };
75
+ menu: {
76
+ viewBox: string;
77
+ body: string;
78
+ };
79
+ plus: {
80
+ viewBox: string;
81
+ body: string;
82
+ };
83
+ "settings-gear": {
84
+ viewBox: string;
85
+ body: string;
86
+ };
87
+ "chevron-down": {
88
+ viewBox: string;
89
+ body: string;
90
+ };
91
+ collapse: {
92
+ viewBox: string;
93
+ body: string;
94
+ };
95
+ check: {
96
+ viewBox: string;
97
+ body: string;
98
+ };
99
+ monitor: {
100
+ viewBox: string;
101
+ body: string;
102
+ };
103
+ "workspace-new": {
104
+ viewBox: string;
105
+ body: string;
106
+ };
107
+ "workspace-isolated": {
108
+ viewBox: string;
109
+ body: string;
110
+ };
111
+ workspace: {
112
+ viewBox: string;
113
+ body: string;
114
+ };
115
+ "outline-worktree": {
116
+ viewBox: string;
117
+ body: string;
118
+ };
119
+ "outline-trash": {
120
+ viewBox: string;
121
+ body: string;
122
+ };
123
+ close: {
124
+ viewBox: string;
125
+ body: string;
126
+ };
127
+ "xmark-small": {
128
+ viewBox: string;
129
+ body: string;
130
+ };
131
+ "outline-xmark": {
132
+ viewBox: string;
133
+ body: string;
134
+ };
135
+ "outline-chevron-down": {
136
+ viewBox: string;
137
+ body: string;
138
+ };
139
+ "outline-dots": {
140
+ viewBox: string;
141
+ body: string;
142
+ };
143
+ expand: {
144
+ viewBox: string;
145
+ body: string;
146
+ };
147
+ filetree: {
148
+ viewBox: string;
149
+ body: string;
150
+ };
151
+ split: {
152
+ viewBox: string;
153
+ body: string;
154
+ };
155
+ unified: {
156
+ viewBox: string;
157
+ body: string;
158
+ };
159
+ review: {
160
+ viewBox: string;
161
+ body: string;
162
+ };
163
+ "window-analytics": {
164
+ viewBox: string;
165
+ body: string;
166
+ };
167
+ "graduation-cap": {
168
+ viewBox: string;
169
+ body: string;
170
+ };
171
+ "code-slash": {
172
+ viewBox: string;
173
+ body: string;
174
+ };
175
+ trash: {
176
+ viewBox: string;
177
+ body: string;
178
+ };
179
+ "outline-sliders": {
180
+ viewBox: string;
181
+ body: string;
182
+ };
183
+ "outline-copy": {
184
+ viewBox: string;
185
+ body: string;
186
+ };
187
+ "arrow-up-right": {
188
+ viewBox: string;
189
+ body: string;
190
+ };
191
+ "outline-square-arrow": {
192
+ viewBox: string;
193
+ body: string;
194
+ };
195
+ "outline-arrow-to-corner-top-right": {
196
+ viewBox: string;
197
+ body: string;
198
+ };
199
+ "outline-hexagonal-warning": {
200
+ viewBox: string;
201
+ body: string;
202
+ };
203
+ "outline-share": {
204
+ viewBox: string;
205
+ body: string;
206
+ };
207
+ "outline-eye": {
208
+ viewBox: string;
209
+ body: string;
210
+ };
211
+ "outline-eye-slash": {
212
+ viewBox: string;
213
+ body: string;
214
+ };
215
+ refresh: {
216
+ viewBox: string;
217
+ body: string;
218
+ };
219
+ reset: {
220
+ viewBox: string;
221
+ body: string;
222
+ };
223
+ "outline-undo": {
224
+ viewBox: string;
225
+ body: string;
226
+ };
227
+ "outline-reset": {
228
+ viewBox: string;
229
+ body: string;
230
+ };
231
+ "fill-triangle-down": {
232
+ viewBox: string;
233
+ body: string;
234
+ };
235
+ archive: {
236
+ viewBox: string;
237
+ body: string;
238
+ };
239
+ };
240
+ /** Icon names derived from the shared artwork, with no UI or runtime dependencies. */
241
+ export type IconName = keyof typeof icons | keyof typeof additionalIcons;
242
+ /** The artwork catalog's names, in sprite order. */
243
+ export declare function iconNames(): IconName[];
244
+ /**
245
+ * Narrows a name against the shared artwork catalog.
246
+ * @param name - A name supplied by a caller, including names unknown to this build.
247
+ */
248
+ export declare function isIconName(name: string): name is IconName;
249
+ /**
250
+ * The SVG body and viewport for a known catalog name, with primary artwork taking precedence.
251
+ * @param name - A name validated by the type or by `isIconName`.
252
+ */
253
+ export declare function getIcon(name: IconName): {
254
+ viewBox: string;
255
+ body: string;
256
+ };
257
+ export {};
@@ -1,3 +1,4 @@
1
+ /** Additional UI artwork, independent of a renderer. */
1
2
  export declare const additionalIcons: {
2
3
  "align-right": string;
3
4
  "arrow-up": string;
@@ -1,244 +1,8 @@
1
1
  import { type ComponentProps } from "solid-js";
2
- import { additionalIcons } from "./additional-icons";
2
+ import { type IconName } from "../catalog";
3
3
  import "./icon.css";
4
- declare const icons: {
5
- lock: {
6
- viewBox: string;
7
- body: string;
8
- };
9
- globe: {
10
- viewBox: string;
11
- body: string;
12
- };
13
- "select-element": {
14
- viewBox: string;
15
- body: string;
16
- };
17
- flask: {
18
- viewBox: string;
19
- body: string;
20
- };
21
- edit: {
22
- viewBox: string;
23
- body: string;
24
- };
25
- "folder-add-left": {
26
- viewBox: string;
27
- body: string;
28
- };
29
- folder: {
30
- viewBox: string;
31
- body: string;
32
- };
33
- branch: {
34
- viewBox: string;
35
- body: string;
36
- };
37
- "branch-out": {
38
- viewBox: string;
39
- body: string;
40
- };
41
- "grid-plus": {
42
- viewBox: string;
43
- body: string;
44
- };
45
- help: {
46
- viewBox: string;
47
- body: string;
48
- };
49
- info: {
50
- viewBox: string;
51
- body: string;
52
- };
53
- "circle-exclamation": {
54
- viewBox: string;
55
- body: string;
56
- };
57
- "circle-xmark": {
58
- viewBox: string;
59
- body: string;
60
- };
61
- "sidebar-right": {
62
- viewBox: string;
63
- body: string;
64
- };
65
- status: {
66
- viewBox: string;
67
- body: string;
68
- };
69
- "status-active": {
70
- viewBox: string;
71
- body: string;
72
- };
73
- "magnifying-glass": {
74
- viewBox: string;
75
- body: string;
76
- };
77
- menu: {
78
- viewBox: string;
79
- body: string;
80
- };
81
- plus: {
82
- viewBox: string;
83
- body: string;
84
- };
85
- "settings-gear": {
86
- viewBox: string;
87
- body: string;
88
- };
89
- "chevron-down": {
90
- viewBox: string;
91
- body: string;
92
- };
93
- collapse: {
94
- viewBox: string;
95
- body: string;
96
- };
97
- check: {
98
- viewBox: string;
99
- body: string;
100
- };
101
- monitor: {
102
- viewBox: string;
103
- body: string;
104
- };
105
- "workspace-new": {
106
- viewBox: string;
107
- body: string;
108
- };
109
- "workspace-isolated": {
110
- viewBox: string;
111
- body: string;
112
- };
113
- workspace: {
114
- viewBox: string;
115
- body: string;
116
- };
117
- "outline-worktree": {
118
- viewBox: string;
119
- body: string;
120
- };
121
- "outline-trash": {
122
- viewBox: string;
123
- body: string;
124
- };
125
- close: {
126
- viewBox: string;
127
- body: string;
128
- };
129
- "xmark-small": {
130
- viewBox: string;
131
- body: string;
132
- };
133
- "outline-xmark": {
134
- viewBox: string;
135
- body: string;
136
- };
137
- "outline-chevron-down": {
138
- viewBox: string;
139
- body: string;
140
- };
141
- "outline-dots": {
142
- viewBox: string;
143
- body: string;
144
- };
145
- expand: {
146
- viewBox: string;
147
- body: string;
148
- };
149
- filetree: {
150
- viewBox: string;
151
- body: string;
152
- };
153
- split: {
154
- viewBox: string;
155
- body: string;
156
- };
157
- unified: {
158
- viewBox: string;
159
- body: string;
160
- };
161
- review: {
162
- viewBox: string;
163
- body: string;
164
- };
165
- "window-analytics": {
166
- viewBox: string;
167
- body: string;
168
- };
169
- "graduation-cap": {
170
- viewBox: string;
171
- body: string;
172
- };
173
- "code-slash": {
174
- viewBox: string;
175
- body: string;
176
- };
177
- trash: {
178
- viewBox: string;
179
- body: string;
180
- };
181
- "outline-sliders": {
182
- viewBox: string;
183
- body: string;
184
- };
185
- "outline-copy": {
186
- viewBox: string;
187
- body: string;
188
- };
189
- "arrow-up-right": {
190
- viewBox: string;
191
- body: string;
192
- };
193
- "outline-square-arrow": {
194
- viewBox: string;
195
- body: string;
196
- };
197
- "outline-arrow-to-corner-top-right": {
198
- viewBox: string;
199
- body: string;
200
- };
201
- "outline-hexagonal-warning": {
202
- viewBox: string;
203
- body: string;
204
- };
205
- "outline-share": {
206
- viewBox: string;
207
- body: string;
208
- };
209
- "outline-eye": {
210
- viewBox: string;
211
- body: string;
212
- };
213
- "outline-eye-slash": {
214
- viewBox: string;
215
- body: string;
216
- };
217
- refresh: {
218
- viewBox: string;
219
- body: string;
220
- };
221
- reset: {
222
- viewBox: string;
223
- body: string;
224
- };
225
- "outline-reset": {
226
- viewBox: string;
227
- body: string;
228
- };
229
- "fill-triangle-down": {
230
- viewBox: string;
231
- body: string;
232
- };
233
- archive: {
234
- viewBox: string;
235
- body: string;
236
- };
237
- };
238
- type IconName = keyof typeof icons | keyof typeof additionalIcons;
239
4
  export interface IconProps extends ComponentProps<"svg"> {
240
5
  name: IconName | (string & {});
241
6
  size?: "small" | "normal" | "large";
242
7
  }
243
8
  export declare function Icon(props: IconProps): import("solid-js").JSX.Element;
244
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencode/ui",
3
- "version": "2.0.22",
3
+ "version": "2.0.24",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -76,6 +76,10 @@
76
76
  "types": "./dist/icons/icon/icon.d.ts",
77
77
  "import": "./src/icons/icon/icon.tsx"
78
78
  },
79
+ "./icons/catalog": {
80
+ "types": "./dist/icons/catalog.d.ts",
81
+ "import": "./src/icons/catalog.ts"
82
+ },
79
83
  "./icon-button": {
80
84
  "types": "./dist/actions/icon-button/icon-button.d.ts",
81
85
  "import": "./src/actions/icon-button/icon-button.tsx"
@@ -23,6 +23,7 @@ export interface ButtonProps
23
23
 
24
24
  export function Button(props: ButtonProps) {
25
25
  const [split, rest] = splitProps(props, ["variant", "size", "icon", "class", "classList"])
26
+
26
27
  return (
27
28
  <Root
28
29
  {...rest}
@@ -14,6 +14,7 @@ export interface IconButtonProps
14
14
 
15
15
  export function IconButton(props: ComponentProps<"button"> & IconButtonProps) {
16
16
  const [local, rest] = splitProps(props, ["variant", "size", "icon", "class", "classList", "state"])
17
+
17
18
  return (
18
19
  <Root
19
20
  {...rest}
@@ -3,6 +3,7 @@ import "./split-button.css"
3
3
 
4
4
  export function SplitButton(props: ParentProps<ComponentProps<"div">>) {
5
5
  const [split, rest] = splitProps(props, ["class", "classList", "children"])
6
+
6
7
  return (
7
8
  <div
8
9
  data-component="split-button-v2"
@@ -19,6 +20,7 @@ export function SplitButton(props: ParentProps<ComponentProps<"div">>) {
19
20
 
20
21
  export function SplitButtonAction(props: ComponentProps<"button">) {
21
22
  const [split, rest] = splitProps(props, ["class", "classList"])
23
+
22
24
  return (
23
25
  <button
24
26
  type="button"
@@ -34,6 +36,7 @@ export function SplitButtonAction(props: ComponentProps<"button">) {
34
36
 
35
37
  export function SplitButtonMenuTrigger(props: ComponentProps<"button">) {
36
38
  const [split, rest] = splitProps(props, ["class", "classList"])
39
+
37
40
  return (
38
41
  <button
39
42
  type="button"
@@ -2,6 +2,7 @@ import { For, Index, createEffect, createMemo, on } from "solid-js"
2
2
  import { createStore } from "solid-js/store"
3
3
 
4
4
  const TRACK = Array.from({ length: 30 }, (_, index) => index % 10)
5
+
5
6
  const DURATION = 600
6
7
 
7
8
  function normalize(value: number) {
@@ -10,7 +11,9 @@ function normalize(value: number) {
10
11
 
11
12
  function spin(from: number, to: number, direction: 1 | -1) {
12
13
  if (from === to) return 0
14
+
13
15
  if (direction > 0) return (to - from + 10) % 10
16
+
14
17
  return -((from - to + 10) % 10)
15
18
  }
16
19
 
@@ -19,6 +22,7 @@ function Digit(props: { value: number; direction: 1 | -1 }) {
19
22
  step: props.value + 10,
20
23
  animating: false,
21
24
  })
25
+
22
26
  const step = () => state.step
23
27
  const animating = () => state.animating
24
28
  let last = props.value
@@ -29,9 +33,11 @@ function Digit(props: { value: number; direction: 1 | -1 }) {
29
33
  (next) => {
30
34
  const delta = spin(last, next, props.direction)
31
35
  last = next
36
+
32
37
  if (!delta) {
33
38
  setState("animating", false)
34
39
  setState("step", next + 10)
40
+
35
41
  return
36
42
  }
37
43
 
@@ -65,6 +71,7 @@ function Digit(props: { value: number; direction: 1 | -1 }) {
65
71
  export function AnimatedNumber(props: { value: number; class?: string }) {
66
72
  const target = createMemo(() => {
67
73
  if (!Number.isFinite(props.value)) return 0
74
+
68
75
  return Math.max(0, Math.round(props.value))
69
76
  })
70
77
 
@@ -72,6 +79,7 @@ export function AnimatedNumber(props: { value: number; class?: string }) {
72
79
  value: target(),
73
80
  direction: 1 as 1 | -1,
74
81
  })
82
+
75
83
  const value = () => state.value
76
84
  const direction = () => state.direction
77
85
 
@@ -80,6 +88,7 @@ export function AnimatedNumber(props: { value: number; class?: string }) {
80
88
  target,
81
89
  (next) => {
82
90
  const current = value()
91
+
83
92
  if (next === current) return
84
93
 
85
94
  setState("direction", next > current ? 1 : -1)
@@ -90,13 +99,17 @@ export function AnimatedNumber(props: { value: number; class?: string }) {
90
99
  )
91
100
 
92
101
  const label = createMemo(() => value().toString())
102
+
93
103
  const digits = createMemo(() =>
94
104
  Array.from(label(), (char) => {
95
105
  const code = char.charCodeAt(0) - 48
106
+
96
107
  if (code < 0 || code > 9) return 0
108
+
97
109
  return code
98
110
  }).reverse(),
99
111
  )
112
+
100
113
  const width = createMemo(() => `${digits().length}ch`)
101
114
 
102
115
  return (
@@ -46,7 +46,9 @@ const themed: Partial<Record<IconName, { light: string; dark: string }>> = {
46
46
 
47
47
  const scheme = () => {
48
48
  if (typeof document !== "object") return "light" as const
49
+
49
50
  if (document.documentElement.dataset.colorScheme === "dark") return "dark" as const
51
+
50
52
  return "light" as const
51
53
  }
52
54