@flesler/cursor-canvas-web 1.4.0 → 1.5.0
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/cursor-canvas-web.css +1 -0
- package/dist/cursor-canvas.cjs +1 -1
- package/dist/cursor-canvas.js +530 -565
- package/dist/pie-donut-DNbA0GeH.cjs +1 -0
- package/dist/pie-donut-qRBFP0tT.js +63 -0
- package/package.json +6 -2
- package/src/runtime/index.tsx +64 -0
- package/src/shim/__tests__/barChart.test.ts +61 -0
- package/src/shim/__tests__/canvas.smoke.test.tsx +209 -0
- package/src/shim/__tests__/category-theme.test.tsx +58 -0
- package/src/shim/__tests__/dag.test.ts +49 -0
- package/src/shim/__tests__/host-tokens.test.ts +106 -0
- package/src/shim/__tests__/lineChart.test.ts +28 -0
- package/src/shim/__tests__/useCanvasState.test.tsx +35 -0
- package/src/shim/__tests__/useHostTheme.test.tsx +43 -0
- package/src/shim/__tests__/valueAxis.test.ts +39 -0
- package/src/shim/bar-chart.tsx +77 -0
- package/src/shim/canvas-hooks.tsx +57 -0
- package/src/shim/canvas-mantine-root.tsx +129 -0
- package/src/shim/chart-shared.tsx +252 -0
- package/src/shim/cursor-canvas.tsx +136 -0
- package/src/shim/dag.ts +179 -0
- package/src/shim/diff.tsx +161 -0
- package/src/shim/host-tokens.ts +614 -0
- package/src/shim/line-chart.tsx +62 -0
- package/src/shim/pie-chart.tsx +127 -0
- package/src/shim/pie-donut.tsx +79 -0
- package/src/shim/theme.ts +77 -0
- package/src/shim/todo.tsx +184 -0
- package/src/shim/ui/actions.tsx +58 -0
- package/src/shim/ui/card-context.tsx +11 -0
- package/src/shim/ui/card.tsx +79 -0
- package/src/shim/ui/chevron.tsx +23 -0
- package/src/shim/ui/display.tsx +83 -0
- package/src/shim/ui/form.tsx +102 -0
- package/src/shim/ui/layout.tsx +67 -0
- package/src/shim/ui/rich.tsx +136 -0
- package/src/shim/ui/table.tsx +71 -0
- package/src/shim/ui/typography.tsx +129 -0
- package/src/shim/use-tokens.ts +13 -0
- package/src/superset/chart-extra.d.ts +11 -11
- package/src/superset/index.d.ts +4 -4
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Alert, Badge, Text as MantineText } from '@mantine/core'
|
|
2
|
+
import type { CalloutProps, PillProps, StatProps } from '../../vendor/canvas-sdk/ui-primitives.js'
|
|
3
|
+
import { toneColor, toneHex } from '../theme'
|
|
4
|
+
import { useHostTheme } from '../use-tokens'
|
|
5
|
+
|
|
6
|
+
export function Stat({ value, label, tone, style }: StatProps) {
|
|
7
|
+
const host = useHostTheme()
|
|
8
|
+
return (
|
|
9
|
+
<div style={style}>
|
|
10
|
+
<MantineText
|
|
11
|
+
fz={22}
|
|
12
|
+
fw={700}
|
|
13
|
+
lh={1.2}
|
|
14
|
+
style={{
|
|
15
|
+
color: tone ? toneHex[tone] : host.text.primary,
|
|
16
|
+
fontFamily: host.typography.fontFamily,
|
|
17
|
+
}}
|
|
18
|
+
>
|
|
19
|
+
{value}
|
|
20
|
+
</MantineText>
|
|
21
|
+
<MantineText
|
|
22
|
+
fz={12}
|
|
23
|
+
style={{
|
|
24
|
+
color: host.text.tertiary,
|
|
25
|
+
fontFamily: host.typography.fontFamily,
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
{label}
|
|
29
|
+
</MantineText>
|
|
30
|
+
</div>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function Pill({
|
|
35
|
+
children,
|
|
36
|
+
active,
|
|
37
|
+
tone = 'neutral',
|
|
38
|
+
size = 'md',
|
|
39
|
+
leadingContent,
|
|
40
|
+
keyboardHint,
|
|
41
|
+
title,
|
|
42
|
+
style,
|
|
43
|
+
onClick,
|
|
44
|
+
}: PillProps) {
|
|
45
|
+
return (
|
|
46
|
+
<Badge
|
|
47
|
+
color={toneColor[tone]}
|
|
48
|
+
variant={active ? 'filled' : 'light'}
|
|
49
|
+
size={size === 'sm' ? 'sm' : 'md'}
|
|
50
|
+
leftSection={leadingContent}
|
|
51
|
+
rightSection={keyboardHint}
|
|
52
|
+
title={title}
|
|
53
|
+
onClick={onClick}
|
|
54
|
+
style={{
|
|
55
|
+
cursor: onClick ? 'pointer' : undefined,
|
|
56
|
+
textTransform: 'none',
|
|
57
|
+
...style,
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
{children}
|
|
61
|
+
</Badge>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function Callout({
|
|
66
|
+
children,
|
|
67
|
+
tone = 'neutral',
|
|
68
|
+
title,
|
|
69
|
+
icon,
|
|
70
|
+
style,
|
|
71
|
+
}: CalloutProps) {
|
|
72
|
+
return (
|
|
73
|
+
<Alert
|
|
74
|
+
color={toneColor[tone]}
|
|
75
|
+
title={title}
|
|
76
|
+
icon={icon}
|
|
77
|
+
variant="light"
|
|
78
|
+
style={style}
|
|
79
|
+
>
|
|
80
|
+
{children}
|
|
81
|
+
</Alert>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Checkbox as MantineCheckbox, Select as MantineSelect, Textarea as MantineTextarea, TextInput as MantineTextInput, Switch } from '@mantine/core'
|
|
2
|
+
import type { CheckboxProps, SelectProps, TextAreaProps, TextInputProps, ToggleProps } from '../../vendor/canvas-sdk/form-primitives.js'
|
|
3
|
+
|
|
4
|
+
export function Select({
|
|
5
|
+
value,
|
|
6
|
+
onChange,
|
|
7
|
+
options,
|
|
8
|
+
placeholder,
|
|
9
|
+
disabled,
|
|
10
|
+
style,
|
|
11
|
+
}: SelectProps) {
|
|
12
|
+
return (
|
|
13
|
+
<MantineSelect
|
|
14
|
+
value={value}
|
|
15
|
+
data={options}
|
|
16
|
+
placeholder={placeholder}
|
|
17
|
+
disabled={disabled}
|
|
18
|
+
allowDeselect={false}
|
|
19
|
+
onChange={(next) => {
|
|
20
|
+
if (next !== null) onChange?.(next)
|
|
21
|
+
}}
|
|
22
|
+
style={style}
|
|
23
|
+
/>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function Checkbox({
|
|
28
|
+
checked,
|
|
29
|
+
onChange,
|
|
30
|
+
disabled,
|
|
31
|
+
label,
|
|
32
|
+
style,
|
|
33
|
+
}: CheckboxProps) {
|
|
34
|
+
return (
|
|
35
|
+
<MantineCheckbox
|
|
36
|
+
checked={checked}
|
|
37
|
+
disabled={disabled}
|
|
38
|
+
label={label}
|
|
39
|
+
onChange={event => onChange?.(event.currentTarget.checked)}
|
|
40
|
+
style={style}
|
|
41
|
+
/>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function Toggle({
|
|
46
|
+
checked,
|
|
47
|
+
onChange,
|
|
48
|
+
disabled,
|
|
49
|
+
size = 'sm',
|
|
50
|
+
style,
|
|
51
|
+
}: ToggleProps) {
|
|
52
|
+
return (
|
|
53
|
+
<Switch
|
|
54
|
+
checked={checked}
|
|
55
|
+
disabled={disabled}
|
|
56
|
+
size={size === 'sm' ? 'sm' : 'md'}
|
|
57
|
+
onChange={event => onChange?.(event.currentTarget.checked)}
|
|
58
|
+
style={style}
|
|
59
|
+
/>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function TextInput({
|
|
64
|
+
value,
|
|
65
|
+
onChange,
|
|
66
|
+
placeholder,
|
|
67
|
+
disabled,
|
|
68
|
+
type,
|
|
69
|
+
style,
|
|
70
|
+
}: TextInputProps) {
|
|
71
|
+
return (
|
|
72
|
+
<MantineTextInput
|
|
73
|
+
value={value}
|
|
74
|
+
placeholder={placeholder}
|
|
75
|
+
disabled={disabled}
|
|
76
|
+
type={type}
|
|
77
|
+
onChange={event => onChange?.(event.currentTarget.value)}
|
|
78
|
+
style={style}
|
|
79
|
+
/>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function TextArea({
|
|
84
|
+
value,
|
|
85
|
+
onChange,
|
|
86
|
+
placeholder,
|
|
87
|
+
disabled,
|
|
88
|
+
rows = 3,
|
|
89
|
+
style,
|
|
90
|
+
}: TextAreaProps) {
|
|
91
|
+
return (
|
|
92
|
+
<MantineTextarea
|
|
93
|
+
value={value}
|
|
94
|
+
placeholder={placeholder}
|
|
95
|
+
disabled={disabled}
|
|
96
|
+
autosize
|
|
97
|
+
minRows={rows}
|
|
98
|
+
onChange={event => onChange?.(event.currentTarget.value)}
|
|
99
|
+
style={style}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Group, Divider as MantineDivider, Stack as MantineStack } from '@mantine/core'
|
|
2
|
+
import type { DividerProps, GridProps, RowProps, StackProps } from '../../vendor/canvas-sdk/ui-primitives.js'
|
|
3
|
+
|
|
4
|
+
export function Stack({ children, gap, style }: StackProps) {
|
|
5
|
+
return (
|
|
6
|
+
<MantineStack gap={gap} style={style}>
|
|
7
|
+
{children}
|
|
8
|
+
</MantineStack>
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const FLEX: Record<string, string> = {
|
|
13
|
+
start: 'flex-start',
|
|
14
|
+
center: 'center',
|
|
15
|
+
end: 'flex-end',
|
|
16
|
+
stretch: 'stretch',
|
|
17
|
+
'space-between': 'space-between',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function Row({
|
|
21
|
+
children,
|
|
22
|
+
gap,
|
|
23
|
+
align = 'center',
|
|
24
|
+
justify = 'start',
|
|
25
|
+
wrap = false,
|
|
26
|
+
style,
|
|
27
|
+
}: RowProps) {
|
|
28
|
+
return (
|
|
29
|
+
<Group
|
|
30
|
+
gap={gap}
|
|
31
|
+
align={FLEX[align]}
|
|
32
|
+
justify={FLEX[justify]}
|
|
33
|
+
wrap={wrap ? 'wrap' : 'nowrap'}
|
|
34
|
+
style={style}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</Group>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function Spacer() {
|
|
42
|
+
return <div style={{ flex: 1 }} />
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function Grid({ children, columns, gap = 16, align, style }: GridProps) {
|
|
46
|
+
const gridTemplateColumns =
|
|
47
|
+
typeof columns === 'number'
|
|
48
|
+
? `repeat(${columns}, minmax(0, 1fr))`
|
|
49
|
+
: columns
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
style={{
|
|
53
|
+
display: 'grid',
|
|
54
|
+
gridTemplateColumns,
|
|
55
|
+
gap,
|
|
56
|
+
alignItems: align,
|
|
57
|
+
...style,
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
{children}
|
|
61
|
+
</div>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function Divider({ style }: DividerProps) {
|
|
66
|
+
return <MantineDivider style={style} />
|
|
67
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import type { CollapsibleSectionProps } from '../../vendor/canvas-sdk/collapsible-section.js'
|
|
3
|
+
import type { SwatchProps } from '../../vendor/canvas-sdk/swatch.js'
|
|
4
|
+
import type { UsageBarProps } from '../../vendor/canvas-sdk/usage-bar.js'
|
|
5
|
+
import { usageColorSequence } from '../theme'
|
|
6
|
+
import { useHostTheme } from '../use-tokens'
|
|
7
|
+
import { Chevron } from './chevron'
|
|
8
|
+
|
|
9
|
+
export function Swatch({ color, style }: SwatchProps) {
|
|
10
|
+
const theme = useHostTheme()
|
|
11
|
+
return (
|
|
12
|
+
<span
|
|
13
|
+
style={{
|
|
14
|
+
display: 'inline-block',
|
|
15
|
+
width: 14,
|
|
16
|
+
height: 14,
|
|
17
|
+
borderRadius: 4,
|
|
18
|
+
background: theme.category[color],
|
|
19
|
+
flex: '0 0 auto',
|
|
20
|
+
...style,
|
|
21
|
+
}}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function UsageBar({
|
|
27
|
+
segments,
|
|
28
|
+
total,
|
|
29
|
+
topLeftLabel,
|
|
30
|
+
topRightLabel,
|
|
31
|
+
style,
|
|
32
|
+
}: UsageBarProps) {
|
|
33
|
+
const theme = useHostTheme()
|
|
34
|
+
const safeTotal = total > 0 ? total : 1
|
|
35
|
+
const used = segments.reduce(
|
|
36
|
+
(sum, s) => sum + (Number.isFinite(s.value) && s.value > 0 ? s.value : 0),
|
|
37
|
+
0,
|
|
38
|
+
)
|
|
39
|
+
const remainder = Math.max(0, safeTotal - used)
|
|
40
|
+
return (
|
|
41
|
+
<div style={style}>
|
|
42
|
+
{(topLeftLabel != null || topRightLabel != null) && (
|
|
43
|
+
<div
|
|
44
|
+
style={{
|
|
45
|
+
display: 'flex',
|
|
46
|
+
justifyContent: 'space-between',
|
|
47
|
+
fontSize: 12,
|
|
48
|
+
color: theme.text.secondary,
|
|
49
|
+
marginBottom: 6,
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<span>{topLeftLabel}</span>
|
|
53
|
+
<span>{topRightLabel}</span>
|
|
54
|
+
</div>
|
|
55
|
+
)}
|
|
56
|
+
<div style={{ display: 'flex', gap: 2, height: 8 }}>
|
|
57
|
+
{segments.map((segment, index) => {
|
|
58
|
+
const value =
|
|
59
|
+
Number.isFinite(segment.value) && segment.value > 0
|
|
60
|
+
? segment.value
|
|
61
|
+
: 0
|
|
62
|
+
const color =
|
|
63
|
+
theme.category[
|
|
64
|
+
segment.color ??
|
|
65
|
+
usageColorSequence[index % usageColorSequence.length]
|
|
66
|
+
]
|
|
67
|
+
return (
|
|
68
|
+
<div
|
|
69
|
+
key={segment.id}
|
|
70
|
+
style={{
|
|
71
|
+
width: `${(value / safeTotal) * 100}%`,
|
|
72
|
+
background: color,
|
|
73
|
+
borderRadius: 3,
|
|
74
|
+
}}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
})}
|
|
78
|
+
{remainder > 0 && (
|
|
79
|
+
<div
|
|
80
|
+
style={{
|
|
81
|
+
width: `${(remainder / safeTotal) * 100}%`,
|
|
82
|
+
background: theme.fill.tertiary,
|
|
83
|
+
borderRadius: 3,
|
|
84
|
+
}}
|
|
85
|
+
/>
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function CollapsibleSection({
|
|
93
|
+
title,
|
|
94
|
+
leading,
|
|
95
|
+
count,
|
|
96
|
+
trailing,
|
|
97
|
+
children,
|
|
98
|
+
defaultOpen = false,
|
|
99
|
+
style,
|
|
100
|
+
}: CollapsibleSectionProps) {
|
|
101
|
+
const theme = useHostTheme()
|
|
102
|
+
const [open, setOpen] = useState(defaultOpen)
|
|
103
|
+
return (
|
|
104
|
+
<div style={style}>
|
|
105
|
+
<div
|
|
106
|
+
onClick={() => setOpen(o => !o)}
|
|
107
|
+
style={{
|
|
108
|
+
display: 'flex',
|
|
109
|
+
alignItems: 'center',
|
|
110
|
+
gap: 6,
|
|
111
|
+
padding: '4px 0',
|
|
112
|
+
cursor: 'pointer',
|
|
113
|
+
userSelect: 'none',
|
|
114
|
+
color: theme.text.primary,
|
|
115
|
+
fontSize: 14,
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
<Chevron expanded={open} />
|
|
119
|
+
{leading}
|
|
120
|
+
<span style={{ fontWeight: 500 }}>{title}</span>
|
|
121
|
+
{count != null && (
|
|
122
|
+
<span style={{ color: theme.text.tertiary, fontSize: 12 }}>
|
|
123
|
+
{count}
|
|
124
|
+
</span>
|
|
125
|
+
)}
|
|
126
|
+
<span style={{ flex: 1 }} />
|
|
127
|
+
{trailing != null && (
|
|
128
|
+
<span style={{ color: theme.text.tertiary }}>{trailing}</span>
|
|
129
|
+
)}
|
|
130
|
+
</div>
|
|
131
|
+
{open && (
|
|
132
|
+
<div style={{ paddingLeft: 18, paddingBottom: 4 }}>{children}</div>
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Table as MantineTable } from '@mantine/core'
|
|
2
|
+
import type { TableProps, TableRowTone } from '../../vendor/canvas-sdk/ui-primitives.js'
|
|
3
|
+
|
|
4
|
+
const ROW_TONE_BG: Record<TableRowTone, string> = {
|
|
5
|
+
success: 'rgba(31,138,101,0.12)',
|
|
6
|
+
danger: 'rgba(207,45,86,0.12)',
|
|
7
|
+
warning: 'rgba(232,163,61,0.14)',
|
|
8
|
+
info: 'rgba(46,121,181,0.12)',
|
|
9
|
+
neutral: 'rgba(136,136,168,0.12)',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Table({
|
|
13
|
+
headers,
|
|
14
|
+
rows,
|
|
15
|
+
columnAlign,
|
|
16
|
+
rowTone,
|
|
17
|
+
framed = true,
|
|
18
|
+
striped,
|
|
19
|
+
stickyHeader,
|
|
20
|
+
style,
|
|
21
|
+
emptyMessage,
|
|
22
|
+
}: TableProps) {
|
|
23
|
+
return (
|
|
24
|
+
<MantineTable
|
|
25
|
+
withTableBorder={framed}
|
|
26
|
+
withColumnBorders={false}
|
|
27
|
+
striped={striped}
|
|
28
|
+
stickyHeader={stickyHeader}
|
|
29
|
+
highlightOnHover
|
|
30
|
+
style={style}
|
|
31
|
+
>
|
|
32
|
+
<MantineTable.Thead>
|
|
33
|
+
<MantineTable.Tr>
|
|
34
|
+
{headers.map((header, index) => (
|
|
35
|
+
<MantineTable.Th key={index} ta={columnAlign?.[index] ?? 'left'}>
|
|
36
|
+
{header}
|
|
37
|
+
</MantineTable.Th>
|
|
38
|
+
))}
|
|
39
|
+
</MantineTable.Tr>
|
|
40
|
+
</MantineTable.Thead>
|
|
41
|
+
<MantineTable.Tbody>
|
|
42
|
+
{rows.length === 0 ? (
|
|
43
|
+
<MantineTable.Tr>
|
|
44
|
+
<MantineTable.Td colSpan={headers.length} ta="center" c="dimmed">
|
|
45
|
+
{emptyMessage ?? 'No data'}
|
|
46
|
+
</MantineTable.Td>
|
|
47
|
+
</MantineTable.Tr>
|
|
48
|
+
) : (
|
|
49
|
+
rows.map((row, rowIndex) => {
|
|
50
|
+
const tone = rowTone?.[rowIndex]
|
|
51
|
+
return (
|
|
52
|
+
<MantineTable.Tr
|
|
53
|
+
key={rowIndex}
|
|
54
|
+
style={tone ? { background: ROW_TONE_BG[tone] } : undefined}
|
|
55
|
+
>
|
|
56
|
+
{headers.map((_, colIndex) => (
|
|
57
|
+
<MantineTable.Td
|
|
58
|
+
key={colIndex}
|
|
59
|
+
ta={columnAlign?.[colIndex] ?? 'left'}
|
|
60
|
+
>
|
|
61
|
+
{row[colIndex]}
|
|
62
|
+
</MantineTable.Td>
|
|
63
|
+
))}
|
|
64
|
+
</MantineTable.Tr>
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
)}
|
|
68
|
+
</MantineTable.Tbody>
|
|
69
|
+
</MantineTable>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Text as MantineText, Title } from '@mantine/core'
|
|
2
|
+
import { createContext, useContext, type CSSProperties } from 'react'
|
|
3
|
+
import type { CodeProps, H1Props, H2Props, H3Props, LinkProps, TextProps, TextWeight } from '../../vendor/canvas-sdk/ui-primitives.js'
|
|
4
|
+
import { useHostTheme } from '../use-tokens'
|
|
5
|
+
|
|
6
|
+
function headingStyle(
|
|
7
|
+
host: ReturnType<typeof useHostTheme>,
|
|
8
|
+
level: 'h1' | 'h2' | 'h3',
|
|
9
|
+
style?: CSSProperties,
|
|
10
|
+
): CSSProperties {
|
|
11
|
+
const block = host.typography[level]
|
|
12
|
+
return {
|
|
13
|
+
fontFamily: host.typography.fontFamily,
|
|
14
|
+
fontSize: block.fontSize,
|
|
15
|
+
lineHeight: block.lineHeight,
|
|
16
|
+
fontWeight: block.fontWeight,
|
|
17
|
+
color: host.text.primary,
|
|
18
|
+
margin: 0,
|
|
19
|
+
...style,
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function H1({ children, style }: H1Props) {
|
|
24
|
+
const host = useHostTheme()
|
|
25
|
+
return (
|
|
26
|
+
<Title order={1} style={headingStyle(host, 'h1', style)}>
|
|
27
|
+
{children}
|
|
28
|
+
</Title>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function H2({ children, style }: H2Props) {
|
|
33
|
+
const host = useHostTheme()
|
|
34
|
+
return (
|
|
35
|
+
<Title order={2} style={headingStyle(host, 'h2', style)}>
|
|
36
|
+
{children}
|
|
37
|
+
</Title>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function H3({ children, style }: H3Props) {
|
|
42
|
+
const host = useHostTheme()
|
|
43
|
+
return (
|
|
44
|
+
<Title order={3} style={headingStyle(host, 'h3', style)}>
|
|
45
|
+
{children}
|
|
46
|
+
</Title>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const TEXT_WEIGHT: Record<TextWeight, number> = {
|
|
51
|
+
normal: 400,
|
|
52
|
+
medium: 500,
|
|
53
|
+
semibold: 600,
|
|
54
|
+
bold: 700,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const TextParentContext = createContext(false)
|
|
58
|
+
|
|
59
|
+
export function Text({
|
|
60
|
+
children,
|
|
61
|
+
tone = 'primary',
|
|
62
|
+
size = 'body',
|
|
63
|
+
as = 'p',
|
|
64
|
+
weight = 'normal',
|
|
65
|
+
italic,
|
|
66
|
+
truncate,
|
|
67
|
+
style,
|
|
68
|
+
}: TextProps) {
|
|
69
|
+
const theme = useHostTheme()
|
|
70
|
+
const nestedInText = useContext(TextParentContext)
|
|
71
|
+
const component = nestedInText && as === 'p' ? 'span' : as
|
|
72
|
+
const blockParagraph = as === 'p'
|
|
73
|
+
return (
|
|
74
|
+
<TextParentContext.Provider value={true}>
|
|
75
|
+
<MantineText
|
|
76
|
+
component={component}
|
|
77
|
+
size={size === 'small' ? 'xs' : 'sm'}
|
|
78
|
+
fw={TEXT_WEIGHT[weight]}
|
|
79
|
+
c={tone === 'primary' ? undefined : theme.text[tone]}
|
|
80
|
+
truncate={truncate}
|
|
81
|
+
style={{
|
|
82
|
+
fontStyle: italic ? 'italic' : undefined,
|
|
83
|
+
...(tone === 'primary' ? { color: theme.text.primary } : undefined),
|
|
84
|
+
...(blockParagraph && component === 'span'
|
|
85
|
+
? { display: 'block' }
|
|
86
|
+
: undefined),
|
|
87
|
+
fontFamily: theme.typography.fontFamily,
|
|
88
|
+
...style,
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
{children}
|
|
92
|
+
</MantineText>
|
|
93
|
+
</TextParentContext.Provider>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function Code({ children, style }: CodeProps) {
|
|
98
|
+
const host = useHostTheme()
|
|
99
|
+
return (
|
|
100
|
+
<code
|
|
101
|
+
style={{
|
|
102
|
+
fontFamily:
|
|
103
|
+
'ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Code", monospace',
|
|
104
|
+
fontSize: '0.92em',
|
|
105
|
+
color: host.text.primary,
|
|
106
|
+
background: host.fill.secondary,
|
|
107
|
+
borderRadius: host.radius.sm,
|
|
108
|
+
padding: '1px 4px',
|
|
109
|
+
...style,
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
112
|
+
{children}
|
|
113
|
+
</code>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function Link({ children, href, style }: LinkProps) {
|
|
118
|
+
const host = useHostTheme()
|
|
119
|
+
return (
|
|
120
|
+
<a
|
|
121
|
+
href={href}
|
|
122
|
+
target="_blank"
|
|
123
|
+
rel="noreferrer"
|
|
124
|
+
style={{ color: host.text.link, ...style }}
|
|
125
|
+
>
|
|
126
|
+
{children}
|
|
127
|
+
</a>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useComputedColorScheme } from '@mantine/core'
|
|
2
|
+
import { resolveThemeForColorScheme, type ShimHostTheme } from './host-tokens'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns the host theme tokens for the active color scheme. Reads
|
|
6
|
+
* `window.__cursorCanvas.state.theme` when present (IDE bridge); otherwise
|
|
7
|
+
* Mantine color scheme + `prefers-color-scheme` defaults.
|
|
8
|
+
*/
|
|
9
|
+
export function useHostTheme(): ShimHostTheme {
|
|
10
|
+
const scheme = useComputedColorScheme('light')
|
|
11
|
+
const polarity = scheme === 'dark' ? 'dark' : 'light'
|
|
12
|
+
return resolveThemeForColorScheme(polarity)
|
|
13
|
+
}
|
|
@@ -12,7 +12,7 @@ export type CanvasChartScale = NonNullable<YAxisProps['scale']>
|
|
|
12
12
|
* horizontal bar charts. Non-linear scales default `domain` to `[1, 'dataMax']`.
|
|
13
13
|
*/
|
|
14
14
|
export type CanvasChartValueAxisExtra = Pick<
|
|
15
|
-
|
|
15
|
+
Omit<YAxisProps, 'ref'>,
|
|
16
16
|
| 'scale'
|
|
17
17
|
| 'domain'
|
|
18
18
|
| 'type'
|
|
@@ -26,20 +26,20 @@ export type CanvasChartValueAxisExtra = Pick<
|
|
|
26
26
|
>
|
|
27
27
|
|
|
28
28
|
export type CanvasChartExtra = {
|
|
29
|
-
|
|
29
|
+
valueAxis?: CanvasChartValueAxisExtra
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export type CanvasBarChartExtra = CanvasChartExtra & {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
/** Category (y) axis on `horizontal` bar charts. */
|
|
34
|
+
categoryAxis?: {
|
|
35
|
+
/** Label column width in px; labels truncate to fit. Default 96. */
|
|
36
|
+
width?: number
|
|
37
|
+
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export type CanvasLineChartExtra = CanvasChartExtra & {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
/** Curved (`monotone`) segments; the IDE draws straight segments. */
|
|
42
|
+
smooth?: boolean;
|
|
43
|
+
/** Stack the filled areas. Requires `fill`. */
|
|
44
|
+
stacked?: boolean
|
|
45
45
|
}
|
package/src/superset/index.d.ts
CHANGED
|
@@ -12,13 +12,13 @@ export * from '../vendor/canvas-sdk/index.js'
|
|
|
12
12
|
export type * from './chart-extra.js'
|
|
13
13
|
|
|
14
14
|
export type BarChartProps = SdkBarChartProps & {
|
|
15
|
-
|
|
15
|
+
extra?: CanvasBarChartExtra
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export type LineChartProps = SdkLineChartProps & {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
extra?: CanvasLineChartExtra;
|
|
20
|
+
/** @deprecated Use `extra.smooth`. */
|
|
21
|
+
smooth?: boolean
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export declare function BarChart(props: BarChartProps): JSX.Element
|