@refraction-ui/astro 0.11.1 → 0.13.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 (148) hide show
  1. package/dist/astro-audio-room/AudioRoom.astro +81 -0
  2. package/dist/astro-audio-room/index.ts +1 -0
  3. package/dist/astro-call-controls/CallControls.astro +57 -0
  4. package/dist/astro-call-controls/index.ts +1 -0
  5. package/dist/astro-checklist/Checklist.astro +76 -0
  6. package/dist/astro-checklist/index.ts +1 -0
  7. package/dist/astro-editor-status-bar/EditorStatusBar.astro +92 -0
  8. package/dist/astro-editor-status-bar/index.ts +1 -0
  9. package/dist/astro-editor-tabs/EditorTabs.astro +74 -0
  10. package/dist/astro-editor-tabs/index.ts +1 -0
  11. package/dist/astro-empty-state/EmptyState.astro +57 -0
  12. package/dist/astro-empty-state/index.ts +1 -0
  13. package/dist/astro-floating-reactions/FloatingReactions.astro +56 -0
  14. package/dist/astro-floating-reactions/index.ts +1 -0
  15. package/dist/astro-flow-editor/FlowEditor.astro +99 -0
  16. package/dist/astro-flow-editor/index.ts +3 -0
  17. package/dist/astro-graph-view/GraphView.astro +109 -0
  18. package/dist/astro-graph-view/index.ts +1 -0
  19. package/dist/astro-infinite-canvas/InfiniteCanvas.astro +43 -0
  20. package/dist/astro-infinite-canvas/index.ts +1 -0
  21. package/dist/astro-input/Input.astro +5 -1
  22. package/dist/astro-live-captions/LiveCaptions.astro +54 -0
  23. package/dist/astro-live-captions/index.ts +1 -0
  24. package/dist/astro-live-cursors/LiveCursors.astro +55 -0
  25. package/dist/astro-live-cursors/index.ts +1 -0
  26. package/dist/astro-live-transcript/LiveTranscript.astro +55 -0
  27. package/dist/astro-live-transcript/index.ts +1 -0
  28. package/dist/astro-mini-map/MiniMap.astro +74 -0
  29. package/dist/astro-mini-map/index.ts +1 -0
  30. package/dist/astro-password-input/PasswordInput.astro +102 -0
  31. package/dist/astro-password-input/index.ts +1 -0
  32. package/dist/astro-pre-call-lobby/PreCallLobby.astro +202 -0
  33. package/dist/astro-pre-call-lobby/index.ts +1 -0
  34. package/dist/astro-radial-gauge/RadialGauge.astro +144 -0
  35. package/dist/astro-radial-gauge/index.ts +1 -0
  36. package/dist/astro-rating-scale/RatingScale.astro +73 -0
  37. package/dist/astro-rating-scale/index.ts +1 -0
  38. package/dist/astro-segmented-control/SegmentedControl.astro +106 -0
  39. package/dist/astro-segmented-control/SegmentedControlItem.astro +32 -0
  40. package/dist/astro-segmented-control/index.ts +1 -0
  41. package/dist/astro-separator/Separator.astro +49 -0
  42. package/dist/astro-separator/index.ts +1 -0
  43. package/dist/astro-social-auth-button/SocialAuthButton.astro +110 -0
  44. package/dist/astro-social-auth-button/SocialAuthRow.astro +13 -0
  45. package/dist/astro-social-auth-button/index.ts +1 -0
  46. package/dist/astro-sticky-note/StickyNote.astro +55 -0
  47. package/dist/astro-sticky-note/index.ts +1 -0
  48. package/dist/astro-terminal/Terminal.astro +67 -0
  49. package/dist/astro-terminal/index.ts +1 -0
  50. package/dist/astro-test-results/TestResults.astro +76 -0
  51. package/dist/astro-test-results/index.ts +1 -0
  52. package/dist/astro-timeline/Timeline.astro +59 -0
  53. package/dist/astro-timeline/index.ts +1 -0
  54. package/dist/astro-video-grid/VideoGrid.astro +182 -0
  55. package/dist/astro-video-grid/index.ts +1 -0
  56. package/dist/astro-video-tile/VideoTile.astro +104 -0
  57. package/dist/astro-video-tile/index.ts +1 -0
  58. package/dist/astro-wizard/Wizard.astro +137 -0
  59. package/dist/astro-wizard/index.ts +1 -0
  60. package/dist/audio-room/audio-room.styles.ts +88 -0
  61. package/dist/audio-room/audio-room.ts +70 -0
  62. package/dist/audio-room/index.ts +16 -0
  63. package/dist/call-controls/call-controls.styles.ts +63 -0
  64. package/dist/call-controls/call-controls.ts +79 -0
  65. package/dist/call-controls/index.ts +15 -0
  66. package/dist/checklist/checklist.styles.ts +76 -0
  67. package/dist/checklist/checklist.ts +62 -0
  68. package/dist/checklist/index.ts +18 -0
  69. package/dist/editor-status-bar/editor-status-bar.styles.ts +40 -0
  70. package/dist/editor-status-bar/editor-status-bar.ts +78 -0
  71. package/dist/editor-status-bar/index.ts +15 -0
  72. package/dist/editor-tabs/editor-tabs.styles.ts +52 -0
  73. package/dist/editor-tabs/editor-tabs.ts +82 -0
  74. package/dist/editor-tabs/index.ts +15 -0
  75. package/dist/empty-state/empty-state.styles.ts +42 -0
  76. package/dist/empty-state/empty-state.ts +27 -0
  77. package/dist/empty-state/index.ts +14 -0
  78. package/dist/floating-reactions/floating-reactions.styles.ts +54 -0
  79. package/dist/floating-reactions/floating-reactions.ts +85 -0
  80. package/dist/floating-reactions/index.ts +14 -0
  81. package/dist/flow-editor/flow-editor.styles.ts +56 -0
  82. package/dist/flow-editor/flow-editor.ts +126 -0
  83. package/dist/flow-editor/index.ts +18 -0
  84. package/dist/graph-view/graph-view.styles.ts +66 -0
  85. package/dist/graph-view/graph-view.ts +130 -0
  86. package/dist/graph-view/index.ts +21 -0
  87. package/dist/index.ts +45 -17
  88. package/dist/infinite-canvas/index.ts +17 -0
  89. package/dist/infinite-canvas/infinite-canvas.styles.ts +49 -0
  90. package/dist/infinite-canvas/infinite-canvas.ts +97 -0
  91. package/dist/input/index.ts +2 -0
  92. package/dist/input/input.styles.ts +4 -0
  93. package/dist/input/input.ts +39 -3
  94. package/dist/live-captions/index.ts +13 -0
  95. package/dist/live-captions/live-captions.styles.ts +45 -0
  96. package/dist/live-captions/live-captions.ts +57 -0
  97. package/dist/live-cursors/index.ts +14 -0
  98. package/dist/live-cursors/live-cursors.styles.ts +41 -0
  99. package/dist/live-cursors/live-cursors.ts +73 -0
  100. package/dist/live-transcript/index.ts +16 -0
  101. package/dist/live-transcript/live-transcript.styles.ts +48 -0
  102. package/dist/live-transcript/live-transcript.ts +82 -0
  103. package/dist/mini-map/index.ts +16 -0
  104. package/dist/mini-map/mini-map.styles.ts +32 -0
  105. package/dist/mini-map/mini-map.ts +122 -0
  106. package/dist/password-input/index.ts +9 -0
  107. package/dist/password-input/password-input.styles.ts +10 -0
  108. package/dist/password-input/password-input.ts +45 -0
  109. package/dist/pre-call-lobby/index.ts +22 -0
  110. package/dist/pre-call-lobby/pre-call-lobby.styles.ts +108 -0
  111. package/dist/pre-call-lobby/pre-call-lobby.ts +61 -0
  112. package/dist/radial-gauge/index.ts +26 -0
  113. package/dist/radial-gauge/radial-gauge.styles.ts +75 -0
  114. package/dist/radial-gauge/radial-gauge.ts +183 -0
  115. package/dist/rating-scale/index.ts +16 -0
  116. package/dist/rating-scale/rating-scale.styles.ts +48 -0
  117. package/dist/rating-scale/rating-scale.ts +101 -0
  118. package/dist/segmented-control/index.ts +13 -0
  119. package/dist/segmented-control/segmented-control.styles.ts +42 -0
  120. package/dist/segmented-control/segmented-control.ts +80 -0
  121. package/dist/separator/index.ts +12 -0
  122. package/dist/separator/separator.styles.ts +34 -0
  123. package/dist/separator/separator.ts +53 -0
  124. package/dist/social-auth-button/index.ts +14 -0
  125. package/dist/social-auth-button/social-auth-button.styles.ts +16 -0
  126. package/dist/social-auth-button/social-auth-button.ts +51 -0
  127. package/dist/sticky-note/index.ts +14 -0
  128. package/dist/sticky-note/sticky-note.styles.ts +37 -0
  129. package/dist/sticky-note/sticky-note.ts +47 -0
  130. package/dist/terminal/index.ts +13 -0
  131. package/dist/terminal/terminal.styles.ts +56 -0
  132. package/dist/terminal/terminal.ts +60 -0
  133. package/dist/test-results/index.ts +19 -0
  134. package/dist/test-results/test-results.styles.ts +93 -0
  135. package/dist/test-results/test-results.ts +83 -0
  136. package/dist/timeline/index.ts +22 -0
  137. package/dist/timeline/timeline.styles.ts +98 -0
  138. package/dist/timeline/timeline.ts +86 -0
  139. package/dist/video-grid/index.ts +16 -0
  140. package/dist/video-grid/video-grid.styles.ts +38 -0
  141. package/dist/video-grid/video-grid.ts +93 -0
  142. package/dist/video-tile/index.ts +17 -0
  143. package/dist/video-tile/video-tile.styles.ts +59 -0
  144. package/dist/video-tile/video-tile.ts +74 -0
  145. package/dist/wizard/index.ts +28 -0
  146. package/dist/wizard/wizard.styles.ts +147 -0
  147. package/dist/wizard/wizard.ts +128 -0
  148. package/package.json +47 -19
@@ -0,0 +1,109 @@
1
+ ---
2
+ import {
3
+ createGraphView,
4
+ graphEdgePath,
5
+ summarizeStates,
6
+ graphViewVariants,
7
+ graphNodeVariants,
8
+ graphNodeLabelClass,
9
+ graphEdgeClass,
10
+ graphLegendChipVariants,
11
+ type GraphNode,
12
+ type GraphEdge,
13
+ type GraphNodeState,
14
+ } from '../graph-view/index.ts'
15
+ import { cn } from '../shared/index.ts'
16
+
17
+ interface Props extends astroHTML.JSX.HTMLAttributes {
18
+ /** Nodes to render. */
19
+ nodes: GraphNode[]
20
+ /** Directed edges connecting nodes. */
21
+ edges: GraphEdge[]
22
+ /** Show a legend summarising mastery-state counts. */
23
+ showLegend?: boolean
24
+ }
25
+
26
+ const { nodes, edges, showLegend = false, class: className, ...rest } = Astro.props
27
+
28
+ const api = createGraphView()
29
+ const summary = summarizeStates(nodes)
30
+
31
+ const STATE_LABELS: Record<GraphNodeState, string> = {
32
+ mastered: 'Mastered',
33
+ 'in-progress': 'In Progress',
34
+ 'not-started': 'Not Started',
35
+ highlight: 'Highlight',
36
+ }
37
+
38
+ const LEGEND_ORDER: GraphNodeState[] = ['mastered', 'in-progress', 'not-started', 'highlight']
39
+
40
+ const padding = 80
41
+ const xs = nodes.map((n) => n.x)
42
+ const ys = nodes.map((n) => n.y)
43
+ const svgWidth = nodes.length === 0 ? 400 : Math.max(...xs) + padding * 2
44
+ const svgHeight = nodes.length === 0 ? 300 : Math.max(...ys) + padding * 2
45
+
46
+ // Build node lookup for edge resolution
47
+ const nodeMap = new Map<string, GraphNode>(nodes.map((n) => [n.id, n]))
48
+ ---
49
+
50
+ <div
51
+ class={cn(graphViewVariants(), className)}
52
+ {...api.ariaProps}
53
+ {...api.dataAttributes}
54
+ {...rest}
55
+ >
56
+ <div class="relative" style={`width:${svgWidth}px;height:${svgHeight}px;`}>
57
+ <!-- SVG edge layer -->
58
+ <svg
59
+ width={svgWidth}
60
+ height={svgHeight}
61
+ aria-hidden="true"
62
+ style="position:absolute;top:0;left:0;pointer-events:none;"
63
+ >
64
+ {
65
+ edges.map((edge) => {
66
+ const source = nodeMap.get(edge.source)
67
+ const target = nodeMap.get(edge.target)
68
+ if (!source || !target) return null
69
+ return <path d={graphEdgePath(source, target)} class={graphEdgeClass} />
70
+ })
71
+ }
72
+ </svg>
73
+
74
+ <!-- Node chips -->
75
+ {
76
+ nodes.map((node) => {
77
+ const state: GraphNodeState = node.state ?? 'not-started'
78
+ return (
79
+ <span
80
+ data-state={state}
81
+ aria-label={node.label}
82
+ class={graphNodeVariants({ state, interactive: 'false' })}
83
+ style={`left:${node.x}px;top:${node.y}px;`}
84
+ >
85
+ <span class={graphNodeLabelClass}>{node.label}</span>
86
+ </span>
87
+ )
88
+ })
89
+ }
90
+ </div>
91
+
92
+ <!-- Optional legend -->
93
+ {
94
+ showLegend && (
95
+ <div
96
+ role="list"
97
+ aria-label="Graph legend"
98
+ class="flex flex-wrap gap-1.5 p-3"
99
+ >
100
+ {LEGEND_ORDER.filter((s) => summary[s] > 0).map((s) => (
101
+ <span role="listitem" class={graphLegendChipVariants({ state: s })}>
102
+ {STATE_LABELS[s]}
103
+ <span class="opacity-70">{summary[s]}</span>
104
+ </span>
105
+ ))}
106
+ </div>
107
+ )
108
+ }
109
+ </div>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,43 @@
1
+ ---
2
+ import {
3
+ createInfiniteCanvas,
4
+ transformToCss,
5
+ infiniteCanvasVariants,
6
+ canvasContentClass,
7
+ } from '../infinite-canvas/index.ts'
8
+ import { cn } from '../shared/index.ts'
9
+
10
+ interface Props extends astroHTML.JSX.HTMLAttributes {
11
+ /** Zoom level (default 1). */
12
+ zoom?: number
13
+ /** Pan offset x (default 0). */
14
+ x?: number
15
+ /** Pan offset y (default 0). */
16
+ y?: number
17
+ /** Show a dot-grid background. */
18
+ showGrid?: boolean
19
+ }
20
+
21
+ const {
22
+ zoom = 1,
23
+ x = 0,
24
+ y = 0,
25
+ showGrid = false,
26
+ class: className,
27
+ ...rest
28
+ } = Astro.props
29
+
30
+ const { ariaProps, dataAttributes } = createInfiniteCanvas({ zoom })
31
+ const transform = transformToCss({ zoom, x, y })
32
+ ---
33
+
34
+ <div
35
+ class={cn(infiniteCanvasVariants({ grid: showGrid ? 'true' : 'false' }), className)}
36
+ {...ariaProps}
37
+ {...dataAttributes}
38
+ {...rest}
39
+ >
40
+ <div class={canvasContentClass} style={`transform:${transform};transform-origin:0 0`}>
41
+ <slot />
42
+ </div>
43
+ </div>
@@ -0,0 +1 @@
1
+ export {}
@@ -3,6 +3,7 @@ import {
3
3
  createInput,
4
4
  inputVariants,
5
5
  type InputType,
6
+ type InputValidationState,
6
7
  } from '../input/index.ts'
7
8
  import { cn } from '../shared/index.ts'
8
9
 
@@ -13,6 +14,7 @@ interface Props extends astroHTML.JSX.HTMLAttributes {
13
14
  readonly?: boolean
14
15
  required?: boolean
15
16
  'aria-invalid'?: boolean
17
+ validationState?: InputValidationState
16
18
  }
17
19
 
18
20
  const {
@@ -23,6 +25,7 @@ const {
23
25
  readonly,
24
26
  required,
25
27
  'aria-invalid': ariaInvalid,
28
+ validationState,
26
29
  ...props
27
30
  } = Astro.props
28
31
 
@@ -32,9 +35,10 @@ const api = createInput({
32
35
  readOnly: readonly,
33
36
  required,
34
37
  'aria-invalid': ariaInvalid === true ? true : undefined,
38
+ validationState,
35
39
  })
36
40
 
37
- const classes = cn(inputVariants({ size }), className)
41
+ const classes = cn(inputVariants({ size, validationState }), className)
38
42
  ---
39
43
 
40
44
  <input
@@ -0,0 +1,54 @@
1
+ ---
2
+ import {
3
+ visibleCues,
4
+ createLiveCaptions,
5
+ liveCaptionsVariants,
6
+ liveCaptionsCueVariants,
7
+ liveCaptionsSpeakerClass,
8
+ type CaptionCue,
9
+ } from '../live-captions/index.ts'
10
+ import { cn } from '../shared/index.ts'
11
+
12
+ interface Props extends astroHTML.JSX.HTMLAttributes {
13
+ /** The full ordered list of caption cues. */
14
+ cues: CaptionCue[]
15
+ /**
16
+ * Maximum number of cue lines to display at once.
17
+ * @default 2
18
+ */
19
+ maxLines?: number
20
+ /**
21
+ * How the container is positioned in the layout.
22
+ * @default 'static'
23
+ */
24
+ position?: 'static' | 'absolute'
25
+ }
26
+
27
+ const {
28
+ cues,
29
+ maxLines = 2,
30
+ position = 'static',
31
+ class: className,
32
+ ...rest
33
+ } = Astro.props
34
+
35
+ const shown = visibleCues(cues, maxLines)
36
+ const { ariaProps, dataAttributes } = createLiveCaptions()
37
+ ---
38
+
39
+ <div class={cn(liveCaptionsVariants({ position }), className)} {...ariaProps} {...dataAttributes} {...rest}>
40
+ {
41
+ shown.map((cue) => (
42
+ <p class={liveCaptionsCueVariants({ interim: cue.final === false ? 'true' : 'false' })}>
43
+ {cue.speaker ? (
44
+ <>
45
+ <span class={liveCaptionsSpeakerClass}>{cue.speaker}</span>
46
+ {`: ${cue.text}`}
47
+ </>
48
+ ) : (
49
+ cue.text
50
+ )}
51
+ </p>
52
+ ))
53
+ }
54
+ </div>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,55 @@
1
+ ---
2
+ import {
3
+ createLiveCursors,
4
+ assignCursorColor,
5
+ liveCursorsVariants,
6
+ cursorWrapperClass,
7
+ cursorArrowClass,
8
+ cursorLabelClass,
9
+ type CursorData,
10
+ } from '../live-cursors/index.ts'
11
+ import { cn } from '../shared/index.ts'
12
+
13
+ interface Props extends astroHTML.JSX.HTMLAttributes {
14
+ /** Array of collaborator cursor data to render. */
15
+ cursors: CursorData[]
16
+ }
17
+
18
+ const { cursors, class: className, ...rest } = Astro.props
19
+
20
+ const { ariaProps, dataAttributes } = createLiveCursors()
21
+ ---
22
+
23
+ <div class={cn(liveCursorsVariants(), className)} {...ariaProps} {...dataAttributes} {...rest}>
24
+ {
25
+ cursors.map((cursor, index) => {
26
+ const color = cursor.color ?? assignCursorColor(cursor.id, index)
27
+ return (
28
+ <div
29
+ class={cursorWrapperClass}
30
+ style={`left:${cursor.x}px;top:${cursor.y}px`}
31
+ data-cursor-name={cursor.name}
32
+ >
33
+ <svg
34
+ class={cursorArrowClass}
35
+ viewBox="0 0 20 20"
36
+ fill="none"
37
+ xmlns="http://www.w3.org/2000/svg"
38
+ aria-hidden="true"
39
+ style={`fill:${color}`}
40
+ >
41
+ <path
42
+ d="M3 2L17 9.5L10.5 11.5L8 18L3 2Z"
43
+ stroke="white"
44
+ stroke-width="1.5"
45
+ stroke-linejoin="round"
46
+ />
47
+ </svg>
48
+ <span class={cursorLabelClass} style={`background-color:${color}`}>
49
+ {cursor.name}
50
+ </span>
51
+ </div>
52
+ )
53
+ })
54
+ }
55
+ </div>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,55 @@
1
+ ---
2
+ import {
3
+ createLiveTranscript,
4
+ groupConsecutiveBySpeaker,
5
+ liveTranscriptVariants,
6
+ transcriptBlockVariants,
7
+ transcriptSpeakerRowClass,
8
+ transcriptSpeakerNameClass,
9
+ transcriptTimestampClass,
10
+ transcriptTextLineClass,
11
+ type TranscriptEntry,
12
+ } from '../live-transcript/index.ts'
13
+ import { cn } from '../shared/index.ts'
14
+
15
+ interface Props extends astroHTML.JSX.HTMLAttributes {
16
+ /** The ordered list of transcript entries to display. */
17
+ entries: TranscriptEntry[]
18
+ /** Tightens spacing between speaker blocks. */
19
+ compact?: boolean
20
+ }
21
+
22
+ const { entries, compact = false, class: className, ...rest } = Astro.props
23
+
24
+ const compactVariant = compact ? 'true' : 'false'
25
+ const blocks = groupConsecutiveBySpeaker(entries)
26
+ const { ariaProps, dataAttributes } = createLiveTranscript()
27
+ ---
28
+
29
+ <div
30
+ class={cn(liveTranscriptVariants({ compact: compactVariant }), className)}
31
+ {...ariaProps}
32
+ {...dataAttributes}
33
+ {...rest}
34
+ >
35
+ {
36
+ blocks.map((block, blockIndex) => (
37
+ <div class={transcriptBlockVariants({ compact: compactVariant })}>
38
+ <div class={transcriptSpeakerRowClass}>
39
+ <span
40
+ class={transcriptSpeakerNameClass}
41
+ style={block.speakerColor ? `color:${block.speakerColor}` : undefined}
42
+ >
43
+ {block.speaker}
44
+ </span>
45
+ {block.timestamp && (
46
+ <span class={transcriptTimestampClass}>{block.timestamp}</span>
47
+ )}
48
+ </div>
49
+ {block.texts.map((text) => (
50
+ <p class={transcriptTextLineClass}>{text}</p>
51
+ ))}
52
+ </div>
53
+ ))
54
+ }
55
+ </div>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,74 @@
1
+ ---
2
+ import {
3
+ contentBounds,
4
+ miniScale,
5
+ worldToMini,
6
+ viewportRectInMini,
7
+ createMiniMap,
8
+ miniMapVariants,
9
+ miniMapDotClass,
10
+ miniMapViewportClass,
11
+ type MiniMapItem,
12
+ type Rect,
13
+ } from '../mini-map/index.ts'
14
+ import { cn } from '../shared/index.ts'
15
+
16
+ interface Props extends astroHTML.JSX.HTMLAttributes {
17
+ /** Items to render as dots on the minimap. */
18
+ items: MiniMapItem[]
19
+ /** Current viewport in world coordinates. Renders a viewport indicator rect. */
20
+ viewport?: Rect
21
+ /** Width of the minimap box in px. */
22
+ width?: number
23
+ /** Height of the minimap box in px. */
24
+ height?: number
25
+ /** Padding inset in px (applied to all sides). */
26
+ padding?: number
27
+ }
28
+
29
+ const {
30
+ items,
31
+ viewport,
32
+ width = 200,
33
+ height = 140,
34
+ padding = 8,
35
+ class: className,
36
+ ...rest
37
+ } = Astro.props
38
+
39
+ const bounds = contentBounds(items)
40
+ const scale = miniScale(bounds, width, height, padding)
41
+ const { ariaProps, dataAttributes } = createMiniMap()
42
+
43
+ const viewportRect = viewport != null
44
+ ? viewportRectInMini(viewport, bounds, scale, padding)
45
+ : null
46
+ ---
47
+
48
+ <div
49
+ class={cn(miniMapVariants({ interactive: 'false' }), className)}
50
+ style={`width:${width}px;height:${height}px;position:relative`}
51
+ {...ariaProps}
52
+ {...dataAttributes}
53
+ {...rest}
54
+ >
55
+ {items.map((item) => {
56
+ const pos = worldToMini(item, bounds, scale, padding)
57
+ const w = Math.max(4, (item.width ?? 8) * scale)
58
+ const h = Math.max(4, (item.height ?? 8) * scale)
59
+ return (
60
+ <span
61
+ class={miniMapDotClass}
62
+ style={`position:absolute;left:${pos.x}px;top:${pos.y}px;width:${w}px;height:${h}px`}
63
+ aria-hidden="true"
64
+ />
65
+ )
66
+ })}
67
+ {viewportRect != null && (
68
+ <span
69
+ class={miniMapViewportClass}
70
+ style={`position:absolute;left:${viewportRect.x}px;top:${viewportRect.y}px;width:${viewportRect.width}px;height:${viewportRect.height}px`}
71
+ aria-hidden="true"
72
+ />
73
+ )}
74
+ </div>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,102 @@
1
+ ---
2
+ import { inputVariants, type InputValidationState } from '../input/index.ts'
3
+ import {
4
+ createPasswordInput,
5
+ passwordToggleVariants,
6
+ } from '../password-input/index.ts'
7
+ import { cn } from '../shared/index.ts'
8
+
9
+ interface Props extends astroHTML.JSX.HTMLAttributes {
10
+ size?: 'sm' | 'default' | 'lg'
11
+ disabled?: boolean
12
+ readonly?: boolean
13
+ required?: boolean
14
+ validationState?: InputValidationState
15
+ revealLabel?: string
16
+ hideLabel?: string
17
+ }
18
+
19
+ const {
20
+ size,
21
+ class: className,
22
+ disabled,
23
+ readonly,
24
+ required,
25
+ validationState,
26
+ revealLabel = 'Show password',
27
+ hideLabel = 'Hide password',
28
+ ...props
29
+ } = Astro.props
30
+
31
+ // Render masked initially; progressive enhancement toggles it client-side.
32
+ const { inputType, toggleLabel, togglePressed } = createPasswordInput({
33
+ revealed: false,
34
+ revealLabel,
35
+ hideLabel,
36
+ })
37
+
38
+ const inputClasses = cn(inputVariants({ size, validationState }), 'pr-10', className)
39
+ const ariaInvalid =
40
+ validationState === 'invalid' ? true : validationState === 'valid' ? false : undefined
41
+ ---
42
+
43
+ <div class="relative" data-rfr-password-input>
44
+ <input
45
+ type={inputType}
46
+ class={inputClasses}
47
+ disabled={disabled}
48
+ readonly={readonly}
49
+ required={required}
50
+ aria-invalid={ariaInvalid}
51
+ data-rfr-password-field
52
+ {...props}
53
+ />
54
+ <button
55
+ type="button"
56
+ aria-label={toggleLabel}
57
+ aria-pressed={togglePressed}
58
+ class={passwordToggleVariants()}
59
+ data-rfr-password-toggle
60
+ data-reveal-label={revealLabel}
61
+ data-hide-label={hideLabel}
62
+ >
63
+ <svg
64
+ aria-hidden="true"
65
+ viewBox="0 0 24 24"
66
+ fill="none"
67
+ stroke="currentColor"
68
+ stroke-width="2"
69
+ stroke-linecap="round"
70
+ stroke-linejoin="round"
71
+ class="size-4"
72
+ >
73
+ <path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"></path>
74
+ <circle cx="12" cy="12" r="3"></circle>
75
+ </svg>
76
+ </button>
77
+ </div>
78
+
79
+ <script>
80
+ document
81
+ .querySelectorAll<HTMLElement>('[data-rfr-password-input]')
82
+ .forEach((root) => {
83
+ const field = root.querySelector<HTMLInputElement>(
84
+ '[data-rfr-password-field]',
85
+ )
86
+ const toggle = root.querySelector<HTMLButtonElement>(
87
+ '[data-rfr-password-toggle]',
88
+ )
89
+ if (!field || !toggle) return
90
+
91
+ const revealLabel = toggle.dataset.revealLabel ?? 'Show password'
92
+ const hideLabel = toggle.dataset.hideLabel ?? 'Hide password'
93
+
94
+ toggle.addEventListener('click', () => {
95
+ const revealed = field.type === 'text'
96
+ const next = !revealed
97
+ field.type = next ? 'text' : 'password'
98
+ toggle.setAttribute('aria-pressed', String(next))
99
+ toggle.setAttribute('aria-label', next ? hideLabel : revealLabel)
100
+ })
101
+ })
102
+ </script>
@@ -0,0 +1 @@
1
+ export {}