@studio-piot/native-ui 0.1.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 +81 -19
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/SelectCloseButton.d.ts +9 -2
- package/dist/components/Select/SelectCloseButton.d.ts.map +1 -1
- package/dist/components/Select/SelectCloseButton.js +14 -6
- package/dist/components/Select/SelectCloseButton.js.map +1 -1
- package/dist/components/Select/index.d.ts +3 -3
- package/dist/components/Select/index.d.ts.map +1 -1
- package/dist/components/Select/index.js +2 -1
- package/dist/components/Select/index.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/resolveSelectDetentIndex.d.ts +2 -0
- package/dist/components/Select/resolveSelectDetentIndex.d.ts.map +1 -1
- package/dist/components/Select/resolveSelectDetentIndex.js +5 -0
- package/dist/components/Select/resolveSelectDetentIndex.js.map +1 -1
- 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/trueSheetReanimated.d.ts +13 -0
- package/dist/components/Select/trueSheetReanimated.d.ts.map +1 -0
- package/dist/components/Select/trueSheetReanimated.js +14 -0
- package/dist/components/Select/trueSheetReanimated.js.map +1 -0
- package/dist/components/Select/types.d.ts +3 -1
- 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 +2 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -1
- package/dist/components/index.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/docs/components/select.md +32 -10
- package/docs/components/slider.md +65 -0
- package/docs/superpowers/plans/2026-09-25-select.md +26 -8
- package/docs/superpowers/plans/2026-09-25-slider.md +35 -0
- package/docs/superpowers/specs/2026-09-25-select-design.md +39 -67
- package/docs/superpowers/specs/2026-09-25-slider-design.md +117 -0
- package/package.json +12 -4
- package/src/components/Select/Select.tsx +188 -75
- package/src/components/Select/SelectCloseButton.tsx +32 -7
- package/src/components/Select/index.ts +6 -2
- package/src/components/Select/resolveSelectDetentIndex.test.ts +15 -1
- package/src/components/Select/resolveSelectDetentIndex.ts +5 -0
- package/src/components/Select/selectThemeRoles.test.ts +16 -0
- package/src/components/Select/selectThemeRoles.ts +1 -1
- package/src/components/Select/types.ts +3 -1
- 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 +8 -1
- package/src/index.ts +9 -2
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SLIDER_THEME_ROLES = exports.Slider = void 0;
|
|
4
|
+
var Slider_1 = require("./Slider");
|
|
5
|
+
Object.defineProperty(exports, "Slider", { enumerable: true, get: function () { return Slider_1.Slider; } });
|
|
6
|
+
var sliderThemeRoles_1 = require("./sliderThemeRoles");
|
|
7
|
+
Object.defineProperty(exports, "SLIDER_THEME_ROLES", { enumerable: true, get: function () { return sliderThemeRoles_1.SLIDER_THEME_ROLES; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/Slider/index.ts"],"names":[],"mappings":";;;AAAA,mCAAkC;AAAzB,gGAAA,MAAM,OAAA;AACf,uDAG4B;AAF1B,sHAAA,kBAAkB,OAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const SLIDER_THEME_ROLES: {
|
|
2
|
+
readonly labelColor: "fieldLabel";
|
|
3
|
+
readonly valueColor: "fieldText";
|
|
4
|
+
readonly highlightColor: "fieldSliderHighlight";
|
|
5
|
+
readonly trackColor: "fieldBorder";
|
|
6
|
+
};
|
|
7
|
+
export type SliderThemeColorProp = keyof typeof SLIDER_THEME_ROLES;
|
|
8
|
+
//# sourceMappingURL=sliderThemeRoles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sliderThemeRoles.d.ts","sourceRoot":"","sources":["../../../src/components/Slider/sliderThemeRoles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB;;;;;CAKrB,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SLIDER_THEME_ROLES = void 0;
|
|
4
|
+
exports.SLIDER_THEME_ROLES = {
|
|
5
|
+
labelColor: "fieldLabel",
|
|
6
|
+
valueColor: "fieldText",
|
|
7
|
+
highlightColor: "fieldSliderHighlight",
|
|
8
|
+
trackColor: "fieldBorder",
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=sliderThemeRoles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sliderThemeRoles.js","sourceRoot":"","sources":["../../../src/components/Slider/sliderThemeRoles.ts"],"names":[],"mappings":";;;AAAa,QAAA,kBAAkB,GAAG;IAChC,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,WAAW;IACvB,cAAc,EAAE,sBAAsB;IACtC,UAAU,EAAE,aAAa;CACjB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StyleProp, ViewStyle } from "react-native";
|
|
2
|
+
export type SliderProps = {
|
|
3
|
+
value: number;
|
|
4
|
+
onChange: (value: number) => void;
|
|
5
|
+
minimumValue: number;
|
|
6
|
+
maximumValue: number;
|
|
7
|
+
step?: number;
|
|
8
|
+
label?: string;
|
|
9
|
+
/** Defaults to `String(value)`. */
|
|
10
|
+
formatValue?: (value: number) => string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
labelColor?: string;
|
|
13
|
+
valueColor?: string;
|
|
14
|
+
highlightColor?: string;
|
|
15
|
+
trackColor?: string;
|
|
16
|
+
style?: StyleProp<ViewStyle>;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/Slider/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/components/Slider/types.ts"],"names":[],"mappings":""}
|
|
@@ -3,5 +3,6 @@ export { LinkBlocks, filterLinkBlockGroups, type LinkBlockGroup, type LinkBlockI
|
|
|
3
3
|
export { FieldText, FieldTextarea, FIELD_THEME_ROLES, type FieldThemeColorProp, type FieldSharedProps, type FieldTextProps, type FieldTextareaProps, } from "./Field";
|
|
4
4
|
export { Form, FormCloseButton, type FormProps } from "./Form";
|
|
5
5
|
export { RadioField, RADIO_THEME_ROLES, type RadioThemeColorProp, type RadioOption, type RadioFieldProps, } from "./RadioField";
|
|
6
|
-
export { Select, SelectCloseButton, SELECT_THEME_ROLES, DEFAULT_SELECT_DETENTS, DEFAULT_SELECT_INITIAL_DETENT, resolveSelectDetentIndex, type SelectThemeColorProp, type
|
|
6
|
+
export { Select, SelectCloseButton, SELECT_THEME_ROLES, DEFAULT_SELECT_DETENTS, DEFAULT_SELECT_INITIAL_DETENT, detentsToSnapPoints, resolveSelectDetentIndex, type SelectThemeColorProp, type SelectCloseButtonSlot, type SelectOption, type SelectProps, } from "./Select";
|
|
7
|
+
export { Slider, SLIDER_THEME_ROLES, type SliderThemeColorProp, type SliderProps, } from "./Slider";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,UAAU,EACV,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAC/D,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,MAAM,EACN,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,EAC7B,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,UAAU,EACV,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAC/D,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,MAAM,EACN,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,EAC7B,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,MAAM,EACN,kBAAkB,EAClB,KAAK,oBAAoB,EACzB,KAAK,WAAW,GACjB,MAAM,UAAU,CAAC"}
|
package/dist/components/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveSelectDetentIndex = exports.DEFAULT_SELECT_INITIAL_DETENT = exports.DEFAULT_SELECT_DETENTS = exports.SELECT_THEME_ROLES = exports.SelectCloseButton = exports.Select = exports.RADIO_THEME_ROLES = exports.RadioField = exports.FormCloseButton = exports.Form = exports.FIELD_THEME_ROLES = exports.FieldTextarea = exports.FieldText = exports.filterLinkBlockGroups = exports.LinkBlocks = exports.buttonRadiusValue = exports.Button = void 0;
|
|
3
|
+
exports.SLIDER_THEME_ROLES = exports.Slider = exports.resolveSelectDetentIndex = exports.detentsToSnapPoints = exports.DEFAULT_SELECT_INITIAL_DETENT = exports.DEFAULT_SELECT_DETENTS = exports.SELECT_THEME_ROLES = exports.SelectCloseButton = exports.Select = exports.RADIO_THEME_ROLES = exports.RadioField = exports.FormCloseButton = exports.Form = exports.FIELD_THEME_ROLES = exports.FieldTextarea = exports.FieldText = exports.filterLinkBlockGroups = exports.LinkBlocks = exports.buttonRadiusValue = exports.Button = void 0;
|
|
4
4
|
var Button_1 = require("./Button");
|
|
5
5
|
Object.defineProperty(exports, "Button", { enumerable: true, get: function () { return Button_1.Button; } });
|
|
6
6
|
Object.defineProperty(exports, "buttonRadiusValue", { enumerable: true, get: function () { return Button_1.buttonRadiusValue; } });
|
|
@@ -23,5 +23,9 @@ Object.defineProperty(exports, "SelectCloseButton", { enumerable: true, get: fun
|
|
|
23
23
|
Object.defineProperty(exports, "SELECT_THEME_ROLES", { enumerable: true, get: function () { return Select_1.SELECT_THEME_ROLES; } });
|
|
24
24
|
Object.defineProperty(exports, "DEFAULT_SELECT_DETENTS", { enumerable: true, get: function () { return Select_1.DEFAULT_SELECT_DETENTS; } });
|
|
25
25
|
Object.defineProperty(exports, "DEFAULT_SELECT_INITIAL_DETENT", { enumerable: true, get: function () { return Select_1.DEFAULT_SELECT_INITIAL_DETENT; } });
|
|
26
|
+
Object.defineProperty(exports, "detentsToSnapPoints", { enumerable: true, get: function () { return Select_1.detentsToSnapPoints; } });
|
|
26
27
|
Object.defineProperty(exports, "resolveSelectDetentIndex", { enumerable: true, get: function () { return Select_1.resolveSelectDetentIndex; } });
|
|
28
|
+
var Slider_1 = require("./Slider");
|
|
29
|
+
Object.defineProperty(exports, "Slider", { enumerable: true, get: function () { return Slider_1.Slider; } });
|
|
30
|
+
Object.defineProperty(exports, "SLIDER_THEME_ROLES", { enumerable: true, get: function () { return Slider_1.SLIDER_THEME_ROLES; } });
|
|
27
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":";;;AAAA,mCAKkB;AAJhB,gGAAA,MAAM,OAAA;AAEN,2GAAA,iBAAiB,OAAA;AAGnB,2CAMsB;AALpB,wGAAA,UAAU,OAAA;AACV,mHAAA,qBAAqB,OAAA;AAKvB,iCAQiB;AAPf,kGAAA,SAAS,OAAA;AACT,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AAMnB,+BAA+D;AAAtD,4FAAA,IAAI,OAAA;AAAE,uGAAA,eAAe,OAAA;AAC9B,2CAMsB;AALpB,wGAAA,UAAU,OAAA;AACV,+GAAA,iBAAiB,OAAA;AAKnB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":";;;AAAA,mCAKkB;AAJhB,gGAAA,MAAM,OAAA;AAEN,2GAAA,iBAAiB,OAAA;AAGnB,2CAMsB;AALpB,wGAAA,UAAU,OAAA;AACV,mHAAA,qBAAqB,OAAA;AAKvB,iCAQiB;AAPf,kGAAA,SAAS,OAAA;AACT,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AAMnB,+BAA+D;AAAtD,4FAAA,IAAI,OAAA;AAAE,uGAAA,eAAe,OAAA;AAC9B,2CAMsB;AALpB,wGAAA,UAAU,OAAA;AACV,+GAAA,iBAAiB,OAAA;AAKnB,mCAYkB;AAXhB,gGAAA,MAAM,OAAA;AACN,2GAAA,iBAAiB,OAAA;AACjB,4GAAA,kBAAkB,OAAA;AAClB,gHAAA,sBAAsB,OAAA;AACtB,uHAAA,6BAA6B,OAAA;AAC7B,6GAAA,mBAAmB,OAAA;AACnB,kHAAA,wBAAwB,OAAA;AAM1B,mCAKkB;AAJhB,gGAAA,MAAM,OAAA;AACN,4GAAA,kBAAkB,OAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
export declare const version = "0.
|
|
1
|
+
export declare const version = "0.2.2";
|
|
2
2
|
export * from "./theme";
|
|
3
3
|
export { Button, type ButtonProps, buttonRadiusValue, type ButtonRadius, } from "./components/Button";
|
|
4
4
|
export { LinkBlocks, filterLinkBlockGroups, type LinkBlockGroup, type LinkBlockItem, type LinkBlocksProps, } from "./components/LinkBlocks";
|
|
5
5
|
export { FieldText, FieldTextarea, FIELD_THEME_ROLES, type FieldThemeColorProp, type FieldSharedProps, type FieldTextProps, type FieldTextareaProps, } from "./components/Field";
|
|
6
6
|
export { Form, FormCloseButton, type FormProps, } from "./components/Form";
|
|
7
7
|
export { RadioField, RADIO_THEME_ROLES, type RadioThemeColorProp, type RadioOption, type RadioFieldProps, } from "./components/RadioField";
|
|
8
|
-
export { Select, SelectCloseButton, SELECT_THEME_ROLES, DEFAULT_SELECT_DETENTS, DEFAULT_SELECT_INITIAL_DETENT, resolveSelectDetentIndex, type SelectThemeColorProp, type
|
|
8
|
+
export { Select, SelectCloseButton, SELECT_THEME_ROLES, DEFAULT_SELECT_DETENTS, DEFAULT_SELECT_INITIAL_DETENT, detentsToSnapPoints, resolveSelectDetentIndex, type SelectThemeColorProp, type SelectCloseButtonSlot, type SelectOption, type SelectProps, } from "./components/Select";
|
|
9
|
+
export { Slider, SLIDER_THEME_ROLES, type SliderThemeColorProp, type SliderProps, } from "./components/Slider";
|
|
9
10
|
export * as components from "./components";
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,cAAc,SAAS,CAAC;AACxB,OAAO,EACL,MAAM,EACN,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,YAAY,GAClB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,UAAU,EACV,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,IAAI,EACJ,eAAe,EACf,KAAK,SAAS,GACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,MAAM,EACN,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,EAC7B,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,cAAc,SAAS,CAAC;AACxB,OAAO,EACL,MAAM,EACN,KAAK,WAAW,EAChB,iBAAiB,EACjB,KAAK,YAAY,GAClB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,UAAU,EACV,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,IAAI,EACJ,eAAe,EACf,KAAK,SAAS,GACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,MAAM,EACN,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,EAC7B,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,MAAM,EACN,kBAAkB,EAClB,KAAK,oBAAoB,EACzB,KAAK,WAAW,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -36,8 +36,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
36
36
|
};
|
|
37
37
|
})();
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.components = exports.resolveSelectDetentIndex = exports.DEFAULT_SELECT_INITIAL_DETENT = exports.DEFAULT_SELECT_DETENTS = exports.SELECT_THEME_ROLES = exports.SelectCloseButton = exports.Select = exports.RADIO_THEME_ROLES = exports.RadioField = exports.FormCloseButton = exports.Form = exports.FIELD_THEME_ROLES = exports.FieldTextarea = exports.FieldText = exports.filterLinkBlockGroups = exports.LinkBlocks = exports.buttonRadiusValue = exports.Button = exports.version = void 0;
|
|
40
|
-
exports.version = "0.
|
|
39
|
+
exports.components = exports.SLIDER_THEME_ROLES = exports.Slider = exports.resolveSelectDetentIndex = exports.detentsToSnapPoints = exports.DEFAULT_SELECT_INITIAL_DETENT = exports.DEFAULT_SELECT_DETENTS = exports.SELECT_THEME_ROLES = exports.SelectCloseButton = exports.Select = exports.RADIO_THEME_ROLES = exports.RadioField = exports.FormCloseButton = exports.Form = exports.FIELD_THEME_ROLES = exports.FieldTextarea = exports.FieldText = exports.filterLinkBlockGroups = exports.LinkBlocks = exports.buttonRadiusValue = exports.Button = exports.version = void 0;
|
|
40
|
+
exports.version = "0.2.2";
|
|
41
41
|
__exportStar(require("./theme"), exports);
|
|
42
42
|
var Button_1 = require("./components/Button");
|
|
43
43
|
Object.defineProperty(exports, "Button", { enumerable: true, get: function () { return Button_1.Button; } });
|
|
@@ -61,6 +61,10 @@ Object.defineProperty(exports, "SelectCloseButton", { enumerable: true, get: fun
|
|
|
61
61
|
Object.defineProperty(exports, "SELECT_THEME_ROLES", { enumerable: true, get: function () { return Select_1.SELECT_THEME_ROLES; } });
|
|
62
62
|
Object.defineProperty(exports, "DEFAULT_SELECT_DETENTS", { enumerable: true, get: function () { return Select_1.DEFAULT_SELECT_DETENTS; } });
|
|
63
63
|
Object.defineProperty(exports, "DEFAULT_SELECT_INITIAL_DETENT", { enumerable: true, get: function () { return Select_1.DEFAULT_SELECT_INITIAL_DETENT; } });
|
|
64
|
+
Object.defineProperty(exports, "detentsToSnapPoints", { enumerable: true, get: function () { return Select_1.detentsToSnapPoints; } });
|
|
64
65
|
Object.defineProperty(exports, "resolveSelectDetentIndex", { enumerable: true, get: function () { return Select_1.resolveSelectDetentIndex; } });
|
|
66
|
+
var Slider_1 = require("./components/Slider");
|
|
67
|
+
Object.defineProperty(exports, "Slider", { enumerable: true, get: function () { return Slider_1.Slider; } });
|
|
68
|
+
Object.defineProperty(exports, "SLIDER_THEME_ROLES", { enumerable: true, get: function () { return Slider_1.SLIDER_THEME_ROLES; } });
|
|
65
69
|
exports.components = __importStar(require("./components"));
|
|
66
70
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAa,QAAA,OAAO,GAAG,OAAO,CAAC;AAE/B,0CAAwB;AACxB,8CAK6B;AAJ3B,gGAAA,MAAM,OAAA;AAEN,2GAAA,iBAAiB,OAAA;AAGnB,sDAMiC;AAL/B,wGAAA,UAAU,OAAA;AACV,mHAAA,qBAAqB,OAAA;AAKvB,4CAQ4B;AAP1B,kGAAA,SAAS,OAAA;AACT,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AAMnB,0CAI2B;AAHzB,4FAAA,IAAI,OAAA;AACJ,uGAAA,eAAe,OAAA;AAGjB,sDAMiC;AAL/B,wGAAA,UAAU,OAAA;AACV,+GAAA,iBAAiB,OAAA;AAKnB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAa,QAAA,OAAO,GAAG,OAAO,CAAC;AAE/B,0CAAwB;AACxB,8CAK6B;AAJ3B,gGAAA,MAAM,OAAA;AAEN,2GAAA,iBAAiB,OAAA;AAGnB,sDAMiC;AAL/B,wGAAA,UAAU,OAAA;AACV,mHAAA,qBAAqB,OAAA;AAKvB,4CAQ4B;AAP1B,kGAAA,SAAS,OAAA;AACT,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AAMnB,0CAI2B;AAHzB,4FAAA,IAAI,OAAA;AACJ,uGAAA,eAAe,OAAA;AAGjB,sDAMiC;AAL/B,wGAAA,UAAU,OAAA;AACV,+GAAA,iBAAiB,OAAA;AAKnB,8CAY6B;AAX3B,gGAAA,MAAM,OAAA;AACN,2GAAA,iBAAiB,OAAA;AACjB,4GAAA,kBAAkB,OAAA;AAClB,gHAAA,sBAAsB,OAAA;AACtB,uHAAA,6BAA6B,OAAA;AAC7B,6GAAA,mBAAmB,OAAA;AACnB,kHAAA,wBAAwB,OAAA;AAM1B,8CAK6B;AAJ3B,gGAAA,MAAM,OAAA;AACN,4GAAA,kBAAkB,OAAA;AAIpB,2DAA2C"}
|
|
@@ -1,22 +1,42 @@
|
|
|
1
1
|
# Select — usage
|
|
2
2
|
|
|
3
|
-
Field-like select trigger that opens a
|
|
3
|
+
Field-like select trigger that opens a Gorhom bottom sheet (`@gorhom/bottom-sheet`) of options. Selecting an option updates the value and dismisses the sheet.
|
|
4
4
|
|
|
5
5
|
For `ThemeProvider`, see [theme provider and Button usage](./button.md). Design: [Select design](../superpowers/specs/2026-09-25-select-design.md).
|
|
6
6
|
|
|
7
|
-
## Peer
|
|
7
|
+
## Peer dependencies
|
|
8
8
|
|
|
9
|
-
Install in the app:
|
|
9
|
+
Install in the app (Expo example):
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx expo install @
|
|
12
|
+
npx expo install @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler react-native-screens
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
On iOS, Select uses `FullWindowOverlay` so the sheet appears above React Navigation `fullScreenModal` screens.
|
|
16
|
+
|
|
17
|
+
Wrap the app root with `GestureHandlerRootView` and `BottomSheetModalProvider`. Put **`BottomSheetModalProvider` inside `ThemeProvider`** so sheet content (portaled) still resolves theme colours:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
|
|
21
|
+
import { ThemeProvider } from "@studio-piot/native-ui";
|
|
22
|
+
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
23
|
+
|
|
24
|
+
export default function RootLayout() {
|
|
25
|
+
return (
|
|
26
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
27
|
+
<ThemeProvider colors={Colors}>
|
|
28
|
+
<BottomSheetModalProvider>{/* … */}</BottomSheetModalProvider>
|
|
29
|
+
</ThemeProvider>
|
|
30
|
+
</GestureHandlerRootView>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Import `react-native-gesture-handler` at the top of the entry layout (before other imports) if your template requires it.
|
|
16
36
|
|
|
17
37
|
## Theme roles
|
|
18
38
|
|
|
19
|
-
Uses Field roles: `fieldBackground`, `fieldText`, `fieldPlaceholder`, `fieldLabel`, `fieldDescription`, `fieldBorder`, `fieldError`, plus
|
|
39
|
+
Uses Field roles: `fieldBackground`, `fieldText`, `fieldPlaceholder`, `fieldLabel`, `fieldDescription`, `fieldBorder`, `fieldError`, plus **`fieldSelectSelected`** for the selected option check / label tint.
|
|
20
40
|
|
|
21
41
|
## Basic usage
|
|
22
42
|
|
|
@@ -36,15 +56,17 @@ import { Select } from "@studio-piot/native-ui";
|
|
|
36
56
|
/>
|
|
37
57
|
```
|
|
38
58
|
|
|
39
|
-
##
|
|
59
|
+
## Close control
|
|
60
|
+
|
|
61
|
+
Default is a dark disc with a white × (`SelectCloseButton`). Override:
|
|
40
62
|
|
|
41
63
|
```tsx
|
|
42
|
-
closeButton={(dismiss) => <
|
|
64
|
+
closeButton={(dismiss) => <YourClose onPress={dismiss} />}
|
|
43
65
|
```
|
|
44
66
|
|
|
45
|
-
## Detents
|
|
67
|
+
## Detents / height
|
|
46
68
|
|
|
47
|
-
|
|
69
|
+
Sheet height follows content (`enableDynamicSizing`), capped by the largest `detents` fraction (default `0.75` of the window). Dragging cannot expand past content (or that cap when the list is long).
|
|
48
70
|
|
|
49
71
|
## Imports
|
|
50
72
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Slider — usage
|
|
2
|
+
|
|
3
|
+
Controlled slider with label on the left and a live formatted value on the top right. Track uses `@react-native-community/slider`. Your app owns form state.
|
|
4
|
+
|
|
5
|
+
Design: [Slider design](../superpowers/specs/2026-09-25-slider-design.md).
|
|
6
|
+
|
|
7
|
+
## Peer dependency
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx expo install @react-native-community/slider
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Theme roles
|
|
14
|
+
|
|
15
|
+
| Usage | Role |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Label | `fieldLabel` |
|
|
18
|
+
| Value | `fieldText` |
|
|
19
|
+
| Filled track + thumb | **`fieldSliderHighlight`** (apps must add) |
|
|
20
|
+
| Unfilled track | `fieldBorder` |
|
|
21
|
+
|
|
22
|
+
## Basic usage
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { Slider } from "@studio-piot/native-ui";
|
|
26
|
+
import { useState } from "react";
|
|
27
|
+
|
|
28
|
+
export function EffortSlider() {
|
|
29
|
+
const [effort, setEffort] = useState(5);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Slider
|
|
33
|
+
label="Effort"
|
|
34
|
+
value={effort}
|
|
35
|
+
onChange={setEffort}
|
|
36
|
+
minimumValue={1}
|
|
37
|
+
maximumValue={10}
|
|
38
|
+
step={1}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Optional colour overrides
|
|
45
|
+
|
|
46
|
+
| Prop | Default theme role |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `labelColor` | `fieldLabel` |
|
|
49
|
+
| `valueColor` | `fieldText` |
|
|
50
|
+
| `highlightColor` | `fieldSliderHighlight` |
|
|
51
|
+
| `trackColor` | `fieldBorder` |
|
|
52
|
+
|
|
53
|
+
### Props
|
|
54
|
+
|
|
55
|
+
| Prop | Type | Default | Notes |
|
|
56
|
+
|---|---|---|---|
|
|
57
|
+
| `value` | `number` | — | Required |
|
|
58
|
+
| `onChange` | `(value: number) => void` | — | Required |
|
|
59
|
+
| `minimumValue` | `number` | — | Required |
|
|
60
|
+
| `maximumValue` | `number` | — | Required |
|
|
61
|
+
| `step` | `number` | — | Optional; omit for continuous |
|
|
62
|
+
| `label` | `string` | — | Optional |
|
|
63
|
+
| `formatValue` | `(value: number) => string` | `String` | Value display |
|
|
64
|
+
| `disabled` | `boolean` | `false` | |
|
|
65
|
+
| `style` | view style | — | Outer column |
|
|
@@ -2,21 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
> **For agentic workers:** Inline execution in session; checkboxes track progress.
|
|
4
4
|
|
|
5
|
-
**Goal:** Ship `Select` (Field-like trigger +
|
|
5
|
+
**Goal:** Ship `Select` (Field-like trigger + Gorhom `BottomSheetModal`) and wire Ribe create-activity Type; remove TrueSheet from Ribe.
|
|
6
6
|
|
|
7
|
-
**Architecture:** Controlled `Select` presents `@
|
|
7
|
+
**Architecture:** Controlled `Select` presents `@gorhom/bottom-sheet` at snap points from detents `[0.25, 0.5, 0.75]` (open index for `0.5`). Default close is DiscClose. Field theme roles + `fieldRadioSelected` for selected check. App provides `BottomSheetModalProvider` (+ existing `GestureHandlerRootView`).
|
|
8
8
|
|
|
9
|
-
**Tech Stack:** TypeScript, RN,
|
|
9
|
+
**Tech Stack:** TypeScript, RN, Gorhom peer (+ reanimated, gesture-handler), Expo Ribe.
|
|
10
10
|
|
|
11
11
|
## Global Constraints
|
|
12
12
|
|
|
13
13
|
- Spec: `docs/superpowers/specs/2026-09-25-select-design.md`
|
|
14
|
-
-
|
|
14
|
+
- Peers: `@gorhom/bottom-sheet`, `react-native-reanimated`, `react-native-gesture-handler`
|
|
15
|
+
- No TrueSheet in package or Ribe
|
|
15
16
|
- No brand in package; no search/icons/grids
|
|
17
|
+
- Commit only when the user asks
|
|
18
|
+
|
|
19
|
+
## File map
|
|
20
|
+
|
|
21
|
+
| File | Responsibility |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `src/components/Select/resolveSelectDetentIndex.ts` | Detent → snap index + % snap points |
|
|
24
|
+
| `src/components/Select/resolveSelectDetentIndex.test.ts` | Unit tests |
|
|
25
|
+
| `src/components/Select/selectThemeRoles.ts` | Role map |
|
|
26
|
+
| `src/components/Select/selectThemeRoles.test.ts` | Role map assertions |
|
|
27
|
+
| `src/components/Select/types.ts` | Props |
|
|
28
|
+
| `src/components/Select/SelectCloseButton.tsx` | DiscClose default |
|
|
29
|
+
| `src/components/Select/Select.tsx` | Trigger + BottomSheetModal |
|
|
30
|
+
| `src/components/Select/index.ts` | Barrel |
|
|
31
|
+
| `docs/components/select.md` | Usage |
|
|
32
|
+
| Exports / README | Public surface |
|
|
33
|
+
| Ribe create-activity, root layout | Wire Select + BottomSheetModalProvider |
|
|
34
|
+
| Ribe package / sheet-lab / activities | Remove TrueSheet + lab |
|
|
16
35
|
|
|
17
36
|
## Tasks
|
|
18
37
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
---
|
|
38
|
+
- [x] Spec (Gorhom)
|
|
39
|
+
- [x] Package Select + peers + docs + exports + unit tests
|
|
40
|
+
- [x] Ribe: BottomSheetModalProvider, create-activity Select, remove TrueSheet + sheet-lab
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Slider Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** Inline execution in session; checkboxes track progress.
|
|
4
|
+
|
|
5
|
+
**Goal:** Ship controlled `Slider` (label left, formatted value top-right, community track) with `fieldSliderHighlight`, and wire Ribe create-activity Effort (1–10).
|
|
6
|
+
|
|
7
|
+
**Architecture:** Presentational wrapper around `@react-native-community/slider`. Theme colours resolve like Field via `useResolvedFieldColor`. New role `fieldSliderHighlight` for filled track + thumb; unfilled track uses `fieldBorder`.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** TypeScript, RN, `@react-native-community/slider` peer, Expo Ribe.
|
|
10
|
+
|
|
11
|
+
## Global Constraints
|
|
12
|
+
|
|
13
|
+
- Spec: `docs/superpowers/specs/2026-09-25-slider-design.md`
|
|
14
|
+
- Peer `@react-native-community/slider`
|
|
15
|
+
- No brand in package; no custom-drawn track; no Optimum migration
|
|
16
|
+
- Commit only when the user asks
|
|
17
|
+
|
|
18
|
+
## File map
|
|
19
|
+
|
|
20
|
+
| File | Responsibility |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `src/components/Slider/sliderThemeRoles.ts` | Role map |
|
|
23
|
+
| `src/components/Slider/sliderThemeRoles.test.ts` | Role assertions |
|
|
24
|
+
| `src/components/Slider/types.ts` | `SliderProps` |
|
|
25
|
+
| `src/components/Slider/Slider.tsx` | Header + community Slider |
|
|
26
|
+
| `src/components/Slider/index.ts` | Barrel |
|
|
27
|
+
| Exports / README / `docs/components/slider.md` | Public surface |
|
|
28
|
+
| Ribe `colors.ts` (+ test) | `fieldSliderHighlight` |
|
|
29
|
+
| Ribe create-activity | Effort Slider |
|
|
30
|
+
| Ribe `package.json` | Install community slider |
|
|
31
|
+
|
|
32
|
+
## Tasks
|
|
33
|
+
|
|
34
|
+
- [x] Package Slider + peer + docs + exports + unit test
|
|
35
|
+
- [x] Ribe: theme role + Effort on create-activity + install peer
|
|
@@ -7,22 +7,24 @@ Apps: Ribe create-activity Type field in the same pass
|
|
|
7
7
|
|
|
8
8
|
## Goal
|
|
9
9
|
|
|
10
|
-
Ship a presentational **Select**: Field-like trigger that opens a
|
|
10
|
+
Ship a presentational **Select**: Field-like trigger that opens a Gorhom bottom sheet of options. Highlight the selected option; choosing one updates value and dismisses the sheet. Grabber, dimmed backdrop, and snap heights match the spike UX. Ribe wires Type of activity to Select; default close is a dark disc with white cross (not glass Cancel).
|
|
11
11
|
|
|
12
12
|
## Decisions
|
|
13
13
|
|
|
14
14
|
| Topic | Choice |
|
|
15
15
|
|---|---|
|
|
16
16
|
| API shape | Single `Select`: trigger + internal sheet |
|
|
17
|
-
| Sheet library | `@
|
|
18
|
-
|
|
|
19
|
-
| Close control | `closeButton` slot; package default
|
|
20
|
-
| Colours | Field `field*` roles + `
|
|
17
|
+
| Sheet library | `@gorhom/bottom-sheet` (`BottomSheetModal`) |
|
|
18
|
+
| Sheet height | Content-sized (`enableDynamicSizing`); max = largest detent (default 75% of window) |
|
|
19
|
+
| Close control | `closeButton` slot; package default **DiscClose** (dark disc + white ×); Ribe uses default |
|
|
20
|
+
| Colours | Field `field*` roles + `fieldSelectSelected` for selected check / emphasis |
|
|
21
21
|
| Trigger | Field-like chrome (label, description, error, chevron, radius) |
|
|
22
22
|
| Options | `{ value, label, disabled? }[]`; scrollable when long |
|
|
23
23
|
| Select behaviour | Tap option → `onChange(value)` + dismiss |
|
|
24
|
+
| App provider | App must wrap with `GestureHandlerRootView` + `BottomSheetModalProvider` |
|
|
24
25
|
| Icons / search / grids | Out of scope |
|
|
25
|
-
|
|
|
26
|
+
| TrueSheet | Not used; no TrueSheet peer or native bits |
|
|
27
|
+
| Optimum migration | Out of scope this pass |
|
|
26
28
|
| Brand coupling | None in the package |
|
|
27
29
|
|
|
28
30
|
## Architecture
|
|
@@ -30,29 +32,30 @@ Ship a presentational **Select**: Field-like trigger that opens a native bottom
|
|
|
30
32
|
```
|
|
31
33
|
Select
|
|
32
34
|
├── trigger (Field-like Pressable)
|
|
33
|
-
└──
|
|
34
|
-
├──
|
|
35
|
+
└── BottomSheetModal
|
|
36
|
+
├── BottomSheetBackdrop (opacity 0.72)
|
|
37
|
+
├── handle / grabber
|
|
35
38
|
├── header (title + closeButton)
|
|
36
|
-
└──
|
|
39
|
+
└── BottomSheetScrollView options
|
|
37
40
|
└── row (label + check when selected)
|
|
38
41
|
```
|
|
39
42
|
|
|
40
|
-
- Public export: `Select` (+ types). Default close
|
|
43
|
+
- Public export: `Select` (+ types). Default close is `SelectCloseButton` (DiscClose).
|
|
41
44
|
- Controlled only: `value` + `onChange` + `options`.
|
|
42
|
-
- Peer
|
|
45
|
+
- Peer dependencies: `@gorhom/bottom-sheet`, `react-native-reanimated`, `react-native-gesture-handler` (plus existing RN peers).
|
|
43
46
|
|
|
44
47
|
## Theme roles
|
|
45
48
|
|
|
46
49
|
| Usage | Theme role |
|
|
47
50
|
|---|---|
|
|
48
|
-
| Trigger / sheet
|
|
51
|
+
| Trigger / sheet ground | `fieldBackground` |
|
|
49
52
|
| Trigger value / option label | `fieldText` |
|
|
50
|
-
| Placeholder / chevron | `fieldPlaceholder` |
|
|
53
|
+
| Placeholder / chevron / handle | `fieldPlaceholder` |
|
|
51
54
|
| Label above trigger | `fieldLabel` |
|
|
52
55
|
| Description under trigger | `fieldDescription` |
|
|
53
56
|
| Trigger border / dividers | `fieldBorder` |
|
|
54
57
|
| Error border + message | `fieldError` |
|
|
55
|
-
| Selected option emphasis / check | `
|
|
58
|
+
| Selected option emphasis / check | `fieldSelectSelected` |
|
|
56
59
|
|
|
57
60
|
Optional colour override props follow the Field pattern (explicit prop wins over theme role).
|
|
58
61
|
|
|
@@ -65,6 +68,10 @@ type SelectOption = {
|
|
|
65
68
|
disabled?: boolean;
|
|
66
69
|
};
|
|
67
70
|
|
|
71
|
+
type SelectCloseButton =
|
|
72
|
+
| ReactNode
|
|
73
|
+
| ((dismiss: () => void) => ReactNode);
|
|
74
|
+
|
|
68
75
|
type SelectProps = {
|
|
69
76
|
value: string | null;
|
|
70
77
|
onChange: (value: string) => void;
|
|
@@ -74,7 +81,7 @@ type SelectProps = {
|
|
|
74
81
|
description?: string;
|
|
75
82
|
error?: string;
|
|
76
83
|
sheetTitle?: string;
|
|
77
|
-
closeButton?:
|
|
84
|
+
closeButton?: SelectCloseButton;
|
|
78
85
|
detents?: number[];
|
|
79
86
|
initialDetent?: number;
|
|
80
87
|
radius?: ButtonRadius;
|
|
@@ -88,11 +95,11 @@ type SelectProps = {
|
|
|
88
95
|
|---|---|
|
|
89
96
|
| `value` | Controlled; `null` / unmatched → show placeholder |
|
|
90
97
|
| `onChange` | Fired with option `value` on row press |
|
|
91
|
-
| `options` | Empty list:
|
|
98
|
+
| `options` | Empty list: open sheet with “No options” empty state |
|
|
92
99
|
| `sheetTitle` | Header title; default `label` or `"Select"` |
|
|
93
|
-
| `closeButton` |
|
|
94
|
-
| `detents` |
|
|
95
|
-
| `initialDetent` | Default `0.5` (must be one of `detents`) |
|
|
100
|
+
| `closeButton` | Header trailing close; default DiscClose that dismisses |
|
|
101
|
+
| `detents` | Fractions `0–1`; default `[0.25, 0.5, 0.75]` → Gorhom snap `%` |
|
|
102
|
+
| `initialDetent` | Default `0.5` (must be one of `detents` or falls back to index 0) |
|
|
96
103
|
| `radius` | Trigger radius; default `"xl"` |
|
|
97
104
|
| `editable` | `false` → reduced opacity, no open |
|
|
98
105
|
|
|
@@ -107,58 +114,23 @@ Aligned with Field:
|
|
|
107
114
|
|
|
108
115
|
## Sheet behaviour
|
|
109
116
|
|
|
110
|
-
- Present
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
117
|
+
- Present `BottomSheetModal` on trigger press (when `editable`)
|
|
118
|
+
- Backdrop opacity `0.72`, press closes
|
|
119
|
+
- Handle indicator; `enablePanDownToClose`
|
|
120
|
+
- Header: title + `closeButton` (or default DiscClose)
|
|
121
|
+
- Scrollable option list; row min height ~52; selected row uses `fieldRadioSelected` for check (and label tint)
|
|
114
122
|
- Row press: `onChange` + dismiss
|
|
115
|
-
- Dismiss also via
|
|
116
|
-
- No search field, no category grids, no leading sport icons in this pass
|
|
123
|
+
- Dismiss also via pan-down / backdrop / close control
|
|
117
124
|
|
|
118
125
|
## Accessibility
|
|
119
126
|
|
|
120
|
-
- Trigger: `accessibilityRole="button"`, label
|
|
121
|
-
-
|
|
122
|
-
- Close
|
|
123
|
-
|
|
124
|
-
## App work (Ribe)
|
|
125
|
-
|
|
126
|
-
1. `npx expo install @lodev09/react-native-true-sheet` (or pnpm equivalent)
|
|
127
|
-
2. Create-activity: replace Type `FieldText` with `Select`
|
|
128
|
-
- Options: Ride, Run, Swim, Walk, Hike (values lowercase slug or same as label — pick stable string values e.g. `ride`, `run`, …)
|
|
129
|
-
- `error` when empty (same validation copy intent as today)
|
|
130
|
-
- `closeButton` that dismisses the sheet using glass `FormCloseButton` (needs a dismiss callback from Select — either `closeButton` as render prop `(dismiss) => ReactNode` **or** Select clones/passes dismiss via slot convention)
|
|
131
|
-
|
|
132
|
-
### Close slot + dismiss
|
|
133
|
-
|
|
134
|
-
Prefer **render prop** so the app can wire glass Cancel correctly:
|
|
135
|
-
|
|
136
|
-
```ts
|
|
137
|
-
closeButton?: ReactNode | ((dismiss: () => void) => ReactNode);
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
If `ReactNode` only, the default Cancel works but glass Cancel cannot call dismiss unless Select exposes an imperative API. **Decision: support function form** `(dismiss) => ReactNode`, and also accept a static `ReactNode` for simple cases (static node cannot dismiss unless it uses an internal context — for static nodes, wrap with Pressable only in default Cancel).
|
|
141
|
-
|
|
142
|
-
Ribe usage:
|
|
143
|
-
|
|
144
|
-
```tsx
|
|
145
|
-
closeButton={(dismiss) => <FormCloseButton onPress={dismiss} />}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
3. Keep Name / Notes as Field; form submit still gated on name (and optionally require type — keep current “type empty → error” UX).
|
|
127
|
+
- Trigger: `accessibilityRole="button"`, label includes field label + current display, hint that it opens options
|
|
128
|
+
- Option rows: `accessibilityRole="button"`, `accessibilityState.selected`
|
|
129
|
+
- Close: `accessibilityLabel="Close"`
|
|
149
130
|
|
|
150
131
|
## Out of scope
|
|
151
132
|
|
|
152
|
-
-
|
|
153
|
-
-
|
|
154
|
-
- Migrating Optimum
|
|
155
|
-
-
|
|
156
|
-
- Liquid glass Cancel inside the package
|
|
157
|
-
- New `select*` theme roles
|
|
158
|
-
|
|
159
|
-
## Success criteria
|
|
160
|
-
|
|
161
|
-
- Package exports `Select` with usage docs and TrueSheet peer documented
|
|
162
|
-
- Sheet: grabber, fade backdrop, detents ¼ / ½ / ¾, open at ½, scrollable options, select-to-dismiss
|
|
163
|
-
- Ribe create-activity Type uses Select + glass close
|
|
164
|
-
- `npm test` / `npm run build` (package) and Ribe `pnpm typecheck` pass
|
|
133
|
+
- Multi-select, search, icons, section headers
|
|
134
|
+
- TrueSheet / RN Modal sheet implementations
|
|
135
|
+
- Migrating Optimum CustomPicker
|
|
136
|
+
- Publishing / EAS workflow changes beyond peers + Ribe wire
|