@gemboss/gem-framework 0.18.16 → 0.20.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 +109 -1
- package/dist/SOURCE.json +3 -3
- package/dist/gem-framework.css +23 -1
- package/dist/gem-runtime.js +97 -54
- package/dist/index.js +2511 -44
- package/dist/motion/core.d.ts +208 -0
- package/dist/motion/core.js +1 -0
- package/dist/motion/orbit.d.ts +4 -0
- package/dist/motion/orbit.js +1 -0
- package/dist/motion/quick-view.d.ts +4 -0
- package/dist/motion/quick-view.js +1 -0
- package/dist/motion/rail.d.ts +5 -0
- package/dist/motion/rail.js +1 -0
- package/dist/orbit-base.css +39 -0
- package/dist/plugins/before_after.js +1 -1
- package/dist/plugins/bundle.js +1 -1
- package/dist/plugins/carousel.js +1 -1
- package/dist/plugins/cart-drawer.js +1 -1
- package/dist/plugins/context-adapter.js +1 -1
- package/dist/plugins/countdown.js +1 -1
- package/dist/plugins/delivery-estimate.d.ts +9 -0
- package/dist/plugins/delivery-estimate.js +1 -0
- package/dist/plugins/disclosure.js +1 -1
- package/dist/plugins/hero-slideshow.js +1 -1
- package/dist/plugins/img-in.js +1 -1
- package/dist/plugins/localization.js +1 -1
- package/dist/plugins/media-gallery.js +1 -1
- package/dist/plugins/mobile-menu.js +1 -1
- package/dist/plugins/offer-engine.js +1 -1
- package/dist/plugins/orbit.d.ts +9 -0
- package/dist/plugins/orbit.js +1 -0
- package/dist/plugins/personalize.d.ts +9 -0
- package/dist/plugins/personalize.js +1 -0
- package/dist/plugins/predictive-search.js +1 -1
- package/dist/plugins/print-preview.d.ts +9 -0
- package/dist/plugins/print-preview.js +1 -0
- package/dist/plugins/promo-popup.js +1 -1
- package/dist/plugins/quantity-input.js +1 -1
- package/dist/plugins/quick-view.js +1 -69
- package/dist/plugins/rail.d.ts +9 -0
- package/dist/plugins/rail.js +1 -0
- package/dist/plugins/recently-viewed.js +1 -1
- package/dist/plugins/reveal-on-scroll.js +1 -1
- package/dist/plugins/reviews.js +1 -1
- package/dist/plugins/runtime-slot-loader.js +1 -1
- package/dist/plugins/seasonal-effects.js +1 -1
- package/dist/plugins/size-guide.d.ts +9 -0
- package/dist/plugins/size-guide.js +38 -0
- package/dist/plugins/sticky-atc.js +1 -1
- package/dist/plugins/tabs.js +1 -1
- package/dist/plugins/variant-selects.js +1 -1
- package/dist/pod/core.d.ts +26 -0
- package/dist/pod/core.js +1 -0
- package/dist/pod/delivery-estimate.d.ts +28 -0
- package/dist/pod/delivery-estimate.js +1 -0
- package/dist/pod/personalize.d.ts +25 -0
- package/dist/pod/personalize.js +1 -0
- package/dist/pod/print-preview.d.ts +8 -0
- package/dist/pod/print-preview.js +1 -0
- package/dist/pod-buybox.css +55 -0
- package/dist/popup-shell.css +15 -0
- package/dist/primitives.css +4 -1
- package/dist/rail-base.css +48 -0
- package/dist/runtime-core.d.ts +2 -0
- package/dist/runtime-core.js +26 -15
- package/dist/section-gate.js +2522 -36
- package/dist/tokens.css +4 -0
- package/package.json +20 -1
|
@@ -1,69 +1 @@
|
|
|
1
|
-
|
|
2
|
-
// packages/gem-framework/src/runtime.ts, the same lines gem-runtime.js carries; do not edit here.
|
|
3
|
-
import { mountPlugin } from "../runtime-core.js";
|
|
4
|
-
|
|
5
|
-
export const key = "quick-view";
|
|
6
|
-
export const readyEvent = "gem:quick-view:ready";
|
|
7
|
-
|
|
8
|
-
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin }) {
|
|
9
|
-
registerPlugin('quick-view', ({ api }) => {
|
|
10
|
-
const triggers = document.querySelectorAll('[data-gem-quick-view], [data-gem-action="quick-view"]');
|
|
11
|
-
const surface = document.querySelector('[data-gem-quick-view-surface], .gem-quick-view, .gem-modal[data-gem-component="quick-view"]');
|
|
12
|
-
let bound = 0;
|
|
13
|
-
const close = (reason = 'close-control') => {
|
|
14
|
-
if (surface) {
|
|
15
|
-
surface.dataset.gemQuickViewState = 'closed';
|
|
16
|
-
surface.removeAttribute && surface.removeAttribute('open');
|
|
17
|
-
surface.setAttribute && surface.setAttribute('aria-hidden', 'true');
|
|
18
|
-
}
|
|
19
|
-
api.emit('gem:quick-view:close', { source: 'gem-runtime', reason });
|
|
20
|
-
};
|
|
21
|
-
const openSurface = (detail) => {
|
|
22
|
-
if (surface) {
|
|
23
|
-
surface.dataset.gemQuickViewState = 'open';
|
|
24
|
-
surface.dataset.gemProductHandle = detail.productHandle || '';
|
|
25
|
-
surface.dataset.gemProductUrl = detail.productUrl || '';
|
|
26
|
-
surface.setAttribute && surface.setAttribute('open', '');
|
|
27
|
-
surface.setAttribute && surface.setAttribute('aria-hidden', 'false');
|
|
28
|
-
surface.setAttribute && surface.setAttribute('role', 'dialog');
|
|
29
|
-
surface.setAttribute && surface.setAttribute('aria-modal', 'true');
|
|
30
|
-
const content = surface.querySelector && surface.querySelector('[data-gem-quick-view-content]');
|
|
31
|
-
if (content && content.textContent !== undefined) content.textContent = 'Quick view for ' + (detail.productHandle || 'product');
|
|
32
|
-
else if (surface.textContent !== undefined) surface.textContent = 'Quick view for ' + (detail.productHandle || 'product');
|
|
33
|
-
const closeButton = surface.querySelector && surface.querySelector('[data-gem-quick-view-close]');
|
|
34
|
-
if (closeButton && closeButton.focus) closeButton.focus();
|
|
35
|
-
}
|
|
36
|
-
api.emit('gem:quick-view:open', { source: 'gem-runtime', ...detail, hasSurface: Boolean(surface) });
|
|
37
|
-
};
|
|
38
|
-
triggers.forEach((trigger) => {
|
|
39
|
-
if (!mark(trigger, 'quick-view')) return;
|
|
40
|
-
if (!canListen(trigger)) return;
|
|
41
|
-
__gemListen(trigger, 'click', (event) => {
|
|
42
|
-
const productUrl = trigger.getAttribute && (trigger.getAttribute('data-gem-product-url') || trigger.getAttribute('href'));
|
|
43
|
-
const productHandle = trigger.getAttribute && trigger.getAttribute('data-gem-product-handle');
|
|
44
|
-
if (!productUrl && !productHandle) return;
|
|
45
|
-
event.preventDefault && event.preventDefault();
|
|
46
|
-
openSurface({ productUrl, productHandle });
|
|
47
|
-
});
|
|
48
|
-
bound += 1;
|
|
49
|
-
});
|
|
50
|
-
if (surface && mark(surface, 'quick-view-surface')) {
|
|
51
|
-
surface.dataset.gemQuickViewState = 'closed';
|
|
52
|
-
surface.setAttribute && surface.setAttribute('aria-hidden', 'true');
|
|
53
|
-
if (canListen(surface)) __gemListen(surface, 'click', (event) => {
|
|
54
|
-
const target = event.target;
|
|
55
|
-
if (target && target.closest && target.closest('[data-gem-quick-view-close]')) close('close-control');
|
|
56
|
-
});
|
|
57
|
-
if (canListen(surface)) __gemListen(surface, 'keydown', (event) => { if (event.key === 'Escape') close('escape'); });
|
|
58
|
-
}
|
|
59
|
-
api.quickView = { open: (detail = {}) => openSurface({ ...detail }), close };
|
|
60
|
-
api.emit('gem:quick-view:ready', { source: 'gem-runtime', count: bound, hasSurface: Boolean(surface) });
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Bind every "quick-view" hook inside root (default: the whole document). Returns unmount(). Mounting the same root twice binds once. */
|
|
65
|
-
export function mount(root, options) {
|
|
66
|
-
return mountPlugin(key, install, root, options);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export default mount;
|
|
1
|
+
import{mountPlugin as w}from"../runtime-core.js";import{mountEffects as b}from"../motion/core.js";import{quickViewEffect as h}from"../motion/quick-view.js";const _="quick-view",E="gem:quick-view:ready";function q({document:a,window:u,target:y,mark:m,canListen:c,listen:n,registerPlugin:v,registerNoopPlugin:A,onUnmount:f}){v("quick-view",({api:o})=>{const k=a.querySelectorAll('[data-gem-quick-view], [data-gem-action="quick-view"]'),e=a.querySelector('[data-gem-quick-view-surface], .gem-quick-view, .gem-modal[data-gem-component="quick-view"]');let l=0;const g=(t="close-control")=>{e&&(e.dataset.gemQuickViewState="closed",e.removeAttribute&&e.removeAttribute("open"),e.setAttribute&&e.setAttribute("aria-hidden","true")),o.emit("gem:quick-view:close",{source:"gem-runtime",reason:t})},d=t=>{if(e){e.dataset.gemQuickViewState="open",e.dataset.gemProductHandle=t.productHandle||"",e.dataset.gemProductUrl=t.productUrl||"",e.setAttribute&&e.setAttribute("open",""),e.setAttribute&&e.setAttribute("aria-hidden","false"),e.setAttribute&&e.setAttribute("role","dialog"),e.setAttribute&&e.setAttribute("aria-modal","true");const i=e.querySelector&&e.querySelector("[data-gem-quick-view-content]");i&&i.textContent!==void 0?i.textContent="Quick view for "+(t.productHandle||"product"):e.textContent!==void 0&&(e.textContent="Quick view for "+(t.productHandle||"product"));const r=e.querySelector&&e.querySelector("[data-gem-quick-view-close]");r&&r.focus&&r.focus()}o.emit("gem:quick-view:open",{source:"gem-runtime",...t,hasSurface:!!e})};k.forEach(t=>{m(t,"quick-view")&&c(t)&&(n(t,"click",i=>{const r=t.getAttribute&&(t.getAttribute("data-gem-product-url")||t.getAttribute("href")),s=t.getAttribute&&t.getAttribute("data-gem-product-handle");!r&&!s||(i.preventDefault&&i.preventDefault(),d({productUrl:r,productHandle:s}))}),l+=1)}),e&&m(e,"quick-view-surface")&&(e.dataset.gemQuickViewState="closed",e.setAttribute&&e.setAttribute("aria-hidden","true"),c(e)&&n(e,"click",t=>{const i=t.target;i&&i.closest&&i.closest("[data-gem-quick-view-close]")&&g("close-control")}),c(e)&&n(e,"keydown",t=>{t.key==="Escape"&&g("escape")})),(e||!o.quickView)&&(o.quickView={open:(t={})=>d({...t}),close:g});const p=b(h,{window:u,document:a,on:(t,i,r,s)=>{c(t)&&n(t,i,r,s)},mark:m,api:o,css:"[data-gem-quick-view-trigger]{--gem-quick-view-css:1}.gem-quick-view__shell{display:contents}.gem-quick-view__shell .gem-quick-view__dialog{overflow:visible;isolation:isolate;color:var(--gem-color-text);background:transparent;box-shadow:none;user-select:text;-webkit-user-select:text}.gem-quick-view__surface{position:absolute;inset:0;z-index:-1;border-radius:inherit;box-shadow:var(--gem-shadow-md);background:color-mix(in srgb,var(--gem-motion-tint,var(--gem-color-background)) 45%,var(--gem-color-background));transition:background-color var(--gem-motion-slow,0.5s) var(--gem-ease-soft,ease)}.gem-quick-view__shell .gem-quick-view__media{overflow:visible;background:transparent;min-height:0}.gem-quick-view__image{position:absolute;inset:6% 4%;width:92%;height:88%;object-fit:contain;transform-origin:50% 50%;will-change:transform}.gem-quick-view__image--next{opacity:0;pointer-events:none}.gem-quick-view__image--next:not([src]){display:none}.gem-quick-view__shell .gem-quick-view__panel{justify-content:flex-start;gap:var(--gem-space-sm)}.gem-quick-view__shell [hidden]{display:none}.gem-quick-view__bar{display:flex;align-items:center;gap:var(--gem-space-xs);font-family:var(--gem-font-mono);font-size:var(--gem-text-xs);font-variant-numeric:tabular-nums}.gem-quick-view__icon{display:inline-grid;place-items:center;width:var(--gem-tap-min);height:var(--gem-tap-min);padding:0;cursor:pointer;border:var(--gem-stroke,1px) solid color-mix(in srgb,currentColor 25%,transparent);border-radius:var(--gem-radius-pill);color:inherit;background:transparent;font:inherit;font-size:var(--gem-h5);line-height:1}.gem-quick-view__icon:hover{border-color:currentColor}.gem-quick-view__icon:focus-visible,.gem-quick-view__swatch:focus-visible,.gem-quick-view__size:focus-visible,.gem-quick-view__details:focus-visible{outline:var(--gem-focus-ring);outline-offset:var(--gem-focus-offset)}.gem-quick-view__eyebrow{margin:var(--gem-space-md) 0 0;color:var(--gem-color-muted);font-family:var(--gem-font-mono);font-size:var(--gem-text-xs);letter-spacing:0.12em;line-height:1.3;text-transform:uppercase}.gem-quick-view__title{margin:0;font-family:var(--gem-font-heading);font-size:var(--gem-h2);line-height:1.05}.gem-quick-view__price{margin:0;font-size:var(--gem-h5);font-variant-numeric:tabular-nums}.gem-quick-view__compare{margin:calc(-1 * var(--gem-space-xs)) 0 0;color:var(--gem-color-muted);font-size:var(--gem-text-sm)}.gem-quick-view__swatches,.gem-quick-view__sizes{display:flex;flex-wrap:wrap;gap:var(--gem-space-xs)}.gem-quick-view__swatch{position:relative;width:var(--gem-tap-min);height:var(--gem-tap-min);padding:0;border:0;color:inherit;background:transparent;cursor:pointer}.gem-quick-view__swatch::before{content:'';position:absolute;inset:8px;border-radius:var(--gem-radius-pill);background:var(--gem-quick-view-swatch,var(--gem-color-surface));box-shadow:inset 0 0 0 var(--gem-stroke,1px) color-mix(in srgb,var(--gem-color-text) 15%,transparent)}.gem-quick-view__swatch[aria-checked='true']::after{content:'';position:absolute;inset:3px;border:var(--gem-stroke-thick,2px) solid currentColor;border-radius:var(--gem-radius-pill)}.gem-quick-view__size{display:inline-grid;place-items:center;min-width:var(--gem-tap-min);height:var(--gem-tap-min);padding:0 var(--gem-space-sm);cursor:pointer;border:var(--gem-stroke,1px) solid color-mix(in srgb,currentColor 22%,transparent);border-radius:var(--gem-radius-pill);color:inherit;background:transparent;font:inherit;font-size:var(--gem-text-sm)}.gem-quick-view__size[aria-checked='true']{color:var(--gem-color-background);background:var(--gem-color-text);border-color:var(--gem-color-text)}.gem-quick-view__size:disabled{opacity:0.4;text-decoration:line-through;cursor:not-allowed}.gem-quick-view__add{width:100%;margin:var(--gem-space-xs) 0 0;font-variant-numeric:tabular-nums}.gem-quick-view__status{margin:0;min-height:1.2em;color:var(--gem-color-muted);font-size:var(--gem-text-sm)}.gem-quick-view__description{margin:0;max-width:46ch;font-size:var(--gem-text-sm);line-height:1.55}.gem-quick-view__details{color:inherit;font-size:var(--gem-text-sm);text-underline-offset:3px}[data-gem-quick-view-source]{visibility:hidden}@keyframes gem-quick-view-fade{from{opacity:0}to{opacity:1}}.gem-quick-view__dialog[data-gem-state='open']::backdrop{animation:gem-quick-view-fade var(--gem-motion-base,0.35s) ease both}.gem-quick-view__dialog[data-gem-state='closing']::backdrop{animation:gem-quick-view-fade var(--gem-motion-base,0.35s) ease reverse both}@media (max-width:749px){.gem-quick-view__shell .gem-quick-view__media{height:34dvh}}@media (prefers-reduced-motion:reduce){.gem-quick-view__dialog::backdrop{animation:none}.gem-quick-view__surface{transition:none}}"},f);o.emit("gem:quick-view:ready",{source:"gem-runtime",count:l+p,hasSurface:!!e})})}function x(a,u){return w(_,q,a,u)}var H=x;export{H as default,_ as key,x as mount,E as readyEvent};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// @gemboss/gem-framework/plugins/rail: types of the ES module next to this file. Generated; do not edit here.
|
|
2
|
+
import type { MountOptions, Unmount } from "../runtime-core.js";
|
|
3
|
+
|
|
4
|
+
export type { MountOptions, Unmount };
|
|
5
|
+
export declare const key: "rail";
|
|
6
|
+
export declare const readyEvent: "gem:rail:ready";
|
|
7
|
+
/** Bind every "rail" hook inside root (default: the whole document). Returns unmount(). Mounting the same root twice binds once. */
|
|
8
|
+
export declare function mount(root?: ParentNode | null, options?: MountOptions): Unmount;
|
|
9
|
+
export default mount;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{mountPlugin as d}from"../runtime-core.js";import{mountEffects as f}from"../motion/core.js";import{railEffect as p}from"../motion/rail.js";const _="rail",P="gem:rail:ready";function v({document:e,window:t,target:x,mark:i,canListen:o,listen:n,registerPlugin:m,registerNoopPlugin:y,onUnmount:s}){m("rail",({api:a})=>{const g=f(p,{window:t,document:e,on:(r,l,c,u)=>{o(r)&&n(r,l,c,u)},mark:i,api:a,css:".gem-rail{--gem-rail-css:1;user-select:none;-webkit-user-select:none;transition:background-color var(--gem-motion-slow,0.6s) var(--gem-ease-soft,ease)}.gem-rail[data-gem-state] .gem-rail__item{will-change:transform}.gem-rail[data-gem-state] .gem-rail__stage{cursor:pointer}.gem-rail[data-gem-state] .gem-rail__hit{pointer-events:none;transition:opacity var(--gem-motion-base,0.35s) var(--gem-ease-soft,ease)}@container (max-width:699px){.gem-rail[data-gem-state] .gem-rail__hit{pointer-events:auto}}.gem-rail[data-gem-state='open'] .gem-rail__hit{opacity:0.15}@media (prefers-reduced-motion:reduce){.gem-rail,.gem-rail[data-gem-state] .gem-rail__hit{transition:none}}"},s);a.emit("gem:rail:ready",{source:"gem-runtime",count:g})})}function h(e,t){return d(_,v,e,t)}var N=h;export{N as default,_ as key,h as mount,P as readyEvent};
|
|
@@ -5,7 +5,7 @@ import { mountPlugin } from "../runtime-core.js";
|
|
|
5
5
|
export const key = "recently-viewed";
|
|
6
6
|
export const readyEvent = "gem:recently-viewed:ready";
|
|
7
7
|
|
|
8
|
-
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin }) {
|
|
8
|
+
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin, onUnmount }) {
|
|
9
9
|
registerPlugin('recently-viewed', ({ api }) => {
|
|
10
10
|
const storageKey = 'gem:recently-viewed-products';
|
|
11
11
|
const readItems = () => {
|
|
@@ -5,7 +5,7 @@ import { mountPlugin } from "../runtime-core.js";
|
|
|
5
5
|
export const key = "reveal-on-scroll";
|
|
6
6
|
export const readyEvent = "gem:reveal:ready";
|
|
7
7
|
|
|
8
|
-
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin }) {
|
|
8
|
+
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin, onUnmount }) {
|
|
9
9
|
registerPlugin('reveal-on-scroll', ({ api }) => {
|
|
10
10
|
const nodes = document.querySelectorAll('[data-gem-reveal], .gem-reveal');
|
|
11
11
|
let bound = 0;
|
package/dist/plugins/reviews.js
CHANGED
|
@@ -5,7 +5,7 @@ import { mountPlugin } from "../runtime-core.js";
|
|
|
5
5
|
export const key = "reviews";
|
|
6
6
|
export const readyEvent = "gem:reviews:ready";
|
|
7
7
|
|
|
8
|
-
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin }) {
|
|
8
|
+
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin, onUnmount }) {
|
|
9
9
|
registerPlugin('reviews', ({ api }) => {
|
|
10
10
|
let boundReviews = 0;
|
|
11
11
|
document.querySelectorAll('[data-rv-root]').forEach((root) => {
|
|
@@ -5,7 +5,7 @@ import { mountPlugin } from "../runtime-core.js";
|
|
|
5
5
|
export const key = "runtime-slot-loader";
|
|
6
6
|
export const readyEvent = "gem:slot:ready";
|
|
7
7
|
|
|
8
|
-
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin }) {
|
|
8
|
+
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin, onUnmount }) {
|
|
9
9
|
registerPlugin('runtime-slot-loader', ({ api }) => {
|
|
10
10
|
const slots = document.querySelectorAll('[data-gem-runtime-slot], [data-gem-footer-block-builder], .gem-navigation-shell__layout');
|
|
11
11
|
let bound = 0;
|
|
@@ -5,7 +5,7 @@ import { mountPlugin } from "../runtime-core.js";
|
|
|
5
5
|
export const key = "seasonal-effects";
|
|
6
6
|
export const readyEvent = "gem:seasonal:ready";
|
|
7
7
|
|
|
8
|
-
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin }) {
|
|
8
|
+
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin, onUnmount }) {
|
|
9
9
|
registerNoopPlugin("seasonal-effects", "gem:seasonal:ready");
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// @gemboss/gem-framework/plugins/size-guide: types of the ES module next to this file. Generated; do not edit here.
|
|
2
|
+
import type { MountOptions, Unmount } from "../runtime-core.js";
|
|
3
|
+
|
|
4
|
+
export type { MountOptions, Unmount };
|
|
5
|
+
export declare const key: "size-guide";
|
|
6
|
+
export declare const readyEvent: "gem:size-guide:ready";
|
|
7
|
+
/** Bind every "size-guide" hook inside root (default: the whole document). Returns unmount(). Mounting the same root twice binds once. */
|
|
8
|
+
export declare function mount(root?: ParentNode | null, options?: MountOptions): Unmount;
|
|
9
|
+
export default mount;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @gemboss/gem-framework/plugins/size-guide: the gem-runtime plugin "size-guide" as an ES module. Generated from
|
|
2
|
+
// packages/gem-framework/src/runtime.ts, the same lines gem-runtime.js carries; do not edit here.
|
|
3
|
+
import { mountPlugin } from "../runtime-core.js";
|
|
4
|
+
|
|
5
|
+
export const key = "size-guide";
|
|
6
|
+
export const readyEvent = "gem:size-guide:ready";
|
|
7
|
+
|
|
8
|
+
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin, onUnmount }) {
|
|
9
|
+
registerPlugin('size-guide', ({ api }) => {
|
|
10
|
+
const page = document.documentElement && typeof document.documentElement.querySelectorAll === 'function' ? document.documentElement : document;
|
|
11
|
+
const guides = Array.prototype.slice.call(page.querySelectorAll('[data-gem-size-guide]'));
|
|
12
|
+
const opens = (target) => guides.some((guide) => !target || guide.getAttribute('data-gem-size-guide') === target || guide.id === target);
|
|
13
|
+
let bound = 0;
|
|
14
|
+
document.querySelectorAll('[data-gem-size-guide-trigger]').forEach((trigger) => {
|
|
15
|
+
const target = trigger.getAttribute('data-gem-size-guide-trigger') || '';
|
|
16
|
+
if (!opens(target)) { trigger.hidden = true; return; }
|
|
17
|
+
if (!mark(trigger, 'size-guide')) return;
|
|
18
|
+
trigger.hidden = false;
|
|
19
|
+
if (!canListen(trigger)) return;
|
|
20
|
+
__gemListen(trigger, 'click', (event) => {
|
|
21
|
+
event.preventDefault && event.preventDefault();
|
|
22
|
+
const holder = trigger.closest ? trigger.closest('[data-product-id]') : null;
|
|
23
|
+
const detail = { source: 'gem-runtime', sectionId: target || null, productId: holder ? holder.getAttribute('data-product-id') : null };
|
|
24
|
+
if (typeof window.CustomEvent === 'function') window.dispatchEvent(new window.CustomEvent('gem:size-guide:open', { detail }));
|
|
25
|
+
api.emit('gem:size-guide:open', detail);
|
|
26
|
+
});
|
|
27
|
+
bound += 1;
|
|
28
|
+
});
|
|
29
|
+
api.emit('gem:size-guide:ready', { source: 'gem-runtime', count: bound, guides: guides.length });
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Bind every "size-guide" hook inside root (default: the whole document). Returns unmount(). Mounting the same root twice binds once. */
|
|
34
|
+
export function mount(root, options) {
|
|
35
|
+
return mountPlugin(key, install, root, options);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default mount;
|
|
@@ -5,7 +5,7 @@ import { mountPlugin } from "../runtime-core.js";
|
|
|
5
5
|
export const key = "sticky-atc";
|
|
6
6
|
export const readyEvent = "gem:sticky-atc:ready";
|
|
7
7
|
|
|
8
|
-
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin }) {
|
|
8
|
+
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin, onUnmount }) {
|
|
9
9
|
registerPlugin('sticky-atc', ({ api }) => {
|
|
10
10
|
const bars = document.querySelectorAll('[data-gem-sticky-atc], .gem-sticky-atc');
|
|
11
11
|
let bound = 0;
|
package/dist/plugins/tabs.js
CHANGED
|
@@ -5,7 +5,7 @@ import { mountPlugin } from "../runtime-core.js";
|
|
|
5
5
|
export const key = "tabs";
|
|
6
6
|
export const readyEvent = "gem:tabs:ready";
|
|
7
7
|
|
|
8
|
-
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin }) {
|
|
8
|
+
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin, onUnmount }) {
|
|
9
9
|
registerPlugin('tabs', ({ api }) => {
|
|
10
10
|
const roots = document.querySelectorAll('[data-gem-tabs]');
|
|
11
11
|
let bound = 0;
|
|
@@ -5,7 +5,7 @@ import { mountPlugin } from "../runtime-core.js";
|
|
|
5
5
|
export const key = "variant-selects";
|
|
6
6
|
export const readyEvent = "gem:variant:ready";
|
|
7
7
|
|
|
8
|
-
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin }) {
|
|
8
|
+
function install({ document, window, target, mark, canListen, listen: __gemListen, registerPlugin, registerNoopPlugin, onUnmount }) {
|
|
9
9
|
registerPlugin('variant-selects', ({ api }) => {
|
|
10
10
|
const selects = document.querySelectorAll('[data-gem-variant-select], select[name="id"]');
|
|
11
11
|
let bound = 0;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Types for @gemboss/gem-framework/pod/core (core.js, copied minified into dist/pod/).
|
|
2
|
+
|
|
3
|
+
/** What a personalization field holds now (readField). */
|
|
4
|
+
export interface PersonalizeRead {
|
|
5
|
+
name: string;
|
|
6
|
+
type: string;
|
|
7
|
+
/** What the cart line gets: "" when blank; an upload's stored URL. */
|
|
8
|
+
value: string;
|
|
9
|
+
/** The picked option's hex colour, when it has one. */
|
|
10
|
+
color: string;
|
|
11
|
+
/** An upload's local picture (shown before the upload finishes), or its stored URL. */
|
|
12
|
+
preview: string;
|
|
13
|
+
/** An upload's storage key (written as `_<name>_upload`). */
|
|
14
|
+
key: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export declare const FIELD: "[data-gem-personalize]";
|
|
18
|
+
export declare function scopeOf(el: Element | null | undefined): Element | null;
|
|
19
|
+
export declare const uploads: WeakMap<Element, { uploading: boolean; preview: string; url: string; key: string }>;
|
|
20
|
+
export declare function fieldName(field: Element): string;
|
|
21
|
+
export declare function fieldType(field: Element): string;
|
|
22
|
+
export declare function controlsOf(field: Element): Array<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>;
|
|
23
|
+
export declare function hexColor(value: unknown): string;
|
|
24
|
+
export declare function readField(field: Element): PersonalizeRead;
|
|
25
|
+
export declare function readScope(scope: ParentNode | null | undefined): Record<string, PersonalizeRead>;
|
|
26
|
+
export declare function adoptCss(el: Element, key: string, sentinel: string, css: string): boolean;
|
package/dist/pod/core.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const y="[data-gem-personalize]",m=["[data-gem-personalize-scope]",'[data-gem-element="product"]','form[action*="/cart/add"]',"[data-gem-section-id]"];function b(e){for(const r of m){const o=e&&e.closest?e.closest(r):null;if(o)return o}return e&&e.ownerDocument?e.ownerDocument.documentElement:null}const x=new WeakMap,i=(e,r)=>e&&e.getAttribute?e.getAttribute(r):null,l=e=>typeof e=="string"?e.trim():"";function S(e){const r=l(i(e,"data-gem-personalize-name"));if(r)return r;const o=e.querySelector&&e.querySelector("input, select, textarea");return o?l(o.getAttribute("name")):""}function g(e){const r=l(i(e,"data-gem-personalize-type"));if(r)return r;const o=e.querySelector&&e.querySelector("input, select, textarea");return o?o.tagName==="SELECT"?"select":o.tagName==="TEXTAREA"?"textarea":o.type==="file"?"upload":o.type==="checkbox"?"checkbox":o.type==="radio"?"swatch":"text":"text"}const h=e=>Array.prototype.slice.call(e.querySelectorAll?e.querySelectorAll("input, select, textarea"):[]).filter(r=>r.type!=="hidden"),v=/^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,p=e=>v.test(l(e))?l(e):"";function w(e){const r=S(e),o=g(e),n={name:r,type:o,value:"",color:"",preview:"",key:""},a=h(e);if(o==="upload"){const t=x.get(e);return t&&Object.assign(n,{value:t.url||"",preview:t.preview||t.url||"",key:t.key||""}),n}if(o==="checkbox"){const t=a.find(c=>c.type==="checkbox"&&c.checked);return t&&(n.value=t.value&&t.value!=="on"?t.value:"Yes"),n}if(o==="select"){const t=a.find(f=>f.tagName==="SELECT"),c=t&&t.selectedIndex>-1?t.options[t.selectedIndex]:null;return n.value=l(t?t.value:""),n.color=p(i(c,"data-gem-personalize-color")),n}const u=a.filter(t=>t.type==="radio");if(u.length){const t=u.find(c=>c.checked);if(t){n.value=l(t.value);const c=t.closest?t.closest("label"):null;n.color=p(i(t,"data-gem-personalize-color")||i(c,"data-gem-personalize-color"))}return n}const s=a[0];return n.value=l(s?s.value:""),n}function k(e){const r={},o=e&&e.querySelectorAll?e.querySelectorAll(y):[];return Array.prototype.forEach.call(o,n=>{const a=w(n);a.name&&(r[a.name]=n.hidden?{...a,value:"",color:"",preview:""}:a)}),r}const d=new WeakMap;function A(e,r,o,n){const a=e.ownerDocument,u=a&&a.defaultView;if(!n||!u)return!1;let s=d.get(a);if(s||d.set(a,s=new Set),s.has(r))return!1;s.add(r);try{if(u.getComputedStyle(e).getPropertyValue(o).trim())return!1;const t=new u.CSSStyleSheet;return t.replaceSync(n),a.adoptedStyleSheets=[...a.adoptedStyleSheets,t],!0}catch{return!1}}export{y as FIELD,A as adoptCss,h as controlsOf,S as fieldName,g as fieldType,p as hexColor,w as readField,k as readScope,b as scopeOf,x as uploads};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Types for @gemboss/gem-framework/pod/delivery-estimate (delivery-estimate.js, copied minified into dist/pod/).
|
|
2
|
+
|
|
3
|
+
export interface DeliverySpec {
|
|
4
|
+
/** Production days: "3-5", "3", or a number. */
|
|
5
|
+
production: string | number;
|
|
6
|
+
/** Shipping days, the same shapes. */
|
|
7
|
+
shipping: string | number;
|
|
8
|
+
/** Count Monday to Friday only (default true). */
|
|
9
|
+
businessDays?: boolean;
|
|
10
|
+
/** 0–23 in the store's time: past it, the order counts from the next day. */
|
|
11
|
+
cutoffHour?: number | string | null;
|
|
12
|
+
/** The store's IANA zone, for the cutoff (default: the shopper's clock). */
|
|
13
|
+
timeZone?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DeliveryEstimate {
|
|
17
|
+
/** ISO dates (YYYY-MM-DD). */
|
|
18
|
+
ordered: string;
|
|
19
|
+
start: string;
|
|
20
|
+
ships: [string, string];
|
|
21
|
+
arrives: [string, string];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export declare function parseDayRange(value: unknown): [number, number] | null;
|
|
25
|
+
export declare function storeHour(now: Date, timeZone?: string): number;
|
|
26
|
+
export declare function deliveryEstimate(now: Date, spec: DeliverySpec): DeliveryEstimate | null;
|
|
27
|
+
export declare function formatDeliveryRange(from: string, to: string | undefined, locale?: string): string;
|
|
28
|
+
export declare function mountDeliveryEstimate(env: { document: Document; mark(el: Element, key: string): boolean }): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const b=864e5;function f(e){if(typeof e=="number")return Number.isFinite(e)&&e>=0?[Math.floor(e),Math.floor(e)]:null;const t=/^\s*(\d{1,3})\s*(?:[-–—]\s*(\d{1,3}))?\s*$/.exec(String(e??""));if(!t)return null;const i=Number(t[1]),n=t[2]===void 0?i:Number(t[2]);return n>=i?[i,n]:null}const g=e=>Date.UTC(e.getFullYear(),e.getMonth(),e.getDate()),y=e=>{const t=new Date(e).getUTCDay();return t===0||t===6},l=e=>new Date(e).toISOString().slice(0,10);function c(e,t,i){let n=e,r=t;for(;r>0;)n+=864e5,(!i||!y(n))&&(r-=1);return n}function h(e,t){if(t)try{const i=new Intl.DateTimeFormat("en-US",{timeZone:t,hour:"numeric",hourCycle:"h23"}).formatToParts(e).find(n=>n.type==="hour");if(i)return Number(i.value)%24}catch{}return e.getHours()}function D(e,t){const i=f(t.production),n=f(t.shipping);if(!i||!n||!(e instanceof Date)||Number.isNaN(e.getTime()))return null;const r=t.businessDays!==!1,a=g(e);let o=a;const m=Number(t.cutoffHour);for(t.cutoffHour!==void 0&&t.cutoffHour!==null&&t.cutoffHour!==""&&Number.isInteger(m)&&m>=0&&m<=23&&h(e,t.timeZone)>=m&&(o+=864e5);r&&y(o);)o+=864e5;const s=[c(o,i[0],r),c(o,i[1],r)],u=[c(s[0],n[0],r),c(s[1],n[1],r)];return{ordered:l(a),start:l(o),ships:s.map(l),arrives:u.map(l)}}function p(e,t,i){const n=a=>new Date(`${a}T00:00:00Z`);let r;try{r=new Intl.DateTimeFormat(i||void 0,{month:"short",day:"numeric",timeZone:"UTC"})}catch{r=new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric",timeZone:"UTC"})}return!t||t===e?r.format(n(e)):typeof r.formatRange=="function"?r.formatRange(n(e),n(t)):`${r.format(n(e))} \u2013 ${r.format(n(t))}`}const d=(e,t)=>(e.getAttribute(t)||"").trim();function v(e){const{document:t,mark:i}=e;let n=0;return t.querySelectorAll("[data-gem-delivery-estimate]").forEach(r=>{if(!i(r,"delivery-estimate"))return;const a=D(new Date,{production:d(r,"data-gem-delivery-production"),shipping:d(r,"data-gem-delivery-shipping"),businessDays:d(r,"data-gem-delivery-business-days")!=="false",cutoffHour:d(r,"data-gem-delivery-cutoff-hour"),timeZone:d(r,"data-gem-delivery-timezone")});if(!a)return;const o=d(r,"data-gem-delivery-locale")||t.documentElement&&t.documentElement.lang||void 0,m={ordered:[a.ordered,a.ordered],ships:a.ships,arrives:a.arrives};r.querySelectorAll("[data-gem-delivery-date]").forEach(s=>{const u=m[d(s,"data-gem-delivery-date")];u&&(s.textContent=p(u[0],u[1],o),s.setAttribute("data-gem-delivery-from",u[0]),s.setAttribute("data-gem-delivery-to",u[1]))}),r.setAttribute("data-gem-delivery-state","local"),n+=1}),n}export{D as deliveryEstimate,p as formatDeliveryRange,v as mountDeliveryEstimate,f as parseDayRange,h as storeHour};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Types for @gemboss/gem-framework/pod/personalize (personalize.js, copied minified into dist/pod/).
|
|
2
|
+
import type { PersonalizeRead } from "./core.js";
|
|
3
|
+
|
|
4
|
+
export interface PersonalizeWhen {
|
|
5
|
+
name: string;
|
|
6
|
+
op: "set" | "unset" | "is" | "not";
|
|
7
|
+
values: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** The plugin's environment, as the chunk body hands it over (plugins/personalize.js). */
|
|
11
|
+
export interface PodEnv {
|
|
12
|
+
window: Window;
|
|
13
|
+
document: Document;
|
|
14
|
+
on(el: EventTarget, type: string, fn: (event: any) => void, options?: boolean | AddEventListenerOptions): void;
|
|
15
|
+
mark(el: Element, key: string): boolean;
|
|
16
|
+
api?: { emit(event: string, detail?: Record<string, unknown>): void; uploadEndpoint?: string };
|
|
17
|
+
css?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export declare const PERSONALIZE_MESSAGES: Readonly<Record<"required" | "type" | "size" | "failed" | "uploading" | "unavailable", string>>;
|
|
21
|
+
export declare function parsePersonalizeWhen(text: unknown): PersonalizeWhen | null;
|
|
22
|
+
export declare function personalizeWhenHolds(cond: PersonalizeWhen, values: Record<string, PersonalizeRead>): boolean;
|
|
23
|
+
export declare function fileAccepted(file: { type?: string; name?: string }, accept: string | null | undefined): boolean;
|
|
24
|
+
/** Binds every [data-gem-personalize] field in env.document; returns how many it bound. */
|
|
25
|
+
export declare function mountPersonalize(env: PodEnv, onUnmount: (cleanup: () => void) => void): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{FIELD as j,adoptCss as ce,controlsOf as z,fieldName as Z,fieldType as K,readField as T,readScope as ue,scopeOf as A,uploads as L}from"./core.js";const pe={required:"Fill this in to add to cart.",type:"This file type is not accepted.",size:"This file is over {mb} MB.",failed:"The upload failed. Try again.",uploading:"Wait for the upload to finish.",unavailable:"Photo upload is not available."},de=/^\s*(!)?\s*([^!=|]+?)\s*(?:(!=|==|=)\s*(.+?))?\s*$/;function me(l){if(typeof l!="string"||!l.trim())return null;const g=de.exec(l);if(!g)return null;const[,s,u,h,b]=g;if(!h)return{name:u.trim(),op:s?"unset":"set",values:[]};const C=b.split("|").map(y=>y.trim().toLowerCase()).filter(Boolean);return s||!C.length?null:{name:u.trim(),op:h==="!="?"not":"is",values:C}}function fe(l,g){const s=Object.keys(g).find(h=>h.toLowerCase()===l.name.toLowerCase()),u=s?String(g[s].value||"").trim().toLowerCase():"";return l.op==="set"?u!=="":l.op==="unset"?u==="":l.op==="is"?l.values.includes(u):!l.values.includes(u)}function ge(l,g){const s=String(g||"").split(",").map(b=>b.trim().toLowerCase()).filter(Boolean);if(!s.length)return!0;const u=String(l.type||"").toLowerCase(),h=String(l.name||"").toLowerCase();return s.some(b=>b.startsWith(".")?h.endsWith(b):b.endsWith("/*")?u.startsWith(b.slice(0,-1)):u===b)}const p=(l,g)=>l&&l.getAttribute?l.getAttribute(g):null,P=l=>String(l).split("/").pop(),he='[data-gem-element="product-related"], [data-gem-element="product-list"]';function ye(l,g){const{window:s,document:u,on:h,mark:b,api:C}=l,y=new Set,I=new Set,q=new Set;let U=!1,M=!0;const k=e=>[...y].filter(t=>t.isConnected&&A(t)===e),Q=e=>p(e,"data-gem-personalize-required")==="true"||z(e).some(t=>t.required),Y=(e,t,a={})=>(p(e,`data-gem-personalize-message-${t}`)||p(A(e),`data-gem-personalize-message-${t}`)||pe[t]||"").replace(/\{(\w+)\}/g,(o,r)=>r in a?String(a[r]):""),ee=e=>{let t=e.querySelector("[data-gem-personalize-error]");return t||(t=u.createElement("p"),t.className="gem-el-product-personalization__error",t.setAttribute("data-gem-personalize-error",""),t.setAttribute("role","alert"),e.appendChild(t)),t.id||(t.id=`gem-personalize-error-${Math.random().toString(36).slice(2,9)}`),t},W=(e,t,a)=>{const n=ee(e);n.textContent=Y(e,t,a),n.hidden=!1,e.setAttribute("data-gem-personalize-invalid",t),z(e).forEach(o=>{o.setAttribute("aria-invalid","true");const r=(p(o,"aria-describedby")||"").split(/\s+/).filter(Boolean);r.includes(n.id)||o.setAttribute("aria-describedby",[...r,n.id].join(" "))})},w=e=>{if(!e.hasAttribute("data-gem-personalize-invalid"))return;e.removeAttribute("data-gem-personalize-invalid");const t=e.querySelector("[data-gem-personalize-error]");t&&(t.textContent="",t.hidden=!0),z(e).forEach(a=>a.removeAttribute("aria-invalid"))},x=e=>{const{name:t,value:a,type:n,color:o,preview:r}=T(e);e.dispatchEvent(new s.CustomEvent("gem:personalize:change",{bubbles:!0,detail:{name:t,value:a,type:n,color:o,preview:r}}))},_=e=>{const t=e.querySelector("[data-gem-personalize-count]"),a=z(e).find(o=>o.tagName==="TEXTAREA"||o.type==="text"||o.type===""),n=Number(p(e,"data-gem-personalize-max"))||(a&&a.maxLength>0?a.maxLength:0);!t||!a||!n||(t.textContent=`${a.value.length}/${n}`,a.value.length>=n?t.setAttribute("data-gem-personalize-full",""):t.removeAttribute("data-gem-personalize-full"))},R=e=>{const t=k(e).filter(a=>p(a,"data-gem-personalize-when"));for(let a=0;a<4;a+=1){const n=ue(e);let o=!1;for(const r of t){if(p(r,"data-gem-personalize-state")==="unavailable")continue;const c=me(p(r,"data-gem-personalize-when"));if(!c){r.setAttribute("data-gem-personalize-when-invalid","");continue}const i=fe(c,n);r.hidden!==!i&&(r.hidden=!i,z(r).forEach(f=>{f.disabled=!i}),i||w(r),o=!0)}if(!o)break}},te=e=>{if(!b(e,"personalize"))return!1;y.add(e),!U&&l.css&&(ce(e,"personalize","--gem-personalize-css",l.css),U=!0);const t=Number(p(e,"data-gem-personalize-max"));return z(e).forEach(a=>{t>0&&(a.tagName==="TEXTAREA"||a.type==="text")&&!(a.maxLength>0)&&(a.maxLength=t)}),_(e),K(e)==="upload"&&!B(e)&&N(e),!0},$=()=>{const e=Array.prototype.filter.call(u.querySelectorAll(j),te);return new Set(e.map(A)).forEach(R),e.length},O=e=>{const t=L.get(e);t&&t.preview&&I.delete(t.preview)&&s.URL&&s.URL.revokeObjectURL&&s.URL.revokeObjectURL(t.preview),L.delete(e),e.removeAttribute("data-gem-personalize-state");const a=e.querySelector("[data-gem-personalize-thumb]");a&&(a.removeAttribute("src"),a.hidden=!0)},B=e=>{const t=s.GemTheme||{},a=p(e,"data-gem-personalize-endpoint")||p(A(e),"data-gem-personalize-endpoint")||C&&C.uploadEndpoint||t.uploadEndpoint;return typeof a=="string"&&a.trim()?a.trim():""},N=e=>{O(e),w(e),e.setAttribute("data-gem-personalize-state","unavailable"),e.hidden=!0,z(e).forEach(t=>{t.disabled=!0}),x(e)},F=e=>e&&typeof e.json=="function"?e.json().catch(()=>({})):Promise.resolve({}),E=(e,t={})=>Object.assign(new Error(e),{reason:e,...t}),ae=(e,t,a,n,o)=>{const r=(c,i)=>s.fetch(c,{...i,...o?{signal:o}:{}});return r(e,{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({type:a.type,size:a.size,max_mb:n})}).then(c=>F(c).then(i=>{if(c.status===404)throw E("unavailable");if(c.status===415)throw E("type");if(c.status===413)throw E("size",{mb:Number(i.max_mb)||n});if(!c.ok)throw E("failed");const f=i&&i.upload;if(f&&typeof f.url=="string"){const d=f.headers&&typeof f.headers=="object"?f.headers:{};return r(f.url,{method:typeof f.method=="string"?f.method:"PUT",headers:d,body:a,credentials:"omit"}).then(m=>{if(!m||!m.ok)throw E("failed");return i})}const S=new s.FormData;return S.append("file",a,a.name),S.append("name",Z(t)),r(e,{method:"POST",body:S,credentials:"same-origin"}).then(d=>{if(!d||!d.ok)throw E(d&&d.status===404?"unavailable":"failed");return F(d)})}))},re=(e,t)=>{O(e),w(e);const a=t.files&&t.files[0];if(!a){x(e);return}const n=p(e,"data-gem-personalize-accept")||p(t,"accept")||"image/*",o=Number(p(e,"data-gem-personalize-max-mb"))||10,r=B(e),c=(m,v={mb:o})=>{t.value="",W(e,m,v),x(e)};if(!ge(a,n))return c("type");if(a.size>o*1048576)return c("size");if(!r||typeof s.fetch!="function")return N(e);const i=s.URL&&s.URL.createObjectURL?s.URL.createObjectURL(a):"";i&&I.add(i);const f={uploading:!0,preview:i,url:"",key:""};L.set(e,f),e.setAttribute("data-gem-personalize-state","uploading");const S=e.querySelector("[data-gem-personalize-thumb]");S&&i&&(S.src=i,S.hidden=!1),x(e);const d=s.AbortController?new s.AbortController:null;d&&q.add(d),ae(r,e,a,o,d&&d.signal).then(m=>{const v=m&&typeof m.url=="string"&&/^https?:\/\//i.test(m.url)?m.url:"";if(!v)throw E("failed");L.get(e)===f&&(Object.assign(f,{uploading:!1,url:v,key:typeof m.key=="string"?m.key:""}),e.setAttribute("data-gem-personalize-state","done"),w(e),x(e))}).catch(m=>{if(L.get(e)!==f||d&&d.signal.aborted)return;const v=m&&m.reason;if(v==="unavailable")return N(e);O(e),c(v==="type"||v==="size"?v:"failed",{mb:m&&m.mb||o})}).finally(()=>{d&&q.delete(d)})},D=e=>{const t=e.target&&e.target.closest?e.target.closest(j):null;if(!t||!y.has(t))return;const a=K(t),n=a==="text"||a==="textarea";if(!(e.type==="input"?!n:n)){if(a==="upload"){e.target.type==="file"&&re(t,e.target);return}_(t),T(t).value&&w(t),R(A(t)),x(t)}},ne=e=>k(e).filter(t=>!t.hidden).flatMap(t=>{const a=L.get(t);return a&&a.uploading?[[t,"uploading"]]:Q(t)&&!T(t).value?[[t,"required"]]:[]}),G=e=>{R(e);const t=ne(e);if(k(e).forEach(o=>{t.some(([r])=>r===o)||w(o)}),!t.length)return!0;t.forEach(([o,r])=>W(o,r));const[a]=t[0],n=z(a)[0];return n&&n.focus&&n.focus({preventScroll:!0}),a.scrollIntoView&&a.scrollIntoView({block:"center"}),e.dispatchEvent(new s.CustomEvent("gem:personalize:blocked",{bubbles:!0,detail:{names:t.map(([o])=>Z(o)),reasons:t.map(([,o])=>o)}})),!1},H=e=>k(e).filter(t=>!t.hidden).map(T).filter(t=>t.name&&t.value).flatMap(t=>[{key:t.name,value:t.value},...t.type==="upload"&&t.key?[{key:`_${t.name}_upload`,value:t.key}]:[]]),V=(e,t)=>[...Array.isArray(e)?e.filter(a=>!t.some(n=>a&&n.key===a.key)):[],...t],X=e=>[e,...e.querySelectorAll("[data-gem-variant-id]")].filter(t=>t===e||A(t)===e&&!t.closest(he)).map(t=>p(t,"data-gem-variant-id")).filter(Boolean).map(P),oe=e=>{const t=e.target;if(t&&t.nodeType===1){const r=A(t);if(k(r).length)return r}const a=e.detail||{},n=[a.variantId,...Array.isArray(a.lines)?a.lines.map(r=>r&&r.variantId):[]].filter(Boolean).map(P);return n.length&&[...new Set([...y].filter(r=>r.isConnected).map(A))].find(r=>X(r).some(c=>n.includes(c)))||null},J=e=>{const t=oe(e);if(!t)return;const a=e.detail&&typeof e.detail=="object"?e.detail:null;if(!G(t)){e.stopImmediatePropagation(),e.cancelable&&e.preventDefault(),s.setTimeout(()=>s.dispatchEvent(new s.CustomEvent("gem:cart:add-failed",{detail:{variantId:a&&a.variantId,reason:"personalization"}})),0);return}const n=H(t);if(!a||!n.length)return;if(e.type==="gem:cart:add"){a.properties=V(a.properties,n);return}const o=Array.isArray(a.lines)?a.lines.filter(i=>i&&typeof i=="object"):[],r=X(t),c=o.filter(i=>r.includes(P(i.variantId)));(c.length?c:o).forEach(i=>{i.properties=V(i.properties,n)})},se=e=>[...new Set([...y].filter(t=>t.isConnected).map(A))].filter(t=>t.contains(e)).sort((t,a)=>t.contains(a)?1:-1)[0]||null,ie=e=>{const t=e.target;if(!t||t.tagName!=="FORM")return;const a=se(t);if(a){if(!G(a)){e.preventDefault(),e.stopImmediatePropagation();return}t.hasAttribute("action")&&(t.querySelectorAll("[data-gem-personalize-hidden]").forEach(n=>n.remove()),H(a).forEach(({key:n,value:o})=>{const r=u.createElement("input");Object.assign(r,{type:"hidden",name:`properties[${n}]`,value:o}),r.setAttribute("data-gem-personalize-hidden",""),t.appendChild(r)}))}},le=$();if(h(u,"input",D),h(u,"change",D),h(u,"submit",ie,!0),h(s,"gem:cart:add",J,!0),h(s,"gem:cart:add-many",J,!0),typeof s.MutationObserver=="function"){let e=!1;const t=new s.MutationObserver(a=>{e||!a.some(n=>Array.prototype.some.call(n.addedNodes,o=>o.nodeType===1&&(o.matches(j)||o.querySelector(j))))||(e=!0,Promise.resolve().then(()=>{e=!1,M&&$()}))});t.observe(u.documentElement,{childList:!0,subtree:!0}),g(()=>t.disconnect())}return g(()=>{M=!1,q.forEach(e=>e.abort()),y.forEach(e=>{e.hidden&&(p(e,"data-gem-personalize-when")||p(e,"data-gem-personalize-state")==="unavailable")&&(e.hidden=!1,z(e).forEach(t=>{t.disabled=!1})),O(e),w(e)}),y.clear()}),le}export{pe as PERSONALIZE_MESSAGES,ge as fileAccepted,ye as mountPersonalize,me as parsePersonalizeWhen,fe as personalizeWhenHolds};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Types for @gemboss/gem-framework/pod/print-preview (print-preview.js, copied minified into dist/pod/).
|
|
2
|
+
import type { PersonalizeRead } from "./core.js";
|
|
3
|
+
import type { PodEnv } from "./personalize.js";
|
|
4
|
+
|
|
5
|
+
/** What a preview draws for these field values (each "" when there is nothing to draw). */
|
|
6
|
+
export declare function printPreviewContent(root: Element, values: Record<string, PersonalizeRead>): { text: string; photo: string; color: string };
|
|
7
|
+
/** Binds every [data-gem-print-preview] in env.document; returns how many it bound. */
|
|
8
|
+
export declare function mountPrintPreview(env: PodEnv, onUnmount: (cleanup: () => void) => void): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{adoptCss as y,hexColor as h,readScope as b,scopeOf as x}from"./core.js";const A="[data-gem-print-preview]",v=(i,p)=>i&&i.getAttribute&&i.getAttribute(p)||"";function C(i,p){const c=n=>{const u=n&&Object.keys(p).find(e=>e.toLowerCase()===n.trim().toLowerCase());return u?p[u]:null},l=c(v(i,"data-gem-print-preview-text")),m=c(v(i,"data-gem-print-preview-photo")),f=v(i,"data-gem-print-preview-color").trim(),a=/^from:/i.test(f)?c(f.slice(5)):null,t=m?m.preview||m.value:"";return{text:l?String(l.value||""):"",photo:/^(?:https?:|blob:|data:image\/)/i.test(t)?t:"",color:a?a.color||h(a.value):h(f)}}function P(i,p){const{window:c,document:l,on:m,mark:f}=i;let a=0;return l.querySelectorAll(A).forEach(t=>{if(!f(t,"print-preview"))return;a+=1,i.css&&y(t,"print-preview","--gem-print-preview-css",i.css);const n=t.querySelector("[data-gem-print-preview-area]");if(!n)return;const u=x(t);let e=null,r=null;const w=()=>{if(!e)return;e.style.transform="";const o=n.clientWidth,s=e.scrollWidth;o>0&&s>o&&(e.style.transform=`scale(${Math.max(.3,o/s).toFixed(3)})`)},d=()=>{const{text:o,photo:s,color:g}=C(t,b(u));s?(r||(r=l.createElement("img"),r.className="gem-el-product-print-preview__photo",r.alt="",n.prepend(r)),r.getAttribute("src")!==s&&(r.src=s)):r&&(r.remove(),r=null),o?(e||(e=l.createElement("p"),e.className="gem-el-product-print-preview__text",n.append(e)),e.textContent=o,w()):e&&(e.remove(),e=null),g?t.style.setProperty("--gem-print-preview-color",g):t.style.removeProperty("--gem-print-preview-color"),o||s?t.setAttribute("data-gem-print-preview-state","drawn"):t.removeAttribute("data-gem-print-preview-state")};m(u,"gem:personalize:change",d),typeof c.ResizeObserver=="function"&&new c.ResizeObserver(w).observe(n),d(),p(()=>{r&&r.remove(),e&&e.remove(),t.removeAttribute("data-gem-print-preview-state"),t.style.removeProperty("--gem-print-preview-color")})}),a}export{P as mountPrintPreview,C as printPreviewContent};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
.gem-el-product-personalization { display: grid; gap: var(--gem-space-2xs); min-width: 0; }
|
|
2
|
+
.gem-el-product-personalization[hidden] { display: none; }
|
|
3
|
+
.gem-el-product-personalization__label { display: grid; gap: var(--gem-space-2xs); }
|
|
4
|
+
.gem-el-product-personalization__title { font-size: var(--gem-text-sm); font-weight: 600; }
|
|
5
|
+
.gem-el-product-personalization__required { color: var(--gem-color-danger); }
|
|
6
|
+
.gem-el-product-personalization__input { box-sizing: border-box; width: 100%; min-height: var(--gem-tap-min); padding: var(--gem-space-xs) var(--gem-space-sm); font: inherit; color: var(--gem-color-text); background: var(--gem-color-background); border: var(--gem-stroke, 1px) solid var(--gem-color-border); border-radius: var(--gem-radius-md); }
|
|
7
|
+
textarea.gem-el-product-personalization__input { min-height: calc(var(--gem-tap-min) * 2); resize: vertical; }
|
|
8
|
+
.gem-el-product-personalization__meta { display: flex; gap: var(--gem-space-xs); align-items: baseline; }
|
|
9
|
+
.gem-el-product-personalization__help { margin: 0; color: var(--gem-color-muted); font-size: var(--gem-text-xs); }
|
|
10
|
+
.gem-el-product-personalization__count { margin-left: auto; color: var(--gem-color-muted); font-size: var(--gem-text-xs); font-variant-numeric: tabular-nums; }
|
|
11
|
+
.gem-el-product-personalization__options { display: flex; flex-wrap: wrap; gap: var(--gem-space-xs); margin: 0; padding: 0; border: 0; min-width: 0; }
|
|
12
|
+
.gem-el-product-personalization__option { position: relative; display: inline-grid; justify-items: center; gap: var(--gem-space-2xs); font-size: var(--gem-text-xs); cursor: pointer; }
|
|
13
|
+
.gem-el-product-personalization__option input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
|
|
14
|
+
.gem-el-product-personalization__swatch { display: block; width: var(--gem-tap-min); height: var(--gem-tap-min); border-radius: var(--gem-radius-pill); background: var(--gem-personalize-swatch, var(--gem-color-surface)); border: var(--gem-stroke, 1px) solid var(--gem-color-border); }
|
|
15
|
+
.gem-el-product-personalization__choice-image { display: block; width: calc(var(--gem-tap-min) * 1.75); aspect-ratio: 1; object-fit: cover; border-radius: var(--gem-radius-md); border: var(--gem-stroke, 1px) solid var(--gem-color-border); }
|
|
16
|
+
.gem-el-product-personalization__option input:checked ~ .gem-el-product-personalization__swatch, .gem-el-product-personalization__option input:checked ~ .gem-el-product-personalization__choice-image { box-shadow: 0 0 0 var(--gem-stroke-thick, 2px) var(--gem-color-background), 0 0 0 calc(var(--gem-stroke-thick, 2px) * 2) var(--gem-color-text); }
|
|
17
|
+
.gem-el-product-personalization__option input:focus-visible ~ .gem-el-product-personalization__swatch, .gem-el-product-personalization__option input:focus-visible ~ .gem-el-product-personalization__choice-image { outline: var(--gem-focus-ring); outline-offset: calc(var(--gem-focus-offset) + var(--gem-stroke-thick, 2px) * 2); }
|
|
18
|
+
.gem-el-product-personalization__checkbox { display: inline-flex; align-items: center; gap: var(--gem-space-xs); min-height: var(--gem-tap-min); cursor: pointer; }
|
|
19
|
+
.gem-el-product-personalization__upload { position: relative; display: grid; justify-items: center; gap: var(--gem-space-2xs); padding: var(--gem-space-md); text-align: center; background: var(--gem-color-surface); border: var(--gem-stroke, 1px) dashed var(--gem-color-border); border-radius: var(--gem-radius-md); cursor: pointer; }
|
|
20
|
+
.gem-el-product-personalization__upload:focus-within { outline: var(--gem-focus-ring); outline-offset: var(--gem-focus-offset); }
|
|
21
|
+
.gem-el-product-personalization__file { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
|
|
22
|
+
.gem-el-product-personalization__thumb { display: block; width: calc(var(--gem-tap-min) * 2); aspect-ratio: 1; object-fit: cover; border-radius: var(--gem-radius-sm); }
|
|
23
|
+
.gem-el-product-personalization__thumb[hidden], .gem-el-product-personalization__thumb:not([src]) { display: none; }
|
|
24
|
+
.gem-el-product-personalization__privacy { margin: 0; color: var(--gem-color-muted); font-size: var(--gem-text-xs); }
|
|
25
|
+
.gem-el-product-personalization__error { margin: 0; color: var(--gem-color-danger); font-size: var(--gem-text-xs); }
|
|
26
|
+
.gem-el-product-personalization__error:empty, .gem-el-product-personalization__error[hidden] { display: none; }
|
|
27
|
+
.gem-el-product-print-preview { position: relative; display: block; overflow: hidden; border-radius: var(--gem-media-radius, var(--gem-radius-md)); }
|
|
28
|
+
.gem-el-product-print-preview__media { display: block; width: 100%; height: auto; }
|
|
29
|
+
.gem-el-product-print-preview__area { position: absolute; left: calc(var(--gem-print-preview-x, 20) * 1%); top: calc(var(--gem-print-preview-y, 35) * 1%); width: calc(var(--gem-print-preview-w, 60) * 1%); height: calc(var(--gem-print-preview-h, 20) * 1%); display: grid; place-items: center; overflow: hidden; pointer-events: none; container-type: size; }
|
|
30
|
+
.gem-el-product-print-preview[data-gem-print-preview-shape="circle"] .gem-el-product-print-preview__area { border-radius: 50%; }
|
|
31
|
+
.gem-el-product-print-preview[data-gem-print-preview-font="body"] { --gem-print-preview-font: var(--gem-font-body); }
|
|
32
|
+
.gem-el-product-print-preview[data-gem-print-preview-font="accent"] { --gem-print-preview-font: var(--gem-font-accent, var(--gem-font-heading)); }
|
|
33
|
+
.gem-el-product-delivery-estimate { display: grid; gap: var(--gem-space-xs); font-size: var(--gem-text-sm); }
|
|
34
|
+
.gem-el-product-delivery-estimate__steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gem-space-sm); margin: 0; padding: 0; list-style: none; }
|
|
35
|
+
.gem-el-product-delivery-estimate__step { position: relative; display: grid; justify-items: center; gap: var(--gem-space-2xs); text-align: center; }
|
|
36
|
+
.gem-el-product-delivery-estimate__step::before { content: ""; width: 0.75em; height: 0.75em; border-radius: var(--gem-radius-pill); background: var(--gem-color-accent); }
|
|
37
|
+
.gem-el-product-delivery-estimate__step + .gem-el-product-delivery-estimate__step::after { content: ""; position: absolute; top: 0.375em; right: calc(50% + 0.75em); width: calc(100% - 1.5em + var(--gem-space-sm)); height: var(--gem-stroke, 1px); background: var(--gem-color-border); }
|
|
38
|
+
.gem-el-product-delivery-estimate__label { color: var(--gem-color-muted); font-size: var(--gem-text-xs); }
|
|
39
|
+
.gem-el-product-delivery-estimate__date { font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
40
|
+
.gem-el-product-delivery-estimate__note { margin: 0; color: var(--gem-color-muted); font-size: var(--gem-text-xs); }
|
|
41
|
+
.gem-el-product-delivery-estimate[data-gem-delivery-style="line"] .gem-el-product-delivery-estimate__steps { display: flex; flex-wrap: wrap; gap: var(--gem-space-2xs) var(--gem-space-sm); }
|
|
42
|
+
.gem-el-product-delivery-estimate[data-gem-delivery-style="line"] .gem-el-product-delivery-estimate__step { display: inline-flex; gap: var(--gem-space-2xs); text-align: start; }
|
|
43
|
+
.gem-el-product-delivery-estimate[data-gem-delivery-style="line"] .gem-el-product-delivery-estimate__step::before, .gem-el-product-delivery-estimate[data-gem-delivery-style="line"] .gem-el-product-delivery-estimate__step::after { content: none; }
|
|
44
|
+
.gem-el-product-design-switcher { display: grid; gap: var(--gem-space-xs); }
|
|
45
|
+
.gem-el-product-design-switcher__list { display: flex; flex-wrap: wrap; gap: var(--gem-space-xs); margin: 0; padding: 0; list-style: none; }
|
|
46
|
+
.gem-el-product-design-switcher__item { display: inline-flex; align-items: center; gap: var(--gem-space-2xs); min-height: var(--gem-tap-min); padding: var(--gem-space-2xs) var(--gem-space-sm); font-size: var(--gem-text-sm); color: var(--gem-color-text); text-decoration: none; background: var(--gem-color-background); border: var(--gem-stroke, 1px) solid var(--gem-color-border); border-radius: var(--gem-radius-pill); }
|
|
47
|
+
.gem-el-product-design-switcher__item:hover { border-color: var(--gem-color-text); }
|
|
48
|
+
.gem-el-product-design-switcher__item:focus-visible { outline: var(--gem-focus-ring); outline-offset: var(--gem-focus-offset); }
|
|
49
|
+
.gem-el-product-design-switcher__item[aria-current="page"] { border-color: var(--gem-color-text); box-shadow: inset 0 0 0 var(--gem-stroke, 1px) var(--gem-color-text); }
|
|
50
|
+
.gem-el-product-design-switcher__price { color: var(--gem-color-muted); font-variant-numeric: tabular-nums; }
|
|
51
|
+
.gem-el-product-design-switcher__image { display: none; }
|
|
52
|
+
.gem-el-product-design-switcher[data-gem-design-switcher-style="cards"] .gem-el-product-design-switcher__list { display: grid; grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr)); }
|
|
53
|
+
.gem-el-product-design-switcher[data-gem-design-switcher-style="cards"] .gem-el-product-design-switcher__item { flex-direction: column; align-items: stretch; padding: var(--gem-space-xs); border-radius: var(--gem-radius-md); }
|
|
54
|
+
.gem-el-product-design-switcher[data-gem-design-switcher-style="cards"] .gem-el-product-design-switcher__image { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--gem-radius-sm); }
|
|
55
|
+
.gem-el-product-design-switcher[data-gem-design-switcher-style="cards"] .gem-el-product-design-switcher__label { font-weight: 600; }
|
package/dist/popup-shell.css
CHANGED
|
@@ -58,6 +58,19 @@
|
|
|
58
58
|
.gem-popup-shell[data-gem-popup-media='background']:is([data-gem-popup-desktop='split-left'], [data-gem-popup-desktop='split-right'], [data-gem-popup-desktop='card']) .gem-popup-shell__close { color: var(--gem-color-text); }
|
|
59
59
|
.gem-popup-shell[data-gem-popup-media='background']:is([data-gem-popup-desktop='split-left'], [data-gem-popup-desktop='split-right'], [data-gem-popup-desktop='card']) .gem-popup-shell__media::after { content: none; }
|
|
60
60
|
}
|
|
61
|
+
@keyframes gem-popup-drawer-in { from { translate: calc(100% * var(--gem-popup-drawer-dir, 1)) 0; } }
|
|
62
|
+
.gem-popup-shell__dialog:dir(rtl) { --gem-popup-drawer-dir: -1; }
|
|
63
|
+
@media (min-width: 750px) {
|
|
64
|
+
.gem-popup-shell[data-gem-popup-desktop='drawer-end'] .gem-popup-shell__dialog {
|
|
65
|
+
width: min(var(--gem-popup-drawer-width, 640px), 100vw); max-width: 100vw; height: 100dvh; max-height: 100dvh;
|
|
66
|
+
margin-block: 0; margin-inline: auto 0; border-radius: 0;
|
|
67
|
+
animation: gem-popup-drawer-in var(--gem-motion-base, 180ms) var(--gem-ease-enter, ease-out);
|
|
68
|
+
}
|
|
69
|
+
.gem-popup-shell[data-gem-popup-desktop='drawer-end'] .gem-popup-shell__frame { grid-template-columns: 1fr; align-content: start; min-height: 100%; }
|
|
70
|
+
.gem-popup-shell[data-gem-popup-desktop='drawer-end'] .gem-popup-shell__media { max-height: 240px; }
|
|
71
|
+
.gem-popup-shell[data-gem-popup-desktop='drawer-end'] .gem-popup-shell__panel { justify-content: flex-start; align-items: stretch; text-align: start; }
|
|
72
|
+
}
|
|
73
|
+
@media (prefers-reduced-motion: reduce) { .gem-popup-shell[data-gem-popup-desktop='drawer-end'] .gem-popup-shell__dialog { animation: none; } }
|
|
61
74
|
@media (max-width: 749px) {
|
|
62
75
|
.gem-popup-shell__dialog { width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0; border-radius: 0; }
|
|
63
76
|
.gem-popup-shell[data-gem-popup-mobile='sheet'] .gem-popup-shell__dialog { height: auto; max-height: 88dvh; margin: auto 0 0; border-radius: var(--gem-radius-lg) var(--gem-radius-lg) 0 0; }
|
|
@@ -81,6 +94,8 @@
|
|
|
81
94
|
@media (min-width: 750px) {
|
|
82
95
|
:root:has([data-gem-canvas]) .gem-popup-shell[data-gem-popup-preview='true'][data-gem-popup-desktop='fullscreen'] { padding: 0; }
|
|
83
96
|
: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; }
|
|
97
|
+
:root:has([data-gem-canvas]) .gem-popup-shell[data-gem-popup-preview='true'][data-gem-popup-desktop='drawer-end'] { padding-inline: 0; }
|
|
98
|
+
:root:has([data-gem-canvas]) .gem-popup-shell[data-gem-popup-preview='true'][data-gem-popup-desktop='drawer-end'] .gem-popup-shell__dialog { height: 720px; max-height: none; animation: none; }
|
|
84
99
|
}
|
|
85
100
|
@media (max-width: 749px) {
|
|
86
101
|
:root:has([data-gem-canvas]) .gem-popup-shell[data-gem-popup-preview='true'] { padding: 0; }
|
package/dist/primitives.css
CHANGED
|
@@ -103,6 +103,9 @@ a {
|
|
|
103
103
|
cursor: not-allowed;
|
|
104
104
|
opacity: 0.55;
|
|
105
105
|
}
|
|
106
|
+
[data-gem-button-shape='square'] { --gem-radius-button: 0px; }
|
|
107
|
+
[data-gem-button-shape='soft'] { --gem-radius-button: var(--gem-radius-sm); }
|
|
108
|
+
[data-gem-button-shape='pill'] { --gem-radius-button: 999px; }
|
|
106
109
|
.gem-input:disabled, .gem-select:disabled, .gem-textarea:disabled, .gem-quantity-input__button:disabled {
|
|
107
110
|
cursor: not-allowed;
|
|
108
111
|
opacity: 0.6;
|
|
@@ -1068,7 +1071,7 @@ a {
|
|
|
1068
1071
|
:where(.gem-mark--alert) { color: var(--gem-color-danger, #b42318); }
|
|
1069
1072
|
:where(.gem-mark--highlight.gem-mark--accent), :where(.gem-mark--highlight.gem-mark--alert) { color: var(--gem-mark-highlight-ink, #1f1d18); }
|
|
1070
1073
|
.gem-mark-link { color: var(--gem-color-accent); text-decoration-line: underline; text-decoration-thickness: from-font; text-underline-offset: 0.18em; }
|
|
1071
|
-
.gem-mark-link:hover { text-decoration-thickness: 2px; }
|
|
1074
|
+
.gem-mark-link:hover { text-decoration-thickness: var(--gem-underline-thickness, 2px); }
|
|
1072
1075
|
.gem-mark-link.gem-mark--highlight, .gem-mark--highlight .gem-mark-link { color: var(--gem-mark-highlight-ink, #1f1d18); }
|
|
1073
1076
|
@keyframes gem-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(calc(-1 * var(--gem-ambient-amp, 7px))); } }
|
|
1074
1077
|
@keyframes gem-sheen { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
.gem-rail { display: block; position: relative; container-type: inline-size; background-color: var(--gem-motion-tint, transparent); }
|
|
2
|
+
.gem-rail__stage { position: relative; height: var(--gem-rail-stage-height, clamp(380px, 62vh, 640px)); overflow: hidden; container-type: size; }
|
|
3
|
+
.gem-rail__rod { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
|
|
4
|
+
.gem-rail__rod path { fill: none; stroke: var(--gem-rail-rod, currentColor); stroke-width: 5; stroke-linecap: round; vector-effect: non-scaling-stroke; opacity: 0.85; }
|
|
5
|
+
.gem-rail__track { list-style: none; margin: 0; padding: 0; position: absolute; inset: 0; }
|
|
6
|
+
.gem-rail__item {
|
|
7
|
+
--gem-rail-t: calc(0.04 + 0.92 * (var(--gem-rail-i, 0) + 0.5) / var(--gem-rail-n, 1));
|
|
8
|
+
position: absolute; left: 0; top: 0; width: 0; height: 0; z-index: 10;
|
|
9
|
+
transform: translate3d(calc(var(--gem-rail-t) * 100cqw), calc((0.14 + 4 * var(--gem-rail-sag, 0.07) * var(--gem-rail-t) * (1 - var(--gem-rail-t))) * 100cqh), 0);
|
|
10
|
+
}
|
|
11
|
+
.gem-rail__hit {
|
|
12
|
+
position: absolute; left: 0; top: -6px; width: calc(var(--gem-rail-height, 0.7) * 78cqh); height: calc(var(--gem-rail-height, 0.7) * 100cqh + 34px);
|
|
13
|
+
padding: 0; border: 0; color: inherit; background: transparent; text-decoration: none; cursor: pointer; transform: translateX(-50%);
|
|
14
|
+
}
|
|
15
|
+
.gem-rail__hit:focus-visible { outline: var(--gem-focus-ring); outline-offset: var(--gem-focus-offset); border-radius: var(--gem-radius-md); }
|
|
16
|
+
.gem-rail__body { position: absolute; inset: 0; display: block; transform-origin: 50% 0; }
|
|
17
|
+
.gem-rail__hook {
|
|
18
|
+
position: absolute; left: calc(50% - 8px); top: 0; width: 16px; height: 22px; opacity: 0.8;
|
|
19
|
+
border: var(--gem-stroke-thick, 2px) solid var(--gem-rail-rod, currentColor); border-bottom: 0; border-radius: var(--gem-radius-md) var(--gem-radius-md) 0 0;
|
|
20
|
+
}
|
|
21
|
+
.gem-rail__hook::after { content: ''; position: absolute; left: calc(50% - 23px); top: 18px; width: 46px; height: var(--gem-stroke-thick, 2px); background: var(--gem-rail-rod, currentColor); border-radius: var(--gem-radius-sm); }
|
|
22
|
+
.gem-rail__tag {
|
|
23
|
+
position: absolute; left: calc(50% + 14px); top: 18px; z-index: 2; padding: var(--gem-space-2xs) var(--gem-space-xs); transform: rotate(4deg);
|
|
24
|
+
font-family: var(--gem-font-mono); font-size: var(--gem-text-xs); font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums;
|
|
25
|
+
color: var(--gem-color-text); background: var(--gem-color-background); border-radius: var(--gem-radius-sm); box-shadow: var(--gem-shadow-sm);
|
|
26
|
+
}
|
|
27
|
+
.gem-rail .gem-turn { position: absolute; inset: 26px 0 0; width: auto; height: auto; }
|
|
28
|
+
.gem-rail__caption { margin: var(--gem-space-xs) 0 0; min-height: 1.5em; text-align: center; font-variant-numeric: tabular-nums; }
|
|
29
|
+
@container (max-width: 699px) {
|
|
30
|
+
.gem-rail__stage { height: auto; overflow: visible; container-type: normal; }
|
|
31
|
+
.gem-rail__rod { display: none; }
|
|
32
|
+
.gem-rail__track { position: static; display: flex; gap: var(--gem-space-2xs); overflow-x: auto; scroll-snap-type: x mandatory; padding: 0 20cqw var(--gem-space-xs); scrollbar-width: none; }
|
|
33
|
+
.gem-rail__track::-webkit-scrollbar { display: none; }
|
|
34
|
+
.gem-rail__item { position: relative; flex: 0 0 60cqw; width: auto; height: calc(72cqw + 34px); transform: none; scroll-snap-align: center; border-top: var(--gem-stroke-thick, 4px) solid var(--gem-rail-rod, currentColor); }
|
|
35
|
+
.gem-rail__hit { left: 50%; width: 100%; height: 100%; }
|
|
36
|
+
.gem-rail__item:first-child .gem-turn__side { opacity: 0; transform: perspective(900px) rotateY(-82deg); }
|
|
37
|
+
.gem-rail__item:first-child .gem-turn:has(> .gem-turn__side) > .gem-turn__front { opacity: 1; transform: scale(1); }
|
|
38
|
+
.gem-rail__item:first-child .gem-turn:not(:has(> .gem-turn__side)) > .gem-turn__front { transform: perspective(900px) rotateY(0deg) scale(1); }
|
|
39
|
+
.gem-rail__item:first-child .gem-turn__sheet { transform: translate(calc(-100% / var(--gem-turn-cols, 1) * mod(var(--gem-turn-frames, 1) - 1, var(--gem-turn-cols, 1))), calc(-100% / var(--gem-turn-rows, 1) * round(down, (var(--gem-turn-frames, 1) - 1) / var(--gem-turn-cols, 1)))); }
|
|
40
|
+
}
|
|
41
|
+
.gem-turn { position: relative; display: block; width: 100%; height: 100%; }
|
|
42
|
+
.gem-turn[data-gem-turn-frames] { overflow: hidden; }
|
|
43
|
+
.gem-turn__side, .gem-turn__front { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: contain; object-position: 50% 0; pointer-events: none; }
|
|
44
|
+
.gem-turn__side { transform: perspective(900px) rotateY(0deg); backface-visibility: hidden; }
|
|
45
|
+
.gem-turn:has(> .gem-turn__side) > .gem-turn__front { opacity: 0; transform: scale(0.9); }
|
|
46
|
+
.gem-turn:not(:has(> .gem-turn__side)) > .gem-turn__front { transform: perspective(900px) rotateY(-74deg) scale(0.86); }
|
|
47
|
+
.gem-turn__sheet { position: absolute; left: 0; top: 0; display: block; max-width: none; pointer-events: none; width: calc(var(--gem-turn-cols, 1) * 100%); height: calc(var(--gem-turn-rows, 1) * 100%); }
|
|
48
|
+
.gem-turn__sheet + .gem-turn__sheet { opacity: 0; }
|
package/dist/runtime-core.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ export interface PluginInstallScope {
|
|
|
38
38
|
listen(element: EventTarget, type: string, callback: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
|
39
39
|
registerPlugin(key: string, setup: (context: { api: GemApi; config: unknown; reason: string }) => void): void;
|
|
40
40
|
registerNoopPlugin(key: string, readyEvent?: string): void;
|
|
41
|
+
/** Run `cleanup` at unmount (0.19.0), for what is not a listener, timer or observer. */
|
|
42
|
+
onUnmount(cleanup: () => void): void;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
export declare function createGemApi(doc?: Document): GemApi;
|