melta-app 0.5.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +493 -186
- package/docs/architecture.md +99 -0
- package/eslint-rules/melta.d.mts +44 -0
- package/lib/module/a11y/tap-target.js +41 -0
- package/lib/module/a11y/tap-target.js.map +1 -0
- package/lib/module/components/ActionSheet.js +20 -6
- package/lib/module/components/ActionSheet.js.map +1 -1
- package/lib/module/components/Alert.js +11 -7
- package/lib/module/components/Alert.js.map +1 -1
- package/lib/module/components/Avatar.js +7 -2
- package/lib/module/components/Avatar.js.map +1 -1
- package/lib/module/components/BottomSheet.js +11 -3
- package/lib/module/components/BottomSheet.js.map +1 -1
- package/lib/module/components/Card.js +4 -3
- package/lib/module/components/Card.js.map +1 -1
- package/lib/module/components/Checkbox.js +8 -5
- package/lib/module/components/Checkbox.js.map +1 -1
- package/lib/module/components/EmptyState.js +2 -1
- package/lib/module/components/EmptyState.js.map +1 -1
- package/lib/module/components/Header.js.map +1 -1
- package/lib/module/components/Image.js +5 -3
- package/lib/module/components/Image.js.map +1 -1
- package/lib/module/components/Modal.js +12 -4
- package/lib/module/components/Modal.js.map +1 -1
- package/lib/module/components/Progress.js +2 -1
- package/lib/module/components/Progress.js.map +1 -1
- package/lib/module/components/Radio.js +11 -3
- package/lib/module/components/Radio.js.map +1 -1
- package/lib/module/components/Screen.js +28 -3
- package/lib/module/components/Screen.js.map +1 -1
- package/lib/module/components/Skeleton.js +2 -1
- package/lib/module/components/Skeleton.js.map +1 -1
- package/lib/module/components/Surface.js +2 -1
- package/lib/module/components/Surface.js.map +1 -1
- package/lib/module/components/TextField.js +16 -4
- package/lib/module/components/TextField.js.map +1 -1
- package/lib/module/components/Toast.js +17 -9
- package/lib/module/components/Toast.js.map +1 -1
- package/lib/module/components/Toggle.js +13 -4
- package/lib/module/components/Toggle.js.map +1 -1
- package/lib/module/components/alert.styles.js +12 -26
- package/lib/module/components/alert.styles.js.map +1 -1
- package/lib/module/components/avatar.styles.js +24 -2
- package/lib/module/components/avatar.styles.js.map +1 -1
- package/lib/module/components/card.validate.js.map +1 -1
- package/lib/module/components/checkbox.styles.js +5 -2
- package/lib/module/components/checkbox.styles.js.map +1 -1
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/components/modal.styles.js +9 -0
- package/lib/module/components/modal.styles.js.map +1 -1
- package/lib/module/components/radio.styles.js +11 -2
- package/lib/module/components/radio.styles.js.map +1 -1
- package/lib/module/components/safe-area-registry.js +64 -13
- package/lib/module/components/safe-area-registry.js.map +1 -1
- package/lib/module/components/status-colors.js +53 -0
- package/lib/module/components/status-colors.js.map +1 -0
- package/lib/module/components/textfield.styles.js +15 -8
- package/lib/module/components/textfield.styles.js.map +1 -1
- package/lib/module/components/toast.styles.js +36 -25
- package/lib/module/components/toast.styles.js.map +1 -1
- package/lib/module/components/toggle.styles.js +20 -0
- package/lib/module/components/toggle.styles.js.map +1 -1
- package/lib/module/icons/Icon.js +4 -1
- package/lib/module/icons/Icon.js.map +1 -1
- package/lib/module/icons/icon.styles.js +32 -1
- package/lib/module/icons/icon.styles.js.map +1 -1
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/primitives/Button.js +23 -11
- package/lib/module/primitives/Button.js.map +1 -1
- package/lib/module/primitives/Metric.js +2 -1
- package/lib/module/primitives/Metric.js.map +1 -1
- package/lib/module/primitives/Row.js.map +1 -1
- package/lib/module/primitives/Stack.js.map +1 -1
- package/lib/module/primitives/Tag.js +15 -7
- package/lib/module/primitives/Tag.js.map +1 -1
- package/lib/module/primitives/Text.js +28 -7
- package/lib/module/primitives/Text.js.map +1 -1
- package/lib/module/primitives/_internal/focus-ring.js.map +1 -1
- package/lib/module/primitives/button.styles.js +58 -8
- package/lib/module/primitives/button.styles.js.map +1 -1
- package/lib/module/primitives/index.js.map +1 -1
- package/lib/module/primitives/metric.styles.js +4 -1
- package/lib/module/primitives/metric.styles.js.map +1 -1
- package/lib/module/primitives/tag.styles.js +42 -3
- package/lib/module/primitives/tag.styles.js.map +1 -1
- package/lib/module/primitives/text.styles.js +10 -5
- package/lib/module/primitives/text.styles.js.map +1 -1
- package/lib/module/safe-area/index.js +11 -5
- package/lib/module/safe-area/index.js.map +1 -1
- package/lib/module/theme/ThemeProvider.js +5 -2
- package/lib/module/theme/ThemeProvider.js.map +1 -1
- package/lib/module/theme/define-theme.js +27 -1
- package/lib/module/theme/define-theme.js.map +1 -1
- package/lib/module/theme/index.js +7 -8
- package/lib/module/theme/index.js.map +1 -1
- package/lib/module/theme/letter-spacing.js +20 -0
- package/lib/module/theme/letter-spacing.js.map +1 -0
- package/lib/module/theme/line-height.js +52 -0
- package/lib/module/theme/line-height.js.map +1 -0
- package/lib/module/theme/native-theme.js +8 -7
- package/lib/module/theme/native-theme.js.map +1 -1
- package/lib/typescript/src/a11y/tap-target.d.ts +34 -0
- package/lib/typescript/src/a11y/tap-target.d.ts.map +1 -0
- package/lib/typescript/src/components/ActionSheet.d.ts +8 -1
- package/lib/typescript/src/components/ActionSheet.d.ts.map +1 -1
- package/lib/typescript/src/components/Alert.d.ts +9 -2
- package/lib/typescript/src/components/Alert.d.ts.map +1 -1
- package/lib/typescript/src/components/Avatar.d.ts +1 -1
- package/lib/typescript/src/components/Avatar.d.ts.map +1 -1
- package/lib/typescript/src/components/BottomSheet.d.ts +4 -1
- package/lib/typescript/src/components/BottomSheet.d.ts.map +1 -1
- package/lib/typescript/src/components/Card.d.ts +2 -2
- package/lib/typescript/src/components/Checkbox.d.ts +3 -3
- package/lib/typescript/src/components/Checkbox.d.ts.map +1 -1
- package/lib/typescript/src/components/Image.d.ts +4 -3
- package/lib/typescript/src/components/Image.d.ts.map +1 -1
- package/lib/typescript/src/components/Modal.d.ts +9 -3
- package/lib/typescript/src/components/Modal.d.ts.map +1 -1
- package/lib/typescript/src/components/Progress.d.ts +1 -1
- package/lib/typescript/src/components/Progress.d.ts.map +1 -1
- package/lib/typescript/src/components/Radio.d.ts +3 -2
- package/lib/typescript/src/components/Radio.d.ts.map +1 -1
- package/lib/typescript/src/components/Screen.d.ts +28 -5
- package/lib/typescript/src/components/Screen.d.ts.map +1 -1
- package/lib/typescript/src/components/Skeleton.d.ts +1 -1
- package/lib/typescript/src/components/Skeleton.d.ts.map +1 -1
- package/lib/typescript/src/components/Surface.d.ts +1 -1
- package/lib/typescript/src/components/Surface.d.ts.map +1 -1
- package/lib/typescript/src/components/TextField.d.ts +11 -4
- package/lib/typescript/src/components/TextField.d.ts.map +1 -1
- package/lib/typescript/src/components/Toast.d.ts +10 -3
- package/lib/typescript/src/components/Toast.d.ts.map +1 -1
- package/lib/typescript/src/components/Toggle.d.ts +3 -2
- package/lib/typescript/src/components/Toggle.d.ts.map +1 -1
- package/lib/typescript/src/components/action-sheet.styles.d.ts +1 -1
- package/lib/typescript/src/components/action-sheet.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/alert.styles.d.ts +14 -14
- package/lib/typescript/src/components/alert.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/avatar.styles.d.ts +36 -1
- package/lib/typescript/src/components/avatar.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/bottom-sheet.styles.d.ts +1 -1
- package/lib/typescript/src/components/bottom-sheet.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/card.styles.d.ts +1 -1
- package/lib/typescript/src/components/card.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/card.validate.d.ts +1 -1
- package/lib/typescript/src/components/card.validate.d.ts.map +1 -1
- package/lib/typescript/src/components/checkbox.styles.d.ts +6 -3
- package/lib/typescript/src/components/checkbox.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/empty-state.styles.d.ts +1 -1
- package/lib/typescript/src/components/empty-state.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/header.styles.d.ts +1 -1
- package/lib/typescript/src/components/header.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/image.styles.d.ts +1 -1
- package/lib/typescript/src/components/image.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/index.d.ts +18 -18
- package/lib/typescript/src/components/index.d.ts.map +1 -1
- package/lib/typescript/src/components/modal.styles.d.ts +13 -2
- package/lib/typescript/src/components/modal.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/progress.styles.d.ts +1 -1
- package/lib/typescript/src/components/progress.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/radio.styles.d.ts +10 -2
- package/lib/typescript/src/components/radio.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/safe-area-registry.d.ts +47 -11
- package/lib/typescript/src/components/safe-area-registry.d.ts.map +1 -1
- package/lib/typescript/src/components/screen.styles.d.ts +1 -1
- package/lib/typescript/src/components/screen.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/skeleton.styles.d.ts +1 -1
- package/lib/typescript/src/components/skeleton.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/status-colors.d.ts +33 -0
- package/lib/typescript/src/components/status-colors.d.ts.map +1 -0
- package/lib/typescript/src/components/surface.styles.d.ts +1 -1
- package/lib/typescript/src/components/surface.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/textfield.styles.d.ts +9 -5
- package/lib/typescript/src/components/textfield.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/toast.styles.d.ts +34 -14
- package/lib/typescript/src/components/toast.styles.d.ts.map +1 -1
- package/lib/typescript/src/components/toggle.styles.d.ts +17 -1
- package/lib/typescript/src/components/toggle.styles.d.ts.map +1 -1
- package/lib/typescript/src/icons/Icon.d.ts +12 -6
- package/lib/typescript/src/icons/Icon.d.ts.map +1 -1
- package/lib/typescript/src/icons/icon.styles.d.ts +14 -2
- package/lib/typescript/src/icons/icon.styles.d.ts.map +1 -1
- package/lib/typescript/src/icons/index.d.ts +3 -3
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -4
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/Button.d.ts +8 -4
- package/lib/typescript/src/primitives/Button.d.ts.map +1 -1
- package/lib/typescript/src/primitives/Metric.d.ts +1 -1
- package/lib/typescript/src/primitives/Metric.d.ts.map +1 -1
- package/lib/typescript/src/primitives/Row.d.ts +2 -2
- package/lib/typescript/src/primitives/Row.d.ts.map +1 -1
- package/lib/typescript/src/primitives/Stack.d.ts +2 -2
- package/lib/typescript/src/primitives/Stack.d.ts.map +1 -1
- package/lib/typescript/src/primitives/Tag.d.ts +2 -2
- package/lib/typescript/src/primitives/Tag.d.ts.map +1 -1
- package/lib/typescript/src/primitives/Text.d.ts +20 -6
- package/lib/typescript/src/primitives/Text.d.ts.map +1 -1
- package/lib/typescript/src/primitives/button.styles.d.ts +44 -7
- package/lib/typescript/src/primitives/button.styles.d.ts.map +1 -1
- package/lib/typescript/src/primitives/index.d.ts +6 -6
- package/lib/typescript/src/primitives/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/metric.styles.d.ts +1 -1
- package/lib/typescript/src/primitives/metric.styles.d.ts.map +1 -1
- package/lib/typescript/src/primitives/row.styles.d.ts +1 -1
- package/lib/typescript/src/primitives/row.styles.d.ts.map +1 -1
- package/lib/typescript/src/primitives/stack.styles.d.ts +1 -1
- package/lib/typescript/src/primitives/stack.styles.d.ts.map +1 -1
- package/lib/typescript/src/primitives/tag.styles.d.ts +34 -1
- package/lib/typescript/src/primitives/tag.styles.d.ts.map +1 -1
- package/lib/typescript/src/primitives/text.styles.d.ts +2 -4
- package/lib/typescript/src/primitives/text.styles.d.ts.map +1 -1
- package/lib/typescript/src/safe-area/index.d.ts +19 -5
- package/lib/typescript/src/safe-area/index.d.ts.map +1 -1
- package/lib/typescript/src/theme/ThemeProvider.d.ts +2 -2
- package/lib/typescript/src/theme/ThemeProvider.d.ts.map +1 -1
- package/lib/typescript/src/theme/define-theme.d.ts +15 -2
- package/lib/typescript/src/theme/define-theme.d.ts.map +1 -1
- package/lib/typescript/src/theme/index.d.ts +14 -13
- package/lib/typescript/src/theme/index.d.ts.map +1 -1
- package/lib/typescript/src/theme/letter-spacing.d.ts +15 -0
- package/lib/typescript/src/theme/letter-spacing.d.ts.map +1 -0
- package/lib/typescript/src/theme/line-height.d.ts +44 -0
- package/lib/typescript/src/theme/line-height.d.ts.map +1 -0
- package/lib/typescript/src/theme/native-theme.d.ts +1 -1
- package/lib/typescript/src/theme/native-theme.d.ts.map +1 -1
- package/lib/typescript/src/theme/types.d.ts +10 -1
- package/lib/typescript/src/theme/types.d.ts.map +1 -1
- package/llms.txt +2 -1
- package/package.json +22 -7
- package/src/a11y/tap-target.ts +38 -0
- package/src/components/ActionSheet.tsx +25 -15
- package/src/components/Alert.tsx +37 -10
- package/src/components/Avatar.tsx +12 -4
- package/src/components/BottomSheet.tsx +16 -13
- package/src/components/Card.tsx +9 -8
- package/src/components/Checkbox.tsx +12 -9
- package/src/components/EmptyState.tsx +7 -6
- package/src/components/Header.tsx +4 -4
- package/src/components/Image.tsx +9 -7
- package/src/components/Modal.tsx +22 -6
- package/src/components/Progress.tsx +5 -4
- package/src/components/Radio.tsx +11 -6
- package/src/components/Screen.tsx +66 -8
- package/src/components/Skeleton.tsx +6 -5
- package/src/components/Surface.tsx +5 -4
- package/src/components/TextField.tsx +25 -7
- package/src/components/Toast.tsx +33 -11
- package/src/components/Toggle.tsx +15 -6
- package/src/components/action-sheet.styles.ts +1 -1
- package/src/components/alert.styles.ts +13 -25
- package/src/components/avatar.styles.ts +25 -3
- package/src/components/bottom-sheet.styles.ts +1 -1
- package/src/components/card.styles.ts +1 -1
- package/src/components/card.validate.ts +2 -2
- package/src/components/checkbox.styles.ts +6 -3
- package/src/components/empty-state.styles.ts +1 -1
- package/src/components/header.styles.ts +1 -1
- package/src/components/image.styles.ts +1 -1
- package/src/components/index.ts +18 -18
- package/src/components/modal.styles.ts +11 -2
- package/src/components/progress.styles.ts +1 -1
- package/src/components/radio.styles.ts +11 -2
- package/src/components/safe-area-registry.ts +81 -14
- package/src/components/screen.styles.ts +1 -1
- package/src/components/skeleton.styles.ts +1 -1
- package/src/components/status-colors.ts +59 -0
- package/src/components/surface.styles.ts +1 -1
- package/src/components/textfield.styles.ts +18 -15
- package/src/components/toast.styles.ts +32 -25
- package/src/components/toggle.styles.ts +21 -1
- package/src/icons/Icon.tsx +13 -8
- package/src/icons/icon.styles.ts +38 -3
- package/src/icons/index.ts +3 -3
- package/src/index.ts +4 -4
- package/src/primitives/Button.tsx +28 -14
- package/src/primitives/Metric.tsx +5 -4
- package/src/primitives/Row.tsx +4 -4
- package/src/primitives/Stack.tsx +4 -4
- package/src/primitives/Tag.tsx +29 -11
- package/src/primitives/Text.tsx +42 -9
- package/src/primitives/_internal/focus-ring.tsx +1 -1
- package/src/primitives/button.styles.ts +63 -10
- package/src/primitives/index.ts +6 -6
- package/src/primitives/metric.styles.ts +9 -2
- package/src/primitives/row.styles.ts +1 -1
- package/src/primitives/stack.styles.ts +1 -1
- package/src/primitives/tag.styles.ts +43 -4
- package/src/primitives/text.styles.ts +10 -6
- package/src/safe-area/index.ts +21 -7
- package/src/theme/ThemeProvider.tsx +8 -5
- package/src/theme/define-theme.ts +33 -2
- package/src/theme/index.ts +18 -16
- package/src/theme/letter-spacing.ts +17 -0
- package/src/theme/line-height.ts +53 -0
- package/src/theme/native-theme.ts +9 -8
- package/src/theme/types.ts +10 -1
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
import { useMemo } from "react";
|
|
14
14
|
import { Text as RNText, View, type StyleProp, type ViewStyle } from "react-native";
|
|
15
|
-
import { useTheme } from "../theme";
|
|
16
|
-
import { CONTRACTS, type SizeOf } from "../contracts/contract-types";
|
|
17
|
-
import { resolveMetricStyles } from "./metric.styles";
|
|
15
|
+
import { useTheme } from "../theme/index.js";
|
|
16
|
+
import { CONTRACTS, type SizeOf } from "../contracts/contract-types.js";
|
|
17
|
+
import { resolveMetricStyles } from "./metric.styles.js";
|
|
18
18
|
|
|
19
19
|
type MetricSize = SizeOf<"metric">; // "sm" | "md" | "lg"
|
|
20
20
|
|
|
@@ -63,5 +63,6 @@ export function Metric({
|
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
//
|
|
66
|
+
// conformance test 用の contract メタ(§2 A-3)。scripts/lib/conformance.test.ts が
|
|
67
|
+
// 「この宣言が正しい contract を指しているか」を静的スキャンで照合する。
|
|
67
68
|
Metric.__contract = CONTRACTS.metric;
|
package/src/primitives/Row.tsx
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
import { useMemo, type ReactNode } from "react";
|
|
11
11
|
import { View, type StyleProp, type ViewStyle } from "react-native";
|
|
12
|
-
import { useTheme } from "../theme";
|
|
13
|
-
import type { SpacingKey } from "../theme";
|
|
14
|
-
import { CONTRACTS } from "../contracts/contract-types";
|
|
15
|
-
import { resolveRowStyle, type RowAlign, type RowJustify, type RowStyle } from "./row.styles";
|
|
12
|
+
import { useTheme } from "../theme/index.js";
|
|
13
|
+
import type { SpacingKey } from "../theme/index.js";
|
|
14
|
+
import { CONTRACTS } from "../contracts/contract-types.js";
|
|
15
|
+
import { resolveRowStyle, type RowAlign, type RowJustify, type RowStyle } from "./row.styles.js";
|
|
16
16
|
|
|
17
17
|
interface RowProps {
|
|
18
18
|
/** 子要素間の gap(spacing token キー限定)。省略時 gap なし。 */
|
package/src/primitives/Stack.tsx
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
import { useMemo, type ReactNode } from "react";
|
|
11
11
|
import { View, type StyleProp, type ViewStyle } from "react-native";
|
|
12
|
-
import { useTheme } from "../theme";
|
|
13
|
-
import type { SpacingKey } from "../theme";
|
|
14
|
-
import { CONTRACTS } from "../contracts/contract-types";
|
|
15
|
-
import { resolveStackStyle, type StackAlign, type StackStyle } from "./stack.styles";
|
|
12
|
+
import { useTheme } from "../theme/index.js";
|
|
13
|
+
import type { SpacingKey } from "../theme/index.js";
|
|
14
|
+
import { CONTRACTS } from "../contracts/contract-types.js";
|
|
15
|
+
import { resolveStackStyle, type StackAlign, type StackStyle } from "./stack.styles.js";
|
|
16
16
|
|
|
17
17
|
interface StackProps {
|
|
18
18
|
/** 子要素間の gap(spacing token キー限定)。省略時 gap なし。 */
|
package/src/primitives/Tag.tsx
CHANGED
|
@@ -9,16 +9,21 @@
|
|
|
9
9
|
* 色・寸法の決定は pure resolver(tag.styles.ts)に分離、recipe との機械照合は
|
|
10
10
|
* scripts/lib/tag-conformance.test.ts が行う。
|
|
11
11
|
* - label は Text primitive。filter-chip active の文字色だけ primary.700(SemanticColors 外なので style 上書き)。
|
|
12
|
-
* - focus outline は Button
|
|
13
|
-
*
|
|
12
|
+
* - focus outline は Button と共通の Pressable focus handling(_internal/focus-ring)を使う
|
|
13
|
+
* (removable / filter-chip の押せる要素に FocusRing を描く)。
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { Pressable, View, type StyleProp, type ViewStyle } from "react-native";
|
|
17
|
-
import { Text } from "./Text";
|
|
18
|
-
import { useTheme } from "../theme";
|
|
19
|
-
import { useFocusRing, FocusRing } from "./_internal/focus-ring";
|
|
20
|
-
import { CONTRACTS } from "../contracts/contract-types";
|
|
21
|
-
import {
|
|
17
|
+
import { Text } from "./Text.js";
|
|
18
|
+
import { useTheme } from "../theme/index.js";
|
|
19
|
+
import { useFocusRing, FocusRing } from "./_internal/focus-ring.js";
|
|
20
|
+
import { CONTRACTS } from "../contracts/contract-types.js";
|
|
21
|
+
import {
|
|
22
|
+
resolveTagBase,
|
|
23
|
+
resolveTagVariant,
|
|
24
|
+
TAG_FILTER_CHIP_VERTICAL_HIT_SLOP,
|
|
25
|
+
TAG_REMOVE_TAP_TARGET,
|
|
26
|
+
} from "./tag.styles.js";
|
|
22
27
|
|
|
23
28
|
interface TagBase {
|
|
24
29
|
label: string;
|
|
@@ -53,6 +58,12 @@ function FilterChipTag(props: TagBase & { selected: boolean; onToggle: () => voi
|
|
|
53
58
|
onPress={onToggle}
|
|
54
59
|
accessibilityRole="button"
|
|
55
60
|
accessibilityState={{ selected }}
|
|
61
|
+
// 視覚高さ 34pt(padding 駆動)に縦 hitSlop を足して実効 44pt(A11Y_MIN_TAP_TARGET_44)。
|
|
62
|
+
// 背景と枠を持つので minHeight で伸ばすと見た目が変わる → 当たり判定だけ広げる。
|
|
63
|
+
hitSlop={{
|
|
64
|
+
top: TAG_FILTER_CHIP_VERTICAL_HIT_SLOP,
|
|
65
|
+
bottom: TAG_FILTER_CHIP_VERTICAL_HIT_SLOP,
|
|
66
|
+
}}
|
|
56
67
|
testID={testID}
|
|
57
68
|
style={[
|
|
58
69
|
base,
|
|
@@ -86,14 +97,20 @@ function RemovableTag(
|
|
|
86
97
|
<Text variant={v.font} color="text-default">
|
|
87
98
|
{label}
|
|
88
99
|
</Text>
|
|
89
|
-
{/* 最小タップターゲット確保: 親 Tag の高さを超えられないので remove
|
|
100
|
+
{/* 最小タップターゲット確保: 親 Tag の高さを超えられないので remove 自身に正典パターン
|
|
101
|
+
(視覚 24 + hitSlop 10 = 実効 44)を持たせる(Codex M-2 / A11Y_MIN_TAP_TARGET_44)。 */}
|
|
90
102
|
<Pressable
|
|
91
103
|
{...focusHandlers}
|
|
92
104
|
onPress={onRemove}
|
|
93
105
|
accessibilityRole="button"
|
|
94
106
|
accessibilityLabel={removeAccessibilityLabel}
|
|
95
|
-
hitSlop={
|
|
96
|
-
style={{
|
|
107
|
+
hitSlop={TAG_REMOVE_TAP_TARGET.hitSlop}
|
|
108
|
+
style={{
|
|
109
|
+
minWidth: TAG_REMOVE_TAP_TARGET.minWidth,
|
|
110
|
+
minHeight: TAG_REMOVE_TAP_TARGET.minHeight,
|
|
111
|
+
alignItems: "center",
|
|
112
|
+
justifyContent: "center",
|
|
113
|
+
}}
|
|
97
114
|
>
|
|
98
115
|
<Text variant="xs" color="text-muted">
|
|
99
116
|
×
|
|
@@ -122,5 +139,6 @@ export function Tag(props: TagProps) {
|
|
|
122
139
|
);
|
|
123
140
|
}
|
|
124
141
|
|
|
125
|
-
//
|
|
142
|
+
// conformance test 用の contract メタ(§2 A-3)。scripts/lib/conformance.test.ts が
|
|
143
|
+
// 「この宣言が正しい contract を指しているか」を静的スキャンで照合する。
|
|
126
144
|
Tag.__contract = CONTRACTS.tag;
|
package/src/primitives/Text.tsx
CHANGED
|
@@ -6,18 +6,21 @@
|
|
|
6
6
|
* 構造一致している前提で theme.typography.fontSize[variant] を引く。乖離したら型エラーで検知
|
|
7
7
|
* される(= A-3 conformance の型レベル最低ライン、§2)。
|
|
8
8
|
* - 色は token キーのみ(生 hex 不可、§5 lint の意味を保つ)。
|
|
9
|
+
* - fontScale 制御(allowFontScaling / maxFontSizeMultiplier)は RN Text へ素通しする。
|
|
10
|
+
* 既定は未指定 = RN 既定(OS の文字サイズ設定に追随)。器が固定寸法の箇所だけ opt-in で絞る。
|
|
9
11
|
* - letterSpacing は role(heading/body) の ratio を fontSize から pt 換算(text.styles.ts)。
|
|
10
12
|
* - 形状(fontSize/lineHeight/letterSpacing/fontWeight)は variant/role/weight 依存なので useMemo で
|
|
11
|
-
* 分離(B-3 の「形状/色 分離 +
|
|
12
|
-
*
|
|
13
|
+
* 分離(B-3 の「形状/色 分離 + 参照安定性」は useMemo で満たす。StyleSheet 事前生成による
|
|
14
|
+
* 最適化はどのコンポーネントでも採っていない)。色のみ render 時に colors から取る。
|
|
13
15
|
*/
|
|
14
16
|
|
|
15
17
|
import { useMemo, type ReactNode } from "react";
|
|
16
|
-
import { Text as RNText, type StyleProp, type TextStyle } from "react-native";
|
|
17
|
-
import { useTheme } from "../theme";
|
|
18
|
-
import
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
18
|
+
import { StyleSheet, Text as RNText, type StyleProp, type TextStyle } from "react-native";
|
|
19
|
+
import { useTheme } from "../theme/index.js";
|
|
20
|
+
import { minLineHeightFor, minRatioOf } from "../theme/line-height.js";
|
|
21
|
+
import type { FontWeightKey, SemanticColors } from "../theme/index.js";
|
|
22
|
+
import { CONTRACTS, type VariantOf } from "../contracts/contract-types.js";
|
|
23
|
+
import { resolveTextShape, type TextRole } from "./text.styles.js";
|
|
21
24
|
|
|
22
25
|
type TextVariant = VariantOf<"text">;
|
|
23
26
|
|
|
@@ -31,6 +34,18 @@ interface TextProps {
|
|
|
31
34
|
/** letterSpacing の切替軸。default "body"。 */
|
|
32
35
|
role?: TextRole;
|
|
33
36
|
numberOfLines?: number;
|
|
37
|
+
/**
|
|
38
|
+
* OS の文字サイズ設定に追随するか(RN Text へそのまま透過)。既定は未指定 = RN 既定(true)。
|
|
39
|
+
* **原則は既定のまま**(false にすると視覚障害者の拡大設定を無視することになる)。
|
|
40
|
+
* 固定寸法の図版・チャートのラベルなど、拡大するとレイアウトが壊れる箇所だけ false にする。
|
|
41
|
+
*/
|
|
42
|
+
allowFontScaling?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* 文字サイズ倍率の上限(RN Text へそのまま透過)。既定は未指定 = RN 既定(上限なし)。
|
|
45
|
+
* 拡大は許しつつ器からの溢れだけ抑えたいとき(円形の Avatar initials 等)に使う。
|
|
46
|
+
* `0` は「上限なし」、`1` は「拡大しない」という RN の規約に従う。
|
|
47
|
+
*/
|
|
48
|
+
maxFontSizeMultiplier?: number;
|
|
34
49
|
style?: StyleProp<TextStyle>;
|
|
35
50
|
testID?: string;
|
|
36
51
|
children: ReactNode;
|
|
@@ -42,6 +57,8 @@ export function Text({
|
|
|
42
57
|
color = "text-default",
|
|
43
58
|
role = "body",
|
|
44
59
|
numberOfLines,
|
|
60
|
+
allowFontScaling,
|
|
61
|
+
maxFontSizeMultiplier,
|
|
45
62
|
style,
|
|
46
63
|
testID,
|
|
47
64
|
children,
|
|
@@ -55,10 +72,25 @@ export function Text({
|
|
|
55
72
|
[theme, variant, role, weight],
|
|
56
73
|
);
|
|
57
74
|
|
|
75
|
+
// 消費者 style は合成順で最後=上書きが勝つため、resolver 内のクランプだけでは
|
|
76
|
+
// `style={{lineHeight: 16}}` を止められない。flatten した**最終値**に行間の安全下限を掛ける
|
|
77
|
+
// (fontSize の上書きにも追随させるため、下限は最終 fontSize から算出。機序は theme/line-height.ts)。
|
|
78
|
+
const flat: TextStyle = StyleSheet.flatten([shape, { color: colors[color] }, style]);
|
|
79
|
+
// `fontSize: undefined` の明示上書き(flatten は undefined でも上書きする)は、RN 既定サイズで
|
|
80
|
+
// 描画されるのにクランプ基準だけ variant 値になる齟齬を生む。variant の fontSize を復元して
|
|
81
|
+
// 「Text の文字サイズは variant が決める」契約とクランプ基準を一致させる。
|
|
82
|
+
if (typeof flat.fontSize !== "number") flat.fontSize = shape.fontSize;
|
|
83
|
+
if (flat.lineHeight !== undefined) {
|
|
84
|
+
const floor = minLineHeightFor(flat.fontSize ?? 0, minRatioOf(theme));
|
|
85
|
+
if (flat.lineHeight < floor) flat.lineHeight = floor;
|
|
86
|
+
}
|
|
87
|
+
|
|
58
88
|
return (
|
|
59
89
|
<RNText
|
|
60
|
-
style={
|
|
90
|
+
style={flat}
|
|
61
91
|
numberOfLines={numberOfLines}
|
|
92
|
+
allowFontScaling={allowFontScaling}
|
|
93
|
+
maxFontSizeMultiplier={maxFontSizeMultiplier}
|
|
62
94
|
accessibilityRole={role === "heading" ? "header" : undefined}
|
|
63
95
|
testID={testID}
|
|
64
96
|
>
|
|
@@ -67,5 +99,6 @@ export function Text({
|
|
|
67
99
|
);
|
|
68
100
|
}
|
|
69
101
|
|
|
70
|
-
//
|
|
102
|
+
// conformance test 用の contract メタ(§2 A-3)。scripts/lib/conformance.test.ts が
|
|
103
|
+
// 「この宣言が正しい contract を指しているか」を静的スキャンで照合する。
|
|
71
104
|
Text.__contract = CONTRACTS.text;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import { useState } from "react";
|
|
19
19
|
import { View } from "react-native";
|
|
20
|
-
import { useTheme } from "../../theme";
|
|
20
|
+
import { useTheme } from "../../theme/index.js";
|
|
21
21
|
|
|
22
22
|
export function useFocusRing() {
|
|
23
23
|
const [focused, setFocused] = useState(false);
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* button.styles — Button の pure style resolver(
|
|
2
|
+
* button.styles — Button の pure style resolver(styleRefs conformance 対応で Button.tsx から分離)。
|
|
3
3
|
*
|
|
4
4
|
* react-native を import しない純粋モジュールにすることで node テスト(tsx --test)から
|
|
5
5
|
* 直接実行できる。recipes/app/button.recipe.json(melta-contracts の styleRefs)との
|
|
6
|
-
* 機械照合は scripts/lib/recipe-conformance.test.ts
|
|
6
|
+
* 機械照合は scripts/lib/recipe-conformance.test.ts が行う(層B)。
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ このファイルは resolver 機構の**最初の実装**で、戻り値が slot 単位に揃っていない
|
|
9
|
+
* (色だけを返し、寸法は component 側で組む)。現行の書き方は AGENTS.md「style resolver の規約」
|
|
10
|
+
* を参照すること — 新規 / 改修は alert.styles.ts・textfield.styles.ts の形に寄せる。
|
|
7
11
|
*/
|
|
8
12
|
|
|
9
|
-
import type { NativeTheme, ThemeMode, FontSizeKey, SpacingKey } from "../theme";
|
|
13
|
+
import type { NativeTheme, ThemeMode, FontSizeKey, SpacingKey } from "../theme/index.js";
|
|
10
14
|
|
|
11
15
|
export type ButtonVariant =
|
|
12
16
|
| "contained"
|
|
@@ -18,22 +22,71 @@ export type ButtonVariant =
|
|
|
18
22
|
| "subtle";
|
|
19
23
|
export type ButtonSize = "small" | "medium" | "large";
|
|
20
24
|
|
|
21
|
-
/**
|
|
22
|
-
|
|
25
|
+
/**
|
|
26
|
+
* size → 最小高さ / 横 padding / label fontSize / icon box(contract sizes/iconButton と整合)。
|
|
27
|
+
*
|
|
28
|
+
* `minHeight`(`height` ではない)なのは fontScale 対策。label は Text primitive の
|
|
29
|
+
* lineHeight(base = 36pt)で伸びるため、height 固定だと fontScale 1.12x あたりから
|
|
30
|
+
* medium(40pt)で文字がクリップする。recipe 側も 0.7.0 で `minHeight` に変わっている。
|
|
31
|
+
* iconOnly だけは正方形を保つため width/height 固定のまま(recipe の iconOnlyWidth/iconOnlyHeight)。
|
|
32
|
+
*/
|
|
33
|
+
export const BUTTON_SIZE_SPEC: Record<
|
|
23
34
|
ButtonSize,
|
|
24
|
-
{
|
|
35
|
+
{ minHeight: number; px: SpacingKey; font: FontSizeKey; iconBox: number }
|
|
25
36
|
> = {
|
|
26
|
-
small: {
|
|
27
|
-
medium: {
|
|
28
|
-
large: {
|
|
37
|
+
small: { minHeight: 32, px: "3", font: "sm", iconBox: 32 },
|
|
38
|
+
medium: { minHeight: 40, px: "4", font: "base", iconBox: 40 },
|
|
39
|
+
large: { minHeight: 48, px: "6", font: "base", iconBox: 48 },
|
|
29
40
|
};
|
|
30
41
|
|
|
42
|
+
/**
|
|
43
|
+
* size → 縦方向の片側 hitSlop(実効タップ標的 44pt 確保。A11Y_MIN_TAP_TARGET_44)。
|
|
44
|
+
*
|
|
45
|
+
* 視覚寸法は据え置き、当たり判定だけを広げる:
|
|
46
|
+
* small 32 + 6*2 = 44 / medium 40 + 2*2 = 44 / large 48(既に 44 以上なので 0)
|
|
47
|
+
*
|
|
48
|
+
* ⚠️ literal で持つ(BUTTON_SIZE_SPEC から自動導出しない)。導出にすると視覚寸法を変えたときに
|
|
49
|
+
* hitSlop が黙って追随してしまい、conformance が構造的に fail-open になる。
|
|
50
|
+
*/
|
|
51
|
+
export const BUTTON_VERTICAL_HIT_SLOP: Record<ButtonSize, number> = {
|
|
52
|
+
small: 6,
|
|
53
|
+
medium: 2,
|
|
54
|
+
large: 0,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/** Pressable の hitSlop(RN の Insets)。 */
|
|
58
|
+
export interface ButtonHitSlop {
|
|
59
|
+
top: number;
|
|
60
|
+
bottom: number;
|
|
61
|
+
left?: number;
|
|
62
|
+
right?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* size / iconOnly → Pressable に渡す hitSlop。0 のときは undefined(prop を付けない)。
|
|
67
|
+
*
|
|
68
|
+
* - labeled: **縦だけ**。横は付けない — Row の gap 0 で隣接した Button 同士の当たり判定が
|
|
69
|
+
* 重なって押し違いが起きるため(横方向は padding で既に広い)。
|
|
70
|
+
* - iconOnly: 幅も 32/40 と狭い正方形なので**横にも同値**を付ける(左右の隣接は
|
|
71
|
+
* iconOnly ボタンを gap 0 で並べない前提。並べる場合は消費者側で gap を取る)。
|
|
72
|
+
*/
|
|
73
|
+
export function resolveButtonHitSlop(
|
|
74
|
+
size: ButtonSize,
|
|
75
|
+
iconOnly: boolean,
|
|
76
|
+
): ButtonHitSlop | undefined {
|
|
77
|
+
const slop = BUTTON_VERTICAL_HIT_SLOP[size];
|
|
78
|
+
if (slop === 0) return undefined;
|
|
79
|
+
return iconOnly
|
|
80
|
+
? { top: slop, bottom: slop, left: slop, right: slop }
|
|
81
|
+
: { top: slop, bottom: slop };
|
|
82
|
+
}
|
|
83
|
+
|
|
31
84
|
/**
|
|
32
85
|
* variant → 色解決(button.contract tokenRefs の 1:1 写像)。
|
|
33
86
|
* 文字色は variant により semantic 外(primary.500 等)もあるため hex 文字列で返し、
|
|
34
87
|
* Text の style で color 上書きする(Text の color prop は SemanticColors キー限定のため)。
|
|
35
88
|
*/
|
|
36
|
-
export function
|
|
89
|
+
export function resolveButtonColors(
|
|
37
90
|
theme: NativeTheme,
|
|
38
91
|
mode: ThemeMode,
|
|
39
92
|
variant: ButtonVariant,
|
package/src/primitives/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** melta-app primitives の公開エントリ。実装ごとにここへ追記する(設計書 §1)。 */
|
|
2
2
|
|
|
3
|
-
export { Text } from "./Text";
|
|
4
|
-
export { Metric } from "./Metric";
|
|
5
|
-
export { Tag } from "./Tag";
|
|
6
|
-
export { Button } from "./Button";
|
|
7
|
-
export { Stack } from "./Stack";
|
|
8
|
-
export { Row } from "./Row";
|
|
3
|
+
export { Text } from "./Text.js";
|
|
4
|
+
export { Metric } from "./Metric.js";
|
|
5
|
+
export { Tag } from "./Tag.js";
|
|
6
|
+
export { Button } from "./Button.js";
|
|
7
|
+
export { Stack } from "./Stack.js";
|
|
8
|
+
export { Row } from "./Row.js";
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { FontVariant } from "react-native";
|
|
10
|
-
import type { NativeTheme, ThemeMode, FontSizeKey, FontWeightValue } from "../theme";
|
|
10
|
+
import type { NativeTheme, ThemeMode, FontSizeKey, FontWeightValue } from "../theme/index.js";
|
|
11
|
+
// theme index からの runtime import は ThemeProvider → react-native を引くため pure module を直接参照
|
|
12
|
+
import { clampLineHeight, minRatioOf } from "../theme/line-height.js";
|
|
11
13
|
|
|
12
14
|
export type MetricSize = "sm" | "md" | "lg";
|
|
13
15
|
|
|
@@ -56,7 +58,12 @@ export function resolveMetricStyles(
|
|
|
56
58
|
return {
|
|
57
59
|
valueStyle: {
|
|
58
60
|
fontSize: fontSize[font.value].fontSize,
|
|
59
|
-
|
|
61
|
+
// カスタム theme の未クランプ値への防波堤(text.styles.ts と同じ。根拠は theme/line-height.ts)
|
|
62
|
+
lineHeight: clampLineHeight(
|
|
63
|
+
fontSize[font.value].fontSize,
|
|
64
|
+
fontSize[font.value].lineHeight,
|
|
65
|
+
minRatioOf(theme),
|
|
66
|
+
),
|
|
60
67
|
fontWeight: theme.typography.fontWeight.bold,
|
|
61
68
|
color: sem["text-heading"],
|
|
62
69
|
fontVariant: ["tabular-nums"],
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 機械照合は scripts/lib/row-conformance.test.ts が行う。
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { NativeTheme, SpacingKey } from "../theme";
|
|
9
|
+
import type { NativeTheme, SpacingKey } from "../theme/index.js";
|
|
10
10
|
|
|
11
11
|
/** 交差軸の配置(RN alignItems への写像)。default "center"(recipe default に焼いてある)。 */
|
|
12
12
|
export type RowAlign = "start" | "center" | "end" | "baseline" | "stretch";
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 機械照合は scripts/lib/stack-conformance.test.ts が行う。
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { NativeTheme, SpacingKey } from "../theme";
|
|
9
|
+
import type { NativeTheme, SpacingKey } from "../theme/index.js";
|
|
10
10
|
|
|
11
11
|
/** 交差軸の配置(RN alignItems への写像。default stretch = RN デフォルトなので出力しない)。 */
|
|
12
12
|
export type StackAlign = "start" | "center" | "end" | "stretch";
|
|
@@ -6,10 +6,49 @@
|
|
|
6
6
|
* 機械照合は scripts/lib/tag-conformance.test.ts が行う。
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { NativeTheme, ThemeMode, FontSizeKey } from "../theme";
|
|
9
|
+
import type { NativeTheme, ThemeMode, FontSizeKey } from "../theme/index.js";
|
|
10
|
+
import { CANONICAL_TAP_TARGET } from "../a11y/tap-target.js";
|
|
11
|
+
import { clampLineHeight, minRatioOf } from "../theme/line-height.js";
|
|
10
12
|
|
|
11
13
|
export type TagVariant = "basic" | "removable" | "filter-chip";
|
|
12
14
|
|
|
15
|
+
/** label の fontSize token キー(component / resolver / 検算が同じキーを読む SSOT)。 */
|
|
16
|
+
export const TAG_SPEC = {
|
|
17
|
+
/** basic / removable の label。 */
|
|
18
|
+
labelFont: "xs",
|
|
19
|
+
/** filter-chip の label(押せる要素なので一段大きい)。 */
|
|
20
|
+
chipLabelFont: "sm",
|
|
21
|
+
} as const satisfies { labelFont: FontSizeKey; chipLabelFont: FontSizeKey };
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* removable の × の当たり判定(正典パターン: 視覚 24pt + hitSlop 10 = 実効 44pt)。
|
|
25
|
+
* 親 Tag の高さ(padding 駆動で 34pt 前後)を超えられないので × 自身に持たせる。
|
|
26
|
+
*/
|
|
27
|
+
export const TAG_REMOVE_TAP_TARGET = CANONICAL_TAP_TARGET;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* filter-chip(押せる chip 本体)の縦 hitSlop。
|
|
31
|
+
*
|
|
32
|
+
* chip は背景と枠を持つので minHeight で伸ばすと**見た目が変わる**(他 variant と高さが揃わない)。
|
|
33
|
+
* よって視覚寸法は据え置き、当たり判定だけ広げる:
|
|
34
|
+
* 視覚高さ 34pt(paddingVertical 4 × 2 + label sm の lineHeight 26)+ 5 × 2 = 44pt。
|
|
35
|
+
*
|
|
36
|
+
* padding 駆動なので fontScale で視覚高さ自体が伸びる = 拡大時に過剰な当たり判定にならない。
|
|
37
|
+
* ⚠️ literal で持つ(resolveTagFilterChipVisualHeight から導出しない)。導出にすると
|
|
38
|
+
* 寸法変更に hitSlop が黙って追随し、conformance が fail-open になる。
|
|
39
|
+
*/
|
|
40
|
+
export const TAG_FILTER_CHIP_VERTICAL_HIT_SLOP = 5;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* filter-chip の視覚高さ(padding 駆動)。conformance が 44pt 到達を検算するための実測値。
|
|
44
|
+
* = paddingVertical × 2 + label(sm)の lineHeight。
|
|
45
|
+
*/
|
|
46
|
+
export function resolveTagFilterChipVisualHeight(theme: NativeTheme): number {
|
|
47
|
+
const font = theme.typography.fontSize[TAG_SPEC.chipLabelFont];
|
|
48
|
+
const lineHeight = clampLineHeight(font.fontSize, font.lineHeight, minRatioOf(theme));
|
|
49
|
+
return resolveTagBase(theme).paddingVertical * 2 + lineHeight;
|
|
50
|
+
}
|
|
51
|
+
|
|
13
52
|
/** 共通形状(px-3 py-1 gap-1 rounded-full。tag.recipe の全 variant style と共通の寸法キー)。 */
|
|
14
53
|
export function resolveTagBase(theme: NativeTheme): {
|
|
15
54
|
gap: number;
|
|
@@ -44,7 +83,7 @@ export function resolveTagVariant(
|
|
|
44
83
|
switch (variant) {
|
|
45
84
|
case "basic":
|
|
46
85
|
case "removable":
|
|
47
|
-
return { bg: sem["bg-page-alt"], textColor: sem["text-default"], font:
|
|
86
|
+
return { bg: sem["bg-page-alt"], textColor: sem["text-default"], font: TAG_SPEC.labelFont };
|
|
48
87
|
case "filter-chip":
|
|
49
88
|
return selected
|
|
50
89
|
? {
|
|
@@ -52,14 +91,14 @@ export function resolveTagVariant(
|
|
|
52
91
|
borderWidth: 1,
|
|
53
92
|
border: c.primary["200"],
|
|
54
93
|
textColor: c.primary["700"],
|
|
55
|
-
font:
|
|
94
|
+
font: TAG_SPEC.chipLabelFont,
|
|
56
95
|
}
|
|
57
96
|
: {
|
|
58
97
|
bg: sem["bg-surface"],
|
|
59
98
|
borderWidth: 1,
|
|
60
99
|
border: sem["border-default"],
|
|
61
100
|
textColor: sem["text-default"],
|
|
62
|
-
font:
|
|
101
|
+
font: TAG_SPEC.chipLabelFont,
|
|
63
102
|
};
|
|
64
103
|
}
|
|
65
104
|
}
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* 機械照合は scripts/lib/text-conformance.test.ts が行う。
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { NativeTheme, FontSizeKey, FontWeightKey, FontWeightValue } from "../theme";
|
|
9
|
+
import type { NativeTheme, FontSizeKey, FontWeightKey, FontWeightValue } from "../theme/index.js";
|
|
10
|
+
// theme index からの runtime import は ThemeProvider → react-native を引くため、
|
|
11
|
+
// pure module(line-height.ts / letter-spacing.ts)を直接参照する。
|
|
12
|
+
import { clampLineHeight, minRatioOf } from "../theme/line-height.js";
|
|
13
|
+
import { resolveLetterSpacing } from "../theme/letter-spacing.js";
|
|
10
14
|
|
|
11
15
|
/** letterSpacing の切替軸(text.recipe description の role prop に対応)。 */
|
|
12
16
|
export type TextRole = "heading" | "body";
|
|
@@ -22,9 +26,7 @@ export interface TextShape {
|
|
|
22
26
|
/**
|
|
23
27
|
* variant / role / weight → 形状解決(text.recipe styleRefs の 1:1 写像)。
|
|
24
28
|
* - fontSize token は複合値(px + lineHeight 比率)。theme 生成時に lineHeight は px 化済み。
|
|
25
|
-
* - letterSpacing は em 比率 token のため fontSize × ratio で pt
|
|
26
|
-
* theme の resolveLetterSpacing と同一式だが、theme index 経由の runtime import は
|
|
27
|
-
* ThemeProvider → react-native を引くため、pure に保つ目的でここでは式を直書きする。
|
|
29
|
+
* - letterSpacing は em 比率 token のため fontSize × ratio で pt 化する(resolveLetterSpacing)。
|
|
28
30
|
*/
|
|
29
31
|
export function resolveTextShape(
|
|
30
32
|
theme: NativeTheme,
|
|
@@ -35,8 +37,10 @@ export function resolveTextShape(
|
|
|
35
37
|
const fs = theme.typography.fontSize[variant];
|
|
36
38
|
return {
|
|
37
39
|
fontSize: fs.fontSize,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
// 既定 theme は codegen 時点でクランプ済みだが、defineTheme で注入されたカスタム theme の
|
|
41
|
+
// 値はここが最初の防波堤(機序と下限の根拠は theme/line-height.ts)。
|
|
42
|
+
lineHeight: clampLineHeight(fs.fontSize, fs.lineHeight, minRatioOf(theme)),
|
|
43
|
+
letterSpacing: resolveLetterSpacing(fs.fontSize, theme.typography.letterSpacingRatio[role]),
|
|
40
44
|
...(weight ? { fontWeight: theme.typography.fontWeight[weight] } : null),
|
|
41
45
|
};
|
|
42
46
|
}
|
package/src/safe-area/index.ts
CHANGED
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
* import { enableSafeAreaContext } from "melta-app/safe-area";
|
|
12
12
|
* enableSafeAreaContext();
|
|
13
13
|
*
|
|
14
|
-
* これで Screen の SafeArea が useSafeAreaInsets() + View の
|
|
15
|
-
* Provider の context 値を render 中に同期参照して padding を付けるため、
|
|
16
|
-
* SafeAreaView の layout/state 更新を待たず、初回 render から inset が反映される。
|
|
14
|
+
* これで Screen / ActionSheet / BottomSheet の SafeArea が useSafeAreaInsets() + View の
|
|
15
|
+
* adapter に切り替わる。Provider の context 値を render 中に同期参照して padding を付けるため、
|
|
16
|
+
* native SafeAreaView の layout/state 更新を待たず、初回 render から inset が反映される。
|
|
17
|
+
* Android でも効く(RN core の SafeAreaView は Android では完全 no-op)。
|
|
17
18
|
*
|
|
18
19
|
* ⚠️ 前提: アプリの root に SafeAreaProvider が必要(無いと useSafeAreaInsets が throw
|
|
19
20
|
* する)。初回 render から正しい inset を使うには Provider に initialMetrics も渡す。
|
|
@@ -35,13 +36,21 @@ import {
|
|
|
35
36
|
setSafeAreaView,
|
|
36
37
|
type SafeAreaViewLike,
|
|
37
38
|
type SafeAreaViewLikeProps,
|
|
38
|
-
} from "../components/safe-area-registry";
|
|
39
|
+
} from "../components/safe-area-registry.js";
|
|
39
40
|
|
|
40
41
|
const ALL_EDGES = ["top", "right", "bottom", "left"] as const satisfies readonly Edge[];
|
|
41
42
|
|
|
42
43
|
/** enableSafeAreaContext() の設定。edges 省略時は従来相当の全 edge。 */
|
|
43
44
|
export interface EnableSafeAreaContextOptions {
|
|
44
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* **Screen の既定 edge**(`edges` prop を渡さなかった Screen に適用される)。
|
|
47
|
+
* tab bar 等が担当する edge は除外する。
|
|
48
|
+
*
|
|
49
|
+
* ⚠️ 0.5.x までは「アプリ全体で 1 個のグローバル」だったが、edge は消費者ごとに
|
|
50
|
+
* 決まるべきものなので既定値の意味に変わった。ActionSheet / BottomSheet は画面下端に
|
|
51
|
+
* 出る都合上、ここの指定に関わらず自前の edge(bottom + 左右)を使う。
|
|
52
|
+
* 画面ごとに変えたい場合は `<Screen edges={["top"]} />` のように Screen 側で指定する。
|
|
53
|
+
*/
|
|
45
54
|
edges?: readonly Edge[];
|
|
46
55
|
}
|
|
47
56
|
|
|
@@ -100,7 +109,12 @@ function createContextSafeAreaView(selectedEdges: readonly Edge[]): SafeAreaView
|
|
|
100
109
|
return ContextSafeAreaView;
|
|
101
110
|
}
|
|
102
111
|
|
|
103
|
-
/**
|
|
112
|
+
/**
|
|
113
|
+
* melta の SafeArea を context 同期参照の View adapter に切り替える。
|
|
114
|
+
*
|
|
115
|
+
* registry には**ファクトリ**を渡す(消費者ごとに edges が違うため)。同じ edges 集合には
|
|
116
|
+
* 同じコンポーネント参照が返るよう memo するのは registry 側の責務。
|
|
117
|
+
*/
|
|
104
118
|
export function enableSafeAreaContext(options: EnableSafeAreaContextOptions = {}): void {
|
|
105
|
-
setSafeAreaView(createContextSafeAreaView
|
|
119
|
+
setSafeAreaView(createContextSafeAreaView, options.edges ?? ALL_EDGES);
|
|
106
120
|
}
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
import { createContext, useContext, useMemo, type ReactNode } from "react";
|
|
16
16
|
import { useColorScheme } from "react-native";
|
|
17
|
-
import { nativeTheme } from "./native-theme";
|
|
18
|
-
import { defineTheme, isDev, resolveMode, type ResolvedCapabilities, type ResolvedNativeTheme, type ThemeModeViolation } from "./define-theme";
|
|
19
|
-
import type { NativeTheme, SemanticColors, ThemeMode } from "./types";
|
|
17
|
+
import { nativeTheme } from "./native-theme.js";
|
|
18
|
+
import { defineTheme, isDev, resolveMode, type ResolvedCapabilities, type ResolvedNativeTheme, type ThemeModeViolation } from "./define-theme.js";
|
|
19
|
+
import type { NativeTheme, SemanticColors, ThemeMode } from "./types.js";
|
|
20
20
|
|
|
21
21
|
export type { ThemeMode };
|
|
22
22
|
|
|
@@ -41,8 +41,11 @@ const ThemeContext = createContext<ThemeContextValue | null>(null);
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* 既定 theme。melta-contracts 由来の codegen 結果を注入経路と同じ形に通す(自分でも dogfood する)。
|
|
44
|
-
*
|
|
45
|
-
*
|
|
44
|
+
*
|
|
45
|
+
* dev で freeze されるのは **`defineTheme()` の戻り値**(= `useTheme().theme` として配られる
|
|
46
|
+
* 解決済み theme)で、入れ子のトークン群まで再帰的に凍る。公開 export の `nativeTheme` 自体は
|
|
47
|
+
* `defineTheme` 内の `cloneTokenTree` で参照が切り離されているので**凍らない**
|
|
48
|
+
* (0.4.3 で意図的にこう変えた: 凍らせると `{ ...nativeTheme }` からの正当な派生が dev で壊れるため)。
|
|
46
49
|
*/
|
|
47
50
|
const DEFAULT_THEME: ResolvedNativeTheme = defineTheme({ ...nativeTheme, id: "melta" });
|
|
48
51
|
|