@charcoal-ui/react 6.0.0-rc.6 → 6.0.0-rc.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/dist/_lib/createDivComponent.cjs +20 -0
- package/dist/_lib/createDivComponent.cjs.map +1 -0
- package/dist/_lib/createDivComponent.js +19 -0
- package/dist/_lib/createDivComponent.js.map +1 -0
- package/dist/_lib/index.cjs +22 -0
- package/dist/_lib/index.cjs.map +1 -0
- package/dist/_lib/index.js +20 -0
- package/dist/_lib/index.js.map +1 -0
- package/dist/_lib/useClassNames.cjs +15 -0
- package/dist/_lib/useClassNames.cjs.map +1 -0
- package/dist/_lib/useClassNames.js +14 -0
- package/dist/_lib/useClassNames.js.map +1 -0
- package/dist/_lib/useForwardedRef.cjs +19 -0
- package/dist/_lib/useForwardedRef.cjs.map +1 -0
- package/dist/_lib/useForwardedRef.js +17 -0
- package/dist/_lib/useForwardedRef.js.map +1 -0
- package/dist/_lib/useIsomorphicLayoutEffect.cjs +13 -0
- package/dist/_lib/useIsomorphicLayoutEffect.cjs.map +1 -0
- package/dist/_lib/useIsomorphicLayoutEffect.js +12 -0
- package/dist/_lib/useIsomorphicLayoutEffect.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.cjs +30 -0
- package/dist/components/Button/index2.cjs +26 -0
- package/dist/components/Button/index2.cjs.map +1 -0
- package/dist/components/Button/index2.js +24 -0
- package/dist/components/Button/index2.js.map +1 -0
- package/dist/components/Carousel/CarouselItem.cjs +46 -0
- package/dist/components/Carousel/CarouselItem.cjs.map +1 -0
- package/dist/components/Carousel/CarouselItem.js +45 -0
- package/dist/components/Carousel/CarouselItem.js.map +1 -0
- package/dist/components/Carousel/carouselStore.cjs +38 -0
- package/dist/components/Carousel/carouselStore.cjs.map +1 -0
- package/dist/components/Carousel/carouselStore.js +37 -0
- package/dist/components/Carousel/carouselStore.js.map +1 -0
- package/dist/components/Carousel/index.d.ts +2 -0
- package/dist/components/Carousel/index.d.ts.map +1 -1
- package/dist/components/Carousel/index2.cjs +145 -0
- package/dist/components/Carousel/index2.cjs.map +1 -0
- package/dist/components/Carousel/index2.js +144 -0
- package/dist/components/Carousel/index2.js.map +1 -0
- package/dist/components/Carousel/intersectionObserver.cjs +46 -0
- package/dist/components/Carousel/intersectionObserver.cjs.map +1 -0
- package/dist/components/Carousel/intersectionObserver.js +45 -0
- package/dist/components/Carousel/intersectionObserver.js.map +1 -0
- package/dist/components/Carousel/resizeObserver.cjs +34 -0
- package/dist/components/Carousel/resizeObserver.cjs.map +1 -0
- package/dist/components/Carousel/resizeObserver.js +33 -0
- package/dist/components/Carousel/resizeObserver.js.map +1 -0
- package/dist/components/Carousel/store.cjs +24 -0
- package/dist/components/Carousel/store.cjs.map +1 -0
- package/dist/components/Carousel/store.js +23 -0
- package/dist/components/Carousel/store.js.map +1 -0
- package/dist/components/Carousel/useCarouselScroller.cjs +149 -0
- package/dist/components/Carousel/useCarouselScroller.cjs.map +1 -0
- package/dist/components/Carousel/useCarouselScroller.js +148 -0
- package/dist/components/Carousel/useCarouselScroller.js.map +1 -0
- package/dist/components/Checkbox/CheckboxInput/index2.cjs +29 -0
- package/dist/components/Checkbox/CheckboxInput/index2.cjs.map +1 -0
- package/dist/components/Checkbox/CheckboxInput/index2.js +28 -0
- package/dist/components/Checkbox/CheckboxInput/index2.js.map +1 -0
- package/dist/components/Checkbox/CheckboxWithLabel.cjs +23 -0
- package/dist/components/Checkbox/CheckboxWithLabel.cjs.map +1 -0
- package/dist/components/Checkbox/CheckboxWithLabel.js +21 -0
- package/dist/components/Checkbox/CheckboxWithLabel.js.map +1 -0
- package/dist/components/Checkbox/index2.cjs +34 -0
- package/dist/components/Checkbox/index2.cjs.map +1 -0
- package/dist/components/Checkbox/index2.js +33 -0
- package/dist/components/Checkbox/index2.js.map +1 -0
- package/dist/components/Clickable/index2.cjs +21 -0
- package/dist/components/Clickable/index2.cjs.map +1 -0
- package/dist/components/Clickable/index2.js +19 -0
- package/dist/components/Clickable/index2.js.map +1 -0
- package/dist/components/DropdownSelector/DropdownMenuItem/index2.cjs +44 -0
- package/dist/components/DropdownSelector/DropdownMenuItem/index2.cjs.map +1 -0
- package/dist/components/DropdownSelector/DropdownMenuItem/index2.js +43 -0
- package/dist/components/DropdownSelector/DropdownMenuItem/index2.js.map +1 -0
- package/dist/components/DropdownSelector/DropdownPopover.cjs +41 -0
- package/dist/components/DropdownSelector/DropdownPopover.cjs.map +1 -0
- package/dist/components/DropdownSelector/DropdownPopover.js +40 -0
- package/dist/components/DropdownSelector/DropdownPopover.js.map +1 -0
- package/dist/components/DropdownSelector/ListItem/index2.cjs +19 -0
- package/dist/components/DropdownSelector/ListItem/index2.cjs.map +1 -0
- package/dist/components/DropdownSelector/ListItem/index2.js +18 -0
- package/dist/components/DropdownSelector/ListItem/index2.js.map +1 -0
- package/dist/components/DropdownSelector/MenuItem/index.cjs +30 -0
- package/dist/components/DropdownSelector/MenuItem/index.cjs.map +1 -0
- package/dist/components/DropdownSelector/MenuItem/index.js +29 -0
- package/dist/components/DropdownSelector/MenuItem/index.js.map +1 -0
- package/dist/components/DropdownSelector/MenuItem/internals/handleFocusByKeyBoard.cjs +30 -0
- package/dist/components/DropdownSelector/MenuItem/internals/handleFocusByKeyBoard.cjs.map +1 -0
- package/dist/components/DropdownSelector/MenuItem/internals/handleFocusByKeyBoard.js +29 -0
- package/dist/components/DropdownSelector/MenuItem/internals/handleFocusByKeyBoard.js.map +1 -0
- package/dist/components/DropdownSelector/MenuItem/internals/useMenuItemHandleKeyDown.cjs +53 -0
- package/dist/components/DropdownSelector/MenuItem/internals/useMenuItemHandleKeyDown.cjs.map +1 -0
- package/dist/components/DropdownSelector/MenuItem/internals/useMenuItemHandleKeyDown.js +52 -0
- package/dist/components/DropdownSelector/MenuItem/internals/useMenuItemHandleKeyDown.js.map +1 -0
- package/dist/components/DropdownSelector/MenuItemGroup/index2.cjs +20 -0
- package/dist/components/DropdownSelector/MenuItemGroup/index2.cjs.map +1 -0
- package/dist/components/DropdownSelector/MenuItemGroup/index2.js +19 -0
- package/dist/components/DropdownSelector/MenuItemGroup/index2.js.map +1 -0
- package/dist/components/DropdownSelector/MenuList/MenuListContext.cjs +15 -0
- package/dist/components/DropdownSelector/MenuList/MenuListContext.cjs.map +1 -0
- package/dist/components/DropdownSelector/MenuList/MenuListContext.js +14 -0
- package/dist/components/DropdownSelector/MenuList/MenuListContext.js.map +1 -0
- package/dist/components/DropdownSelector/MenuList/index2.cjs +32 -0
- package/dist/components/DropdownSelector/MenuList/index2.cjs.map +1 -0
- package/dist/components/DropdownSelector/MenuList/index2.js +31 -0
- package/dist/components/DropdownSelector/MenuList/index2.js.map +1 -0
- package/dist/components/DropdownSelector/MenuList/internals/getValuesRecursive.cjs +34 -0
- package/dist/components/DropdownSelector/MenuList/internals/getValuesRecursive.cjs.map +1 -0
- package/dist/components/DropdownSelector/MenuList/internals/getValuesRecursive.js +32 -0
- package/dist/components/DropdownSelector/MenuList/internals/getValuesRecursive.js.map +1 -0
- package/dist/components/DropdownSelector/Popover/index2.cjs +71 -0
- package/dist/components/DropdownSelector/Popover/index2.cjs.map +1 -0
- package/dist/components/DropdownSelector/Popover/index2.js +70 -0
- package/dist/components/DropdownSelector/Popover/index2.js.map +1 -0
- package/dist/components/DropdownSelector/Popover/usePreventScroll.cjs +27 -0
- package/dist/components/DropdownSelector/Popover/usePreventScroll.cjs.map +1 -0
- package/dist/components/DropdownSelector/Popover/usePreventScroll.js +26 -0
- package/dist/components/DropdownSelector/Popover/usePreventScroll.js.map +1 -0
- package/dist/components/DropdownSelector/index2.cjs +113 -0
- package/dist/components/DropdownSelector/index2.cjs.map +1 -0
- package/dist/components/DropdownSelector/index2.js +111 -0
- package/dist/components/DropdownSelector/index2.js.map +1 -0
- package/dist/components/DropdownSelector/utils/findPreviewRecursive.cjs +34 -0
- package/dist/components/DropdownSelector/utils/findPreviewRecursive.cjs.map +1 -0
- package/dist/components/DropdownSelector/utils/findPreviewRecursive.js +32 -0
- package/dist/components/DropdownSelector/utils/findPreviewRecursive.js.map +1 -0
- package/dist/components/FieldLabel/index2.cjs +35 -0
- package/dist/components/FieldLabel/index2.cjs.map +1 -0
- package/dist/components/FieldLabel/index2.js +33 -0
- package/dist/components/FieldLabel/index2.js.map +1 -0
- package/dist/components/HintText/index2.cjs +25 -0
- package/dist/components/HintText/index2.cjs.map +1 -0
- package/dist/components/HintText/index2.js +24 -0
- package/dist/components/HintText/index2.js.map +1 -0
- package/dist/components/Icon/index.cjs +39 -0
- package/dist/components/Icon/index.cjs.map +1 -0
- package/dist/components/Icon/index.js +37 -0
- package/dist/components/Icon/index.js.map +1 -0
- package/dist/components/IconButton/index2.cjs +46 -0
- package/dist/components/IconButton/index2.cjs.map +1 -0
- package/dist/components/IconButton/index2.js +44 -0
- package/dist/components/IconButton/index2.js.map +1 -0
- package/dist/components/LoadingSpinner/index2.cjs +43 -0
- package/dist/components/LoadingSpinner/index2.cjs.map +1 -0
- package/dist/components/LoadingSpinner/index2.js +41 -0
- package/dist/components/LoadingSpinner/index2.js.map +1 -0
- package/dist/components/Modal/Dialog/index2.cjs +30 -0
- package/dist/components/Modal/Dialog/index2.cjs.map +1 -0
- package/dist/components/Modal/Dialog/index2.js +28 -0
- package/dist/components/Modal/Dialog/index2.js.map +1 -0
- package/dist/components/Modal/ModalBackgroundContext.cjs +14 -0
- package/dist/components/Modal/ModalBackgroundContext.cjs.map +1 -0
- package/dist/components/Modal/ModalBackgroundContext.js +12 -0
- package/dist/components/Modal/ModalBackgroundContext.js.map +1 -0
- package/dist/components/Modal/ModalPlumbing2.cjs +30 -0
- package/dist/components/Modal/ModalPlumbing2.cjs.map +1 -0
- package/dist/components/Modal/ModalPlumbing2.js +26 -0
- package/dist/components/Modal/ModalPlumbing2.js.map +1 -0
- package/dist/components/Modal/index2.cjs +121 -0
- package/dist/components/Modal/index2.cjs.map +1 -0
- package/dist/components/Modal/index2.js +118 -0
- package/dist/components/Modal/index2.js.map +1 -0
- package/dist/components/Modal/useCustomModalOverlay.cjs +48 -0
- package/dist/components/Modal/useCustomModalOverlay.cjs.map +1 -0
- package/dist/components/Modal/useCustomModalOverlay.js +45 -0
- package/dist/components/Modal/useCustomModalOverlay.js.map +1 -0
- package/dist/components/Modal/useTransitionPresence.cjs +57 -0
- package/dist/components/Modal/useTransitionPresence.cjs.map +1 -0
- package/dist/components/Modal/useTransitionPresence.js +56 -0
- package/dist/components/Modal/useTransitionPresence.js.map +1 -0
- package/dist/components/MultiSelect/context.cjs +19 -0
- package/dist/components/MultiSelect/context.cjs.map +1 -0
- package/dist/components/MultiSelect/context.js +18 -0
- package/dist/components/MultiSelect/context.js.map +1 -0
- package/dist/components/MultiSelect/index2.cjs +97 -0
- package/dist/components/MultiSelect/index2.cjs.map +1 -0
- package/dist/components/MultiSelect/index2.js +93 -0
- package/dist/components/MultiSelect/index2.js.map +1 -0
- package/dist/components/Pagination/PaginationContext.cjs +16 -0
- package/dist/components/Pagination/PaginationContext.cjs.map +1 -0
- package/dist/components/Pagination/PaginationContext.js +14 -0
- package/dist/components/Pagination/PaginationContext.js.map +1 -0
- package/dist/components/Pagination/helper.cjs +63 -0
- package/dist/components/Pagination/helper.cjs.map +1 -0
- package/dist/components/Pagination/helper.js +61 -0
- package/dist/components/Pagination/helper.js.map +1 -0
- package/dist/components/Pagination/index2.cjs +301 -0
- package/dist/components/Pagination/index2.cjs.map +1 -0
- package/dist/components/Pagination/index2.js +288 -0
- package/dist/components/Pagination/index2.js.map +1 -0
- package/dist/components/Radio/RadioGroup/index2.cjs +49 -0
- package/dist/components/Radio/RadioGroup/index2.cjs.map +1 -0
- package/dist/components/Radio/RadioGroup/index2.js +47 -0
- package/dist/components/Radio/RadioGroup/index2.js.map +1 -0
- package/dist/components/Radio/RadioGroupContext.cjs +20 -0
- package/dist/components/Radio/RadioGroupContext.cjs.map +1 -0
- package/dist/components/Radio/RadioGroupContext.js +18 -0
- package/dist/components/Radio/RadioGroupContext.js.map +1 -0
- package/dist/components/Radio/RadioInput/index2.cjs +27 -0
- package/dist/components/Radio/RadioInput/index2.cjs.map +1 -0
- package/dist/components/Radio/RadioInput/index2.js +26 -0
- package/dist/components/Radio/RadioInput/index2.js.map +1 -0
- package/dist/components/Radio/index2.cjs +42 -0
- package/dist/components/Radio/index2.cjs.map +1 -0
- package/dist/components/Radio/index2.js +39 -0
- package/dist/components/Radio/index2.js.map +1 -0
- package/dist/components/SegmentedControl/RadioGroupContext.cjs +24 -0
- package/dist/components/SegmentedControl/RadioGroupContext.cjs.map +1 -0
- package/dist/components/SegmentedControl/RadioGroupContext.js +21 -0
- package/dist/components/SegmentedControl/RadioGroupContext.js.map +1 -0
- package/dist/components/SegmentedControl/index2.cjs +72 -0
- package/dist/components/SegmentedControl/index2.cjs.map +1 -0
- package/dist/components/SegmentedControl/index2.js +70 -0
- package/dist/components/SegmentedControl/index2.js.map +1 -0
- package/dist/components/Switch/SwitchInput/index2.cjs +25 -0
- package/dist/components/Switch/SwitchInput/index2.cjs.map +1 -0
- package/dist/components/Switch/SwitchInput/index2.js +24 -0
- package/dist/components/Switch/SwitchInput/index2.js.map +1 -0
- package/dist/components/Switch/SwitchWithLabel.cjs +23 -0
- package/dist/components/Switch/SwitchWithLabel.cjs.map +1 -0
- package/dist/components/Switch/SwitchWithLabel.js +21 -0
- package/dist/components/Switch/SwitchWithLabel.js.map +1 -0
- package/dist/components/Switch/index2.cjs +37 -0
- package/dist/components/Switch/index2.cjs.map +1 -0
- package/dist/components/Switch/index2.js +36 -0
- package/dist/components/Switch/index2.js.map +1 -0
- package/dist/components/TagItem/index.d.ts.map +1 -1
- package/dist/components/TagItem/index2.cjs +57 -0
- package/dist/components/TagItem/index2.cjs.map +1 -0
- package/dist/components/TagItem/index2.js +55 -0
- package/dist/components/TagItem/index2.js.map +1 -0
- package/dist/components/TextArea/index2.cjs +134 -0
- package/dist/components/TextArea/index2.cjs.map +1 -0
- package/dist/components/TextArea/index2.js +133 -0
- package/dist/components/TextArea/index2.js.map +1 -0
- package/dist/components/TextEllipsis/helper.cjs +31 -0
- package/dist/components/TextEllipsis/helper.cjs.map +1 -0
- package/dist/components/TextEllipsis/helper.js +30 -0
- package/dist/components/TextEllipsis/helper.js.map +1 -0
- package/dist/components/TextEllipsis/index2.cjs +119 -0
- package/dist/components/TextEllipsis/index2.cjs.map +1 -0
- package/dist/components/TextEllipsis/index2.js +114 -0
- package/dist/components/TextEllipsis/index2.js.map +1 -0
- package/dist/components/TextField/AssistiveText/index2.cjs +10 -0
- package/dist/components/TextField/AssistiveText/index2.cjs.map +1 -0
- package/dist/components/TextField/AssistiveText/index2.js +10 -0
- package/dist/components/TextField/AssistiveText/index2.js.map +1 -0
- package/dist/components/TextField/index2.cjs +101 -0
- package/dist/components/TextField/index2.cjs.map +1 -0
- package/dist/components/TextField/index2.js +100 -0
- package/dist/components/TextField/index2.js.map +1 -0
- package/dist/components/TextField/useFocusWithClick.cjs +23 -0
- package/dist/components/TextField/useFocusWithClick.cjs.map +1 -0
- package/dist/components/TextField/useFocusWithClick.js +22 -0
- package/dist/components/TextField/useFocusWithClick.js.map +1 -0
- package/dist/core/CharcoalProvider.cjs +16 -0
- package/dist/core/CharcoalProvider.cjs.map +1 -0
- package/dist/core/CharcoalProvider.js +14 -0
- package/dist/core/CharcoalProvider.js.map +1 -0
- package/dist/core/OverlayProvider.js +4 -0
- package/dist/core/SSRProvider.cjs +15 -0
- package/dist/core/SSRProvider.cjs.map +1 -0
- package/dist/core/SSRProvider.js +14 -0
- package/dist/core/SSRProvider.js.map +1 -0
- package/dist/core/SetThemeScript.cjs +45 -0
- package/dist/core/SetThemeScript.cjs.map +1 -0
- package/dist/core/SetThemeScript.js +43 -0
- package/dist/core/SetThemeScript.js.map +1 -0
- package/dist/core/themeHelper.cjs +154 -0
- package/dist/core/themeHelper.cjs.map +1 -0
- package/dist/core/themeHelper.js +143 -0
- package/dist/core/themeHelper.js.map +1 -0
- package/dist/index.cjs +81 -12
- package/dist/index.css +1380 -1355
- package/dist/index.js +31 -12
- package/dist/layered.css +1376 -1351
- package/dist/layered.css.map +1 -1
- package/package.json +5 -5
- package/src/components/Carousel/MIGRATION.md +8 -8
- package/src/components/Carousel/__snapshots__/index.css.snap +4 -2
- package/src/components/Carousel/index.css +5 -2
- package/src/components/Carousel/index.story.tsx +14 -12
- package/src/components/Carousel/index.test.tsx +24 -0
- package/src/components/Carousel/index.tsx +17 -0
- package/src/components/TagItem/index.test.tsx +38 -0
- package/src/components/TagItem/index.tsx +1 -0
- package/src/components/TextArea/__snapshots__/index.css.snap +29 -8
- package/src/components/TextArea/index.css +30 -8
- package/src/components/TextArea/index.tsx +1 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/components/TextField/useFocusWithClick.tsx
|
|
5
|
+
function useFocusWithClick(containerRef, inputRef) {
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const el = containerRef.current;
|
|
8
|
+
if (el) {
|
|
9
|
+
const handleDown = (e) => {
|
|
10
|
+
if (e.target !== inputRef.current) inputRef.current?.focus();
|
|
11
|
+
};
|
|
12
|
+
el.addEventListener("click", handleDown);
|
|
13
|
+
return () => {
|
|
14
|
+
el.removeEventListener("click", handleDown);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { useFocusWithClick };
|
|
22
|
+
//# sourceMappingURL=useFocusWithClick.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFocusWithClick.js","names":["useEffect","React","useFocusWithClick","containerRef","RefObject","HTMLDivElement","inputRef","HTMLInputElement","HTMLTextAreaElement","el","current","handleDown","e","MouseEvent","target","focus","addEventListener","removeEventListener"],"sources":["../../../src/components/TextField/useFocusWithClick.tsx"],"sourcesContent":["import { useEffect } from 'react'\nimport * as React from 'react'\n\nexport function useFocusWithClick(\n containerRef: React.RefObject<HTMLDivElement | null>,\n inputRef: React.RefObject<HTMLInputElement | HTMLTextAreaElement | null>,\n) {\n useEffect(() => {\n const el = containerRef.current\n if (el) {\n const handleDown = (e: MouseEvent) => {\n if (e.target !== inputRef.current) {\n inputRef.current?.focus()\n }\n }\n el.addEventListener('click', handleDown)\n return () => {\n el.removeEventListener('click', handleDown)\n }\n }\n })\n}\n"],"mappings":";;;;AAGA,SAAgBE,kBACdC,cACAG,UACA;CACAN,gBAAgB;EACd,MAAMS,KAAKN,aAAaO;EACxB,IAAID,IAAI;GACN,MAAME,cAAcC,MAAkB;IACpC,IAAIA,EAAEE,WAAWR,SAASI,SACxBJ,SAASI,SAASK,OAAO;;GAG7BN,GAAGO,iBAAiB,SAASL,WAAW;GACxC,aAAa;IACXF,GAAGQ,oBAAoB,SAASN,WAAW;;;GAG/C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_SSRProvider = require('./SSRProvider.cjs');
|
|
4
|
+
let react = require("react");
|
|
5
|
+
react = require_runtime.__toESM(react);
|
|
6
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
|
+
let react_aria_private_overlays_useModal = require("react-aria/private/overlays/useModal");
|
|
8
|
+
|
|
9
|
+
//#region src/core/CharcoalProvider.tsx
|
|
10
|
+
function CharcoalProvider({ children }) {
|
|
11
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SSRProvider.SSRProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_aria_private_overlays_useModal.OverlayProvider, { children }) });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
exports.CharcoalProvider = CharcoalProvider;
|
|
16
|
+
//# sourceMappingURL=CharcoalProvider.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CharcoalProvider.cjs","names":["React","OverlayProvider","SSRProvider","CharcoalProviderProps","children","ReactNode","CharcoalProvider"],"sources":["../../src/core/CharcoalProvider.tsx"],"sourcesContent":["import * as React from 'react'\nimport { OverlayProvider } from './OverlayProvider'\nimport { SSRProvider } from './SSRProvider'\n\nexport type CharcoalProviderProps = {\n children: React.ReactNode\n}\n\nexport function CharcoalProvider({ children }: CharcoalProviderProps) {\n return (\n <SSRProvider>\n <OverlayProvider>{children}</OverlayProvider>\n </SSRProvider>\n )\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgBM,iBAAiB,EAAEF,YAAmC;CACpE,OACE,2CAAC,iCAAD,YACE,2CAAC,sDAAD,EAAkBA,UAA0B,GAChC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { SSRProvider } from "./SSRProvider.js";
|
|
3
|
+
import { OverlayProvider } from "./OverlayProvider.js";
|
|
4
|
+
import "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/core/CharcoalProvider.tsx
|
|
8
|
+
function CharcoalProvider({ children }) {
|
|
9
|
+
return /* @__PURE__ */ jsx(SSRProvider, { children: /* @__PURE__ */ jsx(OverlayProvider, { children }) });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { CharcoalProvider };
|
|
14
|
+
//# sourceMappingURL=CharcoalProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CharcoalProvider.js","names":["React","OverlayProvider","SSRProvider","CharcoalProviderProps","children","ReactNode","CharcoalProvider"],"sources":["../../src/core/CharcoalProvider.tsx"],"sourcesContent":["import * as React from 'react'\nimport { OverlayProvider } from './OverlayProvider'\nimport { SSRProvider } from './SSRProvider'\n\nexport type CharcoalProviderProps = {\n children: React.ReactNode\n}\n\nexport function CharcoalProvider({ children }: CharcoalProviderProps) {\n return (\n <SSRProvider>\n <OverlayProvider>{children}</OverlayProvider>\n </SSRProvider>\n )\n}\n"],"mappings":";;;;;;;AAQA,SAAgBM,iBAAiB,EAAEF,YAAmC;CACpE,OACE,oBAAC,aAAD,YACE,oBAAC,iBAAD,EAAkBA,UAA0B,GAChC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
let react = require("react");
|
|
4
|
+
let react_aria_SSRProvider = require("react-aria/SSRProvider");
|
|
5
|
+
|
|
6
|
+
//#region src/core/SSRProvider.tsx
|
|
7
|
+
function isReactVersionOver(minVersion) {
|
|
8
|
+
const reactMajorVersion = parseInt(react.version.split(".")[0], 10);
|
|
9
|
+
return Number.isFinite(reactMajorVersion) ? reactMajorVersion >= minVersion : false;
|
|
10
|
+
}
|
|
11
|
+
const SSRProvider = isReactVersionOver(18) ? react.Fragment : react_aria_SSRProvider.SSRProvider;
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
exports.SSRProvider = SSRProvider;
|
|
15
|
+
//# sourceMappingURL=SSRProvider.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SSRProvider.cjs","names":["version","Fragment","SSRProvider","OriginSSRProvider","isReactVersionOver","minVersion","reactMajorVersion","parseInt","split","Number","isFinite"],"sources":["../../src/core/SSRProvider.tsx"],"sourcesContent":["import { version, Fragment } from 'react'\nimport { SSRProvider as OriginSSRProvider } from 'react-aria/SSRProvider'\n\nexport function isReactVersionOver(minVersion: number): boolean {\n // version history on the react side: https://github.com/facebook/react/commits/main/packages/shared/ReactVersion.js\n const reactMajorVersion = parseInt(version.split('.')[0], 10)\n return Number.isFinite(reactMajorVersion)\n ? reactMajorVersion >= minVersion\n : false\n}\n\nexport const SSRProvider = isReactVersionOver(18) ? Fragment : OriginSSRProvider\n"],"mappings":";;;;;;AAGA,SAAgBI,mBAAmBC,YAA6B;CAE9D,MAAMC,oBAAoBC,SAASP,cAAQQ,MAAM,IAAI,CAAC,IAAI,GAAG;CAC7D,OAAOC,OAAOC,SAASJ,kBAAkB,GACrCA,qBAAqBD,aACrB;;AAGN,MAAaH,cAAcE,mBAAmB,GAAG,GAAGH,iBAAWE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, version } from "react";
|
|
3
|
+
import { SSRProvider } from "react-aria/SSRProvider";
|
|
4
|
+
|
|
5
|
+
//#region src/core/SSRProvider.tsx
|
|
6
|
+
function isReactVersionOver(minVersion) {
|
|
7
|
+
const reactMajorVersion = parseInt(version.split(".")[0], 10);
|
|
8
|
+
return Number.isFinite(reactMajorVersion) ? reactMajorVersion >= minVersion : false;
|
|
9
|
+
}
|
|
10
|
+
const SSRProvider$1 = isReactVersionOver(18) ? Fragment : SSRProvider;
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { SSRProvider$1 as SSRProvider };
|
|
14
|
+
//# sourceMappingURL=SSRProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SSRProvider.js","names":["version","Fragment","SSRProvider","OriginSSRProvider","isReactVersionOver","minVersion","reactMajorVersion","parseInt","split","Number","isFinite"],"sources":["../../src/core/SSRProvider.tsx"],"sourcesContent":["import { version, Fragment } from 'react'\nimport { SSRProvider as OriginSSRProvider } from 'react-aria/SSRProvider'\n\nexport function isReactVersionOver(minVersion: number): boolean {\n // version history on the react side: https://github.com/facebook/react/commits/main/packages/shared/ReactVersion.js\n const reactMajorVersion = parseInt(version.split('.')[0], 10)\n return Number.isFinite(reactMajorVersion)\n ? reactMajorVersion >= minVersion\n : false\n}\n\nexport const SSRProvider = isReactVersionOver(18) ? Fragment : OriginSSRProvider\n"],"mappings":";;;;;AAGA,SAAgBI,mBAAmBC,YAA6B;CAE9D,MAAMC,oBAAoBC,SAASP,QAAQQ,MAAM,IAAI,CAAC,IAAI,GAAG;CAC7D,OAAOC,OAAOC,SAASJ,kBAAkB,GACrCA,qBAAqBD,aACrB;;AAGN,MAAaH,gBAAcE,mBAAmB,GAAG,GAAGH,WAAWE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_themeHelper = require('./themeHelper.cjs');
|
|
4
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
|
+
|
|
6
|
+
//#region src/core/SetThemeScript.tsx
|
|
7
|
+
/**
|
|
8
|
+
* 同期的にテーマをローカルストレージから取得してhtmlの属性に設定するコードを取得する
|
|
9
|
+
* @param props localStorageのキー、htmlのdataになる属性のキーを含むオブジェクト
|
|
10
|
+
* @returns ソースコードの文字列
|
|
11
|
+
*/
|
|
12
|
+
function makeSetThemeScriptCode({ localStorageKey = defaultProps.localStorageKey, rootAttribute = defaultProps.rootAttribute } = defaultProps) {
|
|
13
|
+
require_themeHelper.assertKeyString(localStorageKey);
|
|
14
|
+
require_themeHelper.assertKeyString(rootAttribute);
|
|
15
|
+
return `'use strict';
|
|
16
|
+
(function () {
|
|
17
|
+
var localStorageKey = '${localStorageKey}'
|
|
18
|
+
var rootAttribute = '${rootAttribute}'
|
|
19
|
+
var currentTheme = localStorage.getItem(localStorageKey);
|
|
20
|
+
if (currentTheme) {
|
|
21
|
+
document.documentElement.dataset[rootAttribute] = currentTheme;
|
|
22
|
+
}
|
|
23
|
+
})();
|
|
24
|
+
`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 同期的にテーマをローカルストレージから取得してhtmlの属性に設定するスクリプトタグ
|
|
28
|
+
* @param props localStorageのキー、htmlのdataになる属性のキーを含むオブジェクト
|
|
29
|
+
* @returns
|
|
30
|
+
*/
|
|
31
|
+
function SetThemeScript({ localStorageKey = defaultProps.localStorageKey, rootAttribute = defaultProps.rootAttribute }) {
|
|
32
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("script", { dangerouslySetInnerHTML: { __html: makeSetThemeScriptCode({
|
|
33
|
+
localStorageKey,
|
|
34
|
+
rootAttribute
|
|
35
|
+
}) } });
|
|
36
|
+
}
|
|
37
|
+
const defaultProps = {
|
|
38
|
+
localStorageKey: require_themeHelper.LOCAL_STORAGE_KEY,
|
|
39
|
+
rootAttribute: require_themeHelper.DEFAULT_ROOT_ATTRIBUTE
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
exports.SetThemeScript = SetThemeScript;
|
|
44
|
+
exports.makeSetThemeScriptCode = makeSetThemeScriptCode;
|
|
45
|
+
//# sourceMappingURL=SetThemeScript.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SetThemeScript.cjs","names":["assertKeyString","DEFAULT_ROOT_ATTRIBUTE","LOCAL_STORAGE_KEY","Props","localStorageKey","rootAttribute","makeSetThemeScriptCode","defaultProps","Partial","SetThemeScript","src","__html"],"sources":["../../src/core/SetThemeScript.tsx"],"sourcesContent":["import {\n assertKeyString,\n DEFAULT_ROOT_ATTRIBUTE,\n LOCAL_STORAGE_KEY,\n} from './themeHelper'\n\ninterface Props {\n localStorageKey: string\n rootAttribute: string\n}\n\n/**\n * 同期的にテーマをローカルストレージから取得してhtmlの属性に設定するコードを取得する\n * @param props localStorageのキー、htmlのdataになる属性のキーを含むオブジェクト\n * @returns ソースコードの文字列\n */\nexport function makeSetThemeScriptCode({\n localStorageKey = defaultProps.localStorageKey,\n rootAttribute = defaultProps.rootAttribute,\n}: Partial<Props> = defaultProps) {\n assertKeyString(localStorageKey)\n assertKeyString(rootAttribute)\n return `'use strict';\n(function () {\n var localStorageKey = '${localStorageKey}'\n var rootAttribute = '${rootAttribute}'\n var currentTheme = localStorage.getItem(localStorageKey);\n if (currentTheme) {\n document.documentElement.dataset[rootAttribute] = currentTheme;\n }\n})();\n`\n}\n\n/**\n * 同期的にテーマをローカルストレージから取得してhtmlの属性に設定するスクリプトタグ\n * @param props localStorageのキー、htmlのdataになる属性のキーを含むオブジェクト\n * @returns\n */\nexport function SetThemeScript({\n localStorageKey = defaultProps.localStorageKey,\n rootAttribute = defaultProps.rootAttribute,\n}: Props) {\n const src = makeSetThemeScriptCode({ localStorageKey, rootAttribute })\n return (\n <script\n dangerouslySetInnerHTML={{\n __html: src,\n }}\n />\n )\n}\n\nconst defaultProps: Props = {\n localStorageKey: LOCAL_STORAGE_KEY,\n rootAttribute: DEFAULT_ROOT_ATTRIBUTE,\n}\n"],"mappings":";;;;;;;;;;;AAgBA,SAAgBM,uBAAuB,EACrCF,kBAAkBG,aAAaH,iBAC/BC,gBAAgBE,aAAaF,kBACXE,cAAc;CAChCP,oCAAgBI,gBAAgB;CAChCJ,oCAAgBK,cAAc;CAC9B,OAAO;;6BAEoBD,gBAAe;2BACjBC,cAAa;;;;;;;;;;;;;AAcxC,SAAgBI,eAAe,EAC7BL,kBAAkBG,aAAaH,iBAC/BC,gBAAgBE,aAAaF,iBACrB;CAER,OACE,2CAAC,UAAD,EACE,yBAAyB,EACvBM,QAJML,uBAAuB;EAAEF;EAAiBC;EAAe,CAIvDK,EACT,EACD;;AAIN,MAAMH,eAAsB;CAC1BH,iBAAiBF;CACjBG,eAAeJ;CAChB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { DEFAULT_ROOT_ATTRIBUTE, LOCAL_STORAGE_KEY, assertKeyString } from "./themeHelper.js";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/core/SetThemeScript.tsx
|
|
6
|
+
/**
|
|
7
|
+
* 同期的にテーマをローカルストレージから取得してhtmlの属性に設定するコードを取得する
|
|
8
|
+
* @param props localStorageのキー、htmlのdataになる属性のキーを含むオブジェクト
|
|
9
|
+
* @returns ソースコードの文字列
|
|
10
|
+
*/
|
|
11
|
+
function makeSetThemeScriptCode({ localStorageKey = defaultProps.localStorageKey, rootAttribute = defaultProps.rootAttribute } = defaultProps) {
|
|
12
|
+
assertKeyString(localStorageKey);
|
|
13
|
+
assertKeyString(rootAttribute);
|
|
14
|
+
return `'use strict';
|
|
15
|
+
(function () {
|
|
16
|
+
var localStorageKey = '${localStorageKey}'
|
|
17
|
+
var rootAttribute = '${rootAttribute}'
|
|
18
|
+
var currentTheme = localStorage.getItem(localStorageKey);
|
|
19
|
+
if (currentTheme) {
|
|
20
|
+
document.documentElement.dataset[rootAttribute] = currentTheme;
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 同期的にテーマをローカルストレージから取得してhtmlの属性に設定するスクリプトタグ
|
|
27
|
+
* @param props localStorageのキー、htmlのdataになる属性のキーを含むオブジェクト
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
function SetThemeScript({ localStorageKey = defaultProps.localStorageKey, rootAttribute = defaultProps.rootAttribute }) {
|
|
31
|
+
return /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: makeSetThemeScriptCode({
|
|
32
|
+
localStorageKey,
|
|
33
|
+
rootAttribute
|
|
34
|
+
}) } });
|
|
35
|
+
}
|
|
36
|
+
const defaultProps = {
|
|
37
|
+
localStorageKey: LOCAL_STORAGE_KEY,
|
|
38
|
+
rootAttribute: DEFAULT_ROOT_ATTRIBUTE
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { SetThemeScript, makeSetThemeScriptCode };
|
|
43
|
+
//# sourceMappingURL=SetThemeScript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SetThemeScript.js","names":["assertKeyString","DEFAULT_ROOT_ATTRIBUTE","LOCAL_STORAGE_KEY","Props","localStorageKey","rootAttribute","makeSetThemeScriptCode","defaultProps","Partial","SetThemeScript","src","__html"],"sources":["../../src/core/SetThemeScript.tsx"],"sourcesContent":["import {\n assertKeyString,\n DEFAULT_ROOT_ATTRIBUTE,\n LOCAL_STORAGE_KEY,\n} from './themeHelper'\n\ninterface Props {\n localStorageKey: string\n rootAttribute: string\n}\n\n/**\n * 同期的にテーマをローカルストレージから取得してhtmlの属性に設定するコードを取得する\n * @param props localStorageのキー、htmlのdataになる属性のキーを含むオブジェクト\n * @returns ソースコードの文字列\n */\nexport function makeSetThemeScriptCode({\n localStorageKey = defaultProps.localStorageKey,\n rootAttribute = defaultProps.rootAttribute,\n}: Partial<Props> = defaultProps) {\n assertKeyString(localStorageKey)\n assertKeyString(rootAttribute)\n return `'use strict';\n(function () {\n var localStorageKey = '${localStorageKey}'\n var rootAttribute = '${rootAttribute}'\n var currentTheme = localStorage.getItem(localStorageKey);\n if (currentTheme) {\n document.documentElement.dataset[rootAttribute] = currentTheme;\n }\n})();\n`\n}\n\n/**\n * 同期的にテーマをローカルストレージから取得してhtmlの属性に設定するスクリプトタグ\n * @param props localStorageのキー、htmlのdataになる属性のキーを含むオブジェクト\n * @returns\n */\nexport function SetThemeScript({\n localStorageKey = defaultProps.localStorageKey,\n rootAttribute = defaultProps.rootAttribute,\n}: Props) {\n const src = makeSetThemeScriptCode({ localStorageKey, rootAttribute })\n return (\n <script\n dangerouslySetInnerHTML={{\n __html: src,\n }}\n />\n )\n}\n\nconst defaultProps: Props = {\n localStorageKey: LOCAL_STORAGE_KEY,\n rootAttribute: DEFAULT_ROOT_ATTRIBUTE,\n}\n"],"mappings":";;;;;;;;;;AAgBA,SAAgBM,uBAAuB,EACrCF,kBAAkBG,aAAaH,iBAC/BC,gBAAgBE,aAAaF,kBACXE,cAAc;CAChCP,gBAAgBI,gBAAgB;CAChCJ,gBAAgBK,cAAc;CAC9B,OAAO;;6BAEoBD,gBAAe;2BACjBC,cAAa;;;;;;;;;;;;;AAcxC,SAAgBI,eAAe,EAC7BL,kBAAkBG,aAAaH,iBAC/BC,gBAAgBE,aAAaF,iBACrB;CAER,OACE,oBAAC,UAAD,EACE,yBAAyB,EACvBM,QAJML,uBAAuB;EAAEF;EAAiBC;EAAe,CAIvDK,EACT,EACD;;AAIN,MAAMH,eAAsB;CAC1BH,iBAAiBF;CACjBG,eAAeJ;CAChB"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
let react = require("react");
|
|
4
|
+
|
|
5
|
+
//#region src/core/themeHelper.ts
|
|
6
|
+
const LOCAL_STORAGE_KEY = "charcoal-theme";
|
|
7
|
+
const DEFAULT_ROOT_ATTRIBUTE = "theme";
|
|
8
|
+
const keyStringRegExp = /* @__PURE__ */ new RegExp(/^(\w|-)+$/);
|
|
9
|
+
/**
|
|
10
|
+
* 文字列が英数字_-のみで構成されているか検証する。不正な文字列ならエラーを投げる
|
|
11
|
+
* @param key 検証するキー
|
|
12
|
+
*/
|
|
13
|
+
function assertKeyString(key) {
|
|
14
|
+
if (!keyStringRegExp.test(key)) throw new Error(`Unexpected key :${key}, expect: /^(\\w|-)+$/`);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* `<html data-theme="dark">` のような設定を行うデフォルトのセッター
|
|
18
|
+
*/
|
|
19
|
+
const themeSetter = (attr = DEFAULT_ROOT_ATTRIBUTE) => (theme) => {
|
|
20
|
+
assertKeyString(attr);
|
|
21
|
+
if (theme !== void 0) document.documentElement.dataset[attr] = theme;
|
|
22
|
+
else delete document.documentElement.dataset[attr];
|
|
23
|
+
};
|
|
24
|
+
const defaultThemeSetter = themeSetter();
|
|
25
|
+
/**
|
|
26
|
+
* `<html data-theme="dark">` にマッチするセレクタを生成する
|
|
27
|
+
*/
|
|
28
|
+
function themeSelector(theme, attr) {
|
|
29
|
+
return `:root[data-${attr ?? "theme"}='${theme}']`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* prefers-color-scheme を利用する media クエリを生成する
|
|
33
|
+
*/
|
|
34
|
+
function prefersColorScheme(theme) {
|
|
35
|
+
return `@media (prefers-color-scheme: ${theme})`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* LocalStorageからテーマの情報を取得して、変化時にテーマをセットするhooks
|
|
39
|
+
*/
|
|
40
|
+
function useThemeSetter({ key = LOCAL_STORAGE_KEY, setter = defaultThemeSetter } = {}) {
|
|
41
|
+
const [theme, , system] = useTheme(key);
|
|
42
|
+
(0, react.useEffect)(() => {
|
|
43
|
+
if (theme === void 0) return;
|
|
44
|
+
setter(system ? void 0 : theme);
|
|
45
|
+
}, [
|
|
46
|
+
setter,
|
|
47
|
+
system,
|
|
48
|
+
theme
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 同期的にLocalStorageからテーマを取得するヘルパ
|
|
53
|
+
*/
|
|
54
|
+
function getThemeSync(key = LOCAL_STORAGE_KEY) {
|
|
55
|
+
return localStorage.getItem(key);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* LocalStorage, prefers-color-scheme からテーマの情報を取得して、現在のテーマを返すhooks
|
|
59
|
+
*
|
|
60
|
+
* `dark` `light` という名前だけは特別扱いされていて、prefers-color-schemeにマッチした場合に返ります
|
|
61
|
+
*/
|
|
62
|
+
const useTheme = (localStorageKey = LOCAL_STORAGE_KEY) => {
|
|
63
|
+
assertKeyString(localStorageKey);
|
|
64
|
+
const isDark = useMedia("(prefers-color-scheme: dark)");
|
|
65
|
+
const media = isDark !== void 0 ? isDark ? "dark" : "light" : void 0;
|
|
66
|
+
const [local, setTheme, ready] = useLocalStorage(localStorageKey);
|
|
67
|
+
return [
|
|
68
|
+
!ready || media === void 0 ? void 0 : local ?? media,
|
|
69
|
+
setTheme,
|
|
70
|
+
local === void 0
|
|
71
|
+
];
|
|
72
|
+
};
|
|
73
|
+
function useLocalStorage(key, defaultValue) {
|
|
74
|
+
const [ready, setReady] = (0, react.useState)(false);
|
|
75
|
+
const [state, setState] = (0, react.useState)();
|
|
76
|
+
const defaultValueMemo = (0, react.useMemo)(() => defaultValue?.(), [defaultValue]);
|
|
77
|
+
const fetch = (0, react.useCallback)(() => {
|
|
78
|
+
const raw = localStorage.getItem(key);
|
|
79
|
+
setState((raw !== null ? deserialize(raw) : null) ?? defaultValueMemo);
|
|
80
|
+
setReady(true);
|
|
81
|
+
}, [defaultValueMemo, key]);
|
|
82
|
+
const handleStorage = (0, react.useCallback)((e) => {
|
|
83
|
+
if (e.storageArea !== localStorage) return;
|
|
84
|
+
if (e.key !== key) return;
|
|
85
|
+
fetch();
|
|
86
|
+
}, [fetch, key]);
|
|
87
|
+
(0, react.useEffect)(() => {
|
|
88
|
+
fetch();
|
|
89
|
+
window.addEventListener("storage", handleStorage);
|
|
90
|
+
return () => {
|
|
91
|
+
window.removeEventListener("storage", handleStorage);
|
|
92
|
+
};
|
|
93
|
+
}, [fetch, handleStorage]);
|
|
94
|
+
const set = (value) => {
|
|
95
|
+
if (value === void 0) localStorage.removeItem(key);
|
|
96
|
+
else {
|
|
97
|
+
const raw = serialize(value);
|
|
98
|
+
localStorage.setItem(key, raw);
|
|
99
|
+
}
|
|
100
|
+
const event = new StorageEvent("storage", {
|
|
101
|
+
bubbles: true,
|
|
102
|
+
cancelable: false,
|
|
103
|
+
key,
|
|
104
|
+
url: location.href,
|
|
105
|
+
storageArea: localStorage
|
|
106
|
+
});
|
|
107
|
+
dispatchEvent(event);
|
|
108
|
+
};
|
|
109
|
+
return [
|
|
110
|
+
state ?? defaultValueMemo,
|
|
111
|
+
set,
|
|
112
|
+
ready
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
function deserialize(raw) {
|
|
116
|
+
try {
|
|
117
|
+
return JSON.parse(raw);
|
|
118
|
+
} catch {
|
|
119
|
+
return raw;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function serialize(value) {
|
|
123
|
+
if (typeof value === "string") return value;
|
|
124
|
+
else return JSON.stringify(value);
|
|
125
|
+
}
|
|
126
|
+
function useMedia(query) {
|
|
127
|
+
const [match, setState] = (0, react.useState)();
|
|
128
|
+
(0, react.useEffect)(() => {
|
|
129
|
+
const matcher = window.matchMedia(query);
|
|
130
|
+
const onChange = () => {
|
|
131
|
+
setState(matcher.matches);
|
|
132
|
+
};
|
|
133
|
+
matcher.addEventListener("change", onChange);
|
|
134
|
+
setState(matcher.matches);
|
|
135
|
+
return () => {
|
|
136
|
+
matcher.removeEventListener("change", onChange);
|
|
137
|
+
};
|
|
138
|
+
}, [query]);
|
|
139
|
+
return match;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
exports.DEFAULT_ROOT_ATTRIBUTE = DEFAULT_ROOT_ATTRIBUTE;
|
|
144
|
+
exports.LOCAL_STORAGE_KEY = LOCAL_STORAGE_KEY;
|
|
145
|
+
exports.assertKeyString = assertKeyString;
|
|
146
|
+
exports.getThemeSync = getThemeSync;
|
|
147
|
+
exports.prefersColorScheme = prefersColorScheme;
|
|
148
|
+
exports.themeSelector = themeSelector;
|
|
149
|
+
exports.themeSetter = themeSetter;
|
|
150
|
+
exports.useLocalStorage = useLocalStorage;
|
|
151
|
+
exports.useMedia = useMedia;
|
|
152
|
+
exports.useTheme = useTheme;
|
|
153
|
+
exports.useThemeSetter = useThemeSetter;
|
|
154
|
+
//# sourceMappingURL=themeHelper.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themeHelper.cjs","names":["useCallback","useEffect","useMemo","useState","LOCAL_STORAGE_KEY","DEFAULT_ROOT_ATTRIBUTE","keyStringRegExp","RegExp","assertKeyString","key","test","Error","themeSetter","attr","theme","undefined","document","documentElement","dataset","defaultThemeSetter","themeSelector","T","S","const","prefersColorScheme","useThemeSetter","setter","system","useTheme","getThemeSync","localStorage","getItem","localStorageKey","isDark","useMedia","media","local","setTheme","ready","useLocalStorage","defaultValue","setReady","state","setState","defaultValueMemo","fetch","raw","deserialize","handleStorage","e","StorageEvent","storageArea","window","addEventListener","removeEventListener","set","value","removeItem","serialize","setItem","event","bubbles","cancelable","url","location","href","dispatchEvent","JSON","parse","stringify","query","match","matcher","matchMedia","onChange","matches"],"sources":["../../src/core/themeHelper.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react'\n\nexport const LOCAL_STORAGE_KEY = 'charcoal-theme'\nexport const DEFAULT_ROOT_ATTRIBUTE = 'theme'\n\nconst keyStringRegExp = new RegExp(/^(\\w|-)+$/)\n\n/**\n * 文字列が英数字_-のみで構成されているか検証する。不正な文字列ならエラーを投げる\n * @param key 検証するキー\n */\nexport function assertKeyString(key: string) {\n if (!keyStringRegExp.test(key)) {\n throw new Error(`Unexpected key :${key}, expect: /^(\\\\w|-)+$/`)\n }\n}\n\n/**\n * `<html data-theme=\"dark\">` のような設定を行うデフォルトのセッター\n */\nexport const themeSetter =\n (attr: string = DEFAULT_ROOT_ATTRIBUTE) =>\n (theme: string | undefined) => {\n assertKeyString(attr)\n if (theme !== undefined) {\n document.documentElement.dataset[attr] = theme\n } else {\n delete document.documentElement.dataset[attr]\n }\n }\n\n// デフォルト引数で生成すると毎レンダー新しい関数になり、effect が再実行される\nconst defaultThemeSetter = themeSetter()\n\n/**\n * `<html data-theme=\"dark\">` にマッチするセレクタを生成する\n */\nexport function themeSelector<\n T extends string,\n S extends string = typeof DEFAULT_ROOT_ATTRIBUTE,\n>(theme: T, attr?: S) {\n return `:root[data-${attr ?? DEFAULT_ROOT_ATTRIBUTE}='${theme}']` as const\n}\n\n/**\n * prefers-color-scheme を利用する media クエリを生成する\n */\nexport function prefersColorScheme<T extends 'light' | 'dark'>(theme: T) {\n return `@media (prefers-color-scheme: ${theme})` as const\n}\n\n/**\n * LocalStorageからテーマの情報を取得して、変化時にテーマをセットするhooks\n */\nexport function useThemeSetter({\n key = LOCAL_STORAGE_KEY,\n setter = defaultThemeSetter,\n}: { key?: string; setter?: (theme: string | undefined) => void } = {}) {\n const [theme, , system] = useTheme(key)\n\n useEffect(() => {\n if (theme === undefined) {\n return\n }\n // prefers-color-scheme から値を取っている場合にはcssのみで処理したいのでアンセットする\n setter(system ? undefined : theme)\n }, [setter, system, theme])\n}\n\n/**\n * 同期的にLocalStorageからテーマを取得するヘルパ\n */\nexport function getThemeSync(key: string = LOCAL_STORAGE_KEY) {\n const theme = localStorage.getItem(key)\n return theme\n}\n\n/**\n * LocalStorage, prefers-color-scheme からテーマの情報を取得して、現在のテーマを返すhooks\n *\n * `dark` `light` という名前だけは特別扱いされていて、prefers-color-schemeにマッチした場合に返ります\n */\nexport const useTheme = (localStorageKey: string = LOCAL_STORAGE_KEY) => {\n assertKeyString(localStorageKey)\n const isDark = useMedia('(prefers-color-scheme: dark)')\n const media = isDark !== undefined ? (isDark ? 'dark' : 'light') : undefined\n const [local, setTheme, ready] =\n useLocalStorage<typeof media>(localStorageKey)\n const theme = !ready || media === undefined ? undefined : (local ?? media)\n const system = local === undefined\n return [theme, setTheme, system] as const\n}\n\nexport function useLocalStorage<T>(key: string, defaultValue?: () => T) {\n const [ready, setReady] = useState(false)\n const [state, setState] = useState<T>()\n const defaultValueMemo = useMemo(() => defaultValue?.(), [defaultValue])\n\n const fetch = useCallback(() => {\n const raw = localStorage.getItem(key)\n setState((raw !== null ? deserialize(raw) : null) ?? defaultValueMemo)\n setReady(true)\n }, [defaultValueMemo, key])\n\n const handleStorage = useCallback(\n (e: StorageEvent) => {\n if (e.storageArea !== localStorage) {\n return\n }\n if (e.key !== key) {\n return\n }\n fetch()\n },\n [fetch, key],\n )\n\n // JSON は deserialize のたびに新しい object になるため、入力変更時だけ再取得する\n useEffect(() => {\n fetch()\n window.addEventListener('storage', handleStorage)\n return () => {\n window.removeEventListener('storage', handleStorage)\n }\n }, [fetch, handleStorage])\n\n const set = (value: T | undefined) => {\n if (value === undefined) {\n // undefinedがセットされる場合にはkeyごと削除\n localStorage.removeItem(key)\n } else {\n const raw = serialize(value)\n localStorage.setItem(key, raw)\n }\n\n // 同一ウィンドウではstorageイベントが発火しないので、手動で発火させる\n const event = new StorageEvent('storage', {\n bubbles: true,\n cancelable: false,\n key,\n url: location.href,\n storageArea: localStorage,\n })\n dispatchEvent(event)\n }\n\n return [state ?? defaultValueMemo, set, ready] as const\n}\n\nfunction deserialize<T>(raw: string): T {\n try {\n return JSON.parse(raw) as T\n } catch {\n // syntax error はすべて文字列として扱う\n return raw as unknown as T\n }\n}\n\nfunction serialize(value: unknown): string {\n if (typeof value === 'string') {\n return value\n } else {\n return JSON.stringify(value)\n }\n}\n\nexport function useMedia(query: string) {\n const [match, setState] = useState<boolean>()\n\n useEffect(() => {\n const matcher = window.matchMedia(query)\n\n const onChange = () => {\n setState(matcher.matches)\n }\n\n matcher.addEventListener('change', onChange)\n\n setState(matcher.matches)\n\n return () => {\n matcher.removeEventListener('change', onChange)\n }\n }, [query])\n\n return match\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/core/themeHelper.ts
|
|
5
|
+
const LOCAL_STORAGE_KEY = "charcoal-theme";
|
|
6
|
+
const DEFAULT_ROOT_ATTRIBUTE = "theme";
|
|
7
|
+
const keyStringRegExp = /* @__PURE__ */ new RegExp(/^(\w|-)+$/);
|
|
8
|
+
/**
|
|
9
|
+
* 文字列が英数字_-のみで構成されているか検証する。不正な文字列ならエラーを投げる
|
|
10
|
+
* @param key 検証するキー
|
|
11
|
+
*/
|
|
12
|
+
function assertKeyString(key) {
|
|
13
|
+
if (!keyStringRegExp.test(key)) throw new Error(`Unexpected key :${key}, expect: /^(\\w|-)+$/`);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `<html data-theme="dark">` のような設定を行うデフォルトのセッター
|
|
17
|
+
*/
|
|
18
|
+
const themeSetter = (attr = DEFAULT_ROOT_ATTRIBUTE) => (theme) => {
|
|
19
|
+
assertKeyString(attr);
|
|
20
|
+
if (theme !== void 0) document.documentElement.dataset[attr] = theme;
|
|
21
|
+
else delete document.documentElement.dataset[attr];
|
|
22
|
+
};
|
|
23
|
+
const defaultThemeSetter = themeSetter();
|
|
24
|
+
/**
|
|
25
|
+
* `<html data-theme="dark">` にマッチするセレクタを生成する
|
|
26
|
+
*/
|
|
27
|
+
function themeSelector(theme, attr) {
|
|
28
|
+
return `:root[data-${attr ?? "theme"}='${theme}']`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* prefers-color-scheme を利用する media クエリを生成する
|
|
32
|
+
*/
|
|
33
|
+
function prefersColorScheme(theme) {
|
|
34
|
+
return `@media (prefers-color-scheme: ${theme})`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* LocalStorageからテーマの情報を取得して、変化時にテーマをセットするhooks
|
|
38
|
+
*/
|
|
39
|
+
function useThemeSetter({ key = LOCAL_STORAGE_KEY, setter = defaultThemeSetter } = {}) {
|
|
40
|
+
const [theme, , system] = useTheme(key);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (theme === void 0) return;
|
|
43
|
+
setter(system ? void 0 : theme);
|
|
44
|
+
}, [
|
|
45
|
+
setter,
|
|
46
|
+
system,
|
|
47
|
+
theme
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 同期的にLocalStorageからテーマを取得するヘルパ
|
|
52
|
+
*/
|
|
53
|
+
function getThemeSync(key = LOCAL_STORAGE_KEY) {
|
|
54
|
+
return localStorage.getItem(key);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* LocalStorage, prefers-color-scheme からテーマの情報を取得して、現在のテーマを返すhooks
|
|
58
|
+
*
|
|
59
|
+
* `dark` `light` という名前だけは特別扱いされていて、prefers-color-schemeにマッチした場合に返ります
|
|
60
|
+
*/
|
|
61
|
+
const useTheme = (localStorageKey = LOCAL_STORAGE_KEY) => {
|
|
62
|
+
assertKeyString(localStorageKey);
|
|
63
|
+
const isDark = useMedia("(prefers-color-scheme: dark)");
|
|
64
|
+
const media = isDark !== void 0 ? isDark ? "dark" : "light" : void 0;
|
|
65
|
+
const [local, setTheme, ready] = useLocalStorage(localStorageKey);
|
|
66
|
+
return [
|
|
67
|
+
!ready || media === void 0 ? void 0 : local ?? media,
|
|
68
|
+
setTheme,
|
|
69
|
+
local === void 0
|
|
70
|
+
];
|
|
71
|
+
};
|
|
72
|
+
function useLocalStorage(key, defaultValue) {
|
|
73
|
+
const [ready, setReady] = useState(false);
|
|
74
|
+
const [state, setState] = useState();
|
|
75
|
+
const defaultValueMemo = useMemo(() => defaultValue?.(), [defaultValue]);
|
|
76
|
+
const fetch = useCallback(() => {
|
|
77
|
+
const raw = localStorage.getItem(key);
|
|
78
|
+
setState((raw !== null ? deserialize(raw) : null) ?? defaultValueMemo);
|
|
79
|
+
setReady(true);
|
|
80
|
+
}, [defaultValueMemo, key]);
|
|
81
|
+
const handleStorage = useCallback((e) => {
|
|
82
|
+
if (e.storageArea !== localStorage) return;
|
|
83
|
+
if (e.key !== key) return;
|
|
84
|
+
fetch();
|
|
85
|
+
}, [fetch, key]);
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
fetch();
|
|
88
|
+
window.addEventListener("storage", handleStorage);
|
|
89
|
+
return () => {
|
|
90
|
+
window.removeEventListener("storage", handleStorage);
|
|
91
|
+
};
|
|
92
|
+
}, [fetch, handleStorage]);
|
|
93
|
+
const set = (value) => {
|
|
94
|
+
if (value === void 0) localStorage.removeItem(key);
|
|
95
|
+
else {
|
|
96
|
+
const raw = serialize(value);
|
|
97
|
+
localStorage.setItem(key, raw);
|
|
98
|
+
}
|
|
99
|
+
const event = new StorageEvent("storage", {
|
|
100
|
+
bubbles: true,
|
|
101
|
+
cancelable: false,
|
|
102
|
+
key,
|
|
103
|
+
url: location.href,
|
|
104
|
+
storageArea: localStorage
|
|
105
|
+
});
|
|
106
|
+
dispatchEvent(event);
|
|
107
|
+
};
|
|
108
|
+
return [
|
|
109
|
+
state ?? defaultValueMemo,
|
|
110
|
+
set,
|
|
111
|
+
ready
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
function deserialize(raw) {
|
|
115
|
+
try {
|
|
116
|
+
return JSON.parse(raw);
|
|
117
|
+
} catch {
|
|
118
|
+
return raw;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function serialize(value) {
|
|
122
|
+
if (typeof value === "string") return value;
|
|
123
|
+
else return JSON.stringify(value);
|
|
124
|
+
}
|
|
125
|
+
function useMedia(query) {
|
|
126
|
+
const [match, setState] = useState();
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
const matcher = window.matchMedia(query);
|
|
129
|
+
const onChange = () => {
|
|
130
|
+
setState(matcher.matches);
|
|
131
|
+
};
|
|
132
|
+
matcher.addEventListener("change", onChange);
|
|
133
|
+
setState(matcher.matches);
|
|
134
|
+
return () => {
|
|
135
|
+
matcher.removeEventListener("change", onChange);
|
|
136
|
+
};
|
|
137
|
+
}, [query]);
|
|
138
|
+
return match;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//#endregion
|
|
142
|
+
export { DEFAULT_ROOT_ATTRIBUTE, LOCAL_STORAGE_KEY, assertKeyString, getThemeSync, prefersColorScheme, themeSelector, themeSetter, useLocalStorage, useMedia, useTheme, useThemeSetter };
|
|
143
|
+
//# sourceMappingURL=themeHelper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themeHelper.js","names":["useCallback","useEffect","useMemo","useState","LOCAL_STORAGE_KEY","DEFAULT_ROOT_ATTRIBUTE","keyStringRegExp","RegExp","assertKeyString","key","test","Error","themeSetter","attr","theme","undefined","document","documentElement","dataset","defaultThemeSetter","themeSelector","T","S","const","prefersColorScheme","useThemeSetter","setter","system","useTheme","getThemeSync","localStorage","getItem","localStorageKey","isDark","useMedia","media","local","setTheme","ready","useLocalStorage","defaultValue","setReady","state","setState","defaultValueMemo","fetch","raw","deserialize","handleStorage","e","StorageEvent","storageArea","window","addEventListener","removeEventListener","set","value","removeItem","serialize","setItem","event","bubbles","cancelable","url","location","href","dispatchEvent","JSON","parse","stringify","query","match","matcher","matchMedia","onChange","matches"],"sources":["../../src/core/themeHelper.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react'\n\nexport const LOCAL_STORAGE_KEY = 'charcoal-theme'\nexport const DEFAULT_ROOT_ATTRIBUTE = 'theme'\n\nconst keyStringRegExp = new RegExp(/^(\\w|-)+$/)\n\n/**\n * 文字列が英数字_-のみで構成されているか検証する。不正な文字列ならエラーを投げる\n * @param key 検証するキー\n */\nexport function assertKeyString(key: string) {\n if (!keyStringRegExp.test(key)) {\n throw new Error(`Unexpected key :${key}, expect: /^(\\\\w|-)+$/`)\n }\n}\n\n/**\n * `<html data-theme=\"dark\">` のような設定を行うデフォルトのセッター\n */\nexport const themeSetter =\n (attr: string = DEFAULT_ROOT_ATTRIBUTE) =>\n (theme: string | undefined) => {\n assertKeyString(attr)\n if (theme !== undefined) {\n document.documentElement.dataset[attr] = theme\n } else {\n delete document.documentElement.dataset[attr]\n }\n }\n\n// デフォルト引数で生成すると毎レンダー新しい関数になり、effect が再実行される\nconst defaultThemeSetter = themeSetter()\n\n/**\n * `<html data-theme=\"dark\">` にマッチするセレクタを生成する\n */\nexport function themeSelector<\n T extends string,\n S extends string = typeof DEFAULT_ROOT_ATTRIBUTE,\n>(theme: T, attr?: S) {\n return `:root[data-${attr ?? DEFAULT_ROOT_ATTRIBUTE}='${theme}']` as const\n}\n\n/**\n * prefers-color-scheme を利用する media クエリを生成する\n */\nexport function prefersColorScheme<T extends 'light' | 'dark'>(theme: T) {\n return `@media (prefers-color-scheme: ${theme})` as const\n}\n\n/**\n * LocalStorageからテーマの情報を取得して、変化時にテーマをセットするhooks\n */\nexport function useThemeSetter({\n key = LOCAL_STORAGE_KEY,\n setter = defaultThemeSetter,\n}: { key?: string; setter?: (theme: string | undefined) => void } = {}) {\n const [theme, , system] = useTheme(key)\n\n useEffect(() => {\n if (theme === undefined) {\n return\n }\n // prefers-color-scheme から値を取っている場合にはcssのみで処理したいのでアンセットする\n setter(system ? undefined : theme)\n }, [setter, system, theme])\n}\n\n/**\n * 同期的にLocalStorageからテーマを取得するヘルパ\n */\nexport function getThemeSync(key: string = LOCAL_STORAGE_KEY) {\n const theme = localStorage.getItem(key)\n return theme\n}\n\n/**\n * LocalStorage, prefers-color-scheme からテーマの情報を取得して、現在のテーマを返すhooks\n *\n * `dark` `light` という名前だけは特別扱いされていて、prefers-color-schemeにマッチした場合に返ります\n */\nexport const useTheme = (localStorageKey: string = LOCAL_STORAGE_KEY) => {\n assertKeyString(localStorageKey)\n const isDark = useMedia('(prefers-color-scheme: dark)')\n const media = isDark !== undefined ? (isDark ? 'dark' : 'light') : undefined\n const [local, setTheme, ready] =\n useLocalStorage<typeof media>(localStorageKey)\n const theme = !ready || media === undefined ? undefined : (local ?? media)\n const system = local === undefined\n return [theme, setTheme, system] as const\n}\n\nexport function useLocalStorage<T>(key: string, defaultValue?: () => T) {\n const [ready, setReady] = useState(false)\n const [state, setState] = useState<T>()\n const defaultValueMemo = useMemo(() => defaultValue?.(), [defaultValue])\n\n const fetch = useCallback(() => {\n const raw = localStorage.getItem(key)\n setState((raw !== null ? deserialize(raw) : null) ?? defaultValueMemo)\n setReady(true)\n }, [defaultValueMemo, key])\n\n const handleStorage = useCallback(\n (e: StorageEvent) => {\n if (e.storageArea !== localStorage) {\n return\n }\n if (e.key !== key) {\n return\n }\n fetch()\n },\n [fetch, key],\n )\n\n // JSON は deserialize のたびに新しい object になるため、入力変更時だけ再取得する\n useEffect(() => {\n fetch()\n window.addEventListener('storage', handleStorage)\n return () => {\n window.removeEventListener('storage', handleStorage)\n }\n }, [fetch, handleStorage])\n\n const set = (value: T | undefined) => {\n if (value === undefined) {\n // undefinedがセットされる場合にはkeyごと削除\n localStorage.removeItem(key)\n } else {\n const raw = serialize(value)\n localStorage.setItem(key, raw)\n }\n\n // 同一ウィンドウではstorageイベントが発火しないので、手動で発火させる\n const event = new StorageEvent('storage', {\n bubbles: true,\n cancelable: false,\n key,\n url: location.href,\n storageArea: localStorage,\n })\n dispatchEvent(event)\n }\n\n return [state ?? defaultValueMemo, set, ready] as const\n}\n\nfunction deserialize<T>(raw: string): T {\n try {\n return JSON.parse(raw) as T\n } catch {\n // syntax error はすべて文字列として扱う\n return raw as unknown as T\n }\n}\n\nfunction serialize(value: unknown): string {\n if (typeof value === 'string') {\n return value\n } else {\n return JSON.stringify(value)\n }\n}\n\nexport function useMedia(query: string) {\n const [match, setState] = useState<boolean>()\n\n useEffect(() => {\n const matcher = window.matchMedia(query)\n\n const onChange = () => {\n setState(matcher.matches)\n }\n\n matcher.addEventListener('change', onChange)\n\n setState(matcher.matches)\n\n return () => {\n matcher.removeEventListener('change', onChange)\n }\n }, [query])\n\n return match\n}\n"],"mappings":"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"}
|