@grantcodes/ui 2.0.0 → 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 (181) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/custom-elements.json +1926 -191
  3. package/package.json +7 -6
  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/grantcodes.css +3 -3
  168. package/src/css/themes/todomap.css +3 -2
  169. package/src/css/themes/wireframe.css +2 -2
  170. package/src/css/tokens.stories.js +26 -21
  171. package/src/css/typography.css +1 -3
  172. package/src/css/util/focus-ring.css +30 -0
  173. package/src/css/util/index.css +1 -2
  174. package/src/lib/styles/focus-ring.styles.js +34 -0
  175. package/src/main.js +10 -1
  176. package/src/pages/agency.stories.js +164 -0
  177. package/src/pages/blog-post.stories.js +381 -0
  178. package/src/pages/saas-landing.stories.js +307 -0
  179. package/src/test-utils/assert-helpers.js +10 -8
  180. package/src/css/util/functions.css +0 -16
  181. package/src/css/util/mixins.css +0 -63
@@ -6,37 +6,37 @@ export const avatarStyles = css`
6
6
  *,
7
7
  *::before,
8
8
  *::after {
9
- box-sizing: border-box;
9
+ box-sizing: border-box;
10
10
  }
11
11
 
12
12
  :host {
13
- display: block;
13
+ display: block;
14
14
  }
15
15
 
16
16
  .avatar {
17
- display: flex;
18
- align-items: center;
19
- justify-content: center;
20
- width: 3rem;
21
- height: 3rem;
22
- border-radius: 50%;
23
- overflow: hidden;
24
- background-color: var(--g-color-brand-purple-200);
25
- color: var(--g-color-brand-purple-900);
26
- text-align: center;
27
- font-size: 1.2rem;
28
- font-weight: bold;
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ inline-size: var(--g-theme-spacing-2xl);
21
+ block-size: var(--g-theme-spacing-2xl);
22
+ border-radius: 50%;
23
+ overflow: hidden;
24
+ background-color: var(--g-color-brand-purple-200);
25
+ color: var(--g-color-brand-purple-900);
26
+ text-align: center;
27
+ font-size: var(--g-theme-typography-title-sm-font-size);
28
+ font-weight: var(--g-theme-typography-label-default-font-weight);
29
29
  }
30
30
 
31
31
  .avatar__image {
32
- width: 100%;
33
- height: 100%;
34
- object-fit: cover;
35
- object-position: center;
32
+ inline-size: 100%;
33
+ block-size: 100%;
34
+ object-fit: cover;
35
+ object-position: center;
36
36
  }
37
37
 
38
38
  .avatar__fallback {
39
- line-height: 1;
39
+ line-height: 1;
40
40
  }
41
41
 
42
42
  `;
@@ -21,7 +21,8 @@ describe("Avatar Component", () => {
21
21
  name: "John Doe",
22
22
  });
23
23
 
24
- const initialsElement = element.shadowRoot.querySelector(".avatar__initials");
24
+ const initialsElement =
25
+ element.shadowRoot.querySelector(".avatar__initials");
25
26
  assert.ok(initialsElement, "Initials element should exist");
26
27
  assert.strictEqual(
27
28
  initialsElement.textContent,
@@ -35,7 +36,8 @@ describe("Avatar Component", () => {
35
36
  name: "John",
36
37
  });
37
38
 
38
- const initialsElement = element.shadowRoot.querySelector(".avatar__initials");
39
+ const initialsElement =
40
+ element.shadowRoot.querySelector(".avatar__initials");
39
41
  assert.strictEqual(
40
42
  initialsElement.textContent,
41
43
  "J",
@@ -81,5 +83,3 @@ describe("Avatar Component", () => {
81
83
  }
82
84
  });
83
85
  });
84
-
85
-
@@ -1,13 +1 @@
1
- export * from "./avatar";
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
1
+ export * from "./avatar.js";
@@ -4,5 +4,3 @@ export * from "./badge.component.js";
4
4
  export default GrantCodesBadge;
5
5
 
6
6
  customElements.define("grantcodes-badge", GrantCodesBadge);
7
-
8
-
@@ -1,94 +1,91 @@
1
1
  import { css } from "lit";
2
2
 
3
3
  export const badgeStyles = css`
4
- *,
5
- *::before,
6
- *::after {
7
- box-sizing: border-box;
8
- }
4
+ *,
5
+ *::before,
6
+ *::after {
7
+ box-sizing: border-box;
8
+ }
9
9
 
10
- :host {
11
- display: inline-block;
12
- }
10
+ :host {
11
+ display: inline-block;
12
+ }
13
13
 
14
- .badge {
15
- display: inline-flex;
16
- align-items: center;
17
- gap: 0.375rem;
18
- padding-inline: 0.625em;
19
- padding-block: 0.375em;
20
- border-radius: var(--g-theme-border-radius-md, 0.375rem);
21
- font-size: var(--g-typography-font-size-14);
22
- font-weight: 500;
23
- line-height: 1;
24
- white-space: nowrap;
25
- border-width: 1px;
26
- border-style: solid;
27
- transition: all 0.2s ease;
28
- }
14
+ .badge {
15
+ display: inline-flex;
16
+ align-items: center;
17
+ gap: var(--g-theme-spacing-xs);
18
+ padding-inline: 0.625em;
19
+ padding-block: 0.375em;
20
+ border-radius: var(--g-theme-border-radius-md, 0.375rem);
21
+ font: var(--g-typography-font-label-sm);
22
+ line-height: 1;
23
+ white-space: nowrap;
24
+ border-width: 1px;
25
+ border-style: solid;
26
+ transition: all 0.2s ease;
27
+ }
29
28
 
30
-
29
+ /* Soft style variants */
30
+ .badge--primary {
31
+ background-color: color-mix(
32
+ in srgb,
33
+ var(--g-color-brand-purple-500) 15%,
34
+ transparent
35
+ );
36
+ color: var(--g-color-brand-purple-700);
37
+ border-color: transparent;
38
+ }
31
39
 
32
- /* Soft style variants */
33
- .badge--primary {
34
- background-color: color-mix(
35
- in srgb,
36
- var(--g-color-brand-purple-500) 15%,
37
- transparent
38
- );
39
- color: var(--g-color-brand-purple-700);
40
- border-color: transparent;
41
- }
40
+ .badge--success {
41
+ background-color: color-mix(
42
+ in srgb,
43
+ var(--g-color-utility-green-500) 15%,
44
+ transparent
45
+ );
46
+ color: var(--g-color-utility-green-700);
47
+ border-color: transparent;
48
+ }
42
49
 
43
- .badge--success {
44
- background-color: color-mix(
45
- in srgb,
46
- var(--g-color-utility-green-500) 15%,
47
- transparent
48
- );
49
- color: var(--g-color-utility-green-700);
50
- border-color: transparent;
51
- }
50
+ .badge--warning {
51
+ background-color: color-mix(
52
+ in srgb,
53
+ var(--g-color-utility-yellow-500) 15%,
54
+ transparent
55
+ );
56
+ color: var(--g-color-utility-yellow-700);
57
+ border-color: transparent;
58
+ }
52
59
 
53
- .badge--warning {
54
- background-color: color-mix(
55
- in srgb,
56
- var(--g-color-utility-yellow-500) 15%,
57
- transparent
58
- );
59
- color: var(--g-color-utility-yellow-700);
60
- border-color: transparent;
61
- }
60
+ .badge--error {
61
+ background-color: color-mix(
62
+ in srgb,
63
+ var(--g-color-utility-red-500) 15%,
64
+ transparent
65
+ );
66
+ color: var(--g-color-utility-red-700);
67
+ border-color: transparent;
68
+ }
62
69
 
63
- .badge--error {
64
- background-color: color-mix(
65
- in srgb,
66
- var(--g-color-utility-red-500) 15%,
67
- transparent
68
- );
69
- color: var(--g-color-utility-red-700);
70
- border-color: transparent;
71
- }
70
+ .badge--info {
71
+ background-color: color-mix(
72
+ in srgb,
73
+ var(--g-color-utility-blue-500) 15%,
74
+ transparent
75
+ );
76
+ color: var(--g-color-utility-blue-700);
77
+ border-color: transparent;
78
+ }
72
79
 
73
- .badge--info {
74
- background-color: color-mix(
75
- in srgb,
76
- var(--g-color-utility-blue-500) 15%,
77
- transparent
78
- );
79
- color: var(--g-color-utility-blue-700);
80
- border-color: transparent;
81
- }
80
+ .badge--neutral {
81
+ background-color: var(--g-color-brand-purple-100);
82
+ color: var(--g-color-brand-purple-800);
83
+ border-color: transparent;
84
+ }
82
85
 
83
- .badge--neutral {
84
- background-color: var(--g-color-brand-purple-100);
85
- color: var(--g-color-brand-purple-800);
86
- border-color: transparent;
87
- }
88
-
89
- .badge__content {
90
- display: inline-flex;
91
- align-items: center;
92
- gap: 0.25em;
93
- }
86
+ .badge__content {
87
+ display: inline-flex;
88
+ align-items: center;
89
+ gap: 0.25em;
90
+ }
94
91
  `;
@@ -18,7 +18,11 @@ describe("Badge Component", () => {
18
18
 
19
19
  it("should have neutral variant by default", async () => {
20
20
  element = await fixture("grantcodes-badge");
21
- assert.strictEqual(element.variant, "neutral", "Default variant should be neutral");
21
+ assert.strictEqual(
22
+ element.variant,
23
+ "neutral",
24
+ "Default variant should be neutral",
25
+ );
22
26
  });
23
27
 
24
28
  // it("should have outline style by default", async () => {
@@ -41,11 +45,22 @@ describe("Badge Component", () => {
41
45
 
42
46
  await element.updateComplete;
43
47
 
44
- assert.strictEqual(element.textContent, "Badge Text", "Slotted content should be rendered");
48
+ assert.strictEqual(
49
+ element.textContent,
50
+ "Badge Text",
51
+ "Slotted content should be rendered",
52
+ );
45
53
  });
46
54
 
47
55
  it("should support all variant types", async () => {
48
- const variants = ["primary", "success", "warning", "error", "info", "neutral"];
56
+ const variants = [
57
+ "primary",
58
+ "success",
59
+ "warning",
60
+ "error",
61
+ "info",
62
+ "neutral",
63
+ ];
49
64
 
50
65
  for (const variant of variants) {
51
66
  element = await fixture("grantcodes-badge", { variant });
@@ -66,5 +81,3 @@ describe("Badge Component", () => {
66
81
  // }
67
82
  // });
68
83
  });
69
-
70
-
@@ -1,3 +1 @@
1
1
  export * from "./badge.js";
2
-
3
-
@@ -24,7 +24,7 @@ export class GrantCodesBreadcrumb extends LitElement {
24
24
  this.style.setProperty("--component-breadcrumb-separator", `'${value}'`);
25
25
 
26
26
  // Track slot content changes to update separators
27
- const slot = this.renderRoot.querySelector('slot:not([name])');
27
+ const slot = this.renderRoot.querySelector("slot:not([name])");
28
28
  if (slot) {
29
29
  slot.addEventListener("slotchange", () => this._updateSeparators());
30
30
  this._updateSeparators();
@@ -45,11 +45,11 @@ export class GrantCodesBreadcrumb extends LitElement {
45
45
  }
46
46
 
47
47
  _updateSeparators() {
48
- const slot = this.renderRoot.querySelector('slot:not([name])');
48
+ const slot = this.renderRoot.querySelector("slot:not([name])");
49
49
  if (!slot) return;
50
- const items = slot.assignedElements({ flatten: true }).filter((el) =>
51
- el.tagName === "GRANTCODES-BREADCRUMB-ITEM",
52
- );
50
+ const items = slot
51
+ .assignedElements({ flatten: true })
52
+ .filter((el) => el.tagName === "GRANTCODES-BREADCRUMB-ITEM");
53
53
  items.forEach((el, index) => {
54
54
  if (index < items.length - 1) {
55
55
  el.setAttribute("data-has-separator", "");
@@ -95,9 +95,10 @@ export class GrantCodesBreadcrumbItem extends LitElement {
95
95
  }
96
96
 
97
97
  render() {
98
- const content = this.href && !this.current
99
- ? html`<a href="${this.href}" class="breadcrumb__link"><slot></slot></a>`
100
- : html`<span class="breadcrumb__text"><slot></slot></span>`;
98
+ const content =
99
+ this.href && !this.current
100
+ ? html`<a href="${this.href}" class="breadcrumb__link focus-ring"><slot></slot></a>`
101
+ : html`<span class="breadcrumb__text"><slot></slot></span>`;
101
102
 
102
103
  return html`
103
104
  <li class="breadcrumb__item" ?data-current=${this.current}>
@@ -106,5 +107,3 @@ export class GrantCodesBreadcrumbItem extends LitElement {
106
107
  `;
107
108
  }
108
109
  }
109
-
110
-
@@ -6,7 +6,9 @@ import {
6
6
  export * from "./breadcrumb.component.js";
7
7
  export default GrantCodesBreadcrumb;
8
8
 
9
- customElements.define("grantcodes-breadcrumb", GrantCodesBreadcrumb);
10
- customElements.define("grantcodes-breadcrumb-item", GrantCodesBreadcrumbItem);
11
-
12
-
9
+ if (!customElements.get("grantcodes-breadcrumb")) {
10
+ customElements.define("grantcodes-breadcrumb", GrantCodesBreadcrumb);
11
+ }
12
+ if (!customElements.get("grantcodes-breadcrumb-item")) {
13
+ customElements.define("grantcodes-breadcrumb-item", GrantCodesBreadcrumbItem);
14
+ }
@@ -1,96 +1,92 @@
1
1
  import { css } from "lit";
2
+ import { focusRingStyles } from "../../lib/styles/focus-ring.styles.js";
2
3
 
3
4
  export const breadcrumbStyles = css`
4
- *,
5
+ ${focusRingStyles}
6
+
7
+ *,
5
8
  *::before,
6
9
  *::after {
7
- box-sizing: border-box;
8
- }
9
-
10
- :host {
11
- display: block;
12
- }
13
-
14
- .breadcrumb {
15
- display: block;
16
- }
17
-
18
- .breadcrumb__list {
19
- display: flex;
20
- flex-wrap: wrap;
21
- align-items: center;
22
- gap: 0.5rem;
23
- margin: 0;
24
- padding: 0;
25
- list-style: none;
26
- }
27
-
28
- .breadcrumb__item {
29
- display: inline-flex;
30
- align-items: center;
31
- gap: 0.5rem;
32
- font-size: var(--g-typography-font-size-14);
33
- color: var(--g-color-brand-purple-700);
34
- }
35
-
36
- /* Separator using ::after pseudo-element; driven by parent via data-has-separator */
37
- :host([data-has-separator]) .breadcrumb__item::after {
38
- content: var(--component-breadcrumb-separator, "/");
39
- display: inline-block;
40
- color: var(--g-color-brand-purple-400);
41
- font-weight: 300;
42
- user-select: none;
43
- pointer-events: none;
44
- }
45
-
46
- /* Current page styling */
47
- .breadcrumb__item[data-current] {
48
- font-weight: 600;
49
- color: var(--color-base-primary-900);
50
- }
51
-
52
- .breadcrumb__item[data-current]::after {
53
- display: none;
54
- }
55
-
56
- .breadcrumb__link {
57
- color: var(--g-color-brand-purple-600);
58
- text-decoration: none;
59
- transition: color 0.2s ease;
60
- border-radius: var(--g-theme-border-radius-md, 0.25rem);
61
- padding-inline: 0.25em;
62
- padding-block: 0.125em;
63
- margin-inline: -0.25em;
64
- margin-block: -0.125em;
65
- }
66
-
67
- .breadcrumb__link:hover {
68
- color: var(--g-color-brand-purple-700);
69
- text-decoration: underline;
70
- }
71
-
72
- .breadcrumb__link:focus-visible {
73
- outline: 2px solid var(--component-focus-ring-color, rgba(106, 91, 197, 0.4));
74
- outline-offset: 2px;
75
- }
76
-
77
- .breadcrumb__text {
78
- display: inline-block;
79
- }
80
-
81
- /* Responsive: Show only last few items on small screens */
82
- @media (max-width: 640px) {
83
- .breadcrumb__item:not(:last-child):not(:nth-last-child(2)) {
84
- display: none;
85
- }
86
-
87
- .breadcrumb__item:nth-last-child(2)::before {
88
- content: "...";
89
- display: inline-block;
90
- margin-inline-end: 0.5rem;
91
- color: var(--g-color-brand-purple-400);
92
- }
93
- }
10
+ box-sizing: border-box;
11
+ }
12
+
13
+ :host {
14
+ display: block;
15
+ }
16
+
17
+ .breadcrumb {
18
+ display: block;
19
+ }
20
+
21
+ .breadcrumb__list {
22
+ display: flex;
23
+ flex-wrap: wrap;
24
+ align-items: center;
25
+ gap: var(--g-theme-spacing-sm);
26
+ margin: 0;
27
+ padding: 0;
28
+ list-style: none;
29
+ }
30
+
31
+ .breadcrumb__item {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ gap: var(--g-theme-spacing-sm);
35
+ font-size: var(--g-typography-font-size-14);
36
+ color: var(--g-color-brand-purple-700);
37
+ }
38
+
39
+ /* Separator using ::after pseudo-element; driven by parent via data-has-separator */
40
+ :host([data-has-separator]) .breadcrumb__item::after {
41
+ content: var(--component-breadcrumb-separator, "/");
42
+ display: inline-block;
43
+ color: var(--g-color-brand-purple-400);
44
+ font-weight: var(--g-typography-font-weight-400);
45
+ user-select: none;
46
+ pointer-events: none;
47
+ }
48
+
49
+ /* Current page styling */
50
+ .breadcrumb__item[data-current] {
51
+ font-weight: var(--g-typography-font-weight-600);
52
+ color: var(--color-base-primary-900);
53
+ }
54
+
55
+ .breadcrumb__item[data-current]::after {
56
+ display: none;
57
+ }
58
+
59
+ .breadcrumb__link {
60
+ color: var(--g-color-brand-purple-600);
61
+ text-decoration: none;
62
+ transition: color 0.2s ease;
63
+ border-radius: var(--g-theme-border-radius-md, 0.25rem);
64
+ padding-inline: 0.25em;
65
+ padding-block: 0.125em;
66
+ margin-inline: -0.25em;
67
+ margin-block: -0.125em;
68
+ }
69
+
70
+ .breadcrumb__link:hover {
71
+ color: var(--g-color-brand-purple-700);
72
+ text-decoration: underline;
73
+ }
74
+
75
+ .breadcrumb__text {
76
+ display: inline-block;
77
+ }
78
+
79
+ /* Responsive: Show only last few items on small screens */
80
+ @media (max-width: 640px) {
81
+ .breadcrumb__item:not(:last-child):not(:nth-last-child(2)) {
82
+ display: none;
83
+ }
84
+
85
+ .breadcrumb__item:nth-last-child(2)::before {
86
+ content: "...";
87
+ display: inline-block;
88
+ margin-inline-end: 0.5rem;
89
+ color: var(--g-color-brand-purple-400);
90
+ }
91
+ }
94
92
  `;
95
-
96
-
@@ -69,7 +69,11 @@ describe("Breadcrumb Item Component", () => {
69
69
 
70
70
  const link = element.shadowRoot.querySelector(".breadcrumb__link");
71
71
  assert.ok(link, "Link should exist");
72
- assert.strictEqual(link.getAttribute("href"), "/test", "Href should be set");
72
+ assert.strictEqual(
73
+ link.getAttribute("href"),
74
+ "/test",
75
+ "Href should be set",
76
+ );
73
77
  });
74
78
 
75
79
  it("should render as span when no href", async () => {
@@ -127,12 +131,20 @@ describe("Breadcrumb Item Component", () => {
127
131
 
128
132
  await element.updateComplete;
129
133
 
130
- assert.strictEqual(element.textContent, "Home", "Slotted content should be rendered");
134
+ assert.strictEqual(
135
+ element.textContent,
136
+ "Home",
137
+ "Slotted content should be rendered",
138
+ );
131
139
  });
132
140
 
133
141
  it("should not be current by default", async () => {
134
142
  element = await fixture("grantcodes-breadcrumb-item");
135
- assert.strictEqual(element.current, false, "Should not be current by default");
143
+ assert.strictEqual(
144
+ element.current,
145
+ false,
146
+ "Should not be current by default",
147
+ );
136
148
  });
137
149
 
138
150
  it("should have empty href by default", async () => {
@@ -140,5 +152,3 @@ describe("Breadcrumb Item Component", () => {
140
152
  assert.strictEqual(element.href, "", "Href should be empty by default");
141
153
  });
142
154
  });
143
-
144
-
@@ -1,3 +1 @@
1
1
  export * from "./breadcrumb.js";
2
-
3
-
@@ -40,7 +40,7 @@ export class GrantCodesButton extends LitElement {
40
40
  if (isLink) {
41
41
  return html`
42
42
  <${tag}
43
- class="button"
43
+ class="button focus-ring"
44
44
  href=${this.href}
45
45
  ?disabled=${this.disabled}
46
46
  >
@@ -51,7 +51,7 @@ export class GrantCodesButton extends LitElement {
51
51
 
52
52
  return html`
53
53
  <${tag}
54
- class="button"
54
+ class="button focus-ring"
55
55
  type=${this.type}
56
56
  name=${this.name ?? ""}
57
57
  value=${this.value ?? ""}