@refraction-ui/astro 0.13.0 → 0.15.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.
Files changed (62) hide show
  1. package/dist/astro-audience-feature-card/AudienceFeatureCard.astro +53 -0
  2. package/dist/astro-audience-feature-card/index.ts +1 -0
  3. package/dist/astro-brand-network-cell/BrandNetworkCell.astro +77 -0
  4. package/dist/astro-brand-network-cell/index.ts +1 -0
  5. package/dist/astro-browser-chrome-mock/BrowserChromeMock.astro +62 -0
  6. package/dist/astro-browser-chrome-mock/index.ts +1 -0
  7. package/dist/astro-kanban-board/KanbanBoard.astro +92 -0
  8. package/dist/astro-kanban-board/index.ts +1 -0
  9. package/dist/astro-marquee-strip/MarqueeStrip.astro +63 -0
  10. package/dist/astro-marquee-strip/index.ts +1 -0
  11. package/dist/astro-mastery-bar/MasteryBar.astro +56 -0
  12. package/dist/astro-mastery-bar/index.ts +1 -0
  13. package/dist/astro-numbered-steps/NumberedSteps.astro +47 -0
  14. package/dist/astro-numbered-steps/index.ts +1 -0
  15. package/dist/astro-pricing-card/PricingCard.astro +114 -0
  16. package/dist/astro-pricing-card/index.ts +1 -0
  17. package/dist/astro-section-head/SectionHead.astro +44 -0
  18. package/dist/astro-section-head/index.ts +1 -0
  19. package/dist/astro-slot-picker/SlotPicker.astro +105 -0
  20. package/dist/astro-slot-picker/index.ts +1 -0
  21. package/dist/astro-sortable-list/SortableList.astro +68 -0
  22. package/dist/astro-sortable-list/index.ts +1 -0
  23. package/dist/astro-stat-grid/StatGrid.astro +46 -0
  24. package/dist/astro-stat-grid/index.ts +1 -0
  25. package/dist/audience-feature-card/audience-feature-card.styles.ts +23 -0
  26. package/dist/audience-feature-card/audience-feature-card.ts +39 -0
  27. package/dist/audience-feature-card/index.ts +13 -0
  28. package/dist/brand-network-cell/brand-network-cell.styles.ts +46 -0
  29. package/dist/brand-network-cell/brand-network-cell.ts +35 -0
  30. package/dist/brand-network-cell/index.ts +14 -0
  31. package/dist/browser-chrome-mock/browser-chrome-mock.styles.ts +43 -0
  32. package/dist/browser-chrome-mock/browser-chrome-mock.ts +52 -0
  33. package/dist/browser-chrome-mock/index.ts +17 -0
  34. package/dist/index.ts +12 -0
  35. package/dist/kanban-board/index.ts +20 -0
  36. package/dist/kanban-board/kanban-board.styles.ts +78 -0
  37. package/dist/kanban-board/kanban-board.ts +82 -0
  38. package/dist/marquee-strip/index.ts +14 -0
  39. package/dist/marquee-strip/marquee-strip.styles.ts +61 -0
  40. package/dist/marquee-strip/marquee-strip.ts +35 -0
  41. package/dist/mastery-bar/index.ts +15 -0
  42. package/dist/mastery-bar/mastery-bar.styles.ts +45 -0
  43. package/dist/mastery-bar/mastery-bar.ts +55 -0
  44. package/dist/numbered-steps/index.ts +16 -0
  45. package/dist/numbered-steps/numbered-steps.styles.ts +36 -0
  46. package/dist/numbered-steps/numbered-steps.ts +64 -0
  47. package/dist/pricing-card/index.ts +19 -0
  48. package/dist/pricing-card/pricing-card.styles.ts +71 -0
  49. package/dist/pricing-card/pricing-card.ts +37 -0
  50. package/dist/section-head/index.ts +13 -0
  51. package/dist/section-head/section-head.styles.ts +30 -0
  52. package/dist/section-head/section-head.ts +28 -0
  53. package/dist/slot-picker/index.ts +18 -0
  54. package/dist/slot-picker/slot-picker.styles.ts +70 -0
  55. package/dist/slot-picker/slot-picker.ts +64 -0
  56. package/dist/sortable-list/index.ts +13 -0
  57. package/dist/sortable-list/sortable-list.styles.ts +42 -0
  58. package/dist/sortable-list/sortable-list.ts +90 -0
  59. package/dist/stat-grid/index.ts +13 -0
  60. package/dist/stat-grid/stat-grid.styles.ts +25 -0
  61. package/dist/stat-grid/stat-grid.ts +41 -0
  62. package/package.json +13 -1
@@ -0,0 +1,28 @@
1
+ /** Horizontal alignment of the section head cluster. */
2
+ export type SectionHeadAlign = 'center' | 'left'
3
+
4
+ export interface SectionHeadProps {
5
+ /** Alignment of the kicker, title, and lede. */
6
+ align?: SectionHeadAlign
7
+ }
8
+
9
+ export interface SectionHeadAPI {
10
+ /** Data attributes for styling hooks. */
11
+ dataAttributes: Record<string, string>
12
+ }
13
+
14
+ /**
15
+ * Build the framework-agnostic data attributes for a SectionHead.
16
+ *
17
+ * Returns data-align so adapters can apply styles via CSS or Tailwind
18
+ * variants. All visual logic (classes, cva) lives in `section-head.styles.ts`.
19
+ */
20
+ export function createSectionHead(props: SectionHeadProps = {}): SectionHeadAPI {
21
+ const { align = 'center' } = props
22
+
23
+ const dataAttributes: Record<string, string> = {
24
+ 'data-align': align,
25
+ }
26
+
27
+ return { dataAttributes }
28
+ }
@@ -0,0 +1,18 @@
1
+ export {
2
+ slotsForDay,
3
+ isSlotSelected,
4
+ createSlotPicker,
5
+ type SlotDay,
6
+ type SlotSelection,
7
+ type SlotPickerAPI,
8
+ } from './slot-picker.js'
9
+
10
+ export {
11
+ slotPickerVariants,
12
+ slotPickerDayRowClass,
13
+ slotPickerDayVariants,
14
+ slotPickerGridClass,
15
+ slotPickerSlotVariants,
16
+ slotPickerSectionLabelClass,
17
+ slotPickerTimezoneClass,
18
+ } from './slot-picker.styles.js'
@@ -0,0 +1,70 @@
1
+ import { cva } from '../shared/index.ts'
2
+
3
+ /** Root wrapper for the entire slot picker (day row + slots grid). */
4
+ export const slotPickerVariants = cva({
5
+ base: 'flex flex-col gap-4',
6
+ variants: {},
7
+ defaultVariants: {},
8
+ })
9
+
10
+ /** Scrollable row of day chips. */
11
+ export const slotPickerDayRowClass = 'flex items-center gap-2 overflow-x-auto pb-1'
12
+
13
+ /**
14
+ * Individual day chip.
15
+ *
16
+ * `selected` → primary treatment; `unselected` → card with border.
17
+ */
18
+ export const slotPickerDayVariants = cva({
19
+ base: [
20
+ 'inline-flex flex-col items-center justify-center rounded-lg px-3 py-2 min-w-[3.5rem]',
21
+ 'text-sm font-medium cursor-pointer transition-colors',
22
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
23
+ 'disabled:pointer-events-none disabled:opacity-50',
24
+ ].join(' '),
25
+ variants: {
26
+ selected: {
27
+ true: 'bg-primary text-primary-foreground',
28
+ false: 'bg-card border border-input text-foreground hover:bg-muted',
29
+ },
30
+ },
31
+ defaultVariants: {
32
+ selected: 'false',
33
+ },
34
+ })
35
+
36
+ /** Grid that holds the time-slot buttons. */
37
+ export const slotPickerGridClass = 'grid grid-cols-3 gap-2 sm:grid-cols-4'
38
+
39
+ /**
40
+ * Individual time-slot button.
41
+ *
42
+ * `selected` → primary; `disabled` → dimmed regardless of selection.
43
+ */
44
+ export const slotPickerSlotVariants = cva({
45
+ base: [
46
+ 'inline-flex items-center justify-center rounded-md border px-3 py-2 text-sm font-medium',
47
+ 'transition-colors cursor-pointer',
48
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
49
+ ].join(' '),
50
+ variants: {
51
+ selected: {
52
+ true: 'bg-primary text-primary-foreground border-primary',
53
+ false: 'bg-card border-input text-foreground hover:bg-muted',
54
+ },
55
+ disabled: {
56
+ true: 'opacity-40 pointer-events-none',
57
+ false: '',
58
+ },
59
+ },
60
+ defaultVariants: {
61
+ selected: 'false',
62
+ disabled: 'false',
63
+ },
64
+ })
65
+
66
+ /** Section label above the day row or slot grid (e.g. "Pick a day"). */
67
+ export const slotPickerSectionLabelClass = 'text-sm font-semibold text-foreground'
68
+
69
+ /** Timezone label rendered beside the "Pick a time" heading. */
70
+ export const slotPickerTimezoneClass = 'text-xs text-muted-foreground ml-2'
@@ -0,0 +1,64 @@
1
+ /** A single day chip shown in the day-selector row. */
2
+ export type SlotDay = {
3
+ /** Unique identifier for the day (e.g. "2024-06-14"). */
4
+ id: string
5
+ /** Short weekday label (e.g. "Fri"). */
6
+ weekday: string
7
+ /** Day-of-month label (e.g. "14" or 14). */
8
+ dayNum: string | number
9
+ }
10
+
11
+ /** The currently-selected day + time slot pair. */
12
+ export type SlotSelection = {
13
+ /** The `id` of the selected day. */
14
+ dayId: string
15
+ /** The selected time slot string (e.g. "10:00 AM"). */
16
+ slot: string
17
+ }
18
+
19
+ /**
20
+ * Return the list of available time slots for a given day.
21
+ * Returns an empty array when `dayId` has no entry in `slotsByDay`.
22
+ */
23
+ export function slotsForDay(
24
+ slotsByDay: Record<string, string[]>,
25
+ dayId: string,
26
+ ): string[] {
27
+ return slotsByDay[dayId] ?? []
28
+ }
29
+
30
+ /**
31
+ * Check whether a specific slot in a specific day is currently selected.
32
+ */
33
+ export function isSlotSelected(
34
+ value: SlotSelection | undefined,
35
+ dayId: string,
36
+ slot: string,
37
+ ): boolean {
38
+ return value?.dayId === dayId && value?.slot === slot
39
+ }
40
+
41
+ export interface SlotPickerAPI {
42
+ /** ARIA attributes to spread on the root group element. */
43
+ ariaProps: { role: 'group'; 'aria-label': string }
44
+ /** Data attributes for styling hooks. */
45
+ dataAttributes: Record<string, string>
46
+ }
47
+
48
+ /**
49
+ * Build the framework-agnostic root props for a slot picker.
50
+ *
51
+ * Returns `role="group"` with an accessible label and data attributes.
52
+ * Adapters spread these onto their container element.
53
+ */
54
+ export function createSlotPicker(): SlotPickerAPI {
55
+ return {
56
+ ariaProps: {
57
+ role: 'group',
58
+ 'aria-label': 'Pick a time',
59
+ },
60
+ dataAttributes: {
61
+ 'data-component': 'slot-picker',
62
+ },
63
+ }
64
+ }
@@ -0,0 +1,13 @@
1
+ export {
2
+ reorder,
3
+ getNextOrderIndex,
4
+ createSortableList,
5
+ type SortableListAPI,
6
+ } from './sortable-list.js'
7
+
8
+ export {
9
+ sortableListVariants,
10
+ sortableListRowVariants,
11
+ sortableListGripClass,
12
+ sortableListContentClass,
13
+ } from './sortable-list.styles.js'
@@ -0,0 +1,42 @@
1
+ import { cva } from '../shared/index.ts'
2
+
3
+ /** The outer list container. */
4
+ export const sortableListVariants = cva({
5
+ base: 'flex flex-col gap-1 w-full',
6
+ variants: {
7
+ disabled: {
8
+ true: 'opacity-50 pointer-events-none',
9
+ false: '',
10
+ },
11
+ },
12
+ defaultVariants: {
13
+ disabled: 'false',
14
+ },
15
+ })
16
+
17
+ /**
18
+ * A single row in the list. The `dragging` variant visually lifts the row
19
+ * while it is being dragged.
20
+ */
21
+ export const sortableListRowVariants = cva({
22
+ base: [
23
+ 'flex items-center gap-3 rounded-md border border-border bg-card px-3 py-2',
24
+ 'transition-opacity',
25
+ ].join(' '),
26
+ variants: {
27
+ dragging: {
28
+ true: 'opacity-50 ring-2 ring-ring',
29
+ false: '',
30
+ },
31
+ },
32
+ defaultVariants: {
33
+ dragging: 'false',
34
+ },
35
+ })
36
+
37
+ /** The drag-grip handle button/icon area. */
38
+ export const sortableListGripClass =
39
+ 'cursor-grab text-muted-foreground shrink-0 flex items-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded'
40
+
41
+ /** Wraps the caller-supplied row content (fills remaining space). */
42
+ export const sortableListContentClass = 'flex-1 min-w-0'
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Pure, JSX-free headless logic for a drag-to-reorder vertical list.
3
+ *
4
+ * Three exports:
5
+ * - `reorder` — immutable array move, clamped
6
+ * - `getNextOrderIndex` — keyboard navigation rule (clamped, no wrap)
7
+ * - `createSortableList` — builds ARIA props for the list container
8
+ */
9
+
10
+ export interface SortableListAPI {
11
+ /** ARIA attributes to spread on the list element. */
12
+ ariaProps: Record<string, string | number | boolean>
13
+ /** Data attributes for styling hooks. */
14
+ dataAttributes: Record<string, string>
15
+ }
16
+
17
+ /**
18
+ * Move an item from index `from` to index `to` in `items`, returning a new
19
+ * array. Out-of-range indices return a shallow copy of the original array
20
+ * (no mutation, no throw).
21
+ */
22
+ export function reorder<T>(items: T[], from: number, to: number): T[] {
23
+ const len = items.length
24
+ if (
25
+ len === 0 ||
26
+ from < 0 ||
27
+ from >= len ||
28
+ to < 0 ||
29
+ to >= len ||
30
+ from === to
31
+ ) {
32
+ return [...items]
33
+ }
34
+ const result = [...items]
35
+ const [moved] = result.splice(from, 1)
36
+ result.splice(to, 0, moved)
37
+ return result
38
+ }
39
+
40
+ /**
41
+ * Keyboard reorder navigation — returns the next index for a given key.
42
+ *
43
+ * - ArrowUp / ArrowLeft → max(0, current - 1)
44
+ * - ArrowDown / ArrowRight → min(count - 1, current + 1)
45
+ * - Home → 0
46
+ * - End → count - 1
47
+ * - All other keys / empty list → current (clamped to valid range)
48
+ *
49
+ * Never wraps.
50
+ */
51
+ export function getNextOrderIndex(
52
+ current: number,
53
+ key: string,
54
+ count: number,
55
+ ): number {
56
+ if (count <= 0) return current
57
+ const clamped = Math.max(0, Math.min(current, count - 1))
58
+
59
+ switch (key) {
60
+ case 'ArrowUp':
61
+ case 'ArrowLeft':
62
+ return Math.max(0, clamped - 1)
63
+ case 'ArrowDown':
64
+ case 'ArrowRight':
65
+ return Math.min(count - 1, clamped + 1)
66
+ case 'Home':
67
+ return 0
68
+ case 'End':
69
+ return count - 1
70
+ default:
71
+ return clamped
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Build the framework-agnostic props for a sortable list container.
77
+ *
78
+ * Returns `role="list"` so screen readers announce the number of items
79
+ * correctly, plus a `data-component` hook for styling.
80
+ */
81
+ export function createSortableList(): SortableListAPI {
82
+ return {
83
+ ariaProps: {
84
+ role: 'list',
85
+ },
86
+ dataAttributes: {
87
+ 'data-component': 'sortable-list',
88
+ },
89
+ }
90
+ }
@@ -0,0 +1,13 @@
1
+ export {
2
+ createStatGrid,
3
+ statColumns,
4
+ type StatItem,
5
+ type StatGridAPI,
6
+ } from './stat-grid.js'
7
+
8
+ export {
9
+ statGridVariants,
10
+ statItemClass,
11
+ statValueClass,
12
+ statLabelClass,
13
+ } from './stat-grid.styles.js'
@@ -0,0 +1,25 @@
1
+ import { cva } from '../shared/index.ts'
2
+
3
+ /** Grid container that lays out stat items. */
4
+ export const statGridVariants = cva({
5
+ base: 'grid gap-8',
6
+ variants: {
7
+ columns: {
8
+ '1': 'grid-cols-1',
9
+ '2': 'grid-cols-2',
10
+ '3': 'grid-cols-3',
11
+ },
12
+ },
13
+ defaultVariants: {
14
+ columns: '3',
15
+ },
16
+ })
17
+
18
+ /** Individual stat item container (role="listitem"). */
19
+ export const statItemClass = 'flex flex-col'
20
+
21
+ /** The large bold value of the stat. */
22
+ export const statValueClass = 'text-xl sm:text-2xl font-bold text-primary'
23
+
24
+ /** The descriptive label below the value. */
25
+ export const statLabelClass = 'mt-1 text-sm text-muted-foreground leading-snug'
@@ -0,0 +1,41 @@
1
+ /** A single stat callout displayed in the grid. */
2
+ export type StatItem = {
3
+ /** The primary value displayed prominently (e.g. "10k+", "$4.2M"). */
4
+ value: string
5
+ /** The descriptive label shown below the value. */
6
+ label: string
7
+ }
8
+
9
+ export interface StatGridAPI {
10
+ /** ARIA attributes to spread on the grid container element (`role="list"`). */
11
+ ariaProps: { role: 'list' }
12
+ /** Data attributes for styling hooks. */
13
+ dataAttributes: Record<string, string>
14
+ }
15
+
16
+ /**
17
+ * Compute the number of grid columns for a stat grid.
18
+ *
19
+ * - 1 item → 1 column
20
+ * - 2 items → 2 columns
21
+ * - 3 or more items → capped at `max` (default 3)
22
+ */
23
+ export function statColumns(count: number, max = 3): number {
24
+ if (count <= 0) return 1
25
+ if (count === 1) return 1
26
+ if (count === 2) return 2
27
+ return Math.min(count, max)
28
+ }
29
+
30
+ /**
31
+ * Build the framework-agnostic container props for a stat grid.
32
+ *
33
+ * Returns `role="list"` and data attributes; adapters spread these onto their
34
+ * container element and render the items themselves.
35
+ */
36
+ export function createStatGrid(): StatGridAPI {
37
+ return {
38
+ ariaProps: { role: 'list' },
39
+ dataAttributes: {},
40
+ }
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@refraction-ui/astro",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "All Refraction UI Astro components in one package",
5
5
  "type": "module",
6
6
  "exports": {
@@ -25,13 +25,16 @@
25
25
  "@refraction-ui/astro-analytics": "workspace:*",
26
26
  "@refraction-ui/astro-animated-text": "workspace:*",
27
27
  "@refraction-ui/astro-app-shell": "workspace:*",
28
+ "@refraction-ui/astro-audience-feature-card": "workspace:*",
28
29
  "@refraction-ui/astro-audio-room": "workspace:*",
29
30
  "@refraction-ui/astro-auth": "workspace:*",
30
31
  "@refraction-ui/astro-avatar": "workspace:*",
31
32
  "@refraction-ui/astro-avatar-group": "workspace:*",
32
33
  "@refraction-ui/astro-badge": "workspace:*",
33
34
  "@refraction-ui/astro-bottom-nav": "workspace:*",
35
+ "@refraction-ui/astro-brand-network-cell": "workspace:*",
34
36
  "@refraction-ui/astro-breadcrumbs": "workspace:*",
37
+ "@refraction-ui/astro-browser-chrome-mock": "workspace:*",
35
38
  "@refraction-ui/astro-button": "workspace:*",
36
39
  "@refraction-ui/astro-calendar": "workspace:*",
37
40
  "@refraction-ui/astro-call-controls": "workspace:*",
@@ -73,6 +76,7 @@
73
76
  "@refraction-ui/astro-input": "workspace:*",
74
77
  "@refraction-ui/astro-input-group": "workspace:*",
75
78
  "@refraction-ui/astro-install-prompt": "workspace:*",
79
+ "@refraction-ui/astro-kanban-board": "workspace:*",
76
80
  "@refraction-ui/astro-keyboard-shortcut": "workspace:*",
77
81
  "@refraction-ui/astro-language-selector": "workspace:*",
78
82
  "@refraction-ui/astro-link-card": "workspace:*",
@@ -81,9 +85,12 @@
81
85
  "@refraction-ui/astro-live-transcript": "workspace:*",
82
86
  "@refraction-ui/astro-logger": "workspace:*",
83
87
  "@refraction-ui/astro-markdown-renderer": "workspace:*",
88
+ "@refraction-ui/astro-marquee-strip": "workspace:*",
89
+ "@refraction-ui/astro-mastery-bar": "workspace:*",
84
90
  "@refraction-ui/astro-mini-map": "workspace:*",
85
91
  "@refraction-ui/astro-mobile-nav": "workspace:*",
86
92
  "@refraction-ui/astro-navbar": "workspace:*",
93
+ "@refraction-ui/astro-numbered-steps": "workspace:*",
87
94
  "@refraction-ui/astro-otp-input": "workspace:*",
88
95
  "@refraction-ui/astro-pagination": "workspace:*",
89
96
  "@refraction-ui/astro-password-input": "workspace:*",
@@ -91,6 +98,7 @@
91
98
  "@refraction-ui/astro-popover": "workspace:*",
92
99
  "@refraction-ui/astro-pre-call-lobby": "workspace:*",
93
100
  "@refraction-ui/astro-presence-indicator": "workspace:*",
101
+ "@refraction-ui/astro-pricing-card": "workspace:*",
94
102
  "@refraction-ui/astro-progress-display": "workspace:*",
95
103
  "@refraction-ui/astro-radial-gauge": "workspace:*",
96
104
  "@refraction-ui/astro-radio": "workspace:*",
@@ -99,6 +107,7 @@
99
107
  "@refraction-ui/astro-resizable-layout": "workspace:*",
100
108
  "@refraction-ui/astro-rich-editor": "workspace:*",
101
109
  "@refraction-ui/astro-search-bar": "workspace:*",
110
+ "@refraction-ui/astro-section-head": "workspace:*",
102
111
  "@refraction-ui/astro-segmented-control": "workspace:*",
103
112
  "@refraction-ui/astro-select": "workspace:*",
104
113
  "@refraction-ui/astro-separator": "workspace:*",
@@ -107,7 +116,10 @@
107
116
  "@refraction-ui/astro-skip-to-content": "workspace:*",
108
117
  "@refraction-ui/astro-slide-viewer": "workspace:*",
109
118
  "@refraction-ui/astro-slider": "workspace:*",
119
+ "@refraction-ui/astro-slot-picker": "workspace:*",
110
120
  "@refraction-ui/astro-social-auth-button": "workspace:*",
121
+ "@refraction-ui/astro-sortable-list": "workspace:*",
122
+ "@refraction-ui/astro-stat-grid": "workspace:*",
111
123
  "@refraction-ui/astro-status-indicator": "workspace:*",
112
124
  "@refraction-ui/astro-steps": "workspace:*",
113
125
  "@refraction-ui/astro-sticky-note": "workspace:*",