@astronox/core 0.1.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 (259) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -0
  3. package/package.json +77 -0
  4. package/src/client/clipboard.ts +7 -0
  5. package/src/client/focus.ts +17 -0
  6. package/src/client/index.ts +3 -0
  7. package/src/client/scroll.ts +15 -0
  8. package/src/components/actions/ActionListItem/ActionListItem.astro +78 -0
  9. package/src/components/actions/ActionListItem/ActionListItem.css +43 -0
  10. package/src/components/actions/Button/Button.astro +100 -0
  11. package/src/components/actions/Button/Button.css +165 -0
  12. package/src/components/actions/CardAction/CardAction.astro +97 -0
  13. package/src/components/actions/CardAction/CardAction.css +188 -0
  14. package/src/components/actions/MediaTrigger/MediaTrigger.astro +55 -0
  15. package/src/components/actions/MediaTrigger/MediaTrigger.css +175 -0
  16. package/src/components/actions/ScrollToTop/ScrollToTop.astro +36 -0
  17. package/src/components/actions/ScrollToTop/ScrollToTop.css +19 -0
  18. package/src/components/actions/ScrollToTop/scrollToTopController.ts +32 -0
  19. package/src/components/content/CardBody/CardBody.astro +31 -0
  20. package/src/components/content/CardBody/CardBody.css +74 -0
  21. package/src/components/content/CardFooter/CardFooter.astro +58 -0
  22. package/src/components/content/CardFooter/CardFooter.css +102 -0
  23. package/src/components/content/CardHeader/CardHeader.astro +96 -0
  24. package/src/components/content/CardHeader/CardHeader.css +164 -0
  25. package/src/components/content/CardLink/CardLink.astro +138 -0
  26. package/src/components/content/CardLink/CardLink.css +362 -0
  27. package/src/components/content/CodeBlock/CodeBlock.astro +102 -0
  28. package/src/components/content/CodeBlock/CodeBlock.css +85 -0
  29. package/src/components/content/CodeBlock/codeBlockController.ts +60 -0
  30. package/src/components/content/CodeBlock/contracts.ts +8 -0
  31. package/src/components/content/InlineDefinition/InlineDefinition.astro +31 -0
  32. package/src/components/content/InlineDefinition/InlineDefinition.css +9 -0
  33. package/src/components/content/MarkdownContent/MarkdownContent.astro +32 -0
  34. package/src/components/content/MarkdownContent/MarkdownContent.css +358 -0
  35. package/src/components/content/MarkdownContent/MarkdownInline.astro +44 -0
  36. package/src/components/content/MarkdownContent/MarkdownNode.astro +280 -0
  37. package/src/components/content/MarkdownContent/MarkdownSymbol.astro +47 -0
  38. package/src/components/content/MarkdownContent/contracts.ts +181 -0
  39. package/src/components/data-display/BadgeList/BadgeList.astro +54 -0
  40. package/src/components/data-display/BadgeList/BadgeList.css +29 -0
  41. package/src/components/data-display/IconList/IconList.astro +64 -0
  42. package/src/components/data-display/IconList/IconList.css +55 -0
  43. package/src/components/data-display/MetricTile/MetricTile.astro +68 -0
  44. package/src/components/data-display/MetricTile/MetricTile.css +103 -0
  45. package/src/components/data-display/MetricTile/MetricTileContent.astro +70 -0
  46. package/src/components/data-display/MetricTile/metricTileController.ts +9 -0
  47. package/src/components/data-display/Tag/Tag.astro +67 -0
  48. package/src/components/data-display/Tag/Tag.css +134 -0
  49. package/src/components/data-display/Tag/TagAffix.astro +33 -0
  50. package/src/components/data-display/TextPair/TextPair.astro +63 -0
  51. package/src/components/data-display/TextPair/TextPair.css +99 -0
  52. package/src/components/feedback/Spinner/Spinner.astro +32 -0
  53. package/src/components/feedback/Spinner/Spinner.css +37 -0
  54. package/src/components/feedback/Tooltip/Tooltip.astro +66 -0
  55. package/src/components/feedback/Tooltip/Tooltip.css +67 -0
  56. package/src/components/feedback/Tooltip/tooltipController.ts +371 -0
  57. package/src/components/forms/FieldError/FieldError.astro +31 -0
  58. package/src/components/forms/FieldError/FieldError.css +12 -0
  59. package/src/components/forms/FieldError/fieldErrorState.ts +21 -0
  60. package/src/components/forms/FieldLabel/FieldLabel.astro +32 -0
  61. package/src/components/forms/FieldLabel/FieldLabel.css +17 -0
  62. package/src/components/forms/TextInput/TextInput.astro +79 -0
  63. package/src/components/forms/TextInput/TextInput.css +121 -0
  64. package/src/components/forms/TextInput/textInputController.ts +53 -0
  65. package/src/components/icons/ArrowDownIcon.astro +26 -0
  66. package/src/components/icons/ArrowLeftIcon.astro +26 -0
  67. package/src/components/icons/ArrowRightIcon.astro +26 -0
  68. package/src/components/icons/ArrowUpDownIcon.astro +26 -0
  69. package/src/components/icons/ArrowUpIcon.astro +26 -0
  70. package/src/components/icons/BulletIcon.astro +21 -0
  71. package/src/components/icons/BurnIcon.astro +24 -0
  72. package/src/components/icons/CircleSymbolIcon.css +66 -0
  73. package/src/components/icons/ClearIcon.astro +28 -0
  74. package/src/components/icons/CloseIcon.astro +21 -0
  75. package/src/components/icons/CopyIcon.astro +30 -0
  76. package/src/components/icons/CurrencyIcon.css +9 -0
  77. package/src/components/icons/DayIcon.astro +33 -0
  78. package/src/components/icons/DollarIcon.astro +28 -0
  79. package/src/components/icons/DownloadIcon.astro +22 -0
  80. package/src/components/icons/EnterFullscreenIcon.astro +22 -0
  81. package/src/components/icons/EqualIcon.astro +25 -0
  82. package/src/components/icons/ExitFullscreenIcon.astro +22 -0
  83. package/src/components/icons/ExternalLinkIcon.astro +22 -0
  84. package/src/components/icons/FieldIcon.astro +28 -0
  85. package/src/components/icons/GrassIcon.astro +29 -0
  86. package/src/components/icons/InfoIcon.astro +24 -0
  87. package/src/components/icons/MinusIcon.astro +21 -0
  88. package/src/components/icons/MountainIcon.astro +31 -0
  89. package/src/components/icons/NightIcon.astro +32 -0
  90. package/src/components/icons/PlayIcon.astro +22 -0
  91. package/src/components/icons/PlusIcon.astro +21 -0
  92. package/src/components/icons/PoisonIcon.astro +24 -0
  93. package/src/components/icons/RibbonIcon.astro +25 -0
  94. package/src/components/icons/SlashIcon.astro +22 -0
  95. package/src/components/icons/SlowIcon.astro +25 -0
  96. package/src/components/icons/StarIcon.astro +28 -0
  97. package/src/components/icons/StunIcon.astro +22 -0
  98. package/src/components/icons/TableSortIcon.astro +34 -0
  99. package/src/components/icons/WaterIcon.astro +30 -0
  100. package/src/components/index.ts +83 -0
  101. package/src/components/media/CanvasFrame/CanvasFrame.astro +130 -0
  102. package/src/components/media/CanvasFrame/CanvasFrame.css +59 -0
  103. package/src/components/media/CanvasFrame/canvasFrameController.ts +104 -0
  104. package/src/components/media/EmbedFrame/EmbedFrame.astro +147 -0
  105. package/src/components/media/EmbedFrame/EmbedFrame.css +51 -0
  106. package/src/components/media/EmbedFrame/embedFrameController.ts +66 -0
  107. package/src/components/media/MediaFrame/MediaFrame.astro +34 -0
  108. package/src/components/media/MediaFrame/MediaFrame.css +66 -0
  109. package/src/components/navigation/Breadcrumbs/Breadcrumbs.astro +55 -0
  110. package/src/components/navigation/Breadcrumbs/Breadcrumbs.css +89 -0
  111. package/src/components/navigation/DesktopNavigation.astro +92 -0
  112. package/src/components/navigation/DesktopNavigation.css +99 -0
  113. package/src/components/navigation/Header.astro +73 -0
  114. package/src/components/navigation/Header.css +20 -0
  115. package/src/components/navigation/MobileNavigation.astro +124 -0
  116. package/src/components/navigation/MobileNavigation.css +177 -0
  117. package/src/components/navigation/NavigationBrand.astro +63 -0
  118. package/src/components/navigation/NavigationBrand.css +52 -0
  119. package/src/components/navigation/NavigationControl.css +166 -0
  120. package/src/components/navigation/NavigationItemContent.astro +24 -0
  121. package/src/components/navigation/NavigationLink.astro +121 -0
  122. package/src/components/navigation/NavigationLinks.astro +27 -0
  123. package/src/components/navigation/NavigationMenuList.astro +37 -0
  124. package/src/components/navigation/NavigationMenuList.css +6 -0
  125. package/src/components/navigation/SkipLink/SkipLink.astro +18 -0
  126. package/src/components/navigation/SkipLink/SkipLink.css +26 -0
  127. package/src/components/navigation/SubNavigation/SubNavigation.astro +124 -0
  128. package/src/components/navigation/SubNavigation/SubNavigation.css +211 -0
  129. package/src/components/navigation/mobileNavigationController.ts +122 -0
  130. package/src/components/navigation/navigationState.ts +35 -0
  131. package/src/components/navigation/navigationTypes.ts +18 -0
  132. package/src/components/seo/SeoHead.astro +194 -0
  133. package/src/components/widgetTypes.ts +3 -0
  134. package/src/composition/Grid/Grid.astro +82 -0
  135. package/src/composition/Grid/Grid.css +314 -0
  136. package/src/composition/GridItem/GridItem.astro +50 -0
  137. package/src/composition/GridItem/GridItem.css +95 -0
  138. package/src/composition/Inline/Inline.astro +48 -0
  139. package/src/composition/Inline/Inline.css +65 -0
  140. package/src/composition/Stack/Stack.astro +37 -0
  141. package/src/composition/Stack/Stack.css +31 -0
  142. package/src/composition/SurfaceGroup/SurfaceGroup.astro +44 -0
  143. package/src/composition/SurfaceGroup/SurfaceGroup.css +76 -0
  144. package/src/composition/SurfaceGroup/stickySurfaceGroupController.ts +89 -0
  145. package/src/composition/index.ts +6 -0
  146. package/src/config/index.ts +2 -0
  147. package/src/config/pageMeta.ts +55 -0
  148. package/src/config/siteConfig.ts +90 -0
  149. package/src/data/collectionValidation.ts +61 -0
  150. package/src/data/index.ts +1 -0
  151. package/src/display/contracts.ts +284 -0
  152. package/src/display/index.ts +1 -0
  153. package/src/index.ts +6 -0
  154. package/src/layouts/BaseLayout.astro +74 -0
  155. package/src/layouts/PageSurface.astro +15 -0
  156. package/src/layouts/PageSurface.css +24 -0
  157. package/src/layouts/index.ts +2 -0
  158. package/src/patterns/CircuitPuzzle/CircuitPuzzle.astro +93 -0
  159. package/src/patterns/CircuitPuzzle/CircuitPuzzle.css +118 -0
  160. package/src/patterns/CircuitPuzzle/circuitPuzzleController.ts +205 -0
  161. package/src/patterns/CircuitPuzzle/contracts.ts +42 -0
  162. package/src/patterns/Combobox/Combobox.astro +462 -0
  163. package/src/patterns/Combobox/Combobox.css +403 -0
  164. package/src/patterns/Combobox/comboboxController.ts +788 -0
  165. package/src/patterns/Combobox/contracts.ts +18 -0
  166. package/src/patterns/Dropdown/Dropdown.astro +127 -0
  167. package/src/patterns/Dropdown/Dropdown.css +100 -0
  168. package/src/patterns/Dropdown/dropdownController.ts +157 -0
  169. package/src/patterns/Fullscreen/FullscreenControl.astro +103 -0
  170. package/src/patterns/Fullscreen/FullscreenControl.css +49 -0
  171. package/src/patterns/Fullscreen/fullscreenController.ts +73 -0
  172. package/src/patterns/GlitchOverlay/GlitchOverlay.astro +50 -0
  173. package/src/patterns/GlitchOverlay/GlitchOverlay.css +234 -0
  174. package/src/patterns/GlitchOverlay/glitchOverlayController.ts +152 -0
  175. package/src/patterns/GuidedFlow/GuidedFlow.astro +60 -0
  176. package/src/patterns/GuidedFlow/GuidedFlow.css +82 -0
  177. package/src/patterns/GuidedFlow/contracts.ts +3 -0
  178. package/src/patterns/GuidedFlow/guidedFlowController.ts +49 -0
  179. package/src/patterns/MagneticFieldPuzzle/MagneticFieldPuzzle.astro +217 -0
  180. package/src/patterns/MagneticFieldPuzzle/MagneticFieldPuzzle.css +383 -0
  181. package/src/patterns/MagneticFieldPuzzle/contracts.ts +81 -0
  182. package/src/patterns/MagneticFieldPuzzle/magneticFieldPuzzleController.ts +802 -0
  183. package/src/patterns/MagneticFieldPuzzle/simulation.ts +244 -0
  184. package/src/patterns/MapViewport/MapViewport.astro +296 -0
  185. package/src/patterns/MapViewport/MapViewport.css +257 -0
  186. package/src/patterns/MapViewport/contracts.ts +79 -0
  187. package/src/patterns/MapViewport/geometry.ts +80 -0
  188. package/src/patterns/MapViewport/mapViewportController.ts +636 -0
  189. package/src/patterns/Modal/Modal.astro +64 -0
  190. package/src/patterns/Modal/Modal.css +87 -0
  191. package/src/patterns/Modal/ModalClose.astro +37 -0
  192. package/src/patterns/Modal/ModalOpen.astro +36 -0
  193. package/src/patterns/Modal/modalController.ts +118 -0
  194. package/src/patterns/PuzzleGrid/PuzzleGrid.astro +22 -0
  195. package/src/patterns/PuzzleGrid/PuzzleGrid.css +149 -0
  196. package/src/patterns/PuzzleGrid/contracts.ts +2 -0
  197. package/src/patterns/PuzzleGrid/selectionDismissal.ts +27 -0
  198. package/src/patterns/PuzzleGrid/state.ts +25 -0
  199. package/src/patterns/SpriteProjectilePreview/SpriteProjectilePreview.astro +65 -0
  200. package/src/patterns/SpriteProjectilePreview/SpriteProjectilePreview.css +35 -0
  201. package/src/patterns/SpriteProjectilePreview/contracts.ts +33 -0
  202. package/src/patterns/SpriteProjectilePreview/spriteProjectilePreviewController.ts +586 -0
  203. package/src/patterns/StageFlow/StageFlow.astro +57 -0
  204. package/src/patterns/StageFlow/StageFlow.css +54 -0
  205. package/src/patterns/StageFlow/StageFlowAlternative.astro +23 -0
  206. package/src/patterns/StageFlow/StageFlowArrow.astro +22 -0
  207. package/src/patterns/StageFlow/StageFlowConnector.astro +7 -0
  208. package/src/patterns/StageFlow/StageFlowConnector.css +4 -0
  209. package/src/patterns/StageFlow/StageFlowStage.astro +51 -0
  210. package/src/patterns/StageFlow/StageFlowStage.css +106 -0
  211. package/src/patterns/StageFlow/StageFlowStep.astro +24 -0
  212. package/src/patterns/StageFlow/StageFlowStep.css +19 -0
  213. package/src/patterns/StageFlow/StageFlowSymbol.css +28 -0
  214. package/src/patterns/Table/Table.astro +176 -0
  215. package/src/patterns/Table/Table.css +70 -0
  216. package/src/patterns/Table/TableBody.astro +185 -0
  217. package/src/patterns/Table/TableBody.css +262 -0
  218. package/src/patterns/Table/TableCell.astro +59 -0
  219. package/src/patterns/Table/TableCell.css +99 -0
  220. package/src/patterns/Table/TableCellValue.astro +86 -0
  221. package/src/patterns/Table/TableFooter.astro +32 -0
  222. package/src/patterns/Table/TableFooter.css +31 -0
  223. package/src/patterns/Table/TableHeader.astro +118 -0
  224. package/src/patterns/Table/TableHeader.css +209 -0
  225. package/src/patterns/Table/TablePagination.astro +70 -0
  226. package/src/patterns/Table/TablePagination.css +133 -0
  227. package/src/patterns/Table/TableSkeleton.astro +36 -0
  228. package/src/patterns/Table/TableSkeleton.css +81 -0
  229. package/src/patterns/Table/tableCellController.ts +11 -0
  230. package/src/patterns/Table/tableFilterController.ts +206 -0
  231. package/src/patterns/Table/tableHeaderOverflowController.ts +105 -0
  232. package/src/patterns/Table/tableLayout.ts +113 -0
  233. package/src/patterns/Table/tableProgressiveController.ts +319 -0
  234. package/src/patterns/Table/tableRowNavigationController.ts +91 -0
  235. package/src/patterns/Table/tableScrollController.ts +192 -0
  236. package/src/patterns/Table/tableSortController.ts +272 -0
  237. package/src/patterns/index.ts +46 -0
  238. package/src/primitives/index.ts +4 -0
  239. package/src/primitives/layout/Separator/Separator.astro +29 -0
  240. package/src/primitives/layout/Separator/Separator.css +20 -0
  241. package/src/primitives/media/AmbientAudio/AmbientAudio.astro +28 -0
  242. package/src/primitives/media/Media/Media.astro +122 -0
  243. package/src/primitives/media/Media/Media.css +161 -0
  244. package/src/primitives/text/TextBlock/TextBlock.astro +46 -0
  245. package/src/primitives/text/TextBlock/TextBlock.css +21 -0
  246. package/src/seo/StaticRedirect.astro +32 -0
  247. package/src/seo/index.ts +6 -0
  248. package/src/seo/pageSeo.ts +99 -0
  249. package/src/seo/robots.ts +16 -0
  250. package/src/seo/sitemap.ts +38 -0
  251. package/src/seo/structuredData.ts +133 -0
  252. package/src/seo/url.ts +64 -0
  253. package/src/styles/base.css +148 -0
  254. package/src/styles/interaction.css +108 -0
  255. package/src/styles/style.css +93 -0
  256. package/src/styles/tokens.css +256 -0
  257. package/src/theme/contracts.ts +7 -0
  258. package/src/theme/index.ts +1 -0
  259. package/tsconfig.json +20 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gaudesp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # AstroNox Core
2
+
3
+ AstroNox Core is the shared Astro foundation used by AstroNox sites. It owns
4
+ reusable components, composition primitives, interaction patterns, display
5
+ contracts, SEO helpers, and the complete default stylesheet.
6
+
7
+ Product data, product routes, branding, integrations, and business rules stay
8
+ in the consuming site.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install @astronox/core
14
+ ```
15
+
16
+ Astro is a peer dependency. Consumers must use a compatible Astro 7 release.
17
+
18
+ ## Usage
19
+
20
+ Import components through the curated package entry points:
21
+
22
+ ```astro
23
+ ---
24
+ import { CardBody, CardHeader } from '@astronox/core/components';
25
+ import { Stack, SurfaceGroup } from '@astronox/core/composition';
26
+ ---
27
+
28
+ <Stack gap="md">
29
+ <SurfaceGroup>
30
+ <CardHeader title="Example" />
31
+ <CardBody>Content</CardBody>
32
+ </SurfaceGroup>
33
+ </Stack>
34
+ ```
35
+
36
+ Load the shared visual system once from the consuming application's stylesheet:
37
+
38
+ ```css
39
+ @import '@astronox/core/styles.css';
40
+ @import './site-theme.css';
41
+ ```
42
+
43
+ Use the remaining entry points for layouts, patterns, primitives, display
44
+ contracts, configuration, theme, client behavior, data validation, and SEO.
45
+ Deep imports into the physical `src` tree are not part of the public API.
46
+
47
+ ## Local Development
48
+
49
+ `astronox-core` is the only source of truth. A consuming project may link this
50
+ package locally while developing a shared change, but committed dependencies
51
+ must always reference a released package version.
52
+
53
+ The expected workflow is:
54
+
55
+ 1. Implement and commit the generic change in this repository.
56
+ 2. Validate it from the relevant linked consumer.
57
+ 3. Publish a prerelease or stable package version.
58
+ 4. Update consumers through their dependency management workflow.
59
+
60
+ Do not edit installed package files or copy `src` folders between projects.
61
+
62
+ ## Releases
63
+
64
+ AstroNox Core follows semantic versioning. Public entry points are compatibility
65
+ boundaries; internal files may change without notice. The initial `0.x` series
66
+ is reserved for stabilizing the API with the first production consumers.
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@astronox/core",
3
+ "version": "0.1.0",
4
+ "description": "Reusable Astro components, patterns, styles, and infrastructure for AstroNox sites.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "astro",
8
+ "components",
9
+ "design-system",
10
+ "frontend",
11
+ "ui"
12
+ ],
13
+ "homepage": "https://github.com/gaudesp/astronox-core#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/gaudesp/astronox-core/issues"
16
+ },
17
+ "type": "module",
18
+ "sideEffects": [
19
+ "**/*.css"
20
+ ],
21
+ "engines": {
22
+ "node": ">=22.12.0"
23
+ },
24
+ "files": [
25
+ "src",
26
+ "tsconfig.json",
27
+ "LICENSE",
28
+ "README.md"
29
+ ],
30
+ "exports": {
31
+ ".": "./src/index.ts",
32
+ "./client": "./src/client/index.ts",
33
+ "./components": "./src/components/index.ts",
34
+ "./composition": "./src/composition/index.ts",
35
+ "./config": "./src/config/index.ts",
36
+ "./data": "./src/data/index.ts",
37
+ "./display": "./src/display/index.ts",
38
+ "./layouts": "./src/layouts/index.ts",
39
+ "./patterns": "./src/patterns/index.ts",
40
+ "./primitives": "./src/primitives/index.ts",
41
+ "./seo": "./src/seo/index.ts",
42
+ "./theme": "./src/theme/index.ts",
43
+ "./styles.css": "./src/styles/style.css",
44
+ "./package.json": "./package.json"
45
+ },
46
+ "scripts": {
47
+ "check": "astro check",
48
+ "format": "prettier --write .",
49
+ "format:check": "prettier --check .",
50
+ "lint": "eslint ."
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/gaudesp/astronox-core.git"
58
+ },
59
+ "peerDependencies": {
60
+ "astro": "^7.0.0"
61
+ },
62
+ "dependencies": {
63
+ "zod": "4.4.3"
64
+ },
65
+ "devDependencies": {
66
+ "@astrojs/check": "0.9.9",
67
+ "@eslint/js": "9.39.5",
68
+ "astro": "7.0.9",
69
+ "astro-eslint-parser": "1.4.0",
70
+ "eslint": "9.39.5",
71
+ "eslint-plugin-astro": "1.7.0",
72
+ "prettier": "3.9.5",
73
+ "prettier-plugin-astro": "0.14.1",
74
+ "typescript": "6.0.3",
75
+ "typescript-eslint": "8.64.0"
76
+ }
77
+ }
@@ -0,0 +1,7 @@
1
+ export async function copyText(value: string): Promise<void> {
2
+ if (!navigator.clipboard?.writeText) {
3
+ throw new Error('Clipboard API unavailable');
4
+ }
5
+
6
+ await navigator.clipboard.writeText(value);
7
+ }
@@ -0,0 +1,17 @@
1
+ const focusableSelector = [
2
+ 'a[href]',
3
+ 'button:not([disabled])',
4
+ 'input:not([disabled])',
5
+ 'select:not([disabled])',
6
+ 'textarea:not([disabled])',
7
+ '[tabindex]:not([tabindex="-1"])',
8
+ ].join(',');
9
+
10
+ export const getFocusableElements = (root: ParentNode): HTMLElement[] =>
11
+ Array.from(root.querySelectorAll<HTMLElement>(focusableSelector)).filter(
12
+ (element) =>
13
+ !element.hasAttribute('disabled') &&
14
+ element.getAttribute('aria-disabled') !== 'true' &&
15
+ element.tabIndex >= 0 &&
16
+ element.getClientRects().length > 0,
17
+ );
@@ -0,0 +1,3 @@
1
+ export * from './clipboard';
2
+ export * from './focus';
3
+ export * from './scroll';
@@ -0,0 +1,15 @@
1
+ type JumpToElementOptions = {
2
+ block?: ScrollLogicalPosition;
3
+ inline?: ScrollLogicalPosition;
4
+ };
5
+
6
+ export function jumpToElement(
7
+ element: Element,
8
+ { block = 'center', inline = 'nearest' }: JumpToElementOptions = {},
9
+ ): void {
10
+ element.scrollIntoView({
11
+ behavior: 'auto',
12
+ block,
13
+ inline,
14
+ });
15
+ }
@@ -0,0 +1,78 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+
4
+ type ActionListItemAccent = 'start';
5
+ type ActionListItemElement = 'auto' | 'button';
6
+
7
+ type Props = Omit<HTMLAttributes<'a'>, 'href'> &
8
+ Omit<HTMLAttributes<'button'>, 'type'> & {
9
+ accent?: ActionListItemAccent;
10
+ active?: boolean;
11
+ as?: ActionListItemElement;
12
+ disabled?: boolean;
13
+ href?: string;
14
+ type?: HTMLAttributes<'button'>['type'];
15
+ };
16
+
17
+ const hasActiveState = Astro.props.active !== undefined;
18
+ const {
19
+ accent,
20
+ active = false,
21
+ as = 'auto',
22
+ class: className,
23
+ disabled = false,
24
+ href,
25
+ rel,
26
+ target,
27
+ type = 'button',
28
+ ...attrs
29
+ } = Astro.props;
30
+ const classes = ['action-list-item', className];
31
+ const resolvedRel =
32
+ rel ?? (target === '_blank' ? 'noopener noreferrer' : undefined);
33
+ const shouldRenderButton = as === 'button';
34
+ ---
35
+
36
+ {
37
+ shouldRenderButton ? (
38
+ <button
39
+ {...attrs}
40
+ class:list={classes}
41
+ data-action-list-item
42
+ data-action-list-item-active={active ? true : undefined}
43
+ data-interaction-accent={accent}
44
+ data-interaction-accent-active={accent && active ? true : undefined}
45
+ aria-pressed={hasActiveState ? active : undefined}
46
+ disabled={disabled}
47
+ type={type}
48
+ >
49
+ <slot />
50
+ </button>
51
+ ) : href && !disabled ? (
52
+ <a
53
+ {...attrs}
54
+ class:list={classes}
55
+ data-action-list-item
56
+ data-action-list-item-active={active ? true : undefined}
57
+ data-interaction-accent={accent}
58
+ data-interaction-accent-active={accent && active ? true : undefined}
59
+ href={href}
60
+ rel={resolvedRel}
61
+ target={target}
62
+ >
63
+ <slot />
64
+ </a>
65
+ ) : (
66
+ <span
67
+ {...attrs}
68
+ class:list={classes}
69
+ data-action-list-item
70
+ data-action-list-item-active={active ? true : undefined}
71
+ data-interaction-accent={accent}
72
+ data-interaction-accent-active={accent && active ? true : undefined}
73
+ aria-disabled="true"
74
+ >
75
+ <slot />
76
+ </span>
77
+ )
78
+ }
@@ -0,0 +1,43 @@
1
+ .action-list-item {
2
+ position: relative;
3
+ display: flex;
4
+ width: 100%;
5
+ min-width: 0;
6
+ min-height: 2.75rem;
7
+ align-items: center;
8
+ justify-content: flex-start;
9
+ padding: var(--nox-space-3) var(--nox-space-4);
10
+ border: 0;
11
+ border-radius: var(--nox-radius-sm);
12
+ background: transparent;
13
+ color: var(--nox-link-active);
14
+ font: inherit;
15
+ font-size: var(--nox-font-size-sm);
16
+ font-weight: var(--nox-font-weight-strong);
17
+ letter-spacing: var(--nox-letter-spacing-wide);
18
+ line-height: 1;
19
+ text-align: start;
20
+ text-decoration: none;
21
+ text-transform: uppercase;
22
+ cursor: pointer;
23
+ }
24
+
25
+ .action-list-item[data-action-list-item-active] {
26
+ color: var(--nox-link-active);
27
+ }
28
+
29
+ .action-list-item:focus-visible {
30
+ outline: var(--nox-focus-ring-width) solid var(--nox-focus-ring);
31
+ outline-offset: var(--nox-focus-ring-offset);
32
+ }
33
+
34
+ .action-list-item:where([aria-disabled='true'], [disabled]) {
35
+ color: var(--nox-text-disabled);
36
+ cursor: not-allowed;
37
+ }
38
+
39
+ @media (hover: hover) and (pointer: fine) {
40
+ .action-list-item:where([href], button):hover {
41
+ color: var(--nox-link-hover);
42
+ }
43
+ }
@@ -0,0 +1,100 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+ import type { Tone } from '../../../theme/contracts';
4
+
5
+ type ButtonSize = 'sm' | 'md' | 'lg';
6
+
7
+ type Props = Omit<HTMLAttributes<'button'>, 'size'> &
8
+ Omit<HTMLAttributes<'a'>, 'href'> & {
9
+ borderless?: boolean;
10
+ disabled?: boolean;
11
+ full?: boolean;
12
+ href?: string;
13
+ hoverTone?: Tone;
14
+ iconOnly?: boolean;
15
+ prominent?: boolean;
16
+ size?: ButtonSize;
17
+ tone?: Tone;
18
+ };
19
+
20
+ const {
21
+ borderless = false,
22
+ class: className,
23
+ 'data-tone': dataTone,
24
+ disabled = false,
25
+ full = false,
26
+ href,
27
+ hoverTone,
28
+ iconOnly = false,
29
+ prominent = false,
30
+ size = 'md',
31
+ target,
32
+ type = 'button',
33
+ rel,
34
+ tone,
35
+ ...attrs
36
+ } = Astro.props;
37
+ const hasLeading = Astro.slots.has('leading');
38
+ const hasTrailing = Astro.slots.has('trailing');
39
+ const resolvedRel =
40
+ rel ?? (target === '_blank' ? 'noopener noreferrer' : undefined);
41
+ const resolvedTone = tone ?? dataTone;
42
+ ---
43
+
44
+ {
45
+ href && !disabled ? (
46
+ <a
47
+ {...attrs}
48
+ class:list={['nox-button', className]}
49
+ data-button-borderless={borderless ? true : undefined}
50
+ data-button-full={full ? true : undefined}
51
+ data-button-hover-tone={hoverTone}
52
+ data-button-icon-only={iconOnly ? true : undefined}
53
+ data-button-prominent={prominent ? true : undefined}
54
+ data-button-size={size}
55
+ data-tone={resolvedTone}
56
+ href={href}
57
+ rel={resolvedRel}
58
+ target={target}
59
+ >
60
+ {hasLeading ? <slot name="leading" /> : null}
61
+ <slot />
62
+ {hasTrailing ? <slot name="trailing" /> : null}
63
+ </a>
64
+ ) : href ? (
65
+ <span
66
+ {...attrs}
67
+ aria-disabled="true"
68
+ class:list={['nox-button', className]}
69
+ data-button-borderless={borderless ? true : undefined}
70
+ data-button-full={full ? true : undefined}
71
+ data-button-hover-tone={hoverTone}
72
+ data-button-icon-only={iconOnly ? true : undefined}
73
+ data-button-prominent={prominent ? true : undefined}
74
+ data-button-size={size}
75
+ data-tone={resolvedTone}
76
+ >
77
+ {hasLeading ? <slot name="leading" /> : null}
78
+ <slot />
79
+ {hasTrailing ? <slot name="trailing" /> : null}
80
+ </span>
81
+ ) : (
82
+ <button
83
+ {...attrs}
84
+ class:list={['nox-button', className]}
85
+ data-button-borderless={borderless ? true : undefined}
86
+ data-button-full={full ? true : undefined}
87
+ data-button-hover-tone={hoverTone}
88
+ data-button-icon-only={iconOnly ? true : undefined}
89
+ data-button-prominent={prominent ? true : undefined}
90
+ data-button-size={size}
91
+ data-tone={resolvedTone}
92
+ disabled={disabled}
93
+ type={type}
94
+ >
95
+ {hasLeading ? <slot name="leading" /> : null}
96
+ <slot />
97
+ {hasTrailing ? <slot name="trailing" /> : null}
98
+ </button>
99
+ )
100
+ }
@@ -0,0 +1,165 @@
1
+ .nox-button {
2
+ --nox-button-background: var(--nox-tone-background);
3
+ --nox-button-border-color: var(--nox-border);
4
+ --nox-button-color: var(--nox-tone-color);
5
+ --nox-button-hover-background: var(--nox-tone-hover-background);
6
+ --nox-button-active-background: var(--nox-tone-active-background);
7
+ --nox-button-focus-ring: var(--nox-tone-focus-ring);
8
+
9
+ display: inline-flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ gap: var(--nox-space-2);
13
+ border: var(--nox-border-width) solid var(--nox-button-border-color);
14
+ border-radius: var(--nox-radius-pill);
15
+ background: var(--nox-button-background);
16
+ color: var(--nox-button-color);
17
+ font: inherit;
18
+ font-size: var(--nox-font-size-sm);
19
+ font-weight: var(--nox-font-weight-strong);
20
+ letter-spacing: var(--nox-letter-spacing-wide);
21
+ line-height: 1;
22
+ text-align: center;
23
+ text-decoration: none;
24
+ text-transform: uppercase;
25
+ cursor: pointer;
26
+ }
27
+
28
+ .nox-button[data-button-hover-tone='neutral'] {
29
+ --nox-button-hover-tone-seed: var(--nox-source-tone-neutral);
30
+ }
31
+
32
+ .nox-button[data-button-hover-tone='primary'] {
33
+ --nox-button-hover-tone-seed: var(--nox-source-tone-primary);
34
+ }
35
+
36
+ .nox-button[data-button-hover-tone='info'] {
37
+ --nox-button-hover-tone-seed: var(--nox-source-tone-info);
38
+ }
39
+
40
+ .nox-button[data-button-hover-tone='success'] {
41
+ --nox-button-hover-tone-seed: var(--nox-source-tone-success);
42
+ }
43
+
44
+ .nox-button[data-button-hover-tone='warning'] {
45
+ --nox-button-hover-tone-seed: var(--nox-source-tone-warning);
46
+ }
47
+
48
+ .nox-button[data-button-hover-tone='danger'] {
49
+ --nox-button-hover-tone-seed: var(--nox-source-tone-danger);
50
+ }
51
+
52
+ .nox-button[data-button-size='sm'] {
53
+ min-height: 2.25rem;
54
+ padding: var(--nox-space-2) var(--nox-space-3);
55
+ }
56
+
57
+ .nox-button[data-button-size='md'] {
58
+ min-height: 2.625rem;
59
+ padding: var(--nox-space-2) var(--nox-space-4);
60
+ }
61
+
62
+ .nox-button[data-button-size='lg'] {
63
+ min-height: 3rem;
64
+ padding: var(--nox-space-3) var(--nox-space-5);
65
+ }
66
+
67
+ .nox-button[data-button-full] {
68
+ inline-size: 100%;
69
+ block-size: 100%;
70
+ }
71
+
72
+ .nox-button[data-button-icon-only] {
73
+ padding: 0;
74
+ aspect-ratio: 1;
75
+ }
76
+
77
+ .nox-button[data-button-icon-only] svg {
78
+ display: block;
79
+ inline-size: 2rem;
80
+ block-size: 2rem;
81
+ }
82
+
83
+ .nox-button[data-button-icon-only][data-button-size='sm'] svg {
84
+ inline-size: 1.5rem;
85
+ block-size: 1.5rem;
86
+ }
87
+
88
+ .nox-button[data-button-icon-only][data-button-size='lg'] svg {
89
+ inline-size: 2.25rem;
90
+ block-size: 2.25rem;
91
+ }
92
+
93
+ .nox-button[data-button-borderless] {
94
+ border: 0;
95
+ border-radius: 0;
96
+ }
97
+
98
+ .nox-button[data-button-borderless]:focus-visible {
99
+ outline-offset: calc(var(--nox-focus-ring-width) * -1);
100
+ }
101
+
102
+ .nox-button[data-button-prominent] {
103
+ --nox-button-background: var(--nox-tone-color);
104
+ --nox-button-border-color: var(--nox-tone-color);
105
+ --nox-button-color: var(--nox-text-inverse);
106
+ --nox-button-hover-background: var(--nox-tone-text);
107
+ --nox-button-active-background: var(--nox-tone-text);
108
+ --nox-button-focus-ring: var(--nox-tone-focus-ring);
109
+ }
110
+
111
+ .nox-button:focus-visible {
112
+ outline: var(--nox-focus-ring-width) solid var(--nox-button-focus-ring);
113
+ outline-offset: var(--nox-focus-ring-offset);
114
+ }
115
+
116
+ .nox-button[disabled],
117
+ .nox-button[aria-disabled='true'] {
118
+ opacity: 0.58;
119
+ cursor: not-allowed;
120
+ }
121
+
122
+ @media (hover: hover) {
123
+ .nox-button:hover:not([disabled], [aria-disabled='true']) {
124
+ background: var(--nox-button-hover-background);
125
+ }
126
+
127
+ .nox-button[data-button-hover-tone]:hover:not(
128
+ [disabled],
129
+ [aria-disabled='true']
130
+ ) {
131
+ background: color-mix(
132
+ in srgb,
133
+ var(--nox-button-hover-tone-seed) 12%,
134
+ var(--nox-mix-light)
135
+ );
136
+ color: var(--nox-button-hover-tone-seed);
137
+ }
138
+ }
139
+
140
+ .nox-button:active:not([disabled], [aria-disabled='true']) {
141
+ background: var(--nox-button-active-background);
142
+ }
143
+
144
+ @media (prefers-reduced-motion: no-preference) {
145
+ .nox-button {
146
+ transition:
147
+ background-color var(--nox-motion-duration-sm)
148
+ var(--nox-motion-easing-standard),
149
+ border-color var(--nox-motion-duration-sm)
150
+ var(--nox-motion-easing-standard),
151
+ color var(--nox-motion-duration-sm) var(--nox-motion-easing-standard),
152
+ transform var(--nox-motion-duration-sm) var(--nox-motion-easing-standard);
153
+ }
154
+
155
+ .nox-button:active:not([disabled], [aria-disabled='true']) {
156
+ transform: translateY(1px);
157
+ }
158
+
159
+ .nox-button[data-button-full][data-button-borderless]:active:not(
160
+ [disabled],
161
+ [aria-disabled='true']
162
+ ) {
163
+ transform: none;
164
+ }
165
+ }
@@ -0,0 +1,97 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+ import type { AstroComponent } from '../../widgetTypes';
4
+ import type { DisplayMedia } from '../../../display/contracts';
5
+ import type { Tone } from '../../../theme/contracts';
6
+ import Media from '../../../primitives/media/Media/Media.astro';
7
+
8
+ type Props = Omit<HTMLAttributes<'button'>, 'type'> &
9
+ Omit<HTMLAttributes<'a'>, 'href'> & {
10
+ compactLabel?: string;
11
+ disabled?: boolean;
12
+ href?: string;
13
+ hoverTone?: Tone;
14
+ icon?: AstroComponent;
15
+ iconTone?: Tone;
16
+ label: string;
17
+ labelTreatment?: 'default' | 'heading';
18
+ media?: DisplayMedia;
19
+ tone?: Tone;
20
+ type?: 'button' | 'submit' | 'reset';
21
+ visualPosition?: 'start' | 'end';
22
+ };
23
+
24
+ const {
25
+ class: className,
26
+ 'data-tone': dataTone,
27
+ compactLabel,
28
+ disabled = false,
29
+ href,
30
+ hoverTone,
31
+ icon: Icon,
32
+ iconTone,
33
+ label,
34
+ labelTreatment = 'default',
35
+ media,
36
+ rel,
37
+ target,
38
+ tone,
39
+ type = 'button',
40
+ visualPosition = 'start',
41
+ ...attrs
42
+ }: Props = Astro.props;
43
+ const resolvedRel =
44
+ rel ?? (target === '_blank' ? 'noopener noreferrer' : undefined);
45
+ const resolvedTone = tone ?? dataTone;
46
+ const hasVisual = Boolean(Icon || media);
47
+ const isLink = Boolean(href);
48
+ const isDisabledLink = isLink && disabled;
49
+ const Root = isLink ? (isDisabledLink ? 'span' : 'a') : 'button';
50
+ ---
51
+
52
+ <Root
53
+ {...attrs}
54
+ aria-disabled={isDisabledLink ? 'true' : undefined}
55
+ class:list={['card-action', className]}
56
+ data-card-action-compact-label={compactLabel ? true : undefined}
57
+ data-card-action-hover-tone={hoverTone}
58
+ data-card-action-label-treatment={labelTreatment}
59
+ data-card-action-visual-position={hasVisual ? visualPosition : undefined}
60
+ data-has-visual={hasVisual ? true : undefined}
61
+ data-surface
62
+ data-tone={resolvedTone}
63
+ data-widget="card-action"
64
+ disabled={!isLink ? disabled : undefined}
65
+ href={isLink && !disabled ? href : undefined}
66
+ rel={isLink && !disabled ? resolvedRel : undefined}
67
+ role={isDisabledLink ? 'link' : undefined}
68
+ target={isLink && !disabled ? target : undefined}
69
+ type={!isLink ? type : undefined}
70
+ >
71
+ {
72
+ hasVisual ? (
73
+ <span class="card-action__visual" aria-hidden="true">
74
+ {Icon ? (
75
+ <Icon class="card-action__icon" data-tone={iconTone} />
76
+ ) : media ? (
77
+ <Media
78
+ class="card-action__media"
79
+ media={media}
80
+ fit="contain"
81
+ size="intrinsic"
82
+ />
83
+ ) : null}
84
+ </span>
85
+ ) : null
86
+ }
87
+ <span class="card-action__label">
88
+ <span class="card-action__label-full">{label}</span>
89
+ {
90
+ compactLabel ? (
91
+ <span class="card-action__label-compact" aria-hidden="true">
92
+ {compactLabel}
93
+ </span>
94
+ ) : null
95
+ }
96
+ </span>
97
+ </Root>