diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..f9ea1c1 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "es2017", "stage-2"] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8563206..8e98ced 100644 --- a/.gitignore +++ b/.gitignore @@ -38,5 +38,8 @@ jspm_packages typings/ dist/ +framework7-vue/ +framework7-react/ +kitchen-sink/framework7/ .DS_Store \ No newline at end of file diff --git a/.npmignore b/.npmignore index 3905121..3288771 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,6 @@ .gitignore gulpfile.js +tsconfig.json src/ kitchen-sink/ .vscode/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 0453106..af155fe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,10 @@ "**/.DS_Store": true, "**/typings/": true, "**/dist/": true, - "**/node_modules/": true + "**/node_modules/": true, + "**/framework7-vue/": true, + "**/framework7-react/": true, + "**/framework7/": true }, "typescript.tsdk": "./node_modules/typescript/lib" } \ No newline at end of file diff --git a/LICENSE b/LICENSE index bf25587..8dada3e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,201 @@ -MIT License - -Copyright (c) 2016 Ben Compton - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 1789c12..39df770 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,40 @@ # Framework7 React -**UPDATE**: Work is in progress on [this branch](https://github.com/bencompton/Framework7-react/tree/f7-router) to create an automated process for converting components from [Framework7 Vue](https://github.com/nolimits4web/Framework7-Vue) into React components. Vue 2.0 and React work very similarly, and this automated approach has been working out very well. This means that as new components and bugfixes are added to Framework7 Vue over time, React users will be able to enjoy all of the same goodness. +[Framework7](http://framework7.io) is a JavaScript framework for building iOS and Material web and hybrid apps that are virtually indistinguishable from native apps. Framework7 React brings the attention to detail, ease of use, and great features of Framework7 to React. -Keep an eye on the [kitchen sink](https://bencompton.github.io/framework7-react/reactify-vue/) over the coming weeks as new pages are added and bugs are squashed. Once the kitchen sink is complete and the components are all stable, this new version will be merged to master and published to NPM. At that point, everything currently available in Framework7 Vue should be in Framework7 React as well. +## Getting started -Also in development is in progress on [Framework7 Redux](https://github.com/bencompton/framework7-redux). +``` +npm install framework7-react +``` + + +Official docs are coming soon. For now, check out the [kitchen sink](https://github.com/bencompton/framework7-react/tree/f7-router/kitchen-sink) for an example of how to consume Framework7 React. + +## Usage with Redux + +Firstly, as the author of [Redux points out](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367#.nfg6gm6yl), Redux is not a requirement for building apps with React. In turn, Redux is not a requirement for building apps with Framework7 React—it is designed to be perfectly usable either way. However, as your app grows beyond a certain level of complexity, it is definitely recommended that you consider Redux (or some other state management library like [MobX](https://github.com/mobxjs/mobx)). For more information about using Redux with Framework7 React, have a look at [Framework7 Redux](https://github.com/bencompton/framework7-redux). + +## FAQ + +#### Why does Framework7 React have its own router instead of just using React Router? + +It turned out to be difficult to make the complex iOS page transition animation and page swipe-back functionality play nicely with [React Router](https://github.com/ReactTraining/react-router). While React’s abstracted DOM manipulation works well in most cases, it can actually get in the way when sophisticated animation and complex DOM manipulation are required. In many cases, it is often simpler to just use imperative DOM manipulation code and not even bother trying to coax React into performing such intricate DOM manipulation tasks. As a result, Framework7 React comes with a router that is custom-made to work in harmony with Framework7’s intricate page animation logic. + +#### Can I use React Router with Framework7 React? + +The short answer is yes, but animated page transitions will not work. It is recommended that you instead use the router that is built into Framework7 React. The goal of the built-in router is to provide everything you need and leave no reason to use React Router. The main missing feature right now is support for the HTML5 History API with the browser back button and URL changes driving route changes, but the router is still a work in progress. + +#### Should I use React Native or Framework7 React for my project? + +[React Native](https://facebook.github.io/react-native/) is designed for building native apps with React, and often requires writing Objective C, Swift and Java in addition to JavaScript. On the other hand, Framework7 React is designed for building web apps and hybrid apps (with Apache Cordova, etc.) that are virtually indistinguishable from native apps. The main advantages of Framework7 React are: + +1. Ability to create mobile apps with a web development skill set (HTML, CSS, JavaScript) with no need to write Objective C, Swift or Java +2. Apps that can run on any device with a browser, not just iOS or Android devices +3. Option to install your app from a website or use it directly in a browser instead of installing from an app store + +The main advantage of React Native is of course performance. Framework7 React is very fast, and is a great option in a lot of cases. However, there is no denying that native apps can have superior rendering performance, which is even more noticeable on older, slower devices. If your app has complex screens that must squeeze every last ounce of performance out of every device, but you still want to use React, then it is possible that React Native is a better fit for your project. + +#### I would like to contribute an enhancement or fix to a component, but I don’t see the React component in the code. What gives? + +Given that [Vue](https://vuejs.org) 2.0 and React are incredibly similar, it was decided that Framework7 React would automatically generate its React components from [Framework7 Vue’s](https://github.com/nolimits4web/Framework7-Vue) components. This makes it super easy to keep the two frameworks in sync and ensure that React and Vue users both get access to the same capabilities. In a nutshell, Vue components have `render` methods just like React components do, and just like in React, Vue component render methods call a `createElement` function and return the created elements for the framework to mount in the DOM and reactively update. Therefore, it is relatively simple to leverage the rendering logic in Vue components by substituting React’s createElement function for Vue’s createElement function. That is the basic principle at least. In practice, there is a bit more to it than that. It works surprisingly well, though, and many hours of testing have shown that rendering performance in Framework7 React is more or less equivalent to Framework7 Vue. diff --git a/framework7-custom-build.js b/framework7-custom-build.js index f548e67..183446b 100644 --- a/framework7-custom-build.js +++ b/framework7-custom-build.js @@ -3,7 +3,27 @@ var fw7ModulesConfig = require('framework7/modules.json'); //Include any component you wish to use in the app from Framework7. //Listing of components can be found here...http://framework7.io/docs/custom-build.html. -var fw7ModulesBeingUsed = ['fast-clicks', 'modals']; +var fw7ModulesBeingUsed = [ + 'accordion', + 'cards', + 'fast-clicks', + 'forms', + 'infinite-scroll', + 'messages', + 'modals', + 'photo-browser', + 'picker', + 'pull-to-refresh', + 'push-state', + 'searchbar', + 'scroll-toolbars', + 'smart-select', + 'sortable', + 'swipeout', + 'swiper', + 'tabs', + 'virtual-list' +]; //Prefix framework7 file paths with base path because their files are listed as paths relative to the node module. //For example: 'src/js/f7-intro.js'...needs to be node_modules/framework7/src/js/f7-intro.js instead so our build process will know where to find the files. @@ -67,7 +87,7 @@ function getAllFw7ModulesAndDependenciesBeingUsed() { function getFw7CustomDependencies() { var fw7CustomDependencies = []; - for (i = 0; i < fw7ModulesBeingUsed.length; i++) { + for (let i = 0; i < fw7ModulesBeingUsed.length; i++) { var module = fw7ModulesConfig[fw7ModulesBeingUsed[i]]; fw7CustomDependencies.push.apply(fw7CustomDependencies, module.dependencies); diff --git a/framework7-react-component-gen.js b/framework7-react-component-gen.js new file mode 100644 index 0000000..6244352 --- /dev/null +++ b/framework7-react-component-gen.js @@ -0,0 +1,327 @@ +import {stringify} from 'json-fn'; +import {readFileSync, writeFileSync} from 'fs'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as to from 'to-case'; +import * as babel from 'babel-core'; + +const ensureDirectoryExistence = (filePath) => { + var dirname = path.dirname(filePath); + + if (fs.existsSync(dirname)) { + return true; + } + + ensureDirectoryExistence(dirname); + + fs.mkdirSync(dirname); +}; + +const generateImportString = (componentToImport, path) => { + return `import {${componentToImport}} from '${path}';` +}; + +const getPropType = (propValue) => { + let propType = propValue.type || propValue; + + if (Array.isArray(propType)) { + return propType.reduce((typesArray, nextType) => { + return [ + ...typesArray, + getPropType(nextType) + ] + }, []).join(' | '); + } else { + switch(propType) { + case Boolean: + return 'boolean'; + case Number: + return 'number'; + case String: + return 'string'; + case Object: + return 'Object'; + case Function: + return 'Function'; + case Array: + return 'any[]'; + default: + return 'string'; + } + } +}; + +const generateTypeScriptInterfaceFromProps = (props, componentName, eventList, slotList, mixin) => { + let interfaceProps = []; + + if (props) { + interfaceProps = Object.keys(props).reduce((interfaceProps, nextPropName) => { + const propType = getPropType(props[nextPropName]); + + return [ + ...interfaceProps, + ` ${to.camel(nextPropName)}?: ${propType};` + ]; + }, []); + } + + eventList.forEach(eventName => { + interfaceProps.push(` ${to.camel('on-' + eventName.split(':').join('-'))}?: (eventArgs?: any) => void;`); + }); + + slotList.forEach(slotName => { + interfaceProps.push(` ${to.camel(slotName + '-slot')}?: React.ReactElement;`) + }); + + if (!props || !props.id) interfaceProps.push(' id?: string;'); + if (!props || !props.className) interfaceProps.push(' className?: string;'); + if (!props || !props.style) interfaceProps.push(' style?: {[cssAttribute: string]: string};'); + + if (interfaceProps.length) { + if (mixin) { + return `\nexport interface I${componentName}Props extends I${mixin}Props {\n${interfaceProps.join('\n')}\n}`; + } else { + return `\nexport interface I${componentName}Props {\n${interfaceProps.join('\n')}\n}`; + } + } else { + return null; + } +}; + +const getEventList = (vueComponentString) => { + const regex = new RegExp(/\$emit\(["']([A-Za-z0-9-:]+)["'],?/, 'g'); + let match; + const events = []; + + while (match = regex.exec(vueComponentString)) { + if (events.indexOf(match[1]) === -1) events.push(match[1]); + } + + return events; +}; + +const getComponentToTagMappings = () => { + const framework7Vue = readFileSync('./node_modules/framework7-vue/src/framework7-vue.js', 'utf8'); + const framework7VueString = stringify(framework7Vue); + const regex = new RegExp(/["'](f7-[A-Za-z0-9-]+)["']\s*\:\s*([A-Za-z0-9]+),/, 'g'); + let match; + const tagToComponentMap = {}; + const componentToTagMap = {}; + + while (match = regex.exec(framework7VueString)) { + const tagName = match[1]; + const componentName = match[2]; + + tagToComponentMap[tagName] = componentName; + componentToTagMap[componentName] = tagName; + } + + return { + componentToTagMap, + tagToComponentMap + }; +}; + +const getInstantiatedComponentList = (vueComponentString, tagToComponentMap) => { + return Object.keys(tagToComponentMap).reduce((componentList, nextTag) => { + const regex = new RegExp(`["']${nextTag}["']`, 'g'); + + if (regex.test(vueComponentString) && componentList.indexOf(tagToComponentMap[nextTag]) === -1) { + return componentList.concat([tagToComponentMap[nextTag]]); + } else { + return componentList; + } + }, []); +}; + +const getSlotList = (vueComponentString) => { + const regexDict = new RegExp(/\$slots\[\s*["']([A-Za-z0-9-:]+)["']\s*]/, 'g'); + const regexDot = new RegExp(/\$slots\.([A-Za-z0-9-:]+)/, 'g'); + const regexT = new RegExp(/_vm\._t\(["']([A-Za-z0-9-:]+)["']\)/, 'g'); + + let match; + const slots = []; + + [regexDict, regexDot, regexT].forEach(regex => { + while (match = regex.exec(vueComponentString)) { + if (slots.indexOf(match[1]) === -1 && match[1] !== 'default') slots.push(match[1]); + } + }); + + return slots; +}; + +const getComponentMixinMap = () => { + let framework7Vue = readFileSync('./framework7-vue/framework7-vue.js', 'utf8'); + const regex = new RegExp(/mixins:\s*\[([A-Za-z0-9]+)/, 'g'); + let match; + + framework7Vue = framework7Vue.replace(regex, (mixinStatement, mixinName) => { + return mixinStatement.replace(mixinName, `'${mixinName}'`); + }); + + let transpiledFramework7Vue = babel.transform(framework7Vue, { + presets: ['es2015'] + }).code; + + const framework7VueExports = new Function('exports, console', 'try {\n' + transpiledFramework7Vue + '\n} catch (err) { console.log("An error occurred: "); console.error(err);}; return exports;')({}, console); + + return Object.keys(framework7VueExports).reduce((componentMixinMap, nextExportName) => { + const exportedComponent = framework7VueExports[nextExportName]; + + if (exportedComponent.mixins) { + return { + ...componentMixinMap, + [nextExportName]: exportedComponent.mixins[0] + }; + } else { + return componentMixinMap; + } + }, {}); +}; + +const generateReactifyF7VueCall = ( + vueComponent, + vueComponentName, + vueComponentString, + reactComponentName, + componentToTagMappings, + componentMixinMap, + overrides +) => { + const reactifyF7VueArgs = []; + let eventList; + let instantiatedComponentList; + let slotList; + + const imports = [ + `import * as React from 'react'`, + generateImportString('reactifyF7Vue', '../src/utils/ReactifyF7Vue'), + generateImportString(vueComponentName, '../framework7-vue/framework7-vue') + ]; + + reactifyF7VueArgs.push(`component: ${vueComponentName}`); + reactifyF7VueArgs.push(`tag: '${componentToTagMappings.componentToTagMap[reactComponentName]}'`); + + const componentOverrides = overrides && overrides[reactComponentName]; + + if (componentOverrides && componentOverrides.events) { + eventList = componentOverrides.events; + } else { + eventList = getEventList(vueComponentString); + } + + if (eventList.length) reactifyF7VueArgs.push(`events: [\n\t\t'${eventList.join('\',\n\t\t\'')}'\n\t]`); + + if (componentOverrides && componentOverrides.instantiatedComponents) { + instantiatedComponentList = componentOverrides.instantiatedComponents.instantiatedComponents; + } else { + instantiatedComponentList = getInstantiatedComponentList(vueComponentString, componentToTagMappings.tagToComponentMap); + } + + if (instantiatedComponentList.length) reactifyF7VueArgs.push(`instantiatedComponents: [\n\t\t${instantiatedComponentList.join(',\n\t\t')}\n\t]`); + + if (componentOverrides && componentOverrides.slots) { + slotList = componentOverrides.slots; + } else { + slotList = getSlotList(vueComponentString); + } + + if (slotList.length) reactifyF7VueArgs.push(`slots: [\n\t\t'${slotList.join('\',\n\t\t\'')}'\n\t]`); + + imports.push(...instantiatedComponentList.map(componentName => { + return generateImportString(componentName, `./${componentName}`) + })); + + const mixin = componentMixinMap[vueComponentName]; + + if (mixin) { + imports.push(generateImportString(`Vue${mixin}`, '../framework7-vue/framework7-vue')); + imports.push(generateImportString(`I${mixin}Props`, `./${mixin}`)); + reactifyF7VueArgs.push(`mixin: Vue${mixin}`); + } + + const typeScriptInterface = generateTypeScriptInterfaceFromProps( + vueComponent.props, + reactComponentName, + eventList, + slotList, + mixin + ); + + const propInterfaceName = (typeScriptInterface) ? `I${reactComponentName}Props` : 'void'; + + const reactifyVueCall = `\nexport const ${reactComponentName} = reactifyF7Vue<${propInterfaceName}>({\n\t${reactifyF7VueArgs.join(',\n\t')}\n});`; + + const componentCode = [ + imports.join('\n'), + typeScriptInterface + ]; + + if (vueComponentName.indexOf('Mixin') === -1) componentCode.push(reactifyVueCall); + + return componentCode.join('\n'); +}; + +const generateIndexTsFile = (vueComponents, excludes) => { + const importedFiles = []; + const exportedModules = []; + + importedFiles.push(generateImportString('Framework7App', '../src/components/Framework7App')); + exportedModules.push('Framework7App'); + importedFiles.push(generateImportString('Framework7', '../src/Framework7')); + exportedModules.push('Framework7'); + + Object.keys(vueComponents).forEach(vueComponentName => { + if (vueComponentName.indexOf('Mixin') === -1) { + const reactComponentName = vueComponentName.replace('Vue', ''); + + if (excludes && excludes.indexOf(reactComponentName) !== -1) { + importedFiles.push(generateImportString(reactComponentName, `../src/components/${reactComponentName}`)); + } else { + importedFiles.push(generateImportString(reactComponentName, `./${reactComponentName}`)); + } + + exportedModules.push(reactComponentName); + } + }); + + const indexTsFile = `${importedFiles.join('\n')}\n\nexport {\n\t${exportedModules.join(',\n\t')}\n}`; + const outPath = './framework7-react/index.ts'; + + writeFileSync(outPath, indexTsFile); +} + +export const generateReactComponents = (args) => { + const componentFile = []; + + const componentMixinMap = getComponentMixinMap(); + + const vueComponents = require('./framework7-vue/framework7-vue'); + + Object.keys(vueComponents).forEach(vueComponentName => { + const reactComponentName = vueComponentName.replace('Vue', ''); + const vueComponent = vueComponents[vueComponentName] + const vueComponentString = stringify(vueComponent).split(`\\"`).join('"'); + const componentToTagMappings = getComponentToTagMappings(); + + if (!args || !args.exclude || args.exclude.indexOf(reactComponentName) === -1) { + const reactifyF7VueCall = generateReactifyF7VueCall( + vueComponent, + vueComponentName, + vueComponentString, + reactComponentName, + componentToTagMappings, + componentMixinMap, + args && args.overrides + ); + + const outPath = `./framework7-react/${reactComponentName}.ts`; + + ensureDirectoryExistence(outPath); + writeFileSync(outPath, reactifyF7VueCall); + } + }); + + generateIndexTsFile(vueComponents, args && args.exclude); +}; diff --git a/framework7-vue-build.js b/framework7-vue-build.js new file mode 100644 index 0000000..c912ab9 --- /dev/null +++ b/framework7-vue-build.js @@ -0,0 +1,67 @@ +var gulp = require('gulp'), + path = require('path'), + rollup = require('rollup-stream'), + buble = require('rollup-plugin-buble'), + vue = require('rollup-plugin-vue2'), + source = require('vinyl-source-stream'), + buffer = require('vinyl-buffer'), + sourcemaps = require('gulp-sourcemaps'), + rename = require('gulp-rename'), + fs = require('fs'), + to = require('to-case'); + +const ensureDirectoryExistence = (filePath) => { + var dirname = path.dirname(filePath); + + if (fs.existsSync(dirname)) { + return true; + } + + ensureDirectoryExistence(dirname); + + fs.mkdirSync(dirname); +}; + +export default function(cb) { + const paths = [ + './node_modules/framework7-vue/src/components/', + './node_modules/framework7-vue/src/mixins/' + ]; + + const components = []; + const imports = []; + + paths.forEach(path => { + const files = fs.readdirSync(path); + files.filter(file => file.indexOf('.vue') != -1).forEach(file => { + const componentName = to.pascal(`vue-${file.replace('.vue', '')}${(path.indexOf('mixins') !== -1) ? '-mixin' : ''}`); + imports.push(`import ${componentName} from '${'.' + path + file}'`); + components.push(componentName); + }); + }); + + const index = `${imports.join('\n')}\n\nexport {\n\t${components.join(',\n\t')}\n}`; + + ensureDirectoryExistence('./framework7-vue/index.js'); + + fs.writeFileSync('./framework7-vue/index.js', index); + + rollup({ + entry: './framework7-vue/index.js', + plugins: [vue(), buble()], + format: 'es', + moduleName: 'Framework7Vue', + useStrict: false, + sourceMap: true + }) + .pipe(source('framework7-vue.js', './framework7-vue')) + .pipe(buffer()) + .pipe(sourcemaps.init({loadMaps: true})) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest('./framework7-vue/')) + .on('end', function() { + gulp.src('./framework7-vue/framework7-vue.js') + .pipe(gulp.dest('./dist/framework7-vue/')) + .on('end', cb); + }); +}; \ No newline at end of file diff --git a/gulpfile.babel.js b/gulpfile.babel.js new file mode 100644 index 0000000..774528d --- /dev/null +++ b/gulpfile.babel.js @@ -0,0 +1,79 @@ +import {generateReactComponents} from './framework7-react-component-gen'; +import compileFramework7Vue from './framework7-vue-build'; + +const gulp = require('gulp'), + path = require('path'), + clean = require('gulp-clean'), + concat = require('gulp-concat'), + getF7FileList = require('./framework7-custom-build'), + tsc = require('gulp-typescript'), + merge = require('merge2'), + replace = require('gulp-replace'), + sourcemaps = require('gulp-sourcemaps'); + +gulp.task('clean', () => { + return gulp.src(['./dist', './framework7-vue', './framework7-react'], { read: false }) + .pipe(clean()); +}); + +gulp.task('build-framework7-core', ['clean'], () => { + return merge( + gulp.src(getF7FileList()) + .pipe(concat('Framework7.js')) + .pipe(replace('window.Framework7 = ', 'window.Framework7 = module.exports.Framework7 = ')) + .pipe(replace('window.Dom7 = ', 'window.Dom7 = module.exports.Dom7 = ')) + .pipe(replace('window.Template7 = ', 'window.Template7 = module.exports.Template7 = ')) + .pipe(gulp.dest('dist/src/')), + gulp.src('./src/Framework7.d.ts') + .pipe(gulp.dest('./dist/src/')) + ); +}); + +gulp.task('compile-framework7-vue', ['clean'], (cb) => { + return compileFramework7Vue(() => { + gulp.src('./node_modules/framework7-vue/src/utils/router.js') + .pipe(gulp.dest('./framework7-vue/')) + .pipe(gulp.dest('./dist/framework7-vue/')) + .on('end', cb); + }); +}); + +gulp.task('generate-react-components', ['clean', 'compile-framework7-vue'], () => { + return generateReactComponents(); +}); + +gulp.task('compile-ts', ['clean', 'compile-framework7-vue'], () => { + var tsProject = tsc.createProject('tsconfig.json'); + + var tsResult = tsProject.src() + .pipe(sourcemaps.init()) + .pipe(tsProject()); + + return merge([ + tsResult.dts.pipe(gulp.dest('dist/')), + tsResult.js.pipe(sourcemaps.write('.', { + includeContent: false, + sourceRoot: function (file) { + var sourceFile = path.join(file.cwd, file.sourceMap.file); + return "../" + path.relative(path.dirname(sourceFile), __dirname); + } + })) + .pipe(gulp.dest('dist/')) + ]); +}); + +gulp.task('tidy-dist-dir', ['compile-ts'], () => { + return gulp.src(['./dist/*.js', './dist/*.map'], { read: false }) + .pipe(clean()); +}); + +gulp.task('default', + [ + 'clean', + 'build-framework7-core', + 'compile-framework7-vue', + 'generate-react-components', + 'compile-ts', + 'tidy-dist-dir' + ] +); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index c6bc108..0000000 --- a/gulpfile.js +++ /dev/null @@ -1,62 +0,0 @@ -var gulp = require('gulp'), - path = require('path'), - clean = require('gulp-clean'), - concat = require('gulp-concat'), - getF7FileList = require('./framework7-custom-build'), - sourcemaps = require('gulp-sourcemaps'), - tsc = require('gulp-typescript'), - merge = require('merge2'), - replace = require('gulp-replace'), - tslint = require('gulp-tslint'); - -gulp.task('clean', function () { - return gulp.src('./dist', { read: false }) - .pipe(clean()); -}); - -gulp.task('build-framework7-core', ['clean'], function () { - return merge( - gulp.src(getF7FileList()) - .pipe(concat('Framework7.js')) - .pipe(replace('window.Framework7 = ', 'window.Framework7 = module.exports.Framework7 = ')) - .pipe(gulp.dest('dist/src/')), - gulp.src('./src/Framework7.d.ts') - .pipe(gulp.dest('./dist/src/')) - ); -}); - -gulp.task('copy-less', ['clean'], function () { - gulp - .src('./src/less/**/*') - .pipe(gulp.dest('./dist/src/less')) -}); - -gulp.task("tslint", () => - gulp.src(["./src/**/*.ts", "./src/**/*.tsx"]) - .pipe(tslint({ - formatter: "verbose" - })) - .pipe(tslint.report()) -); - -gulp.task('compile-ts', ['tslint', 'clean'], function () { - var tsProject = tsc.createProject('tsconfig.json'); - - var tsResult = gulp.src(['./src/**/*.ts', './src/**/*.tsx', './typings/**/*.ts']) - .pipe(sourcemaps.init()) - .pipe(tsProject()); - - return merge([ - tsResult.dts.pipe(gulp.dest('dist/src/')), - tsResult.js.pipe(sourcemaps.write('.', { - includeContent: false, - sourceRoot: function (file) { - var sourceFile = path.join(file.cwd, file.sourceMap.file); - return "../" + path.relative(path.dirname(sourceFile), __dirname); - } - })) - .pipe(gulp.dest('dist/src/')) - ]); -}); - -gulp.task('default', ['build-framework7-core', 'tslint', 'compile-ts', 'copy-less']); \ No newline at end of file diff --git a/kitchen-sink/components/App.tsx b/kitchen-sink/components/App.tsx index 631e3e6..c40dacf 100644 --- a/kitchen-sink/components/App.tsx +++ b/kitchen-sink/components/App.tsx @@ -1,12 +1,13 @@ import * as React from 'react'; -import {Route, IndexRoute, Router, hashHistory} from 'react-router'; -import {Framework7App, ThemeTypeEnum, Views, View, AnimationDirectionEnum} from 'framework7-react'; +import { + Framework7App, + Views, View, + Pages, Page, PageContent, + Navbar, NavLeft, NavCenter, NavRight, Toolbar, + Panel, Statusbar, Link, List, ListItem +} from 'framework7-react'; -import {routeState} from '../utils/RouteState'; -import {IndexPage} from './pages/IndexPage'; -import {NavbarAndToolbarPage} from './pages/NavbarAndToolbarPage'; -import {ListViewPage} from './pages/ListViewPage'; -import {ProgressBarPage} from './pages/ProgressBarPage'; +import {routes} from '../routes'; export interface IKitchenSinkPage { path: string; @@ -14,49 +15,143 @@ export interface IKitchenSinkPage { component: React.ComponentClass | React.StatelessComponent; } -export const pages: IKitchenSinkPage[] = [{ - path: '/', - pageTitle: '', - component: IndexPage -}, { - path: 'list-view', - pageTitle: 'List View', - component: ListViewPage -}, { - path: 'navbars-and-toolbars', - pageTitle: 'Navbars and Toolbars', - component: NavbarAndToolbarPage -}, { - path: 'progress-bar', - pageTitle: 'Progress Bar', - component: ProgressBarPage -}]; - -const App = (props: React.Props) => { - return ( - - - - - {props.children} - - - - ); -}; - -const getPages = () => { - return pages.map(pageRoute => { - return - }); -}; - -export const Routes = () => { - return ( - - - {getPages()} - - - ); +let framework7: any; +let currentRoute: any; + +export const getFramework7 = () => { + return framework7; +} + +const onRouteChange = (route: any) => { + currentRoute = route; +} + +export const getCurrentRoute = () => { + return currentRoute; +} + +export interface IAppState { + leftPanelOpened: boolean; + rightPanelOpened: boolean; +} + +export class App extends React.Component { + constructor() { + super(); + + this.state = { + leftPanelOpened: false, + rightPanelOpened: false + } + } + + render() { + return ( + {framework7 = f7}} themeType="ios" routes={routes} onRouteChange={onRouteChange}> + + + + + + + + + + + + + + + +

Panel right content

+
+ + + + + + + Hello World + + + + + + + + Left + Right + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ); + } + + private openLeftPanel() { + this.setState({ + ...this.state, + leftPanelOpened: true + }) + } + + private openRightPanel() { + this.setState({ + ...this.state, + rightPanelOpened: true + }) + } + + + private closedLeftPanel() { + this.setState({ + ...this.state, + leftPanelOpened: false + }) + } + + private closedRightPanel() { + this.setState({ + ...this.state, + rightPanelOpened: false + }) + } }; \ No newline at end of file diff --git a/kitchen-sink/components/demo/ActionsDemo.tsx b/kitchen-sink/components/demo/ActionsDemo.tsx new file mode 100644 index 0000000..758cf8d --- /dev/null +++ b/kitchen-sink/components/demo/ActionsDemo.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; + +import {Actions, ActionsGroup, ActionsLabel, ActionsButton} from 'framework7-react'; + +export interface IActionsDemoProps extends React.Props { + opened: boolean; + onActionsClosed: () => void; +} + +export const ActionsDemo = (props: IActionsDemoProps) => { + return ( + + + Hello + Button 1 + Button 2 + + + Cancel + + + ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/demo/LoginScreenDemo.tsx b/kitchen-sink/components/demo/LoginScreenDemo.tsx new file mode 100644 index 0000000..ac0c4bd --- /dev/null +++ b/kitchen-sink/components/demo/LoginScreenDemo.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; + +import {LoginScreen, View, Pages, Page, LoginScreenTitle, List, ListItem, FormLabel, FormInput, ListButton, ListLabel} from 'framework7-react'; + +export interface ILoginScreenDemoProps { + opened: boolean; + closeLoginScreen: () => void; +} + +export const LoginScreenDemo = (props: ILoginScreenDemoProps) => { + return ( + + + + + My App + + + + Username + + + + Password + + + + + + + +

Click Sign In to close Login Screen

+
+
+
+
+
+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/demo/PickerModalDemo.tsx b/kitchen-sink/components/demo/PickerModalDemo.tsx new file mode 100644 index 0000000..5f1a61b --- /dev/null +++ b/kitchen-sink/components/demo/PickerModalDemo.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; + +import {PickerModal, Toolbar, NavLeft, NavRight, Link, ContentBlock} from 'framework7-react'; + +export interface IPickerModalDemoProps { + opened: boolean; + closePicker: () => void; +} + +export const PickerModalDemo = (props: IPickerModalDemoProps) => { + return ( + + + + + Done + + + +

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nobis iste qui architecto recusandae veniam delectus vero libero illo aliquid, fuga ratione vel facilis iure est fugiat sunt nihil, consectetur veritatis.

+
+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/demo/PopoverDemo.tsx b/kitchen-sink/components/demo/PopoverDemo.tsx new file mode 100644 index 0000000..9e1790d --- /dev/null +++ b/kitchen-sink/components/demo/PopoverDemo.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; + +import {Popover, ContentBlock} from 'framework7-react'; + +export interface IPopoverDemoProps { + id: string; +} + +export const PopoverDemo = (props: IPopoverDemoProps) => { + return ( + + +

Hello, I'm a Popover

+
+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/demo/PopupDemo.tsx b/kitchen-sink/components/demo/PopupDemo.tsx new file mode 100644 index 0000000..5cf6380 --- /dev/null +++ b/kitchen-sink/components/demo/PopupDemo.tsx @@ -0,0 +1,34 @@ +import * as React from 'react'; + +import {Popup, View, Pages, Page, Navbar, NavRight, Link, ContentBlock} from 'framework7-react'; + +export interface IPopupDemoProps { + opened: boolean; + closePopup: () => void; +} + +export const PopupDemo = (props: IPopupDemoProps) => { + return ( + + + + + + + Close + + + + +

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nobis iste qui architecto recusandae veniam delectus vero libero illo aliquid, fuga ratione vel facilis iure est fugiat sunt nihil, consectetur veritatis.

+

Itaque impedit, nam, sed reprehenderit quaerat commodi veritatis ducimus eos nisi, at aliquam dolorum alias optio natus. Sit voluptate aperiam, cupiditate repellat quod fugiat non doloribus eveniet dolorem fugit nihil.

+

Error cumque sunt dolorem aut, similique accusantium delectus. Minima, natus. Doloremque ratione veniam cupiditate modi aspernatur debitis possimus iure id delectus! Totam eveniet, impedit minus deserunt aliquid facere laboriosam dignissimos.

+

Aliquid autem saepe sit cumque odit nihil eius consectetur impedit accusantium sunt, repudiandae quaerat cum! Esse autem ipsum aliquam, distinctio laborum excepturi facilis fuga vitae atque iusto eligendi, explicabo corporis.

+

Necessitatibus minima quidem fugit corporis reprehenderit saepe facilis perspiciatis sit, consectetur nulla officia, pariatur accusantium quas voluptas. Illum placeat eligendi dolor nihil libero culpa, ex quas voluptas deleniti, unde id.

+
+
+
+
+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/nested-routes/tabs/Tab1.tsx b/kitchen-sink/components/nested-routes/tabs/Tab1.tsx new file mode 100644 index 0000000..8573816 --- /dev/null +++ b/kitchen-sink/components/nested-routes/tabs/Tab1.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; + +import {ContentBlock} from 'framework7-react'; + +export const Tab1 = () => { + return ( + +

Tab 1

+

Go to tab 2

+

Go to tab 3

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/nested-routes/tabs/Tab2.tsx b/kitchen-sink/components/nested-routes/tabs/Tab2.tsx new file mode 100644 index 0000000..cca4cd9 --- /dev/null +++ b/kitchen-sink/components/nested-routes/tabs/Tab2.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; + +import {ContentBlock} from 'framework7-react'; + +export const Tab2 = () => { + return ( + +

Tab 2

+

Go to tab 1

+

Go to tab 3

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/nested-routes/tabs/Tab3.tsx b/kitchen-sink/components/nested-routes/tabs/Tab3.tsx new file mode 100644 index 0000000..b16d40d --- /dev/null +++ b/kitchen-sink/components/nested-routes/tabs/Tab3.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; + +import {ContentBlock} from 'framework7-react'; + +export const Tab3 = () => { + return ( + +

Tab 3

+

Go to tab3 alternate content

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/nested-routes/tabs/Tab3AlternateContent.tsx b/kitchen-sink/components/nested-routes/tabs/Tab3AlternateContent.tsx new file mode 100644 index 0000000..aaa377b --- /dev/null +++ b/kitchen-sink/components/nested-routes/tabs/Tab3AlternateContent.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; + +import {ContentBlock} from 'framework7-react'; + +export const Tab3AlternateContent = () => { + return ( + +

Tab 3 Alternate Content

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/nested-routes/tabs/TabbarTab1.tsx b/kitchen-sink/components/nested-routes/tabs/TabbarTab1.tsx new file mode 100644 index 0000000..6803bc4 --- /dev/null +++ b/kitchen-sink/components/nested-routes/tabs/TabbarTab1.tsx @@ -0,0 +1,19 @@ + +import * as React from 'react'; + +import {ContentBlock} from 'framework7-react'; + +export const TabbarTab1 = () => { + return ( + +

Tabbar Tab 1

+

Go to tab 2

+

Go to tab 3

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/nested-routes/tabs/TabbarTab2.tsx b/kitchen-sink/components/nested-routes/tabs/TabbarTab2.tsx new file mode 100644 index 0000000..f600193 --- /dev/null +++ b/kitchen-sink/components/nested-routes/tabs/TabbarTab2.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; + +import {ContentBlock} from 'framework7-react'; + +export const TabbarTab2 = () => { + return ( + +

Tabbar Tab 2

+

Go to tab 1

+

Go to tab 3

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/nested-routes/tabs/TabbarTab3.tsx b/kitchen-sink/components/nested-routes/tabs/TabbarTab3.tsx new file mode 100644 index 0000000..5bafc2d --- /dev/null +++ b/kitchen-sink/components/nested-routes/tabs/TabbarTab3.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; + +import {ContentBlock} from 'framework7-react'; + +export const TabbarTab3 = () => { + return ( + +

Tabbar Tab 3

+

Go to tab3 alternate content

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/nested-routes/tabs/TabbarTab3AlternateContent.tsx b/kitchen-sink/components/nested-routes/tabs/TabbarTab3AlternateContent.tsx new file mode 100644 index 0000000..25ef9e2 --- /dev/null +++ b/kitchen-sink/components/nested-routes/tabs/TabbarTab3AlternateContent.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; + +import {ContentBlock} from 'framework7-react'; + +export const TabbarTab3AlternateContent = () => { + return ( + +

Tabbar Tab 3 Alternate Content

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+ ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/AccordionPage.tsx b/kitchen-sink/components/pages/AccordionPage.tsx new file mode 100644 index 0000000..d918da5 --- /dev/null +++ b/kitchen-sink/components/pages/AccordionPage.tsx @@ -0,0 +1,77 @@ +import * as React from 'react'; +import { + Page, + Navbar, + ContentBlock, + ContentBlockTitle, + List, + ListItem, + AccordionContent, + AccordionItem, + AccordionToggle +} from 'framework7-react'; + +const onOpen = (event) => { + console.log('open'); +}; + +const onOpened = (event) =>{ + console.log('opened'); +}; + +const onClose = (event) => { + console.log('close'); +}; + +const onClosed = (event) => { + console.log('closed'); +}; + +export const AccordionPage = () => { + return ( + + + + Accordion List + + { + [1 ,2, 3].map(n => { + return ( + + + +

{`Accordion content ${n}`}

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eu felis volutpat, rutrum ex quis, lobortis ex. Curabitur quis mattis lorem. Nullam magna lacus, interdum vel maximus nec, vestibulum non quam. Phasellus ornare efficitur porttitor. Quisque neque diam, imperdiet in fermentum nec, congue vitae ante. Nullam imperdiet maximus commodo. Morbi pharetra id purus ac ultrices. Duis non posuere libero.

+
+
+
+ ); + }) + } +
+ + Custom Collapsible + + { + [1, 2, 3].map(n => { + return ( + + {`Item ${n}`} + {`Content ${n}`} + + ); + }) + } + +
+ ); +}; + diff --git a/kitchen-sink/components/pages/BarsHidePage.tsx b/kitchen-sink/components/pages/BarsHidePage.tsx new file mode 100644 index 0000000..d2da028 --- /dev/null +++ b/kitchen-sink/components/pages/BarsHidePage.tsx @@ -0,0 +1,39 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, Toolbar, Link} from 'framework7-react'; + + +export const BarsHidePage = () => { + return ( + + + + Link1 + Link2 + + +

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eos voluptatibus, sunt quam reprehenderit assumenda hic aut illo, optio fuga reiciendis. Sapiente suscipit sint ratione tenetur voluptate repellendus quaerat perspiciatis repudiandae.

+

Delectus fuga tempora dignissimos eveniet maxime labore animi, magnam error quas quasi adipisci sed architecto atque maiores facilis natus tempore excepturi libero? Perferendis odio veritatis, aliquam consectetur? Sunt, qui, architecto.

+

Officiis soluta mollitia, asperiores consequatur itaque optio dolorem laudantium facere eveniet distinctio, cumque. Dolore similique ut, quas ullam ipsam, accusantium unde repellendus voluptatem sint odio id magnam quia sunt harum?

+

Itaque consequuntur excepturi unde pariatur maiores impedit aliquam necessitatibus perferendis, dolorem tempore nostrum hic iure obcaecati officiis vero cum numquam a dolores atque et! Blanditiis quibusdam, saepe excepturi animi aperiam.

+

Id facilis magnam nostrum similique repudiandae earum doloremque iusto tempore dolorum amet blanditiis assumenda aliquam deserunt consequuntur, sequi hic odit corrupti? Dolore illo, nihil aut rem dignissimos impedit ex necessitatibus?

+

Aliquid fugit molestias enim, facere consequatur vitae doloremque modi, dolore perspiciatis nam sequi. Corrupti repellendus blanditiis quo neque vel possimus, ipsum at sed adipisci voluptatibus aliquid quidem, placeat dolor eaque?

+

Voluptatum, eum, asperiores! Sunt ab maiores ratione iure obcaecati cum reiciendis reprehenderit, quibusdam, blanditiis in facere. Blanditiis maiores laudantium, autem harum ipsam labore eum adipisci inventore eligendi iure dicta ratione!

+

Ipsum expedita, similique excepturi blanditiis neque aut. Provident labore ea nihil ducimus, distinctio voluptate, tempore facere possimus ipsam, voluptates aliquid cupiditate maiores veniam eos nesciunt. Dolorem eius consectetur voluptates recusandae!

+

Eius, iusto maxime tempora officia impedit cumque, delectus fugiat enim fugit, ex repudiandae modi autem quasi repellat ea saepe sequi similique animi ipsam doloremque placeat natus minima voluptatibus cum nulla.

+

Id iste, quod, deserunt maiores consectetur optio placeat quas obcaecati animi, assumenda hic. Temporibus obcaecati fugit omnis modi velit esse dolor nam illo laboriosam ut voluptates voluptatibus vitae, voluptatum officiis!

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eos voluptatibus, sunt quam reprehenderit assumenda hic aut illo, optio fuga reiciendis. Sapiente suscipit sint ratione tenetur voluptate repellendus quaerat perspiciatis repudiandae.

+

Delectus fuga tempora dignissimos eveniet maxime labore animi, magnam error quas quasi adipisci sed architecto atque maiores facilis natus tempore excepturi libero? Perferendis odio veritatis, aliquam consectetur? Sunt, qui, architecto.

+

Officiis soluta mollitia, asperiores consequatur itaque optio dolorem laudantium facere eveniet distinctio, cumque. Dolore similique ut, quas ullam ipsam, accusantium unde repellendus voluptatem sint odio id magnam quia sunt harum?

+

Itaque consequuntur excepturi unde pariatur maiores impedit aliquam necessitatibus perferendis, dolorem tempore nostrum hic iure obcaecati officiis vero cum numquam a dolores atque et! Blanditiis quibusdam, saepe excepturi animi aperiam.

+

Id facilis magnam nostrum similique repudiandae earum doloremque iusto tempore dolorum amet blanditiis assumenda aliquam deserunt consequuntur, sequi hic odit corrupti? Dolore illo, nihil aut rem dignissimos impedit ex necessitatibus?

+

Aliquid fugit molestias enim, facere consequatur vitae doloremque modi, dolore perspiciatis nam sequi. Corrupti repellendus blanditiis quo neque vel possimus, ipsum at sed adipisci voluptatibus aliquid quidem, placeat dolor eaque?

+

Voluptatum, eum, asperiores! Sunt ab maiores ratione iure obcaecati cum reiciendis reprehenderit, quibusdam, blanditiis in facere. Blanditiis maiores laudantium, autem harum ipsam labore eum adipisci inventore eligendi iure dicta ratione!

+

Ipsum expedita, similique excepturi blanditiis neque aut. Provident labore ea nihil ducimus, distinctio voluptate, tempore facere possimus ipsam, voluptates aliquid cupiditate maiores veniam eos nesciunt. Dolorem eius consectetur voluptates recusandae!

+

Eius, iusto maxime tempora officia impedit cumque, delectus fugiat enim fugit, ex repudiandae modi autem quasi repellat ea saepe sequi similique animi ipsam doloremque placeat natus minima voluptatibus cum nulla.

+

Id iste, quod, deserunt maiores consectetur optio placeat quas obcaecati animi, assumenda hic. Temporibus obcaecati fugit omnis modi velit esse dolor nam illo laboriosam ut voluptates voluptatibus vitae, voluptatum officiis!

+
+ + +
+ ); +} diff --git a/kitchen-sink/components/pages/BarsPage.tsx b/kitchen-sink/components/pages/BarsPage.tsx new file mode 100644 index 0000000..cf7dbb2 --- /dev/null +++ b/kitchen-sink/components/pages/BarsPage.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import {Page, Navbar, List, ListItem} from 'framework7-react'; + +export const BarsPage = () => { + return ( + + + + + + + + + + + ); +} diff --git a/kitchen-sink/components/pages/BarsSubnavbarPage.tsx b/kitchen-sink/components/pages/BarsSubnavbarPage.tsx new file mode 100644 index 0000000..d62b307 --- /dev/null +++ b/kitchen-sink/components/pages/BarsSubnavbarPage.tsx @@ -0,0 +1,45 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, Toolbar, Link, ButtonsSegmented, Button, Subnavbar} from 'framework7-react'; + + +export const BarsSubnavbarPage = () => { + return ( + + + + + + + + + + + + Link1 + Link2 + + +

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eos voluptatibus, sunt quam reprehenderit assumenda hic aut illo, optio fuga reiciendis. Sapiente suscipit sint ratione tenetur voluptate repellendus quaerat perspiciatis repudiandae.

+

Delectus fuga tempora dignissimos eveniet maxime labore animi, magnam error quas quasi adipisci sed architecto atque maiores facilis natus tempore excepturi libero? Perferendis odio veritatis, aliquam consectetur? Sunt, qui, architecto.

+

Officiis soluta mollitia, asperiores consequatur itaque optio dolorem laudantium facere eveniet distinctio, cumque. Dolore similique ut, quas ullam ipsam, accusantium unde repellendus voluptatem sint odio id magnam quia sunt harum?

+

Itaque consequuntur excepturi unde pariatur maiores impedit aliquam necessitatibus perferendis, dolorem tempore nostrum hic iure obcaecati officiis vero cum numquam a dolores atque et! Blanditiis quibusdam, saepe excepturi animi aperiam.

+

Id facilis magnam nostrum similique repudiandae earum doloremque iusto tempore dolorum amet blanditiis assumenda aliquam deserunt consequuntur, sequi hic odit corrupti? Dolore illo, nihil aut rem dignissimos impedit ex necessitatibus?

+

Aliquid fugit molestias enim, facere consequatur vitae doloremque modi, dolore perspiciatis nam sequi. Corrupti repellendus blanditiis quo neque vel possimus, ipsum at sed adipisci voluptatibus aliquid quidem, placeat dolor eaque?

+

Voluptatum, eum, asperiores! Sunt ab maiores ratione iure obcaecati cum reiciendis reprehenderit, quibusdam, blanditiis in facere. Blanditiis maiores laudantium, autem harum ipsam labore eum adipisci inventore eligendi iure dicta ratione!

+

Ipsum expedita, similique excepturi blanditiis neque aut. Provident labore ea nihil ducimus, distinctio voluptate, tempore facere possimus ipsam, voluptates aliquid cupiditate maiores veniam eos nesciunt. Dolorem eius consectetur voluptates recusandae!

+

Eius, iusto maxime tempora officia impedit cumque, delectus fugiat enim fugit, ex repudiandae modi autem quasi repellat ea saepe sequi similique animi ipsam doloremque placeat natus minima voluptatibus cum nulla.

+

Id iste, quod, deserunt maiores consectetur optio placeat quas obcaecati animi, assumenda hic. Temporibus obcaecati fugit omnis modi velit esse dolor nam illo laboriosam ut voluptates voluptatibus vitae, voluptatum officiis!

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eos voluptatibus, sunt quam reprehenderit assumenda hic aut illo, optio fuga reiciendis. Sapiente suscipit sint ratione tenetur voluptate repellendus quaerat perspiciatis repudiandae.

+

Delectus fuga tempora dignissimos eveniet maxime labore animi, magnam error quas quasi adipisci sed architecto atque maiores facilis natus tempore excepturi libero? Perferendis odio veritatis, aliquam consectetur? Sunt, qui, architecto.

+

Officiis soluta mollitia, asperiores consequatur itaque optio dolorem laudantium facere eveniet distinctio, cumque. Dolore similique ut, quas ullam ipsam, accusantium unde repellendus voluptatem sint odio id magnam quia sunt harum?

+

Itaque consequuntur excepturi unde pariatur maiores impedit aliquam necessitatibus perferendis, dolorem tempore nostrum hic iure obcaecati officiis vero cum numquam a dolores atque et! Blanditiis quibusdam, saepe excepturi animi aperiam.

+

Id facilis magnam nostrum similique repudiandae earum doloremque iusto tempore dolorum amet blanditiis assumenda aliquam deserunt consequuntur, sequi hic odit corrupti? Dolore illo, nihil aut rem dignissimos impedit ex necessitatibus?

+

Aliquid fugit molestias enim, facere consequatur vitae doloremque modi, dolore perspiciatis nam sequi. Corrupti repellendus blanditiis quo neque vel possimus, ipsum at sed adipisci voluptatibus aliquid quidem, placeat dolor eaque?

+

Voluptatum, eum, asperiores! Sunt ab maiores ratione iure obcaecati cum reiciendis reprehenderit, quibusdam, blanditiis in facere. Blanditiis maiores laudantium, autem harum ipsam labore eum adipisci inventore eligendi iure dicta ratione!

+

Ipsum expedita, similique excepturi blanditiis neque aut. Provident labore ea nihil ducimus, distinctio voluptate, tempore facere possimus ipsam, voluptates aliquid cupiditate maiores veniam eos nesciunt. Dolorem eius consectetur voluptates recusandae!

+

Eius, iusto maxime tempora officia impedit cumque, delectus fugiat enim fugit, ex repudiandae modi autem quasi repellat ea saepe sequi similique animi ipsam doloremque placeat natus minima voluptatibus cum nulla.

+

Id iste, quod, deserunt maiores consectetur optio placeat quas obcaecati animi, assumenda hic. Temporibus obcaecati fugit omnis modi velit esse dolor nam illo laboriosam ut voluptates voluptatibus vitae, voluptatum officiis!

+
+
+ ); +} diff --git a/kitchen-sink/components/pages/BarsTabbarLabelsPage.tsx b/kitchen-sink/components/pages/BarsTabbarLabelsPage.tsx new file mode 100644 index 0000000..9387229 --- /dev/null +++ b/kitchen-sink/components/pages/BarsTabbarLabelsPage.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, Tab, Toolbar, Link} from 'framework7-react'; + + +export const BarsTabbarLabelsPage = () => { + return ( + + + + + +

Tab 1

+
+ +

Tab 2

+
+ +

Tab 3

+
+
+ + + + + + +
+ ); +} diff --git a/kitchen-sink/components/pages/BarsTabbarPage.tsx b/kitchen-sink/components/pages/BarsTabbarPage.tsx new file mode 100644 index 0000000..220d45d --- /dev/null +++ b/kitchen-sink/components/pages/BarsTabbarPage.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, Tab, Toolbar, Link} from 'framework7-react'; + + +export const BarsTabbarPage = () => { + return ( + + + + + +

Tab 1

+
+ +

Tab 2

+
+ +

Tab 3

+
+
+ + + + + + +
+ ); +} diff --git a/kitchen-sink/components/pages/CardsPage.tsx b/kitchen-sink/components/pages/CardsPage.tsx new file mode 100644 index 0000000..63c5ab3 --- /dev/null +++ b/kitchen-sink/components/pages/CardsPage.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import {Page, Navbar, Card, CardHeader, CardContent, CardFooter} from 'framework7-react'; + +export const CardsPage = () => { + return ( + + + + + + Header + Card Content + Footer + + + ); +} \ No newline at end of file diff --git a/kitchen-sink/components/pages/ChipsPage.tsx b/kitchen-sink/components/pages/ChipsPage.tsx new file mode 100644 index 0000000..b616f2c --- /dev/null +++ b/kitchen-sink/components/pages/ChipsPage.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlockTitle, ContentBlock, Chip} from 'framework7-react'; + +const onChipDelete = (event) => { + console.log('delete'); +}; + +const chipMargin = { + marginRight: ".5em" +}; + +export const ChipsPage = () => { + return ( + + + + Chips + + + + + '} style={chipMargin} /> + '} style={chipMargin} /> + + '} deleteable onDelete={onChipDelete} /> + + + ); +} diff --git a/kitchen-sink/components/pages/ContactsPage.tsx b/kitchen-sink/components/pages/ContactsPage.tsx new file mode 100644 index 0000000..b63a5b9 --- /dev/null +++ b/kitchen-sink/components/pages/ContactsPage.tsx @@ -0,0 +1,57 @@ +import * as React from 'react'; +import {Page, Navbar, List, ListGroup, ListItem} from 'framework7-react'; + +const contacts = { + 'A': [ + 'Aaron', + 'Abbie', + 'Adam', + 'Adele', + 'Agatha', + 'Agnes', + 'Albert', + 'Alexander' + ], + 'B': [ + 'Bailey', + 'Barclay', + 'Bartolo', + 'Bellamy', + 'Belle', + 'Benjamin' + ], + 'C': [ + 'Caiden', + 'Calvin', + 'Candy', + 'Carl', + 'Cherilyn', + 'Chester', + 'Chloe' + ], + 'V': [ + 'Vladimir' + ] +}; + +export const ContactsPage = () => { + return ( + + + + + {Object.keys(contacts).reduce((listGroups, nextGroupName) => { + return [ + ...listGroups, + + + {contacts[nextGroupName].map(contactName => { + return ; + })} + + ]; + }, [])} + + + ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/ContentBlockPage.tsx b/kitchen-sink/components/pages/ContentBlockPage.tsx new file mode 100644 index 0000000..4df146f --- /dev/null +++ b/kitchen-sink/components/pages/ContentBlockPage.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock} from 'framework7-react'; + +export const ContentBlockPage = () => { + return ( + + + +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eu felis volutpat, rutrum ex quis, lobortis ex. Curabitur quis mattis lorem. Nullam magna lacus, interdum vel maximus nec, vestibulum non quam. Phasellus ornare efficitur porttitor. Quisque neque diam, imperdiet in fermentum nec, congue vitae ante. Nullam imperdiet maximus commodo. Morbi pharetra id purus ac ultrices. Duis non posuere libero.

+
+ +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eu felis volutpat, rutrum ex quis, lobortis ex. Curabitur quis mattis lorem. Nullam magna lacus, interdum vel maximus nec, vestibulum non quam. Phasellus ornare efficitur porttitor. Quisque neque diam, imperdiet in fermentum nec, congue vitae ante. Nullam imperdiet maximus commodo. Morbi pharetra id purus ac ultrices. Duis non posuere libero.

+
+ +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eu felis volutpat, rutrum ex quis, lobortis ex. Curabitur quis mattis lorem. Nullam magna lacus, interdum vel maximus nec, vestibulum non quam. Phasellus ornare efficitur porttitor. Quisque neque diam, imperdiet in fermentum nec, congue vitae ante. Nullam imperdiet maximus commodo. Morbi pharetra id purus ac ultrices. Duis non posuere libero.

+
+
+ ); +}; + + diff --git a/kitchen-sink/components/pages/DynamicRoutePage.tsx b/kitchen-sink/components/pages/DynamicRoutePage.tsx new file mode 100644 index 0000000..d98f832 --- /dev/null +++ b/kitchen-sink/components/pages/DynamicRoutePage.tsx @@ -0,0 +1,55 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlockTitle, ContentBlock, List, ListItem, ListLabel, ListGroup, ListButton} from 'framework7-react'; +import {getCurrentRoute} from '../App'; + +export class DynamicRoutePage extends React.Component { + private currentRoute: any; + + constructor(props: any, context: any) { + super(props, context); + + this.currentRoute = getCurrentRoute(); + } + + render() { + return ( + + + + +
    +
  • Url: {this.currentRoute.url}
  • +
  • Path: {this.currentRoute.path}
  • +
  • Hash: {this.currentRoute.hash}
  • +
  • Params: +
      + { + Object.keys(this.currentRoute.params).map((paramName, index) => { + return (
    • {`${paramName}: `}{this.currentRoute.params[paramName]}
    • ); + }) + } +
    +
  • +
  • Query: +
      + { + Object.keys(this.currentRoute.query).map((queryItem, index) => { + return (
    • {`${queryItem}:`} {this.currentRoute.query[queryItem]}
    • ); + }) + } +
    +
  • +
  • Route: {this.currentRoute.route.path}
  • +
+
+ +

Route params are also passed as component props:

+
    +
  • id: {this.props.id}
  • +
  • post_id: {this.props.post_id}
  • +
+
+
+ ); + } +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/FabDialPage.tsx b/kitchen-sink/components/pages/FabDialPage.tsx new file mode 100644 index 0000000..2cb985e --- /dev/null +++ b/kitchen-sink/components/pages/FabDialPage.tsx @@ -0,0 +1,49 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, Fab, FabSpeedDial, FabSpeedDialActions, FabSpeedDialAction, Icon} from 'framework7-react'; + +const onActionClick = () => { + console.log('Dial action clicked!') +} + +export const FabDialPage = () => { + return ( + + + + + + A + B + C + + + + + + + + +

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reiciendis autem necessitatibus, commodi nostrum ad, quod laudantium magnam facilis sed explicabo maiores aliquam, iure ipsam totam. Cum rerum facilis, eveniet temporibus.

+

Blanditiis mollitia recusandae eius, repellat, vero nihil totam, asperiores voluptas vitae omnis sapiente. Optio recusandae impedit quae pariatur rem sed officia fugiat ipsum, ut esse ex delectus, provident. Error, fuga.

+

Labore harum dignissimos obcaecati quae? In cum pariatur culpa delectus provident alias sed libero optio assumenda recusandae doloribus praesentium, natus, quaerat itaque consequuntur velit ipsam minus illo reiciendis rem quisquam.

+

Necessitatibus aut optio consectetur quia illum praesentium culpa, alias aliquam accusantium, molestiae sapiente tenetur porro ipsum eligendi doloribus qui laudantium corporis ullam dolore. Illum, nostrum, eveniet? Explicabo quibusdam assumenda unde.

+

Mollitia libero explicabo nemo id nesciunt blanditiis repellat sed alias ipsum saepe repellendus dolorum laborum molestias commodi quia temporibus error provident, vitae nihil eum corporis, voluptatum. Nobis quasi error porro?

+

Perspiciatis illo veniam dolorem, dignissimos provident odio maiores sit voluptatem, commodi nostrum non quidem molestias rem dolores, magni odit omnis officiis? Quia impedit atque ut optio officiis, pariatur necessitatibus voluptatum.

+

Eveniet officiis iure voluptatum, deserunt explicabo recusandae nemo aperiam dolorem quaerat sapiente. Quo facilis aspernatur fuga, fugit animi provident voluptas excepturi. Nihil deleniti, quisquam, ipsa eaque recusandae deserunt placeat iste!

+

Rem, corporis doloremque porro neque incidunt sequi molestiae consectetur, mollitia repellendus, ipsa laborum omnis commodi similique. Nulla assumenda cumque distinctio saepe at voluptatem laudantium soluta, enim, perspiciatis, accusamus, non officia.

+

Obcaecati odit libero dolor, quasi corporis, illum. Modi voluptatum, alias ea quia dolorem sapiente dolor qui nihil expedita fugiat provident omnis quidem explicabo vitae, non pariatur. Laudantium, explicabo, dolorem. Sunt.

+

Expedita architecto, consectetur quo veniam, labore, optio aut illo quibusdam minus doloremque mollitia voluptate corrupti dolorum maxime repellendus a qui sunt omnis? Voluptas esse officia porro dicta officiis incidunt facilis!

+

Nam aperiam pariatur quo repellat maiores voluptatibus, excepturi mollitia, dolores eveniet suscipit in a ex voluptas dignissimos soluta aspernatur eius quasi. Illum quis iusto dignissimos commodi sequi dolores non, laboriosam?

+

Minima quas illum consectetur, id cumque odit dolor dolores tempora suscipit sapiente rem repudiandae, a veniam, non officiis facere, enim earum est. Rerum ullam consectetur, voluptatibus, dolor amet eligendi voluptatem?

+

Eius ad earum, vero eos. Odit blanditiis explicabo maiores, sint facere qui adipisci temporibus officia rerum voluptatibus debitis. Veritatis tempore rem porro illum quasi aut eveniet molestiae modi, aliquam impedit!

+

Aliquam suscipit sunt dolorum sapiente deleniti natus a beatae labore libero excepturi laudantium molestiae magni hic itaque officiis unde doloribus enim placeat nisi dolore, voluptas ipsum quaerat! Magnam, culpa, natus.

+

Est quidem doloremque, tempore quam earum ipsa accusantium, suscipit quaerat vitae pariatur velit sit expedita atque. Doloribus magnam magni ab, autem aliquam veritatis! Perspiciatis, laboriosam provident, impedit saepe maxime aspernatur.

+

Autem nihil voluptatem beatae deserunt distinctio ex ad maiores adipisci omnis et, sint quia eveniet expedita quis provident dolores? Sit ipsam saepe, consequuntur! Eos non amet mollitia nesciunt labore error.

+

Esse voluptatum animi tempora voluptatem, quibusdam nobis tenetur, odio optio placeat, nesciunt praesentium consequuntur consequatur repellat alias porro! Enim veritatis nobis a aspernatur maiores nostrum praesentium, consequatur laudantium quos ratione.

+

Adipisci amet, tempore, distinctio laboriosam nisi numquam earum, reprehenderit nesciunt esse quam illum, illo similique provident in a commodi dignissimos consectetur neque enim porro. Sint maiores pariatur ab iusto quo!

+

Consectetur non, reprehenderit fuga, vitae pariatur est numquam mollitia eius ut at enim cumque. Sunt consequuntur aut, amet fuga! Omnis architecto autem necessitatibus voluptatem sunt minus quod quam laborum inventore.

+

Error excepturi libero commodi, consequuntur molestiae facilis ea! Quod molestiae a voluptates ex maiores harum, aut reprehenderit repudiandae temporibus officiis, esse ratione est asperiores architecto nesciunt veritatis laudantium recusandae. Harum!

+
+
+ ); +} diff --git a/kitchen-sink/components/pages/FabPage.tsx b/kitchen-sink/components/pages/FabPage.tsx new file mode 100644 index 0000000..ce87095 --- /dev/null +++ b/kitchen-sink/components/pages/FabPage.tsx @@ -0,0 +1,37 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, Fab, Icon} from 'framework7-react'; + + +export const FabPage = () => { + return ( + + + + + + + +

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reiciendis autem necessitatibus, commodi nostrum ad, quod laudantium magnam facilis sed explicabo maiores aliquam, iure ipsam totam. Cum rerum facilis, eveniet temporibus.

+

Blanditiis mollitia recusandae eius, repellat, vero nihil totam, asperiores voluptas vitae omnis sapiente. Optio recusandae impedit quae pariatur rem sed officia fugiat ipsum, ut esse ex delectus, provident. Error, fuga.

+

Labore harum dignissimos obcaecati quae? In cum pariatur culpa delectus provident alias sed libero optio assumenda recusandae doloribus praesentium, natus, quaerat itaque consequuntur velit ipsam minus illo reiciendis rem quisquam.

+

Necessitatibus aut optio consectetur quia illum praesentium culpa, alias aliquam accusantium, molestiae sapiente tenetur porro ipsum eligendi doloribus qui laudantium corporis ullam dolore. Illum, nostrum, eveniet? Explicabo quibusdam assumenda unde.

+

Mollitia libero explicabo nemo id nesciunt blanditiis repellat sed alias ipsum saepe repellendus dolorum laborum molestias commodi quia temporibus error provident, vitae nihil eum corporis, voluptatum. Nobis quasi error porro?

+

Perspiciatis illo veniam dolorem, dignissimos provident odio maiores sit voluptatem, commodi nostrum non quidem molestias rem dolores, magni odit omnis officiis? Quia impedit atque ut optio officiis, pariatur necessitatibus voluptatum.

+

Eveniet officiis iure voluptatum, deserunt explicabo recusandae nemo aperiam dolorem quaerat sapiente. Quo facilis aspernatur fuga, fugit animi provident voluptas excepturi. Nihil deleniti, quisquam, ipsa eaque recusandae deserunt placeat iste!

+

Rem, corporis doloremque porro neque incidunt sequi molestiae consectetur, mollitia repellendus, ipsa laborum omnis commodi similique. Nulla assumenda cumque distinctio saepe at voluptatem laudantium soluta, enim, perspiciatis, accusamus, non officia.

+

Obcaecati odit libero dolor, quasi corporis, illum. Modi voluptatum, alias ea quia dolorem sapiente dolor qui nihil expedita fugiat provident omnis quidem explicabo vitae, non pariatur. Laudantium, explicabo, dolorem. Sunt.

+

Expedita architecto, consectetur quo veniam, labore, optio aut illo quibusdam minus doloremque mollitia voluptate corrupti dolorum maxime repellendus a qui sunt omnis? Voluptas esse officia porro dicta officiis incidunt facilis!

+

Nam aperiam pariatur quo repellat maiores voluptatibus, excepturi mollitia, dolores eveniet suscipit in a ex voluptas dignissimos soluta aspernatur eius quasi. Illum quis iusto dignissimos commodi sequi dolores non, laboriosam?

+

Minima quas illum consectetur, id cumque odit dolor dolores tempora suscipit sapiente rem repudiandae, a veniam, non officiis facere, enim earum est. Rerum ullam consectetur, voluptatibus, dolor amet eligendi voluptatem?

+

Eius ad earum, vero eos. Odit blanditiis explicabo maiores, sint facere qui adipisci temporibus officia rerum voluptatibus debitis. Veritatis tempore rem porro illum quasi aut eveniet molestiae modi, aliquam impedit!

+

Aliquam suscipit sunt dolorum sapiente deleniti natus a beatae labore libero excepturi laudantium molestiae magni hic itaque officiis unde doloribus enim placeat nisi dolore, voluptas ipsum quaerat! Magnam, culpa, natus.

+

Est quidem doloremque, tempore quam earum ipsa accusantium, suscipit quaerat vitae pariatur velit sit expedita atque. Doloribus magnam magni ab, autem aliquam veritatis! Perspiciatis, laboriosam provident, impedit saepe maxime aspernatur.

+

Autem nihil voluptatem beatae deserunt distinctio ex ad maiores adipisci omnis et, sint quia eveniet expedita quis provident dolores? Sit ipsam saepe, consequuntur! Eos non amet mollitia nesciunt labore error.

+

Esse voluptatum animi tempora voluptatem, quibusdam nobis tenetur, odio optio placeat, nesciunt praesentium consequuntur consequatur repellat alias porro! Enim veritatis nobis a aspernatur maiores nostrum praesentium, consequatur laudantium quos ratione.

+

Adipisci amet, tempore, distinctio laboriosam nisi numquam earum, reprehenderit nesciunt esse quam illum, illo similique provident in a commodi dignissimos consectetur neque enim porro. Sint maiores pariatur ab iusto quo!

+

Consectetur non, reprehenderit fuga, vitae pariatur est numquam mollitia eius ut at enim cumque. Sunt consequuntur aut, amet fuga! Omnis architecto autem necessitatibus voluptatem sunt minus quod quam laborum inventore.

+

Error excepturi libero commodi, consequuntur molestiae facilis ea! Quod molestiae a voluptates ex maiores harum, aut reprehenderit repudiandae temporibus officiis, esse ratione est asperiores architecto nesciunt veritatis laudantium recusandae. Harum!

+
+
+ ); +} diff --git a/kitchen-sink/components/pages/FormsPage.tsx b/kitchen-sink/components/pages/FormsPage.tsx new file mode 100644 index 0000000..f268447 --- /dev/null +++ b/kitchen-sink/components/pages/FormsPage.tsx @@ -0,0 +1,186 @@ +import * as React from 'react'; +import {Page, Navbar, Button, ButtonsSegmented, ContentBlock, ContentBlockTitle, GridCol, GridRow, List, ListItem, ListLabel, FormLabel, FormInput} from 'framework7-react'; +import {getFramework7} from '../App'; + +const onChangeHandler = (event) => { + console.log('change'); +}; + +const pStyle = {margin: '1em 0'}; + +export interface IFormsPageState { + birthDate: string; + radioSelected: number; +} + +export class FormsPage extends React.Component { + private fw7: any; + + constructor() { + super(); + + this.state = { + birthDate: '2014-04-30', + radioSelected: 1 + } + + this.fw7 = getFramework7(); + } + + private onRadioChange(value) { + this.setState({ + ...this.state, + radioSelected: value + }); + } + + render() { + return ( + + + + Form + + + Name + + + + Password + + + + E-mail + + + + URL + + + + Phone + + + + Birth date + + + + Date time + + + + Gender + + + + + + + Switch + + + + Range + + + + Textarea + + + + + Form With Floating Labels + + + Name + + + + Password + + + + E-mail + + + + + Form Without Labels + + + + + + + + + + + + + Checkboxes + + { + [1, 2, 3].map(n => { + return ( + + ); + }) + } + + + Radios + + { + [1, 2, 3].map(n => { + return ( + {this.onRadioChange(n);}} + /> + ); + }) + } + + + Buttons + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } +} diff --git a/kitchen-sink/components/pages/GridPage.tsx b/kitchen-sink/components/pages/GridPage.tsx new file mode 100644 index 0000000..4f53396 --- /dev/null +++ b/kitchen-sink/components/pages/GridPage.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, ContentBlockTitle, GridRow, GridCol} from 'framework7-react'; + +const columnStyle = {border: '1px solid #e5e5e5', padding: '5px', textAlign: 'center'}; +const rowStyle = { margin: '1em 0' }; + +export const GridPage = () => { + return ( + + + + Grid + + + 50% + 50% + + + 33% + 33% + 33% + + + 50% + 25% + 25% + + + 66% + 33% + + + + ); +} \ No newline at end of file diff --git a/kitchen-sink/components/pages/IndexPage.tsx b/kitchen-sink/components/pages/IndexPage.tsx deleted file mode 100644 index 1d17e54..0000000 --- a/kitchen-sink/components/pages/IndexPage.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import * as React from 'react'; -import {hashHistory} from 'react-router'; -import { - Page, PageBody, PageContent, - Navbar, Left, Center, Right, - ContentBlock, - ListBlock, ListItem, - Icon, - SidePanel, PanelSlideInType, PanelSideEnum -} from 'framework7-react'; - -import {routeState} from '../../utils/RouteState'; -import {pages} from '../App'; - -export interface IIndexPageState { - leftPanelOpen: boolean; -} - -const getPages = () => { - return pages.map((page, index) => { - const pageTitle = page.pageTitle; - const pageId = '/' + pageTitle.toLowerCase().replace(/\s/g, '-'); - - if (index) { - return routeState.navigate(pageId, false)} /> - } else { - return null; - } - }); -}; - -const PageList = () => { - return ( - - {getPages()} - - ); -}; - -export class IndexPage extends React.Component { - constructor() { - super(); - - this.state = { - leftPanelOpen: false - }; - } - - public render() { - return ( - - - -

- This is a side panel. You can close it by clicking outsite or on this link: - close me. -

-
- -
- - -
Framework7 React
- -
- - - - - -
- ); - } - - private toggleLeftPanel() { - this.setState({ - leftPanelOpen: !this.state.leftPanelOpen - }); - } -} \ No newline at end of file diff --git a/kitchen-sink/components/pages/InfinitePage.tsx b/kitchen-sink/components/pages/InfinitePage.tsx new file mode 100644 index 0000000..58963a2 --- /dev/null +++ b/kitchen-sink/components/pages/InfinitePage.tsx @@ -0,0 +1,67 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, ContentBlockTitle, List, ListItem, ListLabel} from 'framework7-react'; + +export interface IInfinitePageState { + items: number[]; + counter: number; +} + +export class InfinitePage extends React.Component { + private timeout: any; + + constructor() { + super(); + let itemsArr: number[] = []; + + for (let i = 0; i < 25; i++) { + itemsArr.push(i + 1); + } + + this.state = { + items: itemsArr, + counter: itemsArr.length + }; + } + + render() { + return ( + + + + Scroll list down to load new items + Infinite Scroll + + { + this.state.items.map(n => { + return ; + }) + } + + + ); + } + + private onInfiniteScroll() { + let self = this; + let newItems = this.state.items.slice(); + let newCounter = this.state.counter; + + if (this.timeout) { + clearTimeout(this.timeout); + } + + this.timeout = setTimeout(function () { + for (let i = newCounter; i < newCounter + 25; i++) { + newItems.push(i + 1); + } + + self.setState({ + counter: newCounter + 25, + items: newItems + }); + }, 500); + } +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/ListViewPage.tsx b/kitchen-sink/components/pages/ListViewPage.tsx deleted file mode 100644 index cdaca3a..0000000 --- a/kitchen-sink/components/pages/ListViewPage.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from 'react'; -import {Page, Navbar, Left, Right, Center, PageBody, PageContent, ContentBlock, ListBlock, ListItem, Icon, BackButton} from 'framework7-react'; - -import {routeState} from '../../utils/RouteState'; - -export const ListViewPage = () => { - return ( - - - routeState.navigate('/', true)} /> -
List View
- -
- - - -

- Framework7 allows you to be flexible with list views (table views). - You can make them as navigation menus, you can use their icons, - inputs, and any elements inside of the list, and even make them nested: -

-
- - - - - - - - - - - - - - -
-
-
- ); -}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/ListsPage.tsx b/kitchen-sink/components/pages/ListsPage.tsx new file mode 100644 index 0000000..13924ef --- /dev/null +++ b/kitchen-sink/components/pages/ListsPage.tsx @@ -0,0 +1,74 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlockTitle, List, ListItem, ListLabel, ListGroup, ListButton} from 'framework7-react'; + +export const ListsPage = () => { + return ( + + + + List + + { + [1, 2, 3, 4, 5].map(n => { + return ; + }) + } + Hello I'm List Label + + + Grouped List + + { + [1, 2].map(n => { + return ( + + { + [1, 2, 3].map(m => { + return + }) + } + + ); + }) + } + Hello I'm List Label + + + Media List + + { + [1, 2].map(n => { + return `} + text="Some text goes here" + after="After" + link="http://google.com" + />; + }) + } + + + Buttons List + + { + [1, 2, 3].map(n => { + return + }) + } + + + ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/LoginScreenPage.tsx b/kitchen-sink/components/pages/LoginScreenPage.tsx new file mode 100644 index 0000000..bc78b7b --- /dev/null +++ b/kitchen-sink/components/pages/LoginScreenPage.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; +import {Page, LoginScreenTitle, List, ListButton, ListItem, ListLabel, FormInput, FormLabel} from 'framework7-react'; + +export const LoginScreenPage = () => { + return ( + + My App + + + Username + + + + Password + + + + + + +

Click Sign In to close Login Screen

+
+
+
+ ); +} diff --git a/kitchen-sink/components/pages/MessagesPage.tsx b/kitchen-sink/components/pages/MessagesPage.tsx new file mode 100644 index 0000000..8147252 --- /dev/null +++ b/kitchen-sink/components/pages/MessagesPage.tsx @@ -0,0 +1,126 @@ +import * as React from 'react'; +import {Page, Navbar, Subnavbar, FormInput, Messages, Message, Messagebar} from 'framework7-react'; + +export interface IMessagesPageState { + name: string; + messages: any[]; +} + +export const MessagesPageDefaultState = { + name: 'Vladimir', + messages: [{ + day: 'Wendesday', + time: '13:34' + }, { + name: 'Vladimir', + text: 'How are you?', + label: 'Sent in good mood :)', + avatar: 'http://lorempixel.com/100/100/people/3', + date: 'Yesterday 13:34' + }, { + name: 'Jane', + text: 'I\'m good, thank you!', + type: 'received', + avatar: 'http://lorempixel.com/100/100/people/9', + date: 'Yesterday at 13:50' + } + ] +} + +export class MessagesPage extends React.Component { + constructor() { + super(); + this.state = { + name: MessagesPageDefaultState.name, + messages: MessagesPageDefaultState.messages + }; + } + + private getMessage(props, index) { + let messageProps = {} + + if (props) { + messageProps = props; + } + + return ( + + + ); + } + + render() { + return ( + + + + + + + { + this.state.messages.map((message, index) => { + return this.getMessage(message, index); + }) + } + + + + ); + } + + private onClick() { + console.log('click'); + } + + private onTextClick() { + console.log('text click'); + } + + private onNameClick() { + console.log('name click'); + } + + private onAvatarClick() { + console.log('avatar click'); + } + + private onSubmit(text, clear) { + if (text.trim().length === 0) return; + + this.setState({ + ...this.state, + messages: [ + ...this.state.messages, + { + name: this.state.name, + avatar: 'http://lorempixel.com/100/100/people/3', + text: text, + date: (function () { + let now = new Date(); + let hours = now.getHours(); + let hoursString = hours < 10 ? `0${hours}` : `${hours}`; + let minutes = now.getMinutes(); + let minutesString = minutes < 10 ? `0${minutes}` : `${minutes}`; + return `${hours}:${minutesString}`; + })() + } + ] + }); + + clear(); + } + + private onNameChange(event) { + this.setState({ + ...this.state, + name: event.target.value + }); + } + +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/ModalsPage.tsx b/kitchen-sink/components/pages/ModalsPage.tsx new file mode 100644 index 0000000..8e81aa7 --- /dev/null +++ b/kitchen-sink/components/pages/ModalsPage.tsx @@ -0,0 +1,187 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, ContentBlockTitle, GridRow, GridCol, Button} from 'framework7-react'; +import {getFramework7} from '../App'; + +import {ActionsDemo} from '../demo/ActionsDemo'; +import {PopoverDemo} from '../demo/PopoverDemo'; +import {PopupDemo} from '../demo/PopupDemo'; +import {PickerModalDemo} from '../demo/PickerModalDemo'; +import {LoginScreenDemo} from '../demo/LoginScreenDemo'; + +declare const require: any; +const Portal = require('react-portal'); + +export interface IModalsPageState { + pickerOpened: boolean; + popupOpened: boolean; + actionsOpened: boolean; + loginScreenOpened: boolean; +} + +export class ModalsPage extends React.Component { + private fw7: any; + + constructor() { + super(); + + this.fw7 = getFramework7(); + + this.state = { + pickerOpened: false, + popupOpened: false, + actionsOpened: false, + loginScreenOpened: false + } + } + + render() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* Anything you want rendered in the body like modals, etc. can be done using react-portal */} + + + + + + + + + + + ); + } + + private openLoginScreen() { + this.setState({ + ...this.state, + loginScreenOpened: true + }); + } + + private closeLoginScreen() { + this.setState({ + ...this.state, + loginScreenOpened: false + }); + } + + private openPicker() { + this.setState({ + ...this.state, + pickerOpened: true + }); + } + + private closePicker() { + this.setState({ + ...this.state, + pickerOpened: false + }); + } + + private openActions() { + this.setState({ + ...this.state, + actionsOpened: true + }); + } + + private closeActions() { + this.setState({ + ...this.state, + actionsOpened: false + }); + } + + private openAlert() { + this.fw7.alert('Hi, this is alert', 'Alert Title'); + } + + private openConfirm() { + this.fw7.confirm('Are you sure you want to do it?', 'Confirm Title', function () { + console.log('Confirm Ok'); + }, function () { + console.log('Confirm Cancel'); + }); + } + + private openPrompt() { + let self = this; + + self.fw7.prompt('Your name please!', 'Prompt Title', function (value) { + self.fw7.alert('Your name is: ' + value, 'Your name'); + }); + } + + private openPreloader() { + let self = this; + self.fw7.showPreloader('Loading text...'); + + setTimeout(function () { + self.fw7.hidePreloader(); + }, 3000); + } + + private openPopup() { + this.setState({ + ...this.state, + popupOpened: true + }); + } + + private closePopup() { + this.setState({ + ...this.state, + popupOpened: false + }); + } +} \ No newline at end of file diff --git a/kitchen-sink/components/pages/NavbarAndToolbarPage.tsx b/kitchen-sink/components/pages/NavbarAndToolbarPage.tsx deleted file mode 100644 index c026f3c..0000000 --- a/kitchen-sink/components/pages/NavbarAndToolbarPage.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from 'react'; -import {Page, PageBody, PageContent, Navbar, Left, Center, Right, BackButton, ContentBlock} from 'framework7-react'; - -import {routeState} from '../../utils/RouteState'; - -export const NavbarAndToolbarPage = () => { - return ( - - - routeState.navigate('/', true)} /> -
Navbars and Toolbars
- -
- - - - WIP - - - -
- ); -}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/NestedRoutesPage.tsx b/kitchen-sink/components/pages/NestedRoutesPage.tsx new file mode 100644 index 0000000..56328d3 --- /dev/null +++ b/kitchen-sink/components/pages/NestedRoutesPage.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlockTitle, List, ListItem} from 'framework7-react'; + +export const NestedRoutesPage = () => { + return ( + + + Tabs + + + + + + ); +}; + diff --git a/kitchen-sink/components/pages/NestedRoutesTabbarPage.tsx b/kitchen-sink/components/pages/NestedRoutesTabbarPage.tsx new file mode 100644 index 0000000..5672396 --- /dev/null +++ b/kitchen-sink/components/pages/NestedRoutesTabbarPage.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; +import {Page, Navbar, Toolbar, ContentBlock, ContentBlockTitle, List, ListItem, Tab, Link} from 'framework7-react'; + +export const NestedRoutesTabbarPage = () => { + return ( + + + + + + + + + + + + + + + + ); +}; + diff --git a/kitchen-sink/components/pages/NestedRoutesTabsPage.tsx b/kitchen-sink/components/pages/NestedRoutesTabsPage.tsx new file mode 100644 index 0000000..f154a38 --- /dev/null +++ b/kitchen-sink/components/pages/NestedRoutesTabsPage.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import {Page, Navbar, Subnavbar, ContentBlock, ContentBlockTitle, List, ListItem, Tabs, Tab, ButtonsSegmented, Button} from 'framework7-react'; + +export const NestedRoutesTabsPage = () => { + return ( + + + + + + + + + + + + + + + + + + ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/PhotoBrowserPage.tsx b/kitchen-sink/components/pages/PhotoBrowserPage.tsx new file mode 100644 index 0000000..d07788c --- /dev/null +++ b/kitchen-sink/components/pages/PhotoBrowserPage.tsx @@ -0,0 +1,93 @@ +import * as React from 'react'; +import {Page, Navbar, PhotoBrowser, Link} from 'framework7-react'; +import {getFramework7} from '../App'; + +export interface IPhoto { + url?: string, + caption?: string +} + +export interface IPhotoBrowserPageState { + photos: IPhoto[] +} + +export const PhotoBrowserPageDefaultState = [{ + url: 'http://lorempixel.com/400/400/nature/1/', + caption: 'Ants on grass' + }, + 'http://placekitten.com/600/600', + 'http://lorempixel.com/400/400/nature/2/', + { + url: 'http://lorempixel.com/400/400/nature/3/', + caption: 'Beautiful mountains in Zhangjiajie, China' + }, { + url: 'http://lorempixel.com/400/400/nature/4/', + caption: 'Trees in the Fall' + } +]; + +const photoStyle = { + height: "20vw", + width: "20%" +}; + +export class PhotoBrowserPage extends React.Component { + private fw7: any; + + constructor() { + super(); + this.state = { + photos: PhotoBrowserPageDefaultState + }; + + this.fw7 = getFramework7(); + } + + render() { + return ( + + + { + this.state.photos.map((photo, index) => { + return ( + {this.openPhotoBrowser(index)}}> + { + this.getImage(photo, index) + } + + ); + }) + } + + ); + } + + private openPhotoBrowser(index:number) { + let photoBrowser = this.fw7.photoBrowser({ + photos: this.state.photos, + theme: "dark", + onOpen: this.onOpen, + onClose: this.onClose + }); + + photoBrowser.open(index); + } + + private onOpen(index:number) { + console.log('Photo Browser opened'); + } + + private onClose(index:number) { + console.log('Photo Browser closed'); + } + + private getImage(photo: any, index: number ) { + let imageSrc = ''; + + if (typeof photo === 'string') { + return (); + } else if (typeof photo === 'object') { + return (); + } + } +} \ No newline at end of file diff --git a/kitchen-sink/components/pages/PreloaderPage.tsx b/kitchen-sink/components/pages/PreloaderPage.tsx new file mode 100644 index 0000000..e779b2e --- /dev/null +++ b/kitchen-sink/components/pages/PreloaderPage.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, ContentBlockTitle, GridRow, GridCol, Preloader} from 'framework7-react'; + +const pStyle = {margin: '1em 0'}; +const backgroundStyle = {background: '#333'}; + +export const PreloaderPage = () => { + return ( + + + + Preloader + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} \ No newline at end of file diff --git a/kitchen-sink/components/pages/ProgressBarPage.tsx b/kitchen-sink/components/pages/ProgressBarPage.tsx index fe87cb5..478d221 100644 --- a/kitchen-sink/components/pages/ProgressBarPage.tsx +++ b/kitchen-sink/components/pages/ProgressBarPage.tsx @@ -1,46 +1,29 @@ import * as React from 'react'; -import {Page, Navbar, Left, Right, Center, ColorsEnum, PageBody, PageContent, ContentBlock, ListBlock, ListItem, Icon, BackButton, ProgressBar} from 'framework7-react'; +import {Page, Navbar, ContentBlockTitle, List, ListItem, Progressbar} from 'framework7-react'; -import {routeState} from '../../utils/RouteState'; - -export const ProgressBarPage = () => { +export const ProgressbarPage = () => { return ( - - - routeState.navigate('/', true)} /> -
Progress Bar
- -
- - - -

- Framework7 has two different styles of progress bars...determinate - (accepts a progress percentage number to update itself) and indeterminate/infinite - (when no progress number can be calculated) to indicate activity: -

-
- - - - - - - - - - - - - - - - - - - -
-
+ + + + Progressbar + + + + + + + + + + + + + + + + + ); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/kitchen-sink/components/pages/PullRefreshPage.tsx b/kitchen-sink/components/pages/PullRefreshPage.tsx new file mode 100644 index 0000000..37f0939 --- /dev/null +++ b/kitchen-sink/components/pages/PullRefreshPage.tsx @@ -0,0 +1,55 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlockTitle, List, ListItem, ListLabel} from 'framework7-react'; + +export interface IPullRefreshPageState { + items: number[]; + counter: number; +} + +export class PullRefreshPage extends React.Component { + constructor() { + super(); + this.state = { + items: [1, 2, 3, 4, 5], + counter: 5 + }; + } + + render() { + return ( + + + + Pull To Refresh + + { + this.state.items.map(n => { + return ; + }) + } + Pull list down to refresh items + + + ); + } + + private onRefresh(event, callBack) { + let self = this; + let newItems = this.state.items.slice(); + let newCounter = this.state.counter + 1; + + newItems.push(newCounter); + + setTimeout(function () { + self.setState({ + counter: newCounter, + items: newItems + }); + + callBack(); + }, 2000); + } +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/SearchbarPage.tsx b/kitchen-sink/components/pages/SearchbarPage.tsx new file mode 100644 index 0000000..5aa41fd --- /dev/null +++ b/kitchen-sink/components/pages/SearchbarPage.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import {Page, Navbar, List, ListItem, Searchbar} from 'framework7-react'; + +const onSearch = (event) => { + console.log('search', event[0]); +} + +const onClear = (event) => { + console.log('clear'); +} + +const onEnable = (event) => { + console.log('enable'); +} + +const onDisable = (event) => { + console.log('disable'); +} + +export const SearchbarPage = () => { + return ( + + + + + + + + + { + Array.apply(null, Array(100)).map((item, index) => { + return (); + }) + } + + + ); +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/SmartSelectPage.tsx b/kitchen-sink/components/pages/SmartSelectPage.tsx new file mode 100644 index 0000000..84014fd --- /dev/null +++ b/kitchen-sink/components/pages/SmartSelectPage.tsx @@ -0,0 +1,59 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlockTitle, List, ListItem} from 'framework7-react'; + +const onChangeHandler = (event) => { + console.log('change'); +}; + +export const SmartSelectPage = () => { + return ( + + + + Smart Select + + + + + + + + + + + + + ); +} diff --git a/kitchen-sink/components/pages/SortablePage.tsx b/kitchen-sink/components/pages/SortablePage.tsx new file mode 100644 index 0000000..ed2e18b --- /dev/null +++ b/kitchen-sink/components/pages/SortablePage.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import {Page, Navbar, NavRight, Link, ContentBlockTitle, List, ListItem} from 'framework7-react'; + +export interface ISortablePageState { + items: number[]; + sorting: boolean; +} + +export class SortablePage extends React.Component { + constructor() { + super(); + this.state = { + sorting: false, + items: [1, 2, 3, 4, 5] + }; + } + + render() { + return ( + + + + {this.state.sorting ? 'Done' : 'Open'} + + + + Sortable List + + { + this.state.items.map(item => { + return ; + }) + } + + + ); + } + + private onOpen() { + this.setState({ + ...this.state, + sorting: !this.state.sorting + }); + } + + private onClose() { + this.setState({ + ...this.state, + sorting: !this.state.sorting + }); + } +}; \ No newline at end of file diff --git a/kitchen-sink/components/pages/SwipeoutPage.tsx b/kitchen-sink/components/pages/SwipeoutPage.tsx new file mode 100644 index 0000000..f437d18 --- /dev/null +++ b/kitchen-sink/components/pages/SwipeoutPage.tsx @@ -0,0 +1,88 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlockTitle, List, ListItem, ListItemSwipeoutActions, ListItemSwipeoutButton} from 'framework7-react'; + +const onSwipeoutDeleted = (event) => { + console.log('swipeout deleted'); +}; + +export const SwipeoutPage = () => ( + + + + Swipe To Delete + + { + [1, 2, 3].map(n => { + return ( + + + Delete + + + ); + }) + } + + + Multiple Actions + + { + [1, 2, 3].map(n => { + return ( + + + Close + Delete + + + ); + }) + } + + + Actions On Left + + { + [1, 2, 3].map(n => { + return ( + + + Reply + Close + + + ); + }) + } + + + Actions On Both Sides + + { + [1, 2].map(n => { + return ( + `} + text="Some text goes here" + after="After" + link="http://google.com" + > + + Reply + Close + + + More + Delete + + + ); + }) + } + + +); \ No newline at end of file diff --git a/kitchen-sink/components/pages/SwiperPage.tsx b/kitchen-sink/components/pages/SwiperPage.tsx new file mode 100644 index 0000000..0dade1e --- /dev/null +++ b/kitchen-sink/components/pages/SwiperPage.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlockTitle, Swiper, SwiperSlide} from 'framework7-react'; + + +const swiperItems = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + +const swiperHeight = { + height: "200px" +}; + +const swiperParams = { + slidesPerView: 3, + spaceBetween: 20 +} + +const swiperMap = (item: number) => { + return ({`Slide ${item}`}); +} + +export const SwiperPage = () => { + return ( + + + + Default + + { + swiperItems.map(swiperMap) + } + + + Navigation + + { + swiperItems.map(swiperMap) + } + + + Slides Per View + + { + swiperItems.map(swiperMap) + } + + + ); +} \ No newline at end of file diff --git a/kitchen-sink/components/pages/TabsPage.tsx b/kitchen-sink/components/pages/TabsPage.tsx new file mode 100644 index 0000000..47cff5c --- /dev/null +++ b/kitchen-sink/components/pages/TabsPage.tsx @@ -0,0 +1,63 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, Subnavbar, Tabs, Tab, ButtonsSegmented, Button} from 'framework7-react'; + + +export const TabsPage = () => { + return ( + + + + + + + + + + + + + + + +

Tab 1

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+
+ + +

Tab 2

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+
+ + +

Tab 3

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+
+ + +

Tab 4

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+
+
+
+ ); +} diff --git a/kitchen-sink/components/pages/TabsSwipeablePage.tsx b/kitchen-sink/components/pages/TabsSwipeablePage.tsx new file mode 100644 index 0000000..2988f29 --- /dev/null +++ b/kitchen-sink/components/pages/TabsSwipeablePage.tsx @@ -0,0 +1,63 @@ +import * as React from 'react'; +import {Page, PageContent, Navbar, ContentBlock, Subnavbar, Tabs, Tab, ButtonsSegmented, Button} from 'framework7-react'; + + +export const TabsSwipeablePage = () => { + return ( + + + + + + + + + + + + + + + +

Tab 1

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+
+ + +

Tab 2

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+
+ + +

Tab 3

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+
+ + +

Tab 4

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure odio dolor, soluta reprehenderit, corporis officia earum corrupti amet ea aspernatur praesentium, distinctio ipsa atque officiis. Recusandae ab error, atque natus.

+

Quibusdam repellendus, repudiandae nulla commodi ut nemo eum, quia dolorum dicta voluptate reprehenderit. Omnis, temporibus iure quia ad sit incidunt similique et quaerat dicta delectus aspernatur, unde illo cum ipsam?

+

Officia alias inventore soluta illo, omnis tempore obcaecati at, harum impedit nemo enim, iure fugit est explicabo commodi ipsam distinctio architecto voluptatum reprehenderit, aperiam dolorem praesentium repellendus repudiandae ducimus saepe.

+

Autem ullam tempore suscipit consectetur, odit soluta. Neque quasi mollitia culpa autem, quis ab nostrum non distinctio illo magni perspiciatis et consequuntur possimus aliquam reprehenderit reiciendis praesentium consectetur, voluptas obcaecati?

+

Quae repellendus aut iste provident consectetur inventore voluptatibus, saepe ad dolorem voluptatum recusandae praesentium animi harum officiis error nulla ullam nobis? Mollitia possimus voluptatum pariatur omnis quibusdam, quidem recusandae velit.

+
+
+
+
+ ); +} diff --git a/kitchen-sink/components/pages/TimelineCalendarPage.tsx b/kitchen-sink/components/pages/TimelineCalendarPage.tsx new file mode 100644 index 0000000..050e6bf --- /dev/null +++ b/kitchen-sink/components/pages/TimelineCalendarPage.tsx @@ -0,0 +1,68 @@ +import * as React from 'react'; +import {Page, Navbar, Timeline, TimelineItem, TimelineItemChild, TimelineYear, TimelineMonth, List, ListItem, Card} from 'framework7-react'; + +const generateRandomDailyTasks = (maxNumberOfTasksPerDay: number) => { + return (Array.apply(null, Array(Math.round(Math.random() * maxNumberOfTasksPerDay))).map((item, index) => { + return ( + + ); + })); +} + +export const TimelineCalendarPage = () => { + return ( + + + + + + + { + Array.apply(null, Array(11)).map((item, index) => { + return ( + + { + generateRandomDailyTasks(3) + } + + ); + }) + } + + + + + { + Array.apply(null, Array(31)).map((item, index) => { + return ( + + { + generateRandomDailyTasks(4) + } + + ); + }) + } + + + { + Array.apply(null, Array(28)).map((item, index) => { + return ( + + { + generateRandomDailyTasks(5) + } + + ); + }) + } + + + + + ); +} diff --git a/kitchen-sink/components/pages/TimelineHorizontalPage.tsx b/kitchen-sink/components/pages/TimelineHorizontalPage.tsx new file mode 100644 index 0000000..044d8d5 --- /dev/null +++ b/kitchen-sink/components/pages/TimelineHorizontalPage.tsx @@ -0,0 +1,46 @@ +import * as React from 'react'; +import {Page, Navbar, Timeline, TimelineItem, TimelineItemChild, List, ListItem, Card} from 'framework7-react'; + + +export const TimelineHorizontalPage = () => { + return ( + + + + + + + + + + Plain text goes here + + + + + + + + + + + + + + + + + + + ); +} diff --git a/kitchen-sink/components/pages/TimelineVerticalPage.tsx b/kitchen-sink/components/pages/TimelineVerticalPage.tsx new file mode 100644 index 0000000..9ee48bd --- /dev/null +++ b/kitchen-sink/components/pages/TimelineVerticalPage.tsx @@ -0,0 +1,82 @@ +import * as React from 'react'; +import {Page, Navbar, ContentBlock, ContentBlockTitle, Timeline, TimelineItem, List, ListItem, Card} from 'framework7-react'; + + +export const TimelineVerticalPage = () => { + return ( + + + + Default + + + + + + + + Side By Side + + + + + + + + Only Tablet Side By Side + + + + + + + + Forced Sides + + + + + + + + Rich Content + + + + + + + + + + + + + + Plain text + + + Inside Content Block + + + + + + + + ); +} diff --git a/kitchen-sink/components/pages/VirtualListPage.tsx b/kitchen-sink/components/pages/VirtualListPage.tsx new file mode 100644 index 0000000..474bf4c --- /dev/null +++ b/kitchen-sink/components/pages/VirtualListPage.tsx @@ -0,0 +1,93 @@ +import * as React from 'react'; +import {Page, Navbar, List, ListItem, Searchbar, Template7Template, NavRight, Link, ContentBlock} from 'framework7-react'; + +export interface IVirtualListPageState { + items: IVirtualListItem[] +} + +export interface IVirtualListItem { + title: string, + subtitle: string +} + +export class VirtualListPage extends React.Component { + constructor() { + super(); + let defaultItems = this.getVirtualListPageDefaultState(); + + this.state = { + items: defaultItems + }; + } + + render() { + return ( + + + + New Item + + + + +

Virtual List allows to render lists with huge amount of elements without loss of performance. And it is fully compatible with all Framework7 list components such as Search Bar, Infinite Scroll, Pull To Refresh, Swipeouts (swipe-to-delete) and Sortable.

+

{`Here is the example of virtual list with 10,000 items: ${this.state.items.length}`}

+
+ + + + + + + + +
+ ); + } + + private addNewItem() { + let newItem: IVirtualListItem = { + title: `Item ${this.state.items.length +1 }`, + subtitle: `Subtitle ${this.state.items.length + 1}` + }; + + this.setState({ + items: [ + ...this.state.items, + newItem + ] + }); + } + + private searchAll(query, items) { + let found = []; + + for (let i = 0; i < items.length; i++) { + if (items[i].title.indexOf(query) >= 0 || query.trim() === '') { + found.push(i); + } + } + + return found; + } + + private getVirtualListPageDefaultState() { + let items: IVirtualListItem[] = []; + + for (let i = 1; i <= 10000; i++) { + items.push({ + title: 'Item ' + i, + subtitle: 'Subtitle ' + i + }) + } + + return items; + } +}; \ No newline at end of file diff --git a/kitchen-sink/gulpfile.js b/kitchen-sink/gulpfile.js index 4dc1193..0211bd6 100644 --- a/kitchen-sink/gulpfile.js +++ b/kitchen-sink/gulpfile.js @@ -15,4 +15,12 @@ gulp.task('webpack', ['clean'], function () { .pipe(gulp.dest('dist/')); }); -gulp.task('default', ['webpack']); \ No newline at end of file +gulp.task('copyFw7', function() { + return gulp.src([ + './node_modules/framework7-vue/kitchen-sink/framework7/*']) + .pipe(gulp.dest('./framework7/')); +}); + + + +gulp.task('default', ['webpack', 'copyFw7']); \ No newline at end of file diff --git a/kitchen-sink/index.html b/kitchen-sink/index.html index ef078a6..1e90839 100644 --- a/kitchen-sink/index.html +++ b/kitchen-sink/index.html @@ -7,7 +7,8 @@ Framework7 React - + + diff --git a/kitchen-sink/index.ts b/kitchen-sink/index.ts index 5e76d16..88f89ac 100644 --- a/kitchen-sink/index.ts +++ b/kitchen-sink/index.ts @@ -1,6 +1,6 @@ import {render} from 'react-dom'; import * as React from 'react'; -import {Routes} from './components/App'; +import {App} from './components/App'; -render(React.createElement(Routes), document.getElementById('react-root')); \ No newline at end of file +render(React.createElement(App), document.getElementById('react-root')); \ No newline at end of file diff --git a/kitchen-sink/package.json b/kitchen-sink/package.json index 3eac1c1..1124010 100644 --- a/kitchen-sink/package.json +++ b/kitchen-sink/package.json @@ -9,11 +9,8 @@ "less": "^2.7.1", "less-loader": "^2.2.3", "style-loader": "^0.13.1", - "tslint": "^4.0.2", - "tslint-loader": "^3.3.0", - "tslint-microsoft-contrib": "^4.0.0", - "tslint-react": "^2.0.0", - "typescript": "2.0.6", + "ts-loader": "^1.3.3", + "typescript": "^2.1.4", "url-loader": "^0.5.7", "webpack": "2.1.0-beta.25", "webpack-node-externals": "^1.5.4", @@ -21,8 +18,8 @@ }, "dependencies": { "framework7-react": "file:../", - "react": "15.3.2", - "react-dom": "^15.3.2", - "react-router": "2.8.1" + "react": "^15.3.2", + "react-dom": "^15.3.2", + "react-portal": "^3.0.0" } -} +} \ No newline at end of file diff --git a/kitchen-sink/routes.ts b/kitchen-sink/routes.ts new file mode 100644 index 0000000..f81f6ea --- /dev/null +++ b/kitchen-sink/routes.ts @@ -0,0 +1,201 @@ +import {ContentBlockPage} from './components/pages/ContentBlockPage'; +import {CardsPage} from './components/pages/CardsPage'; +import {ListsPage} from './components/pages/ListsPage'; +import {ContactsPage} from './components/pages/ContactsPage'; +import {SortablePage} from './components/pages/SortablePage'; +import {SwipeoutPage} from './components/pages/SwipeoutPage'; +import {AccordionPage} from './components/pages/AccordionPage'; +import {ProgressbarPage} from './components/pages/ProgressbarPage'; +import {FormsPage} from './components/pages/FormsPage'; +import {GridPage} from './components/pages/GridPage'; +import {SmartSelectPage} from './components/pages/SmartSelectPage'; +import {ChipsPage} from './components/pages/ChipsPage'; +import {PreloaderPage} from './components/pages/PreloaderPage'; +import {PullRefreshPage} from './components/pages/PullRefreshPage'; +import {InfinitePage} from './components/pages/InfinitePage'; +import {SwiperPage} from './components/pages/SwiperPage'; +import {SearchbarPage} from './components/pages/SearchbarPage'; +import {TabsPage} from './components/pages/TabsPage'; +import {TabsSwipeablePage} from './components/pages/TabsSwipeablePage'; +import {MessagesPage} from './components/pages/MessagesPage'; +import {BarsPage} from './components/pages/BarsPage'; +import {BarsTabbarPage} from './components/pages/BarsTabbarPage'; +import {BarsTabbarLabelsPage} from './components/pages/BarsTabbarLabelsPage'; +import {BarsHidePage} from './components/pages/BarsHidePage'; +import {BarsSubnavbarPage} from './components/pages/BarsSubnavbarPage'; +import {FabPage} from './components/pages/FabPage'; +import {FabDialPage} from './components/pages/FabDialPage'; +import {LoginScreenPage} from './components/pages/LoginScreenPage'; +import {VirtualListPage} from './components/pages/VirtualListPage'; +import {PhotoBrowserPage} from './components/pages/PhotoBrowserPage'; +import {ModalsPage} from './components/pages/ModalsPage'; +import {TimelineVerticalPage} from './components/pages/TimelineVerticalPage'; +import {TimelineHorizontalPage} from './components/pages/TimelineHorizontalPage'; +import {TimelineCalendarPage} from './components/pages/TimelineCalendarPage'; +import {DynamicRoutePage} from './components/pages/DynamicRoutePage'; + +import {NestedRoutesPage} from './components/pages/NestedRoutesPage'; +import {NestedRoutesTabsPage} from'./components/pages/NestedRoutesTabsPage'; +import {NestedRoutesTabbarPage} from'./components/pages/NestedRoutesTabbarPage'; +import {Tab1} from './components/nested-routes/tabs/Tab1'; +import {Tab2} from './components/nested-routes/tabs/Tab2'; +import {Tab3} from './components/nested-routes/tabs/Tab3'; +import {Tab3AlternateContent} from './components/nested-routes/tabs/Tab3AlternateContent'; +import {TabbarTab1} from './components/nested-routes/tabs/TabbarTab1'; +import {TabbarTab2} from './components/nested-routes/tabs/TabbarTab2'; +import {TabbarTab3} from './components/nested-routes/tabs/TabbarTab3'; +import {TabbarTab3AlternateContent} from './components/nested-routes/tabs/TabbarTab3AlternateContent'; + +export const routes = [{ + path: '/content-block/', + component: ContentBlockPage +}, { + path: '/cards/', + component: CardsPage +}, { + path: '/lists/', + component: ListsPage +}, { + path: '/contacts/', + component: ContactsPage +}, { + path: '/sortable/', + component: SortablePage +}, { + path: '/swipeout/', + component: SwipeoutPage +}, { + path: '/accordion/', + component: AccordionPage +}, { + path: '/progressbar/', + component: ProgressbarPage +}, { + path: '/forms/', + component: FormsPage +}, { + path: '/smart-select/', + component: SmartSelectPage +}, { + path: '/chips/', + component: ChipsPage +}, { + path: '/grid/', + component: GridPage +}, { + path: '/preloader/', + component: PreloaderPage +}, { + path: '/pull-to-refresh/', + component: PullRefreshPage +}, { + path: '/infinite/', + component: InfinitePage +}, { + path: '/swiper/', + component: SwiperPage +}, { + path: '/searchbar/', + component: SearchbarPage +}, { + path: '/tabs/', + component: TabsPage +}, { + path: '/tabs-swipeable/', + component: TabsSwipeablePage +}, { + path: '/messages/', + component: MessagesPage +}, { + path: '/bars/', + component: BarsPage +}, { + path: '/bars-tabbar/', + component: BarsTabbarPage +}, { + path: '/bars-tabbar-labels/', + component: BarsTabbarLabelsPage +}, { + path: '/bars-hide/', + component: BarsHidePage +}, { + path: '/bars-subnavbar/', + component: BarsSubnavbarPage +}, { + path: '/fab/', + component: FabPage +}, { + path: '/fab-dial/', + component: FabDialPage +}, { + path: '/login-screen/', + component: LoginScreenPage +}, { + path: '/virtual-list/', + component: VirtualListPage +}, { + path: '/photo-browser/', + component: PhotoBrowserPage +}, { + path: '/nested-routes/', + component: NestedRoutesPage +}, { + path: '/nested-routes/tabs/', + component: NestedRoutesTabsPage, + tabs: [{ + path: '/', + tabId: 'tab1', + component: Tab1 + }, { + path: '/tab-2/', + tabId: 'tab2', + component: Tab2 + }, { + path: '/tab-3/', + tabId: 'tab3', + routes: [{ + path: '/', + component: Tab3 + }, { + path: '/alternate-content/', + component: Tab3AlternateContent + }] + }] + }, { + path: '/nested-routes/tabbar/', + component: NestedRoutesTabbarPage, + tabs: [{ + path: '/', + tabId: 'tab1', + component: TabbarTab1 + }, { + path: '/tab-2/', + tabId: 'tab2', + component: TabbarTab2 + }, { + path: '/tab-3/', + tabId: 'tab3', + routes: [{ + path: '/', + component: TabbarTab3 + }, { + path: '/alternate-content/', + component: TabbarTab3AlternateContent + }] + }] + }, { + path: '/modals/', + component: ModalsPage +}, { + path: '/timeline-vertical/', + component: TimelineVerticalPage +}, { + path: '/timeline-horizontal/', + component: TimelineHorizontalPage +}, { + path: '/timeline-calendar/', + component: TimelineCalendarPage +}, { + path: '/user/:id/posts/:post_id/', + component: DynamicRoutePage +}]; \ No newline at end of file diff --git a/kitchen-sink/tsconfig.json b/kitchen-sink/tsconfig.json index 09b7f2a..4320d05 100644 --- a/kitchen-sink/tsconfig.json +++ b/kitchen-sink/tsconfig.json @@ -8,6 +8,6 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "noImplicitAny": false, - "jsx": "react" + "jsx": "react" } } \ No newline at end of file diff --git a/kitchen-sink/utils/RouteState.ts b/kitchen-sink/utils/RouteState.ts deleted file mode 100644 index faacc41..0000000 --- a/kitchen-sink/utils/RouteState.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {hashHistory} from 'react-router'; -import {AnimationDirectionEnum} from 'framework7-react'; - -export class RouteState { - public lastNavigationDirection: AnimationDirectionEnum; - - public navigate(path: string, goingBack: boolean) { - hashHistory.replace(path); - this.lastNavigationDirection = goingBack ? AnimationDirectionEnum.Back : AnimationDirectionEnum.Forward; - } -} - -export const routeState = new RouteState(); \ No newline at end of file diff --git a/kitchen-sink/webpack.config.js b/kitchen-sink/webpack.config.js index fd6e3a8..9dec3bc 100644 --- a/kitchen-sink/webpack.config.js +++ b/kitchen-sink/webpack.config.js @@ -3,6 +3,7 @@ var ExtractTextPlugin = require("extract-text-webpack-plugin"); var webpack = require('webpack'); module.exports = { + watch: true, entry: "./index.ts", resolve: { extensions: [".ts", ".tsx", ".js"] @@ -19,24 +20,24 @@ module.exports = { }, devtool: 'source-map', plugins: [ - new webpack.LoaderOptionsPlugin({ - minimize: true, - debug: false - }), - new webpack.optimize.UglifyJsPlugin({ - compress: { - warnings: false, - screw_ie8: true, - conditionals: true, - unused: true, - comparisons: true, - sequences: true, - dead_code: true, - evaluate: true, - if_return: true, - join_vars: true, - } - }), + // new webpack.LoaderOptionsPlugin({ + // minimize: true, + // debug: false + // }), + // new webpack.optimize.UglifyJsPlugin({ + // compress: { + // warnings: false, + // screw_ie8: true, + // conditionals: true, + // unused: true, + // comparisons: true, + // sequences: true, + // dead_code: true, + // evaluate: true, + // if_return: true, + // join_vars: true, + // } + // }), new ExtractTextPlugin("app.css") ] }; \ No newline at end of file diff --git a/package.json b/package.json index 9163d44..66fe998 100644 --- a/package.json +++ b/package.json @@ -1,53 +1,76 @@ { "name": "framework7-react", "version": "0.8.2-beta-1", - "description": "A React ", - "main": "dist/src/index.js", - "typings": "dist/src/index.d.ts", + "description": "A React version of Framework7", + "main": "dist/framework7-react/index.js", + "typings": "dist/framework7-react/index.d.ts", "directories": { "example": "examples" }, "scripts": { "test": "gulp test", - "build": "gulp && cd kitchen-sink && rm -rf node_modules/framework7-react && npm install && gulp" + "build": "gulp && cd kitchen-sink && rm -rf node_modules/framework7-react && npm install && gulp", + "update-f7-vue": "rm -rf node_modules/framework7-vue && npm install" }, "repository": { "type": "git", "url": "git+https://github.com/bencompton/framework7-react.git" }, - "keywords": [ - "framework7", + "keywords": [ "react", + "reactjs", + "mobile", + "framework", + "framework7", + "ios", + "iphone", + "ipad", + "apple", + "phonegap", + "touch", + "app", + "f7", + "material", + "android", "typescript" ], "author": "Ben Compton", - "license": "MIT", + "license": "APACHE 2.0", "bugs": { "url": "https://github.com/bencompton/framework7-react/issues" }, "homepage": "https://github.com/bencompton/framework7-react#readme", "devDependencies": { + "@types/node": "^6.0.54", + "babel-core": "^6.21.0", + "babel-preset-es2015": "^6.18.0", + "babel-preset-es2017": "^6.16.0", + "babel-preset-stage-2": "^6.18.0", "css-loader": "^0.25.0", - "del": "2.2.2", + "framework7": "^1.5.3", + "framework7-vue": "0.8.2", "gulp": "3.9.1", "gulp-clean": "^0.3.2", "gulp-concat": "^2.6.1", + "gulp-rename": "^1.2.2", "gulp-replace": "^0.5.4", - "gulp-sourcemaps": "^2.2.0", - "gulp-tslint": "^7.0.1", + "gulp-sourcemaps": "^2.2.1", "gulp-typescript": "^3.1.3", + "json-fn": "^1.1.1", "merge2": "^1.0.2", - "tslint": "^4.0.2", - "tslint-microsoft-contrib": "^4.0.0", - "tslint-react": "^2.0.0", - "typescript": "2.0.6" + "rollup-plugin-buble": "^0.15.0", + "rollup-plugin-vue2": "^0.6.1", + "rollup-stream": "^1.16.0", + "to-case": "^2.0.0", + "typescript": "^2.1.4", + "vinyl-buffer": "^1.0.0", + "vinyl-source-stream": "^1.1.0" }, "dependencies": { - "bluebird": "^3.4.6", - "framework7": "1.4.2", - "invariant": "2.2.1", - "jquery": "3.1.1", - "react": "^15.4.0", - "react-portal": "git+https://github.com/bencompton/react-portal.git#release" + "change-case": "^3.0.0", + "query-string": "^4.3.1" + }, + "peerDependencies": { + "react": "15.x" } } diff --git a/src/Framework7.d.ts b/src/Framework7.d.ts index 9751acf..28758c8 100644 --- a/src/Framework7.d.ts +++ b/src/Framework7.d.ts @@ -1,125 +1,125 @@ export interface IFramework7Params { - root: string; - cache: boolean; - cacheIgnore: string[]; - cacheIgnoreGetParameters: boolean; - cacheDuration: number; - preloadPreviousPage: boolean; - uniqueHistory: boolean; - uniqueHistoryIgnoreGetParameters: boolean; - dynamicPageUrl: string; - allowDuplicateUrls: boolean; - router: boolean; - routerRemoveTimeout: boolean; - routerRemoveWithTimeout: boolean; + // Auto init + init?: boolean; + preroute?: (view: View, params: any) => boolean; + root?: string; + cache?: boolean; + cacheIgnore?: string[]; + cacheIgnoreGetParameters?: boolean; + cacheDuration?: number; + preloadPreviousPage?: boolean; + uniqueHistory?: boolean; + uniqueHistoryIgnoreGetParameters?: boolean; + dynamicPageUrl?: string; + allowDuplicateUrls?: boolean; + router?: boolean; + routerRemoveTimeout?: boolean; + routerRemoveWithTimeout?: boolean; // Push State - pushState: boolean; - pushStateRoot: any; - pushStateNoAnimation: boolean; - pushStateSeparator: string; - pushStateOnLoad: boolean; + pushState?: boolean; + pushStateRoot?: any; + pushStateNoAnimation?: boolean; + pushStateSeparator?: string; + pushStateOnLoad?: boolean; // Fast clicks - fastClicks: boolean; - fastClicksDistanceThreshold: number; - fastClicksDelayBetweenClicks: number; - fastClicksExclude: string; + fastClicks?: boolean; + fastClicksDistanceThreshold?: number; + fastClicksDelayBetweenClicks?: number; + fastClicksExclude?: string; // Tap Hold - tapHold: boolean; - tapHoldDelay: number; - tapHoldPreventClicks: boolean; + tapHold?: boolean; + tapHoldDelay?: number; + tapHoldPreventClicks?: boolean; // Active State - activeState: boolean; - activeStateElements: string; + activeState?: boolean; + activeStateElements?: string; // Animate Nav Back Icon - animateNavBackIcon: boolean; + animateNavBackIcon?: boolean; // Swipe Back - swipeBackPage: boolean; - swipeBackPageThreshold: number; - swipeBackPageActiveArea: number; - swipeBackPageAnimateShadow: boolean; - swipeBackPageAnimateOpacity: boolean; + swipeBackPage?: boolean; + swipeBackPageThreshold?: number; + swipeBackPageActiveArea?: number; + swipeBackPageAnimateShadow?: boolean; + swipeBackPageAnimateOpacity?: boolean; // Ajax - ajaxLinks: string; // or CSS selector + ajaxLinks?: string; // or CSS selector // External Links - externalLinks: string; // CSS selector + externalLinks?: string; // CSS selector // Sortable - sortable: boolean; + sortable?: boolean; // Scroll toolbars - hideNavbarOnPageScroll: boolean; - hideToolbarOnPageScroll: boolean; - hideTabbarOnPageScroll: boolean; - showBarsOnPageScrollEnd: boolean; - showBarsOnPageScrollTop: boolean; + hideNavbarOnPageScroll?: boolean; + hideToolbarOnPageScroll?: boolean; + hideTabbarOnPageScroll?: boolean; + showBarsOnPageScrollEnd?: boolean; + showBarsOnPageScrollTop?: boolean; // Swipeout - swipeout: boolean; - swipeoutActionsNoFold: boolean; - swipeoutNoFollow: boolean; - swipeoutRemoveWithTimeout: boolean; + swipeout?: boolean; + swipeoutActionsNoFold?: boolean; + swipeoutNoFollow?: boolean; + swipeoutRemoveWithTimeout?: boolean; // Smart Select Back link template - smartSelectOpenIn: string; // or 'popup' or 'picker' - smartSelectBackText: string; - smartSelectPopupCloseText: string; - smartSelectPickerCloseText: string; - smartSelectSearchbar: boolean; - smartSelectBackOnSelect: boolean; + smartSelectOpenIn?: string; // or 'popup' or 'picker' + smartSelectBackText?: string; + smartSelectPopupCloseText?: string; + smartSelectPickerCloseText?: string; + smartSelectSearchbar?: boolean; + smartSelectBackOnSelect?: boolean; // Tap Navbar or Statusbar to scroll to top - scrollTopOnNavbarClick: boolean; - scrollTopOnStatusbarClick: boolean; + scrollTopOnNavbarClick?: boolean; + scrollTopOnStatusbarClick?: boolean; // Panels - swipePanel: boolean; // or 'left' or 'right' - swipePanelActiveArea: number; - swipePanelCloseOpposite: boolean; - swipePanelOnlyClose: boolean; - swipePanelNoFollow: boolean; - swipePanelThreshold: number; - panelsCloseByOutside: boolean; + swipePanel?: boolean; // or 'left' or 'right' + swipePanelActiveArea?: number; + swipePanelCloseOpposite?: boolean; + swipePanelOnlyClose?: boolean; + swipePanelNoFollow?: boolean; + swipePanelThreshold?: number; + panelsCloseByOutside?: boolean; // Modals - modalButtonOk: string; - modalButtonCancel: string; - modalUsernamePlaceholder: string; - modalPasswordPlaceholder: string; - modalTitle: string; - modalCloseByOutside: boolean; - actionsCloseByOutside: boolean; - popupCloseByOutside: boolean; - modalPreloaderTitle: string; - modalStack: boolean; + modalButtonOk?: string; + modalButtonCancel?: string; + modalUsernamePlaceholder?: string; + modalPasswordPlaceholder?: string; + modalTitle?: string; + modalCloseByOutside?: boolean; + actionsCloseByOutside?: boolean; + popupCloseByOutside?: boolean; + modalPreloaderTitle?: string; + modalStack?: boolean; // Lazy Load - imagesLazyLoadThreshold: number; - imagesLazyLoadSequential: boolean; + imagesLazyLoadThreshold?: number; + imagesLazyLoadSequential?: boolean; // Name space - viewClass: string; - viewMainClass: string; - viewsClass: string; + viewClass?: string; + viewMainClass?: string; + viewsClass?: string; // Notifications defaults - notificationCloseOnClick: boolean; - notificationCloseIcon: boolean; - notificationCloseButtonText: string; + notificationCloseOnClick?: boolean; + notificationCloseIcon?: boolean; + notificationCloseButtonText?: string; // Animate Pages - animatePages: boolean; + animatePages?: boolean; // Template7 - templates: Object; - template7Data: Object; - template7Pages: boolean; - precompileTemplates: boolean; + templates?: Object; + template7Data?: Object; + template7Pages?: boolean; + precompileTemplates?: boolean; // Material - material: boolean; - materialPageLoadDelay: number; - materialPreloaderSvg: string; - materialPreloaderHtml: string; - materialRipple: boolean; - materialRippleElements: string; - // Auto init - init: boolean; - preroute: Function; + material?: boolean; + materialPageLoadDelay?: number; + materialPreloaderSvg?: string; + materialPreloaderHtml?: string; + materialRipple?: boolean; + materialRippleElements?: string; } export declare class Framework7 { constructor(params?: IFramework7Params); - public addView(viewElement: HTMLElement, viewParams: any): View; + addView(viewElement: HTMLElement, viewParams: any): View; - public modal(parameters?: { + modal(parameters?: { title?: string; text?: string; afterText?: string; @@ -128,13 +128,23 @@ export declare class Framework7 { onClick?: (modalElement: HTMLElement, index: number) => void; }): HTMLElement; - public closeModal(modalElement: HTMLElement | string): void; + closeModal(modalElement: HTMLElement | string): void; + + sizeNavbars(): void; + + openPanel(side: string): void; - public params: IFramework7Params; + closePanel(side: string): void; + + initPageScrollToolbars(pageContainer: HTMLElement | string): void; + + params: IFramework7Params; } export declare class View { - public dynamicNavbar: boolean; + public destroy: () => void; + public pagesContainer: HTMLElement; + public router: any; } export interface IButton { @@ -142,4 +152,28 @@ export interface IButton { bold?: boolean; close?: boolean; onClick?: () => void; -} \ No newline at end of file +} + +export declare class VirtualList { + destroy: () => void; +} + +export declare type Dom7ReturnObject = { + length: number; + insertBefore: (element: HTMLElement) => void; + addClass: (classes: string) => void; +} + +export declare function Dom7(selector: string): Dom7ReturnObject; +export declare function Dom7(selector: string, context: string): Dom7ReturnObject; + +export declare type Template7ReturnObject = { + compile: (template: string) => void; + registerHelper: (name: string, helper: () => void) => void; + unregisterHelper: (name: string) => void; + registerPartial: (name: string, helper: string) => void; + unregisterPartial: (name: string) => void; + global: Object; +} + +export declare function Template7(): Template7ReturnObject \ No newline at end of file diff --git a/src/components/Alert.tsx b/src/components/Alert.tsx deleted file mode 100644 index 279ae6d..0000000 --- a/src/components/Alert.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import * as React from 'react'; - -import '../less/modals.less'; - -import {IFramework7AppContext} from './Framework7App'; - -export interface IAlertProps { - visible: boolean; - text: string; - title: string; - onClick: () => void; -} - -export interface IAlertModalState { - modal: any; -} - -export class Alert extends React.Component { - public static contextTypes = { - framework7AppContext: React.PropTypes.object - }; - - constructor(props: IAlertProps) { - super(props); - this.state = { - modal: null - }; - } - - public render(): any { - if (this.props.visible && !this.state.modal) { - this.showAlert(); - } else if (!this.props.visible && this.state.modal) { - this.hideAlert(); - } - - return null; - } - - public componentWillUnmount() { - try { - this.hideAlert(); - } catch (err) { - //Eat it - } - } - - private get framework7() { - return ((this.context as any).framework7AppContext as IFramework7AppContext).getFramework7(); - } - - private showAlert() { - setTimeout(() => { - if (this.framework7) { - this.state.modal = this.framework7.modal({ - title: this.props.title, - text: this.props.text, - buttons: [{ text: this.framework7.params.modalButtonOk, bold: true, onClick: this.props.onClick }] - }); - } else { - this.showAlert(); - } - }, 100); - - } - - private hideAlert() { - this.framework7.closeModal(this.state.modal); - this.state.modal = null; - } -} \ No newline at end of file diff --git a/src/components/AnimationWrapper.tsx b/src/components/AnimationWrapper.tsx deleted file mode 100755 index 5b9cf7b..0000000 --- a/src/components/AnimationWrapper.tsx +++ /dev/null @@ -1,277 +0,0 @@ -import * as React from 'react'; -import * as $ from 'jquery'; - -import {animationEnd} from '../utils/AnimationEnd'; - -export enum AnimationDirectionEnum { - Forward, - Back -} - -export interface IAnimationClasses { - initialClass: string; - animatingClass: string; - afterAnimationClass?: string; -} - -export interface IItemAnimationClasses { - back: IAnimationClasses; - forward: IAnimationClasses; - none: string; -} - -export interface IPageAnimationWrapper extends React.Props { - currentItemAnimationClasses: IItemAnimationClasses; - previousItemAnimationClasses: IItemAnimationClasses; - animationDirection: AnimationDirectionEnum; - onBeforeAnimation?: (currentPageElement: HTMLElement, previousPageElement: HTMLElement) => boolean; - onAfterAnimation?: (currentPageElement: HTMLElement, previousPageElement: HTMLElement) => void; - component?: React.ReactElement | string; - className?: string; -} - -export interface IAnimationContext { - getPreviousItem: (elementType: React.ComponentClass | React.StatelessComponent | string) => React.ReactElement; - setPreviousItem: (elementType: React.ComponentClass | React.StatelessComponent | string, component: React.ReactElement) => void; -} - -export class AnimationParent extends React.Component { - private animationContext: IAnimationContext; - private previousItems: any = {}; - - constructor(props: React.Props, context: any) { - super(props, context); - - this.animationContext = { - getPreviousItem: this.getPreviousItem.bind(this), - setPreviousItem: this.setPreviousItem.bind(this) - }; - } - - public static childContextTypes = { - animationContext: React.PropTypes.object - }; - - public getChildContext() { - return { - animationContext: this.animationContext - }; - } - - public render() { - return this.props.children; - } - - private getPreviousItem(elementType: React.ComponentClass | React.StatelessComponent | string) { - return this.previousItems[elementType as any] as React.ReactElement; - } - - private setPreviousItem(elementType: React.ComponentClass | React.StatelessComponent | string, item: React.ReactElement) { - this.previousItems[elementType as any] = item; - } -} - -export class AnimationWrapper extends React.Component { - private element: HTMLElement; - - public static contextTypes = { - animationContext: React.PropTypes.object - }; - - public render() { - return React.createElement((this.props.component || 'span') as any, { - ref: (item: HTMLElement) => this.element = item, - children: this.currentAndPreviousItem, - className: this.props.className - }); - } - - public componentDidMount() { - if (this.previousItem) { - this.animateItems(); - } - - this.previousItem = this.currentItem; - } - - public componentDidUpdate() { - if (this.previousAndCurrentComponentDifferent) { - this.animateItems(); - } - - this.previousItem = this.currentItem; - } - - private get previousAndCurrentComponentDifferent() { - if (!this.previousItem) { - return true; - } else { - return this.previousItem.key !== this.currentItem.key; - } - } - - private get currentAndPreviousItem() { - if (this.props.animationDirection == null || !this.previousItem || !this.previousAndCurrentComponentDifferent) { - return [this.currentItem]; - } else if (this.props.animationDirection === AnimationDirectionEnum.Forward) { - return [this.previousItem, this.currentItem]; - } else { - return [this.currentItem, this.previousItem]; - } - } - - private get currentItem() { - return this.props.children as any; - } - - private get animationContext() { - const context = this.context as any; - let animationContext: IAnimationContext = null; - - if (context && context.animationContext) { - animationContext = context.animationContext; - } - - return animationContext; - } - - private get previousItem() { - let previousItem: React.ReactElement; - - if (this.animationContext) { - previousItem = this.animationContext.getPreviousItem(this.currentItem.type); - } - - return previousItem || null; - } - - private set previousItem(item: React.ReactElement) { - if (this.animationContext) { - this.animationContext.setPreviousItem(this.currentItem.type, item); - } - } - - private get currentItemInitialClassName() { - if (this.props.animationDirection === null) { - return this.props.currentItemAnimationClasses.none; - } else if (this.props.animationDirection === AnimationDirectionEnum.Forward) { - return this.props.currentItemAnimationClasses.forward.initialClass; - } else { - return this.props.currentItemAnimationClasses.back.initialClass; - } - } - - private get previousItemInitialClassName() { - if (this.props.animationDirection === null) { - return this.props.previousItemAnimationClasses.none; - } else if (this.props.animationDirection === AnimationDirectionEnum.Forward) { - return this.props.previousItemAnimationClasses.forward.initialClass; - } else { - return this.props.previousItemAnimationClasses.back.initialClass; - } - } - - private get currentItemAnimatingClassName() { - if (this.props.animationDirection === null) { - return this.props.currentItemAnimationClasses.none; - } else if (this.props.animationDirection === AnimationDirectionEnum.Forward) { - return this.props.currentItemAnimationClasses.forward.animatingClass; - } else { - return this.props.currentItemAnimationClasses.back.animatingClass; - } - } - - private get previousItemAnimatingClassName() { - if (this.props.animationDirection === null) { - return this.props.previousItemAnimationClasses.none; - } else if (this.props.animationDirection === AnimationDirectionEnum.Forward) { - return this.props.previousItemAnimationClasses.forward.animatingClass; - } else { - return this.props.previousItemAnimationClasses.back.animatingClass; - } - } - - private get currentItemFinalClassName() { - if (this.props.animationDirection === null) { - return this.props.currentItemAnimationClasses.none; - } else if (this.props.animationDirection === AnimationDirectionEnum.Forward) { - return this.props.currentItemAnimationClasses.forward.afterAnimationClass; - } else { - return this.props.currentItemAnimationClasses.back.afterAnimationClass; - } - } - - private get previousItemFinalClassName() { - if (this.props.animationDirection === null) { - return this.props.previousItemAnimationClasses.none; - } else if (this.props.animationDirection === AnimationDirectionEnum.Forward) { - return this.props.previousItemAnimationClasses.forward.afterAnimationClass; - } else { - return this.props.previousItemAnimationClasses.back.afterAnimationClass; - } - } - - private animateItems() { - const allChildren = $(this.element).children(); - let currentItemElement: HTMLElement = null; - let previousItemElement: HTMLElement = null; - - if (this.props.animationDirection === AnimationDirectionEnum.Forward) { - previousItemElement = allChildren[0]; - currentItemElement = allChildren[1]; - } else { - currentItemElement = allChildren[0]; - previousItemElement = allChildren[1]; - } - - if (currentItemElement && previousItemElement) { - $(currentItemElement).addClass(this.currentItemInitialClassName); - $(previousItemElement).addClass(this.previousItemInitialClassName); - - $(currentItemElement).css('display', ''); - $(previousItemElement).css('display', ''); - - //Disable all events while animating - $(previousItemElement).css('pointer-events', 'none'); - $(currentItemElement).css('pointer-events', 'none'); - - if (this.props.onBeforeAnimation) { - if (this.props.onBeforeAnimation(currentItemElement, previousItemElement) === false) { - return; - } - } - - setTimeout(() => { - this.animateCurrentItem(currentItemElement); - this.animatePreviousItem(previousItemElement); - - if (this.props.onAfterAnimation) { - this.props.onAfterAnimation(currentItemElement, previousItemElement); - } - }, 0); - } - } - - private animateCurrentItem(element: HTMLElement) { - animationEnd(element).then(() => { - $(element) - .removeClass(this.currentItemAnimatingClassName) - .addClass(this.currentItemFinalClassName) - .css('pointer-events', ''); - }); - - $(element) - .removeClass(this.currentItemInitialClassName) - .addClass(this.currentItemAnimatingClassName); - } - - private animatePreviousItem(element: HTMLElement) { - animationEnd(element).then(() => { - $(element).css('display', 'none'); - }); - - $(element) - .removeClass(this.previousItemInitialClassName) - .addClass(this.previousItemAnimatingClassName); - } -} \ No newline at end of file diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx deleted file mode 100644 index 16d04a1..0000000 --- a/src/components/Badge.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from 'react'; - -import {ColorsEnum, getColorCls} from '../utils/Colors'; - -import '../less/badges.less'; - -export interface IBadgeProps { - text: string; - color?: ColorsEnum; -} - -export const Badge = (props: IBadgeProps) => { - return {props.text}; -}; \ No newline at end of file diff --git a/src/components/ContentBlock.tsx b/src/components/ContentBlock.tsx deleted file mode 100755 index 5646790..0000000 --- a/src/components/ContentBlock.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import * as React from 'react'; - -import '../less/content-block.less'; - -import {BlockMarginTypeEnum} from '../utils/BlockMarginType'; - -export interface IContentBlockProps extends React.Props { - title?: string; - marginType?: BlockMarginTypeEnum; - background?: boolean; -} - -export interface IContentBlockTitleProps extends React.Props { - title: string; -} - -export const ContentBlockTitle = (props: IContentBlockTitleProps) => { - return
{props.title}
; -}; - -const ContentBlockInner = (props: React.Props) => { - return
{props.children}
; -}; - -const ContentBlockOuter = (props: React.Props) => { - return
{props.children}
; -}; - -export const ContentBlock = (props: IContentBlockProps) => { - if (props.title || !props.background) { - return ( - - {props.title ? : null} - {!props.background ? {props.children} : null} - - ); - } else { - return ( - - - {props.children} - - - ); - } -}; \ No newline at end of file diff --git a/src/components/Framework7App.tsx b/src/components/Framework7App.tsx index ac6092e..9f39b2c 100755 --- a/src/components/Framework7App.tsx +++ b/src/components/Framework7App.tsx @@ -1,40 +1,74 @@ import * as React from 'react'; -import {Framework7} from '../Framework7'; +import Framework7Router from '../../framework7-vue/router'; +import {Framework7, IFramework7Params, Dom7} from '../Framework7'; import {applyOverscrollFix} from '../utils/OverscrollFix'; -import {AnimationDirectionEnum} from './AnimationWrapper'; -export enum ThemeTypeEnum { - iOS, - Material +export type ThemeTypeEnum = 'ios' | 'material'; + +export interface ITabChildRoute { + path: string; + component: React.ComponentClass | React.StatelessComponent; +} + +export interface ITabRoute { + tabId: string; + component?: React.ComponentClass | React.StatelessComponent; + routes?: ITabChildRoute[]; +} + +export interface IFramework7Route { + path: string; + component: React.ComponentClass | React.StatelessComponent; + tabs?: ITabRoute[]; } export interface IFramework7AppContext { - themeType: ThemeTypeEnum; - rtl?: boolean; - pageAnimationDirection: AnimationDirectionEnum; - getFramework7: () => Framework7; + theme: { + material: boolean; + ios: boolean; + }, + themeClass: string; + routes: IFramework7Route[]; + getFramework7: (callback: (f7: Framework7) => void) => void; + onRouteChange: (componentId: number, callback: (route: IFramework7Route) => void) => void; + unregisterRouteChange: (callback: (componentId: number) => void) => void; + getCurrentRoute: () => any; + getRouter: () => any; } -export interface IFramework7AppProps extends React.Props { +export interface IFramework7AppProps extends IFramework7Params, React.Props { applyOverscrollFix?: boolean; themeType: ThemeTypeEnum; - rtl?: boolean; - pageAnimationDirection: AnimationDirectionEnum; + routes: IFramework7Route[]; + onFramework7Init?: (framework7: Framework7) => void; + onRouteChange?: (route: IFramework7Route) => void; } -export class Framework7App extends React.Component { +export class Framework7App extends React.Component { + private framework7: Framework7 = null; + private framework7InitCallbacks: ((framework7: Framework7) => void)[] = []; + private routeChangeCallbacks: any = {}; + private currentRoute; + private router; + public static childContextTypes = { framework7AppContext: React.PropTypes.object - }; + } public getChildContext() { return { framework7AppContext: { themeType: this.props.themeType, - rtl: this.props.rtl, - pageAnimationDirection: this.props.pageAnimationDirection, - getFramework7: () => this.state + getFramework7: this.getFramework7.bind(this), + theme: { + ios: this.props.themeType === 'ios', + material: this.props.themeType === 'material' + }, + onRouteChange: this.onRouteChange.bind(this), + unregisterRouteChange: this.unregisterRouteChange.bind(this), + getCurrentRoute: () => this.currentRoute, + getRouter: () => this.router } }; } @@ -45,7 +79,7 @@ export class Framework7App extends React.Component { + this.currentRoute = route; + + if (this.props.onRouteChange) { + this.props.onRouteChange(route); + } + + Object.keys(this.routeChangeCallbacks).forEach(componentId => { + //Need this if statement in case a component gets unregistered during this forEach + if (this.routeChangeCallbacks[componentId]) { + this.routeChangeCallbacks[componentId](route); + } + }); + }); + + if (this.props.onFramework7Init) { + this.props.onFramework7Init(this.framework7); + } + + this.framework7InitCallbacks.forEach(callback => { + callback(this.framework7); + }); + } + + private getFramework7(callback: (framework7: Framework7) => void) { + if (this.framework7) { + callback(this.framework7); + } else { + this.framework7InitCallbacks.push(callback); + } + } + + private onRouteChange(componentId, callback: (route) => void) { + this.routeChangeCallbacks[componentId] = callback; + } + + private unregisterRouteChange(componentId) { + delete this.routeChangeCallbacks[componentId]; + } +}; \ No newline at end of file diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx deleted file mode 100644 index 1d5a9fa..0000000 --- a/src/components/Icon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import * as React from 'react'; - -export interface IIconProps { - iconClass: string; - onClick?: () => void; - showAsLink?: boolean; -} - -const IconInner = (props: IIconProps) => { - return ; -}; - -export const Icon = (props: IIconProps) => { - if (props.showAsLink) { - return ; - } else { - return React.createElement(IconInner, props); - } -}; \ No newline at end of file diff --git a/src/components/Page.tsx b/src/components/Page.tsx deleted file mode 100755 index 2465a66..0000000 --- a/src/components/Page.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import * as React from 'react'; - -import {IFramework7AppContext} from './Framework7App'; -import {AnimationWrapper, AnimationDirectionEnum} from './AnimationWrapper'; -import {ViewInner} from './View'; - -import '../less/pages.less'; - -export interface IPageProps extends React.Props { - name: string; - animationDirection?: AnimationDirectionEnum; - className?: string; -} - -export interface IPageBodyProps extends React.Props { - className?: string; -} - -interface IPageInnerProps extends React.Props { - className: string; -} - -export interface IPageContentProps extends React.Props { - className?: string; -} - -export interface IPageContext { - pageName: string; - pageAnimationDirection: AnimationDirectionEnum; -} - -class PageInner extends React.Component { - public render() { - return ( -
- {this.props.children} -
- ); - } -} - -const currentItemAnimationClasses = { - back: { - initialClass: 'page-on-left', - animatingClass: 'page-from-left-to-center', - afterAnimationClass: 'page-on-center' - }, - forward: { - initialClass: 'page-on-right', - animatingClass: 'page-from-right-to-center', - afterAnimationClass: 'page-on-center' - }, - none: 'page-on-center' -}; - -const previousItemAnimationClasses = { - back: { - initialClass: 'page-on-center', - animatingClass: 'page-from-center-to-right' - }, - forward: { - initialClass: 'page-on-center', - animatingClass: 'page-from-center-to-left' - }, - none: '' -}; - -export class Page extends React.Component { - public static childContextTypes = { - pageContext: React.PropTypes.object - }; - - public static contextTypes = { - viewContext: React.PropTypes.object - }; - - public getChildContext() { - return { - pageContext: { - pageAnimationDirection: this.props.animationDirection, - pageName: this.props.name - } - }; - } - - public render() { - return ( - - {this.props.children} - - ); - } -} - -export const PageBody = (props: IPageBodyProps, context: IPageContext) => { - const pageContext = (context as any).pageContext as IPageContext; - const appContext = (context as any).framework7AppContext as IFramework7AppContext; - - const animationDirection = pageContext.pageAnimationDirection || appContext.pageAnimationDirection; - - return ( - - - {props.children} - - - ); -}; - -(PageBody as any).contextTypes = { - pageContext: React.PropTypes.object, - viewContext: React.PropTypes.object, - framework7AppContext: React.PropTypes.object -}; - -export const PageContent = (props: IPageContentProps) =>
{props.children}
; \ No newline at end of file diff --git a/src/components/ProgressBar.tsx b/src/components/ProgressBar.tsx deleted file mode 100644 index a145730..0000000 --- a/src/components/ProgressBar.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import * as React from 'react'; - -import {ColorsEnum, getColorCls} from '../utils/Colors'; - -import '../less/progress-bar.less'; - -export interface IProgressBarProps { - infinite: boolean; - progress?: number; - color?: ColorsEnum; - animationSpeed?: number; -} - -const setProgressBarClasses = (values: IProgressBarProps) => { - return [ - ('progressbar'), - ((values.color) ? `${getColorCls(values.color)} preloader-${getColorCls(values.color)}` : ''), - ((values.infinite) ? 'progressbar-infinite' : '') - ].join(' '); -}; - -const setProgress = (values: IProgressBarProps) => { - if (!values.infinite) { - return { - transform: `translate3d(-${(100 - values.progress)}%, 0px, 0px)`, - WebkitTransform: `translate3d(-${(100 - values.progress)}%, 0px, 0px)`, - transitionDuration: `${values.animationSpeed}ms` || '150ms', - WebkitTransitionDuration: `${values.animationSpeed}ms` || '150ms' - }; - } else { - return null; - } - -}; - -export const ProgressBar = (props: IProgressBarProps) => { - return ( -
- -
- ); -}; \ No newline at end of file diff --git a/src/components/SidePanel.tsx b/src/components/SidePanel.tsx deleted file mode 100755 index ff9f6a2..0000000 --- a/src/components/SidePanel.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import * as React from 'react'; -import * as $ from 'jquery'; -import * as Portal from 'react-portal'; - -import '../less/panels.less'; - -import {transitionEnd} from '../utils/AnimationEnd'; - -export enum PanelSideEnum { - Left, - Right -} - -export enum PanelSlideInType { - Cover, - Reveal -} - -export interface ISidePanelProps { - side: PanelSideEnum; - slideInType: PanelSlideInType; - isOpen: boolean; - isSwipable: boolean; - additionalClassName?: string; - overlayClickHandler?: () => void; -} - -export class SidePanel extends React.Component { - private elementId: string = 'side-panel'; - - constructor(props: ISidePanelProps) { - super(props); - - if (props.side === PanelSideEnum.Right) { - throw new Error('Panels on right not currently supported!'); - } - - if (props.slideInType === PanelSlideInType.Reveal) { - throw new Error('Panel reveal is not currently supported!'); - } - } - - public componentDidMount() { - this.reconcilePanelOpenState(); - } - - public componentWillUnmount() { - $(document.body).removeClass('with-panel-left-cover'); - } - - public render() { - return ( - - -
-
- {this.props.children} -
- - - ); - } - - public componentDidUpdate() { - this.reconcilePanelOpenState(); - } - - private reconcilePanelOpenState() { - if (!this.element) { - return; - } - - if (this.props.isOpen && !this.isPanelOpen) { - this.openPanel(); - } else if (!this.props.isOpen && this.isPanelOpen) { - this.closePanel(); - } - } - - private get element(): HTMLElement { - const elements = document.getElementsByClassName(this.elementId); - - if (elements.length) { - return elements[0] as HTMLElement; - } else { - return null; - } - } - - private get panelSideClass(): string { - return this.props.side === PanelSideEnum.Left ? 'panel-left' : 'panel-right'; - } - - private get panelSlideInTypeClass(): string { - return this.props.slideInType === PanelSlideInType.Cover ? 'panel-cover' : 'panel-reveal'; - } - - private get additionalCls(): string { - return this.props.additionalClassName; - } - - private get isPanelOpen(): boolean { - return $(document.body).hasClass('with-panel-left-cover'); - } - - private openPanel() { - $(this.element).css({ display: 'block' }); - - //Trigger re-layout - const dummy = this.element.clientLeft; - // tslint:disable-next-line:no-unused-expression - dummy; - - $(document.body).addClass('with-panel-left-cover'); - } - - private closePanel() { - transitionEnd(this.element).then(() => { - $(this.element).css({ display: '' }); - $(document.body).removeClass('panel-closing'); - }); - - $(document.body).removeClass('with-panel-left-cover'); - $(document.body).addClass('panel-closing'); - } -} \ No newline at end of file diff --git a/src/components/View.tsx b/src/components/View.tsx deleted file mode 100755 index 2dc0789..0000000 --- a/src/components/View.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import * as React from 'react'; -import * as invariant from 'invariant'; -import {Page} from './Page'; - -import '../less/views.less'; - -export interface IViewProps { - dockLeft?: boolean; -} - -/* tslint:disable-next-line */ -export interface IViewContext extends IViewProps { - -} - -export class View extends React.Component { - public static childContextTypes = { - viewContext: React.PropTypes.object - }; - - public getChildContext() { - return { - viewContext: { - dockLeft: this.props.dockLeft - } - }; - } - - public render() { - const children = React.Children.toArray(this.props.children); - const page = children.length ? children[0] as React.ReactElement : null; - - invariant( - !page || (page.type !== typeof Page && children.length > 0), - 'A View is expected to have one Page component within it' - ); - - return page; - } -} - -export class ViewInner extends React.Component { - public static contextTypes = { - viewContext: React.PropTypes.object - }; - - private get viewContext() { - return (this.context as any).viewContext as IViewContext; - } - - private get containsNavbar() { - return true; - } - - public render() { - return ( -
- {this.props.children} -
- ); - } -} \ No newline at end of file diff --git a/src/components/Views.tsx b/src/components/Views.tsx deleted file mode 100755 index 21318dc..0000000 --- a/src/components/Views.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from 'react'; -import {AnimationParent} from './AnimationWrapper'; - -import '../less/views.less'; - -export const Views = (props: __React.Props) => { - return ( - -
- {props.children} -
-
- ); -}; \ No newline at end of file diff --git a/src/components/buttons/BackButton.tsx b/src/components/buttons/BackButton.tsx deleted file mode 100755 index ad6c306..0000000 --- a/src/components/buttons/BackButton.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from 'react'; - -import '../../less/forms.less'; - -export interface IBackButtonProps { - onClick: () => void; - text?: string; -} - -export const BackButton = (props: IBackButtonProps) => { - return ( - - - {props.text || 'Back'} - - ); -}; \ No newline at end of file diff --git a/src/components/buttons/Button.tsx b/src/components/buttons/Button.tsx deleted file mode 100755 index 2738cb0..0000000 --- a/src/components/buttons/Button.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import * as React from 'react'; - -import '../../less/forms.less'; - -import {ColorsEnum, getColorCls} from '../../utils/Colors'; -import {BlockMarginTypeEnum} from '../../utils/BlockMarginType'; -import {ListBlock} from '../list/ListBlock'; - -export enum ButtonTypeEnum { - Standard, - Filled -} - -export enum ButtonSizeEnum { - Normal, - Big -} - -export interface IButtonProps { - text: string; - onClick: Function; - additionalClassNames?: string; - buttonType?: ButtonTypeEnum; - size?: ButtonSizeEnum; - round?: boolean; - color?: ColorsEnum; - inset?: boolean; -} - -const getButtonSizeCls = (props: IButtonProps) => { - return props.size === ButtonSizeEnum.Big ? 'button-big' : ''; -}; - -const getButtonTypeCls = (props: IButtonProps) => { - return props.buttonType === ButtonTypeEnum.Filled ? 'button-fill' : ''; -}; - -const getButtonRoundnessCls = (props: IButtonProps) => { - return props.round ? 'button-round' : ''; -}; - -const buttonClicked = (e: React.MouseEvent, props: IButtonProps) => { - e.preventDefault(); - - if (props.onClick) { - props.onClick(); - } -}; - -const ButtonInner = (props: IButtonProps) => { - return buttonClicked(e, props)} - role="button" - > - {props.text} - ; -}; - -export const Button = (props: IButtonProps) => { - if (props.inset) { - return ( - -
  • - {React.createElement(ButtonInner, props)} -
  • -
    - ); - } else { - return React.createElement(ButtonInner, props); - } -}; \ No newline at end of file diff --git a/src/components/buttons/IconButton.tsx b/src/components/buttons/IconButton.tsx deleted file mode 100755 index 88dff1d..0000000 --- a/src/components/buttons/IconButton.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import * as React from 'react'; - -import {Icon} from '../Icon'; - -import '../../less/forms.less'; - -export interface IIconButtonProps { - onClick: () => void; - iconCls: string; - additionalClassNames?: string; -} - -export const IconButton = (props: IIconButtonProps) => { - return ( - - - - ); -}; \ No newline at end of file diff --git a/src/components/forms/Checkbox.tsx b/src/components/forms/Checkbox.tsx deleted file mode 100644 index 69ea62c..0000000 --- a/src/components/forms/Checkbox.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from 'react'; - -import '../../less/forms.less'; - -export interface ICheckboxProps extends React.Props { - id: string | number; - text: string; - checked: boolean; - showAsLink?: boolean; - onTap?: (id: string | number) => void; -} - -const getCheckboxInner = (props: ICheckboxProps) => { - return ( - - ); -}; - -const checkboxClicked = (e: React.MouseEvent, props: ICheckboxProps) => { - e.preventDefault(); - - if (props.onTap) { - props.onTap(props.id); - } -}; - -export const Checkbox = (props: ICheckboxProps) => { - return ( -
  • checkboxClicked(e, props)}> - {props.showAsLink ? {getCheckboxInner(props)} : getCheckboxInner(props)} -
  • - ); -}; \ No newline at end of file diff --git a/src/components/grid/GridCol.tsx b/src/components/grid/GridCol.tsx deleted file mode 100644 index 45b15c0..0000000 --- a/src/components/grid/GridCol.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import * as React from 'react'; - -import '../../less/grid.less'; - -export interface IGridColProps extends React.Props { - width: number; - tabletWidth: number; -} - -export const GridCol = (props: IGridColProps) => { - return
    {props.children}
    ; -}; \ No newline at end of file diff --git a/src/components/grid/GridRow.tsx b/src/components/grid/GridRow.tsx deleted file mode 100644 index 08199d5..0000000 --- a/src/components/grid/GridRow.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import * as React from 'react'; - -import '../../less/grid.less'; - -export interface IGridRowProps extends React.Props { - noGutter?: boolean; - className?: string; -} - -export const GridRow = (props: IGridRowProps) => { - return
    {props.children}
    ; -}; \ No newline at end of file diff --git a/src/components/inputs/ManagedFormInput.tsx b/src/components/inputs/ManagedFormInput.tsx new file mode 100644 index 0000000..457bd6d --- /dev/null +++ b/src/components/inputs/ManagedFormInput.tsx @@ -0,0 +1,31 @@ +import * as React from 'react'; + +export interface IManagedFormInputState { + currentValue?: string +} + +export class ManagedFormInput extends React.Component { + constructor(props: any) { + super(props); + + this.state = { + currentValue: this.props.value || "" + } + } + + render() { + return ( + + ); + } + + private onInput(event) { + if (this.props.type === "radio" || this.props.type === "checkbox") { + this.props.onChange(); + } else { + this.setState({ + currentValue: event.target.value + }); + } + } +}; \ No newline at end of file diff --git a/src/components/list/GroupedList.tsx b/src/components/list/GroupedList.tsx deleted file mode 100755 index fb9a45c..0000000 --- a/src/components/list/GroupedList.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import * as React from 'react'; - -import '../../less/lists.less'; - -export interface IGroupedListProps { - items: any[]; - innerListItemComponent: __React.ComponentClass | __React.StatelessComponent; - groupBy: string; - searchable: boolean; - itemIdField?: string; - selectedItemId?: number; - onItemSelected?: (itemId: number) => void; - additionalClassName?: string; - selectedClass?: string; -} - -const buildGroupedItems = (items: any[], groupBy: string) => { - const groupedItems: { [groupName: string]: any[] } = {}; - - for (let i = 0; i < items.length; i++) { - const groupName = items[i][groupBy].charAt(0).toUpperCase(); - - if (!(groupName in groupedItems)) { - groupedItems[groupName] = []; - } - - groupedItems[groupName].push(items[i]); - } - - return groupedItems; -}; - -const getGroupItems = (groupedItems: { [groupName: string]: any[] }, value: string, props: IGroupedListProps) => { - return groupedItems[value].map((item: any) => -
  • -
    props.onItemSelected(item.id)}> -
    - {React.createElement(props.innerListItemComponent, item)} -
    -
    -
  • - ); -}; - -const getListGroups = (props: IGroupedListProps) => { - const groupedItems: { [groupName: string]: any[] } = buildGroupedItems(props.items, props.groupBy); - - return Object.keys(groupedItems).map((value) => ( -
    -
      -
    • {value}
    • - {getGroupItems(groupedItems, value, props)} -
    -
    - )); -}; - -export const GroupedList = (props: IGroupedListProps) => { - return ( -
    - {getListGroups(props)} -
    - ); -}; diff --git a/src/components/list/ListBlock.tsx b/src/components/list/ListBlock.tsx deleted file mode 100755 index 6a722fa..0000000 --- a/src/components/list/ListBlock.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import * as React from 'react'; - -import '../../less/lists.less'; - -import {BlockMarginTypeEnum, getMarginTypeClass} from '../../utils/BlockMarginType'; -import {IListItemProps} from './ListItem'; - -export interface IListBlockProps extends React.Props { - title?: string; - label?: string; - marginType?: BlockMarginTypeEnum; - className?: string; -} - -const ListBlockInner = (props: IListBlockProps) => { - const listItems = React.Children.toArray(props.children) as React.ReactElement[]; - const containsListItemWithMedia = listItems.filter(listItem => listItem.props.mediaElement !== undefined).length > 0; - - return ( -
    -
      - {props.children} -
    -
    - ); -}; - -export const ListBlock = (props: IListBlockProps) => { - if (props.title) { - return ( - - {props.title ?
    {props.title}
    : null} - {ListBlockInner(props)} -
    - ); - } else { - return ListBlockInner(props); - } -}; \ No newline at end of file diff --git a/src/components/list/ListItem.tsx b/src/components/list/ListItem.tsx deleted file mode 100755 index 686be1a..0000000 --- a/src/components/list/ListItem.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import * as React from 'react'; - -import '../../less/lists.less'; - -import {Icon} from '../Icon'; - -export interface IListItemProps extends React.Props { - title?: string; - afterTitleText?: string; - subTitle?: string; - text?: string; - showAsLink?: boolean; - onClick?: () => void; - mediaElement?: React.ReactElement; - iconClass?: string; - className?: string; -} - -const ListItemTitle = (props: IListItemProps) => { - return ( -
    - {props.title ?
    {props.title}
    : null} - {props.afterTitleText ?
    {props.afterTitleText}
    : null} -
    - ); -}; - -const ListItemInner = (props: IListItemProps) => { - if (props.children) { - return ( -
    - {props.children} -
    - ); - } else if (props.text || props.subTitle) { - return ( -
    - {(props.title || props.afterTitleText) ? ListItemTitle(props) : null} - {props.subTitle ?
    {props.subTitle}
    : null} - {props.text ?
    {props.text}
    : null} -
    - ); - } else { - return ( -
    - {props.title ?
    {props.title}
    : null} - {props.afterTitleText ?
    {props.afterTitleText}
    : null} -
    - ); - } -}; - -const ListItemMedia = (props: IListItemProps) => { - return ( -
    {props.mediaElement}
    - ); -}; - -export const ListItem = (props: IListItemProps) => { - if (props.showAsLink) { - return ( -
  • - - {props.iconClass ? ListItemMedia({mediaElement: }) : null} - {props.mediaElement ? ListItemMedia(props) : null} - {ListItemInner(props)} - -
  • - ); - } else { - return ( -
  • -
    - {props.iconClass ? ListItemMedia({mediaElement: }) : null} - {props.mediaElement ? ListItemMedia(props) : null} - {ListItemInner(props)} -
    -
  • - ); - } -}; \ No newline at end of file diff --git a/src/components/popovers/PopoverList.tsx b/src/components/popovers/PopoverList.tsx deleted file mode 100755 index a71319c..0000000 --- a/src/components/popovers/PopoverList.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import * as React from 'react'; - -export interface IPopoverList { - listToDisplayWithValues: IPopoverItems[]; - onClick: Function; - listClassName: string; -} - -export interface IPopoverItems { - value: string; - displayText: string; -} - -const getListItems = (props: IPopoverList) => { - return props.listToDisplayWithValues.map((val, index) => { - return
  • props.onClick(val.value)} - key={`${index}-${val.value}`} - > - {val.displayText} -
  • ; - }); -}; - -export class PopoverList extends React.Component { - public render() { - return ( -
    -
    -
    -
      - {getListItems(this.props)} -
    -
    -
    -
    - ); - } -} \ No newline at end of file diff --git a/src/components/toolbars-and-navbars/Navbar.tsx b/src/components/toolbars-and-navbars/Navbar.tsx deleted file mode 100755 index 24f334f..0000000 --- a/src/components/toolbars-and-navbars/Navbar.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import * as React from 'react'; -import * as $ from 'jquery'; - -import '../../less/toolbars.less'; - -import {IFramework7AppContext} from '../Framework7App'; -import {AnimationWrapper, AnimationDirectionEnum} from '../AnimationWrapper'; -import {prepareNavbar, sizeNavbars, animateNavbars} from '../../utils/NavbarAnimationLogic'; -import {IPageContext} from '../Page'; - -export interface INavbarProps extends React.Props { - className?: string; -} - -interface INavbarInnerProps extends React.Props { - pageName: string; -} - -const NavbarInner = (props: INavbarInnerProps) => { - return ( -
    - {props.children} -
    - ); -}; - -const currentItemAnimationClasses = { - back: { - initialClass: 'navbar-on-right', - animatingClass: 'navbar-from-left-to-center', - afterAnimationClass: 'navbar-on-center' - }, - forward: { - initialClass: 'navbar-on-left', - animatingClass: 'navbar-from-right-to-center', - afterAnimationClass: 'navbar-on-center' - }, - none: 'navbar-on-center' -}; - -const previousItemAnimationClasses = { - back: { - initialClass: 'navbar-on-center', - animatingClass: 'navbar-from-center-to-right' - }, - forward: { - initialClass: 'navbar-on-center', - animatingClass: 'navbar-from-center-to-left' - }, - none: '' -}; - -export class Navbar extends React.Component { - public static contextTypes = { - pageContext: React.PropTypes.object, - framework7AppContext: React.PropTypes.object - }; - - private get pageContext() { - return (this.context as any).pageContext as IPageContext; - } - - private get framework7AppContext() { - return (this.context as any).framework7AppContext as IFramework7AppContext; - } - - private get pageName() { - return this.pageContext.pageName; - } - - private get animationDirection() { - return this.pageContext.pageAnimationDirection || this.framework7AppContext.pageAnimationDirection; - } - - public render() { - return ( - - - {this.props.children} - - - ); - } - - private onBeforeAnimation(currentNavbar: HTMLElement, previousNavbar: HTMLElement) { - sizeNavbars($(currentNavbar).closest('.view')); - prepareNavbar(currentNavbar, previousNavbar, this.animationDirection === AnimationDirectionEnum.Back ? 'left' : 'right'); - - return true; - } - - private onAfterAnimation(currentNavbar: HTMLElement, previousNavbar: HTMLElement) { - if (this.animationDirection === AnimationDirectionEnum.Back) { - animateNavbars($(currentNavbar), $(previousNavbar), 'to-right'); - } else { - animateNavbars($(previousNavbar), $(currentNavbar), 'to-left'); - } - } -} \ No newline at end of file diff --git a/src/components/toolbars-and-navbars/TabBar.tsx b/src/components/toolbars-and-navbars/TabBar.tsx deleted file mode 100755 index 8db28f4..0000000 --- a/src/components/toolbars-and-navbars/TabBar.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import * as React from 'react'; - -import {Badge} from '../Badge'; -import {ColorsEnum} from '../../utils/Colors'; - -import '../../less/tabs.less'; - -export interface ITab { - id: string; - badgeText?: string; - badgeColor?: ColorsEnum; - label: string; - icon: string; - onTabSelected?: (tabId: string) => void; - isActive?: boolean; -} - -export interface ITabBarProps { - tabs: ITab[]; - activeTabId: string; - onTabSelected: (tabId: string) => void; - beforeTabsItem?: React.ReactElement; - afterTabsItem?: React.ReactElement; -} - -const Tab = (tab: ITab) => { - return ( - tab.onTabSelected(tab.id)}> - - {(tab.badgeText) ? : null} - - {tab.label} - - ); -}; - -const getTabs = (props: ITabBarProps) => { - const activeTabId = props.activeTabId || props.tabs[0].id; - - return props.tabs.map(tab => { - return Tab({ - id: tab.id, - badgeText: tab.badgeText, - label: tab.label, - icon: tab.icon, - onTabSelected: props.onTabSelected, - isActive: tab.id === activeTabId - }); - }); -}; - -export const TabBar = (props: ITabBarProps) => { - return ( -
    -
    - {props.beforeTabsItem} - {getTabs(props)} - {props.afterTabsItem} -
    -
    - ); -}; \ No newline at end of file diff --git a/src/components/toolbars-and-navbars/Toolbar.tsx b/src/components/toolbars-and-navbars/Toolbar.tsx deleted file mode 100755 index 8247798..0000000 --- a/src/components/toolbars-and-navbars/Toolbar.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import * as React from 'react'; - -import '../../less/toolbars.less'; - -export interface IToolbarProps extends React.Props { - className?: string; -} - -export const Toolbar = (props: IToolbarProps) => { - return ( -
    -
    - {props.children} -
    -
    - ); -}; - -export interface IToolbarChildProps extends React.Props { - className?: string; -} - -export const Left = (props: IToolbarChildProps) =>
    {props.children}
    ; -export const Center = (props: IToolbarChildProps) =>
    {props.children}
    ; -export const Right = (props: IToolbarChildProps) =>
    {props.children}
    ; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts deleted file mode 100755 index bdb8cce..0000000 --- a/src/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {Framework7App, ThemeTypeEnum} from './components/Framework7App'; -import {AnimationDirectionEnum} from './components/AnimationWrapper'; -import {ColorsEnum} from './utils/Colors'; -import {Alert} from './components/Alert'; -import {Badge} from './components/Badge'; -import {View} from './components/View'; -import {Views} from './components/Views'; -import {Page, PageBody, PageContent} from './components/Page'; -import {Navbar} from './components/toolbars-and-navbars/Navbar'; -import {Toolbar, Left, Center, Right} from './components/toolbars-and-navbars/Toolbar'; -import {TabBar} from './components/toolbars-and-navbars/TabBar'; -import {Icon} from './components/Icon'; -import {Button, ButtonTypeEnum, ButtonSizeEnum} from './components/buttons/Button'; -import {BackButton} from './components/buttons/BackButton'; -import {IconButton} from './components/buttons/IconButton'; -import {SidePanel, PanelSideEnum, PanelSlideInType} from './components/SidePanel'; -import {PopoverList, IPopoverItems} from './components/popovers/PopoverList'; -import {GroupedList} from './components/list/GroupedList'; -import {ContentBlock, ContentBlockTitle} from './components/ContentBlock'; -import {BlockMarginTypeEnum} from './utils/BlockMarginType'; -import {ListBlock} from './components/list/ListBlock'; -import {ListItem} from './components/list/ListItem'; -import {Checkbox} from './components/forms/Checkbox'; -import {GridRow} from './components/grid/GridRow'; -import {GridCol} from './components/grid/GridCol'; -import {ProgressBar} from './components/ProgressBar'; - -import './less/intro.less'; -import './less/framework7.ios.colors.less'; - -export { - Alert, Badge, ColorsEnum, - AnimationDirectionEnum, - View, Views, - Page, PageBody, PageContent, - Navbar, Toolbar, TabBar, Left, Center, Right, - Icon, Button, ButtonTypeEnum, ButtonSizeEnum, BackButton, IconButton, - SidePanel, PanelSideEnum, PanelSlideInType, - Framework7App, ThemeTypeEnum, - PopoverList, IPopoverItems, - ContentBlock, ContentBlockTitle, BlockMarginTypeEnum, - GroupedList, ListBlock, ListItem, - Checkbox, - GridRow, GridCol, - ProgressBar -} \ No newline at end of file diff --git a/src/less/badges.less b/src/less/badges.less deleted file mode 100644 index fec859f..0000000 --- a/src/less/badges.less +++ /dev/null @@ -1 +0,0 @@ -@import "~framework7/src/less/ios/badges.less"; \ No newline at end of file diff --git a/src/less/content-block.less b/src/less/content-block.less deleted file mode 100644 index 18180c8..0000000 --- a/src/less/content-block.less +++ /dev/null @@ -1,2 +0,0 @@ -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/content-block.less"; \ No newline at end of file diff --git a/src/less/forms.less b/src/less/forms.less deleted file mode 100644 index 61c7e07..0000000 --- a/src/less/forms.less +++ /dev/null @@ -1,3 +0,0 @@ -@import "~framework7/src/less/ios/_colors-vars.less"; -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/forms.less"; \ No newline at end of file diff --git a/src/less/framework7.ios.colors.less b/src/less/framework7.ios.colors.less deleted file mode 100644 index 0d2b9b0..0000000 --- a/src/less/framework7.ios.colors.less +++ /dev/null @@ -1 +0,0 @@ -@import "~framework7/src/less/ios/framework7.ios.colors.less"; \ No newline at end of file diff --git a/src/less/grid.less b/src/less/grid.less deleted file mode 100644 index e2d97e5..0000000 --- a/src/less/grid.less +++ /dev/null @@ -1,2 +0,0 @@ -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/grid.less"; \ No newline at end of file diff --git a/src/less/intro.less b/src/less/intro.less deleted file mode 100644 index 20b87a8..0000000 --- a/src/less/intro.less +++ /dev/null @@ -1,5 +0,0 @@ -@import "~framework7/src/less/ios/_colors-vars.less"; -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/intro.less"; -@imgBaseUrl: "../../img"; -@import "~framework7/src/less/ios/icons.less"; \ No newline at end of file diff --git a/src/less/lists.less b/src/less/lists.less deleted file mode 100644 index 0012642..0000000 --- a/src/less/lists.less +++ /dev/null @@ -1,3 +0,0 @@ -@import "~framework7/src/less/ios/_colors-vars.less"; -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/lists.less"; \ No newline at end of file diff --git a/src/less/modals.less b/src/less/modals.less deleted file mode 100644 index b14a3c9..0000000 --- a/src/less/modals.less +++ /dev/null @@ -1,4 +0,0 @@ -@import "~framework7/src/less/ios/_colors-vars.less"; -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/toolbars.less"; -@import "~framework7/src/less/ios/modals.less"; \ No newline at end of file diff --git a/src/less/pages.less b/src/less/pages.less deleted file mode 100644 index 1700cc0..0000000 --- a/src/less/pages.less +++ /dev/null @@ -1,2 +0,0 @@ -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/pages.less"; \ No newline at end of file diff --git a/src/less/panels.less b/src/less/panels.less deleted file mode 100644 index fbb89ef..0000000 --- a/src/less/panels.less +++ /dev/null @@ -1,2 +0,0 @@ -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/panels.less"; \ No newline at end of file diff --git a/src/less/progress-bar.less b/src/less/progress-bar.less deleted file mode 100644 index 0b1337c..0000000 --- a/src/less/progress-bar.less +++ /dev/null @@ -1,3 +0,0 @@ -@import "~framework7/src/less/ios/_colors-vars.less"; -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/progressbar.less"; \ No newline at end of file diff --git a/src/less/tabs.less b/src/less/tabs.less deleted file mode 100644 index 4f6a296..0000000 --- a/src/less/tabs.less +++ /dev/null @@ -1,2 +0,0 @@ -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/tabs.less"; \ No newline at end of file diff --git a/src/less/toolbars.less b/src/less/toolbars.less deleted file mode 100644 index 7a6f6c3..0000000 --- a/src/less/toolbars.less +++ /dev/null @@ -1,4 +0,0 @@ -@import "~framework7/src/less/ios/_colors-vars.less"; -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/toolbars.less"; -@import "~framework7/src/less/ios/toolbars-pages.less"; \ No newline at end of file diff --git a/src/less/views.less b/src/less/views.less deleted file mode 100644 index 4f8a690..0000000 --- a/src/less/views.less +++ /dev/null @@ -1,2 +0,0 @@ -@import "~framework7/src/less/ios/_mixins.less"; -@import "~framework7/src/less/ios/views.less"; \ No newline at end of file diff --git a/src/utils/AnimationEnd.ts b/src/utils/AnimationEnd.ts deleted file mode 100755 index 5d6af51..0000000 --- a/src/utils/AnimationEnd.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as Promise from 'bluebird'; -import * as $ from 'jquery'; - -const transitionEndEvents = 'transitionend webkitTransitionEnd oTransitionEnd'; -const animationEndEvents = 'animationend webkitAnimationEnd oAnimationEnd'; - -const listenToEvent = (element: HTMLElement, events: string) => { - return new Promise(resolve => { - const handleEvent = () => { - $(element).unbind(events, handleEvent); - resolve(); - }; - - $(element).bind(events, handleEvent); - }); -}; - -export const transitionEnd = (element: HTMLElement) => listenToEvent(element, transitionEndEvents); -export const animationEnd = (element: HTMLElement) => listenToEvent(element, animationEndEvents); \ No newline at end of file diff --git a/src/utils/BlockMarginType.ts b/src/utils/BlockMarginType.ts deleted file mode 100755 index e64499d..0000000 --- a/src/utils/BlockMarginType.ts +++ /dev/null @@ -1,16 +0,0 @@ -export enum BlockMarginTypeEnum { - None, - Inset, - TabletInset -} - -export const getMarginTypeClass = (blockMarginType: BlockMarginTypeEnum) => { - switch (blockMarginType) { - case BlockMarginTypeEnum.Inset: - return ' inset'; - case BlockMarginTypeEnum.None: - return ''; - default: - return ' tablet-inset'; - } -}; \ No newline at end of file diff --git a/src/utils/Colors.tsx b/src/utils/Colors.tsx index f2603f5..956ece7 100755 --- a/src/utils/Colors.tsx +++ b/src/utils/Colors.tsx @@ -1,15 +1,14 @@ -export enum ColorsEnum { - Blue, - Red, - White, - Black, - LightBlue, - Yellow, - Orange, - Pink, - Green, - Gray, - Multi -} +export type iosColors = + 'blue' | + 'red' | + 'white' | + 'black' | + 'lightblue' | + 'yellow' | + 'orange' | + 'pink' | + 'green' | + 'gray' | + 'multi'; -export const getColorCls = (color: ColorsEnum) => (ColorsEnum[color]) ? `color-${ColorsEnum[color].toLowerCase()}` : ''; \ No newline at end of file +export type ColorsEnum = iosColors; \ No newline at end of file diff --git a/src/utils/Layout.ts b/src/utils/Layout.ts new file mode 100644 index 0000000..7b29666 --- /dev/null +++ b/src/utils/Layout.ts @@ -0,0 +1,4 @@ +export type LayoutEnum = + 'light' | + 'dark' | + 'default'; \ No newline at end of file diff --git a/src/utils/NavbarAnimationLogic.ts b/src/utils/NavbarAnimationLogic.ts deleted file mode 100755 index 14e97a7..0000000 --- a/src/utils/NavbarAnimationLogic.ts +++ /dev/null @@ -1,194 +0,0 @@ -import * as $ from 'jquery'; - -//Disable TSLint for this file because this code will soon be discarded once these duties are delegated to Framework7 -/* tslint:disable */ - -export const animateNavbars = (leftNavbarInner: JQuery, rightNavbarInner: JQuery, direction: string) => { - if (direction === 'to-left') { - rightNavbarInner.find('.sliding') - .each(function() { - var sliding = $(this); - sliding.css('transform', 'translate3d(0,0,0)'); - - if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) { - sliding.find('.back .icon').css('transform', 'translate3d(0,0,0)'); - } - }); - - leftNavbarInner.find('.sliding') - .each(function() { - var sliding = $(this); - var rightText: any; - - if (sliding.hasClass('center') && rightNavbarInner.find('.sliding.left .back .icon').length > 0) { - rightText = rightNavbarInner.find('.sliding.left .back span'); - if (rightText.length > 0) this.f7NavbarLeftOffset += rightText[0].offsetLeft; - } - if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) { - sliding.find('.back .icon') - .css('transform', 'translate3d(' + (-this.f7NavbarLeftOffset) + 'px,0,0)'); - } - - sliding.css('transform', 'translate3d(' + (this.f7NavbarLeftOffset) + 'px,0,0)'); - }); - } - - if (direction === 'to-right') { - leftNavbarInner.find('.sliding') - .each(function() { - var sliding = $(this); - sliding.css('transform', 'translate3d(0px,0,0)'); - - if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) { - sliding.find('.back .icon').css('transform', 'translate3d(0px,0,0)'); - } - }); - - rightNavbarInner.find('.sliding') - .each(function() { - var sliding = $(this); - - if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) { - sliding.find('.back .icon') - .css('transform', 'translate3d(' + (-this.f7NavbarRightOffset) + 'px,0,0)'); - } - - sliding.css('transform', 'translate3d(' + (this.f7NavbarRightOffset) + 'px,0,0)'); - }); - } -}; - -export const sizeNavbars = (viewContainer: JQuery) => { - let app = { rtl: false, params: { material: false } }; - - if (app.params.material) return; - - var navbarInner = viewContainer - ? $(viewContainer).find('.navbar .navbar-inner:not(.cached)') - : $('.navbar .navbar-inner:not(.cached)'); - - navbarInner.each(function() { - var n = $(this); - if (n.hasClass('cached')) return; - var left = app.rtl ? n.find('.right') : n.find('.left'), - right = app.rtl ? n.find('.left') : n.find('.right'), - center = n.find('.center'), - subnavbar = n.find('.subnavbar'), - noLeft = left.length === 0, - noRight = right.length === 0, - leftWidth = noLeft ? 0 : left.outerWidth(true), - rightWidth = noRight ? 0 : right.outerWidth(true), - centerWidth = center.outerWidth(true), - navbarStyles = n[0].style, - navbarWidth = n[0].offsetWidth - - parseInt(((navbarStyles.paddingLeft === '') ? '0' : navbarStyles.paddingLeft), 10) - - parseInt(((navbarStyles.paddingRight === '') ? '0' : navbarStyles.paddingRight), 10), - onLeft = n.hasClass('navbar-on-left'), - currLeft: any, - diff: any; - - if (noRight) { - currLeft = navbarWidth - centerWidth; - } - - if (noLeft) { - currLeft = 0; - } - - if (!noLeft && !noRight) { - currLeft = (navbarWidth - rightWidth - centerWidth + leftWidth) / 2; - } - - var requiredLeft = (navbarWidth - centerWidth) / 2; - - if (navbarWidth - leftWidth - rightWidth > centerWidth) { - if (requiredLeft < leftWidth) { - requiredLeft = leftWidth; - } - if (requiredLeft + centerWidth > navbarWidth - rightWidth) { - requiredLeft = navbarWidth - rightWidth - centerWidth; - } - diff = requiredLeft - currLeft; - } else { - diff = 0; - } - - // RTL inverter - var inverter = app.rtl ? -1 : 1; - - if (center.hasClass('sliding')) { - let centerElement = center[0] as any; - - centerElement.f7NavbarLeftOffset = -(currLeft + diff) * inverter; - centerElement.f7NavbarRightOffset = (navbarWidth - currLeft - diff - centerWidth) * inverter; - if (onLeft) { - var activeNavbarBackLink = n - .parent() - .find('.navbar-on-center') - .find('.left.sliding .back .icon ~ span'); - - if (activeNavbarBackLink.length > 0) { - centerElement.f7NavbarLeftOffset += activeNavbarBackLink[0].offsetLeft; - } - - center.css('transform', 'translate3d(' + centerElement.f7NavbarLeftOffset + 'px, 0, 0)'); - } - } - - if (!noLeft && left.hasClass('sliding')) { - let leftElement = left[0] as any; - - if (app.rtl) { - leftElement.f7NavbarLeftOffset = -(navbarWidth - left[0].offsetWidth) / 2 * inverter; - leftElement.f7NavbarRightOffset = leftWidth * inverter; - } else { - leftElement.f7NavbarLeftOffset = -leftWidth; - leftElement.f7NavbarRightOffset = (navbarWidth - left[0].offsetWidth) / 2; - - if (left.find('.back .icon').length > 0) { - leftElement.f7NavbarRightOffset -= left.find('.back .icon')[0].offsetWidth; - } - } - - if (onLeft) left.css('transform', 'translate3d(' + leftElement.f7NavbarLeftOffset + 'px, 0, 0)'); - } - - if (!noRight && right.hasClass('sliding')) { - let rightElement = right[0] as any; - - if (app.rtl) { - rightElement.f7NavbarLeftOffset = -rightWidth * inverter; - rightElement.f7NavbarRightOffset = (navbarWidth - right[0].offsetWidth) / 2 * inverter; - } else { - rightElement.f7NavbarLeftOffset = -(navbarWidth - right[0].offsetWidth) / 2; - rightElement.f7NavbarRightOffset = rightWidth; - } - if (onLeft) right.css('transform', 'translate3d(' + rightElement.f7NavbarLeftOffset + 'px, 0, 0)'); - } - - if (subnavbar.length && subnavbar.hasClass('sliding')) { - let subnavbarElement = subnavbar[0] as any; - - subnavbarElement.f7NavbarLeftOffset = app.rtl ? subnavbar[0].offsetWidth : -subnavbar[0].offsetWidth; - subnavbarElement.f7NavbarRightOffset = -subnavbarElement.f7NavbarLeftOffset; - } - - // Center left - var centerLeft = diff; - if (app.rtl && noLeft && noRight && center.length > 0) centerLeft = -centerLeft; - center.css('left', centerLeft + 'px'); - }); -}; - -export const prepareNavbar = (newNavbarInner: HTMLElement, _oldNavbarInner: HTMLElement, newNavbarPosition: string) => { - $(newNavbarInner).find('.sliding').each(function () { - var sliding = $(this); - var slidingOffset = newNavbarPosition === 'right' ? this.f7NavbarRightOffset : this.f7NavbarLeftOffset; - - if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) { - sliding.find('.back .icon').css('transform', 'translate3d(' + (-slidingOffset) + 'px,0,0)'); - } - - sliding.css('transform', 'translate3d(' + slidingOffset + 'px,0,0)'); - }); -} \ No newline at end of file diff --git a/src/utils/OverscrollFix.ts b/src/utils/OverscrollFix.ts index f3639c4..8aa7c5d 100755 --- a/src/utils/OverscrollFix.ts +++ b/src/utils/OverscrollFix.ts @@ -1,10 +1,10 @@ export const applyOverscrollFix = () => { - let touchTarget: HTMLElement; - let touchScreenX: number; - let touchScreenY: number; - let conditionParentUntilTrue: any; - let disableScroll: boolean; - let scrollMap: any; + let touchTarget: HTMLElement, + touchScreenX: number, + touchScreenY: number, + conditionParentUntilTrue: any, + disableScroll: boolean, + scrollMap: any; conditionParentUntilTrue = (element: HTMLElement, condition: any) => { let outcome: boolean = false; @@ -25,7 +25,7 @@ window.addEventListener('touchstart', (e: any) => { touchTarget = e.targetTouches[0].target; // a boolean map indicating if the element (or either of element parents, excluding the document.body) can be scrolled to the X direction. - scrollMap = {}; + scrollMap = {} scrollMap.left = conditionParentUntilTrue(touchTarget, (element: HTMLElement) => { return element.scrollLeft > 0; @@ -51,8 +51,8 @@ }); window.addEventListener('touchmove', (e: any) => { - let moveScreenX: number; - let moveScreenY: number; + let moveScreenX: number, + moveScreenY: number; if (disableScroll) { e.preventDefault(); diff --git a/src/utils/ReactifyF7Vue.ts b/src/utils/ReactifyF7Vue.ts new file mode 100644 index 0000000..65088b9 --- /dev/null +++ b/src/utils/ReactifyF7Vue.ts @@ -0,0 +1,110 @@ +import * as React from 'react'; +import {camelCase} from 'change-case'; + +import {IFramework7AppContext} from '../components/Framework7App'; +import {reactifyVue} from './reactify-vue/ReactifyVue'; +import {Dom7} from '../Framework7'; +import {Template7} from '../Framework7'; + +let nextComponentId = 0; + +export interface IReactifyF7VueArgs { + component: any; + tag: string; + slots?: string[]; + args?: any; + instantiatedComponents?: (React.ComponentClass | React.StatelessComponent)[]; + events?: string[]; + mixin?: any; +} + +export const reactifyF7Vue = (args: IReactifyF7VueArgs) => { + const innerComponent = reactifyVue({ + component: args.component, + tag: args.tag, + slots: !args.slots ? null : args.slots.reduce((slotMap, currentSlotName) => { + return { ...slotMap, [currentSlotName]: camelCase(currentSlotName) + 'Slot' }; + }, {}), + events: !args.events ? null : args.events.reduce((eventMap, currentEventName) => { + return { ...eventMap, [currentEventName]: camelCase('on-' + currentEventName.split(':').join('-')) }; + }, {}), + instantiatedComponents: args.instantiatedComponents, + args: { + ...args.args, + $$: Dom7, + $t7: Template7 + }, + mixin: args.mixin + }); + + const reactClass = React.createClass({ + getInitialState: function () { + const framework7AppContext = (this.context as any).framework7AppContext as IFramework7AppContext; + + framework7AppContext.getFramework7(f7 => { + this.framework7 = f7; + }); + + Object.defineProperty(args.component, '$router', { + get: framework7AppContext.getRouter, + enumerable: true, + configurable: true + }); + + Object.defineProperty(args.component, '$route', { + get: framework7AppContext.getCurrentRoute, + enumerable: true, + configurable: true + }); + + Object.defineProperty(args.component, '$f7', { + get: () => this.framework7, + enumerable: true, + configurable: true + }); + + this.componentId = nextComponentId++; + + return null; + }, + + componentWillUnmount: function () { + const framework7AppContext = (this.context as any).framework7AppContext as IFramework7AppContext; + framework7AppContext.unregisterRouteChange(this.componentId) + }, + + render: function() { + const props = this.props; + + const innerEl = React.createElement(innerComponent, { + ...props, + $theme: { material: false, ios: true }, + __onMount: (self) => { + const framework7AppContext = (this.context as any).framework7AppContext as IFramework7AppContext; + + framework7AppContext.getFramework7(f7 => { + if (self.vueComponent.onF7Init) { + self.vueComponent.onF7Init(f7); + } + }); + + framework7AppContext.onRouteChange(this.componentId, route => { + if (self.vueComponent.onRouteChange) { + self.vueComponent.onRouteChange(route); + } + }); + } + }); + + return innerEl; + } + }); + + (reactClass as any).tag = args.tag; + (reactClass as any).vueComponent = args.component; + (reactClass as any).contextTypes = { + framework7AppContext: React.PropTypes.object + }; + + return reactClass; +} \ No newline at end of file diff --git a/src/utils/reactify-vue/ReactifyVue.ts b/src/utils/reactify-vue/ReactifyVue.ts new file mode 100644 index 0000000..66c3b8b --- /dev/null +++ b/src/utils/reactify-vue/ReactifyVue.ts @@ -0,0 +1,48 @@ +import * as React from 'react'; + +import {generateReactClass} from './react-class-creation-and-runtime/GenerateReactClass'; + +export interface IVueEventToPropsMap { + [vueEvent: string]: string; +} + +export interface IVueSlotToReactElementMap { + [slotName: string]: (React.ReactElement | (React.ReactElement)[])[]; +} + +export interface IVueSlotToReactPropNameMap { + [slotName: string]: string; +} + +export interface IVueComponent { + render: (createElement: any) => React.ReactElement; + beforeDestroy?: () => void; + methods?: {[methodName: string]: Function}; + $slots?: IVueSlotToReactElementMap; + $emit?: (eventName: string, ...eventArgs: any[]) => void; + watch?: {[watchedProp: string]: Function}; + computed?: {[computedProp: string]: () => any}; + element?: HTMLElement; + props: any; +} + +export interface IReactifyVueArgs { + component: IVueComponent; + tag: string; + events?: IVueEventToPropsMap; + instantiatedComponents?: (React.ComponentClass | React.StatelessComponent)[]; + slots?: IVueSlotToReactPropNameMap; + args?: any; + mixin?: any; +} + +export const reactifyVue = (reactifyVueArgs: IReactifyVueArgs) => { + return generateReactClass( + reactifyVueArgs.instantiatedComponents, + reactifyVueArgs.component, + reactifyVueArgs.slots, + reactifyVueArgs.tag, + reactifyVueArgs.mixin, + reactifyVueArgs.args + ); +}; \ No newline at end of file diff --git a/src/utils/reactify-vue/react-class-creation-and-runtime/GenerateReactClass.ts b/src/utils/reactify-vue/react-class-creation-and-runtime/GenerateReactClass.ts new file mode 100644 index 0000000..fadb6b8 --- /dev/null +++ b/src/utils/reactify-vue/react-class-creation-and-runtime/GenerateReactClass.ts @@ -0,0 +1,103 @@ +import * as React from 'react'; + +import {convertVueComponentToClass} from './VueComponentClass'; +import { + copyMethodsToVueComponent, + copyPropsToVueComponent, + getComponentTag, + copySlotsToVueComponent, + copyArgsToVueComponent, + handleWatchedProperties, + handleComputedProperties, + getDefaultProps, + addCompiledTemplateFunctionsToVueComponent, + generateCreateElementFunctionForClass, + applyPropOverridesToTopLevelElement, + initData +} from './ReactClassRuntime'; + +export const generateReactClass = (instantiatedComponents, vueComponent, slots, tag, mixin, args) => { + const vueComponentClass = convertVueComponentToClass(vueComponent); + + copyMethodsToVueComponent(vueComponent); + copyArgsToVueComponent(vueComponent, args); + + const reactClass = React.createClass({ + getInitialState: function() { + this.vueComponent = new vueComponentClass(this.props, this); + this.createElement = generateCreateElementFunctionForClass( + this.vueComponent, + instantiatedComponents, + this.vueComponent + ); + + copyPropsToVueComponent(this.vueComponent, this.props); + copySlotsToVueComponent(this.vueComponent, slots, this.props); + const state = initData(this.vueComponent); + handleComputedProperties(this.vueComponent); + + addCompiledTemplateFunctionsToVueComponent(this.vueComponent, this.createElement); + + if (this.props.__onInit) { + this.props.__onInit(this); + } + + return state; + }, + + componentWillUpdate: function () { + if (this.vueComponent.beforeUpdate) this.vueComponent.beforeUpdate(); + }, + + componentDidUpdate: function () { + if (this.vueComponent.updated) this.vueComponent.updated(); + }, + + componentDidMount: function() { + if (this.vueComponent.mounted) this.vueComponent.mounted(); + if (this.props.__onMount) this.props.__onMount(this); + this.didMount = true; + }, + + componentWillUnmount: function() { + if (vueComponent.beforeDestroy) vueComponent.beforeDestroy(); + }, + + componentWillReceiveProps: function(nextProps) { + handleWatchedProperties(this.vueComponent, this.props, nextProps); + }, + + render: function() { + if (this.hasRendered) { + //Only do this after the first render, since it happens in getInitialState the first time + copyPropsToVueComponent(this.vueComponent, this.props); + copySlotsToVueComponent(this.vueComponent, slots, this.props); + handleComputedProperties(this.vueComponent); + } + + const reactElement = this.vueComponent.render(this.createElement.bind(this)); + + this.hasRendered = true; + + if (reactElement) { + return applyPropOverridesToTopLevelElement(reactElement, tag, this); + } else { + return null; + } + }, + + callVueMethod: function(methodName: string, ...args: any[]) { + return this.vueComponent[methodName](args); + } + }); + + (reactClass as any).tag = tag; + (reactClass as any).vueComponent = vueComponent; + (reactClass as any).getVueComponentInstance = () => this.vueComponent; + + const defaultProps = getDefaultProps(vueComponent); + + if (defaultProps) (reactClass as any).defaultProps = defaultProps; + + return reactClass; +}; \ No newline at end of file diff --git a/src/utils/reactify-vue/react-class-creation-and-runtime/ReactClassRuntime.ts b/src/utils/reactify-vue/react-class-creation-and-runtime/ReactClassRuntime.ts new file mode 100644 index 0000000..8a9d61a --- /dev/null +++ b/src/utils/reactify-vue/react-class-creation-and-runtime/ReactClassRuntime.ts @@ -0,0 +1,191 @@ +import * as React from 'react'; +import {camelCase} from 'change-case'; + +import {IVueComponent} from '../ReactifyVue'; +import {createReactElement} from '../react-element-creation/CreateReactElements'; + +export const copyMethodsToVueComponent = (vueComponent: IVueComponent) => { + if (vueComponent.methods) { + Object.keys(vueComponent.methods) + .forEach(methodName => vueComponent[methodName] = vueComponent.methods[methodName]); + + delete vueComponent.methods; + } +}; + +export const copyPropsToVueComponent = (vueComponent: IVueComponent, props: any) => { + if (props) { + Object.keys(props) + .forEach(propName => { + if (typeof vueComponent[propName] !== 'function' || typeof vueComponent[propName] === 'function' && !vueComponent[propName]) { + vueComponent[propName] = props[propName]; + } + }); + } +}; + +export const getComponentTag = (component: any) => { + if (component.type && component.type.tag) { + return component.type.tag; + } else if (component.type && typeof component.type === 'string') { + return component.type; + } else { + return undefined; + } +}; + +export const copySlotsToVueComponent = (vueComponent: IVueComponent, slotMapping, props) => { + const reactChildrenArray = props && props.children && React.Children.toArray(props.children) as (React.ReactElement)[]; + + const slots = { + default: (reactChildrenArray && reactChildrenArray.length) ? reactChildrenArray : null + }; + + if (slotMapping && props) { + Object.keys(slotMapping) + .forEach(slotName => { + slots[slotName] = props[slotMapping[slotName]] || []; + }); + } + + Object.keys(slots) + .forEach(slotName => { + const slot = slots[slotName]; + + if (Array.isArray(slot)) { + slot.forEach((slotChild, index) => { + if (typeof slotChild !== 'string') { + slots[slotName][index] = {...slotChild, tag: getComponentTag(slotChild)}; + } + }); + } + }); + + vueComponent.$slots = slots; +} + +export const copyArgsToVueComponent = (vueComponent: IVueComponent, args: any) => { + if (args) { + Object.keys(args) + .forEach(argName => vueComponent[argName] = args[argName]); + } +} + +export const handleWatchedProperties = (vueComponent: IVueComponent, currentProps: any, nextProps: any) => { + if (vueComponent.watch) { + copyPropsToVueComponent(vueComponent,nextProps); + handleComputedProperties(vueComponent); + + Object.keys(vueComponent.watch) + .forEach(watchedProperty => { + if (currentProps[watchedProperty] !== nextProps[watchedProperty]) { + vueComponent.watch[watchedProperty].apply(vueComponent, [nextProps[watchedProperty]]); + } + }); + } +}; + +export const handleComputedProperties = (vueComponent: IVueComponent) => { + if (vueComponent.computed) { + Object.keys(vueComponent.computed) + .forEach(propertyName => { + vueComponent[propertyName] = vueComponent.computed[propertyName].apply(vueComponent, []) + }); + } +} + +export const getDefaultProps = (vueComponent: IVueComponent) => { + if (vueComponent.props) { + const defaultProps = Object.keys(vueComponent.props).reduce((defaultProps, propName) => { + const propDef = vueComponent.props[propName]; + + if (propDef.default) { + return { + ...defaultProps, + [camelCase(propName)]: propDef.default + }; + } else { + return defaultProps; + } + }, {}); + + return Object.keys(defaultProps).length ? defaultProps : null; + } else { + return null; + } +}; + +export const addCompiledTemplateFunctionsToVueComponent = (vueComponent: any, createElement: Function) => { + vueComponent._self = { _c: createElement.bind(vueComponent) }; + vueComponent._t = (slotName: string, fallback) => { + const slotValue = vueComponent.$slots[slotName]; + + if (fallback && (!slotValue || !slotValue.length)) { + return fallback; + } else { + return slotValue; + } + }; + + vueComponent._v = (text: string) => text || ''; + vueComponent._s = (text: string) => text || ''; + vueComponent._e = () => null; +}; + +export const generateCreateElementFunctionForClass = (classVueComponentInstance, instantiatedComponents, vueComponent) => { + return (element, args, children) => { + if (typeof args !== 'object' || Array.isArray(args)) { + //Children passed in as second argument + return createReactElement(element, {}, args, instantiatedComponents, vueComponent); + } else { + return createReactElement(element, args, children, instantiatedComponents, vueComponent); + } + }; +}; + +export const applyPropOverridesToTopLevelElement = (reactElement: React.ReactElement, tag: string, self) => { + const refFunc = (e: HTMLElement) => { + (reactElement as any).ref(e); + self.element = e; + + self.nextTickCallbacks.forEach(callback => callback.apply(this.vueComponent, [])); + self.nextTickCallbacks = []; + self.hasUnrenderedStateChanges = false; + }; + + const elementWithPropOverrides = {...reactElement, props: { ...reactElement.props}, tag: tag, ref: refFunc}; + + if (self.vueComponent.className) { + const existingClassName = elementWithPropOverrides.props.className || ''; + elementWithPropOverrides.props.className = [existingClassName, ' ', self.vueComponent.className].join(''); + } + + if (self.vueComponent.style) { + const existingStyles = elementWithPropOverrides.props.style || {}; + + elementWithPropOverrides.props.style = { + ...existingStyles, + ...self.vueComponent.style + }; + } + + if (self.vueComponent.id) { + elementWithPropOverrides.props.id = self.vueComponent.id; + } + + return elementWithPropOverrides; +}; + +export const initData = (vueComponent) => { + let state = null; + + if (vueComponent.data) { + state = vueComponent.data(); + + Object.keys(state).forEach(stateKey => { + vueComponent[stateKey] = state[stateKey]; + }); + } + + return state; +}; \ No newline at end of file diff --git a/src/utils/reactify-vue/react-class-creation-and-runtime/VueComponentClass.ts b/src/utils/reactify-vue/react-class-creation-and-runtime/VueComponentClass.ts new file mode 100644 index 0000000..dccc773 --- /dev/null +++ b/src/utils/reactify-vue/react-class-creation-and-runtime/VueComponentClass.ts @@ -0,0 +1,100 @@ +import {camelCase} from 'change-case'; + +const handleStateSet = (stateObject, key, value, vueComponent, self) => { + const stateKey = Object.keys(self.state).reduce((macthingStateKey, nextKey) => { + if (self.state[nextKey] === stateObject) { + return nextKey; + } else { + return macthingStateKey; + } + }, null); + + const newState = { + ...self.state, + [stateKey]: { + ...self.state[stateKey], + [key]: value + } + }; + + vueComponent[stateKey] = newState[stateKey]; + self.setState(newState); +}; + +const callPropOnEvent = (eventName: string, eventArgs: any[], props: any) => { + const eventNameCamelCase = camelCase('on-' + eventName.split(':').join('-')); + + if (props[eventNameCamelCase]) { + props[eventNameCamelCase](...eventArgs); + } +}; + +export const convertVueComponentToClass = (vueComponentObject) => { + const vueComponentClass = function (reactComponentProps, reactComponentInstance) { + this.reactComponentProps = reactComponentProps; + this.reactComponentInstance = reactComponentInstance; + this.reactComponentInstance.nextTickCallbacks = []; + }; + + vueComponentClass.prototype = vueComponentObject; + + if (vueComponentObject.mixins) { + vueComponentObject.mixins.forEach(mixin => { + Object.keys(mixin).forEach(prop => { + vueComponentClass.prototype[prop] = mixin[prop]; + }); + }); + } + + vueComponentClass.prototype.$emit = function (eventName: string, ...eventArgs: any[]) { + callPropOnEvent(eventName, eventArgs, this.reactComponentProps); + }; + + Object.defineProperty(vueComponentClass.prototype, '$el', { + get: function () { return this.reactComponentInstance.element }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(vueComponentClass.prototype, '$parent', { + get: function () { return this.reactComponentProps.parentVueComponent }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(vueComponentClass.prototype, '$children', { + get: function () { + const parentElement = this.$el; + return this.children.map((element, index) => { + return {...element, $el: parentElement.children[index]}; + }); + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(vueComponentClass.prototype, '$options', { + get: function () { + return { + propsData: this.reactComponentProps + }; + }, + enumerable: true, + configurable: true + }); + + vueComponentClass.prototype.$nextTick = function (func) { + if (this.reactComponentInstance.hasUnrenderedStateChanges) { + this.reactComponentInstance.nextTickCallbacks.push(func); + } else { + func(); + } + }; + + vueComponentClass.prototype.$set = function (stateObject, key, value) { + this.reactComponentInstance.hasUnrenderedStateChanges = true; + handleStateSet(stateObject, key, value, this, this.reactComponentInstance); + }; + + return vueComponentClass; +}; \ No newline at end of file diff --git a/src/utils/reactify-vue/react-element-creation/CreateReactElements.ts b/src/utils/reactify-vue/react-element-creation/CreateReactElements.ts new file mode 100644 index 0000000..c0b91e6 --- /dev/null +++ b/src/utils/reactify-vue/react-element-creation/CreateReactElements.ts @@ -0,0 +1,76 @@ +import * as React from 'react'; + +import {IVueComponent} from '../ReactifyVue'; +import {PropsProcessor} from './PropsProcessor'; +import {ManagedFormInput} from '../../../components/inputs/ManagedFormInput'; + +const propsProcessor = new PropsProcessor(); +const formElements = ['input']; + +const resolveDependencyComponent = (instantiatedComponents: (React.ComponentClass | React.StatelessComponent)[], componentToResolve: string) => { + if (instantiatedComponents && componentToResolve.indexOf('f7-') > -1) { + //Is a Vue component that React does not know what to do with, so search for it by tag name so that we can pass the actual React component for rendering. + const results = instantiatedComponents + .filter(instantiatedComponent => { + if ((instantiatedComponent as any).tag) { + return (instantiatedComponent as any).tag === componentToResolve; + } else { + return false; + } + }); + + if (results.length) { return results[0]; } + } else if (formElements.indexOf(componentToResolve) > -1) { + //Is an input that we need to manage to control state + return ManagedFormInput; + } else { + //Is just a plain html element like div, etc. so just return it. + return componentToResolve; + } +}; + +const flattenNestedArrayOfChildren = (children: any[], finalArray: any[] = []) => { + if (children && Array.isArray(children)) { + for (let i = 0; i < children.length; i++) { + if (children[i] && children[i].constructor === Array) { + flattenNestedArrayOfChildren(children[i], finalArray); + } else { + if (finalArray.indexOf(children[i]) === -1) { + finalArray.push(children[i]); + } + } + } + + return finalArray; + } else { + return children; + } +}; + +export const createReactElement = ( + componentOrComponentName: string | React.ComponentClass | React.StatelessComponent, + args, + children, + instantiatedComponents, + vueComponent: IVueComponent +) => { + let reactElement; + + if (!componentOrComponentName) return null; + + let resolvedComponent; + + if (args.tag !== 'component') { + resolvedComponent = resolveDependencyComponent(instantiatedComponents, componentOrComponentName as string); + } + + children = flattenNestedArrayOfChildren(children); + + if (!resolvedComponent) resolvedComponent = componentOrComponentName as React.ComponentClass | React.StatelessComponent; + + const props = propsProcessor.getProps(args, children, componentOrComponentName, resolvedComponent, vueComponent); + + reactElement = React.createElement(resolvedComponent, props); + + return reactElement; +}; \ No newline at end of file diff --git a/src/utils/reactify-vue/react-element-creation/PropsProcessor.ts b/src/utils/reactify-vue/react-element-creation/PropsProcessor.ts new file mode 100644 index 0000000..938912b --- /dev/null +++ b/src/utils/reactify-vue/react-element-creation/PropsProcessor.ts @@ -0,0 +1,334 @@ +import * as React from 'react'; + +import {IVueComponent} from '../ReactifyVue'; + +const camelCase = (str) => { + (camelCase as any).replacement = (camelCase as any).replacement || {}; + + if (!(camelCase as any).replacement[str]) { + (camelCase as any).replacement[str] = str.replace(/-([a-z])/g, function (m, w) { + return w.toUpperCase(); + }); + } + + return (camelCase as any).replacement[str]; +}; + +const hasOwn = {}.hasOwnProperty; + +const classNames = (...args: any[]) => { + const classes = []; + let length = args.length; + + while (length--) { + let arg = args[length]; + + if (!arg) continue; + + let argType = typeof arg; + + if (argType === 'string' || argType === 'number') { + classes.push(arg); + } else if (Array.isArray(arg)) { + classes.push(classNames.apply(null, arg)); + } else if (argType === 'object') { + const keys = Object.keys(arg); + let length = keys.length; + + while (length--) { + let key = keys[length]; + + if (hasOwn.call(arg, key) && arg[key]) { + classes.push(key); + } + } + } + } + + return classes.join(' '); +}; + +const renameEvent = (eventName: string) => { + switch (eventName) { + case 'keypress': + return 'keyPress'; + case 'keyup': + return 'keyUp'; + case 'keydown': + return 'keyDown'; + case 'beforeinput': + return 'beforeInput'; + case 'compositionstart': + return 'compositionStart'; + case 'compositionupdate': + return 'compositionUpdate'; + case 'compositionend': + return 'compositionEnd'; + case 'dblclick': + return 'doubleClick'; + case 'mousedown': + return 'mouseDown'; + case 'mouseenter': + return 'mouseEnter'; + case 'mouseleave': + return 'mouseLeave'; + case 'mousemove': + return 'mouseMove'; + case 'mouseout': + return 'mouseOut'; + case 'mouseover': + return 'mouseOver'; + case 'mouseup': + return 'mouseUp'; + case 'focusin': + return 'focus'; + case 'focusout': + return 'blur' + default: + return eventName; + } +} + +const attributeMap = { + autocapitalize: { + componentNames: ['input', 'textarea', 'select'], + renameTo: 'autoCapitalize' + }, + autocomplete: { + componentNames: ['input', 'textarea', 'select'], + renameTo: 'autoComplete' + }, + autocorrect: { + componentNames: ['input', 'textarea', 'select'], + renameTo: 'autoCorrect' + }, + autofocus: { + componentNames: ['input', 'textarea', 'select'], + renameTo: 'autoFocus' + }, + autosave: { + componentNames: ['input', 'textarea', 'select'], + renameTo: 'autoSave' + }, + maxlength: { + componentNames: ['input', 'textarea', 'select'], + renameTo: 'maxLength' + }, + minlength: { + componentNames: ['input', 'textarea', 'select'], + renameTo: 'minLength' + }, + readonly: { + componentNames: ['input', 'textarea', 'select'], + renameTo: 'readOnly' + }, + spellcheck: { + componentNames: ['input', 'textarea', 'select'], + renameTo: 'spellCheck' + } +}; + +const handleRefs = (element: HTMLElement, vueComponent: IVueComponent, events: {[eventName: string]: Function}, props) => { + if (events) { + for (let eventName in events) { + if (element && element.addEventListener && !((element as any).vueListeners && (element as any).vueListeners[eventName])) { + element.addEventListener(eventName, (...args: any[]) => { + const eventHandler = events[eventName]; + eventHandler.apply(vueComponent, args); + }, true); + + (element as any).vueListeners = (element as any).vueListeners || {}; + (element as any).vueListeners[eventName] = true; + } + } + } + + if (props['data-vue-ref']) { + const vueRef = props['data-vue-ref']; + vueRef.vueComponentInstance.$refs[vueRef.refName] = element; + } +}; + +const renameAttribute = (componentName, attribute) => { + const attributeMapForAttribute = attributeMap[attribute]; + + if (attributeMapForAttribute && attributeMapForAttribute.componentNames.indexOf(componentName) > -1) { + attribute = attributeMapForAttribute.renameTo; + } + + return attribute; +}; + +const renameStyleProperties = (stylesObject) => { + for (var property in stylesObject) { + if (stylesObject.hasOwnProperty(property) && property.indexOf('-') !== -1) { + let newPropertyName = camelCase(property); + + stylesObject[newPropertyName] = stylesObject[property]; + delete stylesObject[property]; + } + } + + return stylesObject; +} + +export class PropsProcessor { + private cachedPropKebabCase: {[camelCasedProp: string]: string}; + + public getProps(args, children, componentOrComponentName, resolvedComponent, vueComponentInstance) { + this.addCurrentComponentAsParentOfChildren(children, vueComponentInstance); + + const props = {}; + + this.getClasses(args, vueComponentInstance, props); + this.getStyle(args, vueComponentInstance, props); + this.getRef(args, vueComponentInstance, resolvedComponent, props); + this.getPropsFromArgs(args, props); + this.getChildren(children, args, props); + this.convertAttrsToProps(args, componentOrComponentName, resolvedComponent, props); + this.getInnerHTML(args, props); + this.handleEvents(resolvedComponent, args.on, vueComponentInstance, props) + this.handleRef(args.ref, vueComponentInstance, props); + + return props; + } + + private getClasses(args, vueComponent, props) { + let classObject = {}; + + if (args.class && typeof args.class === 'string') { + classObject[args.class] = true; + } else if (args.class) { + classObject = args.class; + } + + if (args.staticClass) { + classObject[args.staticClass] = true; + } + + const classes = []; + + for (let key in classObject) { + if (classObject[key]) { + classes.push(key); + } + } + + props.className = classes.join(' '); + } + + private getStyle(args, vueComponent, props) { + let style; + + if (args.style) { + if (typeof args.style === 'object') { + style = args.style; + } else { + throw new Error('ReactifyVue only supports style attributes that are of type object') + } + } + + if (style) { + props.style = renameStyleProperties(style); + } + } + + private handleEvents = (resolvedComponent, eventHandlers, parentVueComponentInstance, props) => { + if (typeof resolvedComponent === 'string') { + + } else { + if (eventHandlers) { + for (let eventName in eventHandlers) { + const camelCasedEventName = `${camelCase('on-' + renameEvent(eventName))}`; + props[camelCasedEventName] = (...eventArgs: any[]) => { + eventHandlers[eventName].apply(parentVueComponentInstance, eventArgs); + }; + } + } + } + } + + private getRef(args, vueComponent, resolvedComponent, props) { + props.ref = ((events, vueComponent) => { + return (element: HTMLElement) => { + const events = args.on; + handleRefs(element, vueComponent, events, props); + }; + })(args.on, vueComponent); + } + + private getPropsFromArgs(args, props) { + if (args.props) { + for (let prop in args.props) { + props[camelCase(prop)] = args.props[prop]; + } + } + } + + private getChildren(children, args, props) { + if (children && !(args.domProps && args.domProps.innerHTML)) { + props.children = children; + } + } + + private convertAttrsToProps(args, componentOrComponentName, resolvedComponent, props) { + if (args.attrs) { + for (let attr in args.attrs) { + attr = renameAttribute(componentOrComponentName, attr); + + const resolvedVueComponent = resolvedComponent.vueComponent; + const attrValue = args.attrs[attr]; + + if (attrValue !== undefined || attrValue !== false) { + const camelCasedAttrName = camelCase(attr); + const vueComponentProp = resolvedVueComponent && resolvedVueComponent.props && resolvedVueComponent.props[camelCasedAttrName]; + + if (vueComponentProp) { + if (vueComponentProp === Boolean && attrValue !== false) { + props[camelCasedAttrName] = true; + } else { + props[camelCasedAttrName] = attrValue; + } + } else { + props[attr] = attrValue; + } + } + } + } + } + + private getInnerHTML(args, props) { + let dangerouslySetInnerHTML; + + if (args.domProps && args.domProps.innerHTML) dangerouslySetInnerHTML = {__html: args.domProps.innerHTML}; + + if (dangerouslySetInnerHTML) { + props.dangerouslySetInnerHTML = dangerouslySetInnerHTML; + } + } + + private addCurrentComponentAsParentOfChildren(children, vueComponent) { + let length = children && children.length; + + if (children && length && Array.isArray(children)) { + for (let i = 0, length = children.length; i < length; i++) { + let child = children[i]; + + if (child && child.tag && child.tag.indexOf('f7-') !== -1) { + child.props = {...child.props, parentVueComponent: vueComponent }; + } + } + } + } + + private handleRef(refName: string, vueComponentInstance, props) { + if (refName) { + if (!vueComponentInstance.$refs) vueComponentInstance.$refs = {}; + + props['data-vue-ref'] = { + refName: refName, + vueComponentInstance + }; + } + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 892cc87..30268d0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,13 +4,11 @@ "module": "commonjs", "declaration": true, "sourceMap": true, - "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, - "noImplicitAny": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "jsx": "react" + "noImplicitAny": false, + "jsx": "react", + "allowJs": true }, - "exclude": ["kitchen-sink"] + "exclude": ["kitchen-sink", "node_modules", "dist"] } \ No newline at end of file diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 8ff97c8..0000000 --- a/tslint.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "extends":["tslint-microsoft-contrib", "tslint-react"], - "rules": { - "no-for-in-array": false, - "restrict-plus-operands": false, - "missing-jsdoc": false, - "eofline": false, - "linebreak-style": [], - "ordered-imports": [], - "export-name": false, - "no-default-export": true, - "no-increment-decrement": false, - "align": [], - "no-any": false, - "max-line-length": [true, 180], - "insecure-random": false , - "quotemark": [true, "single", "jsx-double"], - "variable-name": [true, "allow-pascal-case", "allow-leading-underscore"], - "no-consecutive-blank-lines": [true, 1], - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-module", - "check-type" - ], - "react-this-binding-issue": false, - "react-tsx-curly-spacing": false, - "jsx-no-lambda": false, - "import-name": false, - "no-unused-variable": [false], - "no-console": [false], - "react-a11y-anchors": [false], - "react-a11y-aria-unsupported-elements": [false], - "react-a11y-event-has-role": [false], - "react-a11y-image-button-has-alt": [false], - "react-a11y-img-has-alt": [false], - "react-a11y-lang": [false], - "react-a11y-meta": [false], - "react-a11y-props": [false], - "react-a11y-proptypes": [false], - "react-a11y-role-has-required-aria-props": [false], - "react-a11y-role-supports-aria-props": [false], - "react-a11y-role": [false], - "react-a11y-tabindex-no-positive": [false], - "react-a11y-titles": [false], - "no-relative-imports": false - } -} \ No newline at end of file diff --git a/typings.json b/typings.json index 376bd6e..8eb98f7 100644 --- a/typings.json +++ b/typings.json @@ -1,11 +1,9 @@ { "globalDependencies": { - "bluebird": "registry:dt/bluebird#3.0.0+20160928162057", - "invariant": "registry:dt/invariant#2.2.0+20160317120654", - "jquery": "registry:dt/jquery#1.10.0+20160929162922", "react": "registry:dt/react#0.14.0+20161008064207", - "react-dom": "registry:dt/react-dom#0.14.0+20160412154040", - "react-router": "registry:dt/react-router#2.0.0+20160928130202", - "react-router/history": "registry:dt/react-router/history#2.0.0+20160830150755" + "react-dom": "registry:dt/react-dom#0.14.0+20160412154040" + }, + "dependencies": { + "camelcase": "registry:dt/camelcase#0.0.0+20160428043022" } }