@refraction-ui/astro 0.12.0 → 0.14.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/astro-audience-feature-card/AudienceFeatureCard.astro +53 -0
- package/dist/astro-audience-feature-card/index.ts +1 -0
- package/dist/astro-audio-room/AudioRoom.astro +81 -0
- package/dist/astro-audio-room/index.ts +1 -0
- package/dist/astro-brand-network-cell/BrandNetworkCell.astro +77 -0
- package/dist/astro-brand-network-cell/index.ts +1 -0
- package/dist/astro-browser-chrome-mock/BrowserChromeMock.astro +62 -0
- package/dist/astro-browser-chrome-mock/index.ts +1 -0
- package/dist/astro-call-controls/CallControls.astro +57 -0
- package/dist/astro-call-controls/index.ts +1 -0
- package/dist/astro-checklist/Checklist.astro +76 -0
- package/dist/astro-checklist/index.ts +1 -0
- package/dist/astro-editor-status-bar/EditorStatusBar.astro +92 -0
- package/dist/astro-editor-status-bar/index.ts +1 -0
- package/dist/astro-editor-tabs/EditorTabs.astro +74 -0
- package/dist/astro-editor-tabs/index.ts +1 -0
- package/dist/astro-floating-reactions/FloatingReactions.astro +56 -0
- package/dist/astro-floating-reactions/index.ts +1 -0
- package/dist/astro-flow-editor/FlowEditor.astro +99 -0
- package/dist/astro-flow-editor/index.ts +3 -0
- package/dist/astro-graph-view/GraphView.astro +109 -0
- package/dist/astro-graph-view/index.ts +1 -0
- package/dist/astro-infinite-canvas/InfiniteCanvas.astro +43 -0
- package/dist/astro-infinite-canvas/index.ts +1 -0
- package/dist/astro-live-captions/LiveCaptions.astro +54 -0
- package/dist/astro-live-captions/index.ts +1 -0
- package/dist/astro-live-cursors/LiveCursors.astro +55 -0
- package/dist/astro-live-cursors/index.ts +1 -0
- package/dist/astro-live-transcript/LiveTranscript.astro +55 -0
- package/dist/astro-live-transcript/index.ts +1 -0
- package/dist/astro-marquee-strip/MarqueeStrip.astro +63 -0
- package/dist/astro-marquee-strip/index.ts +1 -0
- package/dist/astro-mastery-bar/MasteryBar.astro +56 -0
- package/dist/astro-mastery-bar/index.ts +1 -0
- package/dist/astro-mini-map/MiniMap.astro +74 -0
- package/dist/astro-mini-map/index.ts +1 -0
- package/dist/astro-numbered-steps/NumberedSteps.astro +47 -0
- package/dist/astro-numbered-steps/index.ts +1 -0
- package/dist/astro-pre-call-lobby/PreCallLobby.astro +202 -0
- package/dist/astro-pre-call-lobby/index.ts +1 -0
- package/dist/astro-pricing-card/PricingCard.astro +114 -0
- package/dist/astro-pricing-card/index.ts +1 -0
- package/dist/astro-radial-gauge/RadialGauge.astro +144 -0
- package/dist/astro-radial-gauge/index.ts +1 -0
- package/dist/astro-rating-scale/RatingScale.astro +73 -0
- package/dist/astro-rating-scale/index.ts +1 -0
- package/dist/astro-section-head/SectionHead.astro +44 -0
- package/dist/astro-section-head/index.ts +1 -0
- package/dist/astro-stat-grid/StatGrid.astro +46 -0
- package/dist/astro-stat-grid/index.ts +1 -0
- package/dist/astro-sticky-note/StickyNote.astro +55 -0
- package/dist/astro-sticky-note/index.ts +1 -0
- package/dist/astro-terminal/Terminal.astro +67 -0
- package/dist/astro-terminal/index.ts +1 -0
- package/dist/astro-test-results/TestResults.astro +76 -0
- package/dist/astro-test-results/index.ts +1 -0
- package/dist/astro-timeline/Timeline.astro +59 -0
- package/dist/astro-timeline/index.ts +1 -0
- package/dist/astro-video-grid/VideoGrid.astro +182 -0
- package/dist/astro-video-grid/index.ts +1 -0
- package/dist/astro-video-tile/VideoTile.astro +104 -0
- package/dist/astro-video-tile/index.ts +1 -0
- package/dist/astro-wizard/Wizard.astro +137 -0
- package/dist/astro-wizard/index.ts +1 -0
- package/dist/audience-feature-card/audience-feature-card.styles.ts +23 -0
- package/dist/audience-feature-card/audience-feature-card.ts +39 -0
- package/dist/audience-feature-card/index.ts +13 -0
- package/dist/audio-room/audio-room.styles.ts +88 -0
- package/dist/audio-room/audio-room.ts +70 -0
- package/dist/audio-room/index.ts +16 -0
- package/dist/brand-network-cell/brand-network-cell.styles.ts +46 -0
- package/dist/brand-network-cell/brand-network-cell.ts +35 -0
- package/dist/brand-network-cell/index.ts +14 -0
- package/dist/browser-chrome-mock/browser-chrome-mock.styles.ts +43 -0
- package/dist/browser-chrome-mock/browser-chrome-mock.ts +52 -0
- package/dist/browser-chrome-mock/index.ts +17 -0
- package/dist/call-controls/call-controls.styles.ts +63 -0
- package/dist/call-controls/call-controls.ts +79 -0
- package/dist/call-controls/index.ts +15 -0
- package/dist/checklist/checklist.styles.ts +76 -0
- package/dist/checklist/checklist.ts +62 -0
- package/dist/checklist/index.ts +18 -0
- package/dist/editor-status-bar/editor-status-bar.styles.ts +40 -0
- package/dist/editor-status-bar/editor-status-bar.ts +78 -0
- package/dist/editor-status-bar/index.ts +15 -0
- package/dist/editor-tabs/editor-tabs.styles.ts +52 -0
- package/dist/editor-tabs/editor-tabs.ts +82 -0
- package/dist/editor-tabs/index.ts +15 -0
- package/dist/floating-reactions/floating-reactions.styles.ts +54 -0
- package/dist/floating-reactions/floating-reactions.ts +85 -0
- package/dist/floating-reactions/index.ts +14 -0
- package/dist/flow-editor/flow-editor.styles.ts +56 -0
- package/dist/flow-editor/flow-editor.ts +126 -0
- package/dist/flow-editor/index.ts +18 -0
- package/dist/graph-view/graph-view.styles.ts +66 -0
- package/dist/graph-view/graph-view.ts +130 -0
- package/dist/graph-view/index.ts +21 -0
- package/dist/index.ts +32 -0
- package/dist/infinite-canvas/index.ts +17 -0
- package/dist/infinite-canvas/infinite-canvas.styles.ts +49 -0
- package/dist/infinite-canvas/infinite-canvas.ts +97 -0
- package/dist/live-captions/index.ts +13 -0
- package/dist/live-captions/live-captions.styles.ts +45 -0
- package/dist/live-captions/live-captions.ts +57 -0
- package/dist/live-cursors/index.ts +14 -0
- package/dist/live-cursors/live-cursors.styles.ts +41 -0
- package/dist/live-cursors/live-cursors.ts +73 -0
- package/dist/live-transcript/index.ts +16 -0
- package/dist/live-transcript/live-transcript.styles.ts +48 -0
- package/dist/live-transcript/live-transcript.ts +82 -0
- package/dist/marquee-strip/index.ts +14 -0
- package/dist/marquee-strip/marquee-strip.styles.ts +61 -0
- package/dist/marquee-strip/marquee-strip.ts +35 -0
- package/dist/mastery-bar/index.ts +15 -0
- package/dist/mastery-bar/mastery-bar.styles.ts +45 -0
- package/dist/mastery-bar/mastery-bar.ts +55 -0
- package/dist/mini-map/index.ts +16 -0
- package/dist/mini-map/mini-map.styles.ts +32 -0
- package/dist/mini-map/mini-map.ts +122 -0
- package/dist/numbered-steps/index.ts +16 -0
- package/dist/numbered-steps/numbered-steps.styles.ts +36 -0
- package/dist/numbered-steps/numbered-steps.ts +64 -0
- package/dist/pre-call-lobby/index.ts +22 -0
- package/dist/pre-call-lobby/pre-call-lobby.styles.ts +108 -0
- package/dist/pre-call-lobby/pre-call-lobby.ts +61 -0
- package/dist/pricing-card/index.ts +19 -0
- package/dist/pricing-card/pricing-card.styles.ts +71 -0
- package/dist/pricing-card/pricing-card.ts +37 -0
- package/dist/radial-gauge/index.ts +26 -0
- package/dist/radial-gauge/radial-gauge.styles.ts +75 -0
- package/dist/radial-gauge/radial-gauge.ts +183 -0
- package/dist/rating-scale/index.ts +16 -0
- package/dist/rating-scale/rating-scale.styles.ts +48 -0
- package/dist/rating-scale/rating-scale.ts +101 -0
- package/dist/section-head/index.ts +13 -0
- package/dist/section-head/section-head.styles.ts +30 -0
- package/dist/section-head/section-head.ts +28 -0
- package/dist/stat-grid/index.ts +13 -0
- package/dist/stat-grid/stat-grid.styles.ts +25 -0
- package/dist/stat-grid/stat-grid.ts +41 -0
- package/dist/sticky-note/index.ts +14 -0
- package/dist/sticky-note/sticky-note.styles.ts +37 -0
- package/dist/sticky-note/sticky-note.ts +47 -0
- package/dist/terminal/index.ts +13 -0
- package/dist/terminal/terminal.styles.ts +56 -0
- package/dist/terminal/terminal.ts +60 -0
- package/dist/test-results/index.ts +19 -0
- package/dist/test-results/test-results.styles.ts +93 -0
- package/dist/test-results/test-results.ts +83 -0
- package/dist/timeline/index.ts +22 -0
- package/dist/timeline/timeline.styles.ts +98 -0
- package/dist/timeline/timeline.ts +86 -0
- package/dist/video-grid/index.ts +16 -0
- package/dist/video-grid/video-grid.styles.ts +38 -0
- package/dist/video-grid/video-grid.ts +93 -0
- package/dist/video-tile/index.ts +17 -0
- package/dist/video-tile/video-tile.styles.ts +59 -0
- package/dist/video-tile/video-tile.ts +74 -0
- package/dist/wizard/index.ts +28 -0
- package/dist/wizard/wizard.styles.ts +147 -0
- package/dist/wizard/wizard.ts +128 -0
- package/package.json +33 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AccessibilityProps } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
export interface AudienceFeatureCardProps {
|
|
4
|
+
/** Kicker text displayed above the title (e.g. "For teams"). */
|
|
5
|
+
kicker?: string
|
|
6
|
+
/** Main title — required. */
|
|
7
|
+
title: string
|
|
8
|
+
/** Body copy. */
|
|
9
|
+
body: string
|
|
10
|
+
/** Footer content (optional). */
|
|
11
|
+
footer?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface AudienceFeatureCardAPI {
|
|
15
|
+
/** ARIA attributes to spread on the group element (`role="group"`). */
|
|
16
|
+
ariaProps: Partial<AccessibilityProps>
|
|
17
|
+
/** Data attributes for styling hooks. */
|
|
18
|
+
dataAttributes: Record<string, string>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Build the framework-agnostic group props for an audience feature card.
|
|
23
|
+
*
|
|
24
|
+
* Returns `role="group"` plus data attributes; adapters spread these onto
|
|
25
|
+
* their container and render the kicker, title, body, and footer slots.
|
|
26
|
+
*/
|
|
27
|
+
export function createAudienceFeatureCard(
|
|
28
|
+
_props: Partial<AudienceFeatureCardProps> = {},
|
|
29
|
+
): AudienceFeatureCardAPI {
|
|
30
|
+
const ariaProps: Partial<AccessibilityProps> = {
|
|
31
|
+
role: 'group',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const dataAttributes: Record<string, string> = {
|
|
35
|
+
'data-component': 'audience-feature-card',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { ariaProps, dataAttributes }
|
|
39
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createAudienceFeatureCard,
|
|
3
|
+
type AudienceFeatureCardProps,
|
|
4
|
+
type AudienceFeatureCardAPI,
|
|
5
|
+
} from './audience-feature-card.js'
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
audienceFeatureCardVariants,
|
|
9
|
+
audienceFeatureCardKickerClass,
|
|
10
|
+
audienceFeatureCardTitleClass,
|
|
11
|
+
audienceFeatureCardBodyClass,
|
|
12
|
+
audienceFeatureCardFooterClass,
|
|
13
|
+
} from './audience-feature-card.styles.js'
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { cva } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Grid container that lays out the speaking orbs.
|
|
5
|
+
*
|
|
6
|
+
* Column count and gap are applied via inline `gridTemplateColumns` in
|
|
7
|
+
* adapters (dynamic count); this cva handles only the non-dynamic layout
|
|
8
|
+
* concerns — display, alignment, and padding.
|
|
9
|
+
*/
|
|
10
|
+
export const audioRoomVariants = cva({
|
|
11
|
+
base: 'grid place-items-center gap-6 p-6 w-full',
|
|
12
|
+
variants: {},
|
|
13
|
+
defaultVariants: {},
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Wrapper cell for a single orb + name label combination.
|
|
18
|
+
* Keeps the avatar and label centred as a column.
|
|
19
|
+
*/
|
|
20
|
+
export const audioRoomOrbCellVariants = cva({
|
|
21
|
+
base: 'flex flex-col items-center gap-2',
|
|
22
|
+
variants: {},
|
|
23
|
+
defaultVariants: {},
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The circular avatar / speaking indicator.
|
|
28
|
+
*
|
|
29
|
+
* - `speaking` adds an animated ring using the primary colour.
|
|
30
|
+
* - `muted` dims the orb slightly to signal a silenced microphone.
|
|
31
|
+
*/
|
|
32
|
+
export const speakingOrbVariants = cva({
|
|
33
|
+
base: [
|
|
34
|
+
'relative inline-flex items-center justify-center',
|
|
35
|
+
'size-20 rounded-full',
|
|
36
|
+
'bg-muted text-muted-foreground font-semibold text-xl select-none',
|
|
37
|
+
'overflow-hidden',
|
|
38
|
+
'transition-shadow duration-300',
|
|
39
|
+
].join(' '),
|
|
40
|
+
variants: {
|
|
41
|
+
speaking: {
|
|
42
|
+
true: [
|
|
43
|
+
'ring-4 ring-primary ring-offset-2 ring-offset-background',
|
|
44
|
+
'shadow-[0_0_0_4px_hsl(var(--primary)/0.25),0_0_16px_4px_hsl(var(--primary)/0.35)]',
|
|
45
|
+
].join(' '),
|
|
46
|
+
false: 'ring-2 ring-border',
|
|
47
|
+
},
|
|
48
|
+
muted: {
|
|
49
|
+
true: 'opacity-60',
|
|
50
|
+
false: '',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
defaultVariants: {
|
|
54
|
+
speaking: 'false',
|
|
55
|
+
muted: 'false',
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
/** Name label rendered below each orb. */
|
|
60
|
+
export const audioRoomNameLabelClass =
|
|
61
|
+
'text-sm font-medium text-foreground text-center max-w-[6rem] truncate'
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Muted badge — a small indicator overlaid at the bottom-right of the orb
|
|
65
|
+
* to show the microphone is off.
|
|
66
|
+
*/
|
|
67
|
+
export const audioRoomMutedBadgeClass = [
|
|
68
|
+
'absolute bottom-0 right-0',
|
|
69
|
+
'inline-flex items-center justify-center',
|
|
70
|
+
'size-6 rounded-full',
|
|
71
|
+
'bg-destructive text-destructive-foreground',
|
|
72
|
+
'text-[10px] leading-none',
|
|
73
|
+
'border-2 border-background',
|
|
74
|
+
'translate-x-1 translate-y-1',
|
|
75
|
+
].join(' ')
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Hand-raise badge — shown at the top-right of the orb.
|
|
79
|
+
*/
|
|
80
|
+
export const audioRoomHandBadgeClass = [
|
|
81
|
+
'absolute top-0 right-0',
|
|
82
|
+
'inline-flex items-center justify-center',
|
|
83
|
+
'size-6 rounded-full',
|
|
84
|
+
'bg-warning text-warning-foreground',
|
|
85
|
+
'text-[12px] leading-none',
|
|
86
|
+
'border-2 border-background',
|
|
87
|
+
'translate-x-1 -translate-y-1',
|
|
88
|
+
].join(' ')
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** A participant in an audio-only room. */
|
|
2
|
+
export interface AudioParticipant {
|
|
3
|
+
/** Unique participant identifier. */
|
|
4
|
+
id: string
|
|
5
|
+
/** Display name shown below the orb. */
|
|
6
|
+
name: string
|
|
7
|
+
/** Optional avatar image URL. Falls back to initials when absent. */
|
|
8
|
+
avatarUrl?: string
|
|
9
|
+
/** Whether this participant is currently speaking. */
|
|
10
|
+
speaking?: boolean
|
|
11
|
+
/** Whether this participant's microphone is muted. */
|
|
12
|
+
muted?: boolean
|
|
13
|
+
/** Whether this participant has raised their hand. */
|
|
14
|
+
handRaised?: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface AudioRoomAPI {
|
|
18
|
+
/** ARIA attributes to spread on the room container element. */
|
|
19
|
+
ariaProps: { role: 'group' }
|
|
20
|
+
/** Data attributes for styling hooks. */
|
|
21
|
+
dataAttributes: Record<string, string>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Derive up to two uppercase initials from a display name.
|
|
26
|
+
*
|
|
27
|
+
* Examples: "Alice" → "A", "Bob Smith" → "BS", "Dr. Jane Doe" → "JD"
|
|
28
|
+
* (only word-initial alphabetic characters are used).
|
|
29
|
+
*/
|
|
30
|
+
export function getInitials(name: string): string {
|
|
31
|
+
const words = name
|
|
32
|
+
.trim()
|
|
33
|
+
.split(/\s+/)
|
|
34
|
+
.filter((w) => /[A-Za-z]/.test(w))
|
|
35
|
+
if (words.length === 0) return ''
|
|
36
|
+
if (words.length === 1) return words[0][0].toUpperCase()
|
|
37
|
+
return (words[0][0] + words[words.length - 1][0]).toUpperCase()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Determine the number of grid columns for the orb grid.
|
|
42
|
+
*
|
|
43
|
+
* | Count | Columns |
|
|
44
|
+
* |--------|---------|
|
|
45
|
+
* | 1 | 1 |
|
|
46
|
+
* | 2–4 | 2 |
|
|
47
|
+
* | 5–9 | 3 |
|
|
48
|
+
* | 10+ | 4 |
|
|
49
|
+
*/
|
|
50
|
+
export function orbColumns(count: number): number {
|
|
51
|
+
if (count <= 1) return 1
|
|
52
|
+
if (count <= 4) return 2
|
|
53
|
+
if (count <= 9) return 3
|
|
54
|
+
return 4
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Build the framework-agnostic container props for an audio room.
|
|
59
|
+
*
|
|
60
|
+
* Returns `role="group"` plus data attributes that adapters spread onto
|
|
61
|
+
* their outermost container element.
|
|
62
|
+
*/
|
|
63
|
+
export function createAudioRoom(): AudioRoomAPI {
|
|
64
|
+
return {
|
|
65
|
+
ariaProps: { role: 'group' },
|
|
66
|
+
dataAttributes: {
|
|
67
|
+
'data-component': 'audio-room',
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createAudioRoom,
|
|
3
|
+
getInitials,
|
|
4
|
+
orbColumns,
|
|
5
|
+
type AudioParticipant,
|
|
6
|
+
type AudioRoomAPI,
|
|
7
|
+
} from './audio-room.js'
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
audioRoomVariants,
|
|
11
|
+
audioRoomOrbCellVariants,
|
|
12
|
+
speakingOrbVariants,
|
|
13
|
+
audioRoomNameLabelClass,
|
|
14
|
+
audioRoomMutedBadgeClass,
|
|
15
|
+
audioRoomHandBadgeClass,
|
|
16
|
+
} from './audio-room.styles.js'
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { cva } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Root card container. The `current` variant adds the primary ring that signals
|
|
5
|
+
* "You are here". Background and border come from semantic tokens so the card
|
|
6
|
+
* works in both light and dark themes without callers touching class names.
|
|
7
|
+
*/
|
|
8
|
+
export const brandNetworkCellVariants = cva({
|
|
9
|
+
base: [
|
|
10
|
+
'relative rounded-xl border border-border bg-card p-4',
|
|
11
|
+
'flex flex-col gap-3 transition-shadow',
|
|
12
|
+
].join(' '),
|
|
13
|
+
variants: {
|
|
14
|
+
current: {
|
|
15
|
+
true: 'ring-1 ring-primary',
|
|
16
|
+
false: '',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
current: 'false',
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Square glyph box — the brand monogram or icon.
|
|
26
|
+
* Background and text colour are caller-provided via inline `style` (brand
|
|
27
|
+
* tints vary per product); this class only controls geometry and typography.
|
|
28
|
+
*/
|
|
29
|
+
export const brandNetworkCellGlyphClass =
|
|
30
|
+
'flex size-10 items-center justify-center rounded-lg text-sm font-bold'
|
|
31
|
+
|
|
32
|
+
/** Domain / product name row. */
|
|
33
|
+
export const brandNetworkCellDomainClass = 'font-semibold text-foreground'
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* "You are here" badge shown beside the domain when `current` is true.
|
|
37
|
+
* Uses semantic token colours so it inherits the active theme automatically.
|
|
38
|
+
*/
|
|
39
|
+
export const brandNetworkCellCurrentBadgeClass =
|
|
40
|
+
'inline-flex items-center rounded-md bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary'
|
|
41
|
+
|
|
42
|
+
/** Supporting body text below the domain. */
|
|
43
|
+
export const brandNetworkCellBodyClass = 'text-sm text-muted-foreground'
|
|
44
|
+
|
|
45
|
+
/** Inline link row rendered at the bottom of the card. */
|
|
46
|
+
export const brandNetworkCellLinkClass = 'text-sm text-primary'
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AccessibilityProps } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
export interface BrandNetworkCellProps {
|
|
4
|
+
/** Whether this cell represents the current/active product in the network. */
|
|
5
|
+
current?: boolean
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface BrandNetworkCellAPI {
|
|
9
|
+
/** ARIA attributes to spread on the group element (`role="group"`). */
|
|
10
|
+
ariaProps: Partial<AccessibilityProps>
|
|
11
|
+
/** Data attributes for styling hooks. */
|
|
12
|
+
dataAttributes: Record<string, string>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Build the framework-agnostic group props for a brand network card.
|
|
17
|
+
*
|
|
18
|
+
* Returns `role="group"` plus a `data-current` attribute so adapters and
|
|
19
|
+
* consumers can style the "You are here" state without coupling to class names.
|
|
20
|
+
*/
|
|
21
|
+
export function createBrandNetworkCell(
|
|
22
|
+
props: BrandNetworkCellProps = {},
|
|
23
|
+
): BrandNetworkCellAPI {
|
|
24
|
+
const { current = false } = props
|
|
25
|
+
|
|
26
|
+
const ariaProps: Partial<AccessibilityProps> = {
|
|
27
|
+
role: 'group',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const dataAttributes: Record<string, string> = {
|
|
31
|
+
'data-current': String(current),
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { ariaProps, dataAttributes }
|
|
35
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createBrandNetworkCell,
|
|
3
|
+
type BrandNetworkCellProps,
|
|
4
|
+
type BrandNetworkCellAPI,
|
|
5
|
+
} from './brand-network-cell.js'
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
brandNetworkCellVariants,
|
|
9
|
+
brandNetworkCellGlyphClass,
|
|
10
|
+
brandNetworkCellDomainClass,
|
|
11
|
+
brandNetworkCellCurrentBadgeClass,
|
|
12
|
+
brandNetworkCellBodyClass,
|
|
13
|
+
brandNetworkCellLinkClass,
|
|
14
|
+
} from './brand-network-cell.styles.js'
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { cva } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
/** Outer frame wrapping the chrome bar and content. */
|
|
4
|
+
export const browserChromeMockVariants = cva({
|
|
5
|
+
base: 'rounded-xl border border-border overflow-hidden bg-card',
|
|
6
|
+
variants: {},
|
|
7
|
+
defaultVariants: {},
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
/** The chrome toolbar row containing dots, URL bar, and optional badge. */
|
|
11
|
+
export const chromeBarClass =
|
|
12
|
+
'flex items-center gap-2 bg-muted/40 border-b border-border px-3 py-2'
|
|
13
|
+
|
|
14
|
+
/** A single traffic-light dot. */
|
|
15
|
+
export const trafficDotClass = 'size-2.5 rounded-full border border-border'
|
|
16
|
+
|
|
17
|
+
/** Centered URL bar. */
|
|
18
|
+
export const urlBarClass = 'flex-1 text-center font-mono text-[11px] text-muted-foreground'
|
|
19
|
+
|
|
20
|
+
/** Bold domain segment inside the URL bar. */
|
|
21
|
+
export const urlDomainClass = 'font-semibold text-foreground'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Status badge shown in the chrome bar.
|
|
25
|
+
*
|
|
26
|
+
* live → emerald tint (approved exception to semantic tokens)
|
|
27
|
+
* rec → destructive tint with a pulsing dot
|
|
28
|
+
*/
|
|
29
|
+
export const statusBadgeVariants = cva({
|
|
30
|
+
base: 'inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide',
|
|
31
|
+
variants: {
|
|
32
|
+
status: {
|
|
33
|
+
live: 'text-emerald-500 bg-emerald-500/10',
|
|
34
|
+
rec: 'text-destructive bg-destructive/10',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
defaultVariants: {
|
|
38
|
+
status: 'live',
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
/** Inner content area that receives slotted/children content. */
|
|
43
|
+
export const contentAreaClass = 'p-0'
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Recording or live stream status for the browser chrome mock. */
|
|
2
|
+
export type BrowserChromeStatus = 'live' | 'rec'
|
|
3
|
+
|
|
4
|
+
export interface BrowserChromeMockProps {
|
|
5
|
+
/** URL to display in the address bar. */
|
|
6
|
+
url: string
|
|
7
|
+
/** Optional status badge shown in the chrome bar. */
|
|
8
|
+
status?: BrowserChromeStatus
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface BrowserChromeMockAPI {
|
|
12
|
+
/** ARIA attributes to spread on the group element. */
|
|
13
|
+
ariaProps: { role: 'group'; 'aria-label': string }
|
|
14
|
+
/** Data attributes for styling hooks. */
|
|
15
|
+
dataAttributes: Record<string, string>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Split a URL into bold domain and normal path segments. */
|
|
19
|
+
export function splitUrl(url: string): { domain: string; path: string } {
|
|
20
|
+
const slashIndex = url.indexOf('/')
|
|
21
|
+
if (slashIndex === -1) {
|
|
22
|
+
return { domain: url, path: '' }
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
domain: url.slice(0, slashIndex),
|
|
26
|
+
path: url.slice(slashIndex),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Build the framework-agnostic props for a BrowserChromeMock.
|
|
32
|
+
*
|
|
33
|
+
* Returns a `role="group"` aria label plus optional `data-status` so adapters
|
|
34
|
+
* can hook CSS without duplicating logic.
|
|
35
|
+
*/
|
|
36
|
+
export function createBrowserChromeMock(
|
|
37
|
+
props: Pick<BrowserChromeMockProps, 'status'> = {},
|
|
38
|
+
): BrowserChromeMockAPI {
|
|
39
|
+
const { status } = props
|
|
40
|
+
|
|
41
|
+
const ariaProps = {
|
|
42
|
+
role: 'group' as const,
|
|
43
|
+
'aria-label': 'Browser preview',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const dataAttributes: Record<string, string> = {}
|
|
47
|
+
if (status !== undefined) {
|
|
48
|
+
dataAttributes['data-status'] = status
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { ariaProps, dataAttributes }
|
|
52
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createBrowserChromeMock,
|
|
3
|
+
splitUrl,
|
|
4
|
+
type BrowserChromeStatus,
|
|
5
|
+
type BrowserChromeMockProps,
|
|
6
|
+
type BrowserChromeMockAPI,
|
|
7
|
+
} from './browser-chrome-mock.js'
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
browserChromeMockVariants,
|
|
11
|
+
chromeBarClass,
|
|
12
|
+
trafficDotClass,
|
|
13
|
+
urlBarClass,
|
|
14
|
+
urlDomainClass,
|
|
15
|
+
statusBadgeVariants,
|
|
16
|
+
contentAreaClass,
|
|
17
|
+
} from './browser-chrome-mock.styles.js'
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { cva } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Toolbar container — flex row, centred, with a card background and gap
|
|
5
|
+
* between the control buttons.
|
|
6
|
+
*/
|
|
7
|
+
export const callControlsVariants = cva({
|
|
8
|
+
base: [
|
|
9
|
+
'inline-flex items-center justify-center gap-2',
|
|
10
|
+
'rounded-xl bg-card px-4 py-3',
|
|
11
|
+
'shadow-sm border border-border',
|
|
12
|
+
].join(' '),
|
|
13
|
+
variants: {
|
|
14
|
+
size: {
|
|
15
|
+
sm: 'gap-1.5 px-3 py-2',
|
|
16
|
+
md: 'gap-2 px-4 py-3',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
size: 'md',
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Individual call-control button.
|
|
26
|
+
*
|
|
27
|
+
* `tone` variants:
|
|
28
|
+
* - `default` → neutral muted appearance (standard inactive controls)
|
|
29
|
+
* - `active` → primary/highlighted (e.g. mic on, screen-share running)
|
|
30
|
+
* - `destructive` → red/danger (leave button or a muted mic indicator)
|
|
31
|
+
*
|
|
32
|
+
* `size` variants match the toolbar container.
|
|
33
|
+
*/
|
|
34
|
+
export const callControlButtonVariants = cva({
|
|
35
|
+
base: [
|
|
36
|
+
'inline-flex flex-col items-center justify-center rounded-full',
|
|
37
|
+
'font-medium transition-colors',
|
|
38
|
+
'focus-visible:outline-none focus-visible:ring-2',
|
|
39
|
+
'focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
|
|
40
|
+
'disabled:pointer-events-none disabled:opacity-50',
|
|
41
|
+
'cursor-pointer',
|
|
42
|
+
].join(' '),
|
|
43
|
+
variants: {
|
|
44
|
+
size: {
|
|
45
|
+
sm: 'size-9 text-xs',
|
|
46
|
+
md: 'size-11 text-xs',
|
|
47
|
+
},
|
|
48
|
+
tone: {
|
|
49
|
+
default: 'bg-muted text-foreground hover:bg-muted/80',
|
|
50
|
+
active: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
51
|
+
destructive:
|
|
52
|
+
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
defaultVariants: {
|
|
56
|
+
size: 'md',
|
|
57
|
+
tone: 'default',
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
/** Label beneath the icon inside a call-control button. */
|
|
62
|
+
export const callControlLabelClass =
|
|
63
|
+
'sr-only text-[10px] leading-none mt-0.5'
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AccessibilityProps } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
/** Visual/semantic tone of a call control button. */
|
|
4
|
+
export type CallControlTone = 'default' | 'active' | 'destructive'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Toggleable state for controls like mic or camera.
|
|
8
|
+
* `'on'` = currently active (mic/camera live).
|
|
9
|
+
* `'off'` = currently muted/disabled.
|
|
10
|
+
*/
|
|
11
|
+
export type CallControlState = 'on' | 'off'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A single control descriptor used by adapters to drive button rendering.
|
|
15
|
+
*/
|
|
16
|
+
export interface CallControlItem {
|
|
17
|
+
/** Unique identifier for this control. */
|
|
18
|
+
id: string
|
|
19
|
+
/** Visible label (also used as aria-label). */
|
|
20
|
+
label: string
|
|
21
|
+
/** Optional icon to render inside the button. */
|
|
22
|
+
icon?: string
|
|
23
|
+
/** Explicit tone override; when omitted `controlTone` is used with `state`. */
|
|
24
|
+
tone?: CallControlTone
|
|
25
|
+
/** Toggleable state (present only for toggleable controls). */
|
|
26
|
+
pressed?: boolean
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface CallControlsProps {
|
|
30
|
+
/** Controls to render. */
|
|
31
|
+
controls?: CallControlItem[]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface CallControlsAPI {
|
|
35
|
+
/** ARIA attributes to spread on the toolbar element (`role="toolbar"`). */
|
|
36
|
+
ariaProps: Partial<AccessibilityProps>
|
|
37
|
+
/** Data attributes for styling hooks. */
|
|
38
|
+
dataAttributes: Record<string, string>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Derive the visual tone for a control given its kind and current toggle state.
|
|
43
|
+
*
|
|
44
|
+
* Convention used by easyloops meeting toolbar:
|
|
45
|
+
* - `leave` / `end` → always `'destructive'`
|
|
46
|
+
* - any control that is `'off'` (muted/stopped) → `'destructive'` to signal
|
|
47
|
+
* the user that something is disabled (e.g. mic muted = red indicator).
|
|
48
|
+
* - a control that is `'on'` → `'active'` (lit up / highlighted).
|
|
49
|
+
* - otherwise → `'default'` (neutral).
|
|
50
|
+
*/
|
|
51
|
+
export function controlTone(
|
|
52
|
+
kind: string,
|
|
53
|
+
state: CallControlState | undefined,
|
|
54
|
+
): CallControlTone {
|
|
55
|
+
const normalised = kind.toLowerCase()
|
|
56
|
+
if (normalised === 'leave' || normalised === 'end') return 'destructive'
|
|
57
|
+
if (state === 'off') return 'destructive'
|
|
58
|
+
if (state === 'on') return 'active'
|
|
59
|
+
return 'default'
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Build the framework-agnostic toolbar props for a call-controls bar.
|
|
64
|
+
*
|
|
65
|
+
* Returns `role="toolbar"` plus `aria-label="Call controls"` and data
|
|
66
|
+
* attributes; adapters spread these onto their container element.
|
|
67
|
+
*/
|
|
68
|
+
export function createCallControls(_props: CallControlsProps = {}): CallControlsAPI {
|
|
69
|
+
const ariaProps: Partial<AccessibilityProps> = {
|
|
70
|
+
role: 'toolbar',
|
|
71
|
+
'aria-label': 'Call controls',
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const dataAttributes: Record<string, string> = {
|
|
75
|
+
'data-component': 'call-controls',
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { ariaProps, dataAttributes }
|
|
79
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
controlTone,
|
|
3
|
+
createCallControls,
|
|
4
|
+
type CallControlTone,
|
|
5
|
+
type CallControlState,
|
|
6
|
+
type CallControlItem,
|
|
7
|
+
type CallControlsProps,
|
|
8
|
+
type CallControlsAPI,
|
|
9
|
+
} from './call-controls.js'
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
callControlsVariants,
|
|
13
|
+
callControlButtonVariants,
|
|
14
|
+
callControlLabelClass,
|
|
15
|
+
} from './call-controls.styles.js'
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { cva } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
/** Outer container that wraps the list and optional progress summary. */
|
|
4
|
+
export const checklistContainerClass = 'flex flex-col gap-2'
|
|
5
|
+
|
|
6
|
+
/** The `role="list"` element holding all item rows. */
|
|
7
|
+
export const checklistListClass = 'flex flex-col gap-1'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A single item row — a button with checkbox semantics.
|
|
11
|
+
*
|
|
12
|
+
* The `checked` variant applies muted text and a line-through on the label
|
|
13
|
+
* to communicate completion without relying solely on the checkbox visual.
|
|
14
|
+
*/
|
|
15
|
+
export const checklistItemVariants = cva({
|
|
16
|
+
base: [
|
|
17
|
+
'flex items-start gap-3 rounded-md px-2 py-2 text-left',
|
|
18
|
+
'transition-colors hover:bg-accent',
|
|
19
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
|
|
20
|
+
'disabled:pointer-events-none disabled:opacity-50',
|
|
21
|
+
].join(' '),
|
|
22
|
+
variants: {
|
|
23
|
+
checked: {
|
|
24
|
+
true: 'text-muted-foreground',
|
|
25
|
+
false: 'text-foreground',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
defaultVariants: {
|
|
29
|
+
checked: 'false',
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The visual checkbox box (the square indicator beside the label).
|
|
35
|
+
*
|
|
36
|
+
* The `checked` variant fills the box with the primary colour and shows a
|
|
37
|
+
* checkmark via a border trick; the unchecked state shows an empty border.
|
|
38
|
+
*/
|
|
39
|
+
export const checklistBoxVariants = cva({
|
|
40
|
+
base: [
|
|
41
|
+
'mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded',
|
|
42
|
+
'border transition-colors',
|
|
43
|
+
].join(' '),
|
|
44
|
+
variants: {
|
|
45
|
+
checked: {
|
|
46
|
+
true: 'border-primary bg-primary text-primary-foreground',
|
|
47
|
+
false: 'border-input bg-background',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
defaultVariants: {
|
|
51
|
+
checked: 'false',
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
/** Wrapper for label + optional description text. */
|
|
56
|
+
export const checklistLabelWrapClass = 'flex flex-col gap-0.5 min-w-0'
|
|
57
|
+
|
|
58
|
+
/** The item's primary label. Strikethrough is applied when the item is checked. */
|
|
59
|
+
export const checklistLabelVariants = cva({
|
|
60
|
+
base: 'text-sm font-medium leading-none transition-colors',
|
|
61
|
+
variants: {
|
|
62
|
+
checked: {
|
|
63
|
+
true: 'line-through text-muted-foreground',
|
|
64
|
+
false: 'text-foreground',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
defaultVariants: {
|
|
68
|
+
checked: 'false',
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
/** Optional description — always in muted text, smaller than the label. */
|
|
73
|
+
export const checklistDescriptionClass = 'text-xs text-muted-foreground'
|
|
74
|
+
|
|
75
|
+
/** Progress summary line shown below the list when `showProgress` is true. */
|
|
76
|
+
export const checklistProgressClass = 'text-xs text-muted-foreground tabular-nums'
|