@adea-ai/ui 0.99.1 → 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 (89) hide show
  1. package/dist/components/layout/orbit-layout/orbit-layout.d.ts +5 -1
  2. package/dist/components/layout/orbit-layout/orbit-layout.d.ts.map +1 -1
  3. package/dist/components/layout/orbit-layout/orbit-layout.js.map +1 -1
  4. package/dist/components/layout/side-rail/side-rail.d.ts +4 -1
  5. package/dist/components/layout/side-rail/side-rail.d.ts.map +1 -1
  6. package/dist/components/layout/side-rail/side-rail.js +58 -64
  7. package/dist/components/layout/side-rail/side-rail.js.map +1 -1
  8. package/dist/components/layout/sidebar-nav/sidebar-nav.js +2 -2
  9. package/dist/components/layout/sidebar-nav/sidebar-nav.js.map +1 -1
  10. package/dist/components/motion/presence.d.ts +17 -7
  11. package/dist/components/motion/presence.d.ts.map +1 -1
  12. package/dist/components/motion/presence.js.map +1 -1
  13. package/dist/components/theme/theme-picker.d.ts.map +1 -1
  14. package/dist/components/theme/theme-picker.js +1 -1
  15. package/dist/components/theme/theme-picker.js.map +1 -1
  16. package/dist/components/theme/theme-provider.d.ts.map +1 -1
  17. package/dist/components/theme/theme-provider.js +15 -4
  18. package/dist/components/theme/theme-provider.js.map +1 -1
  19. package/dist/components/ui/aspect-ratio/aspect-ratio.d.ts +2 -2
  20. package/dist/components/ui/aspect-ratio/aspect-ratio.d.ts.map +1 -1
  21. package/dist/components/ui/aspect-ratio/aspect-ratio.js +15 -1
  22. package/dist/components/ui/aspect-ratio/aspect-ratio.js.map +1 -1
  23. package/dist/components/ui/badge/badge.d.ts +1 -1
  24. package/dist/components/ui/button/button.d.ts +1 -1
  25. package/dist/components/ui/calendar/calendar.d.ts.map +1 -1
  26. package/dist/components/ui/calendar/calendar.js +1 -1
  27. package/dist/components/ui/calendar/calendar.js.map +1 -1
  28. package/dist/components/ui/card/card.d.ts +2 -2
  29. package/dist/components/ui/card/card.js +2 -2
  30. package/dist/components/ui/card/card.js.map +1 -1
  31. package/dist/components/ui/chart/chart-options.d.ts +50 -0
  32. package/dist/components/ui/chart/chart-options.d.ts.map +1 -0
  33. package/dist/components/ui/chart/chart-options.js +178 -0
  34. package/dist/components/ui/chart/chart-options.js.map +1 -0
  35. package/dist/components/ui/chart/chart.d.ts +21 -18
  36. package/dist/components/ui/chart/chart.d.ts.map +1 -1
  37. package/dist/components/ui/chart/chart.js +175 -155
  38. package/dist/components/ui/chart/chart.js.map +1 -1
  39. package/dist/components/ui/chart/index.js +2 -1
  40. package/dist/components/ui/input-otp/input-otp.d.ts.map +1 -1
  41. package/dist/components/ui/input-otp/input-otp.js +2 -2
  42. package/dist/components/ui/input-otp/input-otp.js.map +1 -1
  43. package/dist/components/ui/pagination/pagination.d.ts.map +1 -1
  44. package/dist/components/ui/pagination/pagination.js +1 -1
  45. package/dist/components/ui/pagination/pagination.js.map +1 -1
  46. package/dist/components/ui/resizable/resizable.d.ts +0 -12
  47. package/dist/components/ui/resizable/resizable.d.ts.map +1 -1
  48. package/dist/components/ui/resizable/resizable.js +43 -9
  49. package/dist/components/ui/resizable/resizable.js.map +1 -1
  50. package/dist/lib/cn-tables.generated.js +10 -10
  51. package/dist/lib/cn-tables.generated.js.map +1 -1
  52. package/dist/r/chart.json +5 -0
  53. package/dist/r/registry.json +5 -0
  54. package/dist/r/src/components/layout/orbit-layout/orbit-layout.tsx +5 -1
  55. package/dist/r/src/components/layout/side-rail/side-rail.tsx +29 -16
  56. package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +2 -2
  57. package/dist/r/src/components/motion/presence.tsx +17 -7
  58. package/dist/r/src/components/theme/theme-picker.tsx +5 -1
  59. package/dist/r/src/components/theme/theme-provider.tsx +19 -9
  60. package/dist/r/src/components/ui/aspect-ratio/aspect-ratio.tsx +14 -3
  61. package/dist/r/src/components/ui/calendar/calendar.tsx +6 -1
  62. package/dist/r/src/components/ui/card/card.tsx +2 -2
  63. package/dist/r/src/components/ui/chart/chart-options.ts +196 -0
  64. package/dist/r/src/components/ui/chart/chart.tsx +149 -101
  65. package/dist/r/src/components/ui/input-otp/input-otp.tsx +14 -2
  66. package/dist/r/src/components/ui/pagination/pagination.tsx +8 -1
  67. package/dist/r/src/components/ui/resizable/resizable.tsx +46 -8
  68. package/dist/r/src/lib/cn-tables.generated.ts +10 -10
  69. package/dist/r/src/styles/base.css +4 -1
  70. package/dist/r/src/styles/theme.css +23 -43
  71. package/package.json +1 -1
  72. package/registry.json +5 -0
  73. package/src/components/layout/orbit-layout/orbit-layout.tsx +5 -1
  74. package/src/components/layout/side-rail/side-rail.tsx +29 -16
  75. package/src/components/layout/sidebar-nav/sidebar-nav.tsx +2 -2
  76. package/src/components/motion/presence.tsx +17 -7
  77. package/src/components/theme/theme-picker.tsx +5 -1
  78. package/src/components/theme/theme-provider.tsx +19 -9
  79. package/src/components/ui/aspect-ratio/aspect-ratio.tsx +14 -3
  80. package/src/components/ui/calendar/calendar.tsx +6 -1
  81. package/src/components/ui/card/card.tsx +2 -2
  82. package/src/components/ui/chart/chart-options.ts +196 -0
  83. package/src/components/ui/chart/chart.tsx +149 -101
  84. package/src/components/ui/input-otp/input-otp.tsx +14 -2
  85. package/src/components/ui/pagination/pagination.tsx +8 -1
  86. package/src/components/ui/resizable/resizable.tsx +46 -8
  87. package/src/lib/cn-tables.generated.ts +10 -10
  88. package/src/styles/base.css +4 -1
  89. package/src/styles/theme.css +23 -43
@@ -121,11 +121,23 @@ export function useTheme(): ThemeContextValue {
121
121
  return value
122
122
  }
123
123
 
124
+ /**
125
+ * The preference store, or nothing.
126
+ *
127
+ * Only ever called inside a `try`: where storage is blocked — a sandboxed iframe, a
128
+ * privacy mode, a denied site-data permission — merely *reading* the `localStorage`
129
+ * global throws ("Access is denied", `SecurityError`), so even the `typeof` guard
130
+ * has to sit inside the `try` rather than in front of it. Without a store the
131
+ * preference lives only in the provider's signal for the session.
132
+ */
133
+ function preferenceStore(): Storage | undefined {
134
+ return typeof localStorage === 'undefined' ? undefined : localStorage
135
+ }
136
+
124
137
  /** The stored preference, validated against the catalogue. */
125
138
  function readSelection(storageKey: string): ThemeSelection {
126
- if (typeof localStorage === 'undefined') return defaultThemeSelection
127
139
  try {
128
- const raw = localStorage.getItem(storageKey)
140
+ const raw = preferenceStore()?.getItem(storageKey)
129
141
  if (!raw) return defaultThemeSelection
130
142
  const parsed = JSON.parse(raw) as Partial<ThemeSelection>
131
143
  return {
@@ -268,13 +280,11 @@ export function ThemeProvider(props: ThemeProviderProps) {
268
280
  setSelection(patch) {
269
281
  const next = { ...selection(), ...patch }
270
282
  setSelectionState(next)
271
- if (typeof localStorage !== 'undefined') {
272
- try {
273
- localStorage.setItem(storageKey(), JSON.stringify(next))
274
- } catch {
275
- // A full or unavailable store must not break the switch: the preference
276
- // simply does not survive the reload.
277
- }
283
+ try {
284
+ preferenceStore()?.setItem(storageKey(), JSON.stringify(next))
285
+ } catch {
286
+ // A full, blocked or unavailable store must not break the switch: the
287
+ // preference simply does not survive the reload.
278
288
  }
279
289
  },
280
290
  }
@@ -1,4 +1,4 @@
1
- import type { ComponentProps } from 'solid-js'
1
+ import type { ComponentProps, JSX } from 'solid-js'
2
2
  import { splitProps } from 'solid-js'
3
3
  import { cn } from '../../../lib/utils'
4
4
 
@@ -22,13 +22,24 @@ export type AspectRatioProps = ComponentProps<'div'> & {
22
22
  ratio?: number
23
23
  }
24
24
 
25
+ /**
26
+ * The caller's style with the ratio laid over it. A spread `style` replaces the
27
+ * element's rather than merging, so passing any style used to drop the ratio and
28
+ * collapse the box to zero height. `ratio` is the API for the ratio, so it wins.
29
+ */
30
+ function withRatio(style: AspectRatioProps['style'], ratio: number): JSX.CSSProperties | string {
31
+ const value = String(ratio)
32
+ if (typeof style === 'string') return `${style};aspect-ratio:${value}`
33
+ return { ...style, 'aspect-ratio': value }
34
+ }
35
+
25
36
  export function AspectRatio(props: AspectRatioProps) {
26
- const [local, rest] = splitProps(props, ['class', 'ratio', 'children'])
37
+ const [local, rest] = splitProps(props, ['class', 'ratio', 'style', 'children'])
27
38
 
28
39
  return (
29
40
  <div
30
41
  data-slot="aspect-ratio"
31
- style={{ 'aspect-ratio': String(local.ratio ?? 16 / 9) }}
42
+ style={withRatio(local.style, local.ratio ?? 16 / 9)}
32
43
  class={cn('relative w-full [&>*]:absolute [&>*]:inset-0 [&>*]:size-full', local.class)}
33
44
  {...rest}
34
45
  >
@@ -171,7 +171,12 @@ function CalendarGrid(props: {
171
171
  // Styled from data states, so a day can be a range
172
172
  // end and today at once without a prop per pair.
173
173
  'data-selected:bg-primary data-selected:text-primary-foreground',
174
- 'data-in-range:bg-primary-subtle',
174
+ // corvu marks every day of a range selected, so the
175
+ // span between the ends steps back to the subtle
176
+ // fill and the ends take the solid one again.
177
+ 'data-in-range:bg-primary-subtle data-in-range:text-foreground',
178
+ 'data-range-start:bg-primary data-range-start:text-primary-foreground',
179
+ 'data-range-end:bg-primary data-range-end:text-primary-foreground',
175
180
  'data-range-start:rounded-r-none data-range-end:rounded-l-none',
176
181
  'data-today:ring-1 data-today:ring-ring',
177
182
  'data-disabled:text-muted-foreground data-disabled:line-through',
@@ -6,8 +6,8 @@ import { cn } from '../../../lib/utils'
6
6
  * Card.
7
7
  *
8
8
  * A surface that sits on the canvas. Every card carries its own edge — a
9
- * border — because in the light theme `--card` and `--background` are both
10
- * white, and a borderless card there is invisible. Making the border
9
+ * border — because in the light theme `--card` is one faint step off a white
10
+ * `--background`, and a borderless card there all but disappears. Making the border
11
11
  * structural rather than optional is what stops one app's cards from reading
12
12
  * as floating panels and another's as nothing at all.
13
13
  *
@@ -0,0 +1,196 @@
1
+ import type { ChartOptions } from 'chart.js'
2
+
3
+ /**
4
+ * The chart's options, as data: no Chart.js runtime and no DOM, so the theme's
5
+ * defaults and the merge rules are testable on their own.
6
+ *
7
+ * Every colour here is written as `var(--token)`. A canvas cannot read a custom
8
+ * property — `fillStyle = 'var(--chart-1)'` is an invalid colour, which the
9
+ * canvas ignores and paints in its default black — so these strings are the
10
+ * *declaration* of which token a colour comes from. The components resolve them
11
+ * against their own element at render time (see `resolveCssVariables` and the
12
+ * resolver in `chart.tsx`).
13
+ */
14
+
15
+ /** The five series colours, in the order a multi-series chart should use them. */
16
+ export const chartSeriesColors = [
17
+ 'var(--chart-1)',
18
+ 'var(--chart-2)',
19
+ 'var(--chart-3)',
20
+ 'var(--chart-4)',
21
+ 'var(--chart-5)',
22
+ ] as const
23
+
24
+ /**
25
+ * The chart furniture, mapped onto existing semantic tokens rather than given
26
+ * tokens of its own. A grid line is a line, so it is `--border`; an axis tick and
27
+ * a legend label are secondary text, so they are `--muted-foreground`, whose
28
+ * contrast on `--card` (the frame's surface) is already measured in
29
+ * `tests/tokens.test.ts`. Dedicated `--chart-grid`/`--chart-axis`/`--chart-label`
30
+ * tokens would be three more values to keep in step with these in every theme
31
+ * for no difference anyone has asked for.
32
+ */
33
+ const furniture = {
34
+ grid: 'var(--border)',
35
+ axis: 'var(--muted-foreground)',
36
+ label: 'var(--muted-foreground)',
37
+ surface: 'var(--card)',
38
+ } as const
39
+
40
+ /**
41
+ * Which scales a chart type draws. Chart.js creates a scale for every key under
42
+ * `options.scales` whatever the chart type, so cartesian defaults handed to a
43
+ * doughnut draw an x and a y axis and a grid behind it. The shape keeps each
44
+ * type's defaults to the scales it actually has.
45
+ */
46
+ export type ChartScaleShape = 'cartesian' | 'radial' | 'none'
47
+
48
+ const tickFont = { size: 10 }
49
+
50
+ function scalesFor(shape: ChartScaleShape): ChartOptions['scales'] {
51
+ if (shape === 'cartesian') {
52
+ return {
53
+ x: {
54
+ border: { color: furniture.grid },
55
+ grid: { color: furniture.grid, drawTicks: false },
56
+ ticks: { color: furniture.axis, font: tickFont },
57
+ },
58
+ y: {
59
+ border: { display: false },
60
+ grid: { color: furniture.grid, drawTicks: false },
61
+ ticks: { color: furniture.axis, font: tickFont },
62
+ },
63
+ }
64
+ }
65
+ if (shape === 'radial') {
66
+ return {
67
+ r: {
68
+ grid: { color: furniture.grid },
69
+ angleLines: { color: furniture.grid },
70
+ pointLabels: { color: furniture.axis, font: tickFont },
71
+ // The default backdrop is a translucent white box, which is a white box
72
+ // on a dark card. The frame's own surface makes it disappear in both.
73
+ ticks: { color: furniture.axis, backdropColor: furniture.surface, font: tickFont },
74
+ },
75
+ }
76
+ }
77
+ return undefined
78
+ }
79
+
80
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
81
+ if (typeof value !== 'object' || value === null) return false
82
+ const prototype = Object.getPrototypeOf(value)
83
+ return prototype === Object.prototype || prototype === null
84
+ }
85
+
86
+ function mergeInto(target: Record<string, unknown>, source: Record<string, unknown>) {
87
+ for (const [key, value] of Object.entries(source)) {
88
+ if (value === undefined) continue
89
+ const current = target[key]
90
+ target[key] =
91
+ isPlainObject(value) && isPlainObject(current)
92
+ ? mergeInto({ ...current }, value)
93
+ : isPlainObject(value)
94
+ ? mergeInto({}, value)
95
+ : value
96
+ }
97
+ return target
98
+ }
99
+
100
+ /**
101
+ * Merge Chart.js options, later sources winning, object by object.
102
+ *
103
+ * Deep, because Chart.js options are deep: `{ scales: { x: { stacked: true } } }`
104
+ * means "also stack x", and a spread would replace the whole axis — its grid,
105
+ * its tick colour, its font — with that one flag. Arrays, functions (scriptable
106
+ * options) and class instances (gradients, patterns) are values and replace
107
+ * rather than merge. No source is mutated.
108
+ */
109
+ export function mergeChartOptions(...sources: (ChartOptions | undefined)[]): ChartOptions {
110
+ const merged: Record<string, unknown> = {}
111
+ for (const source of sources) {
112
+ if (source) mergeInto(merged, source as Record<string, unknown>)
113
+ }
114
+ return merged as ChartOptions
115
+ }
116
+
117
+ /**
118
+ * The theme's defaults as Chart.js options.
119
+ *
120
+ * Exported so a caller can spread it and change one thing, rather than
121
+ * restating every colour. Everything a chart draws that is not data — grid,
122
+ * ticks, legend, tooltip — is decided here once, which is what makes two charts
123
+ * in one application look like they came from the same place. `overrides` is
124
+ * merged deeply; `shape` selects the scales the chart type has.
125
+ */
126
+ export function chartOptions(
127
+ overrides?: ChartOptions,
128
+ shape: ChartScaleShape = 'cartesian'
129
+ ): ChartOptions {
130
+ return mergeChartOptions(
131
+ {
132
+ responsive: true,
133
+ maintainAspectRatio: false,
134
+ interaction: { mode: 'nearest', intersect: false },
135
+ plugins: {
136
+ legend: {
137
+ labels: {
138
+ color: furniture.label,
139
+ boxWidth: 8,
140
+ boxHeight: 8,
141
+ usePointStyle: true,
142
+ pointStyle: 'circle',
143
+ font: { size: 11 },
144
+ },
145
+ },
146
+ tooltip: {
147
+ backgroundColor: 'var(--popover)',
148
+ titleColor: 'var(--popover-foreground)',
149
+ bodyColor: 'var(--popover-foreground)',
150
+ borderColor: 'var(--border)',
151
+ borderWidth: 1,
152
+ padding: 8,
153
+ cornerRadius: 6,
154
+ displayColors: true,
155
+ boxWidth: 8,
156
+ boxHeight: 8,
157
+ usePointStyle: true,
158
+ titleFont: { size: 11, weight: 600 },
159
+ bodyFont: { size: 11 },
160
+ },
161
+ },
162
+ scales: scalesFor(shape),
163
+ },
164
+ overrides
165
+ )
166
+ }
167
+
168
+ const cssVariable = /^\s*var\(\s*(--[\w-]+)\s*(?:,\s*(.*?))?\s*\)\s*$/
169
+
170
+ /**
171
+ * Replace every `var(--token)` string in `value` — options, datasets, nested
172
+ * arrays — with what `read` returns for the token. A token `read` cannot
173
+ * resolve falls back to the `var()`'s own fallback, then to the string as
174
+ * written. Functions and class instances pass through untouched, so scriptable
175
+ * options and gradients keep working.
176
+ */
177
+ export function resolveCssVariables<T>(value: T, read: (name: string) => string | undefined): T {
178
+ if (typeof value === 'string') {
179
+ const match = cssVariable.exec(value)
180
+ if (!match) return value
181
+ const resolved = read(match[1]!)
182
+ if (resolved) return resolved as T
183
+ return (match[2] ? resolveCssVariables(match[2], read) : value) as T
184
+ }
185
+ if (Array.isArray(value)) {
186
+ return value.map((entry: unknown) => resolveCssVariables(entry, read)) as T
187
+ }
188
+ if (isPlainObject(value)) {
189
+ const resolved: Record<string, unknown> = {}
190
+ for (const [key, entry] of Object.entries(value)) {
191
+ resolved[key] = resolveCssVariables(entry, read)
192
+ }
193
+ return resolved as T
194
+ }
195
+ return value
196
+ }