@grantcodes/ui 2.2.0 → 2.4.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 (44) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/package.json +15 -2
  3. package/src/components/accordion/accordion.react.js +9 -0
  4. package/src/components/app-bar/app-bar.react.js +12 -0
  5. package/src/components/avatar/avatar.react.js +9 -0
  6. package/src/components/badge/badge.react.js +9 -0
  7. package/src/components/breadcrumb/breadcrumb.react.js +15 -0
  8. package/src/components/button/button.react.js +9 -0
  9. package/src/components/button-group/button-group.react.js +9 -0
  10. package/src/components/card/card.react.js +9 -0
  11. package/src/components/code-preview/code-preview.react.js +9 -0
  12. package/src/components/container/container.react.js +9 -0
  13. package/src/components/cta/cta.react.js +9 -0
  14. package/src/components/dialog/dialog.react.js +9 -0
  15. package/src/components/dropdown/dropdown.react.js +21 -0
  16. package/src/components/dropzone/dropzone.react.js +9 -0
  17. package/src/components/feature-list/feature-list.react.js +9 -0
  18. package/src/components/footer/footer.react.js +15 -0
  19. package/src/components/form-field/form-field.react.js +9 -0
  20. package/src/components/gallery/gallery-image.react.js +9 -0
  21. package/src/components/gallery/gallery.react.js +9 -0
  22. package/src/components/hero/hero.react.js +9 -0
  23. package/src/components/icon/icon.react.js +9 -0
  24. package/src/components/loading/loading.react.js +9 -0
  25. package/src/components/logo-cloud/logo-cloud.react.js +9 -0
  26. package/src/components/media-text/media-text.react.js +9 -0
  27. package/src/components/newsletter/newsletter.react.js +9 -0
  28. package/src/components/notice/notice.react.js +9 -0
  29. package/src/components/pagination/pagination.react.js +9 -0
  30. package/src/components/pricing/pricing.react.js +9 -0
  31. package/src/components/sidebar/sidebar.react.js +13 -0
  32. package/src/components/stats/stats.react.js +9 -0
  33. package/src/components/tabs/internal/tabs-button.react.js +9 -0
  34. package/src/components/tabs/tab.react.js +9 -0
  35. package/src/components/tabs/tabs.react.js +9 -0
  36. package/src/components/testimonials/testimonials.react.js +9 -0
  37. package/src/components/toast/toast.react.js +18 -0
  38. package/src/components/tooltip/tooltip.react.js +9 -0
  39. package/src/css/all.css +7 -1
  40. package/src/css/base.css +240 -10
  41. package/src/css/layers.stories.js +113 -0
  42. package/src/lib/styles/all.css +37 -0
  43. package/src/react.js +36 -0
  44. package/src/react.test.js +56 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.4.0](https://github.com/grantcodes/ui/compare/ui-v2.3.0...ui-v2.4.0) (2026-03-30)
4
+
5
+
6
+ ### Features
7
+
8
+ * **ui:** add CSS layers and simplify component stylesheet bundle ([42c183c](https://github.com/grantcodes/ui/commit/42c183c303b81d8a4d0a7bb7a4d5f6482697b3d9))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **ui:** replace sanitize.css imports with inlined custom reset ([c97182b](https://github.com/grantcodes/ui/commit/c97182bc98406055f81e6b2433427e52723776b8))
14
+ * **ui:** replace sanitize.css with inlined custom reset ([f5fe733](https://github.com/grantcodes/ui/commit/f5fe733007783452a4f4612e846960e074386677))
15
+
16
+ ## [2.3.0](https://github.com/grantcodes/ui/compare/ui-v2.2.0...ui-v2.3.0) (2026-03-25)
17
+
18
+
19
+ ### Features
20
+
21
+ * **01-01:** create React wrapper components for all Lit web components ([f5d47a7](https://github.com/grantcodes/ui/commit/f5d47a7e1dc45d5d5f21823dcba59c687feed56f))
22
+ * **ui:** add react exports ([f040673](https://github.com/grantcodes/ui/commit/f04067332e5d70803d6f72aade875f08ad05e090))
23
+
3
24
  ## [2.2.0](https://github.com/grantcodes/ui/compare/ui-v2.1.1...ui-v2.2.0) (2026-03-25)
4
25
 
5
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grantcodes/ui",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "description": "A personal component system built with Lit web components",
5
5
  "type": "module",
6
6
  "main": "src/main.js",
@@ -28,11 +28,15 @@
28
28
  "require": "./src/css/themes/*"
29
29
  },
30
30
  "./styles/focus-ring.css": "./src/lib/styles/focus-ring.css",
31
+ "./styles/all.css": "./src/lib/styles/all.css",
31
32
  "./components/*": {
32
33
  "import": "./src/components/*",
33
34
  "require": "./src/components/*"
34
35
  },
35
36
  "./fonts/*": "./src/fonts/*",
37
+ "./react": {
38
+ "import": "./src/react.js"
39
+ },
36
40
  "./css-import-attributes": {
37
41
  "types": "./css-import-attributes.d.ts"
38
42
  },
@@ -40,8 +44,8 @@
40
44
  },
41
45
  "license": "MIT",
42
46
  "dependencies": {
47
+ "@lit/react": "^1.0.8",
43
48
  "lit": "^3.3.1",
44
- "sanitize.css": "^13.0.0",
45
49
  "shiki": "^3.17.1",
46
50
  "@grantcodes/style-dictionary": "^1.3.1"
47
51
  },
@@ -64,6 +68,7 @@
64
68
  "lucide-static": "^0.555.0",
65
69
  "npm-run-all": "^4.1.5",
66
70
  "plop": "^4.0.4",
71
+ "react": "^19.2.4",
67
72
  "storybook": "^10.1.4",
68
73
  "vite": "^7.2.6"
69
74
  },
@@ -77,6 +82,14 @@
77
82
  "LICENCE"
78
83
  ],
79
84
  "customElements": "custom-elements.json",
85
+ "peerDependencies": {
86
+ "react": "^18.0.0 || ^19.0.0"
87
+ },
88
+ "peerDependenciesMeta": {
89
+ "react": {
90
+ "optional": true
91
+ }
92
+ },
80
93
  "scripts": {
81
94
  "dev": "storybook dev -p 6006",
82
95
  "watch": "vite build --watch",
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesAccordion } from "./accordion.js"
4
+
5
+ export const Accordion = createComponent({
6
+ tagName: "grantcodes-accordion",
7
+ elementClass: GrantCodesAccordion,
8
+ react: React,
9
+ })
@@ -0,0 +1,12 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesAppBar } from "./app-bar.js"
4
+
5
+ export const AppBar = createComponent({
6
+ tagName: "grantcodes-app-bar",
7
+ elementClass: GrantCodesAppBar,
8
+ react: React,
9
+ events: {
10
+ onMenuToggle: "menu-toggle",
11
+ },
12
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesAvatar } from "./avatar.js"
4
+
5
+ export const Avatar = createComponent({
6
+ tagName: "grantcodes-avatar",
7
+ elementClass: GrantCodesAvatar,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesBadge } from "./badge.js"
4
+
5
+ export const Badge = createComponent({
6
+ tagName: "grantcodes-badge",
7
+ elementClass: GrantCodesBadge,
8
+ react: React,
9
+ })
@@ -0,0 +1,15 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesBreadcrumb, GrantCodesBreadcrumbItem } from "./breadcrumb.js"
4
+
5
+ export const Breadcrumb = createComponent({
6
+ tagName: "grantcodes-breadcrumb",
7
+ elementClass: GrantCodesBreadcrumb,
8
+ react: React,
9
+ })
10
+
11
+ export const BreadcrumbItem = createComponent({
12
+ tagName: "grantcodes-breadcrumb-item",
13
+ elementClass: GrantCodesBreadcrumbItem,
14
+ react: React,
15
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesButton } from "./button.js"
4
+
5
+ export const Button = createComponent({
6
+ tagName: "grantcodes-button",
7
+ elementClass: GrantCodesButton,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesButtonGroup } from "./button-group.js"
4
+
5
+ export const ButtonGroup = createComponent({
6
+ tagName: "grantcodes-button-group",
7
+ elementClass: GrantCodesButtonGroup,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesCard } from "./card.js"
4
+
5
+ export const Card = createComponent({
6
+ tagName: "grantcodes-card",
7
+ elementClass: GrantCodesCard,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesCodePreview } from "./code-preview.js"
4
+
5
+ export const CodePreview = createComponent({
6
+ tagName: "grantcodes-code-preview",
7
+ elementClass: GrantCodesCodePreview,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesContainer } from "./container.js"
4
+
5
+ export const Container = createComponent({
6
+ tagName: "grantcodes-container",
7
+ elementClass: GrantCodesContainer,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesCta } from "./cta.js"
4
+
5
+ export const Cta = createComponent({
6
+ tagName: "grantcodes-cta",
7
+ elementClass: GrantCodesCta,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesDialog } from "./dialog.js"
4
+
5
+ export const Dialog = createComponent({
6
+ tagName: "grantcodes-dialog",
7
+ elementClass: GrantCodesDialog,
8
+ react: React,
9
+ })
@@ -0,0 +1,21 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesDropdown, GrantCodesDropdownItem } from "./dropdown.js"
4
+
5
+ export const Dropdown = createComponent({
6
+ tagName: "grantcodes-dropdown",
7
+ elementClass: GrantCodesDropdown,
8
+ react: React,
9
+ events: {
10
+ onToggle: "toggle",
11
+ },
12
+ })
13
+
14
+ export const DropdownItem = createComponent({
15
+ tagName: "grantcodes-dropdown-item",
16
+ elementClass: GrantCodesDropdownItem,
17
+ react: React,
18
+ events: {
19
+ onSelect: "select",
20
+ },
21
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesDropzone } from "./dropzone.js"
4
+
5
+ export const Dropzone = createComponent({
6
+ tagName: "grantcodes-dropzone",
7
+ elementClass: GrantCodesDropzone,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesFeatureList } from "./feature-list.js"
4
+
5
+ export const FeatureList = createComponent({
6
+ tagName: "grantcodes-feature-list",
7
+ elementClass: GrantCodesFeatureList,
8
+ react: React,
9
+ })
@@ -0,0 +1,15 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesFooter, GrantCodesFooterColumn } from "./footer.js"
4
+
5
+ export const Footer = createComponent({
6
+ tagName: "grantcodes-footer",
7
+ elementClass: GrantCodesFooter,
8
+ react: React,
9
+ })
10
+
11
+ export const FooterColumn = createComponent({
12
+ tagName: "grantcodes-footer-column",
13
+ elementClass: GrantCodesFooterColumn,
14
+ react: React,
15
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesFormField } from "./form-field.js"
4
+
5
+ export const FormField = createComponent({
6
+ tagName: "grantcodes-form-field",
7
+ elementClass: GrantCodesFormField,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesGalleryImage } from "./gallery-image.js"
4
+
5
+ export const GalleryImage = createComponent({
6
+ tagName: "grantcodes-gallery-image",
7
+ elementClass: GrantCodesGalleryImage,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesGallery } from "./gallery.js"
4
+
5
+ export const Gallery = createComponent({
6
+ tagName: "grantcodes-gallery",
7
+ elementClass: GrantCodesGallery,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesHero } from "./hero.js"
4
+
5
+ export const Hero = createComponent({
6
+ tagName: "grantcodes-hero",
7
+ elementClass: GrantCodesHero,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesIcon } from "./icon.js"
4
+
5
+ export const Icon = createComponent({
6
+ tagName: "grantcodes-icon",
7
+ elementClass: GrantCodesIcon,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesLoading } from "./loading.js"
4
+
5
+ export const Loading = createComponent({
6
+ tagName: "grantcodes-loading",
7
+ elementClass: GrantCodesLoading,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesLogoCloud } from "./logo-cloud.js"
4
+
5
+ export const LogoCloud = createComponent({
6
+ tagName: "grantcodes-logo-cloud",
7
+ elementClass: GrantCodesLogoCloud,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesMediaText } from "./media-text.js"
4
+
5
+ export const MediaText = createComponent({
6
+ tagName: "grantcodes-media-text",
7
+ elementClass: GrantCodesMediaText,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesNewsletter } from "./newsletter.js"
4
+
5
+ export const Newsletter = createComponent({
6
+ tagName: "grantcodes-newsletter",
7
+ elementClass: GrantCodesNewsletter,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesNotice } from "./notice.js"
4
+
5
+ export const Notice = createComponent({
6
+ tagName: "grantcodes-notice",
7
+ elementClass: GrantCodesNotice,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesPagination } from "./pagination.js"
4
+
5
+ export const Pagination = createComponent({
6
+ tagName: "grantcodes-pagination",
7
+ elementClass: GrantCodesPagination,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesPricing } from "./pricing.js"
4
+
5
+ export const Pricing = createComponent({
6
+ tagName: "grantcodes-pricing",
7
+ elementClass: GrantCodesPricing,
8
+ react: React,
9
+ })
@@ -0,0 +1,13 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesSidebar } from "./sidebar.js"
4
+
5
+ export const Sidebar = createComponent({
6
+ tagName: "grantcodes-sidebar",
7
+ elementClass: GrantCodesSidebar,
8
+ react: React,
9
+ events: {
10
+ onToggle: "toggle",
11
+ onDrawerToggle: "drawer-toggle",
12
+ },
13
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesStats } from "./stats.js"
4
+
5
+ export const Stats = createComponent({
6
+ tagName: "grantcodes-stats",
7
+ elementClass: GrantCodesStats,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesTabsButton } from "./tabs-button.js"
4
+
5
+ export const TabsButton = createComponent({
6
+ tagName: "grantcodes-tabs-button",
7
+ elementClass: GrantCodesTabsButton,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesTab } from "./tab.js"
4
+
5
+ export const Tab = createComponent({
6
+ tagName: "grantcodes-tab",
7
+ elementClass: GrantCodesTab,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesTabs } from "./tabs.js"
4
+
5
+ export const Tabs = createComponent({
6
+ tagName: "grantcodes-tabs",
7
+ elementClass: GrantCodesTabs,
8
+ react: React,
9
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesTestimonials } from "./testimonials.js"
4
+
5
+ export const Testimonials = createComponent({
6
+ tagName: "grantcodes-testimonials",
7
+ elementClass: GrantCodesTestimonials,
8
+ react: React,
9
+ })
@@ -0,0 +1,18 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesToast, GrantCodesToastContainer } from "./toast.js"
4
+
5
+ export const Toast = createComponent({
6
+ tagName: "grantcodes-toast",
7
+ elementClass: GrantCodesToast,
8
+ react: React,
9
+ events: {
10
+ onDismiss: "dismiss",
11
+ },
12
+ })
13
+
14
+ export const ToastContainer = createComponent({
15
+ tagName: "grantcodes-toast-container",
16
+ elementClass: GrantCodesToastContainer,
17
+ react: React,
18
+ })
@@ -0,0 +1,9 @@
1
+ import React from "react"
2
+ import { createComponent } from "@lit/react"
3
+ import { GrantCodesTooltip } from "./tooltip.js"
4
+
5
+ export const Tooltip = createComponent({
6
+ tagName: "grantcodes-tooltip",
7
+ elementClass: GrantCodesTooltip,
8
+ react: React,
9
+ })
package/src/css/all.css CHANGED
@@ -1 +1,7 @@
1
- @import "./base.css";
1
+ @layer reset, base, utilities, components;
2
+
3
+ @import "./base.css" layer(reset);
4
+ @import "./typography.css" layer(base);
5
+ @import "./elements.css" layer(base);
6
+ @import "./util/index.css" layer(utilities);
7
+ @import "./helpers.css" layer(utilities);
package/src/css/base.css CHANGED
@@ -1,13 +1,243 @@
1
- /* CSS defaults */
2
- /* NOTE: Converted from SCSS - using standard CSS imports */
3
- @import "../../node_modules/sanitize.css/sanitize.css";
4
- @import "../../node_modules/sanitize.css/forms.css";
5
- @import "../../node_modules/sanitize.css/typography.css";
6
- @import "../../node_modules/sanitize.css/reduce-motion.css";
7
-
8
- @import "./typography.css";
9
- @import "./elements.css";
10
- @import "./util/index.css";
1
+ /* CSS reset — inspired by sanitize.css (https://csstools.github.io/sanitize.css/)
2
+ Inlined to avoid broken relative node_modules paths when installed externally. */
3
+
4
+ /* Box sizing and background */
5
+ *,
6
+ ::before,
7
+ ::after {
8
+ box-sizing: border-box;
9
+ background-repeat: no-repeat;
10
+ }
11
+
12
+ ::before,
13
+ ::after {
14
+ text-decoration: inherit;
15
+ vertical-align: inherit;
16
+ }
17
+
18
+ /* Root defaults */
19
+ :where(:root) {
20
+ cursor: default;
21
+ line-height: 1.5;
22
+ overflow-wrap: break-word;
23
+ -moz-tab-size: 4;
24
+ tab-size: 4;
25
+ -webkit-tap-highlight-color: transparent;
26
+ -webkit-text-size-adjust: 100%;
27
+ }
28
+
29
+ /* Typography — system font stack */
30
+ html {
31
+ font-family:
32
+ system-ui,
33
+ -apple-system,
34
+ "Segoe UI",
35
+ "Roboto",
36
+ "Ubuntu",
37
+ "Cantarell",
38
+ "Noto Sans",
39
+ sans-serif,
40
+ "Apple Color Emoji",
41
+ "Segoe UI Emoji",
42
+ "Segoe UI Symbol",
43
+ "Noto Color Emoji";
44
+ }
45
+
46
+ code,
47
+ kbd,
48
+ samp,
49
+ pre {
50
+ font-family:
51
+ ui-monospace,
52
+ "Menlo",
53
+ "Consolas",
54
+ "Roboto Mono",
55
+ "Ubuntu Monospace",
56
+ "Noto Mono",
57
+ "Oxygen Mono",
58
+ "Liberation Mono",
59
+ monospace,
60
+ "Apple Color Emoji",
61
+ "Segoe UI Emoji",
62
+ "Segoe UI Symbol",
63
+ "Noto Color Emoji";
64
+ }
65
+
66
+ /* Sections */
67
+ :where(body) {
68
+ margin: 0;
69
+ }
70
+
71
+ :where(h1) {
72
+ font-size: 2em;
73
+ margin: 0.67em 0;
74
+ }
75
+
76
+ /* Grouping */
77
+ :where(dl, ol, ul) :where(dl, ol, ul) {
78
+ margin: 0;
79
+ }
80
+
81
+ :where(hr) {
82
+ color: inherit;
83
+ height: 0;
84
+ }
85
+
86
+ :where(nav) :where(ol, ul) {
87
+ list-style-type: none;
88
+ padding: 0;
89
+ }
90
+
91
+ /* Prevent VoiceOver from ignoring list semantics in Safari */
92
+ :where(nav li)::before {
93
+ content: "\200B";
94
+ float: left;
95
+ }
96
+
97
+ :where(pre) {
98
+ font-size: 1em;
99
+ overflow: auto;
100
+ }
101
+
102
+ /* Text-level semantics */
103
+ :where(abbr[title]) {
104
+ text-decoration: underline dotted;
105
+ }
106
+
107
+ :where(b, strong) {
108
+ font-weight: bolder;
109
+ }
110
+
111
+ :where(code, kbd, samp) {
112
+ font-size: 1em;
113
+ }
114
+
115
+ :where(small) {
116
+ font-size: 80%;
117
+ }
118
+
119
+ /* Embedded content */
120
+ :where(audio, canvas, iframe, img, svg, video) {
121
+ vertical-align: middle;
122
+ }
123
+
124
+ :where(iframe) {
125
+ border-style: none;
126
+ }
127
+
128
+ :where(svg:not([fill])) {
129
+ fill: currentColor;
130
+ }
131
+
132
+ /* Tabular data */
133
+ :where(table) {
134
+ border-collapse: collapse;
135
+ border-color: inherit;
136
+ text-indent: 0;
137
+ }
138
+
139
+ /* Forms — baseline normalisation */
140
+ :where(button, input, select) {
141
+ margin: 0;
142
+ }
143
+
144
+ :where(button, [type="button" i], [type="reset" i], [type="submit" i]) {
145
+ -webkit-appearance: button;
146
+ }
147
+
148
+ :where(fieldset) {
149
+ border: 1px solid #a0a0a0;
150
+ }
151
+
152
+ :where(progress) {
153
+ vertical-align: baseline;
154
+ }
155
+
156
+ :where(textarea) {
157
+ margin: 0;
158
+ resize: vertical;
159
+ }
160
+
161
+ :where([type="search" i]) {
162
+ -webkit-appearance: textfield;
163
+ outline-offset: -2px;
164
+ }
165
+
166
+ ::-webkit-inner-spin-button,
167
+ ::-webkit-outer-spin-button {
168
+ height: auto;
169
+ }
170
+
171
+ ::-webkit-input-placeholder {
172
+ color: inherit;
173
+ opacity: 0.54;
174
+ }
175
+
176
+ ::-webkit-search-decoration {
177
+ -webkit-appearance: none;
178
+ }
179
+
180
+ ::-webkit-file-upload-button {
181
+ -webkit-appearance: button;
182
+ font: inherit;
183
+ }
184
+
185
+ /* Forms — typography and colour inheritance */
186
+ :where(button, input, select, textarea) {
187
+ background-color: transparent;
188
+ border: 1px solid WindowFrame;
189
+ color: inherit;
190
+ font: inherit;
191
+ letter-spacing: inherit;
192
+ padding: 0.25em 0.375em;
193
+ }
194
+
195
+ :where([type="color" i], [type="range" i]) {
196
+ border-width: 0;
197
+ padding: 0;
198
+ }
199
+
200
+ /* Interactive */
201
+ :where(details > summary:first-of-type) {
202
+ display: list-item;
203
+ }
204
+
205
+ /* Accessibility */
206
+ :where([aria-busy="true" i]) {
207
+ cursor: progress;
208
+ }
209
+
210
+ :where([aria-controls]) {
211
+ cursor: pointer;
212
+ }
213
+
214
+ :where([aria-disabled="true" i], [disabled]) {
215
+ cursor: not-allowed;
216
+ }
217
+
218
+ :where([aria-hidden="false" i][hidden]) {
219
+ display: initial;
220
+ }
221
+
222
+ :where([aria-hidden="false" i][hidden]:not(:focus)) {
223
+ clip: rect(0, 0, 0, 0);
224
+ position: absolute;
225
+ }
226
+
227
+ /* Reduced motion — !important is required here to override any animation/transition regardless of specificity */
228
+ @media (prefers-reduced-motion: reduce) {
229
+ *,
230
+ ::before,
231
+ ::after {
232
+ animation-delay: -1ms !important;
233
+ animation-duration: 1ms !important;
234
+ animation-iteration-count: 1 !important;
235
+ background-attachment: initial !important;
236
+ scroll-behavior: auto !important;
237
+ transition-delay: 0s !important;
238
+ transition-duration: 0s !important;
239
+ }
240
+ }
11
241
 
12
242
  /* Design tokens are provided by @grantcodes/style-dictionary and applied to :root */
13
243
  :root {
@@ -0,0 +1,113 @@
1
+ import { html } from "lit";
2
+
3
+ const meta = {
4
+ title: "Styles/CSS Layers",
5
+ };
6
+
7
+ export default meta;
8
+
9
+ export const LayerOrder = {
10
+ render: () => html`
11
+ <div style="max-width: 40rem;">
12
+ <h2>CSS Layers</h2>
13
+ <p>Styles are organized into CSS cascade layers, from lowest to highest priority:</p>
14
+
15
+ <ol>
16
+ <li><strong>reset</strong> — sanitize.css, root defaults</li>
17
+ <li><strong>base</strong> — typography, element styles</li>
18
+ <li><strong>utilities</strong> — focus-ring, helpers</li>
19
+ <li><strong>components</strong> — web component styles</li>
20
+ </ol>
21
+
22
+ <p>Unlayered styles (your overrides, theme variables) always win.</p>
23
+ </div>
24
+ `,
25
+ };
26
+
27
+ export const LayerOverrideDemo = {
28
+ render: () => html`
29
+ <style>
30
+ /* This override is unlayered, so it beats all layers */
31
+ .layer-demo-override {
32
+ color: var(--g-theme-color-content-brand, rebeccapurple);
33
+ font-weight: bold;
34
+ }
35
+ </style>
36
+ <div style="max-width: 40rem; display: flex; flex-direction: column; gap: 1.5rem;">
37
+ <h2>Layer Override Demo</h2>
38
+ <p>Because styles are layered, overriding component/base styles is straightforward — no <code>!important</code> needed.</p>
39
+
40
+ <div>
41
+ <h3>Default paragraph (base layer)</h3>
42
+ <p>This paragraph uses the default typography styles from the <code>base</code> layer.</p>
43
+ </div>
44
+
45
+ <div>
46
+ <h3>Overridden paragraph (unlayered)</h3>
47
+ <p class="layer-demo-override">This paragraph is overridden with an unlayered style — it wins over the base layer automatically.</p>
48
+ </div>
49
+
50
+ <div>
51
+ <h3>Component with override</h3>
52
+ <grantcodes-button>Default button</grantcodes-button>
53
+ <style>
54
+ .custom-btn::part(button) {
55
+ border-radius: 999px;
56
+ }
57
+ </style>
58
+ <grantcodes-button class="custom-btn">Custom border radius (unlayered override)</grantcodes-button>
59
+ </div>
60
+ </div>
61
+ `,
62
+ };
63
+
64
+ export const AllLayers = {
65
+ render: () => html`
66
+ <style>
67
+ .layers-grid {
68
+ display: grid;
69
+ grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
70
+ gap: 1rem;
71
+ max-width: 60rem;
72
+ }
73
+ .layer-card {
74
+ padding: 1rem;
75
+ border: 1px solid var(--g-theme-color-border-default, #ccc);
76
+ border-radius: var(--g-theme-border-radius-md, 0.5rem);
77
+ }
78
+ .layer-card h4 {
79
+ margin-top: 0;
80
+ }
81
+ .layer-card code {
82
+ font-size: 0.85em;
83
+ }
84
+ </style>
85
+ <h2>All Layers</h2>
86
+ <div class="layers-grid">
87
+ <div class="layer-card">
88
+ <h4>1. reset</h4>
89
+ <p>Lowest priority. Normalizes browser defaults.</p>
90
+ <code>sanitize.css</code><br>
91
+ <code>::selection</code><br>
92
+ <code>::backdrop</code>
93
+ </div>
94
+ <div class="layer-card">
95
+ <h4>2. base</h4>
96
+ <p>Typography and HTML element styles.</p>
97
+ <code>typography.css</code><br>
98
+ <code>elements.css</code>
99
+ </div>
100
+ <div class="layer-card">
101
+ <h4>3. utilities</h4>
102
+ <p>Reusable utility classes.</p>
103
+ <code>focus-ring.css</code><br>
104
+ <code>helpers.css</code>
105
+ </div>
106
+ <div class="layer-card">
107
+ <h4>4. components</h4>
108
+ <p>All web component styles.</p>
109
+ <code>accordion</code>, <code>button</code>, <code>card</code>, etc.
110
+ </div>
111
+ </div>
112
+ `,
113
+ };
@@ -0,0 +1,37 @@
1
+ @layer components {
2
+ @import "./focus-ring.css";
3
+ @import "../../components/accordion/accordion.css";
4
+ @import "../../components/app-bar/app-bar.css";
5
+ @import "../../components/avatar/avatar.css";
6
+ @import "../../components/badge/badge.css";
7
+ @import "../../components/breadcrumb/breadcrumb.css";
8
+ @import "../../components/button/button.css";
9
+ @import "../../components/button-group/button-group.css";
10
+ @import "../../components/card/card.css";
11
+ @import "../../components/code-preview/code-preview.css";
12
+ @import "../../components/container/container.css";
13
+ @import "../../components/cta/cta.css";
14
+ @import "../../components/dialog/dialog.css";
15
+ @import "../../components/dropdown/dropdown.css";
16
+ @import "../../components/dropzone/dropzone.css";
17
+ @import "../../components/feature-list/feature-list.css";
18
+ @import "../../components/footer/footer.css";
19
+ @import "../../components/footer/footer-column.css";
20
+ @import "../../components/form-field/form-field.css";
21
+ @import "../../components/gallery/gallery.css";
22
+ @import "../../components/hero/hero.css";
23
+ @import "../../components/icon/icon.css";
24
+ @import "../../components/loading/loading.css";
25
+ @import "../../components/logo-cloud/logo-cloud.css";
26
+ @import "../../components/media-text/media-text.css";
27
+ @import "../../components/newsletter/newsletter.css";
28
+ @import "../../components/notice/notice.css";
29
+ @import "../../components/pagination/pagination.css";
30
+ @import "../../components/pricing/pricing.css";
31
+ @import "../../components/sidebar/sidebar.css";
32
+ @import "../../components/stats/stats.css";
33
+ @import "../../components/tabs/tabs.css";
34
+ @import "../../components/testimonials/testimonials.css";
35
+ @import "../../components/toast/toast.css";
36
+ @import "../../components/tooltip/tooltip.css";
37
+ }
package/src/react.js ADDED
@@ -0,0 +1,36 @@
1
+ export { Accordion } from "./components/accordion/accordion.react.js"
2
+ export { AppBar } from "./components/app-bar/app-bar.react.js"
3
+ export { Avatar } from "./components/avatar/avatar.react.js"
4
+ export { Badge } from "./components/badge/badge.react.js"
5
+ export { Breadcrumb, BreadcrumbItem } from "./components/breadcrumb/breadcrumb.react.js"
6
+ export { Button } from "./components/button/button.react.js"
7
+ export { ButtonGroup } from "./components/button-group/button-group.react.js"
8
+ export { Card } from "./components/card/card.react.js"
9
+ export { CodePreview } from "./components/code-preview/code-preview.react.js"
10
+ export { Container } from "./components/container/container.react.js"
11
+ export { Cta } from "./components/cta/cta.react.js"
12
+ export { Dialog } from "./components/dialog/dialog.react.js"
13
+ export { Dropdown, DropdownItem } from "./components/dropdown/dropdown.react.js"
14
+ export { Dropzone } from "./components/dropzone/dropzone.react.js"
15
+ export { FeatureList } from "./components/feature-list/feature-list.react.js"
16
+ export { Footer, FooterColumn } from "./components/footer/footer.react.js"
17
+ export { FormField } from "./components/form-field/form-field.react.js"
18
+ export { Gallery } from "./components/gallery/gallery.react.js"
19
+ export { GalleryImage } from "./components/gallery/gallery-image.react.js"
20
+ export { Hero } from "./components/hero/hero.react.js"
21
+ export { Icon } from "./components/icon/icon.react.js"
22
+ export { Loading } from "./components/loading/loading.react.js"
23
+ export { LogoCloud } from "./components/logo-cloud/logo-cloud.react.js"
24
+ export { MediaText } from "./components/media-text/media-text.react.js"
25
+ export { Newsletter } from "./components/newsletter/newsletter.react.js"
26
+ export { Notice } from "./components/notice/notice.react.js"
27
+ export { Pagination } from "./components/pagination/pagination.react.js"
28
+ export { Pricing } from "./components/pricing/pricing.react.js"
29
+ export { Sidebar } from "./components/sidebar/sidebar.react.js"
30
+ export { Stats } from "./components/stats/stats.react.js"
31
+ export { Tab } from "./components/tabs/tab.react.js"
32
+ export { Tabs } from "./components/tabs/tabs.react.js"
33
+ export { TabsButton } from "./components/tabs/internal/tabs-button.react.js"
34
+ export { Testimonials } from "./components/testimonials/testimonials.react.js"
35
+ export { Toast, ToastContainer } from "./components/toast/toast.react.js"
36
+ export { Tooltip } from "./components/tooltip/tooltip.react.js"
@@ -0,0 +1,56 @@
1
+ import { describe, it } from "node:test";
2
+ import { strict as assert } from "node:assert";
3
+
4
+ describe("React Wrappers", () => {
5
+ it("should export all component wrappers", async () => {
6
+ const react = await import("./react.js");
7
+ assert.ok(react.Button, "Button wrapper should be exported");
8
+ assert.ok(react.Card, "Card wrapper should be exported");
9
+ assert.ok(react.Dialog, "Dialog wrapper should be exported");
10
+ assert.ok(react.Accordion, "Accordion wrapper should be exported");
11
+ assert.ok(react.Tooltip, "Tooltip wrapper should be exported");
12
+ assert.ok(react.Hero, "Hero wrapper should be exported");
13
+ assert.ok(react.Container, "Container wrapper should be exported");
14
+ assert.ok(react.Icon, "Icon wrapper should be exported");
15
+ assert.ok(react.Loading, "Loading wrapper should be exported");
16
+ assert.ok(react.Notice, "Notice wrapper should be exported");
17
+ });
18
+
19
+ it("should export at least 35 component wrappers", async () => {
20
+ const react = await import("./react.js");
21
+ const exportCount = Object.keys(react).length;
22
+ assert.ok(
23
+ exportCount >= 35,
24
+ `Expected at least 35 exports, got ${exportCount}`,
25
+ );
26
+ });
27
+
28
+ it("should export event-mapped components", async () => {
29
+ const react = await import("./react.js");
30
+ assert.ok(react.AppBar, "AppBar wrapper should be exported");
31
+ assert.ok(react.Dropdown, "Dropdown wrapper should be exported");
32
+ assert.ok(react.DropdownItem, "DropdownItem wrapper should be exported");
33
+ assert.ok(react.Sidebar, "Sidebar wrapper should be exported");
34
+ assert.ok(react.Toast, "Toast wrapper should be exported");
35
+ });
36
+
37
+ it("should export compound component wrappers", async () => {
38
+ const react = await import("./react.js");
39
+ assert.ok(react.Breadcrumb, "Breadcrumb wrapper should be exported");
40
+ assert.ok(
41
+ react.BreadcrumbItem,
42
+ "BreadcrumbItem wrapper should be exported",
43
+ );
44
+ assert.ok(react.Footer, "Footer wrapper should be exported");
45
+ assert.ok(react.FooterColumn, "FooterColumn wrapper should be exported");
46
+ assert.ok(react.Gallery, "Gallery wrapper should be exported");
47
+ assert.ok(react.GalleryImage, "GalleryImage wrapper should be exported");
48
+ assert.ok(react.Tabs, "Tabs wrapper should be exported");
49
+ assert.ok(react.Tab, "Tab wrapper should be exported");
50
+ assert.ok(react.TabsButton, "TabsButton wrapper should be exported");
51
+ assert.ok(
52
+ react.ToastContainer,
53
+ "ToastContainer wrapper should be exported",
54
+ );
55
+ });
56
+ });