Initial commit: HMDesignSystem baseline

This commit is contained in:
shkim4 committed 2026-10-08 16:58:09 +09:00
commit b6a0a61103
486 files changed
+68432

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
import { runtimeThemeContract, runtimeGradientGroups, type RuntimeThemeToken } from "./contract"
import { invalidateThemeRequest } from "./requests"
type SavedProperty = { property: string; value: string; priority: string }
const applied = new WeakMap<HTMLElement, { properties: SavedProperty[]; scope: string | null }>()
const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null && !Array.isArray(value)
/** Restore the host's previous inline values and scope. */
export function resetRuntimeTheme(root: HTMLElement) {
invalidateThemeRequest(root)
const previous = applied.get(root)
if (!previous) return
for (const { property, value, priority } of previous.properties) {
if (value) root.style.setProperty(property, value, priority)
else root.style.removeProperty(property)
}
if (previous.scope === null) root.removeAttribute("data-hm-theme")
else root.setAttribute("data-hm-theme", previous.scope)
applied.delete(root)
}
/** Validate without touching the DOM (editors/loaders can preserve their last valid value). */
export function isRuntimeTheme(theme: unknown): theme is import("./contract").RuntimeTheme {
if (!isRecord(theme) || theme.schemaVersion !== 1 || !isRecord(theme.tokens)) return false
const tokens = theme.tokens
for (const group of runtimeGradientGroups) {
const count = group.filter(key => Object.hasOwn(tokens, key)).length
if (count !== 0 && count !== group.length) return false
}
for (const [key, value] of Object.entries(tokens)) {
if (!Object.hasOwn(runtimeThemeContract, key) || typeof value !== "string") return false
const definition = runtimeThemeContract[key as RuntimeThemeToken]
const valid = definition.type === "radius"
? /^(?:[2-9]|1[0-2])px$/.test(value)
: /^#[0-9a-fA-F]{6}$/.test(value)
if (!valid) return false
}
return true
}
/** Atomic validation. Invalid documents release the previous override to host/default. */
export function applyRuntimeTheme(root: HTMLElement, theme: unknown): boolean {
if (!isRuntimeTheme(theme)) { resetRuntimeTheme(root); return false }
const values = Object.entries(theme.tokens).map(([key, value]) =>
[runtimeThemeContract[key as RuntimeThemeToken].property, value!] as const)
resetRuntimeTheme(root)
const scope = root.getAttribute("data-hm-theme")
const properties = values.map(([property]) => ({
property, value: root.style.getPropertyValue(property), priority: root.style.getPropertyPriority(property),
}))
root.setAttribute("data-hm-theme", "runtime")
for (const [property, value] of values) root.style.setProperty(property, value)
applied.set(root, { properties, scope })
return true
}