@studio-piot/native-ui 0.2.0 → 0.2.2
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 +3 -1
- package/dist/components/Select/Select.d.ts +3 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.js +72 -28
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/SelectCloseButton.d.ts +9 -3
- package/dist/components/Select/SelectCloseButton.d.ts.map +1 -1
- package/dist/components/Select/SelectCloseButton.js +2 -5
- package/dist/components/Select/SelectCloseButton.js.map +1 -1
- package/dist/components/Select/presentSelectSheet.d.ts +7 -0
- package/dist/components/Select/presentSelectSheet.d.ts.map +1 -0
- package/dist/components/Select/presentSelectSheet.js +14 -0
- package/dist/components/Select/presentSelectSheet.js.map +1 -0
- package/dist/components/Select/selectThemeRoles.d.ts +1 -1
- package/dist/components/Select/selectThemeRoles.js +1 -1
- package/dist/components/Select/selectThemeRoles.js.map +1 -1
- package/dist/components/Select/types.d.ts +2 -2
- package/dist/components/Select/types.d.ts.map +1 -1
- package/dist/components/Slider/Slider.d.ts +3 -0
- package/dist/components/Slider/Slider.d.ts.map +1 -0
- package/dist/components/Slider/Slider.js +46 -0
- package/dist/components/Slider/Slider.js.map +1 -0
- package/dist/components/Slider/index.d.ts +4 -0
- package/dist/components/Slider/index.d.ts.map +1 -0
- package/dist/components/Slider/index.js +8 -0
- package/dist/components/Slider/index.js.map +1 -0
- package/dist/components/Slider/sliderThemeRoles.d.ts +8 -0
- package/dist/components/Slider/sliderThemeRoles.d.ts.map +1 -0
- package/dist/components/Slider/sliderThemeRoles.js +10 -0
- package/dist/components/Slider/sliderThemeRoles.js.map +1 -0
- package/dist/components/Slider/types.d.ts +18 -0
- package/dist/components/Slider/types.d.ts.map +1 -0
- package/dist/components/Slider/types.js +3 -0
- package/dist/components/Slider/types.js.map +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +4 -1
- package/dist/components/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/docs/components/select.md +11 -6
- package/docs/components/slider.md +65 -0
- package/docs/superpowers/plans/2026-09-25-slider.md +35 -0
- package/docs/superpowers/specs/2026-09-25-select-design.md +3 -3
- package/docs/superpowers/specs/2026-09-25-slider-design.md +117 -0
- package/package.json +6 -2
- package/src/components/Select/Select.tsx +133 -64
- package/src/components/Select/SelectCloseButton.tsx +15 -7
- package/src/components/Select/selectThemeRoles.test.ts +2 -2
- package/src/components/Select/selectThemeRoles.ts +1 -1
- package/src/components/Select/types.ts +2 -2
- package/src/components/Slider/Slider.tsx +95 -0
- package/src/components/Slider/index.ts +6 -0
- package/src/components/Slider/sliderThemeRoles.test.ts +12 -0
- package/src/components/Slider/sliderThemeRoles.ts +8 -0
- package/src/components/Slider/types.ts +18 -0
- package/src/components/index.ts +6 -0
- package/src/index.ts +7 -1
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import { Pressable, StyleSheet, Text } from "react-native";
|
|
2
|
-
import { useThemeColor } from "../../theme/useThemeColor";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
type SelectCloseButtonProps = {
|
|
4
|
+
onPress: () => void;
|
|
5
|
+
/** Disc fill. Select passes theme colours so this stays portal-safe. */
|
|
6
|
+
backgroundColor?: string;
|
|
7
|
+
/** Cross colour. */
|
|
8
|
+
iconColor?: string;
|
|
9
|
+
};
|
|
8
10
|
|
|
11
|
+
/** Default Select sheet close: filled disc + contrasting cross. */
|
|
12
|
+
export function SelectCloseButton({
|
|
13
|
+
onPress,
|
|
14
|
+
backgroundColor = "#111111",
|
|
15
|
+
iconColor = "#FFFFFF",
|
|
16
|
+
}: SelectCloseButtonProps) {
|
|
9
17
|
return (
|
|
10
18
|
<Pressable
|
|
11
19
|
accessibilityLabel="Close"
|
|
12
20
|
accessibilityRole="button"
|
|
13
21
|
hitSlop={8}
|
|
14
22
|
onPress={onPress}
|
|
15
|
-
style={[styles.disc, { backgroundColor
|
|
23
|
+
style={[styles.disc, { backgroundColor }]}
|
|
16
24
|
>
|
|
17
|
-
<Text style={[styles.discX, { color:
|
|
25
|
+
<Text style={[styles.discX, { color: iconColor }]}>×</Text>
|
|
18
26
|
</Pressable>
|
|
19
27
|
);
|
|
20
28
|
}
|
|
@@ -3,7 +3,7 @@ import { describe, it } from "node:test";
|
|
|
3
3
|
import { SELECT_THEME_ROLES } from "./selectThemeRoles.ts";
|
|
4
4
|
|
|
5
5
|
describe("SELECT_THEME_ROLES", () => {
|
|
6
|
-
it("maps colour props to Field roles plus
|
|
6
|
+
it("maps colour props to Field roles plus fieldSelectSelected", () => {
|
|
7
7
|
assert.equal(SELECT_THEME_ROLES.backgroundColor, "fieldBackground");
|
|
8
8
|
assert.equal(SELECT_THEME_ROLES.textColor, "fieldText");
|
|
9
9
|
assert.equal(SELECT_THEME_ROLES.placeholderColor, "fieldPlaceholder");
|
|
@@ -11,6 +11,6 @@ describe("SELECT_THEME_ROLES", () => {
|
|
|
11
11
|
assert.equal(SELECT_THEME_ROLES.descriptionColor, "fieldDescription");
|
|
12
12
|
assert.equal(SELECT_THEME_ROLES.borderColor, "fieldBorder");
|
|
13
13
|
assert.equal(SELECT_THEME_ROLES.errorColor, "fieldError");
|
|
14
|
-
assert.equal(SELECT_THEME_ROLES.selectedColor, "
|
|
14
|
+
assert.equal(SELECT_THEME_ROLES.selectedColor, "fieldSelectSelected");
|
|
15
15
|
});
|
|
16
16
|
});
|
|
@@ -6,7 +6,7 @@ export const SELECT_THEME_ROLES = {
|
|
|
6
6
|
descriptionColor: "fieldDescription",
|
|
7
7
|
borderColor: "fieldBorder",
|
|
8
8
|
errorColor: "fieldError",
|
|
9
|
-
selectedColor: "
|
|
9
|
+
selectedColor: "fieldSelectSelected",
|
|
10
10
|
} as const;
|
|
11
11
|
|
|
12
12
|
export type SelectThemeColorProp = keyof typeof SELECT_THEME_ROLES;
|
|
@@ -23,9 +23,9 @@ export type SelectProps = {
|
|
|
23
23
|
sheetTitle?: string;
|
|
24
24
|
/** DiscClose by default. Pass `(dismiss) => <YourClose onPress={dismiss} />` to override. */
|
|
25
25
|
closeButton?: SelectCloseButton;
|
|
26
|
-
/** Detent fractions 0–1
|
|
26
|
+
/** Detent fractions 0–1. Largest value caps sheet height (content-sized up to that max). Default `[0.25, 0.5, 0.75]`. */
|
|
27
27
|
detents?: number[];
|
|
28
|
-
/**
|
|
28
|
+
/** @deprecated Ignored — sheet opens at content height (capped by `detents`). */
|
|
29
29
|
initialDetent?: number;
|
|
30
30
|
radius?: ButtonRadius;
|
|
31
31
|
editable?: boolean;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { StyleSheet, Text, View } from "react-native";
|
|
2
|
+
import CommunitySlider from "@react-native-community/slider";
|
|
3
|
+
import { useResolvedFieldColor } from "../Field/useResolvedFieldColor";
|
|
4
|
+
import { SLIDER_THEME_ROLES } from "./sliderThemeRoles";
|
|
5
|
+
import type { SliderProps } from "./types";
|
|
6
|
+
|
|
7
|
+
export function Slider({
|
|
8
|
+
value,
|
|
9
|
+
onChange,
|
|
10
|
+
minimumValue,
|
|
11
|
+
maximumValue,
|
|
12
|
+
step,
|
|
13
|
+
label,
|
|
14
|
+
formatValue = String,
|
|
15
|
+
disabled = false,
|
|
16
|
+
labelColor: labelColorProp,
|
|
17
|
+
valueColor: valueColorProp,
|
|
18
|
+
highlightColor: highlightColorProp,
|
|
19
|
+
trackColor: trackColorProp,
|
|
20
|
+
style,
|
|
21
|
+
}: SliderProps) {
|
|
22
|
+
const labelColor = useResolvedFieldColor(
|
|
23
|
+
labelColorProp,
|
|
24
|
+
SLIDER_THEME_ROLES.labelColor,
|
|
25
|
+
);
|
|
26
|
+
const valueColor = useResolvedFieldColor(
|
|
27
|
+
valueColorProp,
|
|
28
|
+
SLIDER_THEME_ROLES.valueColor,
|
|
29
|
+
);
|
|
30
|
+
const highlightColor = useResolvedFieldColor(
|
|
31
|
+
highlightColorProp,
|
|
32
|
+
SLIDER_THEME_ROLES.highlightColor,
|
|
33
|
+
);
|
|
34
|
+
const trackColor = useResolvedFieldColor(
|
|
35
|
+
trackColorProp,
|
|
36
|
+
SLIDER_THEME_ROLES.trackColor,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const display = formatValue(value);
|
|
40
|
+
const accessibilityLabel = label ? `${label}. ${display}` : display;
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<View style={[styles.column, disabled && styles.blocked, style]}>
|
|
44
|
+
<View style={styles.header}>
|
|
45
|
+
{label ? (
|
|
46
|
+
<Text style={[styles.label, { color: labelColor, flex: 1 }]}>
|
|
47
|
+
{label}
|
|
48
|
+
</Text>
|
|
49
|
+
) : (
|
|
50
|
+
<View style={{ flex: 1 }} />
|
|
51
|
+
)}
|
|
52
|
+
<Text style={[styles.value, { color: valueColor }]}>{display}</Text>
|
|
53
|
+
</View>
|
|
54
|
+
<CommunitySlider
|
|
55
|
+
accessibilityLabel={accessibilityLabel}
|
|
56
|
+
disabled={disabled}
|
|
57
|
+
maximumTrackTintColor={trackColor}
|
|
58
|
+
maximumValue={maximumValue}
|
|
59
|
+
minimumTrackTintColor={highlightColor}
|
|
60
|
+
minimumValue={minimumValue}
|
|
61
|
+
onValueChange={onChange}
|
|
62
|
+
step={step}
|
|
63
|
+
style={styles.track}
|
|
64
|
+
thumbTintColor={highlightColor}
|
|
65
|
+
value={value}
|
|
66
|
+
/>
|
|
67
|
+
</View>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const styles = StyleSheet.create({
|
|
72
|
+
column: {
|
|
73
|
+
width: "100%",
|
|
74
|
+
gap: 6,
|
|
75
|
+
},
|
|
76
|
+
blocked: {
|
|
77
|
+
opacity: 0.4,
|
|
78
|
+
},
|
|
79
|
+
header: {
|
|
80
|
+
flexDirection: "row",
|
|
81
|
+
alignItems: "center",
|
|
82
|
+
gap: 12,
|
|
83
|
+
},
|
|
84
|
+
label: {
|
|
85
|
+
fontSize: 13,
|
|
86
|
+
fontWeight: "600",
|
|
87
|
+
},
|
|
88
|
+
value: {
|
|
89
|
+
fontSize: 17,
|
|
90
|
+
},
|
|
91
|
+
track: {
|
|
92
|
+
width: "100%",
|
|
93
|
+
height: 40,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { SLIDER_THEME_ROLES } from "./sliderThemeRoles.ts";
|
|
4
|
+
|
|
5
|
+
describe("SLIDER_THEME_ROLES", () => {
|
|
6
|
+
it("maps colour props to Field roles plus fieldSliderHighlight", () => {
|
|
7
|
+
assert.equal(SLIDER_THEME_ROLES.labelColor, "fieldLabel");
|
|
8
|
+
assert.equal(SLIDER_THEME_ROLES.valueColor, "fieldText");
|
|
9
|
+
assert.equal(SLIDER_THEME_ROLES.highlightColor, "fieldSliderHighlight");
|
|
10
|
+
assert.equal(SLIDER_THEME_ROLES.trackColor, "fieldBorder");
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StyleProp, ViewStyle } from "react-native";
|
|
2
|
+
|
|
3
|
+
export type SliderProps = {
|
|
4
|
+
value: number;
|
|
5
|
+
onChange: (value: number) => void;
|
|
6
|
+
minimumValue: number;
|
|
7
|
+
maximumValue: number;
|
|
8
|
+
step?: number;
|
|
9
|
+
label?: string;
|
|
10
|
+
/** Defaults to `String(value)`. */
|
|
11
|
+
formatValue?: (value: number) => string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
labelColor?: string;
|
|
14
|
+
valueColor?: string;
|
|
15
|
+
highlightColor?: string;
|
|
16
|
+
trackColor?: string;
|
|
17
|
+
style?: StyleProp<ViewStyle>;
|
|
18
|
+
};
|
package/src/components/index.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const version = "0.2.
|
|
1
|
+
export const version = "0.2.2";
|
|
2
2
|
|
|
3
3
|
export * from "./theme";
|
|
4
4
|
export {
|
|
@@ -48,4 +48,10 @@ export {
|
|
|
48
48
|
type SelectOption,
|
|
49
49
|
type SelectProps,
|
|
50
50
|
} from "./components/Select";
|
|
51
|
+
export {
|
|
52
|
+
Slider,
|
|
53
|
+
SLIDER_THEME_ROLES,
|
|
54
|
+
type SliderThemeColorProp,
|
|
55
|
+
type SliderProps,
|
|
56
|
+
} from "./components/Slider";
|
|
51
57
|
export * as components from "./components";
|