@refraction-ui/astro 0.18.1 → 0.20.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/action-list/action-list.styles.ts +33 -0
- package/dist/action-list/action-list.ts +31 -0
- package/dist/action-list/index.ts +16 -0
- package/dist/analytics-sink-app-insights/app-insights-sink.ts +1 -1
- package/dist/analytics-sink-posthog/client-sdk-sink.ts +1 -1
- package/dist/analytics-sink-posthog/replay.ts +1 -1
- package/dist/astro-action-list/ActionList.astro +12 -0
- package/dist/astro-action-list/ActionListItem.astro +62 -0
- package/dist/astro-action-list/index.ts +1 -0
- package/dist/astro-avatar/Avatar.astro +5 -4
- package/dist/astro-callout/Callout.astro +4 -1
- package/dist/astro-card/Card.astro +3 -2
- package/dist/astro-card/CardTitle.astro +6 -4
- package/dist/astro-data-table/DataTable.astro +7 -3
- package/dist/astro-funnel-chart/FunnelChart.astro +64 -0
- package/dist/astro-funnel-chart/index.ts +1 -0
- package/dist/astro-line-chart/LineChart.astro +82 -0
- package/dist/astro-line-chart/index.ts +1 -0
- package/dist/astro-native-select/NativeSelect.astro +26 -0
- package/dist/astro-native-select/index.ts +1 -0
- package/dist/astro-page-header/PageHeader.astro +46 -0
- package/dist/astro-page-header/index.ts +1 -0
- package/dist/astro-stat-grid/StatGrid.astro +23 -19
- package/dist/astro-table/Table.astro +21 -0
- package/dist/astro-table/TableCaption.astro +9 -0
- package/dist/astro-table/TableCell.astro +13 -0
- package/dist/astro-table/TableHead.astro +13 -0
- package/dist/astro-table/TableRow.astro +9 -0
- package/dist/astro-table/index.ts +1 -0
- package/dist/avatar/avatar.styles.ts +7 -2
- package/dist/avatar/avatar.ts +8 -3
- package/dist/avatar/index.ts +1 -0
- package/dist/badge/badge.styles.ts +6 -1
- package/dist/badge/badge.ts +24 -2
- package/dist/button/button.styles.ts +10 -4
- package/dist/button/button.ts +4 -1
- package/dist/callout/callout.ts +12 -3
- package/dist/card/card.styles.ts +10 -1
- package/dist/card/card.ts +14 -0
- package/dist/card/index.ts +3 -0
- package/dist/data-table/data-table.styles.ts +18 -0
- package/dist/data-table/data-table.ts +49 -7
- package/dist/data-table/index.ts +8 -0
- package/dist/diff-viewer/diff-viewer.styles.ts +3 -0
- package/dist/funnel-chart/funnel-chart.styles.ts +16 -0
- package/dist/funnel-chart/funnel-chart.ts +68 -0
- package/dist/funnel-chart/index.ts +10 -0
- package/dist/index.ts +6 -0
- package/dist/input/input.styles.ts +2 -2
- package/dist/line-chart/index.ts +20 -0
- package/dist/line-chart/line-chart.styles.ts +16 -0
- package/dist/line-chart/line-chart.ts +215 -0
- package/dist/logger/faro-engine.ts +2 -2
- package/dist/native-select/index.ts +6 -0
- package/dist/native-select/native-select.styles.ts +30 -0
- package/dist/native-select/native-select.ts +5 -0
- package/dist/page-header/index.ts +15 -0
- package/dist/page-header/page-header.styles.ts +21 -0
- package/dist/page-header/page-header.ts +27 -0
- package/dist/progress-display/progress-display.styles.ts +1 -1
- package/dist/select/index.ts +2 -0
- package/dist/select/select.styles.ts +9 -3
- package/dist/select/select.ts +11 -3
- package/dist/separator/index.ts +2 -0
- package/dist/separator/separator.styles.ts +17 -2
- package/dist/shared/cn.ts +6 -3
- package/dist/slide-viewer/slide-viewer.styles.ts +2 -0
- package/dist/stat-grid/index.ts +9 -0
- package/dist/stat-grid/stat-grid.styles.ts +73 -6
- package/dist/stat-grid/stat-grid.ts +25 -5
- package/dist/sticky-note/sticky-note.styles.ts +2 -0
- package/dist/table/index.ts +16 -0
- package/dist/table/table.styles.ts +72 -0
- package/dist/table/table.ts +24 -0
- package/dist/tabs/index.ts +1 -0
- package/dist/tabs/tabs.ts +29 -0
- package/dist/textarea/textarea.styles.ts +2 -2
- package/package.json +7 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { cva } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
/** The list: rows separated by hairlines, no bullets. */
|
|
4
|
+
export const actionListClass = 'm-0 flex list-none flex-col divide-y divide-border-subtle p-0'
|
|
5
|
+
|
|
6
|
+
/** A row button: full width, whole row is the hit target. */
|
|
7
|
+
export const actionListItemVariants = cva({
|
|
8
|
+
base:
|
|
9
|
+
'flex w-full items-center gap-4 bg-transparent text-left text-sm text-foreground transition-colors ' +
|
|
10
|
+
'hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring ' +
|
|
11
|
+
'disabled:pointer-events-none disabled:opacity-50',
|
|
12
|
+
variants: {
|
|
13
|
+
density: {
|
|
14
|
+
default: 'px-4 py-3',
|
|
15
|
+
compact: 'px-3 py-2',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
density: 'default',
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
/** Leading text column (title, description, meta). */
|
|
24
|
+
export const actionListItemBodyClass = 'flex min-w-0 flex-1 flex-col gap-0.5'
|
|
25
|
+
/** Primary line. */
|
|
26
|
+
export const actionListItemTitleClass = 'break-words font-semibold text-foreground'
|
|
27
|
+
/** Supporting line under the title. */
|
|
28
|
+
export const actionListItemDescriptionClass = 'break-words text-xs text-muted-foreground'
|
|
29
|
+
/** Tertiary line (owner, tags, ids). */
|
|
30
|
+
export const actionListItemMetaClass = 'break-words text-xs text-muted-foreground'
|
|
31
|
+
/** Trailing column (dates, sizes, counts). */
|
|
32
|
+
export const actionListItemTrailingClass =
|
|
33
|
+
'flex flex-none items-center gap-4 text-xs tabular-nums text-muted-foreground'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Row padding. */
|
|
2
|
+
export type ActionListDensity = 'default' | 'compact'
|
|
3
|
+
|
|
4
|
+
export interface ActionListItemProps {
|
|
5
|
+
disabled?: boolean
|
|
6
|
+
density?: ActionListDensity
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ActionListItemAPI {
|
|
10
|
+
/** ARIA attributes for the row button. */
|
|
11
|
+
ariaProps: Record<string, string | number | boolean>
|
|
12
|
+
/** Data attributes for styling hooks. */
|
|
13
|
+
dataAttributes: Record<string, string>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Build the framework-agnostic props for one ActionList row. Each row is ONE
|
|
18
|
+
* action (open, select, go to) rendered as a native button, so it is reachable
|
|
19
|
+
* by Tab and activated by Enter / Space — unlike a clickable table row.
|
|
20
|
+
*/
|
|
21
|
+
export function createActionListItem(props: ActionListItemProps = {}): ActionListItemAPI {
|
|
22
|
+
const { disabled = false, density = 'default' } = props
|
|
23
|
+
const dataAttributes: Record<string, string> = {
|
|
24
|
+
'data-slot': 'action-list-item',
|
|
25
|
+
'data-density': density,
|
|
26
|
+
}
|
|
27
|
+
if (disabled) dataAttributes['data-disabled'] = ''
|
|
28
|
+
const ariaProps: Record<string, string | number | boolean> = {}
|
|
29
|
+
if (disabled) ariaProps['aria-disabled'] = true
|
|
30
|
+
return { ariaProps, dataAttributes }
|
|
31
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createActionListItem,
|
|
3
|
+
type ActionListDensity,
|
|
4
|
+
type ActionListItemProps,
|
|
5
|
+
type ActionListItemAPI,
|
|
6
|
+
} from './action-list.js'
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
actionListClass,
|
|
10
|
+
actionListItemVariants,
|
|
11
|
+
actionListItemBodyClass,
|
|
12
|
+
actionListItemTitleClass,
|
|
13
|
+
actionListItemDescriptionClass,
|
|
14
|
+
actionListItemMetaClass,
|
|
15
|
+
actionListItemTrailingClass,
|
|
16
|
+
} from './action-list.styles.js'
|
|
@@ -131,7 +131,7 @@ function createClientSdkSink(opts: ClientSdkOptions): AnalyticsSink {
|
|
|
131
131
|
return instance
|
|
132
132
|
}
|
|
133
133
|
// Lazy, dynamic, optional — never a static/hard dependency.
|
|
134
|
-
const mod = (await import(appInsightsWebSpecifier)) as {
|
|
134
|
+
const mod = (await import(/* webpackIgnore: true */ /* @vite-ignore */ appInsightsWebSpecifier)) as {
|
|
135
135
|
ApplicationInsights: new (cfg: {
|
|
136
136
|
config: {
|
|
137
137
|
connectionString?: string
|
|
@@ -68,7 +68,7 @@ const posthogJsSpecifier = 'posthog-js'
|
|
|
68
68
|
|
|
69
69
|
async function defaultLoad(): Promise<PostHogJs> {
|
|
70
70
|
// Dynamic import keeps `posthog-js` out of the graph until first delivery.
|
|
71
|
-
const mod = (await import(posthogJsSpecifier)) as unknown as
|
|
71
|
+
const mod = (await import(/* webpackIgnore: true */ /* @vite-ignore */ posthogJsSpecifier)) as unknown as
|
|
72
72
|
| { default: PostHogJs }
|
|
73
73
|
| PostHogJs
|
|
74
74
|
return 'default' in mod ? mod.default : mod
|
|
@@ -78,7 +78,7 @@ export interface SessionReplayHandle {
|
|
|
78
78
|
const posthogJsSpecifier = 'posthog-js'
|
|
79
79
|
|
|
80
80
|
async function defaultLoad(): Promise<PostHogReplay> {
|
|
81
|
-
const mod = (await import(posthogJsSpecifier)) as unknown as
|
|
81
|
+
const mod = (await import(/* webpackIgnore: true */ /* @vite-ignore */ posthogJsSpecifier)) as unknown as
|
|
82
82
|
| { default: PostHogReplay }
|
|
83
83
|
| PostHogReplay
|
|
84
84
|
return 'default' in mod ? mod.default : mod
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { actionListClass } from '../action-list/index.ts'
|
|
3
|
+
import { cn } from '../shared/index.ts'
|
|
4
|
+
|
|
5
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {}
|
|
6
|
+
|
|
7
|
+
const { class: className, ...rest } = Astro.props
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<ul class={cn(actionListClass, className)} data-slot="action-list" {...rest}>
|
|
11
|
+
<slot />
|
|
12
|
+
</ul>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createActionListItem,
|
|
4
|
+
actionListItemVariants,
|
|
5
|
+
actionListItemBodyClass,
|
|
6
|
+
actionListItemTitleClass,
|
|
7
|
+
actionListItemDescriptionClass,
|
|
8
|
+
actionListItemMetaClass,
|
|
9
|
+
actionListItemTrailingClass,
|
|
10
|
+
type ActionListDensity,
|
|
11
|
+
} from '../action-list/index.ts'
|
|
12
|
+
import { cn } from '../shared/index.ts'
|
|
13
|
+
|
|
14
|
+
interface Props extends astroHTML.JSX.ButtonHTMLAttributes {
|
|
15
|
+
/** Primary line. */
|
|
16
|
+
title: string
|
|
17
|
+
/** Optional supporting line under the title. */
|
|
18
|
+
description?: string
|
|
19
|
+
/** Optional tertiary line. */
|
|
20
|
+
meta?: string
|
|
21
|
+
/** Optional trailing column (or use the `trailing` slot). */
|
|
22
|
+
trailing?: string
|
|
23
|
+
/** Row padding. */
|
|
24
|
+
density?: ActionListDensity
|
|
25
|
+
disabled?: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
title,
|
|
30
|
+
description,
|
|
31
|
+
meta,
|
|
32
|
+
trailing,
|
|
33
|
+
density = 'default',
|
|
34
|
+
disabled = false,
|
|
35
|
+
class: className,
|
|
36
|
+
...rest
|
|
37
|
+
} = Astro.props
|
|
38
|
+
const api = createActionListItem({ disabled, density })
|
|
39
|
+
const hasTrailing = trailing != null || Astro.slots.has('trailing')
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
<li>
|
|
43
|
+
<button
|
|
44
|
+
type="button"
|
|
45
|
+
disabled={disabled}
|
|
46
|
+
class={cn(actionListItemVariants({ density }), className)}
|
|
47
|
+
{...api.ariaProps}
|
|
48
|
+
{...api.dataAttributes}
|
|
49
|
+
{...rest}
|
|
50
|
+
>
|
|
51
|
+
<span class={actionListItemBodyClass}>
|
|
52
|
+
<span class={actionListItemTitleClass}>{title}</span>
|
|
53
|
+
{description && <span class={actionListItemDescriptionClass}>{description}</span>}
|
|
54
|
+
{meta && <span class={actionListItemMetaClass}>{meta}</span>}
|
|
55
|
+
</span>
|
|
56
|
+
{hasTrailing && (
|
|
57
|
+
<span class={actionListItemTrailingClass}>
|
|
58
|
+
<slot name="trailing">{trailing}</slot>
|
|
59
|
+
</span>
|
|
60
|
+
)}
|
|
61
|
+
</button>
|
|
62
|
+
</li>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { createAvatar, avatarVariants, type AvatarSize } from '../avatar/index.ts'
|
|
2
|
+
import { createAvatar, avatarVariants, type AvatarSize, type AvatarShape } from '../avatar/index.ts'
|
|
3
3
|
import { cn } from '../shared/index.ts'
|
|
4
4
|
|
|
5
5
|
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
6
6
|
size?: AvatarSize
|
|
7
|
+
shape?: AvatarShape
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
const { size = 'md', class: className, ...props } = Astro.props
|
|
10
|
-
const api = createAvatar({ size })
|
|
10
|
+
const { size = 'md', shape = 'circle', class: className, ...props } = Astro.props
|
|
11
|
+
const api = createAvatar({ size, alt: props['aria-label'] as string | undefined })
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
<span
|
|
14
|
-
class={cn(avatarVariants({ size }), className)}
|
|
15
|
+
class={cn(avatarVariants({ size, shape }), className)}
|
|
15
16
|
data-rfr-avatar
|
|
16
17
|
data-rfr-avatar-size={size}
|
|
17
18
|
{...api.ariaProps}
|
|
@@ -7,7 +7,10 @@ interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const { variant = 'default', class: className, ...props } = Astro.props
|
|
10
|
-
const api = createCallout({
|
|
10
|
+
const api = createCallout({
|
|
11
|
+
destructive: variant === 'destructive',
|
|
12
|
+
labelled: Boolean(props['aria-label'] || props['aria-labelledby']),
|
|
13
|
+
})
|
|
11
14
|
---
|
|
12
15
|
|
|
13
16
|
<div
|
|
@@ -3,15 +3,16 @@ import { createCard, cardVariants } from '../card/index.ts'
|
|
|
3
3
|
import { cn } from '../shared/index.ts'
|
|
4
4
|
|
|
5
5
|
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
6
|
+
variant?: 'default' | 'subtle' | 'tertiary'
|
|
6
7
|
padding?: 'none' | 'default' | 'compact'
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
const { padding, class: className, ...props } = Astro.props
|
|
10
|
+
const { variant, padding, class: className, ...props } = Astro.props
|
|
10
11
|
const api = createCard(props)
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
<div
|
|
14
|
-
class={cn(cardVariants({ padding }), className)}
|
|
15
|
+
class={cn(cardVariants({ variant, padding }), className)}
|
|
15
16
|
{...api.ariaProps}
|
|
16
17
|
{...api.dataAttributes}
|
|
17
18
|
{...props}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { createCardTitle, cardTitleVariants } from '../card/index.ts'
|
|
2
|
+
import { createCardTitle, cardTitleVariants, type CardTitleLevel } from '../card/index.ts'
|
|
3
3
|
import { cn } from '../shared/index.ts'
|
|
4
4
|
|
|
5
5
|
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
6
6
|
size?: 'sm' | 'default' | 'lg'
|
|
7
|
+
/** Heading element. Defaults to `h3`. */
|
|
8
|
+
as?: CardTitleLevel
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
const { size, class: className, ...props } = Astro.props
|
|
11
|
+
const { size, as: Heading = 'h3', class: className, ...props } = Astro.props
|
|
10
12
|
const api = createCardTitle()
|
|
11
13
|
---
|
|
12
14
|
|
|
13
|
-
<
|
|
15
|
+
<Heading class={cn(cardTitleVariants({ size }), className)} {...api.dataAttributes} {...props}>
|
|
14
16
|
<slot />
|
|
15
|
-
</
|
|
17
|
+
</Heading>
|
|
@@ -5,6 +5,10 @@ import {
|
|
|
5
5
|
headerVariants,
|
|
6
6
|
cellVariants,
|
|
7
7
|
rowVariants,
|
|
8
|
+
getColumnValue,
|
|
9
|
+
resolveColumnAlign,
|
|
10
|
+
dataTableAlignClass,
|
|
11
|
+
dataTableNumericClass,
|
|
8
12
|
type ColumnDef,
|
|
9
13
|
type SortDirection,
|
|
10
14
|
} from '../data-table/index.ts'
|
|
@@ -41,7 +45,7 @@ const hasFilterable = columns.some((c: ColumnDef) => c.filterable)
|
|
|
41
45
|
const hProps = api.getHeaderProps(col)
|
|
42
46
|
return (
|
|
43
47
|
<th
|
|
44
|
-
class={headerVariants({ sortable: col.sortable ? 'true' : 'false' })}
|
|
48
|
+
class={cn(headerVariants({ sortable: col.sortable ? 'true' : 'false' }), dataTableAlignClass[resolveColumnAlign(col)], col.headerClassName)}
|
|
45
49
|
role={hProps.role as string}
|
|
46
50
|
aria-sort={hProps['aria-sort'] as any}
|
|
47
51
|
data-rfr-data-table-header={col.id}
|
|
@@ -94,10 +98,10 @@ const hasFilterable = columns.some((c: ColumnDef) => c.filterable)
|
|
|
94
98
|
{columns.map((col: ColumnDef) => (
|
|
95
99
|
<td
|
|
96
100
|
role="cell"
|
|
97
|
-
class={cellVariants()}
|
|
101
|
+
class={cn(cellVariants(), dataTableAlignClass[resolveColumnAlign(col)], col.numeric && dataTableNumericClass, col.className)}
|
|
98
102
|
data-column={col.id}
|
|
99
103
|
>
|
|
100
|
-
{String(col
|
|
104
|
+
{String(getColumnValue(col, row) ?? '')}
|
|
101
105
|
</td>
|
|
102
106
|
))}
|
|
103
107
|
</tr>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
computeFunnel,
|
|
4
|
+
funnelChartClasses as c,
|
|
5
|
+
funnelChartDefaults,
|
|
6
|
+
DEFAULT_FUNNEL_MIN_BAR_PERCENT,
|
|
7
|
+
type FunnelChartStep,
|
|
8
|
+
} from '../funnel-chart/index.ts'
|
|
9
|
+
import { cn } from '../shared/index.ts'
|
|
10
|
+
|
|
11
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
12
|
+
/** The funnel steps, top first. */
|
|
13
|
+
steps: FunnelChartStep[]
|
|
14
|
+
formatValue?: (value: number) => string
|
|
15
|
+
formatPercent?: (percent: number) => string
|
|
16
|
+
minBarPercent?: number
|
|
17
|
+
shareLabel?: (share: string) => string
|
|
18
|
+
conversionLabel?: (percent: string) => string
|
|
19
|
+
droppedLabel?: (count: string) => string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
steps,
|
|
24
|
+
formatValue = funnelChartDefaults.formatValue,
|
|
25
|
+
formatPercent = funnelChartDefaults.formatPercent,
|
|
26
|
+
minBarPercent = DEFAULT_FUNNEL_MIN_BAR_PERCENT,
|
|
27
|
+
shareLabel = funnelChartDefaults.shareLabel,
|
|
28
|
+
conversionLabel = funnelChartDefaults.conversionLabel,
|
|
29
|
+
droppedLabel = funnelChartDefaults.droppedLabel,
|
|
30
|
+
class: className,
|
|
31
|
+
...rest
|
|
32
|
+
} = Astro.props
|
|
33
|
+
const rows = computeFunnel(steps, minBarPercent)
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
<ol class={cn(c.root, className)} data-slot="funnel-chart" {...rest}>
|
|
37
|
+
{
|
|
38
|
+
rows.map((row) => (
|
|
39
|
+
<li>
|
|
40
|
+
<div class={c.bar}>
|
|
41
|
+
<div class={c.fill} style={`width:${row.barPercent}%`} aria-hidden="true" />
|
|
42
|
+
<svg class={c.chevron} width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
43
|
+
<path d="m9 18 6-6-6-6" />
|
|
44
|
+
</svg>
|
|
45
|
+
<div class={c.text}>
|
|
46
|
+
<b class={c.label}>{row.step.label}</b>
|
|
47
|
+
{row.step.description && <span class={c.description}>{row.step.description}</span>}
|
|
48
|
+
</div>
|
|
49
|
+
<div class={c.figure}>
|
|
50
|
+
<b class={c.value}>{formatValue(row.step.value)}</b>
|
|
51
|
+
<span class={c.share}>{shareLabel(formatPercent(row.shareOfTop))}</span>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
{row.next && (
|
|
55
|
+
<div class={c.transition}>
|
|
56
|
+
<span class={c.conversion}>{conversionLabel(formatPercent(row.next.conversion))}</span>
|
|
57
|
+
<span aria-hidden="true">·</span>
|
|
58
|
+
<span class={c.dropped}>{droppedLabel(formatValue(row.next.dropped))}</span>
|
|
59
|
+
</div>
|
|
60
|
+
)}
|
|
61
|
+
</li>
|
|
62
|
+
))
|
|
63
|
+
}
|
|
64
|
+
</ol>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
computeLineChart,
|
|
4
|
+
lineChartClasses as c,
|
|
5
|
+
DEFAULT_LINE_CHART_WIDTH,
|
|
6
|
+
DEFAULT_LINE_CHART_HEIGHT,
|
|
7
|
+
type LineChartSeries,
|
|
8
|
+
} from '../line-chart/index.ts'
|
|
9
|
+
import { cn } from '../shared/index.ts'
|
|
10
|
+
|
|
11
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
12
|
+
/** The series to plot, all on one shared y-scale. */
|
|
13
|
+
series: LineChartSeries[]
|
|
14
|
+
/** One category label per data point. */
|
|
15
|
+
labels: string[]
|
|
16
|
+
/** Accessible name of the chart image. */
|
|
17
|
+
ariaLabel: string
|
|
18
|
+
height?: number
|
|
19
|
+
width?: number
|
|
20
|
+
/** Formats a y-axis tick. */
|
|
21
|
+
formatTick?: (value: number) => string
|
|
22
|
+
/** Fill the area under each line. Defaults to on for a single series only. */
|
|
23
|
+
area?: boolean
|
|
24
|
+
showLegend?: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
series,
|
|
29
|
+
labels,
|
|
30
|
+
ariaLabel,
|
|
31
|
+
height = DEFAULT_LINE_CHART_HEIGHT,
|
|
32
|
+
width = DEFAULT_LINE_CHART_WIDTH,
|
|
33
|
+
formatTick = (value: number) => String(Math.round(value)),
|
|
34
|
+
area,
|
|
35
|
+
showLegend = true,
|
|
36
|
+
class: className,
|
|
37
|
+
...rest
|
|
38
|
+
} = Astro.props
|
|
39
|
+
const geo = computeLineChart({ series, labels, width, height })
|
|
40
|
+
const fillArea = area ?? series.length === 1
|
|
41
|
+
const gradientBase = `line-chart-${ariaLabel.replace(/[^a-zA-Z0-9]+/g, '-').toLowerCase()}`
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
<div class={cn(c.root, className)} data-slot="line-chart" {...rest}>
|
|
45
|
+
<svg class={c.svg} viewBox={`0 0 ${width} ${height}`} style={`height:${height}px`} role="img" aria-label={ariaLabel}>
|
|
46
|
+
{geo.ticks.map((t) => (
|
|
47
|
+
<g>
|
|
48
|
+
<line class={c.gridline} x1={geo.padding.left} y1={t.y} x2={width - geo.padding.right} y2={t.y} />
|
|
49
|
+
<text class={c.axis} x={geo.padding.left - 8} y={t.y + 3} text-anchor="end">{formatTick(t.value)}</text>
|
|
50
|
+
</g>
|
|
51
|
+
))}
|
|
52
|
+
{geo.xLabels.map((l) => (
|
|
53
|
+
<text class={c.axis} x={l.x} y={height - 6} text-anchor="middle">{l.label}</text>
|
|
54
|
+
))}
|
|
55
|
+
{geo.paths.map((p, si) => (
|
|
56
|
+
<g>
|
|
57
|
+
{fillArea && (
|
|
58
|
+
<Fragment>
|
|
59
|
+
<defs>
|
|
60
|
+
<linearGradient id={`${gradientBase}-${si}`} x1="0" y1="0" x2="0" y2="1">
|
|
61
|
+
<stop offset="0%" stop-color={p.color} stop-opacity="0.22" />
|
|
62
|
+
<stop offset="100%" stop-color={p.color} stop-opacity="0" />
|
|
63
|
+
</linearGradient>
|
|
64
|
+
</defs>
|
|
65
|
+
<path d={p.area} fill={`url(#${gradientBase}-${si})`} />
|
|
66
|
+
</Fragment>
|
|
67
|
+
)}
|
|
68
|
+
<path d={p.line} fill="none" stroke={p.color} stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" />
|
|
69
|
+
</g>
|
|
70
|
+
))}
|
|
71
|
+
</svg>
|
|
72
|
+
{showLegend && (
|
|
73
|
+
<div class={c.legend}>
|
|
74
|
+
{series.map((s, si) => (
|
|
75
|
+
<span class={c.legendItem}>
|
|
76
|
+
<i class={c.legendSwatch} style={`background:${geo.paths[si].color}`} aria-hidden="true" />
|
|
77
|
+
{s.name}
|
|
78
|
+
</span>
|
|
79
|
+
))}
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
nativeSelectChevronPath,
|
|
4
|
+
nativeSelectIconClass,
|
|
5
|
+
nativeSelectVariants,
|
|
6
|
+
nativeSelectWrapperClass,
|
|
7
|
+
type NativeSelectSize,
|
|
8
|
+
} from '../native-select/index.ts'
|
|
9
|
+
import { cn } from '../shared/index.ts'
|
|
10
|
+
|
|
11
|
+
interface Props extends Omit<astroHTML.JSX.SelectHTMLAttributes, 'size'> {
|
|
12
|
+
size?: NativeSelectSize
|
|
13
|
+
containerClass?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { size = 'default', class: className, containerClass, ...rest } = Astro.props
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<span class={cn(nativeSelectWrapperClass, containerClass)} data-slot="native-select">
|
|
20
|
+
<select class={cn(nativeSelectVariants({ size }), className)} {...rest}>
|
|
21
|
+
<slot />
|
|
22
|
+
</select>
|
|
23
|
+
<svg class={nativeSelectIconClass} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
24
|
+
<path d={nativeSelectChevronPath} />
|
|
25
|
+
</svg>
|
|
26
|
+
</span>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createPageHeader,
|
|
4
|
+
pageHeaderClass,
|
|
5
|
+
pageHeaderTextClass,
|
|
6
|
+
pageHeaderKickerClass,
|
|
7
|
+
pageHeaderTitleClass,
|
|
8
|
+
pageHeaderDescriptionClass,
|
|
9
|
+
pageHeaderActionsClass,
|
|
10
|
+
type PageHeaderTitleLevel,
|
|
11
|
+
} from '../page-header/index.ts'
|
|
12
|
+
import { cn } from '../shared/index.ts'
|
|
13
|
+
|
|
14
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
15
|
+
/** Optional eyebrow rendered above the title. */
|
|
16
|
+
kicker?: string
|
|
17
|
+
/** The page title. */
|
|
18
|
+
title: string
|
|
19
|
+
/** Optional supporting copy under the title (or use the `description` slot). */
|
|
20
|
+
description?: string
|
|
21
|
+
/** Heading element for the title. Defaults to `h1`. */
|
|
22
|
+
as?: PageHeaderTitleLevel
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { kicker, title, description, as: Title = 'h1', class: className, ...rest } = Astro.props
|
|
26
|
+
const hasActions = Astro.slots.has('actions')
|
|
27
|
+
const hasDescription = description != null || Astro.slots.has('description')
|
|
28
|
+
const { dataAttributes } = createPageHeader({ hasActions })
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
<header class={cn(pageHeaderClass, className)} {...dataAttributes} {...rest}>
|
|
32
|
+
<div class={pageHeaderTextClass}>
|
|
33
|
+
{kicker && <p class={pageHeaderKickerClass}>{kicker}</p>}
|
|
34
|
+
<Title class={pageHeaderTitleClass}>{title}</Title>
|
|
35
|
+
{hasDescription && (
|
|
36
|
+
<div class={pageHeaderDescriptionClass}>
|
|
37
|
+
<slot name="description">{description}</slot>
|
|
38
|
+
</div>
|
|
39
|
+
)}
|
|
40
|
+
</div>
|
|
41
|
+
{hasActions && (
|
|
42
|
+
<div class={pageHeaderActionsClass}>
|
|
43
|
+
<slot name="actions" />
|
|
44
|
+
</div>
|
|
45
|
+
)}
|
|
46
|
+
</header>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -2,44 +2,48 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createStatGrid,
|
|
4
4
|
statColumns,
|
|
5
|
+
statColumnsKey,
|
|
5
6
|
statGridVariants,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
statItemVariants,
|
|
8
|
+
statValueVariants,
|
|
9
|
+
statLabelVariants,
|
|
10
|
+
statDescriptionClass,
|
|
9
11
|
type StatItem,
|
|
12
|
+
type StatGridVariant,
|
|
13
|
+
type StatGridLayout,
|
|
14
|
+
type StatGridColumns,
|
|
10
15
|
} from '../stat-grid/index.ts'
|
|
11
16
|
import { cn } from '../shared/index.ts'
|
|
12
17
|
|
|
13
18
|
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
14
|
-
/** The stat items to display in the grid
|
|
19
|
+
/** The stat items to display in the grid. */
|
|
15
20
|
items: StatItem[]
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
columns?: number
|
|
21
|
+
/** Maximum columns (reflows on narrow screens) or `auto`. Defaults to statColumns(items.length). */
|
|
22
|
+
columns?: StatGridColumns
|
|
23
|
+
variant?: StatGridVariant
|
|
24
|
+
layout?: StatGridLayout
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
const { items, columns, class: className, ...rest } = Astro.props
|
|
24
|
-
|
|
25
|
-
const cols = columns ?? statColumns(items.length)
|
|
26
|
-
const colsKey = String(cols) as '1' | '2' | '3'
|
|
27
|
+
const { items, columns, variant = 'plain', layout = 'value-first', class: className, ...rest } = Astro.props
|
|
28
|
+
const cols = statColumnsKey(columns ?? statColumns(items.length))
|
|
27
29
|
const { ariaProps, dataAttributes } = createStatGrid()
|
|
28
|
-
const gridStyle = `grid-template-columns:repeat(${cols}, 1fr)`
|
|
29
30
|
---
|
|
30
31
|
|
|
31
32
|
<div
|
|
32
|
-
class={cn(statGridVariants({ columns:
|
|
33
|
-
|
|
33
|
+
class={cn(statGridVariants({ columns: cols, variant }), className)}
|
|
34
|
+
data-variant={variant}
|
|
35
|
+
data-layout={layout}
|
|
34
36
|
{...ariaProps}
|
|
35
37
|
{...dataAttributes}
|
|
36
38
|
{...rest}
|
|
37
39
|
>
|
|
38
40
|
{
|
|
39
41
|
items.map((item) => (
|
|
40
|
-
<div role="listitem" class={
|
|
41
|
-
<span class={
|
|
42
|
-
<span class={
|
|
42
|
+
<div role="listitem" class={statItemVariants({ variant })} data-tone={item.tone ?? 'default'}>
|
|
43
|
+
{layout === 'label-first' && <span class={statLabelVariants({ layout })}>{item.label}</span>}
|
|
44
|
+
<span class={statValueVariants({ variant, tone: item.tone ?? 'default' })}>{item.value}</span>
|
|
45
|
+
{layout === 'value-first' && <span class={statLabelVariants({ layout })}>{item.label}</span>}
|
|
46
|
+
{item.description && <span class={statDescriptionClass}>{item.description}</span>}
|
|
43
47
|
</div>
|
|
44
48
|
))
|
|
45
49
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { createTable, tableContainerClass, tableRootVariants, type TableDensity, type TableHeadTone } from '../table/index.ts'
|
|
3
|
+
import { cn } from '../shared/index.ts'
|
|
4
|
+
|
|
5
|
+
interface Props extends astroHTML.JSX.TableHTMLAttributes {
|
|
6
|
+
/** Recorded as data-density; pass the same density to TableHead/TableCell. */
|
|
7
|
+
density?: TableDensity
|
|
8
|
+
headTone?: TableHeadTone
|
|
9
|
+
fixed?: boolean
|
|
10
|
+
containerClass?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { density = 'default', headTone = 'default', fixed = false, containerClass, class: className, ...rest } = Astro.props
|
|
14
|
+
const { dataAttributes } = createTable({ density, headTone })
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<div class={cn(tableContainerClass, containerClass)} data-slot="table-container">
|
|
18
|
+
<table class={cn(tableRootVariants({ fixed: fixed ? 'true' : 'false' }), className)} {...dataAttributes} {...rest}>
|
|
19
|
+
<slot />
|
|
20
|
+
</table>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { tableCaptionClass } from '../table/index.ts'
|
|
3
|
+
import { cn } from '../shared/index.ts'
|
|
4
|
+
|
|
5
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {}
|
|
6
|
+
const { class: className, ...rest } = Astro.props
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<caption class={cn(tableCaptionClass, className)} data-slot="table-caption" {...rest}><slot /></caption>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { tableCellVariants, type TableAlign, type TableDensity } from '../table/index.ts'
|
|
3
|
+
import { cn } from '../shared/index.ts'
|
|
4
|
+
|
|
5
|
+
interface Props extends Omit<astroHTML.JSX.TdHTMLAttributes, 'align'> {
|
|
6
|
+
align?: TableAlign
|
|
7
|
+
density?: TableDensity
|
|
8
|
+
numeric?: boolean
|
|
9
|
+
}
|
|
10
|
+
const { align, density, numeric = false, class: className, ...rest } = Astro.props
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<td class={cn(tableCellVariants({ align, density, numeric: numeric ? 'true' : 'false' }), className)} data-slot="table-cell" {...rest}><slot /></td>
|