Add text input and tooltip components
Add tooltip component Add text input component rename Signed-off-by: Gheorghe Pinzaru <feross95@gmail.com>
@ -1,8 +1,9 @@
|
||||
{:lint-as {status-im.utils.views/defview clojure.core/defn
|
||||
status-im.utils.views/letsubs clojure.core/let
|
||||
status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
|
||||
status-im.utils.styles/def clojure.core/def
|
||||
status-im.utils.styles/defn clojure.core/defn}
|
||||
{:lint-as {status-im.utils.views/defview clojure.core/defn
|
||||
status-im.utils.views/letsubs clojure.core/let
|
||||
status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
|
||||
quo.previews.preview/list-comp clojure.core/for
|
||||
status-im.utils.styles/def clojure.core/def
|
||||
status-im.utils.styles/defn clojure.core/defn}
|
||||
:linters {:invalid-arity {:skip-args [status-im.utils.fx/defn]}
|
||||
;;TODO remove number when this is fixed
|
||||
;;https://github.com/borkdude/clj-kondo/issues/867
|
||||
|
BIN
android/app/src/main/res/drawable-mdpi/hide.png
Normal file
After Width: | Height: | Size: 352 B |
BIN
android/app/src/main/res/drawable-mdpi/show.png
Normal file
After Width: | Height: | Size: 326 B |
BIN
android/app/src/main/res/drawable-mdpi/tooltip_tip.png
Normal file
After Width: | Height: | Size: 184 B |
BIN
android/app/src/main/res/drawable-xhdpi/hide.png
Normal file
After Width: | Height: | Size: 616 B |
BIN
android/app/src/main/res/drawable-xhdpi/show.png
Normal file
After Width: | Height: | Size: 586 B |
BIN
android/app/src/main/res/drawable-xhdpi/tooltip_tip.png
Normal file
After Width: | Height: | Size: 245 B |
BIN
android/app/src/main/res/drawable-xxhdpi/hide.png
Normal file
After Width: | Height: | Size: 913 B |
BIN
android/app/src/main/res/drawable-xxhdpi/show.png
Normal file
After Width: | Height: | Size: 840 B |
BIN
android/app/src/main/res/drawable-xxhdpi/tooltip_tip.png
Normal file
After Width: | Height: | Size: 364 B |
@ -14,6 +14,7 @@
|
||||
25DC9C9DC25846BD8D084888 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A886A2CB448B1ABA0EB62 /* libc++.tbd */; };
|
||||
3870E1E692E24133A80B07DE /* Inter-SemiBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 693A62DB37BC4CD5A30E5C96 /* Inter-SemiBold.otf */; };
|
||||
393D26E3080B443A998F4A2F /* Inter-Italic.otf in Resources */ = {isa = PBXBuildFile; fileRef = B07176ACDAA1422E8F0A3D6B /* Inter-Italic.otf */; };
|
||||
3ABC7AF8245FF85900612C45 /* InterStatus-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9C76AF5A418D4D65A4CAD1D9 /* InterStatus-Regular.otf */; };
|
||||
57C854A7993C47A3B1AECD32 /* Inter-MediumItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = C6B1215047604CD59A4C74D6 /* Inter-MediumItalic.otf */; };
|
||||
70ADBB5ECF934DCF8A0E4919 /* Inter-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 1426DF592BA248FC81D955CB /* Inter-Regular.otf */; };
|
||||
74B758FC20D7C00B003343C3 /* launch-image-universal.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74B758FB20D7C00B003343C3 /* launch-image-universal.storyboard */; };
|
||||
@ -90,7 +91,6 @@
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = StatusIm/main.m; sourceTree = "<group>"; };
|
||||
1426DF592BA248FC81D955CB /* Inter-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Regular.otf"; path = "../resources/fonts/Inter-Regular.otf"; sourceTree = "<group>"; };
|
||||
38A44830EC5708E89387F641 /* Pods-StatusIm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StatusIm.release.xcconfig"; path = "Pods/Target Support Files/Pods-StatusIm/Pods-StatusIm.release.xcconfig"; sourceTree = "<group>"; };
|
||||
3A0B103024581B74004B0F23 /* InterStatus-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "InterStatus-Regular.otf"; path = "../resources/fonts/InterStatus-Regular.otf"; sourceTree = "<group>"; };
|
||||
439B6B4B407A4E2AACAFE5BE /* RCTStatus.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTStatus.xcodeproj; path = "../modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj"; sourceTree = "<group>"; };
|
||||
4C16DE0B1F89508700AA10DB /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
4E586E1B0E544F64AA9F5BD1 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
@ -98,6 +98,7 @@
|
||||
74B758FB20D7C00B003343C3 /* launch-image-universal.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "launch-image-universal.storyboard"; sourceTree = "<group>"; };
|
||||
8B9A886A2CB448B1ABA0EB62 /* libc++.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||
922C4CA61F4D5F8B0033C753 /* StatusIm.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = StatusIm.entitlements; path = StatusIm/StatusIm.entitlements; sourceTree = "<group>"; };
|
||||
9C76AF5A418D4D65A4CAD1D9 /* InterStatus-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "InterStatus-Regular.otf"; path = "../resources/fonts/InterStatus-Regular.otf"; sourceTree = "<group>"; };
|
||||
9EC0135C1E06FB1900155B5C /* RCTWKWebView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWKWebView.xcodeproj; path = "../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView.xcodeproj"; sourceTree = "<group>"; };
|
||||
9EF083381F3B538A00876A8F /* ReactNativeConfig.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeConfig.xcodeproj; path = "../node_modules/react-native-config/ios/ReactNativeConfig.xcodeproj"; sourceTree = "<group>"; };
|
||||
A4F2BBE8D4DD4140A6CCAC39 /* Inter-SemiBoldItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-SemiBoldItalic.otf"; path = "../resources/fonts/Inter-SemiBoldItalic.otf"; sourceTree = "<group>"; };
|
||||
@ -181,12 +182,12 @@
|
||||
CD4A2C27D6D5473184DC1F7E /* Inter-Bold.otf */,
|
||||
B321D25F4493470980039457 /* Inter-BoldItalic.otf */,
|
||||
B07176ACDAA1422E8F0A3D6B /* Inter-Italic.otf */,
|
||||
3A0B103024581B74004B0F23 /* InterStatus-Regular.otf */,
|
||||
B2A38FC3D3954DE7B2B171F8 /* Inter-Medium.otf */,
|
||||
C6B1215047604CD59A4C74D6 /* Inter-MediumItalic.otf */,
|
||||
1426DF592BA248FC81D955CB /* Inter-Regular.otf */,
|
||||
693A62DB37BC4CD5A30E5C96 /* Inter-SemiBold.otf */,
|
||||
A4F2BBE8D4DD4140A6CCAC39 /* Inter-SemiBoldItalic.otf */,
|
||||
9C76AF5A418D4D65A4CAD1D9 /* InterStatus-Regular.otf */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
@ -429,6 +430,7 @@
|
||||
B2F2D1BC1D9D531B00B7B453 /* Images.xcassets in Resources */,
|
||||
D84616FB563A48EBB1678699 /* Inter-Bold.otf in Resources */,
|
||||
D99C50E5E18942A39C8DDF61 /* Inter-BoldItalic.otf in Resources */,
|
||||
3ABC7AF8245FF85900612C45 /* InterStatus-Regular.otf in Resources */,
|
||||
393D26E3080B443A998F4A2F /* Inter-Italic.otf in Resources */,
|
||||
D1786306E0184916B11F4C37 /* Inter-Medium.otf in Resources */,
|
||||
57C854A7993C47A3B1AECD32 /* Inter-MediumItalic.otf in Resources */,
|
||||
|
23
ios/StatusIm/Images.xcassets/hide.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Hide.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Hide@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Hide@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/hide.imageset/Hide.png
vendored
Normal file
After Width: | Height: | Size: 352 B |
BIN
ios/StatusIm/Images.xcassets/hide.imageset/Hide@2x.png
vendored
Normal file
After Width: | Height: | Size: 616 B |
BIN
ios/StatusIm/Images.xcassets/hide.imageset/Hide@3x.png
vendored
Normal file
After Width: | Height: | Size: 913 B |
23
ios/StatusIm/Images.xcassets/show.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Show.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Show@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Show@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/show.imageset/Show.png
vendored
Normal file
After Width: | Height: | Size: 326 B |
BIN
ios/StatusIm/Images.xcassets/show.imageset/Show@2x.png
vendored
Normal file
After Width: | Height: | Size: 586 B |
BIN
ios/StatusIm/Images.xcassets/show.imageset/Show@3x.png
vendored
Normal file
After Width: | Height: | Size: 840 B |
23
ios/StatusIm/Images.xcassets/tooltip-tip.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Tip.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Tip@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Tip@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
ios/StatusIm/Images.xcassets/tooltip-tip.imageset/Tip.png
vendored
Normal file
After Width: | Height: | Size: 184 B |
BIN
ios/StatusIm/Images.xcassets/tooltip-tip.imageset/Tip@2x.png
vendored
Normal file
After Width: | Height: | Size: 245 B |
BIN
ios/StatusIm/Images.xcassets/tooltip-tip.imageset/Tip@3x.png
vendored
Normal file
After Width: | Height: | Size: 364 B |
@ -103,6 +103,7 @@
|
||||
<string>Inter-SemiBoldItalic.otf</string>
|
||||
<string>Inter-Thin-BETA.otf</string>
|
||||
<string>Inter-ThinItalic-BETA.otf</string>
|
||||
<string>InterStatus-Regular.otf</string>
|
||||
</array>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
|
@ -28,9 +28,13 @@
|
||||
(def set (oget animated "set"))
|
||||
(def start-clock (oget animated "startClock"))
|
||||
(def stop-clock (oget animated "stopClock"))
|
||||
(def clock-running clockRunning)
|
||||
(def bezier (.-bezier ^js Easing))
|
||||
(def linear (.-linear ^js Easing))
|
||||
|
||||
(def easings {:ease-in (bezier 0.42 0 1 1)
|
||||
:ease-out (bezier 0 0 0.58 1)})
|
||||
|
||||
(defn set-value [anim val]
|
||||
(ocall anim "setValue" val))
|
||||
|
||||
@ -111,3 +115,9 @@
|
||||
|
||||
(defn on-scroll [opts]
|
||||
(ocall redash "onScrollEvent" (clj->js opts)))
|
||||
|
||||
(defn b-interpolate [anim-value a b]
|
||||
(ocall redash "bInterpolate" anim-value a b))
|
||||
|
||||
(defn loop* [opts]
|
||||
(ocall redash "loop" (clj->js opts)))
|
||||
|
@ -86,7 +86,7 @@
|
||||
(when accessibility-label
|
||||
{:accessibility-label accessibility-label}))
|
||||
(cond
|
||||
icon [icons/icon icon]
|
||||
icon [icons/icon icon {:color (:icon-01 @colors/theme)}]
|
||||
label [text/text {:color :link} label])]])
|
||||
|
||||
(defn header-actions [{:keys [accessories component]}]
|
||||
@ -102,12 +102,12 @@
|
||||
[rn/view {:style header-action-placeholder}])])
|
||||
|
||||
(defn header-title [{:keys [title subtitle component title-align]}]
|
||||
[react/fragment
|
||||
[:<>
|
||||
(cond
|
||||
component component
|
||||
|
||||
(and title subtitle)
|
||||
[react/fragment
|
||||
[:<>
|
||||
[text/text {:weight :medium
|
||||
:number-of-lines 1}
|
||||
title]
|
||||
|
@ -5,19 +5,16 @@
|
||||
[quo.react-native :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn text-style [{:keys [size align weight color style]
|
||||
:or {size :base
|
||||
weight :regular
|
||||
align :auto
|
||||
color :main}}]
|
||||
(merge (case weight
|
||||
(defn text-style [{:keys [size align weight color style]}]
|
||||
;; NOTE(Ferossgo): or in destructoring will keep nil as a value
|
||||
(merge (case (or weight :regular)
|
||||
:regular typography/font-regular
|
||||
:medium typography/font-medium
|
||||
:semi-bold typography/font-semi-bold
|
||||
:bold typography/font-bold
|
||||
:monospace typography/monospace
|
||||
:inherit nil)
|
||||
(case color
|
||||
(case (or color :main)
|
||||
:main {:color (:text-01 @colors/theme)}
|
||||
:secondary {:color (:text-02 @colors/theme)}
|
||||
:secondary-inverse {:color (:text-03 @colors/theme)}
|
||||
@ -25,7 +22,7 @@
|
||||
:positive {:color (:positive-01 @colors/theme)}
|
||||
:negative {:color (:negative-01 @colors/theme)}
|
||||
:inherit nil)
|
||||
(case size
|
||||
(case (or size :base)
|
||||
:tiny typography/tiny
|
||||
:small typography/small
|
||||
:base typography/base
|
||||
@ -33,7 +30,7 @@
|
||||
:x-large typography/x-large
|
||||
:xx-large typography/xx-large
|
||||
:inherit nil)
|
||||
{:text-align align}
|
||||
{:text-align (or align :auto)}
|
||||
style))
|
||||
|
||||
(defn text []
|
||||
|
204
src/quo/components/text_input.cljs
Normal file
@ -0,0 +1,204 @@
|
||||
(ns quo.components.text-input
|
||||
(:require [clojure.spec.alpha :as s]
|
||||
[reagent.core :as reagent]
|
||||
[oops.core :refer [ocall]]
|
||||
[quo.react-native :as rn]
|
||||
;; TODO(Ferossgp): Move icon component to lib
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
;; TODO(Ferossgp): Move tooltip into lib
|
||||
[quo.components.tooltip :as tooltip]
|
||||
[quo.react :as react]
|
||||
[quo.platform :as platform]
|
||||
[quo.design-system.typography :as typography]
|
||||
[quo.design-system.spacing :as spacing]
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.components.text :as text]))
|
||||
|
||||
(s/def ::multiline boolean?)
|
||||
(s/def ::secure-text-entry boolean?)
|
||||
(s/def ::show-cancel boolean?)
|
||||
(s/def ::label (s/nilable string?))
|
||||
(s/def ::cancel-label (s/nilable string?))
|
||||
(s/def ::default-value (s/nilable string?))
|
||||
(s/def ::placeholder (s/nilable string?))
|
||||
(s/def ::keyboard-type #{})
|
||||
(s/def ::accessibility-label (s/nilable (s/or :string string? :keyword keyword?)))
|
||||
(s/def ::on-focus fn?)
|
||||
(s/def ::on-blur fn?)
|
||||
(s/def ::on-press fn?)
|
||||
|
||||
(s/def ::accessory (s/keys :req-un [::icon]
|
||||
:opt-un [::on-press]))
|
||||
(s/def ::after (s/nilable ::accessory))
|
||||
(s/def ::before (s/nilable ::accessory))
|
||||
|
||||
(s/def ::style (s/nilable map?))
|
||||
(s/def ::input-style (s/nilable map?))
|
||||
|
||||
(s/def ::text-input (s/keys :opt-un
|
||||
[::label
|
||||
::multiline
|
||||
::error
|
||||
::style
|
||||
::input-style
|
||||
::keyboard-type
|
||||
::before
|
||||
::after
|
||||
::cancel-label
|
||||
::on-focus
|
||||
::on-blur
|
||||
::show-cancel
|
||||
::accessibility-label
|
||||
::bottom-value
|
||||
::secure-text-entry]))
|
||||
|
||||
(defn check-spec [spec prop]
|
||||
(if (s/valid? spec prop)
|
||||
true
|
||||
(do
|
||||
(s/explain spec prop)
|
||||
false)))
|
||||
|
||||
;; TODO(Ferossgp): Check performance for android layout animations
|
||||
(when (and platform/android?
|
||||
(aget rn/ui-manager "setLayoutAnimationEnabledExperimental"))
|
||||
(ocall rn/ui-manager "setLayoutAnimationEnabledExperimental" true))
|
||||
|
||||
(def height 44) ; 22 line-height + 11*2 vertical padding
|
||||
(def multiline-height 88) ; 3 * 22 three line-height + 11* vertical padding
|
||||
|
||||
(defn container-style [])
|
||||
|
||||
(defn label-style []
|
||||
{:margin-bottom (:tiny spacing/spacing)})
|
||||
|
||||
(defn text-input-row-style []
|
||||
{:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(defn text-input-view-style [style]
|
||||
(merge {:border-radius 8
|
||||
:flex-direction :row
|
||||
:flex 1
|
||||
:align-items :center
|
||||
:background-color (:ui-01 @colors/theme)}
|
||||
style))
|
||||
|
||||
(defn text-input-style [multiline input-style before after]
|
||||
(merge typography/font-regular
|
||||
{:padding-top 11
|
||||
:padding-bottom 11
|
||||
:font-size 15
|
||||
:margin 0
|
||||
:text-align-vertical :center
|
||||
:flex 1
|
||||
:height height}
|
||||
(when-not before
|
||||
{:padding-left (:base spacing/spacing)})
|
||||
(when-not after
|
||||
{:padding-right (:base spacing/spacing)})
|
||||
(when multiline
|
||||
{:text-align-vertical :top
|
||||
:line-height 22
|
||||
:height multiline-height})
|
||||
input-style))
|
||||
|
||||
(defn cancel-style []
|
||||
{:margin-left (:tiny spacing/spacing)
|
||||
:padding-left (:tiny spacing/spacing)
|
||||
:justify-content :center
|
||||
:align-self :stretch})
|
||||
|
||||
(defn accessory-style []
|
||||
(merge (:base spacing/padding-horizontal)
|
||||
{:flex 1
|
||||
:justify-content :center}))
|
||||
|
||||
(defn accessory-element [{:keys [icon icon-opts style accessibility-label on-press]}]
|
||||
(let [el (if on-press
|
||||
rn/touchable-opacity
|
||||
rn/view)]
|
||||
[el (merge {:style {:align-self :stretch}}
|
||||
(when on-press
|
||||
{:on-press on-press}))
|
||||
[rn/view (merge {:style (merge (accessory-style)
|
||||
style)}
|
||||
(when accessibility-label
|
||||
{:accessibility-label accessibility-label}))
|
||||
[icons/icon icon (merge {:color (:icon-01 @colors/theme)}
|
||||
icon-opts)]]]))
|
||||
|
||||
(defn text-input []
|
||||
(let [focused (reagent/atom nil)
|
||||
visible (reagent/atom false)
|
||||
ref (react/create-ref)
|
||||
on-cancel (fn []
|
||||
(some-> (react/current-ref ref) (ocall "blur")))]
|
||||
(fn [{:keys [label multiline error style input-style keyboard-type before after
|
||||
cancel-label on-focus on-blur show-cancel accessibility-label
|
||||
bottom-value secure-text-entry container-style]
|
||||
:or {cancel-label "Cancel"
|
||||
show-cancel true}
|
||||
:as props}]
|
||||
{:pre [(check-spec ::text-input props)]}
|
||||
(let [after (cond
|
||||
(and secure-text-entry @visible)
|
||||
{:icon :main-icons/hide
|
||||
:on-press #(reset! visible false)}
|
||||
|
||||
(and secure-text-entry (not @visible))
|
||||
{:icon :main-icons/show
|
||||
:on-press #(reset! visible true)}
|
||||
|
||||
:else after)
|
||||
secure (and secure-text-entry (not @visible))]
|
||||
[rn/view {:style container-style}
|
||||
(when label
|
||||
[text/text {:style (label-style)}
|
||||
label])
|
||||
[rn/view {:style (text-input-row-style)}
|
||||
[rn/view {:style (text-input-view-style style)}
|
||||
(when before
|
||||
[accessory-element before])
|
||||
[rn/text-input
|
||||
(merge {:style (text-input-style multiline input-style before after)
|
||||
:ref ref
|
||||
:placeholder-text-color (:text-02 @colors/theme)
|
||||
:color (:text-01 @colors/theme)
|
||||
:underline-color-android :transparent
|
||||
:auto-capitalize :none
|
||||
:secure-text-entry secure
|
||||
:on-focus (fn [evt]
|
||||
(when on-focus (on-focus evt))
|
||||
(rn/configure-next (:ease-in-ease-out rn/layout-animation-presets))
|
||||
(reset! focused true))
|
||||
:on-blur (fn [evt]
|
||||
(when on-blur (on-blur evt))
|
||||
(rn/configure-next (:ease-in-ease-out rn/layout-animation-presets))
|
||||
(reset! focused false))}
|
||||
(when (and platform/ios? (not after))
|
||||
{:clear-button-mode :while-editing})
|
||||
(when (and platform/ios?
|
||||
(not= keyboard-type "visible-password"))
|
||||
{:keyboard-type keyboard-type})
|
||||
(dissoc props
|
||||
:style :keyboard-type :on-focus :on-blur
|
||||
:secure-text-entry :ref))]
|
||||
(when after
|
||||
[accessory-element after])]
|
||||
(when (and platform/ios?
|
||||
show-cancel
|
||||
(not multiline)
|
||||
@focused)
|
||||
[rn/touchable-opacity {:style (cancel-style)
|
||||
:on-press on-cancel}
|
||||
[text/text {:color :link} cancel-label]])]
|
||||
(when error
|
||||
[tooltip/tooltip (merge {:bottom-value (cond bottom-value bottom-value
|
||||
label 30 ; 22 line height 8 margin
|
||||
)}
|
||||
(when accessibility-label
|
||||
{:accessibility-label (str (name accessibility-label) "-error")}))
|
||||
[text/text {:color :negative
|
||||
:size :small}
|
||||
error]])]))))
|
65
src/quo/components/tooltip.cljs
Normal file
@ -0,0 +1,65 @@
|
||||
(ns quo.components.tooltip
|
||||
(:require [reagent.core :as reagent]
|
||||
[oops.core :refer [oget]]
|
||||
[quo.animated :as animated]
|
||||
[quo.react :as react]
|
||||
[quo.react-native :as rn]
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.design-system.spacing :as spacing]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]))
|
||||
|
||||
(def ^:private initial-height 22)
|
||||
|
||||
(defn tooltip-style [{:keys [bottom-value animation]}]
|
||||
(merge
|
||||
(:base spacing/padding-horizontal)
|
||||
{:position :absolute
|
||||
:align-items :center
|
||||
:left 0
|
||||
:right 0
|
||||
:top (- bottom-value)
|
||||
:opacity animation
|
||||
:transform [{:translateY (animated/b-interpolate animation 10 0)}]}))
|
||||
|
||||
(defn container-style []
|
||||
{:z-index 2
|
||||
:align-items :center
|
||||
:shadow-radius 16
|
||||
:shadow-opacity 1
|
||||
:shadow-color (:shadow-01 @colors/theme)
|
||||
:shadow-offset {:width 0 :height 4}})
|
||||
|
||||
(defn content-style []
|
||||
(merge (:base spacing/padding-horizontal)
|
||||
{:padding-vertical 6
|
||||
:elevation 2
|
||||
:background-color (:ui-background @colors/theme)
|
||||
:border-radius 8}))
|
||||
|
||||
(defn tooltip []
|
||||
(let [layout (reagent/atom {:height initial-height})
|
||||
animation-v (animated/value 0)
|
||||
animation (animated/with-timing
|
||||
animation-v
|
||||
{:easing (:ease-in animated/easings)})
|
||||
on-layout (fn [evt]
|
||||
(let [width (oget evt "nativeEvent" "layout" "width")
|
||||
height (oget evt "nativeEvent" "layout" "height")]
|
||||
(reset! layout {:width width
|
||||
:height height})))]
|
||||
(fn [{:keys [bottom-value]} & children]
|
||||
[:<>
|
||||
[animated/code {:exec (animated/set animation-v 1)}]
|
||||
[animated/view {:style (tooltip-style {:bottom-value (- (get @layout :height)
|
||||
bottom-value)
|
||||
:animation animation})
|
||||
:pointer-events :box-none}
|
||||
[animated/view {:style (container-style)
|
||||
:pointer-events :box-none}
|
||||
(into [rn/view {:style (content-style)
|
||||
:on-layout on-layout}]
|
||||
children)
|
||||
[vector-icons/icon :icons/tooltip-tip {:width 18
|
||||
:height 8
|
||||
:container-style {:elevation 3}
|
||||
:color (:ui-background @colors/theme)}]]]])))
|
@ -2,12 +2,15 @@
|
||||
(:require [quo.components.animated-header :as animated-header]
|
||||
[quo.components.header :as header]
|
||||
[quo.components.safe-area :as safe-area]
|
||||
[quo.components.text-input :as text-input]
|
||||
[quo.components.tooltip :as tooltip]
|
||||
[quo.components.text :as text]))
|
||||
|
||||
(def text text/text)
|
||||
(def header header/header)
|
||||
(def animated-header animated-header/header)
|
||||
|
||||
(def text-input text-input/text-input)
|
||||
(def tooltip tooltip/tooltip)
|
||||
(def safe-area-provider safe-area/provider)
|
||||
(def safe-area-consumer safe-area/consumer)
|
||||
(def safe-area-view safe-area/view)
|
||||
|
@ -1,6 +1,8 @@
|
||||
(ns quo.previews.header
|
||||
(:require [quo.core :as quo]
|
||||
[quo.react-native :as rn]))
|
||||
[quo.react-native :as rn]
|
||||
[quo.design-system.colors :as colors])
|
||||
(:require-macros [quo.previews.preview :as preview]))
|
||||
|
||||
(def accessories [nil
|
||||
[{:icon :main-icons/close
|
||||
@ -16,17 +18,27 @@
|
||||
[{:label "Text"
|
||||
:on-press identity}]])
|
||||
|
||||
(def all-props (preview/list-comp [left-accessories accessories
|
||||
right-accessories accessories
|
||||
title [nil "This is a title" "This is a very long super title"]
|
||||
subtitle [nil "This is a subtitle"]
|
||||
title-align [:left :center]]
|
||||
{:left-accessories left-accessories
|
||||
:right-accessories right-accessories
|
||||
:title title
|
||||
:subtitle subtitle
|
||||
:title-align title-align}))
|
||||
|
||||
(defn render-item [props]
|
||||
[rn/view {:border-bottom-color "#EEF2F5"
|
||||
:border-bottom-width 2}
|
||||
[quo/header props]])
|
||||
|
||||
(defn preview-header []
|
||||
[rn/scroll-view {:flex 1}
|
||||
(for [left-accessories accessories
|
||||
right-accessories accessories
|
||||
title [nil "This is a title" "This is a very long super title"]
|
||||
subtitle [nil "This is a subtitle"]
|
||||
title-align [:left :center]]
|
||||
[rn/view {:border-bottom-color "#EEF2F5"
|
||||
:border-bottom-width 2}
|
||||
[quo/header {:left-accessories left-accessories
|
||||
:right-accessories right-accessories
|
||||
:title title
|
||||
:subtitle subtitle
|
||||
:title-align title-align}]])])
|
||||
[rn/view {:background-color (:ui-background @colors/theme)
|
||||
:flex 1}
|
||||
[rn/flat-list {:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:data all-props
|
||||
:render-fn render-item
|
||||
:key-fn str}]])
|
||||
|
@ -2,26 +2,62 @@
|
||||
(:require [oops.core :refer [ocall]]
|
||||
[quo.previews.header :as header]
|
||||
[quo.previews.text :as text]
|
||||
[quo.previews.text-input :as text-input]
|
||||
[quo.previews.tooltip :as tooltip]
|
||||
[quo.react-native :as rn]
|
||||
[quo.core :as quo]
|
||||
[reagent.core :as reagent]
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.theme :as theme]
|
||||
[status-im.ui.screens.routing.core :as navigation]))
|
||||
|
||||
(def screens [{:name :texts
|
||||
:insets {:top false}
|
||||
:component text/preview-text}
|
||||
{:name :tooltip
|
||||
:insets {:top false}
|
||||
:component tooltip/preview-tooltip}
|
||||
{:name :text-input
|
||||
:insets {:top false}
|
||||
:component text-input/preview-text}
|
||||
{:name :headers
|
||||
:insets {:top false}
|
||||
:component header/preview-header}])
|
||||
|
||||
(defn theme-switcher []
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:margin-vertical 8
|
||||
:border-radius 4
|
||||
:background-color (:ui-01 @colors/theme)
|
||||
:border-width 1
|
||||
:border-color (:ui-02 @colors/theme)}}
|
||||
[rn/touchable-opacity {:style {:padding 8
|
||||
:flex 1
|
||||
:justify-content :center
|
||||
:align-items :center}
|
||||
:on-press #(theme/set-theme :light)}
|
||||
[quo/text "Set light theme"]]
|
||||
[rn/view {:width 1
|
||||
:margin-vertical 4
|
||||
:background-color (:ui-02 @colors/theme)}]
|
||||
[rn/touchable-opacity {:style {:padding 8
|
||||
:flex 1
|
||||
:justify-content :center
|
||||
:align-items :center}
|
||||
:on-press #(theme/set-theme :dark)}
|
||||
[quo/text "Set dark theme"]]])
|
||||
|
||||
(defn main-screen []
|
||||
[rn/scroll-view {:flex 1
|
||||
:padding-vertical 8
|
||||
:padding-horizontal 16}
|
||||
:padding-horizontal 16
|
||||
:background-color (:ui-background @colors/theme)}
|
||||
[theme-switcher]
|
||||
[rn/view
|
||||
(for [{:keys [name]} screens]
|
||||
[rn/touchable-opacity {:on-press #(navigation/navigate-to name nil)}
|
||||
[rn/view {:style {:padding-vertical 8}}
|
||||
[rn/text (str "Preview " name)]]])]])
|
||||
[quo/text (str "Preview " name)]]])]])
|
||||
|
||||
(defonce navigation-state (atom nil))
|
||||
|
||||
|
15
src/quo/previews/preview.clj
Normal file
@ -0,0 +1,15 @@
|
||||
(ns quo.previews.preview)
|
||||
|
||||
(defn descriptor->values [{:keys [key options type]}]
|
||||
{key (case type
|
||||
:boolean [false true]
|
||||
:text [nil "Just simple text"] ; NOTE(Ferossgp): add example with long text?
|
||||
:select (mapv :key options))})
|
||||
|
||||
(defmacro list-comp [[binding seq-expr & bindings] body-expr]
|
||||
(cond (not binding)
|
||||
`(list ~body-expr)
|
||||
|
||||
:else
|
||||
`(mapcat (fn [~binding] (list-comp ~bindings ~body-expr))
|
||||
~seq-expr)))
|
171
src/quo/previews/preview.cljs
Normal file
@ -0,0 +1,171 @@
|
||||
(ns quo.previews.preview
|
||||
(:require [reagent.core :as reagent]
|
||||
[quo.react-native :as rn]
|
||||
[quo.core :as quo]
|
||||
[quo.design-system.colors :as colors])
|
||||
(:require-macros quo.previews.preview))
|
||||
|
||||
(def container {:flex-direction :row
|
||||
:padding-vertical 8
|
||||
:align-items :center})
|
||||
|
||||
(defn touchable-style []
|
||||
{:flex 1
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:padding-horizontal 16
|
||||
:height 44})
|
||||
|
||||
(defn select-style []
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:padding-horizontal 16
|
||||
:height 44
|
||||
:border-radius 4
|
||||
:background-color (:ui-01 @colors/theme)
|
||||
:border-width 1
|
||||
:border-color (:ui-02 @colors/theme)})
|
||||
|
||||
(defn select-option-style [selected]
|
||||
(merge (select-style)
|
||||
{:margin-vertical 8
|
||||
:justify-content :center}
|
||||
(if selected
|
||||
{:background-color (:interactive-02 @colors/theme)}
|
||||
{:background-color (:ui-01 @colors/theme)})))
|
||||
|
||||
(def label-style {:flex 0.4
|
||||
:padding-right 8})
|
||||
|
||||
(defn modal-container []
|
||||
{:flex 1
|
||||
:justify-content :center
|
||||
:padding-horizontal 24
|
||||
:background-color "rgba(0,0,0,0.4)"})
|
||||
|
||||
(defn modal-view []
|
||||
{:padding-horizontal 16
|
||||
:padding-vertical 8
|
||||
:border-radius 8
|
||||
:flex-direction :column
|
||||
:background-color (:ui-background @colors/theme)})
|
||||
|
||||
(defn customizer-boolean
|
||||
[{:keys [label key state]}]
|
||||
(let [state* (reagent/cursor state [key])]
|
||||
[rn/view {:style container}
|
||||
[rn/view {:style label-style}
|
||||
[quo/text label]]
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:flex 0.6
|
||||
:border-radius 4
|
||||
:background-color (:ui-01 @colors/theme)
|
||||
:border-width 1
|
||||
:border-color (:ui-02 @colors/theme)}}
|
||||
[rn/touchable-opacity {:style (touchable-style)
|
||||
:on-press #(reset! state* true)}
|
||||
[quo/text {:color (if @state* :link :secondary)}
|
||||
"True"]]
|
||||
[rn/view {:width 1
|
||||
:margin-vertical 4
|
||||
:background-color (:ui-02 @colors/theme)}]
|
||||
[rn/touchable-opacity {:style (touchable-style)
|
||||
:on-press #(reset! state* false)}
|
||||
[quo/text {:color (if (not @state*) :link :secondary)}
|
||||
"False"]]]]))
|
||||
|
||||
(defn customizer-text
|
||||
[{:keys [label key state]}]
|
||||
(let [state* (reagent/cursor state [key])]
|
||||
[rn/view {:style container}
|
||||
[rn/view {:style label-style}
|
||||
[quo/text label]]
|
||||
[rn/view {:style {:flex 0.6}}
|
||||
[quo/text-input {:value @state*
|
||||
:show-cancel false
|
||||
:style {:border-radius 4
|
||||
:border-width 1
|
||||
:border-color (:ui-02 @colors/theme)}
|
||||
:on-change-text #(do
|
||||
(reset! state* %)
|
||||
(reagent/flush))}]]]))
|
||||
|
||||
(defn value-for-key
|
||||
[id v]
|
||||
(:value (first (filter #(= (:key %) id) v))))
|
||||
|
||||
(defn customizer-select []
|
||||
(let [open (reagent/atom nil)]
|
||||
(fn [{:keys [label key state options]}]
|
||||
(let [state* (reagent/cursor state [key])
|
||||
selected (value-for-key @state* options)]
|
||||
[rn/view {:style container}
|
||||
[rn/view {:style label-style}
|
||||
[quo/text label]]
|
||||
[rn/view {:style {:flex 0.6}}
|
||||
[rn/modal {:visible @open
|
||||
:on-request-close #(reset! open false)
|
||||
:transparent :true
|
||||
:animation :slide}
|
||||
[rn/view {:style (modal-container)}
|
||||
[rn/view {:style (modal-view)}
|
||||
[rn/scroll-view
|
||||
(doall
|
||||
(for [{:keys [key value]} options]
|
||||
^{:key key}
|
||||
[rn/touchable-opacity {:style (select-option-style (= @state* key))
|
||||
:on-press #(do
|
||||
(reset! open false)
|
||||
(reset! state* key))}
|
||||
[quo/text {:color (if (= @state* key) :link :secondary)}
|
||||
value]]))
|
||||
[rn/view {:flex-direction :row}
|
||||
[rn/touchable-opacity {:style (select-option-style false)
|
||||
:on-press #(do
|
||||
(reset! state* nil)
|
||||
(reset! open false))}
|
||||
[quo/text "Clear"]]
|
||||
[rn/view {:width 16}]
|
||||
[rn/touchable-opacity {:style (select-option-style false)
|
||||
:on-press #(reset! open false)}
|
||||
[quo/text "Close"]]]]]]]
|
||||
|
||||
[rn/touchable-opacity {:style (select-style)
|
||||
:on-press #(reset! open true)}
|
||||
(if selected
|
||||
[quo/text {:color :link} selected]
|
||||
[quo/text "Select option"])
|
||||
[rn/view {:position :absolute
|
||||
:right 16
|
||||
:top 0
|
||||
:bottom 0
|
||||
:justify-content :center}
|
||||
[quo/text "↓"]]]]]))))
|
||||
|
||||
(defn customizer [state descriptors]
|
||||
[rn/view
|
||||
(doall
|
||||
(for [{:keys [key type]
|
||||
:as desc} descriptors
|
||||
:let [descriptor (merge desc
|
||||
{:state state})]]
|
||||
^{:key key}
|
||||
[rn/view
|
||||
(case type
|
||||
:boolean [customizer-boolean descriptor]
|
||||
:text [customizer-text descriptor]
|
||||
:select [customizer-select descriptor])]))])
|
||||
|
||||
(comment
|
||||
[{:label "Show error:"
|
||||
:key :error
|
||||
:type :boolean}
|
||||
{:label "Label:"
|
||||
:key :label
|
||||
:type :text}
|
||||
{:label "Type:"
|
||||
:key :type
|
||||
:type :select
|
||||
:options [{:key :primary :value "Primary"}
|
||||
{:key :secondary :value "Secondary"}]}])
|
@ -1,14 +1,89 @@
|
||||
(ns quo.previews.text
|
||||
(:require [quo.core :as quo]
|
||||
[quo.react-native :as rn]))
|
||||
(:require [reagent.core :as reagent]
|
||||
[quo.core :as quo]
|
||||
[quo.animated :as animated]
|
||||
[quo.react-native :as rn]
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.previews.preview :as preview]))
|
||||
|
||||
(def all-props (preview/list-comp [size [:tiny :small :base :large :x-large :xx-large]
|
||||
weight [:regular :medium :semi-bold :bold :monospace]]
|
||||
{:weight weight
|
||||
:size size}))
|
||||
|
||||
(def descriptor [{:label "Size:"
|
||||
:key :size
|
||||
:type :select
|
||||
:options [{:key :tiny
|
||||
:value "Tiny"}
|
||||
{:key :small
|
||||
:value "Small"}
|
||||
{:key :base
|
||||
:value "Base"}
|
||||
{:key :large
|
||||
:value "Large"}
|
||||
{:key :x-large
|
||||
:value "X-Large"}
|
||||
{:key :xx-large
|
||||
:value "XX-Large"}]}
|
||||
{:label "Weight:"
|
||||
:key :weight
|
||||
:type :select
|
||||
:options [{:key :regular
|
||||
:value "Regular"}
|
||||
{:key :medium
|
||||
:value "Medium"}
|
||||
{:key :semi-bold
|
||||
:value "Semi-bold"}
|
||||
{:key :bold
|
||||
:value "Bold"}
|
||||
{:key :monospace
|
||||
:value "Monospace"}]}
|
||||
{:label "Color:"
|
||||
:key :color
|
||||
:type :select
|
||||
:options [{:key :main
|
||||
:value "main"}
|
||||
{:key :secondary
|
||||
:value "secondary"}
|
||||
{:key :secondary-inverse
|
||||
:value "secondary-inverse"}
|
||||
{:key :link
|
||||
:value "link"}
|
||||
{:key :negative
|
||||
:value "negative"}
|
||||
{:key :positive
|
||||
:value "positive"}]}
|
||||
{:label "Animated:"
|
||||
:key :animated?
|
||||
:type :boolean}])
|
||||
|
||||
(defn render-item [props]
|
||||
[rn/view {:style {:padding-vertical 24
|
||||
:padding-horizontal 16}}
|
||||
[quo/text props
|
||||
(str "Text size " props " number 0 1x2")]])
|
||||
|
||||
(defn cool-preview []
|
||||
(let [state (reagent/atom {})
|
||||
animation (animated/value 0)]
|
||||
(fn []
|
||||
[rn/view {:margin-bottom 50
|
||||
:padding 16}
|
||||
[animated/code {:exec (animated/set animation (animated/loop* {:duration 1000}))}]
|
||||
[preview/customizer state descriptor]
|
||||
[rn/view {:padding-vertical 16}
|
||||
[quo/text (merge @state
|
||||
(when (:animated? @state)
|
||||
{:opacity animation}))
|
||||
"This is a demo text 1 2 0 2x2 0x0"]]])))
|
||||
|
||||
(defn preview-text []
|
||||
[rn/scroll-view {:flex 1
|
||||
:padding-horizontal 16}
|
||||
(for [size [:tiny :small :base :large :x-large :xx-large]
|
||||
weight [:regular :medium :semi-bold :bold :monospace]]
|
||||
^{:key (str)}
|
||||
[rn/view {:padding-vertical 16}
|
||||
[quo/text {:weight weight
|
||||
:size size}
|
||||
(str "Text size " size ", font weight " weight)]])])
|
||||
[rn/view {:background-color (:ui-background @colors/theme)
|
||||
:flex 1}
|
||||
[rn/flat-list {:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:header [cool-preview]
|
||||
:data all-props
|
||||
:render-fn render-item
|
||||
:key-fn str}]])
|
||||
|
81
src/quo/previews/text_input.cljs
Normal file
@ -0,0 +1,81 @@
|
||||
(ns quo.previews.text-input
|
||||
(:require [reagent.core :as reagent]
|
||||
[quo.core :as quo]
|
||||
[quo.react-native :as rn]
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.previews.preview :as preview]))
|
||||
|
||||
(def all-props (preview/list-comp [multiline [false true]
|
||||
label [nil "Input label"]
|
||||
default-value [nil "Test initial value"]
|
||||
placeholder [nil "Placeholder value"]
|
||||
before [nil {:icon :main-icons/search}]
|
||||
after [nil {:icon :main-icons/close}]
|
||||
error [nil "Something went wrong!"]
|
||||
secure [false true]
|
||||
show-cancel [false true]]
|
||||
{:label label
|
||||
:default-value default-value
|
||||
:placeholder placeholder
|
||||
:multiline multiline
|
||||
:before before
|
||||
:after after
|
||||
:error error
|
||||
:show-cancel show-cancel
|
||||
:secure-text-entry secure}))
|
||||
|
||||
(def descriptor [{:label "Multiline:"
|
||||
:key :multiline
|
||||
:type :boolean}
|
||||
{:label "Show cancel:"
|
||||
:key :show-cancel
|
||||
:type :boolean}
|
||||
{:label "Secure:"
|
||||
:key :secure-text-entry
|
||||
:type :boolean}
|
||||
{:label "After icon:"
|
||||
:key :after
|
||||
:type :boolean}
|
||||
{:label "Before icon:"
|
||||
:key :before
|
||||
:type :boolean}
|
||||
{:label "Show error:"
|
||||
:key :error
|
||||
:type :boolean}
|
||||
{:label "Label"
|
||||
:key :label
|
||||
:type :text}])
|
||||
|
||||
(defn render-item [props]
|
||||
[rn/view {:style {:padding-horizontal 16
|
||||
:padding-vertical 24}}
|
||||
[quo/text-input props]])
|
||||
|
||||
(defn cool-preview []
|
||||
(let [state (reagent/atom {:secure false
|
||||
:show-cancel false
|
||||
:multiline false
|
||||
:label "I'm a cool label"})
|
||||
before (reagent/cursor state [:before])
|
||||
after (reagent/cursor state [:after])
|
||||
error (reagent/cursor state [:error])]
|
||||
(fn []
|
||||
[rn/view {:margin-bottom 50
|
||||
:padding 16}
|
||||
[preview/customizer state descriptor]
|
||||
[quo/text-input (merge @state
|
||||
{:default-value nil
|
||||
:placeholder "I'm a cool placeholder"
|
||||
:before (when @before {:icon :main-icons/search})
|
||||
:after (when @after {:icon :main-icons/close})
|
||||
:error (when @error "Something went wrong!")})]])))
|
||||
|
||||
(defn preview-text []
|
||||
[rn/view {:background-color (:ui-background @colors/theme)
|
||||
:flex 1}
|
||||
[rn/flat-list {:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:header [cool-preview]
|
||||
:data all-props
|
||||
:render-fn render-item
|
||||
:key-fn str}]])
|
30
src/quo/previews/tooltip.cljs
Normal file
@ -0,0 +1,30 @@
|
||||
(ns quo.previews.tooltip
|
||||
(:require [quo.core :as quo]
|
||||
[quo.react-native :as rn]
|
||||
[quo.design-system.colors :as colors])
|
||||
(:require-macros [quo.previews.preview :as preview]))
|
||||
|
||||
(def all-props (preview/list-comp
|
||||
[child [[quo/text {:size :small} "Simple text"]
|
||||
[quo/text {:color :negative
|
||||
:size :small}
|
||||
"Error text"]
|
||||
[rn/view {:width 100 :height 20 :background-color :red}]
|
||||
[quo/text "Just text, but long. Officia autem est repellendus ad quia exercitationem veniam."]]]
|
||||
child))
|
||||
|
||||
(defn render-item [children]
|
||||
[rn/view {:margin-vertical 50}
|
||||
[rn/view {:height 20
|
||||
:background-color "rgba(0,0,0,0.1)"}]
|
||||
[quo/tooltip {}
|
||||
children]])
|
||||
|
||||
(defn preview-tooltip []
|
||||
[rn/view {:background-color (:ui-background @colors/theme)
|
||||
:flex 1}
|
||||
[rn/flat-list {:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:data all-props
|
||||
:render-fn render-item
|
||||
:key-fn str}]])
|
@ -1,7 +1,8 @@
|
||||
(ns quo.react
|
||||
(:require [oops.core :refer [oget]]
|
||||
[reagent.core :as reagent]
|
||||
["react" :as react]))
|
||||
|
||||
;; NOTE(Ferossgp): Available in new versions of reagent as `:<>`
|
||||
(def fragment (reagent/adapt-react-class (oget react "Fragment")))
|
||||
(def create-ref (oget react "createRef"))
|
||||
|
||||
(defn current-ref [ref]
|
||||
(oget ref "current"))
|
||||
|
@ -11,6 +11,45 @@
|
||||
(def text (reagent/adapt-react-class (.-Text ^js rn)))
|
||||
|
||||
(def scroll-view (reagent/adapt-react-class (.-ScrollView ^js rn)))
|
||||
(def modal (reagent/adapt-react-class (.-Modal ^js rn)))
|
||||
|
||||
(def touchable-opacity (reagent/adapt-react-class (.-TouchableOpacity ^js rn)))
|
||||
(def touchable-highlight (reagent/adapt-react-class (.-TouchableHighlight ^js rn)))
|
||||
|
||||
(def text-input (reagent/adapt-react-class (.-TextInput ^js rn)))
|
||||
|
||||
(def ui-manager (.-UIManager ^js rn))
|
||||
|
||||
(def layout-animation (.-LayoutAnimation ^js rn))
|
||||
(def configure-next (.-configureNext ^js layout-animation))
|
||||
(def layout-animation-presets {:ease-in-ease-out (-> ^js layout-animation .-Presets .-easeInEaseOut)
|
||||
:linear (-> ^js layout-animation .-Presets .-linear)
|
||||
:spring (-> ^js layout-animation .-Presets .-spring)})
|
||||
|
||||
(def switch (reagent/adapt-react-class (.-Switch ^js rn)))
|
||||
|
||||
;; Flat-list
|
||||
(def ^:private rn-flat-list (reagent/adapt-react-class (.-FlatList ^js rn)))
|
||||
|
||||
(defn- wrap-render-fn [f]
|
||||
(fn [data]
|
||||
(reagent/as-element (f (.-item data) (.-index data) (.-separators data)))))
|
||||
|
||||
(defn- wrap-key-fn [f]
|
||||
(fn [data index]
|
||||
{:post [(some? %)]}
|
||||
(f data index)))
|
||||
|
||||
(defn- base-list-props
|
||||
[{:keys [key-fn render-fn empty-component header footer separator data] :as props}]
|
||||
(merge {:data (to-array data)}
|
||||
(when key-fn {:keyExtractor (wrap-key-fn key-fn)})
|
||||
(when render-fn {:renderItem (wrap-render-fn render-fn)})
|
||||
(when separator {:ItemSeparatorComponent (fn [] (reagent/as-element separator))})
|
||||
(when empty-component {:ListEmptyComponent (fn [] (reagent/as-element empty-component))})
|
||||
(when header {:ListHeaderComponent (reagent/as-element header)})
|
||||
(when footer {:ListFooterComponent (reagent/as-element footer)})
|
||||
(dissoc props :data :header :footer :empty-component :separator :render-fn :key-fn)))
|
||||
|
||||
(defn flat-list [props]
|
||||
[rn-flat-list (base-list-props props)])
|
||||
|
4
src/quo/spec.cljs
Normal file
@ -0,0 +1,4 @@
|
||||
(ns quo.spec
|
||||
(:require [clojure.spec.alpha :as s]))
|
||||
|
||||
(s/def ::style (s/nilable map?))
|