foss-design 0.9.15 → 0.9.16

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.
@@ -695,12 +695,78 @@ var frameUrl = location.pathname + location.search + location.hash;
695
695
  servePublicFolder(config.public);
696
696
  var theme = config.theme ?? (query.get("theme") === "dark" ? "dark" : "light");
697
697
  var themeListeners = /* @__PURE__ */ new Set();
698
+ var SCHEME = /\(\s*prefers-color-scheme\s*:\s*(dark|light)\s*\)/gi;
699
+ var hasScheme = (text) => /prefers-color-scheme/i.test(text);
700
+ var themed = (text) => text.replace(
701
+ SCHEME,
702
+ (_, wanted) => wanted.toLowerCase() === theme ? "(min-width: 0px)" : "(max-width: 0px)"
703
+ );
704
+ var writtenMedia = /* @__PURE__ */ new WeakMap();
705
+ function themeMediaList(media) {
706
+ const written = writtenMedia.get(media) ?? media.mediaText;
707
+ if (!hasScheme(written)) return;
708
+ writtenMedia.set(media, written);
709
+ const next = themed(written);
710
+ if (media.mediaText !== next) media.mediaText = next;
711
+ }
712
+ function themeRules(rules) {
713
+ for (const rule of Array.from(rules)) {
714
+ if (rule instanceof CSSMediaRule) themeMediaList(rule.media);
715
+ const inner = rule.cssRules;
716
+ if (inner?.length) themeRules(inner);
717
+ }
718
+ }
719
+ function themeStylesheets() {
720
+ for (const sheet of Array.from(document.styleSheets)) {
721
+ try {
722
+ themeMediaList(sheet.media);
723
+ themeRules(sheet.cssRules);
724
+ } catch {
725
+ }
726
+ }
727
+ }
728
+ var nativeMatchMedia = window.matchMedia.bind(window);
729
+ var schemeQueries = /* @__PURE__ */ new Set();
730
+ var ThemeQuery = class extends EventTarget {
731
+ constructor(media) {
732
+ super();
733
+ this.media = media;
734
+ this.last = this.matches;
735
+ schemeQueries.add(this);
736
+ }
737
+ media;
738
+ onchange = null;
739
+ last;
740
+ get matches() {
741
+ return nativeMatchMedia(themed(this.media)).matches;
742
+ }
743
+ addListener(listener) {
744
+ if (listener) this.addEventListener("change", listener);
745
+ }
746
+ removeListener(listener) {
747
+ if (listener) this.removeEventListener("change", listener);
748
+ }
749
+ update() {
750
+ const matches = this.matches;
751
+ if (matches === this.last) return;
752
+ this.last = matches;
753
+ const event = new MediaQueryListEvent("change", { matches, media: this.media });
754
+ this.onchange?.call(this, event);
755
+ this.dispatchEvent(event);
756
+ }
757
+ };
758
+ window.matchMedia = (query2) => hasScheme(query2) ? new ThemeQuery(query2) : nativeMatchMedia(query2);
698
759
  function applyTheme(next) {
699
760
  theme = next;
700
761
  const root = document.documentElement;
701
762
  root.dataset.theme = next;
763
+ root.dataset.mode = next;
764
+ root.dataset.colorScheme = next;
702
765
  root.classList.toggle("dark", next === "dark");
766
+ root.classList.toggle("theme-dark", next === "dark");
703
767
  root.style.colorScheme = next;
768
+ themeStylesheets();
769
+ for (const query2 of schemeQueries) query2.update();
704
770
  for (const listener of themeListeners) listener();
705
771
  }
706
772
  function post(message) {
@@ -728,20 +794,138 @@ function go(target) {
728
794
  function useScreen() {
729
795
  return { canvas: config.canvas, id: config.id, props: config.props };
730
796
  }
797
+ var px2 = (value) => Number.parseFloat(value) || 0;
798
+ var follows = /* @__PURE__ */ new WeakMap();
799
+ var styleKey = (el) => `${el.getAttribute("class") ?? ""}|${el.getAttribute("style") ?? ""}`;
800
+ var stretched = [];
801
+ function measured(el) {
802
+ if (el instanceof HTMLScriptElement || el instanceof HTMLStyleElement || el instanceof HTMLLinkElement) return false;
803
+ const style = getComputedStyle(el);
804
+ return style.display !== "none" && style.display !== "contents" && style.position !== "fixed";
805
+ }
806
+ var VIEWPORT_UNIT = /\d(?:[dsl]?vh|vb)\b/;
807
+ function viewportHeight(el) {
808
+ if (el instanceof HTMLElement && VIEWPORT_UNIT.test(`${el.style.height} ${el.style.minHeight}`)) return true;
809
+ const walk = (rules) => {
810
+ for (const rule of Array.from(rules)) {
811
+ if (rule instanceof CSSStyleRule) {
812
+ const s = rule.style;
813
+ if (VIEWPORT_UNIT.test(`${s.height} ${s.minHeight} ${s.blockSize} ${s.minBlockSize}`)) {
814
+ try {
815
+ if (el.matches(rule.selectorText)) return true;
816
+ } catch {
817
+ }
818
+ }
819
+ }
820
+ const inner = rule.cssRules;
821
+ if (inner?.length && walk(inner)) return true;
822
+ }
823
+ return false;
824
+ };
825
+ for (const sheet of Array.from(document.styleSheets)) {
826
+ let rules;
827
+ try {
828
+ rules = sheet.cssRules;
829
+ } catch {
830
+ continue;
831
+ }
832
+ if (walk(rules)) return true;
833
+ }
834
+ return false;
835
+ }
836
+ var GROWN = ["transition", "height", "min-height", "max-height"];
837
+ function grow(boxes, height) {
838
+ const saved = boxes.map((el) => ({
839
+ had: el.hasAttribute("style"),
840
+ values: GROWN.map((name) => [el.style.getPropertyValue(name), el.style.getPropertyPriority(name)])
841
+ }));
842
+ for (const el of boxes) {
843
+ el.style.setProperty("transition", "none", "important");
844
+ el.style.setProperty("height", `${height}px`, "important");
845
+ el.style.setProperty("min-height", `${height}px`, "important");
846
+ el.style.setProperty("max-height", "none", "important");
847
+ }
848
+ const put = (el, index, at) => {
849
+ const [value, priority] = saved[index].values[at];
850
+ if (value) el.style.setProperty(GROWN[at], value, priority);
851
+ else el.style.removeProperty(GROWN[at]);
852
+ };
853
+ return () => {
854
+ boxes.forEach((el, index) => {
855
+ for (let at = 1; at < GROWN.length; at++) put(el, index, at);
856
+ });
857
+ void document.documentElement.offsetHeight;
858
+ boxes.forEach((el, index) => {
859
+ put(el, index, 0);
860
+ if (!saved[index].had && el.getAttribute("style") === "") el.removeAttribute("style");
861
+ });
862
+ };
863
+ }
864
+ function decide(holders, boxes) {
865
+ const open = boxes.filter((el) => follows.get(el)?.key !== styleKey(el));
866
+ if (!open.length) return;
867
+ const keys = open.map(styleKey);
868
+ const before = open.map((el) => el.getBoundingClientRect().height);
869
+ const tallest = Math.max(window.innerHeight, ...holders.map((el) => el.getBoundingClientRect().height));
870
+ const undo = grow(holders, tallest + 997);
871
+ const after = open.map((el) => el.getBoundingClientRect().height);
872
+ undo();
873
+ open.forEach((el, index) => {
874
+ const grew = after[index] - before[index] > 1;
875
+ const value = grew || Math.abs(px2(getComputedStyle(el).minHeight) - window.innerHeight) < 1 || viewportHeight(el);
876
+ follows.set(el, { key: keys[index], value });
877
+ });
878
+ }
879
+ var filling = (el, room) => Array.from(el.children).filter(
880
+ (child) => measured(child) && Math.abs(child.getBoundingClientRect().height - room) < 1
881
+ );
882
+ function contentBottom(el, room, depth) {
883
+ const style = getComputedStyle(el);
884
+ const rect = el.getBoundingClientRect();
885
+ const margin = px2(style.marginBottom);
886
+ const top = rect.top + window.scrollY;
887
+ const stretch = depth < 8 && Math.abs(rect.height - room) < 1 && follows.get(el)?.value === true;
888
+ if (!stretch || !(el instanceof HTMLElement)) return top + rect.height + margin;
889
+ stretched.push(el);
890
+ const edgeTop = px2(style.borderTopWidth) + px2(style.paddingTop);
891
+ const edgeBottom = px2(style.borderBottomWidth) + px2(style.paddingBottom);
892
+ const space = rect.height - edgeTop - edgeBottom;
893
+ decide([el], filling(el, space));
894
+ const contentTop = top + edgeTop;
895
+ let first = Number.POSITIVE_INFINITY;
896
+ let last = Number.NEGATIVE_INFINITY;
897
+ for (const node of Array.from(el.childNodes)) {
898
+ let from;
899
+ let to;
900
+ if (node instanceof Element) {
901
+ if (!measured(node)) continue;
902
+ from = node.getBoundingClientRect().top + window.scrollY - px2(getComputedStyle(node).marginTop);
903
+ to = contentBottom(node, space, depth + 1);
904
+ } else if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) {
905
+ const range = document.createRange();
906
+ range.selectNode(node);
907
+ const box = range.getBoundingClientRect();
908
+ from = box.top + window.scrollY;
909
+ to = box.bottom + window.scrollY;
910
+ } else continue;
911
+ first = Math.min(first, from);
912
+ last = Math.max(last, to);
913
+ }
914
+ const content = Number.isFinite(first) ? last - Math.max(first, contentTop) : 0;
915
+ return contentTop + Math.max(0, content) + edgeBottom + margin;
916
+ }
731
917
  function contentHeight() {
732
918
  const body = document.body;
733
919
  if (!body) return 0;
734
920
  const bodyStyle = getComputedStyle(body);
921
+ stretched = [];
922
+ decide([document.documentElement, body], filling(body, window.innerHeight));
735
923
  let bottom = 0;
736
924
  for (const child of Array.from(body.children)) {
737
- if (child instanceof HTMLScriptElement || child instanceof HTMLStyleElement || child instanceof HTMLLinkElement)
738
- continue;
739
- const style = getComputedStyle(child);
740
- if (style.display === "none" || style.position === "fixed") continue;
741
- const rect = child.getBoundingClientRect();
742
- bottom = Math.max(bottom, rect.bottom + Number.parseFloat(style.marginBottom || "0") + window.scrollY);
925
+ if (!measured(child)) continue;
926
+ bottom = Math.max(bottom, contentBottom(child, window.innerHeight, 0));
743
927
  }
744
- const extra = Number.parseFloat(bodyStyle.paddingBottom || "0") + Number.parseFloat(bodyStyle.marginBottom || "0");
928
+ const extra = px2(bodyStyle.paddingBottom) + px2(bodyStyle.marginBottom);
745
929
  return Math.min(Math.ceil(bottom + extra), 4e4);
746
930
  }
747
931
  function canScroll(target, dx, dy) {
@@ -773,24 +957,34 @@ function reportSize() {
773
957
  }
774
958
  function watchSize() {
775
959
  let queued = false;
960
+ const resize = new ResizeObserver(() => queue());
961
+ const observed = /* @__PURE__ */ new Set();
962
+ const observe = () => {
963
+ const want = /* @__PURE__ */ new Set([document.documentElement, document.body, ...Array.from(document.body.children)]);
964
+ for (const box of stretched) for (const child of Array.from(box.children)) want.add(child);
965
+ for (const el of observed)
966
+ if (!want.has(el)) {
967
+ resize.unobserve(el);
968
+ observed.delete(el);
969
+ }
970
+ for (const el of want)
971
+ if (!observed.has(el)) {
972
+ resize.observe(el);
973
+ observed.add(el);
974
+ }
975
+ };
776
976
  const queue = () => {
777
977
  if (queued) return;
778
978
  queued = true;
779
979
  requestAnimationFrame(() => {
780
980
  queued = false;
781
981
  reportSize();
982
+ observe();
782
983
  });
783
984
  };
784
- const resize = new ResizeObserver(queue);
785
- const observeChildren = () => {
786
- resize.disconnect();
787
- resize.observe(document.documentElement);
788
- resize.observe(document.body);
789
- for (const child of Array.from(document.body.children)) resize.observe(child);
790
- };
791
- observeChildren();
985
+ observe();
792
986
  new MutationObserver(() => {
793
- observeChildren();
987
+ observe();
794
988
  queue();
795
989
  }).observe(document.body, { childList: true });
796
990
  window.addEventListener("load", queue);
@@ -914,6 +1108,19 @@ function boot() {
914
1108
  if (booted) return;
915
1109
  booted = true;
916
1110
  applyTheme(theme);
1111
+ let restyle = 0;
1112
+ new MutationObserver(() => {
1113
+ cancelAnimationFrame(restyle);
1114
+ themeStylesheets();
1115
+ restyle = requestAnimationFrame(themeStylesheets);
1116
+ }).observe(document.head, { childList: true, subtree: true, characterData: true });
1117
+ document.addEventListener(
1118
+ "load",
1119
+ (event) => {
1120
+ if (event.target instanceof HTMLLinkElement) themeStylesheets();
1121
+ },
1122
+ true
1123
+ );
917
1124
  if (embedded) {
918
1125
  const style = document.createElement("style");
919
1126
  style.textContent = ":where(html, body) { overscroll-behavior: none; }";
@@ -0,0 +1 @@
1
+ "use strict";(()=>{(()=>{if(window.parent===window)return;let o=e=>window.parent.postMessage({source:"design-runtime",key:"page",...e},"*"),a=e=>{if(e.defaultPrevented||e.button>1)return;let t=e.target?.closest?.("a[href], area[href]");if(!t||t.hasAttribute("download"))return;let n=new URL(t.href,location.href);if(n.origin===location.origin){t.target&&t.target!=="_self"&&(e.preventDefault(),location.assign(n.href));return}n.protocol!=="http:"&&n.protocol!=="https:"&&n.protocol!=="mailto:"||(e.preventDefault(),o({type:"link",href:n.href,path:null,form:!1,raw:t.getAttribute("href")??""}))};window.addEventListener("click",a),window.addEventListener("auxclick",a),window.addEventListener("submit",e=>{let t=e.target;if(e.defaultPrevented||t.method==="dialog")return;e.preventDefault();let n=t.getAttribute("action")??"";o({type:"link",href:new URL(n||location.href,location.href).href,path:null,form:!0,raw:n})}),window.addEventListener("keydown",e=>{e.key==="Escape"&&!e.defaultPrevented&&o({type:"keydown",code:"Escape"})});let l=!1;window.addEventListener("message",e=>{let t=e.data;t?.source==="design-viewer"&&e.source===window.parent&&t.type==="pointer"&&(l=!0)});let r=null,i=(e,t,n)=>{if(l){if(n||e<0){o({type:"pointer",x:e,y:t,down:n});return}r||requestAnimationFrame(()=>{r&&o({type:"pointer",x:r.x,y:r.y,down:!1}),r=null}),r={x:e,y:t}}};window.addEventListener("pointermove",e=>i(e.clientX,e.clientY,!1),{capture:!0,passive:!0}),window.addEventListener("pointerdown",e=>i(e.clientX,e.clientY,!0),!0),document.addEventListener("pointerout",e=>{e.relatedTarget||(r=null,i(-1,-1,!1))})})();})();