@askrjs/themes 0.0.7 → 0.0.8

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.
package/THEMING.md CHANGED
@@ -117,7 +117,11 @@ ShellNav, ShellMain, and EmptyState.
117
117
 
118
118
  Theme state helpers also live there: `ThemeProvider`, `ThemePicker`,
119
119
  `ThemeToggle`, and `useTheme`. `ThemeToggle` intentionally has no built-in
120
- icons; applications pass their own icon/content props.
120
+ icons; applications pass their own icon/content props. The rendered content is
121
+ wrapped in `data-slot="theme-toggle-content"` so icon and text compositions can
122
+ be styled consistently across themes. If you use icon children, the direct child
123
+ icon is sized from `var(--ak-theme-toggle-icon-size, var(--ak-icon-size, 1em))`,
124
+ so apps can override `--ak-theme-toggle-icon-size` to fit custom icon dimensions.
121
125
  The common wrapper components also emit familiar alias classes such as
122
126
  `alert`, `btn-group`, `btn-close`, `input-group`, `list-group`, and
123
127
  `pagination` so app-level CSS can stay close to the Bootstrap mental model
@@ -1 +1 @@
1
- {"version":3,"file":"classes.js","names":[],"sources":["../../../src/components/_internal/classes.ts"],"sourcesContent":["export function classes(...values: Array<unknown>): string | undefined {\n const value = values.filter((item) => typeof item === \"string\" && item.trim()).join(\" \");\n\n return value || undefined;\n}\n"],"mappings":";AAAA,SAAgB,QAAQ,GAAG,QAA4C;CAGrE,OAFc,OAAO,QAAQ,SAAS,OAAO,SAAS,YAAY,KAAK,KAAK,CAAC,EAAE,KAAK,GAEzE,KAAK,KAAA;AAClB"}
1
+ {"version":3,"file":"classes.js","names":[],"sources":["../../../src/components/_internal/classes.ts"],"sourcesContent":["export function classes(...values: Array<unknown>): string | undefined {\n const value = values.filter((item) => typeof item === \"string\" && item.trim()).join(\" \");\n\n return value || undefined;\n}\n"],"mappings":";AAAA,SAAgB,QAAQ,GAAG,QAA4C;CAGrE,OAFc,OAAO,QAAQ,SAAS,OAAO,SAAS,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,GAEzE,KAAK,KAAA;AAClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"layout.js","names":[],"sources":["../../../src/components/_internal/layout.ts"],"sourcesContent":["/**\n * Layout helpers shared by headless layout primitives.\n */\n\nexport type LayoutBreakpoint = \"initial\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type ResponsiveValue<T> = T | Partial<Record<LayoutBreakpoint, T>>;\n\nconst BREAKPOINTS: readonly LayoutBreakpoint[] = [\"initial\", \"sm\", \"md\", \"lg\", \"xl\"];\n\n/** Units and patterns that identify a concrete CSS length value. */\nconst CSS_UNIT_RE =\n /^-?[\\d.]+(%|px|em|rem|ex|ch|ic|lh|rlh|vw|vh|vmin|vmax|svw|svh|dvw|dvh|cqw|cqh|cqi|cqb|fr|cm|mm|in|pt|pc|Q)$/;\n\nconst SPACE_TOKEN_MAP: Record<string, string> = {\n \"1\": \"var(--ak-space-1)\",\n \"2\": \"var(--ak-space-2)\",\n \"3\": \"var(--ak-space-3)\",\n \"4\": \"var(--ak-space-4)\",\n \"5\": \"var(--ak-space-5)\",\n \"6\": \"var(--ak-space-6)\",\n \"7\": \"var(--ak-space-7)\",\n \"8\": \"var(--ak-space-8)\",\n \"9\": \"var(--ak-space-9)\",\n xs: \"var(--ak-space-xs)\",\n sm: \"var(--ak-space-sm)\",\n md: \"var(--ak-space-md)\",\n lg: \"var(--ak-space-lg)\",\n xl: \"var(--ak-space-xl)\",\n \"2xl\": \"var(--ak-space-2xl)\",\n \"3xl\": \"var(--ak-space-3xl)\",\n};\n\nconst CONTAINER_SIZE_MAP: Record<string, string> = {\n \"1\": \"var(--ak-container-1)\",\n \"2\": \"var(--ak-container-2)\",\n \"3\": \"var(--ak-container-3)\",\n \"4\": \"var(--ak-container-4)\",\n sm: \"var(--ak-container-1)\",\n md: \"var(--ak-container-2)\",\n lg: \"var(--ak-container-3)\",\n xl: \"var(--ak-container-4)\",\n fluid: \"100%\",\n};\n\nconst SECTION_SIZE_MAP: Record<string, string> = {\n \"1\": \"var(--ak-section-1)\",\n \"2\": \"var(--ak-section-2)\",\n \"3\": \"var(--ak-section-3)\",\n \"4\": \"var(--ak-section-4)\",\n};\n\n/**\n * Returns true when `value` is a concrete CSS length/size that can be serialized\n * into a CSS declaration without token translation.\n */\nexport function isCssLength(value: unknown): value is string {\n if (typeof value !== \"string\") return false;\n const v = value.trim();\n if (v === \"0\") return true;\n if (CSS_UNIT_RE.test(v)) return true;\n // CSS functions: calc(), min(), max(), clamp(), fit-content(), env(), var()\n if (/^[a-z][a-z-]*\\(/.test(v)) return true;\n return false;\n}\n\nexport function isResponsiveValue<T>(\n value: ResponsiveValue<T> | undefined,\n): value is Partial<Record<LayoutBreakpoint, T>> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n return BREAKPOINTS.some((breakpoint) => breakpoint in value);\n}\n\nexport function normalizeResponsiveValue<T>(\n value: ResponsiveValue<T> | undefined,\n): Partial<Record<LayoutBreakpoint, T>> | undefined {\n if (value === undefined) return undefined;\n if (isResponsiveValue(value)) return value;\n return { initial: value };\n}\n\nexport function serializeResponsiveValue<T>(\n value: ResponsiveValue<T> | undefined,\n): string | undefined {\n const normalized = normalizeResponsiveValue(value);\n if (!normalized) return undefined;\n\n return BREAKPOINTS.map((breakpoint) => {\n const breakpointValue = normalized[breakpoint];\n if (breakpointValue === undefined) return \"\";\n return `${breakpoint}:${String(breakpointValue)}`;\n })\n .filter(Boolean)\n .join(\"|\");\n}\n\nexport function serializeResponsiveValueIf<T>(\n value: ResponsiveValue<T> | undefined,\n predicate: (value: T) => boolean,\n): string | undefined {\n const normalized = normalizeResponsiveValue(value);\n if (!normalized) return undefined;\n\n for (const breakpoint of BREAKPOINTS) {\n const breakpointValue = normalized[breakpoint];\n if (breakpointValue === undefined) continue;\n if (!predicate(breakpointValue)) return undefined;\n }\n\n return serializeResponsiveValue(value);\n}\n\nexport function serializeValueIf<T>(\n value: T | undefined,\n predicate: (value: T) => boolean,\n): string | undefined {\n if (value === undefined || !predicate(value)) return undefined;\n return String(value);\n}\n\nexport function setResponsiveStyleVar<T>(\n styles: Record<string, string | number>,\n variable: string,\n value: ResponsiveValue<T> | undefined,\n resolve: (value: T) => string | number | undefined = (input) =>\n input as string | number | undefined,\n) {\n const normalized = normalizeResponsiveValue(value);\n if (!normalized) return;\n\n for (const breakpoint of BREAKPOINTS) {\n const breakpointValue = normalized[breakpoint];\n if (breakpointValue === undefined) continue;\n const resolved = resolve(breakpointValue);\n if (resolved === undefined || resolved === null || resolved === \"\") continue;\n styles[`--ak-${variable}-${breakpoint}`] = resolved;\n }\n}\n\nexport function resolveSpaceValue(value: string | number): string | number {\n if (typeof value === \"number\") return String(value);\n const trimmed = value.trim();\n return SPACE_TOKEN_MAP[trimmed] ?? trimmed;\n}\n\nexport function resolveContainerSizeValue(value: string): string {\n const trimmed = value.trim();\n return CONTAINER_SIZE_MAP[trimmed] ?? trimmed;\n}\n\nexport function resolveSectionSizeValue(value: string): string {\n const trimmed = value.trim();\n return SECTION_SIZE_MAP[trimmed] ?? trimmed;\n}\n\nexport function resolveJustifyValue(value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"between\") return \"space-between\";\n if (trimmed === \"start\") return \"flex-start\";\n if (trimmed === \"end\") return \"flex-end\";\n return trimmed;\n}\n\nexport function resolveAlignValue(value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"start\") return \"flex-start\";\n if (trimmed === \"end\") return \"flex-end\";\n return trimmed;\n}\n\nexport function resolveInlineAlignValue(value: \"left\" | \"center\" | \"right\"): {\n marginLeft?: string;\n marginRight?: string;\n} {\n if (value === \"left\") return { marginLeft: \"0\", marginRight: \"auto\" };\n if (value === \"right\") return { marginLeft: \"auto\", marginRight: \"0\" };\n return { marginLeft: \"auto\", marginRight: \"auto\" };\n}\n\n/**\n * Merges a record of computed layout declarations with a user-supplied style\n * value. The user's declarations take precedence for conflicting keys.\n */\nexport function mergeLayoutStyles(\n layout: Record<string, string | number>,\n user: unknown,\n): string | undefined {\n const merged: Record<string, unknown> = { ...layout };\n\n if (user !== null && user !== undefined && typeof user === \"object\") {\n Object.assign(merged, user as Record<string, unknown>);\n }\n\n const mergedString = objectToCssString(merged);\n\n if (typeof user === \"string\" && user.trim()) {\n return mergedString ? `${mergedString};${user.trim()}` : user.trim();\n }\n\n return mergedString || undefined;\n}\n\nfunction camelToKebab(s: string): string {\n return s.replace(/([A-Z])/g, (c) => `-${c.toLowerCase()}`);\n}\n\nfunction objectToCssString(styles: Record<string, unknown>): string {\n return Object.entries(styles)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => `${camelToKebab(key)}:${String(value)}`)\n .join(\";\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"layout.js","names":[],"sources":["../../../src/components/_internal/layout.ts"],"sourcesContent":["/**\n * Layout helpers shared by headless layout primitives.\n */\n\nexport type LayoutBreakpoint = \"initial\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type ResponsiveValue<T> = T | Partial<Record<LayoutBreakpoint, T>>;\n\nconst BREAKPOINTS: readonly LayoutBreakpoint[] = [\"initial\", \"sm\", \"md\", \"lg\", \"xl\"];\n\n/** Units and patterns that identify a concrete CSS length value. */\nconst CSS_UNIT_RE =\n /^-?[\\d.]+(%|px|em|rem|ex|ch|ic|lh|rlh|vw|vh|vmin|vmax|svw|svh|dvw|dvh|cqw|cqh|cqi|cqb|fr|cm|mm|in|pt|pc|Q)$/;\n\nconst SPACE_TOKEN_MAP: Record<string, string> = {\n \"1\": \"var(--ak-space-1)\",\n \"2\": \"var(--ak-space-2)\",\n \"3\": \"var(--ak-space-3)\",\n \"4\": \"var(--ak-space-4)\",\n \"5\": \"var(--ak-space-5)\",\n \"6\": \"var(--ak-space-6)\",\n \"7\": \"var(--ak-space-7)\",\n \"8\": \"var(--ak-space-8)\",\n \"9\": \"var(--ak-space-9)\",\n xs: \"var(--ak-space-xs)\",\n sm: \"var(--ak-space-sm)\",\n md: \"var(--ak-space-md)\",\n lg: \"var(--ak-space-lg)\",\n xl: \"var(--ak-space-xl)\",\n \"2xl\": \"var(--ak-space-2xl)\",\n \"3xl\": \"var(--ak-space-3xl)\",\n};\n\nconst CONTAINER_SIZE_MAP: Record<string, string> = {\n \"1\": \"var(--ak-container-1)\",\n \"2\": \"var(--ak-container-2)\",\n \"3\": \"var(--ak-container-3)\",\n \"4\": \"var(--ak-container-4)\",\n sm: \"var(--ak-container-1)\",\n md: \"var(--ak-container-2)\",\n lg: \"var(--ak-container-3)\",\n xl: \"var(--ak-container-4)\",\n fluid: \"100%\",\n};\n\nconst SECTION_SIZE_MAP: Record<string, string> = {\n \"1\": \"var(--ak-section-1)\",\n \"2\": \"var(--ak-section-2)\",\n \"3\": \"var(--ak-section-3)\",\n \"4\": \"var(--ak-section-4)\",\n};\n\n/**\n * Returns true when `value` is a concrete CSS length/size that can be serialized\n * into a CSS declaration without token translation.\n */\nexport function isCssLength(value: unknown): value is string {\n if (typeof value !== \"string\") return false;\n const v = value.trim();\n if (v === \"0\") return true;\n if (CSS_UNIT_RE.test(v)) return true;\n // CSS functions: calc(), min(), max(), clamp(), fit-content(), env(), var()\n if (/^[a-z][a-z-]*\\(/.test(v)) return true;\n return false;\n}\n\nexport function isResponsiveValue<T>(\n value: ResponsiveValue<T> | undefined,\n): value is Partial<Record<LayoutBreakpoint, T>> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n return BREAKPOINTS.some((breakpoint) => breakpoint in value);\n}\n\nexport function normalizeResponsiveValue<T>(\n value: ResponsiveValue<T> | undefined,\n): Partial<Record<LayoutBreakpoint, T>> | undefined {\n if (value === undefined) return undefined;\n if (isResponsiveValue(value)) return value;\n return { initial: value };\n}\n\nexport function serializeResponsiveValue<T>(\n value: ResponsiveValue<T> | undefined,\n): string | undefined {\n const normalized = normalizeResponsiveValue(value);\n if (!normalized) return undefined;\n\n return BREAKPOINTS.map((breakpoint) => {\n const breakpointValue = normalized[breakpoint];\n if (breakpointValue === undefined) return \"\";\n return `${breakpoint}:${String(breakpointValue)}`;\n })\n .filter(Boolean)\n .join(\"|\");\n}\n\nexport function serializeResponsiveValueIf<T>(\n value: ResponsiveValue<T> | undefined,\n predicate: (value: T) => boolean,\n): string | undefined {\n const normalized = normalizeResponsiveValue(value);\n if (!normalized) return undefined;\n\n for (const breakpoint of BREAKPOINTS) {\n const breakpointValue = normalized[breakpoint];\n if (breakpointValue === undefined) continue;\n if (!predicate(breakpointValue)) return undefined;\n }\n\n return serializeResponsiveValue(value);\n}\n\nexport function serializeValueIf<T>(\n value: T | undefined,\n predicate: (value: T) => boolean,\n): string | undefined {\n if (value === undefined || !predicate(value)) return undefined;\n return String(value);\n}\n\nexport function setResponsiveStyleVar<T>(\n styles: Record<string, string | number>,\n variable: string,\n value: ResponsiveValue<T> | undefined,\n resolve: (value: T) => string | number | undefined = (input) =>\n input as string | number | undefined,\n) {\n const normalized = normalizeResponsiveValue(value);\n if (!normalized) return;\n\n for (const breakpoint of BREAKPOINTS) {\n const breakpointValue = normalized[breakpoint];\n if (breakpointValue === undefined) continue;\n const resolved = resolve(breakpointValue);\n if (resolved === undefined || resolved === null || resolved === \"\") continue;\n styles[`--ak-${variable}-${breakpoint}`] = resolved;\n }\n}\n\nexport function resolveSpaceValue(value: string | number): string | number {\n if (typeof value === \"number\") return String(value);\n const trimmed = value.trim();\n return SPACE_TOKEN_MAP[trimmed] ?? trimmed;\n}\n\nexport function resolveContainerSizeValue(value: string): string {\n const trimmed = value.trim();\n return CONTAINER_SIZE_MAP[trimmed] ?? trimmed;\n}\n\nexport function resolveSectionSizeValue(value: string): string {\n const trimmed = value.trim();\n return SECTION_SIZE_MAP[trimmed] ?? trimmed;\n}\n\nexport function resolveJustifyValue(value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"between\") return \"space-between\";\n if (trimmed === \"start\") return \"flex-start\";\n if (trimmed === \"end\") return \"flex-end\";\n return trimmed;\n}\n\nexport function resolveAlignValue(value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"start\") return \"flex-start\";\n if (trimmed === \"end\") return \"flex-end\";\n return trimmed;\n}\n\nexport function resolveInlineAlignValue(value: \"left\" | \"center\" | \"right\"): {\n marginLeft?: string;\n marginRight?: string;\n} {\n if (value === \"left\") return { marginLeft: \"0\", marginRight: \"auto\" };\n if (value === \"right\") return { marginLeft: \"auto\", marginRight: \"0\" };\n return { marginLeft: \"auto\", marginRight: \"auto\" };\n}\n\n/**\n * Merges a record of computed layout declarations with a user-supplied style\n * value. The user's declarations take precedence for conflicting keys.\n */\nexport function mergeLayoutStyles(\n layout: Record<string, string | number>,\n user: unknown,\n): string | undefined {\n const merged: Record<string, unknown> = { ...layout };\n\n if (user !== null && user !== undefined && typeof user === \"object\") {\n Object.assign(merged, user as Record<string, unknown>);\n }\n\n const mergedString = objectToCssString(merged);\n\n if (typeof user === \"string\" && user.trim()) {\n return mergedString ? `${mergedString};${user.trim()}` : user.trim();\n }\n\n return mergedString || undefined;\n}\n\nfunction camelToKebab(s: string): string {\n return s.replace(/([A-Z])/g, (c) => `-${c.toLowerCase()}`);\n}\n\nfunction objectToCssString(styles: Record<string, unknown>): string {\n return Object.entries(styles)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => `${camelToKebab(key)}:${String(value)}`)\n .join(\";\");\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/_internal/style.ts"],"sourcesContent":["export function mergeCssVar(style: unknown, name: string, value: string): string {\n const decl = `${name}:${value}`;\n\n if (typeof style === \"string\") {\n const trimmed = style.trim();\n return trimmed ? `${trimmed};${decl}` : decl;\n }\n\n if (style && typeof style === \"object\") {\n const entries = Object.entries(style as Record<string, unknown>)\n .filter(([, v]) => v !== undefined && v !== null)\n .map(([k, v]) => `${k.replace(/([A-Z])/g, (c) => `-${c.toLowerCase()}`)}:${String(v)}`)\n .join(\";\");\n return entries ? `${entries};${decl}` : decl;\n }\n\n return decl;\n}\n\nconst STYLE_REGISTRY_ATTR = \"data-askr-style-registry\";\nconst STYLE_CLASS_PREFIX = \"ak-style-\";\n\nconst styleClassCache = new Map<string, string>();\nconst registeredDeclarations = new Set<string>();\n\nlet nextStyleClassId = 0;\n\nfunction ensureStyleElement(): HTMLStyleElement | null {\n if (typeof document === \"undefined\") return null;\n\n const existing = document.querySelector(`style[${STYLE_REGISTRY_ATTR}]`);\n if (existing instanceof HTMLStyleElement) {\n return existing;\n }\n\n const styleElement = document.createElement(\"style\");\n styleElement.setAttribute(STYLE_REGISTRY_ATTR, \"true\");\n (document.head ?? document.documentElement).append(styleElement);\n\n return styleElement;\n}\n\nfunction normalizeDeclarations(declarations: string): string {\n return declarations.trim().replace(/;+\\s*$/, \"\");\n}\n\nexport function styleDeclarationsToClass(declarations: string | undefined): string | undefined {\n if (typeof declarations !== \"string\") return undefined;\n\n const normalized = normalizeDeclarations(declarations);\n if (!normalized) return undefined;\n\n let className = styleClassCache.get(normalized);\n if (className === undefined) {\n className = `${STYLE_CLASS_PREFIX}${++nextStyleClassId}`;\n styleClassCache.set(normalized, className);\n }\n\n if (!registeredDeclarations.has(normalized)) {\n const styleElement = ensureStyleElement();\n if (styleElement) {\n const rule = `.${className}{${normalized}}`;\n styleElement.textContent = `${styleElement.textContent ?? \"\"}\\n${rule}`;\n registeredDeclarations.add(normalized);\n }\n }\n\n return className;\n}\n"],"mappings":";AAmBA,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAE3B,MAAM,kCAAkB,IAAI,IAAoB;AAChD,MAAM,yCAAyB,IAAI,IAAY;AAE/C,IAAI,mBAAmB;AAEvB,SAAS,qBAA8C;CACrD,IAAI,OAAO,aAAa,aAAa,OAAO;CAE5C,MAAM,WAAW,SAAS,cAAc,SAAS,oBAAoB,EAAE;CACvE,IAAI,oBAAoB,kBACtB,OAAO;CAGT,MAAM,eAAe,SAAS,cAAc,OAAO;CACnD,aAAa,aAAa,qBAAqB,MAAM;CACrD,CAAC,SAAS,QAAQ,SAAS,iBAAiB,OAAO,YAAY;CAE/D,OAAO;AACT;AAEA,SAAS,sBAAsB,cAA8B;CAC3D,OAAO,aAAa,KAAK,EAAE,QAAQ,UAAU,EAAE;AACjD;AAEA,SAAgB,yBAAyB,cAAsD;CAC7F,IAAI,OAAO,iBAAiB,UAAU,OAAO,KAAA;CAE7C,MAAM,aAAa,sBAAsB,YAAY;CACrD,IAAI,CAAC,YAAY,OAAO,KAAA;CAExB,IAAI,YAAY,gBAAgB,IAAI,UAAU;CAC9C,IAAI,cAAc,KAAA,GAAW;EAC3B,YAAY,GAAG,qBAAqB,EAAE;EACtC,gBAAgB,IAAI,YAAY,SAAS;CAC3C;CAEA,IAAI,CAAC,uBAAuB,IAAI,UAAU,GAAG;EAC3C,MAAM,eAAe,mBAAmB;EACxC,IAAI,cAAc;GAChB,MAAM,OAAO,IAAI,UAAU,GAAG,WAAW;GACzC,aAAa,cAAc,GAAG,aAAa,eAAe,GAAG,IAAI;GACjE,uBAAuB,IAAI,UAAU;EACvC;CACF;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/_internal/style.ts"],"sourcesContent":["export function mergeCssVar(style: unknown, name: string, value: string): string {\n const decl = `${name}:${value}`;\n\n if (typeof style === \"string\") {\n const trimmed = style.trim();\n return trimmed ? `${trimmed};${decl}` : decl;\n }\n\n if (style && typeof style === \"object\") {\n const entries = Object.entries(style as Record<string, unknown>)\n .filter(([, v]) => v !== undefined && v !== null)\n .map(([k, v]) => `${k.replace(/([A-Z])/g, (c) => `-${c.toLowerCase()}`)}:${String(v)}`)\n .join(\";\");\n return entries ? `${entries};${decl}` : decl;\n }\n\n return decl;\n}\n\nconst STYLE_REGISTRY_ATTR = \"data-askr-style-registry\";\nconst STYLE_CLASS_PREFIX = \"ak-style-\";\n\nconst styleClassCache = new Map<string, string>();\nconst registeredDeclarations = new Set<string>();\n\nlet nextStyleClassId = 0;\n\nfunction ensureStyleElement(): HTMLStyleElement | null {\n if (typeof document === \"undefined\") return null;\n\n const existing = document.querySelector(`style[${STYLE_REGISTRY_ATTR}]`);\n if (existing instanceof HTMLStyleElement) {\n return existing;\n }\n\n const styleElement = document.createElement(\"style\");\n styleElement.setAttribute(STYLE_REGISTRY_ATTR, \"true\");\n (document.head ?? document.documentElement).append(styleElement);\n\n return styleElement;\n}\n\nfunction normalizeDeclarations(declarations: string): string {\n return declarations.trim().replace(/;+\\s*$/, \"\");\n}\n\nexport function styleDeclarationsToClass(declarations: string | undefined): string | undefined {\n if (typeof declarations !== \"string\") return undefined;\n\n const normalized = normalizeDeclarations(declarations);\n if (!normalized) return undefined;\n\n let className = styleClassCache.get(normalized);\n if (className === undefined) {\n className = `${STYLE_CLASS_PREFIX}${++nextStyleClassId}`;\n styleClassCache.set(normalized, className);\n }\n\n if (!registeredDeclarations.has(normalized)) {\n const styleElement = ensureStyleElement();\n if (styleElement) {\n const rule = `.${className}{${normalized}}`;\n styleElement.textContent = `${styleElement.textContent ?? \"\"}\\n${rule}`;\n registeredDeclarations.add(normalized);\n }\n }\n\n return className;\n}\n"],"mappings":";AAmBA,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAE3B,MAAM,kCAAkB,IAAI,IAAoB;AAChD,MAAM,yCAAyB,IAAI,IAAY;AAE/C,IAAI,mBAAmB;AAEvB,SAAS,qBAA8C;CACrD,IAAI,OAAO,aAAa,aAAa,OAAO;CAE5C,MAAM,WAAW,SAAS,cAAc,SAAS,oBAAoB,EAAE;CACvE,IAAI,oBAAoB,kBACtB,OAAO;CAGT,MAAM,eAAe,SAAS,cAAc,OAAO;CACnD,aAAa,aAAa,qBAAqB,MAAM;CACrD,CAAC,SAAS,QAAQ,SAAS,gBAAA,CAAiB,OAAO,YAAY;CAE/D,OAAO;AACT;AAEA,SAAS,sBAAsB,cAA8B;CAC3D,OAAO,aAAa,KAAK,CAAC,CAAC,QAAQ,UAAU,EAAE;AACjD;AAEA,SAAgB,yBAAyB,cAAsD;CAC7F,IAAI,OAAO,iBAAiB,UAAU,OAAO,KAAA;CAE7C,MAAM,aAAa,sBAAsB,YAAY;CACrD,IAAI,CAAC,YAAY,OAAO,KAAA;CAExB,IAAI,YAAY,gBAAgB,IAAI,UAAU;CAC9C,IAAI,cAAc,KAAA,GAAW;EAC3B,YAAY,GAAG,qBAAqB,EAAE;EACtC,gBAAgB,IAAI,YAAY,SAAS;CAC3C;CAEA,IAAI,CAAC,uBAAuB,IAAI,UAAU,GAAG;EAC3C,MAAM,eAAe,mBAAmB;EACxC,IAAI,cAAc;GAChB,MAAM,OAAO,IAAI,UAAU,GAAG,WAAW;GACzC,aAAa,cAAc,GAAG,aAAa,eAAe,GAAG,IAAI;GACjE,uBAAuB,IAAI,UAAU;EACvC;CACF;CAEA,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"block.js","names":[],"sources":["../../../src/components/block/block.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport { serializeResponsiveValueIf } from \"../_internal/layout\";\nimport type { BlockAsChildProps, BlockDivProps, BlockSpanProps } from \"./block.types\";\n\nconst SPACE_TOKENS = new Set([\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"xs\",\n \"sm\",\n \"md\",\n \"lg\",\n \"xl\",\n \"2xl\",\n \"3xl\",\n]);\n\nexport function Block(props: BlockDivProps): JSX.Element;\nexport function Block(props: BlockSpanProps): JSX.Element;\nexport function Block(props: BlockAsChildProps): JSX.Element;\nexport function Block(props: BlockDivProps | BlockSpanProps | BlockAsChildProps) {\n const as = \"as\" in props ? props.as : \"div\";\n const { asChild, children, gap, gapX, gapY, align, justify, size = \"md\", ref, ...rest } = props;\n\n const finalProps = mergeProps(rest, {\n ref,\n \"data-slot\": \"block\",\n \"data-ak-layout\": \"true\",\n \"data-gap\": serializeResponsiveValueIf(\n gap,\n (value) => typeof value === \"string\" && SPACE_TOKENS.has(value.trim()),\n ),\n \"data-gap-x\": serializeResponsiveValueIf(\n gapX,\n (value) => typeof value === \"string\" && SPACE_TOKENS.has(value.trim()),\n ),\n \"data-gap-y\": serializeResponsiveValueIf(\n gapY,\n (value) => typeof value === \"string\" && SPACE_TOKENS.has(value.trim()),\n ),\n \"data-align\": serializeResponsiveValueIf(\n align,\n (value) =>\n typeof value === \"string\" &&\n [\"start\", \"end\", \"center\", \"stretch\", \"baseline\"].includes(value.trim()),\n ),\n \"data-justify\": serializeResponsiveValueIf(\n justify,\n (value) =>\n typeof value === \"string\" && [\"start\", \"end\", \"center\", \"between\"].includes(value.trim()),\n ),\n \"data-size\": `initial:${size}`,\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children as JSX.Element} />;\n }\n\n if (as === \"span\") {\n return <span {...finalProps}>{children}</span>;\n }\n\n return <div {...finalProps}>{children}</div>;\n}\n"],"mappings":";;;;;AAKA,MAAM,eAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAKD,SAAgB,MAAM,OAA2D;CAC/E,MAAM,KAAK,QAAQ,QAAQ,MAAM,KAAK;CACtC,MAAM,EAAE,SAAS,UAAU,KAAK,MAAM,MAAM,OAAO,SAAS,OAAO,MAAM,KAAK,GAAG,SAAS;CAE1F,MAAM,aAAa,WAAW,MAAM;EAClC;EACA,aAAa;EACb,kBAAkB;EAClB,YAAY,2BACV,MACC,UAAU,OAAO,UAAU,YAAY,aAAa,IAAI,MAAM,KAAK,CAAC,CACvE;EACA,cAAc,2BACZ,OACC,UAAU,OAAO,UAAU,YAAY,aAAa,IAAI,MAAM,KAAK,CAAC,CACvE;EACA,cAAc,2BACZ,OACC,UAAU,OAAO,UAAU,YAAY,aAAa,IAAI,MAAM,KAAK,CAAC,CACvE;EACA,cAAc,2BACZ,QACC,UACC,OAAO,UAAU,YACjB;GAAC;GAAS;GAAO;GAAU;GAAW;EAAU,EAAE,SAAS,MAAM,KAAK,CAAC,CAC3E;EACA,gBAAgB,2BACd,UACC,UACC,OAAO,UAAU,YAAY;GAAC;GAAS;GAAO;GAAU;EAAS,EAAE,SAAS,MAAM,KAAK,CAAC,CAC5F;EACA,aAAa,WAAW;CAC1B,CAAC;CAED,IAAI,SACF,OAAO,oBAAC,MAAD;EAAM,SAAA;EAAQ,GAAI;EAAsB;CAA0B,CAAA;CAG3E,IAAI,OAAO,QACT,OAAO,oBAAC,QAAD;EAAM,GAAI;EAAa;CAAe,CAAA;CAG/C,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAa;CAAc,CAAA;AAC7C"}
1
+ {"version":3,"file":"block.js","names":[],"sources":["../../../src/components/block/block.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport { serializeResponsiveValueIf } from \"../_internal/layout\";\nimport type { BlockAsChildProps, BlockDivProps, BlockSpanProps } from \"./block.types\";\n\nconst SPACE_TOKENS = new Set([\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"xs\",\n \"sm\",\n \"md\",\n \"lg\",\n \"xl\",\n \"2xl\",\n \"3xl\",\n]);\n\nexport function Block(props: BlockDivProps): JSX.Element;\nexport function Block(props: BlockSpanProps): JSX.Element;\nexport function Block(props: BlockAsChildProps): JSX.Element;\nexport function Block(props: BlockDivProps | BlockSpanProps | BlockAsChildProps) {\n const as = \"as\" in props ? props.as : \"div\";\n const { asChild, children, gap, gapX, gapY, align, justify, size = \"md\", ref, ...rest } = props;\n\n const finalProps = mergeProps(rest, {\n ref,\n \"data-slot\": \"block\",\n \"data-ak-layout\": \"true\",\n \"data-gap\": serializeResponsiveValueIf(\n gap,\n (value) => typeof value === \"string\" && SPACE_TOKENS.has(value.trim()),\n ),\n \"data-gap-x\": serializeResponsiveValueIf(\n gapX,\n (value) => typeof value === \"string\" && SPACE_TOKENS.has(value.trim()),\n ),\n \"data-gap-y\": serializeResponsiveValueIf(\n gapY,\n (value) => typeof value === \"string\" && SPACE_TOKENS.has(value.trim()),\n ),\n \"data-align\": serializeResponsiveValueIf(\n align,\n (value) =>\n typeof value === \"string\" &&\n [\"start\", \"end\", \"center\", \"stretch\", \"baseline\"].includes(value.trim()),\n ),\n \"data-justify\": serializeResponsiveValueIf(\n justify,\n (value) =>\n typeof value === \"string\" && [\"start\", \"end\", \"center\", \"between\"].includes(value.trim()),\n ),\n \"data-size\": `initial:${size}`,\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children as JSX.Element} />;\n }\n\n if (as === \"span\") {\n return <span {...finalProps}>{children}</span>;\n }\n\n return <div {...finalProps}>{children}</div>;\n}\n"],"mappings":";;;;;AAKA,MAAM,eAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAKD,SAAgB,MAAM,OAA2D;CAC/E,MAAM,KAAK,QAAQ,QAAQ,MAAM,KAAK;CACtC,MAAM,EAAE,SAAS,UAAU,KAAK,MAAM,MAAM,OAAO,SAAS,OAAO,MAAM,KAAK,GAAG,SAAS;CAE1F,MAAM,aAAa,WAAW,MAAM;EAClC;EACA,aAAa;EACb,kBAAkB;EAClB,YAAY,2BACV,MACC,UAAU,OAAO,UAAU,YAAY,aAAa,IAAI,MAAM,KAAK,CAAC,CACvE;EACA,cAAc,2BACZ,OACC,UAAU,OAAO,UAAU,YAAY,aAAa,IAAI,MAAM,KAAK,CAAC,CACvE;EACA,cAAc,2BACZ,OACC,UAAU,OAAO,UAAU,YAAY,aAAa,IAAI,MAAM,KAAK,CAAC,CACvE;EACA,cAAc,2BACZ,QACC,UACC,OAAO,UAAU,YACjB;GAAC;GAAS;GAAO;GAAU;GAAW;EAAU,CAAC,CAAC,SAAS,MAAM,KAAK,CAAC,CAC3E;EACA,gBAAgB,2BACd,UACC,UACC,OAAO,UAAU,YAAY;GAAC;GAAS;GAAO;GAAU;EAAS,CAAC,CAAC,SAAS,MAAM,KAAK,CAAC,CAC5F;EACA,aAAa,WAAW;CAC1B,CAAC;CAED,IAAI,SACF,OAAO,oBAAC,MAAD;EAAM,SAAA;EAAQ,GAAI;EAAsB;CAA0B,CAAA;CAG3E,IAAI,OAAO,QACT,OAAO,oBAAC,QAAD;EAAM,GAAI;EAAa;CAAe,CAAA;CAG/C,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAa;CAAc,CAAA;AAC7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"container.js","names":[],"sources":["../../../src/components/container/container.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport {\n applyBoxLayoutStyles,\n splitBoxLayoutProps,\n withBoxLayoutClass,\n} from \"../_internal/box-layout\";\nimport {\n isResponsiveValue,\n resolveContainerSizeValue,\n resolveInlineAlignValue,\n resolveSpaceValue,\n serializeResponsiveValueIf,\n setResponsiveStyleVar,\n} from \"../_internal/layout\";\nimport type { ContainerAsChildProps, ContainerNativeProps } from \"./container.types\";\n\nconst CONTAINER_WIDTH_TOKENS = new Set([\"1\", \"2\", \"3\", \"4\", \"sm\", \"md\", \"lg\", \"xl\", \"fluid\"]);\n\nfunction isContainerWidthToken(value: unknown): value is string {\n return typeof value === \"string\" && CONTAINER_WIDTH_TOKENS.has(value.trim());\n}\n\nfunction isContainerAlignToken(value: unknown): value is \"left\" | \"center\" | \"right\" {\n return typeof value === \"string\" && [\"left\", \"center\", \"right\"].includes(value.trim());\n}\n\nfunction hasStyleValue(value: unknown): boolean {\n if (typeof value === \"string\") return value.trim().length > 0;\n if (value && typeof value === \"object\") {\n return Object.keys(value as Record<string, unknown>).length > 0;\n }\n\n return false;\n}\n\nfunction isStaticValue(value: unknown): boolean {\n return !isResponsiveValue(value as Record<string, unknown> | undefined);\n}\n\nexport function Container(props: ContainerNativeProps): JSX.Element;\nexport function Container(props: ContainerAsChildProps): JSX.Element;\nexport function Container(props: ContainerNativeProps | ContainerAsChildProps) {\n const {\n asChild,\n children,\n variant,\n maxWidth,\n padding,\n size,\n align = \"center\",\n ref,\n style: userStyle,\n ...rest\n } = props;\n\n const responsiveVariant =\n size === undefined && maxWidth === undefined ? (variant ?? \"default\") : undefined;\n\n const { boxProps, rest: passthroughProps } = splitBoxLayoutProps(rest);\n const layoutStyle: Record<string, string | number> = {\n boxSizing: \"border-box\",\n width: \"100%\",\n };\n applyBoxLayoutStyles(layoutStyle, boxProps);\n\n const widthValue = maxWidth ?? size;\n const usesInlineMaxWidth =\n boxProps.maxWidth === undefined &&\n widthValue !== undefined &&\n (isResponsiveValue(widthValue) || !isContainerWidthToken(widthValue));\n\n if (usesInlineMaxWidth) {\n setResponsiveStyleVar(layoutStyle, \"max-width\", widthValue, (value) =>\n typeof value === \"string\" && isContainerWidthToken(value)\n ? resolveContainerSizeValue(value)\n : value,\n );\n }\n\n if (\n padding !== undefined &&\n boxProps.px === undefined &&\n boxProps.pl === undefined &&\n boxProps.pr === undefined\n ) {\n setResponsiveStyleVar(layoutStyle, \"px\", padding, resolveSpaceValue);\n }\n\n const applyAlign = (side: \"marginLeft\" | \"marginRight\", value: typeof align) => {\n setResponsiveStyleVar(layoutStyle, side === \"marginLeft\" ? \"ml\" : \"mr\", value, (input) => {\n const margins = resolveInlineAlignValue(input);\n return side === \"marginLeft\" ? margins.marginLeft : margins.marginRight;\n });\n };\n\n if (boxProps.ml === undefined && boxProps.mr === undefined && isResponsiveValue(align)) {\n applyAlign(\"marginLeft\", align);\n applyAlign(\"marginRight\", align);\n }\n\n const layoutClass =\n Object.keys(layoutStyle).length > 2 || hasStyleValue(userStyle)\n ? withBoxLayoutClass(layoutStyle, userStyle)\n : undefined;\n\n const finalProps = mergeProps(passthroughProps, {\n ref,\n \"data-slot\": \"container\",\n \"data-ak-layout\": \"true\",\n \"data-variant\": responsiveVariant,\n \"data-size\": isStaticValue(size)\n ? serializeResponsiveValueIf(size, isContainerWidthToken)\n : undefined,\n \"data-align\": isStaticValue(align)\n ? serializeResponsiveValueIf(align, isContainerAlignToken)\n : undefined,\n \"data-max-width\": isStaticValue(maxWidth)\n ? serializeResponsiveValueIf(maxWidth, isContainerWidthToken)\n : undefined,\n ...(layoutClass ? { class: layoutClass } : {}),\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <div {...finalProps}>{children}</div>;\n}\n"],"mappings":";;;;;;AAiBA,MAAM,yBAAyB,IAAI,IAAI;CAAC;CAAK;CAAK;CAAK;CAAK;CAAM;CAAM;CAAM;CAAM;AAAO,CAAC;AAE5F,SAAS,sBAAsB,OAAiC;CAC9D,OAAO,OAAO,UAAU,YAAY,uBAAuB,IAAI,MAAM,KAAK,CAAC;AAC7E;AAEA,SAAS,sBAAsB,OAAsD;CACnF,OAAO,OAAO,UAAU,YAAY;EAAC;EAAQ;EAAU;CAAO,EAAE,SAAS,MAAM,KAAK,CAAC;AACvF;AAEA,SAAS,cAAc,OAAyB;CAC9C,IAAI,OAAO,UAAU,UAAU,OAAO,MAAM,KAAK,EAAE,SAAS;CAC5D,IAAI,SAAS,OAAO,UAAU,UAC5B,OAAO,OAAO,KAAK,KAAgC,EAAE,SAAS;CAGhE,OAAO;AACT;AAEA,SAAS,cAAc,OAAyB;CAC9C,OAAO,CAAC,kBAAkB,KAA4C;AACxE;AAIA,SAAgB,UAAU,OAAqD;CAC7E,MAAM,EACJ,SACA,UACA,SACA,UACA,SACA,MACA,QAAQ,UACR,KACA,OAAO,WACP,GAAG,SACD;CAEJ,MAAM,oBACJ,SAAS,KAAA,KAAa,aAAa,KAAA,IAAa,WAAW,YAAa,KAAA;CAE1E,MAAM,EAAE,UAAU,MAAM,qBAAqB,oBAAoB,IAAI;CACrE,MAAM,cAA+C;EACnD,WAAW;EACX,OAAO;CACT;CACA,qBAAqB,aAAa,QAAQ;CAE1C,MAAM,aAAa,YAAY;CAM/B,IAJE,SAAS,aAAa,KAAA,KACtB,eAAe,KAAA,MACd,kBAAkB,UAAU,KAAK,CAAC,sBAAsB,UAAU,IAGnE,sBAAsB,aAAa,aAAa,aAAa,UAC3D,OAAO,UAAU,YAAY,sBAAsB,KAAK,IACpD,0BAA0B,KAAK,IAC/B,KACN;CAGF,IACE,YAAY,KAAA,KACZ,SAAS,OAAO,KAAA,KAChB,SAAS,OAAO,KAAA,KAChB,SAAS,OAAO,KAAA,GAEhB,sBAAsB,aAAa,MAAM,SAAS,iBAAiB;CAGrE,MAAM,cAAc,MAAoC,UAAwB;EAC9E,sBAAsB,aAAa,SAAS,eAAe,OAAO,MAAM,QAAQ,UAAU;GACxF,MAAM,UAAU,wBAAwB,KAAK;GAC7C,OAAO,SAAS,eAAe,QAAQ,aAAa,QAAQ;EAC9D,CAAC;CACH;CAEA,IAAI,SAAS,OAAO,KAAA,KAAa,SAAS,OAAO,KAAA,KAAa,kBAAkB,KAAK,GAAG;EACtF,WAAW,cAAc,KAAK;EAC9B,WAAW,eAAe,KAAK;CACjC;CAEA,MAAM,cACJ,OAAO,KAAK,WAAW,EAAE,SAAS,KAAK,cAAc,SAAS,IAC1D,mBAAmB,aAAa,SAAS,IACzC,KAAA;CAEN,MAAM,aAAa,WAAW,kBAAkB;EAC9C;EACA,aAAa;EACb,kBAAkB;EAClB,gBAAgB;EAChB,aAAa,cAAc,IAAI,IAC3B,2BAA2B,MAAM,qBAAqB,IACtD,KAAA;EACJ,cAAc,cAAc,KAAK,IAC7B,2BAA2B,OAAO,qBAAqB,IACvD,KAAA;EACJ,kBAAkB,cAAc,QAAQ,IACpC,2BAA2B,UAAU,qBAAqB,IAC1D,KAAA;EACJ,GAAI,cAAc,EAAE,OAAO,YAAY,IAAI,CAAC;CAC9C,CAAC;CAED,IAAI,SACF,OAAO,oBAAC,MAAD;EAAM,SAAA;EAAQ,GAAI;EAAsB;CAAW,CAAA;CAG5D,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAa;CAAc,CAAA;AAC7C"}
1
+ {"version":3,"file":"container.js","names":[],"sources":["../../../src/components/container/container.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport {\n applyBoxLayoutStyles,\n splitBoxLayoutProps,\n withBoxLayoutClass,\n} from \"../_internal/box-layout\";\nimport {\n isResponsiveValue,\n resolveContainerSizeValue,\n resolveInlineAlignValue,\n resolveSpaceValue,\n serializeResponsiveValueIf,\n setResponsiveStyleVar,\n} from \"../_internal/layout\";\nimport type { ContainerAsChildProps, ContainerNativeProps } from \"./container.types\";\n\nconst CONTAINER_WIDTH_TOKENS = new Set([\"1\", \"2\", \"3\", \"4\", \"sm\", \"md\", \"lg\", \"xl\", \"fluid\"]);\n\nfunction isContainerWidthToken(value: unknown): value is string {\n return typeof value === \"string\" && CONTAINER_WIDTH_TOKENS.has(value.trim());\n}\n\nfunction isContainerAlignToken(value: unknown): value is \"left\" | \"center\" | \"right\" {\n return typeof value === \"string\" && [\"left\", \"center\", \"right\"].includes(value.trim());\n}\n\nfunction hasStyleValue(value: unknown): boolean {\n if (typeof value === \"string\") return value.trim().length > 0;\n if (value && typeof value === \"object\") {\n return Object.keys(value as Record<string, unknown>).length > 0;\n }\n\n return false;\n}\n\nfunction isStaticValue(value: unknown): boolean {\n return !isResponsiveValue(value as Record<string, unknown> | undefined);\n}\n\nexport function Container(props: ContainerNativeProps): JSX.Element;\nexport function Container(props: ContainerAsChildProps): JSX.Element;\nexport function Container(props: ContainerNativeProps | ContainerAsChildProps) {\n const {\n asChild,\n children,\n variant,\n maxWidth,\n padding,\n size,\n align = \"center\",\n ref,\n style: userStyle,\n ...rest\n } = props;\n\n const responsiveVariant =\n size === undefined && maxWidth === undefined ? (variant ?? \"default\") : undefined;\n\n const { boxProps, rest: passthroughProps } = splitBoxLayoutProps(rest);\n const layoutStyle: Record<string, string | number> = {\n boxSizing: \"border-box\",\n width: \"100%\",\n };\n applyBoxLayoutStyles(layoutStyle, boxProps);\n\n const widthValue = maxWidth ?? size;\n const usesInlineMaxWidth =\n boxProps.maxWidth === undefined &&\n widthValue !== undefined &&\n (isResponsiveValue(widthValue) || !isContainerWidthToken(widthValue));\n\n if (usesInlineMaxWidth) {\n setResponsiveStyleVar(layoutStyle, \"max-width\", widthValue, (value) =>\n typeof value === \"string\" && isContainerWidthToken(value)\n ? resolveContainerSizeValue(value)\n : value,\n );\n }\n\n if (\n padding !== undefined &&\n boxProps.px === undefined &&\n boxProps.pl === undefined &&\n boxProps.pr === undefined\n ) {\n setResponsiveStyleVar(layoutStyle, \"px\", padding, resolveSpaceValue);\n }\n\n const applyAlign = (side: \"marginLeft\" | \"marginRight\", value: typeof align) => {\n setResponsiveStyleVar(layoutStyle, side === \"marginLeft\" ? \"ml\" : \"mr\", value, (input) => {\n const margins = resolveInlineAlignValue(input);\n return side === \"marginLeft\" ? margins.marginLeft : margins.marginRight;\n });\n };\n\n if (boxProps.ml === undefined && boxProps.mr === undefined && isResponsiveValue(align)) {\n applyAlign(\"marginLeft\", align);\n applyAlign(\"marginRight\", align);\n }\n\n const layoutClass =\n Object.keys(layoutStyle).length > 2 || hasStyleValue(userStyle)\n ? withBoxLayoutClass(layoutStyle, userStyle)\n : undefined;\n\n const finalProps = mergeProps(passthroughProps, {\n ref,\n \"data-slot\": \"container\",\n \"data-ak-layout\": \"true\",\n \"data-variant\": responsiveVariant,\n \"data-size\": isStaticValue(size)\n ? serializeResponsiveValueIf(size, isContainerWidthToken)\n : undefined,\n \"data-align\": isStaticValue(align)\n ? serializeResponsiveValueIf(align, isContainerAlignToken)\n : undefined,\n \"data-max-width\": isStaticValue(maxWidth)\n ? serializeResponsiveValueIf(maxWidth, isContainerWidthToken)\n : undefined,\n ...(layoutClass ? { class: layoutClass } : {}),\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <div {...finalProps}>{children}</div>;\n}\n"],"mappings":";;;;;;AAiBA,MAAM,yBAAyB,IAAI,IAAI;CAAC;CAAK;CAAK;CAAK;CAAK;CAAM;CAAM;CAAM;CAAM;AAAO,CAAC;AAE5F,SAAS,sBAAsB,OAAiC;CAC9D,OAAO,OAAO,UAAU,YAAY,uBAAuB,IAAI,MAAM,KAAK,CAAC;AAC7E;AAEA,SAAS,sBAAsB,OAAsD;CACnF,OAAO,OAAO,UAAU,YAAY;EAAC;EAAQ;EAAU;CAAO,CAAC,CAAC,SAAS,MAAM,KAAK,CAAC;AACvF;AAEA,SAAS,cAAc,OAAyB;CAC9C,IAAI,OAAO,UAAU,UAAU,OAAO,MAAM,KAAK,CAAC,CAAC,SAAS;CAC5D,IAAI,SAAS,OAAO,UAAU,UAC5B,OAAO,OAAO,KAAK,KAAgC,CAAC,CAAC,SAAS;CAGhE,OAAO;AACT;AAEA,SAAS,cAAc,OAAyB;CAC9C,OAAO,CAAC,kBAAkB,KAA4C;AACxE;AAIA,SAAgB,UAAU,OAAqD;CAC7E,MAAM,EACJ,SACA,UACA,SACA,UACA,SACA,MACA,QAAQ,UACR,KACA,OAAO,WACP,GAAG,SACD;CAEJ,MAAM,oBACJ,SAAS,KAAA,KAAa,aAAa,KAAA,IAAa,WAAW,YAAa,KAAA;CAE1E,MAAM,EAAE,UAAU,MAAM,qBAAqB,oBAAoB,IAAI;CACrE,MAAM,cAA+C;EACnD,WAAW;EACX,OAAO;CACT;CACA,qBAAqB,aAAa,QAAQ;CAE1C,MAAM,aAAa,YAAY;CAM/B,IAJE,SAAS,aAAa,KAAA,KACtB,eAAe,KAAA,MACd,kBAAkB,UAAU,KAAK,CAAC,sBAAsB,UAAU,IAGnE,sBAAsB,aAAa,aAAa,aAAa,UAC3D,OAAO,UAAU,YAAY,sBAAsB,KAAK,IACpD,0BAA0B,KAAK,IAC/B,KACN;CAGF,IACE,YAAY,KAAA,KACZ,SAAS,OAAO,KAAA,KAChB,SAAS,OAAO,KAAA,KAChB,SAAS,OAAO,KAAA,GAEhB,sBAAsB,aAAa,MAAM,SAAS,iBAAiB;CAGrE,MAAM,cAAc,MAAoC,UAAwB;EAC9E,sBAAsB,aAAa,SAAS,eAAe,OAAO,MAAM,QAAQ,UAAU;GACxF,MAAM,UAAU,wBAAwB,KAAK;GAC7C,OAAO,SAAS,eAAe,QAAQ,aAAa,QAAQ;EAC9D,CAAC;CACH;CAEA,IAAI,SAAS,OAAO,KAAA,KAAa,SAAS,OAAO,KAAA,KAAa,kBAAkB,KAAK,GAAG;EACtF,WAAW,cAAc,KAAK;EAC9B,WAAW,eAAe,KAAK;CACjC;CAEA,MAAM,cACJ,OAAO,KAAK,WAAW,CAAC,CAAC,SAAS,KAAK,cAAc,SAAS,IAC1D,mBAAmB,aAAa,SAAS,IACzC,KAAA;CAEN,MAAM,aAAa,WAAW,kBAAkB;EAC9C;EACA,aAAa;EACb,kBAAkB;EAClB,gBAAgB;EAChB,aAAa,cAAc,IAAI,IAC3B,2BAA2B,MAAM,qBAAqB,IACtD,KAAA;EACJ,cAAc,cAAc,KAAK,IAC7B,2BAA2B,OAAO,qBAAqB,IACvD,KAAA;EACJ,kBAAkB,cAAc,QAAQ,IACpC,2BAA2B,UAAU,qBAAqB,IAC1D,KAAA;EACJ,GAAI,cAAc,EAAE,OAAO,YAAY,IAAI,CAAC;CAC9C,CAAC;CAED,IAAI,SACF,OAAO,oBAAC,MAAD;EAAM,SAAA;EAAQ,GAAI;EAAsB;CAAW,CAAA;CAG5D,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAa;CAAc,CAAA;AAC7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"flex.js","names":[],"sources":["../../../src/components/flex/flex.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport {\n applyBoxLayoutStyles,\n splitBoxLayoutProps,\n withBoxLayoutClass,\n} from \"../_internal/box-layout\";\nimport {\n isResponsiveValue,\n resolveAlignValue,\n resolveJustifyValue,\n resolveSpaceValue,\n serializeResponsiveValueIf,\n setResponsiveStyleVar,\n} from \"../_internal/layout\";\nimport type { FlexAsChildProps, FlexDivProps, FlexSpanProps } from \"./flex.types\";\n\nconst SPACE_TOKENS = new Set([\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"xs\",\n \"sm\",\n \"md\",\n \"lg\",\n \"xl\",\n \"2xl\",\n \"3xl\",\n]);\n\nfunction isResponsiveObject(value: unknown): boolean {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isCssCoveredSpaceValue(value: unknown): value is string {\n return typeof value === \"string\" && SPACE_TOKENS.has(value.trim());\n}\n\nfunction isCssCoveredDirectionValue(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n [\"row\", \"column\", \"row-reverse\", \"column-reverse\"].includes(value.trim())\n );\n}\n\nfunction isCssCoveredAlignValue(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n [\"start\", \"end\", \"center\", \"stretch\", \"baseline\"].includes(value.trim())\n );\n}\n\nfunction isCssCoveredJustifyValue(value: unknown): value is string {\n return typeof value === \"string\" && [\"start\", \"end\", \"center\", \"between\"].includes(value.trim());\n}\n\nfunction isCssCoveredWrapValue(value: unknown): value is string {\n return typeof value === \"string\" && [\"wrap\", \"nowrap\", \"wrap-reverse\"].includes(value.trim());\n}\n\nfunction serializeStaticThemeValue<T>(\n value: T | Partial<Record<\"initial\" | \"sm\" | \"md\" | \"lg\" | \"xl\", T>> | undefined,\n predicate: (value: T) => boolean,\n): string | undefined {\n if (isResponsiveValue(value)) return undefined;\n return serializeResponsiveValueIf(value, predicate);\n}\n\nconst SLOTS = {\n root: \"flex\",\n} as const;\n\nexport function Flex(props: FlexDivProps): JSX.Element;\nexport function Flex(props: FlexSpanProps): JSX.Element;\nexport function Flex(props: FlexAsChildProps): JSX.Element;\nexport function Flex(props: FlexDivProps | FlexSpanProps | FlexAsChildProps) {\n const as = \"as\" in props ? props.as : \"div\";\n const {\n asChild,\n children,\n direction = \"row\",\n gap,\n gapX,\n gapY,\n align,\n justify,\n wrap,\n collapseBelow,\n ref,\n style: userStyle,\n ...rest\n } = props;\n\n const { boxProps, rest: passthroughProps } = splitBoxLayoutProps(rest);\n const rootSlot =\n typeof (passthroughProps as Record<string, unknown>)[\"data-slot\"] === \"string\"\n ? String((passthroughProps as Record<string, unknown>)[\"data-slot\"])\n : SLOTS.root;\n const layoutStyle: Record<string, string | number> = {};\n applyBoxLayoutStyles(layoutStyle, boxProps);\n\n if (boxProps.display !== undefined) {\n setResponsiveStyleVar(layoutStyle, \"display\", boxProps.display, (value) => value);\n }\n if (\n direction !== \"row\" &&\n (!isCssCoveredDirectionValue(direction) || isResponsiveObject(direction))\n ) {\n setResponsiveStyleVar(layoutStyle, \"flex-direction\", direction, (value) => value);\n }\n if (!isCssCoveredSpaceValue(gap) || isResponsiveObject(gap)) {\n setResponsiveStyleVar(layoutStyle, \"gap\", gap, resolveSpaceValue);\n }\n if (!isCssCoveredSpaceValue(gapX) || isResponsiveObject(gapX)) {\n setResponsiveStyleVar(layoutStyle, \"column-gap\", gapX, resolveSpaceValue);\n }\n if (!isCssCoveredSpaceValue(gapY) || isResponsiveObject(gapY)) {\n setResponsiveStyleVar(layoutStyle, \"row-gap\", gapY, resolveSpaceValue);\n }\n if (!isCssCoveredAlignValue(align) || isResponsiveObject(align)) {\n setResponsiveStyleVar(layoutStyle, \"align-items\", align, resolveAlignValue);\n }\n if (!isCssCoveredJustifyValue(justify) || isResponsiveObject(justify)) {\n setResponsiveStyleVar(layoutStyle, \"justify-content\", justify, resolveJustifyValue);\n }\n if (!isCssCoveredWrapValue(wrap) || isResponsiveObject(wrap)) {\n setResponsiveStyleVar(layoutStyle, \"flex-wrap\", wrap, (value) => value);\n }\n\n const layoutClass = withBoxLayoutClass(layoutStyle, userStyle);\n\n const finalProps = mergeProps(passthroughProps, {\n ref,\n \"data-slot\": rootSlot,\n \"data-ak-layout\": \"true\",\n \"data-direction\": serializeStaticThemeValue(direction, isCssCoveredDirectionValue),\n \"data-gap\": serializeStaticThemeValue(gap, isCssCoveredSpaceValue),\n \"data-gap-x\": serializeStaticThemeValue(gapX, isCssCoveredSpaceValue),\n \"data-gap-y\": serializeStaticThemeValue(gapY, isCssCoveredSpaceValue),\n \"data-align\": serializeStaticThemeValue(align, isCssCoveredAlignValue),\n \"data-justify\": serializeStaticThemeValue(justify, isCssCoveredJustifyValue),\n \"data-wrap\": serializeStaticThemeValue(wrap, isCssCoveredWrapValue),\n \"data-collapse-below\": collapseBelow,\n ...(layoutClass ? { class: layoutClass } : {}),\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children as JSX.Element} />;\n }\n\n if (as === \"span\") {\n return <span {...finalProps}>{children}</span>;\n }\n\n return <div {...finalProps}>{children}</div>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flex.js","names":[],"sources":["../../../src/components/flex/flex.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport {\n applyBoxLayoutStyles,\n splitBoxLayoutProps,\n withBoxLayoutClass,\n} from \"../_internal/box-layout\";\nimport {\n isResponsiveValue,\n resolveAlignValue,\n resolveJustifyValue,\n resolveSpaceValue,\n serializeResponsiveValueIf,\n setResponsiveStyleVar,\n} from \"../_internal/layout\";\nimport type { FlexAsChildProps, FlexDivProps, FlexSpanProps } from \"./flex.types\";\n\nconst SPACE_TOKENS = new Set([\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"xs\",\n \"sm\",\n \"md\",\n \"lg\",\n \"xl\",\n \"2xl\",\n \"3xl\",\n]);\n\nfunction isResponsiveObject(value: unknown): boolean {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isCssCoveredSpaceValue(value: unknown): value is string {\n return typeof value === \"string\" && SPACE_TOKENS.has(value.trim());\n}\n\nfunction isCssCoveredDirectionValue(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n [\"row\", \"column\", \"row-reverse\", \"column-reverse\"].includes(value.trim())\n );\n}\n\nfunction isCssCoveredAlignValue(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n [\"start\", \"end\", \"center\", \"stretch\", \"baseline\"].includes(value.trim())\n );\n}\n\nfunction isCssCoveredJustifyValue(value: unknown): value is string {\n return typeof value === \"string\" && [\"start\", \"end\", \"center\", \"between\"].includes(value.trim());\n}\n\nfunction isCssCoveredWrapValue(value: unknown): value is string {\n return typeof value === \"string\" && [\"wrap\", \"nowrap\", \"wrap-reverse\"].includes(value.trim());\n}\n\nfunction serializeStaticThemeValue<T>(\n value: T | Partial<Record<\"initial\" | \"sm\" | \"md\" | \"lg\" | \"xl\", T>> | undefined,\n predicate: (value: T) => boolean,\n): string | undefined {\n if (isResponsiveValue(value)) return undefined;\n return serializeResponsiveValueIf(value, predicate);\n}\n\nconst SLOTS = {\n root: \"flex\",\n} as const;\n\nexport function Flex(props: FlexDivProps): JSX.Element;\nexport function Flex(props: FlexSpanProps): JSX.Element;\nexport function Flex(props: FlexAsChildProps): JSX.Element;\nexport function Flex(props: FlexDivProps | FlexSpanProps | FlexAsChildProps) {\n const as = \"as\" in props ? props.as : \"div\";\n const {\n asChild,\n children,\n direction = \"row\",\n gap,\n gapX,\n gapY,\n align,\n justify,\n wrap,\n collapseBelow,\n ref,\n style: userStyle,\n ...rest\n } = props;\n\n const { boxProps, rest: passthroughProps } = splitBoxLayoutProps(rest);\n const rootSlot =\n typeof (passthroughProps as Record<string, unknown>)[\"data-slot\"] === \"string\"\n ? String((passthroughProps as Record<string, unknown>)[\"data-slot\"])\n : SLOTS.root;\n const layoutStyle: Record<string, string | number> = {};\n applyBoxLayoutStyles(layoutStyle, boxProps);\n\n if (boxProps.display !== undefined) {\n setResponsiveStyleVar(layoutStyle, \"display\", boxProps.display, (value) => value);\n }\n if (\n direction !== \"row\" &&\n (!isCssCoveredDirectionValue(direction) || isResponsiveObject(direction))\n ) {\n setResponsiveStyleVar(layoutStyle, \"flex-direction\", direction, (value) => value);\n }\n if (!isCssCoveredSpaceValue(gap) || isResponsiveObject(gap)) {\n setResponsiveStyleVar(layoutStyle, \"gap\", gap, resolveSpaceValue);\n }\n if (!isCssCoveredSpaceValue(gapX) || isResponsiveObject(gapX)) {\n setResponsiveStyleVar(layoutStyle, \"column-gap\", gapX, resolveSpaceValue);\n }\n if (!isCssCoveredSpaceValue(gapY) || isResponsiveObject(gapY)) {\n setResponsiveStyleVar(layoutStyle, \"row-gap\", gapY, resolveSpaceValue);\n }\n if (!isCssCoveredAlignValue(align) || isResponsiveObject(align)) {\n setResponsiveStyleVar(layoutStyle, \"align-items\", align, resolveAlignValue);\n }\n if (!isCssCoveredJustifyValue(justify) || isResponsiveObject(justify)) {\n setResponsiveStyleVar(layoutStyle, \"justify-content\", justify, resolveJustifyValue);\n }\n if (!isCssCoveredWrapValue(wrap) || isResponsiveObject(wrap)) {\n setResponsiveStyleVar(layoutStyle, \"flex-wrap\", wrap, (value) => value);\n }\n\n const layoutClass = withBoxLayoutClass(layoutStyle, userStyle);\n\n const finalProps = mergeProps(passthroughProps, {\n ref,\n \"data-slot\": rootSlot,\n \"data-ak-layout\": \"true\",\n \"data-direction\": serializeStaticThemeValue(direction, isCssCoveredDirectionValue),\n \"data-gap\": serializeStaticThemeValue(gap, isCssCoveredSpaceValue),\n \"data-gap-x\": serializeStaticThemeValue(gapX, isCssCoveredSpaceValue),\n \"data-gap-y\": serializeStaticThemeValue(gapY, isCssCoveredSpaceValue),\n \"data-align\": serializeStaticThemeValue(align, isCssCoveredAlignValue),\n \"data-justify\": serializeStaticThemeValue(justify, isCssCoveredJustifyValue),\n \"data-wrap\": serializeStaticThemeValue(wrap, isCssCoveredWrapValue),\n \"data-collapse-below\": collapseBelow,\n ...(layoutClass ? { class: layoutClass } : {}),\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children as JSX.Element} />;\n }\n\n if (as === \"span\") {\n return <span {...finalProps}>{children}</span>;\n }\n\n return <div {...finalProps}>{children}</div>;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"nav.js","names":[],"sources":["../../../src/components/nav/nav.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { currentRoute, navigate } from \"@askrjs/askr/router\";\nimport { classes } from \"../_internal/classes\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport { resolvePathname } from \"../_internal/pathname\";\nimport type {\n NavAsChildProps,\n NavDivProps,\n NavItemAsChildProps,\n NavItemProps,\n NavItemVariant,\n NavLinkProps,\n NavListProps,\n NavNavProps,\n NavProps,\n} from \"./nav.types\";\n\nfunction navItemClasses(variant: NavItemVariant, className: unknown): string | undefined {\n return classes(\n \"nav-item\",\n \"navbar-item\",\n variant === \"icon\" && \"nav-item-icon\",\n variant === \"icon\" && \"navbar-item-icon\",\n className,\n );\n}\n\nfunction normalizePathname(pathname: string): string {\n return pathname.endsWith(\"/\") && pathname !== \"/\" ? pathname.slice(0, -1) : pathname;\n}\n\nfunction getCurrentPathname(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n return normalizePathname(window.location.pathname || \"/\");\n}\n\nfunction getReactiveCurrentPathname(): string | null {\n try {\n return normalizePathname(currentRoute().path || \"/\");\n } catch {\n return getCurrentPathname();\n }\n}\n\nfunction shouldHandleClientNavigation(\n event: MouseEvent,\n target: string | undefined,\n targetPathname: string | null,\n): boolean {\n if (targetPathname === null || target) {\n return false;\n }\n\n return (\n !event.defaultPrevented &&\n (event.button ?? 0) === 0 &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.shiftKey\n );\n}\n\nfunction isActiveNavLink(\n currentPathname: string,\n targetPathname: string,\n match: NavLinkProps[\"match\"] = \"prefix\",\n): boolean {\n if (targetPathname === \"/\") {\n return currentPathname === \"/\";\n }\n\n if (match === \"exact\") {\n return currentPathname === targetPathname;\n }\n\n return currentPathname === targetPathname || currentPathname.startsWith(`${targetPathname}/`);\n}\n\nexport function Nav(props: NavNavProps): JSX.Element;\nexport function Nav(props: NavDivProps): JSX.Element;\nexport function Nav(props: NavListProps): JSX.Element;\nexport function Nav(props: NavAsChildProps): JSX.Element;\nexport function Nav(props: NavProps): JSX.Element {\n const as = \"as\" in props ? props.as : \"nav\";\n const className = \"class\" in props ? props.class : undefined;\n const {\n asChild,\n children,\n orientation = \"horizontal\",\n variant = \"default\",\n ref,\n ...rest\n } = props;\n const finalProps = mergeProps(rest, {\n ref,\n class: classes(\"nav\", className),\n \"data-slot\": \"nav\",\n \"data-orientation\": orientation,\n \"data-variant\": variant,\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children as JSX.Element} />;\n }\n\n if (as === \"div\") {\n return <div {...finalProps}>{children}</div>;\n }\n\n if (as === \"ul\") {\n return <ul {...finalProps}>{children}</ul>;\n }\n\n return <nav {...finalProps}>{children}</nav>;\n}\n\nexport function NavItem(props: NavItemProps): JSX.Element;\nexport function NavItem(props: NavItemAsChildProps): JSX.Element;\nexport function NavItem(props: NavItemProps | NavItemAsChildProps): JSX.Element {\n const {\n asChild,\n children,\n ref,\n class: className,\n match: _match,\n variant = \"default\",\n ...rest\n } = props as (NavItemProps | NavItemAsChildProps) & { match?: unknown };\n void _match;\n\n const finalProps = mergeProps(rest, {\n ref,\n class: navItemClasses(variant, className),\n \"data-slot\": \"nav-item\",\n \"data-variant\": variant,\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <a {...finalProps}>{children}</a>;\n}\n\nexport function NavLink(props: NavLinkProps): JSX.Element {\n const {\n children,\n href,\n onClick,\n ref,\n class: className,\n match = \"prefix\",\n target,\n variant = \"default\",\n ...rest\n } = props as NavLinkProps & { onClick?: (event: MouseEvent) => void };\n const currentPathname = getReactiveCurrentPathname();\n const targetPathname = resolvePathname(href);\n const isActive =\n currentPathname !== null &&\n targetPathname !== null &&\n isActiveNavLink(currentPathname, targetPathname, match);\n\n const linkProps = mergeProps(rest, {\n href,\n target,\n ref,\n class: navItemClasses(variant, className),\n \"data-slot\": \"nav-link\",\n \"data-variant\": variant,\n });\n\n const finalProps = isActive\n ? mergeProps(\n {\n \"aria-current\": \"page\",\n \"data-active\": \"true\",\n },\n linkProps,\n )\n : linkProps;\n\n const handleClick = (event: MouseEvent) => {\n onClick?.(event);\n\n if (!shouldHandleClientNavigation(event, target, targetPathname)) {\n return;\n }\n\n event.preventDefault();\n navigate(href);\n };\n\n return (\n <a {...finalProps} onClick={handleClick}>\n {children}\n </a>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"nav.js","names":[],"sources":["../../../src/components/nav/nav.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { currentRoute, navigate } from \"@askrjs/askr/router\";\nimport { classes } from \"../_internal/classes\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport { resolvePathname } from \"../_internal/pathname\";\nimport type {\n NavAsChildProps,\n NavDivProps,\n NavItemAsChildProps,\n NavItemProps,\n NavItemVariant,\n NavLinkProps,\n NavListProps,\n NavNavProps,\n NavProps,\n} from \"./nav.types\";\n\nfunction navItemClasses(variant: NavItemVariant, className: unknown): string | undefined {\n return classes(\n \"nav-item\",\n \"navbar-item\",\n variant === \"icon\" && \"nav-item-icon\",\n variant === \"icon\" && \"navbar-item-icon\",\n className,\n );\n}\n\nfunction normalizePathname(pathname: string): string {\n return pathname.endsWith(\"/\") && pathname !== \"/\" ? pathname.slice(0, -1) : pathname;\n}\n\nfunction getCurrentPathname(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n return normalizePathname(window.location.pathname || \"/\");\n}\n\nfunction getReactiveCurrentPathname(): string | null {\n try {\n return normalizePathname(currentRoute().path || \"/\");\n } catch {\n return getCurrentPathname();\n }\n}\n\nfunction shouldHandleClientNavigation(\n event: MouseEvent,\n target: string | undefined,\n targetPathname: string | null,\n): boolean {\n if (targetPathname === null || target) {\n return false;\n }\n\n return (\n !event.defaultPrevented &&\n (event.button ?? 0) === 0 &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.shiftKey\n );\n}\n\nfunction isActiveNavLink(\n currentPathname: string,\n targetPathname: string,\n match: NavLinkProps[\"match\"] = \"prefix\",\n): boolean {\n if (targetPathname === \"/\") {\n return currentPathname === \"/\";\n }\n\n if (match === \"exact\") {\n return currentPathname === targetPathname;\n }\n\n return currentPathname === targetPathname || currentPathname.startsWith(`${targetPathname}/`);\n}\n\nexport function Nav(props: NavNavProps): JSX.Element;\nexport function Nav(props: NavDivProps): JSX.Element;\nexport function Nav(props: NavListProps): JSX.Element;\nexport function Nav(props: NavAsChildProps): JSX.Element;\nexport function Nav(props: NavProps): JSX.Element {\n const as = \"as\" in props ? props.as : \"nav\";\n const className = \"class\" in props ? props.class : undefined;\n const {\n asChild,\n children,\n orientation = \"horizontal\",\n variant = \"default\",\n ref,\n ...rest\n } = props;\n const finalProps = mergeProps(rest, {\n ref,\n class: classes(\"nav\", className),\n \"data-slot\": \"nav\",\n \"data-orientation\": orientation,\n \"data-variant\": variant,\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children as JSX.Element} />;\n }\n\n if (as === \"div\") {\n return <div {...finalProps}>{children}</div>;\n }\n\n if (as === \"ul\") {\n return <ul {...finalProps}>{children}</ul>;\n }\n\n return <nav {...finalProps}>{children}</nav>;\n}\n\nexport function NavItem(props: NavItemProps): JSX.Element;\nexport function NavItem(props: NavItemAsChildProps): JSX.Element;\nexport function NavItem(props: NavItemProps | NavItemAsChildProps): JSX.Element {\n const {\n asChild,\n children,\n ref,\n class: className,\n match: _match,\n variant = \"default\",\n ...rest\n } = props as (NavItemProps | NavItemAsChildProps) & { match?: unknown };\n void _match;\n\n const finalProps = mergeProps(rest, {\n ref,\n class: navItemClasses(variant, className),\n \"data-slot\": \"nav-item\",\n \"data-variant\": variant,\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <a {...finalProps}>{children}</a>;\n}\n\nexport function NavLink(props: NavLinkProps): JSX.Element {\n const {\n children,\n href,\n onClick,\n ref,\n class: className,\n match = \"prefix\",\n target,\n variant = \"default\",\n ...rest\n } = props as NavLinkProps & { onClick?: (event: MouseEvent) => void };\n const currentPathname = getReactiveCurrentPathname();\n const targetPathname = resolvePathname(href);\n const isActive =\n currentPathname !== null &&\n targetPathname !== null &&\n isActiveNavLink(currentPathname, targetPathname, match);\n\n const linkProps = mergeProps(rest, {\n href,\n target,\n ref,\n class: navItemClasses(variant, className),\n \"data-slot\": \"nav-link\",\n \"data-variant\": variant,\n });\n\n const finalProps = isActive\n ? mergeProps(\n {\n \"aria-current\": \"page\",\n \"data-active\": \"true\",\n },\n linkProps,\n )\n : linkProps;\n\n const handleClick = (event: MouseEvent) => {\n onClick?.(event);\n\n if (!shouldHandleClientNavigation(event, target, targetPathname)) {\n return;\n }\n\n event.preventDefault();\n navigate(href);\n };\n\n return (\n <a {...finalProps} onClick={handleClick}>\n {children}\n </a>\n );\n}\n"],"mappings":"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"}
@@ -2,29 +2,23 @@ import { renderShellPanel } from "../shell/shell-panel.js";
2
2
  import { NavbarResponsiveContext } from "./navbar.context.js";
3
3
  import { readContext } from "@askrjs/askr";
4
4
  //#region src/components/navbar/navbar-panel.tsx
5
+ const DEFAULT_NAVBAR_RESPONSIVE_CONTEXT = {
6
+ active: () => false,
7
+ collapseLabel: () => "Menu",
8
+ closePanel: () => void 0,
9
+ panelId: () => void 0,
10
+ panelOpen: () => false,
11
+ togglePanel: () => void 0
12
+ };
5
13
  function NavbarPanel(props) {
6
14
  const { active: activeProp, brand, children, class: className, collapseLabel: collapseLabelProp, onClose, open: openProp, panelId: panelIdProp, ref, ...rest } = props;
7
15
  const responsive = activeProp === void 0 || collapseLabelProp === void 0 || onClose === void 0 || openProp === void 0 || panelIdProp === void 0 ? (() => {
8
16
  try {
9
17
  return readContext(NavbarResponsiveContext);
10
18
  } catch {
11
- return {
12
- active: () => false,
13
- collapseLabel: () => "Menu",
14
- closePanel: () => void 0,
15
- panelId: () => void 0,
16
- panelOpen: () => false,
17
- togglePanel: () => void 0
18
- };
19
+ return DEFAULT_NAVBAR_RESPONSIVE_CONTEXT;
19
20
  }
20
- })() : {
21
- active: () => false,
22
- collapseLabel: () => "Menu",
23
- closePanel: () => void 0,
24
- panelId: () => void 0,
25
- panelOpen: () => false,
26
- togglePanel: () => void 0
27
- };
21
+ })() : DEFAULT_NAVBAR_RESPONSIVE_CONTEXT;
28
22
  const active = activeProp ?? responsive.active();
29
23
  const open = openProp ?? responsive.panelOpen();
30
24
  const panelId = panelIdProp ?? responsive.panelId();
@@ -1 +1 @@
1
- {"version":3,"file":"navbar-panel.js","names":[],"sources":["../../../src/components/navbar/navbar-panel.tsx"],"sourcesContent":["import { readContext } from \"@askrjs/askr\";\nimport { renderShellPanel } from \"../shell/shell-panel\";\nimport { NavbarResponsiveContext } from \"./navbar.context\";\nimport type { NavbarPanelProps } from \"./navbar.types\";\n\nexport function NavbarPanel(props: NavbarPanelProps): JSX.Element | null {\n const {\n active: activeProp,\n brand,\n children,\n class: className,\n collapseLabel: collapseLabelProp,\n onClose,\n open: openProp,\n panelId: panelIdProp,\n ref,\n ...rest\n } = props;\n const needsResponsiveContext =\n activeProp === undefined ||\n collapseLabelProp === undefined ||\n onClose === undefined ||\n openProp === undefined ||\n panelIdProp === undefined;\n const responsive = needsResponsiveContext\n ? (() => {\n try {\n return readContext(NavbarResponsiveContext);\n } catch {\n return {\n active: () => false,\n collapseLabel: () => \"Menu\",\n closePanel: () => undefined,\n panelId: () => undefined,\n panelOpen: () => false,\n togglePanel: () => undefined,\n };\n }\n })()\n : {\n active: () => false,\n collapseLabel: () => \"Menu\",\n closePanel: () => undefined,\n panelId: () => undefined,\n panelOpen: () => false,\n togglePanel: () => undefined,\n };\n const active = activeProp ?? responsive.active();\n const open = openProp ?? responsive.panelOpen();\n const panelId = panelIdProp ?? responsive.panelId();\n const collapseLabel = collapseLabelProp ?? responsive.collapseLabel();\n const closePanel = onClose ?? responsive.closePanel;\n\n return renderShellPanel({\n active,\n brand,\n children,\n className,\n collapseLabel,\n onClose: closePanel,\n open,\n panelId,\n prefix: \"navbar\",\n ref,\n rest,\n });\n}\n"],"mappings":";;;;AAKA,SAAgB,YAAY,OAA6C;CACvE,MAAM,EACJ,QAAQ,YACR,OACA,UACA,OAAO,WACP,eAAe,mBACf,SACA,MAAM,UACN,SAAS,aACT,KACA,GAAG,SACD;CAOJ,MAAM,aALJ,eAAe,KAAA,KACf,sBAAsB,KAAA,KACtB,YAAY,KAAA,KACZ,aAAa,KAAA,KACb,gBAAgB,KAAA,WAEP;EACL,IAAI;GACF,OAAO,YAAY,uBAAuB;EAC5C,QAAQ;GACN,OAAO;IACL,cAAc;IACd,qBAAqB;IACrB,kBAAkB,KAAA;IAClB,eAAe,KAAA;IACf,iBAAiB;IACjB,mBAAmB,KAAA;GACrB;EACF;CACF,GAAG,IACH;EACE,cAAc;EACd,qBAAqB;EACrB,kBAAkB,KAAA;EAClB,eAAe,KAAA;EACf,iBAAiB;EACjB,mBAAmB,KAAA;CACrB;CACJ,MAAM,SAAS,cAAc,WAAW,OAAO;CAC/C,MAAM,OAAO,YAAY,WAAW,UAAU;CAC9C,MAAM,UAAU,eAAe,WAAW,QAAQ;CAIlD,OAAO,iBAAiB;EACtB;EACA;EACA;EACA;EACA,eARoB,qBAAqB,WAAW,cAAc;EASlE,SARiB,WAAW,WAAW;EASvC;EACA;EACA,QAAQ;EACR;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"navbar-panel.js","names":[],"sources":["../../../src/components/navbar/navbar-panel.tsx"],"sourcesContent":["import { readContext } from \"@askrjs/askr\";\nimport { renderShellPanel } from \"../shell/shell-panel\";\nimport { NavbarResponsiveContext } from \"./navbar.context\";\nimport type { NavbarPanelProps } from \"./navbar.types\";\n\nconst DEFAULT_NAVBAR_RESPONSIVE_CONTEXT = {\n active: () => false,\n collapseLabel: () => \"Menu\",\n closePanel: () => undefined,\n panelId: () => undefined,\n panelOpen: () => false,\n togglePanel: () => undefined,\n};\n\nexport function NavbarPanel(props: NavbarPanelProps): JSX.Element | null {\n const {\n active: activeProp,\n brand,\n children,\n class: className,\n collapseLabel: collapseLabelProp,\n onClose,\n open: openProp,\n panelId: panelIdProp,\n ref,\n ...rest\n } = props;\n const needsResponsiveContext =\n activeProp === undefined ||\n collapseLabelProp === undefined ||\n onClose === undefined ||\n openProp === undefined ||\n panelIdProp === undefined;\n const responsive = needsResponsiveContext\n ? (() => {\n try {\n return readContext(NavbarResponsiveContext);\n } catch {\n return DEFAULT_NAVBAR_RESPONSIVE_CONTEXT;\n }\n })()\n : DEFAULT_NAVBAR_RESPONSIVE_CONTEXT;\n const active = activeProp ?? responsive.active();\n const open = openProp ?? responsive.panelOpen();\n const panelId = panelIdProp ?? responsive.panelId();\n const collapseLabel = collapseLabelProp ?? responsive.collapseLabel();\n const closePanel = onClose ?? responsive.closePanel;\n\n return renderShellPanel({\n active,\n brand,\n children,\n className,\n collapseLabel,\n onClose: closePanel,\n open,\n panelId,\n prefix: \"navbar\",\n ref,\n rest,\n });\n}\n"],"mappings":";;;;AAKA,MAAM,oCAAoC;CACxC,cAAc;CACd,qBAAqB;CACrB,kBAAkB,KAAA;CAClB,eAAe,KAAA;CACf,iBAAiB;CACjB,mBAAmB,KAAA;AACrB;AAEA,SAAgB,YAAY,OAA6C;CACvE,MAAM,EACJ,QAAQ,YACR,OACA,UACA,OAAO,WACP,eAAe,mBACf,SACA,MAAM,UACN,SAAS,aACT,KACA,GAAG,SACD;CAOJ,MAAM,aALJ,eAAe,KAAA,KACf,sBAAsB,KAAA,KACtB,YAAY,KAAA,KACZ,aAAa,KAAA,KACb,gBAAgB,KAAA,WAEP;EACL,IAAI;GACF,OAAO,YAAY,uBAAuB;EAC5C,QAAQ;GACN,OAAO;EACT;CACF,EAAA,CAAG,IACH;CACJ,MAAM,SAAS,cAAc,WAAW,OAAO;CAC/C,MAAM,OAAO,YAAY,WAAW,UAAU;CAC9C,MAAM,UAAU,eAAe,WAAW,QAAQ;CAIlD,OAAO,iBAAiB;EACtB;EACA;EACA;EACA;EACA,eARoB,qBAAqB,WAAW,cAAc;EASlE,SARiB,WAAW,WAAW;EASvC;EACA;EACA,QAAQ;EACR;EACA;CACF,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"navbar.js","names":[],"sources":["../../../src/components/navbar/navbar.tsx"],"sourcesContent":["import { state } from \"@askrjs/askr\";\nimport { classes } from \"../_internal/classes\";\nimport { isJsxElement, toChildArray } from \"../_internal/jsx\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport {\n renderKeyedShellChildren,\n ShellPanelWatcher,\n ShellResponsiveWatcher,\n} from \"../shell/shell-responsive\";\nimport { renderNavbarCollapseContents } from \"./navbar.render\";\nimport { NavbarPanel } from \"./navbar-panel\";\nimport { NavbarResponsiveContext } from \"./navbar.context\";\nimport { isNavbarCollapsed, resolveNavGroupAlign } from \"./navbar.shared\";\nimport type { NavBrandProps, NavGroupProps, NavToggleProps, NavbarProps } from \"./navbar.types\";\n\n/**\n * Extracts the first NavBrand child to display in the mobile panel.\n * NavBrand should be the first child of Navbar for it to appear in the mobile menu.\n */\nfunction findNavbarBrand(children: unknown): unknown {\n return toChildArray(children).find((child) => isJsxElement(child) && child.type === NavBrand);\n}\n\nfunction withoutNavbarBrand(children: unknown): unknown[] {\n return toChildArray(children).filter(\n (child) => !(isJsxElement(child) && child.type === NavBrand),\n );\n}\n\n/**\n * Responsive mobile-first navbar component.\n *\n * Composition: Navbar should contain NavBrand (extracted to mobile panel), NavGroup items with optional align,\n * and NavLink children. Brand must be first child to appear in mobile menu.\n *\n * @example\n * <Navbar breakpoint=\"md\" aria-label=\"Main navigation\">\n * <NavBrand><a href=\"/\">Logo</a></NavBrand>\n * <NavGroup align=\"center\">\n * <NavLink href=\"/docs\">Docs</NavLink>\n * </NavGroup>\n * <NavGroup align=\"end\">\n * <NavLink href=\"/settings\">Settings</NavLink>\n * </NavGroup>\n * </Navbar>\n */\nexport function Navbar(props: NavbarProps): JSX.Element {\n const {\n children,\n breakpoint,\n collapseIcon,\n collapseIconPlacement = \"start\",\n collapseLabel,\n ref,\n class: className,\n id,\n \"aria-label\": ariaLabel,\n ...rest\n } = props;\n const effectiveCollapseLabel = collapseLabel ?? \"Menu\";\n const responsiveChildren = toChildArray(children);\n const desktopChildren = renderKeyedShellChildren(responsiveChildren, \"navbar-desktop\");\n const panelChildren = renderKeyedShellChildren(\n withoutNavbarBrand(responsiveChildren),\n \"navbar-panel\",\n );\n // Extract brand to display in mobile panel header\n const responsiveCollapsedState =\n breakpoint !== undefined ? state(isNavbarCollapsed(breakpoint)) : undefined;\n const mobileMenuState = state(false);\n const mobileMenuOpen = mobileMenuState();\n const panelId = typeof id === \"string\" ? `${id}-panel` : undefined;\n const responsiveCollapsed = breakpoint !== undefined ? responsiveCollapsedState?.() : false;\n const panelOpen = Boolean(responsiveCollapsed && mobileMenuOpen);\n const closePanel = () => mobileMenuState.set(false);\n const closePanelOnNavActivation = (event: MouseEvent) => {\n const target = event.target;\n\n if (!(target instanceof Element)) {\n return;\n }\n\n if (target.closest('a[data-slot=\"nav-link\"], a[data-slot=\"nav-item\"], a.navbar-item')) {\n closePanel();\n }\n };\n const togglePanel = () => {\n mobileMenuState.set(!mobileMenuState());\n };\n const contextValue = {\n active: () => breakpoint !== undefined,\n collapseLabel: () => effectiveCollapseLabel,\n closePanel,\n panelId: () => panelId,\n panelOpen: () => Boolean(responsiveCollapsedState?.() && mobileMenuOpen),\n togglePanel,\n };\n const panelBrand = findNavbarBrand(responsiveChildren);\n const finalProps = mergeProps(rest, {\n \"aria-label\": ariaLabel,\n ref,\n class: classes(\"navbar\", className),\n \"data-collapse-below\": breakpoint,\n \"data-responsive-collapsed\": responsiveCollapsed ? \"true\" : \"false\",\n \"data-slot\": \"navbar\",\n });\n\n return (\n <NavbarResponsiveContext.Scope value={contextValue}>\n <nav {...finalProps}>\n {breakpoint !== undefined ? (\n <div class=\"navbar-mobile\" data-slot=\"navbar-mobile\">\n <NavToggle\n active={breakpoint !== undefined}\n aria-controls={panelId}\n aria-label={effectiveCollapseLabel}\n icon={collapseIcon}\n iconPlacement={collapseIconPlacement}\n label={effectiveCollapseLabel}\n onToggle={togglePanel}\n open={panelOpen}\n panelId={panelId}\n />\n </div>\n ) : null}\n\n <div class=\"navbar-shell\" data-slot=\"navbar-shell\">\n {desktopChildren}\n </div>\n\n {breakpoint !== undefined ? (\n <NavbarPanel\n active={breakpoint !== undefined}\n brand={panelBrand}\n collapseLabel={effectiveCollapseLabel}\n onClose={closePanel}\n onClick={closePanelOnNavActivation}\n open={panelOpen}\n panelId={panelId}\n >\n {panelChildren}\n </NavbarPanel>\n ) : null}\n\n {responsiveCollapsed && mobileMenuOpen ? (\n <button\n aria-label={`Close ${effectiveCollapseLabel}`}\n class=\"navbar-backdrop\"\n data-slot=\"navbar-backdrop\"\n data-state=\"open\"\n tabIndex={-1}\n type=\"button\"\n onClick={closePanel}\n />\n ) : null}\n\n {breakpoint !== undefined ? (\n <ShellResponsiveWatcher\n breakpoint={breakpoint}\n isCollapsed={isNavbarCollapsed}\n onResize={(nextCollapsed) => {\n responsiveCollapsedState?.set(nextCollapsed);\n }}\n onExpand={() => {\n mobileMenuState?.set(false);\n }}\n />\n ) : null}\n\n <ShellPanelWatcher\n contentId={panelId}\n open={panelOpen}\n panelSlot=\"navbar-panel\"\n onClose={closePanel}\n />\n </nav>\n </NavbarResponsiveContext.Scope>\n );\n}\n\n/**\n * Menu toggle button for responsive navbar collapse.\n * Auto-renders when navbar is responsive (collapseBelow set).\n */\nexport function NavToggle(props: NavToggleProps): JSX.Element | null {\n const {\n children,\n class: className,\n active,\n icon,\n iconPlacement = \"start\",\n label = \"Menu\",\n ref,\n onToggle,\n open,\n panelId,\n ...rest\n } = props;\n\n if (active === false) {\n return null;\n }\n\n const isOpen = open === true;\n\n const finalProps = mergeProps(rest, {\n ref,\n class: classes(\"navbar-toggle\", className),\n \"aria-controls\": panelId,\n \"aria-expanded\": isOpen ? \"true\" : \"false\",\n \"aria-label\": label,\n \"data-slot\": \"navbar-toggle\",\n \"data-state\": isOpen ? \"open\" : \"closed\",\n type: \"button\",\n onClick: () => onToggle?.(),\n });\n\n return (\n <button {...finalProps}>\n {children ?? renderNavbarCollapseContents(label, icon, iconPlacement)}\n </button>\n );\n}\n\n/**\n * Brand/logo container displayed in navbar and mobile panel header.\n */\nexport function NavBrand(props: NavBrandProps): JSX.Element {\n const { children, ref, class: className, ...rest } = props;\n\n return (\n <div {...rest} ref={ref} class={classes(\"navbar-brand\", className)} data-slot=\"navbar-brand\">\n {children}\n </div>\n );\n}\n\n/**\n * Navigation group for organizing related nav items.\n *\n * @param align - Alignment: \"start\" (default), \"center\", or \"end\". Using align=\"end\" automatically right-aligns the group.\n * @param label - Optional accessible label for grouped items.\n *\n * @example\n * <NavGroup align=\"center\">\n * <NavLink href=\"/docs\">Docs</NavLink>\n * </NavGroup>\n */\nexport function NavGroup(props: NavGroupProps): JSX.Element {\n const { children, id, ref, class: className, label, ...rest } = props;\n const rawAlign = (rest as Record<string, unknown>)[\"data-align\"];\n const align =\n props.align ??\n (rawAlign === \"start\" || rawAlign === \"center\" || rawAlign === \"end\"\n ? (rawAlign as NavGroupProps[\"align\"])\n : undefined);\n const hasLabel = label !== undefined && label !== null;\n const labelId = hasLabel && id ? `${id}-label` : undefined;\n const accessibleLabel = typeof label === \"string\" ? label : undefined;\n\n return (\n <div\n {...rest}\n id={id}\n ref={ref}\n class={classes(\"navbar-group\", className)}\n aria-label={labelId ? undefined : accessibleLabel}\n aria-labelledby={labelId}\n role={hasLabel ? \"group\" : rest.role}\n data-align={resolveNavGroupAlign(align)}\n data-has-label={hasLabel ? \"true\" : undefined}\n data-slot=\"navbar-group\"\n >\n {hasLabel ? (\n <>\n <div id={labelId} class=\"navbar-group-label\" data-slot=\"navbar-group-label\">\n {label}\n </div>\n <div class=\"navbar-group-body\" data-slot=\"navbar-group-body\">\n {children}\n </div>\n </>\n ) : (\n children\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"navbar.js","names":[],"sources":["../../../src/components/navbar/navbar.tsx"],"sourcesContent":["import { state } from \"@askrjs/askr\";\nimport { classes } from \"../_internal/classes\";\nimport { isJsxElement, toChildArray } from \"../_internal/jsx\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport {\n renderKeyedShellChildren,\n ShellPanelWatcher,\n ShellResponsiveWatcher,\n} from \"../shell/shell-responsive\";\nimport { renderNavbarCollapseContents } from \"./navbar.render\";\nimport { NavbarPanel } from \"./navbar-panel\";\nimport { NavbarResponsiveContext } from \"./navbar.context\";\nimport { isNavbarCollapsed, resolveNavGroupAlign } from \"./navbar.shared\";\nimport type { NavBrandProps, NavGroupProps, NavToggleProps, NavbarProps } from \"./navbar.types\";\n\n/**\n * Extracts the first NavBrand child to display in the mobile panel.\n * NavBrand should be the first child of Navbar for it to appear in the mobile menu.\n */\nfunction findNavbarBrand(children: unknown): unknown {\n return toChildArray(children).find((child) => isJsxElement(child) && child.type === NavBrand);\n}\n\nfunction withoutNavbarBrand(children: unknown): unknown[] {\n return toChildArray(children).filter(\n (child) => !(isJsxElement(child) && child.type === NavBrand),\n );\n}\n\n/**\n * Responsive mobile-first navbar component.\n *\n * Composition: Navbar should contain NavBrand (extracted to mobile panel), NavGroup items with optional align,\n * and NavLink children. Brand must be first child to appear in mobile menu.\n *\n * @example\n * <Navbar breakpoint=\"md\" aria-label=\"Main navigation\">\n * <NavBrand><a href=\"/\">Logo</a></NavBrand>\n * <NavGroup align=\"center\">\n * <NavLink href=\"/docs\">Docs</NavLink>\n * </NavGroup>\n * <NavGroup align=\"end\">\n * <NavLink href=\"/settings\">Settings</NavLink>\n * </NavGroup>\n * </Navbar>\n */\nexport function Navbar(props: NavbarProps): JSX.Element {\n const {\n children,\n breakpoint,\n collapseIcon,\n collapseIconPlacement = \"start\",\n collapseLabel,\n ref,\n class: className,\n id,\n \"aria-label\": ariaLabel,\n ...rest\n } = props;\n const effectiveCollapseLabel = collapseLabel ?? \"Menu\";\n const responsiveChildren = toChildArray(children);\n const desktopChildren = renderKeyedShellChildren(responsiveChildren, \"navbar-desktop\");\n const panelChildren = renderKeyedShellChildren(\n withoutNavbarBrand(responsiveChildren),\n \"navbar-panel\",\n );\n // Extract brand to display in mobile panel header\n const responsiveCollapsedState =\n breakpoint !== undefined ? state(isNavbarCollapsed(breakpoint)) : undefined;\n const mobileMenuState = state(false);\n const mobileMenuOpen = mobileMenuState();\n const panelId = typeof id === \"string\" ? `${id}-panel` : undefined;\n const responsiveCollapsed = breakpoint !== undefined ? responsiveCollapsedState?.() : false;\n const panelOpen = Boolean(responsiveCollapsed && mobileMenuOpen);\n const closePanel = () => mobileMenuState.set(false);\n const closePanelOnNavActivation = (event: MouseEvent) => {\n const target = event.target;\n\n if (!(target instanceof Element)) {\n return;\n }\n\n if (target.closest('a[data-slot=\"nav-link\"], a[data-slot=\"nav-item\"], a.navbar-item')) {\n closePanel();\n }\n };\n const togglePanel = () => {\n mobileMenuState.set(!mobileMenuState());\n };\n const contextValue = {\n active: () => breakpoint !== undefined,\n collapseLabel: () => effectiveCollapseLabel,\n closePanel,\n panelId: () => panelId,\n panelOpen: () => Boolean(responsiveCollapsedState?.() && mobileMenuOpen),\n togglePanel,\n };\n const panelBrand = findNavbarBrand(responsiveChildren);\n const finalProps = mergeProps(rest, {\n \"aria-label\": ariaLabel,\n ref,\n class: classes(\"navbar\", className),\n \"data-collapse-below\": breakpoint,\n \"data-responsive-collapsed\": responsiveCollapsed ? \"true\" : \"false\",\n \"data-slot\": \"navbar\",\n });\n\n return (\n <NavbarResponsiveContext.Scope value={contextValue}>\n <nav {...finalProps}>\n {breakpoint !== undefined ? (\n <div class=\"navbar-mobile\" data-slot=\"navbar-mobile\">\n <NavToggle\n active={breakpoint !== undefined}\n aria-controls={panelId}\n aria-label={effectiveCollapseLabel}\n icon={collapseIcon}\n iconPlacement={collapseIconPlacement}\n label={effectiveCollapseLabel}\n onToggle={togglePanel}\n open={panelOpen}\n panelId={panelId}\n />\n </div>\n ) : null}\n\n <div class=\"navbar-shell\" data-slot=\"navbar-shell\">\n {desktopChildren}\n </div>\n\n {breakpoint !== undefined ? (\n <NavbarPanel\n active={breakpoint !== undefined}\n brand={panelBrand}\n collapseLabel={effectiveCollapseLabel}\n onClose={closePanel}\n onClick={closePanelOnNavActivation}\n open={panelOpen}\n panelId={panelId}\n >\n {panelChildren}\n </NavbarPanel>\n ) : null}\n\n {responsiveCollapsed && mobileMenuOpen ? (\n <button\n aria-label={`Close ${effectiveCollapseLabel}`}\n class=\"navbar-backdrop\"\n data-slot=\"navbar-backdrop\"\n data-state=\"open\"\n tabIndex={-1}\n type=\"button\"\n onClick={closePanel}\n />\n ) : null}\n\n {breakpoint !== undefined ? (\n <ShellResponsiveWatcher\n breakpoint={breakpoint}\n isCollapsed={isNavbarCollapsed}\n onResize={(nextCollapsed) => {\n responsiveCollapsedState?.set(nextCollapsed);\n }}\n onExpand={() => {\n mobileMenuState?.set(false);\n }}\n />\n ) : null}\n\n <ShellPanelWatcher\n contentId={panelId}\n open={panelOpen}\n panelSlot=\"navbar-panel\"\n onClose={closePanel}\n />\n </nav>\n </NavbarResponsiveContext.Scope>\n );\n}\n\n/**\n * Menu toggle button for responsive navbar collapse.\n * Auto-renders when navbar is responsive (collapseBelow set).\n */\nexport function NavToggle(props: NavToggleProps): JSX.Element | null {\n const {\n children,\n class: className,\n active,\n icon,\n iconPlacement = \"start\",\n label = \"Menu\",\n ref,\n onToggle,\n open,\n panelId,\n ...rest\n } = props;\n\n if (active === false) {\n return null;\n }\n\n const isOpen = open === true;\n\n const finalProps = mergeProps(rest, {\n ref,\n class: classes(\"navbar-toggle\", className),\n \"aria-controls\": panelId,\n \"aria-expanded\": isOpen ? \"true\" : \"false\",\n \"aria-label\": label,\n \"data-slot\": \"navbar-toggle\",\n \"data-state\": isOpen ? \"open\" : \"closed\",\n type: \"button\",\n onClick: () => onToggle?.(),\n });\n\n return (\n <button {...finalProps}>\n {children ?? renderNavbarCollapseContents(label, icon, iconPlacement)}\n </button>\n );\n}\n\n/**\n * Brand/logo container displayed in navbar and mobile panel header.\n */\nexport function NavBrand(props: NavBrandProps): JSX.Element {\n const { children, ref, class: className, ...rest } = props;\n\n return (\n <div {...rest} ref={ref} class={classes(\"navbar-brand\", className)} data-slot=\"navbar-brand\">\n {children}\n </div>\n );\n}\n\n/**\n * Navigation group for organizing related nav items.\n *\n * @param align - Alignment: \"start\" (default), \"center\", or \"end\". Using align=\"end\" automatically right-aligns the group.\n * @param label - Optional accessible label for grouped items.\n *\n * @example\n * <NavGroup align=\"center\">\n * <NavLink href=\"/docs\">Docs</NavLink>\n * </NavGroup>\n */\nexport function NavGroup(props: NavGroupProps): JSX.Element {\n const { children, id, ref, class: className, label, ...rest } = props;\n const rawAlign = (rest as Record<string, unknown>)[\"data-align\"];\n const align =\n props.align ??\n (rawAlign === \"start\" || rawAlign === \"center\" || rawAlign === \"end\"\n ? (rawAlign as NavGroupProps[\"align\"])\n : undefined);\n const hasLabel = label !== undefined && label !== null;\n const labelId = hasLabel && id ? `${id}-label` : undefined;\n const accessibleLabel = typeof label === \"string\" ? label : undefined;\n\n return (\n <div\n {...rest}\n id={id}\n ref={ref}\n class={classes(\"navbar-group\", className)}\n aria-label={labelId ? undefined : accessibleLabel}\n aria-labelledby={labelId}\n role={hasLabel ? \"group\" : rest.role}\n data-align={resolveNavGroupAlign(align)}\n data-has-label={hasLabel ? \"true\" : undefined}\n data-slot=\"navbar-group\"\n >\n {hasLabel ? (\n <>\n <div id={labelId} class=\"navbar-group-label\" data-slot=\"navbar-group-label\">\n {label}\n </div>\n <div class=\"navbar-group-body\" data-slot=\"navbar-group-body\">\n {children}\n </div>\n </>\n ) : (\n children\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"section.js","names":[],"sources":["../../../src/components/section/section.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport {\n applyBoxLayoutStyles,\n splitBoxLayoutProps,\n withBoxLayoutClass,\n} from \"../_internal/box-layout\";\nimport { serializeResponsiveValueIf } from \"../_internal/layout\";\nimport type { SectionAsChildProps, SectionElementProps } from \"./section.types\";\n\nfunction isSectionSizeToken(value: unknown): value is string {\n return typeof value === \"string\" && [\"1\", \"2\", \"3\", \"4\"].includes(value.trim());\n}\n\nexport function Section(props: SectionElementProps): JSX.Element;\nexport function Section(props: SectionAsChildProps): JSX.Element;\nexport function Section(props: SectionElementProps | SectionAsChildProps) {\n const { asChild, children, size = \"3\", ref, style: userStyle, ...rest } = props;\n\n const { boxProps, rest: passthroughProps } = splitBoxLayoutProps(rest);\n const layoutStyle: Record<string, string | number> = {};\n applyBoxLayoutStyles(layoutStyle, boxProps);\n const layoutClass = withBoxLayoutClass(layoutStyle, userStyle);\n\n const finalProps = mergeProps(passthroughProps, {\n ref,\n \"data-slot\": \"section\",\n \"data-ak-layout\": \"true\",\n \"data-size\": serializeResponsiveValueIf(size, isSectionSizeToken),\n ...(layoutClass ? { class: layoutClass } : {}),\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <section {...finalProps}>{children}</section>;\n}\n"],"mappings":";;;;;;AAUA,SAAS,mBAAmB,OAAiC;CAC3D,OAAO,OAAO,UAAU,YAAY;EAAC;EAAK;EAAK;EAAK;CAAG,EAAE,SAAS,MAAM,KAAK,CAAC;AAChF;AAIA,SAAgB,QAAQ,OAAkD;CACxE,MAAM,EAAE,SAAS,UAAU,OAAO,KAAK,KAAK,OAAO,WAAW,GAAG,SAAS;CAE1E,MAAM,EAAE,UAAU,MAAM,qBAAqB,oBAAoB,IAAI;CACrE,MAAM,cAA+C,CAAC;CACtD,qBAAqB,aAAa,QAAQ;CAC1C,MAAM,cAAc,mBAAmB,aAAa,SAAS;CAE7D,MAAM,aAAa,WAAW,kBAAkB;EAC9C;EACA,aAAa;EACb,kBAAkB;EAClB,aAAa,2BAA2B,MAAM,kBAAkB;EAChE,GAAI,cAAc,EAAE,OAAO,YAAY,IAAI,CAAC;CAC9C,CAAC;CAED,IAAI,SACF,OAAO,oBAAC,MAAD;EAAM,SAAA;EAAQ,GAAI;EAAsB;CAAW,CAAA;CAG5D,OAAO,oBAAC,WAAD;EAAS,GAAI;EAAa;CAAkB,CAAA;AACrD"}
1
+ {"version":3,"file":"section.js","names":[],"sources":["../../../src/components/section/section.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport {\n applyBoxLayoutStyles,\n splitBoxLayoutProps,\n withBoxLayoutClass,\n} from \"../_internal/box-layout\";\nimport { serializeResponsiveValueIf } from \"../_internal/layout\";\nimport type { SectionAsChildProps, SectionElementProps } from \"./section.types\";\n\nfunction isSectionSizeToken(value: unknown): value is string {\n return typeof value === \"string\" && [\"1\", \"2\", \"3\", \"4\"].includes(value.trim());\n}\n\nexport function Section(props: SectionElementProps): JSX.Element;\nexport function Section(props: SectionAsChildProps): JSX.Element;\nexport function Section(props: SectionElementProps | SectionAsChildProps) {\n const { asChild, children, size = \"3\", ref, style: userStyle, ...rest } = props;\n\n const { boxProps, rest: passthroughProps } = splitBoxLayoutProps(rest);\n const layoutStyle: Record<string, string | number> = {};\n applyBoxLayoutStyles(layoutStyle, boxProps);\n const layoutClass = withBoxLayoutClass(layoutStyle, userStyle);\n\n const finalProps = mergeProps(passthroughProps, {\n ref,\n \"data-slot\": \"section\",\n \"data-ak-layout\": \"true\",\n \"data-size\": serializeResponsiveValueIf(size, isSectionSizeToken),\n ...(layoutClass ? { class: layoutClass } : {}),\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <section {...finalProps}>{children}</section>;\n}\n"],"mappings":";;;;;;AAUA,SAAS,mBAAmB,OAAiC;CAC3D,OAAO,OAAO,UAAU,YAAY;EAAC;EAAK;EAAK;EAAK;CAAG,CAAC,CAAC,SAAS,MAAM,KAAK,CAAC;AAChF;AAIA,SAAgB,QAAQ,OAAkD;CACxE,MAAM,EAAE,SAAS,UAAU,OAAO,KAAK,KAAK,OAAO,WAAW,GAAG,SAAS;CAE1E,MAAM,EAAE,UAAU,MAAM,qBAAqB,oBAAoB,IAAI;CACrE,MAAM,cAA+C,CAAC;CACtD,qBAAqB,aAAa,QAAQ;CAC1C,MAAM,cAAc,mBAAmB,aAAa,SAAS;CAE7D,MAAM,aAAa,WAAW,kBAAkB;EAC9C;EACA,aAAa;EACb,kBAAkB;EAClB,aAAa,2BAA2B,MAAM,kBAAkB;EAChE,GAAI,cAAc,EAAE,OAAO,YAAY,IAAI,CAAC;CAC9C,CAAC;CAED,IAAI,SACF,OAAO,oBAAC,MAAD;EAAM,SAAA;EAAQ,GAAI;EAAsB;CAAW,CAAA;CAG5D,OAAO,oBAAC,WAAD;EAAS,GAAI;EAAa;CAAkB,CAAA;AACrD"}
@@ -25,13 +25,14 @@ function isShellPanelChild(child, panelComponent) {
25
25
  return isJsxElement(child) && child.type === panelComponent;
26
26
  }
27
27
  function renderKeyedShellChildren(children, keyPrefix) {
28
- const keyedChildren = toChildArray(children).map((child, index) => {
28
+ const childList = toChildArray(children);
29
+ const keyedChildren = childList.some((child) => isJsxElement(child) && child.key == null) ? childList.map((child, index) => {
29
30
  if (!isJsxElement(child) || child.key != null) return child;
30
31
  return {
31
32
  ...child,
32
33
  key: `${keyPrefix}-${index}`
33
34
  };
34
- });
35
+ }) : childList;
35
36
  return /* @__PURE__ */ jsx(For, {
36
37
  each: () => keyedChildren,
37
38
  by: (child, index) => isJsxElement(child) && child.key != null ? String(child.key) : `${keyPrefix}-${index}`,
@@ -39,13 +40,20 @@ function renderKeyedShellChildren(children, keyPrefix) {
39
40
  });
40
41
  }
41
42
  function renderKeyedShellPanelChildren(children, keyPrefix, panelProps) {
42
- const keyedChildren = toChildArray(children).map((child, index) => {
43
+ const childList = toChildArray(children);
44
+ const keyedChildren = childList.some((child) => {
45
+ if (!isJsxElement(child)) return false;
46
+ const props = child.props;
47
+ return props?.active !== panelProps.active || props?.collapseLabel !== panelProps.collapseLabel || props?.onClose !== panelProps.onClose || props?.open !== panelProps.open || props?.panelId !== panelProps.panelId;
48
+ }) ? childList.map((child, index) => {
43
49
  if (!isJsxElement(child)) return child;
50
+ const props = child.props;
51
+ if (props?.active === panelProps.active && props?.collapseLabel === panelProps.collapseLabel && props?.onClose === panelProps.onClose && props?.open === panelProps.open && props?.panelId === panelProps.panelId) return child;
44
52
  return {
45
53
  ...child,
46
54
  key: child.key != null ? child.key : `${keyPrefix}-${index}`,
47
55
  props: {
48
- ...child.props,
56
+ ...props,
49
57
  active: panelProps.active,
50
58
  collapseLabel: panelProps.collapseLabel,
51
59
  onClose: panelProps.onClose,
@@ -53,7 +61,7 @@ function renderKeyedShellPanelChildren(children, keyPrefix, panelProps) {
53
61
  panelId: panelProps.panelId
54
62
  }
55
63
  };
56
- });
64
+ }) : childList;
57
65
  return /* @__PURE__ */ jsx(For, {
58
66
  each: () => keyedChildren,
59
67
  by: (child, index) => isJsxElement(child) && child.key != null ? String(child.key) : `${keyPrefix}-${index}`,
@@ -1 +1 @@
1
- {"version":3,"file":"shell-responsive.js","names":[],"sources":["../../../src/components/shell/shell-responsive.tsx"],"sourcesContent":["import { For } from \"@askrjs/askr/control\";\nimport { resource } from \"@askrjs/askr/resources\";\nimport type { JSXElement } from \"@askrjs/askr/foundations\";\nimport { isJsxElement, toChildArray } from \"../_internal/jsx\";\n\nexport type ShellResponsivePanelProps = {\n active: boolean;\n collapseLabel: string;\n onClose: () => void;\n open: boolean;\n panelId?: string;\n};\n\nlet shellScrollLockCount = 0;\nlet shellScrollLockPreviousValue: string | null = null;\n\nfunction acquireShellScrollLock(): void {\n if (typeof document === \"undefined\") return;\n\n const body = document.body;\n if (shellScrollLockCount === 0) {\n shellScrollLockPreviousValue = body.getAttribute(\"data-shell-scroll-lock\");\n }\n\n shellScrollLockCount += 1;\n body.setAttribute(\"data-shell-scroll-lock\", \"true\");\n}\n\nfunction releaseShellScrollLock(): void {\n if (typeof document === \"undefined\" || shellScrollLockCount === 0) return;\n\n shellScrollLockCount -= 1;\n if (shellScrollLockCount > 0) return;\n\n const body = document.body;\n if (shellScrollLockPreviousValue === null) {\n body.removeAttribute(\"data-shell-scroll-lock\");\n } else {\n body.setAttribute(\"data-shell-scroll-lock\", shellScrollLockPreviousValue);\n }\n\n shellScrollLockPreviousValue = null;\n}\n\nexport function isShellPanelChild(child: unknown, panelComponent: unknown): child is JSXElement {\n return isJsxElement(child) && child.type === panelComponent;\n}\n\nexport function renderKeyedShellChildren(children: unknown, keyPrefix: string): JSX.Element {\n const keyedChildren = toChildArray(children).map((child, index) => {\n if (!isJsxElement(child) || child.key != null) {\n return child;\n }\n\n return {\n ...child,\n key: `${keyPrefix}-${index}`,\n };\n });\n\n return (\n <For\n each={() => keyedChildren}\n by={(child, index) =>\n isJsxElement(child) && child.key != null ? String(child.key) : `${keyPrefix}-${index}`\n }\n >\n {(child) => child as never}\n </For>\n );\n}\n\nexport function renderKeyedShellPanelChildren(\n children: unknown,\n keyPrefix: string,\n panelProps: ShellResponsivePanelProps,\n): JSX.Element {\n const keyedChildren = toChildArray(children).map((child, index) => {\n if (!isJsxElement(child)) {\n return child;\n }\n\n return {\n ...child,\n key: child.key != null ? child.key : `${keyPrefix}-${index}`,\n props: {\n ...child.props,\n active: panelProps.active,\n collapseLabel: panelProps.collapseLabel,\n onClose: panelProps.onClose,\n open: panelProps.open,\n panelId: panelProps.panelId,\n },\n };\n });\n\n return (\n <For\n each={() => keyedChildren}\n by={(child, index) =>\n isJsxElement(child) && child.key != null ? String(child.key) : `${keyPrefix}-${index}`\n }\n >\n {(child) => child as never}\n </For>\n );\n}\n\nexport function ShellResponsiveWatcher<TBreakpoint extends string>(props: {\n breakpoint: TBreakpoint;\n isCollapsed: (breakpoint: TBreakpoint) => boolean;\n onExpand: () => void;\n onResize: (nextCollapsed: boolean) => void;\n}): JSX.Element | null {\n const { breakpoint, isCollapsed, onExpand, onResize } = props;\n\n resource(\n ({ signal }: { signal: AbortSignal }) => {\n const updateCollapsedState = () => {\n const nextCollapsed = isCollapsed(breakpoint);\n onResize(nextCollapsed);\n\n if (!nextCollapsed) {\n onExpand();\n }\n };\n\n updateCollapsedState();\n\n if (typeof window === \"undefined\") {\n return null;\n }\n\n window.addEventListener(\"resize\", updateCollapsedState);\n signal.addEventListener(\n \"abort\",\n () => {\n window.removeEventListener(\"resize\", updateCollapsedState);\n },\n { once: true },\n );\n\n return null;\n },\n [breakpoint],\n );\n\n return null;\n}\n\nexport function ShellPanelWatcher(props: {\n contentId?: string;\n onClose: () => void;\n open: boolean;\n panelSlot: string;\n}): JSX.Element | null {\n const { contentId, onClose, open, panelSlot } = props;\n\n resource(\n ({ signal }: { signal: AbortSignal }) => {\n if (!open || typeof window === \"undefined\") {\n releaseShellScrollLock();\n return null;\n }\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") {\n return;\n }\n\n event.preventDefault();\n onClose();\n };\n\n window.addEventListener(\"keydown\", onKeyDown);\n\n const focusFrame =\n typeof window.requestAnimationFrame === \"function\"\n ? window.requestAnimationFrame(() => {\n const content =\n (typeof contentId === \"string\" ? document.getElementById(contentId) : null) ??\n document.querySelector<HTMLElement>(\n `[data-slot=\"${panelSlot}\"][data-state=\"open\"]`,\n );\n\n content?.focus({ preventScroll: true });\n })\n : undefined;\n\n acquireShellScrollLock();\n\n signal.addEventListener(\n \"abort\",\n () => {\n window.removeEventListener(\"keydown\", onKeyDown);\n\n if (focusFrame !== undefined && typeof window.cancelAnimationFrame === \"function\") {\n window.cancelAnimationFrame(focusFrame);\n }\n\n releaseShellScrollLock();\n },\n { once: true },\n );\n\n return null;\n },\n [open],\n );\n\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shell-responsive.js","names":[],"sources":["../../../src/components/shell/shell-responsive.tsx"],"sourcesContent":["import { For } from \"@askrjs/askr/control\";\nimport { resource } from \"@askrjs/askr/resources\";\nimport type { JSXElement } from \"@askrjs/askr/foundations\";\nimport { isJsxElement, toChildArray } from \"../_internal/jsx\";\n\nexport type ShellResponsivePanelProps = {\n active: boolean;\n collapseLabel: string;\n onClose: () => void;\n open: boolean;\n panelId?: string;\n};\n\nlet shellScrollLockCount = 0;\nlet shellScrollLockPreviousValue: string | null = null;\n\nfunction acquireShellScrollLock(): void {\n if (typeof document === \"undefined\") return;\n\n const body = document.body;\n if (shellScrollLockCount === 0) {\n shellScrollLockPreviousValue = body.getAttribute(\"data-shell-scroll-lock\");\n }\n\n shellScrollLockCount += 1;\n body.setAttribute(\"data-shell-scroll-lock\", \"true\");\n}\n\nfunction releaseShellScrollLock(): void {\n if (typeof document === \"undefined\" || shellScrollLockCount === 0) return;\n\n shellScrollLockCount -= 1;\n if (shellScrollLockCount > 0) return;\n\n const body = document.body;\n if (shellScrollLockPreviousValue === null) {\n body.removeAttribute(\"data-shell-scroll-lock\");\n } else {\n body.setAttribute(\"data-shell-scroll-lock\", shellScrollLockPreviousValue);\n }\n\n shellScrollLockPreviousValue = null;\n}\n\nexport function isShellPanelChild(child: unknown, panelComponent: unknown): child is JSXElement {\n return isJsxElement(child) && child.type === panelComponent;\n}\n\nexport function renderKeyedShellChildren(children: unknown, keyPrefix: string): JSX.Element {\n const childList = toChildArray(children);\n const needsKeying = childList.some((child) => isJsxElement(child) && child.key == null);\n const keyedChildren = needsKeying\n ? childList.map((child, index) => {\n if (!isJsxElement(child) || child.key != null) {\n return child;\n }\n\n return {\n ...child,\n key: `${keyPrefix}-${index}`,\n };\n })\n : childList;\n\n return (\n <For\n each={() => keyedChildren}\n by={(child, index) =>\n isJsxElement(child) && child.key != null ? String(child.key) : `${keyPrefix}-${index}`\n }\n >\n {(child) => child as never}\n </For>\n );\n}\n\nexport function renderKeyedShellPanelChildren(\n children: unknown,\n keyPrefix: string,\n panelProps: ShellResponsivePanelProps,\n): JSX.Element {\n const childList = toChildArray(children);\n const needsPanelProps = childList.some((child) => {\n if (!isJsxElement(child)) {\n return false;\n }\n\n const props = child.props as Record<string, unknown> | undefined;\n\n return (\n props?.active !== panelProps.active ||\n props?.collapseLabel !== panelProps.collapseLabel ||\n props?.onClose !== panelProps.onClose ||\n props?.open !== panelProps.open ||\n props?.panelId !== panelProps.panelId\n );\n });\n const keyedChildren = needsPanelProps\n ? childList.map((child, index) => {\n if (!isJsxElement(child)) {\n return child;\n }\n\n const props = child.props as Record<string, unknown> | undefined;\n\n if (\n props?.active === panelProps.active &&\n props?.collapseLabel === panelProps.collapseLabel &&\n props?.onClose === panelProps.onClose &&\n props?.open === panelProps.open &&\n props?.panelId === panelProps.panelId\n ) {\n return child;\n }\n\n return {\n ...child,\n key: child.key != null ? child.key : `${keyPrefix}-${index}`,\n props: {\n ...props,\n active: panelProps.active,\n collapseLabel: panelProps.collapseLabel,\n onClose: panelProps.onClose,\n open: panelProps.open,\n panelId: panelProps.panelId,\n },\n };\n })\n : childList;\n\n return (\n <For\n each={() => keyedChildren}\n by={(child, index) =>\n isJsxElement(child) && child.key != null ? String(child.key) : `${keyPrefix}-${index}`\n }\n >\n {(child) => child as never}\n </For>\n );\n}\n\nexport function ShellResponsiveWatcher<TBreakpoint extends string>(props: {\n breakpoint: TBreakpoint;\n isCollapsed: (breakpoint: TBreakpoint) => boolean;\n onExpand: () => void;\n onResize: (nextCollapsed: boolean) => void;\n}): JSX.Element | null {\n const { breakpoint, isCollapsed, onExpand, onResize } = props;\n\n resource(\n ({ signal }: { signal: AbortSignal }) => {\n const updateCollapsedState = () => {\n const nextCollapsed = isCollapsed(breakpoint);\n onResize(nextCollapsed);\n\n if (!nextCollapsed) {\n onExpand();\n }\n };\n\n updateCollapsedState();\n\n if (typeof window === \"undefined\") {\n return null;\n }\n\n window.addEventListener(\"resize\", updateCollapsedState);\n signal.addEventListener(\n \"abort\",\n () => {\n window.removeEventListener(\"resize\", updateCollapsedState);\n },\n { once: true },\n );\n\n return null;\n },\n [breakpoint],\n );\n\n return null;\n}\n\nexport function ShellPanelWatcher(props: {\n contentId?: string;\n onClose: () => void;\n open: boolean;\n panelSlot: string;\n}): JSX.Element | null {\n const { contentId, onClose, open, panelSlot } = props;\n\n resource(\n ({ signal }: { signal: AbortSignal }) => {\n if (!open || typeof window === \"undefined\") {\n releaseShellScrollLock();\n return null;\n }\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") {\n return;\n }\n\n event.preventDefault();\n onClose();\n };\n\n window.addEventListener(\"keydown\", onKeyDown);\n\n const focusFrame =\n typeof window.requestAnimationFrame === \"function\"\n ? window.requestAnimationFrame(() => {\n const content =\n (typeof contentId === \"string\" ? document.getElementById(contentId) : null) ??\n document.querySelector<HTMLElement>(\n `[data-slot=\"${panelSlot}\"][data-state=\"open\"]`,\n );\n\n content?.focus({ preventScroll: true });\n })\n : undefined;\n\n acquireShellScrollLock();\n\n signal.addEventListener(\n \"abort\",\n () => {\n window.removeEventListener(\"keydown\", onKeyDown);\n\n if (focusFrame !== undefined && typeof window.cancelAnimationFrame === \"function\") {\n window.cancelAnimationFrame(focusFrame);\n }\n\n releaseShellScrollLock();\n },\n { once: true },\n );\n\n return null;\n },\n [open],\n );\n\n return null;\n}\n"],"mappings":"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"}
@@ -2,37 +2,27 @@ import { renderShellPanel } from "../shell/shell-panel.js";
2
2
  import { SidebarResponsiveContext } from "./sidebar.context.js";
3
3
  import { readContext } from "@askrjs/askr";
4
4
  //#region src/components/sidebar/sidebar-panel.tsx
5
+ const DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT = {
6
+ active: () => false,
7
+ collapseLabel: () => "Menu",
8
+ closePanel: () => void 0,
9
+ iconCollapsed: () => false,
10
+ isRailCollapsible: () => false,
11
+ orientation: () => "vertical",
12
+ panelId: () => void 0,
13
+ panelOpen: () => false,
14
+ togglePanel: () => void 0,
15
+ toggleRail: () => void 0
16
+ };
5
17
  function SidebarPanel(props) {
6
18
  const { active: activeProp, brand, children, class: className, collapseLabel: collapseLabelProp, onClose, open: openProp, panelId: panelIdProp, ref, ...rest } = props;
7
19
  const responsive = activeProp === void 0 || collapseLabelProp === void 0 || onClose === void 0 || openProp === void 0 || panelIdProp === void 0 ? (() => {
8
20
  try {
9
21
  return readContext(SidebarResponsiveContext);
10
22
  } catch {
11
- return {
12
- active: () => false,
13
- collapseLabel: () => "Menu",
14
- closePanel: () => void 0,
15
- iconCollapsed: () => false,
16
- isRailCollapsible: () => false,
17
- orientation: () => "vertical",
18
- panelId: () => void 0,
19
- panelOpen: () => false,
20
- togglePanel: () => void 0,
21
- toggleRail: () => void 0
22
- };
23
+ return DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT;
23
24
  }
24
- })() : {
25
- active: () => false,
26
- collapseLabel: () => "Menu",
27
- closePanel: () => void 0,
28
- iconCollapsed: () => false,
29
- isRailCollapsible: () => false,
30
- orientation: () => "vertical",
31
- panelId: () => void 0,
32
- panelOpen: () => false,
33
- togglePanel: () => void 0,
34
- toggleRail: () => void 0
35
- };
25
+ })() : DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT;
36
26
  const active = activeProp ?? responsive.active();
37
27
  const open = openProp ?? responsive.panelOpen();
38
28
  const panelId = panelIdProp ?? responsive.panelId();
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-panel.js","names":[],"sources":["../../../src/components/sidebar/sidebar-panel.tsx"],"sourcesContent":["import { readContext } from \"@askrjs/askr\";\nimport { renderShellPanel } from \"../shell/shell-panel\";\nimport { SidebarResponsiveContext } from \"./sidebar.context\";\nimport type { SidebarPanelProps } from \"./sidebar.types\";\n\nexport function SidebarPanel(props: SidebarPanelProps): JSX.Element | null {\n const {\n active: activeProp,\n brand,\n children,\n class: className,\n collapseLabel: collapseLabelProp,\n onClose,\n open: openProp,\n panelId: panelIdProp,\n ref,\n ...rest\n } = props;\n const needsResponsiveContext =\n activeProp === undefined ||\n collapseLabelProp === undefined ||\n onClose === undefined ||\n openProp === undefined ||\n panelIdProp === undefined;\n const responsive = needsResponsiveContext\n ? (() => {\n try {\n return readContext(SidebarResponsiveContext);\n } catch {\n return {\n active: () => false,\n collapseLabel: () => \"Menu\",\n closePanel: () => undefined,\n iconCollapsed: () => false,\n isRailCollapsible: () => false,\n orientation: () => \"vertical\" as const,\n panelId: () => undefined,\n panelOpen: () => false,\n togglePanel: () => undefined,\n toggleRail: () => undefined,\n };\n }\n })()\n : {\n active: () => false,\n collapseLabel: () => \"Menu\",\n closePanel: () => undefined,\n iconCollapsed: () => false,\n isRailCollapsible: () => false,\n orientation: () => \"vertical\" as const,\n panelId: () => undefined,\n panelOpen: () => false,\n togglePanel: () => undefined,\n toggleRail: () => undefined,\n };\n const active = activeProp ?? responsive.active();\n const open = openProp ?? responsive.panelOpen();\n const panelId = panelIdProp ?? responsive.panelId();\n const collapseLabel = collapseLabelProp ?? responsive.collapseLabel();\n const closePanel = onClose ?? responsive.closePanel;\n\n return renderShellPanel({\n active,\n brand,\n children,\n className,\n collapseLabel,\n dataOrientation: responsive.orientation(),\n onClose: closePanel,\n open,\n panelId,\n prefix: \"sidebar\",\n ref,\n rest,\n });\n}\n"],"mappings":";;;;AAKA,SAAgB,aAAa,OAA8C;CACzE,MAAM,EACJ,QAAQ,YACR,OACA,UACA,OAAO,WACP,eAAe,mBACf,SACA,MAAM,UACN,SAAS,aACT,KACA,GAAG,SACD;CAOJ,MAAM,aALJ,eAAe,KAAA,KACf,sBAAsB,KAAA,KACtB,YAAY,KAAA,KACZ,aAAa,KAAA,KACb,gBAAgB,KAAA,WAEP;EACL,IAAI;GACF,OAAO,YAAY,wBAAwB;EAC7C,QAAQ;GACN,OAAO;IACL,cAAc;IACd,qBAAqB;IACrB,kBAAkB,KAAA;IAClB,qBAAqB;IACrB,yBAAyB;IACzB,mBAAmB;IACnB,eAAe,KAAA;IACf,iBAAiB;IACjB,mBAAmB,KAAA;IACnB,kBAAkB,KAAA;GACpB;EACF;CACF,GAAG,IACH;EACE,cAAc;EACd,qBAAqB;EACrB,kBAAkB,KAAA;EAClB,qBAAqB;EACrB,yBAAyB;EACzB,mBAAmB;EACnB,eAAe,KAAA;EACf,iBAAiB;EACjB,mBAAmB,KAAA;EACnB,kBAAkB,KAAA;CACpB;CACJ,MAAM,SAAS,cAAc,WAAW,OAAO;CAC/C,MAAM,OAAO,YAAY,WAAW,UAAU;CAC9C,MAAM,UAAU,eAAe,WAAW,QAAQ;CAClD,MAAM,gBAAgB,qBAAqB,WAAW,cAAc;CACpE,MAAM,aAAa,WAAW,WAAW;CAEzC,OAAO,iBAAiB;EACtB;EACA;EACA;EACA;EACA;EACA,iBAAiB,WAAW,YAAY;EACxC,SAAS;EACT;EACA;EACA,QAAQ;EACR;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"sidebar-panel.js","names":[],"sources":["../../../src/components/sidebar/sidebar-panel.tsx"],"sourcesContent":["import { readContext } from \"@askrjs/askr\";\nimport { renderShellPanel } from \"../shell/shell-panel\";\nimport { SidebarResponsiveContext } from \"./sidebar.context\";\nimport type { SidebarPanelProps } from \"./sidebar.types\";\n\nconst DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT = {\n active: () => false,\n collapseLabel: () => \"Menu\",\n closePanel: () => undefined,\n iconCollapsed: () => false,\n isRailCollapsible: () => false,\n orientation: () => \"vertical\" as const,\n panelId: () => undefined,\n panelOpen: () => false,\n togglePanel: () => undefined,\n toggleRail: () => undefined,\n};\n\nexport function SidebarPanel(props: SidebarPanelProps): JSX.Element | null {\n const {\n active: activeProp,\n brand,\n children,\n class: className,\n collapseLabel: collapseLabelProp,\n onClose,\n open: openProp,\n panelId: panelIdProp,\n ref,\n ...rest\n } = props;\n const needsResponsiveContext =\n activeProp === undefined ||\n collapseLabelProp === undefined ||\n onClose === undefined ||\n openProp === undefined ||\n panelIdProp === undefined;\n const responsive = needsResponsiveContext\n ? (() => {\n try {\n return readContext(SidebarResponsiveContext);\n } catch {\n return DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT;\n }\n })()\n : DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT;\n const active = activeProp ?? responsive.active();\n const open = openProp ?? responsive.panelOpen();\n const panelId = panelIdProp ?? responsive.panelId();\n const collapseLabel = collapseLabelProp ?? responsive.collapseLabel();\n const closePanel = onClose ?? responsive.closePanel;\n\n return renderShellPanel({\n active,\n brand,\n children,\n className,\n collapseLabel,\n dataOrientation: responsive.orientation(),\n onClose: closePanel,\n open,\n panelId,\n prefix: \"sidebar\",\n ref,\n rest,\n });\n}\n"],"mappings":";;;;AAKA,MAAM,qCAAqC;CACzC,cAAc;CACd,qBAAqB;CACrB,kBAAkB,KAAA;CAClB,qBAAqB;CACrB,yBAAyB;CACzB,mBAAmB;CACnB,eAAe,KAAA;CACf,iBAAiB;CACjB,mBAAmB,KAAA;CACnB,kBAAkB,KAAA;AACpB;AAEA,SAAgB,aAAa,OAA8C;CACzE,MAAM,EACJ,QAAQ,YACR,OACA,UACA,OAAO,WACP,eAAe,mBACf,SACA,MAAM,UACN,SAAS,aACT,KACA,GAAG,SACD;CAOJ,MAAM,aALJ,eAAe,KAAA,KACf,sBAAsB,KAAA,KACtB,YAAY,KAAA,KACZ,aAAa,KAAA,KACb,gBAAgB,KAAA,WAEP;EACL,IAAI;GACF,OAAO,YAAY,wBAAwB;EAC7C,QAAQ;GACN,OAAO;EACT;CACF,EAAA,CAAG,IACH;CACJ,MAAM,SAAS,cAAc,WAAW,OAAO;CAC/C,MAAM,OAAO,YAAY,WAAW,UAAU;CAC9C,MAAM,UAAU,eAAe,WAAW,QAAQ;CAClD,MAAM,gBAAgB,qBAAqB,WAAW,cAAc;CACpE,MAAM,aAAa,WAAW,WAAW;CAEzC,OAAO,iBAAiB;EACtB;EACA;EACA;EACA;EACA;EACA,iBAAiB,WAAW,YAAY;EACxC,SAAS;EACT;EACA;EACA,QAAQ;EACR;EACA;CACF,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"spacer.js","names":[],"sources":["../../../src/components/spacer/spacer.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport { isCssLength, mergeLayoutStyles } from \"../_internal/layout\";\nimport { styleDeclarationsToClass } from \"../_internal/style\";\nimport { isJsxElement, toChildArray } from \"../_internal/jsx\";\nimport type { SpacerAsChildProps, SpacerNativeProps } from \"./spacer.types\";\n\nexport function Spacer(props: SpacerNativeProps): JSX.Element;\nexport function Spacer(props: SpacerAsChildProps): JSX.Element;\nexport function Spacer(props: SpacerNativeProps | SpacerAsChildProps) {\n const { asChild, children, grow, shrink, basis, axis, ref, style: userStyle, ...rest } = props;\n\n const layoutStyle: Record<string, string | number> = {};\n\n if (axis === \"inline\") {\n if (shrink !== undefined && shrink !== 0) {\n layoutStyle.flexShrink = shrink;\n }\n if (isCssLength(basis)) layoutStyle.width = basis!;\n } else if (axis === \"block\") {\n if (shrink !== undefined && shrink !== 0) {\n layoutStyle.flexShrink = shrink;\n }\n if (isCssLength(basis)) layoutStyle.height = basis!;\n } else {\n if (grow !== undefined && grow !== 1) {\n layoutStyle.flexGrow = grow;\n }\n if (shrink !== undefined && shrink !== 1) {\n layoutStyle.flexShrink = shrink;\n }\n if (isCssLength(basis)) {\n layoutStyle.flexBasis = basis!;\n }\n }\n\n const layoutClass = styleDeclarationsToClass(mergeLayoutStyles(layoutStyle, userStyle));\n\n const finalProps = mergeProps(rest, {\n ref,\n \"data-slot\": \"spacer\",\n \"data-axis\": axis,\n ...(layoutClass ? { class: layoutClass } : {}),\n });\n const keyedChildren = toChildArray(children).map((child, index) => {\n if (!isJsxElement(child) || child.key != null) {\n return child;\n }\n\n return {\n ...child,\n key: `spacer-${index}`,\n };\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <div {...finalProps}>{keyedChildren}</div>;\n}\n"],"mappings":";;;;;;;AASA,SAAgB,OAAO,OAA+C;CACpE,MAAM,EAAE,SAAS,UAAU,MAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,WAAW,GAAG,SAAS;CAEzF,MAAM,cAA+C,CAAC;CAEtD,IAAI,SAAS,UAAU;EACrB,IAAI,WAAW,KAAA,KAAa,WAAW,GACrC,YAAY,aAAa;EAE3B,IAAI,YAAY,KAAK,GAAG,YAAY,QAAQ;CAC9C,OAAO,IAAI,SAAS,SAAS;EAC3B,IAAI,WAAW,KAAA,KAAa,WAAW,GACrC,YAAY,aAAa;EAE3B,IAAI,YAAY,KAAK,GAAG,YAAY,SAAS;CAC/C,OAAO;EACL,IAAI,SAAS,KAAA,KAAa,SAAS,GACjC,YAAY,WAAW;EAEzB,IAAI,WAAW,KAAA,KAAa,WAAW,GACrC,YAAY,aAAa;EAE3B,IAAI,YAAY,KAAK,GACnB,YAAY,YAAY;CAE5B;CAEA,MAAM,cAAc,yBAAyB,kBAAkB,aAAa,SAAS,CAAC;CAEtF,MAAM,aAAa,WAAW,MAAM;EAClC;EACA,aAAa;EACb,aAAa;EACb,GAAI,cAAc,EAAE,OAAO,YAAY,IAAI,CAAC;CAC9C,CAAC;CACD,MAAM,gBAAgB,aAAa,QAAQ,EAAE,KAAK,OAAO,UAAU;EACjE,IAAI,CAAC,aAAa,KAAK,KAAK,MAAM,OAAO,MACvC,OAAO;EAGT,OAAO;GACL,GAAG;GACH,KAAK,UAAU;EACjB;CACF,CAAC;CAED,IAAI,SACF,OAAO,oBAAC,MAAD;EAAM,SAAA;EAAQ,GAAI;EAAsB;CAAW,CAAA;CAG5D,OAAO,oBAAC,OAAD;EAAK,GAAI;YAAa;CAAmB,CAAA;AAClD"}
1
+ {"version":3,"file":"spacer.js","names":[],"sources":["../../../src/components/spacer/spacer.tsx"],"sourcesContent":["import { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport { isCssLength, mergeLayoutStyles } from \"../_internal/layout\";\nimport { styleDeclarationsToClass } from \"../_internal/style\";\nimport { isJsxElement, toChildArray } from \"../_internal/jsx\";\nimport type { SpacerAsChildProps, SpacerNativeProps } from \"./spacer.types\";\n\nexport function Spacer(props: SpacerNativeProps): JSX.Element;\nexport function Spacer(props: SpacerAsChildProps): JSX.Element;\nexport function Spacer(props: SpacerNativeProps | SpacerAsChildProps) {\n const { asChild, children, grow, shrink, basis, axis, ref, style: userStyle, ...rest } = props;\n\n const layoutStyle: Record<string, string | number> = {};\n\n if (axis === \"inline\") {\n if (shrink !== undefined && shrink !== 0) {\n layoutStyle.flexShrink = shrink;\n }\n if (isCssLength(basis)) layoutStyle.width = basis!;\n } else if (axis === \"block\") {\n if (shrink !== undefined && shrink !== 0) {\n layoutStyle.flexShrink = shrink;\n }\n if (isCssLength(basis)) layoutStyle.height = basis!;\n } else {\n if (grow !== undefined && grow !== 1) {\n layoutStyle.flexGrow = grow;\n }\n if (shrink !== undefined && shrink !== 1) {\n layoutStyle.flexShrink = shrink;\n }\n if (isCssLength(basis)) {\n layoutStyle.flexBasis = basis!;\n }\n }\n\n const layoutClass = styleDeclarationsToClass(mergeLayoutStyles(layoutStyle, userStyle));\n\n const finalProps = mergeProps(rest, {\n ref,\n \"data-slot\": \"spacer\",\n \"data-axis\": axis,\n ...(layoutClass ? { class: layoutClass } : {}),\n });\n const keyedChildren = toChildArray(children).map((child, index) => {\n if (!isJsxElement(child) || child.key != null) {\n return child;\n }\n\n return {\n ...child,\n key: `spacer-${index}`,\n };\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <div {...finalProps}>{keyedChildren}</div>;\n}\n"],"mappings":";;;;;;;AASA,SAAgB,OAAO,OAA+C;CACpE,MAAM,EAAE,SAAS,UAAU,MAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,WAAW,GAAG,SAAS;CAEzF,MAAM,cAA+C,CAAC;CAEtD,IAAI,SAAS,UAAU;EACrB,IAAI,WAAW,KAAA,KAAa,WAAW,GACrC,YAAY,aAAa;EAE3B,IAAI,YAAY,KAAK,GAAG,YAAY,QAAQ;CAC9C,OAAO,IAAI,SAAS,SAAS;EAC3B,IAAI,WAAW,KAAA,KAAa,WAAW,GACrC,YAAY,aAAa;EAE3B,IAAI,YAAY,KAAK,GAAG,YAAY,SAAS;CAC/C,OAAO;EACL,IAAI,SAAS,KAAA,KAAa,SAAS,GACjC,YAAY,WAAW;EAEzB,IAAI,WAAW,KAAA,KAAa,WAAW,GACrC,YAAY,aAAa;EAE3B,IAAI,YAAY,KAAK,GACnB,YAAY,YAAY;CAE5B;CAEA,MAAM,cAAc,yBAAyB,kBAAkB,aAAa,SAAS,CAAC;CAEtF,MAAM,aAAa,WAAW,MAAM;EAClC;EACA,aAAa;EACb,aAAa;EACb,GAAI,cAAc,EAAE,OAAO,YAAY,IAAI,CAAC;CAC9C,CAAC;CACD,MAAM,gBAAgB,aAAa,QAAQ,CAAC,CAAC,KAAK,OAAO,UAAU;EACjE,IAAI,CAAC,aAAa,KAAK,KAAK,MAAM,OAAO,MACvC,OAAO;EAGT,OAAO;GACL,GAAG;GACH,KAAK,UAAU;EACjB;CACF,CAAC;CAED,IAAI,SACF,OAAO,oBAAC,MAAD;EAAM,SAAA;EAAQ,GAAI;EAAsB;CAAW,CAAA;CAG5D,OAAO,oBAAC,OAAD;EAAK,GAAI;YAAa;CAAmB,CAAA;AAClD"}
@@ -59,6 +59,7 @@ function useTheme() {
59
59
  function ThemeProvider(props) {
60
60
  const { children, defaultTheme = "system", themes = DEFAULT_THEME_OPTIONS, storageKey = DEFAULT_STORAGE_KEY } = props;
61
61
  const themeState = state(readStoredTheme(storageKey) ?? defaultTheme);
62
+ const currentTheme = themeState();
62
63
  const setTheme = (nextTheme) => {
63
64
  themeState.set(nextTheme);
64
65
  writeStoredTheme(storageKey, nextTheme);
@@ -70,7 +71,6 @@ function ThemeProvider(props) {
70
71
  themes,
71
72
  storageKey
72
73
  };
73
- const currentTheme = themeState();
74
74
  return /* @__PURE__ */ jsxs(ThemeContext.Scope, {
75
75
  value,
76
76
  children: [/* @__PURE__ */ jsx(ThemeRootSync, { theme: currentTheme }), /* @__PURE__ */ jsx("div", {
@@ -140,7 +140,10 @@ function ThemeToggle(props) {
140
140
  onPress?.(event);
141
141
  if (!event.defaultPrevented) theme.setTheme(nextTheme);
142
142
  },
143
- children: content
143
+ children: /* @__PURE__ */ jsx("span", {
144
+ "data-slot": "theme-toggle-content",
145
+ children: content
146
+ })
144
147
  });
145
148
  }
146
149
  function getNextTheme(currentTheme, themes) {
@@ -161,9 +164,11 @@ function isJSXElement(value) {
161
164
  }
162
165
  function cloneThemeToggleIcon(icon) {
163
166
  if (!isJSXElement(icon)) return icon;
167
+ const props = icon.props;
168
+ if (!props || Object.keys(props).length === 0) return icon;
164
169
  return {
165
170
  ...icon,
166
- props: { ...icon.props }
171
+ props: { ...props }
167
172
  };
168
173
  }
169
174
  function syncThemeRoot(themeChoice) {
@@ -1 +1 @@
1
- {"version":3,"file":"theme.js","names":[],"sources":["../../../src/components/theme/theme.tsx"],"sourcesContent":["import { defineContext, readContext, state } from \"@askrjs/askr\";\nimport type { JSXElement } from \"@askrjs/askr/foundations/structures\";\nimport { resource } from \"@askrjs/askr/resources\";\nimport { Button } from \"@askrjs/ui\";\nimport type { ButtonNativeProps, PressEvent } from \"@askrjs/ui\";\n\nexport const CAT_THEME_NAMES = [\"tabby\", \"ginger\", \"tuxedo\", \"calico\", \"torty\"] as const;\n\nexport type CatThemeName = (typeof CAT_THEME_NAMES)[number];\nexport type ThemeName = \"light\" | \"dark\" | \"system\" | CatThemeName | (string & {});\n\nexport type ThemeOption = {\n value: ThemeName;\n label: string;\n};\n\nexport type ThemeContextValue = {\n theme: () => ThemeName;\n setTheme: (theme: ThemeName) => void;\n themes: readonly ThemeOption[];\n storageKey: string;\n};\n\nexport type ThemeProviderProps = {\n children?: unknown;\n defaultTheme?: ThemeName;\n themes?: readonly ThemeOption[];\n storageKey?: string;\n};\n\nexport type ThemePickerProps = Omit<\n JSX.IntrinsicElements[\"select\"],\n \"children\" | \"value\" | \"defaultValue\" | \"onChange\"\n> & {\n themes?: readonly ThemeOption[];\n label?: string;\n};\n\nexport type ThemeToggleRenderContext = {\n theme: ThemeName;\n nextTheme: ThemeName;\n};\n\nexport type ThemeToggleProps = Omit<ButtonNativeProps, \"children\" | \"onPress\"> & {\n children?: unknown | ((context: ThemeToggleRenderContext) => unknown);\n lightIcon?: unknown;\n darkIcon?: unknown;\n systemIcon?: unknown;\n themes?: readonly ThemeName[];\n onPress?: (event: PressEvent) => void;\n};\n\nexport const DEFAULT_THEME_OPTIONS: readonly ThemeOption[] = [\n { value: \"system\", label: \"System\" },\n { value: \"light\", label: \"Light\" },\n { value: \"dark\", label: \"Dark\" },\n];\n\nexport const CAT_THEME_OPTIONS: readonly ThemeOption[] = [\n { value: \"tabby\", label: \"Tabby\" },\n { value: \"ginger\", label: \"Ginger\" },\n { value: \"tuxedo\", label: \"Tuxedo\" },\n { value: \"calico\", label: \"Calico\" },\n { value: \"torty\", label: \"Torty\" },\n];\n\nconst DEFAULT_STORAGE_KEY = \"askr-theme\";\n\nconst ThemeContext = defineContext<ThemeContextValue>({\n theme: () => \"system\",\n setTheme: () => undefined,\n themes: DEFAULT_THEME_OPTIONS,\n storageKey: DEFAULT_STORAGE_KEY,\n});\n\nexport function useTheme(): ThemeContextValue {\n return readContext(ThemeContext);\n}\n\nexport function ThemeProvider(props: ThemeProviderProps): JSX.Element {\n const {\n children,\n defaultTheme = \"system\",\n themes = DEFAULT_THEME_OPTIONS,\n storageKey = DEFAULT_STORAGE_KEY,\n } = props;\n\n const themeState = state<ThemeName>(readStoredTheme(storageKey) ?? defaultTheme);\n\n const setTheme = (nextTheme: ThemeName) => {\n themeState.set(nextTheme);\n writeStoredTheme(storageKey, nextTheme);\n syncThemeRoot(nextTheme);\n };\n\n const value: ThemeContextValue = {\n theme: themeState,\n setTheme,\n themes,\n storageKey,\n };\n\n const currentTheme = themeState();\n\n return (\n <ThemeContext.Scope value={value}>\n <ThemeRootSync theme={currentTheme} />\n <div data-slot=\"theme-provider\">{children}</div>\n </ThemeContext.Scope>\n );\n}\n\nfunction ThemeRootSync(props: { theme: ThemeName }): JSX.Element | null {\n const { theme } = props;\n\n resource(\n ({ signal }: { signal: AbortSignal }) => {\n if (typeof window === \"undefined\") {\n syncThemeRoot(theme);\n return null;\n }\n\n const timeoutId = window.setTimeout(() => {\n if (!signal.aborted) {\n syncThemeRoot(theme);\n }\n }, 0);\n\n signal.addEventListener(\n \"abort\",\n () => {\n window.clearTimeout(timeoutId);\n },\n { once: true },\n );\n\n return null;\n },\n [theme],\n );\n\n return null;\n}\n\nexport function ThemePicker(props: ThemePickerProps): JSX.Element {\n const theme = useTheme();\n const { themes = theme.themes, label = \"Theme\", ...rest } = props;\n\n return (\n <select\n {...rest}\n aria-label={rest[\"aria-label\"] ?? label}\n data-slot=\"theme-picker\"\n value={theme.theme()}\n onChange={(event: Event) => {\n const target = event.currentTarget as HTMLSelectElement;\n theme.setTheme(target.value as ThemeName);\n }}\n >\n {themes.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n );\n}\n\nexport function ThemeToggle(props: ThemeToggleProps): JSX.Element {\n const theme = useTheme();\n const {\n children,\n lightIcon,\n darkIcon,\n systemIcon,\n themes = [\"light\", \"dark\"],\n onPress,\n ...rest\n } = props;\n\n const currentTheme = theme.theme();\n const nextTheme = getNextTheme(currentTheme, themes);\n const renderContext = { theme: currentTheme, nextTheme };\n const ariaLabel = (rest as Record<string, unknown>)[\"aria-label\"];\n const themedIcon = resolveThemeToggleIcon(currentTheme, nextTheme, {\n lightIcon,\n darkIcon,\n systemIcon,\n });\n const renderedIcon = cloneThemeToggleIcon(themedIcon);\n const content =\n typeof children === \"function\" ? children(renderContext) : (children ?? renderedIcon);\n\n return (\n <Button\n {...(rest as ButtonNativeProps)}\n aria-label={typeof ariaLabel === \"string\" ? ariaLabel : `Switch to ${nextTheme} theme`}\n data-theme-control=\"toggle\"\n data-theme-choice={currentTheme}\n data-next-theme={nextTheme}\n onPress={(event) => {\n onPress?.(event);\n if (!event.defaultPrevented) theme.setTheme(nextTheme);\n }}\n >\n {content}\n </Button>\n );\n}\n\nfunction getNextTheme(currentTheme: ThemeName, themes: readonly ThemeName[]): ThemeName {\n if (themes.length === 0) return currentTheme;\n const index = themes.indexOf(currentTheme);\n return themes[index >= 0 && index < themes.length - 1 ? index + 1 : 0]!;\n}\n\nfunction getThemeIcon(\n theme: ThemeName,\n icons: Pick<ThemeToggleProps, \"lightIcon\" | \"darkIcon\" | \"systemIcon\">,\n): unknown {\n if (theme === \"light\") return icons.lightIcon;\n if (theme === \"dark\") return icons.darkIcon;\n if (theme === \"system\") return icons.systemIcon;\n return undefined;\n}\n\nexport function resolveThemeToggleIcon(\n theme: ThemeName,\n nextTheme: ThemeName,\n icons: Pick<ThemeToggleProps, \"lightIcon\" | \"darkIcon\" | \"systemIcon\">,\n): unknown {\n return getThemeIcon(theme, icons) ?? getThemeIcon(nextTheme, icons);\n}\n\nfunction isJSXElement(value: unknown): value is JSXElement {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"$$typeof\" in value &&\n \"type\" in value &&\n \"props\" in value\n );\n}\n\nfunction cloneThemeToggleIcon(icon: unknown): unknown {\n if (!isJSXElement(icon)) return icon;\n\n return {\n ...icon,\n props: { ...(icon.props as Record<string, unknown> | undefined) },\n };\n}\n\nfunction syncThemeRoot(themeChoice: ThemeName | null | undefined): void {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const html = document.documentElement;\n\n if (themeChoice == null) {\n html.removeAttribute(\"data-theme\");\n html.removeAttribute(\"data-theme-choice\");\n return;\n }\n\n html.setAttribute(\"data-theme-choice\", themeChoice);\n\n if (themeChoice === \"system\") {\n html.removeAttribute(\"data-theme\");\n } else {\n html.setAttribute(\"data-theme\", themeChoice);\n }\n}\n\nfunction readStoredTheme(storageKey: string): ThemeName | undefined {\n if (typeof window === \"undefined\") return undefined;\n try {\n return (window.localStorage.getItem(storageKey) as ThemeName | null) ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction writeStoredTheme(storageKey: string, theme: ThemeName): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(storageKey, theme);\n } catch {\n // Storage can be unavailable in private or locked-down browser contexts.\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"theme.js","names":[],"sources":["../../../src/components/theme/theme.tsx"],"sourcesContent":["import { defineContext, readContext, state } from \"@askrjs/askr\";\nimport type { JSXElement } from \"@askrjs/askr/foundations/structures\";\nimport { resource } from \"@askrjs/askr/resources\";\nimport { Button } from \"@askrjs/ui\";\nimport type { ButtonNativeProps, PressEvent } from \"@askrjs/ui\";\n\nexport const CAT_THEME_NAMES = [\"tabby\", \"ginger\", \"tuxedo\", \"calico\", \"torty\"] as const;\n\nexport type CatThemeName = (typeof CAT_THEME_NAMES)[number];\nexport type ThemeName = \"light\" | \"dark\" | \"system\" | CatThemeName | (string & {});\n\nexport type ThemeOption = {\n value: ThemeName;\n label: string;\n};\n\nexport type ThemeContextValue = {\n theme: () => ThemeName;\n setTheme: (theme: ThemeName) => void;\n themes: readonly ThemeOption[];\n storageKey: string;\n};\n\nexport type ThemeProviderProps = {\n children?: unknown;\n defaultTheme?: ThemeName;\n themes?: readonly ThemeOption[];\n storageKey?: string;\n};\n\nexport type ThemePickerProps = Omit<\n JSX.IntrinsicElements[\"select\"],\n \"children\" | \"value\" | \"defaultValue\" | \"onChange\"\n> & {\n themes?: readonly ThemeOption[];\n label?: string;\n};\n\nexport type ThemeToggleRenderContext = {\n theme: ThemeName;\n nextTheme: ThemeName;\n};\n\nexport type ThemeToggleProps = Omit<ButtonNativeProps, \"children\" | \"onPress\"> & {\n children?: unknown | ((context: ThemeToggleRenderContext) => unknown);\n lightIcon?: unknown;\n darkIcon?: unknown;\n systemIcon?: unknown;\n themes?: readonly ThemeName[];\n onPress?: (event: PressEvent) => void;\n};\n\nexport const DEFAULT_THEME_OPTIONS: readonly ThemeOption[] = [\n { value: \"system\", label: \"System\" },\n { value: \"light\", label: \"Light\" },\n { value: \"dark\", label: \"Dark\" },\n];\n\nexport const CAT_THEME_OPTIONS: readonly ThemeOption[] = [\n { value: \"tabby\", label: \"Tabby\" },\n { value: \"ginger\", label: \"Ginger\" },\n { value: \"tuxedo\", label: \"Tuxedo\" },\n { value: \"calico\", label: \"Calico\" },\n { value: \"torty\", label: \"Torty\" },\n];\n\nconst DEFAULT_STORAGE_KEY = \"askr-theme\";\n\nconst ThemeContext = defineContext<ThemeContextValue>({\n theme: () => \"system\",\n setTheme: () => undefined,\n themes: DEFAULT_THEME_OPTIONS,\n storageKey: DEFAULT_STORAGE_KEY,\n});\n\nexport function useTheme(): ThemeContextValue {\n return readContext(ThemeContext);\n}\n\nexport function ThemeProvider(props: ThemeProviderProps): JSX.Element {\n const {\n children,\n defaultTheme = \"system\",\n themes = DEFAULT_THEME_OPTIONS,\n storageKey = DEFAULT_STORAGE_KEY,\n } = props;\n\n const themeState = state<ThemeName>(readStoredTheme(storageKey) ?? defaultTheme);\n const currentTheme = themeState();\n\n const setTheme = (nextTheme: ThemeName) => {\n themeState.set(nextTheme);\n writeStoredTheme(storageKey, nextTheme);\n syncThemeRoot(nextTheme);\n };\n\n const value: ThemeContextValue = {\n theme: themeState,\n setTheme,\n themes,\n storageKey,\n };\n\n return (\n <ThemeContext.Scope value={value}>\n <ThemeRootSync theme={currentTheme} />\n <div data-slot=\"theme-provider\">{children}</div>\n </ThemeContext.Scope>\n );\n}\n\nfunction ThemeRootSync(props: { theme: ThemeName }): JSX.Element | null {\n const { theme } = props;\n\n resource(\n ({ signal }: { signal: AbortSignal }) => {\n if (typeof window === \"undefined\") {\n syncThemeRoot(theme);\n return null;\n }\n\n const timeoutId = window.setTimeout(() => {\n if (!signal.aborted) {\n syncThemeRoot(theme);\n }\n }, 0);\n\n signal.addEventListener(\n \"abort\",\n () => {\n window.clearTimeout(timeoutId);\n },\n { once: true },\n );\n\n return null;\n },\n [theme],\n );\n\n return null;\n}\n\nexport function ThemePicker(props: ThemePickerProps): JSX.Element {\n const theme = useTheme();\n const { themes = theme.themes, label = \"Theme\", ...rest } = props;\n\n return (\n <select\n {...rest}\n aria-label={rest[\"aria-label\"] ?? label}\n data-slot=\"theme-picker\"\n value={theme.theme()}\n onChange={(event: Event) => {\n const target = event.currentTarget as HTMLSelectElement;\n theme.setTheme(target.value as ThemeName);\n }}\n >\n {themes.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n );\n}\n\nexport function ThemeToggle(props: ThemeToggleProps): JSX.Element {\n const theme = useTheme();\n const {\n children,\n lightIcon,\n darkIcon,\n systemIcon,\n themes = [\"light\", \"dark\"],\n onPress,\n ...rest\n } = props;\n\n const currentTheme = theme.theme();\n const nextTheme = getNextTheme(currentTheme, themes);\n const renderContext = { theme: currentTheme, nextTheme };\n const ariaLabel = (rest as Record<string, unknown>)[\"aria-label\"];\n const themedIcon = resolveThemeToggleIcon(currentTheme, nextTheme, {\n lightIcon,\n darkIcon,\n systemIcon,\n });\n const renderedIcon = cloneThemeToggleIcon(themedIcon);\n const content =\n typeof children === \"function\" ? children(renderContext) : (children ?? renderedIcon);\n\n return (\n <Button\n {...(rest as ButtonNativeProps)}\n aria-label={typeof ariaLabel === \"string\" ? ariaLabel : `Switch to ${nextTheme} theme`}\n data-theme-control=\"toggle\"\n data-theme-choice={currentTheme}\n data-next-theme={nextTheme}\n onPress={(event) => {\n onPress?.(event);\n if (!event.defaultPrevented) theme.setTheme(nextTheme);\n }}\n >\n <span data-slot=\"theme-toggle-content\">{content}</span>\n </Button>\n );\n}\n\nfunction getNextTheme(currentTheme: ThemeName, themes: readonly ThemeName[]): ThemeName {\n if (themes.length === 0) return currentTheme;\n const index = themes.indexOf(currentTheme);\n return themes[index >= 0 && index < themes.length - 1 ? index + 1 : 0]!;\n}\n\nfunction getThemeIcon(\n theme: ThemeName,\n icons: Pick<ThemeToggleProps, \"lightIcon\" | \"darkIcon\" | \"systemIcon\">,\n): unknown {\n if (theme === \"light\") return icons.lightIcon;\n if (theme === \"dark\") return icons.darkIcon;\n if (theme === \"system\") return icons.systemIcon;\n return undefined;\n}\n\nexport function resolveThemeToggleIcon(\n theme: ThemeName,\n nextTheme: ThemeName,\n icons: Pick<ThemeToggleProps, \"lightIcon\" | \"darkIcon\" | \"systemIcon\">,\n): unknown {\n return getThemeIcon(theme, icons) ?? getThemeIcon(nextTheme, icons);\n}\n\nfunction isJSXElement(value: unknown): value is JSXElement {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"$$typeof\" in value &&\n \"type\" in value &&\n \"props\" in value\n );\n}\n\nfunction cloneThemeToggleIcon(icon: unknown): unknown {\n if (!isJSXElement(icon)) return icon;\n\n const props = icon.props as Record<string, unknown> | undefined;\n if (!props || Object.keys(props).length === 0) {\n return icon;\n }\n\n return {\n ...icon,\n props: { ...props },\n };\n}\n\nfunction syncThemeRoot(themeChoice: ThemeName | null | undefined): void {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const html = document.documentElement;\n\n if (themeChoice == null) {\n html.removeAttribute(\"data-theme\");\n html.removeAttribute(\"data-theme-choice\");\n return;\n }\n\n html.setAttribute(\"data-theme-choice\", themeChoice);\n\n if (themeChoice === \"system\") {\n html.removeAttribute(\"data-theme\");\n } else {\n html.setAttribute(\"data-theme\", themeChoice);\n }\n}\n\nfunction readStoredTheme(storageKey: string): ThemeName | undefined {\n if (typeof window === \"undefined\") return undefined;\n try {\n return (window.localStorage.getItem(storageKey) as ThemeName | null) ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction writeStoredTheme(storageKey: string, theme: ThemeName): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(storageKey, theme);\n } catch {\n // Storage can be unavailable in private or locked-down browser contexts.\n }\n}\n"],"mappings":"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"}
@@ -2628,6 +2628,22 @@
2628
2628
  display: inline-flex;
2629
2629
  }
2630
2630
 
2631
+ :where([data-slot="theme-toggle-content"]) {
2632
+ --_ak-theme-toggle-icon-size: var(--ak-theme-toggle-icon-size, var(--ak-icon-size, 1em));
2633
+ flex: none;
2634
+ justify-content: center;
2635
+ align-items: center;
2636
+ min-inline-size: 0;
2637
+ display: inline-flex;
2638
+ }
2639
+
2640
+ :where([data-slot="theme-toggle-content"]) > :where([data-slot="icon"], svg) {
2641
+ inline-size: var(--_ak-theme-toggle-icon-size);
2642
+ block-size: var(--_ak-theme-toggle-icon-size);
2643
+ color: currentColor;
2644
+ flex: none;
2645
+ }
2646
+
2631
2647
  :where(.btn) > :where([data-slot="icon"], svg), :where([data-slot="button"]) > :where([data-slot="icon"], svg) {
2632
2648
  color: currentColor;
2633
2649
  flex: none;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askrjs/themes",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Default theme tokens, styles, and themed layout wrappers for Askr apps.",
5
5
  "keywords": [
6
6
  "askr",
@@ -142,21 +142,22 @@
142
142
  "devDependencies": {
143
143
  "@askrjs/askr": ">=0.0.1 <0.1.0",
144
144
  "@askrjs/ui": ">=0.0.1 <0.1.0",
145
- "@askrjs/vite": ">=0.0.2 <0.1.0",
146
- "@tsdown/css": "0.22.2",
147
- "@types/node": "^25.9.2",
145
+ "@askrjs/vite": ">=0.0.1 <0.1.0",
146
+ "@tsdown/css": "0.22.3",
147
+ "@types/node": "^25.9.3",
148
+ "@vitest/browser-playwright": "^4.1.9",
148
149
  "cross-env": "^10.1.0",
149
150
  "jsdom": "^29.1.1",
150
- "playwright": "^1.60.0",
151
+ "playwright": "^1.61.0",
151
152
  "typescript": "^6.0.3",
152
- "vite-plus": "^0.1.24"
153
+ "vite-plus": "^0.2.0"
153
154
  },
154
155
  "peerDependencies": {
155
156
  "@askrjs/askr": ">=0.0.1 <0.1.0",
156
- "@askrjs/ui": ">=0.0.1 <0.1.0"
157
+ "@askrjs/ui": ">=0.0.10 <0.1.0"
157
158
  },
158
159
  "engines": {
159
160
  "node": ">=18"
160
161
  },
161
- "packageManager": "npm@11.16.0"
162
+ "packageManager": "npm@11.17.0"
162
163
  }
@@ -3,6 +3,15 @@ import { renderShellPanel } from "../shell/shell-panel";
3
3
  import { NavbarResponsiveContext } from "./navbar.context";
4
4
  import type { NavbarPanelProps } from "./navbar.types";
5
5
 
6
+ const DEFAULT_NAVBAR_RESPONSIVE_CONTEXT = {
7
+ active: () => false,
8
+ collapseLabel: () => "Menu",
9
+ closePanel: () => undefined,
10
+ panelId: () => undefined,
11
+ panelOpen: () => false,
12
+ togglePanel: () => undefined,
13
+ };
14
+
6
15
  export function NavbarPanel(props: NavbarPanelProps): JSX.Element | null {
7
16
  const {
8
17
  active: activeProp,
@@ -27,24 +36,10 @@ export function NavbarPanel(props: NavbarPanelProps): JSX.Element | null {
27
36
  try {
28
37
  return readContext(NavbarResponsiveContext);
29
38
  } catch {
30
- return {
31
- active: () => false,
32
- collapseLabel: () => "Menu",
33
- closePanel: () => undefined,
34
- panelId: () => undefined,
35
- panelOpen: () => false,
36
- togglePanel: () => undefined,
37
- };
39
+ return DEFAULT_NAVBAR_RESPONSIVE_CONTEXT;
38
40
  }
39
41
  })()
40
- : {
41
- active: () => false,
42
- collapseLabel: () => "Menu",
43
- closePanel: () => undefined,
44
- panelId: () => undefined,
45
- panelOpen: () => false,
46
- togglePanel: () => undefined,
47
- };
42
+ : DEFAULT_NAVBAR_RESPONSIVE_CONTEXT;
48
43
  const active = activeProp ?? responsive.active();
49
44
  const open = openProp ?? responsive.panelOpen();
50
45
  const panelId = panelIdProp ?? responsive.panelId();
@@ -47,16 +47,20 @@ export function isShellPanelChild(child: unknown, panelComponent: unknown): chil
47
47
  }
48
48
 
49
49
  export function renderKeyedShellChildren(children: unknown, keyPrefix: string): JSX.Element {
50
- const keyedChildren = toChildArray(children).map((child, index) => {
51
- if (!isJsxElement(child) || child.key != null) {
52
- return child;
53
- }
50
+ const childList = toChildArray(children);
51
+ const needsKeying = childList.some((child) => isJsxElement(child) && child.key == null);
52
+ const keyedChildren = needsKeying
53
+ ? childList.map((child, index) => {
54
+ if (!isJsxElement(child) || child.key != null) {
55
+ return child;
56
+ }
54
57
 
55
- return {
56
- ...child,
57
- key: `${keyPrefix}-${index}`,
58
- };
59
- });
58
+ return {
59
+ ...child,
60
+ key: `${keyPrefix}-${index}`,
61
+ };
62
+ })
63
+ : childList;
60
64
 
61
65
  return (
62
66
  <For
@@ -75,24 +79,54 @@ export function renderKeyedShellPanelChildren(
75
79
  keyPrefix: string,
76
80
  panelProps: ShellResponsivePanelProps,
77
81
  ): JSX.Element {
78
- const keyedChildren = toChildArray(children).map((child, index) => {
82
+ const childList = toChildArray(children);
83
+ const needsPanelProps = childList.some((child) => {
79
84
  if (!isJsxElement(child)) {
80
- return child;
85
+ return false;
81
86
  }
82
87
 
83
- return {
84
- ...child,
85
- key: child.key != null ? child.key : `${keyPrefix}-${index}`,
86
- props: {
87
- ...child.props,
88
- active: panelProps.active,
89
- collapseLabel: panelProps.collapseLabel,
90
- onClose: panelProps.onClose,
91
- open: panelProps.open,
92
- panelId: panelProps.panelId,
93
- },
94
- };
88
+ const props = child.props as Record<string, unknown> | undefined;
89
+
90
+ return (
91
+ props?.active !== panelProps.active ||
92
+ props?.collapseLabel !== panelProps.collapseLabel ||
93
+ props?.onClose !== panelProps.onClose ||
94
+ props?.open !== panelProps.open ||
95
+ props?.panelId !== panelProps.panelId
96
+ );
95
97
  });
98
+ const keyedChildren = needsPanelProps
99
+ ? childList.map((child, index) => {
100
+ if (!isJsxElement(child)) {
101
+ return child;
102
+ }
103
+
104
+ const props = child.props as Record<string, unknown> | undefined;
105
+
106
+ if (
107
+ props?.active === panelProps.active &&
108
+ props?.collapseLabel === panelProps.collapseLabel &&
109
+ props?.onClose === panelProps.onClose &&
110
+ props?.open === panelProps.open &&
111
+ props?.panelId === panelProps.panelId
112
+ ) {
113
+ return child;
114
+ }
115
+
116
+ return {
117
+ ...child,
118
+ key: child.key != null ? child.key : `${keyPrefix}-${index}`,
119
+ props: {
120
+ ...props,
121
+ active: panelProps.active,
122
+ collapseLabel: panelProps.collapseLabel,
123
+ onClose: panelProps.onClose,
124
+ open: panelProps.open,
125
+ panelId: panelProps.panelId,
126
+ },
127
+ };
128
+ })
129
+ : childList;
96
130
 
97
131
  return (
98
132
  <For
@@ -3,6 +3,19 @@ import { renderShellPanel } from "../shell/shell-panel";
3
3
  import { SidebarResponsiveContext } from "./sidebar.context";
4
4
  import type { SidebarPanelProps } from "./sidebar.types";
5
5
 
6
+ const DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT = {
7
+ active: () => false,
8
+ collapseLabel: () => "Menu",
9
+ closePanel: () => undefined,
10
+ iconCollapsed: () => false,
11
+ isRailCollapsible: () => false,
12
+ orientation: () => "vertical" as const,
13
+ panelId: () => undefined,
14
+ panelOpen: () => false,
15
+ togglePanel: () => undefined,
16
+ toggleRail: () => undefined,
17
+ };
18
+
6
19
  export function SidebarPanel(props: SidebarPanelProps): JSX.Element | null {
7
20
  const {
8
21
  active: activeProp,
@@ -27,32 +40,10 @@ export function SidebarPanel(props: SidebarPanelProps): JSX.Element | null {
27
40
  try {
28
41
  return readContext(SidebarResponsiveContext);
29
42
  } catch {
30
- return {
31
- active: () => false,
32
- collapseLabel: () => "Menu",
33
- closePanel: () => undefined,
34
- iconCollapsed: () => false,
35
- isRailCollapsible: () => false,
36
- orientation: () => "vertical" as const,
37
- panelId: () => undefined,
38
- panelOpen: () => false,
39
- togglePanel: () => undefined,
40
- toggleRail: () => undefined,
41
- };
43
+ return DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT;
42
44
  }
43
45
  })()
44
- : {
45
- active: () => false,
46
- collapseLabel: () => "Menu",
47
- closePanel: () => undefined,
48
- iconCollapsed: () => false,
49
- isRailCollapsible: () => false,
50
- orientation: () => "vertical" as const,
51
- panelId: () => undefined,
52
- panelOpen: () => false,
53
- togglePanel: () => undefined,
54
- toggleRail: () => undefined,
55
- };
46
+ : DEFAULT_SIDEBAR_RESPONSIVE_CONTEXT;
56
47
  const active = activeProp ?? responsive.active();
57
48
  const open = openProp ?? responsive.panelOpen();
58
49
  const panelId = panelIdProp ?? responsive.panelId();
@@ -86,6 +86,7 @@ export function ThemeProvider(props: ThemeProviderProps): JSX.Element {
86
86
  } = props;
87
87
 
88
88
  const themeState = state<ThemeName>(readStoredTheme(storageKey) ?? defaultTheme);
89
+ const currentTheme = themeState();
89
90
 
90
91
  const setTheme = (nextTheme: ThemeName) => {
91
92
  themeState.set(nextTheme);
@@ -100,8 +101,6 @@ export function ThemeProvider(props: ThemeProviderProps): JSX.Element {
100
101
  storageKey,
101
102
  };
102
103
 
103
- const currentTheme = themeState();
104
-
105
104
  return (
106
105
  <ThemeContext.Scope value={value}>
107
106
  <ThemeRootSync theme={currentTheme} />
@@ -203,7 +202,7 @@ export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
203
202
  if (!event.defaultPrevented) theme.setTheme(nextTheme);
204
203
  }}
205
204
  >
206
- {content}
205
+ <span data-slot="theme-toggle-content">{content}</span>
207
206
  </Button>
208
207
  );
209
208
  }
@@ -245,9 +244,14 @@ function isJSXElement(value: unknown): value is JSXElement {
245
244
  function cloneThemeToggleIcon(icon: unknown): unknown {
246
245
  if (!isJSXElement(icon)) return icon;
247
246
 
247
+ const props = icon.props as Record<string, unknown> | undefined;
248
+ if (!props || Object.keys(props).length === 0) {
249
+ return icon;
250
+ }
251
+
248
252
  return {
249
253
  ...icon,
250
- props: { ...(icon.props as Record<string, unknown> | undefined) },
254
+ props: { ...props },
251
255
  };
252
256
  }
253
257
 
@@ -35,6 +35,22 @@
35
35
  opacity var(--ak-duration-fast) var(--ak-ease-standard);
36
36
  }
37
37
 
38
+ :where([data-slot="theme-toggle-content"]) {
39
+ --_ak-theme-toggle-icon-size: var(--ak-theme-toggle-icon-size, var(--ak-icon-size, 1em));
40
+ display: inline-flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ flex: none;
44
+ min-inline-size: 0;
45
+ }
46
+
47
+ :where([data-slot="theme-toggle-content"]) > :where([data-slot="icon"], svg) {
48
+ flex: none;
49
+ inline-size: var(--_ak-theme-toggle-icon-size);
50
+ block-size: var(--_ak-theme-toggle-icon-size);
51
+ color: currentColor;
52
+ }
53
+
38
54
  :where(.btn) > :where([data-slot="icon"], svg),
39
55
  :where([data-slot="button"]) > :where([data-slot="icon"], svg) {
40
56
  flex: none;
@@ -35,6 +35,22 @@
35
35
  opacity var(--ak-duration-fast) var(--ak-ease-standard);
36
36
  }
37
37
 
38
+ :where([data-slot="theme-toggle-content"]) {
39
+ --_ak-theme-toggle-icon-size: var(--ak-theme-toggle-icon-size, var(--ak-icon-size, 1em));
40
+ display: inline-flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ flex: none;
44
+ min-inline-size: 0;
45
+ }
46
+
47
+ :where([data-slot="theme-toggle-content"]) > :where([data-slot="icon"], svg) {
48
+ flex: none;
49
+ inline-size: var(--_ak-theme-toggle-icon-size);
50
+ block-size: var(--_ak-theme-toggle-icon-size);
51
+ color: currentColor;
52
+ }
53
+
38
54
  :where(.btn) > :where([data-slot="icon"], svg),
39
55
  :where([data-slot="button"]) > :where([data-slot="icon"], svg) {
40
56
  flex: none;