mnfst 0.5.93 → 0.5.95

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.
@@ -344,7 +344,7 @@
344
344
 
345
345
  /* Indent code when line numbers present */
346
346
  &:has(.lines) code {
347
- padding-inline-start: calc(calc(var(--spacing, 0.25rem) * 6) + 2ch)
347
+ padding-inline-start: calc(calc(var(--spacing, 0.25rem) * 8) + 2ch)
348
348
  }
349
349
 
350
350
  /* Code */
@@ -88,6 +88,17 @@ function injectScript(src) {
88
88
  });
89
89
  }
90
90
 
91
+ // Sentinel used by both loaders to detect whether `window.hljs` is already
92
+ // the FULL bundle (which registers ~190 languages) vs the lean core (which
93
+ // starts with very few). Threshold of 50 separates the two reliably —
94
+ // neither the lean core nor any realistic per-language top-up will reach
95
+ // 50 languages before the full bundle does, and the full bundle always
96
+ // ships well above that.
97
+ function hljsIsFullBundle() {
98
+ return typeof window.hljs?.listLanguages === 'function'
99
+ && window.hljs.listLanguages().length > 50;
100
+ }
101
+
91
102
  async function loadHighlightFull() {
92
103
  if (hljsFullPromise) return hljsFullPromise;
93
104
  hljsFullPromise = injectScript(HLJS_FULL_URL).then(() => {
@@ -98,6 +109,15 @@ async function loadHighlightFull() {
98
109
  }
99
110
 
100
111
  async function loadHighlightCore() {
112
+ // Don't downgrade. If the full bundle is already loaded on window.hljs
113
+ // (because the hero editor — or any other caller — asked for full mode
114
+ // first), returning the lean core would mean OVERWRITING window.hljs
115
+ // with a 4-language instance, deleting the full bundle's grammars.
116
+ // Per-block callers downstream would then re-request languages,
117
+ // re-fire reactive bumps, and feed an Alpine re-eval loop. Just hand
118
+ // back the full instance — registerLanguage's "already includes"
119
+ // check below makes the rest of the lean path a no-op.
120
+ if (hljsIsFullBundle()) return window.hljs;
101
121
  if (hljsCorePromise) return hljsCorePromise;
102
122
  hljsCorePromise = import(HLJS_CORE_URL).then(mod => {
103
123
  // esm.run's CJS→ESM shim exposes hljs as the default export. Mirror
@@ -105,6 +125,10 @@ async function loadHighlightCore() {
105
125
  // editor, etc.) that read `hljs` as a global keep working.
106
126
  const hl = mod.default;
107
127
  if (!hl) throw new Error('hljs undefined after core ESM import');
128
+ // Second guard: even after we awaited the dynamic import, the full
129
+ // bundle may have arrived in the meantime (its <script> tag races
130
+ // our ESM fetch). Don't clobber it with the lean core.
131
+ if (hljsIsFullBundle()) return window.hljs;
108
132
  window.hljs = hl;
109
133
  return hl;
110
134
  });
@@ -1 +1 @@
1
- @import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap");:root{--icon-code-copy:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='14' height='14' x='8' y='8' rx='2' ry='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/g%3E%3C/svg%3E");--icon-code-copied:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiBjbGFzcz0ibHVjaWRlIGx1Y2lkZS1jb3B5LWNoZWNrLWljb24gbHVjaWRlLWNvcHktY2hlY2siIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0ibTEyIDE1IDIgMiA0LTQiLz48cmVjdCB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHg9IjgiIHk9IjgiIHJ4PSIyIiByeT0iMiIvPjxwYXRoIGQ9Ik00IDE2Yy0xLjEgMC0yLS45LTItMlY0YzAtMS4xLjktMiAyLTJoMTBjMS4xIDAgMiAuOSAyIDIiLz48L3N2Zz4=");--icon-code-expand:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9 6 6 6-6'/%3E%3C/svg%3E");--color-code-keyword:#b8860b;--color-code-string:#8b4513;--color-code-comment:gray;--color-code-function:peru;--color-code-number:sienna;--color-code-operator:#2f4f4f;--color-code-class-name:#daa520;--color-code-tag:#4682b4;--color-code-attr-name:#ff8c00;--color-code-attr-value:#8b4513;--color-code-property:sienna;--color-code-selector:#4682b4;--color-code-punctuation:#2f4f4f;--color-code-builtin:#b8860b;--color-code-constant:sienna;--color-code-boolean:sienna;--color-code-regex:#8b4513;--color-code-symbol:#daa520;--color-code-entity:#daa520;--color-code-url:sienna;--color-code-atrule:#b8860b;--color-code-rule:#4682b4;--color-code-doctype:gray;--color-code-cdata:gray;--color-code-prolog:gray;--color-code-namespace:gray;--color-code-important:#b8860b;--color-code-inserted:#228b22;--color-code-deleted:#dc143c;--color-code-char:#8b4513}.dark{--color-code-keyword:#f4a460;--color-code-string:#deb887;--color-code-comment:#8b8b8b;--color-code-function:#daa520;--color-code-number:tan;--color-code-operator:wheat;--color-code-class-name:peru;--color-code-tag:#87ceeb;--color-code-attr-name:gold;--color-code-attr-value:#deb887;--color-code-property:tan;--color-code-selector:#87ceeb;--color-code-punctuation:wheat;--color-code-builtin:#f4a460;--color-code-constant:tan;--color-code-boolean:tan;--color-code-regex:#deb887;--color-code-symbol:peru;--color-code-entity:peru;--color-code-url:tan;--color-code-atrule:#f4a460;--color-code-rule:#98fb98;--color-code-doctype:#8b8b8b;--color-code-cdata:#8b8b8b;--color-code-prolog:#8b8b8b;--color-code-namespace:#8b8b8b;--color-code-important:#f4a460;--color-code-inserted:#98fb98;--color-code-deleted:#f08080;--color-code-char:#deb887}@layer utilities{.hljs-comment{color:var(--color-code-comment)!important}.hljs-keyword{color:var(--color-code-keyword)!important}.hljs-string{color:var(--color-code-string)!important}.hljs-number{color:var(--color-code-number)!important}.hljs-literal{color:var(--color-code-constant)!important}.hljs-type{color:var(--color-code-class-name)!important}.hljs-variable{color:var(--color-code-property)!important}.hljs-variable.language_{color:var(--color-code-keyword)!important}.hljs-variable.constant_{color:var(--color-code-constant)!important}.hljs-title{color:var(--color-code-function)!important}.hljs-title.class_.inherited__{color:var(--color-code-class-name)!important}.hljs-title.function_.invoke__{color:var(--color-code-function)!important}.hljs-params{color:var(--color-code-property)!important}.hljs-doctag{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-meta{color:var(--color-code-comment)!important}.hljs-meta.keyword_,.hljs-meta.prompt_{color:var(--color-code-keyword)!important}.hljs-meta.string_{color:var(--color-code-string)!important}.hljs-section{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-name{color:var(--color-code-tag)!important}.hljs-attribute{color:var(--color-code-attr-name)!important}.hljs-bullet{color:var(--color-code-punctuation)!important}.hljs-code{color:var(--color-code-property)!important}.hljs-formula{color:var(--color-code-number)!important}.hljs-quote{color:var(--color-code-string)!important}.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo{color:var(--color-code-selector)!important}.hljs-template-tag{color:var(--color-code-tag)!important}.hljs-template-variable{color:var(--color-code-property)!important}.hljs-subst{color:var(--color-code-string)!important}}@layer components{:where(code[role=button]){height:fit-content}:where(.code-copied-icon){background-color:currentColor;display:inline-block;height:1em;mask-image:var(--icon-code-copied);mask-position:center;mask-repeat:no-repeat;mask-size:contain;width:1em}:where([x-code],[x-code-group]):not(.unstyle){position:relative;:where(header):not(:where(:is(aside.frame) header)){align-items:center;background-color:color-mix(in oklch,var(--color-content-stark,#2f4f4f) 8%,transparent);color:var(--color-content-neutral,gray);display:flex;flex-direction:row;font-family:var(--font-sans,sans-serif);font-size:inherit;min-height:var(--spacing-field-height,2.25rem);padding-inline-end:var(--spacing-field-height);padding-inline-start:calc(var(--spacing, .25rem)*4);width:100%;&:has(button[role=tab]){padding-inline-start:calc(var(--spacing, .25rem)*2)}& [role=tablist]{display:flex;flex-direction:row;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;&::-webkit-scrollbar{display:none}& button[role=tab]{background:transparent;border:0;color:inherit;flex-shrink:0;font-family:inherit;font-size:inherit;height:fit-content;justify-content:start;&:hover{background-color:var(--color-field-surface,color-mix(#2f4f4f 10%,transparent));color:var(--color-content-stark,#2f4f4f)}&[aria-selected=true]{color:var(--color-brand-content,#daa520);pointer-events:none;position:relative}}}}& button.copy{background-color:transparent;font-size:75%;inset-inline-end:0;position:absolute;top:0;&:hover{background-color:transparent;&:after{background-color:var(--color-field-inverse,#2f4f4f)}}&:after{background-color:var(--color-content-neutral,gray);content:"";display:block;height:.8125rem;mask-image:var(--icon-code-copy);mask-repeat:no-repeat;mask-size:contain;width:.8125rem}&.copied:after{mask-image:var(--icon-code-copied)}}:where(header)::-webkit-scrollbar{display:none}& .lines{background-color:var(--color-page,#fff);color:var(--color-content-subtle,#a9a9a9);display:inline-flex;flex-direction:column;font-family:inherit;font-size:inherit;inset-inline-start:0;line-height:inherit;padding:calc(var(--spacing, .25rem)*4);pointer-events:none;position:absolute;text-align:end;user-select:none}&:has(.lines) code{padding-inline-start:calc(var(--spacing, .25rem)*6 + 2ch)}:where(code):not(:where(:is(aside.frame) code)){flex:1 1 100%;min-width:0;white-space:pre;white-space-collapse:preserve}& button.expand{align-items:center;background:transparent;border:0;border-radius:0;color:var(--color-content-subtle,#a9a9a9);cursor:pointer;display:flex;font-family:var(--font-sans,sans-serif);font-size:inherit;height:var(--spacing-field-height,2.25rem);justify-content:center;order:99;padding:0 calc(var(--spacing, .25rem)*2);transition:var(--transition,all .05s ease-in-out);width:100%;&:hover{background:color-mix(in oklch,var(--color-content-stark,#2f4f4f) 8%,transparent);color:var(--color-content-neutral,gray)}}&[data-collapsed] .lines,&[data-collapsed] code{mask-image:linear-gradient(180deg,#000 0,#000 calc(100% - 3em),transparent calc(100% - .75em),transparent);max-height:calc(var(--collapse-lines, 20)*1.7em + var(--spacing, .25rem)*8);overflow:hidden}:where(aside.frame){background:unset;border:0;box-shadow:unset;color:unset;font-family:unset;font-size:unset;font-weight:unset;line-height:unset;white-space:normal;white-space-collapse:collapse}}:where([x-code-group]){flex-flow:column;:where([x-code]){background:transparent;border:0;border-radius:0}}:where([x-code]):has(>header){& .lines{top:var(--spacing-field-height,2.25rem)}}}
1
+ @import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap");:root{--icon-code-copy:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='14' height='14' x='8' y='8' rx='2' ry='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/g%3E%3C/svg%3E");--icon-code-copied:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiBjbGFzcz0ibHVjaWRlIGx1Y2lkZS1jb3B5LWNoZWNrLWljb24gbHVjaWRlLWNvcHktY2hlY2siIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0ibTEyIDE1IDIgMiA0LTQiLz48cmVjdCB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHg9IjgiIHk9IjgiIHJ4PSIyIiByeT0iMiIvPjxwYXRoIGQ9Ik00IDE2Yy0xLjEgMC0yLS45LTItMlY0YzAtMS4xLjktMiAyLTJoMTBjMS4xIDAgMiAuOSAyIDIiLz48L3N2Zz4=");--icon-code-expand:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9 6 6 6-6'/%3E%3C/svg%3E");--color-code-keyword:#b8860b;--color-code-string:#8b4513;--color-code-comment:gray;--color-code-function:peru;--color-code-number:sienna;--color-code-operator:#2f4f4f;--color-code-class-name:#daa520;--color-code-tag:#4682b4;--color-code-attr-name:#ff8c00;--color-code-attr-value:#8b4513;--color-code-property:sienna;--color-code-selector:#4682b4;--color-code-punctuation:#2f4f4f;--color-code-builtin:#b8860b;--color-code-constant:sienna;--color-code-boolean:sienna;--color-code-regex:#8b4513;--color-code-symbol:#daa520;--color-code-entity:#daa520;--color-code-url:sienna;--color-code-atrule:#b8860b;--color-code-rule:#4682b4;--color-code-doctype:gray;--color-code-cdata:gray;--color-code-prolog:gray;--color-code-namespace:gray;--color-code-important:#b8860b;--color-code-inserted:#228b22;--color-code-deleted:#dc143c;--color-code-char:#8b4513}.dark{--color-code-keyword:#f4a460;--color-code-string:#deb887;--color-code-comment:#8b8b8b;--color-code-function:#daa520;--color-code-number:tan;--color-code-operator:wheat;--color-code-class-name:peru;--color-code-tag:#87ceeb;--color-code-attr-name:gold;--color-code-attr-value:#deb887;--color-code-property:tan;--color-code-selector:#87ceeb;--color-code-punctuation:wheat;--color-code-builtin:#f4a460;--color-code-constant:tan;--color-code-boolean:tan;--color-code-regex:#deb887;--color-code-symbol:peru;--color-code-entity:peru;--color-code-url:tan;--color-code-atrule:#f4a460;--color-code-rule:#98fb98;--color-code-doctype:#8b8b8b;--color-code-cdata:#8b8b8b;--color-code-prolog:#8b8b8b;--color-code-namespace:#8b8b8b;--color-code-important:#f4a460;--color-code-inserted:#98fb98;--color-code-deleted:#f08080;--color-code-char:#deb887}@layer utilities{.hljs-comment{color:var(--color-code-comment)!important}.hljs-keyword{color:var(--color-code-keyword)!important}.hljs-string{color:var(--color-code-string)!important}.hljs-number{color:var(--color-code-number)!important}.hljs-literal{color:var(--color-code-constant)!important}.hljs-type{color:var(--color-code-class-name)!important}.hljs-variable{color:var(--color-code-property)!important}.hljs-variable.language_{color:var(--color-code-keyword)!important}.hljs-variable.constant_{color:var(--color-code-constant)!important}.hljs-title{color:var(--color-code-function)!important}.hljs-title.class_.inherited__{color:var(--color-code-class-name)!important}.hljs-title.function_.invoke__{color:var(--color-code-function)!important}.hljs-params{color:var(--color-code-property)!important}.hljs-doctag{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-meta{color:var(--color-code-comment)!important}.hljs-meta.keyword_,.hljs-meta.prompt_{color:var(--color-code-keyword)!important}.hljs-meta.string_{color:var(--color-code-string)!important}.hljs-section{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-name{color:var(--color-code-tag)!important}.hljs-attribute{color:var(--color-code-attr-name)!important}.hljs-bullet{color:var(--color-code-punctuation)!important}.hljs-code{color:var(--color-code-property)!important}.hljs-formula{color:var(--color-code-number)!important}.hljs-quote{color:var(--color-code-string)!important}.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo{color:var(--color-code-selector)!important}.hljs-template-tag{color:var(--color-code-tag)!important}.hljs-template-variable{color:var(--color-code-property)!important}.hljs-subst{color:var(--color-code-string)!important}}@layer components{:where(code[role=button]){height:fit-content}:where(.code-copied-icon){background-color:currentColor;display:inline-block;height:1em;mask-image:var(--icon-code-copied);mask-position:center;mask-repeat:no-repeat;mask-size:contain;width:1em}:where([x-code],[x-code-group]):not(.unstyle){position:relative;:where(header):not(:where(:is(aside.frame) header)){align-items:center;background-color:color-mix(in oklch,var(--color-content-stark,#2f4f4f) 8%,transparent);color:var(--color-content-neutral,gray);display:flex;flex-direction:row;font-family:var(--font-sans,sans-serif);font-size:inherit;min-height:var(--spacing-field-height,2.25rem);padding-inline-end:var(--spacing-field-height);padding-inline-start:calc(var(--spacing, .25rem)*4);width:100%;&:has(button[role=tab]){padding-inline-start:calc(var(--spacing, .25rem)*2)}& [role=tablist]{display:flex;flex-direction:row;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;&::-webkit-scrollbar{display:none}& button[role=tab]{background:transparent;border:0;color:inherit;flex-shrink:0;font-family:inherit;font-size:inherit;height:fit-content;justify-content:start;&:hover{background-color:var(--color-field-surface,color-mix(#2f4f4f 10%,transparent));color:var(--color-content-stark,#2f4f4f)}&[aria-selected=true]{color:var(--color-brand-content,#daa520);pointer-events:none;position:relative}}}}& button.copy{background-color:transparent;font-size:75%;inset-inline-end:0;position:absolute;top:0;&:hover{background-color:transparent;&:after{background-color:var(--color-field-inverse,#2f4f4f)}}&:after{background-color:var(--color-content-neutral,gray);content:"";display:block;height:.8125rem;mask-image:var(--icon-code-copy);mask-repeat:no-repeat;mask-size:contain;width:.8125rem}&.copied:after{mask-image:var(--icon-code-copied)}}:where(header)::-webkit-scrollbar{display:none}& .lines{background-color:var(--color-page,#fff);color:var(--color-content-subtle,#a9a9a9);display:inline-flex;flex-direction:column;font-family:inherit;font-size:inherit;inset-inline-start:0;line-height:inherit;padding:calc(var(--spacing, .25rem)*4);pointer-events:none;position:absolute;text-align:end;user-select:none}&:has(.lines) code{padding-inline-start:calc(var(--spacing, .25rem)*8 + 2ch)}:where(code):not(:where(:is(aside.frame) code)){flex:1 1 100%;min-width:0;white-space:pre;white-space-collapse:preserve}& button.expand{align-items:center;background:transparent;border:0;border-radius:0;color:var(--color-content-subtle,#a9a9a9);cursor:pointer;display:flex;font-family:var(--font-sans,sans-serif);font-size:inherit;height:var(--spacing-field-height,2.25rem);justify-content:center;order:99;padding:0 calc(var(--spacing, .25rem)*2);transition:var(--transition,all .05s ease-in-out);width:100%;&:hover{background:color-mix(in oklch,var(--color-content-stark,#2f4f4f) 8%,transparent);color:var(--color-content-neutral,gray)}}&[data-collapsed] .lines,&[data-collapsed] code{mask-image:linear-gradient(180deg,#000 0,#000 calc(100% - 3em),transparent calc(100% - .75em),transparent);max-height:calc(var(--collapse-lines, 20)*1.7em + var(--spacing, .25rem)*8);overflow:hidden}:where(aside.frame){background:unset;border:0;box-shadow:unset;color:unset;font-family:unset;font-size:unset;font-weight:unset;line-height:unset;white-space:normal;white-space-collapse:collapse}}:where([x-code-group]){flex-flow:column;:where([x-code]){background:transparent;border:0;border-radius:0}}:where([x-code]):has(>header){& .lines{top:var(--spacing-field-height,2.25rem)}}}
@@ -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-r0cbKtg4/bih6lzNiIdnwiCurW2ohbC8E8zNljSSoO5r+5ewPQcWP4QT+jZp3Oec",
5
+ "manifest.code.js": "sha384-jYW7i5F+K+mL5d/HKpw/Xoo0vOz/pmlvotGd7MUPOu+CB+O28OohqgPAEI4y6bSS",
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",
@@ -10,7 +10,7 @@
10
10
  "manifest.dropdowns.js": "sha384-WMrFoSpKfJuo81dyrwhVrDO8rq+rDwh2x8x4nH01BY5ZHkvjE+/SaT2gWCI0zOn+",
11
11
  "manifest.export.js": "sha384-qvdGz1TiGEDOeWJ5os1z03RURdKX+ezZEQ1KyV+9iC7X0esLK83mtY87t4MQv45t",
12
12
  "manifest.icons.js": "sha384-uOkboYrovjCpl22eey3Jaxpey+pOnot5NDnRRumcRxiR7IOVaRh1i20gYnWXR5dW",
13
- "manifest.localization.js": "sha384-eR418BsWisFmFnmhNnNEqx5SMUJywngz6MjWJW7EQWAu1PilepjO/Rp99Z2MTbH5",
13
+ "manifest.localization.js": "sha384-M40EWrbWs2MoJvUiYVQaPxPiOzMYBn/ywuMR02rvoSXG77eIHT/aRoYub9r6+jC+",
14
14
  "manifest.markdown.js": "sha384-3LgPiHrftPqAIJGhxi87C0TtfJXbsH0Qj4JmfmYgV4y5UjSx7nVSP+ppsRUWT0Xs",
15
15
  "manifest.resize.js": "sha384-Ak5gf44ERfh9pOSAD1qZzJSysslpwBCkevIlz7R3dszTUyzUKGKGF4pn5arOtgG0",
16
16
  "manifest.router.js": "sha384-n6xmIfWnYzd/0kkVTFuHhFzHuxiDgZ1Lg1W0yB6/w3Myw5pQ6PgE6SJBHfVsO7/D",
@@ -1,5 +1,16 @@
1
1
  /* Manifest Localization */
2
2
 
3
+ // Snapshot the original <html lang> attribute at the moment this script
4
+ // loads, before any locale-mutation code (this plugin's own init, or any
5
+ // other script) has had a chance to overwrite it. This is the developer's
6
+ // declared default — the value baked into index.html's <html lang="…"> tag
7
+ // — and is the locale $locale.reset() restores to. Captured at module
8
+ // scope so both initializeLocalizationPlugin and the reset implementation
9
+ // can reach it through lexical closure.
10
+ const originalHtmlLang = (typeof document !== 'undefined' && document.documentElement)
11
+ ? (document.documentElement.lang || '')
12
+ : '';
13
+
3
14
  // Global setLocale wrapper - will be replaced with real implementation
4
15
  let setLocaleImpl = null;
5
16
 
@@ -190,6 +201,14 @@ function initializeLocalizationPlugin() {
190
201
  } catch (error) {
191
202
  return false;
192
203
  }
204
+ },
205
+ remove: (key) => {
206
+ try {
207
+ localStorage.removeItem(key);
208
+ return true;
209
+ } catch (error) {
210
+ return false;
211
+ }
193
212
  }
194
213
  };
195
214
 
@@ -515,6 +534,85 @@ function initializeLocalizationPlugin() {
515
534
  setLocaleImpl = setLocaleReal;
516
535
  window.__manifestSetLocale = setLocaleReal;
517
536
 
537
+ // $locale.reset implementation — exposed across functions via window so the
538
+ // magic registration (in registerLocaleMagic, a sibling top-level function)
539
+ // can call it. Inlining the logic in the magic's closure would put it out
540
+ // of scope from safeStorage / isValidLanguageCode / isRTL / originalHtmlLang.
541
+ function resetLocaleReal(href) {
542
+ const store = Alpine.store('locale');
543
+ const available = store?.available || [originalHtmlLang || 'en'];
544
+
545
+ // 1. Clear stored UI-toggle preference so future page loads re-detect.
546
+ safeStorage.remove('lang');
547
+
548
+ // 2. Resolve the default locale. Matches initial detection minus URL
549
+ // and localStorage layers, since reset opts out of both:
550
+ // a. Original <html lang> baked into index.html (snapshotted at
551
+ // plugin init, before any locale mutation).
552
+ // b. Browser language if it matches an available locale.
553
+ // c. First locale registered in manifest.json.
554
+ let defaultLocale = null;
555
+ if (originalHtmlLang
556
+ && isValidLanguageCode(originalHtmlLang)
557
+ && available.includes(originalHtmlLang)) {
558
+ defaultLocale = originalHtmlLang;
559
+ } else if (navigator.language) {
560
+ const browserLang = navigator.language.split('-')[0];
561
+ if (isValidLanguageCode(browserLang) && available.includes(browserLang)) {
562
+ defaultLocale = browserLang;
563
+ }
564
+ }
565
+ if (!defaultLocale) {
566
+ defaultLocale = available[0] || 'en';
567
+ }
568
+
569
+ // 3. Resolve target URL (passed-in href or current) and strip its
570
+ // leading locale segment, if any.
571
+ let target;
572
+ try {
573
+ target = new URL(href || window.location.href, window.location.href);
574
+ } catch {
575
+ return false;
576
+ }
577
+ const segs = target.pathname.split('/').filter(Boolean);
578
+ if (segs.length && available.includes(segs[0])) {
579
+ segs.shift();
580
+ }
581
+ target.pathname = '/' + segs.join('/');
582
+
583
+ // 4. Apply the default locale to the live store + DOM before
584
+ // navigating, so $locale.current and any reactive readers update
585
+ // immediately.
586
+ if (store && store.current !== defaultLocale) {
587
+ store.current = defaultLocale;
588
+ store.direction = isRTL(defaultLocale) ? 'rtl' : 'ltr';
589
+ try {
590
+ document.documentElement.lang = defaultLocale;
591
+ document.documentElement.dir = store.direction;
592
+ } catch { /* DOM unavailable */ }
593
+ try {
594
+ window.dispatchEvent(new CustomEvent('localechange', {
595
+ detail: { locale: defaultLocale }
596
+ }));
597
+ } catch { /* event dispatch unavailable */ }
598
+ }
599
+
600
+ // 5. Navigate to the locale-stripped URL. SPA hop in the live app,
601
+ // MPA hop in prerendered output so the new URL's prerendered HTML
602
+ // loads from disk.
603
+ const isSameOrigin = target.origin === window.location.origin;
604
+ const isPrerendered = !!document.querySelector('meta[name="manifest:prerendered"]:not([content="0"]):not([content="false"])');
605
+
606
+ if (isSameOrigin && !isPrerendered && typeof history?.pushState === 'function') {
607
+ history.pushState(null, '', target.pathname + target.search + target.hash);
608
+ window.dispatchEvent(new PopStateEvent('popstate'));
609
+ } else {
610
+ window.location.assign(target.toString());
611
+ }
612
+ return true;
613
+ }
614
+ window.__manifestResetLocale = resetLocaleReal;
615
+
518
616
  // Event listener cleanup tracking
519
617
  let routeChangeListener = null;
520
618
 
@@ -633,59 +731,42 @@ function registerLocaleMagic() {
633
731
  }
634
732
  };
635
733
  }
636
- // $locale.reset([href]) — strip any leading locale segment from
637
- // the URL (or from a passed-in href) and navigate there. Pairs
638
- // with the router's sticky-locale rewriter: that adds the
639
- // current locale to outgoing same-origin links automatically,
640
- // and this method is the opt-out for a developer who wants to
641
- // surface a "go to default locale" action without hard-coding
642
- // the default's language code.
734
+ // $locale.reset([href]) — restore the project's default
735
+ // locale. Reset clears the user's stored language preference,
736
+ // recomputes the default from the developer's declarations,
737
+ // and applies it to the live store + <html lang>/<html dir>.
738
+ //
739
+ // Default resolution (matches initial detection minus the
740
+ // URL and localStorage layers, since reset explicitly opts
741
+ // out of both):
742
+ // 1. Original <html lang> baked into index.html
743
+ // (snapshotted at plugin init, before any mutation)
744
+ // 2. Browser language (navigator.language) if it matches
745
+ // an available locale
746
+ // 3. First locale registered in manifest.json
643
747
  //
644
- // Behaviour:
645
- // $locale.reset() → reset current URL to no prefix
646
- // $locale.reset('/foo') → strip prefix from /foo (no-op
647
- // if there isn't one) and navigate
648
- // $locale.reset('/fr/foo') → 'fr' is stripped → /foo
748
+ // As a side effect, any leading locale slug in the URL is
749
+ // stripped (since the URL prefix would otherwise re-detect
750
+ // back into a non-default locale on the next page load).
649
751
  //
650
- // Routing path: if Manifest's SPA navigation is active
651
- // (`history.pushState` + `manifest:route-change` event), this
652
- // is a SPA hop with no full reload. In prerendered MPA mode
653
- // we use `window.location.assign` so the new URL's
654
- // prerendered HTML loads from disk.
752
+ // Forms:
753
+ // $locale.reset() → reset current URL
754
+ // $locale.reset('/fr/foo') strip prefix from given href,
755
+ // then navigate (useful for
756
+ // "View in default language"
757
+ // links anywhere on the page)
758
+ //
759
+ // Routing path: SPA hop via history.pushState when running
760
+ // in the live SPA; full navigation via location.assign in
761
+ // prerendered MPA mode so the new URL's prerendered HTML
762
+ // loads from disk.
655
763
  if (prop === 'reset') {
656
764
  return (href) => {
657
- const store = Alpine.store('locale');
658
- const available = store?.available || [document.documentElement.lang || 'en'];
659
-
660
- // Resolve target URL: passed-in href, or current URL
661
- let target;
662
- try {
663
- target = new URL(href || window.location.href, window.location.href);
664
- } catch {
665
- return false;
765
+ if (window.__manifestResetLocale) {
766
+ return window.__manifestResetLocale(href);
666
767
  }
667
-
668
- // Strip leading locale segment if present
669
- const segs = target.pathname.split('/').filter(Boolean);
670
- if (segs.length && available.includes(segs[0])) {
671
- segs.shift();
672
- }
673
- target.pathname = '/' + segs.join('/');
674
-
675
- // Same-origin navigation only — external URLs are
676
- // passed through unchanged via window.location.assign.
677
- const isSameOrigin = target.origin === window.location.origin;
678
- const isPrerendered = !!document.querySelector('meta[name="manifest:prerendered"]:not([content="0"]):not([content="false"])');
679
-
680
- if (isSameOrigin && !isPrerendered && typeof history?.pushState === 'function') {
681
- // SPA hop: keep the in-memory app, fire route-change.
682
- history.pushState(null, '', target.pathname + target.search + target.hash);
683
- window.dispatchEvent(new PopStateEvent('popstate'));
684
- } else {
685
- // MPA hop: load the prerendered HTML for the new URL.
686
- window.location.assign(target.toString());
687
- }
688
- return true;
768
+ console.error('[Manifest Localization] resetLocale not available');
769
+ return false;
689
770
  };
690
771
  }
691
772
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.93",
3
+ "version": "0.5.95",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",