@k8o/arte-odyssey 8.0.3 → 9.1.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 (132) hide show
  1. package/dist/components/buttons/button/button.d.mts +1 -1
  2. package/dist/components/buttons/button/button.mjs +1 -1
  3. package/dist/components/buttons/icon-button/icon-button.d.mts +1 -1
  4. package/dist/components/buttons/icon-button/icon-button.mjs +5 -16
  5. package/dist/components/data-display/accordion/accordion-button.mjs +2 -2
  6. package/dist/components/data-display/accordion/accordion-item.mjs +4 -1
  7. package/dist/components/data-display/accordion/accordion.mjs +1 -1
  8. package/dist/components/data-display/accordion/context.d.mts +1 -1
  9. package/dist/components/data-display/accordion/context.mjs +3 -12
  10. package/dist/components/data-display/avatar/avatar.d.mts +1 -1
  11. package/dist/components/data-display/avatar/avatar.mjs +2 -2
  12. package/dist/components/data-display/badge/badge.d.mts +1 -1
  13. package/dist/components/data-display/badge/badge.mjs +3 -3
  14. package/dist/components/data-display/card/card.mjs +2 -2
  15. package/dist/components/data-display/card/interactive-card.mjs +2 -2
  16. package/dist/components/data-display/card/type.d.mts +1 -1
  17. package/dist/components/data-display/code/code.d.mts +1 -1
  18. package/dist/components/data-display/code/code.mjs +4 -5
  19. package/dist/{helpers/color → components/data-display/code}/find-all-colors.d.mts +1 -1
  20. package/dist/{helpers/color → components/data-display/code}/find-all-colors.mjs +1 -1
  21. package/dist/components/data-display/heading/heading.d.mts +1 -1
  22. package/dist/components/data-display/heading/heading.mjs +7 -7
  23. package/dist/components/data-display/table/table.d.mts +12 -17
  24. package/dist/components/data-display/table/table.mjs +23 -21
  25. package/dist/components/feedback/alert/alert.d.mts +1 -1
  26. package/dist/components/feedback/alert/alert.mjs +2 -2
  27. package/dist/components/feedback/progress/progress.d.mts +1 -1
  28. package/dist/components/feedback/progress/progress.mjs +6 -7
  29. package/dist/components/feedback/skeleton/skeleton.d.mts +1 -1
  30. package/dist/components/feedback/skeleton/skeleton.mjs +2 -2
  31. package/dist/components/feedback/spinner/spinner.d.mts +1 -1
  32. package/dist/components/feedback/spinner/spinner.mjs +2 -2
  33. package/dist/components/feedback/toast/context.d.mts +2 -2
  34. package/dist/components/feedback/toast/context.mjs +6 -7
  35. package/dist/components/feedback/toast/provider.mjs +1 -1
  36. package/dist/components/form/autocomplete/autocomplete.d.mts +1 -1
  37. package/dist/components/form/autocomplete/autocomplete.mjs +75 -51
  38. package/dist/components/form/checkbox/checkbox.d.mts +1 -1
  39. package/dist/components/form/checkbox/checkbox.mjs +7 -4
  40. package/dist/components/form/checkbox-card/checkbox-card.d.mts +1 -1
  41. package/dist/components/form/checkbox-card/checkbox-card.mjs +10 -9
  42. package/dist/components/form/checkbox-group/checkbox-group.d.mts +1 -1
  43. package/dist/components/form/checkbox-group/index.d.mts +3 -3
  44. package/dist/components/form/file-field/file-field.d.mts +1 -1
  45. package/dist/components/form/file-field/file-field.mjs +4 -10
  46. package/dist/components/form/form/form.d.mts +1 -1
  47. package/dist/components/form/form/form.mjs +2 -3
  48. package/dist/{helpers/number → components/form/number-field}/cast.d.mts +1 -1
  49. package/dist/{helpers/number → components/form/number-field}/cast.mjs +2 -2
  50. package/dist/components/form/number-field/number-field.d.mts +1 -1
  51. package/dist/components/form/number-field/number-field.mjs +25 -24
  52. package/dist/components/form/password-input/password-input.d.mts +1 -1
  53. package/dist/components/form/password-input/password-input.mjs +3 -3
  54. package/dist/components/form/radio/radio.d.mts +1 -1
  55. package/dist/components/form/radio/radio.mjs +6 -4
  56. package/dist/components/form/radio-card/radio-card.d.mts +1 -1
  57. package/dist/components/form/radio-card/radio-card.mjs +11 -8
  58. package/dist/components/form/select/select.d.mts +1 -1
  59. package/dist/components/form/select/select.mjs +5 -4
  60. package/dist/components/form/slider/slider.d.mts +1 -1
  61. package/dist/components/form/slider/slider.mjs +15 -8
  62. package/dist/components/form/switch/switch.d.mts +1 -1
  63. package/dist/components/form/switch/switch.mjs +9 -6
  64. package/dist/components/form/text-field/text-field.d.mts +1 -1
  65. package/dist/components/form/text-field/text-field.mjs +1 -1
  66. package/dist/components/form/textarea/textarea.d.mts +1 -1
  67. package/dist/components/form/textarea/textarea.mjs +1 -1
  68. package/dist/components/icons/index.d.mts +3 -2
  69. package/dist/components/icons/index.mjs +3 -2
  70. package/dist/components/icons/logo.mjs +3 -3
  71. package/dist/components/icons/lucide.d.mts +2 -1
  72. package/dist/components/icons/lucide.mjs +6 -2
  73. package/dist/components/icons/qiita.mjs +4 -4
  74. package/dist/components/icons/twitter.mjs +1 -1
  75. package/dist/components/icons/vertical-writing.d.mts +7 -0
  76. package/dist/components/icons/vertical-writing.mjs +25 -0
  77. package/dist/components/index.d.mts +3 -2
  78. package/dist/components/index.mjs +3 -2
  79. package/dist/components/layout/separator/separator.d.mts +1 -1
  80. package/dist/components/layout/separator/separator.mjs +2 -5
  81. package/dist/components/navigation/anchor/anchor.d.mts +1 -1
  82. package/dist/components/navigation/anchor/anchor.mjs +1 -2
  83. package/dist/components/navigation/breadcrumb/breadcrumb.mjs +1 -1
  84. package/dist/components/navigation/pagination/pagination.mjs +12 -6
  85. package/dist/components/navigation/tabs/tabs.mjs +25 -25
  86. package/dist/components/overlays/dialog/dialog.mjs +3 -7
  87. package/dist/components/overlays/drawer/drawer.mjs +1 -1
  88. package/dist/components/overlays/dropdown-menu/dropdown-menu.mjs +1 -1
  89. package/dist/components/overlays/dropdown-menu/hooks.d.mts +2 -3
  90. package/dist/components/overlays/dropdown-menu/hooks.mjs +4 -9
  91. package/dist/components/overlays/list-box/hooks.d.mts +0 -1
  92. package/dist/components/overlays/list-box/hooks.mjs +3 -8
  93. package/dist/components/overlays/list-box/list-box.mjs +1 -1
  94. package/dist/components/overlays/modal/modal.mjs +9 -5
  95. package/dist/components/overlays/popover/hooks.d.mts +1 -3
  96. package/dist/components/overlays/popover/hooks.mjs +3 -8
  97. package/dist/components/overlays/popover/popover.mjs +8 -2
  98. package/dist/components/overlays/tooltip/tooltip.mjs +19 -6
  99. package/dist/helpers/chain.d.mts +5 -0
  100. package/dist/helpers/chain.mjs +29 -0
  101. package/dist/helpers/create-safe-context.d.mts +7 -0
  102. package/dist/helpers/create-safe-context.mjs +13 -0
  103. package/dist/helpers/index.d.mts +5 -8
  104. package/dist/helpers/index.mjs +5 -8
  105. package/dist/helpers/merge-props.d.mts +6 -0
  106. package/dist/helpers/merge-props.mjs +56 -0
  107. package/dist/hooks/click-away/index.mjs +1 -1
  108. package/dist/hooks/index.d.mts +2 -1
  109. package/dist/hooks/index.mjs +2 -1
  110. package/dist/hooks/writing-mode/index.d.mts +7 -0
  111. package/dist/hooks/writing-mode/index.mjs +22 -0
  112. package/dist/index.d.mts +8 -9
  113. package/dist/index.mjs +8 -9
  114. package/dist/internal/clamp.d.mts +4 -0
  115. package/dist/internal/clamp.mjs +15 -0
  116. package/dist/{helpers/number → internal}/to-precision.d.mts +1 -1
  117. package/dist/{helpers/number → internal}/to-precision.mjs +1 -1
  118. package/dist/styles/index.css +37 -0
  119. package/dist/styles/tokens.d.mts +12 -1
  120. package/dist/styles/tokens.mjs +25 -1
  121. package/docs/references/typography.md +29 -0
  122. package/package.json +2 -2
  123. package/dist/helpers/is-internal-route.d.mts +0 -4
  124. package/dist/helpers/is-internal-route.mjs +0 -12
  125. package/dist/helpers/number/between.d.mts +0 -4
  126. package/dist/helpers/number/between.mjs +0 -15
  127. package/dist/helpers/number/commalize.d.mts +0 -4
  128. package/dist/helpers/number/commalize.mjs +0 -20
  129. package/dist/helpers/number/index.d.mts +0 -5
  130. package/dist/helpers/number/index.mjs +0 -5
  131. package/dist/helpers/uuid-v4.d.mts +0 -4
  132. 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);
@@ -20,4 +20,5 @@ import { useStep } from "./step/index.mjs";
20
20
  import { useTimeout } from "./timeout/index.mjs";
21
21
  import { useWindowResize } from "./window-resize/index.mjs";
22
22
  import { useWindowSize } from "./window-size/index.mjs";
23
- export { useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebouncedTransition, useDeferredDebounce, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useTimeout, useWindowResize, useWindowSize };
23
+ import { WritingMode, useWritingMode } from "./writing-mode/index.mjs";
24
+ export { type WritingMode, useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebouncedTransition, useDeferredDebounce, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useTimeout, useWindowResize, useWindowSize, useWritingMode };
@@ -1,4 +1,5 @@
1
1
  import { useDisclosure } from "./disclosure/index.mjs";
2
+ import { useWritingMode } from "./writing-mode/index.mjs";
2
3
  import { useTimeout } from "./timeout/index.mjs";
3
4
  import { useClickAway } from "./click-away/index.mjs";
4
5
  import { useClient } from "./client/index.mjs";
@@ -20,4 +21,4 @@ import { useSessionStorage } from "./session-storage/index.mjs";
20
21
  import { useStep } from "./step/index.mjs";
21
22
  import { useWindowResize } from "./window-resize/index.mjs";
22
23
  import { useWindowSize } from "./window-size/index.mjs";
23
- export { useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebouncedTransition, useDeferredDebounce, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useTimeout, useWindowResize, useWindowSize };
24
+ export { useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebouncedTransition, useDeferredDebounce, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useTimeout, useWindowResize, useWindowSize, useWritingMode };
@@ -0,0 +1,7 @@
1
+ import { RefObject } from "react";
2
+
3
+ //#region src/hooks/writing-mode/index.d.ts
4
+ type WritingMode = 'horizontal' | 'vertical';
5
+ declare const useWritingMode: (ref: RefObject<Element | null>) => WritingMode;
6
+ //#endregion
7
+ export { WritingMode, useWritingMode };
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { useCallback, useSyncExternalStore } from "react";
3
+ //#region src/hooks/writing-mode/index.ts
4
+ const getServerSnapshot = () => "horizontal";
5
+ const resolve = (value) => value.startsWith("vertical") || value.startsWith("sideways") ? "vertical" : "horizontal";
6
+ const useWritingMode = (ref) => {
7
+ return useSyncExternalStore(useCallback((onChange) => {
8
+ const el = ref.current;
9
+ if (!el) return () => {};
10
+ const observer = new ResizeObserver(onChange);
11
+ observer.observe(el);
12
+ return () => {
13
+ observer.disconnect();
14
+ };
15
+ }, [ref]), useCallback(() => {
16
+ const el = ref.current;
17
+ if (!el) return "horizontal";
18
+ return resolve(getComputedStyle(el).writingMode);
19
+ }, [ref]), getServerSnapshot);
20
+ };
21
+ //#endregion
22
+ export { useWritingMode };
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,5 @@ 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
+ import { WritingMode, useWritingMode } from "./hooks/writing-mode/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, 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, WritingMode, 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, useWritingMode };
package/dist/index.mjs CHANGED
@@ -2,14 +2,16 @@ 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 { useWritingMode } from "./hooks/writing-mode/index.mjs";
6
+ import { createSafeContext } from "./helpers/create-safe-context.mjs";
6
7
  import { useToast } from "./components/feedback/toast/context.mjs";
7
8
  import { ArteOdyssey } from "./components/icons/arte-odyssey.mjs";
8
9
  import { GitHubIcon } from "./components/icons/github-mark.mjs";
9
10
  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";
11
+ 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
12
  import { QiitaIcon } from "./components/icons/qiita.mjs";
12
13
  import { TwitterIcon } from "./components/icons/twitter.mjs";
14
+ import { VerticalWritingIcon } from "./components/icons/vertical-writing.mjs";
13
15
  import { Alert } from "./components/feedback/alert/alert.mjs";
14
16
  import { useTimeout } from "./hooks/timeout/index.mjs";
15
17
  import { ToastProvider } from "./components/feedback/toast/provider.mjs";
@@ -19,6 +21,8 @@ import { useClickAway } from "./hooks/click-away/index.mjs";
19
21
  import { useOpenContext } from "./components/overlays/popover/hooks.mjs";
20
22
  import { Popover } from "./components/overlays/popover/popover.mjs";
21
23
  import { Tooltip } from "./components/overlays/tooltip/tooltip.mjs";
24
+ import { chain } from "./helpers/chain.mjs";
25
+ import { mergeRefs } from "./helpers/merge-refs.mjs";
22
26
  import { IconButton } from "./components/buttons/icon-button/icon-button.mjs";
23
27
  import { Accordion } from "./components/data-display/accordion/index.mjs";
24
28
  import { Avatar } from "./components/data-display/avatar/avatar.mjs";
@@ -27,14 +31,9 @@ import { useClient } from "./hooks/client/index.mjs";
27
31
  import { BaselineStatus } from "./components/data-display/baseline-status/baseline-status.mjs";
28
32
  import { Card } from "./components/data-display/card/card.mjs";
29
33
  import { InteractiveCard } from "./components/data-display/card/interactive-card.mjs";
30
- import { findAllColors } from "./helpers/color/find-all-colors.mjs";
31
34
  import { Code } from "./components/data-display/code/code.mjs";
32
35
  import { Heading } from "./components/data-display/heading/heading.mjs";
33
36
  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
37
  import { Progress } from "./components/feedback/progress/progress.mjs";
39
38
  import { Skeleton } from "./components/feedback/skeleton/skeleton.mjs";
40
39
  import { useControllableState } from "./hooks/controllable-state/index.mjs";
@@ -57,7 +56,6 @@ import { TextField } from "./components/form/text-field/text-field.mjs";
57
56
  import { Textarea } from "./components/form/textarea/textarea.mjs";
58
57
  import { ScrollLinked } from "./components/layout/scroll-linked/scroll-linked.mjs";
59
58
  import { Separator } from "./components/layout/separator/separator.mjs";
60
- import { isInternalRoute } from "./helpers/is-internal-route.mjs";
61
59
  import { Anchor } from "./components/navigation/anchor/anchor.mjs";
62
60
  import { Breadcrumb } from "./components/navigation/breadcrumb/breadcrumb.mjs";
63
61
  import { Pagination } from "./components/navigation/pagination/pagination.mjs";
@@ -67,6 +65,7 @@ import { Modal } from "./components/overlays/modal/modal.mjs";
67
65
  import { Drawer } from "./components/overlays/drawer/drawer.mjs";
68
66
  import { DropdownMenu } from "./components/overlays/dropdown-menu/dropdown-menu.mjs";
69
67
  import { ListBox } from "./components/overlays/list-box/list-box.mjs";
68
+ import { mergeProps } from "./helpers/merge-props.mjs";
70
69
  import { useClipboard } from "./hooks/clipboard/index.mjs";
71
70
  import { useDebouncedTransition } from "./hooks/debounced-transition/index.mjs";
72
71
  import { useHash } from "./hooks/hash/index.mjs";
@@ -83,4 +82,4 @@ import { useSessionStorage } from "./hooks/session-storage/index.mjs";
83
82
  import { useStep } from "./hooks/step/index.mjs";
84
83
  import { useWindowResize } from "./hooks/window-resize/index.mjs";
85
84
  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 };
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, 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, useWritingMode };
@@ -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;
@@ -73,6 +73,11 @@
73
73
  @custom-variant dark (&:where(.dark, .dark *));
74
74
  @custom-variant light (&:where(.light, .light *));
75
75
 
76
+ /* 縦書きモード。`.writing-v` 配下に適用し、`.writing-h` 配下のアイランドでは無効化する */
77
+ @custom-variant vertical (
78
+ &:where(.writing-v, .writing-v *):not(.writing-h, .writing-h *)
79
+ );
80
+
76
81
  :root {
77
82
  --white: oklch(1 0 0);
78
83
 
@@ -253,6 +258,10 @@
253
258
 
254
259
  --back-drop: rgb(0, 0, 0, 0.5);
255
260
 
261
+ --z-overlay: 1000;
262
+ --z-modal: 1300;
263
+ --z-toast: 1500;
264
+
256
265
  /* TODO: 上の変数の一環として使えるようにする */
257
266
  --group-primary: var(--teal-800);
258
267
  --group-secondary: var(--cyan-800);
@@ -467,3 +476,31 @@
467
476
  minmax(min(calc(var(--spacing) * --value(integer)), 100%), 1fr)
468
477
  );
469
478
  }
479
+
480
+ @utility writing-h {
481
+ writing-mode: horizontal-tb;
482
+ }
483
+
484
+ @utility writing-v {
485
+ writing-mode: vertical-rl;
486
+ text-orientation: mixed;
487
+ text-underline-position: under left;
488
+ line-break: strict;
489
+ word-break: normal;
490
+ }
491
+
492
+ @utility writing-sideways-rl {
493
+ writing-mode: sideways-rl;
494
+ }
495
+
496
+ @utility z-overlay {
497
+ z-index: var(--z-overlay);
498
+ }
499
+
500
+ @utility z-modal {
501
+ z-index: var(--z-modal);
502
+ }
503
+
504
+ @utility z-toast {
505
+ z-index: var(--z-toast);
506
+ }
@@ -80,5 +80,16 @@ type Breakpoint = {
80
80
  px: string;
81
81
  };
82
82
  declare const BREAKPOINTS: readonly Breakpoint[];
83
+ /**
84
+ * オーバーレイ系コンポーネントの重なり順を定義する 3 層スケール。
85
+ *
86
+ * overlay (1000) — trigger に紐付く浮遊 UI (Popover / DropdownMenu / ListBox / Tooltip)
87
+ * modal (1300) — Modal / Drawer。`<dialog>` top-layer により実質はネイティブ制御だが、
88
+ * stacking context を持つ非ネイティブ実装に切り替えても破綻しないよう明示
89
+ * toast (1500) — Toast。モーダルや浮遊 UI より上に必ず表示される
90
+ *
91
+ * 同層内の同時表示はサポート外。新たな層が必要になったら間に挿入する。
92
+ */
93
+ declare const Z_INDICES: readonly NamedScale[];
83
94
  //#endregion
84
- export { BACK_DROP, BG_TOKENS, BORDER_TOKENS, BREAKPOINTS, Breakpoint, FG_TOKENS, FONT_FAMILIES, FONT_WEIGHTS, GROUP_TOKENS, INSET_SHADOWS, LETTER_SPACINGS, LINE_HEIGHTS, NamedScale, PALETTE, PALETTE_PREFIXES, PRIMARY_TOKENS, PaletteFamily, PalettePrefix, RADII, SECONDARY_TOKENS, SHADES, SHADOWS, SPACING_BASE, SPACING_SCALE, SemanticToken, Shade, ShadeRef, SpacingStep, TEXT_SIZES, TextSize, WHITE, lineHeightToNumber };
95
+ export { BACK_DROP, BG_TOKENS, BORDER_TOKENS, BREAKPOINTS, Breakpoint, FG_TOKENS, FONT_FAMILIES, FONT_WEIGHTS, GROUP_TOKENS, INSET_SHADOWS, LETTER_SPACINGS, LINE_HEIGHTS, NamedScale, PALETTE, PALETTE_PREFIXES, PRIMARY_TOKENS, PaletteFamily, PalettePrefix, RADII, SECONDARY_TOKENS, SHADES, SHADOWS, SPACING_BASE, SPACING_SCALE, SemanticToken, Shade, ShadeRef, SpacingStep, TEXT_SIZES, TextSize, WHITE, Z_INDICES, lineHeightToNumber };
@@ -748,5 +748,29 @@ const BREAKPOINTS = [
748
748
  px: "1536px"
749
749
  }
750
750
  ];
751
+ /**
752
+ * オーバーレイ系コンポーネントの重なり順を定義する 3 層スケール。
753
+ *
754
+ * overlay (1000) — trigger に紐付く浮遊 UI (Popover / DropdownMenu / ListBox / Tooltip)
755
+ * modal (1300) — Modal / Drawer。`<dialog>` top-layer により実質はネイティブ制御だが、
756
+ * stacking context を持つ非ネイティブ実装に切り替えても破綻しないよう明示
757
+ * toast (1500) — Toast。モーダルや浮遊 UI より上に必ず表示される
758
+ *
759
+ * 同層内の同時表示はサポート外。新たな層が必要になったら間に挿入する。
760
+ */
761
+ const Z_INDICES = [
762
+ {
763
+ name: "overlay",
764
+ value: "1000"
765
+ },
766
+ {
767
+ name: "modal",
768
+ value: "1300"
769
+ },
770
+ {
771
+ name: "toast",
772
+ value: "1500"
773
+ }
774
+ ];
751
775
  //#endregion
752
- export { BACK_DROP, BG_TOKENS, BORDER_TOKENS, BREAKPOINTS, FG_TOKENS, FONT_FAMILIES, FONT_WEIGHTS, GROUP_TOKENS, INSET_SHADOWS, LETTER_SPACINGS, LINE_HEIGHTS, PALETTE, PALETTE_PREFIXES, PRIMARY_TOKENS, RADII, SECONDARY_TOKENS, SHADES, SHADOWS, SPACING_BASE, SPACING_SCALE, TEXT_SIZES, WHITE, lineHeightToNumber };
776
+ export { BACK_DROP, BG_TOKENS, BORDER_TOKENS, BREAKPOINTS, FG_TOKENS, FONT_FAMILIES, FONT_WEIGHTS, GROUP_TOKENS, INSET_SHADOWS, LETTER_SPACINGS, LINE_HEIGHTS, PALETTE, PALETTE_PREFIXES, PRIMARY_TOKENS, RADII, SECONDARY_TOKENS, SHADES, SHADOWS, SPACING_BASE, SPACING_SCALE, TEXT_SIZES, WHITE, Z_INDICES, lineHeightToNumber };
@@ -72,6 +72,35 @@ import { Heading } from '@k8o/arte-odyssey';
72
72
  <Heading type="h3">サブセクション</Heading>
73
73
  ```
74
74
 
75
+ ## 縦書きモード
76
+
77
+ 縦書き表示には専用のユーティリティと variant を用意している。
78
+
79
+ ### ユーティリティ
80
+
81
+ | Tailwind クラス | 用途 |
82
+ | --------------- | ----------------------------------------------------------------------------------------------------------- |
83
+ | `writing-h` | 横書き (`writing-mode: horizontal-tb`) に戻す。縦書きツリー内の図表・コードブロック・置換要素などで使う。 |
84
+ | `writing-v` | 縦書き (`writing-mode: vertical-rl`) を適用し、`text-orientation: mixed` などの推奨初期値も一括で設定する。 |
85
+
86
+ ### `vertical:` variant
87
+
88
+ `.writing-v` 子孫で活性化し、`.writing-h` 子孫では無効化する Tailwind variant。横書きデフォルトに対する上書きを宣言的に書ける。
89
+
90
+ ```tsx
91
+ <div className="writing-v">
92
+ <p className="my-4 vertical:my-0">
93
+ {/* 横書き時のみ縦マージン、縦書きでは外す */}
94
+ </p>
95
+ </div>
96
+ ```
97
+
98
+ ### 注意点
99
+
100
+ - 画像・iframe などの置換要素は `vertical-rl` で大きさが想定通りにならないことがある。`<img className="vertical:writing-h" />` のように要素自体は横書きに戻す。
101
+ - `-webkit-line-clamp` (`line-clamp-*`) は Safari で `writing-mode` と干渉する。縦書きでは `block-size` 上限 + `overflow: hidden` に置き換える。
102
+ - KaTeX など内部で水平レイアウトを前提とするライブラリは、必要箇所だけ `writing-h` を上書きする。
103
+
75
104
  ## やってはいけないこと
76
105
 
77
106
  - 3種類以上のフォントウェイトを1画面で使う
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k8o/arte-odyssey",
3
- "version": "8.0.3",
3
+ "version": "9.1.0",
4
4
  "description": "k8o's react ui library",
5
5
  "keywords": [
6
6
  "components",
@@ -68,7 +68,7 @@
68
68
  "@vitest/browser-playwright": "4.1.5",
69
69
  "@vitest/coverage-v8": "4.1.5",
70
70
  "@vitest/ui": "4.1.5",
71
- "postcss": "8.5.13",
71
+ "postcss": "8.5.14",
72
72
  "react": "19.2.6",
73
73
  "react-dom": "19.2.6",
74
74
  "storybook": "10.3.6",
@@ -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 };