@ngrok/mantle 0.66.9 → 0.66.11

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.
@@ -147,9 +147,9 @@ declare const AlertDialog: {
147
147
  * ```
148
148
  */
149
149
  readonly Action: react.ForwardRefExoticComponent<(Omit<react.ClassAttributes<HTMLButtonElement> & react.ButtonHTMLAttributes<HTMLButtonElement> & Partial<DeepNonNullable<class_variance_authority0.VariantProps<(props?: ({
150
- appearance?: "filled" | "link" | "ghost" | "outlined" | null | undefined;
150
+ appearance?: "link" | "ghost" | "outlined" | "filled" | null | undefined;
151
151
  isLoading?: boolean | null | undefined;
152
- priority?: "danger" | "neutral" | "default" | null | undefined;
152
+ priority?: "default" | "danger" | "neutral" | null | undefined;
153
153
  } & class_variance_authority_types0.ClassProp) | undefined) => string>>> & {
154
154
  icon?: ReactNode;
155
155
  iconPlacement?: "start" | "end";
@@ -157,9 +157,9 @@ declare const AlertDialog: {
157
157
  asChild: true;
158
158
  type?: ComponentProps<"button">["type"];
159
159
  }, "ref"> | Omit<react.ClassAttributes<HTMLButtonElement> & react.ButtonHTMLAttributes<HTMLButtonElement> & Partial<DeepNonNullable<class_variance_authority0.VariantProps<(props?: ({
160
- appearance?: "filled" | "link" | "ghost" | "outlined" | null | undefined;
160
+ appearance?: "link" | "ghost" | "outlined" | "filled" | null | undefined;
161
161
  isLoading?: boolean | null | undefined;
162
- priority?: "danger" | "neutral" | "default" | null | undefined;
162
+ priority?: "default" | "danger" | "neutral" | null | undefined;
163
163
  } & class_variance_authority_types0.ClassProp) | undefined) => string>>> & {
164
164
  icon?: ReactNode;
165
165
  iconPlacement?: "start" | "end";
@@ -204,9 +204,9 @@ declare const AlertDialog: {
204
204
  * ```
205
205
  */
206
206
  readonly Cancel: react.ForwardRefExoticComponent<(Omit<react.ClassAttributes<HTMLButtonElement> & react.ButtonHTMLAttributes<HTMLButtonElement> & Partial<DeepNonNullable<class_variance_authority0.VariantProps<(props?: ({
207
- appearance?: "filled" | "link" | "ghost" | "outlined" | null | undefined;
207
+ appearance?: "link" | "ghost" | "outlined" | "filled" | null | undefined;
208
208
  isLoading?: boolean | null | undefined;
209
- priority?: "danger" | "neutral" | "default" | null | undefined;
209
+ priority?: "default" | "danger" | "neutral" | null | undefined;
210
210
  } & class_variance_authority_types0.ClassProp) | undefined) => string>>> & {
211
211
  icon?: ReactNode;
212
212
  iconPlacement?: "start" | "end";
@@ -214,9 +214,9 @@ declare const AlertDialog: {
214
214
  asChild: true;
215
215
  type?: ComponentProps<"button">["type"];
216
216
  }, "ref"> | Omit<react.ClassAttributes<HTMLButtonElement> & react.ButtonHTMLAttributes<HTMLButtonElement> & Partial<DeepNonNullable<class_variance_authority0.VariantProps<(props?: ({
217
- appearance?: "filled" | "link" | "ghost" | "outlined" | null | undefined;
217
+ appearance?: "link" | "ghost" | "outlined" | "filled" | null | undefined;
218
218
  isLoading?: boolean | null | undefined;
219
- priority?: "danger" | "neutral" | "default" | null | undefined;
219
+ priority?: "default" | "danger" | "neutral" | null | undefined;
220
220
  } & class_variance_authority_types0.ClassProp) | undefined) => string>>> & {
221
221
  icon?: ReactNode;
222
222
  iconPlacement?: "start" | "end";
package/dist/alert.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as SvgAttributes } from "./types-Dh4BVhXC.js";
2
2
  import { t as WithAsChild } from "./as-child-XMVTepJu.js";
3
- import { n as IconButtonProps } from "./icon-button-ikEU0Ctp.js";
3
+ import { n as IconButtonProps } from "./icon-button-2r6S3HVA.js";
4
4
  import * as react from "react";
5
5
  import { ComponentProps, HTMLAttributes, ReactNode } from "react";
6
6
  import * as react_jsx_runtime0 from "react/jsx-runtime";
@@ -7,9 +7,9 @@ import * as class_variance_authority_types0 from "class-variance-authority/types
7
7
 
8
8
  //#region src/components/button/button.d.ts
9
9
  declare const buttonVariants: (props?: ({
10
- appearance?: "filled" | "link" | "ghost" | "outlined" | null | undefined;
10
+ appearance?: "link" | "ghost" | "outlined" | "filled" | null | undefined;
11
11
  isLoading?: boolean | null | undefined;
12
- priority?: "danger" | "neutral" | "default" | null | undefined;
12
+ priority?: "default" | "danger" | "neutral" | null | undefined;
13
13
  } & class_variance_authority_types0.ClassProp) | undefined) => string;
14
14
  type ButtonVariants = VariantProps$1<typeof buttonVariants>;
15
15
  /**
@@ -91,9 +91,9 @@ type ButtonProps = ComponentProps<"button"> & ButtonVariants & {
91
91
  * ```
92
92
  */
93
93
  declare const Button: react.ForwardRefExoticComponent<(Omit<react.ClassAttributes<HTMLButtonElement> & react.ButtonHTMLAttributes<HTMLButtonElement> & Partial<DeepNonNullable<class_variance_authority0.VariantProps<(props?: ({
94
- appearance?: "filled" | "link" | "ghost" | "outlined" | null | undefined;
94
+ appearance?: "link" | "ghost" | "outlined" | "filled" | null | undefined;
95
95
  isLoading?: boolean | null | undefined;
96
- priority?: "danger" | "neutral" | "default" | null | undefined;
96
+ priority?: "default" | "danger" | "neutral" | null | undefined;
97
97
  } & class_variance_authority_types0.ClassProp) | undefined) => string>>> & {
98
98
  /**
99
99
  * An icon to render inside the button. If the `state` is `"pending"`, then
@@ -137,9 +137,9 @@ declare const Button: react.ForwardRefExoticComponent<(Omit<react.ClassAttribute
137
137
  */
138
138
  type?: ComponentProps<"button">["type"];
139
139
  }, "ref"> | Omit<react.ClassAttributes<HTMLButtonElement> & react.ButtonHTMLAttributes<HTMLButtonElement> & Partial<DeepNonNullable<class_variance_authority0.VariantProps<(props?: ({
140
- appearance?: "filled" | "link" | "ghost" | "outlined" | null | undefined;
140
+ appearance?: "link" | "ghost" | "outlined" | "filled" | null | undefined;
141
141
  isLoading?: boolean | null | undefined;
142
- priority?: "danger" | "neutral" | "default" | null | undefined;
142
+ priority?: "default" | "danger" | "neutral" | null | undefined;
143
143
  } & class_variance_authority_types0.ClassProp) | undefined) => string>>> & {
144
144
  /**
145
145
  * An icon to render inside the button. If the `state` is `"pending"`, then
@@ -172,4 +172,4 @@ declare const Button: react.ForwardRefExoticComponent<(Omit<react.ClassAttribute
172
172
  }, "ref">) & react.RefAttributes<HTMLButtonElement>>;
173
173
  //#endregion
174
174
  export { ButtonProps as n, Button as t };
175
- //# sourceMappingURL=button-DQO0IuzC.d.ts.map
175
+ //# sourceMappingURL=button-CKL-3sIr.d.ts.map
package/dist/button.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as IconButtonProps, t as IconButton } from "./icon-button-ikEU0Ctp.js";
2
- import { n as ButtonProps, t as Button } from "./button-DQO0IuzC.js";
3
- import { n as ButtonGroupProps, t as ButtonGroup } from "./index-ViSCOUrU.js";
1
+ import { n as IconButtonProps, t as IconButton } from "./icon-button-2r6S3HVA.js";
2
+ import { n as ButtonProps, t as Button } from "./button-CKL-3sIr.js";
3
+ import { n as ButtonGroupProps, t as ButtonGroup } from "./index-CMbK9igL.js";
4
4
  export { Button, ButtonGroup, ButtonGroupProps, ButtonProps, IconButton, IconButtonProps };
@@ -19,7 +19,7 @@ type CheckedState = boolean | "indeterminate";
19
19
  * </form>
20
20
  * ```
21
21
  */
22
- declare const Checkbox: react.ForwardRefExoticComponent<Omit<Omit<react.DetailedHTMLProps<react.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "defaultChecked" | "checked" | "type"> & WithValidation & {
22
+ declare const Checkbox: react.ForwardRefExoticComponent<Omit<Omit<react.DetailedHTMLProps<react.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "type" | "defaultChecked" | "checked"> & WithValidation & {
23
23
  /**
24
24
  * The controlled checked state of the checkbox. Must be used in conjunction with onChange.
25
25
  */
@@ -27,7 +27,7 @@ declare const isSupportedLanguage: (value: unknown) => value is SupportedLanguag
27
27
  * Formats a language name into a class name that Prism.js can understand.
28
28
  * @default "language-sh"
29
29
  */
30
- declare function formatLanguageClassName(language?: SupportedLanguage | undefined): "language-text" | "language-ruby" | "language-plaintext" | "language-html" | "language-go" | "language-py" | "language-jsx" | "language-bash" | "language-cs" | "language-csharp" | "language-css" | "language-dotnet" | "language-java" | "language-javascript" | "language-js" | "language-json" | "language-markup" | "language-plain" | "language-python" | "language-rb" | "language-rust" | "language-sh" | "language-shell" | "language-ts" | "language-tsx" | "language-txt" | "language-typescript" | "language-xml" | "language-yaml" | "language-yml";
30
+ declare function formatLanguageClassName(language?: SupportedLanguage | undefined): "language-py" | "language-text" | "language-html" | "language-ruby" | "language-go" | "language-plaintext" | "language-bash" | "language-cs" | "language-csharp" | "language-css" | "language-dotnet" | "language-java" | "language-javascript" | "language-js" | "language-json" | "language-jsx" | "language-markup" | "language-plain" | "language-python" | "language-rb" | "language-rust" | "language-sh" | "language-shell" | "language-ts" | "language-tsx" | "language-txt" | "language-typescript" | "language-xml" | "language-yaml" | "language-yml";
31
31
  //#endregion
32
32
  //#region src/components/code-block/indentation.d.ts
33
33
  declare const indentations: readonly ["tabs", "spaces"];
@@ -1,4 +1,4 @@
1
- import{t as e}from"./cx-bKromGBh.js";import{t}from"./icon-B5oNYYrJ.js";import{t as n}from"./booleanish-CBGdPL3Q.js";import{t as r}from"./slot-DdnjeV2n.js";import{t as i}from"./use-copy-to-clipboard-BEbQOKHc.js";import{t as a}from"./traffic-policy-file-QnF-2YkY.js";import{CaretDownIcon as o}from"@phosphor-icons/react/CaretDown";import{createContext as s,forwardRef as c,useContext as l,useEffect as u,useId as d,useMemo as f,useRef as p,useState as m}from"react";import h from"clsx";import g from"tiny-invariant";import{Fragment as _,jsx as v,jsxs as y}from"react/jsx-runtime";import{CheckIcon as b}from"@phosphor-icons/react/Check";import{CopyIcon as x}from"@phosphor-icons/react/Copy";import{FileTextIcon as S}from"@phosphor-icons/react/FileText";import{TerminalIcon as C}from"@phosphor-icons/react/Terminal";import w from"prismjs";import"prismjs/components/prism-bash.js";import"prismjs/components/prism-csharp.js";import"prismjs/components/prism-css.js";import"prismjs/components/prism-go.js";import"prismjs/components/prism-java.js";import"prismjs/components/prism-javascript.js";import"prismjs/components/prism-json.js";import"prismjs/components/prism-jsx.js";import"prismjs/components/prism-markup.js";import"prismjs/components/prism-python.js";import"prismjs/components/prism-ruby.js";import"prismjs/components/prism-rust.js";import"prismjs/components/prism-tsx.js";import"prismjs/components/prism-typescript.js";import"prismjs/components/prism-yaml.js";function T(e){let t=-1;for(let n=0;n<e.length;n++){let r=e[n];if(r===`&`||r===`<`||r===`>`||r===`"`||r===`'`){t=n;break}}if(t===-1)return e;let n=e.slice(0,t);for(let r=t;r<e.length;r++){let t=e[r];switch(t){case`&`:n+=`&amp;`;break;case`<`:n+=`&lt;`;break;case`>`:n+=`&gt;`;break;case`"`:n+=`&quot;`;break;case`'`:n+=`&#39;`;break;default:n+=t}}return n}const E=[`tabs`,`spaces`];function D(e){return E.includes(e)}function O(e,t){return t||(j(e)?`tabs`:(M(e),`spaces`))}const k=new Set([`csharp`,`css`,`go`,`html`,`java`,`javascript`,`js`,`jsx`,`ts`,`tsx`,`typescript`,`xml`]),A=new Set([`python`,`py`,`yaml`,`yml`,`ruby`,`rb`]);function j(e){return k.has(e)}function M(e){return A.has(e)}function N(e,...t){if(!ee(e)||!Array.isArray(t))throw Error("It looks like you tried to call `fmtCode` as a function. Make sure to use it as a tagged template.\n Example: fmtCode`SELECT * FROM users`, not fmtCode('SELECT * FROM users')");let n=String.raw({raw:e},...t),r=P(n),i=n.trim().split(`
1
+ import{t as e}from"./cx-bKromGBh.js";import{t}from"./icon-B5oNYYrJ.js";import{t as n}from"./booleanish-CBGdPL3Q.js";import{t as r}from"./slot-DdnjeV2n.js";import{t as i}from"./use-copy-to-clipboard-BCpEp-sO.js";import{t as a}from"./traffic-policy-file-QnF-2YkY.js";import{CaretDownIcon as o}from"@phosphor-icons/react/CaretDown";import{createContext as s,forwardRef as c,useContext as l,useEffect as u,useId as d,useMemo as f,useRef as p,useState as m}from"react";import h from"clsx";import g from"tiny-invariant";import{Fragment as _,jsx as v,jsxs as y}from"react/jsx-runtime";import{CheckIcon as b}from"@phosphor-icons/react/Check";import{CopyIcon as x}from"@phosphor-icons/react/Copy";import{FileTextIcon as S}from"@phosphor-icons/react/FileText";import{TerminalIcon as C}from"@phosphor-icons/react/Terminal";import w from"prismjs";import"prismjs/components/prism-bash.js";import"prismjs/components/prism-csharp.js";import"prismjs/components/prism-css.js";import"prismjs/components/prism-go.js";import"prismjs/components/prism-java.js";import"prismjs/components/prism-javascript.js";import"prismjs/components/prism-json.js";import"prismjs/components/prism-jsx.js";import"prismjs/components/prism-markup.js";import"prismjs/components/prism-python.js";import"prismjs/components/prism-ruby.js";import"prismjs/components/prism-rust.js";import"prismjs/components/prism-tsx.js";import"prismjs/components/prism-typescript.js";import"prismjs/components/prism-yaml.js";function T(e){let t=-1;for(let n=0;n<e.length;n++){let r=e[n];if(r===`&`||r===`<`||r===`>`||r===`"`||r===`'`){t=n;break}}if(t===-1)return e;let n=e.slice(0,t);for(let r=t;r<e.length;r++){let t=e[r];switch(t){case`&`:n+=`&amp;`;break;case`<`:n+=`&lt;`;break;case`>`:n+=`&gt;`;break;case`"`:n+=`&quot;`;break;case`'`:n+=`&#39;`;break;default:n+=t}}return n}const E=[`tabs`,`spaces`];function D(e){return E.includes(e)}function O(e,t){return t||(j(e)?`tabs`:(M(e),`spaces`))}const k=new Set([`csharp`,`css`,`go`,`html`,`java`,`javascript`,`js`,`jsx`,`ts`,`tsx`,`typescript`,`xml`]),A=new Set([`python`,`py`,`yaml`,`yml`,`ruby`,`rb`]);function j(e){return k.has(e)}function M(e){return A.has(e)}function N(e,...t){if(!ee(e)||!Array.isArray(t))throw Error("It looks like you tried to call `fmtCode` as a function. Make sure to use it as a tagged template.\n Example: fmtCode`SELECT * FROM users`, not fmtCode('SELECT * FROM users')");let n=String.raw({raw:e},...t),r=P(n),i=n.trim().split(`
2
2
  `),a=Array(i.length);for(let e=0;e<i.length;e++){let t=i[e];t!=null&&(a[e]=F(t)?t:t.slice(r))}return a.join(`
3
3
  `)}function P(e){let t=1/0,n=0,r=!0;for(let i=0;i<e.length;i++){let a=e[i];if(r){if(a===` `||a===` `){n+=1;continue}if(a===`
4
4
  `||a===`\r`){n=0;continue}if(n<t&&(t=n,t===0))return 0;r=!1;continue}(a===`
package/dist/command.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as WithAsChild } from "./as-child-XMVTepJu.js";
2
- import { t as Dialog } from "./dialog-BAZ_LYI4.js";
2
+ import { t as Dialog } from "./dialog-BuD_JQf_.js";
3
3
  import * as react from "react";
4
4
  import { ComponentProps, ComponentPropsWithoutRef } from "react";
5
5
  import * as react_jsx_runtime0 from "react/jsx-runtime";
@@ -89,7 +89,7 @@ declare const Command: {
89
89
  ref?: React.Ref<HTMLDivElement>;
90
90
  } & {
91
91
  asChild?: boolean;
92
- }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & {
92
+ }, "key" | "asChild" | keyof react.HTMLAttributes<HTMLDivElement>> & {
93
93
  label?: string;
94
94
  shouldFilter?: boolean;
95
95
  filter?: (value: string, search: string, keywords?: string[]) => number;
@@ -142,7 +142,7 @@ declare const Command: {
142
142
  ref?: React.Ref<HTMLInputElement>;
143
143
  } & {
144
144
  asChild?: boolean;
145
- }, "key" | "asChild" | keyof react.InputHTMLAttributes<HTMLInputElement>>, "value" | "onChange" | "type"> & {
145
+ }, "key" | "asChild" | keyof react.InputHTMLAttributes<HTMLInputElement>>, "type" | "value" | "onChange"> & {
146
146
  value?: string;
147
147
  onValueChange?: (search: string) => void;
148
148
  } & react.RefAttributes<HTMLInputElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
@@ -163,7 +163,7 @@ declare const Command: {
163
163
  ref?: React.Ref<HTMLDivElement>;
164
164
  } & {
165
165
  asChild?: boolean;
166
- }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & {
166
+ }, "key" | "asChild" | keyof react.HTMLAttributes<HTMLDivElement>> & {
167
167
  label?: string;
168
168
  } & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
169
169
  /**
@@ -182,7 +182,7 @@ declare const Command: {
182
182
  ref?: React.Ref<HTMLDivElement>;
183
183
  } & {
184
184
  asChild?: boolean;
185
- }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
185
+ }, "key" | "asChild" | keyof react.HTMLAttributes<HTMLDivElement>> & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
186
186
  /**
187
187
  * The group component for the Command component.
188
188
  *
@@ -203,7 +203,7 @@ declare const Command: {
203
203
  ref?: React.Ref<HTMLDivElement>;
204
204
  } & {
205
205
  asChild?: boolean;
206
- }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild">, "value" | "heading"> & {
206
+ }, "key" | "asChild" | keyof react.HTMLAttributes<HTMLDivElement>>, "value" | "heading"> & {
207
207
  heading?: React.ReactNode;
208
208
  value?: string;
209
209
  forceMount?: boolean;
@@ -226,7 +226,7 @@ declare const Command: {
226
226
  ref?: React.Ref<HTMLDivElement>;
227
227
  } & {
228
228
  asChild?: boolean;
229
- }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild">, "disabled" | "value" | "onSelect"> & {
229
+ }, "key" | "asChild" | keyof react.HTMLAttributes<HTMLDivElement>>, "disabled" | "value" | "onSelect"> & {
230
230
  disabled?: boolean;
231
231
  onSelect?: (value: string) => void;
232
232
  value?: string;
@@ -1,4 +1,4 @@
1
- import { t as Button } from "./button-DQO0IuzC.js";
1
+ import { t as Button } from "./button-CKL-3sIr.js";
2
2
  import { s as SortingMode } from "./direction-deXpJFDZ.js";
3
3
  import { t as Table$1 } from "./table-Dpt192qt.js";
4
4
  import * as react from "react";
@@ -1,5 +1,5 @@
1
1
  import { t as Root } from "./primitive-tuHqhoRE.js";
2
- import { n as IconButtonProps } from "./icon-button-ikEU0Ctp.js";
2
+ import { n as IconButtonProps } from "./icon-button-2r6S3HVA.js";
3
3
  import * as react from "react";
4
4
  import { ComponentProps } from "react";
5
5
  import * as react_jsx_runtime0 from "react/jsx-runtime";
@@ -419,4 +419,4 @@ declare const Dialog: {
419
419
  };
420
420
  //#endregion
421
421
  export { Dialog as t };
422
- //# sourceMappingURL=dialog-BAZ_LYI4.d.ts.map
422
+ //# sourceMappingURL=dialog-BuD_JQf_.d.ts.map
package/dist/dialog.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { n as isDialogOverlayTarget } from "./primitive-tuHqhoRE.js";
2
- import { t as Dialog } from "./dialog-BAZ_LYI4.js";
2
+ import { t as Dialog } from "./dialog-BuD_JQf_.js";
3
3
  export { Dialog, isDialogOverlayTarget };
package/dist/hooks.js CHANGED
@@ -1,2 +1,2 @@
1
- import{t as e}from"./use-matches-media-query-CojcYxlA.js";import{r as t}from"./browser-only-QPyyfLaB.js";import{n}from"./compose-refs-DeIsFv68.js";import{t as r}from"./use-copy-to-clipboard-BEbQOKHc.js";import{n as i,t as a}from"./use-prefers-reduced-motion-BiG6QGkf.js";import{t as o}from"./in-view-bPnaWEL4.js";import{useCallback as s,useEffect as c,useLayoutEffect as l,useMemo as u,useReducer as d,useRef as f,useState as p,useSyncExternalStore as m}from"react";const h=[`2xl`,`xl`,`lg`,`md`,`sm`,`xs`,`2xs`],g=[`default`,...h];function _(){return m(j,M,()=>`default`)}function v(e){return m(P(e),I(e),()=>!1)}const y={"2xl":`(min-width: 96rem)`,xl:`(min-width: 80rem)`,lg:`(min-width: 64rem)`,md:`(min-width: 48rem)`,sm:`(min-width: 40rem)`,xs:`(min-width: 30rem)`,"2xs":`(min-width: 22.5rem)`},b={"2xl":`(max-width: 95.99rem)`,xl:`(max-width: 79.99rem)`,lg:`(max-width: 63.99rem)`,md:`(max-width: 47.99rem)`,sm:`(max-width: 39.99rem)`,xs:`(max-width: 29.99rem)`,"2xs":`(max-width: 22.49rem)`};let x=null,S=null;function C(){return x||={"2xl":window.matchMedia(y[`2xl`]),xl:window.matchMedia(y.xl),lg:window.matchMedia(y.lg),md:window.matchMedia(y.md),sm:window.matchMedia(y.sm),xs:window.matchMedia(y.xs),"2xs":window.matchMedia(y[`2xs`])},x}function w(e){return S||={"2xl":window.matchMedia(b[`2xl`]),xl:window.matchMedia(b.xl),lg:window.matchMedia(b.lg),md:window.matchMedia(b.md),sm:window.matchMedia(b.sm),xs:window.matchMedia(b.xs),"2xs":window.matchMedia(b[`2xs`])},S[e]}let T=`default`;const E=new Set;let D=!1;function O(){let e=C();for(let t of h)if(e[t].matches)return t;return`default`}let k=!1;function A(){k||(k=!0,requestAnimationFrame(()=>{k=!1;let e=O();if(e!==T){T=e;for(let e of E)e()}}))}function j(e){if(E.add(e),!D){D=!0;let e=C();T=O();for(let t of Object.values(e))t.addEventListener(`change`,A)}return e(),()=>{if(E.delete(e),E.size===0&&D){D=!1;let e=C();for(let t of Object.values(e))t.removeEventListener(`change`,A)}}}function M(){return T}const N=new Map;function P(e){let t=N.get(e);return t||(t=t=>{let n=w(e),r=!1,i=()=>{r||(r=!0,requestAnimationFrame(()=>{r=!1,t()}))};return n.addEventListener(`change`,i),()=>{n.removeEventListener(`change`,i)}},N.set(e,t),t)}const F=new Map;function I(e){let t=F.get(e);return t||(t=()=>w(e).matches,F.set(e,t),t)}function L(e){let t=f(e);return c(()=>{t.current=e}),u(()=>((...e)=>t.current?.(...e)),[])}function R(e,t){let n=L(e),r=f(0);return c(()=>()=>window.clearTimeout(r.current),[]),s((...e)=>{window.clearTimeout(r.current),r.current=window.setTimeout(()=>n(...e),t.waitMs)},[n,t.waitMs])}const z=typeof window<`u`?l:c,B=(e=`mantle`)=>u(()=>V(e),[e]);function V(e=`mantle`){return[e.trim()||`mantle`,H()].join(`-`)}function H(){return Math.random().toString(36).substring(2,9)}function U(){let e=i();return u(()=>e?`auto`:`smooth`,[e])}function W(e,{root:t,margin:n,amount:r,once:i=!1,initial:a=!1}={}){let[s,l]=p(a);return c(()=>{if(!e.current||i&&s)return;function a(){return l(!0),i?void 0:()=>l(!1)}let c={root:t&&t.current||void 0,margin:n,amount:r};return o(e.current,a,c)},[t,e,n,i,r]),s}function G(e,t){switch(t.type){case`push`:return{undoStack:[...e.undoStack,t.snapshot],redoStack:[]};case`undo`:{if(e.undoStack.length===0)return e;let n=e.undoStack.slice(0,-1);return e.undoStack[e.undoStack.length-1]===void 0?e:{undoStack:n,redoStack:[...e.redoStack,t.current]}}case`redo`:{if(e.redoStack.length===0)return e;let n=e.redoStack.slice(0,-1);return e.redoStack[e.redoStack.length-1]===void 0?e:{undoStack:[...e.undoStack,t.current],redoStack:n}}}}function K(){let[e,t]=d(G,{undoStack:[],redoStack:[]}),n=s(e=>{t({type:`push`,snapshot:e})},[]),r=s(n=>{let r=e.undoStack[e.undoStack.length-1];if(r!==void 0)return t({type:`undo`,current:n}),r},[e.undoStack]),i=s(n=>{let r=e.redoStack[e.redoStack.length-1];if(r!==void 0)return t({type:`redo`,current:n}),r},[e.redoStack]);return u(()=>({canUndo:e.undoStack.length>0,canRedo:e.redoStack.length>0,push:n,undo:r,redo:i}),[e.undoStack.length,e.redoStack.length,n,r,i])}export{g as breakpoints,a as getPrefersReducedMotion,_ as useBreakpoint,L as useCallbackRef,n as useComposedRefs,r as useCopyToClipboard,R as useDebouncedCallback,W as useInView,v as useIsBelowBreakpoint,t as useIsHydrated,z as useIsomorphicLayoutEffect,e as useMatchesMediaQuery,i as usePrefersReducedMotion,B as useRandomStableId,U as useScrollBehavior,K as useUndoRedo};
1
+ import{t as e}from"./use-matches-media-query-CojcYxlA.js";import{r as t}from"./browser-only-QPyyfLaB.js";import{n}from"./compose-refs-DeIsFv68.js";import{t as r}from"./use-copy-to-clipboard-BCpEp-sO.js";import{n as i,t as a}from"./use-prefers-reduced-motion-BiG6QGkf.js";import{t as o}from"./in-view-bPnaWEL4.js";import{useCallback as s,useEffect as c,useLayoutEffect as l,useMemo as u,useReducer as d,useRef as f,useState as p,useSyncExternalStore as m}from"react";const h=[`2xl`,`xl`,`lg`,`md`,`sm`,`xs`,`2xs`],g=[`default`,...h];function _(){return m(j,M,()=>`default`)}function v(e){return m(P(e),I(e),()=>!1)}const y={"2xl":`(min-width: 96rem)`,xl:`(min-width: 80rem)`,lg:`(min-width: 64rem)`,md:`(min-width: 48rem)`,sm:`(min-width: 40rem)`,xs:`(min-width: 30rem)`,"2xs":`(min-width: 22.5rem)`},b={"2xl":`(max-width: 95.99rem)`,xl:`(max-width: 79.99rem)`,lg:`(max-width: 63.99rem)`,md:`(max-width: 47.99rem)`,sm:`(max-width: 39.99rem)`,xs:`(max-width: 29.99rem)`,"2xs":`(max-width: 22.49rem)`};let x=null,S=null;function C(){return x||={"2xl":window.matchMedia(y[`2xl`]),xl:window.matchMedia(y.xl),lg:window.matchMedia(y.lg),md:window.matchMedia(y.md),sm:window.matchMedia(y.sm),xs:window.matchMedia(y.xs),"2xs":window.matchMedia(y[`2xs`])},x}function w(e){return S||={"2xl":window.matchMedia(b[`2xl`]),xl:window.matchMedia(b.xl),lg:window.matchMedia(b.lg),md:window.matchMedia(b.md),sm:window.matchMedia(b.sm),xs:window.matchMedia(b.xs),"2xs":window.matchMedia(b[`2xs`])},S[e]}let T=`default`;const E=new Set;let D=!1;function O(){let e=C();for(let t of h)if(e[t].matches)return t;return`default`}let k=!1;function A(){k||(k=!0,requestAnimationFrame(()=>{k=!1;let e=O();if(e!==T){T=e;for(let e of E)e()}}))}function j(e){if(E.add(e),!D){D=!0;let e=C();T=O();for(let t of Object.values(e))t.addEventListener(`change`,A)}return e(),()=>{if(E.delete(e),E.size===0&&D){D=!1;let e=C();for(let t of Object.values(e))t.removeEventListener(`change`,A)}}}function M(){return T}const N=new Map;function P(e){let t=N.get(e);return t||(t=t=>{let n=w(e),r=!1,i=()=>{r||(r=!0,requestAnimationFrame(()=>{r=!1,t()}))};return n.addEventListener(`change`,i),()=>{n.removeEventListener(`change`,i)}},N.set(e,t),t)}const F=new Map;function I(e){let t=F.get(e);return t||(t=()=>w(e).matches,F.set(e,t),t)}function L(e){let t=f(e);return c(()=>{t.current=e}),u(()=>((...e)=>t.current?.(...e)),[])}function R(e,t){let n=L(e),r=f(0);return c(()=>()=>window.clearTimeout(r.current),[]),s((...e)=>{window.clearTimeout(r.current),r.current=window.setTimeout(()=>n(...e),t.waitMs)},[n,t.waitMs])}const z=typeof window<`u`?l:c,B=(e=`mantle`)=>u(()=>V(e),[e]);function V(e=`mantle`){return[e.trim()||`mantle`,H()].join(`-`)}function H(){return Math.random().toString(36).substring(2,9)}function U(){let e=i();return u(()=>e?`auto`:`smooth`,[e])}function W(e,{root:t,margin:n,amount:r,once:i=!1,initial:a=!1}={}){let[s,l]=p(a);return c(()=>{if(!e.current||i&&s)return;function a(){return l(!0),i?void 0:()=>l(!1)}let c={root:t&&t.current||void 0,margin:n,amount:r};return o(e.current,a,c)},[t,e,n,i,r]),s}function G(e,t){switch(t.type){case`push`:return{undoStack:[...e.undoStack,t.snapshot],redoStack:[]};case`undo`:{if(e.undoStack.length===0)return e;let n=e.undoStack.slice(0,-1);return e.undoStack[e.undoStack.length-1]===void 0?e:{undoStack:n,redoStack:[...e.redoStack,t.current]}}case`redo`:{if(e.redoStack.length===0)return e;let n=e.redoStack.slice(0,-1);return e.redoStack[e.redoStack.length-1]===void 0?e:{undoStack:[...e.undoStack,t.current],redoStack:n}}}}function K(){let[e,t]=d(G,{undoStack:[],redoStack:[]}),n=s(e=>{t({type:`push`,snapshot:e})},[]),r=s(n=>{let r=e.undoStack[e.undoStack.length-1];if(r!==void 0)return t({type:`undo`,current:n}),r},[e.undoStack]),i=s(n=>{let r=e.redoStack[e.redoStack.length-1];if(r!==void 0)return t({type:`redo`,current:n}),r},[e.redoStack]);return u(()=>({canUndo:e.undoStack.length>0,canRedo:e.redoStack.length>0,push:n,undo:r,redo:i}),[e.undoStack.length,e.redoStack.length,n,r,i])}export{g as breakpoints,a as getPrefersReducedMotion,_ as useBreakpoint,L as useCallbackRef,n as useComposedRefs,r as useCopyToClipboard,R as useDebouncedCallback,W as useInView,v as useIsBelowBreakpoint,t as useIsHydrated,z as useIsomorphicLayoutEffect,e as useMatchesMediaQuery,i as usePrefersReducedMotion,B as useRandomStableId,U as useScrollBehavior,K as useUndoRedo};
2
2
  //# sourceMappingURL=hooks.js.map
@@ -8,7 +8,7 @@ import * as class_variance_authority_types0 from "class-variance-authority/types
8
8
  declare const iconButtonVariants: (props?: ({
9
9
  appearance?: "ghost" | "outlined" | null | undefined;
10
10
  isLoading?: boolean | null | undefined;
11
- size?: "md" | "sm" | "xs" | null | undefined;
11
+ size?: "xs" | "sm" | "md" | null | undefined;
12
12
  } & class_variance_authority_types0.ClassProp) | undefined) => string;
13
13
  type IconButtonVariants = VariantProps<typeof iconButtonVariants>;
14
14
  /**
@@ -95,4 +95,4 @@ type IconButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & WithAsChild & I
95
95
  declare const IconButton: react.ForwardRefExoticComponent<IconButtonProps & react.RefAttributes<HTMLButtonElement>>;
96
96
  //#endregion
97
97
  export { IconButtonProps as n, IconButton as t };
98
- //# sourceMappingURL=icon-button-ikEU0Ctp.d.ts.map
98
+ //# sourceMappingURL=icon-button-2r6S3HVA.d.ts.map
@@ -5,7 +5,7 @@ import * as class_variance_authority_types0 from "class-variance-authority/types
5
5
 
6
6
  //#region src/components/button/button-group.d.ts
7
7
  declare const buttonGroupVariants: (props?: ({
8
- appearance?: "ghost" | "outlined" | "panel" | null | undefined;
8
+ appearance?: "panel" | "ghost" | "outlined" | null | undefined;
9
9
  } & class_variance_authority_types0.ClassProp) | undefined) => string;
10
10
  type ButtonGroupVariants = VariantProps<typeof buttonGroupVariants>;
11
11
  type ButtonGroupProps = ComponentProps<"div"> & ButtonGroupVariants;
@@ -26,4 +26,4 @@ type ButtonGroupProps = ComponentProps<"div"> & ButtonGroupVariants;
26
26
  declare const ButtonGroup: react.ForwardRefExoticComponent<Omit<ButtonGroupProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
27
27
  //#endregion
28
28
  export { ButtonGroupProps as n, ButtonGroup as t };
29
- //# sourceMappingURL=index-ViSCOUrU.d.ts.map
29
+ //# sourceMappingURL=index-CMbK9igL.d.ts.map
@@ -23,7 +23,7 @@ type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "
23
23
  * />
24
24
  * ```
25
25
  */
26
- declare const Input: react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & WithAutoComplete & WithInputType & WithValidation & {
26
+ declare const Input: react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "autoComplete"> & WithAutoComplete & WithInputType & WithValidation & {
27
27
  children?: react.ReactNode | undefined;
28
28
  } & react.RefAttributes<HTMLInputElement>>;
29
29
  type InputCaptureProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & BaseProps;
@@ -41,7 +41,7 @@ type InputCaptureProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoComple
41
41
  * </Input>
42
42
  * ```
43
43
  */
44
- declare const InputCapture: react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & WithAutoComplete & WithInputType & WithValidation & react.RefAttributes<HTMLInputElement>>;
44
+ declare const InputCapture: react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "autoComplete"> & WithAutoComplete & WithInputType & WithValidation & react.RefAttributes<HTMLInputElement>>;
45
45
  //#endregion
46
46
  //#region src/components/input/password-input.d.ts
47
47
  type PasswordInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & WithValidation & WithAutoComplete & {
@@ -70,7 +70,7 @@ type PasswordInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "autoCompl
70
70
  * />
71
71
  * ```
72
72
  */
73
- declare const PasswordInput: react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "autoComplete" | "type"> & WithValidation & WithAutoComplete & {
73
+ declare const PasswordInput: react.ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "autoComplete"> & WithValidation & WithAutoComplete & {
74
74
  /**
75
75
  * Callback for when the visibility of the password value changes.
76
76
  */
@@ -100,4 +100,4 @@ declare const PasswordInput: react.ForwardRefExoticComponent<Omit<InputHTMLAttri
100
100
  declare function isInput(value: unknown): value is HTMLInputElement;
101
101
  //#endregion
102
102
  export { InputCapture as a, Input as i, PasswordInput as n, InputCaptureProps as o, PasswordInputProps as r, InputProps as s, isInput as t };
103
- //# sourceMappingURL=index-aG53Gdqx.d.ts.map
103
+ //# sourceMappingURL=index-DWqhfw9n.d.ts.map
package/dist/input.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { a as WithInputType, i as WithAutoComplete, n as InputType, o as WithValidation, r as Validation, t as AutoComplete } from "./types-DgXUgkpc.js";
2
- import { a as InputCapture, i as Input, n as PasswordInput, o as InputCaptureProps, r as PasswordInputProps, s as InputProps, t as isInput } from "./index-aG53Gdqx.js";
2
+ import { a as InputCapture, i as Input, n as PasswordInput, o as InputCaptureProps, r as PasswordInputProps, s as InputProps, t as isInput } from "./index-DWqhfw9n.js";
3
3
  export { AutoComplete, Input, InputCapture, InputCaptureProps, InputProps, InputType, PasswordInput, PasswordInputProps, Validation, WithAutoComplete, WithInputType, WithValidation, isInput };
@@ -1,5 +1,5 @@
1
1
  import { t as WithAsChild } from "./as-child-XMVTepJu.js";
2
- import { t as ButtonGroup } from "./index-ViSCOUrU.js";
2
+ import { t as ButtonGroup } from "./index-CMbK9igL.js";
3
3
  import { t as Select } from "./select-39Jfc1Cb.js";
4
4
  import * as react from "react";
5
5
  import { ComponentProps } from "react";
package/dist/sheet.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as Root } from "./primitive-tuHqhoRE.js";
2
- import { n as IconButtonProps } from "./icon-button-ikEU0Ctp.js";
2
+ import { n as IconButtonProps } from "./icon-button-2r6S3HVA.js";
3
3
  import * as react from "react";
4
4
  import { HTMLAttributes } from "react";
5
5
  import * as react_jsx_runtime0 from "react/jsx-runtime";
@@ -1,5 +1,5 @@
1
- import { t as IconButton } from "./icon-button-ikEU0Ctp.js";
2
- import { t as Button } from "./button-DQO0IuzC.js";
1
+ import { t as IconButton } from "./icon-button-2r6S3HVA.js";
2
+ import { t as Button } from "./button-CKL-3sIr.js";
3
3
  import { t as DropdownMenu } from "./dropdown-menu-D_ZoY1AH.js";
4
4
  import * as react from "react";
5
5
  import { ComponentProps, ReactNode } from "react";
package/dist/theme.d.ts CHANGED
@@ -97,6 +97,24 @@ type MantleStyleSheetsProps = MantleThemeCssUrls & {
97
97
  */
98
98
  nonce?: string;
99
99
  };
100
+ /**
101
+ * Returns the raw JavaScript string for the inline `<script>` that runs synchronously
102
+ * after the `<link>` tags are parsed to fix their `media` attributes based on the applied
103
+ * theme already written to `html[data-applied-theme]` by `PreventWrongThemeFlashScript`.
104
+ * This eliminates FOUC for users who have manually selected a theme that differs from
105
+ * their OS preference.
106
+ *
107
+ * Use this when you need to inline the script directly into SSR HTML outside of a React
108
+ * context — for example, in a legacy Go service that renders the initial HTML response.
109
+ *
110
+ * @example
111
+ * ```go
112
+ * // In a Go template, inline script content that was pre-generated by mantle
113
+ * // (e.g., via fixMediaScriptContent(undefined) in a JS/Node build step)
114
+ * fmt.Fprintf(w, `<script nonce="%s">%s</script>`, nonce, scriptContent)
115
+ * ```
116
+ */
117
+ declare function fixMediaScriptContent(forceTheme?: ResolvedTheme): string;
100
118
  /**
101
119
  * Renders `<link rel="stylesheet">` tags for the dark, light-high-contrast, and
102
120
  * dark-high-contrast theme CSS files. Each stylesheet is gated behind a `media` attribute
@@ -423,5 +441,5 @@ declare const PreloadFont: {
423
441
  displayName: string;
424
442
  };
425
443
  //#endregion
426
- export { $resolvedTheme, $theme, type CoreFontName, MantleStyleSheets, type MantleStyleSheetsProps, type MantleThemeCssUrls, PreloadFont, PreventWrongThemeFlashScript, type ResolvedTheme, type Theme, ThemeProvider, assetsCdnOrigin, extractThemeCookie, fontHref, getStoredTheme, isResolvedTheme, isTheme, mantleStyleSheetUrls, preloadFontLink, preventWrongThemeFlashScriptContent, readThemeFromHtmlElement, resolvedThemes, themes, useAppliedTheme, useInitialHtmlThemeProps, useTheme };
444
+ export { $resolvedTheme, $theme, type CoreFontName, MantleStyleSheets, type MantleStyleSheetsProps, type MantleThemeCssUrls, PreloadFont, PreventWrongThemeFlashScript, type ResolvedTheme, type Theme, ThemeProvider, assetsCdnOrigin, extractThemeCookie, fixMediaScriptContent, fontHref, getStoredTheme, isResolvedTheme, isTheme, mantleStyleSheetUrls, preloadFontLink, preventWrongThemeFlashScriptContent, readThemeFromHtmlElement, resolvedThemes, themes, useAppliedTheme, useInitialHtmlThemeProps, useTheme };
427
445
  //# sourceMappingURL=theme.d.ts.map
package/dist/theme.js CHANGED
@@ -1,2 +1,2 @@
1
- import{a as e,c as t,d as n,f as r,h as i,i as a,l as o,m as s,n as c,o as l,p as u,r as d,s as f,t as p,u as m}from"./theme-provider-8xCwja4v.js";import{useEffect as h}from"react";import{Fragment as g,jsx as _,jsxs as v}from"react/jsx-runtime";const y=`mantle-dark-styles`,b=`mantle-light-high-contrast-styles`,x=`mantle-dark-high-contrast-styles`,S=`(prefers-color-scheme: dark)`,C=`(prefers-contrast: more) and (prefers-color-scheme: light)`,w=`(prefers-contrast: more) and (prefers-color-scheme: dark)`;function T(e,t){let n=t??e;return{dark:n===`dark`?`all`:S,lightHighContrast:n===`light-high-contrast`?`all`:C,darkHighContrast:n===`dark-high-contrast`?`all`:w}}function E(e){return e}function D(e){let{darkLinkId:t,lightHcLinkId:n,darkHcLinkId:r,mediaDark:i,mediaLightHc:a,mediaDarkHc:o,forceTheme:s}=e,c=document.documentElement.dataset.appliedTheme,l=s??c,u=document.getElementById(t),d=document.getElementById(n),f=document.getElementById(r);u&&(u.media=l===`dark`?`all`:i),d&&(d.media=l===`light-high-contrast`?`all`:a),f&&(f.media=l===`dark-high-contrast`?`all`:o)}function O(e){let t={darkLinkId:y,lightHcLinkId:b,darkHcLinkId:x,mediaDark:S,mediaLightHc:C,mediaDarkHc:w,forceTheme:e};return`(${D.toString()})(${JSON.stringify(t)})`}function k({darkCssUrl:e,lightHighContrastCssUrl:t,darkHighContrastCssUrl:n,forceTheme:i,nonce:o,ssrCookie:s}){h(()=>{function e(){let e=document.documentElement.dataset.appliedTheme;return r(e)?e:void 0}function t(){let{dark:t,lightHighContrast:n,darkHighContrast:r}=T(e(),i),a=document.getElementById(y),o=document.getElementById(b),s=document.getElementById(x);a&&(a.media=t),o&&(o.media=n),s&&(s.media=r)}t();let n=new MutationObserver(t);return n.observe(document.documentElement,{attributes:!0,attributeFilter:[`data-applied-theme`]}),()=>{n.disconnect()}},[i]);let c=s==null?void 0:a({cookie:s}),l=c===`system`?void 0:c,{dark:u,lightHighContrast:d,darkHighContrast:f}=T(l,i);return v(g,{children:[(!i||i===`dark`)&&_(`link`,{rel:`stylesheet`,id:y,href:e,media:u,suppressHydrationWarning:!0}),(!i||i===`light-high-contrast`)&&_(`link`,{rel:`stylesheet`,id:b,href:t,media:d,suppressHydrationWarning:!0}),(!i||i===`dark-high-contrast`)&&_(`link`,{rel:`stylesheet`,id:x,href:n,media:f,suppressHydrationWarning:!0}),!i&&l==null&&_(`script`,{dangerouslySetInnerHTML:{__html:O(i)},nonce:o,suppressHydrationWarning:!0})]})}k.displayName=`MantleStyleSheets`;const A=`https://assets.ngrok.com`,j=`${A}/fonts`,M={roobert:`/roobert/roobert-proportional-vf.woff2`,"jetbrains-mono":`/jetbrains/jetbrainsmono-wght.woff2`,"jetbrains-mono-italic":`/jetbrains/jetbrainsmono-italic-wght.woff2`,"family-regular":`/family/family-regular.woff2`,"family-italic":`/family/family-italic.woff2`};function N(e){return`${j}${e.startsWith(`/`)?e:`/${e}`}`}function P(e){return`<${N(M[e])}>; rel=preload; as=font; type="font/woff2"; crossorigin`}const F=({name:e})=>_(`link`,{rel:`preload`,href:N(M[e]),as:`font`,type:`font/woff2`,crossOrigin:`anonymous`});F.displayName=`PreloadFont`;export{m as $resolvedTheme,n as $theme,k as MantleStyleSheets,F as PreloadFont,p as PreventWrongThemeFlashScript,c as ThemeProvider,A as assetsCdnOrigin,d as extractThemeCookie,N as fontHref,a as getStoredTheme,r as isResolvedTheme,u as isTheme,E as mantleStyleSheetUrls,P as preloadFontLink,e as preventWrongThemeFlashScriptContent,l as readThemeFromHtmlElement,s as resolvedThemes,i as themes,f as useAppliedTheme,t as useInitialHtmlThemeProps,o as useTheme};
1
+ import{a as e,c as t,d as n,f as r,h as i,i as a,l as o,m as s,n as c,o as l,p as u,r as d,s as f,t as p,u as m}from"./theme-provider-8xCwja4v.js";import{useEffect as h}from"react";import{Fragment as g,jsx as _,jsxs as v}from"react/jsx-runtime";const y=`mantle-dark-styles`,b=`mantle-light-high-contrast-styles`,x=`mantle-dark-high-contrast-styles`,S=`(prefers-color-scheme: dark)`,C=`(prefers-contrast: more) and (prefers-color-scheme: light)`,w=`(prefers-contrast: more) and (prefers-color-scheme: dark)`;function T(e,t){let n=t??e;return{dark:n===`dark`?`all`:S,lightHighContrast:n===`light-high-contrast`?`all`:C,darkHighContrast:n===`dark-high-contrast`?`all`:w}}function E(e){return e}function D(e){let{darkLinkId:t,lightHcLinkId:n,darkHcLinkId:r,mediaDark:i,mediaLightHc:a,mediaDarkHc:o,forceTheme:s}=e,c=document.documentElement.dataset.appliedTheme,l=s??c,u=document.getElementById(t),d=document.getElementById(n),f=document.getElementById(r);u&&(u.media=l===`dark`?`all`:i),d&&(d.media=l===`light-high-contrast`?`all`:a),f&&(f.media=l===`dark-high-contrast`?`all`:o)}function O(e){let t={darkLinkId:y,lightHcLinkId:b,darkHcLinkId:x,mediaDark:S,mediaLightHc:C,mediaDarkHc:w,forceTheme:e};return`(${D.toString()})(${JSON.stringify(t)})`}function k({darkCssUrl:e,lightHighContrastCssUrl:t,darkHighContrastCssUrl:n,forceTheme:i,nonce:o,ssrCookie:s}){h(()=>{function e(){let e=document.documentElement.dataset.appliedTheme;return r(e)?e:void 0}function t(){let{dark:t,lightHighContrast:n,darkHighContrast:r}=T(e(),i),a=document.getElementById(y),o=document.getElementById(b),s=document.getElementById(x);a&&(a.media=t),o&&(o.media=n),s&&(s.media=r)}t();let n=new MutationObserver(t);return n.observe(document.documentElement,{attributes:!0,attributeFilter:[`data-applied-theme`]}),()=>{n.disconnect()}},[i]);let c=s==null?void 0:a({cookie:s}),l=c===`system`?void 0:c,{dark:u,lightHighContrast:d,darkHighContrast:f}=T(l,i);return v(g,{children:[(!i||i===`dark`)&&_(`link`,{rel:`stylesheet`,id:y,href:e,media:u,suppressHydrationWarning:!0}),(!i||i===`light-high-contrast`)&&_(`link`,{rel:`stylesheet`,id:b,href:t,media:d,suppressHydrationWarning:!0}),(!i||i===`dark-high-contrast`)&&_(`link`,{rel:`stylesheet`,id:x,href:n,media:f,suppressHydrationWarning:!0}),!i&&l==null&&_(`script`,{dangerouslySetInnerHTML:{__html:O(i)},nonce:o,suppressHydrationWarning:!0})]})}k.displayName=`MantleStyleSheets`;const A=`https://assets.ngrok.com`,j=`${A}/fonts`,M={roobert:`/roobert/roobert-proportional-vf.woff2`,"jetbrains-mono":`/jetbrains/jetbrainsmono-wght.woff2`,"jetbrains-mono-italic":`/jetbrains/jetbrainsmono-italic-wght.woff2`,"family-regular":`/family/family-regular.woff2`,"family-italic":`/family/family-italic.woff2`};function N(e){return`${j}${e.startsWith(`/`)?e:`/${e}`}`}function P(e){return`<${N(M[e])}>; rel=preload; as=font; type="font/woff2"; crossorigin`}const F=({name:e})=>_(`link`,{rel:`preload`,href:N(M[e]),as:`font`,type:`font/woff2`,crossOrigin:`anonymous`});F.displayName=`PreloadFont`;export{m as $resolvedTheme,n as $theme,k as MantleStyleSheets,F as PreloadFont,p as PreventWrongThemeFlashScript,c as ThemeProvider,A as assetsCdnOrigin,d as extractThemeCookie,O as fixMediaScriptContent,N as fontHref,a as getStoredTheme,r as isResolvedTheme,u as isTheme,E as mantleStyleSheetUrls,P as preloadFontLink,e as preventWrongThemeFlashScriptContent,l as readThemeFromHtmlElement,s as resolvedThemes,i as themes,f as useAppliedTheme,t as useInitialHtmlThemeProps,o as useTheme};
2
2
  //# sourceMappingURL=theme.js.map
package/dist/theme.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"theme.js","names":[],"sources":["../src/components/theme/mantle-style-sheets.tsx","../src/components/theme/fonts.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { getStoredTheme } from \"./theme-provider.js\";\nimport type { ResolvedTheme } from \"./themes.js\";\nimport { isResolvedTheme } from \"./themes.js\";\n\n/**\n * Stable IDs for the three lazy-loaded theme `<link>` elements.\n * Used to locate them in the DOM for media attribute updates.\n */\nconst DARK_LINK_ID = \"mantle-dark-styles\";\nconst LIGHT_HIGH_CONTRAST_LINK_ID = \"mantle-light-high-contrast-styles\";\nconst DARK_HIGH_CONTRAST_LINK_ID = \"mantle-dark-high-contrast-styles\";\n\n/**\n * Default `media` attribute values for each lazy-loaded stylesheet.\n * Each one matches only the OS preference for that theme, making them\n * non-render-blocking for users whose OS does not match.\n */\nconst MEDIA_DARK = \"(prefers-color-scheme: dark)\";\nconst MEDIA_LIGHT_HC = \"(prefers-contrast: more) and (prefers-color-scheme: light)\";\nconst MEDIA_DARK_HC = \"(prefers-contrast: more) and (prefers-color-scheme: dark)\";\n\ntype MediaValues = {\n\tdark: string;\n\tlightHighContrast: string;\n\tdarkHighContrast: string;\n};\n\n/**\n * Compute the `media` attribute value for each stylesheet given the active theme.\n * When a theme is active (either from the resolved applied theme or a forced override),\n * its stylesheet's `media` is set to `\"all\"` so the CSS is applied regardless of OS preference.\n */\nfunction computeMediaValues(\n\tappliedTheme: ResolvedTheme | undefined,\n\tforceTheme: ResolvedTheme | undefined,\n): MediaValues {\n\tconst theme = forceTheme ?? appliedTheme;\n\treturn {\n\t\tdark: theme === \"dark\" ? \"all\" : MEDIA_DARK,\n\t\tlightHighContrast: theme === \"light-high-contrast\" ? \"all\" : MEDIA_LIGHT_HC,\n\t\tdarkHighContrast: theme === \"dark-high-contrast\" ? \"all\" : MEDIA_DARK_HC,\n\t};\n}\n\n/**\n * Browser-accessible URLs for mantle's three lazy-loaded theme stylesheets.\n *\n * Use {@link mantleStyleSheetUrls} to create this object from Vite `?url` imports.\n */\nexport type MantleThemeCssUrls = {\n\t/**\n\t * Browser-accessible URL for `mantle-dark.css`.\n\t * @example\n\t * ```tsx\n\t * // in vite app\n\t * import darkCssUrl from \"@ngrok/mantle/mantle-dark.css?url\"\n\t * ```\n\t */\n\tdarkCssUrl: string;\n\t/**\n\t * Browser-accessible URL for `mantle-light-high-contrast.css`.\n\t * @example\n\t * ```tsx\n\t * // in vite app\n\t * import lightHighContrastCssUrl from \"@ngrok/mantle/mantle-light-high-contrast.css?url\"\n\t * ```\n\t */\n\tlightHighContrastCssUrl: string;\n\t/**\n\t * Browser-accessible URL for `mantle-dark-high-contrast.css`.\n\t * @example\n\t * ```tsx\n\t * // in vite app\n\t * import darkHighContrastCssUrl from \"@ngrok/mantle/mantle-dark-high-contrast.css?url\"\n\t * ```\n\t */\n\tdarkHighContrastCssUrl: string;\n};\n\n/**\n * Collects the three Vite `?url` imports for mantle's theme stylesheets into a typed object\n * that can be spread directly into `<MantleStyleSheets>`.\n *\n * Call this once at the top of your app entry (e.g. `root.tsx`) and spread the result:\n *\n * ```ts\n * import darkCssUrl from \"@ngrok/mantle/mantle-dark.css?url\";\n * import darkHighContrastCssUrl from \"@ngrok/mantle/mantle-dark-high-contrast.css?url\";\n * import lightHighContrastCssUrl from \"@ngrok/mantle/mantle-light-high-contrast.css?url\";\n *\n * const themeUrls = mantleStyleSheetUrls({ darkCssUrl, lightHighContrastCssUrl, darkHighContrastCssUrl });\n *\n * // In JSX:\n * <MantleStyleSheets {...themeUrls} nonce={nonce} ssrCookie={ssrCookie} />\n * ```\n */\nfunction mantleStyleSheetUrls(urls: MantleThemeCssUrls): MantleThemeCssUrls {\n\treturn urls;\n}\n\nexport type MantleStyleSheetsProps = MantleThemeCssUrls & {\n\t/**\n\t * Force a specific resolved theme's stylesheet to load unconditionally (`media=\"all\"`),\n\t * regardless of the user's OS preference. Use this when your app is locked to a single\n\t * theme (e.g. a dark-only page) so the required CSS is render-blocking as intended.\n\t *\n\t * When omitted, each stylesheet uses its OS media query and becomes non-render-blocking\n\t * for users whose OS preference does not match.\n\t *\n\t * @example\n\t * // Dark-only app — always load dark CSS eagerly\n\t * <MantleStyleSheets forceTheme=\"dark\" {...themeUrls} />\n\t */\n\tforceTheme?: ResolvedTheme;\n\t/**\n\t * The theme cookie string from the incoming HTTP request (e.g. `request.headers.get(\"Cookie\")`\n\t * or the pre-extracted value from {@link extractThemeCookie}). When provided, the server can\n\t * resolve the stored theme and render the correct `media` attribute directly in the SSR HTML,\n\t * eliminating the need for the inline fix script in cases where the user has a non-system\n\t * theme stored in their cookie.\n\t *\n\t * @example\n\t * ```tsx\n\t * // root.tsx loader\n\t * export async function loader({ request }: Route.LoaderArgs) {\n\t * return { ssrCookie: extractThemeCookie(request.headers.get(\"Cookie\")) };\n\t * }\n\t *\n\t * // root.tsx component\n\t * <MantleStyleSheets {...themeUrls} ssrCookie={loaderData.ssrCookie} nonce={nonce} />\n\t * ```\n\t */\n\tssrCookie?: string;\n\t/**\n\t * An optional CSP nonce to allowlist the inline script that fixes `media` attributes\n\t * synchronously after the `<link>` tags are parsed. Mirror the same nonce you pass\n\t * to {@link PreventWrongThemeFlashScript}.\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce\n\t */\n\tnonce?: string;\n};\n\n/**\n * Inline script that runs synchronously after the `<link>` tags are parsed to fix their\n * `media` attributes based on the applied theme already written to `html[data-applied-theme]`\n * by `PreventWrongThemeFlashScript`. This eliminates FOUC for users who have manually\n * selected a theme that differs from their OS preference.\n */\nfunction fixMediaAttributes(args: {\n\tdarkLinkId: string;\n\tlightHcLinkId: string;\n\tdarkHcLinkId: string;\n\tmediaDark: string;\n\tmediaLightHc: string;\n\tmediaDarkHc: string;\n\tforceTheme: ResolvedTheme | undefined;\n}) {\n\tconst {\n\t\tdarkLinkId,\n\t\tlightHcLinkId,\n\t\tdarkHcLinkId,\n\t\tmediaDark,\n\t\tmediaLightHc,\n\t\tmediaDarkHc,\n\t\tforceTheme,\n\t} = args;\n\tconst appliedTheme = document.documentElement.dataset.appliedTheme;\n\tconst theme = forceTheme ?? appliedTheme;\n\n\tconst darkLink = document.getElementById(darkLinkId) as HTMLLinkElement | null;\n\tconst lightHcLink = document.getElementById(lightHcLinkId) as HTMLLinkElement | null;\n\tconst darkHcLink = document.getElementById(darkHcLinkId) as HTMLLinkElement | null;\n\n\tif (darkLink) {\n\t\tdarkLink.media = theme === \"dark\" ? \"all\" : mediaDark;\n\t}\n\tif (lightHcLink) {\n\t\tlightHcLink.media = theme === \"light-high-contrast\" ? \"all\" : mediaLightHc;\n\t}\n\tif (darkHcLink) {\n\t\tdarkHcLink.media = theme === \"dark-high-contrast\" ? \"all\" : mediaDarkHc;\n\t}\n}\n\nfunction fixMediaScriptContent(forceTheme: ResolvedTheme | undefined): string {\n\tconst args = {\n\t\tdarkLinkId: DARK_LINK_ID,\n\t\tlightHcLinkId: LIGHT_HIGH_CONTRAST_LINK_ID,\n\t\tdarkHcLinkId: DARK_HIGH_CONTRAST_LINK_ID,\n\t\tmediaDark: MEDIA_DARK,\n\t\tmediaLightHc: MEDIA_LIGHT_HC,\n\t\tmediaDarkHc: MEDIA_DARK_HC,\n\t\tforceTheme,\n\t} satisfies Parameters<typeof fixMediaAttributes>[0];\n\treturn `(${fixMediaAttributes.toString()})(${JSON.stringify(args)})`;\n}\n\n/**\n * Renders `<link rel=\"stylesheet\">` tags for the dark, light-high-contrast, and\n * dark-high-contrast theme CSS files. Each stylesheet is gated behind a `media` attribute\n * matching its OS preference so it is non-render-blocking for users who do not need it.\n *\n * Use {@link mantleStyleSheetUrls} to collect the required CSS URL props from Vite `?url`\n * imports and spread them in:\n *\n * ```ts\n * import darkCssUrl from \"@ngrok/mantle/mantle-dark.css?url\";\n * import darkHighContrastCssUrl from \"@ngrok/mantle/mantle-dark-high-contrast.css?url\";\n * import lightHighContrastCssUrl from \"@ngrok/mantle/mantle-light-high-contrast.css?url\";\n *\n * const themeUrls = mantleStyleSheetUrls({ darkCssUrl, lightHighContrastCssUrl, darkHighContrastCssUrl });\n * ```\n *\n * Place this component in `<head>`, after `<PreventWrongThemeFlashScript>`.\n *\n * On the client, a `MutationObserver` watches `html[data-applied-theme]` (kept in sync by\n * `ThemeProvider`) and updates the `media` attributes to `\"all\"` when the user manually\n * selects a theme that differs from their OS preference, ensuring the correct CSS is applied.\n *\n * When `forceTheme` is set, only the link tag for that theme is rendered — the others are\n * omitted entirely to avoid unnecessary network requests.\n *\n * @example\n * ```tsx\n * // root.tsx\n * import darkCssUrl from \"@ngrok/mantle/mantle-dark.css?url\";\n * import darkHighContrastCssUrl from \"@ngrok/mantle/mantle-dark-high-contrast.css?url\";\n * import lightHighContrastCssUrl from \"@ngrok/mantle/mantle-light-high-contrast.css?url\";\n * import { mantleStyleSheetUrls, MantleStyleSheets, PreventWrongThemeFlashScript } from \"@ngrok/mantle/theme\";\n *\n * const themeUrls = mantleStyleSheetUrls({ darkCssUrl, lightHighContrastCssUrl, darkHighContrastCssUrl });\n *\n * <head>\n * <PreventWrongThemeFlashScript nonce={nonce} />\n * <MantleStyleSheets {...themeUrls} nonce={nonce} ssrCookie={loaderData?.ssrCookie} />\n * </head>\n * ```\n */\nfunction MantleStyleSheets({\n\tdarkCssUrl,\n\tlightHighContrastCssUrl,\n\tdarkHighContrastCssUrl,\n\tforceTheme,\n\tnonce,\n\tssrCookie,\n}: MantleStyleSheetsProps) {\n\tuseEffect(() => {\n\t\tfunction getAppliedTheme(): ResolvedTheme | undefined {\n\t\t\tconst value = document.documentElement.dataset.appliedTheme;\n\t\t\treturn isResolvedTheme(value) ? value : undefined;\n\t\t}\n\n\t\tfunction updateMediaAttributes() {\n\t\t\tconst { dark, lightHighContrast, darkHighContrast } = computeMediaValues(\n\t\t\t\tgetAppliedTheme(),\n\t\t\t\tforceTheme,\n\t\t\t);\n\n\t\t\tconst darkLink = document.getElementById(DARK_LINK_ID) as HTMLLinkElement | null;\n\t\t\tconst lightHighContrastLink = document.getElementById(\n\t\t\t\tLIGHT_HIGH_CONTRAST_LINK_ID,\n\t\t\t) as HTMLLinkElement | null;\n\t\t\tconst darkHighContrastLink = document.getElementById(\n\t\t\t\tDARK_HIGH_CONTRAST_LINK_ID,\n\t\t\t) as HTMLLinkElement | null;\n\n\t\t\tif (darkLink) {\n\t\t\t\tdarkLink.media = dark;\n\t\t\t}\n\t\t\tif (lightHighContrastLink) {\n\t\t\t\tlightHighContrastLink.media = lightHighContrast;\n\t\t\t}\n\t\t\tif (darkHighContrastLink) {\n\t\t\t\tdarkHighContrastLink.media = darkHighContrast;\n\t\t\t}\n\t\t}\n\n\t\t// Sync immediately on mount in case the applied theme diverges from the SSR-rendered media values\n\t\tupdateMediaAttributes();\n\n\t\t// Watch for theme changes driven by ThemeProvider\n\t\tconst observer = new MutationObserver(updateMediaAttributes);\n\t\tobserver.observe(document.documentElement, {\n\t\t\tattributes: true,\n\t\t\tattributeFilter: [\"data-applied-theme\"],\n\t\t});\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [forceTheme]);\n\n\t// On SSR (and as the initial React render), emit the link tags with media values\n\t// derived from the cookie-stored theme (if available) and forceTheme.\n\t// The useEffect above will correct them on the client before the user can interact.\n\tconst ssrStoredTheme = ssrCookie != null ? getStoredTheme({ cookie: ssrCookie }) : undefined;\n\tconst ssrAppliedTheme = ssrStoredTheme !== \"system\" ? ssrStoredTheme : undefined;\n\tconst { dark, lightHighContrast, darkHighContrast } = computeMediaValues(\n\t\tssrAppliedTheme,\n\t\tforceTheme,\n\t);\n\n\t// The inline fix script corrects media attributes for users whose stored theme differs from\n\t// their OS preference. It is only needed when the SSR HTML may have been rendered with\n\t// incorrect media values — i.e. when neither ssrCookie (with a non-system theme) nor\n\t// forceTheme provide a deterministic answer at render time.\n\tconst needsFixScript = !forceTheme && ssrAppliedTheme == null;\n\n\t// When forceTheme is set, only render the link tag for that specific theme's stylesheet.\n\t// Light is the base theme with no dedicated lazy stylesheet, so forceTheme=\"light\" renders\n\t// no link tags at all. When forceTheme is unset, all three are rendered.\n\tconst renderDark = !forceTheme || forceTheme === \"dark\";\n\tconst renderLightHighContrast = !forceTheme || forceTheme === \"light-high-contrast\";\n\tconst renderDarkHighContrast = !forceTheme || forceTheme === \"dark-high-contrast\";\n\n\treturn (\n\t\t<>\n\t\t\t{renderDark && (\n\t\t\t\t<link\n\t\t\t\t\trel=\"stylesheet\"\n\t\t\t\t\tid={DARK_LINK_ID}\n\t\t\t\t\thref={darkCssUrl}\n\t\t\t\t\tmedia={dark}\n\t\t\t\t\tsuppressHydrationWarning\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{renderLightHighContrast && (\n\t\t\t\t<link\n\t\t\t\t\trel=\"stylesheet\"\n\t\t\t\t\tid={LIGHT_HIGH_CONTRAST_LINK_ID}\n\t\t\t\t\thref={lightHighContrastCssUrl}\n\t\t\t\t\tmedia={lightHighContrast}\n\t\t\t\t\tsuppressHydrationWarning\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{renderDarkHighContrast && (\n\t\t\t\t<link\n\t\t\t\t\trel=\"stylesheet\"\n\t\t\t\t\tid={DARK_HIGH_CONTRAST_LINK_ID}\n\t\t\t\t\thref={darkHighContrastCssUrl}\n\t\t\t\t\tmedia={darkHighContrast}\n\t\t\t\t\tsuppressHydrationWarning\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{needsFixScript && (\n\t\t\t\t<script\n\t\t\t\t\tdangerouslySetInnerHTML={{ __html: fixMediaScriptContent(forceTheme) }}\n\t\t\t\t\tnonce={nonce}\n\t\t\t\t\tsuppressHydrationWarning\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n}\nMantleStyleSheets.displayName = \"MantleStyleSheets\";\n\nexport {\n\t//,\n\tmantleStyleSheetUrls,\n\tMantleStyleSheets,\n};\n","/**\n * @fileoverview Helpers for preloading ngrok brand fonts from the CDN.\n * All font URLs resolve to `${assetsCdnOrigin}/fonts`.\n */\n\n/**\n * The origin for the assets CDN where custom ngrok fonts and assets are hosted.\n *\n * Keep this stable across the app so we can preconnect/DNS-prefetch consistently.\n * @public\n */\nconst assetsCdnOrigin = \"https://assets.ngrok.com\";\n\n/**\n * Base path for font assets on the CDN.\n * @internal\n */\nconst cdnBase = `${assetsCdnOrigin}/fonts`;\n\nconst coreFontNames = [\n\t\"roobert\",\n\t\"jetbrains-mono\",\n\t\"jetbrains-mono-italic\",\n\t\"family-regular\",\n\t\"family-italic\",\n] as const;\n/**\n * Named keys identifying each individual core font.\n * @public\n */\ntype CoreFontName = (typeof coreFontNames)[number];\n\n/**\n * Maps each {@link CoreFontName} to its CDN font path (relative to the fonts base).\n * @internal\n */\nconst coreFontPathByName = {\n\troobert: \"/roobert/roobert-proportional-vf.woff2\",\n\t\"jetbrains-mono\": \"/jetbrains/jetbrainsmono-wght.woff2\",\n\t\"jetbrains-mono-italic\": \"/jetbrains/jetbrainsmono-italic-wght.woff2\",\n\t\"family-regular\": \"/family/family-regular.woff2\",\n\t\"family-italic\": \"/family/family-italic.woff2\",\n} as const satisfies Record<CoreFontName, `/${string}`>;\n\ntype FontPath = `/${string}` | (string & {});\n\n/**\n * Builds an absolute CDN URL for a given font.\n *\n * @returns {`https://assets.ngrok.com/fonts${T}`} An absolute, literal-typed CDN URL.\n *\n * @example\n * const href = fontHref(\"/roobert/roobert-proportional-vf.woff2\");\n * // -> \"https://assets.ngrok.com/fonts/roobert/roobert-proportional-vf.woff2\"\n */\nfunction fontHref<T extends FontPath = FontPath>(font: T) {\n\tconst path = font.startsWith(\"/\") ? font : `/${font}`;\n\treturn `${cdnBase}${path}` as const;\n}\n\n/**\n * Props for {@link PreloadFont}.\n * @public\n */\ntype PreloadFontProps = {\n\t/**\n\t * The name of the individual core font to preload.\n\t *\n\t * - `\"roobert\"` — Roobert proportional variable font\n\t * - `\"jetbrains-mono\"` — JetBrains Mono variable weight\n\t * - `\"jetbrains-mono-italic\"` — JetBrains Mono italic variable weight\n\t * - `\"family-regular\"` — Family regular\n\t * - `\"family-italic\"` — Family italic\n\t */\n\tname: CoreFontName;\n};\n\n/**\n * Returns an HTTP `Link` header value that preloads a single core font by name.\n *\n * Identical in intent to {@link PreloadFont}, but for server-side use where\n * you want to send the preload hint as an HTTP header instead of (or in\n * addition to) an HTML `<link>` element. Sending this as a `Link` header lets\n * the browser start the font fetch before it has parsed any HTML.\n *\n * @remarks\n * For best performance, also send a `preconnect` hint to {@link assetsCdnOrigin}\n * in the same `Link` header.\n *\n * @example\n * ```ts\n * // In an HTTP handler / server entry:\n * headers.append(\"Link\", preloadFontLink(\"roobert\"));\n * headers.append(\"Link\", preloadFontLink(\"jetbrains-mono\"));\n *\n * // Or as a single combined header:\n * headers.set(\"Link\", [\n * `<${assetsCdnOrigin}>; rel=preconnect; crossorigin`,\n * preloadFontLink(\"roobert\"),\n * ].join(\", \"));\n * ```\n */\nfunction preloadFontLink(name: CoreFontName): string {\n\tconst href = fontHref(coreFontPathByName[name]);\n\treturn `<${href}>; rel=preload; as=font; type=\"font/woff2\"; crossorigin`;\n}\n\n/**\n * Preloads a single core font by name.\n *\n * Use this when you only need one or two specific fonts rather than all core\n * fonts. Include it as early as possible in the document `<head>`.\n *\n * @remarks\n * For best performance, pair this with preconnect/dns-prefetch hints to the CDN.\n *\n * @example\n * ```tsx\n * <head>\n * <link rel=\"preconnect\" href={assetsCdnOrigin} crossOrigin=\"anonymous\" />\n * <link rel=\"dns-prefetch\" href={assetsCdnOrigin} />\n * <PreloadFont name=\"roobert\" />\n * <PreloadFont name=\"jetbrains-mono\" />\n * </head>\n * ```\n */\nconst PreloadFont = ({ name }: PreloadFontProps) => (\n\t<link\n\t\trel=\"preload\"\n\t\thref={fontHref(coreFontPathByName[name])}\n\t\tas=\"font\"\n\t\ttype=\"font/woff2\"\n\t\tcrossOrigin=\"anonymous\"\n\t/>\n);\nPreloadFont.displayName = \"PreloadFont\";\n\nexport type { CoreFontName };\n\nexport {\n\t//,\n\tassetsCdnOrigin,\n\tfontHref,\n\tpreloadFontLink,\n\tPreloadFont,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"theme.js","names":[],"sources":["../src/components/theme/mantle-style-sheets.tsx","../src/components/theme/fonts.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { getStoredTheme } from \"./theme-provider.js\";\nimport type { ResolvedTheme } from \"./themes.js\";\nimport { isResolvedTheme } from \"./themes.js\";\n\n/**\n * Stable IDs for the three lazy-loaded theme `<link>` elements.\n * Used to locate them in the DOM for media attribute updates.\n */\nconst DARK_LINK_ID = \"mantle-dark-styles\";\nconst LIGHT_HIGH_CONTRAST_LINK_ID = \"mantle-light-high-contrast-styles\";\nconst DARK_HIGH_CONTRAST_LINK_ID = \"mantle-dark-high-contrast-styles\";\n\n/**\n * Default `media` attribute values for each lazy-loaded stylesheet.\n * Each one matches only the OS preference for that theme, making them\n * non-render-blocking for users whose OS does not match.\n */\nconst MEDIA_DARK = \"(prefers-color-scheme: dark)\";\nconst MEDIA_LIGHT_HC = \"(prefers-contrast: more) and (prefers-color-scheme: light)\";\nconst MEDIA_DARK_HC = \"(prefers-contrast: more) and (prefers-color-scheme: dark)\";\n\ntype MediaValues = {\n\tdark: string;\n\tlightHighContrast: string;\n\tdarkHighContrast: string;\n};\n\n/**\n * Compute the `media` attribute value for each stylesheet given the active theme.\n * When a theme is active (either from the resolved applied theme or a forced override),\n * its stylesheet's `media` is set to `\"all\"` so the CSS is applied regardless of OS preference.\n */\nfunction computeMediaValues(\n\tappliedTheme: ResolvedTheme | undefined,\n\tforceTheme: ResolvedTheme | undefined,\n): MediaValues {\n\tconst theme = forceTheme ?? appliedTheme;\n\treturn {\n\t\tdark: theme === \"dark\" ? \"all\" : MEDIA_DARK,\n\t\tlightHighContrast: theme === \"light-high-contrast\" ? \"all\" : MEDIA_LIGHT_HC,\n\t\tdarkHighContrast: theme === \"dark-high-contrast\" ? \"all\" : MEDIA_DARK_HC,\n\t};\n}\n\n/**\n * Browser-accessible URLs for mantle's three lazy-loaded theme stylesheets.\n *\n * Use {@link mantleStyleSheetUrls} to create this object from Vite `?url` imports.\n */\nexport type MantleThemeCssUrls = {\n\t/**\n\t * Browser-accessible URL for `mantle-dark.css`.\n\t * @example\n\t * ```tsx\n\t * // in vite app\n\t * import darkCssUrl from \"@ngrok/mantle/mantle-dark.css?url\"\n\t * ```\n\t */\n\tdarkCssUrl: string;\n\t/**\n\t * Browser-accessible URL for `mantle-light-high-contrast.css`.\n\t * @example\n\t * ```tsx\n\t * // in vite app\n\t * import lightHighContrastCssUrl from \"@ngrok/mantle/mantle-light-high-contrast.css?url\"\n\t * ```\n\t */\n\tlightHighContrastCssUrl: string;\n\t/**\n\t * Browser-accessible URL for `mantle-dark-high-contrast.css`.\n\t * @example\n\t * ```tsx\n\t * // in vite app\n\t * import darkHighContrastCssUrl from \"@ngrok/mantle/mantle-dark-high-contrast.css?url\"\n\t * ```\n\t */\n\tdarkHighContrastCssUrl: string;\n};\n\n/**\n * Collects the three Vite `?url` imports for mantle's theme stylesheets into a typed object\n * that can be spread directly into `<MantleStyleSheets>`.\n *\n * Call this once at the top of your app entry (e.g. `root.tsx`) and spread the result:\n *\n * ```ts\n * import darkCssUrl from \"@ngrok/mantle/mantle-dark.css?url\";\n * import darkHighContrastCssUrl from \"@ngrok/mantle/mantle-dark-high-contrast.css?url\";\n * import lightHighContrastCssUrl from \"@ngrok/mantle/mantle-light-high-contrast.css?url\";\n *\n * const themeUrls = mantleStyleSheetUrls({ darkCssUrl, lightHighContrastCssUrl, darkHighContrastCssUrl });\n *\n * // In JSX:\n * <MantleStyleSheets {...themeUrls} nonce={nonce} ssrCookie={ssrCookie} />\n * ```\n */\nfunction mantleStyleSheetUrls(urls: MantleThemeCssUrls): MantleThemeCssUrls {\n\treturn urls;\n}\n\nexport type MantleStyleSheetsProps = MantleThemeCssUrls & {\n\t/**\n\t * Force a specific resolved theme's stylesheet to load unconditionally (`media=\"all\"`),\n\t * regardless of the user's OS preference. Use this when your app is locked to a single\n\t * theme (e.g. a dark-only page) so the required CSS is render-blocking as intended.\n\t *\n\t * When omitted, each stylesheet uses its OS media query and becomes non-render-blocking\n\t * for users whose OS preference does not match.\n\t *\n\t * @example\n\t * // Dark-only app — always load dark CSS eagerly\n\t * <MantleStyleSheets forceTheme=\"dark\" {...themeUrls} />\n\t */\n\tforceTheme?: ResolvedTheme;\n\t/**\n\t * The theme cookie string from the incoming HTTP request (e.g. `request.headers.get(\"Cookie\")`\n\t * or the pre-extracted value from {@link extractThemeCookie}). When provided, the server can\n\t * resolve the stored theme and render the correct `media` attribute directly in the SSR HTML,\n\t * eliminating the need for the inline fix script in cases where the user has a non-system\n\t * theme stored in their cookie.\n\t *\n\t * @example\n\t * ```tsx\n\t * // root.tsx loader\n\t * export async function loader({ request }: Route.LoaderArgs) {\n\t * return { ssrCookie: extractThemeCookie(request.headers.get(\"Cookie\")) };\n\t * }\n\t *\n\t * // root.tsx component\n\t * <MantleStyleSheets {...themeUrls} ssrCookie={loaderData.ssrCookie} nonce={nonce} />\n\t * ```\n\t */\n\tssrCookie?: string;\n\t/**\n\t * An optional CSP nonce to allowlist the inline script that fixes `media` attributes\n\t * synchronously after the `<link>` tags are parsed. Mirror the same nonce you pass\n\t * to {@link PreventWrongThemeFlashScript}.\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce\n\t */\n\tnonce?: string;\n};\n\n/**\n * Inline script that runs synchronously after the `<link>` tags are parsed to fix their\n * `media` attributes based on the applied theme already written to `html[data-applied-theme]`\n * by `PreventWrongThemeFlashScript`. This eliminates FOUC for users who have manually\n * selected a theme that differs from their OS preference.\n */\nfunction fixMediaAttributes(args: {\n\tdarkLinkId: string;\n\tlightHcLinkId: string;\n\tdarkHcLinkId: string;\n\tmediaDark: string;\n\tmediaLightHc: string;\n\tmediaDarkHc: string;\n\tforceTheme: ResolvedTheme | undefined;\n}) {\n\tconst {\n\t\tdarkLinkId,\n\t\tlightHcLinkId,\n\t\tdarkHcLinkId,\n\t\tmediaDark,\n\t\tmediaLightHc,\n\t\tmediaDarkHc,\n\t\tforceTheme,\n\t} = args;\n\tconst appliedTheme = document.documentElement.dataset.appliedTheme;\n\tconst theme = forceTheme ?? appliedTheme;\n\n\tconst darkLink = document.getElementById(darkLinkId) as HTMLLinkElement | null;\n\tconst lightHcLink = document.getElementById(lightHcLinkId) as HTMLLinkElement | null;\n\tconst darkHcLink = document.getElementById(darkHcLinkId) as HTMLLinkElement | null;\n\n\tif (darkLink) {\n\t\tdarkLink.media = theme === \"dark\" ? \"all\" : mediaDark;\n\t}\n\tif (lightHcLink) {\n\t\tlightHcLink.media = theme === \"light-high-contrast\" ? \"all\" : mediaLightHc;\n\t}\n\tif (darkHcLink) {\n\t\tdarkHcLink.media = theme === \"dark-high-contrast\" ? \"all\" : mediaDarkHc;\n\t}\n}\n\n/**\n * Returns the raw JavaScript string for the inline `<script>` that runs synchronously\n * after the `<link>` tags are parsed to fix their `media` attributes based on the applied\n * theme already written to `html[data-applied-theme]` by `PreventWrongThemeFlashScript`.\n * This eliminates FOUC for users who have manually selected a theme that differs from\n * their OS preference.\n *\n * Use this when you need to inline the script directly into SSR HTML outside of a React\n * context — for example, in a legacy Go service that renders the initial HTML response.\n *\n * @example\n * ```go\n * // In a Go template, inline script content that was pre-generated by mantle\n * // (e.g., via fixMediaScriptContent(undefined) in a JS/Node build step)\n * fmt.Fprintf(w, `<script nonce=\"%s\">%s</script>`, nonce, scriptContent)\n * ```\n */\nfunction fixMediaScriptContent(forceTheme?: ResolvedTheme): string {\n\tconst args = {\n\t\tdarkLinkId: DARK_LINK_ID,\n\t\tlightHcLinkId: LIGHT_HIGH_CONTRAST_LINK_ID,\n\t\tdarkHcLinkId: DARK_HIGH_CONTRAST_LINK_ID,\n\t\tmediaDark: MEDIA_DARK,\n\t\tmediaLightHc: MEDIA_LIGHT_HC,\n\t\tmediaDarkHc: MEDIA_DARK_HC,\n\t\tforceTheme,\n\t} satisfies Parameters<typeof fixMediaAttributes>[0];\n\treturn `(${fixMediaAttributes.toString()})(${JSON.stringify(args)})`;\n}\n\n/**\n * Renders `<link rel=\"stylesheet\">` tags for the dark, light-high-contrast, and\n * dark-high-contrast theme CSS files. Each stylesheet is gated behind a `media` attribute\n * matching its OS preference so it is non-render-blocking for users who do not need it.\n *\n * Use {@link mantleStyleSheetUrls} to collect the required CSS URL props from Vite `?url`\n * imports and spread them in:\n *\n * ```ts\n * import darkCssUrl from \"@ngrok/mantle/mantle-dark.css?url\";\n * import darkHighContrastCssUrl from \"@ngrok/mantle/mantle-dark-high-contrast.css?url\";\n * import lightHighContrastCssUrl from \"@ngrok/mantle/mantle-light-high-contrast.css?url\";\n *\n * const themeUrls = mantleStyleSheetUrls({ darkCssUrl, lightHighContrastCssUrl, darkHighContrastCssUrl });\n * ```\n *\n * Place this component in `<head>`, after `<PreventWrongThemeFlashScript>`.\n *\n * On the client, a `MutationObserver` watches `html[data-applied-theme]` (kept in sync by\n * `ThemeProvider`) and updates the `media` attributes to `\"all\"` when the user manually\n * selects a theme that differs from their OS preference, ensuring the correct CSS is applied.\n *\n * When `forceTheme` is set, only the link tag for that theme is rendered — the others are\n * omitted entirely to avoid unnecessary network requests.\n *\n * @example\n * ```tsx\n * // root.tsx\n * import darkCssUrl from \"@ngrok/mantle/mantle-dark.css?url\";\n * import darkHighContrastCssUrl from \"@ngrok/mantle/mantle-dark-high-contrast.css?url\";\n * import lightHighContrastCssUrl from \"@ngrok/mantle/mantle-light-high-contrast.css?url\";\n * import { mantleStyleSheetUrls, MantleStyleSheets, PreventWrongThemeFlashScript } from \"@ngrok/mantle/theme\";\n *\n * const themeUrls = mantleStyleSheetUrls({ darkCssUrl, lightHighContrastCssUrl, darkHighContrastCssUrl });\n *\n * <head>\n * <PreventWrongThemeFlashScript nonce={nonce} />\n * <MantleStyleSheets {...themeUrls} nonce={nonce} ssrCookie={loaderData?.ssrCookie} />\n * </head>\n * ```\n */\nfunction MantleStyleSheets({\n\tdarkCssUrl,\n\tlightHighContrastCssUrl,\n\tdarkHighContrastCssUrl,\n\tforceTheme,\n\tnonce,\n\tssrCookie,\n}: MantleStyleSheetsProps) {\n\tuseEffect(() => {\n\t\tfunction getAppliedTheme(): ResolvedTheme | undefined {\n\t\t\tconst value = document.documentElement.dataset.appliedTheme;\n\t\t\treturn isResolvedTheme(value) ? value : undefined;\n\t\t}\n\n\t\tfunction updateMediaAttributes() {\n\t\t\tconst { dark, lightHighContrast, darkHighContrast } = computeMediaValues(\n\t\t\t\tgetAppliedTheme(),\n\t\t\t\tforceTheme,\n\t\t\t);\n\n\t\t\tconst darkLink = document.getElementById(DARK_LINK_ID) as HTMLLinkElement | null;\n\t\t\tconst lightHighContrastLink = document.getElementById(\n\t\t\t\tLIGHT_HIGH_CONTRAST_LINK_ID,\n\t\t\t) as HTMLLinkElement | null;\n\t\t\tconst darkHighContrastLink = document.getElementById(\n\t\t\t\tDARK_HIGH_CONTRAST_LINK_ID,\n\t\t\t) as HTMLLinkElement | null;\n\n\t\t\tif (darkLink) {\n\t\t\t\tdarkLink.media = dark;\n\t\t\t}\n\t\t\tif (lightHighContrastLink) {\n\t\t\t\tlightHighContrastLink.media = lightHighContrast;\n\t\t\t}\n\t\t\tif (darkHighContrastLink) {\n\t\t\t\tdarkHighContrastLink.media = darkHighContrast;\n\t\t\t}\n\t\t}\n\n\t\t// Sync immediately on mount in case the applied theme diverges from the SSR-rendered media values\n\t\tupdateMediaAttributes();\n\n\t\t// Watch for theme changes driven by ThemeProvider\n\t\tconst observer = new MutationObserver(updateMediaAttributes);\n\t\tobserver.observe(document.documentElement, {\n\t\t\tattributes: true,\n\t\t\tattributeFilter: [\"data-applied-theme\"],\n\t\t});\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [forceTheme]);\n\n\t// On SSR (and as the initial React render), emit the link tags with media values\n\t// derived from the cookie-stored theme (if available) and forceTheme.\n\t// The useEffect above will correct them on the client before the user can interact.\n\tconst ssrStoredTheme = ssrCookie != null ? getStoredTheme({ cookie: ssrCookie }) : undefined;\n\tconst ssrAppliedTheme = ssrStoredTheme !== \"system\" ? ssrStoredTheme : undefined;\n\tconst { dark, lightHighContrast, darkHighContrast } = computeMediaValues(\n\t\tssrAppliedTheme,\n\t\tforceTheme,\n\t);\n\n\t// The inline fix script corrects media attributes for users whose stored theme differs from\n\t// their OS preference. It is only needed when the SSR HTML may have been rendered with\n\t// incorrect media values — i.e. when neither ssrCookie (with a non-system theme) nor\n\t// forceTheme provide a deterministic answer at render time.\n\tconst needsFixScript = !forceTheme && ssrAppliedTheme == null;\n\n\t// When forceTheme is set, only render the link tag for that specific theme's stylesheet.\n\t// Light is the base theme with no dedicated lazy stylesheet, so forceTheme=\"light\" renders\n\t// no link tags at all. When forceTheme is unset, all three are rendered.\n\tconst renderDark = !forceTheme || forceTheme === \"dark\";\n\tconst renderLightHighContrast = !forceTheme || forceTheme === \"light-high-contrast\";\n\tconst renderDarkHighContrast = !forceTheme || forceTheme === \"dark-high-contrast\";\n\n\treturn (\n\t\t<>\n\t\t\t{renderDark && (\n\t\t\t\t<link\n\t\t\t\t\trel=\"stylesheet\"\n\t\t\t\t\tid={DARK_LINK_ID}\n\t\t\t\t\thref={darkCssUrl}\n\t\t\t\t\tmedia={dark}\n\t\t\t\t\tsuppressHydrationWarning\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{renderLightHighContrast && (\n\t\t\t\t<link\n\t\t\t\t\trel=\"stylesheet\"\n\t\t\t\t\tid={LIGHT_HIGH_CONTRAST_LINK_ID}\n\t\t\t\t\thref={lightHighContrastCssUrl}\n\t\t\t\t\tmedia={lightHighContrast}\n\t\t\t\t\tsuppressHydrationWarning\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{renderDarkHighContrast && (\n\t\t\t\t<link\n\t\t\t\t\trel=\"stylesheet\"\n\t\t\t\t\tid={DARK_HIGH_CONTRAST_LINK_ID}\n\t\t\t\t\thref={darkHighContrastCssUrl}\n\t\t\t\t\tmedia={darkHighContrast}\n\t\t\t\t\tsuppressHydrationWarning\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{needsFixScript && (\n\t\t\t\t<script\n\t\t\t\t\tdangerouslySetInnerHTML={{ __html: fixMediaScriptContent(forceTheme) }}\n\t\t\t\t\tnonce={nonce}\n\t\t\t\t\tsuppressHydrationWarning\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n}\nMantleStyleSheets.displayName = \"MantleStyleSheets\";\n\nexport {\n\t//,\n\tfixMediaScriptContent,\n\tmantleStyleSheetUrls,\n\tMantleStyleSheets,\n};\n","/**\n * @fileoverview Helpers for preloading ngrok brand fonts from the CDN.\n * All font URLs resolve to `${assetsCdnOrigin}/fonts`.\n */\n\n/**\n * The origin for the assets CDN where custom ngrok fonts and assets are hosted.\n *\n * Keep this stable across the app so we can preconnect/DNS-prefetch consistently.\n * @public\n */\nconst assetsCdnOrigin = \"https://assets.ngrok.com\";\n\n/**\n * Base path for font assets on the CDN.\n * @internal\n */\nconst cdnBase = `${assetsCdnOrigin}/fonts`;\n\nconst coreFontNames = [\n\t\"roobert\",\n\t\"jetbrains-mono\",\n\t\"jetbrains-mono-italic\",\n\t\"family-regular\",\n\t\"family-italic\",\n] as const;\n/**\n * Named keys identifying each individual core font.\n * @public\n */\ntype CoreFontName = (typeof coreFontNames)[number];\n\n/**\n * Maps each {@link CoreFontName} to its CDN font path (relative to the fonts base).\n * @internal\n */\nconst coreFontPathByName = {\n\troobert: \"/roobert/roobert-proportional-vf.woff2\",\n\t\"jetbrains-mono\": \"/jetbrains/jetbrainsmono-wght.woff2\",\n\t\"jetbrains-mono-italic\": \"/jetbrains/jetbrainsmono-italic-wght.woff2\",\n\t\"family-regular\": \"/family/family-regular.woff2\",\n\t\"family-italic\": \"/family/family-italic.woff2\",\n} as const satisfies Record<CoreFontName, `/${string}`>;\n\ntype FontPath = `/${string}` | (string & {});\n\n/**\n * Builds an absolute CDN URL for a given font.\n *\n * @returns {`https://assets.ngrok.com/fonts${T}`} An absolute, literal-typed CDN URL.\n *\n * @example\n * const href = fontHref(\"/roobert/roobert-proportional-vf.woff2\");\n * // -> \"https://assets.ngrok.com/fonts/roobert/roobert-proportional-vf.woff2\"\n */\nfunction fontHref<T extends FontPath = FontPath>(font: T) {\n\tconst path = font.startsWith(\"/\") ? font : `/${font}`;\n\treturn `${cdnBase}${path}` as const;\n}\n\n/**\n * Props for {@link PreloadFont}.\n * @public\n */\ntype PreloadFontProps = {\n\t/**\n\t * The name of the individual core font to preload.\n\t *\n\t * - `\"roobert\"` — Roobert proportional variable font\n\t * - `\"jetbrains-mono\"` — JetBrains Mono variable weight\n\t * - `\"jetbrains-mono-italic\"` — JetBrains Mono italic variable weight\n\t * - `\"family-regular\"` — Family regular\n\t * - `\"family-italic\"` — Family italic\n\t */\n\tname: CoreFontName;\n};\n\n/**\n * Returns an HTTP `Link` header value that preloads a single core font by name.\n *\n * Identical in intent to {@link PreloadFont}, but for server-side use where\n * you want to send the preload hint as an HTTP header instead of (or in\n * addition to) an HTML `<link>` element. Sending this as a `Link` header lets\n * the browser start the font fetch before it has parsed any HTML.\n *\n * @remarks\n * For best performance, also send a `preconnect` hint to {@link assetsCdnOrigin}\n * in the same `Link` header.\n *\n * @example\n * ```ts\n * // In an HTTP handler / server entry:\n * headers.append(\"Link\", preloadFontLink(\"roobert\"));\n * headers.append(\"Link\", preloadFontLink(\"jetbrains-mono\"));\n *\n * // Or as a single combined header:\n * headers.set(\"Link\", [\n * `<${assetsCdnOrigin}>; rel=preconnect; crossorigin`,\n * preloadFontLink(\"roobert\"),\n * ].join(\", \"));\n * ```\n */\nfunction preloadFontLink(name: CoreFontName): string {\n\tconst href = fontHref(coreFontPathByName[name]);\n\treturn `<${href}>; rel=preload; as=font; type=\"font/woff2\"; crossorigin`;\n}\n\n/**\n * Preloads a single core font by name.\n *\n * Use this when you only need one or two specific fonts rather than all core\n * fonts. Include it as early as possible in the document `<head>`.\n *\n * @remarks\n * For best performance, pair this with preconnect/dns-prefetch hints to the CDN.\n *\n * @example\n * ```tsx\n * <head>\n * <link rel=\"preconnect\" href={assetsCdnOrigin} crossOrigin=\"anonymous\" />\n * <link rel=\"dns-prefetch\" href={assetsCdnOrigin} />\n * <PreloadFont name=\"roobert\" />\n * <PreloadFont name=\"jetbrains-mono\" />\n * </head>\n * ```\n */\nconst PreloadFont = ({ name }: PreloadFontProps) => (\n\t<link\n\t\trel=\"preload\"\n\t\thref={fontHref(coreFontPathByName[name])}\n\t\tas=\"font\"\n\t\ttype=\"font/woff2\"\n\t\tcrossOrigin=\"anonymous\"\n\t/>\n);\nPreloadFont.displayName = \"PreloadFont\";\n\nexport type { CoreFontName };\n\nexport {\n\t//,\n\tassetsCdnOrigin,\n\tfontHref,\n\tpreloadFontLink,\n\tPreloadFont,\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{useCallback as e,useState as t}from"react";function n(){let[n,i]=t(``);return[n,e(e=>{(async()=>{try{if(typeof window.navigator?.clipboard?.writeText==`function`)await navigator.clipboard.writeText(e);else throw Error(`writeText not supported`)}catch{try{r(e)}catch{return}}i(e)})()},[])]}function r(e){let t=document.createElement(`textarea`);t.value=e,document.body.appendChild(t);try{t.select(),document.execCommand(`copy`)}finally{document.body.removeChild(t)}}export{n as t};
2
+ //# sourceMappingURL=use-copy-to-clipboard-BCpEp-sO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-copy-to-clipboard-BCpEp-sO.js","names":[],"sources":["../src/hooks/use-copy-to-clipboard.tsx"],"sourcesContent":["import { useCallback, useState } from \"react\";\n\n/**\n * A hook that allows you to copy a string to the clipboard.\n *\n * Inspired by: https://usehooks.com/usecopytoclipboard\n */\nfunction useCopyToClipboard() {\n\tconst [state, setState] = useState<string>(\"\");\n\n\tconst copyToClipboard = useCallback((value: string) => {\n\t\t(async () => {\n\t\t\ttry {\n\t\t\t\tif (typeof window.navigator?.clipboard?.writeText === \"function\") {\n\t\t\t\t\tawait navigator.clipboard.writeText(value);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\"writeText not supported\");\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\ttry {\n\t\t\t\t\tcopyToClipboardPolyfill(value);\n\t\t\t\t} catch {\n\t\t\t\t\treturn; // both approaches failed; don't update state\n\t\t\t\t}\n\t\t\t}\n\t\t\tsetState(value);\n\t\t})();\n\t}, []);\n\n\treturn [state, copyToClipboard] as const;\n}\n\nexport { useCopyToClipboard };\n\n/**\n * A fallback copy to clipboard function for older browsers.\n */\nfunction copyToClipboardPolyfill(text: string) {\n\tconst tempTextArea = document.createElement(\"textarea\");\n\ttempTextArea.value = text;\n\tdocument.body.appendChild(tempTextArea);\n\ttry {\n\t\ttempTextArea.select();\n\t\tdocument.execCommand(\"copy\");\n\t} finally {\n\t\tdocument.body.removeChild(tempTextArea);\n\t}\n}\n"],"mappings":"kDAOA,SAAS,GAAqB,CAC7B,GAAM,CAAC,EAAO,GAAY,EAAiB,GAAG,CAqB9C,MAAO,CAAC,EAnBgB,EAAa,GAAkB,EACrD,SAAY,CACZ,GAAI,CACH,GAAI,OAAO,OAAO,WAAW,WAAW,WAAc,WACrD,MAAM,UAAU,UAAU,UAAU,EAAM,MAE1C,MAAU,MAAM,0BAA0B,MAEpC,CACP,GAAI,CACH,EAAwB,EAAM,MACvB,CACP,QAGF,EAAS,EAAM,IACZ,EACF,EAAE,CAAC,CAEyB,CAQhC,SAAS,EAAwB,EAAc,CAC9C,IAAM,EAAe,SAAS,cAAc,WAAW,CACvD,EAAa,MAAQ,EACrB,SAAS,KAAK,YAAY,EAAa,CACvC,GAAI,CACH,EAAa,QAAQ,CACrB,SAAS,YAAY,OAAO,QACnB,CACT,SAAS,KAAK,YAAY,EAAa"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ngrok/mantle",
3
- "version": "0.66.9",
3
+ "version": "0.66.11",
4
4
  "description": "mantle is ngrok's UI library and design system.",
5
5
  "homepage": "https://mantle.ngrok.com",
6
6
  "license": "MIT",
@@ -1,2 +0,0 @@
1
- import{useCallback as e,useState as t}from"react";function n(){let[n,i]=t(``);return[n,e(e=>{(async()=>{try{if(typeof window.navigator?.clipboard?.writeText==`function`)await navigator.clipboard.writeText(e),i(e);else throw Error(`writeText not supported`)}catch{r(e),i(e)}})()},[])]}function r(e){let t=document.createElement(`textarea`);t.value=e,document.body.appendChild(t),t.select(),document.execCommand(`copy`),document.body.removeChild(t)}export{n as t};
2
- //# sourceMappingURL=use-copy-to-clipboard-BEbQOKHc.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-copy-to-clipboard-BEbQOKHc.js","names":[],"sources":["../src/hooks/use-copy-to-clipboard.tsx"],"sourcesContent":["import { useCallback, useState } from \"react\";\n\n/**\n * A hook that allows you to copy a string to the clipboard.\n *\n * Inspired by: https://usehooks.com/usecopytoclipboard\n */\nfunction useCopyToClipboard() {\n\tconst [state, setState] = useState<string>(\"\");\n\n\tconst copyToClipboard = useCallback((value: string) => {\n\t\tconst handleCopy = async () => {\n\t\t\ttry {\n\t\t\t\tif (typeof window.navigator?.clipboard?.writeText === \"function\") {\n\t\t\t\t\tawait navigator.clipboard.writeText(value);\n\t\t\t\t\tsetState(value);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\"writeText not supported\");\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tcopyToClipboardPolyfill(value);\n\t\t\t\tsetState(value);\n\t\t\t}\n\t\t};\n\n\t\thandleCopy();\n\t}, []);\n\n\treturn [state, copyToClipboard] as const;\n}\n\nexport {\n\t//,\n\tuseCopyToClipboard,\n};\n\n/**\n * A fallback copy to clipboard function for older browsers.\n */\nfunction copyToClipboardPolyfill(text: string) {\n\tconst tempTextArea = document.createElement(\"textarea\");\n\ttempTextArea.value = text;\n\tdocument.body.appendChild(tempTextArea);\n\ttempTextArea.select();\n\tdocument.execCommand(\"copy\");\n\tdocument.body.removeChild(tempTextArea);\n}\n"],"mappings":"kDAOA,SAAS,GAAqB,CAC7B,GAAM,CAAC,EAAO,GAAY,EAAiB,GAAG,CAoB9C,MAAO,CAAC,EAlBgB,EAAa,GAAkB,EACnC,SAAY,CAC9B,GAAI,CACH,GAAI,OAAO,OAAO,WAAW,WAAW,WAAc,WACrD,MAAM,UAAU,UAAU,UAAU,EAAM,CAC1C,EAAS,EAAM,MAEf,MAAU,MAAM,0BAA0B,MAEpC,CACP,EAAwB,EAAM,CAC9B,EAAS,EAAM,KAIL,EACV,EAAE,CAAC,CAEyB,CAWhC,SAAS,EAAwB,EAAc,CAC9C,IAAM,EAAe,SAAS,cAAc,WAAW,CACvD,EAAa,MAAQ,EACrB,SAAS,KAAK,YAAY,EAAa,CACvC,EAAa,QAAQ,CACrB,SAAS,YAAY,OAAO,CAC5B,SAAS,KAAK,YAAY,EAAa"}