@grantcodes/ui 2.8.0 → 2.8.1

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
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.8.1](https://github.com/grantcodes/ui/compare/ui-v2.8.0...ui-v2.8.1) (2026-04-07)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **gallery:** filmstrip images should fill height with auto width, not square crop ([62d436f](https://github.com/grantcodes/ui/commit/62d436fe75f42c6d99c380c9d4384e53a97abef1))
9
+ * **gallery:** SSR-safe filmstrip variant with variant prop refactor ([2af368c](https://github.com/grantcodes/ui/commit/2af368cba60b55021f563a06c1416219abb0b024))
10
+ * **gallery:** use CSS custom properties for filmstrip styles instead of JS attribute propagation ([f83efcf](https://github.com/grantcodes/ui/commit/f83efcfcf24a896dcdcb943b5988a9daefcf8947))
11
+
3
12
  ## [2.8.0](https://github.com/grantcodes/ui/compare/ui-v2.7.0...ui-v2.8.0) (2026-04-07)
4
13
 
5
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grantcodes/ui",
3
- "version": "2.8.0",
3
+ "version": "2.8.1",
4
4
  "description": "A personal component system built with Lit web components",
5
5
  "type": "module",
6
6
  "main": "src/main.js",
@@ -12,7 +12,6 @@ export class GrantCodesGalleryImage extends LitElement {
12
12
  alt: { type: String },
13
13
  caption: { type: String },
14
14
  thumbnail: { type: String },
15
- filmstrip: { type: Boolean, reflect: true },
16
15
  };
17
16
 
18
17
  constructor() {
@@ -24,7 +23,6 @@ export class GrantCodesGalleryImage extends LitElement {
24
23
  this.alt = "";
25
24
  this.caption = "";
26
25
  this.thumbnail = "";
27
- this.filmstrip = false;
28
26
  }
29
27
 
30
28
  captionTemplate() {
@@ -6,7 +6,7 @@ export class GrantCodesGallery extends LitElement {
6
6
  static styles = [galleryStyles];
7
7
 
8
8
  static properties = {
9
- filmstrip: { type: Boolean, reflect: true },
9
+ variant: { type: String, reflect: true },
10
10
  };
11
11
 
12
12
  /** @type {any[]} */
@@ -14,34 +14,7 @@ export class GrantCodesGallery extends LitElement {
14
14
 
15
15
  constructor() {
16
16
  super();
17
- this.filmstrip = false;
18
- }
19
-
20
- firstUpdated() {
21
- const slot = this.renderRoot.querySelector(".gallery__slot");
22
- if (slot) {
23
- slot.addEventListener("slotchange", () => this._updateChildren());
24
- this._updateChildren();
25
- }
26
- }
27
-
28
- updated(changedProperties) {
29
- if (changedProperties.has("filmstrip")) {
30
- this._updateChildren();
31
- }
32
- }
33
-
34
- _updateChildren() {
35
- const slot = this.renderRoot.querySelector(".gallery__slot");
36
- if (!slot) return;
37
- const assigned = slot.assignedElements({ flatten: true });
38
- for (const el of assigned) {
39
- if (this.filmstrip) {
40
- el.setAttribute("filmstrip", "");
41
- } else {
42
- el.removeAttribute("filmstrip");
43
- }
44
- }
17
+ this.variant = "default";
45
18
  }
46
19
 
47
20
  render() {
@@ -38,8 +38,6 @@
38
38
  display: block;
39
39
  width: 100%;
40
40
  height: auto;
41
- /* Make the image square */
42
- aspect-ratio: 1;
43
41
  object-fit: cover;
44
42
  object-position: center;
45
43
  }
@@ -55,16 +53,50 @@
55
53
  color: white;
56
54
  }
57
55
 
56
+ /* =============================================
57
+ GALLERY-IMAGE DEFAULT STYLES
58
+ (applied inside grantcodes-gallery-image shadow DOM via :host)
59
+ ============================================= */
60
+
61
+ /* Default square crop. :host selector comes after .gallery__image img so
62
+ wins on equal specificity. Uses custom properties so filmstrip mode can
63
+ override them via inheritance from the parent gallery element. */
64
+ :host .gallery__image img {
65
+ aspect-ratio: var(--_gallery-img-aspect-ratio, 1);
66
+ block-size: var(--_gallery-img-block-size, auto);
67
+ width: var(--_gallery-img-width, 100%);
68
+ height: var(--_gallery-img-height, auto);
69
+ max-inline-size: var(--_gallery-img-max-inline-size, unset);
70
+ }
71
+
72
+ :host .gallery__image {
73
+ block-size: var(--_gallery-image-block-size, auto);
74
+ width: var(--_gallery-image-width, 100%);
75
+ }
76
+
58
77
  /* =============================================
59
78
  FILMSTRIP VARIANT
60
79
  ============================================= */
61
80
 
62
- /* Gallery container in filmstrip mode */
63
- :host([filmstrip]) .gallery {
81
+ /* Set inherited CSS custom properties on the gallery host when in filmstrip
82
+ mode. These cascade down to slotted grantcodes-gallery-image children
83
+ without requiring JS attribute propagation, making the filmstrip work
84
+ correctly with SSR-rendered content. */
85
+ :host([variant="filmstrip"]) {
86
+ --_gallery-image-block-size: 100%;
87
+ --_gallery-image-width: fit-content;
88
+ --_gallery-img-aspect-ratio: auto;
89
+ --_gallery-img-block-size: 100%;
90
+ --_gallery-img-width: auto;
91
+ --_gallery-img-height: 100%;
92
+ --_gallery-img-max-inline-size: none;
93
+ }
94
+
95
+ :host([variant="filmstrip"]) .gallery {
64
96
  overflow: hidden;
65
97
  }
66
98
 
67
- :host([filmstrip]) .gallery__slot {
99
+ :host([variant="filmstrip"]) .gallery__slot {
68
100
  display: flex;
69
101
  flex-wrap: nowrap;
70
102
  overflow-x: auto;
@@ -76,11 +108,11 @@
76
108
  scrollbar-width: none;
77
109
  }
78
110
 
79
- :host([filmstrip]) .gallery__slot::-webkit-scrollbar {
111
+ :host([variant="filmstrip"]) .gallery__slot::-webkit-scrollbar {
80
112
  display: none;
81
113
  }
82
114
 
83
- :host([filmstrip]) .gallery__slot::slotted(*) {
115
+ :host([variant="filmstrip"]) .gallery__slot::slotted(*) {
84
116
  flex: 0 0 auto;
85
117
  block-size: 100%;
86
118
  scroll-snap-align: start;
@@ -89,7 +121,7 @@
89
121
  /* Scroll-driven reveal animation */
90
122
  @supports (animation-timeline: view()) {
91
123
  @media (prefers-reduced-motion: no-preference) {
92
- :host([filmstrip]) .gallery__slot::slotted(*) {
124
+ :host([variant="filmstrip"]) .gallery__slot::slotted(*) {
93
125
  animation: filmstrip-reveal linear both;
94
126
  animation-timeline: view(inline);
95
127
  animation-range: entry 0% entry 60%;
@@ -107,19 +139,3 @@
107
139
  scale: 1;
108
140
  }
109
141
  }
110
-
111
- /* Gallery-image host in filmstrip mode */
112
- :host([filmstrip]) .gallery__image {
113
- block-size: 100%;
114
- width: fit-content;
115
- }
116
-
117
- :host([filmstrip]) .gallery__image img {
118
- block-size: 100%;
119
- width: auto;
120
- aspect-ratio: unset;
121
- max-inline-size: none;
122
- object-fit: cover;
123
- object-position: center;
124
- }
125
-
@@ -64,6 +64,7 @@ const filmstripImages = [
64
64
  { w: 160, h: 240 },
65
65
  { w: 360, h: 240 },
66
66
  { w: 180, h: 240 },
67
+ { w: 160, h: 900 }, // tall portrait image
67
68
  { w: 420, h: 240 },
68
69
  { w: 160, h: 240 },
69
70
  { w: 380, h: 240 },
@@ -76,7 +77,7 @@ const filmstripImages = [
76
77
 
77
78
  export const Filmstrip = {
78
79
  args: {
79
- filmstrip: true,
80
+ variant: "filmstrip",
80
81
  },
81
82
  render: (args) =>
82
83
  template(
@@ -66,18 +66,19 @@ describe("Gallery Component", () => {
66
66
  cleanup(element);
67
67
  });
68
68
 
69
- it("should have filmstrip property default to false", async () => {
69
+ it("should have variant property default to 'default'", async () => {
70
70
  element = await fixture("grantcodes-gallery");
71
- assert.strictEqual(element.filmstrip, false, "filmstrip should default to false");
71
+ assert.strictEqual(element.variant, "default", "variant should default to 'default'");
72
72
  });
73
73
 
74
- it("should reflect filmstrip attribute when property is set", async () => {
74
+ it("should reflect variant attribute when property is set", async () => {
75
75
  element = await fixture("grantcodes-gallery");
76
- element.filmstrip = true;
76
+ element.variant = "filmstrip";
77
77
  await element.updateComplete;
78
- assert.ok(
79
- element.hasAttribute("filmstrip"),
80
- "filmstrip attribute should be reflected",
78
+ assert.strictEqual(
79
+ element.getAttribute("variant"),
80
+ "filmstrip",
81
+ "variant attribute should be reflected",
81
82
  );
82
83
  });
83
84
  });