@mmtitanl/tablets-core 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -271,7 +271,40 @@ function registerDeviceSVG(deviceId, component, frame, screenRect, landscape) {
271
271
  function getDeviceSVG(deviceId) {
272
272
  return SVG_REGISTRY.get(deviceId);
273
273
  }
274
- function buildCustomComponent(deviceId, svgString, cropViewBox, screenRect, suffix) {
274
+ function readSVGViewBox(svg) {
275
+ const vb = svg.match(/viewBox\s*=\s*["']([^"']+)["']/i);
276
+ if (vb) {
277
+ const parts = vb[1].split(/[\s,]+/).map(Number);
278
+ if (parts.length === 4 && parts.every((n) => Number.isFinite(n))) {
279
+ return { x: parts[0], y: parts[1], w: parts[2], h: parts[3] };
280
+ }
281
+ }
282
+ const wm = svg.match(/<svg\b[^>]*\swidth\s*=\s*["']([\d.]+)/i);
283
+ const hm = svg.match(/<svg\b[^>]*\sheight\s*=\s*["']([\d.]+)/i);
284
+ if (wm && hm) return { x: 0, y: 0, w: parseFloat(wm[1]), h: parseFloat(hm[1]) };
285
+ return null;
286
+ }
287
+ function injectScreenMask(svg, frame, suffix) {
288
+ if (frame.totalWidth <= 0 || frame.totalHeight <= 0) return svg;
289
+ if (frame.screenWidth <= 0 || frame.screenHeight <= 0) return svg;
290
+ const vb = readSVGViewBox(svg);
291
+ if (!vb) return svg;
292
+ const sx = vb.w / frame.totalWidth;
293
+ const sy = vb.h / frame.totalHeight;
294
+ const x = vb.x + frame.bezelLeft * sx;
295
+ const y = vb.y + frame.bezelTop * sy;
296
+ const w = frame.screenWidth * sx;
297
+ const h = frame.screenHeight * sy;
298
+ const rt = Math.max(0, frame.screenRadiusTop ?? frame.screenRadius) * Math.min(sx, sy);
299
+ const rb = Math.max(0, frame.screenRadiusBottom ?? frame.screenRadius) * Math.min(sx, sy);
300
+ const maskId = `biela-screen-mask-${suffix || "default"}`;
301
+ const innerPath = `M${x + rt},${y} H${x + w - rt} a${rt},${rt} 0 0 1 ${rt},${rt} V${y + h - rb} a${rb},${rb} 0 0 1 ${-rb},${rb} H${x + rb} a${rb},${rb} 0 0 1 ${-rb},${-rb} V${y + rt} a${rt},${rt} 0 0 1 ${rt},${-rt} Z`;
302
+ const maskDef = `<defs><mask id="${maskId}" maskUnits="userSpaceOnUse" x="${vb.x}" y="${vb.y}" width="${vb.w}" height="${vb.h}"><rect x="${vb.x}" y="${vb.y}" width="${vb.w}" height="${vb.h}" fill="white"/><path d="${innerPath}" fill="black"/></mask></defs>`;
303
+ let result = svg.replace(/(<svg\b[^>]*>)/i, (m) => `${m}${maskDef}<g mask="url(#${maskId})">`);
304
+ result = result.replace(/<\/svg\s*>/i, `</g></svg>`);
305
+ return result;
306
+ }
307
+ function buildCustomComponent(deviceId, svgString, cropViewBox, suffix, frame, dieCut = false) {
275
308
  const scopeKey = suffix ? `${deviceId}${suffix}` : deviceId;
276
309
  let svg = scopeSVGIds(svgString, scopeKey);
277
310
  if (cropViewBox) {
@@ -291,7 +324,7 @@ function buildCustomComponent(deviceId, svgString, cropViewBox, screenRect, suff
291
324
  }
292
325
  );
293
326
  }
294
- void screenRect;
327
+ if (frame && dieCut) svg = injectScreenMask(svg, frame, scopeKey);
295
328
  const Component2 = ({ style }) => /* @__PURE__ */ jsx(
296
329
  "span",
297
330
  {
@@ -302,9 +335,10 @@ function buildCustomComponent(deviceId, svgString, cropViewBox, screenRect, suff
302
335
  Component2.displayName = `CustomDeviceSVG(${scopeKey})`;
303
336
  return Component2;
304
337
  }
305
- function registerCustomDeviceSVG(deviceId, svgString, frame, cropViewBox, screenRect, landscape) {
306
- const portraitComponent = buildCustomComponent(deviceId, svgString, cropViewBox, screenRect, "");
307
- const landscapeComponent = landscape ? buildCustomComponent(deviceId, landscape.svgString, landscape.cropViewBox, landscape.screenRect, "-landscape") : void 0;
338
+ function registerCustomDeviceSVG(deviceId, svgString, frame, cropViewBox, screenRect, landscape, options) {
339
+ const dieCut = options?.dieCutScreen ?? false;
340
+ const portraitComponent = buildCustomComponent(deviceId, svgString, cropViewBox, "", frame, dieCut);
341
+ const landscapeComponent = landscape ? buildCustomComponent(deviceId, landscape.svgString, landscape.cropViewBox, "-landscape", landscape.frame, dieCut) : void 0;
308
342
  SVG_REGISTRY.set(deviceId, {
309
343
  component: portraitComponent,
310
344
  frame,
@@ -689,7 +723,9 @@ function DeviceFrame({
689
723
  manualScale = 1,
690
724
  showSafeAreaOverlay = false,
691
725
  showScaleBar = true,
692
- showStatusBar = true,
726
+ // Implicit oprit: SVG-urile device-urilor au status bar-ul desenat în ramă
727
+ // (ceas, semnal, baterie); cel sintetic ar apărea dublat peste conținut.
728
+ showStatusBar = false,
693
729
  colorScheme = "light",
694
730
  iframeRef,
695
731
  onColorSchemeChange,
@@ -771,9 +807,6 @@ function DeviceFrame({
771
807
  const contentBezelTop = activeFrame?.bezelTop ?? 0;
772
808
  const contentScreenW = activeFrame?.screenWidth ?? dw;
773
809
  const contentScreenH = activeFrame?.screenHeight ?? dh;
774
- const baseRadius = activeFrame?.screenRadius ?? meta.screen.cornerRadius ?? 0;
775
- const radiusTop = activeFrame?.screenRadiusTop ?? baseRadius;
776
- const radiusBottom = activeFrame?.screenRadiusBottom ?? baseRadius;
777
810
  const useRotationFallback = rotateFrame && !hasLandscapeSVG;
778
811
  const scalerTransform = useRotationFallback ? `scale(${scale}) translate(0px, ${scalerW}px) rotate(-90deg)` : `scale(${scale})`;
779
812
  return /* @__PURE__ */ jsxs4(
@@ -812,6 +845,29 @@ function DeviceFrame({
812
845
  transition: "transform 400ms cubic-bezier(0.4, 0, 0.2, 1)"
813
846
  },
814
847
  children: [
848
+ /* @__PURE__ */ jsxs4(
849
+ "div",
850
+ {
851
+ className: "bielaframe-content",
852
+ style: {
853
+ position: "absolute",
854
+ left: `${contentBezelLeft / scalerW * 100}%`,
855
+ top: `${contentBezelTop / scalerH * 100}%`,
856
+ width: `${contentScreenW / scalerW * 100}%`,
857
+ height: `${contentScreenH / scalerH * 100}%`,
858
+ overflow: "hidden",
859
+ zIndex: 0,
860
+ background: colorScheme === "dark" ? "#000" : "#fff",
861
+ borderRadius: activeFrame?.screenRadius ?? 0,
862
+ ...cssVarsStyle
863
+ },
864
+ children: [
865
+ /* @__PURE__ */ jsx6(DeviceErrorBoundary, { children }),
866
+ showStatusBar && /* @__PURE__ */ jsx6(DynamicStatusBar, { contract, orientation, colorScheme }),
867
+ showSafeAreaOverlay && /* @__PURE__ */ jsx6(SafeAreaOverlay, { contract, orientation })
868
+ ]
869
+ }
870
+ ),
815
871
  SVGComponent && portraitFrame && /* @__PURE__ */ jsx6(
816
872
  "div",
817
873
  {
@@ -859,38 +915,6 @@ function DeviceFrame({
859
915
  }
860
916
  )
861
917
  }
862
- ),
863
- /* @__PURE__ */ jsxs4(
864
- "div",
865
- {
866
- className: "bielaframe-content",
867
- style: {
868
- position: "absolute",
869
- left: contentBezelLeft,
870
- top: contentBezelTop,
871
- width: contentScreenW,
872
- height: contentScreenH,
873
- // `border-radius + overflow:hidden` clips the <iframe> child
874
- // in every browser. clip-path is kept as belt-and-braces — some
875
- // engines apply it to the iframe, some don't. Per-edge radii
876
- // (top vs bottom) let devices with asymmetric corners — e.g.
877
- // flat-bottom — clip correctly.
878
- borderRadius: `${radiusTop}px ${radiusTop}px ${radiusBottom}px ${radiusBottom}px`,
879
- clipPath: `inset(0 round ${radiusTop}px ${radiusTop}px ${radiusBottom}px ${radiusBottom}px)`,
880
- overflow: "hidden",
881
- isolation: "isolate",
882
- backfaceVisibility: "hidden",
883
- transform: "translateZ(0)",
884
- background: colorScheme === "dark" ? "#000" : "#fff",
885
- zIndex: 5,
886
- ...cssVarsStyle
887
- },
888
- children: [
889
- /* @__PURE__ */ jsx6(DeviceErrorBoundary, { children }),
890
- showStatusBar && /* @__PURE__ */ jsx6(DynamicStatusBar, { contract, orientation, colorScheme }),
891
- showSafeAreaOverlay && /* @__PURE__ */ jsx6(SafeAreaOverlay, { contract, orientation })
892
- ]
893
- }
894
918
  )
895
919
  ]
896
920
  }
@@ -1205,7 +1229,8 @@ var CustomSVGStore = class {
1205
1229
  },
1206
1230
  void 0,
1207
1231
  sr,
1208
- landscape
1232
+ landscape,
1233
+ { dieCutScreen: entry.dieCutScreen ?? false }
1209
1234
  );
1210
1235
  }
1211
1236
  persist(all) {