@adea-ai/ui 0.100.2 → 0.101.1
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/composites/about-dialog/about-dialog.d.ts.map +1 -1
- package/dist/components/composites/about-dialog/about-dialog.js +2 -1
- package/dist/components/composites/about-dialog/about-dialog.js.map +1 -1
- package/dist/components/composites/account-menu/account-menu.d.ts +7 -0
- package/dist/components/composites/account-menu/account-menu.d.ts.map +1 -1
- package/dist/components/composites/account-menu/account-menu.js +116 -89
- package/dist/components/composites/account-menu/account-menu.js.map +1 -1
- package/dist/components/composites/help-center/help-center.d.ts.map +1 -1
- package/dist/components/composites/help-center/help-center.js +26 -21
- package/dist/components/composites/help-center/help-center.js.map +1 -1
- package/dist/components/composites/settings/settings.d.ts.map +1 -1
- package/dist/components/composites/settings/settings.js +43 -36
- package/dist/components/composites/settings/settings.js.map +1 -1
- package/dist/components/composites/stat/stat.d.ts.map +1 -1
- package/dist/components/composites/stat/stat.js +46 -35
- package/dist/components/composites/stat/stat.js.map +1 -1
- package/dist/components/composites/update-dialog/update-dialog.d.ts.map +1 -1
- package/dist/components/composites/update-dialog/update-dialog.js +73 -58
- package/dist/components/composites/update-dialog/update-dialog.js.map +1 -1
- package/dist/components/layout/page/page.d.ts.map +1 -1
- package/dist/components/layout/page/page.js +19 -13
- package/dist/components/layout/page/page.js.map +1 -1
- package/dist/components/theme/appearance-panel.d.ts.map +1 -1
- package/dist/components/theme/appearance-panel.js +37 -18
- package/dist/components/theme/appearance-panel.js.map +1 -1
- package/dist/components/ui/alert-dialog/alert-dialog.d.ts.map +1 -1
- package/dist/components/ui/alert-dialog/alert-dialog.js +5 -1
- package/dist/components/ui/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/components/ui/card/card.d.ts.map +1 -1
- package/dist/components/ui/card/card.js +5 -1
- package/dist/components/ui/card/card.js.map +1 -1
- package/dist/components/ui/chart/chart-options.d.ts +3 -2
- package/dist/components/ui/chart/chart-options.d.ts.map +1 -1
- package/dist/components/ui/chart/chart-options.js +30 -9
- package/dist/components/ui/chart/chart-options.js.map +1 -1
- package/dist/components/ui/chart/chart.d.ts +4 -9
- package/dist/components/ui/chart/chart.d.ts.map +1 -1
- package/dist/components/ui/chart/chart.js +65 -10
- package/dist/components/ui/chart/chart.js.map +1 -1
- package/dist/components/ui/dialog/dialog.d.ts.map +1 -1
- package/dist/components/ui/dialog/dialog.js +5 -1
- package/dist/components/ui/dialog/dialog.js.map +1 -1
- package/dist/components/ui/drawer/drawer.d.ts.map +1 -1
- package/dist/components/ui/drawer/drawer.js +5 -1
- package/dist/components/ui/drawer/drawer.js.map +1 -1
- package/dist/components/ui/field/field.d.ts.map +1 -1
- package/dist/components/ui/field/field.js +2 -1
- package/dist/components/ui/field/field.js.map +1 -1
- package/dist/components/ui/item/item.d.ts +1 -1
- package/dist/components/ui/navigation-menu/navigation-menu.d.ts.map +1 -1
- package/dist/components/ui/navigation-menu/navigation-menu.js +8 -7
- package/dist/components/ui/navigation-menu/navigation-menu.js.map +1 -1
- package/dist/components/ui/sheet/sheet.d.ts.map +1 -1
- package/dist/components/ui/sheet/sheet.js +5 -1
- package/dist/components/ui/sheet/sheet.js.map +1 -1
- package/dist/components/ui/tabs/tabs.d.ts +13 -0
- package/dist/components/ui/tabs/tabs.d.ts.map +1 -1
- package/dist/components/ui/tabs/tabs.js +15 -1
- package/dist/components/ui/tabs/tabs.js.map +1 -1
- package/dist/components/ui/toast/toast.d.ts.map +1 -1
- package/dist/components/ui/toast/toast.js +6 -2
- package/dist/components/ui/toast/toast.js.map +1 -1
- package/dist/components/ui/typography/index.d.ts +3 -0
- package/dist/components/ui/typography/index.d.ts.map +1 -0
- package/dist/components/ui/typography/index.js +2 -0
- package/dist/components/ui/typography/typography.d.ts +84 -0
- package/dist/components/ui/typography/typography.d.ts.map +1 -0
- package/dist/components/ui/typography/typography.js +179 -0
- package/dist/components/ui/typography/typography.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/r/account-menu.json +1 -0
- package/dist/r/alert-dialog.json +1 -0
- package/dist/r/card.json +1 -0
- package/dist/r/dialog.json +1 -0
- package/dist/r/drawer.json +1 -0
- package/dist/r/field.json +1 -0
- package/dist/r/help-center.json +1 -0
- package/dist/r/page.json +1 -0
- package/dist/r/registry.json +37 -0
- package/dist/r/settings.json +1 -0
- package/dist/r/sheet.json +1 -0
- package/dist/r/src/components/composites/about-dialog/about-dialog.tsx +3 -2
- package/dist/r/src/components/composites/account-menu/account-menu.tsx +105 -66
- package/dist/r/src/components/composites/help-center/help-center.tsx +2 -1
- package/dist/r/src/components/composites/settings/settings.tsx +4 -1
- package/dist/r/src/components/composites/stat/stat.tsx +7 -2
- package/dist/r/src/components/composites/update-dialog/update-dialog.tsx +36 -24
- package/dist/r/src/components/layout/page/page.tsx +3 -2
- package/dist/r/src/components/theme/appearance-panel.tsx +13 -4
- package/dist/r/src/components/ui/alert-dialog/alert-dialog.tsx +2 -1
- package/dist/r/src/components/ui/card/card.tsx +2 -1
- package/dist/r/src/components/ui/chart/chart-options.ts +35 -7
- package/dist/r/src/components/ui/chart/chart.tsx +65 -12
- package/dist/r/src/components/ui/dialog/dialog.tsx +2 -1
- package/dist/r/src/components/ui/drawer/drawer.tsx +2 -1
- package/dist/r/src/components/ui/field/field.tsx +2 -3
- package/dist/r/src/components/ui/navigation-menu/navigation-menu.tsx +27 -20
- package/dist/r/src/components/ui/sheet/sheet.tsx +5 -1
- package/dist/r/src/components/ui/tabs/tabs.tsx +18 -1
- package/dist/r/src/components/ui/toast/toast.tsx +7 -6
- package/dist/r/src/components/ui/typography/index.ts +9 -0
- package/dist/r/src/components/ui/typography/typography.tsx +205 -0
- package/dist/r/stat.json +1 -0
- package/dist/r/theming.json +1 -0
- package/dist/r/typography.json +24 -0
- package/dist/r/update-dialog.json +1 -0
- package/package.json +1 -1
- package/registry.json +37 -0
- package/src/components/composites/about-dialog/about-dialog.tsx +3 -2
- package/src/components/composites/account-menu/account-menu.tsx +105 -66
- package/src/components/composites/help-center/help-center.tsx +2 -1
- package/src/components/composites/settings/settings.tsx +4 -1
- package/src/components/composites/stat/stat.tsx +7 -2
- package/src/components/composites/update-dialog/update-dialog.tsx +36 -24
- package/src/components/layout/page/page.tsx +3 -2
- package/src/components/theme/appearance-panel.tsx +13 -4
- package/src/components/ui/alert-dialog/alert-dialog.tsx +2 -1
- package/src/components/ui/card/card.tsx +2 -1
- package/src/components/ui/chart/chart-options.ts +35 -7
- package/src/components/ui/chart/chart.tsx +65 -12
- package/src/components/ui/dialog/dialog.tsx +2 -1
- package/src/components/ui/drawer/drawer.tsx +2 -1
- package/src/components/ui/field/field.tsx +2 -3
- package/src/components/ui/navigation-menu/navigation-menu.tsx +27 -20
- package/src/components/ui/sheet/sheet.tsx +5 -1
- package/src/components/ui/tabs/tabs.tsx +18 -1
- package/src/components/ui/toast/toast.tsx +7 -6
- package/src/components/ui/typography/index.ts +9 -0
- package/src/components/ui/typography/typography.tsx +205 -0
- package/src/index.ts +1 -0
|
@@ -45,7 +45,30 @@ const furniture = {
|
|
|
45
45
|
*/
|
|
46
46
|
export type ChartScaleShape = 'cartesian' | 'radial' | 'none'
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The chart's type: the UI face from the font axis and a rung of the type scale,
|
|
50
|
+
* declared as tokens like the colours.
|
|
51
|
+
*
|
|
52
|
+
* Chart.js does not inherit the page's font — it paints in its own default
|
|
53
|
+
* family — so every text a chart draws names `--font-sans` explicitly, and the
|
|
54
|
+
* chart follows `data-font` the same way it follows `.dark`. Everything is
|
|
55
|
+
* `--text-2xs`, the rung `ChartLegend` and the frame's metadata already use, so
|
|
56
|
+
* a canvas legend and an HTML one beside it are the same size.
|
|
57
|
+
*
|
|
58
|
+
* Chart.js types `size` as a number of pixels. The token is a `rem` length, so
|
|
59
|
+
* it is written as `var(--text-2xs)` here and the component resolves it to
|
|
60
|
+
* pixels with the colours (see `resolveCssVariables` and `chart.tsx`); the cast
|
|
61
|
+
* is that declaration, not a number.
|
|
62
|
+
*/
|
|
63
|
+
function chartFont(weight?: number) {
|
|
64
|
+
return {
|
|
65
|
+
family: 'var(--font-sans)',
|
|
66
|
+
size: 'var(--text-2xs)' as unknown as number,
|
|
67
|
+
...(weight === undefined ? {} : { weight }),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const tickFont = chartFont()
|
|
49
72
|
|
|
50
73
|
function scalesFor(shape: ChartScaleShape): ChartOptions['scales'] {
|
|
51
74
|
if (shape === 'cartesian') {
|
|
@@ -140,7 +163,7 @@ export function chartOptions(
|
|
|
140
163
|
boxHeight: 8,
|
|
141
164
|
usePointStyle: true,
|
|
142
165
|
pointStyle: 'circle',
|
|
143
|
-
font:
|
|
166
|
+
font: chartFont(),
|
|
144
167
|
},
|
|
145
168
|
},
|
|
146
169
|
tooltip: {
|
|
@@ -155,8 +178,9 @@ export function chartOptions(
|
|
|
155
178
|
boxWidth: 8,
|
|
156
179
|
boxHeight: 8,
|
|
157
180
|
usePointStyle: true,
|
|
158
|
-
titleFont:
|
|
159
|
-
bodyFont:
|
|
181
|
+
titleFont: chartFont(600),
|
|
182
|
+
bodyFont: chartFont(),
|
|
183
|
+
footerFont: chartFont(),
|
|
160
184
|
},
|
|
161
185
|
},
|
|
162
186
|
scales: scalesFor(shape),
|
|
@@ -169,17 +193,21 @@ const cssVariable = /^\s*var\(\s*(--[\w-]+)\s*(?:,\s*(.*?))?\s*\)\s*$/
|
|
|
169
193
|
|
|
170
194
|
/**
|
|
171
195
|
* Replace every `var(--token)` string in `value` — options, datasets, nested
|
|
172
|
-
* arrays — with what `read` returns for the token
|
|
196
|
+
* arrays — with what `read` returns for the token, which may be a number (a
|
|
197
|
+
* length token read as pixels). A token `read` cannot
|
|
173
198
|
* resolve falls back to the `var()`'s own fallback, then to the string as
|
|
174
199
|
* written. Functions and class instances pass through untouched, so scriptable
|
|
175
200
|
* options and gradients keep working.
|
|
176
201
|
*/
|
|
177
|
-
export function resolveCssVariables<T>(
|
|
202
|
+
export function resolveCssVariables<T>(
|
|
203
|
+
value: T,
|
|
204
|
+
read: (name: string) => string | number | undefined
|
|
205
|
+
): T {
|
|
178
206
|
if (typeof value === 'string') {
|
|
179
207
|
const match = cssVariable.exec(value)
|
|
180
208
|
if (!match) return value
|
|
181
209
|
const resolved = read(match[1]!)
|
|
182
|
-
if (resolved) return resolved as T
|
|
210
|
+
if (resolved !== undefined && resolved !== '') return resolved as T
|
|
183
211
|
return (match[2] ? resolveCssVariables(match[2], read) : value) as T
|
|
184
212
|
}
|
|
185
213
|
if (Array.isArray(value)) {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
RadialLinearScale,
|
|
16
16
|
Tooltip as ChartTooltip,
|
|
17
17
|
} from 'chart.js'
|
|
18
|
-
import type { ChartOptions, ChartType } from 'chart.js'
|
|
18
|
+
import type { ChartOptions, ChartType, Plugin } from 'chart.js'
|
|
19
19
|
import { cn } from '#lib/utils'
|
|
20
20
|
import {
|
|
21
21
|
chartOptions,
|
|
@@ -62,7 +62,9 @@ import {
|
|
|
62
62
|
* A canvas cannot read a custom property, so the options and datasets carry
|
|
63
63
|
* `var(--token)` strings and each chart resolves them against its own element
|
|
64
64
|
* when it renders, and again whenever the root's attributes change — the
|
|
65
|
-
* `.dark` class, `data-accent`, an inline override.
|
|
65
|
+
* `.dark` class, `data-accent`, `data-font`, an inline override. The type is
|
|
66
|
+
* resolved the same way: `--font-sans` for the family and a type-scale rung for
|
|
67
|
+
* the size, so a chart follows the font axis too. See `createThemeResolver`.
|
|
66
68
|
*/
|
|
67
69
|
|
|
68
70
|
/**
|
|
@@ -119,6 +121,23 @@ function toCanvasColor(value: string): string {
|
|
|
119
121
|
return `rgba(${r}, ${g}, ${b}, ${Math.round(((a ?? 255) / 255) * 1000) / 1000})`
|
|
120
122
|
}
|
|
121
123
|
|
|
124
|
+
const length = /^(-?\d*\.?\d+)(px|rem)$/
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* A token's computed value as a canvas option: a colour as an sRGB colour, a
|
|
128
|
+
* `px`/`rem` length (a type-scale rung) as the number of pixels Chart.js wants,
|
|
129
|
+
* and anything else — a font stack — as written.
|
|
130
|
+
*/
|
|
131
|
+
function toCanvasValue(raw: string): string | number {
|
|
132
|
+
const match = length.exec(raw)
|
|
133
|
+
if (match) {
|
|
134
|
+
const value = Number(match[1])
|
|
135
|
+
if (match[2] === 'px') return value
|
|
136
|
+
return value * (Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16)
|
|
137
|
+
}
|
|
138
|
+
return toCanvasColor(raw)
|
|
139
|
+
}
|
|
140
|
+
|
|
122
141
|
/**
|
|
123
142
|
* Resolves `var(--token)` strings against a chart's element, and re-resolves
|
|
124
143
|
* them when the theme changes.
|
|
@@ -127,16 +146,25 @@ function toCanvasColor(value: string): string {
|
|
|
127
146
|
* inline tokens takes those. The observer watches every attribute on `<html>`,
|
|
128
147
|
* because that is where both applications switch appearance, accent and theme
|
|
129
148
|
* (`.dark`, `data-accent`, `data-theme`, inline variables); a theme axis added
|
|
130
|
-
* later is covered without touching this. It
|
|
149
|
+
* later is covered without touching this. It also re-resolves when a web font
|
|
150
|
+
* finishes loading: a canvas draws text once, so a chart rendered before the
|
|
151
|
+
* face selected by `data-font` arrived would otherwise keep the fallback face
|
|
152
|
+
* until something else redrew it. Both are released with the chart.
|
|
131
153
|
*/
|
|
132
154
|
function createThemeResolver() {
|
|
133
155
|
let element: HTMLElement | undefined
|
|
134
156
|
const [revision, invalidate] = createSignal(undefined, { equals: false })
|
|
157
|
+
const onFontsLoaded = () => invalidate()
|
|
135
158
|
|
|
136
159
|
onMount(() => {
|
|
137
160
|
const observer = new MutationObserver(() => invalidate())
|
|
138
161
|
observer.observe(document.documentElement, { attributes: true })
|
|
139
|
-
|
|
162
|
+
const fonts = typeof document.fonts === 'undefined' ? undefined : document.fonts
|
|
163
|
+
fonts?.addEventListener('loadingdone', onFontsLoaded)
|
|
164
|
+
onCleanup(() => {
|
|
165
|
+
observer.disconnect()
|
|
166
|
+
fonts?.removeEventListener('loadingdone', onFontsLoaded)
|
|
167
|
+
})
|
|
140
168
|
})
|
|
141
169
|
|
|
142
170
|
return {
|
|
@@ -147,11 +175,11 @@ function createThemeResolver() {
|
|
|
147
175
|
revision()
|
|
148
176
|
if (!element || typeof getComputedStyle === 'undefined') return value
|
|
149
177
|
const style = getComputedStyle(element)
|
|
150
|
-
const resolved = new Map<string, string | undefined>()
|
|
178
|
+
const resolved = new Map<string, string | number | undefined>()
|
|
151
179
|
return resolveCssVariables(value, (name) => {
|
|
152
180
|
if (!resolved.has(name)) {
|
|
153
181
|
const raw = style.getPropertyValue(name).trim()
|
|
154
|
-
resolved.set(name, raw ?
|
|
182
|
+
resolved.set(name, raw ? toCanvasValue(raw) : undefined)
|
|
155
183
|
}
|
|
156
184
|
return resolved.get(name)
|
|
157
185
|
})
|
|
@@ -343,13 +371,36 @@ export function RadarChart(props: SeriesChartProps) {
|
|
|
343
371
|
}
|
|
344
372
|
|
|
345
373
|
/**
|
|
346
|
-
*
|
|
374
|
+
* Puts the themed radial scale back on a chart `solid-chartjs` has just created.
|
|
347
375
|
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
376
|
+
* `solid-chartjs` deletes `options.scales.r` for every chart type but radar when
|
|
377
|
+
* it first creates a chart. Today that delete lands on a throwaway copy — Solid
|
|
378
|
+
* compiles `options={…}` to a getter, so its next read rebuilds the object with
|
|
379
|
+
* `r` intact — but that is an accident of how the prop is passed: a memoised or
|
|
380
|
+
* static options object would lose the scale, and the polar area would fall back
|
|
381
|
+
* to Chart.js's defaults (grey ticks on a translucent white box, which is a white
|
|
382
|
+
* box on a dark card). Restoring it from this component's own options makes the
|
|
383
|
+
* themed scale independent of both. Later option updates (every theme change)
|
|
384
|
+
* pass `r` through untouched; only creation drops it.
|
|
385
|
+
*
|
|
386
|
+
* `afterInit` runs inside Chart.js's constructor, after the options are read and
|
|
387
|
+
* before the first update builds the scales and draws, so the themed scale is in
|
|
388
|
+
* place for the first frame — no default-styled frame, and no extra update. The
|
|
389
|
+
* plugin is per instance, passed through the chart's `plugins` prop, so nothing
|
|
390
|
+
* is registered globally.
|
|
352
391
|
*/
|
|
392
|
+
function restoreRadialScale(options: () => ChartOptions): Plugin {
|
|
393
|
+
return {
|
|
394
|
+
id: 'adea-radial-scale',
|
|
395
|
+
afterInit(chart) {
|
|
396
|
+
const scale = options().scales?.['r']
|
|
397
|
+
if (!scale) return
|
|
398
|
+
chart.options.scales = { ...chart.options.scales, r: scale }
|
|
399
|
+
},
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/** A polar area chart: radial bars, for a composition. */
|
|
353
404
|
export function PolarAreaChart(props: {
|
|
354
405
|
labels: readonly string[]
|
|
355
406
|
data: readonly number[]
|
|
@@ -357,9 +408,11 @@ export function PolarAreaChart(props: {
|
|
|
357
408
|
class?: string
|
|
358
409
|
}) {
|
|
359
410
|
const theme = createThemeResolver()
|
|
411
|
+
const options = () => theme.resolve(chartOptions(props.options, 'radial'))
|
|
360
412
|
return (
|
|
361
413
|
<div ref={theme.ref} class={cn('h-64', props.class)}>
|
|
362
414
|
<PolarArea
|
|
415
|
+
plugins={[restoreRadialScale(options)]}
|
|
363
416
|
data={theme.resolve({
|
|
364
417
|
labels: [...props.labels],
|
|
365
418
|
datasets: [
|
|
@@ -371,7 +424,7 @@ export function PolarAreaChart(props: {
|
|
|
371
424
|
},
|
|
372
425
|
],
|
|
373
426
|
})}
|
|
374
|
-
options={
|
|
427
|
+
options={options()}
|
|
375
428
|
/>
|
|
376
429
|
</div>
|
|
377
430
|
)
|
|
@@ -9,6 +9,7 @@ import type { Accessor, ComponentProps, JSX } from 'solid-js'
|
|
|
9
9
|
import { createRenderEffect, onCleanup, Show, splitProps } from 'solid-js'
|
|
10
10
|
import { overlayMotion, overlayPositioner, overlayScrim, overlaySurface } from '#lib/overlay'
|
|
11
11
|
import { cn } from '#lib/utils'
|
|
12
|
+
import { headingVariants } from '../typography'
|
|
12
13
|
|
|
13
14
|
type FocusCycle = {
|
|
14
15
|
content: HTMLElement
|
|
@@ -327,7 +328,7 @@ export function DialogTitle(props: ComponentProps<typeof KobalteDialog.Title>) {
|
|
|
327
328
|
const [local, rest] = splitProps(props, ['class'])
|
|
328
329
|
return (
|
|
329
330
|
<KobalteDialog.Title
|
|
330
|
-
class={cn('
|
|
331
|
+
class={cn(headingVariants({ size: 'card', leading: 'none' }), local.class)}
|
|
331
332
|
{...rest}
|
|
332
333
|
/>
|
|
333
334
|
)
|
|
@@ -2,6 +2,7 @@ import DrawerPrimitive from '@corvu/drawer'
|
|
|
2
2
|
import type { ComponentProps } from 'solid-js'
|
|
3
3
|
import { splitProps } from 'solid-js'
|
|
4
4
|
import { cn } from '#lib/utils'
|
|
5
|
+
import { headingVariants } from '../typography'
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Drawer.
|
|
@@ -96,7 +97,7 @@ export function DrawerTitle(props: ComponentProps<typeof DrawerPrimitive.Label>)
|
|
|
96
97
|
const [local, rest] = splitProps(props, ['class'])
|
|
97
98
|
return (
|
|
98
99
|
<DrawerPrimitive.Label
|
|
99
|
-
class={cn('
|
|
100
|
+
class={cn(headingVariants({ size: 'card', leading: 'none' }), local.class)}
|
|
100
101
|
{...rest}
|
|
101
102
|
/>
|
|
102
103
|
)
|
|
@@ -4,6 +4,7 @@ import { createUniqueId, Show, splitProps } from 'solid-js'
|
|
|
4
4
|
import { Label } from '../label/label'
|
|
5
5
|
import { createFormFieldContext, FormFieldContext } from '#lib/form-field'
|
|
6
6
|
import { cn } from '#lib/utils'
|
|
7
|
+
import { headingVariants } from '../typography'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Field.
|
|
@@ -199,9 +200,7 @@ export function FieldLegend(props: ComponentProps<'legend'> & { variant?: 'legen
|
|
|
199
200
|
<legend
|
|
200
201
|
class={cn(
|
|
201
202
|
'mb-1',
|
|
202
|
-
local.variant === 'label'
|
|
203
|
-
? 'text-sm font-medium'
|
|
204
|
-
: 'text-base font-semibold tracking-tight',
|
|
203
|
+
local.variant === 'label' ? 'text-sm font-medium' : headingVariants({ size: 'card' }),
|
|
205
204
|
local.class
|
|
206
205
|
)}
|
|
207
206
|
{...rest}
|
|
@@ -2,7 +2,14 @@ import { splitProps, type ComponentProps, type JSX } from 'solid-js'
|
|
|
2
2
|
import * as KobalteNavigationMenu from '@kobalte/core/navigation-menu'
|
|
3
3
|
import { ChevronDown } from 'lucide-solid'
|
|
4
4
|
import { cn } from '#lib/utils'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
menuContentPadding,
|
|
7
|
+
menuItem,
|
|
8
|
+
menuLabel,
|
|
9
|
+
menuSeparator,
|
|
10
|
+
overlayMotion,
|
|
11
|
+
overlaySurface,
|
|
12
|
+
} from '#lib/overlay'
|
|
6
13
|
|
|
7
14
|
/**
|
|
8
15
|
* NavigationMenu.
|
|
@@ -123,7 +130,11 @@ export function NavigationMenuContent(props: ComponentProps<typeof KobalteNaviga
|
|
|
123
130
|
class={cn(
|
|
124
131
|
// Absolute so the viewport sizes to the active panel's measured box and
|
|
125
132
|
// animates between panels, rather than stacking them.
|
|
126
|
-
'absolute top-0 left-0 grid w-max gap-1
|
|
133
|
+
'absolute top-0 left-0 grid w-max gap-1 outline-none',
|
|
134
|
+
// The viewport is the surface and carries no padding of its own (its
|
|
135
|
+
// measured size is the panel's), so the panel supplies the inset every
|
|
136
|
+
// menu surface shares — the one the separator's bleed is cut for.
|
|
137
|
+
menuContentPadding,
|
|
127
138
|
// The motion is the panel's, not the viewport's. Kobalte keeps an
|
|
128
139
|
// outgoing panel mounted until the viewport's own animation ends; a
|
|
129
140
|
// viewport that carries an entrance animation never fires that again
|
|
@@ -193,7 +204,11 @@ export function NavigationMenuItem(props: NavigationMenuItemProps) {
|
|
|
193
204
|
<KobalteNavigationMenu.Item
|
|
194
205
|
class={cn(
|
|
195
206
|
menuItem,
|
|
196
|
-
|
|
207
|
+
// The description sits under the label, in the label's column. Without
|
|
208
|
+
// an icon there is no leading column, and a two-column grid would set
|
|
209
|
+
// the description beside the label instead of beneath it.
|
|
210
|
+
local.icon ? 'grid grid-cols-[auto_1fr]' : 'grid grid-cols-1',
|
|
211
|
+
'items-center gap-x-2 gap-y-0.5',
|
|
197
212
|
local.description && 'grid-rows-[auto_auto] py-2',
|
|
198
213
|
local.class
|
|
199
214
|
)}
|
|
@@ -202,7 +217,13 @@ export function NavigationMenuItem(props: NavigationMenuItemProps) {
|
|
|
202
217
|
{local.icon}
|
|
203
218
|
<span class="font-medium">{local.children}</span>
|
|
204
219
|
{local.description && (
|
|
205
|
-
<span
|
|
220
|
+
<span
|
|
221
|
+
class={cn('text-xs text-muted-foreground', {
|
|
222
|
+
'col-start-2': !!local.icon,
|
|
223
|
+
})}
|
|
224
|
+
>
|
|
225
|
+
{local.description}
|
|
226
|
+
</span>
|
|
206
227
|
)}
|
|
207
228
|
</KobalteNavigationMenu.Item>
|
|
208
229
|
)
|
|
@@ -212,12 +233,7 @@ export function NavigationMenuSeparator(
|
|
|
212
233
|
props: ComponentProps<typeof KobalteNavigationMenu.Separator>
|
|
213
234
|
) {
|
|
214
235
|
const [local, rest] = splitProps(props, ['class'])
|
|
215
|
-
return (
|
|
216
|
-
<KobalteNavigationMenu.Separator
|
|
217
|
-
class={cn('-mx-1 my-1 h-px bg-border', local.class)}
|
|
218
|
-
{...rest}
|
|
219
|
-
/>
|
|
220
|
-
)
|
|
236
|
+
return <KobalteNavigationMenu.Separator class={cn(menuSeparator, local.class)} {...rest} />
|
|
221
237
|
}
|
|
222
238
|
|
|
223
239
|
/** A non-interactive caption above a group of items. */
|
|
@@ -225,16 +241,7 @@ export function NavigationMenuGroupLabel(
|
|
|
225
241
|
props: ComponentProps<typeof KobalteNavigationMenu.GroupLabel>
|
|
226
242
|
) {
|
|
227
243
|
const [local, rest] = splitProps(props, ['class'])
|
|
228
|
-
return (
|
|
229
|
-
<KobalteNavigationMenu.GroupLabel
|
|
230
|
-
class={cn(
|
|
231
|
-
menuContentPadding,
|
|
232
|
-
'text-2xs font-semibold text-muted-foreground uppercase',
|
|
233
|
-
local.class
|
|
234
|
-
)}
|
|
235
|
-
{...rest}
|
|
236
|
-
/>
|
|
237
|
-
)
|
|
244
|
+
return <KobalteNavigationMenu.GroupLabel class={cn(menuLabel, local.class)} {...rest} />
|
|
238
245
|
}
|
|
239
246
|
|
|
240
247
|
export function NavigationMenuGroup(props: ComponentProps<typeof KobalteNavigationMenu.Group>) {
|
|
@@ -10,6 +10,7 @@ import { Show, splitProps } from 'solid-js'
|
|
|
10
10
|
import { cva, type VariantProps } from '#lib/variants'
|
|
11
11
|
import { cn } from '#lib/utils'
|
|
12
12
|
import { createDialogFocusRestoration, DialogOverlay } from '../dialog/dialog'
|
|
13
|
+
import { headingVariants } from '../typography'
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Sheet.
|
|
@@ -152,7 +153,10 @@ export function SheetFooter(props: ComponentProps<'div'>) {
|
|
|
152
153
|
export function SheetTitle(props: ComponentProps<typeof KobalteDialog.Title>) {
|
|
153
154
|
const [local, rest] = splitProps(props, ['class'])
|
|
154
155
|
return (
|
|
155
|
-
<KobalteDialog.Title
|
|
156
|
+
<KobalteDialog.Title
|
|
157
|
+
class={cn(headingVariants({ size: 'subsection', leading: 'none' }), local.class)}
|
|
158
|
+
{...rest}
|
|
159
|
+
/>
|
|
156
160
|
)
|
|
157
161
|
}
|
|
158
162
|
|
|
@@ -13,6 +13,7 @@ import { cn } from '#lib/utils'
|
|
|
13
13
|
|
|
14
14
|
type TabsIdContextValue = {
|
|
15
15
|
id: Accessor<string>
|
|
16
|
+
orientation: Accessor<'horizontal' | 'vertical'>
|
|
16
17
|
triggerIds: Accessor<ReadonlyMap<string, string>>
|
|
17
18
|
registerTriggerId: (value: string, id: string) => void
|
|
18
19
|
unregisterTriggerId: (value: string, id: string) => void
|
|
@@ -43,6 +44,7 @@ export function Tabs(props: ComponentProps<typeof KobalteTabs>) {
|
|
|
43
44
|
const [triggerIds, setTriggerIds] = createSignal<ReadonlyMap<string, string>>(new Map())
|
|
44
45
|
const tabs: TabsIdContextValue = {
|
|
45
46
|
id,
|
|
47
|
+
orientation: () => rest.orientation ?? 'horizontal',
|
|
46
48
|
triggerIds,
|
|
47
49
|
registerTriggerId: (value, triggerId) => {
|
|
48
50
|
setTriggerIds((current) => new Map(current).set(value, triggerId))
|
|
@@ -103,6 +105,19 @@ export type TabsTriggerProps = ComponentProps<typeof KobalteTabs.Trigger> & {
|
|
|
103
105
|
appearance?: 'underline' | 'segmented'
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
/**
|
|
109
|
+
* The underline appearance marks the selected trigger on the edge it shares
|
|
110
|
+
* with the list's axis. A horizontal row reads left to right along a baseline,
|
|
111
|
+
* so the mark is a bottom bar sitting on the list's rule. A vertical list stacks
|
|
112
|
+
* its triggers, and a bottom bar there underlines one row of a column — it reads
|
|
113
|
+
* as a divider, not a selection — so the mark moves to the inline-start edge,
|
|
114
|
+
* the leading bar a side navigation uses, and the label aligns to that edge.
|
|
115
|
+
*
|
|
116
|
+
* The orientation is read from the root rather than from a `data-orientation`
|
|
117
|
+
* selector so the vertical classes are unprefixed: a composite that replaces the
|
|
118
|
+
* mark (SettingsNavigation's filled row passes `border-0`) then overrides it
|
|
119
|
+
* through the ordinary class merge instead of fighting a variant-scoped border.
|
|
120
|
+
*/
|
|
106
121
|
export function TabsTrigger(props: TabsTriggerProps) {
|
|
107
122
|
const [local, rest] = splitProps(props, ['class', 'appearance', 'id'])
|
|
108
123
|
const tabs = useTabsId()
|
|
@@ -128,7 +143,9 @@ export function TabsTrigger(props: TabsTriggerProps) {
|
|
|
128
143
|
'[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4',
|
|
129
144
|
local.appearance === 'segmented'
|
|
130
145
|
? 'h-control-sm rounded-md px-control-sm data-[selected]:bg-card data-[selected]:shadow-xs'
|
|
131
|
-
:
|
|
146
|
+
: tabs.orientation() === 'vertical'
|
|
147
|
+
? 'h-control-md justify-start rounded-none border-s-2 border-transparent ps-3 pe-2 data-[selected]:border-primary'
|
|
148
|
+
: 'h-control-md -mb-px rounded-none border-b-2 border-transparent px-2 pb-2 data-[selected]:border-primary',
|
|
132
149
|
local.class
|
|
133
150
|
)}
|
|
134
151
|
{...rest}
|
|
@@ -180,6 +180,10 @@ export type ToasterProps = ComponentProps<typeof KobalteToast.Region> & {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
/**
|
|
183
|
+
* `class` lands on the region too: the props describe the region, and the
|
|
184
|
+
* region is the element a caller lays out (an inset clear of a status bar, a
|
|
185
|
+
* narrower stack). The list inside it is an implementation detail.
|
|
186
|
+
*
|
|
183
187
|
* The corner is set on the region, not the list. The region is the `fixed`
|
|
184
188
|
* element: an inset on the list inside it positions nothing, and the region falls
|
|
185
189
|
* back to wherever it happens to sit in the document flow.
|
|
@@ -217,16 +221,13 @@ export function Toaster(props: ToasterProps) {
|
|
|
217
221
|
*/
|
|
218
222
|
class={cn(
|
|
219
223
|
'pointer-events-none fixed z-(--z-toast) flex max-h-screen w-full flex-col gap-2 p-4 sm:max-w-sm',
|
|
220
|
-
toasterPosition[local.position ?? 'bottom-right']
|
|
224
|
+
toasterPosition[local.position ?? 'bottom-right'],
|
|
225
|
+
local.class
|
|
221
226
|
)}
|
|
222
227
|
{...rest}
|
|
223
228
|
>
|
|
224
229
|
<KobalteToast.List
|
|
225
|
-
class={cn(
|
|
226
|
-
'flex flex-col gap-2',
|
|
227
|
-
toasterAlignment[local.position ?? 'bottom-right'],
|
|
228
|
-
local.class
|
|
229
|
-
)}
|
|
230
|
+
class={cn('flex flex-col gap-2', toasterAlignment[local.position ?? 'bottom-right'])}
|
|
230
231
|
/>
|
|
231
232
|
</KobalteToast.Region>
|
|
232
233
|
)
|