@grantcodes/ui 2.0.2 → 2.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 (179) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/custom-elements.json +1926 -191
  3. package/package.json +6 -5
  4. package/src/components/accordion/accordion.component.js +33 -0
  5. package/src/components/accordion/accordion.js +6 -0
  6. package/src/components/accordion/accordion.stories.js +88 -0
  7. package/src/components/accordion/accordion.styles.js +66 -0
  8. package/src/components/accordion/index.js +6 -0
  9. package/src/components/app-bar/app-bar.component.js +1 -3
  10. package/src/components/app-bar/app-bar.js +0 -2
  11. package/src/components/app-bar/app-bar.styles.js +222 -221
  12. package/src/components/app-bar/app-bar.test.js +58 -17
  13. package/src/components/app-bar/index.js +0 -2
  14. package/src/components/avatar/avatar.js +0 -12
  15. package/src/components/avatar/avatar.stories.js +0 -12
  16. package/src/components/avatar/avatar.styles.js +19 -19
  17. package/src/components/avatar/avatar.test.js +4 -4
  18. package/src/components/avatar/index.js +1 -13
  19. package/src/components/badge/badge.js +0 -2
  20. package/src/components/badge/badge.styles.js +78 -81
  21. package/src/components/badge/badge.test.js +18 -5
  22. package/src/components/badge/index.js +0 -2
  23. package/src/components/breadcrumb/breadcrumb.component.js +9 -10
  24. package/src/components/breadcrumb/breadcrumb.js +6 -4
  25. package/src/components/breadcrumb/breadcrumb.styles.js +86 -90
  26. package/src/components/breadcrumb/breadcrumb.test.js +15 -5
  27. package/src/components/breadcrumb/index.js +0 -2
  28. package/src/components/button/button.component.js +2 -2
  29. package/src/components/button/button.styles.js +58 -86
  30. package/src/components/button/button.test.js +8 -4
  31. package/src/components/button/index.js +1 -1
  32. package/src/components/button-group/button-group.test.js +0 -2
  33. package/src/components/button-group/index.js +1 -1
  34. package/src/components/card/card.component.js +40 -9
  35. package/src/components/card/card.js +3 -1
  36. package/src/components/card/card.stories.js +18 -5
  37. package/src/components/card/card.styles.js +46 -20
  38. package/src/components/card/card.test.js +0 -2
  39. package/src/components/card/index.js +1 -1
  40. package/src/components/code-preview/code-preview.component.js +9 -9
  41. package/src/components/code-preview/code-preview.js +0 -1
  42. package/src/components/code-preview/code-preview.styles.js +3 -3
  43. package/src/components/code-preview/code-preview.test.js +29 -8
  44. package/src/components/code-preview/index.js +1 -1
  45. package/src/components/container/container.component.js +1 -0
  46. package/src/components/container/container.js +0 -1
  47. package/src/components/container/container.stories.js +12 -4
  48. package/src/components/container/container.styles.js +37 -35
  49. package/src/components/container/container.test.js +0 -2
  50. package/src/components/container/index.js +1 -1
  51. package/src/components/cta/cta.component.js +108 -0
  52. package/src/components/cta/cta.js +6 -0
  53. package/src/components/cta/cta.stories.js +56 -0
  54. package/src/components/cta/cta.styles.js +64 -0
  55. package/src/components/cta/index.js +1 -0
  56. package/src/components/dialog/dialog.js +0 -1
  57. package/src/components/dialog/dialog.styles.js +8 -8
  58. package/src/components/dialog/dialog.test.js +11 -5
  59. package/src/components/dialog/index.js +1 -1
  60. package/src/components/dropdown/dropdown.component.js +5 -3
  61. package/src/components/dropdown/dropdown.js +6 -4
  62. package/src/components/dropdown/dropdown.styles.js +5 -5
  63. package/src/components/dropdown/dropdown.test.js +20 -4
  64. package/src/components/dropdown/index.js +0 -2
  65. package/src/components/dropzone/dropzone.component.js +7 -6
  66. package/src/components/dropzone/dropzone.styles.js +4 -4
  67. package/src/components/dropzone/dropzone.test.js +6 -4
  68. package/src/components/dropzone/index.js +1 -1
  69. package/src/components/feature-list/feature-list.component.js +130 -0
  70. package/src/components/feature-list/feature-list.js +6 -0
  71. package/src/components/feature-list/feature-list.stories.js +117 -0
  72. package/src/components/feature-list/feature-list.styles.js +82 -0
  73. package/src/components/feature-list/index.js +1 -0
  74. package/src/components/footer/footer-column.styles.js +46 -47
  75. package/src/components/footer/footer.js +6 -2
  76. package/src/components/footer/footer.styles.js +6 -6
  77. package/src/components/footer/footer.test.js +9 -4
  78. package/src/components/footer/index.js +1 -1
  79. package/src/components/form-field/form-field.component.js +1 -3
  80. package/src/components/form-field/form-field.js +0 -1
  81. package/src/components/form-field/form-field.styles.js +35 -37
  82. package/src/components/form-field/form-field.test.js +9 -4
  83. package/src/components/form-field/index.js +1 -1
  84. package/src/components/gallery/gallery-image.js +0 -1
  85. package/src/components/gallery/gallery.js +0 -1
  86. package/src/components/gallery/gallery.styles.js +1 -1
  87. package/src/components/gallery/gallery.test.js +5 -3
  88. package/src/components/gallery/index.js +2 -2
  89. package/src/components/hero/hero.component.js +66 -0
  90. package/src/components/hero/hero.js +6 -0
  91. package/src/components/hero/hero.stories.js +53 -0
  92. package/src/components/hero/hero.styles.js +46 -0
  93. package/src/components/hero/index.js +1 -0
  94. package/src/components/icon/icon.js +3 -2
  95. package/src/components/icon/icon.stories.js +2 -1
  96. package/src/components/icon/icon.styles.js +23 -21
  97. package/src/components/icon/icon.test.js +2 -3
  98. package/src/components/icon/index.js +1 -1
  99. package/src/components/loading/index.js +1 -1
  100. package/src/components/loading/loading.js +3 -2
  101. package/src/components/loading/loading.styles.js +1 -1
  102. package/src/components/loading/loading.test.js +0 -2
  103. package/src/components/logo-cloud/index.js +1 -0
  104. package/src/components/logo-cloud/logo-cloud.component.js +81 -0
  105. package/src/components/logo-cloud/logo-cloud.js +6 -0
  106. package/src/components/logo-cloud/logo-cloud.stories.js +107 -0
  107. package/src/components/logo-cloud/logo-cloud.styles.js +68 -0
  108. package/src/components/media-text/index.js +1 -0
  109. package/src/components/media-text/media-text.component.js +100 -0
  110. package/src/components/media-text/media-text.js +6 -0
  111. package/src/components/media-text/media-text.stories.js +69 -0
  112. package/src/components/media-text/media-text.styles.js +66 -0
  113. package/src/components/newsletter/index.js +1 -0
  114. package/src/components/newsletter/newsletter.component.js +101 -0
  115. package/src/components/newsletter/newsletter.js +6 -0
  116. package/src/components/newsletter/newsletter.stories.js +59 -0
  117. package/src/components/newsletter/newsletter.styles.js +89 -0
  118. package/src/components/notice/index.js +1 -1
  119. package/src/components/notice/notice.js +0 -1
  120. package/src/components/notice/notice.styles.js +7 -7
  121. package/src/components/notice/notice.test.js +15 -5
  122. package/src/components/pagination/index.js +1 -1
  123. package/src/components/pagination/pagination.stories.js +1 -3
  124. package/src/components/pagination/pagination.styles.js +1 -1
  125. package/src/components/pagination/pagination.test.js +9 -4
  126. package/src/components/pricing/index.js +1 -0
  127. package/src/components/pricing/pricing.component.js +119 -0
  128. package/src/components/pricing/pricing.js +6 -0
  129. package/src/components/pricing/pricing.stories.js +123 -0
  130. package/src/components/pricing/pricing.styles.js +135 -0
  131. package/src/components/sidebar/index.js +0 -2
  132. package/src/components/sidebar/sidebar.component.js +12 -10
  133. package/src/components/sidebar/sidebar.js +3 -3
  134. package/src/components/sidebar/sidebar.stories.js +0 -2
  135. package/src/components/sidebar/sidebar.styles.js +181 -186
  136. package/src/components/sidebar/sidebar.test.js +48 -13
  137. package/src/components/stats/index.js +1 -0
  138. package/src/components/stats/stats.component.js +73 -0
  139. package/src/components/stats/stats.js +6 -0
  140. package/src/components/stats/stats.stories.js +64 -0
  141. package/src/components/stats/stats.styles.js +66 -0
  142. package/src/components/tabs/index.js +2 -2
  143. package/src/components/tabs/internal/tabs-button.component.js +1 -1
  144. package/src/components/tabs/internal/tabs-button.js +0 -1
  145. package/src/components/tabs/tab.js +0 -1
  146. package/src/components/tabs/tabs.js +3 -2
  147. package/src/components/tabs/tabs.styles.js +84 -74
  148. package/src/components/testimonials/index.js +1 -0
  149. package/src/components/testimonials/testimonials.component.js +97 -0
  150. package/src/components/testimonials/testimonials.js +6 -0
  151. package/src/components/testimonials/testimonials.stories.js +78 -0
  152. package/src/components/testimonials/testimonials.styles.js +82 -0
  153. package/src/components/toast/index.js +0 -2
  154. package/src/components/toast/toast.component.js +1 -3
  155. package/src/components/toast/toast.js +10 -5
  156. package/src/components/toast/toast.stories.js +9 -5
  157. package/src/components/toast/toast.styles.js +199 -201
  158. package/src/components/toast/toast.test.js +38 -10
  159. package/src/components/tooltip/index.js +1 -1
  160. package/src/components/tooltip/tooltip.js +3 -2
  161. package/src/components/tooltip/tooltip.styles.js +3 -3
  162. package/src/components/tooltip/tooltip.test.js +10 -4
  163. package/src/css/base.css +8 -5
  164. package/src/css/colors.stories.js +27 -28
  165. package/src/css/elements/forms/input.css +9 -41
  166. package/src/css/elements/media/image.css +1 -1
  167. package/src/css/themes/todomap.css +1 -0
  168. package/src/css/tokens.stories.js +26 -21
  169. package/src/css/typography.css +1 -3
  170. package/src/css/util/focus-ring.css +30 -0
  171. package/src/css/util/index.css +1 -2
  172. package/src/lib/styles/focus-ring.styles.js +34 -0
  173. package/src/main.js +10 -1
  174. package/src/pages/agency.stories.js +164 -0
  175. package/src/pages/blog-post.stories.js +381 -0
  176. package/src/pages/saas-landing.stories.js +307 -0
  177. package/src/test-utils/assert-helpers.js +10 -8
  178. package/src/css/util/functions.css +0 -16
  179. package/src/css/util/mixins.css +0 -63
@@ -0,0 +1,130 @@
1
+ import { LitElement, html } from "lit";
2
+ import { unsafeHTML } from "lit/directives/unsafe-html.js";
3
+ import * as icons from "lucide-static";
4
+ import { featureListStyles } from "./feature-list.styles.js";
5
+ import "../icon/icon.js";
6
+
7
+ export class GrantCodesFeatureList extends LitElement {
8
+ static styles = [featureListStyles];
9
+
10
+ static properties = {
11
+ /**
12
+ * Optional section heading.
13
+ * @type {string}
14
+ */
15
+ title: { type: String },
16
+ /**
17
+ * Optional supporting text below the heading.
18
+ * @type {string}
19
+ */
20
+ subtitle: { type: String },
21
+ /**
22
+ * Feature items as a JSON string array: `[{"title":"...","description":"...","icon":"...","href":"..."}]`.
23
+ * @type {string}
24
+ */
25
+ items: { type: String },
26
+ /**
27
+ * Number of columns in the grid (1–4).
28
+ * @type {number}
29
+ */
30
+ columns: { type: Number },
31
+ };
32
+
33
+ constructor() {
34
+ super();
35
+ this.title = "";
36
+ this.subtitle = "";
37
+ this.items = "[]";
38
+ this.columns = 3;
39
+ }
40
+
41
+ get _items() {
42
+ try {
43
+ return JSON.parse(this.items);
44
+ } catch {
45
+ return [];
46
+ }
47
+ }
48
+
49
+ _iconSvg(name) {
50
+ if (!name) return null;
51
+ // Convert kebab-case to PascalCase for lucide-static lookup
52
+ const key = name
53
+ .split("-")
54
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
55
+ .join("");
56
+ // biome-ignore lint/performance/noDynamicNamespaceImportAccess: icon names are runtime strings; static imports are not feasible here
57
+ return icons[key] ?? null;
58
+ }
59
+
60
+ _renderIcon(name) {
61
+ const svg = this._iconSvg(name);
62
+ if (!svg) return null;
63
+ return html`<grantcodes-icon class="feature-list__icon" aria-hidden="true">${unsafeHTML(svg)}</grantcodes-icon>`;
64
+ }
65
+
66
+ render() {
67
+ const items = this._items;
68
+ return html`
69
+ <section class="feature-list">
70
+ <div class="feature-list__container">
71
+ ${
72
+ this.title
73
+ ? html`<h2 class="feature-list__title">${this.title}</h2>`
74
+ : null
75
+ }
76
+ ${
77
+ this.subtitle
78
+ ? html`<p class="feature-list__subtitle">${this.subtitle}</p>`
79
+ : null
80
+ }
81
+ <ul
82
+ class="feature-list__grid"
83
+ style="--columns: ${this.columns}"
84
+ role="list"
85
+ >
86
+ ${items.map(
87
+ (item) => html`
88
+ <li class="feature-list__item">
89
+ ${
90
+ item.href
91
+ ? html`
92
+ <a href=${item.href} class="feature-list__link">
93
+ ${this._renderIcon(item.icon)}
94
+ <h3 class="feature-list__item-title">
95
+ ${item.title}
96
+ </h3>
97
+ ${
98
+ item.description
99
+ ? html`<p class="feature-list__item-desc">
100
+ ${item.description}
101
+ </p>`
102
+ : null
103
+ }
104
+ </a>
105
+ `
106
+ : html`
107
+ <div class="feature-list__content">
108
+ ${this._renderIcon(item.icon)}
109
+ <h3 class="feature-list__item-title">
110
+ ${item.title}
111
+ </h3>
112
+ ${
113
+ item.description
114
+ ? html`<p class="feature-list__item-desc">
115
+ ${item.description}
116
+ </p>`
117
+ : null
118
+ }
119
+ </div>
120
+ `
121
+ }
122
+ </li>
123
+ `,
124
+ )}
125
+ </ul>
126
+ </div>
127
+ </section>
128
+ `;
129
+ }
130
+ }
@@ -0,0 +1,6 @@
1
+ import { GrantCodesFeatureList } from "./feature-list.component.js";
2
+
3
+ export * from "./feature-list.component.js";
4
+ export default GrantCodesFeatureList;
5
+
6
+ customElements.define("grantcodes-feature-list", GrantCodesFeatureList);
@@ -0,0 +1,117 @@
1
+ import { getStorybookHelpers } from "@wc-toolkit/storybook-helpers";
2
+ import "./feature-list.js";
3
+
4
+ const { events, args, argTypes } = getStorybookHelpers(
5
+ "grantcodes-feature-list",
6
+ );
7
+
8
+ const meta = {
9
+ title: "Blocks/FeatureList",
10
+ component: "grantcodes-feature-list",
11
+ args,
12
+ argTypes,
13
+ parameters: {
14
+ actions: {
15
+ handles: events,
16
+ },
17
+ layout: "fullscreen",
18
+ },
19
+ };
20
+
21
+ export default meta;
22
+
23
+ const sampleItems = JSON.stringify([
24
+ {
25
+ title: "Fast by default",
26
+ description: "Zero-runtime CSS with design tokens baked in at build time.",
27
+ icon: "⚡",
28
+ },
29
+ {
30
+ title: "Accessible",
31
+ description:
32
+ "WAI-ARIA compliant components with keyboard navigation support.",
33
+ icon: "♿",
34
+ },
35
+ {
36
+ title: "Themeable",
37
+ description: "Switch between themes without touching component code.",
38
+ icon: "🎨",
39
+ },
40
+ {
41
+ title: "Framework-agnostic",
42
+ description: "Standard web components that work anywhere.",
43
+ icon: "🔌",
44
+ },
45
+ {
46
+ title: "Tree-shakeable",
47
+ description: "Import only the components you use.",
48
+ icon: "🌲",
49
+ },
50
+ {
51
+ title: "Well documented",
52
+ description: "Storybook stories and JSDoc for every component.",
53
+ icon: "📚",
54
+ },
55
+ ]);
56
+
57
+ /**
58
+ * Default 3-column feature grid with heading and subtitle.
59
+ */
60
+ export const Default = {
61
+ args: {
62
+ title: "Everything you need",
63
+ subtitle: "Built for developers who care about quality.",
64
+ items: sampleItems,
65
+ columns: 3,
66
+ },
67
+ };
68
+
69
+ /**
70
+ * Two-column layout — useful for simpler feature sets.
71
+ */
72
+ export const TwoColumn = {
73
+ args: {
74
+ title: "Key features",
75
+ items: JSON.stringify([
76
+ {
77
+ title: "Design tokens",
78
+ description:
79
+ "Consistent spacing, colour, and typography across your entire UI.",
80
+ icon: "🎯",
81
+ },
82
+ {
83
+ title: "Lit-powered",
84
+ description: "Lightweight reactive web components built with Lit.",
85
+ icon: "🔥",
86
+ },
87
+ ]),
88
+ columns: 2,
89
+ },
90
+ };
91
+
92
+ /**
93
+ * Features with links on each item.
94
+ */
95
+ export const WithLinks = {
96
+ args: {
97
+ title: "Explore components",
98
+ items: JSON.stringify([
99
+ {
100
+ title: "Button",
101
+ description: "Primary, secondary, ghost variants.",
102
+ href: "/button",
103
+ },
104
+ {
105
+ title: "Card",
106
+ description: "Flexible content containers.",
107
+ href: "/card",
108
+ },
109
+ {
110
+ title: "Dialog",
111
+ description: "Accessible modal dialogs.",
112
+ href: "/dialog",
113
+ },
114
+ ]),
115
+ columns: 3,
116
+ },
117
+ };
@@ -0,0 +1,82 @@
1
+ import { css } from "lit";
2
+
3
+ export const featureListStyles = css`
4
+ :host {
5
+ display: block;
6
+ }
7
+
8
+ .feature-list {
9
+ padding-block: var(--g-theme-spacing-3xl);
10
+ padding-inline: var(--g-theme-spacing-md);
11
+ }
12
+
13
+ .feature-list__container {
14
+ max-width: 1200px;
15
+ margin: 0 auto;
16
+ }
17
+
18
+ .feature-list__title {
19
+ margin: 0 0 var(--g-theme-spacing-sm);
20
+ font: var(--g-theme-typography-headline-sm);
21
+ text-align: center;
22
+ color: var(--g-theme-color-content-default);
23
+ }
24
+
25
+ .feature-list__subtitle {
26
+ margin: 0 auto var(--g-theme-spacing-2xl);
27
+ font-size: var(--g-theme-typography-body-lg-font-size);
28
+ text-align: center;
29
+ color: var(--g-theme-color-content-secondary);
30
+ max-width: 55ch;
31
+ }
32
+
33
+ .feature-list__grid {
34
+ display: grid;
35
+ grid-template-columns: repeat(var(--columns, 3), 1fr);
36
+ gap: var(--g-theme-spacing-xl);
37
+ padding: 0;
38
+ margin: 0;
39
+ list-style: none;
40
+ }
41
+
42
+ @media (max-width: 768px) {
43
+ .feature-list__grid {
44
+ grid-template-columns: 1fr;
45
+ }
46
+ }
47
+
48
+ @media (min-width: 769px) and (max-width: 1024px) {
49
+ .feature-list__grid {
50
+ grid-template-columns: repeat(min(var(--columns, 3), 2), 1fr);
51
+ }
52
+ }
53
+
54
+ .feature-list__link,
55
+ .feature-list__content {
56
+ display: block;
57
+ text-decoration: none;
58
+ color: inherit;
59
+ }
60
+
61
+ .feature-list__link:hover .feature-list__item-title {
62
+ color: var(--g-theme-color-content-brand, #7c3aed);
63
+ }
64
+
65
+ .feature-list__icon {
66
+ display: block;
67
+ padding: var(--g-theme-spacing-md);
68
+ border-radius: 50%;
69
+ inline-size: fit-content;
70
+ margin-block-end: var(--g-theme-spacing-md);
71
+ color: var(--g-theme-color-content-brand, currentColor);
72
+ background-color: var(--g-theme-color-background-brand);
73
+ }
74
+
75
+ .feature-list__item-title {
76
+ font: var(--g-theme-typography-title-default);
77
+ }
78
+
79
+ .feature-list__item-desc {
80
+ color: var(--g-theme-color-content-secondary);
81
+ }
82
+ `;
@@ -0,0 +1 @@
1
+ export * from "./feature-list.js";
@@ -1,51 +1,50 @@
1
1
  import { css } from "lit";
2
2
 
3
3
  export const footerColumnStyles = css`
4
- :host {
5
- display: block;
6
- }
7
-
8
- .footer-column {
9
- display: flex;
10
- flex-direction: column;
11
- gap: 0.75rem;
12
- }
13
-
14
- ::slotted(h3) {
15
- font-size: var(--g-typography-font-size-16);
16
- color: var(--g-theme-color-content-default);
17
- margin: 0 0 0.5rem 0;
18
- font-weight: 600;
19
- }
20
-
21
- ::slotted(ul) {
22
- list-style: none;
23
- padding: 0;
24
- margin: 0;
25
- display: flex;
26
- flex-direction: column;
27
- gap: 0.5rem;
28
- }
29
-
30
- ::slotted(li) {
31
- margin: 0;
32
- }
33
-
34
- ::slotted(a) {
35
- color: var(--g-theme-color-content-secondary);
36
- text-decoration: none;
37
- transition: color 0.2s ease;
38
- }
39
-
40
- ::slotted(a:hover) {
41
- color: var(--g-theme-color-content-default);
42
- text-decoration: underline;
43
- }
44
-
45
- ::slotted(p) {
46
- margin: 0;
47
- color: var(--g-theme-color-content-secondary);
48
- font-size: var(--g-typography-font-size-14);
49
- line-height: 1.5;
50
- }
4
+ :host {
5
+ display: block;
6
+ }
7
+
8
+ .footer-column {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: var(--g-spacing-12);
12
+ }
13
+
14
+ ::slotted(h3) {
15
+ font-size: var(--g-typography-font-size-16);
16
+ color: var(--g-theme-color-content-default);
17
+ margin: 0 0 var(--g-theme-spacing-sm) 0;
18
+ font-weight: var(--g-typography-font-weight-600);
19
+ }
20
+
21
+ ::slotted(ul) {
22
+ list-style: none;
23
+ padding: 0;
24
+ margin: 0;
25
+ display: flex;
26
+ flex-direction: column;
27
+ gap: var(--g-theme-spacing-sm);
28
+ }
29
+
30
+ ::slotted(li) {
31
+ margin: 0;
32
+ }
33
+
34
+ ::slotted(a) {
35
+ color: var(--g-theme-color-content-secondary);
36
+ text-decoration: none;
37
+ transition: color 0.2s ease;
38
+ }
39
+
40
+ ::slotted(a:hover) {
41
+ color: var(--g-theme-color-content-default);
42
+ text-decoration: underline;
43
+ }
44
+
45
+ ::slotted(p) {
46
+ margin: 0;
47
+ color: var(--g-theme-color-content-secondary);
48
+ font: var(--g-typography-body-sm);
49
+ }
51
50
  `;
@@ -5,5 +5,9 @@ export * from "./footer.component.js";
5
5
  export * from "./footer-column.component.js";
6
6
  export default GrantCodesFooter;
7
7
 
8
- customElements.define("grantcodes-footer", GrantCodesFooter);
9
- customElements.define("grantcodes-footer-column", GrantCodesFooterColumn);
8
+ if (!customElements.get("grantcodes-footer")) {
9
+ customElements.define("grantcodes-footer", GrantCodesFooter);
10
+ }
11
+ if (!customElements.get("grantcodes-footer-column")) {
12
+ customElements.define("grantcodes-footer-column", GrantCodesFooterColumn);
13
+ }
@@ -18,8 +18,8 @@ export const footerStyles = css`
18
18
  }
19
19
 
20
20
  .footer__container {
21
- padding-block: 3rem 2rem;
22
- padding-inline: 1rem;
21
+ padding-block: var(--g-theme-spacing-2xl) var(--g-theme-spacing-xl);
22
+ padding-inline: var(--g-theme-spacing-md);
23
23
  max-inline-size: 1400px;
24
24
  margin-inline: auto;
25
25
  }
@@ -27,7 +27,7 @@ export const footerStyles = css`
27
27
  .footer__columns {
28
28
  display: grid;
29
29
  grid-template-columns: repeat(var(--footer-columns, 3), 1fr);
30
- gap: 2rem;
30
+ gap: var(--g-theme-spacing-xl);
31
31
  }
32
32
 
33
33
  /* Responsive grid using container queries */
@@ -45,14 +45,14 @@ export const footerStyles = css`
45
45
 
46
46
  /* Bottom section (copyright, social links, etc.) */
47
47
  .footer__bottom {
48
- margin-block-start: 2rem;
49
- padding-block-start: 2rem;
48
+ margin-block-start: var(--g-theme-spacing-xl);
49
+ padding-block-start: var(--g-theme-spacing-xl);
50
50
  border-block-start: 1px solid var(--g-theme-color-border-default);
51
51
  display: flex;
52
52
  flex-wrap: wrap;
53
53
  justify-content: space-between;
54
54
  align-items: center;
55
- gap: 1rem;
55
+ gap: var(--g-theme-spacing-md);
56
56
  }
57
57
 
58
58
  .footer__bottom:has(slot[name="bottom"]:empty) {
@@ -40,7 +40,10 @@ describe("Footer Component", () => {
40
40
 
41
41
  const columns = element.shadowRoot.querySelector(".footer__columns");
42
42
  const style = columns.getAttribute("style");
43
- assert.ok(style.includes("--footer-columns: 4"), "Should set columns CSS variable");
43
+ assert.ok(
44
+ style.includes("--footer-columns: 4"),
45
+ "Should set columns CSS variable",
46
+ );
44
47
  });
45
48
 
46
49
  it("should have default content slot", async () => {
@@ -72,7 +75,11 @@ describe("Footer Component", () => {
72
75
 
73
76
  for (const count of columnCounts) {
74
77
  element = await fixture("grantcodes-footer", { columns: count });
75
- assert.strictEqual(element.columns, count, `Should support ${count} columns`);
78
+ assert.strictEqual(
79
+ element.columns,
80
+ count,
81
+ `Should support ${count} columns`,
82
+ );
76
83
  cleanup(element);
77
84
  }
78
85
  });
@@ -103,5 +110,3 @@ describe("Footer Component", () => {
103
110
  );
104
111
  });
105
112
  });
106
-
107
-
@@ -1,2 +1,2 @@
1
- export { GrantCodesFooter } from "./footer.component.js";
1
+ export * from "./footer.js";
2
2
  export { GrantCodesFooterColumn } from "./footer-column.component.js";
@@ -57,9 +57,7 @@ export class GrantCodesFormField extends LitElement {
57
57
  firstUpdated() {
58
58
  // Initialize inputs and nested fields if not already set
59
59
  if (!this.inputElements) {
60
- this.inputElements = this.querySelectorAll(
61
- "input, select, textarea",
62
- );
60
+ this.inputElements = this.querySelectorAll("input, select, textarea");
63
61
  }
64
62
  if (!this.nestedFields) {
65
63
  this.nestedFields = this.querySelectorAll("grantcodes-form-field");
@@ -4,4 +4,3 @@ export * from "./form-field.component.js";
4
4
  export default GrantCodesFormField;
5
5
 
6
6
  customElements.define("grantcodes-form-field", GrantCodesFormField);
7
-
@@ -1,47 +1,45 @@
1
1
  import { css } from "lit";
2
2
 
3
3
  export const formFieldStyles = css`
4
+ .form-field {
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: var(--g-theme-spacing-xs);
8
+ padding: 0;
9
+ margin: 0;
10
+ border: none;
11
+ }
4
12
 
5
- .form-field {
6
- display: flex;
7
- flex-direction: column;
8
- gap: 0.25rem;
9
- padding: 0;
10
- margin: 0;
11
- border: none;
12
- }
13
-
14
- .form-field label,
15
- .form-field slot {
16
- display: flex;
17
- flex-direction: column;
18
- gap: inherit;
19
- }
13
+ .form-field label,
14
+ .form-field slot {
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: inherit;
18
+ }
20
19
 
21
- .form-field--inline label {
22
- flex-direction: row-reverse;
23
- align-items: center;
24
- justify-content: flex-end;
25
- }
20
+ .form-field--inline label {
21
+ flex-direction: row-reverse;
22
+ align-items: center;
23
+ justify-content: flex-end;
24
+ }
26
25
 
27
- .form-field__label {
28
- margin: 0;
29
- padding: 0;
26
+ .form-field__label {
27
+ margin: 0;
28
+ padding: 0;
30
29
 
31
- &:where(legend) {
32
- margin-bottom: 0.25rem;
30
+ &:where(legend) {
31
+ margin-bottom: var(--g-theme-spacing-xs);
32
+ }
33
33
  }
34
- }
35
34
 
36
- .form-field__help {
37
- font-size: var(--g-typography-font-size-14);
38
- opacity: 0.7;
39
- }
40
-
41
- .form-field__error {
42
- margin: 0;
43
- font-size: var(--g-typography-font-size-14);
44
- color: var(--g-color-utility-red-700);
45
- }
35
+ .form-field__help {
36
+ font-size: var(--g-theme-typography-body-sm-font-size);
37
+ opacity: 0.7;
38
+ }
46
39
 
47
- `;
40
+ .form-field__error {
41
+ margin: 0;
42
+ font-size: var(--g-theme-typography-body-sm-font-size);
43
+ color: var(--g-color-utility-red-700);
44
+ }
45
+ `;
@@ -23,7 +23,11 @@ describe("Form Field Component", () => {
23
23
 
24
24
  const labelElement = element.shadowRoot.querySelector(".form-field__label");
25
25
  assert.ok(labelElement, "Label element should exist");
26
- assert.strictEqual(labelElement.textContent, "Username", "Label text should match");
26
+ assert.strictEqual(
27
+ labelElement.textContent,
28
+ "Username",
29
+ "Label text should match",
30
+ );
27
31
  });
28
32
 
29
33
  it("should display error message when error is set", async () => {
@@ -70,7 +74,10 @@ describe("Form Field Component", () => {
70
74
  });
71
75
 
72
76
  const helpElement = element.shadowRoot.querySelector(".form-field__help");
73
- assert.ok(!helpElement, "Help element should not exist when help is not provided");
77
+ assert.ok(
78
+ !helpElement,
79
+ "Help element should not exist when help is not provided",
80
+ );
74
81
  });
75
82
 
76
83
  it("should generate unique IDs", async () => {
@@ -114,5 +121,3 @@ describe("Form Field Component", () => {
114
121
  assert.ok(slot, "Slot should exist for input elements");
115
122
  });
116
123
  });
117
-
118
-
@@ -1 +1 @@
1
- export * from "./form-field";
1
+ export * from "./form-field.js";
@@ -4,4 +4,3 @@ export * from "./gallery-image.component.js";
4
4
  export default GrantCodesGalleryImage;
5
5
 
6
6
  customElements.define("grantcodes-gallery-image", GrantCodesGalleryImage);
7
-
@@ -4,4 +4,3 @@ export * from "./gallery.component.js";
4
4
  export default GrantCodesGallery;
5
5
 
6
6
  customElements.define("grantcodes-gallery", GrantCodesGallery);
7
-
@@ -53,4 +53,4 @@ export const galleryStyles = css`
53
53
  color: white;
54
54
  }
55
55
 
56
- `;
56
+ `;