@gemboss/gem-framework 0.18.13 → 0.18.15

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 CHANGED
@@ -93,6 +93,34 @@ Từ 0.8.2 mỗi module có `.d.ts` cạnh nó (`mount(root?: ParentNode | null,
93
93
 
94
94
  ## Nhật ký thay đổi
95
95
 
96
+ - **0.18.15** (20/10/2026): plugin `reviews`, engine danh sách review (GemFactory gap #44). 8 section product-reviews của
97
+ GemFactory mỗi cái mang một bản riêng của cùng một lõi trong behavior.js (14–27 KB mỗi cái); nay lõi đó là MỘT plugin:
98
+ `gem-runtime.js` (load `idle`) hoặc `import { mount } from "@gemboss/gem-framework/plugins/reviews"`. Section xin engine bằng
99
+ `data-rv-root` trên gốc của nó; section không có dấu đó (vẫn mang lõi riêng) không bị gắn, nên lõi riêng và plugin không chạy
100
+ chồng. Hợp đồng chỉ là thuộc tính `data-rv-*` (đầy đủ ở đầu `reviews-engine.ts`):
101
+ - Lõi: sort (menu hoặc select, 13 khoá), lọc sao / có ảnh / chủ đề / quốc gia / tìm (trễ 180 ms) / xoá lọc, trang số (một hay
102
+ nhiều thanh, cửa sổ cố định hoặc `1 2 3 4 … n`) hoặc xem thêm, đếm, đọc thêm, menu, sheet lọc, hữu ích một lần mỗi review
103
+ (`gem:review:vote` trên hub và trên window), lightbox.
104
+ - Chỗ 8 section khác nhau thành thuộc tính: thu gọn N review đầu (`data-rv-collapsed` + `data-rv-expand`), Show N mỗi trang,
105
+ nhãn trang, sao giữ khi bấm lại (`data-rv-star-keep`), chip bộ lọc đang bật, sheet có Apply / Reset, vùng bật tắt và vùng tự
106
+ bỏ lọc khi đóng, dải trượt, tô chữ tìm thấy, chữ số ít (`data-rv-count-one`, `data-rv-status-one`), số theo locale
107
+ (`data-rv-locale`), lightbox (đầu cuối ẩn / mờ / vòng, tập ảnh theo review / nhóm / danh sách JSON của thẻ, bỏ trùng, ảnh kế
108
+ ló ra, vuốt, nền mờ, bỏ phiếu từ trong lightbox hoặc chỉ xem).
109
+ - Khác bản cũ có chủ đích: chọn một mục trong menu thì focus về nút của menu (bản cũ để focus rơi xuống `<body>`); cửa sổ trang
110
+ cố định không còn vẽ dấu … trước trang đầu cửa sổ.
111
+ - Còn ở behavior của từng section: masonry, carousel vòng vô tận + tự chạy, hộp đọc cả review, dịch, sắp xếp hỏi đáp, thẻ chen
112
+ giữa. Chúng vẽ lại theo `gem:reviews:render` (phát trên hub VÀ trên gốc section), và nhờ engine vẽ lại bằng
113
+ `gem:reviews:refresh` trên gốc.
114
+ Đối chiếu trong Chromium trên markup thật của cả 8 section, cùng một chuỗi thao tác (sort, sao, lọc, trang, xem thêm, đọc thêm,
115
+ hữu ích, lightbox, menu; 1280 và 390), behavior.js gốc so với engine: trạng thái trùng từng bước, trừ khác biệt có chủ đích ở trên
116
+ và phần còn ở section.
117
+ - **0.18.14** (20/10/2026): lớp phủ tối là một token (GemFactory gap #17). Khoá màu TUỲ CHỌN `color.scrim` (phát thành
118
+ `--gem-color-scrim`) là màu lớp phủ ở độ đậm tối đa; nền sau dialog popup (55%), lớp tối trên ảnh nền popup (35% → 60%), nền sau
119
+ cart drawer (36%) và lớp tối trên ảnh của hero mặc định (32%) đọc nó qua `gemScrim(N)` = `color-mix(in srgb,
120
+ var(--gem-color-scrim, #000) N%, transparent)`. Không đặt thì ra ĐÚNG như trước (đo Chromium: 5/5 độ đậm trùng từng giá trị
121
+ pixel với màu viết cứng cũ); preset đặt màu có alpha (`rgb(0 0 0 / .7)`) thì mọi lớp phủ nhạt cùng tỉ lệ. Băng dark / accent
122
+ không đảo khoá này. Cảnh báo `untokenized_visual_value` trên một màu đen có alpha giờ chỉ thẳng cách viết bằng token, giữ đúng
123
+ độ đậm.
96
124
  - **0.18.13** (20/10/2026): ô nhập, select, textarea có trạng thái hover và lỗi (§9.2; GemFactory Framework › Controls đo cả
97
125
  hai là INERT). Hover dày viền thêm 1px theo màu chữ của ô (vòng theo hộp; ô gạch chân và ô tô nền chỉ dày cạnh đáy), chỉ trên
98
126
  máy có chuột (`@media (hover: hover)`), không áp cho ô disabled hay ô lỗi. Lỗi (`aria-invalid="true"`, do form đặt) tô viền
package/dist/SOURCE.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "package": "@gemboss/gem-framework",
3
- "version": "0.18.13",
4
- "gemtheme_sha": "74aee046a4ea5b333966a87c337ec1d855508775",
3
+ "version": "0.18.15",
4
+ "gemtheme_sha": "998fe4dc3096e9bc0a8e9d39e23b27081138b2c9",
5
5
  "gemtheme_dirty": false,
6
- "framework_version": "0.18.13"
6
+ "framework_version": "0.18.15"
7
7
  }
package/dist/editions.js CHANGED
@@ -83,6 +83,8 @@ var GEM_MOTION_SCALE_DEFAULTS = {
83
83
  blur: "8px"
84
84
  };
85
85
  var optionalGemTokenKeys = {
86
+ // Lớp phủ tối (GemFactory gap #17): xem GEM_SCRIM_FALLBACK / gemScrim bên dưới.
87
+ color: ["scrim"],
86
88
  typography: [...GEM_TYPE_RAMP_KEYS, ...GEM_LINE_HEIGHT_TOKEN_KEYS, ...GEM_BUTTON_TOKEN_KEYS.typography],
87
89
  spacing: [...Object.keys(GEM_DERIVED_SPACE_STEPS), ...GEM_PHONE_TOKEN_TARGETS.spacing.map((k) => `${k}Mobile`)],
88
90
  layout: GEM_PHONE_TOKEN_TARGETS.layout.map((k) => `${k}Mobile`),
@@ -9,6 +9,7 @@
9
9
  --gem-color-success: #008060;
10
10
  --gem-color-warning: #9a661a;
11
11
  --gem-color-danger: #d72c0d;
12
+ --gem-color-scrim: #000;
12
13
  --gem-font-body: Inter, system-ui, sans-serif;
13
14
  --gem-font-heading: Inter, system-ui, sans-serif;
14
15
  --gem-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
@@ -1295,7 +1296,7 @@ a {
1295
1296
  .gem-cart-drawer__overlay {
1296
1297
  position: fixed;
1297
1298
  inset: 0;
1298
- background: rgba(0, 0, 0, 0.36);
1299
+ background: color-mix(in srgb, var(--gem-color-scrim, #000) 36%, transparent);
1299
1300
  }
1300
1301
  @keyframes gem-cart-drawer-panel-in { from { translate: calc(var(--gem-drawer-offset, 24px) * var(--gem-drawer-dir, 1)) 0; opacity: 0; } }
1301
1302
  @keyframes gem-cart-drawer-overlay-in { from { opacity: 0; } }
@@ -1571,7 +1572,7 @@ a {
1571
1572
  width: min(880px, 92vw); max-width: none; max-height: min(640px, 92vh); overflow: hidden;
1572
1573
  border-radius: var(--gem-radius-lg); box-shadow: var(--gem-shadow-md);
1573
1574
  }
1574
- .gem-popup-shell__dialog::backdrop { background: rgb(0 0 0 / 0.55); }
1575
+ .gem-popup-shell__dialog::backdrop { background: color-mix(in srgb, var(--gem-color-scrim, #000) 55%, transparent); }
1575
1576
  .gem-popup-shell__frame { position: relative; display: grid; grid-template-columns: 1fr 1fr; min-height: 520px; height: 100%; }
1576
1577
  .gem-popup-shell__media { position: relative; min-width: 0; overflow: hidden; background: var(--gem-color-surface); }
1577
1578
  .gem-popup-shell__image { display: block; width: 100%; height: 100%; object-fit: cover; }
@@ -1594,7 +1595,7 @@ a {
1594
1595
  .gem-popup-shell[data-gem-popup-desktop='card-over-image'] .gem-popup-shell__panel {
1595
1596
  width: min(420px, 86%); margin: var(--gem-space-xl) 0; background: var(--gem-color-background); border-radius: var(--gem-radius-lg); box-shadow: var(--gem-shadow-sm);
1596
1597
  }
1597
- .gem-popup-shell[data-gem-popup-media='background'] .gem-popup-shell__media::after { content: ''; position: absolute; inset: 0; background: linear-gradient(rgb(0 0 0 / 0.35), rgb(0 0 0 / 0.6)); }
1598
+ .gem-popup-shell[data-gem-popup-media='background'] .gem-popup-shell__media::after { content: ''; position: absolute; inset: 0; background: linear-gradient(color-mix(in srgb, var(--gem-color-scrim, #000) 35%, transparent), color-mix(in srgb, var(--gem-color-scrim, #000) 60%, transparent)); }
1598
1599
  .gem-popup-shell[data-gem-popup-media='background'] .gem-popup-shell__panel,
1599
1600
  .gem-popup-shell[data-gem-popup-media='background'] .gem-popup-shell__close { color: #fff; }
1600
1601
  .gem-popup-shell__close {
@@ -1641,10 +1642,10 @@ a {
1641
1642
  .gem-popup-shell[data-gem-popup-media='background'] .gem-popup-shell__frame { grid-template-rows: 1fr; }
1642
1643
  .gem-popup-shell[data-gem-popup-media='background'] .gem-popup-shell__media { position: absolute; inset: 0; max-height: none; }
1643
1644
  }
1644
- :root:not(:has([data-gem-canvas])) .gem-popup-shell[data-gem-popup-preview='true'] { position: fixed; inset: 0; z-index: 1000; padding: 0; background: rgb(0 0 0 / 0.55); }
1645
+ :root:not(:has([data-gem-canvas])) .gem-popup-shell[data-gem-popup-preview='true'] { position: fixed; inset: 0; z-index: 1000; padding: 0; background: color-mix(in srgb, var(--gem-color-scrim, #000) 55%, transparent); }
1645
1646
  :root:not(:has([data-gem-canvas])) .gem-popup-shell[data-gem-popup-preview='true'] .gem-popup-shell__dialog { position: fixed; inset: 0; display: block; }
1646
1647
  :root:has([data-gem-canvas]) .gem-popup-shell[data-gem-popup-preview='true'] .gem-popup-shell__dialog { position: relative; display: block; inset: auto; }
1647
- :root:has([data-gem-canvas]) .gem-popup-shell[data-gem-popup-preview='true'] { padding: var(--gem-space-xl) var(--gem-layout-gutter); background: rgb(0 0 0 / 0.55); }
1648
+ :root:has([data-gem-canvas]) .gem-popup-shell[data-gem-popup-preview='true'] { padding: var(--gem-space-xl) var(--gem-layout-gutter); background: color-mix(in srgb, var(--gem-color-scrim, #000) 55%, transparent); }
1648
1649
  @media (min-width: 750px) {
1649
1650
  :root:has([data-gem-canvas]) .gem-popup-shell[data-gem-popup-preview='true'][data-gem-popup-desktop='fullscreen'] { padding: 0; }
1650
1651
  :root:has([data-gem-canvas]) .gem-popup-shell[data-gem-popup-preview='true'][data-gem-popup-desktop='fullscreen'] .gem-popup-shell__dialog { height: 720px; max-height: none; }
@@ -2474,7 +2475,7 @@ main > .gem-section:first-child { padding-top: 0; }
2474
2475
  .gem-hero-banner--default { position: relative; overflow: hidden; padding: 0; color: white; place-items: stretch; }
2475
2476
  .gem-hero-banner--default .gem-hero-banner__inner { position: static; width: 100%; min-height: 720px; height: 100%; display: grid; align-items: end; justify-items: center; padding-bottom: 0; }
2476
2477
  .gem-hero-banner--default .gem-hero-banner__media { position: absolute; inset: 0; z-index: 0; }
2477
- .gem-hero-banner--default .gem-hero-banner__media::after { content: ''; position: absolute; inset: 0; background: rgb(0 0 0 / 32%); }
2478
+ .gem-hero-banner--default .gem-hero-banner__media::after { content: ''; position: absolute; inset: 0; background: color-mix(in srgb, var(--gem-color-scrim, #000) 32%, transparent); }
2478
2479
  .gem-hero-banner--default .gem-hero-banner__image, .gem-hero-banner--default .gem-hero-banner__placeholder { width: 100%; height: 100%; object-fit: cover; display: block; }
2479
2480
  .gem-hero-banner--default .gem-hero-banner__copy { position: absolute; z-index: 1; left: 50%; bottom: 50px; transform: translateX(-50%); width: min(702px, 100%); margin: 0; padding: 40px 0; text-align: center; display: block; }
2480
2481
  .gem-hero-banner--default .gem-section__heading { margin: 0; font-size: 52px; line-height: 67.6px; color: currentColor; }