@adea-ai/ui 0.99.0 → 0.99.2

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 (104) hide show
  1. package/dist/components/composites/appearance-editor/appearance-choices.d.ts.map +1 -1
  2. package/dist/components/composites/appearance-editor/appearance-choices.js +32 -28
  3. package/dist/components/composites/appearance-editor/appearance-choices.js.map +1 -1
  4. package/dist/components/composites/appearance-editor/appearance-rows.d.ts.map +1 -1
  5. package/dist/components/composites/appearance-editor/appearance-rows.js +1 -1
  6. package/dist/components/composites/appearance-editor/appearance-rows.js.map +1 -1
  7. package/dist/components/layout/orbit-layout/orbit-layout.d.ts +5 -1
  8. package/dist/components/layout/orbit-layout/orbit-layout.d.ts.map +1 -1
  9. package/dist/components/layout/orbit-layout/orbit-layout.js.map +1 -1
  10. package/dist/components/layout/side-rail/side-rail.d.ts +4 -1
  11. package/dist/components/layout/side-rail/side-rail.d.ts.map +1 -1
  12. package/dist/components/layout/side-rail/side-rail.js +58 -64
  13. package/dist/components/layout/side-rail/side-rail.js.map +1 -1
  14. package/dist/components/layout/sidebar-nav/sidebar-nav.js +2 -2
  15. package/dist/components/layout/sidebar-nav/sidebar-nav.js.map +1 -1
  16. package/dist/components/motion/presence.d.ts +17 -7
  17. package/dist/components/motion/presence.d.ts.map +1 -1
  18. package/dist/components/motion/presence.js.map +1 -1
  19. package/dist/components/theme/theme-picker.d.ts.map +1 -1
  20. package/dist/components/theme/theme-picker.js +1 -1
  21. package/dist/components/theme/theme-picker.js.map +1 -1
  22. package/dist/components/theme/theme-provider.d.ts.map +1 -1
  23. package/dist/components/theme/theme-provider.js +15 -4
  24. package/dist/components/theme/theme-provider.js.map +1 -1
  25. package/dist/components/ui/aspect-ratio/aspect-ratio.d.ts +2 -2
  26. package/dist/components/ui/aspect-ratio/aspect-ratio.d.ts.map +1 -1
  27. package/dist/components/ui/aspect-ratio/aspect-ratio.js +15 -1
  28. package/dist/components/ui/aspect-ratio/aspect-ratio.js.map +1 -1
  29. package/dist/components/ui/badge/badge.d.ts +1 -1
  30. package/dist/components/ui/button/button.d.ts +1 -1
  31. package/dist/components/ui/calendar/calendar.d.ts.map +1 -1
  32. package/dist/components/ui/calendar/calendar.js +1 -1
  33. package/dist/components/ui/calendar/calendar.js.map +1 -1
  34. package/dist/components/ui/card/card.d.ts +2 -2
  35. package/dist/components/ui/card/card.js +2 -2
  36. package/dist/components/ui/card/card.js.map +1 -1
  37. package/dist/components/ui/chart/chart-options.d.ts +50 -0
  38. package/dist/components/ui/chart/chart-options.d.ts.map +1 -0
  39. package/dist/components/ui/chart/chart-options.js +178 -0
  40. package/dist/components/ui/chart/chart-options.js.map +1 -0
  41. package/dist/components/ui/chart/chart.d.ts +21 -18
  42. package/dist/components/ui/chart/chart.d.ts.map +1 -1
  43. package/dist/components/ui/chart/chart.js +175 -155
  44. package/dist/components/ui/chart/chart.js.map +1 -1
  45. package/dist/components/ui/chart/index.js +2 -1
  46. package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts.map +1 -1
  47. package/dist/components/ui/dropdown-menu/dropdown-menu.js +4 -2
  48. package/dist/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
  49. package/dist/components/ui/input-otp/input-otp.d.ts.map +1 -1
  50. package/dist/components/ui/input-otp/input-otp.js +2 -2
  51. package/dist/components/ui/input-otp/input-otp.js.map +1 -1
  52. package/dist/components/ui/pagination/pagination.d.ts.map +1 -1
  53. package/dist/components/ui/pagination/pagination.js +1 -1
  54. package/dist/components/ui/pagination/pagination.js.map +1 -1
  55. package/dist/components/ui/resizable/resizable.d.ts +0 -12
  56. package/dist/components/ui/resizable/resizable.d.ts.map +1 -1
  57. package/dist/components/ui/resizable/resizable.js +43 -9
  58. package/dist/components/ui/resizable/resizable.js.map +1 -1
  59. package/dist/lib/cn-tables.generated.js +10 -10
  60. package/dist/lib/cn-tables.generated.js.map +1 -1
  61. package/dist/r/chart.json +5 -0
  62. package/dist/r/registry.json +5 -0
  63. package/dist/r/src/components/composites/appearance-editor/appearance-choices.tsx +35 -20
  64. package/dist/r/src/components/composites/appearance-editor/appearance-rows.tsx +6 -2
  65. package/dist/r/src/components/layout/orbit-layout/orbit-layout.tsx +5 -1
  66. package/dist/r/src/components/layout/side-rail/side-rail.tsx +29 -16
  67. package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +2 -2
  68. package/dist/r/src/components/motion/presence.tsx +17 -7
  69. package/dist/r/src/components/theme/theme-picker.tsx +5 -1
  70. package/dist/r/src/components/theme/theme-provider.tsx +19 -9
  71. package/dist/r/src/components/ui/aspect-ratio/aspect-ratio.tsx +14 -3
  72. package/dist/r/src/components/ui/calendar/calendar.tsx +6 -1
  73. package/dist/r/src/components/ui/card/card.tsx +2 -2
  74. package/dist/r/src/components/ui/chart/chart-options.ts +196 -0
  75. package/dist/r/src/components/ui/chart/chart.tsx +149 -101
  76. package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +10 -2
  77. package/dist/r/src/components/ui/input-otp/input-otp.tsx +14 -2
  78. package/dist/r/src/components/ui/pagination/pagination.tsx +8 -1
  79. package/dist/r/src/components/ui/resizable/resizable.tsx +46 -8
  80. package/dist/r/src/lib/cn-tables.generated.ts +10 -10
  81. package/dist/r/src/styles/base.css +4 -1
  82. package/dist/r/src/styles/theme.css +23 -43
  83. package/package.json +1 -1
  84. package/registry.json +5 -0
  85. package/src/components/composites/appearance-editor/appearance-choices.tsx +35 -20
  86. package/src/components/composites/appearance-editor/appearance-rows.tsx +6 -2
  87. package/src/components/layout/orbit-layout/orbit-layout.tsx +5 -1
  88. package/src/components/layout/side-rail/side-rail.tsx +29 -16
  89. package/src/components/layout/sidebar-nav/sidebar-nav.tsx +2 -2
  90. package/src/components/motion/presence.tsx +17 -7
  91. package/src/components/theme/theme-picker.tsx +5 -1
  92. package/src/components/theme/theme-provider.tsx +19 -9
  93. package/src/components/ui/aspect-ratio/aspect-ratio.tsx +14 -3
  94. package/src/components/ui/calendar/calendar.tsx +6 -1
  95. package/src/components/ui/card/card.tsx +2 -2
  96. package/src/components/ui/chart/chart-options.ts +196 -0
  97. package/src/components/ui/chart/chart.tsx +149 -101
  98. package/src/components/ui/dropdown-menu/dropdown-menu.tsx +10 -2
  99. package/src/components/ui/input-otp/input-otp.tsx +14 -2
  100. package/src/components/ui/pagination/pagination.tsx +8 -1
  101. package/src/components/ui/resizable/resizable.tsx +46 -8
  102. package/src/lib/cn-tables.generated.ts +10 -10
  103. package/src/styles/base.css +4 -1
  104. 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 resolve from `--chart-1` through `--chart-5`, which every theme
50
- * defines, plus `--chart-grid`, `--chart-axis` and `--chart-label`. That means a
51
- * chart follows the accent axis, the appearance, and the font axis with no
52
- * per-chart configuration — and a caller that wants a specific series colour
53
- * passes it explicitly rather than reaching into the theme.
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
- /** The five series colours, in the order a multi-series chart should use them. */
82
- export const chartSeriesColors = [
83
- 'var(--chart-1)',
84
- 'var(--chart-2)',
85
- 'var(--chart-3)',
86
- 'var(--chart-4)',
87
- 'var(--chart-5)',
88
- ] as const
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
- * The theme's defaults as Chart.js options.
123
+ * Resolves `var(--token)` strings against a chart's element, and re-resolves
124
+ * them when the theme changes.
92
125
  *
93
- * Exported so a caller can spread it and change one thing, rather than
94
- * restating every colour. Everything a chart draws that is not data — grid,
95
- * ticks, legend, tooltip — is decided here once, which is what makes two charts
96
- * in one application look like they came from the same place.
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
- export function chartOptions(overrides?: ChartOptions): ChartOptions {
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
- responsive: true,
101
- maintainAspectRatio: false,
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
- scales: {
131
- x: {
132
- border: { color: 'var(--chart-grid)' },
133
- grid: { color: 'var(--chart-grid)', drawTicks: false },
134
- ticks: { color: 'var(--chart-axis)', font: { size: 10 } },
135
- },
136
- y: {
137
- border: { display: false },
138
- grid: { color: 'var(--chart-grid)', drawTicks: false },
139
- ticks: { color: 'var(--chart-axis)', font: { size: 10 } },
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(props: SeriesChartProps, extra?: ChartOptions): ChartOptions {
210
- return chartOptions({
211
- ...extra,
212
- ...(props.stacked
213
- ? { scales: { ...extra?.scales, x: { stacked: true }, y: { stacked: true } } }
214
- : {}),
215
- ...props.options,
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={{ labels: [...props.labels], datasets: datasetsFor(props.series, true) }}
309
- options={seriesOptions(props, { scales: { r: { grid: { color: 'var(--chart-grid)' } } } })}
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
- /** A polar area chart: radial bars, for a composition. */
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
  )
@@ -153,7 +153,10 @@ export function DropdownMenuCheckboxItem(
153
153
  return (
154
154
  <KobalteDropdownMenu.CheckboxItem class={cn(menuItem, 'pe-8', local.class)} {...rest}>
155
155
  {local.children}
156
- <KobalteDropdownMenu.ItemIndicator class="absolute end-2 flex size-4 items-center justify-center">
156
+ <KobalteDropdownMenu.ItemIndicator
157
+ data-slot="dropdown-menu-indicator"
158
+ class="absolute end-2 flex size-4 items-center justify-center text-primary"
159
+ >
157
160
  <Check class="size-4" />
158
161
  </KobalteDropdownMenu.ItemIndicator>
159
162
  </KobalteDropdownMenu.CheckboxItem>
@@ -172,7 +175,12 @@ export function DropdownMenuRadioItem(props: ComponentProps<typeof KobalteDropdo
172
175
  return (
173
176
  <KobalteDropdownMenu.RadioItem class={cn(menuItem, 'pe-8', local.class)} {...rest}>
174
177
  {local.children}
175
- <KobalteDropdownMenu.ItemIndicator class="absolute end-2 flex size-4 items-center justify-center">
178
+ {/* The indicator reads in the accent, like every other selected state in
179
+ the system — a canvas-colored dot on a checked row reads as decoration. */}
180
+ <KobalteDropdownMenu.ItemIndicator
181
+ data-slot="dropdown-menu-indicator"
182
+ class="absolute end-2 flex size-4 items-center justify-center text-primary"
183
+ >
176
184
  <Circle class="size-2 fill-current" />
177
185
  </KobalteDropdownMenu.ItemIndicator>
178
186
  </KobalteDropdownMenu.RadioItem>
@@ -38,7 +38,17 @@ export function InputOtp(props: InputOtpProps) {
38
38
  return (
39
39
  <OtpField
40
40
  maxLength={length()}
41
- class={cn('flex items-center gap-2', local.class)}
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={props.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>
@@ -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
- class={cn('flex w-full items-center justify-center gap-1', local.class)}
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 />}>
@@ -1,7 +1,7 @@
1
1
  import Resizable from '@corvu/resizable'
2
2
  import { GripVertical } from 'lucide-solid'
3
3
  import type { ComponentProps } from 'solid-js'
4
- import { splitProps } from 'solid-js'
4
+ import { createContext, splitProps, useContext } from 'solid-js'
5
5
  import { cn } from '../../../lib/utils'
6
6
 
7
7
  /**
@@ -16,20 +16,54 @@ import { cn } from '../../../lib/utils'
16
16
  * is a real focusable element with an accessible role, so a split pane can be
17
17
  * adjusted from the keyboard; a bare `cursor-col-resize` div cannot.
18
18
  */
19
+ /**
20
+ * Whether the group was given `initialSizes`. Those are corvu's to apply, and a
21
+ * panel's own `initialSize` overrides them — so an unsized panel must not invent
22
+ * one when the group already has an answer.
23
+ */
24
+ const GroupSizesContext = createContext<() => boolean>(() => false)
25
+
19
26
  export function ResizablePanelGroup(props: ComponentProps<typeof Resizable> & { class?: string }) {
20
27
  const [local, rest] = splitProps(props, ['class'])
21
28
 
22
29
  return (
23
- <Resizable
24
- class={cn('flex size-full data-[orientation=vertical]:flex-col', local.class)}
25
- {...rest}
26
- />
30
+ <GroupSizesContext.Provider value={() => rest.initialSizes !== undefined}>
31
+ <Resizable
32
+ class={cn('flex size-full data-[orientation=vertical]:flex-col', local.class)}
33
+ {...rest}
34
+ />
35
+ </GroupSizesContext.Provider>
27
36
  )
28
37
  }
29
38
 
39
+ /**
40
+ * The size an unsized panel registers with: whatever its earlier siblings left.
41
+ *
42
+ * corvu registers a panel without `initialSize` at a flat 50%, so `0.28` beside
43
+ * an unsized panel summed to 78% and left a gap. Panels register in document
44
+ * order, so at registration `sizes` holds exactly the panels before this one.
45
+ * When nothing is left — a second unsized panel — it takes an equal share, and
46
+ * corvu shrinks the earlier panels by that share to keep the total at 100%.
47
+ */
48
+ function remainingSize(sizes: readonly number[]): number {
49
+ const left = 1 - sizes.reduce((total, size) => total + size, 0)
50
+ return left > 0.001 ? left : 1 / (sizes.length + 1)
51
+ }
52
+
30
53
  export function ResizablePanel(props: ComponentProps<typeof Resizable.Panel> & { class?: string }) {
31
- const [local, rest] = splitProps(props, ['class'])
32
- return <Resizable.Panel class={cn('min-h-0 min-w-0 overflow-hidden', local.class)} {...rest} />
54
+ const [local, rest] = splitProps(props, ['class', 'initialSize'])
55
+ const group = Resizable.useContext(rest.contextId)
56
+ const groupHasSizes = useContext(GroupSizesContext)
57
+
58
+ return (
59
+ <Resizable.Panel
60
+ initialSize={
61
+ local.initialSize ?? (groupHasSizes() ? undefined : remainingSize(group.sizes()))
62
+ }
63
+ class={cn('min-h-0 min-w-0 overflow-hidden', local.class)}
64
+ {...rest}
65
+ />
66
+ )
33
67
  }
34
68
 
35
69
  export type ResizableHandleProps = ComponentProps<typeof Resizable.Handle> & {
@@ -46,11 +80,15 @@ export type ResizableHandleProps = ComponentProps<typeof Resizable.Handle> & {
46
80
 
47
81
  export function ResizableHandle(props: ResizableHandleProps) {
48
82
  const [local, rest] = splitProps(props, ['class', 'withHandle', 'label'])
83
+ const group = Resizable.useContext(rest.contextId)
49
84
 
50
85
  return (
51
86
  <Resizable.Handle
52
87
  aria-label={local.label ?? 'Resize panels'}
53
- aria-orientation="vertical"
88
+ // A separator's orientation is the line's own, which runs across the
89
+ // group: a row of panels is divided by a vertical line, a column by a
90
+ // horizontal one. corvu reports the group's orientation instead.
91
+ aria-orientation={group.orientation() === 'horizontal' ? 'vertical' : 'horizontal'}
54
92
  class={cn(
55
93
  'group/resize bg-border relative flex w-px shrink-0 items-center justify-center',
56
94
  /* Widen the hit target without moving the visual line: the divider is
@@ -54,7 +54,7 @@ const DZ = (s: string): Int32Array => {
54
54
  }
55
55
  return out
56
56
  }
57
- const GROUP_COUNT = 387
57
+ const GROUP_COUNT = 384
58
58
  const customValidatorNames: string[] = []
59
59
  const edgeStart = PS(U("E0500002005282000000002000150000020021820000011200000003022202000300004200120000200420001200021200301200010400162000010000220021010:2192001200220012000220012000200200200400010200040000000000400200108200110100000022010313000162002000020020012020080213000228200000000082000000000120002000120020020040101020300130001001010"))
60
60
  const labelStart = PS(U(":11111111211111119311546544411119731869:671397415686432441111111111161114151214313433415:78311132233313187211117221449443411141111151152226611131111112212518142224214215421421542142424242516171151615616347111111111197911327451111111111111111111113134714133513411111311111111111111111111112444411111342312715245411117:3"))
@@ -91,7 +91,7 @@ const nodeVlist = (() => {
91
91
  for (let i = 0; i < A.length; i++) out[A[i]!] = V[i]!
92
92
  return out
93
93
  })()
94
- const SETS = "container |break-after- all auto avoid avoid-page column left page right|break-before- all auto avoid avoid-page column left page right|break-inside-a uto void void-column void-page|box-decoration- clone slice|box- border content| contents flow-root hidden table table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group| not-sr-only sr-only|float- end left none right start|clear- both end left none right start|isolat e ion-auto|overflow- auto clip hidden scroll visible|overflow-x- auto clip hidden scroll visible|overflow-y- auto clip hidden scroll visible|overscroll- auto contain none|overscroll-x- auto contain none|overscroll-y- auto contain none| absolute fixed relative static sticky| collapse invisible visible|justify- around baseline between center center-safe end end-safe evenly normal start stretch|justify-items- center center-safe end end-safe normal start stretch|justify-self- auto center center-safe end end-safe start stretch|items- baseline baseline-last center center-safe end end-safe start stretch|self- auto baseline baseline-last center center-safe end end-safe start stretch|place-content- around baseline between center center-safe end end-safe evenly start stretch|place-items- baseline center center-safe end end-safe start stretch|place-self- auto center center-safe end end-safe start stretch| antialiased subpixel-antialiased| italic not-italic|normal-nums |ordinal |slashed-zero | lining-nums oldstyle-nums| proportional-nums tabular-nums| diagonal-fractions stacked-fractions| no-underline overline| capitalize lowercase normal-case uppercase|truncate |whitespace- break-spaces normal nowrap pre pre-line pre-wrap|break- all keep normal words|wrap- anywhere break-word normal|hyphens- auto manual none|mix-blend- color color-burn color-dodge darken difference exclusion hard-light hue lighten luminosity multiply normal overlay plus-darker plus-lighter saturation screen soft-light|table- auto fixed|caption- bottom top|backface- hidden visible|appearance- auto none|scheme- dark light light-dark normal only-dark only-light|field-sizing- content fixed|pointer-events- auto none|resize -none -x -y|snap- align-none center end start|snap- always normal|snap- both none x y|snap- mandatory proximity|touch- auto manipulation none|touch-pan- left right x|touch-pan- down up y|touch-pinch-zoom |select- all auto none text|forced-color-adjust- auto none| normal size| baseline bottom middle sub super text-bottom text-top top| bounce none ping pulse spin| auto square video| auto fr max min px|none | auto full px| fixed local scroll|clip- border content padding text|origin- border content padding| bottom bottom-left bottom-right center left left-bottom left-top right right-bottom right-top top top-left top-right| no-repeat repeat repeat-round repeat-space repeat-x repeat-y| auto contain cover| gradient-to-b gradient-to-bl gradient-to-br gradient-to-l gradient-to-r gradient-to-t gradient-to-tl gradient-to-tr none|blend- color color-burn color-dodge darken difference exclusion hard-light hue lighten luminosity multiply normal overlay saturation screen soft-light|to- b bl br l r t tl tr| auto dvh fit full lh lvh max min px screen svh| dashed dotted double hidden none solid| collapse separate|px |auto |full | content none strict| inline-size size|layout |paint |style | around baseline between center center-safe end end-safe evenly normal start stretch| alias all-scroll auto cell col-resize context-menu copy crosshair default e-resize ew-resize grab grabbing help move n-resize ne-resize nesw-resize no-drop none not-allowed ns-resize nw-resize nwse-resize pointer progress row-resize s-resize se-resize sw-resize text vertical-text w-resize wait zoom-in zoom-out| dashed dotted double solid wavy| auto from-font|reverse |initial | in in-out initial linear out| col col-reverse row row-reverse| nowrap wrap wrap-reverse| auto initial none| black bold extrabold extralight light medium normal semibold thin| condensed expanded extra-condensed extra-expanded normal semi-condensed semi-expanded ultra-condensed ultra-expanded|flow- col col-dense dense row row-dense| none subgrid| auto dvh dvw fit full lh lvh lvw max min px screen svh svw| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs rail-item row-lg row-md row-sm statusbar topbar| block flex grid table| auto dvw fit full lvw max min px screen svw| loose none normal px relaxed snug tight|through |item | inside outside| decimal disc none| auto px| clip-border clip-content clip-fill clip-padding clip-stroke clip-view no-clip| add exclude intersect subtract| alpha luminance match|origin- border content fill padding stroke view|type- alpha luminance| circle ellipse| closest-corner closest-side farthest-corner farthest-side|at- bottom bottom-left bottom-right center left left-bottom left-top right right-bottom right-top top top-left top-right| dvh fit full lh lvh max min none px screen svh| auto dvh dvw fit full lh lvh lvw max min none px screen svh svw| dvw fit full lvw max min none px screen svw| auto dvh dvw fit full lvh lvw max min none prose px svh svw| auto dvh dvw fit full lvh lvw max min none px screen svh svw| contain cover fill none scale-down| first last none| distant dramatic midrange near none normal|inset | full none|3d | auto smooth|gutter- auto both stable| auto none thin| inner none| auto dvh dvw fit full lvh lvw max min px svh svw| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs rail-item|base | center end justify left right start| clip ellipsis| balance nowrap pretty wrap| normal tight tighter wide wider widest| cpu gpu none| 3d flat| all colors none opacity shadow transform| discrete normal| full px| auto dvh dvw fit full lvh lvw max min px screen svh svw| rail rail-expanded sidebar sidebar-compact| auto contents scroll transform".split('|').map((s) => {
94
+ const SETS = "container |break-after- all auto avoid avoid-page column left page right|break-before- all auto avoid avoid-page column left page right|break-inside-a uto void void-column void-page|box-decoration- clone slice|box- border content| contents flow-root hidden table table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group| not-sr-only sr-only|float- end left none right start|clear- both end left none right start|isolat e ion-auto|overflow- auto clip hidden scroll visible|overflow-x- auto clip hidden scroll visible|overflow-y- auto clip hidden scroll visible|overscroll- auto contain none|overscroll-x- auto contain none|overscroll-y- auto contain none| absolute fixed relative static sticky| collapse invisible visible|justify- around baseline between center center-safe end end-safe evenly normal start stretch|justify-items- center center-safe end end-safe normal start stretch|justify-self- auto center center-safe end end-safe start stretch|items- baseline baseline-last center center-safe end end-safe start stretch|self- auto baseline baseline-last center center-safe end end-safe start stretch|place-content- around baseline between center center-safe end end-safe evenly start stretch|place-items- baseline center center-safe end end-safe start stretch|place-self- auto center center-safe end end-safe start stretch| antialiased subpixel-antialiased| italic not-italic|normal-nums |ordinal |slashed-zero | lining-nums oldstyle-nums| proportional-nums tabular-nums| diagonal-fractions stacked-fractions| no-underline overline| capitalize lowercase normal-case uppercase|truncate |whitespace- break-spaces normal nowrap pre pre-line pre-wrap|break- all keep normal words|wrap- anywhere break-word normal|hyphens- auto manual none|mix-blend- color color-burn color-dodge darken difference exclusion hard-light hue lighten luminosity multiply normal overlay plus-darker plus-lighter saturation screen soft-light|table- auto fixed|caption- bottom top|backface- hidden visible|appearance- auto none|scheme- dark light light-dark normal only-dark only-light|field-sizing- content fixed|pointer-events- auto none|resize -none -x -y|snap- align-none center end start|snap- always normal|snap- both none x y|snap- mandatory proximity|touch- auto manipulation none|touch-pan- left right x|touch-pan- down up y|touch-pinch-zoom |select- all auto none text|forced-color-adjust- auto none| normal size| baseline bottom middle sub super text-bottom text-top top| bounce none ping pulse spin| auto square video| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs fr max min px|none | auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs full px| fixed local scroll|clip- border content padding text|origin- border content padding| bottom bottom-left bottom-right center left left-bottom left-top right right-bottom right-top top top-left top-right| no-repeat repeat repeat-round repeat-space repeat-x repeat-y| auto contain cover| gradient-to-b gradient-to-bl gradient-to-br gradient-to-l gradient-to-r gradient-to-t gradient-to-tl gradient-to-tr none|blend- color color-burn color-dodge darken difference exclusion hard-light hue lighten luminosity multiply normal overlay saturation screen soft-light|to- b bl br l r t tl tr| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh fit full lh lvh max min px screen svh| dashed dotted double hidden none solid| collapse separate| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs px|auto |full | content none strict| inline-size size|layout |paint |style | around baseline between center center-safe end end-safe evenly normal start stretch| alias all-scroll auto cell col-resize context-menu copy crosshair default e-resize ew-resize grab grabbing help move n-resize ne-resize nesw-resize no-drop none not-allowed ns-resize nw-resize nwse-resize pointer progress row-resize s-resize se-resize sw-resize text vertical-text w-resize wait zoom-in zoom-out| dashed dotted double solid wavy| auto from-font|reverse |initial | in in-out initial linear out| col col-reverse row row-reverse| nowrap wrap wrap-reverse| auto initial none| black bold extrabold extralight light medium normal semibold thin| condensed expanded extra-condensed extra-expanded normal semi-condensed semi-expanded ultra-condensed ultra-expanded|flow- col col-dense dense row row-dense| none subgrid| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lh lvh lvw max min px rail-item row-lg row-md row-sm screen statusbar svh svw topbar| block flex grid table| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvw fit full lvw max min px screen svw| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs loose none normal px relaxed snug tight|through |item | inside outside| decimal disc none| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs px| clip-border clip-content clip-fill clip-padding clip-stroke clip-view no-clip| add exclude intersect subtract| alpha luminance match|origin- border content fill padding stroke view|type- alpha luminance| circle ellipse| closest-corner closest-side farthest-corner farthest-side|at- bottom bottom-left bottom-right center left left-bottom left-top right right-bottom right-top top top-left top-right| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh fit full lh lvh max min none px screen svh| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lh lvh lvw max min none px rail-item row-lg row-md row-sm screen statusbar svh svw topbar| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvw fit full lvw max min none px screen svw| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min none prose px rail rail-expanded sidebar sidebar-compact svh svw| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min none px rail rail-expanded screen sidebar sidebar-compact svh svw| contain cover fill none scale-down| first last none| distant dramatic midrange near none normal|inset | full none|3d | auto smooth|gutter- auto both stable| auto none thin| inner none| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min px rail-item svh svw|base | center end justify left right start| clip ellipsis| balance nowrap pretty wrap| normal tight tighter wide wider widest| cpu gpu none| 3d flat| all colors none opacity shadow transform| discrete normal| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs full px| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min px rail rail-expanded screen sidebar sidebar-compact svh svw| auto contents scroll transform".split('|').map((s) => {
95
95
  const tails = s.split(' ')
96
96
  const prefix = tails.shift()!
97
97
  for (let i = 0; i < tails.length; i++) {
@@ -99,12 +99,12 @@ const SETS = "container |break-after- all auto avoid avoid-page column left page
99
99
  }
100
100
  return tails
101
101
  })
102
- const AA = DZ("0000000000000000000000000000000000000000000000000000000000000262242:6@200000006:240B428:44224000020460442224262200266426424062026224222824220022400000000\\00N222422242222222224062242222222422226264222422222222222222442804222422222222222222222222220<40<02042600024440202042244022")
103
- const AG = DZ("ɠ222222222222222222222222222222222222222222222222222222222222˕4222226>ʶ22ʷʺʷ2ʸʷ42ʴ2ʓ22>621422ɶ222ɹɼɷɺɷɺ22ɱ42222ɨ2ɧ26622ɘɓ24ɐɋƸƵ222]d24242ǖǓƚÆȭ2263ȪȧȪ2222222ǥ222222222222222222DŽƿ2ǀƷ2222222422222ƞƓ22222222222222222222144Ũť22Ťš222222222222222222222ĺ2ij6İħĪħĪɥŰ4Ĥ¯²ġ822ĘĕĘ2ė22226Čĉ2")
104
- const AS = DZ("02222222222222222222222222222222222222222222222222222222222222222202022222222222EH2200IL021042222Y\\222IL0cf2e10j2222U00X2022]`2{0000120~}€„22‡Š‰:22~22222222222G000sˆOVI00000œ2>40000ŽŸB00000Iª«000®00000000000000021M°¯00²•000000000000000000000˜2222ŸHGHa1¾222Ã2Ä2222ÍÐ000±´22·")
105
- const litAnchor = new Int32Array(1020)
106
- const litGroup = new Int32Array(1020)
107
- const litPool = new Int32Array(1020)
102
+ const AA = DZ("0000000000000000000000000000000000000000000000000000000000000262242:6@200000006:240B428:4422400002046044222426220026642642462026224222824220022400000000\\00N222422242222222224062242222222422226264222422222222222222442804222422222222222222222222220<4<0204260002444020204224422")
103
+ const AG = DZ("ɠ222222222222222222222222222222222222222222222222222222222222˕4222226>ʶ22ʷʺʷ2ʸʷ42ʴ2ʓ22>621422ɶ222ɹɼɷɺɷɺ22ɱ42222ɨ2ɧ26622ɘɓ244ƸƵ222]d24242ǖǓƚÄȫ2263ȨȥȨ2222222ǣ222222222222222222ǂƽ2ƾƵ2222222422222ƜƑ22222222222222222222144Ŧţ22Ţş222222222222222222222ĸ2ı68ĦģĦɡŰ4Ġ«®ĝ822ĔđĔ2ē2222622")
104
+ const AS = DZ("02222222222222222222222222222222222222222222222222222222222222222202022222222222EH2200IL021042222Y\\222IL0cf2e10j2222U00X202[^2y0000120|{~‚22…ˆ‡:22|22222222222G000q†OVI00000}š2›>40000ŒB00000I¨©000¬00000000000000021M®­00°“000000000000000000000–222›HGHa1º222¿2À2222ÉÌ000­°2±")
105
+ const litAnchor = new Int32Array(1635)
106
+ const litGroup = new Int32Array(1635)
107
+ const litPool = new Int32Array(1635)
108
108
  let poolText = ''
109
109
  const poolOffsets = new Int32Array(1072)
110
110
  {
@@ -129,9 +129,9 @@ const poolOffsets = new Int32Array(1072)
129
129
  }
130
130
  }
131
131
  // conflict adjacency (engine builds claim bitmask CSR at init)
132
- const adjGid = DZ("0b2N:222@R>F@286¦2@H2D266226FB22B2>BD\\6N22222Z222D222t")
132
+ const adjGid = DZ("0b2N:222@R>F@286¦2@H2D266226FB22B2>BD\\6N22222Z222D222p")
133
133
  const adjStart = PS(U("1::24444432:442:44:44>222222:44:4421322511111311111114"))
134
- const adjTgt = DZ("2Š4A;33N=C@H4A;33N=C@<27;83:;8393NQ:3NQʰ222ˉºŴŽ2R2=18cƴÅҜ=cĞÛC1ƈǝȈ:ħ25=11D3A@4=<1;1DEr25;11B3?<6;:371BCn9@7=<8192>2E121@9@EHE@9>2T25511<398454131<=V25511<398454131<=„ƧNž2Ĕé242L222290000f22500ɛ000ǘ222")
134
+ const adjTgt = DZ("2Š4A;33N=C@H4A;33N=C@<27;83:;8393NQ:3NQʰ222ˉºŴŽ2R2=18cƴÅҜ=cĞÛC1ƈǝȈ:ħ25=11D3A@4=<1;1DEr25;11B3?<6;:371BCn9@7=<8192>2E121@9@EHE@9>2T25511<398454131<=V25511<398454131<=„ƧNž2Đå242L222290000f22500ɛ000ǘ222")
135
135
  const patGid = U("ij")
136
136
  const patTgt = U("—")
137
137
  const postfixLookupGroups = U("1")
@@ -59,8 +59,11 @@
59
59
  }
60
60
  }
61
61
 
62
+ /* Presence, like the variants above: corvu and Kobalte mark a selected item
63
+ with an empty attribute (`data-selected=""`), while cmdk writes `"true"` and
64
+ `"false"`. Matching only `'true'` left every corvu calendar day unfilled. */
62
65
  @custom-variant data-selected {
63
- &:where([data-selected='true']) {
66
+ &:where([data-selected]:not([data-selected='false'])) {
64
67
  @slot;
65
68
  }
66
69
  }