@phcdevworks/spectre-ui 2.1.0 → 2.3.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,62 @@ reflects package releases published to npm.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.3.0] - 2026-06-19
10
+
11
+ Release Title: App Shell Recipe Expansion
12
+
13
+ Contract change type: additive
14
+
15
+ ### Added
16
+
17
+ - **Stack `basis` option**: Added a `basis` option (`sidebar`) to
18
+ `getStackClasses`, mapping a flex child to a fixed width via the new
19
+ `--sp-layout-sidebar-width` token (`@phcdevworks/spectre-tokens@3.1.0`),
20
+ distinct from the default `flex: 1` auto-sizing behavior.
21
+ - **Container `maxWidth` option**: Added a `maxWidth` option (`prose`) to
22
+ `getContainerClasses`, mapping to the new
23
+ `--sp-layout-container-max-width-prose` token, distinct from the existing
24
+ page-level `--sp-layout-container-max-width`.
25
+ - **Sidebar recipe**: Added `getSidebarClasses`, `getSidebarLinkClasses`, and
26
+ `getSidebarBackdropClasses`, wrapping new `.sp-sidebar` / `.sp-sidebar__link`
27
+ / `.sp-sidebar-backdrop` component classes in `src/styles/components.css`.
28
+ Reuses the existing `component.nav` token roles (bg/text/link/border) as
29
+ the vertical counterpart to `SpNav`'s top-bar pattern; sidebar width comes
30
+ from the same `--sp-layout-sidebar-width` token used by Stack's `basis`
31
+ option. Below `breakpoints.md`, the sidebar is an off-canvas drawer
32
+ (`transform: translateX(-100%)`) with a backdrop, toggled via a
33
+ `data-sidebar-open="true"` attribute contract — this is the first recipe
34
+ family with an interactive-state CSS contract. This package owns the CSS
35
+ reaction only; toggle behavior, click handling, and state management
36
+ belong to the consuming adapter.
37
+ - **Footer recipe**: Added `getFooterClasses`, wrapping a new `.sp-footer`
38
+ component class in `src/styles/components.css`, modeled on `SpNav`'s
39
+ `bordered`/`fullWidth` option shape (no `sticky`, per the deferred-unless-
40
+ needed decision in `TODO.md`).
41
+
42
+ This is Phase 4d in `TODO.md` — real downstream need surfaced in
43
+ `docs-phcdevworks-com`'s app shell (top bar + sidebar + main content).
44
+
45
+ ## [2.2.0] - 2026-06-18
46
+
47
+ Release Title: Grid Recipe Expansion
48
+
49
+ Contract change type: additive
50
+
51
+ ### Added
52
+
53
+ - **Grid Recipe**: Added `getGridClasses` recipe wrapping new token-backed
54
+ `.sp-grid` / `.sp-grid-cols-{1,2,3,4,6,12}` utility classes in
55
+ `src/styles/utilities.css`. Options: `columns` (`1 | 2 | 3 | 4 | 6 | 12`)
56
+ and `gap` (`sm | md | lg`, reusing the `layout.stack.gap` scale). Each
57
+ column count is responsive by convention: 1 column below `breakpoints.md`,
58
+ half the target count at `md`, full target count at `breakpoints.lg`+. This
59
+ is the first recipe family in the package to use `@media`; the breakpoint
60
+ values are written as literals (CSS forbids `var()` inside media feature
61
+ queries) and `tests/token-drift.test.ts` now asserts any `@media (...)`
62
+ literal must match a published `--sp-breakpoint-*` token value. This is
63
+ Phase 4c (v1) in `TODO.md`.
64
+
9
65
  ## [2.1.0] - 2026-06-17
10
66
 
11
67
  Release Title: Layout Recipe Expansion
package/README.md CHANGED
@@ -274,9 +274,12 @@ All options are optional and fall back to sensible defaults.
274
274
  | Tooltip | `getTooltipClasses` | placement: `top` `bottom` `left` `right` | — | `visible` |
275
275
  | Dropdown | `getDropdownClasses` | menu placement: `bottom-start` `bottom-end` `top-start` `top-end` | — | `fullWidth`, item: `active` `disabled` |
276
276
  | Modal | `getModalClasses` | — | — | `open` `fullWidth` |
277
- | Container | `getContainerClasses` | | — | — |
278
- | Stack | `getStackClasses` | direction: `vertical` `horizontal` | — | — |
277
+ | Container | `getContainerClasses` | maxWidth: `prose` | — | — |
278
+ | Stack | `getStackClasses` | direction: `vertical` `horizontal`, basis: `sidebar` | — | — |
279
279
  | Section | `getSectionClasses` | — | — | — |
280
+ | Grid | `getGridClasses` | columns: `1` `2` `3` `4` `6` `12` | gap: `sm` `md` `lg` | — |
281
+ | Sidebar | `getSidebarClasses` | — | — | `bordered` |
282
+ | Footer | `getFooterClasses` | — | — | `bordered` `fullWidth` |
280
283
 
281
284
  Each recipe family also exports sub-element helpers for its structural parts
282
285
  (labels, wrappers, sub-containers, text elements). See the full list below.
@@ -303,6 +306,8 @@ Root recipe functions:
303
306
  - `getCardClasses`
304
307
  - `getContainerClasses`
305
308
  - `getDropdownClasses`
309
+ - `getFooterClasses`
310
+ - `getGridClasses`
306
311
  - `getIconBoxClasses`
307
312
  - `getInputClasses`
308
313
  - `getModalClasses`
@@ -310,6 +315,7 @@ Root recipe functions:
310
315
  - `getPricingCardClasses`
311
316
  - `getRatingClasses`
312
317
  - `getSectionClasses`
318
+ - `getSidebarClasses`
313
319
  - `getSpinnerClasses`
314
320
  - `getStackClasses`
315
321
  - `getTagClasses`
@@ -335,6 +341,8 @@ Root recipe helper functions:
335
341
  - `getRatingStarClasses`
336
342
  - `getRatingStarsClasses`
337
343
  - `getRatingTextClasses`
344
+ - `getSidebarBackdropClasses`
345
+ - `getSidebarLinkClasses`
338
346
  - `getTestimonialAuthorClasses`
339
347
  - `getTestimonialAuthorInfoClasses`
340
348
  - `getTestimonialAuthorNameClasses`
@@ -376,6 +384,28 @@ README documentation omits manifest-declared exports, when export snapshots
376
384
  drift, when Tailwind artifacts drift, or when CSS contract coverage no longer
377
385
  matches the declared surface.
378
386
 
387
+ ### Sidebar interactive-state contract
388
+
389
+ `getSidebarClasses` is the first recipe family with an interactive-state CSS
390
+ contract. Below `breakpoints.md` (768px), `.sp-sidebar` renders off-canvas
391
+ (`transform: translateX(-100%)`). This package owns only the CSS reaction to
392
+ that state — it does not own toggle behavior, click handlers, or open/closed
393
+ state management.
394
+
395
+ Consumers (typically a framework adapter) toggle the sidebar by setting a
396
+ `data-sidebar-open="true"` attribute on an ancestor element wrapping
397
+ `.sp-sidebar` and `.sp-sidebar-backdrop` (from `getSidebarBackdropClasses`):
398
+
399
+ - `[data-sidebar-open="true"] .sp-sidebar` slides the sidebar into view
400
+ (`transform: translateX(0)`).
401
+ - `[data-sidebar-open="true"] .sp-sidebar-backdrop` shows the backdrop
402
+ overlay (`display: block`).
403
+ - Above `breakpoints.md`, the sidebar docks inline and the backdrop is
404
+ always hidden, regardless of the `data-sidebar-open` value.
405
+
406
+ Adapters own the hamburger/toggle control, click handling, and SSR-safe
407
+ initial closed state.
408
+
379
409
  ## Downstream boundaries
380
410
 
381
411
  Downstream packages should never redefine locally:
package/dist/base.css CHANGED
@@ -5,6 +5,10 @@
5
5
  --sp-surface-overlay: rgba(0, 0, 0, 0.6);
6
6
  --sp-surface-subtle: #eef1f6;
7
7
  --sp-surface-hero: linear-gradient(135deg, #5b6ee1 0%, #6f3fd7 100%);
8
+ --sp-surface-hover: #eef1f6;
9
+ --sp-surface-selected: #f0f9ff;
10
+ --sp-surface-active: #d9dfeb;
11
+ --sp-surface-divider: #d9dfeb;
8
12
  --sp-text-on-page-default: #141b24;
9
13
  --sp-text-on-page-muted: #4b576a;
10
14
  --sp-text-on-page-subtle: #657287;
@@ -72,6 +76,10 @@
72
76
  --sp-dropdown-item-hover: #eef1f6;
73
77
  --sp-dropdown-item-active: #f0f9ff;
74
78
  --sp-dropdown-item-text: #141b24;
79
+ --sp-link-default: #1f57db;
80
+ --sp-link-hover: #1946b4;
81
+ --sp-link-active: #173b8f;
82
+ --sp-link-visited: #5d28b8;
75
83
  --sp-color-brand-50: #eef4ff;
76
84
  --sp-color-brand-100: #d9e7ff;
77
85
  --sp-color-brand-200: #b9d2ff;
@@ -184,6 +192,8 @@
184
192
  --sp-layout-container-padding-inline-md: 1.5rem;
185
193
  --sp-layout-container-padding-inline-lg: 2rem;
186
194
  --sp-layout-container-max-width: 72rem;
195
+ --sp-layout-container-max-width-prose: 65ch;
196
+ --sp-layout-sidebar-width: 16rem;
187
197
  --sp-border-width-none: 0;
188
198
  --sp-border-width-base: 1px;
189
199
  --sp-border-width-thick: 2px;
@@ -424,6 +434,10 @@
424
434
  --sp-surface-overlay: rgba(0, 0, 0, 0.6);
425
435
  --sp-surface-subtle: #222b38;
426
436
  --sp-surface-hero: linear-gradient(135deg, #5d28b8 0%, #401f75 100%);
437
+ --sp-surface-hover: #374253;
438
+ --sp-surface-selected: #082f49;
439
+ --sp-surface-active: #4b576a;
440
+ --sp-surface-divider: #374253;
427
441
  --sp-text-on-page-default: #f7f8fb;
428
442
  --sp-text-on-page-muted: #b7c1d4;
429
443
  --sp-text-on-page-subtle: #8a96ad;
@@ -491,6 +505,10 @@
491
505
  --sp-dropdown-item-hover: #374253;
492
506
  --sp-dropdown-item-active: #082f49;
493
507
  --sp-dropdown-item-text: #eef1f6;
508
+ --sp-link-default: #1f57db;
509
+ --sp-link-hover: #1946b4;
510
+ --sp-link-active: #173b8f;
511
+ --sp-link-visited: #5d28b8;
494
512
  }
495
513
  @layer base {
496
514
 
@@ -5,6 +5,10 @@
5
5
  --sp-surface-overlay: rgba(0, 0, 0, 0.6);
6
6
  --sp-surface-subtle: #eef1f6;
7
7
  --sp-surface-hero: linear-gradient(135deg, #5b6ee1 0%, #6f3fd7 100%);
8
+ --sp-surface-hover: #eef1f6;
9
+ --sp-surface-selected: #f0f9ff;
10
+ --sp-surface-active: #d9dfeb;
11
+ --sp-surface-divider: #d9dfeb;
8
12
  --sp-text-on-page-default: #141b24;
9
13
  --sp-text-on-page-muted: #4b576a;
10
14
  --sp-text-on-page-subtle: #657287;
@@ -72,6 +76,10 @@
72
76
  --sp-dropdown-item-hover: #eef1f6;
73
77
  --sp-dropdown-item-active: #f0f9ff;
74
78
  --sp-dropdown-item-text: #141b24;
79
+ --sp-link-default: #1f57db;
80
+ --sp-link-hover: #1946b4;
81
+ --sp-link-active: #173b8f;
82
+ --sp-link-visited: #5d28b8;
75
83
  --sp-color-brand-50: #eef4ff;
76
84
  --sp-color-brand-100: #d9e7ff;
77
85
  --sp-color-brand-200: #b9d2ff;
@@ -184,6 +192,8 @@
184
192
  --sp-layout-container-padding-inline-md: 1.5rem;
185
193
  --sp-layout-container-padding-inline-lg: 2rem;
186
194
  --sp-layout-container-max-width: 72rem;
195
+ --sp-layout-container-max-width-prose: 65ch;
196
+ --sp-layout-sidebar-width: 16rem;
187
197
  --sp-border-width-none: 0;
188
198
  --sp-border-width-base: 1px;
189
199
  --sp-border-width-thick: 2px;
@@ -424,6 +434,10 @@
424
434
  --sp-surface-overlay: rgba(0, 0, 0, 0.6);
425
435
  --sp-surface-subtle: #222b38;
426
436
  --sp-surface-hero: linear-gradient(135deg, #5d28b8 0%, #401f75 100%);
437
+ --sp-surface-hover: #374253;
438
+ --sp-surface-selected: #082f49;
439
+ --sp-surface-active: #4b576a;
440
+ --sp-surface-divider: #374253;
427
441
  --sp-text-on-page-default: #f7f8fb;
428
442
  --sp-text-on-page-muted: #b7c1d4;
429
443
  --sp-text-on-page-subtle: #8a96ad;
@@ -491,6 +505,10 @@
491
505
  --sp-dropdown-item-hover: #374253;
492
506
  --sp-dropdown-item-active: #082f49;
493
507
  --sp-dropdown-item-text: #eef1f6;
508
+ --sp-link-default: #1f57db;
509
+ --sp-link-hover: #1946b4;
510
+ --sp-link-active: #173b8f;
511
+ --sp-link-visited: #5d28b8;
494
512
  }
495
513
  @layer components {
496
514
 
@@ -809,6 +827,23 @@
809
827
  --sp-component-nav-link-active: var(--sp-nav-link-active);
810
828
  --sp-component-nav-border: var(--sp-nav-border);
811
829
 
830
+ /* sidebar roles (reuses nav roles - vertical counterpart to the top-bar nav) */
831
+ --sp-component-sidebar-bg: var(--sp-nav-bg);
832
+ --sp-component-sidebar-text: var(--sp-nav-text);
833
+ --sp-component-sidebar-link: var(--sp-nav-link);
834
+ --sp-component-sidebar-link-hover: var(--sp-nav-link-hover);
835
+ --sp-component-sidebar-link-active: var(--sp-nav-link-active);
836
+ --sp-component-sidebar-border: var(--sp-nav-border);
837
+ --sp-component-sidebar-width: var(--sp-layout-sidebar-width);
838
+ --sp-component-sidebar-z-index: var(--sp-z-index-fixed);
839
+ --sp-component-sidebar-backdrop: var(--sp-surface-overlay);
840
+ --sp-component-sidebar-backdrop-z-index: var(--sp-z-index-overlay);
841
+
842
+ /* footer roles (reuses nav roles - bottom-bar counterpart to the top-bar nav) */
843
+ --sp-component-footer-bg: var(--sp-nav-bg);
844
+ --sp-component-footer-text: var(--sp-nav-text);
845
+ --sp-component-footer-border: var(--sp-nav-border);
846
+
812
847
  /* toast roles */
813
848
  --sp-component-toast-radius: var(--sp-radius-lg);
814
849
  --sp-component-toast-padding-x: var(--sp-space-16);
@@ -2722,6 +2757,120 @@
2722
2757
  opacity: var(--sp-opacity-disabled);
2723
2758
  }
2724
2759
 
2760
+ /* SIDEBAR -------------------------------------------------------------- */
2761
+ .sp-sidebar {
2762
+ display: flex;
2763
+ flex-direction: column;
2764
+ gap: var(--sp-space-16);
2765
+ width: var(--sp-component-sidebar-width);
2766
+ padding: var(--sp-space-16);
2767
+ background-color: var(--sp-component-sidebar-bg);
2768
+ color: var(--sp-component-sidebar-text);
2769
+ font-family: var(--sp-font-family-sans);
2770
+ position: fixed;
2771
+ top: 0;
2772
+ left: 0;
2773
+ height: 100%;
2774
+ transform: translateX(-100%);
2775
+ z-index: var(--sp-component-sidebar-z-index);
2776
+ transition:
2777
+ background-color var(--sp-duration-fast) var(--sp-easing-out),
2778
+ color var(--sp-duration-fast) var(--sp-easing-out),
2779
+ border-color var(--sp-duration-fast) var(--sp-easing-out),
2780
+ transform var(--sp-duration-fast) var(--sp-easing-out);
2781
+ }
2782
+
2783
+ .sp-sidebar--bordered {
2784
+ border-right: var(--sp-component-border-width) solid var(--sp-component-sidebar-border);
2785
+ }
2786
+
2787
+ .sp-sidebar__link {
2788
+ color: var(--sp-component-sidebar-link);
2789
+ font-size: var(--sp-font-sm-size);
2790
+ line-height: var(--sp-font-sm-line-height);
2791
+ font-weight: var(--sp-font-sm-weight);
2792
+ text-decoration: none;
2793
+ transition: color var(--sp-duration-fast) var(--sp-easing-out);
2794
+ }
2795
+
2796
+ .sp-sidebar__link:hover,
2797
+ .sp-sidebar__link--hover,
2798
+ .sp-sidebar__link.is-hover {
2799
+ color: var(--sp-component-sidebar-link-hover);
2800
+ }
2801
+
2802
+ .sp-sidebar__link:focus-visible,
2803
+ .sp-sidebar__link--focus,
2804
+ .sp-sidebar__link.is-focus {
2805
+ outline: none;
2806
+ box-shadow: 0 0 0 calc(var(--sp-focus-ring-width) + var(--sp-component-border-width)) var(--sp-color-focus-primary);
2807
+ }
2808
+
2809
+ .sp-sidebar__link--active,
2810
+ .sp-sidebar__link.is-active {
2811
+ color: var(--sp-component-sidebar-link-active);
2812
+ }
2813
+
2814
+ .sp-sidebar__link--disabled,
2815
+ .sp-sidebar__link[aria-disabled="true"] {
2816
+ pointer-events: none;
2817
+ opacity: var(--sp-opacity-disabled);
2818
+ }
2819
+
2820
+ .sp-sidebar-backdrop {
2821
+ display: none;
2822
+ position: fixed;
2823
+ inset: 0;
2824
+ background-color: var(--sp-component-sidebar-backdrop);
2825
+ z-index: var(--sp-component-sidebar-backdrop-z-index);
2826
+ }
2827
+
2828
+ [data-sidebar-open="true"] .sp-sidebar {
2829
+ transform: translateX(0);
2830
+ }
2831
+
2832
+ [data-sidebar-open="true"] .sp-sidebar-backdrop {
2833
+ display: block;
2834
+ }
2835
+
2836
+ /* Above breakpoints.md, the sidebar docks inline instead of as an off-canvas
2837
+ drawer - see Grid's @media literal convention for why this is a literal. */
2838
+ @media (min-width: 768px) {
2839
+ .sp-sidebar {
2840
+ position: static;
2841
+ height: auto;
2842
+ transform: none;
2843
+ }
2844
+
2845
+ .sp-sidebar-backdrop {
2846
+ display: none;
2847
+ }
2848
+ }
2849
+
2850
+ /* FOOTER ----------------------------------------------------------------- */
2851
+ .sp-footer {
2852
+ display: flex;
2853
+ align-items: center;
2854
+ justify-content: space-between;
2855
+ gap: var(--sp-space-16);
2856
+ padding: var(--sp-space-12) var(--sp-space-16);
2857
+ background-color: var(--sp-component-footer-bg);
2858
+ color: var(--sp-component-footer-text);
2859
+ font-family: var(--sp-font-family-sans);
2860
+ transition:
2861
+ background-color var(--sp-duration-fast) var(--sp-easing-out),
2862
+ color var(--sp-duration-fast) var(--sp-easing-out),
2863
+ border-color var(--sp-duration-fast) var(--sp-easing-out);
2864
+ }
2865
+
2866
+ .sp-footer--bordered {
2867
+ border-top: var(--sp-component-border-width) solid var(--sp-component-footer-border);
2868
+ }
2869
+
2870
+ .sp-footer--full {
2871
+ width: 100%;
2872
+ }
2873
+
2725
2874
  /* TOASTS ----------------------------------------------------------------- */
2726
2875
  .sp-toast {
2727
2876
  display: flex;
package/dist/index.cjs CHANGED
@@ -788,6 +788,36 @@ function getNavLinkClasses(opts = {}) {
788
788
  );
789
789
  }
790
790
 
791
+ // src/recipes/sidebar.ts
792
+ function getSidebarClasses(opts = {}) {
793
+ const { bordered = false } = opts;
794
+ return cx("sp-sidebar", bordered && "sp-sidebar--bordered");
795
+ }
796
+ function getSidebarLinkClasses(opts = {}) {
797
+ const {
798
+ active = false,
799
+ disabled = false,
800
+ hovered = false,
801
+ focused = false
802
+ } = opts;
803
+ return cx(
804
+ "sp-sidebar__link",
805
+ active && "sp-sidebar__link--active",
806
+ disabled && "sp-sidebar__link--disabled",
807
+ hovered && "sp-sidebar__link--hover is-hover",
808
+ focused && "sp-sidebar__link--focus is-focus"
809
+ );
810
+ }
811
+ function getSidebarBackdropClasses() {
812
+ return cx("sp-sidebar-backdrop");
813
+ }
814
+
815
+ // src/recipes/footer.ts
816
+ function getFooterClasses(opts = {}) {
817
+ const { bordered = false, fullWidth = false } = opts;
818
+ return cx("sp-footer", bordered && "sp-footer--bordered", fullWidth && "sp-footer--full");
819
+ }
820
+
791
821
  // src/recipes/toast.ts
792
822
  var TOAST_VARIANTS = {
793
823
  info: true,
@@ -899,8 +929,19 @@ function getModalClasses(opts = {}) {
899
929
  }
900
930
 
901
931
  // src/recipes/container.ts
902
- function getContainerClasses(_opts = {}) {
903
- return "sp-container";
932
+ var CONTAINER_MAX_WIDTHS = {
933
+ none: true,
934
+ prose: true
935
+ };
936
+ function getContainerClasses(opts = {}) {
937
+ const { maxWidth: maxWidthInput } = opts;
938
+ const maxWidth = resolveOption({
939
+ name: "container maxWidth",
940
+ value: maxWidthInput,
941
+ allowed: CONTAINER_MAX_WIDTHS,
942
+ fallback: "none"
943
+ });
944
+ return cx("sp-container", maxWidth !== "none" && `sp-container--max-width-${maxWidth}`);
904
945
  }
905
946
 
906
947
  // src/recipes/stack.ts
@@ -908,15 +949,28 @@ var STACK_DIRECTIONS = {
908
949
  vertical: true,
909
950
  horizontal: true
910
951
  };
952
+ var STACK_BASES = {
953
+ none: true,
954
+ sidebar: true
955
+ };
911
956
  function getStackClasses(opts = {}) {
912
- const { direction: directionInput } = opts;
957
+ const { direction: directionInput, basis: basisInput } = opts;
913
958
  const direction = resolveOption({
914
959
  name: "stack direction",
915
960
  value: directionInput,
916
961
  allowed: STACK_DIRECTIONS,
917
962
  fallback: "vertical"
918
963
  });
919
- return direction === "horizontal" ? "sp-hstack" : "sp-stack";
964
+ const basis = resolveOption({
965
+ name: "stack basis",
966
+ value: basisInput,
967
+ allowed: STACK_BASES,
968
+ fallback: "none"
969
+ });
970
+ return cx(
971
+ direction === "horizontal" ? "sp-hstack" : "sp-stack",
972
+ basis !== "none" && `sp-stack--basis-${basis}`
973
+ );
920
974
  }
921
975
 
922
976
  // src/recipes/section.ts
@@ -924,6 +978,37 @@ function getSectionClasses(_opts = {}) {
924
978
  return "sp-section";
925
979
  }
926
980
 
981
+ // src/recipes/grid.ts
982
+ var GRID_COLUMNS = {
983
+ "1": true,
984
+ "2": true,
985
+ "3": true,
986
+ "4": true,
987
+ "6": true,
988
+ "12": true
989
+ };
990
+ var GRID_GAPS = {
991
+ sm: true,
992
+ md: true,
993
+ lg: true
994
+ };
995
+ function getGridClasses(opts = {}) {
996
+ const { columns: columnsInput, gap: gapInput } = opts;
997
+ const columns = resolveOption({
998
+ name: "grid columns",
999
+ value: columnsInput === void 0 ? void 0 : String(columnsInput),
1000
+ allowed: GRID_COLUMNS,
1001
+ fallback: "1"
1002
+ });
1003
+ const gap = resolveOption({
1004
+ name: "grid gap",
1005
+ value: gapInput,
1006
+ allowed: GRID_GAPS,
1007
+ fallback: "md"
1008
+ });
1009
+ return cx("sp-grid", `sp-grid--gap-${gap}`, `sp-grid-cols-${columns}`);
1010
+ }
1011
+
927
1012
  exports.getAlertClasses = getAlertClasses;
928
1013
  exports.getAvatarClasses = getAvatarClasses;
929
1014
  exports.getBadgeClasses = getBadgeClasses;
@@ -933,6 +1018,8 @@ exports.getContainerClasses = getContainerClasses;
933
1018
  exports.getDropdownClasses = getDropdownClasses;
934
1019
  exports.getDropdownItemClasses = getDropdownItemClasses;
935
1020
  exports.getDropdownMenuClasses = getDropdownMenuClasses;
1021
+ exports.getFooterClasses = getFooterClasses;
1022
+ exports.getGridClasses = getGridClasses;
936
1023
  exports.getIconBoxClasses = getIconBoxClasses;
937
1024
  exports.getInputClasses = getInputClasses;
938
1025
  exports.getInputErrorMessageClasses = getInputErrorMessageClasses;
@@ -954,6 +1041,9 @@ exports.getRatingStarClasses = getRatingStarClasses;
954
1041
  exports.getRatingStarsClasses = getRatingStarsClasses;
955
1042
  exports.getRatingTextClasses = getRatingTextClasses;
956
1043
  exports.getSectionClasses = getSectionClasses;
1044
+ exports.getSidebarBackdropClasses = getSidebarBackdropClasses;
1045
+ exports.getSidebarClasses = getSidebarClasses;
1046
+ exports.getSidebarLinkClasses = getSidebarLinkClasses;
957
1047
  exports.getSpinnerClasses = getSpinnerClasses;
958
1048
  exports.getStackClasses = getStackClasses;
959
1049
  exports.getTagClasses = getTagClasses;