@stacksjs/stx 0.2.119 → 0.2.120

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.
Files changed (58) hide show
  1. package/dist/builtins/attrs.d.ts +16 -0
  2. package/dist/builtins/attrs.js +16 -0
  3. package/dist/builtins/safe-image.js +2 -9
  4. package/dist/builtins/stx-image.js +2 -9
  5. package/dist/builtins/stx-link.js +2 -9
  6. package/dist/cli.js +1851 -824
  7. package/dist/client-script-bundler.d.ts +0 -11
  8. package/dist/client-script-bundler.js +26 -4
  9. package/dist/client-script.d.ts +24 -0
  10. package/dist/client-script.js +59 -5
  11. package/dist/component-registry.d.ts +1 -0
  12. package/dist/component-renderer.js +13 -5
  13. package/dist/composables/index.d.ts +1 -0
  14. package/dist/composables/index.js +1 -0
  15. package/dist/composables/use-scroll-lock.d.ts +13 -0
  16. package/dist/composables/use-scroll-lock.js +55 -0
  17. package/dist/composition-api.d.ts +1 -1
  18. package/dist/composition-api.js +13 -4
  19. package/dist/craft-bridge.d.ts +80 -1
  20. package/dist/craft-bridge.js +80 -1
  21. package/dist/craft-components.d.ts +77 -3
  22. package/dist/craft-components.js +138 -9
  23. package/dist/craft.js +481 -73
  24. package/dist/dev-server/crosswind.d.ts +15 -1
  25. package/dist/dev-server/crosswind.js +12 -3
  26. package/dist/dev-server/serve-app.js +3 -3
  27. package/dist/document-shell.d.ts +17 -0
  28. package/dist/document-shell.js +72 -2
  29. package/dist/expressions.js +14 -7
  30. package/dist/head.d.ts +8 -0
  31. package/dist/head.js +11 -8
  32. package/dist/html-masking.d.ts +12 -0
  33. package/dist/html-masking.js +50 -15
  34. package/dist/index.d.ts +9 -1
  35. package/dist/index.js +9 -1
  36. package/dist/process.js +11 -3
  37. package/dist/pwa.js +1154 -431
  38. package/dist/runtime-globals.d.ts +7 -4
  39. package/dist/runtime-globals.js +10 -2
  40. package/dist/runtime-injection.js +15 -1
  41. package/dist/signal-processing.js +19 -28
  42. package/dist/signals-api.d.ts +2 -0
  43. package/dist/signals-api.js +9 -0
  44. package/dist/signals.js +784 -62
  45. package/dist/ssg.js +1143 -420
  46. package/dist/state-management.d.ts +1 -1
  47. package/dist/state-management.js +1 -1
  48. package/dist/strict-lint.d.ts +1 -1
  49. package/dist/strict-lint.js +1 -1
  50. package/dist/stx.d.ts +6 -0
  51. package/dist/style-scoping.js +10 -0
  52. package/dist/utils.js +5 -3
  53. package/dist/variable-extractor.js +14 -22
  54. package/dist/vue-template.js +3 -2
  55. package/dist/x-element.d.ts +2 -2
  56. package/dist/x-element.js +9 -8
  57. package/package.json +5 -5
  58. package/stx.d.ts +6 -0
@@ -123,7 +123,14 @@ export declare const CRAFT_COMPONENTS: {
123
123
  nativeType: 'craft-sidebar';
124
124
  fallbackTag: 'aside';
125
125
  fallbackClasses: 'craft-sidebar craft-sidebar-tahoe';
126
- nativeProps: readonly ['id', 'variant', 'material', 'backgroundEffect', 'allowsVibrancy', 'materialOpacity', 'materialDarkOpacity', 'minWidth', 'maxWidth', 'canCollapse', 'searchPlaceholder', 'selectedItem', 'sections'];
126
+ nativeProps: readonly ['id', 'variant', 'material', 'backgroundEffect', 'allowsVibrancy', 'materialOpacity', 'materialDarkOpacity', 'minWidth', 'maxWidth', 'canCollapse', 'searchPlaceholder', 'selectedItem', 'sections', 'spaces', 'selectedSpace'];
127
+ render: unknown
128
+ };
129
+ 'sidebar-space': {
130
+ nativeType: 'craft-sidebar-space';
131
+ fallbackTag: 'section';
132
+ fallbackClasses: 'craft-sidebar-space';
133
+ nativeProps: readonly ['id', 'label', 'icon', 'tint'];
127
134
  render: unknown
128
135
  };
129
136
  'sidebar-section': {
@@ -503,6 +510,48 @@ export declare const CRAFT_COMPONENT_STYLES: `
503
510
  background: rgba(255, 255, 255, 0.24);
504
511
  }
505
512
 
513
+ /* Spaces fallback. Stacked in document order behind a rail — legible without
514
+ a native host, and deliberately not a second swipe implementation. */
515
+ .craft-sidebar-spaces {
516
+ position: relative;
517
+ z-index: 1;
518
+ flex: 1;
519
+ min-height: 0;
520
+ overflow-y: auto;
521
+ }
522
+ .craft-sidebar-space-title {
523
+ padding: 10px 8px 4px;
524
+ font-size: 13px;
525
+ font-weight: 600;
526
+ }
527
+ .craft-sidebar-space-switcher {
528
+ position: relative;
529
+ z-index: 1;
530
+ display: flex;
531
+ align-items: center;
532
+ gap: 1px;
533
+ padding-top: 6px;
534
+ }
535
+ .craft-sidebar-space-tab {
536
+ display: grid;
537
+ place-items: center;
538
+ width: 28px;
539
+ height: 26px;
540
+ border: 0;
541
+ border-radius: 7px;
542
+ background: transparent;
543
+ color: inherit;
544
+ font: inherit;
545
+ font-size: 11px;
546
+ font-weight: 700;
547
+ opacity: 0.4;
548
+ cursor: default;
549
+ }
550
+ .craft-sidebar-space-tab[data-selected="true"] {
551
+ opacity: 1;
552
+ background: rgba(255, 255, 255, 0.55);
553
+ }
554
+
506
555
  .craft-code-editor {
507
556
  font-family: 'SF Mono', 'Fira Code', monospace;
508
557
  font-size: 13px;
@@ -578,11 +627,36 @@ export declare const CRAFT_COMPONENT_RUNTIME: `
578
627
  var config = parseConfig(sidebar);
579
628
  if (!config) return;
580
629
 
630
+ var hasSpaces = !!(config.spaces && config.spaces.length);
631
+ // Spaces need a host that can swipe between whole scenes. Falling back to
632
+ // createSidebar would flatten every space into one list, which is worse
633
+ // than the web rendering already on the page — so leave that in place.
634
+ if (hasSpaces && typeof nativeUI.createSpacesSidebar !== 'function') return;
635
+
581
636
  try {
582
637
  var nativeConfig = Object.assign({}, config);
583
638
  delete nativeConfig.sections;
584
- var nativeSidebar = nativeUI.createSidebar(nativeConfig);
585
- if (nativeSidebar && config.sections) {
639
+ delete nativeConfig.spaces;
640
+
641
+ var nativeSidebar = hasSpaces
642
+ ? nativeUI.createSpacesSidebar(nativeConfig)
643
+ : nativeUI.createSidebar(nativeConfig);
644
+
645
+ if (nativeSidebar && hasSpaces && nativeSidebar.setSpaces) {
646
+ nativeSidebar.setSpaces(config.spaces);
647
+ }
648
+ if (nativeSidebar && hasSpaces && config.selectedSpace && nativeSidebar.setActiveSpace) {
649
+ nativeSidebar.setActiveSpace(config.selectedSpace);
650
+ }
651
+ if (nativeSidebar && hasSpaces && nativeSidebar.onSpaceChange) {
652
+ nativeSidebar.onSpaceChange(function(spaceId) {
653
+ sidebar.dispatchEvent(new CustomEvent('craft-sidebar:space', {
654
+ bubbles: true,
655
+ detail: { spaceId: spaceId, sidebarId: config.id }
656
+ }));
657
+ });
658
+ }
659
+ if (nativeSidebar && !hasSpaces && config.sections) {
586
660
  config.sections.forEach(function(section) {
587
661
  if (nativeSidebar.addSection) nativeSidebar.addSection(section);
588
662
  });
@@ -218,10 +218,19 @@ export const CRAFT_COMPONENTS = {
218
218
  "canCollapse",
219
219
  "searchPlaceholder",
220
220
  "selectedItem",
221
- "sections"
221
+ "sections",
222
+ "spaces",
223
+ "selectedSpace"
222
224
  ],
223
225
  render: renderCraftSidebar
224
226
  },
227
+ "sidebar-space": {
228
+ nativeType: "craft-sidebar-space",
229
+ fallbackTag: "section",
230
+ fallbackClasses: "craft-sidebar-space",
231
+ nativeProps: ["id", "label", "icon", "tint"],
232
+ render: renderCraftSidebarSpace
233
+ },
225
234
  "sidebar-section": {
226
235
  nativeType: "craft-sidebar-section",
227
236
  fallbackTag: "section",
@@ -620,6 +629,48 @@ export const CRAFT_COMPONENTS = {
620
629
  background: rgba(255, 255, 255, 0.24);
621
630
  }
622
631
 
632
+ /* Spaces fallback. Stacked in document order behind a rail \u2014 legible without
633
+ a native host, and deliberately not a second swipe implementation. */
634
+ .craft-sidebar-spaces {
635
+ position: relative;
636
+ z-index: 1;
637
+ flex: 1;
638
+ min-height: 0;
639
+ overflow-y: auto;
640
+ }
641
+ .craft-sidebar-space-title {
642
+ padding: 10px 8px 4px;
643
+ font-size: 13px;
644
+ font-weight: 600;
645
+ }
646
+ .craft-sidebar-space-switcher {
647
+ position: relative;
648
+ z-index: 1;
649
+ display: flex;
650
+ align-items: center;
651
+ gap: 1px;
652
+ padding-top: 6px;
653
+ }
654
+ .craft-sidebar-space-tab {
655
+ display: grid;
656
+ place-items: center;
657
+ width: 28px;
658
+ height: 26px;
659
+ border: 0;
660
+ border-radius: 7px;
661
+ background: transparent;
662
+ color: inherit;
663
+ font: inherit;
664
+ font-size: 11px;
665
+ font-weight: 700;
666
+ opacity: 0.4;
667
+ cursor: default;
668
+ }
669
+ .craft-sidebar-space-tab[data-selected="true"] {
670
+ opacity: 1;
671
+ background: rgba(255, 255, 255, 0.55);
672
+ }
673
+
623
674
  .craft-code-editor {
624
675
  font-family: 'SF Mono', 'Fira Code', monospace;
625
676
  font-size: 13px;
@@ -694,11 +745,36 @@ export const CRAFT_COMPONENTS = {
694
745
  var config = parseConfig(sidebar);
695
746
  if (!config) return;
696
747
 
748
+ var hasSpaces = !!(config.spaces && config.spaces.length);
749
+ // Spaces need a host that can swipe between whole scenes. Falling back to
750
+ // createSidebar would flatten every space into one list, which is worse
751
+ // than the web rendering already on the page \u2014 so leave that in place.
752
+ if (hasSpaces && typeof nativeUI.createSpacesSidebar !== 'function') return;
753
+
697
754
  try {
698
755
  var nativeConfig = Object.assign({}, config);
699
756
  delete nativeConfig.sections;
700
- var nativeSidebar = nativeUI.createSidebar(nativeConfig);
701
- if (nativeSidebar && config.sections) {
757
+ delete nativeConfig.spaces;
758
+
759
+ var nativeSidebar = hasSpaces
760
+ ? nativeUI.createSpacesSidebar(nativeConfig)
761
+ : nativeUI.createSidebar(nativeConfig);
762
+
763
+ if (nativeSidebar && hasSpaces && nativeSidebar.setSpaces) {
764
+ nativeSidebar.setSpaces(config.spaces);
765
+ }
766
+ if (nativeSidebar && hasSpaces && config.selectedSpace && nativeSidebar.setActiveSpace) {
767
+ nativeSidebar.setActiveSpace(config.selectedSpace);
768
+ }
769
+ if (nativeSidebar && hasSpaces && nativeSidebar.onSpaceChange) {
770
+ nativeSidebar.onSpaceChange(function(spaceId) {
771
+ sidebar.dispatchEvent(new CustomEvent('craft-sidebar:space', {
772
+ bubbles: true,
773
+ detail: { spaceId: spaceId, sidebarId: config.id }
774
+ }));
775
+ });
776
+ }
777
+ if (nativeSidebar && !hasSpaces && config.sections) {
702
778
  config.sections.forEach(function(section) {
703
779
  if (nativeSidebar.addSection) nativeSidebar.addSection(section);
704
780
  });
@@ -755,10 +831,10 @@ export function processCraftComponents(content, config = {}) {
755
831
  </body>`);
756
832
  else
757
833
  content += CRAFT_COMPONENT_RUNTIME;
758
- content = content.replace(/<@craft-sidebar\s*([^>]*)>([\s\S]*?)<\/@craft-sidebar>/g, (match, propsStr, children) => {
834
+ content = content.replace(/<@craft-sidebar(?![-\w])\s*([^>]*)>([\s\S]*?)<\/@craft-sidebar>/g, (match, propsStr, children) => {
759
835
  return renderCraftComponent("sidebar", propsStr, children.trim(), config, classPrefix);
760
836
  });
761
- content = content.replace(/<@craft-sidebar\s*([^>]*?)\/>/g, (match, propsStr) => {
837
+ content = content.replace(/<@craft-sidebar(?![-\w])\s*([^>]*?)\/>/g, (match, propsStr) => {
762
838
  return renderCraftComponent("sidebar", propsStr, "", config, classPrefix);
763
839
  });
764
840
  content = content.replace(/<@craft-(\w+[-\w]*)\s*([^>]*?)\/>/g, (match, componentName, propsStr) => {
@@ -806,7 +882,7 @@ function parseProps(propsStr) {
806
882
  return props;
807
883
  }
808
884
  function renderCraftSidebar(props, children) {
809
- const id = normalizeId(String(props.id || `craft-sidebar-${hashString(children || JSON.stringify(props))}`)), sections = normalizeSidebarSections(props.sections) || extractSidebarSections(children), selectedItem = String(props.selectedItem || props.selected || sections[0]?.items[0]?.id || ""), config = {
885
+ const id = normalizeId(String(props.id || `craft-sidebar-${hashString(children || JSON.stringify(props))}`)), spaces = normalizeSidebarSpaces(props.spaces) || extractSidebarSpaces(children), sections = spaces.length ? [] : normalizeSidebarSections(props.sections) || extractSidebarSections(children), selectedSpace = String(props.selectedSpace || spaces[0]?.id || ""), openSpace = spaces.find((space) => space.id === selectedSpace) || spaces[0], selectedItem = String(props.selectedItem || props.selected || (spaces.length ? openSpace?.sections[0]?.items[0]?.id : sections[0]?.items[0]?.id) || ""), config = {
810
886
  id,
811
887
  variant: String(props.variant || "desktop"),
812
888
  material: String(props.material || "sidebar"),
@@ -819,14 +895,30 @@ function renderCraftSidebar(props, children) {
819
895
  canCollapse: props.canCollapse !== !1 && props.canCollapse !== "false",
820
896
  searchPlaceholder: props.searchPlaceholder ? String(props.searchPlaceholder) : void 0,
821
897
  selectedItem,
822
- sections
823
- }, fallbackClasses = String(props.__fallbackClasses || "craft-sidebar craft-sidebar-tahoe"), width = Number(props.width || props.sidebarWidth || 286), native = props.native === !1 || props.native === "false" ? "false" : "true", search = config.searchPlaceholder ? `<div class="craft-sidebar-search"><input type="search" placeholder="${escapeHtml(config.searchPlaceholder)}"></div>` : "", sectionHtml = sections.length ? sections.map((section) => renderSidebarSectionFallback(section, selectedItem)).join("") : children;
898
+ sections,
899
+ spaces,
900
+ selectedSpace: selectedSpace || void 0
901
+ }, fallbackClasses = String(props.__fallbackClasses || "craft-sidebar craft-sidebar-tahoe"), width = Number(props.width || props.sidebarWidth || 286), native = props.native === !1 || props.native === "false" ? "false" : "true", search = config.searchPlaceholder ? `<div class="craft-sidebar-search"><input type="search" placeholder="${escapeHtml(config.searchPlaceholder)}"></div>` : "";
902
+ let body;
903
+ if (spaces.length)
904
+ body = renderSidebarSpacesFallback(spaces, selectedSpace, selectedItem);
905
+ else if (sections.length)
906
+ body = sections.map((section) => renderSidebarSectionFallback(section, selectedItem)).join("");
907
+ else
908
+ body = children;
824
909
  return `<aside class="${escapeAttribute(fallbackClasses)}" data-craft="craft-sidebar" data-craft-native-sidebar data-craft-sidebar-id="${escapeAttribute(id)}" data-native="${native}" style="--craft-sidebar-width:${width}px">
825
910
  ${search}
826
- ${sectionHtml}
911
+ ${body}
827
912
  </aside>
828
913
  <script type="application/json" data-craft-sidebar-config="${escapeAttribute(id)}">${escapeScriptJson(config)}</script>`;
829
914
  }
915
+ function renderCraftSidebarSpace(props, children) {
916
+ const id = normalizeId(String(props.id || props.label || "space"));
917
+ return `<section class="craft-sidebar-space" data-craft="craft-sidebar-space" data-space-id="${escapeAttribute(id)}">
918
+ ${props.label ? `<div class="craft-sidebar-space-title">${escapeHtml(String(props.label))}</div>` : ""}
919
+ ${children}
920
+ </section>`;
921
+ }
830
922
  function renderCraftSidebarSection(props, children) {
831
923
  const title = String(props.header || props.title || "");
832
924
  return `<section class="craft-sidebar-section" data-craft="craft-sidebar-section" data-section-id="${escapeAttribute(String(props.id || "section"))}">
@@ -868,6 +960,43 @@ function extractSidebarItems(content) {
868
960
  }
869
961
  return items;
870
962
  }
963
+ function extractSidebarSpaces(children) {
964
+ const spaces = [], spacePattern = /<@craft-sidebar-space\s*([^>]*?)(?:\/>|>([\s\S]*?)<\/@craft-sidebar-space>)/g;
965
+ let spaceMatch;
966
+ while ((spaceMatch = spacePattern.exec(children)) !== null) {
967
+ const props = parseProps(spaceMatch[1] || ""), body = spaceMatch[2] || "", label = String(props.label || props.title || `Space ${spaces.length + 1}`);
968
+ spaces.push({
969
+ id: String(props.id || normalizeId(label)),
970
+ label,
971
+ icon: props.icon ? String(props.icon) : void 0,
972
+ tint: props.tint ? String(props.tint) : void 0,
973
+ sections: extractSidebarSections(body)
974
+ });
975
+ }
976
+ return spaces;
977
+ }
978
+ function normalizeSidebarSpaces(value) {
979
+ if (!value)
980
+ return;
981
+ if (Array.isArray(value))
982
+ return value;
983
+ if (typeof value !== "string")
984
+ return;
985
+ try {
986
+ const parsed = JSON.parse(value);
987
+ return Array.isArray(parsed) ? parsed : void 0;
988
+ } catch {
989
+ return;
990
+ }
991
+ }
992
+ function renderSidebarSpacesFallback(spaces, selectedSpace, selectedItem) {
993
+ const rail = spaces.map((space) => `<button class="craft-sidebar-space-tab" type="button" data-space-target="${escapeAttribute(space.id)}" data-selected="${space.id === selectedSpace ? "true" : "false"}" title="${escapeAttribute(space.label || space.id)}">${space.icon ? `<span class="craft-sidebar-item-icon" data-icon="${escapeAttribute(space.icon)}"></span>` : escapeHtml((space.label || space.id).charAt(0))}</button>`).join("");
994
+ return `<div class="craft-sidebar-spaces">${spaces.map((space) => `<section class="craft-sidebar-space" data-space-id="${escapeAttribute(space.id)}" data-selected="${space.id === selectedSpace ? "true" : "false"}">
995
+ ${space.label ? `<div class="craft-sidebar-space-title">${escapeHtml(space.label)}</div>` : ""}
996
+ ${space.sections.map((section) => renderSidebarSectionFallback(section, selectedItem)).join("")}
997
+ </section>`).join("")}</div>
998
+ <div class="craft-sidebar-space-switcher">${rail}</div>`;
999
+ }
871
1000
  function normalizeSidebarSections(value) {
872
1001
  if (!value)
873
1002
  return;