mirror of
https://github.com/hariroshan/elm-native-library.git
synced 2025-01-06 03:54:33 +03:00
added listview
This commit is contained in:
parent
4caa8fa78d
commit
87b77c2ae0
@ -9,6 +9,7 @@ module Native exposing
|
||||
, image
|
||||
, label
|
||||
, listPicker
|
||||
, listView
|
||||
, navigationButton
|
||||
, progress
|
||||
, scrollView
|
||||
@ -151,3 +152,8 @@ actionItem =
|
||||
navigationButton : List (Attribute msg) -> List (Html msg) -> Html msg
|
||||
navigationButton =
|
||||
buildElement "ns-navigation-button"
|
||||
|
||||
|
||||
listView : List (Attribute msg) -> List (Html msg) -> Html msg
|
||||
listView =
|
||||
buildElement "ns-list-view"
|
||||
|
@ -1128,3 +1128,18 @@ iosSystemIcon =
|
||||
androidSystemIcon : String -> Attribute msg
|
||||
androidSystemIcon =
|
||||
attribute "android.system-icon"
|
||||
|
||||
|
||||
iosEstimatedRowHeight : String -> Attribute msg
|
||||
iosEstimatedRowHeight =
|
||||
attribute "ios-estimated-row-height"
|
||||
|
||||
|
||||
rowHeight : String -> Attribute msg
|
||||
rowHeight =
|
||||
attribute "row-height"
|
||||
|
||||
|
||||
separatorColor : String -> Attribute msg
|
||||
separatorColor =
|
||||
attribute "separator-color"
|
||||
|
@ -372,18 +372,14 @@ let actionItem =
|
||||
),
|
||||
]->Belt.Array.concatMany
|
||||
|
||||
let listView =
|
||||
[
|
||||
view,
|
||||
["iosEstimatedRowHeight", "rowHeight", "separatorColor"]->Belt.Array.map(dashed),
|
||||
]->Belt.Array.concatMany
|
||||
|
||||
// Js.log("****************************")
|
||||
// [
|
||||
// "hour",
|
||||
// "iosPreferredDatePickerStyle",
|
||||
// "maxHour",
|
||||
// "maxMinute",
|
||||
// "minHour",
|
||||
// "minMinute",
|
||||
// "minute",
|
||||
// "minuteInterval",
|
||||
// "time",
|
||||
// ]
|
||||
// ["iosEstimatedRowHeight", "rowHeight", "separatorColor"]
|
||||
// ->Belt.Array.map(dashed)
|
||||
// ->Belt.Array.forEach(prop =>
|
||||
// Js.log(
|
||||
|
@ -140,13 +140,12 @@ module ListPicker = {
|
||||
%%private(
|
||||
@module("@nativescript/core") @new
|
||||
external new: unit => Types.nativeObject = "ListPicker"
|
||||
let setItems = (current: Types.htmlElement, data) => {
|
||||
data->Types.setItems(current.items)
|
||||
}
|
||||
)
|
||||
let setItems = (current: Types.htmlElement, data) => {
|
||||
data->Types.setItems(current.items)
|
||||
}
|
||||
let tagName = "ns-list-picker"
|
||||
|
||||
/* TODO: Listen for changes in items property */
|
||||
let handler: Types.handler = {
|
||||
init: (. ()) => new(),
|
||||
observedAttributes: Constants.listPicker,
|
||||
@ -301,6 +300,28 @@ module WebView = {
|
||||
|
||||
let handler: Types.handler = buildHandler(new, Constants.webView, Helper.addView)
|
||||
}
|
||||
module ListView = {
|
||||
%%private(
|
||||
@module("@nativescript/core") @new
|
||||
external new: unit => Types.nativeObject = "ListView"
|
||||
)
|
||||
let tagName = "ns-list-view"
|
||||
|
||||
let handler: Types.handler = {
|
||||
init: (. ()) => new(),
|
||||
observedAttributes: Constants.listView,
|
||||
render: Js.Nullable.return((. current: Types.htmlElement, _) => {
|
||||
current.data->Js.Nullable.toOption->Belt.Option.forEach(ListPicker.setItems(current))
|
||||
Types.definePropertyInHtml(. current, "items", {set: ListPicker.setItems(current)})
|
||||
Helper.addView(. current.parentElement, current)
|
||||
}),
|
||||
handlerKind: Types.Element,
|
||||
update: NativescriptCore.update,
|
||||
dispose: NativescriptCore.dispose,
|
||||
addEventListener: NativescriptCore.addEventListener,
|
||||
removeEventListener: NativescriptCore.removeEventListener,
|
||||
}
|
||||
}
|
||||
|
||||
let all: array<Types.customElement> = [
|
||||
{
|
||||
@ -403,4 +424,8 @@ let all: array<Types.customElement> = [
|
||||
tagName: NavigationButton.tagName,
|
||||
handler: NavigationButton.handler,
|
||||
},
|
||||
{
|
||||
tagName: ListView.tagName,
|
||||
handler: ListView.handler,
|
||||
},
|
||||
]
|
||||
|
@ -13,8 +13,11 @@ let rec assignDeep: (Obj.t, array<string>, int, 'a) => unit = (object, keys, i,
|
||||
})
|
||||
}
|
||||
|
||||
let setAttribute: (Obj.t, string, 'a) => unit = (object, key, value) => {
|
||||
if !(key->Js.String2.includes(".")) {
|
||||
let setAttribute: (Obj.t, string, string) => unit = (object, key, value) => {
|
||||
if value->Js.String2.startsWith("{{") {
|
||||
let expression = value->String.sub(2, value->String.length - 4)
|
||||
object->Types.bindExpression({expression, targetProperty: key})
|
||||
} else if !(key->Js.String2.includes(".")) {
|
||||
Js.Dict.set(Obj.magic(object), key, value)
|
||||
} else {
|
||||
let keys = key->Js.String2.split(".")
|
||||
@ -22,12 +25,6 @@ let setAttribute: (Obj.t, string, 'a) => unit = (object, key, value) => {
|
||||
}
|
||||
}
|
||||
|
||||
let init = (object, props) => {
|
||||
Js.Dict.keys(Obj.magic(props))->Belt.Array.forEach(key =>
|
||||
setAttribute(object, key, Js.Dict.unsafeGet(props, key))
|
||||
)
|
||||
}
|
||||
|
||||
let update = setAttribute
|
||||
|
||||
external typeOf: 'a => string = "typeof"
|
||||
@ -35,7 +32,7 @@ external typeOf: 'a => string = "typeof"
|
||||
let addView: (. Types.htmlElement, Types.htmlElement) => unit = %raw(`
|
||||
function(parentElement, thisElement) {
|
||||
if (parentElement.data == null) return
|
||||
requestAnimationFrame(() => {
|
||||
// requestAnimationFrame(() => {
|
||||
const children = Array.from(parentElement.children)
|
||||
const hasActionBar = children.some(x => x.tagName.toLowerCase() === "ns-action-bar")
|
||||
const index = children.indexOf(thisElement)
|
||||
@ -50,69 +47,80 @@ let addView: (. Types.htmlElement, Types.htmlElement) => unit = %raw(`
|
||||
if (parentElement.data.constructor.name == "ActionBar")
|
||||
return (parentElement.data.titleView = thisElement.data)
|
||||
|
||||
if (parentElement.data.constructor.name == "ListView") {
|
||||
parentElement.data.itemTemplate =
|
||||
function() {
|
||||
const div = document.createElement("div")
|
||||
const cloned = thisElement.cloneAll()
|
||||
div.appendChild(cloned)
|
||||
cloned.manualRender()
|
||||
return cloned.data;
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
return (parentElement.data.content = thisElement.data)
|
||||
})
|
||||
// })
|
||||
}
|
||||
`)
|
||||
|
||||
let addFormattedText: (. Types.htmlElement, Types.htmlElement) => unit = %raw(`
|
||||
function(parentElement, thisElement) {
|
||||
if (parentElement.data == null) return
|
||||
requestAnimationFrame(() => {
|
||||
// requestAnimationFrame(() => {
|
||||
const children = Array.from(parentElement.children)
|
||||
const index = children.indexOf(thisElement)
|
||||
parentElement.data.formattedText = thisElement.data
|
||||
})
|
||||
// })
|
||||
}
|
||||
`)
|
||||
|
||||
let addSpan: (. Types.htmlElement, Types.htmlElement) => unit = %raw(`
|
||||
function(parentElement, thisElement) {
|
||||
if (parentElement.data == null) return
|
||||
requestAnimationFrame(() => {
|
||||
// requestAnimationFrame(() => {
|
||||
const children = Array.from(parentElement.children)
|
||||
const index = children.indexOf(thisElement)
|
||||
parentElement.data.spans.push(thisElement.data)
|
||||
})
|
||||
// })
|
||||
}
|
||||
`)
|
||||
|
||||
let addActionBar: (. Types.htmlElement, Types.htmlElement) => unit = %raw(`
|
||||
function(parentElement, thisElement) {
|
||||
if (parentElement.data == null) return
|
||||
requestAnimationFrame(() => {
|
||||
// requestAnimationFrame(() => {
|
||||
parentElement.data.actionBar = thisElement.data
|
||||
})
|
||||
// })
|
||||
}
|
||||
`)
|
||||
|
||||
let addActionItem: (. Types.htmlElement, Types.htmlElement) => unit = %raw(`
|
||||
function(parentElement, thisElement) {
|
||||
if (parentElement.data == null) return
|
||||
requestAnimationFrame(() => {
|
||||
// requestAnimationFrame(() => {
|
||||
parentElement.data.actionItems.addItem(thisElement.data)
|
||||
})
|
||||
// })
|
||||
}
|
||||
`)
|
||||
|
||||
let addNavigationButton: (. Types.htmlElement, Types.htmlElement) => unit = %raw(`
|
||||
function(parentElement, thisElement) {
|
||||
if (parentElement.data == null) return
|
||||
requestAnimationFrame(() => {
|
||||
console.log(thisElement.data, parentElement.data.navigationButton)
|
||||
// requestAnimationFrame(() => {
|
||||
parentElement.data.navigationButton = thisElement.data
|
||||
})
|
||||
// })
|
||||
}
|
||||
`)
|
||||
|
||||
let addItems: (. Types.htmlElement, Types.htmlElement) => unit = %raw(`
|
||||
function(parentElement, thisElement) {
|
||||
if (parentElement.data == null) return
|
||||
requestAnimationFrame(() => {
|
||||
// requestAnimationFrame(() => {
|
||||
if (parentElement.data.items == null)
|
||||
return (parentElement.data.items = [thisElement.data])
|
||||
parentElement.data.items.push(thisElement.data)
|
||||
})
|
||||
// })
|
||||
}
|
||||
`)
|
||||
|
||||
|
@ -35,10 +35,6 @@ module Page = {
|
||||
%%private(
|
||||
@module("@nativescript/core") @new
|
||||
external new: unit => Types.nativeObject = "Page"
|
||||
let getData = (children, idx) =>
|
||||
children
|
||||
->Belt.Array.get(idx)
|
||||
->Belt.Option.flatMap((x: Types.htmlElement) => x.data->Js.Nullable.toOption)
|
||||
)
|
||||
|
||||
let tagName = "ns-page"
|
||||
@ -46,7 +42,7 @@ module Page = {
|
||||
init: (. ()) => new(),
|
||||
observedAttributes: Constants.pageBase,
|
||||
update: NativescriptCore.update,
|
||||
render: Js.Nullable.return((. current: Types.htmlElement, nativeObject) => {
|
||||
render: Js.Nullable.return((. current: Types.htmlElement, _) => {
|
||||
Types.requestAnimationFrame(._ => {
|
||||
current.parentElement.handler
|
||||
->Js.Nullable.toOption
|
||||
|
@ -1,12 +1,13 @@
|
||||
type event
|
||||
type constructorRec = {name: string}
|
||||
type bindingOptions = {expression: string, targetProperty: string}
|
||||
|
||||
type rec nativeObject = {
|
||||
on: (. event, event => unit) => unit,
|
||||
off: (. event, event => unit) => unit,
|
||||
destroyNode: (. unit) => unit,
|
||||
insertChild: Js.Nullable.t<(. nativeObject, int) => unit>,
|
||||
constructor: constructorRec,
|
||||
constructor: constructorRec
|
||||
}
|
||||
|
||||
type constructor = {
|
||||
@ -30,6 +31,9 @@ type navigationConfig = {create: unit => nativeObject}
|
||||
@send
|
||||
external navigate: (nativeObject, navigationConfig) => unit = "navigate"
|
||||
|
||||
@send
|
||||
external bindExpression: (Obj.t, bindingOptions) => unit = "bind"
|
||||
|
||||
type rec handler = {
|
||||
init: (. unit) => nativeObject,
|
||||
observedAttributes: array<string>,
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
export const withCustomElements = (UIElement, handler) =>
|
||||
class extends UIElement {
|
||||
constructor() {
|
||||
@ -19,7 +18,6 @@ export const withCustomElements = (UIElement, handler) =>
|
||||
this.handler.render(this, this.data)
|
||||
}
|
||||
console.log(`${this.tagName} connected`)
|
||||
|
||||
}
|
||||
disconnectedCallback() {
|
||||
this.handler.dispose(this.data)
|
||||
@ -33,4 +31,23 @@ export const withCustomElements = (UIElement, handler) =>
|
||||
super.removeEventListener(event, callback);
|
||||
this.handler.removeEventListener(this.data, event, callback);
|
||||
}
|
||||
cloneAll() {
|
||||
const tag = document.createElement(this.tagName)
|
||||
const children =
|
||||
Array.from(this.children).forEach(child => tag.appendChild(child.cloneAll()))
|
||||
|
||||
Object.keys(this.attributes).forEach(key => {
|
||||
const attr = this.attributes[key]
|
||||
if (attr && attr.name !== undefined && attr.value !== undefined) {
|
||||
tag.setAttribute(attr.name, attr.value)
|
||||
}
|
||||
})
|
||||
return tag
|
||||
}
|
||||
manualRender() {
|
||||
Array.from(this.children).forEach(child =>
|
||||
child.manualRender()
|
||||
)
|
||||
this.handler.render(this, this.data)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
"scripts": {
|
||||
"res:build": "rescript",
|
||||
"res:dev": "rescript build -w",
|
||||
"build:elm": "elm make src/Main.elm --output ./dist/elm.js",
|
||||
"run:ios": "ns run ios",
|
||||
"build:webpack": "webpack --mode development"
|
||||
},
|
||||
|
27
src/Main.elm
27
src/Main.elm
@ -223,18 +223,23 @@ detailsPage model =
|
||||
Page.pageWithActionBar []
|
||||
-- Event.on "navigatedTo" (D.succeed Destory)
|
||||
-- [ Native.actionBar []
|
||||
[ Native.actionBar [ NA.flat "true", NA.title "Home" ]
|
||||
[]
|
||||
, Layout.asElement <|
|
||||
Layout.rootLayout []
|
||||
[ Native.label
|
||||
[ NA.text "Elm Counter"
|
||||
, NA.textAlignment "center"
|
||||
, NA.color "#610fc8"
|
||||
, NA.fontSize "40"
|
||||
[ Native.listView
|
||||
[ E.list E.string
|
||||
[ "2022", "2021", "2020" ]
|
||||
|> NA.items
|
||||
, NA.separatorColor "orange"
|
||||
, NA.class "list-group"
|
||||
]
|
||||
[ Layout.asElement <|
|
||||
Layout.stackLayout [ NA.class "list-group-item" ]
|
||||
[ Native.label [ NA.text "{{ $value }}", NA.color "green" ] []
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
|
||||
-- Native.actionBar [ NA.flat "true", NA.title "Home" ]
|
||||
-- []
|
||||
-- , Layout.asElement <|
|
||||
--
|
||||
]
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user