@k8o/arte-odyssey 8.0.2 → 9.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.
Files changed (67) hide show
  1. package/dist/components/buttons/icon-button/icon-button.mjs +6 -17
  2. package/dist/components/data-display/accordion/context.d.mts +1 -1
  3. package/dist/components/data-display/accordion/context.mjs +3 -12
  4. package/dist/components/data-display/code/code.mjs +1 -1
  5. package/dist/{helpers/color → components/data-display/code}/find-all-colors.d.mts +1 -1
  6. package/dist/{helpers/color → components/data-display/code}/find-all-colors.mjs +1 -1
  7. package/dist/components/feedback/progress/progress.mjs +1 -1
  8. package/dist/components/feedback/toast/context.d.mts +2 -2
  9. package/dist/components/feedback/toast/context.mjs +6 -7
  10. package/dist/components/form/autocomplete/autocomplete.mjs +14 -13
  11. package/dist/components/form/checkbox/checkbox.mjs +7 -4
  12. package/dist/components/form/checkbox-card/checkbox-card.mjs +8 -7
  13. package/dist/components/form/checkbox-group/index.d.mts +3 -3
  14. package/dist/components/form/file-field/file-field.mjs +4 -10
  15. package/dist/{helpers/number → components/form/number-field}/cast.d.mts +1 -1
  16. package/dist/{helpers/number → components/form/number-field}/cast.mjs +2 -2
  17. package/dist/components/form/number-field/number-field.mjs +20 -19
  18. package/dist/components/form/radio/radio.mjs +6 -4
  19. package/dist/components/form/radio-card/radio-card.mjs +7 -5
  20. package/dist/components/form/switch/switch.mjs +7 -4
  21. package/dist/components/icons/index.d.mts +3 -2
  22. package/dist/components/icons/index.mjs +3 -2
  23. package/dist/components/icons/logo.mjs +3 -3
  24. package/dist/components/icons/lucide.d.mts +2 -1
  25. package/dist/components/icons/lucide.mjs +6 -2
  26. package/dist/components/icons/qiita.mjs +4 -4
  27. package/dist/components/icons/twitter.mjs +1 -1
  28. package/dist/components/icons/vertical-writing.d.mts +7 -0
  29. package/dist/components/icons/vertical-writing.mjs +25 -0
  30. package/dist/components/index.d.mts +3 -2
  31. package/dist/components/index.mjs +3 -2
  32. package/dist/components/navigation/anchor/anchor.mjs +1 -2
  33. package/dist/components/navigation/tabs/tabs.mjs +4 -13
  34. package/dist/components/overlays/dialog/dialog.mjs +3 -7
  35. package/dist/components/overlays/dropdown-menu/hooks.d.mts +2 -3
  36. package/dist/components/overlays/dropdown-menu/hooks.mjs +4 -9
  37. package/dist/components/overlays/list-box/hooks.d.mts +0 -1
  38. package/dist/components/overlays/list-box/hooks.mjs +3 -8
  39. package/dist/components/overlays/popover/hooks.d.mts +1 -3
  40. package/dist/components/overlays/popover/hooks.mjs +3 -8
  41. package/dist/components/overlays/tooltip/tooltip.mjs +19 -6
  42. package/dist/helpers/chain.d.mts +5 -0
  43. package/dist/helpers/chain.mjs +29 -0
  44. package/dist/helpers/create-safe-context.d.mts +7 -0
  45. package/dist/helpers/create-safe-context.mjs +13 -0
  46. package/dist/helpers/index.d.mts +5 -8
  47. package/dist/helpers/index.mjs +5 -8
  48. package/dist/helpers/merge-props.d.mts +6 -0
  49. package/dist/helpers/merge-props.mjs +56 -0
  50. package/dist/hooks/click-away/index.mjs +1 -1
  51. package/dist/index.d.mts +7 -9
  52. package/dist/index.mjs +7 -9
  53. package/dist/internal/clamp.d.mts +4 -0
  54. package/dist/internal/clamp.mjs +15 -0
  55. package/dist/{helpers/number → internal}/to-precision.d.mts +1 -1
  56. package/dist/{helpers/number → internal}/to-precision.mjs +1 -1
  57. package/package.json +5 -5
  58. package/dist/helpers/is-internal-route.d.mts +0 -4
  59. package/dist/helpers/is-internal-route.mjs +0 -12
  60. package/dist/helpers/number/between.d.mts +0 -4
  61. package/dist/helpers/number/between.mjs +0 -15
  62. package/dist/helpers/number/commalize.d.mts +0 -4
  63. package/dist/helpers/number/commalize.mjs +0 -20
  64. package/dist/helpers/number/index.d.mts +0 -5
  65. package/dist/helpers/number/index.mjs +0 -5
  66. package/dist/helpers/uuid-v4.d.mts +0 -4
  67. package/dist/helpers/uuid-v4.mjs +0 -28
@@ -1,21 +1,33 @@
1
1
  "use client";
2
2
  import { usePlacement, usePopoverContext } from "../popover/hooks.mjs";
3
3
  import { Popover } from "../popover/popover.mjs";
4
- import { useMemo } from "react";
4
+ import { useCallback, useMemo, useSyncExternalStore } from "react";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region src/components/overlays/tooltip/tooltip.tsx
7
+ const HOVER_QUERY = "(hover: hover)";
8
+ const useCanHover = () => {
9
+ return useSyncExternalStore(useCallback((cb) => {
10
+ const mql = window.matchMedia(HOVER_QUERY);
11
+ mql.addEventListener("change", cb);
12
+ return () => {
13
+ mql.removeEventListener("change", cb);
14
+ };
15
+ }, []), () => window.matchMedia(HOVER_QUERY).matches, () => true);
16
+ };
17
+ const noop = () => {};
7
18
  const useTooltipTriggerProps = () => {
8
19
  const popover = usePopoverContext();
20
+ const canHover = useCanHover();
9
21
  return useMemo(() => ({
10
22
  ref: popover.setTriggerRef,
11
- onMouseEnter: popover.onOpen,
12
- onMouseLeave: popover.onClose,
23
+ onMouseEnter: canHover ? popover.onOpen : noop,
24
+ onMouseLeave: canHover ? popover.onClose : noop,
13
25
  onFocus: (e) => {
14
26
  if (e.target.matches(":focus-visible")) popover.onOpen();
15
27
  },
16
28
  onBlur: popover.onClose,
17
29
  "aria-describedby": popover.isOpen ? `${popover.rootId}_list` : void 0
18
- }), [popover]);
30
+ }), [popover, canHover]);
19
31
  };
20
32
  const Root = ({ children, placement = "bottom" }) => /* @__PURE__ */ jsx(Popover.Root, {
21
33
  closeOnClickAway: false,
@@ -28,6 +40,7 @@ const Trigger = ({ renderItem }) => renderItem(useTooltipTriggerProps());
28
40
  const Content = ({ children }) => {
29
41
  const placement = usePlacement();
30
42
  const popover = usePopoverContext();
43
+ const canHover = useCanHover();
31
44
  const translate = {
32
45
  top: { translateY: 5 },
33
46
  bottom: { translateY: -5 },
@@ -55,8 +68,8 @@ const Content = ({ children }) => {
55
68
  id,
56
69
  onBlur: popover.onClose,
57
70
  onFocus: popover.onOpen,
58
- onMouseEnter: popover.onOpen,
59
- onMouseLeave: popover.onClose,
71
+ onMouseEnter: canHover ? popover.onOpen : noop,
72
+ onMouseLeave: canHover ? popover.onClose : noop,
60
73
  ref,
61
74
  role: "tooltip",
62
75
  children
@@ -0,0 +1,5 @@
1
+ //#region src/helpers/chain.d.ts
2
+ type AnyFunction = (...args: never[]) => unknown;
3
+ declare const chain: <T extends AnyFunction>(...callbacks: Array<T | undefined>) => (...args: Parameters<T>) => void;
4
+ //#endregion
5
+ export { chain };
@@ -0,0 +1,29 @@
1
+ //#region src/helpers/chain.ts
2
+ const chain = (...callbacks) => (...args) => {
3
+ for (const callback of callbacks) callback?.(...args);
4
+ };
5
+ if (import.meta.vitest) describe("chain", () => {
6
+ it("渡されたコールバックを順番に呼び出す", () => {
7
+ const calls = [];
8
+ chain(() => calls.push(1), () => calls.push(2), () => calls.push(3))();
9
+ expect(calls).toEqual([
10
+ 1,
11
+ 2,
12
+ 3
13
+ ]);
14
+ });
15
+ it("引数を全てのコールバックに渡す", () => {
16
+ const fn1 = vi.fn();
17
+ const fn2 = vi.fn();
18
+ chain(fn1, fn2)("a", 1);
19
+ expect(fn1).toHaveBeenCalledWith("a", 1);
20
+ expect(fn2).toHaveBeenCalledWith("a", 1);
21
+ });
22
+ it("undefinedのコールバックはスキップする", () => {
23
+ const fn = vi.fn();
24
+ chain(void 0, fn, void 0)();
25
+ expect(fn).toHaveBeenCalledOnce();
26
+ });
27
+ });
28
+ //#endregion
29
+ export { chain };
@@ -0,0 +1,7 @@
1
+ import { Context } from "react";
2
+
3
+ //#region src/helpers/create-safe-context.d.ts
4
+ type CreateSafeContextReturn<T> = readonly [Context<T | null>, () => T];
5
+ declare const createSafeContext: <T>(errorMessage: string) => CreateSafeContextReturn<T>;
6
+ //#endregion
7
+ export { createSafeContext };
@@ -0,0 +1,13 @@
1
+ import { createContext, use } from "react";
2
+ //#region src/helpers/create-safe-context.ts
3
+ const createSafeContext = (errorMessage) => {
4
+ const Context = createContext(null);
5
+ const useSafeContext = () => {
6
+ const value = use(Context);
7
+ if (value === null) throw new Error(errorMessage);
8
+ return value;
9
+ };
10
+ return [Context, useSafeContext];
11
+ };
12
+ //#endregion
13
+ export { createSafeContext };
@@ -1,9 +1,6 @@
1
+ import { chain } from "./chain.mjs";
1
2
  import { cn } from "./cn.mjs";
2
- import { findAllColors } from "./color/find-all-colors.mjs";
3
- import { isInternalRoute } from "./is-internal-route.mjs";
4
- import { between } from "./number/between.mjs";
5
- import { cast } from "./number/cast.mjs";
6
- import { commalize } from "./number/commalize.mjs";
7
- import { toPrecision } from "./number/to-precision.mjs";
8
- import { uuidV4 } from "./uuid-v4.mjs";
9
- export { between, cast, cn, commalize, findAllColors, isInternalRoute, toPrecision, uuidV4 };
3
+ import { createSafeContext } from "./create-safe-context.mjs";
4
+ import { mergeProps } from "./merge-props.mjs";
5
+ import { mergeRefs } from "./merge-refs.mjs";
6
+ export { chain, cn, createSafeContext, mergeProps, mergeRefs };
@@ -1,9 +1,6 @@
1
1
  import { cn } from "./cn.mjs";
2
- import { uuidV4 } from "./uuid-v4.mjs";
3
- import { findAllColors } from "./color/find-all-colors.mjs";
4
- import { between } from "./number/between.mjs";
5
- import { toPrecision } from "./number/to-precision.mjs";
6
- import { cast } from "./number/cast.mjs";
7
- import { commalize } from "./number/commalize.mjs";
8
- import { isInternalRoute } from "./is-internal-route.mjs";
9
- export { between, cast, cn, commalize, findAllColors, isInternalRoute, toPrecision, uuidV4 };
2
+ import { createSafeContext } from "./create-safe-context.mjs";
3
+ import { chain } from "./chain.mjs";
4
+ import { mergeRefs } from "./merge-refs.mjs";
5
+ import { mergeProps } from "./merge-props.mjs";
6
+ export { chain, cn, createSafeContext, mergeProps, mergeRefs };
@@ -0,0 +1,6 @@
1
+ //#region src/helpers/merge-props.d.ts
2
+ type Props = Record<string, unknown>;
3
+ type MergedProps<A, B> = Omit<A, keyof B> & B;
4
+ declare const mergeProps: <A extends Props, B extends Props>(base: A, override: B) => MergedProps<A, B>;
5
+ //#endregion
6
+ export { mergeProps };
@@ -0,0 +1,56 @@
1
+ import { cn } from "./cn.mjs";
2
+ import { chain } from "./chain.mjs";
3
+ //#region src/helpers/merge-props.ts
4
+ const isEventHandler = (key, value) => typeof value === "function" && key.startsWith("on") && key.length > 2 && key[2] === (key[2]?.toUpperCase() ?? "");
5
+ const mergeProps = (base, override) => {
6
+ const result = { ...base };
7
+ for (const key of Object.keys(override)) {
8
+ const baseValue = base[key];
9
+ const overrideValue = override[key];
10
+ if (key === "className") result[key] = cn(baseValue, overrideValue);
11
+ else if (key === "style") result[key] = {
12
+ ...baseValue,
13
+ ...overrideValue
14
+ };
15
+ else if (isEventHandler(key, baseValue) && isEventHandler(key, overrideValue)) result[key] = chain(baseValue, overrideValue);
16
+ else if (overrideValue !== void 0) result[key] = overrideValue;
17
+ }
18
+ return result;
19
+ };
20
+ if (import.meta.vitest) describe("mergeProps", () => {
21
+ it("classNameをcnでマージする", () => {
22
+ const merged = mergeProps({ className: "p-2 text-fg-base" }, { className: "text-fg-mute" });
23
+ expect(merged.className).toBe("p-2 text-fg-mute");
24
+ });
25
+ it("styleを浅くマージする", () => {
26
+ const merged = mergeProps({ style: {
27
+ color: "red",
28
+ fontSize: 12
29
+ } }, { style: { color: "blue" } });
30
+ expect(merged.style).toEqual({
31
+ color: "blue",
32
+ fontSize: 12
33
+ });
34
+ });
35
+ it("onClickなどのイベントハンドラを連結する", () => {
36
+ const calls = [];
37
+ mergeProps({ onClick: () => calls.push("a") }, { onClick: () => calls.push("b") }).onClick();
38
+ expect(calls).toEqual(["a", "b"]);
39
+ });
40
+ it("それ以外のpropsは後勝ちで上書きする", () => {
41
+ const merged = mergeProps({
42
+ id: "a",
43
+ disabled: true
44
+ }, { id: "b" });
45
+ expect(merged).toEqual({
46
+ id: "b",
47
+ disabled: true
48
+ });
49
+ });
50
+ it("overrideがundefinedの場合はbaseの値を保持する", () => {
51
+ const merged = mergeProps({ id: "a" }, { id: void 0 });
52
+ expect(merged.id).toBe("a");
53
+ });
54
+ });
55
+ //#endregion
56
+ export { mergeProps };
@@ -9,7 +9,7 @@ const useClickAway = (ref, callback, enabled = true) => {
9
9
  if (element && e.target instanceof Node && !element.contains(e.target)) callback(e);
10
10
  };
11
11
  document.addEventListener("mousedown", handler);
12
- document.addEventListener("touchstart", handler);
12
+ document.addEventListener("touchstart", handler, { passive: true });
13
13
  return () => {
14
14
  document.removeEventListener("mousedown", handler);
15
15
  document.removeEventListener("touchstart", handler);
package/dist/index.d.mts CHANGED
@@ -36,9 +36,10 @@ import { Textarea } from "./components/form/textarea/textarea.mjs";
36
36
  import { ArteOdyssey } from "./components/icons/arte-odyssey.mjs";
37
37
  import { GitHubIcon } from "./components/icons/github-mark.mjs";
38
38
  import { Logo, LogoIcon } from "./components/icons/logo.mjs";
39
- import { AIIcon, AccessibilityIcon, AlertIcon, AtomIcon, BadIcon, BlogIcon, BoringIcon, CheckIcon, ChevronIcon, CloseIcon, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, DifficultIcon, EasyIcon, ExternalLinkIcon, FormIcon, GoodIcon, HistoryIcon, InformativeIcon, InterestingIcon, LightModeIcon, LinkIcon, ListIcon, LocationIcon, MailIcon, MinusIcon, MixedColorIcon, NavigationMenuIcon, NewsIcon, PaletteIcon, PlusIcon, PrepareIcon, PublishDateIcon, RSSIcon, SendIcon, ShallowIcon, ShieldCheckIcon, SlideIcon, SparklesIcon, SubscribeIcon, TableIcon, TagIcon, UpdateDateIcon, ViewIcon, ViewOffIcon } from "./components/icons/lucide.mjs";
39
+ import { AIIcon, AccessibilityIcon, AlertIcon, AtomIcon, BadIcon, BlogIcon, BoringIcon, CheckIcon, ChevronIcon, CloseIcon, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, DifficultIcon, EasyIcon, ExternalLinkIcon, FormIcon, GoodIcon, HistoryIcon, HorizontalWritingIcon, InformativeIcon, InterestingIcon, LightModeIcon, LinkIcon, ListIcon, LocationIcon, MailIcon, MinusIcon, MixedColorIcon, NavigationMenuIcon, NewsIcon, PaletteIcon, PlusIcon, PrepareIcon, PublishDateIcon, RSSIcon, SendIcon, ShallowIcon, ShieldCheckIcon, SlideIcon, SparklesIcon, SubscribeIcon, TableIcon, TagIcon, UpdateDateIcon, ViewIcon, ViewOffIcon } from "./components/icons/lucide.mjs";
40
40
  import { QiitaIcon } from "./components/icons/qiita.mjs";
41
41
  import { TwitterIcon } from "./components/icons/twitter.mjs";
42
+ import { VerticalWritingIcon } from "./components/icons/vertical-writing.mjs";
42
43
  import { ScrollLinked } from "./components/layout/scroll-linked/scroll-linked.mjs";
43
44
  import { Separator } from "./components/layout/separator/separator.mjs";
44
45
  import { Anchor } from "./components/navigation/anchor/anchor.mjs";
@@ -54,14 +55,11 @@ import { useOpenContext } from "./components/overlays/popover/hooks.mjs";
54
55
  import { Popover } from "./components/overlays/popover/popover.mjs";
55
56
  import { ArteOdysseyProvider } from "./components/providers/arte-odyssey-provider.mjs";
56
57
  import { PortalRootProvider, usePortalRoot } from "./components/providers/portal-root.mjs";
58
+ import { chain } from "./helpers/chain.mjs";
57
59
  import { cn } from "./helpers/cn.mjs";
58
- import { findAllColors } from "./helpers/color/find-all-colors.mjs";
59
- import { isInternalRoute } from "./helpers/is-internal-route.mjs";
60
- import { between } from "./helpers/number/between.mjs";
61
- import { cast } from "./helpers/number/cast.mjs";
62
- import { commalize } from "./helpers/number/commalize.mjs";
63
- import { toPrecision } from "./helpers/number/to-precision.mjs";
64
- import { uuidV4 } from "./helpers/uuid-v4.mjs";
60
+ import { createSafeContext } from "./helpers/create-safe-context.mjs";
61
+ import { mergeProps } from "./helpers/merge-props.mjs";
62
+ import { mergeRefs } from "./helpers/merge-refs.mjs";
65
63
  import { useBreakpoint } from "./hooks/breakpoint/index.mjs";
66
64
  import { useClickAway } from "./hooks/click-away/index.mjs";
67
65
  import { useClient } from "./hooks/client/index.mjs";
@@ -84,4 +82,4 @@ import { useStep } from "./hooks/step/index.mjs";
84
82
  import { useTimeout } from "./hooks/timeout/index.mjs";
85
83
  import { useWindowResize } from "./hooks/window-resize/index.mjs";
86
84
  import { useWindowSize } from "./hooks/window-size/index.mjs";
87
- export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Direction, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, Form, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, Option, Pagination, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, Status, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, between, cast, cn, commalize, findAllColors, isInternalRoute, toPrecision, useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebouncedTransition, useDeferredDebounce, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useOpenContext, usePortalRoot, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useTimeout, useToast, useWindowResize, useWindowSize, uuidV4 };
85
+ export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Direction, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, Form, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, HorizontalWritingIcon, IconButton, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, Option, Pagination, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, Status, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, VerticalWritingIcon, ViewIcon, ViewOffIcon, chain, cn, createSafeContext, mergeProps, mergeRefs, useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebouncedTransition, useDeferredDebounce, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useOpenContext, usePortalRoot, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useTimeout, useToast, useWindowResize, useWindowSize };
package/dist/index.mjs CHANGED
@@ -2,14 +2,15 @@ import { cn } from "./helpers/cn.mjs";
2
2
  import { Spinner } from "./components/feedback/spinner/spinner.mjs";
3
3
  import { Button } from "./components/buttons/button/button.mjs";
4
4
  import { useDisclosure } from "./hooks/disclosure/index.mjs";
5
- import { uuidV4 } from "./helpers/uuid-v4.mjs";
5
+ import { createSafeContext } from "./helpers/create-safe-context.mjs";
6
6
  import { useToast } from "./components/feedback/toast/context.mjs";
7
7
  import { ArteOdyssey } from "./components/icons/arte-odyssey.mjs";
8
8
  import { GitHubIcon } from "./components/icons/github-mark.mjs";
9
9
  import { Logo, LogoIcon } from "./components/icons/logo.mjs";
10
- import { AIIcon, AccessibilityIcon, AlertIcon, AtomIcon, BadIcon, BlogIcon, BoringIcon, CheckIcon, ChevronIcon, CloseIcon, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, DifficultIcon, EasyIcon, ExternalLinkIcon, FormIcon, GoodIcon, HistoryIcon, InformativeIcon, InterestingIcon, LightModeIcon, LinkIcon, ListIcon, LocationIcon, MailIcon, MinusIcon, MixedColorIcon, NavigationMenuIcon, NewsIcon, PaletteIcon, PlusIcon, PrepareIcon, PublishDateIcon, RSSIcon, SendIcon, ShallowIcon, ShieldCheckIcon, SlideIcon, SparklesIcon, SubscribeIcon, TableIcon, TagIcon, UpdateDateIcon, ViewIcon, ViewOffIcon } from "./components/icons/lucide.mjs";
10
+ import { AIIcon, AccessibilityIcon, AlertIcon, AtomIcon, BadIcon, BlogIcon, BoringIcon, CheckIcon, ChevronIcon, CloseIcon, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, DifficultIcon, EasyIcon, ExternalLinkIcon, FormIcon, GoodIcon, HistoryIcon, HorizontalWritingIcon, InformativeIcon, InterestingIcon, LightModeIcon, LinkIcon, ListIcon, LocationIcon, MailIcon, MinusIcon, MixedColorIcon, NavigationMenuIcon, NewsIcon, PaletteIcon, PlusIcon, PrepareIcon, PublishDateIcon, RSSIcon, SendIcon, ShallowIcon, ShieldCheckIcon, SlideIcon, SparklesIcon, SubscribeIcon, TableIcon, TagIcon, UpdateDateIcon, ViewIcon, ViewOffIcon } from "./components/icons/lucide.mjs";
11
11
  import { QiitaIcon } from "./components/icons/qiita.mjs";
12
12
  import { TwitterIcon } from "./components/icons/twitter.mjs";
13
+ import { VerticalWritingIcon } from "./components/icons/vertical-writing.mjs";
13
14
  import { Alert } from "./components/feedback/alert/alert.mjs";
14
15
  import { useTimeout } from "./hooks/timeout/index.mjs";
15
16
  import { ToastProvider } from "./components/feedback/toast/provider.mjs";
@@ -19,6 +20,8 @@ import { useClickAway } from "./hooks/click-away/index.mjs";
19
20
  import { useOpenContext } from "./components/overlays/popover/hooks.mjs";
20
21
  import { Popover } from "./components/overlays/popover/popover.mjs";
21
22
  import { Tooltip } from "./components/overlays/tooltip/tooltip.mjs";
23
+ import { chain } from "./helpers/chain.mjs";
24
+ import { mergeRefs } from "./helpers/merge-refs.mjs";
22
25
  import { IconButton } from "./components/buttons/icon-button/icon-button.mjs";
23
26
  import { Accordion } from "./components/data-display/accordion/index.mjs";
24
27
  import { Avatar } from "./components/data-display/avatar/avatar.mjs";
@@ -27,14 +30,9 @@ import { useClient } from "./hooks/client/index.mjs";
27
30
  import { BaselineStatus } from "./components/data-display/baseline-status/baseline-status.mjs";
28
31
  import { Card } from "./components/data-display/card/card.mjs";
29
32
  import { InteractiveCard } from "./components/data-display/card/interactive-card.mjs";
30
- import { findAllColors } from "./helpers/color/find-all-colors.mjs";
31
33
  import { Code } from "./components/data-display/code/code.mjs";
32
34
  import { Heading } from "./components/data-display/heading/heading.mjs";
33
35
  import { Table } from "./components/data-display/table/table.mjs";
34
- import { between } from "./helpers/number/between.mjs";
35
- import { toPrecision } from "./helpers/number/to-precision.mjs";
36
- import { cast } from "./helpers/number/cast.mjs";
37
- import { commalize } from "./helpers/number/commalize.mjs";
38
36
  import { Progress } from "./components/feedback/progress/progress.mjs";
39
37
  import { Skeleton } from "./components/feedback/skeleton/skeleton.mjs";
40
38
  import { useControllableState } from "./hooks/controllable-state/index.mjs";
@@ -57,7 +55,6 @@ import { TextField } from "./components/form/text-field/text-field.mjs";
57
55
  import { Textarea } from "./components/form/textarea/textarea.mjs";
58
56
  import { ScrollLinked } from "./components/layout/scroll-linked/scroll-linked.mjs";
59
57
  import { Separator } from "./components/layout/separator/separator.mjs";
60
- import { isInternalRoute } from "./helpers/is-internal-route.mjs";
61
58
  import { Anchor } from "./components/navigation/anchor/anchor.mjs";
62
59
  import { Breadcrumb } from "./components/navigation/breadcrumb/breadcrumb.mjs";
63
60
  import { Pagination } from "./components/navigation/pagination/pagination.mjs";
@@ -67,6 +64,7 @@ import { Modal } from "./components/overlays/modal/modal.mjs";
67
64
  import { Drawer } from "./components/overlays/drawer/drawer.mjs";
68
65
  import { DropdownMenu } from "./components/overlays/dropdown-menu/dropdown-menu.mjs";
69
66
  import { ListBox } from "./components/overlays/list-box/list-box.mjs";
67
+ import { mergeProps } from "./helpers/merge-props.mjs";
70
68
  import { useClipboard } from "./hooks/clipboard/index.mjs";
71
69
  import { useDebouncedTransition } from "./hooks/debounced-transition/index.mjs";
72
70
  import { useHash } from "./hooks/hash/index.mjs";
@@ -83,4 +81,4 @@ import { useSessionStorage } from "./hooks/session-storage/index.mjs";
83
81
  import { useStep } from "./hooks/step/index.mjs";
84
82
  import { useWindowResize } from "./hooks/window-resize/index.mjs";
85
83
  import { useWindowSize } from "./hooks/window-size/index.mjs";
86
- export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, Form, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, Pagination, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, between, cast, cn, commalize, findAllColors, isInternalRoute, toPrecision, useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebouncedTransition, useDeferredDebounce, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useOpenContext, usePortalRoot, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useTimeout, useToast, useWindowResize, useWindowSize, uuidV4 };
84
+ export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, Form, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, HorizontalWritingIcon, IconButton, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, Pagination, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, VerticalWritingIcon, ViewIcon, ViewOffIcon, chain, cn, createSafeContext, mergeProps, mergeRefs, useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebouncedTransition, useDeferredDebounce, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useOpenContext, usePortalRoot, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useTimeout, useToast, useWindowResize, useWindowSize };
@@ -0,0 +1,4 @@
1
+ //#region src/internal/clamp.d.ts
2
+ declare const clamp: (value: number, min: number, max: number) => number;
3
+ //#endregion
4
+ export { clamp };
@@ -0,0 +1,15 @@
1
+ //#region src/internal/clamp.ts
2
+ const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
3
+ if (import.meta.vitest) describe("clamp", () => {
4
+ it("minとmaxの間の値の場合はそのまま返す", () => {
5
+ expect(clamp(5, 0, 10)).toBe(5);
6
+ });
7
+ it("minより小さい場合はminを返す", () => {
8
+ expect(clamp(-5, 0, 10)).toBe(0);
9
+ });
10
+ it("maxより大きい場合はmaxを返す", () => {
11
+ expect(clamp(15, 0, 10)).toBe(10);
12
+ });
13
+ });
14
+ //#endregion
15
+ export { clamp };
@@ -1,4 +1,4 @@
1
- //#region src/helpers/number/to-precision.d.ts
1
+ //#region src/internal/to-precision.d.ts
2
2
  declare const toPrecision: (value: number, precision?: number) => number;
3
3
  //#endregion
4
4
  export { toPrecision };
@@ -1,4 +1,4 @@
1
- //#region src/helpers/number/to-precision.ts
1
+ //#region src/internal/to-precision.ts
2
2
  const toPrecision = (value, precision) => {
3
3
  const scaleFactor = 10 ** (precision ?? 10);
4
4
  return Math.round(value * scaleFactor) / scaleFactor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k8o/arte-odyssey",
3
- "version": "8.0.2",
3
+ "version": "9.0.0",
4
4
  "description": "k8o's react ui library",
5
5
  "keywords": [
6
6
  "components",
@@ -11,13 +11,13 @@
11
11
  "ui"
12
12
  ],
13
13
  "bugs": {
14
- "url": "https://github.com/k35o/ArteOdyssey/issues"
14
+ "url": "https://github.com/k35o/arte-odyssey/issues"
15
15
  },
16
16
  "license": "MIT",
17
17
  "author": "k8o <kosakanoki@gmail.com>",
18
18
  "repository": {
19
19
  "type": "git",
20
- "url": "git+https://github.com/k35o/ArteOdyssey.git"
20
+ "url": "git+https://github.com/k35o/arte-odyssey.git"
21
21
  },
22
22
  "files": [
23
23
  "dist/**",
@@ -69,8 +69,8 @@
69
69
  "@vitest/coverage-v8": "4.1.5",
70
70
  "@vitest/ui": "4.1.5",
71
71
  "postcss": "8.5.13",
72
- "react": "19.2.5",
73
- "react-dom": "19.2.5",
72
+ "react": "19.2.6",
73
+ "react-dom": "19.2.6",
74
74
  "storybook": "10.3.6",
75
75
  "storybook-addon-mock-date": "2.0.0",
76
76
  "tailwindcss": "4.2.4",
@@ -1,4 +0,0 @@
1
- //#region src/helpers/is-internal-route.d.ts
2
- declare const isInternalRoute: (href: string) => boolean;
3
- //#endregion
4
- export { isInternalRoute };
@@ -1,12 +0,0 @@
1
- //#region src/helpers/is-internal-route.ts
2
- const isInternalRoute = (href) => !href.startsWith("http");
3
- if (import.meta.vitest) {
4
- it("httpから始まるhrefはexternalなものとして判定する", () => {
5
- expect(isInternalRoute("https://k8o.me/dummy")).toBe(false);
6
- });
7
- it("httpから始まらないhrefはexternalなものとして判定する", () => {
8
- expect(isInternalRoute("/dummy")).toBe(true);
9
- });
10
- }
11
- //#endregion
12
- export { isInternalRoute };
@@ -1,4 +0,0 @@
1
- //#region src/helpers/number/between.d.ts
2
- declare const between: (value: number, min: number, max: number) => number;
3
- //#endregion
4
- export { between };
@@ -1,15 +0,0 @@
1
- //#region src/helpers/number/between.ts
2
- const between = (value, min, max) => Math.min(Math.max(value, min), max);
3
- if (import.meta.vitest) describe("between", () => {
4
- it("minとmaxの間の値の場合はそのまま返す", () => {
5
- expect(between(5, 0, 10)).toBe(5);
6
- });
7
- it("minより小さい場合はminを返す", () => {
8
- expect(between(-5, 0, 10)).toBe(0);
9
- });
10
- it("maxより大きい場合はmaxを返す", () => {
11
- expect(between(15, 0, 10)).toBe(10);
12
- });
13
- });
14
- //#endregion
15
- export { between };
@@ -1,4 +0,0 @@
1
- //#region src/helpers/number/commalize.d.ts
2
- declare const commalize: (num: number) => string;
3
- //#endregion
4
- export { commalize };
@@ -1,20 +0,0 @@
1
- //#region src/helpers/number/commalize.ts
2
- const commalize = (num) => {
3
- return Math.round(num).toString().replaceAll(/\B(?=(\d{3})+(?!\d))/g, ",");
4
- };
5
- if (import.meta.vitest) {
6
- it("3桁未満の場合はそのまま返す", () => {
7
- expect(commalize(100)).toBe("100");
8
- });
9
- it("4桁の場合はカンマ区切りにする", () => {
10
- expect(commalize(1e3)).toBe("1,000");
11
- });
12
- it("3桁毎にカンマ区切りにする", () => {
13
- expect(commalize(1e6)).toBe("1,000,000");
14
- });
15
- it("少数の場合は四捨五入して整数にする", () => {
16
- expect(commalize(1000.5)).toBe("1,001");
17
- });
18
- }
19
- //#endregion
20
- export { commalize };
@@ -1,5 +0,0 @@
1
- import { between } from "./between.mjs";
2
- import { cast } from "./cast.mjs";
3
- import { commalize } from "./commalize.mjs";
4
- import { toPrecision } from "./to-precision.mjs";
5
- export { between, cast, commalize, toPrecision };
@@ -1,5 +0,0 @@
1
- import { between } from "./between.mjs";
2
- import { toPrecision } from "./to-precision.mjs";
3
- import { cast } from "./cast.mjs";
4
- import { commalize } from "./commalize.mjs";
5
- export { between, cast, commalize, toPrecision };
@@ -1,4 +0,0 @@
1
- //#region src/helpers/uuid-v4.d.ts
2
- declare const uuidV4: () => string;
3
- //#endregion
4
- export { uuidV4 };
@@ -1,28 +0,0 @@
1
- //#region src/helpers/uuid-v4.ts
2
- const HEX_BASE = 16;
3
- const uuidV4 = () => {
4
- if (typeof window !== "undefined" && isSecureContext) return crypto.randomUUID();
5
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replaceAll(/[xy]/g, (c) => {
6
- const randHex = Math.floor(Math.random() * HEX_BASE);
7
- if (c === "y") return (randHex & 3 | 8).toString(HEX_BASE);
8
- return randHex.toString(HEX_BASE);
9
- });
10
- };
11
- if (import.meta.vitest) {
12
- const testRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
13
- beforeEach(() => {
14
- vi.unstubAllGlobals();
15
- });
16
- it("安全なコンテキストではrandUUIDからuuidv4を返す", () => {
17
- vi.stubGlobal("isSecureContext", true);
18
- const result = uuidV4();
19
- expect(result).toMatch(testRegex);
20
- });
21
- it("安全なコンテキスト外では自作のuuidv4を返す", () => {
22
- vi.stubGlobal("isSecureContext", false);
23
- const result = uuidV4();
24
- expect(result).toMatch(testRegex);
25
- });
26
- }
27
- //#endregion
28
- export { uuidV4 };