@gemboss/gem-framework 0.9.3 → 0.10.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/README.md +75 -0
- package/dist/SOURCE.json +3 -3
- package/dist/gem-framework.css +27 -37
- package/dist/gem-runtime.js +45 -2
- package/dist/index.js +300 -57
- package/dist/plugins/hero-slideshow.js +5 -1
- package/dist/plugins/media-gallery.js +25 -0
- package/dist/plugins/sticky-atc.js +15 -1
- package/dist/primitives.css +9 -23
- package/dist/section-gate.js +3287 -1
- package/dist/sections.css +18 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,6 +73,81 @@ Từ 0.8.2 mỗi module có `.d.ts` cạnh nó (`mount(root?: ParentNode | null,
|
|
|
73
73
|
|
|
74
74
|
## Nhật ký thay đổi
|
|
75
75
|
|
|
76
|
+
- **0.10.0** (08/10/2026, gộp 0.9.10 và 0.9.11 chưa phát hành): phần còn lại của yêu cầu #4 GemFactory (Figma CRO, issue
|
|
77
|
+
gemfactory #95). Plan không khai khoá nào dưới đây thì CSS tính ra như cũ (mỗi `var()` lùi về đúng giá trị cũ).
|
|
78
|
+
- Line-height tiêu đề: opt-in `data-gem-heading="section"` (1.1), `.gem-section__heading` nền (1.04) và của Dawn parity
|
|
79
|
+
(1.08) đọc `--gem-font-heading-line-height`, tức `typography.headingLineHeight`. Khoá này ĐÃ CÓ trong hai style pack
|
|
80
|
+
(`graphic-editorial` 0.95, `warm-mineral-spf` 1.2) mà trước giờ không tới tiêu đề section: store dùng hai pack đó đổi
|
|
81
|
+
line-height tiêu đề section và hero theo đúng khoá đã khai. Giá trị không phải line-height bị bỏ (biến khai sai làm
|
|
82
|
+
`var()` bỏ qua fallback và rơi về 1,5 của body), `validateGemTokens` báo `invalid_line_height_token`. Luật riêng của
|
|
83
|
+
biến thể Dawn có cỡ px cố định (hero split-proof 46px/1.08, compact-collection…) giữ line-height riêng.
|
|
84
|
+
- Cỡ tiêu đề theo thang chữ, CHỈ khi plan khai `typography.base` hoặc `scale`: phát `--gem-section-heading-size`
|
|
85
|
+
(= `--gem-h2` × núm heading-scale), `--gem-hero-heading-size` (`--gem-h1`, chỉ luật hero h1/h2 của Dawn đọc) và bản
|
|
86
|
+
`-mobile` (không lớn hơn `--gem-heading-phone-cap`, trần điện thoại của PROFILE: Dawn khai `clamp(2rem, 11vw, 3.6rem)`
|
|
87
|
+
trên `:root`, profile nền lùi về `clamp(1.75rem, 9vw, 2.75rem)` như #587). Mọi luật tiêu đề section đọc chúng.
|
|
88
|
+
- Khoá điện thoại: `spacing.<bậc>Mobile` (cả 10 bậc) và `layout.sectionMobile` (so khoá bỏ qua hoa thường và dấu nối)
|
|
89
|
+
khai lại biến gốc trong khối `@media (max-width: 749px)` của `baseMobile`. Spacing nhân núm mật độ; giá trị kiểm hình
|
|
90
|
+
dạng như `md` (0 trần thành `0px`); giá trị không đơn vị, hoặc đọc biến của chính nhóm nó (khai lại trên `:root` là
|
|
91
|
+
vòng lặp, padding về 0), bị bỏ và `validateGemTokens` báo `invalid_phone_token`. `sectionMobile` còn đặt
|
|
92
|
+
`--gem-layout-section-mobile` trên `:root` desktop: padding ≤760px của profile nền dùng nguyên giá trị thay vì
|
|
93
|
+
desktop × 0,72. Không có khoá điện thoại cho `page`/`gutter` (bề rộng điện thoại của profile nền không đọc chúng).
|
|
94
|
+
Ở lane một stylesheet (`createGemThemeCss`), `:root` của Dawn đứng sau token và khoá `layout.*` như trước.
|
|
95
|
+
- Opt-in eyebrow có `font-size: var(--gem-text-sm)` (mặc định 13,1px, luật nền 13px).
|
|
96
|
+
- Xuất `optionalGemTokenKeys` (manifest `token_groups[].optional_keys` đọc từ đây, gồm khoá nút của 0.9.10),
|
|
97
|
+
`gemMobileTokenCssVars`, `gemPhoneTokenTarget`, `GEM_HEADING_SIZE_CSS_VARS`, `GEM_LINE_HEIGHT_TOKEN_KEYS`: bản chép ở
|
|
98
|
+
gemsite (`theme-plan-style.ts`) và cổng preset của GemFactory đối chiếu với chúng thay vì chép tay.
|
|
99
|
+
- **0.9.11** (08/10/2026): marquee còn MỘT định nghĩa. Trước đó primitives.css có hai: bản của gemtheme #124 (một track
|
|
100
|
+
nhân đôi con, dịch -50%) nằm TRÊN bản #79 (`__viewport` + hai track, dịch -100%) nên thua mọi thuộc tính cả hai cùng đặt
|
|
101
|
+
(`min-width`, `animation`), và hợp đồng của #124 chưa từng chạy. Giữ hợp đồng #79, đúng thứ clone kit của gemcapture và
|
|
102
|
+
GemFactory dựng, cộng những gì của #124 vẫn đang có hiệu lực: viền `border-block`, `will-change`, dừng khi rê lên cả
|
|
103
|
+
`.gem-marquee`, đảo chiều bằng `data-gem-marquee-reverse` (bên cạnh `.gem-marquee--reverse`). Bỏ dòng `animation-duration`
|
|
104
|
+
của marquee trong khối reduced-motion của ambient: ở đó track đã `animation: none`. Đo Chromium (6 kiểu dựng marquee, 390 và
|
|
105
|
+
1280, có và không reduced-motion, rê chuột 3 chỗ, đồng hồ animation ghim ở 1234 ms): 516.832 giá trị tính ra, 56 lệch, cả 56
|
|
106
|
+
là `animation-duration` dưới reduced-motion trên track có `animation-name: none` ở cả hai bản, tức không có gì chạy; bản cố ý
|
|
107
|
+
hỏng (bỏ `will-change` và hook đảo chiều bằng thuộc tính) lệch 328. Test mới `one-owner-per-selector`: selector viết hai lần
|
|
108
|
+
trong cùng file, cùng @media, có thuộc tính đè nhau thì chỉ được giảm (còn 28 ca, liệt kê trong test).
|
|
109
|
+
- **0.9.10** (08/10/2026): token nút tuỳ chọn (`GEM_BUTTON_TOKEN_KEYS`, hình dạng ở `GEM_BUTTON_TOKEN_SHAPES`), cả bốn tên
|
|
110
|
+
đã có mà chưa ai vẽ: `radius.button` (`--gem-radius-button`, scale theo `--gem-style-radius`; validators và generation-jobs
|
|
111
|
+
đã dùng tên này), `typography.buttonWeight`, `typography.buttonTransform` và `typography.buttonLetterSpacing` (schema style
|
|
112
|
+
pack; `luxury-editorial` khai nút in hoa 0.18em từ trước, giờ mới hiện). Không khai thì nút vẽ y như trước (đo Chromium:
|
|
113
|
+
90/90 giá trị tính ra trùng bản cũ ở dawn-parity và ở morph). Bo góc là của riêng nút, nên nút pill không kéo thẻ thành
|
|
114
|
+
pill; dawn-parity hết ép nút vuông / đậm 400 khi có token. In hoa và giãn chữ không nằm trong `.gem-button` (UA cho
|
|
115
|
+
`<button>` `none`, còn `<a>` kế thừa): `createGemTokenCss` thêm luật `:where(...)` độ ưu tiên 0 chỉ khi có token
|
|
116
|
+
(`gemButtonCaseCss`, export cho storefront tự viết token CSS), nên luật CTA của section vẫn thắng. Nút dạng link không nhận
|
|
117
|
+
độ đậm / chữ hoa của token. Giá trị sai hình dạng (`"pill"`, rỗng, `"semibold"`) không được phát, `validateGemTokens` cảnh
|
|
118
|
+
báo `invalid_button_token`; khoá snake_case của editor đi qua cùng cổng. Manifest có `optional_keys`. Nguồn: GemFactory
|
|
119
|
+
Global Style 08/10/2026 (339 trang store hàng đầu: CTA pill 39%, in hoa 47%, giãn chữ 18%).
|
|
120
|
+
- **0.9.9** (08/10/2026): `gemFrameworkVersion` (và `framework_version` / `gem_framework_version` trong manifest) bằng
|
|
121
|
+
đúng phiên bản của gói. Từ 0.4.0 tới 0.9.8 nó đứng yên ở `"0.1.0"`, nên trang Framework của gemboss hiện sai phiên bản
|
|
122
|
+
và GemFactory phải tự đọc phiên bản npm. Test trong `index.test.ts` đỏ khi hai giá trị lệch nhau. Không đổi CSS hay
|
|
123
|
+
runtime.
|
|
124
|
+
- **0.9.8** (06/10/2026): biến chỉ được tính là "khai trên :root" khi MỌI vế của selector đúng là gốc (`:root`, `html`,
|
|
125
|
+
`:host`, có thể kèm điều kiện như `:root[data-theme="dark"]`), không bao giờ là con của nó. Bản 0.9.7 chỉ xét đầu
|
|
126
|
+
selector, nên một luật `:root .gem-row { --gem-row-auto-sm: … }` sẽ biến biến nội bộ thành công khai. Stylesheet hiện
|
|
127
|
+
tại chưa có luật nào như vậy, nên kết quả không đổi (review của gemboss #3842). Thêm `gemPublicCssVariablesFrom(css)`.
|
|
128
|
+
- **0.9.7** (06/10/2026): `validateGemFrameworkCss` nhận mọi biến CÔNG KHAI của chính framework, đọc từ stylesheet của nó ở
|
|
129
|
+
cả hai profile: biến khai trên `:root` (`--gem-card-radius`, `--gem-media-radius`, `--gem-ease-soft`, `--gem-grid-row-gap`…)
|
|
130
|
+
và điểm mở chỉ được đọc kèm dự phòng (`--gem-card-background`, `--gem-marquee-duration`…). Trước đó danh sách ghép tay
|
|
131
|
+
bỏ sót 25 biến như vậy, nên section đọc đúng biến framework vẫn nhận `unknown_gem_css_variable` (GemFactory gap #29).
|
|
132
|
+
Biến nội bộ mà framework chỉ khai trên class của nó (`--gem-row-auto-*`, `--gem-stars-*`, `--gem-section-bg`) vẫn bị
|
|
133
|
+
báo, và tên gõ sai cũng vậy.
|
|
134
|
+
- **0.9.6** (06/10/2026): `media-gallery` có chế độ ảnh chính + thumbnail (gallery có `[data-gem-media-main]`): bấm
|
|
135
|
+
thumbnail thì ảnh chính nhận `data-gem-media-src` / `-alt` của nó, bỏ `srcset`, `aria-current` chuyển sang thumbnail
|
|
136
|
+
đó, và phát `gem:media:select` `{ index }` như `behavior.js` của section. Phần tử chỉ khớp theo class mà bọc một hook
|
|
137
|
+
`[data-gem-media-gallery]` không còn bị gắn thành gallery thứ hai (trước đó nó đánh số lại thumbnail bằng cách đếm
|
|
138
|
+
mọi `<img>`, kể cả ảnh chính). Gallery không có ảnh chính chạy như cũ.
|
|
139
|
+
- **0.9.5** (06/10/2026): `sticky-atc` làm đủ việc của `behavior.js` section: giá trên thanh đổi theo biến thể khách
|
|
140
|
+
chọn (`data-gem-variant-price` trên từng `<option>`), và form KHÔNG có `action` (thanh headless) thì chặn submit, phát
|
|
141
|
+
`gem:cart:add` với biến thể đang chọn (không phải biến thể đầu ghi trên nút). Form có `action` (Liquid `/cart/add`)
|
|
142
|
+
vẫn để trình duyệt gửi như cũ. Trước đó plugin chỉ báo `gem:sticky-atc:submit`, nên trang nạp plugin mà không có
|
|
143
|
+
bản của section thì bấm thêm vào giỏ là tải lại trang.
|
|
144
|
+
- **0.9.4** (06/10/2026): nút tạm dừng của `hero-slideshow` đổi chữ theo trạng thái như `behavior.js` của section từng làm:
|
|
145
|
+
khi dừng nút ghi `data-gem-hero-play-label` (mặc định `Play`), khi chạy lại ghi đúng chữ ban đầu của nút (nên nhãn đã
|
|
146
|
+
dịch không bị đè). Nút có phần tử con (icon) giữ nguyên markup, chỉ đổi `aria-pressed`. Đây là chỗ lệch cuối cùng
|
|
147
|
+
giữa plugin và section, để section giao hành vi cho plugin (một chủ, Chris 06/10/2026).
|
|
148
|
+
- **0.9.3** (06/10/2026): CSS Dawn parity chỉ đặt `gap !important` cho lưới thẻ quick-view
|
|
149
|
+
(`.gem-product-card-grid--quick-view-grid`), không cho mọi `.gem-product-card-grid__grid`. Khớp bản chép của gemsite;
|
|
150
|
+
store không đổi gì.
|
|
76
151
|
- **0.9.2** (06/10/2026): `reveal-on-scroll` bỏ qua `data-gem-reveal="none"` và `"default"` (hai giá trị "không áp gì" của
|
|
77
152
|
knob reveal): section hiện ngay, không ẩn chờ cuộn. Trước đó section đặt `none` vẫn bị ẩn như mọi section reveal.
|
|
78
153
|
- **0.9.1** (06/10/2026): plugin `reveal-on-scroll` không còn giấu section khách đang thấy. Section đã nằm trong màn hình
|
package/dist/SOURCE.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "@gemboss/gem-framework",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"gemtheme_sha": "
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"gemtheme_sha": "15d7875982c5db5dd12446e59108221eabe273ee",
|
|
5
5
|
"gemtheme_dirty": false,
|
|
6
|
-
"framework_version": "0.
|
|
6
|
+
"framework_version": "0.10.0"
|
|
7
7
|
}
|
package/dist/gem-framework.css
CHANGED
|
@@ -160,9 +160,9 @@ a {
|
|
|
160
160
|
justify-content: center;
|
|
161
161
|
min-height: var(--gem-component-input-height, 44px);
|
|
162
162
|
border: var(--gem-button-border-width, 1px) solid var(--gem-color-border);
|
|
163
|
-
border-radius: var(--gem-radius-md);
|
|
163
|
+
border-radius: var(--gem-radius-button, var(--gem-radius-md));
|
|
164
164
|
padding: var(--gem-component-button-padding-block, 12px) var(--gem-component-button-padding-inline, 18px);
|
|
165
|
-
font-weight: 700;
|
|
165
|
+
font-weight: var(--gem-font-button-weight, 700);
|
|
166
166
|
text-decoration: none;
|
|
167
167
|
transition: background var(--gem-motion-duration, 160ms) var(--gem-motion-easing, ease), color var(--gem-motion-duration, 160ms) var(--gem-motion-easing, ease);
|
|
168
168
|
}
|
|
@@ -440,23 +440,6 @@ a {
|
|
|
440
440
|
border-radius: var(--gem-radius-md);
|
|
441
441
|
background: color-mix(in srgb, var(--gem-color-text) 8%, var(--gem-color-background));
|
|
442
442
|
}
|
|
443
|
-
.gem-marquee {
|
|
444
|
-
overflow: hidden;
|
|
445
|
-
border-block: var(--gem-border-subtle, 1px solid var(--gem-color-border));
|
|
446
|
-
}
|
|
447
|
-
.gem-marquee__track {
|
|
448
|
-
display: flex;
|
|
449
|
-
gap: var(--gem-space-lg);
|
|
450
|
-
min-width: max-content;
|
|
451
|
-
animation: gem-marquee-scroll var(--gem-marquee-duration, 40s) linear infinite;
|
|
452
|
-
will-change: transform;
|
|
453
|
-
}
|
|
454
|
-
.gem-marquee:hover .gem-marquee__track {
|
|
455
|
-
animation-play-state: paused;
|
|
456
|
-
}
|
|
457
|
-
.gem-marquee[data-gem-marquee-reverse] .gem-marquee__track {
|
|
458
|
-
animation-direction: reverse;
|
|
459
|
-
}
|
|
460
443
|
.gem-carousel {
|
|
461
444
|
display: grid;
|
|
462
445
|
gap: var(--gem-space-md);
|
|
@@ -582,7 +565,10 @@ a {
|
|
|
582
565
|
overflow: hidden;
|
|
583
566
|
color: var(--gem-color-accent);
|
|
584
567
|
}
|
|
585
|
-
.gem-marquee {
|
|
568
|
+
.gem-marquee {
|
|
569
|
+
overflow: hidden;
|
|
570
|
+
border-block: var(--gem-border-subtle, 1px solid var(--gem-color-border));
|
|
571
|
+
}
|
|
586
572
|
.gem-marquee__viewport { display: flex; overflow: hidden; }
|
|
587
573
|
.gem-marquee__track {
|
|
588
574
|
flex: 0 0 auto;
|
|
@@ -593,9 +579,10 @@ a {
|
|
|
593
579
|
gap: var(--gem-space-lg);
|
|
594
580
|
white-space: nowrap;
|
|
595
581
|
animation: gem-marquee var(--gem-marquee-duration, 24s) linear infinite;
|
|
582
|
+
will-change: transform;
|
|
596
583
|
}
|
|
597
|
-
.gem-marquee__viewport:hover .gem-marquee__track { animation-play-state: paused; }
|
|
598
|
-
.gem-marquee--reverse .gem-marquee__track { animation-direction: reverse; }
|
|
584
|
+
.gem-marquee:hover .gem-marquee__track, .gem-marquee__viewport:hover .gem-marquee__track { animation-play-state: paused; }
|
|
585
|
+
.gem-marquee--reverse .gem-marquee__track, .gem-marquee[data-gem-marquee-reverse] .gem-marquee__track { animation-direction: reverse; }
|
|
599
586
|
@keyframes gem-marquee { from { transform: translateX(0); } to { transform: translateX(-100%); } }
|
|
600
587
|
@media (prefers-reduced-motion: reduce) {
|
|
601
588
|
.gem-marquee__track { animation: none; }
|
|
@@ -1109,7 +1096,6 @@ a {
|
|
|
1109
1096
|
@media (prefers-reduced-motion: reduce) {
|
|
1110
1097
|
[data-gem-ambient] { --gem-ambient-amp: 2px; animation-duration: 12s; }
|
|
1111
1098
|
[data-gem-reveal] { transition: none; opacity: 1; transform: none; }
|
|
1112
|
-
.gem-marquee__track { animation-duration: calc(var(--gem-marquee-duration, 40s) * 2.5); }
|
|
1113
1099
|
}
|
|
1114
1100
|
:is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-top], :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-bottom] { position: relative; overflow: clip; overflow-clip-margin: var(--gem-divider-height, 48px); }
|
|
1115
1101
|
:is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-bottom='wave']::after, :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-bottom='slope']::after, :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-bottom='spikes']::after, :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-bottom='arch']::after, :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-bottom='blob']::after, :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-top='wave']::before, :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-top='slope']::before, :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-top='spikes']::before, :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-top='arch']::before, :is(.gem-section, .gem-hero, .gem-hero-split, .gem-hero-collage, .gem-hero-triptych, .gem-slideshow)[data-gem-divider-top='blob']::before { content: ''; position: absolute; left: 0; right: 0; z-index: 1; pointer-events: none; height: var(--gem-divider-height, 48px); background: var(--gem-section-bg, var(--gem-color-background)); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-size: 100% 100%; mask-size: 100% 100%; }
|
|
@@ -2231,8 +2217,8 @@ sticky-header.header-wrapper {
|
|
|
2231
2217
|
.gem-section__heading {
|
|
2232
2218
|
margin: 0;
|
|
2233
2219
|
font-family: var(--gem-font-heading);
|
|
2234
|
-
font-size: clamp(calc(2rem * var(--gem-typography-heading-scale, 1)), calc(4vw * var(--gem-typography-heading-scale, 1)), calc(4rem * var(--gem-typography-heading-scale, 1)));
|
|
2235
|
-
line-height: 1.04;
|
|
2220
|
+
font-size: var(--gem-section-heading-size, clamp(calc(2rem * var(--gem-typography-heading-scale, 1)), calc(4vw * var(--gem-typography-heading-scale, 1)), calc(4rem * var(--gem-typography-heading-scale, 1))));
|
|
2221
|
+
line-height: var(--gem-font-heading-line-height, 1.04);
|
|
2236
2222
|
}
|
|
2237
2223
|
.gem-section__body {
|
|
2238
2224
|
margin: 0;
|
|
@@ -2349,20 +2335,20 @@ sticky-header.header-wrapper {
|
|
|
2349
2335
|
}
|
|
2350
2336
|
}
|
|
2351
2337
|
@media (max-width: 760px) {
|
|
2352
|
-
.gem-section { padding-block: calc(var(--gem-layout-section, 64px) * 0.72); }
|
|
2338
|
+
.gem-section { padding-block: var(--gem-layout-section-mobile, calc(var(--gem-layout-section, 64px) * 0.72)); }
|
|
2353
2339
|
.gem-section__inner, .gem-container { width: min(100% - 32px, var(--gem-layout-page, 1180px)); }
|
|
2354
|
-
.gem-section__heading { font-size: clamp(1.75rem, 9vw, 2.75rem); }
|
|
2340
|
+
.gem-section__heading { font-size: var(--gem-section-heading-size-mobile, clamp(1.75rem, 9vw, 2.75rem)); }
|
|
2355
2341
|
.gem-section__grid { grid-template-columns: minmax(0, 1fr); }
|
|
2356
2342
|
.gem-section:is([data-gem-composition-mode='split-collage'], [data-gem-editorial-band-mode='media-story']) .gem-section__grid { grid-template-columns: minmax(0, 1fr); }
|
|
2357
2343
|
.gem-product-main[data-gem-product-main-layout='dawn-main'] .gem-product-main__inner { grid-template-columns: minmax(0, 1fr); }
|
|
2358
2344
|
.gem-product-main[data-gem-product-main-layout='dawn-main'] .gem-product-main__summary { position: static; }
|
|
2359
2345
|
.gem-section:is([data-gem-composition-mode='slideshow'], [data-gem-composition-mode='video-led']) .gem-section__inner { min-block-size: min(62vh, 560px); }
|
|
2360
2346
|
}
|
|
2361
|
-
:where(.gem-section[data-gem-eyebrow='show']) .gem-section__eyebrow { display: block; letter-spacing: 0.12em; }
|
|
2362
|
-
:where(.gem-section[data-gem-heading='section']) .gem-section__heading { margin: 0; font-family: var(--gem-font-heading); font-size: var(--gem-h2); line-height: 1.1; letter-spacing: -0.01em; text-wrap: balance; }
|
|
2347
|
+
:where(.gem-section[data-gem-eyebrow='show']) .gem-section__eyebrow { display: block; font-size: var(--gem-text-sm); letter-spacing: 0.12em; }
|
|
2348
|
+
:where(.gem-section[data-gem-heading='section']) .gem-section__heading { margin: 0; font-family: var(--gem-font-heading); font-size: var(--gem-section-heading-size, var(--gem-h2)); line-height: var(--gem-font-heading-line-height, 1.1); letter-spacing: -0.01em; text-wrap: balance; }
|
|
2363
2349
|
:where(.gem-section[data-gem-body='section']) .gem-section__body { margin: 0; color: var(--gem-color-muted); font-size: var(--gem-body); line-height: var(--gem-font-body-line-height, 1.5); }
|
|
2364
2350
|
@media (max-width: 760px) {
|
|
2365
|
-
:where(.gem-section[data-gem-heading='section']) .gem-section__heading { font-size: min(var(--gem-h2), clamp(1.75rem, 9vw, 2.75rem)); }
|
|
2351
|
+
:where(.gem-section[data-gem-heading='section']) .gem-section__heading { font-size: var(--gem-section-heading-size-mobile, min(var(--gem-h2), clamp(1.75rem, 9vw, 2.75rem))); }
|
|
2366
2352
|
}
|
|
2367
2353
|
.gem-row:where(:not([hidden])) { --gem-row-auto-sm: repeat(var(--gem-row-cols-sm), minmax(0, 1fr)); --gem-row-auto-md: repeat(var(--gem-row-cols-md), minmax(0, 1fr)); --gem-row-auto-lg: repeat(var(--gem-row-cols), minmax(0, 1fr)); display: grid; grid-template-columns: var(--gem-row-tracks-sm, var(--gem-row-auto-sm, minmax(0, 1fr))); }
|
|
2368
2354
|
:where(.gem-row > *) { min-width: 0; --gem-row-cols: initial; --gem-row-cols-md: initial; --gem-row-cols-sm: initial; --gem-row-tracks: initial; --gem-row-tracks-md: initial; --gem-row-tracks-sm: initial; --gem-row-gap: initial; --gem-row-gap-y: initial; }
|
|
@@ -2370,7 +2356,7 @@ sticky-header.header-wrapper {
|
|
|
2370
2356
|
@media (min-width: 990px) { .gem-row { grid-template-columns: var(--gem-row-tracks, var(--gem-row-auto-lg, repeat(2, minmax(0, 1fr)))); } }
|
|
2371
2357
|
|
|
2372
2358
|
/* Dawn parity profile: locked default baseline; morph presets must opt out before applying Gem visual identity. */
|
|
2373
|
-
:root { --gem-profile-mode: dawn-parity; --gem-layout-page: 1100px; --gem-layout-gutter: 32px; --gem-layout-section: 52px; --gem-radius-md: 0px; --gem-card-radius: 0px; --gem-media-radius: 0px; --gem-grid-column-gap: 8px; --gem-grid-row-gap: 8px; }
|
|
2359
|
+
:root { --gem-profile-mode: dawn-parity; --gem-layout-page: 1100px; --gem-layout-gutter: 32px; --gem-layout-section: 52px; --gem-radius-md: 0px; --gem-card-radius: 0px; --gem-media-radius: 0px; --gem-grid-column-gap: 8px; --gem-grid-row-gap: 8px; --gem-heading-phone-cap: clamp(2rem, 11vw, 3.6rem); }
|
|
2374
2360
|
.utility-bar, .announcement-bar, .utility-bar__grid { min-height: 38px; }
|
|
2375
2361
|
.announcement-bar__message { margin: 0; min-height: 38px; padding-block: 10px; font-size: 0.75rem; font-weight: 400; letter-spacing: 0.04em; }
|
|
2376
2362
|
.announcement-bar__message span { font-size: 0.75rem; }
|
|
@@ -2423,7 +2409,9 @@ main > .gem-section:first-child { padding-top: 0; }
|
|
|
2423
2409
|
.gem-hero-banner--split-proof .gem-hero-banner__media, .gem-hero-banner--editorial .gem-hero-banner__media { position: relative; inset: auto; min-height: 26rem; height: 100%; overflow: hidden; border-radius: 6px; background: rgb(244 244 244); }
|
|
2424
2410
|
.gem-hero-banner--split-proof .gem-hero-banner__image, .gem-hero-banner--split-proof .gem-hero-banner__placeholder, .gem-hero-banner--editorial .gem-hero-banner__image, .gem-hero-banner--editorial .gem-hero-banner__placeholder { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
2425
2411
|
.gem-hero-banner .gem-section__content { max-width: 78rem; margin-inline: auto; }
|
|
2426
|
-
.gem-hero-banner h1, .gem-hero-banner h2, .gem-section__heading { margin: 0 0 1.5rem; font-
|
|
2412
|
+
.gem-hero-banner h1, .gem-hero-banner h2, .gem-section__heading { margin: 0 0 1.5rem; font-weight: 400; line-height: var(--gem-font-heading-line-height, 1.08); letter-spacing: 0; }
|
|
2413
|
+
.gem-section__heading { font-size: var(--gem-section-heading-size, clamp(calc(2.5rem * var(--gem-typography-heading-scale, 1)), calc(4vw * var(--gem-typography-heading-scale, 1)), calc(5.2rem * var(--gem-typography-heading-scale, 1)))); }
|
|
2414
|
+
.gem-hero-banner h1, .gem-hero-banner h2 { font-size: var(--gem-hero-heading-size, clamp(calc(2.5rem * var(--gem-typography-heading-scale, 1)), calc(4vw * var(--gem-typography-heading-scale, 1)), calc(5.2rem * var(--gem-typography-heading-scale, 1)))); }
|
|
2427
2415
|
.gem-section__eyebrow { display: none; }
|
|
2428
2416
|
.gem-hero-banner--compact-collection { min-height: auto; display: block; text-align: left; padding-block: 25px; }
|
|
2429
2417
|
.gem-hero-banner--compact-collection .gem-section__content, .gem-product-card-grid--quick-view-grid > .gem-section__inner { width: min(var(--gem-layout-page, 1200px), calc(100% - var(--gem-layout-gutter, 32px))); margin-inline: auto; }
|
|
@@ -2438,7 +2426,8 @@ main > .gem-section:first-child { padding-top: 0; }
|
|
|
2438
2426
|
.gem-rich-text--dawn-intro .gem-section__body { width: 100%; max-width: none; margin: 20px 0 0; font-size: 16px; line-height: 28.8px; }
|
|
2439
2427
|
.gem-rich-text--dawn-intro .gem-section__body p { margin: 0; }
|
|
2440
2428
|
.gem-rich-text--dawn-intro .gem-rich-text__blocks { display: block; width: 100%; }
|
|
2441
|
-
.gem-button { min-width: 12rem; border-radius: 0; font-weight: 400; box-shadow: none; }
|
|
2429
|
+
.gem-button { min-width: 12rem; border-radius: var(--gem-radius-button, 0); font-weight: 400; box-shadow: none; }
|
|
2430
|
+
.gem-button:where(:not(.gem-button--link)) { font-weight: var(--gem-font-button-weight, 400); }
|
|
2442
2431
|
.gem-product-card-wrapper { display: block; min-width: 0; }
|
|
2443
2432
|
.gem-card, .gem-product-card { border: 0; border-radius: 0; box-shadow: none; background: transparent; padding: 0; }
|
|
2444
2433
|
.gem-product-card__media, .gem-media { border: 0; border-radius: 0; box-shadow: none; background: rgb(244 244 244); }
|
|
@@ -2577,8 +2566,8 @@ main > .gem-section:first-child { padding-top: 0; }
|
|
|
2577
2566
|
.gem-shell-footer__payment-fallback { display: inline-grid; place-items: center; min-width: 38px; height: 24px; border: 1px solid rgb(18 18 18 / 12%); border-radius: 3px; background: white; color: rgb(18 18 18 / 72%); font-size: 8px; line-height: 1; }
|
|
2578
2567
|
.gem-shell-footer__localization { order: -1; flex: 0 0 100%; width: 100%; }
|
|
2579
2568
|
.gem-shell-footer__localization .gem-select, .gem-shell-footer__localization > .gem-select { display: inline-flex; align-items: center; min-width: 210px; min-height: 45px; border: 1px solid rgb(18 18 18 / 55%); border-radius: 0; background: transparent; padding: 10px 36px 10px 12px; color: rgb(18 18 18); font-size: 13px; line-height: 18px; }
|
|
2580
|
-
:where(.gem-section[data-gem-eyebrow='show']) .gem-section__eyebrow { display: block; letter-spacing: 0.12em; }
|
|
2581
|
-
:where(.gem-section[data-gem-heading='section']) .gem-section__heading { margin: 0; font-family: var(--gem-font-heading); font-size: var(--gem-h2); line-height: 1.1; letter-spacing: -0.01em; text-wrap: balance; }
|
|
2569
|
+
:where(.gem-section[data-gem-eyebrow='show']) .gem-section__eyebrow { display: block; font-size: var(--gem-text-sm); letter-spacing: 0.12em; }
|
|
2570
|
+
:where(.gem-section[data-gem-heading='section']) .gem-section__heading { margin: 0; font-family: var(--gem-font-heading); font-size: var(--gem-section-heading-size, var(--gem-h2)); line-height: var(--gem-font-heading-line-height, 1.1); letter-spacing: -0.01em; text-wrap: balance; }
|
|
2582
2571
|
:where(.gem-section[data-gem-body='section']) .gem-section__body { margin: 0; color: var(--gem-color-muted); font-size: var(--gem-body); line-height: var(--gem-font-body-line-height, 1.5); }
|
|
2583
2572
|
@media (max-width: 760px) {
|
|
2584
2573
|
:root { --gem-layout-gutter: 24px; --gem-layout-section: 36px; }
|
|
@@ -2615,7 +2604,8 @@ main > .gem-section:first-child { padding-top: 0; }
|
|
|
2615
2604
|
.gem-product-card__content { padding-top: 8px; gap: 4px; }
|
|
2616
2605
|
.gem-product-card__title { font-size: 15px; line-height: 24px; }
|
|
2617
2606
|
.gem-product-card__price, .gem-product-card__price .gem-price { font-size: 16px; line-height: 24px; }
|
|
2618
|
-
.gem-
|
|
2607
|
+
.gem-section__heading { font-size: var(--gem-section-heading-size-mobile, var(--gem-heading-phone-cap)); }
|
|
2608
|
+
.gem-hero-banner h1, .gem-hero-banner h2 { font-size: var(--gem-hero-heading-size-mobile, var(--gem-heading-phone-cap)); }
|
|
2619
2609
|
.gem-featured-collection--editorial-grid .gem-section__grid, .gem-product-card-grid--quick-view-grid .gem-section__grid, .gem-main-search .gem-section__grid { grid-template-columns: repeat(var(--gem-product-card-grid-mobile-columns, 2), minmax(0, 1fr)); }
|
|
2620
2610
|
.gem-product-main[data-gem-product-main-layout='dawn-main'] > .gem-section__inner { width: calc(100% - 30px); }
|
|
2621
2611
|
.gem-product-main[data-gem-product-main-layout='dawn-main'] .gem-product-media-gallery__frame { display: flex; gap: 0; overflow-x: auto; scroll-snap-type: x mandatory; }
|
|
@@ -2696,7 +2686,7 @@ main > .gem-section:first-child { padding-top: 0; }
|
|
|
2696
2686
|
.gem-hero-video--dawn-video > .gem-section__inner, .gem-hero-video--dawn-video .gem-hero-video__inner, .gem-hero-video--dawn-video .gem-hero-video__media { height: 212px; min-height: 212px; }
|
|
2697
2687
|
.gem-advanced-list--feature-grid { height: 420px; min-height: 420px; padding-block: 36px; }
|
|
2698
2688
|
.gem-advanced-list--feature-grid .gem-section__grid { grid-template-columns: 1fr; }
|
|
2699
|
-
:where(.gem-section[data-gem-heading='section']) .gem-section__heading { font-size: min(var(--gem-h2), clamp(1.75rem, 9vw, 2.75rem)); }
|
|
2689
|
+
:where(.gem-section[data-gem-heading='section']) .gem-section__heading { font-size: var(--gem-section-heading-size-mobile, min(var(--gem-h2), clamp(1.75rem, 9vw, 2.75rem))); }
|
|
2700
2690
|
}
|
|
2701
2691
|
.gem-row:where(:not([hidden])) { --gem-row-auto-sm: repeat(var(--gem-row-cols-sm), minmax(0, 1fr)); --gem-row-auto-md: repeat(var(--gem-row-cols-md), minmax(0, 1fr)); --gem-row-auto-lg: repeat(var(--gem-row-cols), minmax(0, 1fr)); display: grid; grid-template-columns: var(--gem-row-tracks-sm, var(--gem-row-auto-sm, minmax(0, 1fr))); }
|
|
2702
2692
|
:where(.gem-row > *) { min-width: 0; --gem-row-cols: initial; --gem-row-cols-md: initial; --gem-row-cols-sm: initial; --gem-row-tracks: initial; --gem-row-tracks-md: initial; --gem-row-tracks-sm: initial; --gem-row-gap: initial; --gem-row-gap-y: initial; }
|
package/dist/gem-runtime.js
CHANGED
|
@@ -382,7 +382,32 @@
|
|
|
382
382
|
const galleries = document.querySelectorAll('[data-gem-media-gallery], .gem-media-gallery, .gem-product-media-gallery');
|
|
383
383
|
let bound = 0;
|
|
384
384
|
galleries.forEach((gallery) => {
|
|
385
|
+
const hooked = !!(gallery.hasAttribute && gallery.hasAttribute('data-gem-media-gallery'));
|
|
386
|
+
if (!hooked && gallery.querySelector && gallery.querySelector('[data-gem-media-gallery]')) return;
|
|
385
387
|
if (!mark(gallery, 'media-gallery')) return;
|
|
388
|
+
const main = gallery.querySelector && gallery.querySelector('[data-gem-media-main]');
|
|
389
|
+
const thumbs = main && gallery.querySelectorAll ? Array.prototype.slice.call(gallery.querySelectorAll('[data-gem-media-item]')) : [];
|
|
390
|
+
if (main && thumbs.length) {
|
|
391
|
+
gallery.dataset.gemMediaState = 'ready';
|
|
392
|
+
const choose = (item, reason) => {
|
|
393
|
+
const src = item.getAttribute('data-gem-media-src');
|
|
394
|
+
const alt = item.getAttribute('data-gem-media-alt');
|
|
395
|
+
if (src) { main.setAttribute('src', src); main.removeAttribute('srcset'); if (alt != null) main.setAttribute('alt', alt); }
|
|
396
|
+
const index = Number(item.getAttribute('data-gem-media-index') || thumbs.indexOf(item));
|
|
397
|
+
thumbs.forEach((thumb) => { const on = thumb === item; thumb.setAttribute('aria-current', String(on)); if (thumb.dataset) thumb.dataset.gemMediaActive = on ? 'true' : 'false'; });
|
|
398
|
+
gallery.dataset.gemMediaActiveIndex = String(index);
|
|
399
|
+
if (gallery.dispatchEvent && typeof window.CustomEvent === 'function') gallery.dispatchEvent(new window.CustomEvent('gem:media:select', { bubbles: true, detail: { index } }));
|
|
400
|
+
api.emit('gem:media:change', { source: 'gem-runtime', index, galleryId: gallery.id || undefined, reason });
|
|
401
|
+
};
|
|
402
|
+
if (canListen(gallery)) gallery.addEventListener('click', (event) => {
|
|
403
|
+
const item = event.target && event.target.closest ? event.target.closest('[data-gem-media-item]') : null;
|
|
404
|
+
if (!item || !gallery.contains(item)) return;
|
|
405
|
+
if (event.preventDefault) event.preventDefault();
|
|
406
|
+
choose(item, 'click');
|
|
407
|
+
});
|
|
408
|
+
bound += 1;
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
386
411
|
const items = gallery.querySelectorAll('[data-gem-media-item], img, video, model-viewer');
|
|
387
412
|
const thumbControls = gallery.querySelectorAll('[data-gem-media-thumb]');
|
|
388
413
|
const controls = thumbControls.length ? thumbControls : items;
|
|
@@ -488,7 +513,11 @@
|
|
|
488
513
|
else if (k === 'Home') { if (e.preventDefault) e.preventDefault(); focusDot(0); }
|
|
489
514
|
else if (k === 'End') { if (e.preventDefault) e.preventDefault(); focusDot(dots.length - 1); }
|
|
490
515
|
}); });
|
|
491
|
-
|
|
516
|
+
// The visible label follows the state like the section's own behavior did: the button's own text while playing
|
|
517
|
+
// (kept, so a translated label survives), data-gem-hero-play-label (or 'Play') while paused. Only a text-only button.
|
|
518
|
+
const pauseText = pause && pause.childElementCount === 0 ? pause.textContent : null;
|
|
519
|
+
const playText = (pause && pause.getAttribute && pause.getAttribute('data-gem-hero-play-label')) || 'Play';
|
|
520
|
+
if (canListen(pause)) pause.addEventListener('click', () => { paused = !paused; if (pause.setAttribute) pause.setAttribute('aria-pressed', String(paused)); if (pauseText !== null) pause.textContent = paused ? playText : pauseText; start(); });
|
|
492
521
|
show(active); start(); bound += 1;
|
|
493
522
|
});
|
|
494
523
|
api.emit('gem:hero-slideshow:ready', { source: 'gem-runtime', count: bound });
|
|
@@ -668,8 +697,22 @@
|
|
|
668
697
|
};
|
|
669
698
|
update();
|
|
670
699
|
if (canListen(target)) target.addEventListener('scroll', update, { passive: true });
|
|
700
|
+
const priceEl = bar.querySelector && bar.querySelector('[data-gem-sticky-atc-price]');
|
|
701
|
+
const select = bar.querySelector && bar.querySelector('select');
|
|
702
|
+
const syncPrice = () => { if (!priceEl || !select) return; const opt = select.options && select.selectedIndex > -1 ? select.options[select.selectedIndex] : null; const price = opt && opt.getAttribute && opt.getAttribute('data-gem-variant-price'); if (price) priceEl.textContent = price; };
|
|
703
|
+
if (canListen(select)) select.addEventListener('change', syncPrice);
|
|
704
|
+
syncPrice();
|
|
671
705
|
const form = bar.querySelector && bar.querySelector('form');
|
|
672
|
-
if (canListen(form)) form.addEventListener('submit', () =>
|
|
706
|
+
if (canListen(form)) form.addEventListener('submit', (event) => {
|
|
707
|
+
if (!(form.hasAttribute && form.hasAttribute('action'))) {
|
|
708
|
+
if (event && event.preventDefault) event.preventDefault();
|
|
709
|
+
const choice = form.querySelector && form.querySelector('select');
|
|
710
|
+
const trigger = bar.querySelector && bar.querySelector('[data-gem-variant-id]');
|
|
711
|
+
const variantId = (choice && choice.value) || (trigger && trigger.getAttribute('data-gem-variant-id')) || undefined;
|
|
712
|
+
if (bar.dispatchEvent && typeof window.CustomEvent === 'function') bar.dispatchEvent(new window.CustomEvent('gem:cart:add', { bubbles: true, detail: { variantId, quantity: 1 } }));
|
|
713
|
+
}
|
|
714
|
+
api.emit('gem:sticky-atc:submit', { source: 'gem-runtime', id: bar.id || undefined });
|
|
715
|
+
});
|
|
673
716
|
bound += 1;
|
|
674
717
|
});
|
|
675
718
|
api.emit('gem:sticky-atc:ready', { source: 'gem-runtime', count: bound });
|