@just-web/toolkits 1.0.0
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/dist/_internal/utils/try-parse-json.cjs +14 -0
- package/dist/_internal/utils/try-parse-json.cjs.map +1 -0
- package/dist/_internal/utils/try-parse-json.mjs +13 -0
- package/dist/_internal/utils/try-parse-json.mjs.map +1 -0
- package/dist/_virtual/rolldown_runtime.cjs +29 -0
- package/dist/attributes/data-attribute.d.cts +17 -0
- package/dist/attributes/data-attribute.d.cts.map +1 -0
- package/dist/attributes/data-attribute.d.mts +17 -0
- package/dist/attributes/data-attribute.d.mts.map +1 -0
- package/dist/attributes/get-attribute.cjs +26 -0
- package/dist/attributes/get-attribute.cjs.map +1 -0
- package/dist/attributes/get-attribute.d.cts +21 -0
- package/dist/attributes/get-attribute.d.cts.map +1 -0
- package/dist/attributes/get-attribute.d.mts +21 -0
- package/dist/attributes/get-attribute.d.mts.map +1 -0
- package/dist/attributes/get-attribute.mjs +25 -0
- package/dist/attributes/get-attribute.mjs.map +1 -0
- package/dist/attributes/get-data-attribute.cjs +19 -0
- package/dist/attributes/get-data-attribute.cjs.map +1 -0
- package/dist/attributes/get-data-attribute.d.cts +17 -0
- package/dist/attributes/get-data-attribute.d.cts.map +1 -0
- package/dist/attributes/get-data-attribute.d.mts +17 -0
- package/dist/attributes/get-data-attribute.d.mts.map +1 -0
- package/dist/attributes/get-data-attribute.mjs +19 -0
- package/dist/attributes/get-data-attribute.mjs.map +1 -0
- package/dist/attributes/observe-attribute.cjs +40 -0
- package/dist/attributes/observe-attribute.cjs.map +1 -0
- package/dist/attributes/observe-attribute.d.cts +23 -0
- package/dist/attributes/observe-attribute.d.cts.map +1 -0
- package/dist/attributes/observe-attribute.d.mts +23 -0
- package/dist/attributes/observe-attribute.d.mts.map +1 -0
- package/dist/attributes/observe-attribute.mjs +39 -0
- package/dist/attributes/observe-attribute.mjs.map +1 -0
- package/dist/attributes/observe-data-attribute.cjs +31 -0
- package/dist/attributes/observe-data-attribute.cjs.map +1 -0
- package/dist/attributes/observe-data-attribute.d.cts +26 -0
- package/dist/attributes/observe-data-attribute.d.cts.map +1 -0
- package/dist/attributes/observe-data-attribute.d.mts +26 -0
- package/dist/attributes/observe-data-attribute.d.mts.map +1 -0
- package/dist/attributes/observe-data-attribute.mjs +31 -0
- package/dist/attributes/observe-data-attribute.mjs.map +1 -0
- package/dist/children/just-children.d.cts +37 -0
- package/dist/children/just-children.d.cts.map +1 -0
- package/dist/children/just-children.d.mts +37 -0
- package/dist/children/just-children.d.mts.map +1 -0
- package/dist/children/resolve-children.cjs +11 -0
- package/dist/children/resolve-children.cjs.map +1 -0
- package/dist/children/resolve-children.d.cts +9 -0
- package/dist/children/resolve-children.d.cts.map +1 -0
- package/dist/children/resolve-children.d.mts +9 -0
- package/dist/children/resolve-children.d.mts.map +1 -0
- package/dist/children/resolve-children.mjs +10 -0
- package/dist/children/resolve-children.mjs.map +1 -0
- package/dist/class-name/class-name-props.d.cts +11 -0
- package/dist/class-name/class-name-props.d.cts.map +1 -0
- package/dist/class-name/class-name-props.d.mts +11 -0
- package/dist/class-name/class-name-props.d.mts.map +1 -0
- package/dist/class-name/clsx.cjs +3 -0
- package/dist/class-name/clsx.d.cts +2 -0
- package/dist/class-name/clsx.d.mts +2 -0
- package/dist/class-name/clsx.mjs +3 -0
- package/dist/class-name/just-class-name.d.cts +36 -0
- package/dist/class-name/just-class-name.d.cts.map +1 -0
- package/dist/class-name/just-class-name.d.mts +36 -0
- package/dist/class-name/just-class-name.d.mts.map +1 -0
- package/dist/class-name/resolve-class-name.cjs +12 -0
- package/dist/class-name/resolve-class-name.cjs.map +1 -0
- package/dist/class-name/resolve-class-name.d.cts +8 -0
- package/dist/class-name/resolve-class-name.d.cts.map +1 -0
- package/dist/class-name/resolve-class-name.d.mts +8 -0
- package/dist/class-name/resolve-class-name.d.mts.map +1 -0
- package/dist/class-name/resolve-class-name.mjs +10 -0
- package/dist/class-name/resolve-class-name.mjs.map +1 -0
- package/dist/color-scheme/get-prefers-color-scheme.cjs +21 -0
- package/dist/color-scheme/get-prefers-color-scheme.cjs.map +1 -0
- package/dist/color-scheme/get-prefers-color-scheme.d.cts +16 -0
- package/dist/color-scheme/get-prefers-color-scheme.d.cts.map +1 -0
- package/dist/color-scheme/get-prefers-color-scheme.d.mts +16 -0
- package/dist/color-scheme/get-prefers-color-scheme.d.mts.map +1 -0
- package/dist/color-scheme/get-prefers-color-scheme.mjs +20 -0
- package/dist/color-scheme/get-prefers-color-scheme.mjs.map +1 -0
- package/dist/color-scheme/observe-prefers-color-scheme.cjs +29 -0
- package/dist/color-scheme/observe-prefers-color-scheme.cjs.map +1 -0
- package/dist/color-scheme/observe-prefers-color-scheme.d.cts +20 -0
- package/dist/color-scheme/observe-prefers-color-scheme.d.cts.map +1 -0
- package/dist/color-scheme/observe-prefers-color-scheme.d.mts +20 -0
- package/dist/color-scheme/observe-prefers-color-scheme.d.mts.map +1 -0
- package/dist/color-scheme/observe-prefers-color-scheme.mjs +28 -0
- package/dist/color-scheme/observe-prefers-color-scheme.mjs.map +1 -0
- package/dist/index.cjs +39 -0
- package/dist/index.d.cts +26 -0
- package/dist/index.d.mts +26 -0
- package/dist/index.mjs +20 -0
- package/dist/react/hooks/use-attribute.cjs +41 -0
- package/dist/react/hooks/use-attribute.cjs.map +1 -0
- package/dist/react/hooks/use-attribute.d.cts +21 -0
- package/dist/react/hooks/use-attribute.d.cts.map +1 -0
- package/dist/react/hooks/use-attribute.d.mts +21 -0
- package/dist/react/hooks/use-attribute.d.mts.map +1 -0
- package/dist/react/hooks/use-attribute.mjs +40 -0
- package/dist/react/hooks/use-attribute.mjs.map +1 -0
- package/dist/react/hooks/use-prefers-color-scheme.cjs +42 -0
- package/dist/react/hooks/use-prefers-color-scheme.cjs.map +1 -0
- package/dist/react/hooks/use-prefers-color-scheme.d.cts +29 -0
- package/dist/react/hooks/use-prefers-color-scheme.d.cts.map +1 -0
- package/dist/react/hooks/use-prefers-color-scheme.d.mts +29 -0
- package/dist/react/hooks/use-prefers-color-scheme.d.mts.map +1 -0
- package/dist/react/hooks/use-prefers-color-scheme.mjs +41 -0
- package/dist/react/hooks/use-prefers-color-scheme.mjs.map +1 -0
- package/dist/react/hooks/use-theme-by-class-name.cjs +60 -0
- package/dist/react/hooks/use-theme-by-class-name.cjs.map +1 -0
- package/dist/react/hooks/use-theme-by-class-name.d.cts +34 -0
- package/dist/react/hooks/use-theme-by-class-name.d.cts.map +1 -0
- package/dist/react/hooks/use-theme-by-class-name.d.mts +34 -0
- package/dist/react/hooks/use-theme-by-class-name.d.mts.map +1 -0
- package/dist/react/hooks/use-theme-by-class-name.mjs +59 -0
- package/dist/react/hooks/use-theme-by-class-name.mjs.map +1 -0
- package/dist/react/hooks/use-theme-by-data-attribute.cjs +73 -0
- package/dist/react/hooks/use-theme-by-data-attribute.cjs.map +1 -0
- package/dist/react/hooks/use-theme-by-data-attribute.d.cts +39 -0
- package/dist/react/hooks/use-theme-by-data-attribute.d.cts.map +1 -0
- package/dist/react/hooks/use-theme-by-data-attribute.d.mts +39 -0
- package/dist/react/hooks/use-theme-by-data-attribute.d.mts.map +1 -0
- package/dist/react/hooks/use-theme-by-data-attribute.mjs +72 -0
- package/dist/react/hooks/use-theme-by-data-attribute.mjs.map +1 -0
- package/dist/react/hooks/use-theme-by-local-storage.cjs +53 -0
- package/dist/react/hooks/use-theme-by-local-storage.cjs.map +1 -0
- package/dist/react/hooks/use-theme-by-local-storage.d.cts +37 -0
- package/dist/react/hooks/use-theme-by-local-storage.d.cts.map +1 -0
- package/dist/react/hooks/use-theme-by-local-storage.d.mts +37 -0
- package/dist/react/hooks/use-theme-by-local-storage.d.mts.map +1 -0
- package/dist/react/hooks/use-theme-by-local-storage.mjs +52 -0
- package/dist/react/hooks/use-theme-by-local-storage.mjs.map +1 -0
- package/dist/react/hooks/use-theme-stores.cjs +40 -0
- package/dist/react/hooks/use-theme-stores.cjs.map +1 -0
- package/dist/react/hooks/use-theme-stores.d.cts +38 -0
- package/dist/react/hooks/use-theme-stores.d.cts.map +1 -0
- package/dist/react/hooks/use-theme-stores.d.mts +38 -0
- package/dist/react/hooks/use-theme-stores.d.mts.map +1 -0
- package/dist/react/hooks/use-theme-stores.mjs +39 -0
- package/dist/react/hooks/use-theme-stores.mjs.map +1 -0
- package/dist/react/theme/create-theme-hook.cjs +105 -0
- package/dist/react/theme/create-theme-hook.cjs.map +1 -0
- package/dist/react/theme/create-theme-hook.d.cts +29 -0
- package/dist/react/theme/create-theme-hook.d.cts.map +1 -0
- package/dist/react/theme/create-theme-hook.d.mts +29 -0
- package/dist/react/theme/create-theme-hook.d.mts.map +1 -0
- package/dist/react/theme/create-theme-hook.mjs +104 -0
- package/dist/react/theme/create-theme-hook.mjs.map +1 -0
- package/dist/react.cjs +15 -0
- package/dist/react.d.cts +8 -0
- package/dist/react.d.mts +8 -0
- package/dist/react.mjs +9 -0
- package/dist/style/css-properties.d.cts +20 -0
- package/dist/style/css-properties.d.cts.map +1 -0
- package/dist/style/css-properties.d.mts +20 -0
- package/dist/style/css-properties.d.mts.map +1 -0
- package/dist/style/define-css-properties.cjs +25 -0
- package/dist/style/define-css-properties.cjs.map +1 -0
- package/dist/style/define-css-properties.d.cts +24 -0
- package/dist/style/define-css-properties.d.cts.map +1 -0
- package/dist/style/define-css-properties.d.mts +24 -0
- package/dist/style/define-css-properties.d.mts.map +1 -0
- package/dist/style/define-css-properties.mjs +24 -0
- package/dist/style/define-css-properties.mjs.map +1 -0
- package/dist/style/get-css-variable-value.cjs +11 -0
- package/dist/style/get-css-variable-value.cjs.map +1 -0
- package/dist/style/get-css-variable-value.d.cts +22 -0
- package/dist/style/get-css-variable-value.d.cts.map +1 -0
- package/dist/style/get-css-variable-value.d.mts +22 -0
- package/dist/style/get-css-variable-value.d.mts.map +1 -0
- package/dist/style/get-css-variable-value.mjs +10 -0
- package/dist/style/get-css-variable-value.mjs.map +1 -0
- package/dist/style/just-style.d.cts +44 -0
- package/dist/style/just-style.d.cts.map +1 -0
- package/dist/style/just-style.d.mts +44 -0
- package/dist/style/just-style.d.mts.map +1 -0
- package/dist/style/resolve-style.cjs +14 -0
- package/dist/style/resolve-style.cjs.map +1 -0
- package/dist/style/resolve-style.d.cts +11 -0
- package/dist/style/resolve-style.d.cts.map +1 -0
- package/dist/style/resolve-style.d.mts +11 -0
- package/dist/style/resolve-style.d.mts.map +1 -0
- package/dist/style/resolve-style.mjs +13 -0
- package/dist/style/resolve-style.mjs.map +1 -0
- package/dist/style/style-props.d.cts +13 -0
- package/dist/style/style-props.d.cts.map +1 -0
- package/dist/style/style-props.d.mts +13 -0
- package/dist/style/style-props.d.mts.map +1 -0
- package/dist/style/to-dom-style.cjs +33 -0
- package/dist/style/to-dom-style.cjs.map +1 -0
- package/dist/style/to-dom-style.d.cts +29 -0
- package/dist/style/to-dom-style.d.cts.map +1 -0
- package/dist/style/to-dom-style.d.mts +29 -0
- package/dist/style/to-dom-style.d.mts.map +1 -0
- package/dist/style/to-dom-style.mjs +32 -0
- package/dist/style/to-dom-style.mjs.map +1 -0
- package/dist/testing/theme/dummy-theme-store.cjs +11 -0
- package/dist/testing/theme/dummy-theme-store.cjs.map +1 -0
- package/dist/testing/theme/dummy-theme-store.mjs +10 -0
- package/dist/testing/theme/dummy-theme-store.mjs.map +1 -0
- package/dist/theme/_utils/get-theme-from-stores.cjs +24 -0
- package/dist/theme/_utils/get-theme-from-stores.cjs.map +1 -0
- package/dist/theme/_utils/get-theme-from-stores.mjs +23 -0
- package/dist/theme/_utils/get-theme-from-stores.mjs.map +1 -0
- package/dist/theme/_utils/observe-theme-from-stores.cjs +39 -0
- package/dist/theme/_utils/observe-theme-from-stores.cjs.map +1 -0
- package/dist/theme/_utils/observe-theme-from-stores.mjs +39 -0
- package/dist/theme/_utils/observe-theme-from-stores.mjs.map +1 -0
- package/dist/theme/_utils/parse-stored-theme.cjs +22 -0
- package/dist/theme/_utils/parse-stored-theme.cjs.map +1 -0
- package/dist/theme/_utils/parse-stored-theme.mjs +22 -0
- package/dist/theme/_utils/parse-stored-theme.mjs.map +1 -0
- package/dist/theme/_utils/set-theme-to-stores.cjs +16 -0
- package/dist/theme/_utils/set-theme-to-stores.cjs.map +1 -0
- package/dist/theme/_utils/set-theme-to-stores.mjs +15 -0
- package/dist/theme/_utils/set-theme-to-stores.mjs.map +1 -0
- package/dist/theme/class-name/apply-theme-to-class-name.cjs +23 -0
- package/dist/theme/class-name/apply-theme-to-class-name.cjs.map +1 -0
- package/dist/theme/class-name/apply-theme-to-class-name.mjs +22 -0
- package/dist/theme/class-name/apply-theme-to-class-name.mjs.map +1 -0
- package/dist/theme/class-name/resolve-theme-from-class-name.cjs +23 -0
- package/dist/theme/class-name/resolve-theme-from-class-name.cjs.map +1 -0
- package/dist/theme/class-name/resolve-theme-from-class-name.mjs +22 -0
- package/dist/theme/class-name/resolve-theme-from-class-name.mjs.map +1 -0
- package/dist/theme/compose-theme-stores.cjs +74 -0
- package/dist/theme/compose-theme-stores.cjs.map +1 -0
- package/dist/theme/compose-theme-stores.d.cts +33 -0
- package/dist/theme/compose-theme-stores.d.cts.map +1 -0
- package/dist/theme/compose-theme-stores.d.mts +33 -0
- package/dist/theme/compose-theme-stores.d.mts.map +1 -0
- package/dist/theme/compose-theme-stores.mjs +74 -0
- package/dist/theme/compose-theme-stores.mjs.map +1 -0
- package/dist/theme/data-attribute/apply-theme-to-data-attribute.cjs +23 -0
- package/dist/theme/data-attribute/apply-theme-to-data-attribute.cjs.map +1 -0
- package/dist/theme/data-attribute/apply-theme-to-data-attribute.mjs +22 -0
- package/dist/theme/data-attribute/apply-theme-to-data-attribute.mjs.map +1 -0
- package/dist/theme/data-attribute/resolve-theme-from-data-attribute.cjs +23 -0
- package/dist/theme/data-attribute/resolve-theme-from-data-attribute.cjs.map +1 -0
- package/dist/theme/data-attribute/resolve-theme-from-data-attribute.mjs +22 -0
- package/dist/theme/data-attribute/resolve-theme-from-data-attribute.mjs.map +1 -0
- package/dist/theme/theme-entry.cjs +13 -0
- package/dist/theme/theme-entry.cjs.map +1 -0
- package/dist/theme/theme-entry.d.cts +9 -0
- package/dist/theme/theme-entry.d.cts.map +1 -0
- package/dist/theme/theme-entry.d.mts +9 -0
- package/dist/theme/theme-entry.d.mts.map +1 -0
- package/dist/theme/theme-entry.mjs +12 -0
- package/dist/theme/theme-entry.mjs.map +1 -0
- package/dist/theme/theme-entry.types.d.cts +16 -0
- package/dist/theme/theme-entry.types.d.cts.map +1 -0
- package/dist/theme/theme-entry.types.d.mts +16 -0
- package/dist/theme/theme-entry.types.d.mts.map +1 -0
- package/dist/theme/theme-map.types.d.cts +10 -0
- package/dist/theme/theme-map.types.d.cts.map +1 -0
- package/dist/theme/theme-map.types.d.mts +10 -0
- package/dist/theme/theme-map.types.d.mts.map +1 -0
- package/dist/theme/theme-store/async-theme-store.types.d.cts +25 -0
- package/dist/theme/theme-store/async-theme-store.types.d.cts.map +1 -0
- package/dist/theme/theme-store/async-theme-store.types.d.mts +25 -0
- package/dist/theme/theme-store/async-theme-store.types.d.mts.map +1 -0
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs +53 -0
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs.map +1 -0
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.cts +28 -0
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.cts.map +1 -0
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.mts +28 -0
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.mts.map +1 -0
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs +53 -0
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs.map +1 -0
- package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.cjs +121 -0
- package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.cjs.map +1 -0
- package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.cts +65 -0
- package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.cts.map +1 -0
- package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.mts +65 -0
- package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.d.mts.map +1 -0
- package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.mjs +120 -0
- package/dist/theme/theme-store/cookie-theme-store/cookie-theme-store.mjs.map +1 -0
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs +51 -0
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs.map +1 -0
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.cts +30 -0
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.cts.map +1 -0
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.mts +30 -0
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.mts.map +1 -0
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs +51 -0
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs.map +1 -0
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.cjs +54 -0
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.cjs.map +1 -0
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.cts +31 -0
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.cts.map +1 -0
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.mts +31 -0
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.mts.map +1 -0
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.mjs +54 -0
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.mjs.map +1 -0
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.cjs +67 -0
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.cjs.map +1 -0
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.cts +34 -0
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.cts.map +1 -0
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.mts +34 -0
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.mts.map +1 -0
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs +67 -0
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.mjs.map +1 -0
- package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.cjs +39 -0
- package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.cjs.map +1 -0
- package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.cts +32 -0
- package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.cts.map +1 -0
- package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.mts +32 -0
- package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.d.mts.map +1 -0
- package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs +39 -0
- package/dist/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.mjs.map +1 -0
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.cjs +67 -0
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.cjs.map +1 -0
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.cts +34 -0
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.cts.map +1 -0
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.mts +34 -0
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.mts.map +1 -0
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs +67 -0
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.mjs.map +1 -0
- package/dist/theme/theme-store/theme-store-factory.types.d.cts +10 -0
- package/dist/theme/theme-store/theme-store-factory.types.d.cts.map +1 -0
- package/dist/theme/theme-store/theme-store-factory.types.d.mts +10 -0
- package/dist/theme/theme-store/theme-store-factory.types.d.mts.map +1 -0
- package/dist/theme/theme-store/theme-store.types.d.cts +33 -0
- package/dist/theme/theme-store/theme-store.types.d.cts.map +1 -0
- package/dist/theme/theme-store/theme-store.types.d.mts +33 -0
- package/dist/theme/theme-store/theme-store.types.d.mts.map +1 -0
- package/dist/theme.cjs +20 -0
- package/dist/theme.d.cts +15 -0
- package/dist/theme.d.mts +15 -0
- package/dist/theme.mjs +11 -0
- package/dist/units/get-rem-to-px-scale.cjs +30 -0
- package/dist/units/get-rem-to-px-scale.cjs.map +1 -0
- package/dist/units/get-rem-to-px-scale.d.cts +21 -0
- package/dist/units/get-rem-to-px-scale.d.cts.map +1 -0
- package/dist/units/get-rem-to-px-scale.d.mts +21 -0
- package/dist/units/get-rem-to-px-scale.d.mts.map +1 -0
- package/dist/units/get-rem-to-px-scale.mjs +29 -0
- package/dist/units/get-rem-to-px-scale.mjs.map +1 -0
- package/dist/units/px-2-num.cjs +23 -0
- package/dist/units/px-2-num.cjs.map +1 -0
- package/dist/units/px-2-num.d.cts +19 -0
- package/dist/units/px-2-num.d.cts.map +1 -0
- package/dist/units/px-2-num.d.mts +19 -0
- package/dist/units/px-2-num.d.mts.map +1 -0
- package/dist/units/px-2-num.mjs +22 -0
- package/dist/units/px-2-num.mjs.map +1 -0
- package/dist/units/px-2-rem.cjs +31 -0
- package/dist/units/px-2-rem.cjs.map +1 -0
- package/dist/units/px-2-rem.d.cts +25 -0
- package/dist/units/px-2-rem.d.cts.map +1 -0
- package/dist/units/px-2-rem.d.mts +25 -0
- package/dist/units/px-2-rem.d.mts.map +1 -0
- package/dist/units/px-2-rem.mjs +30 -0
- package/dist/units/px-2-rem.mjs.map +1 -0
- package/dist/units/rem-2-px.cjs +31 -0
- package/dist/units/rem-2-px.cjs.map +1 -0
- package/dist/units/rem-2-px.d.cts +25 -0
- package/dist/units/rem-2-px.d.cts.map +1 -0
- package/dist/units/rem-2-px.d.mts +25 -0
- package/dist/units/rem-2-px.d.mts.map +1 -0
- package/dist/units/rem-2-px.mjs +30 -0
- package/dist/units/rem-2-px.mjs.map +1 -0
- package/dist/utils/append-id.cjs +16 -0
- package/dist/utils/append-id.cjs.map +1 -0
- package/dist/utils/append-id.d.cts +12 -0
- package/dist/utils/append-id.d.cts.map +1 -0
- package/dist/utils/append-id.d.mts +12 -0
- package/dist/utils/append-id.d.mts.map +1 -0
- package/dist/utils/append-id.mjs +15 -0
- package/dist/utils/append-id.mjs.map +1 -0
- package/package.json +120 -0
- package/readme.md +15 -0
- package/src/_internal/utils/try-parse-json.ts +8 -0
- package/src/attributes/data-attribute.ts +49 -0
- package/src/attributes/get-attribute.ts +20 -0
- package/src/attributes/get-data-attribute.ts +15 -0
- package/src/attributes/observe-attribute.ts +37 -0
- package/src/attributes/observe-data-attribute.ts +29 -0
- package/src/children/just-children-fn-props.editor.default.tsx +29 -0
- package/src/children/just-children-props.editor.default.tsx +17 -0
- package/src/children/just-children.editor.default.tsx +11 -0
- package/src/children/just-children.ts +37 -0
- package/src/children/resolve-children.ts +16 -0
- package/src/class-name/class-name-props.editor.tsx +13 -0
- package/src/class-name/class-name-props.ts +7 -0
- package/src/class-name/clsx.ts +3 -0
- package/src/class-name/just-class-name-props.editor.default.tsx +23 -0
- package/src/class-name/just-class-name-resolver-state.editor.default.tsx +18 -0
- package/src/class-name/just-class-name.editor.default-class-name.tsx +28 -0
- package/src/class-name/just-class-name.editor.default.tsx +14 -0
- package/src/class-name/just-class-name.editor.type-param.tsx +25 -0
- package/src/class-name/just-class-name.ts +36 -0
- package/src/class-name/resolve-class-name.ts +12 -0
- package/src/color-scheme/get-prefers-color-scheme.ts +17 -0
- package/src/color-scheme/observe-prefers-color-scheme.ts +24 -0
- package/src/index.ts +25 -0
- package/src/react/hooks/use-attribute.ts +59 -0
- package/src/react/hooks/use-prefers-color-scheme.ts +42 -0
- package/src/react/hooks/use-theme-by-class-name.ts +69 -0
- package/src/react/hooks/use-theme-by-data-attribute.ts +84 -0
- package/src/react/hooks/use-theme-by-local-storage.ts +68 -0
- package/src/react/hooks/use-theme-stores.ts +83 -0
- package/src/react/theme/create-theme-hook.ts +197 -0
- package/src/react.ts +7 -0
- package/src/style/css-properties.ts +20 -0
- package/src/style/define-css-properties.ts +23 -0
- package/src/style/get-css-variable-value.ts +32 -0
- package/src/style/just-style-props.editor.default.tsx +17 -0
- package/src/style/just-style-resolver-state.editor.default.tsx +22 -0
- package/src/style/just-style.editor.default.tsx +17 -0
- package/src/style/just-style.editor.type-param.tsx +31 -0
- package/src/style/just-style.ts +60 -0
- package/src/style/resolve-style.ts +23 -0
- package/src/style/style-props.editor.tsx +13 -0
- package/src/style/style-props.ts +8 -0
- package/src/style/to-dom-style.ts +36 -0
- package/src/testing/button.theme.ts +21 -0
- package/src/testing/button.tsx +11 -0
- package/src/testing/log-panel.tsx +14 -0
- package/src/testing/theme/dummy-theme-store.ts +7 -0
- package/src/testing/theme/theme-result-card.tsx +43 -0
- package/src/testing/theme/theme-store-demo.tsx +87 -0
- package/src/theme/_utils/get-theme-from-stores.ts +34 -0
- package/src/theme/_utils/observe-theme-from-stores.ts +57 -0
- package/src/theme/_utils/parse-stored-theme.ts +21 -0
- package/src/theme/_utils/set-theme-to-stores.ts +23 -0
- package/src/theme/class-name/apply-theme-to-class-name.ts +26 -0
- package/src/theme/class-name/resolve-theme-from-class-name.ts +22 -0
- package/src/theme/compose-theme-stores.ts +139 -0
- package/src/theme/data-attribute/apply-theme-to-data-attribute.ts +27 -0
- package/src/theme/data-attribute/resolve-theme-from-data-attribute.ts +23 -0
- package/src/theme/theme-entry.ts +10 -0
- package/src/theme/theme-entry.types.ts +11 -0
- package/src/theme/theme-map.types.ts +6 -0
- package/src/theme/theme-store/async-theme-store.types.ts +24 -0
- package/src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts +62 -0
- package/src/theme/theme-store/cookie-theme-store/cookie-theme-store.ts +174 -0
- package/src/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.ts +60 -0
- package/src/theme/theme-store/in-memory-theme-store/in-memory-theme-store.ts +54 -0
- package/src/theme/theme-store/local-storage-theme-store/local-storage-theme-store.ts +83 -0
- package/src/theme/theme-store/prefers-color-scheme-theme-store/prefers-color-scheme-theme-store.ts +43 -0
- package/src/theme/theme-store/session-storage-theme-store/session-storage-theme-store.ts +83 -0
- package/src/theme/theme-store/theme-store-factory.types.ts +9 -0
- package/src/theme/theme-store/theme-store.types.ts +30 -0
- package/src/theme.ts +14 -0
- package/src/units/get-rem-to-px-scale.ts +27 -0
- package/src/units/px-2-num.ts +17 -0
- package/src/units/px-2-rem.ts +30 -0
- package/src/units/rem-2-px.ts +30 -0
- package/src/utils/append-id.ts +10 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react'
|
|
2
|
+
import { themeEntry } from '../../theme/theme-entry.ts'
|
|
3
|
+
import type { ThemeEntry } from '../../theme/theme-entry.types.ts'
|
|
4
|
+
import type { ThemeMap } from '../../theme/theme-map.types.ts'
|
|
5
|
+
import type { AsyncThemeStore } from '../../theme/theme-store/async-theme-store.types.ts'
|
|
6
|
+
import type { ThemeStore } from '../../theme/theme-store/theme-store.types.ts'
|
|
7
|
+
import { appendId } from '../../utils/append-id.ts'
|
|
8
|
+
import { Button } from '../button.tsx'
|
|
9
|
+
import { ThemeResultCard } from './theme-result-card.tsx'
|
|
10
|
+
|
|
11
|
+
type ThemeStoreDemoProps<Themes extends ThemeMap> = {
|
|
12
|
+
store: ThemeStore<Themes> | AsyncThemeStore<Themes>
|
|
13
|
+
themes: Themes
|
|
14
|
+
/** Theme keys to show as "Write X" buttons. Defaults to first 3 keys from themes. */
|
|
15
|
+
setThemeKeys?: (keyof Themes)[] | undefined
|
|
16
|
+
'data-testid'?: string | undefined
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Demo component that uses theme store.read, store.write, and store.subscribe.
|
|
21
|
+
* Renders observed value, a one-time read result, and buttons to trigger read/write for showcasing behavior.
|
|
22
|
+
* All interactive elements and result areas use data-testid for testing.
|
|
23
|
+
*/
|
|
24
|
+
export function ThemeStoreDemo<Themes extends ThemeMap>({
|
|
25
|
+
store,
|
|
26
|
+
themes,
|
|
27
|
+
setThemeKeys,
|
|
28
|
+
'data-testid': dataTestId = 'theme-store-demo'
|
|
29
|
+
}: ThemeStoreDemoProps<Themes>) {
|
|
30
|
+
const [observedResult, setObservedResult] = useState<ThemeEntry<Themes> | undefined | null>(
|
|
31
|
+
undefined
|
|
32
|
+
)
|
|
33
|
+
const [getResult, setGetResult] = useState<ThemeEntry<Themes> | undefined | null>(undefined)
|
|
34
|
+
|
|
35
|
+
const keys = (setThemeKeys ??
|
|
36
|
+
(Object.keys(themes) as (keyof Themes)[]).slice(0, 3)) as (keyof Themes)[]
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
void Promise.resolve(store.read?.()).then((r) => setObservedResult(r ?? undefined))
|
|
40
|
+
}, [store])
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
return store.subscribe?.(setObservedResult)
|
|
44
|
+
}, [store])
|
|
45
|
+
|
|
46
|
+
const handleGet = useCallback(async () => {
|
|
47
|
+
const result = store.read?.()
|
|
48
|
+
const resolved = await Promise.resolve(result)
|
|
49
|
+
setGetResult(resolved ?? undefined)
|
|
50
|
+
}, [store])
|
|
51
|
+
|
|
52
|
+
const handleSet = useCallback(
|
|
53
|
+
(theme: keyof Themes) => async () => {
|
|
54
|
+
const ret = store.write?.(themeEntry(themes, theme))
|
|
55
|
+
await Promise.resolve(ret)
|
|
56
|
+
},
|
|
57
|
+
[store, themes]
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
const observeTestId = appendId(dataTestId, 'observe')
|
|
61
|
+
const readTestId = appendId(dataTestId, 'read')
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className="flex flex-col gap-2" data-testid={dataTestId}>
|
|
65
|
+
<div className="flex flex-wrap gap-2">
|
|
66
|
+
<Button onClick={handleGet} data-testid={appendId(dataTestId, 'btn-read')}>
|
|
67
|
+
Read theme
|
|
68
|
+
</Button>
|
|
69
|
+
{keys.map((key) => (
|
|
70
|
+
<Button
|
|
71
|
+
key={String(key)}
|
|
72
|
+
onClick={handleSet(key)}
|
|
73
|
+
data-testid={appendId(dataTestId, `btn-write-${String(key)}`)}
|
|
74
|
+
>
|
|
75
|
+
Write {String(key)}
|
|
76
|
+
</Button>
|
|
77
|
+
))}
|
|
78
|
+
</div>
|
|
79
|
+
<ThemeResultCard title="Read (one-time)" result={getResult} data-testid={readTestId} />
|
|
80
|
+
<ThemeResultCard
|
|
81
|
+
title="Observed (subscribe)"
|
|
82
|
+
result={observedResult}
|
|
83
|
+
data-testid={observeTestId}
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ThemeEntry } from '../theme-entry.types.ts'
|
|
2
|
+
import type { ThemeMap } from '../theme-map.types.ts'
|
|
3
|
+
import type { AsyncThemeStore } from '../theme-store/async-theme-store.types.ts'
|
|
4
|
+
import type { ThemeStore } from '../theme-store/theme-store.types.ts'
|
|
5
|
+
|
|
6
|
+
type StoreWithRead<Themes extends ThemeMap> = (ThemeStore<Themes> | AsyncThemeStore<Themes>) & {
|
|
7
|
+
read: () => ThemeEntry<Themes> | undefined | Promise<ThemeEntry<Themes> | undefined>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Reads theme from stores using waterfall strategy.
|
|
12
|
+
*
|
|
13
|
+
* Iterates stores in order; returns first non-empty result.
|
|
14
|
+
* Only includes stores that have a `read` method.
|
|
15
|
+
*
|
|
16
|
+
* @param stores - Array of theme stores
|
|
17
|
+
* @param defaultTheme - Fallback when all stores return empty
|
|
18
|
+
* @returns Resolved theme key or defaultTheme
|
|
19
|
+
*/
|
|
20
|
+
export async function getThemeFromStores<Themes extends ThemeMap>(
|
|
21
|
+
stores: (ThemeStore<Themes> | AsyncThemeStore<Themes>)[],
|
|
22
|
+
defaultTheme: keyof Themes | undefined
|
|
23
|
+
): Promise<keyof Themes | undefined> {
|
|
24
|
+
const withRead = stores.filter((s): s is StoreWithRead<Themes> => typeof s.read === 'function')
|
|
25
|
+
|
|
26
|
+
for (const store of withRead) {
|
|
27
|
+
const result = await Promise.resolve(store.read())
|
|
28
|
+
if (result !== undefined) {
|
|
29
|
+
return result.theme
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return defaultTheme
|
|
34
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { RequiredPick } from 'type-plus'
|
|
2
|
+
import type { ThemeMap } from '../theme-map.types.ts'
|
|
3
|
+
import type { AsyncThemeStore } from '../theme-store/async-theme-store.types.ts'
|
|
4
|
+
import type { ThemeStore } from '../theme-store/theme-store.types.ts'
|
|
5
|
+
import { getThemeFromStores } from './get-theme-from-stores.ts'
|
|
6
|
+
|
|
7
|
+
type StoreWithSubscribe<Themes extends ThemeMap> = RequiredPick<
|
|
8
|
+
AsyncThemeStore<Themes>,
|
|
9
|
+
'subscribe'
|
|
10
|
+
>
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Subscribes to stores that have a subscribe method.
|
|
14
|
+
*
|
|
15
|
+
* When any store emits, runs coalesced handler (getThemeFromStores + callback).
|
|
16
|
+
* Skips handler if resolved theme equals last emitted (value equality).
|
|
17
|
+
*
|
|
18
|
+
* @param stores - Array of theme stores
|
|
19
|
+
* @param defaultTheme - Fallback when all stores return empty
|
|
20
|
+
* @param handler - Callback with resolved theme key
|
|
21
|
+
* @returns Unsubscribe function
|
|
22
|
+
*/
|
|
23
|
+
export function observeThemeFromStores<Themes extends ThemeMap>(
|
|
24
|
+
stores: (ThemeStore<Themes> | AsyncThemeStore<Themes>)[],
|
|
25
|
+
defaultTheme: keyof Themes | undefined,
|
|
26
|
+
handler: (theme: keyof Themes | undefined) => void
|
|
27
|
+
): () => void {
|
|
28
|
+
const withSubscribe = stores.filter(
|
|
29
|
+
(s): s is StoreWithSubscribe<Themes> => typeof s.subscribe === 'function'
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
let scheduled = false
|
|
33
|
+
let lastEmitted: keyof Themes | undefined
|
|
34
|
+
|
|
35
|
+
const scheduleNotify = () => {
|
|
36
|
+
if (scheduled) return
|
|
37
|
+
scheduled = true
|
|
38
|
+
queueMicrotask(async () => {
|
|
39
|
+
scheduled = false
|
|
40
|
+
const theme = await getThemeFromStores(stores, defaultTheme)
|
|
41
|
+
if (theme === lastEmitted) return
|
|
42
|
+
lastEmitted = theme
|
|
43
|
+
handler(theme)
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Initial notify
|
|
48
|
+
scheduleNotify()
|
|
49
|
+
|
|
50
|
+
const unSubs = withSubscribe.map((s) => s.subscribe!((_result) => scheduleNotify()))
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
for (const unSub of unSubs) {
|
|
54
|
+
unSub()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { tryParseJSON } from '../../_internal/utils/try-parse-json.ts'
|
|
2
|
+
import type { ThemeMap } from '../theme-map.types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parses stored JSON theme and validates the theme key against theme map.
|
|
6
|
+
*
|
|
7
|
+
* Expects stored shape: { theme: string, value?: unknown }
|
|
8
|
+
*
|
|
9
|
+
* @param themes - Record of valid theme keys (optional; if omitted, any theme string is accepted)
|
|
10
|
+
* @param value - Raw string from localStorage/sessionStorage
|
|
11
|
+
* @returns Theme key if valid, otherwise undefined
|
|
12
|
+
*/
|
|
13
|
+
export function parseStoredTheme<Theme extends string>(
|
|
14
|
+
themes: ThemeMap<Theme> | undefined,
|
|
15
|
+
value: string | null | undefined
|
|
16
|
+
): Theme | undefined {
|
|
17
|
+
const parsed = tryParseJSON<{ theme: string }>(value)
|
|
18
|
+
if (!parsed?.theme || typeof parsed.theme !== 'string') return undefined
|
|
19
|
+
if (themes && !(parsed.theme in themes)) return undefined
|
|
20
|
+
return parsed.theme as Theme
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ThemeEntry } from '../theme-entry.types.ts'
|
|
2
|
+
import type { ThemeMap } from '../theme-map.types.ts'
|
|
3
|
+
import type { AsyncThemeStore } from '../theme-store/async-theme-store.types.ts'
|
|
4
|
+
import type { ThemeStore } from '../theme-store/theme-store.types.ts'
|
|
5
|
+
|
|
6
|
+
type StoreWithWrite<Themes extends ThemeMap> = (ThemeStore<Themes> | AsyncThemeStore<Themes>) & {
|
|
7
|
+
write: (entry: ThemeEntry<Themes> | undefined) => void | Promise<void>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Writes theme entry to all stores that have a write method.
|
|
12
|
+
*
|
|
13
|
+
* @param stores - Array of theme stores
|
|
14
|
+
* @param entry - Theme entry to write, or undefined to clear
|
|
15
|
+
*/
|
|
16
|
+
export async function setThemeToStores<Themes extends ThemeMap>(
|
|
17
|
+
stores: (ThemeStore<Themes> | AsyncThemeStore<Themes>)[],
|
|
18
|
+
entry: ThemeEntry<Themes> | undefined
|
|
19
|
+
): Promise<void> {
|
|
20
|
+
const withWrite = stores.filter((s): s is StoreWithWrite<Themes> => typeof s.write === 'function')
|
|
21
|
+
|
|
22
|
+
await Promise.all(withWrite.map((store) => Promise.resolve(store.write!(entry))))
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ThemeEntry } from '../theme-entry.types.ts'
|
|
2
|
+
import type { ThemeMap } from '../theme-map.types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Applies theme to element by updating its class attribute.
|
|
6
|
+
*
|
|
7
|
+
* Removes all theme classes from the element, then adds classes for the given entry.
|
|
8
|
+
* When entry is undefined, removes all theme classes (themeMap needed for clear path).
|
|
9
|
+
*
|
|
10
|
+
* @param element - Target element
|
|
11
|
+
* @param entry - Theme entry to apply, or undefined to clear
|
|
12
|
+
* @param themes - Record mapping theme keys to class names (used for clear case)
|
|
13
|
+
*/
|
|
14
|
+
export function applyThemeToClassName<Themes extends ThemeMap>(
|
|
15
|
+
themes: Themes,
|
|
16
|
+
element: Element,
|
|
17
|
+
entry: ThemeEntry<Themes> | undefined
|
|
18
|
+
): void {
|
|
19
|
+
const allThemeClasses = Object.values(themes).flatMap((v) => (Array.isArray(v) ? [...v] : [v]))
|
|
20
|
+
const current = element.className.trim()
|
|
21
|
+
const currentClasses = current ? current.split(/\s+/) : []
|
|
22
|
+
const withoutThemes = currentClasses.filter((c) => !allThemeClasses.includes(c))
|
|
23
|
+
const activeClasses =
|
|
24
|
+
entry !== undefined ? (Array.isArray(entry.value) ? [...entry.value] : [entry.value]) : []
|
|
25
|
+
element.className = [...withoutThemes, ...activeClasses].filter(Boolean).join(' ')
|
|
26
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { findKey } from 'type-plus'
|
|
2
|
+
import type { ThemeMap } from '../theme-map.types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolves theme key from class name string by matching against theme map.
|
|
6
|
+
*
|
|
7
|
+
* @param className - Element class attribute value
|
|
8
|
+
* @param themes - Record mapping theme keys to class name(s); arrays use first value for matching
|
|
9
|
+
* @returns Theme key if a match is found, otherwise undefined
|
|
10
|
+
*/
|
|
11
|
+
export function resolveThemeFromClassName<Theme extends string>(
|
|
12
|
+
themes: ThemeMap<Theme>,
|
|
13
|
+
className: string
|
|
14
|
+
): Theme | undefined {
|
|
15
|
+
const theme = findKey(themes, (key) => {
|
|
16
|
+
const value = themes[key]
|
|
17
|
+
if (value === undefined) return false
|
|
18
|
+
const v = Array.isArray(value) ? value[0] : value
|
|
19
|
+
return !!v && className.includes(v)
|
|
20
|
+
})
|
|
21
|
+
return theme as Theme | undefined
|
|
22
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { Required, RequiredPick } from 'type-plus'
|
|
2
|
+
import { setThemeToStores } from './_utils/set-theme-to-stores.ts'
|
|
3
|
+
import { themeEntry } from './theme-entry.ts'
|
|
4
|
+
import type { ThemeEntry } from './theme-entry.types.ts'
|
|
5
|
+
import type { ThemeMap } from './theme-map.types.ts'
|
|
6
|
+
import type { AsyncThemeStore } from './theme-store/async-theme-store.types.ts'
|
|
7
|
+
import type { ThemeStore } from './theme-store/theme-store.types.ts'
|
|
8
|
+
import type { ThemeStoreFactory } from './theme-store/theme-store-factory.types.ts'
|
|
9
|
+
|
|
10
|
+
/** Input item for one position: concrete store or factory config [factory, options?]. */
|
|
11
|
+
export type ComposeThemeStoreEntry<
|
|
12
|
+
Themes extends ThemeMap,
|
|
13
|
+
F extends ThemeStoreFactory<Themes> = never
|
|
14
|
+
> = ThemeStore<Themes> | AsyncThemeStore<Themes> | readonly [F] | readonly [F, Parameters<F>[1]]
|
|
15
|
+
|
|
16
|
+
export type ComposeThemeStoresOptions<Themes extends ThemeMap> = {
|
|
17
|
+
defaultTheme?: keyof Themes | undefined
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Composes multiple theme stores into a single store.
|
|
22
|
+
*
|
|
23
|
+
* Accepts concrete stores or store factory tuples `[factory]` or `[factory, options]`.
|
|
24
|
+
* For factory tuples, calls `factory(themes)` or `factory(themes, options)` to create stores.
|
|
25
|
+
*
|
|
26
|
+
* - **read**: Returns first non-empty `ThemeEntry` from stores (waterfall). When all empty
|
|
27
|
+
* and `defaultTheme` is defined, returns `themeEntry(themes, defaultTheme)`.
|
|
28
|
+
* - **write**: Delegates to `setThemeToStores` (writes to all stores with write).
|
|
29
|
+
* - **subscribe**: Aggregates child store subscriptions. No initial notify—handler is only
|
|
30
|
+
* called when a child store emits.
|
|
31
|
+
*
|
|
32
|
+
* @param themes - ThemeMap for synthesizing fallback ThemeEntry
|
|
33
|
+
* @param stores - Array of theme stores or factory configs [factory, options?]
|
|
34
|
+
* @param options.defaultTheme - Fallback theme key when all stores return empty
|
|
35
|
+
* @returns AsyncThemeStore
|
|
36
|
+
*/
|
|
37
|
+
export function composeThemeStores<
|
|
38
|
+
Themes extends ThemeMap,
|
|
39
|
+
A extends ThemeStoreFactory<Themes> = never,
|
|
40
|
+
B extends ThemeStoreFactory<Themes> = never,
|
|
41
|
+
C extends ThemeStoreFactory<Themes> = never,
|
|
42
|
+
D extends ThemeStoreFactory<Themes> = never,
|
|
43
|
+
E extends ThemeStoreFactory<Themes> = never,
|
|
44
|
+
F extends ThemeStoreFactory<Themes> = never,
|
|
45
|
+
G extends ThemeStoreFactory<Themes> = never,
|
|
46
|
+
H extends ThemeStoreFactory<Themes> = never
|
|
47
|
+
>(
|
|
48
|
+
themes: Themes,
|
|
49
|
+
stores: readonly [
|
|
50
|
+
store1: ComposeThemeStoreEntry<Themes, A>,
|
|
51
|
+
store2?: ComposeThemeStoreEntry<Themes, B>,
|
|
52
|
+
store3?: ComposeThemeStoreEntry<Themes, C>,
|
|
53
|
+
store4?: ComposeThemeStoreEntry<Themes, D>,
|
|
54
|
+
store5?: ComposeThemeStoreEntry<Themes, E>,
|
|
55
|
+
store6?: ComposeThemeStoreEntry<Themes, F>,
|
|
56
|
+
store7?: ComposeThemeStoreEntry<Themes, G>,
|
|
57
|
+
store8?: ComposeThemeStoreEntry<Themes, H>
|
|
58
|
+
],
|
|
59
|
+
options?: ComposeThemeStoresOptions<Themes> | undefined
|
|
60
|
+
): Required<AsyncThemeStore<Themes>> {
|
|
61
|
+
const { defaultTheme } = options ?? {}
|
|
62
|
+
const resolved = resolveStores(themes, stores)
|
|
63
|
+
const withRead = resolved.filter((s): s is StoreWithRead<Themes> => typeof s.read === 'function')
|
|
64
|
+
|
|
65
|
+
async function readFromStores(): Promise<ThemeEntry<Themes> | undefined> {
|
|
66
|
+
for (const store of withRead) {
|
|
67
|
+
const result = await Promise.resolve(store.read())
|
|
68
|
+
if (result !== undefined) return result
|
|
69
|
+
}
|
|
70
|
+
return defaultTheme !== undefined ? themeEntry(themes, defaultTheme) : undefined
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const withSubscribe = resolved.filter(
|
|
74
|
+
(s): s is StoreWithSubscribe<Themes> => typeof s.subscribe === 'function'
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
function subscribe(handler: (theme: ThemeEntry<Themes> | undefined | null) => void): () => void {
|
|
78
|
+
let scheduled = false
|
|
79
|
+
let lastEmitted: keyof Themes | undefined
|
|
80
|
+
|
|
81
|
+
const scheduleNotify = () => {
|
|
82
|
+
if (scheduled) return
|
|
83
|
+
scheduled = true
|
|
84
|
+
queueMicrotask(async () => {
|
|
85
|
+
scheduled = false
|
|
86
|
+
const entry = await readFromStores()
|
|
87
|
+
const key = entry?.theme ?? undefined
|
|
88
|
+
if (key === lastEmitted) return
|
|
89
|
+
lastEmitted = key
|
|
90
|
+
handler(entry ?? undefined)
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const unSubs = withSubscribe.map((s) => s.subscribe!((_result) => scheduleNotify()))
|
|
95
|
+
|
|
96
|
+
return () => {
|
|
97
|
+
for (const unSub of unSubs) {
|
|
98
|
+
unSub()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
read: readFromStores,
|
|
105
|
+
write(entry) {
|
|
106
|
+
return setThemeToStores(resolved, entry)
|
|
107
|
+
},
|
|
108
|
+
subscribe: withSubscribe.length > 0 ? subscribe : () => () => {}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
type StoreWithRead<Themes extends ThemeMap> = RequiredPick<AsyncThemeStore<Themes>, 'read'>
|
|
113
|
+
|
|
114
|
+
type StoreWithSubscribe<Themes extends ThemeMap> = RequiredPick<
|
|
115
|
+
AsyncThemeStore<Themes>,
|
|
116
|
+
'subscribe'
|
|
117
|
+
>
|
|
118
|
+
|
|
119
|
+
function resolveStores<Themes extends ThemeMap>(
|
|
120
|
+
themes: Themes,
|
|
121
|
+
stores: readonly [
|
|
122
|
+
store1: ComposeThemeStoreEntry<Themes, any>,
|
|
123
|
+
store2?: ComposeThemeStoreEntry<Themes, any>,
|
|
124
|
+
store3?: ComposeThemeStoreEntry<Themes, any>,
|
|
125
|
+
store4?: ComposeThemeStoreEntry<Themes, any>,
|
|
126
|
+
store5?: ComposeThemeStoreEntry<Themes, any>,
|
|
127
|
+
store6?: ComposeThemeStoreEntry<Themes, any>,
|
|
128
|
+
store7?: ComposeThemeStoreEntry<Themes, any>,
|
|
129
|
+
store8?: ComposeThemeStoreEntry<Themes, any>
|
|
130
|
+
]
|
|
131
|
+
): (ThemeStore<Themes> | AsyncThemeStore<Themes>)[] {
|
|
132
|
+
return stores.map((item) => {
|
|
133
|
+
if (Array.isArray(item)) {
|
|
134
|
+
const [factory, options] = item
|
|
135
|
+
return (factory as (t: Themes, o?: unknown) => ThemeStore<Themes>)(themes, options)
|
|
136
|
+
}
|
|
137
|
+
return item as ThemeStore<Themes> | AsyncThemeStore<Themes>
|
|
138
|
+
})
|
|
139
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ThemeEntry } from '../theme-entry.types.ts'
|
|
2
|
+
import type { ThemeMap } from '../theme-map.types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Applies theme to element by setting or removing a data attribute.
|
|
6
|
+
*
|
|
7
|
+
* @param element - Target element
|
|
8
|
+
* @param attributeName - Data attribute name (e.g. `data-theme`)
|
|
9
|
+
* @param entry - Theme entry to apply, or undefined to remove attribute
|
|
10
|
+
*/
|
|
11
|
+
export function applyThemeToDataAttribute<Themes extends ThemeMap>(
|
|
12
|
+
element: Element,
|
|
13
|
+
attributeName: `data-${string}`,
|
|
14
|
+
entry: ThemeEntry<Themes> | undefined
|
|
15
|
+
): void {
|
|
16
|
+
if (entry === undefined) {
|
|
17
|
+
element.removeAttribute(attributeName)
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
const val = entry.value
|
|
21
|
+
const attributeValue = Array.isArray(val) ? val[0] : val
|
|
22
|
+
if (attributeValue !== undefined && attributeValue !== '') {
|
|
23
|
+
element.setAttribute(attributeName, attributeValue)
|
|
24
|
+
} else {
|
|
25
|
+
element.removeAttribute(attributeName)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { findKey } from 'type-plus'
|
|
2
|
+
import type { ThemeMap } from '../theme-map.types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolves theme key from data attribute value by matching against theme map.
|
|
6
|
+
*
|
|
7
|
+
* @param attrValue - Data attribute value (e.g. from getAttribute)
|
|
8
|
+
* @param themes - Record mapping theme keys to attribute values
|
|
9
|
+
* @returns Theme key if a match is found, otherwise undefined
|
|
10
|
+
*/
|
|
11
|
+
export function resolveThemeFromDataAttribute<Theme extends string>(
|
|
12
|
+
themes: ThemeMap<Theme>,
|
|
13
|
+
attrValue: string | null
|
|
14
|
+
): Theme | undefined {
|
|
15
|
+
if (attrValue === null || attrValue === '') return undefined
|
|
16
|
+
const theme = findKey(themes, (key) => {
|
|
17
|
+
const value = themes[key]
|
|
18
|
+
if (value === undefined) return false
|
|
19
|
+
const v = Array.isArray(value) ? value[0] : value
|
|
20
|
+
return v === attrValue
|
|
21
|
+
})
|
|
22
|
+
return theme as Theme | undefined
|
|
23
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ThemeEntry } from './theme-entry.types.ts'
|
|
2
|
+
import type { ThemeMap } from './theme-map.types.ts'
|
|
3
|
+
|
|
4
|
+
/** Creates ThemeEntry from theme map and theme key. */
|
|
5
|
+
export function themeEntry<Themes extends ThemeMap>(
|
|
6
|
+
themes: Themes,
|
|
7
|
+
theme: keyof Themes
|
|
8
|
+
): ThemeEntry<Themes> {
|
|
9
|
+
return { theme, value: themes[theme] }
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ThemeMap } from './theme-map.types.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Theme entry is a pair of theme key and theme value.
|
|
5
|
+
*
|
|
6
|
+
* It is the basic value persisted by the theme stores.
|
|
7
|
+
*/
|
|
8
|
+
export interface ThemeEntry<Themes extends ThemeMap = ThemeMap> {
|
|
9
|
+
theme: keyof Themes
|
|
10
|
+
value: Themes[keyof Themes]
|
|
11
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Record mapping theme keys to their values.
|
|
3
|
+
* Each value can be a single string or readonly string[] (e.g. multiple CSS classes).
|
|
4
|
+
* Used by all ThemeStore factories via the themes option.
|
|
5
|
+
*/
|
|
6
|
+
export type ThemeMap<Theme extends string = string> = Record<Theme, string | readonly string[]>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ThemeEntry } from '../theme-entry.types.ts'
|
|
2
|
+
import type { ThemeMap } from '../theme-map.types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Async variant of `ThemeStore` where read and write may return promises.
|
|
6
|
+
* Use for remote persistence, polling, or WebSocket-based sync.
|
|
7
|
+
*
|
|
8
|
+
* Same optional methods as `ThemeStore`:
|
|
9
|
+
*
|
|
10
|
+
* - **read** – Can return `Promise<ThemeEntry | undefined>` for async sources
|
|
11
|
+
* - **write** – Can return `Promise<void>` for async persistence
|
|
12
|
+
* - **subscribe** – Same signature as sync; observes external changes
|
|
13
|
+
*
|
|
14
|
+
* @typeParam Themes - Map of theme keys to their value types (string or readonly string[])
|
|
15
|
+
*/
|
|
16
|
+
export interface AsyncThemeStore<Themes extends ThemeMap = ThemeMap> {
|
|
17
|
+
read?:
|
|
18
|
+
| (() => ThemeEntry<Themes> | undefined | Promise<ThemeEntry<Themes> | undefined>)
|
|
19
|
+
| undefined
|
|
20
|
+
write?: ((entry: ThemeEntry<Themes> | undefined) => void | Promise<void>) | undefined
|
|
21
|
+
subscribe?:
|
|
22
|
+
| ((handler: (entry: ThemeEntry<Themes> | undefined | null) => void) => () => void)
|
|
23
|
+
| undefined
|
|
24
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Required } from 'type-plus'
|
|
2
|
+
import { observeAttributes } from '../../../attributes/observe-attribute.ts'
|
|
3
|
+
import { dummyThemeStore } from '../../../testing/theme/dummy-theme-store.ts'
|
|
4
|
+
import { applyThemeToClassName } from '../../class-name/apply-theme-to-class-name.ts'
|
|
5
|
+
import { resolveThemeFromClassName } from '../../class-name/resolve-theme-from-class-name.ts'
|
|
6
|
+
import { themeEntry } from '../../theme-entry.ts'
|
|
7
|
+
import type { ThemeMap } from '../../theme-map.types.ts'
|
|
8
|
+
import type { ThemeStore } from '../theme-store.types.ts'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a theme store that reads and writes via element class names.
|
|
12
|
+
*
|
|
13
|
+
* @param themes - Record mapping theme keys to class name(s)
|
|
14
|
+
* @param options.element - Element to operate on (defaults to document.documentElement)
|
|
15
|
+
* @returns ThemeStore
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const themes = { current: 'theme-current', grayscale: 'theme-grayscale' }
|
|
20
|
+
* const store = classNameThemeStore(themes)
|
|
21
|
+
* store.read() // returns themeResult from element.className
|
|
22
|
+
* store.write(themeEntry(themes, 'grayscale'))
|
|
23
|
+
* store.subscribe((themeResult) => {})
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function classNameThemeStore<Themes extends ThemeMap>(
|
|
27
|
+
themes: Themes,
|
|
28
|
+
options?: { element?: Element | undefined }
|
|
29
|
+
): Required<ThemeStore<Themes>> {
|
|
30
|
+
const element = options?.element ?? document?.documentElement
|
|
31
|
+
|
|
32
|
+
if (!element) return dummyThemeStore
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
read() {
|
|
36
|
+
const theme = resolveThemeFromClassName(themes, element.className)
|
|
37
|
+
if (theme === undefined) return undefined
|
|
38
|
+
return themeEntry(themes, theme)
|
|
39
|
+
},
|
|
40
|
+
write(entry) {
|
|
41
|
+
applyThemeToClassName(themes, element, entry)
|
|
42
|
+
},
|
|
43
|
+
subscribe(handler) {
|
|
44
|
+
let lastEmitted: keyof Themes | undefined | null = null
|
|
45
|
+
const observer = observeAttributes(
|
|
46
|
+
{
|
|
47
|
+
class: (value) => {
|
|
48
|
+
const theme = value ? resolveThemeFromClassName(themes, value) : undefined
|
|
49
|
+
const entry = theme ? themeEntry(themes, theme) : undefined
|
|
50
|
+
const key = theme ?? undefined
|
|
51
|
+
|
|
52
|
+
if (lastEmitted === key) return
|
|
53
|
+
lastEmitted = key
|
|
54
|
+
handler(entry)
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
element
|
|
58
|
+
)
|
|
59
|
+
return () => observer.disconnect()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|