@neko-os/ui 0.0.13 → 0.1.0

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.
Files changed (137) hide show
  1. package/dist/abstractions/KeyboardAvoidingView.js +1 -0
  2. package/dist/abstractions/KeyboardAvoidingView.native.js +1 -0
  3. package/dist/components/actions/ActionsDrawer.js +1 -0
  4. package/dist/components/actions/Button.js +1 -1
  5. package/dist/components/actions/FloatingMenu.js +1 -0
  6. package/dist/components/actions/index.js +1 -1
  7. package/dist/components/animations/AnimatedTopBar.js +1 -0
  8. package/dist/components/animations/AnimatedTopBar.native.js +1 -0
  9. package/dist/components/animations/AnimatedTopBar.web.js +1 -0
  10. package/dist/components/animations/ParallaxHeader.js +1 -0
  11. package/dist/components/animations/ParallaxHeader.native.js +1 -0
  12. package/dist/components/animations/ParallaxHeader.web.js +1 -0
  13. package/dist/components/animations/ReanimatedScrollHandler.js +1 -0
  14. package/dist/components/animations/ReanimatedScrollHandler.native.js +1 -0
  15. package/dist/components/animations/ReanimatedScrollHandler.web.js +1 -0
  16. package/dist/components/animations/index.js +1 -1
  17. package/dist/components/form/FormItem.js +1 -1
  18. package/dist/components/form/FormList.js +1 -1
  19. package/dist/components/form/SubmitButton.js +1 -1
  20. package/dist/components/form/index.js +1 -1
  21. package/dist/components/form/useNewForm.js +1 -1
  22. package/dist/components/form/validation/defaultMessages.js +1 -0
  23. package/dist/components/form/validation/index.js +1 -0
  24. package/dist/components/form/validation/normalizeRules.js +1 -0
  25. package/dist/components/form/validation/shouldValidateOn.js +1 -0
  26. package/dist/components/form/validation/validateRules.js +1 -0
  27. package/dist/components/form/validation/validators.js +1 -0
  28. package/dist/components/index.js +1 -1
  29. package/dist/components/inputs/InputWrapper.js +1 -1
  30. package/dist/components/inputs/NumberInput.js +1 -1
  31. package/dist/components/inputs/Picker.js +1 -1
  32. package/dist/components/inputs/Select.js +1 -1
  33. package/dist/components/presentation/Avatar.js +1 -1
  34. package/dist/components/presentation/AvatarLabel.js +1 -1
  35. package/dist/components/presentation/LabelValue.js +1 -1
  36. package/dist/components/presentation/Result.js +1 -1
  37. package/dist/components/presentation/Tooltip.js +1 -1
  38. package/dist/components/sections/Section.js +1 -0
  39. package/dist/components/sections/SectionItem.js +1 -0
  40. package/dist/components/sections/SectionItemLink.js +1 -0
  41. package/dist/components/sections/index.js +1 -0
  42. package/dist/components/state/StatePresenter.js +1 -0
  43. package/dist/components/state/index.js +1 -1
  44. package/dist/components/structure/BlurView.js +1 -1
  45. package/dist/components/structure/KeyboardAvoidingView.js +1 -0
  46. package/dist/components/structure/TopBar.js +1 -0
  47. package/dist/components/structure/bottomDrawer/index.js +1 -1
  48. package/dist/components/structure/bottomDrawer/index.native.js +1 -1
  49. package/dist/components/structure/bottomDrawer/index.web.js +1 -1
  50. package/dist/components/structure/bottomDrawer/native/BottomDrawer.js +1 -1
  51. package/dist/components/structure/bottomDrawer/native/DrawerScrollView.js +1 -1
  52. package/dist/components/structure/bottomDrawer/native/createDrawerScrollComponent.js +1 -0
  53. package/dist/components/structure/index.js +1 -1
  54. package/dist/components/text/DateText.js +1 -0
  55. package/dist/components/text/index.js +1 -1
  56. package/dist/components/theme/ThemePicker.js +1 -1
  57. package/dist/helpers/index.js +1 -1
  58. package/dist/helpers/storage.js +1 -1
  59. package/dist/responsive/responsiveHooks.js +1 -1
  60. package/dist/theme/ThemeHandler.js +1 -1
  61. package/dist/theme/default/base.js +1 -1
  62. package/dist/theme/default/blackTheme.js +1 -1
  63. package/dist/theme/default/cyberpunkTheme.js +1 -1
  64. package/dist/theme/default/darkTheme.js +1 -1
  65. package/dist/theme/default/hackerTheme.js +1 -1
  66. package/dist/theme/default/lightTheme.js +1 -1
  67. package/dist/theme/default/msdosTheme.js +1 -1
  68. package/dist/theme/default/paperTheme.js +1 -1
  69. package/package.json +1 -1
  70. package/src/abstractions/KeyboardAvoidingView.js +3 -0
  71. package/src/abstractions/KeyboardAvoidingView.native.js +3 -0
  72. package/src/components/actions/ActionsDrawer.js +68 -0
  73. package/src/components/actions/Button.js +2 -1
  74. package/src/components/actions/FloatingMenu.js +39 -0
  75. package/src/components/actions/index.js +2 -0
  76. package/src/components/animations/AnimatedTopBar.js +10 -0
  77. package/src/components/animations/AnimatedTopBar.native.js +34 -0
  78. package/src/components/animations/AnimatedTopBar.web.js +1 -0
  79. package/src/components/animations/ParallaxHeader.js +9 -0
  80. package/src/components/animations/ParallaxHeader.native.js +32 -0
  81. package/src/components/animations/ParallaxHeader.web.js +32 -0
  82. package/src/components/animations/ReanimatedScrollHandler.js +8 -0
  83. package/src/components/animations/ReanimatedScrollHandler.native.js +24 -0
  84. package/src/components/animations/ReanimatedScrollHandler.web.js +1 -0
  85. package/src/components/animations/index.js +3 -0
  86. package/src/components/form/FormItem.js +42 -5
  87. package/src/components/form/FormList.js +23 -4
  88. package/src/components/form/SubmitButton.js +4 -2
  89. package/src/components/form/index.js +1 -0
  90. package/src/components/form/useNewForm.js +108 -15
  91. package/src/components/form/validation/defaultMessages.js +20 -0
  92. package/src/components/form/validation/index.js +5 -0
  93. package/src/components/form/validation/normalizeRules.js +22 -0
  94. package/src/components/form/validation/shouldValidateOn.js +21 -0
  95. package/src/components/form/validation/validateRules.js +83 -0
  96. package/src/components/form/validation/validators.js +82 -0
  97. package/src/components/index.js +1 -0
  98. package/src/components/inputs/InputWrapper.js +1 -1
  99. package/src/components/inputs/NumberInput.js +6 -5
  100. package/src/components/inputs/Picker.js +3 -2
  101. package/src/components/inputs/Select.js +31 -15
  102. package/src/components/presentation/Avatar.js +2 -2
  103. package/src/components/presentation/AvatarLabel.js +2 -0
  104. package/src/components/presentation/LabelValue.js +7 -5
  105. package/src/components/presentation/Result.js +2 -2
  106. package/src/components/presentation/Tooltip.js +1 -1
  107. package/src/components/sections/Section.js +50 -0
  108. package/src/components/sections/SectionItem.js +24 -0
  109. package/src/components/sections/SectionItemLink.js +33 -0
  110. package/src/components/sections/index.js +3 -0
  111. package/src/components/state/StatePresenter.js +41 -0
  112. package/src/components/state/index.js +1 -0
  113. package/src/components/structure/BlurView.js +1 -0
  114. package/src/components/structure/KeyboardAvoidingView.js +52 -0
  115. package/src/components/structure/TopBar.js +45 -0
  116. package/src/components/structure/bottomDrawer/index.js +2 -0
  117. package/src/components/structure/bottomDrawer/index.native.js +2 -1
  118. package/src/components/structure/bottomDrawer/index.web.js +2 -1
  119. package/src/components/structure/bottomDrawer/native/BottomDrawer.js +14 -20
  120. package/src/components/structure/bottomDrawer/native/DrawerScrollView.js +4 -82
  121. package/src/components/structure/bottomDrawer/native/createDrawerScrollComponent.js +131 -0
  122. package/src/components/structure/index.js +2 -0
  123. package/src/components/text/DateText.js +11 -0
  124. package/src/components/text/index.js +1 -0
  125. package/src/components/theme/ThemePicker.js +1 -2
  126. package/src/helpers/index.js +1 -0
  127. package/src/helpers/storage.js +32 -9
  128. package/src/responsive/responsiveHooks.js +6 -0
  129. package/src/theme/ThemeHandler.js +6 -3
  130. package/src/theme/default/base.js +16 -4
  131. package/src/theme/default/blackTheme.js +1 -0
  132. package/src/theme/default/cyberpunkTheme.js +10 -0
  133. package/src/theme/default/darkTheme.js +1 -0
  134. package/src/theme/default/hackerTheme.js +17 -3
  135. package/src/theme/default/lightTheme.js +1 -0
  136. package/src/theme/default/msdosTheme.js +9 -10
  137. package/src/theme/default/paperTheme.js +10 -0
@@ -1 +1 @@
1
- export*from"./Accordion";export*from"./AccordionGroup";export*from"./View";export*from"./GradientView";export*from"./BlurView";export*from"./SafeAreaView";export*from"./Card";export*from"./Row";export*from"./Col";export*from"./modal";export*from"./drawer";export*from"./bottomDrawer";export*from"./popover/Popover";export*from"./Segment";
1
+ export*from"./Accordion";export*from"./AccordionGroup";export*from"./View";export*from"./GradientView";export*from"./BlurView";export*from"./SafeAreaView";export*from"./Card";export*from"./Row";export*from"./Col";export*from"./modal";export*from"./drawer";export*from"./bottomDrawer";export*from"./popover/Popover";export*from"./Segment";export*from"./TopBar";export*from"./KeyboardAvoidingView";
@@ -0,0 +1 @@
1
+ import _objectWithoutProperties from"@babel/runtime/helpers/objectWithoutProperties";var _jsxFileName="/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/components/text/DateText.js";var _excluded=["format","value","children"];import{is}from'ramda';import dayjs from'dayjs';import{Text}from"../text";import{jsx as _jsx}from"react/jsx-runtime";export function DateText(_ref){var _ref$format=_ref.format,format=_ref$format===void 0?'DD MMM YYYY':_ref$format,value=_ref.value,children=_ref.children,props=_objectWithoutProperties(_ref,_excluded);value=is(String,children)?children:value;return _jsx(Text,Object.assign({},props,{children:dayjs(value).format(format)}));}
@@ -1 +1 @@
1
- export*from"./Text";export*from"./VerticalText";
1
+ export*from"./Text";export*from"./VerticalText";export*from"./DateText";
@@ -1 +1 @@
1
- var _jsxFileName="/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/components/theme/ThemePicker.js";import{mapObjIndexed,mergeDeepRight,values,pipe,filter}from'ramda';import{DEFAULT_THEMES,useThemeHandler}from"../../theme";import{IconLabel}from"../presentation";import{Link}from"../actions";import{Picker}from"../inputs";import{ThemeThumb}from"./ThemeThumb";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export function ThemePicker(_ref){var _this=this;var _onChange=_ref.onChange,onlyKeys=_ref.onlyKeys,hideKeys=_ref.hideKeys;var _useThemeHandler=useThemeHandler(),activeThemeKey=_useThemeHandler.activeThemeKey,setActiveThemeKey=_useThemeHandler.setActiveThemeKey,themes=_useThemeHandler.themes,onChangeTheme=_useThemeHandler.onChangeTheme;var options=pipe(mergeDeepRight(DEFAULT_THEMES),mapObjIndexed(function(obj,key){return Object.assign({},obj,{value:key,key:key});}),values,filter(function(item){if(item.value==='_all')return false;if(onlyKeys&&onlyKeys.includes(item.value))return true;if(hideKeys&&hideKeys.includes(item.value))return false;return true;}))(themes);return _jsx(Picker,{colSpan:12,gap:"lg",value:activeThemeKey,onChange:function onChange(key){setActiveThemeKey(key);onChangeTheme==null?void 0:onChangeTheme(key);_onChange==null?void 0:_onChange(key);},options:options,renderOption:function renderOption(_ref2){var option=_ref2.option,selected=_ref2.selected,onChange=_ref2.onChange;return _jsxs(Link,{onPress:onChange,gap:"xs",children:[_jsx(ThemeThumb,{value:option.value}),_jsx(IconLabel,{center:true,label:option.label,icon:selected&&'checkbox-circle-fill',color:selected?'primary':'text3',strong:true})]});}});}
1
+ var _jsxFileName="/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/components/theme/ThemePicker.js";import{mapObjIndexed,mergeDeepRight,values,pipe,filter}from'ramda';import{DEFAULT_THEMES,useThemeHandler}from"../../theme";import{IconLabel}from"../presentation";import{Link}from"../actions";import{Picker}from"../inputs";import{ThemeThumb}from"./ThemeThumb";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export function ThemePicker(_ref){var _this=this;var _onChange=_ref.onChange,onlyKeys=_ref.onlyKeys,hideKeys=_ref.hideKeys;var _useThemeHandler=useThemeHandler(),activeThemeKey=_useThemeHandler.activeThemeKey,themes=_useThemeHandler.themes,onChangeTheme=_useThemeHandler.onChangeTheme;var options=pipe(mergeDeepRight(DEFAULT_THEMES),mapObjIndexed(function(obj,key){return Object.assign({},obj,{value:key,key:key});}),values,filter(function(item){if(item.value==='_all')return false;if(onlyKeys&&onlyKeys.includes(item.value))return true;if(hideKeys&&hideKeys.includes(item.value))return false;return true;}))(themes);return _jsx(Picker,{colSpan:12,gap:"lg",value:activeThemeKey,onChange:function onChange(key){onChangeTheme==null?void 0:onChangeTheme(key);_onChange==null?void 0:_onChange(key);},options:options,renderOption:function renderOption(_ref2){var option=_ref2.option,selected=_ref2.selected,onChange=_ref2.onChange;return _jsxs(Link,{onPress:onChange,gap:"xs",children:[_jsx(ThemeThumb,{value:option.value}),_jsx(IconLabel,{center:true,label:option.label,icon:selected&&'checkbox-circle-fill',color:selected?'primary':'text3',strong:true})]});}});}
@@ -1 +1 @@
1
- export*from"./debounce";export*from"./string";export*from"./random";export*from"./storage";
1
+ export*from"./debounce";export*from"./string";export*from"./random";export*from"./storage";export*from"./../abstractions/helpers/useSafeAreaInsets";
@@ -1 +1 @@
1
- import _slicedToArray from"@babel/runtime/helpers/slicedToArray";import React from'react';import{AbsStorage}from"../abstractions/helpers/storage";function set(key,value){return AbsStorage.set(key,JSON.stringify(value));}function setAsync(key,value){return AbsStorage.setAsync(key,JSON.stringify(value));}function get(key){var value=AbsStorage.get(key);return formatStoragedValue(value);}function getAsync(key){return AbsStorage.setAsync(key).then(function(value){return formatStoragedValue(value);});}function formatStoragedValue(value){try{if(!value)return value;value=JSON.parse(value);if(value==='undefined')return undefined;if(value==='null')return undefined;return value;}catch(e){return value;}}function useState(key,defaultValue){var _React$useState=React.useState(get(key)||defaultValue),_React$useState2=_slicedToArray(_React$useState,2),value=_React$useState2[0],setValue=_React$useState2[1];var handleChange=function handleChange(newValue){set(key,newValue);setValue(newValue);};return[value,handleChange];}export var Storage=Object.assign({},AbsStorage,{set:set,setAsync:setAsync,get:get,getAsync:getAsync,useState:useState});
1
+ import _slicedToArray from"@babel/runtime/helpers/slicedToArray";import React from'react';import{AbsStorage}from"../abstractions/helpers/storage";var listeners={};function notify(key,value){if(listeners[key]){listeners[key].forEach(function(cb){return cb(value);});}}function subscribe(key,cb){if(!listeners[key])listeners[key]=[];listeners[key].push(cb);return function(){listeners[key]=listeners[key].filter(function(fn){return fn!==cb;});};}function set(key,value){AbsStorage.set(key,JSON.stringify(value));notify(key,value);}function setAsync(key,value){return AbsStorage.setAsync(key,JSON.stringify(value)).then(function(){notify(key,value);});}function get(key,defaultValue){var _formatStoragedValue;var value=AbsStorage.get(key);return(_formatStoragedValue=formatStoragedValue(value))!=null?_formatStoragedValue:defaultValue;}function getAsync(key,defaultValue){return AbsStorage.getAsync(key).then(function(value){var _formatStoragedValue2;return(_formatStoragedValue2=formatStoragedValue(value))!=null?_formatStoragedValue2:defaultValue;});}function formatStoragedValue(value){try{if(!value)return value;value=JSON.parse(value);if(value==='undefined')return undefined;if(value==='null')return undefined;return value;}catch(e){return value;}}function useState(key,defaultValue){var _React$useState=React.useState(function(){var _get;return(_get=get(key))!=null?_get:defaultValue;}),_React$useState2=_slicedToArray(_React$useState,2),value=_React$useState2[0],setValue=_React$useState2[1];React.useEffect(function(){return subscribe(key,setValue);},[key]);var handleChange=function handleChange(newValue){set(key,newValue);};return[value,handleChange];}export var Storage=Object.assign({},AbsStorage,{set:set,setAsync:setAsync,get:get,getAsync:getAsync,useState:useState});
@@ -1 +1 @@
1
- import _toConsumableArray from"@babel/runtime/helpers/toConsumableArray";import{is}from'ramda';import React from'react';import{Platform}from"../abstractions/Platform";import{useBreakpoints}from"../theme/ThemeHandler";import{useResponsive}from"../responsive/ResponsiveHandler";export function useGetResponsiveValue(){var breakpoints=useBreakpoints();var _useResponsive=useResponsive(),width=_useResponsive.width,screen=_useResponsive.screen;return React.useCallback(function(value){var isNative=(value==null?void 0:value.native)!==undefined&&Platform.OS!=='web';if(isNative)return value==null?void 0:value.native;var isWeb=(value==null?void 0:value.web)!==undefined&&Platform.OS==='web';if(isWeb)return value==null?void 0:value.web;var isObj=is(Object,value);if(!isObj)return value;if(value[screen])return value[screen];var keys=Object.keys(value);var _loop=function _loop(){var match=k.match(/^(\w+)([du])$/);if(!match)return 0;var bpName=match[1];var mode=match[2];var bpIndex=breakpoints.findIndex(function(b){return b.name===bpName;});if(bpIndex===-1)return 0;if(mode==='u'){var lowerBound=bpIndex>0?breakpoints[bpIndex-1].value:0;if(width>=lowerBound)return{v:value[k]};}if(mode==='d'){if(width<breakpoints[bpIndex].value)return{v:value[k]};}},_ret;for(var k of keys){_ret=_loop();if(_ret===0)continue;if(_ret)return _ret.v;}return value==null?void 0:value.df;},[screen]);}export function useResponsiveValue(value){var getValue=useGetResponsiveValue();var isObj=is(Object,value);var valueWatch=isObj?Object.keys(value).map(function(k){return`${k}:${value[k]}`;}):[value];return React.useMemo(function(){return getValue(value);},[getValue].concat(_toConsumableArray(valueWatch)));}
1
+ import _toConsumableArray from"@babel/runtime/helpers/toConsumableArray";import{is}from'ramda';import React from'react';import{Platform}from"../abstractions/Platform";import{useBreakpoints}from"../theme/ThemeHandler";import{useResponsive}from"../responsive/ResponsiveHandler";export function useGetResponsiveValue(){var breakpoints=useBreakpoints();var _useResponsive=useResponsive(),width=_useResponsive.width,screen=_useResponsive.screen;return React.useCallback(function(value){var isNative=(value==null?void 0:value.native)!==undefined&&Platform.OS!=='web';if(isNative)return value==null?void 0:value.native;var isWeb=(value==null?void 0:value.web)!==undefined&&Platform.OS==='web';if(isWeb)return value==null?void 0:value.web;var isIOS=(value==null?void 0:value.ios)!==undefined&&Platform.OS==='ios';if(isIOS)return value==null?void 0:value.ios;var isAndroid=(value==null?void 0:value.android)!==undefined&&Platform.OS==='android';if(isAndroid)return value==null?void 0:value.android;var isObj=is(Object,value);if(!isObj)return value;if(value[screen])return value[screen];var keys=Object.keys(value);var _loop=function _loop(){var match=k.match(/^(\w+)([du])$/);if(!match)return 0;var bpName=match[1];var mode=match[2];var bpIndex=breakpoints.findIndex(function(b){return b.name===bpName;});if(bpIndex===-1)return 0;if(mode==='u'){var lowerBound=bpIndex>0?breakpoints[bpIndex-1].value:0;if(width>=lowerBound)return{v:value[k]};}if(mode==='d'){if(width<breakpoints[bpIndex].value)return{v:value[k]};}},_ret;for(var k of keys){_ret=_loop();if(_ret===0)continue;if(_ret)return _ret.v;}return value==null?void 0:value.df;},[screen]);}export function useResponsiveValue(value){var getValue=useGetResponsiveValue();var isObj=is(Object,value);var valueWatch=isObj?Object.keys(value).map(function(k){return`${k}:${value[k]}`;}):[value];return React.useMemo(function(){return getValue(value);},[getValue].concat(_toConsumableArray(valueWatch)));}
@@ -1 +1 @@
1
- import _slicedToArray from"@babel/runtime/helpers/slicedToArray";var _jsxFileName="/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/theme/ThemeHandler.js";import{mergeDeepRight}from'ramda';import React from'react';import{DEFAULT_LIGHT_THEME}from"./default/lightTheme";import{getThemeValue}from"./helpers/relatedScales";import{useFormattedTheme}from"./format/formatTheme";import{jsx as _jsx}from"react/jsx-runtime";var DEFAULT_BREAKPOINTS=[{name:'sm',value:768},{name:'md',value:1024},{name:'lg',value:1440},{name:'xl',value:10000}];var ThemeContext=React.createContext(null);export var useThemeHandler=function useThemeHandler(){return React.useContext(ThemeContext)||{};};export var useBreakpoints=function useBreakpoints(){var _useThemeHandler;return((_useThemeHandler=useThemeHandler())==null?void 0:_useThemeHandler.breakpoints)||DEFAULT_BREAKPOINTS;};export var useTheme=function useTheme(groupKey){var theme=useThemeHandler().theme||DEFAULT_LIGHT_THEME;if(!groupKey)return theme;return(theme==null?void 0:theme[groupKey])||{};};export var useGetThemeValue=function useGetThemeValue(groupKey){var group=useTheme(groupKey);return function(key){return getThemeValue(group,key);};};export var useColors=function useColors(){return useTheme('colors');};export var useGetColor=function useGetColor(){return useGetThemeValue('colors');};export var useSpaces=function useSpaces(){return useTheme('spaces');};export var useGetSpace=function useGetSpace(){return useGetThemeValue('spaces');};export var useRadius=function useRadius(){return useTheme('radius');};export var useGetRadius=function useGetRadius(){return useGetThemeValue('radius');};export var useElementHeights=function useElementHeights(){return useTheme('elementHeights');};export var useGetElementHeight=function useGetElementHeight(){return useGetThemeValue('elementHeights');};export var useTexts=function useTexts(){return useTheme('texts');};export var useGetText=function useGetText(){return useGetThemeValue('text');};export var useThemeComponents=function useThemeComponents(){return useTheme('components');};export function useThemeComponent(name){var components=useThemeComponents();return components[name]||{};}export function useMergeThemeComponent(name,props){var themeProps=useThemeComponent(name);return mergeDeepRight(themeProps,props);}export function ThemeHandler(_ref){var breakpoints=_ref.breakpoints,themes=_ref.themes,initTheme=_ref.initTheme,onChangeTheme=_ref.onChangeTheme,children=_ref.children;var _React$useState=React.useState(false),_React$useState2=_slicedToArray(_React$useState,2),themePickerOpen=_React$useState2[0],setThemePickerOpen=_React$useState2[1];var openThemePicker=function openThemePicker(){return setThemePickerOpen(true);};var _React$useState3=React.useState(initTheme||'light'),_React$useState4=_slicedToArray(_React$useState3,2),activeThemeKey=_React$useState4[0],setActiveThemeKey=_React$useState4[1];var toggleTheme=function toggleTheme(){return setActiveThemeKey(activeThemeKey==='light'?'dark':'light');};var theme=useFormattedTheme(themes,activeThemeKey);var value={theme:theme,themes:themes,activeThemeKey:activeThemeKey,setActiveThemeKey:setActiveThemeKey,toggleTheme:toggleTheme,themePickerOpen:themePickerOpen,setThemePickerOpen:setThemePickerOpen,onChangeTheme:onChangeTheme,openThemePicker:openThemePicker,toggleTheme:toggleTheme,breakpoints:breakpoints||DEFAULT_BREAKPOINTS};return _jsx(ThemeContext.Provider,{value:value,children:children});}
1
+ import _slicedToArray from"@babel/runtime/helpers/slicedToArray";var _jsxFileName="/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/theme/ThemeHandler.js";import{mergeDeepRight}from'ramda';import React from'react';import{DEFAULT_LIGHT_THEME}from"./default/lightTheme";import{getThemeValue}from"./helpers/relatedScales";import{useFormattedTheme}from"./format/formatTheme";import{jsx as _jsx}from"react/jsx-runtime";var DEFAULT_BREAKPOINTS=[{name:'sm',value:768},{name:'md',value:1024},{name:'lg',value:1440},{name:'xl',value:10000}];var ThemeContext=React.createContext(null);export var useThemeHandler=function useThemeHandler(){return React.useContext(ThemeContext)||{};};export var useBreakpoints=function useBreakpoints(){var _useThemeHandler;return((_useThemeHandler=useThemeHandler())==null?void 0:_useThemeHandler.breakpoints)||DEFAULT_BREAKPOINTS;};export var useTheme=function useTheme(groupKey){var theme=useThemeHandler().theme||DEFAULT_LIGHT_THEME;if(!groupKey)return theme;return(theme==null?void 0:theme[groupKey])||{};};export var useGetThemeValue=function useGetThemeValue(groupKey){var group=useTheme(groupKey);return function(key){return getThemeValue(group,key);};};export var useColors=function useColors(){return useTheme('colors');};export var useGetColor=function useGetColor(){return useGetThemeValue('colors');};export var useSpaces=function useSpaces(){return useTheme('spaces');};export var useGetSpace=function useGetSpace(){return useGetThemeValue('spaces');};export var useRadius=function useRadius(){return useTheme('radius');};export var useGetRadius=function useGetRadius(){return useGetThemeValue('radius');};export var useElementHeights=function useElementHeights(){return useTheme('elementHeights');};export var useGetElementHeight=function useGetElementHeight(){return useGetThemeValue('elementHeights');};export var useTexts=function useTexts(){return useTheme('texts');};export var useGetText=function useGetText(){return useGetThemeValue('text');};export var useThemeComponents=function useThemeComponents(){return useTheme('components');};export function useThemeComponent(name){var components=useThemeComponents();return components[name]||{};}export function useMergeThemeComponent(name,props){var themeProps=useThemeComponent(name);return mergeDeepRight(themeProps,props);}export function ThemeHandler(_ref){var breakpoints=_ref.breakpoints,themes=_ref.themes,initTheme=_ref.initTheme,onChangeTheme=_ref.onChangeTheme,children=_ref.children;var _React$useState=React.useState(false),_React$useState2=_slicedToArray(_React$useState,2),themePickerOpen=_React$useState2[0],setThemePickerOpen=_React$useState2[1];var openThemePicker=function openThemePicker(){return setThemePickerOpen(true);};var _React$useState3=React.useState(initTheme||'light'),_React$useState4=_slicedToArray(_React$useState3,2),activeThemeKey=_React$useState4[0],setActiveThemeKey=_React$useState4[1];var handleChangeTheme=function handleChangeTheme(key){setActiveThemeKey(key);onChangeTheme==null?void 0:onChangeTheme(key);};var toggleTheme=function toggleTheme(){return handleChangeTheme(activeThemeKey==='light'?'dark':'light');};var theme=useFormattedTheme(themes,activeThemeKey);var value={theme:theme,themes:themes,activeThemeKey:activeThemeKey,toggleTheme:toggleTheme,themePickerOpen:themePickerOpen,setThemePickerOpen:setThemePickerOpen,onChangeTheme:handleChangeTheme,openThemePicker:openThemePicker,toggleTheme:toggleTheme,breakpoints:breakpoints||DEFAULT_BREAKPOINTS};return _jsx(ThemeContext.Provider,{value:value,children:children});}
@@ -1 +1 @@
1
- export var BASE_THEME={spaces:{xxxs:1,xxs:3,xs:5,sm:10,md:15,lg:20,xl:30,xxl:40,xxxl:50},radius:{xxxs:4,xxs:5,xs:5,sm:7,md:8,lg:10,xl:12,xxl:15,xxxl:18},icons:{xxxs:10,xxs:12,xs:14,sm:16,md:18,lg:22,xl:26,xxl:28,xxxl:32},elementHeights:{xxxs:10,xxs:15,xs:20,sm:30,md:35,lg:40,xl:50,xxl:60,xxxl:70},texts:{h1:{fontSize:35,strong:true},h2:{fontSize:28,strong:true},h3:{fontSize:26,strong:true},h4:{fontSize:22,strong:true},h5:{fontSize:18,strong:true},h6:{fontSize:16,strong:true},p:{fontSize:14},sm:{fontSize:12},xs:{fontSize:10},xxs:{fontSize:8}}};
1
+ export var BASE_THEME={spaces:{xxxs:1,xxs:3,xs:5,sm:10,md:15,lg:20,xl:30,xxl:40,xxxl:50},radius:{xxxs:4,xxs:5,xs:5,sm:7,md:8,lg:10,xl:12,xxl:15,xxxl:18},icons:{xxxs:10,xxs:12,xs:14,sm:16,md:18,lg:22,xl:26,xxl:28,xxxl:32},elementHeights:{xxxs:10,xxs:15,xs:25,sm:35,md:40,lg:45,xl:50,xxl:60,xxxl:70},texts:{h1:{fontSize:35,strong:true},h2:{fontSize:28,strong:true},h3:{fontSize:26,strong:true},h4:{fontSize:22,strong:true},h5:{fontSize:18,strong:true},h6:{fontSize:16,strong:true},p:{fontSize:14},sm:{fontSize:12},xs:{fontSize:10},xxs:{fontSize:8}}};
@@ -1 +1 @@
1
- import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_BLACK_THEME=mergeDeepRight(BASE_THEME,{label:'Pitch Black',colors:{primary:'#818DF9',text:'#FFFFFF',text2:'#E0E0E0',text3:'#B0B0B0',text4:'#8A8A8A',mainBG:'#0f0f0f',overlayBG:'#000000',backdrop:'#1f1f1f',shadow:'rgba(216, 210, 203, 0.1)',divider:'#383E44',blue:'#4DA3FF',yellow:'#FFD93B',green:'#4CAF50',purple:'#9B59B6',orange:'#FF7F50',cyan:'#00BCD4',red:'#E74C3C',navy:'#34495E',indigo:'#5C6BC0',gray:'#9E9E9E',brown:'#8D6E63',lylac:'#B39DDB',pink:'#F48FB1'}});
1
+ import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_BLACK_THEME=mergeDeepRight(BASE_THEME,{label:'Pitch Black',colors:{primary:'#818DF9',text:'#FFFFFF',text2:'#E0E0E0',text3:'#B0B0B0',text4:'#8A8A8A',mainBG:'#0f0f0f',overlayBG:'#000000',backdrop:'#1f1f1f',shadow:'rgba(216, 210, 203, 0.1)',transparent:'rgba(0, 0, 0, 0)',divider:'#383E44',blue:'#4DA3FF',yellow:'#FFD93B',green:'#4CAF50',purple:'#9B59B6',orange:'#FF7F50',cyan:'#00BCD4',red:'#E74C3C',navy:'#34495E',indigo:'#5C6BC0',gray:'#9E9E9E',brown:'#8D6E63',lylac:'#B39DDB',pink:'#F48FB1'}});
@@ -1 +1 @@
1
- import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var CYBERPUNK_DARK_THEME=mergeDeepRight(BASE_THEME,{label:'Cyberpunk',colors:{primary:'#FCEE09',text:'#FFFFFF',text2:'#B3B3B3',text3:'#8C8C8C',text4:'#666666',mainBG:'#14141F',overlayBG:'#14141F',backdrop:'#0A0A0F',shadow:'rgba(39, 45, 52, 0.6)',divider:'rgba(255,255,255, 0.2)',blue:'#00E5FF',yellow:'#FFD600',green:'#00FF9D',purple:'#D500F9',orange:'#FF9100',cyan:'#00B8D4',red:'#FF1744',navy:'#1E2A38',indigo:'#651FFF',gray:'#757575',brown:'#6D4C41',lylac:'#B388FF',pink:'#FF80AB'}});
1
+ import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var CYBERPUNK_DARK_THEME=mergeDeepRight(BASE_THEME,{label:'Cyberpunk',colors:{primary:'#FCEE09',text:'#FFFFFF',text2:'#B3B3B3',text3:'#8C8C8C',text4:'#666666',mainBG:'#14141F',overlayBG:'#14141F',backdrop:'#0A0A0F',shadow:'rgba(39, 45, 52, 0.6)',divider:'rgba(255,255,255, 0.2)',blue:'#00E5FF',yellow:'#FFD600',green:'#00FF9D',purple:'#D500F9',orange:'#FF9100',cyan:'#00B8D4',red:'#FF1744',navy:'#1E2A38',indigo:'#651FFF',gray:'#757575',brown:'#6D4C41',lylac:'#B388FF',pink:'#FF80AB'},components:{Card:{border:true},Section:{border:true}}});
@@ -1 +1 @@
1
- import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_DARK_THEME=mergeDeepRight(BASE_THEME,{label:'Dark',colors:{primary:'#818DF9',text:'#FFFFFF',text2:'#E0E0E0',text3:'#B0B0B0',text4:'#8A8A8A',mainBG:'#383E44',overlayBG:'#272D34',backdrop:'#383E44',shadow:'rgba(216, 210, 203, 0.1)',divider:'#383E44',blue:'#4DA3FF',yellow:'#FFD93B',green:'#4CAF50',purple:'#9B59B6',orange:'#FF7F50',cyan:'#00BCD4',red:'#E74C3C',navy:'#34495E',indigo:'#5C6BC0',gray:'#9E9E9E',brown:'#8D6E63',lylac:'#B39DDB',pink:'#F48FB1'}});
1
+ import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_DARK_THEME=mergeDeepRight(BASE_THEME,{label:'Dark',colors:{primary:'#818DF9',text:'#FFFFFF',text2:'#E0E0E0',text3:'#B0B0B0',text4:'#8A8A8A',mainBG:'#383E44',overlayBG:'#272D34',backdrop:'#383E44',shadow:'rgba(216, 210, 203, 0.1)',transparent:'rgba(0, 0, 0, 0)',divider:'#383E44',blue:'#4DA3FF',yellow:'#FFD93B',green:'#4CAF50',purple:'#9B59B6',orange:'#FF7F50',cyan:'#00BCD4',red:'#E74C3C',navy:'#34495E',indigo:'#5C6BC0',gray:'#9E9E9E',brown:'#8D6E63',lylac:'#B39DDB',pink:'#F48FB1'}});
@@ -1 +1 @@
1
- import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_MATRIX_THEME=mergeDeepRight(BASE_THEME,{label:'Hacker',colors:{primary:'#00FF41',text:'#00FF41',text2:'#00CC33',text3:'#009926',text4:'#00661A',mainBG:'#000000',overlayBG:'#0A0A0A',backdrop:'#000000',shadow:'rgba(0, 255, 65, 0.2)',divider:'rgba(0,255,65, 0.3)',blue:'#0087BD',yellow:'#AEBF00',green:'#00FF41',purple:'#7A1FA2',orange:'#FF6D00',cyan:'#00BFA5',red:'#D50000',navy:'#003366',indigo:'#303F9F',gray:'#4A4A4A',brown:'#5D4037',lylac:'#8E24AA',pink:'#C51162'},components:{Card:{border:1,br:5,borderColor:'divider'}}});
1
+ import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_MATRIX_THEME=mergeDeepRight(BASE_THEME,{label:'Hacker',colors:{primary:'#00FF41',text:'#00FF41',text2:'#00CC33',text3:'#009926',text4:'#00661A',mainBG:'#000000',overlayBG:'#0A0A0A',backdrop:'#000000',shadow:'rgba(0, 255, 65, 0.2)',divider:'rgba(0,255,65, 0.3)',blue:'#0087BD',yellow:'#AEBF00',green:'#00FF41',purple:'#7A1FA2',orange:'#FF6D00',cyan:'#00BFA5',red:'#D50000',navy:'#003366',indigo:'#303F9F',gray:'#4A4A4A',brown:'#5D4037',lylac:'#8E24AA',pink:'#C51162'},radius:{xxxs:0,xxs:1,xs:2,sm:3,md:4,lg:5,xl:6,xxl:7,xxxl:8},components:{Card:{border:true},Section:{border:true}}});
@@ -1 +1 @@
1
- import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_LIGHT_THEME=mergeDeepRight(BASE_THEME,{label:'Light',colors:{primary:'#818DF9',text:'#272D34',text2:'#4A5159',text3:'#6E7680',text4:'#9AA1AC',mainBG:'#F4F5FE',overlayBG:'#FFFFFF',backdrop:'#383E44',shadow:'rgba(39, 45, 52, 0.15)',divider:'#e0e0e0',blue:'#4DA3FF',yellow:'#FFD93B',green:'#4CAF50',purple:'#9B59B6',orange:'#FF7F50',cyan:'#00BCD4',red:'#E74C3C',navy:'#34495E',indigo:'#5C6BC0',gray:'#B0BEC5',brown:'#8D6E63',lylac:'#B39DDB',pink:'#F48FB1'}});
1
+ import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_LIGHT_THEME=mergeDeepRight(BASE_THEME,{label:'Light',colors:{primary:'#818DF9',text:'#272D34',text2:'#4A5159',text3:'#6E7680',text4:'#9AA1AC',mainBG:'#F4F5FE',overlayBG:'#FFFFFF',backdrop:'#383E44',shadow:'rgba(39, 45, 52, 0.15)',transparent:'rgba(255, 255, 255, 0)',divider:'#e0e0e0',blue:'#4DA3FF',yellow:'#FFD93B',green:'#4CAF50',purple:'#9B59B6',orange:'#FF7F50',cyan:'#00BCD4',red:'#E74C3C',navy:'#34495E',indigo:'#5C6BC0',gray:'#B0BEC5',brown:'#8D6E63',lylac:'#B39DDB',pink:'#F48FB1'}});
@@ -1 +1 @@
1
- import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_MSDOS_THEME=mergeDeepRight(BASE_THEME,{label:'MSDOS',colors:{primary:'#FFFF00',text:'#FFFFFF',text2:'#E0E0E0',text3:'#B0B0B0',text4:'#8A8A8A',mainBG:'#0000AA',overlayBG:'#000088',backdrop:'#0000AA',shadow:'rgba(0, 0, 0, 0.6)',divider:'rgba(255,255,255,0.3)',blue:'#0000FF',yellow:'#FFFF00',green:'#00FF00',purple:'#AA00FF',orange:'#FF7700',cyan:'#00FFFF',red:'#FF0000',navy:'#000080',indigo:'#4B0082',gray:'#B0B0B0',brown:'#8B4513',lylac:'#9370DB',pink:'#FF69B4'},radius:{xxxs:1,xxs:2,xs:3,sm:4,md:6,lg:8,xl:10,xxl:12,xxxl:14},components:{Card:{border:1,br:5,borderColor:'divider'}}});
1
+ import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_MSDOS_THEME=mergeDeepRight(BASE_THEME,{label:'MSDOS',colors:{primary:'#FFFF00',text:'#FFFFFF',text2:'#E0E0E0',text3:'#B0B0B0',text4:'#8A8A8A',mainBG:'#0000AA',overlayBG:'#000088',backdrop:'#0000AA',shadow:'rgba(0, 0, 0, 0.6)',divider:'rgba(255,255,255,0.3)',blue:'#0000FF',yellow:'#FFFF00',green:'#00FF00',purple:'#AA00FF',orange:'#FF7700',cyan:'#00FFFF',red:'#FF0000',navy:'#000080',indigo:'#4B0082',gray:'#B0B0B0',brown:'#8B4513',lylac:'#9370DB',pink:'#FF69B4'},radius:{xxxs:0,xxs:1,xs:2,sm:3,md:4,lg:5,xl:6,xxl:7,xxxl:8},components:{Card:{border:1,borderColor:'divider'}}});
@@ -1 +1 @@
1
- import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_PAPER_THEME=mergeDeepRight(BASE_THEME,{label:'Paper',colors:{primary:'#5A5A5A',text:'#000000',text2:'#333333',text3:'#555555',text4:'#777777',mainBG:'#F8F1E3',overlayBG:'#F8F1E3',backdrop:'#383E44',shadow:'rgba(0, 0, 0, 0.04)',divider:'#E3D9C9',blue:'#6B8EAE',yellow:'#EADCA6',green:'#88A288',purple:'#A391B8',orange:'#D9A066',cyan:'#9CC9C2',red:'#B85C5C',navy:'#4A4A4A',indigo:'#70788C',gray:'#B8B8B8',brown:'#8B7355',lylac:'#C7B7D4',pink:'#E4A1B2'}});
1
+ import{mergeDeepRight}from'ramda';import{BASE_THEME}from"./base";export var DEFAULT_PAPER_THEME=mergeDeepRight(BASE_THEME,{label:'Paper',colors:{primary:'#5A5A5A',text:'#000000',text2:'#333333',text3:'#555555',text4:'#777777',mainBG:'#F8F1E3',overlayBG:'#F8F1E3',backdrop:'#383E44',shadow:'rgba(0, 0, 0, 0.04)',divider:'#E3D9C9',blue:'#6B8EAE',yellow:'#EADCA6',green:'#88A288',purple:'#A391B8',orange:'#D9A066',cyan:'#9CC9C2',red:'#B85C5C',navy:'#4A4A4A',indigo:'#70788C',gray:'#B8B8B8',brown:'#8B7355',lylac:'#C7B7D4',pink:'#E4A1B2'},components:{Card:{border:true},Section:{border:true}}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neko-os/ui",
3
- "version": "0.0.13",
3
+ "version": "0.1.0",
4
4
  "author": "Christian Storch <ccstorch@gmail.com>",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -0,0 +1,3 @@
1
+ import { AbsView } from './View'
2
+
3
+ export const AbsKeyboardAvoidingView = AbsView
@@ -0,0 +1,3 @@
1
+ import { KeyboardAvoidingView } from 'react-native'
2
+
3
+ export const AbsKeyboardAvoidingView = KeyboardAvoidingView
@@ -0,0 +1,68 @@
1
+ import { pipe } from 'ramda'
2
+
3
+ import { BottomDrawer, TopBar, View } from '../structure'
4
+ import { DrawerScrollView } from '../structure/bottomDrawer'
5
+ import { Menu } from './menu/Menu'
6
+ import { Section } from '../sections'
7
+ import { useDefaultModifier } from '../../modifiers/default'
8
+ import { useThemeComponentModifier } from '../../modifiers/themeComponent'
9
+
10
+ const DEFAULT_PROPS = {
11
+ useSafeArea: false,
12
+ bg: 'mainBG',
13
+ topBarProps: {
14
+ useSafeArea: false,
15
+ },
16
+ menuProps: {
17
+ vertical: true,
18
+ linkPaddingH: 'md',
19
+ linkMinHeight: 'xl',
20
+ withDivider: true,
21
+ },
22
+ }
23
+
24
+ function Content({ items, title, subtitle, onClose, onChange, topBarProps, menuProps }) {
25
+ const handleChange = (...params) => {
26
+ onChange?.(...params)
27
+ onClose()
28
+ }
29
+
30
+ return (
31
+ <>
32
+ <TopBar title={title} subtitle={subtitle} {...topBarProps} />
33
+
34
+ <View flex>
35
+ <DrawerScrollView>
36
+ {!title && <View paddingT="md" />}
37
+ <Section>
38
+ <Menu items={items} onChange={handleChange} {...menuProps} />
39
+ </Section>
40
+ <View height={100} />
41
+ </DrawerScrollView>
42
+ </View>
43
+ </>
44
+ )
45
+ }
46
+
47
+ export function ActionsDrawer({ items, onChange, title, subtitle, onClose, ...rootProps }) {
48
+ const [{}, formattedProps] = pipe(
49
+ useThemeComponentModifier('ActionsDrawer'), //
50
+ useDefaultModifier(DEFAULT_PROPS)
51
+ )([{}, rootProps])
52
+
53
+ const { topBarProps, menuProps, ...props } = formattedProps
54
+
55
+ return (
56
+ <BottomDrawer onClose={onClose} {...props}>
57
+ <Content
58
+ onClose={onClose}
59
+ topBarProps={topBarProps}
60
+ menuProps={menuProps}
61
+ title={title}
62
+ subtitle={subtitle}
63
+ onChange={onChange}
64
+ items={items}
65
+ />
66
+ </BottomDrawer>
67
+ )
68
+ }
@@ -54,7 +54,7 @@ export function Button({ children, ...rootProps }) {
54
54
  useBorderModifier
55
55
  )([{}, rootProps])
56
56
 
57
- const { label, icon, textProps, iconProps, gap, invert, size, ...props } = formattedProps
57
+ const { label, icon, textProps, iconProps, gap, invert, size, iconLabelProps, ...props } = formattedProps
58
58
 
59
59
  return (
60
60
  <AbsTouchableOpacity className="neko-button neko-wave-click-effect" type="button" {...props}>
@@ -70,6 +70,7 @@ export function Button({ children, ...rootProps }) {
70
70
  textProps={{ strong: true, ...textProps }}
71
71
  iconProps={iconProps}
72
72
  loading={loading}
73
+ {...iconLabelProps}
73
74
  />
74
75
  )}
75
76
  </AbsTouchableOpacity>
@@ -0,0 +1,39 @@
1
+ import { Icon } from '../presentation'
2
+ import { Link } from './Link'
3
+ import { Text } from '../text'
4
+ import { View } from '../structure'
5
+ import { moveScale } from '../../theme/helpers/sizeScale'
6
+ import { useSafeAreaInsets } from '../../abstractions/helpers/useSafeAreaInsets'
7
+
8
+ export function FloatingMenu({ fixed, onChange, items, activeIndex, size = 'md', WrapperView, ...props }) {
9
+ const insets = useSafeAreaInsets()
10
+ const height = moveScale(size, 2)
11
+
12
+ const bg = !WrapperView ? 'overlayBG' : null
13
+ WrapperView = WrapperView || View
14
+
15
+ return (
16
+ <View absolute={!fixed} fixed={fixed} left="md" right="md" centerH bottom={Math.max(insets.bottom, 16)}>
17
+ <WrapperView height={height} shadow round row paddingH="sm" bg={bg} {...props}>
18
+ {items.map((item, index) => {
19
+ const isActive = index === activeIndex
20
+
21
+ return (
22
+ <Link key={index} onPress={() => onChange(item, index)} center padding="xs" gap={3} width={height} round>
23
+ <Icon
24
+ name={isActive ? item.icon?.replace(/line(?=[^line]*$)/, 'fill') : item.icon}
25
+ size={height}
26
+ color={isActive ? 'primary' : 'text3'}
27
+ />
28
+ {!!item.label && (
29
+ <Text size="xxs" center color={isActive ? 'primary' : 'text3'} strong>
30
+ {item.label}
31
+ </Text>
32
+ )}
33
+ </Link>
34
+ )
35
+ })}
36
+ </WrapperView>
37
+ </View>
38
+ )
39
+ }
@@ -5,3 +5,5 @@ export * from './Pressable'
5
5
  export * from './Dropdown'
6
6
  export * from './Breadcrumb'
7
7
  export * from './menu/Menu'
8
+ export * from './FloatingMenu'
9
+ export * from './ActionsDrawer'
@@ -0,0 +1,10 @@
1
+ import { AnimatedView } from './AnimatedView'
2
+ import { TopBar } from '../structure'
3
+
4
+ export function AnimatedTopBar(props) {
5
+ return (
6
+ <AnimatedView style={{ position: 'absolute', top: 0, left: 0, right: 0, zIndex: 90 }} fade>
7
+ <TopBar {...props} />
8
+ </AnimatedView>
9
+ )
10
+ }
@@ -0,0 +1,34 @@
1
+ import Animated, { useAnimatedStyle, useSharedValue, useAnimatedReaction, withTiming } from 'react-native-reanimated'
2
+
3
+ import { TopBar } from '../structure'
4
+ import { useReanimatedScroll } from './ReanimatedScrollHandler'
5
+ import { useSafeAreaInsets } from '../../abstractions/helpers/useSafeAreaInsets'
6
+
7
+ export function AnimatedTopBar({ showAfter = 90, duration = 300, fade = true, slide, ...props }) {
8
+ const { scrollY } = useReanimatedScroll()
9
+ const { top: safeTop } = useSafeAreaInsets()
10
+
11
+ const visibility = useSharedValue(0)
12
+
13
+ useAnimatedReaction(
14
+ () => scrollY.value >= showAfter - safeTop,
15
+ (shouldShow, prev) => {
16
+ if (shouldShow !== prev) {
17
+ visibility.value = withTiming(shouldShow ? 1 : 0, { duration })
18
+ }
19
+ }
20
+ )
21
+
22
+ const animatedStyle = useAnimatedStyle(() => {
23
+ const style = {}
24
+ if (fade) style.opacity = visibility.value
25
+ if (slide) style.transform = [{ translateY: (1 - visibility.value) * (-50 - safeTop) }]
26
+ return style
27
+ })
28
+
29
+ return (
30
+ <Animated.View style={[{ position: 'absolute', top: 0, left: 0, right: 0, zIndex: 90 }, animatedStyle]}>
31
+ <TopBar {...props} />
32
+ </Animated.View>
33
+ )
34
+ }
@@ -0,0 +1 @@
1
+ export { AnimatedTopBar } from './AnimatedTopBar.native'
@@ -0,0 +1,9 @@
1
+ import { AnimatedView } from './AnimatedView'
2
+
3
+ export function ParallaxHeader({ children, height = 200, ...props }) {
4
+ return (
5
+ <AnimatedView height={height} fade {...props}>
6
+ {children}
7
+ </AnimatedView>
8
+ )
9
+ }
@@ -0,0 +1,32 @@
1
+ import Animated, { useAnimatedStyle, interpolate, Extrapolation } from 'react-native-reanimated'
2
+
3
+ import { useReanimatedScroll } from './ReanimatedScrollHandler'
4
+
5
+ const SCALE_FACTOR = 2
6
+
7
+ export function ParallaxHeader({ children, height = 200, parallaxSpeed = 0.5, disableResistence }) {
8
+ const { scrollY } = useReanimatedScroll()
9
+
10
+ const imageStyle = useAnimatedStyle(() => {
11
+ const scale = scrollY.value < 0 ? 1 + (Math.abs(scrollY.value) / height) * SCALE_FACTOR : 1
12
+ const translateY =
13
+ scrollY.value < 0 ? 0 : interpolate(scrollY.value, [0, height], [0, height * parallaxSpeed], Extrapolation.CLAMP)
14
+ return { transform: [{ translateY }, { scale }] }
15
+ })
16
+
17
+ const containerStyle = useAnimatedStyle(() => {
18
+ let calcHeight = height
19
+ if (disableResistence) calcHeight = scrollY.value < 0 ? height + Math.abs(scrollY.value) : height
20
+ return {
21
+ height: calcHeight,
22
+ overflow: scrollY.value < 0 ? 'visible' : 'hidden',
23
+ zIndex: -1,
24
+ }
25
+ })
26
+
27
+ return (
28
+ <Animated.View style={containerStyle}>
29
+ <Animated.View style={imageStyle}>{children}</Animated.View>
30
+ </Animated.View>
31
+ )
32
+ }
@@ -0,0 +1,32 @@
1
+ import Animated, { useAnimatedStyle, interpolate, Extrapolation } from 'react-native-reanimated'
2
+
3
+ import { useReanimatedScroll } from './ReanimatedScrollHandler'
4
+
5
+ const SCALE_FACTOR = 2
6
+
7
+ export function ParallaxHeader({ children, height = 200, parallaxSpeed = 0.5, disableResistence }) {
8
+ const { scrollY } = useReanimatedScroll()
9
+
10
+ const imageStyle = useAnimatedStyle(() => {
11
+ const scale = scrollY.value < 0 ? 1 + (Math.abs(scrollY.value) / height) * SCALE_FACTOR : 1
12
+ const translateY =
13
+ scrollY.value < 0 ? 0 : interpolate(scrollY.value, [0, height], [0, height * parallaxSpeed], Extrapolation.CLAMP)
14
+ return { transform: [{ translateY }, { scale }] }
15
+ })
16
+
17
+ const containerStyle = useAnimatedStyle(() => {
18
+ let calcHeight = height
19
+ if (disableResistence) calcHeight = scrollY.value < 0 ? height + Math.abs(scrollY.value) : height
20
+ return {
21
+ height: calcHeight,
22
+ overflow: scrollY.value < 0 ? 'visible' : 'hidden',
23
+ zIndex: -1,
24
+ }
25
+ })
26
+
27
+ return (
28
+ <Animated.View style={containerStyle}>
29
+ <Animated.View style={imageStyle}>{children}</Animated.View>
30
+ </Animated.View>
31
+ )
32
+ }
@@ -0,0 +1,8 @@
1
+ export function useReanimatedScroll() {
2
+ if (!context) console.error('useReanimatedScroll its not supported for neko web')
3
+ return null
4
+ }
5
+
6
+ export function ReanimatedScrollHandler({ children }) {
7
+ return children
8
+ }
@@ -0,0 +1,24 @@
1
+ import { createContext, useContext, useMemo } from 'react'
2
+ import { useSharedValue, useAnimatedScrollHandler } from 'react-native-reanimated'
3
+
4
+ const ReanimatedScrollContext = createContext(null)
5
+
6
+ export function useReanimatedScroll() {
7
+ const context = useContext(ReanimatedScrollContext)
8
+ if (!context) throw new Error('useReanimatedScroll must be used within ReanimatedScrollHandler')
9
+ return context
10
+ }
11
+
12
+ export function ReanimatedScrollHandler({ children }) {
13
+ const scrollY = useSharedValue(0)
14
+
15
+ const scrollHandler = useAnimatedScrollHandler({
16
+ onScroll: (event) => {
17
+ scrollY.value = event.contentOffset.y
18
+ },
19
+ })
20
+
21
+ const value = useMemo(() => ({ scrollY, scrollHandler }), [])
22
+
23
+ return <ReanimatedScrollContext.Provider value={value}>{children}</ReanimatedScrollContext.Provider>
24
+ }
@@ -0,0 +1 @@
1
+ export { ReanimatedScrollHandler, useReanimatedScroll } from './ReanimatedScrollHandler.native'
@@ -1,2 +1,5 @@
1
1
  export * from './AnimatedView'
2
2
  export * from './DraggableSlideView'
3
+ export * from './ReanimatedScrollHandler'
4
+ export * from './AnimatedTopBar'
5
+ export * from './ParallaxHeader'
@@ -5,38 +5,75 @@ import { Text } from '../text/Text'
5
5
  import { View } from '../structure/View'
6
6
  import { clearProps } from '../../modifiers/_helpers'
7
7
  import { useFormInstance, useFormState } from './Form'
8
+ import { shouldValidateOn } from './validation'
8
9
 
9
- export function FormItem({ name, label, isAbsolutePath, children, useDefaultValue, ...props }) {
10
+ export function FormItem({
11
+ name,
12
+ label,
13
+ isAbsolutePath,
14
+ children,
15
+ useDefaultValue,
16
+ rules,
17
+ validateTrigger = 'onSubmit',
18
+ ...props
19
+ }) {
10
20
  const form = useFormInstance()
11
21
  const formState = useFormState()
12
22
  const listPath = useRelativePath(name, { isAbsolutePath })
23
+ const listPathStr = listPath.join('$NEKOJOIN$')
13
24
  const [value, setValue] = React.useState(form.getFieldValue(listPath))
14
- const error = form.getError(listPath)
25
+ const [error, setError] = React.useState(form.getError(listPath))
15
26
 
27
+ // Register rules with the form
28
+ React.useEffect(() => {
29
+ return form.registerRules(listPath, rules, validateTrigger)
30
+ }, [listPathStr, JSON.stringify(rules), validateTrigger])
31
+
32
+ // Listen for value changes
16
33
  React.useEffect(() => {
17
34
  return form.registerListener(listPath, (val) => setValue(val))
18
- }, [listPath.join('$NEKOJOIN$')])
35
+ }, [listPathStr])
36
+
37
+ // Listen for error changes
38
+ React.useEffect(() => {
39
+ return form.registerErrorListener(listPath, (err) => setError(err))
40
+ }, [listPathStr])
19
41
 
20
42
  const handleChange = (e) => {
21
43
  const val = e?.target?.value ?? e
22
44
  form.setFieldValue(listPath, val)
45
+
46
+ if (shouldValidateOn('onChange', rules, validateTrigger)) {
47
+ form.validateField(listPath, 'onChange')
48
+ }
49
+ }
50
+
51
+ const handleBlur = (e, originalOnBlur) => {
52
+ if (originalOnBlur) originalOnBlur(e)
53
+
54
+ if (shouldValidateOn('onBlur', rules, validateTrigger)) {
55
+ form.validateField(listPath, 'onBlur')
56
+ }
23
57
  }
24
58
 
25
59
  let valueKey = 'value'
26
60
  if (!!useDefaultValue) valueKey = 'defaultValue'
27
61
 
62
+ const child = typeof children === 'function' ? null : React.Children.only(children)
63
+ const originalOnBlur = child?.props?.onBlur
64
+
28
65
  const childProps = clearProps({
29
66
  [valueKey]: value === undefined ? '' : value,
30
67
  onChange: handleChange,
31
- // loading: formState?.loading === true || undefined,
68
+ onBlur: (e) => handleBlur(e, originalOnBlur),
32
69
  disabled: formState?.disabled === true || undefined,
70
+ error: !!error || undefined,
33
71
  })
34
72
 
35
73
  let content
36
74
  if (typeof children === 'function') {
37
75
  content = children(childProps)
38
76
  } else {
39
- const child = React.Children.only(children)
40
77
  content = React.cloneElement(child, { ...child.props, ...childProps })
41
78
  }
42
79
 
@@ -3,22 +3,32 @@ import React from 'react'
3
3
  import { FormGroup, useRelativePath } from './FormGroup'
4
4
  import { Text } from '../text/Text'
5
5
  import { useFormInstance } from './Form'
6
+ import { shouldValidateOn } from './validation'
6
7
 
7
8
  const FormListContext = React.createContext(null)
8
9
  const useFormList = () => React.useContext(FormListContext)
9
10
 
10
- export function FormList({ name, isAbsolutePath, children }) {
11
+ export function FormList({ name, isAbsolutePath, children, rules, validateTrigger = 'onSubmit' }) {
11
12
  const form = useFormInstance()
12
13
  const listPath = useRelativePath(name, { isAbsolutePath })
13
- // To avoid watch being recalled
14
14
  const listPathStr = listPath.join('$NEKOJOIN$')
15
- const error = form.getError(listPath)
15
+ const [error, setError] = React.useState(form.getError(listPath))
16
16
 
17
17
  // Counter to generate unique keys
18
18
  const keyCounter = React.useRef(0)
19
19
  // Map to track keys by value reference
20
20
  const keysMap = React.useRef(new WeakMap())
21
21
 
22
+ // Register rules with the form
23
+ React.useEffect(() => {
24
+ return form.registerRules(listPath, rules, validateTrigger)
25
+ }, [listPathStr, JSON.stringify(rules), validateTrigger])
26
+
27
+ // Listen for error changes
28
+ React.useEffect(() => {
29
+ return form.registerErrorListener(listPath, (err) => setError(err))
30
+ }, [listPathStr])
31
+
22
32
  const generateFields = (items) => {
23
33
  if (!Array.isArray(items)) return []
24
34
  return items.map((item, index) => {
@@ -47,14 +57,22 @@ export function FormList({ name, isAbsolutePath, children }) {
47
57
  })
48
58
  }, [listPathStr])
49
59
 
60
+ const validateOnChange = () => {
61
+ if (shouldValidateOn('onChange', rules, validateTrigger)) {
62
+ form.validateField(listPath, 'onChange')
63
+ }
64
+ }
65
+
50
66
  const add = (defaultValue = {}) => {
51
67
  const current = form.getFieldValue(listPath) || []
52
68
  form.setFieldValue(listPath, [...current, defaultValue])
69
+ validateOnChange()
53
70
  }
54
71
 
55
72
  const addOn = (index, defaultValue = {}) => {
56
73
  const current = form.getFieldValue(listPath) || []
57
74
  form.setFieldValue(listPath, [...current.slice(0, index), defaultValue, ...current.slice(index)])
75
+ validateOnChange()
58
76
  }
59
77
 
60
78
  const replace = (index, value) => {
@@ -91,6 +109,7 @@ export function FormList({ name, isAbsolutePath, children }) {
91
109
  listPath,
92
110
  current.filter((_, i) => i !== index)
93
111
  )
112
+ validateOnChange()
94
113
  }
95
114
 
96
115
  const actions = React.useMemo(
@@ -102,7 +121,7 @@ export function FormList({ name, isAbsolutePath, children }) {
102
121
  move,
103
122
  duplicate,
104
123
  }),
105
- [listPathStr]
124
+ [listPathStr, rules, validateTrigger]
106
125
  )
107
126
 
108
127
  let content
@@ -1,12 +1,14 @@
1
1
  import { Button } from '../actions/Button'
2
2
  import { useFormInstance, useFormState } from './Form'
3
3
 
4
- export function SubmitButton({ form, disabled, ...props }) {
4
+ export function SubmitButton({ form, disabled, Wrapper, ...props }) {
5
5
  const formState = useFormState()
6
6
  const contextForm = useFormInstance()
7
7
  form = form || contextForm
8
8
  disabled = formState?.disabled || disabled
9
9
 
10
+ Wrapper = Wrapper || Button
11
+
10
12
  const handleSubmit = () => {
11
13
  if (!form) {
12
14
  console.error('No form provided to useWatch. Pass it as params or wrap it inside a <Form> component.')
@@ -16,5 +18,5 @@ export function SubmitButton({ form, disabled, ...props }) {
16
18
  form.handleSubmit()
17
19
  }
18
20
 
19
- return <Button {...props} disabled={disabled} onPress={handleSubmit} />
21
+ return <Wrapper {...props} disabled={disabled} onPress={handleSubmit} />
20
22
  }