forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request facebook#37 from BuckleTypes/sectionlist
SectionList API
- Loading branch information
Showing
3 changed files
with
269 additions
and
231 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,151 +1,178 @@ | ||
external view : ReasonReact.reactClass = "SectionList" [@@bs.module "react-native"]; | ||
|
||
module CreateComponent (Item: {type item;}) => { | ||
type renderBag = { | ||
item: Item.item, | ||
index: int, | ||
section, | ||
separators: Js.t {. highlight : unit => unit, unhighlight : unit => unit} | ||
type jsSection 'item = | ||
Js.t { | ||
. | ||
data : array 'item, | ||
key : Js.Undefined.t string, | ||
renderItem : Js.Undefined.t (jsRenderBag 'item => ReasonReact.reactElement) | ||
} | ||
and section = { | ||
data: array Item.item, | ||
key: option string, | ||
renderItem: option (renderBag => ReasonReact.reactElement) | ||
and jsRenderBag 'item = | ||
Js.t { | ||
. | ||
item : 'item, | ||
index : int, | ||
section : jsSection 'item, | ||
separators : Js.t {. highlight : unit => unit, unhighlight : unit => unit} | ||
}; | ||
type viewToken = | ||
Js.t { | ||
. | ||
item : Item.item, | ||
key : string, | ||
index : Js.undefined int, | ||
isViewable : Js.boolean, | ||
section : section | ||
}; | ||
type separatorProps = { | ||
highlighted: bool, | ||
leadingItem: option Item.item, | ||
leadingSection: option section, | ||
section, | ||
trailingItem: option Item.item, | ||
trailingSection: option section | ||
}; | ||
let createRenderBag ::item ::index ::section ::separators => {item, index, section, separators}; | ||
let createSeparatorProps | ||
::highlighted | ||
::leadingItem | ||
::leadingSection | ||
::section | ||
::trailingItem | ||
::trailingSection => { | ||
highlighted, | ||
leadingItem, | ||
leadingSection, | ||
section, | ||
trailingItem, | ||
trailingSection | ||
|
||
type jsSeparatorProps 'item = | ||
Js.t { | ||
. | ||
highlighted : Js.boolean, | ||
leadingItem : Js.Undefined.t 'item, | ||
leadingSection : Js.Undefined.t (jsSection 'item), | ||
section : jsSection 'item, | ||
trailingItem : Js.Undefined.t 'item, | ||
trailingSection : Js.Undefined.t (jsSection 'item) | ||
}; | ||
module SectionList = { | ||
let renderItemFromJS renderItem jsItems => | ||
renderItem ( | ||
createRenderBag | ||
item::jsItems##item | ||
index::jsItems##index | ||
section::jsItems##section | ||
separators::jsItems##separators | ||
); | ||
let section ::data ::key=? ::renderItem=? () => {data, key, renderItem}; | ||
let make: | ||
sections::array section => | ||
renderItem::(renderBag => ReasonReact.reactElement) => | ||
keyExtractor::(Item.item => int => string) => | ||
itemSeparatorComponent::(separatorProps => ReasonReact.reactElement)? => | ||
listEmptyComponent::(unit => ReasonReact.reactElement)? => | ||
listFooterComponent::ReasonReact.reactElement? => | ||
listHeaderComponent::ReasonReact.reactElement? => | ||
sectionSeparatorComponent::(separatorProps => ReasonReact.reactElement)? => | ||
extraData::'extraData? => | ||
initialNumToRender::int? => | ||
onEndReached::Js.t {. distanceFromEnd : float}? => | ||
onEndReachedThreshold::float? => | ||
onViewableItemsChanged::Js.t {. viewableItems : array viewToken, changed : array viewToken}? => | ||
onRefresh::(unit => unit)? => | ||
refreshing::bool? => | ||
renderSectionHeader::(Js.t {. section : section} => ReasonReact.reactElement)? => | ||
renderSectionFooter::(Js.t {. section : section} => ReasonReact.reactElement)? => | ||
stickySectionHeadersEnabled::bool? => | ||
array ReasonReact.reactElement => | ||
ReasonReact.component ReasonReact.stateless = | ||
fun ::sections | ||
::renderItem | ||
::keyExtractor | ||
::itemSeparatorComponent=? | ||
::listEmptyComponent=? | ||
::listFooterComponent=? | ||
::listHeaderComponent=? | ||
::sectionSeparatorComponent=? | ||
::extraData=? | ||
::initialNumToRender=? | ||
::onEndReached=? | ||
::onEndReachedThreshold=? | ||
::onViewableItemsChanged=? | ||
::onRefresh=? | ||
::refreshing=? | ||
::renderSectionHeader=? | ||
::renderSectionFooter=? | ||
::stickySectionHeadersEnabled=? => | ||
ReasonReact.wrapJsForReason | ||
reactClass::view | ||
props:: | ||
Js.Undefined.( | ||
{ | ||
"sections": | ||
Array.map | ||
( | ||
fun {data, key, renderItem} => { | ||
"data": data, | ||
"key": from_opt key, | ||
"renderItem": from_opt (UtilsRN.option_map renderItemFromJS renderItem) | ||
} | ||
) | ||
sections, | ||
"renderItem": renderItemFromJS renderItem, | ||
"keyExtractor": keyExtractor, | ||
"ItemSeparatorComponent": | ||
from_opt ( | ||
UtilsRN.option_map | ||
( | ||
fun itemSeparatorComponent => { | ||
let comp jsItems => | ||
itemSeparatorComponent ( | ||
createSeparatorProps | ||
highlighted::(Js.to_bool jsItems##highlighted) | ||
leadingItem::jsItems##leadingItem | ||
leadingSection::jsItems##leadingSection | ||
section::jsItems##section | ||
trailingItem::jsItems##trailingItem | ||
trailingSection::jsItems##trailingSection | ||
); | ||
comp | ||
} | ||
) | ||
itemSeparatorComponent | ||
), | ||
"ListEmptyComponent": from_opt listEmptyComponent, | ||
"ListFooterComponent": from_opt listFooterComponent, | ||
"ListHeaderComponent": from_opt listHeaderComponent, | ||
"SectionSeparatorComponent": from_opt sectionSeparatorComponent, | ||
"extraData": from_opt extraData, | ||
"initialNumToRender": from_opt initialNumToRender, | ||
"onEndReached": from_opt onEndReached, | ||
"onEndReachedThreshold": from_opt onEndReachedThreshold, | ||
"onRefresh": from_opt onRefresh, | ||
"onViewableItemsChanged": from_opt onViewableItemsChanged, | ||
"refreshing": from_opt (UtilsRN.optBoolToOptJsBoolean refreshing), | ||
"renderSectionHeader": from_opt renderSectionHeader, | ||
"renderSectionFooter": from_opt renderSectionFooter, | ||
"stickySectionHeadersEnabled": | ||
from_opt (UtilsRN.optBoolToOptJsBoolean stickySectionHeadersEnabled) | ||
} | ||
); | ||
|
||
type renderBag 'item = { | ||
item: 'item, | ||
index: int, | ||
section: section 'item, | ||
separators: Js.t {. highlight : unit => unit, unhighlight : unit => unit} | ||
} | ||
and section 'item = { | ||
data: array 'item, | ||
key: option string, | ||
renderItem: option (renderBag 'item => ReasonReact.reactElement) | ||
}; | ||
|
||
type separatorProps 'item = { | ||
highlighted: bool, | ||
leadingItem: option 'item, | ||
leadingSection: option (section 'item), | ||
section: section 'item, | ||
trailingItem: option 'item, | ||
trailingSection: option (section 'item) | ||
}; | ||
|
||
type renderItem 'item = jsRenderBag 'item => ReasonReact.reactElement; | ||
|
||
let jsSectionToSection jsSection => { | ||
data: jsSection##data, | ||
key: Js.Undefined.to_opt jsSection##key, | ||
/** We set renderItem to None to avoid an infinite conversion loop */ | ||
renderItem: None | ||
}; | ||
|
||
type sections 'item = array (jsSection 'item); | ||
|
||
let renderItem (reRenderItem: renderBag 'item => ReasonReact.reactElement) :renderItem 'item => | ||
fun (jsRenderBag: jsRenderBag 'item) => | ||
reRenderItem { | ||
item: jsRenderBag##item, | ||
index: jsRenderBag##index, | ||
section: jsSectionToSection jsRenderBag##section, | ||
separators: jsRenderBag##separators | ||
}; | ||
|
||
let section ::data ::key=? ::renderItem=? () => {data, key, renderItem}; | ||
|
||
let sections reSections :sections 'item => | ||
Array.map | ||
( | ||
fun reSection => { | ||
"data": reSection.data, | ||
"key": Js.Undefined.from_opt reSection.key, | ||
"renderItem": Js.Undefined.from_opt (UtilsRN.option_map renderItem reSection.renderItem) | ||
} | ||
) | ||
reSections; | ||
|
||
type separatorComponent 'item = jsSeparatorProps 'item => ReasonReact.reactElement; | ||
|
||
let separatorComponent | ||
(reSeparatorComponent: separatorProps 'item => ReasonReact.reactElement) | ||
:separatorComponent 'item => | ||
fun (jsSeparatorProps: jsSeparatorProps 'item) => | ||
reSeparatorComponent { | ||
highlighted: Js.to_bool jsSeparatorProps##highlighted, | ||
leadingItem: Js.Undefined.to_opt jsSeparatorProps##leadingItem, | ||
leadingSection: | ||
Js.Undefined.to_opt jsSeparatorProps##leadingSection |> | ||
UtilsRN.option_map jsSectionToSection, | ||
section: jsSectionToSection jsSeparatorProps##section, | ||
trailingItem: Js.Undefined.to_opt jsSeparatorProps##trailingItem, | ||
trailingSection: | ||
Js.Undefined.to_opt jsSeparatorProps##trailingSection |> | ||
UtilsRN.option_map jsSectionToSection | ||
}; | ||
|
||
type viewToken 'item = | ||
Js.t { | ||
. | ||
item : 'item, | ||
key : string, | ||
index : Js.undefined int, | ||
isViewable : Js.boolean, | ||
section : section 'item | ||
}; | ||
}; | ||
|
||
let make: | ||
sections::sections 'item => | ||
renderItem::renderItem 'item => | ||
keyExtractor::('item => int => string) => | ||
itemSeparatorComponent::separatorComponent 'item? => | ||
listEmptyComponent::(unit => ReasonReact.reactElement)? => | ||
listFooterComponent::ReasonReact.reactElement? => | ||
listHeaderComponent::ReasonReact.reactElement? => | ||
sectionSeparatorComponent::separatorComponent 'item? => | ||
extraData::'extraData? => | ||
initialNumToRender::int? => | ||
onEndReached::Js.t {. distanceFromEnd : float}? => | ||
onEndReachedThreshold::float? => | ||
onViewableItemsChanged:: | ||
Js.t {. viewableItems : array (viewToken 'item), changed : array (viewToken 'item)}? => | ||
onRefresh::(unit => unit)? => | ||
refreshing::bool? => | ||
renderSectionHeader::(Js.t {. section : section 'item} => ReasonReact.reactElement)? => | ||
renderSectionFooter::(Js.t {. section : section 'item} => ReasonReact.reactElement)? => | ||
stickySectionHeadersEnabled::bool? => | ||
array ReasonReact.reactElement => | ||
ReasonReact.component ReasonReact.stateless = | ||
fun ::sections | ||
::renderItem | ||
::keyExtractor | ||
::itemSeparatorComponent=? | ||
::listEmptyComponent=? | ||
::listFooterComponent=? | ||
::listHeaderComponent=? | ||
::sectionSeparatorComponent=? | ||
::extraData=? | ||
::initialNumToRender=? | ||
::onEndReached=? | ||
::onEndReachedThreshold=? | ||
::onViewableItemsChanged=? | ||
::onRefresh=? | ||
::refreshing=? | ||
::renderSectionHeader=? | ||
::renderSectionFooter=? | ||
::stickySectionHeadersEnabled=? => | ||
ReasonReact.wrapJsForReason | ||
reactClass::view | ||
props:: | ||
Js.Undefined.( | ||
{ | ||
"sections": sections, | ||
"renderItem": renderItem, | ||
"keyExtractor": keyExtractor, | ||
"ItemSeparatorComponent": from_opt itemSeparatorComponent, | ||
"ListEmptyComponent": from_opt listEmptyComponent, | ||
"ListFooterComponent": from_opt listFooterComponent, | ||
"ListHeaderComponent": from_opt listHeaderComponent, | ||
"SectionSeparatorComponent": from_opt sectionSeparatorComponent, | ||
"extraData": from_opt extraData, | ||
"initialNumToRender": from_opt initialNumToRender, | ||
"onEndReached": from_opt onEndReached, | ||
"onEndReachedThreshold": from_opt onEndReachedThreshold, | ||
"onRefresh": from_opt onRefresh, | ||
"onViewableItemsChanged": from_opt onViewableItemsChanged, | ||
"refreshing": from_opt (UtilsRN.optBoolToOptJsBoolean refreshing), | ||
"renderSectionHeader": from_opt renderSectionHeader, | ||
"renderSectionFooter": from_opt renderSectionFooter, | ||
"stickySectionHeadersEnabled": | ||
from_opt (UtilsRN.optBoolToOptJsBoolean stickySectionHeadersEnabled) | ||
} | ||
); |
Oops, something went wrong.