@adea-ai/ui 0.99.1 → 0.99.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/layout/orbit-layout/orbit-layout.d.ts +5 -1
- package/dist/components/layout/orbit-layout/orbit-layout.d.ts.map +1 -1
- package/dist/components/layout/orbit-layout/orbit-layout.js.map +1 -1
- package/dist/components/layout/side-rail/side-rail.d.ts +4 -1
- package/dist/components/layout/side-rail/side-rail.d.ts.map +1 -1
- package/dist/components/layout/side-rail/side-rail.js +58 -64
- package/dist/components/layout/side-rail/side-rail.js.map +1 -1
- package/dist/components/layout/sidebar-nav/sidebar-nav.js +2 -2
- package/dist/components/layout/sidebar-nav/sidebar-nav.js.map +1 -1
- package/dist/components/motion/presence.d.ts +17 -7
- package/dist/components/motion/presence.d.ts.map +1 -1
- package/dist/components/motion/presence.js.map +1 -1
- package/dist/components/theme/theme-picker.d.ts.map +1 -1
- package/dist/components/theme/theme-picker.js +1 -1
- package/dist/components/theme/theme-picker.js.map +1 -1
- package/dist/components/theme/theme-provider.d.ts.map +1 -1
- package/dist/components/theme/theme-provider.js +15 -4
- package/dist/components/theme/theme-provider.js.map +1 -1
- package/dist/components/ui/aspect-ratio/aspect-ratio.d.ts +2 -2
- package/dist/components/ui/aspect-ratio/aspect-ratio.d.ts.map +1 -1
- package/dist/components/ui/aspect-ratio/aspect-ratio.js +15 -1
- package/dist/components/ui/aspect-ratio/aspect-ratio.js.map +1 -1
- package/dist/components/ui/badge/badge.d.ts +1 -1
- package/dist/components/ui/button/button.d.ts +1 -1
- package/dist/components/ui/calendar/calendar.d.ts.map +1 -1
- package/dist/components/ui/calendar/calendar.js +1 -1
- package/dist/components/ui/calendar/calendar.js.map +1 -1
- package/dist/components/ui/card/card.d.ts +2 -2
- package/dist/components/ui/card/card.js +2 -2
- package/dist/components/ui/card/card.js.map +1 -1
- package/dist/components/ui/chart/chart-options.d.ts +50 -0
- package/dist/components/ui/chart/chart-options.d.ts.map +1 -0
- package/dist/components/ui/chart/chart-options.js +178 -0
- package/dist/components/ui/chart/chart-options.js.map +1 -0
- package/dist/components/ui/chart/chart.d.ts +21 -18
- package/dist/components/ui/chart/chart.d.ts.map +1 -1
- package/dist/components/ui/chart/chart.js +175 -155
- package/dist/components/ui/chart/chart.js.map +1 -1
- package/dist/components/ui/chart/index.js +2 -1
- package/dist/components/ui/context-menu/context-menu.d.ts +8 -0
- package/dist/components/ui/context-menu/context-menu.d.ts.map +1 -1
- package/dist/components/ui/context-menu/context-menu.js +8 -0
- package/dist/components/ui/context-menu/context-menu.js.map +1 -1
- package/dist/components/ui/drawer/drawer.d.ts +8 -1
- package/dist/components/ui/drawer/drawer.d.ts.map +1 -1
- package/dist/components/ui/drawer/drawer.js.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts +8 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.js +8 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
- package/dist/components/ui/input-otp/input-otp.d.ts.map +1 -1
- package/dist/components/ui/input-otp/input-otp.js +2 -2
- package/dist/components/ui/input-otp/input-otp.js.map +1 -1
- package/dist/components/ui/menubar/menubar.d.ts +8 -0
- package/dist/components/ui/menubar/menubar.d.ts.map +1 -1
- package/dist/components/ui/menubar/menubar.js +8 -0
- package/dist/components/ui/menubar/menubar.js.map +1 -1
- package/dist/components/ui/navigation-menu/navigation-menu.d.ts +14 -2
- package/dist/components/ui/navigation-menu/navigation-menu.d.ts.map +1 -1
- package/dist/components/ui/navigation-menu/navigation-menu.js +28 -23
- package/dist/components/ui/navigation-menu/navigation-menu.js.map +1 -1
- package/dist/components/ui/pagination/pagination.d.ts.map +1 -1
- package/dist/components/ui/pagination/pagination.js +1 -1
- package/dist/components/ui/pagination/pagination.js.map +1 -1
- package/dist/components/ui/resizable/resizable.d.ts +0 -12
- package/dist/components/ui/resizable/resizable.d.ts.map +1 -1
- package/dist/components/ui/resizable/resizable.js +43 -9
- package/dist/components/ui/resizable/resizable.js.map +1 -1
- package/dist/components/ui/toast/toast.d.ts.map +1 -1
- package/dist/components/ui/toast/toast.js +19 -6
- package/dist/components/ui/toast/toast.js.map +1 -1
- package/dist/lib/cn-tables.generated.js +10 -10
- package/dist/lib/cn-tables.generated.js.map +1 -1
- package/dist/r/chart.json +5 -0
- package/dist/r/registry.json +5 -0
- package/dist/r/src/components/layout/orbit-layout/orbit-layout.tsx +5 -1
- package/dist/r/src/components/layout/side-rail/side-rail.tsx +29 -16
- package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +2 -2
- package/dist/r/src/components/motion/presence.tsx +17 -7
- package/dist/r/src/components/theme/theme-picker.tsx +5 -1
- package/dist/r/src/components/theme/theme-provider.tsx +19 -9
- package/dist/r/src/components/ui/aspect-ratio/aspect-ratio.tsx +14 -3
- package/dist/r/src/components/ui/calendar/calendar.tsx +6 -1
- package/dist/r/src/components/ui/card/card.tsx +2 -2
- package/dist/r/src/components/ui/chart/chart-options.ts +196 -0
- package/dist/r/src/components/ui/chart/chart.tsx +149 -101
- package/dist/r/src/components/ui/context-menu/context-menu.tsx +8 -0
- package/dist/r/src/components/ui/drawer/drawer.tsx +8 -1
- package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +8 -0
- package/dist/r/src/components/ui/input-otp/input-otp.tsx +14 -2
- package/dist/r/src/components/ui/menubar/menubar.tsx +8 -0
- package/dist/r/src/components/ui/navigation-menu/navigation-menu.tsx +42 -28
- package/dist/r/src/components/ui/pagination/pagination.tsx +8 -1
- package/dist/r/src/components/ui/resizable/resizable.tsx +46 -8
- package/dist/r/src/components/ui/toast/toast.tsx +21 -6
- package/dist/r/src/lib/cn-tables.generated.ts +10 -10
- package/dist/r/src/styles/base.css +4 -1
- package/dist/r/src/styles/theme.css +23 -43
- package/package.json +1 -1
- package/registry.json +5 -0
- package/src/components/layout/orbit-layout/orbit-layout.tsx +5 -1
- package/src/components/layout/side-rail/side-rail.tsx +29 -16
- package/src/components/layout/sidebar-nav/sidebar-nav.tsx +2 -2
- package/src/components/motion/presence.tsx +17 -7
- package/src/components/theme/theme-picker.tsx +5 -1
- package/src/components/theme/theme-provider.tsx +19 -9
- package/src/components/ui/aspect-ratio/aspect-ratio.tsx +14 -3
- package/src/components/ui/calendar/calendar.tsx +6 -1
- package/src/components/ui/card/card.tsx +2 -2
- package/src/components/ui/chart/chart-options.ts +196 -0
- package/src/components/ui/chart/chart.tsx +149 -101
- package/src/components/ui/context-menu/context-menu.tsx +8 -0
- package/src/components/ui/drawer/drawer.tsx +8 -1
- package/src/components/ui/dropdown-menu/dropdown-menu.tsx +8 -0
- package/src/components/ui/input-otp/input-otp.tsx +14 -2
- package/src/components/ui/menubar/menubar.tsx +8 -0
- package/src/components/ui/navigation-menu/navigation-menu.tsx +42 -28
- package/src/components/ui/pagination/pagination.tsx +8 -1
- package/src/components/ui/resizable/resizable.tsx +46 -8
- package/src/components/ui/toast/toast.tsx +21 -6
- package/src/lib/cn-tables.generated.ts +10 -10
- package/src/styles/base.css +4 -1
- package/src/styles/theme.css +23 -43
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { For, splitProps, type JSX } from 'solid-js'
|
|
1
|
+
import { For, Show, createSignal, onCleanup, onMount, splitProps, type JSX } from 'solid-js'
|
|
2
2
|
import { Dynamic } from 'solid-js/web'
|
|
3
3
|
import { Bar, Bubble, Doughnut, Line, Pie, PolarArea, Radar, Scatter } from 'solid-chartjs'
|
|
4
4
|
import {
|
|
@@ -17,6 +17,13 @@ import {
|
|
|
17
17
|
} from 'chart.js'
|
|
18
18
|
import type { ChartOptions, ChartType } from 'chart.js'
|
|
19
19
|
import { cn } from '../../../lib/utils'
|
|
20
|
+
import {
|
|
21
|
+
chartOptions,
|
|
22
|
+
chartSeriesColors,
|
|
23
|
+
mergeChartOptions,
|
|
24
|
+
resolveCssVariables,
|
|
25
|
+
type ChartScaleShape,
|
|
26
|
+
} from './chart-options'
|
|
20
27
|
|
|
21
28
|
/**
|
|
22
29
|
* Chart.
|
|
@@ -46,11 +53,16 @@ import { cn } from '../../../lib/utils'
|
|
|
46
53
|
*
|
|
47
54
|
* ## Theming
|
|
48
55
|
*
|
|
49
|
-
* Colours
|
|
50
|
-
* defines,
|
|
51
|
-
* chart follows the accent axis
|
|
52
|
-
* per-chart configuration — and a caller that wants a
|
|
53
|
-
* passes it explicitly
|
|
56
|
+
* Colours come from `--chart-1` through `--chart-5`, which every theme
|
|
57
|
+
* defines, and the grid, ticks and labels from `--border` and
|
|
58
|
+
* `--muted-foreground`. That means a chart follows the accent axis and the
|
|
59
|
+
* appearance with no per-chart configuration — and a caller that wants a
|
|
60
|
+
* specific series colour passes it explicitly, as a colour or as `var(--token)`.
|
|
61
|
+
*
|
|
62
|
+
* A canvas cannot read a custom property, so the options and datasets carry
|
|
63
|
+
* `var(--token)` strings and each chart resolves them against its own element
|
|
64
|
+
* when it renders, and again whenever the root's attributes change — the
|
|
65
|
+
* `.dark` class, `data-accent`, an inline override. See `createThemeResolver`.
|
|
54
66
|
*/
|
|
55
67
|
|
|
56
68
|
/**
|
|
@@ -78,68 +90,72 @@ ChartJs.register(
|
|
|
78
90
|
Legend
|
|
79
91
|
)
|
|
80
92
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
export { chartOptions, chartSeriesColors }
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* One pixel to paint a colour on, shared by every chart.
|
|
97
|
+
*
|
|
98
|
+
* The canvas *paints* `oklch()`, but Chart.js also *parses* colours — to derive a
|
|
99
|
+
* hover shade and to animate between two colours — and its parser reads only
|
|
100
|
+
* rgb, hsl, hex and names. Painting the computed value and reading the pixel
|
|
101
|
+
* back gives the sRGB colour the canvas would have drawn anyway, in a form both
|
|
102
|
+
* understand, whatever syntax a theme uses (`oklch()`, `color-mix()`, …).
|
|
103
|
+
*/
|
|
104
|
+
let swatch: CanvasRenderingContext2D | null | undefined
|
|
105
|
+
|
|
106
|
+
function toCanvasColor(value: string): string {
|
|
107
|
+
if (typeof CSS === 'undefined' || !CSS.supports('color', value)) return value
|
|
108
|
+
if (swatch === undefined) {
|
|
109
|
+
const canvas = document.createElement('canvas')
|
|
110
|
+
canvas.width = 1
|
|
111
|
+
canvas.height = 1
|
|
112
|
+
swatch = canvas.getContext('2d', { willReadFrequently: true })
|
|
113
|
+
}
|
|
114
|
+
if (!swatch) return value
|
|
115
|
+
swatch.globalCompositeOperation = 'copy'
|
|
116
|
+
swatch.fillStyle = value
|
|
117
|
+
swatch.fillRect(0, 0, 1, 1)
|
|
118
|
+
const [r, g, b, a] = swatch.getImageData(0, 0, 1, 1).data
|
|
119
|
+
return `rgba(${r}, ${g}, ${b}, ${Math.round(((a ?? 255) / 255) * 1000) / 1000})`
|
|
120
|
+
}
|
|
89
121
|
|
|
90
122
|
/**
|
|
91
|
-
*
|
|
123
|
+
* Resolves `var(--token)` strings against a chart's element, and re-resolves
|
|
124
|
+
* them when the theme changes.
|
|
92
125
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
126
|
+
* The element rather than the root, so a chart inside a subtree with its own
|
|
127
|
+
* inline tokens takes those. The observer watches every attribute on `<html>`,
|
|
128
|
+
* because that is where both applications switch appearance, accent and theme
|
|
129
|
+
* (`.dark`, `data-accent`, `data-theme`, inline variables); a theme axis added
|
|
130
|
+
* later is covered without touching this. It is released with the chart.
|
|
97
131
|
*/
|
|
98
|
-
|
|
132
|
+
function createThemeResolver() {
|
|
133
|
+
let element: HTMLElement | undefined
|
|
134
|
+
const [revision, invalidate] = createSignal(undefined, { equals: false })
|
|
135
|
+
|
|
136
|
+
onMount(() => {
|
|
137
|
+
const observer = new MutationObserver(() => invalidate())
|
|
138
|
+
observer.observe(document.documentElement, { attributes: true })
|
|
139
|
+
onCleanup(() => observer.disconnect())
|
|
140
|
+
})
|
|
141
|
+
|
|
99
142
|
return {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
interaction: { mode: 'nearest', intersect: false },
|
|
103
|
-
plugins: {
|
|
104
|
-
legend: {
|
|
105
|
-
labels: {
|
|
106
|
-
color: 'var(--chart-label)',
|
|
107
|
-
boxWidth: 8,
|
|
108
|
-
boxHeight: 8,
|
|
109
|
-
usePointStyle: true,
|
|
110
|
-
pointStyle: 'circle',
|
|
111
|
-
font: { size: 11 },
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
tooltip: {
|
|
115
|
-
backgroundColor: 'var(--popover)',
|
|
116
|
-
titleColor: 'var(--popover-foreground)',
|
|
117
|
-
bodyColor: 'var(--popover-foreground)',
|
|
118
|
-
borderColor: 'var(--border)',
|
|
119
|
-
borderWidth: 1,
|
|
120
|
-
padding: 8,
|
|
121
|
-
cornerRadius: 6,
|
|
122
|
-
displayColors: true,
|
|
123
|
-
boxWidth: 8,
|
|
124
|
-
boxHeight: 8,
|
|
125
|
-
usePointStyle: true,
|
|
126
|
-
titleFont: { size: 11, weight: 600 },
|
|
127
|
-
bodyFont: { size: 11 },
|
|
128
|
-
},
|
|
143
|
+
ref: (el: HTMLElement) => {
|
|
144
|
+
element = el
|
|
129
145
|
},
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
146
|
+
resolve<T>(value: T): T {
|
|
147
|
+
revision()
|
|
148
|
+
if (!element || typeof getComputedStyle === 'undefined') return value
|
|
149
|
+
const style = getComputedStyle(element)
|
|
150
|
+
const resolved = new Map<string, string | undefined>()
|
|
151
|
+
return resolveCssVariables(value, (name) => {
|
|
152
|
+
if (!resolved.has(name)) {
|
|
153
|
+
const raw = style.getPropertyValue(name).trim()
|
|
154
|
+
resolved.set(name, raw ? toCanvasColor(raw) : undefined)
|
|
155
|
+
}
|
|
156
|
+
return resolved.get(name)
|
|
157
|
+
})
|
|
141
158
|
},
|
|
142
|
-
...overrides,
|
|
143
159
|
}
|
|
144
160
|
}
|
|
145
161
|
|
|
@@ -163,7 +179,9 @@ export function ChartFrame(props: ChartFrameProps) {
|
|
|
163
179
|
<figcaption class="flex items-start justify-between gap-3">
|
|
164
180
|
<div>
|
|
165
181
|
<h3 class="text-sm font-semibold text-foreground">{local.title}</h3>
|
|
166
|
-
{local.description}
|
|
182
|
+
<Show when={local.description}>
|
|
183
|
+
<p class="text-xs text-muted-foreground">{local.description}</p>
|
|
184
|
+
</Show>
|
|
167
185
|
</div>
|
|
168
186
|
{local.actions}
|
|
169
187
|
</figcaption>
|
|
@@ -177,7 +195,7 @@ type SeriesChartProps = {
|
|
|
177
195
|
labels: readonly string[]
|
|
178
196
|
/** One entry per series. `data` is aligned to `labels`. */
|
|
179
197
|
series: readonly { label: string; data: readonly number[]; color?: string }[]
|
|
180
|
-
/** Chart.js options, merged over the theme's defaults. */
|
|
198
|
+
/** Chart.js options, merged deeply over the theme's defaults. */
|
|
181
199
|
options?: ChartOptions
|
|
182
200
|
/** Stack the series. */
|
|
183
201
|
stacked?: boolean
|
|
@@ -206,26 +224,31 @@ function datasetsFor(series: SeriesChartProps['series'], filled: boolean) {
|
|
|
206
224
|
}))
|
|
207
225
|
}
|
|
208
226
|
|
|
209
|
-
function seriesOptions(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
227
|
+
function seriesOptions(
|
|
228
|
+
props: SeriesChartProps,
|
|
229
|
+
extra?: ChartOptions,
|
|
230
|
+
shape: ChartScaleShape = 'cartesian'
|
|
231
|
+
): ChartOptions {
|
|
232
|
+
// Stacking is a cartesian idea; a radar has no x or y to stack, and naming
|
|
233
|
+
// them would make Chart.js draw them.
|
|
234
|
+
const stacked =
|
|
235
|
+
props.stacked && shape === 'cartesian'
|
|
236
|
+
? { scales: { x: { stacked: true }, y: { stacked: true } } }
|
|
237
|
+
: undefined
|
|
238
|
+
return chartOptions(mergeChartOptions(extra, stacked, props.options), shape)
|
|
217
239
|
}
|
|
218
240
|
|
|
219
241
|
/** A line chart. The default for a series over time. */
|
|
220
242
|
export function LineChart(props: SeriesChartProps & { area?: boolean }) {
|
|
243
|
+
const theme = createThemeResolver()
|
|
221
244
|
return (
|
|
222
|
-
<div class={cn('h-64', props.class)}>
|
|
245
|
+
<div ref={theme.ref} class={cn('h-64', props.class)}>
|
|
223
246
|
<Line
|
|
224
|
-
data={{
|
|
247
|
+
data={theme.resolve({
|
|
225
248
|
labels: [...props.labels],
|
|
226
249
|
datasets: datasetsFor(props.series, props.area ?? false),
|
|
227
|
-
}}
|
|
228
|
-
options={seriesOptions(props)}
|
|
250
|
+
})}
|
|
251
|
+
options={theme.resolve(seriesOptions(props))}
|
|
229
252
|
/>
|
|
230
253
|
</div>
|
|
231
254
|
)
|
|
@@ -233,18 +256,19 @@ export function LineChart(props: SeriesChartProps & { area?: boolean }) {
|
|
|
233
256
|
|
|
234
257
|
/** A bar chart. `stacked` for parts of a whole over categories. */
|
|
235
258
|
export function BarChart(props: SeriesChartProps & { horizontal?: boolean }) {
|
|
259
|
+
const theme = createThemeResolver()
|
|
236
260
|
return (
|
|
237
|
-
<div class={cn('h-64', props.class)}>
|
|
261
|
+
<div ref={theme.ref} class={cn('h-64', props.class)}>
|
|
238
262
|
<Bar
|
|
239
|
-
data={{
|
|
263
|
+
data={theme.resolve({
|
|
240
264
|
labels: [...props.labels],
|
|
241
265
|
datasets: datasetsFor(props.series, true).map((dataset) => ({
|
|
242
266
|
...dataset,
|
|
243
267
|
borderWidth: 0,
|
|
244
268
|
borderRadius: 3,
|
|
245
269
|
})),
|
|
246
|
-
}}
|
|
247
|
-
options={seriesOptions(props, { indexAxis: props.horizontal ? 'y' : 'x' })}
|
|
270
|
+
})}
|
|
271
|
+
options={theme.resolve(seriesOptions(props, { indexAxis: props.horizontal ? 'y' : 'x' }))}
|
|
248
272
|
/>
|
|
249
273
|
</div>
|
|
250
274
|
)
|
|
@@ -256,10 +280,11 @@ export function ScatterChart(props: {
|
|
|
256
280
|
options?: ChartOptions
|
|
257
281
|
class?: string
|
|
258
282
|
}) {
|
|
283
|
+
const theme = createThemeResolver()
|
|
259
284
|
return (
|
|
260
|
-
<div class={cn('h-64', props.class)}>
|
|
285
|
+
<div ref={theme.ref} class={cn('h-64', props.class)}>
|
|
261
286
|
<Scatter
|
|
262
|
-
data={{
|
|
287
|
+
data={theme.resolve({
|
|
263
288
|
datasets: props.series.map((entry, index) => ({
|
|
264
289
|
label: entry.label,
|
|
265
290
|
data: entry.data.map((point) => ({ ...point })),
|
|
@@ -267,8 +292,8 @@ export function ScatterChart(props: {
|
|
|
267
292
|
pointRadius: 3,
|
|
268
293
|
pointHoverRadius: 5,
|
|
269
294
|
})),
|
|
270
|
-
}}
|
|
271
|
-
options={chartOptions(props.options)}
|
|
295
|
+
})}
|
|
296
|
+
options={theme.resolve(chartOptions(props.options))}
|
|
272
297
|
/>
|
|
273
298
|
</div>
|
|
274
299
|
)
|
|
@@ -284,17 +309,18 @@ export function BubbleChart(props: {
|
|
|
284
309
|
options?: ChartOptions
|
|
285
310
|
class?: string
|
|
286
311
|
}) {
|
|
312
|
+
const theme = createThemeResolver()
|
|
287
313
|
return (
|
|
288
|
-
<div class={cn('h-64', props.class)}>
|
|
314
|
+
<div ref={theme.ref} class={cn('h-64', props.class)}>
|
|
289
315
|
<Bubble
|
|
290
|
-
data={{
|
|
316
|
+
data={theme.resolve({
|
|
291
317
|
datasets: props.series.map((entry, index) => ({
|
|
292
318
|
label: entry.label,
|
|
293
319
|
data: entry.data.map((point) => ({ ...point })),
|
|
294
320
|
backgroundColor: entry.color ?? chartSeriesColors[index % chartSeriesColors.length],
|
|
295
321
|
})),
|
|
296
|
-
}}
|
|
297
|
-
options={chartOptions(props.options)}
|
|
322
|
+
})}
|
|
323
|
+
options={theme.resolve(chartOptions(props.options))}
|
|
298
324
|
/>
|
|
299
325
|
</div>
|
|
300
326
|
)
|
|
@@ -302,27 +328,39 @@ export function BubbleChart(props: {
|
|
|
302
328
|
|
|
303
329
|
/** A radar chart, for a profile across fixed axes. */
|
|
304
330
|
export function RadarChart(props: SeriesChartProps) {
|
|
331
|
+
const theme = createThemeResolver()
|
|
305
332
|
return (
|
|
306
|
-
<div class={cn('h-64', props.class)}>
|
|
333
|
+
<div ref={theme.ref} class={cn('h-64', props.class)}>
|
|
307
334
|
<Radar
|
|
308
|
-
data={
|
|
309
|
-
|
|
335
|
+
data={theme.resolve({
|
|
336
|
+
labels: [...props.labels],
|
|
337
|
+
datasets: datasetsFor(props.series, true),
|
|
338
|
+
})}
|
|
339
|
+
options={theme.resolve(seriesOptions(props, undefined, 'radial'))}
|
|
310
340
|
/>
|
|
311
341
|
</div>
|
|
312
342
|
)
|
|
313
343
|
}
|
|
314
344
|
|
|
315
|
-
/**
|
|
345
|
+
/**
|
|
346
|
+
* A polar area chart: radial bars, for a composition.
|
|
347
|
+
*
|
|
348
|
+
* Its scale is left to Chart.js's polar-area defaults (`'none'` rather than
|
|
349
|
+
* `'radial'`): `solid-chartjs` deletes `options.scales.r` for every chart type
|
|
350
|
+
* but radar when it first creates the chart, so radial styling here would apply
|
|
351
|
+
* only after the first theme change — a chart that restyles itself on a toggle.
|
|
352
|
+
*/
|
|
316
353
|
export function PolarAreaChart(props: {
|
|
317
354
|
labels: readonly string[]
|
|
318
355
|
data: readonly number[]
|
|
319
356
|
options?: ChartOptions
|
|
320
357
|
class?: string
|
|
321
358
|
}) {
|
|
359
|
+
const theme = createThemeResolver()
|
|
322
360
|
return (
|
|
323
|
-
<div class={cn('h-64', props.class)}>
|
|
361
|
+
<div ref={theme.ref} class={cn('h-64', props.class)}>
|
|
324
362
|
<PolarArea
|
|
325
|
-
data={{
|
|
363
|
+
data={theme.resolve({
|
|
326
364
|
labels: [...props.labels],
|
|
327
365
|
datasets: [
|
|
328
366
|
{
|
|
@@ -332,8 +370,8 @@ export function PolarAreaChart(props: {
|
|
|
332
370
|
borderWidth: 2,
|
|
333
371
|
},
|
|
334
372
|
],
|
|
335
|
-
}}
|
|
336
|
-
options={chartOptions(props.options)}
|
|
373
|
+
})}
|
|
374
|
+
options={theme.resolve(chartOptions(props.options, 'none'))}
|
|
337
375
|
/>
|
|
338
376
|
</div>
|
|
339
377
|
)
|
|
@@ -356,14 +394,15 @@ export function DonutChart(props: {
|
|
|
356
394
|
options?: ChartOptions
|
|
357
395
|
class?: string
|
|
358
396
|
}) {
|
|
397
|
+
const theme = createThemeResolver()
|
|
359
398
|
// `Dynamic` rather than a local component accessor: Solid's JSX types require
|
|
360
399
|
// a component reference, and an accessor returning one is a call in disguise.
|
|
361
400
|
const component = () => (props.cutout === 0 ? Pie : Doughnut)
|
|
362
401
|
return (
|
|
363
|
-
<div class={cn('h-64', props.class)}>
|
|
402
|
+
<div ref={theme.ref} class={cn('h-64', props.class)}>
|
|
364
403
|
<Dynamic
|
|
365
404
|
component={component()}
|
|
366
|
-
data={{
|
|
405
|
+
data={theme.resolve({
|
|
367
406
|
labels: [...props.labels],
|
|
368
407
|
datasets: [
|
|
369
408
|
{
|
|
@@ -375,11 +414,20 @@ export function DonutChart(props: {
|
|
|
375
414
|
borderWidth: 2,
|
|
376
415
|
},
|
|
377
416
|
],
|
|
378
|
-
}}
|
|
379
|
-
options={chartOptions({
|
|
380
|
-
...props.options,
|
|
381
|
-
...(props.cutout === 0 ? {} : { cutout: `${props.cutout ?? 60}%` }),
|
|
382
417
|
})}
|
|
418
|
+
options={theme.resolve(
|
|
419
|
+
chartOptions(
|
|
420
|
+
mergeChartOptions(
|
|
421
|
+
props.cutout === 0
|
|
422
|
+
? undefined
|
|
423
|
+
: ({
|
|
424
|
+
cutout: `${props.cutout ?? 60}%`,
|
|
425
|
+
} satisfies ChartOptions<'doughnut'> as ChartOptions),
|
|
426
|
+
props.options
|
|
427
|
+
),
|
|
428
|
+
'none'
|
|
429
|
+
)
|
|
430
|
+
)}
|
|
383
431
|
/>
|
|
384
432
|
</div>
|
|
385
433
|
)
|
|
@@ -131,6 +131,14 @@ export function ContextMenuRadioItem(props: ComponentProps<typeof KobalteContext
|
|
|
131
131
|
)
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* The caption of a `ContextMenuGroup`, and that group's accessible name. It must be a
|
|
136
|
+
* child of the group it names: Kobalte reads the group from context, so a label
|
|
137
|
+
* placed directly in the content throws `useMenuGroupContext must be used within
|
|
138
|
+
* a Menu.Group` the moment the menu opens. For an ungrouped caption, wrap the
|
|
139
|
+
* label and its items in a group anyway — the grouping is what a screen reader
|
|
140
|
+
* announces.
|
|
141
|
+
*/
|
|
134
142
|
export function ContextMenuLabel(props: ComponentProps<typeof KobalteContextMenu.GroupLabel>) {
|
|
135
143
|
const [local, rest] = splitProps(props, ['class'])
|
|
136
144
|
return <KobalteContextMenu.GroupLabel class={cn(menuLabel, local.class)} {...rest} />
|
|
@@ -41,7 +41,14 @@ export function DrawerOverlay(props: ComponentProps<typeof DrawerPrimitive.Overl
|
|
|
41
41
|
)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
export type DrawerContentProps = ComponentProps<typeof DrawerPrimitive.Content> & {
|
|
44
|
+
export type DrawerContentProps = Omit<ComponentProps<typeof DrawerPrimitive.Content>, 'side'> & {
|
|
45
|
+
/**
|
|
46
|
+
* Not accepted here. corvu reads the side from the root `Drawer`, which uses it
|
|
47
|
+
* for the drag axis and publishes it as `data-side`; a `side` on the content
|
|
48
|
+
* would type-check through the polymorphic props and be silently ignored,
|
|
49
|
+
* leaving the drawer on the bottom edge. Set `<Drawer side="right">` instead.
|
|
50
|
+
*/
|
|
51
|
+
side?: never
|
|
45
52
|
/**
|
|
46
53
|
* Draw the grabber at the leading edge of the sheet.
|
|
47
54
|
*
|
|
@@ -187,6 +187,14 @@ export function DropdownMenuRadioItem(props: ComponentProps<typeof KobalteDropdo
|
|
|
187
187
|
)
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
/**
|
|
191
|
+
* The caption of a `DropdownMenuGroup`, and that group's accessible name. It must be a
|
|
192
|
+
* child of the group it names: Kobalte reads the group from context, so a label
|
|
193
|
+
* placed directly in the content throws `useMenuGroupContext must be used within
|
|
194
|
+
* a Menu.Group` the moment the menu opens. For an ungrouped caption, wrap the
|
|
195
|
+
* label and its items in a group anyway — the grouping is what a screen reader
|
|
196
|
+
* announces.
|
|
197
|
+
*/
|
|
190
198
|
export function DropdownMenuLabel(props: ComponentProps<typeof KobalteDropdownMenu.GroupLabel>) {
|
|
191
199
|
const [local, rest] = splitProps(props, ['class'])
|
|
192
200
|
return <KobalteDropdownMenu.GroupLabel class={cn(menuLabel, local.class)} {...rest} />
|
|
@@ -38,7 +38,17 @@ export function InputOtp(props: InputOtpProps) {
|
|
|
38
38
|
return (
|
|
39
39
|
<OtpField
|
|
40
40
|
maxLength={length()}
|
|
41
|
-
class={cn(
|
|
41
|
+
class={cn(
|
|
42
|
+
'flex items-center gap-2',
|
|
43
|
+
// corvu positions the field itself, but its hidden input is 40px wider
|
|
44
|
+
// than the field so a password manager's badge lands outside the boxes
|
|
45
|
+
// (`shiftPWManagers`). `clip-path` only hides that overhang; it still
|
|
46
|
+
// counts as overflow, and a full-width field scrolled the page sideways.
|
|
47
|
+
// `overflow-hidden` contains it, and `p-1` keeps the edge boxes' focus
|
|
48
|
+
// ring (`ring-3`) inside the clip.
|
|
49
|
+
'overflow-hidden p-1',
|
|
50
|
+
local.class
|
|
51
|
+
)}
|
|
42
52
|
{...rest}
|
|
43
53
|
children={(field) => (
|
|
44
54
|
<>
|
|
@@ -72,7 +82,9 @@ export function InputOtp(props: InputOtpProps) {
|
|
|
72
82
|
'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50'
|
|
73
83
|
)}
|
|
74
84
|
data-active={field.activeSlots.includes(slot)}
|
|
75
|
-
data-disabled
|
|
85
|
+
// Present-or-absent, never `"false"`: `data-[disabled]`
|
|
86
|
+
// matches any value, so `disabled={false}` dimmed the boxes.
|
|
87
|
+
data-disabled={props.disabled ? '' : undefined}
|
|
76
88
|
>
|
|
77
89
|
{field.value[slot] ?? ''}
|
|
78
90
|
</span>
|
|
@@ -160,6 +160,14 @@ export function MenubarRadioItem(props: ComponentProps<typeof KobalteMenubar.Rad
|
|
|
160
160
|
)
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
/**
|
|
164
|
+
* The caption of a `MenubarGroup`, and that group's accessible name. It must be a
|
|
165
|
+
* child of the group it names: Kobalte reads the group from context, so a label
|
|
166
|
+
* placed directly in the content throws `useMenuGroupContext must be used within
|
|
167
|
+
* a Menu.Group` the moment the menu opens. For an ungrouped caption, wrap the
|
|
168
|
+
* label and its items in a group anyway — the grouping is what a screen reader
|
|
169
|
+
* announces.
|
|
170
|
+
*/
|
|
163
171
|
export function MenubarLabel(props: ComponentProps<typeof KobalteMenubar.GroupLabel>) {
|
|
164
172
|
const [local, rest] = splitProps(props, ['class'])
|
|
165
173
|
return <KobalteMenubar.GroupLabel class={cn(menuLabel, local.class)} {...rest} />
|
|
@@ -41,9 +41,15 @@ import { menuContentPadding, menuItem, overlayMotion, overlaySurface } from '../
|
|
|
41
41
|
* - `Content` must be a direct child of `Menu`, and the `Viewport` is a **sibling
|
|
42
42
|
* of the menus** — not inside them. All the panels share one viewport, which is
|
|
43
43
|
* what lets the bar animate between them instead of each panel popping in place.
|
|
44
|
+
* - The viewport is an empty surface. Each `Content` reaches it through Kobalte's
|
|
45
|
+
* `Portal`, which mounts the panel inside the viewport while keeping it in its
|
|
46
|
+
* own `Menu`'s context. A `Content` rendered anywhere else — the viewport's own
|
|
47
|
+
* children included — has no `Menu` above it, and Kobalte throws
|
|
48
|
+
* `useMenuRootContext must be used within a MenuRoot` the moment a panel opens.
|
|
44
49
|
*
|
|
45
|
-
* The wrapper enforces the last
|
|
46
|
-
*
|
|
50
|
+
* The wrapper enforces the last two by rendering the `Viewport` itself and by
|
|
51
|
+
* portalling every `NavigationMenuContent`, so a caller cannot forget either and
|
|
52
|
+
* get a menu whose panels never appear.
|
|
47
53
|
*/
|
|
48
54
|
|
|
49
55
|
export type NavigationMenuProps = ComponentProps<typeof KobalteNavigationMenu.Root> & {
|
|
@@ -112,25 +118,41 @@ export function NavigationMenuContent(props: ComponentProps<typeof KobalteNaviga
|
|
|
112
118
|
const [local, rest] = splitProps(props, ['class', 'children'])
|
|
113
119
|
|
|
114
120
|
return (
|
|
115
|
-
<KobalteNavigationMenu.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
121
|
+
<KobalteNavigationMenu.Portal>
|
|
122
|
+
<KobalteNavigationMenu.Content
|
|
123
|
+
class={cn(
|
|
124
|
+
// Absolute so the viewport sizes to the active panel's measured box and
|
|
125
|
+
// animates between panels, rather than stacking them.
|
|
126
|
+
'absolute top-0 left-0 grid w-max gap-1 p-2 outline-none',
|
|
127
|
+
// The motion is the panel's, not the viewport's. Kobalte keeps an
|
|
128
|
+
// outgoing panel mounted until the viewport's own animation ends; a
|
|
129
|
+
// viewport that carries an entrance animation never fires that again
|
|
130
|
+
// after it opens, so the previous panel would stay painted under the
|
|
131
|
+
// next one.
|
|
132
|
+
overlayMotion,
|
|
133
|
+
// A two-column panel is the shape most menu bars want, and it is opt-in
|
|
134
|
+
// through this hook rather than a prop because the column count is a
|
|
135
|
+
// layout decision the caller's content makes.
|
|
136
|
+
'data-[wide]:grid-cols-2',
|
|
137
|
+
local.class
|
|
138
|
+
)}
|
|
139
|
+
{...rest}
|
|
140
|
+
>
|
|
141
|
+
{local.children}
|
|
142
|
+
</KobalteNavigationMenu.Content>
|
|
143
|
+
</KobalteNavigationMenu.Portal>
|
|
128
144
|
)
|
|
129
145
|
}
|
|
130
146
|
|
|
131
147
|
/**
|
|
132
148
|
* The shared panel surface. One per menu bar, and the wrapper supplies it — but
|
|
133
149
|
* exported so a caller with an unusual layout can place it themselves.
|
|
150
|
+
*
|
|
151
|
+
* It renders no children: the panels arrive through each `NavigationMenuContent`'s
|
|
152
|
+
* portal. Kobalte positions it under the bar and publishes the active panel's size
|
|
153
|
+
* as `--kb-navigation-menu-viewport-*`, which the surface animates between.
|
|
154
|
+
* `box-content` keeps the border outside that measured size so a panel is never
|
|
155
|
+
* clipped by its own frame.
|
|
134
156
|
*/
|
|
135
157
|
export function NavigationMenuViewport(
|
|
136
158
|
props: ComponentProps<typeof KobalteNavigationMenu.Viewport>
|
|
@@ -139,24 +161,16 @@ export function NavigationMenuViewport(
|
|
|
139
161
|
|
|
140
162
|
return (
|
|
141
163
|
<KobalteNavigationMenu.Viewport
|
|
164
|
+
data-slot="navigation-menu-viewport"
|
|
142
165
|
class={cn(
|
|
143
|
-
|
|
166
|
+
overlaySurface,
|
|
167
|
+
'isolate z-(--z-menu) mt-1.5 box-content list-none overflow-hidden',
|
|
144
168
|
'h-(--kb-navigation-menu-viewport-height) w-(--kb-navigation-menu-viewport-width)',
|
|
145
|
-
'origin-
|
|
169
|
+
'origin-(--kb-menu-content-transform-origin) transition-[width,height] duration-200 ease-out',
|
|
146
170
|
local.class
|
|
147
171
|
)}
|
|
148
172
|
{...rest}
|
|
149
|
-
|
|
150
|
-
<div
|
|
151
|
-
class={cn(
|
|
152
|
-
overlaySurface,
|
|
153
|
-
overlayMotion,
|
|
154
|
-
'w-full rounded-lg border border-border bg-popover p-1 shadow-lg'
|
|
155
|
-
)}
|
|
156
|
-
>
|
|
157
|
-
<KobalteNavigationMenu.Content />
|
|
158
|
-
</div>
|
|
159
|
-
</KobalteNavigationMenu.Viewport>
|
|
173
|
+
/>
|
|
160
174
|
)
|
|
161
175
|
}
|
|
162
176
|
|
|
@@ -55,7 +55,14 @@ export function Pagination(props: PaginationProps) {
|
|
|
55
55
|
((itemProps) => <PaginationItem page={itemProps.page}>{itemProps.page}</PaginationItem>)
|
|
56
56
|
}
|
|
57
57
|
ellipsisComponent={local.ellipsisComponent ?? (() => <PaginationEllipsis />)}
|
|
58
|
-
|
|
58
|
+
// Kobalte renders the root as a `<nav>` wrapping a `<ul>`, and every control —
|
|
59
|
+
// previous, the page run, next — is an `<li>` inside that list. The row has to be
|
|
60
|
+
// declared on the list: on the `<nav>` alone it lays out one child and the
|
|
61
|
+
// controls stack vertically.
|
|
62
|
+
class={cn(
|
|
63
|
+
'flex w-full items-center justify-center [&>ul]:m-0 [&>ul]:flex [&>ul]:list-none [&>ul]:items-center [&>ul]:gap-1 [&>ul]:p-0',
|
|
64
|
+
local.class
|
|
65
|
+
)}
|
|
59
66
|
{...rest}
|
|
60
67
|
>
|
|
61
68
|
<Show when={local.children} fallback={<DefaultPaginationControls />}>
|