mnfst 0.5.88 → 0.5.89

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.
@@ -587,18 +587,26 @@ const GROUP_INHERITABLE_ATTRS = ['lines', 'edit', 'collapse'];
587
587
  async function setupCodeGroup(group) {
588
588
  if (group.dataset.groupProcessed === 'yes') return;
589
589
 
590
+ // A "panel" is any direct child with a [name] — these are tab panels.
591
+ // Children without [name] are ambient (always visible alongside whichever
592
+ // panel is active). When nothing is named, the group has no tabs at all
593
+ // and renders as a borderless wrapper around its (always-visible) kids —
594
+ // a frame + code pair, for instance, with no title overhead.
590
595
  const sourcePanels = Array.from(group.children).filter(c => c.hasAttribute('name'));
591
- if (sourcePanels.length === 0) return;
596
+ const ambientChildren = Array.from(group.children).filter(c => !c.hasAttribute('name'));
597
+ if (sourcePanels.length === 0 && ambientChildren.length === 0) return;
592
598
  // Claim the group synchronously so re-entrant callers (the directive +
593
599
  // observer can both arrive before the first call's `await` resolves)
594
600
  // bail out — otherwise the wrapper accumulates duplicate tab strips.
595
601
  group.dataset.groupProcessed = 'yes';
596
602
 
597
- // Inherit feature attributes from wrapper to child <pre x-code> panels
598
- // that don't set them. Run BEFORE setupBlock so the inherited attrs
603
+ // Inherit feature attributes from wrapper to child <pre x-code> elements
604
+ // that don't set them. Ambient (unnamed) pres inherit too, so a frame +
605
+ // code pair in an unnamed group still benefits from group-level [lines]
606
+ // / [edit] / [collapse]. Run BEFORE setupBlock so the inherited attrs
599
607
  // drive that block's setup.
600
- for (const panel of sourcePanels) {
601
- if (panel.tagName !== 'PRE') continue;
608
+ const allCodeChildren = [...sourcePanels, ...ambientChildren].filter(c => c.tagName === 'PRE');
609
+ for (const panel of allCodeChildren) {
602
610
  for (const attr of GROUP_INHERITABLE_ATTRS) {
603
611
  if (group.hasAttribute(attr) && !panel.hasAttribute(attr)) {
604
612
  panel.setAttribute(attr, group.getAttribute(attr));
@@ -617,10 +625,11 @@ async function setupCodeGroup(group) {
617
625
  const active = tabNames[0];
618
626
  const slugify = s => s.replace(/\s+/g, '-').toLowerCase();
619
627
 
620
- // Preload hljs + every language needed across the group so each panel's
621
- // setupBlock can synchronously highlight without re-loading.
622
- const codeLangs = sourcePanels
623
- .filter(p => p.tagName === 'PRE' && p.hasAttribute('x-code'))
628
+ // Preload hljs + every language needed across the group (named panels +
629
+ // ambient pres) so each block's setupBlock can synchronously highlight
630
+ // without re-loading.
631
+ const codeLangs = allCodeChildren
632
+ .filter(p => p.hasAttribute('x-code'))
624
633
  .map(p => p.getAttribute('x-code'))
625
634
  .filter(Boolean);
626
635
  let hljs = null;
@@ -647,34 +656,36 @@ async function setupCodeGroup(group) {
647
656
  pre.dataset.groupProcessed = 'yes';
648
657
  if (!pre.hasAttribute('role')) pre.setAttribute('role', 'region');
649
658
 
650
- // Run each code panel through setupBlock so it gets its full feature
651
- // treatment (line numbers, copy button, collapse, editor). Frames stay
652
- // as-is. setupBlock detects [x-code-group] ancestor and suppresses the
653
- // per-panel title bar — the tab strip header serves that role.
654
- for (const panel of sourcePanels) {
655
- if (panel.tagName === 'PRE' && panel.hasAttribute('x-code')) {
659
+ // Run each code child (named or ambient) through setupBlock so it gets
660
+ // its full feature treatment (line numbers, copy button, collapse,
661
+ // editor). Frames stay as-is. setupBlock detects the [x-code-group]
662
+ // ancestor and suppresses the per-panel title bar — the group header
663
+ // (when present) serves that role; for headerless groups, the pre is
664
+ // simply rendered without its own title.
665
+ for (const panel of allCodeChildren) {
666
+ if (panel.hasAttribute('x-code')) {
656
667
  await setupBlock(panel, hljs);
657
668
  panel.dataset.codeProcessed = 'yes';
658
669
  }
659
670
  }
660
671
 
661
672
  // Header: tab strip when there are multiple named panels, plain title bar
662
- // when there's just one. The single-panel form avoids creating a degenerate
663
- // role="tablist" / role="tab" pair that screen readers announce as a
664
- // selectable tab even though there's nothing to switch to same UX and
665
- // ARIA shape as a standalone <pre x-code name="…">, but kept on the group
666
- // wrapper so the wrapper-level copy button and grouped frame siblings still
667
- // work uniformly.
668
- const header = document.createElement('header');
673
+ // when there's just one, no header at all when nothing is named. Skipping
674
+ // the header for headerless groups lets authors pair a frame + code block
675
+ // inside <div x-code-group> with no repetitive "HTML" titleboth render
676
+ // as ambient siblings inside the wrapper.
669
677
  const isSingleTab = tabNames.length === 1;
678
+ const isHeaderless = tabNames.length === 0;
679
+ let header = null;
670
680
  let tablist = null;
671
681
  let tabButtons = [];
682
+ if (!isHeaderless) header = document.createElement('header');
672
683
  if (isSingleTab) {
673
684
  const titleEl = document.createElement('div');
674
685
  titleEl.textContent = active;
675
686
  header.appendChild(titleEl);
676
687
  if (!pre.hasAttribute('aria-label')) pre.setAttribute('aria-label', active);
677
- } else {
688
+ } else if (!isHeaderless) {
678
689
  // The role=tablist sits on an inner <div> that holds the tab buttons.
679
690
  // That way the tablist can have its own overflow-x scrolling (when
680
691
  // there are too many tabs to fit) without dragging sibling header
@@ -714,12 +725,13 @@ async function setupCodeGroup(group) {
714
725
  });
715
726
  });
716
727
  }
717
- pre.insertBefore(header, pre.firstChild);
728
+ if (header) pre.insertBefore(header, pre.firstChild);
718
729
 
719
730
  // Wire ARIA / IDs on each panel. Multi-tab groups get role="tabpanel" with
720
731
  // aria-labelledby pointing at its tab button; single-tab groups keep the
721
732
  // standalone role="region" + aria-label shape (label set on the wrapper
722
- // above) so there's no orphan tabpanel without a tablist.
733
+ // above) so there's no orphan tabpanel without a tablist. Headerless
734
+ // groups have no tabpanels — every child is ambient.
723
735
  sourcePanels.forEach((panel, i) => {
724
736
  const name = panel.getAttribute('name');
725
737
  panel.id = panel.id || `${slugify(name)}-panel-${i}`;
@@ -743,7 +755,7 @@ async function setupCodeGroup(group) {
743
755
  // competing with the header's own overflow-scroll region. Same
744
756
  // positioning rule as for a standalone <pre x-code copy>.
745
757
  const wrapperHasCopy = pre.hasAttribute('copy');
746
- const anyPanelCopy = sourcePanels.some(p => p.hasAttribute('copy'));
758
+ const anyPanelCopy = [...sourcePanels, ...ambientChildren].some(p => p.hasAttribute('copy'));
747
759
  let copyBtn = null;
748
760
  if (wrapperHasCopy || anyPanelCopy) {
749
761
  copyBtn = document.createElement('button');
@@ -754,9 +766,15 @@ async function setupCodeGroup(group) {
754
766
  // When multiple panels share the active name (e.g. a paired
755
767
  // frame + code), prefer the <pre x-code> for copy — the source
756
768
  // is what an author wants to take, not the rendered frame's
757
- // text content.
758
- const sameName = sourcePanels.filter(p => p.getAttribute('name') === activeName);
759
- const activePanel = sameName.find(p => p.tagName === 'PRE' && p.hasAttribute('x-code')) || sameName[0];
769
+ // text content. Headerless groups have no active name, so pick
770
+ // the first ambient <pre x-code> child instead.
771
+ let activePanel;
772
+ if (isHeaderless) {
773
+ activePanel = ambientChildren.find(p => p.tagName === 'PRE' && p.hasAttribute('x-code'));
774
+ } else {
775
+ const sameName = sourcePanels.filter(p => p.getAttribute('name') === activeName);
776
+ activePanel = sameName.find(p => p.tagName === 'PRE' && p.hasAttribute('x-code')) || sameName[0];
777
+ }
760
778
  if (!activePanel) return;
761
779
  const code = activePanel.querySelector(':scope > code') || activePanel;
762
780
  try {
@@ -774,6 +792,7 @@ async function setupCodeGroup(group) {
774
792
  // visibility per-tab: when [copy] sits on the wrapper it stays visible
775
793
  // for every tab; when it sits only on individual panels, the button
776
794
  // shows for tabs whose panels carry [copy] and hides for the rest.
795
+ // Headerless groups have no tabs to switch, so activate() is a no-op.
777
796
  let activeName = active;
778
797
  function activate(name) {
779
798
  activeName = name;
@@ -792,7 +811,7 @@ async function setupCodeGroup(group) {
792
811
  copyBtn.style.display = activeCanCopy ? '' : 'none';
793
812
  }
794
813
  }
795
- activate(active);
814
+ if (!isHeaderless) activate(active);
796
815
  }
797
816
 
798
817
  // ─── Page scan + observation ─────────────────────────────────────────────────
@@ -2,7 +2,7 @@
2
2
  "manifest.appwrite.auth.js": "sha384-to37ssZJXGeOS6+rf2VI47ox2mEqgsi5oQ1E5vv8XU/lDspbDFE1KHEMm8TxBhxW",
3
3
  "manifest.appwrite.data.js": "sha384-00ulLT+GAIuPHA/rRT9p98vYlsyDzkyKXtg86BDQ6FGQa5vVVN+W6kuforniBAsz",
4
4
  "manifest.appwrite.presence.js": "sha384-uxRpx9/Jj0kGtklH5QmUlAzD3zdSvFRfK6bcJQqxl+Bsf5tOo4zgwqJTQgtZoHQP",
5
- "manifest.code.js": "sha384-jO0j5UsOTYYlZs5x/NSzegJQqrEolLEXJZKV29Dxl6tD6qNQwLai1pifsBKh4xWw",
5
+ "manifest.code.js": "sha384-r0cbKtg4/bih6lzNiIdnwiCurW2ohbC8E8zNljSSoO5r+5ewPQcWP4QT+jZp3Oec",
6
6
  "manifest.color.js": "sha384-Z9G/lzt0vVMxjz4wkPuGG1X9mmQAJR15aOoGX3ephf7r2wnlUWet5GLgkUMtT4vt",
7
7
  "manifest.colorpicker.js": "sha384-0EVn+Ha06h7FIvOxc6WjZYnKYXzi+zba08yKvczSEGTRkWRxyKN2TFrZHI1SDCXu",
8
8
  "manifest.components.js": "sha384-3dCTD5EwCZTiX+1obYtDNM3WWwPh2JDQUQQsdRUUK3gs6FXjse1ShkKaT/2jsNaI",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.88",
3
+ "version": "0.5.89",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",