├── .nvmrc ├── stories ├── Image │ ├── README.md │ └── image.stories.js ├── ShexForm │ ├── README.md │ └── shex-form.stories.js ├── ProfileUploader │ ├── README.md │ └── profile-uploader.stories.js ├── LogoutButton │ ├── README.md │ └── logout-button.stories.js ├── withAuthorization │ ├── README.md │ └── with-authorization.stories.js ├── withWebId │ ├── README.md │ └── with-webid.stories.js ├── PrivateRoute │ ├── private-route.stories.js │ └── README.md ├── Uploader │ ├── uploader.stories.js │ └── README.md └── ProviderLogin │ ├── provider-login.stories.js │ └── README.md ├── src ├── lib │ ├── components │ │ ├── FormModel │ │ │ ├── children │ │ │ │ ├── Form │ │ │ │ │ └── UI │ │ │ │ │ │ ├── RadioButtonList │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── radio-button-list.component.js │ │ │ │ │ │ └── radio-button-list.test.js │ │ │ │ │ │ ├── Classifier │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── classifier.style.js │ │ │ │ │ │ └── classifier.component.js │ │ │ │ │ │ ├── Email │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── email.test.js │ │ │ │ │ │ └── email.component.js │ │ │ │ │ │ ├── Float │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── float.test.js │ │ │ │ │ │ └── float.component.js │ │ │ │ │ │ ├── Input │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── input.styles.js │ │ │ │ │ │ ├── input.test.js │ │ │ │ │ │ └── input.component.js │ │ │ │ │ │ ├── Phone │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── phone.test.js │ │ │ │ │ │ └── phone.component.js │ │ │ │ │ │ ├── Select │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── select.component.js │ │ │ │ │ │ └── select.test.js │ │ │ │ │ │ ├── Comment │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── comment.component.js │ │ │ │ │ │ └── comment.test.js │ │ │ │ │ │ ├── Decimal │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── decimal.test.js │ │ │ │ │ │ └── decimal.component.js │ │ │ │ │ │ ├── Heading │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── heading.component.js │ │ │ │ │ │ └── heading.test.js │ │ │ │ │ │ ├── Integer │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── integer.test.js │ │ │ │ │ │ └── integer.component.js │ │ │ │ │ │ ├── CheckBox │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── check-box.styles.js │ │ │ │ │ │ ├── check-box.test.js │ │ │ │ │ │ └── check-box.component.js │ │ │ │ │ │ ├── TextArea │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── text-area.styles.js │ │ │ │ │ │ ├── text-area.test.js │ │ │ │ │ │ └── text-area.component.js │ │ │ │ │ │ ├── RadioButton │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── radio-button.component.js │ │ │ │ │ │ └── radio-button.test.js │ │ │ │ │ │ ├── CheckBoxList │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── check-box-list.component.js │ │ │ │ │ │ └── check-box-list.test.js │ │ │ │ │ │ ├── DeleteButton │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── delete-button.component.js │ │ │ │ │ │ └── delete-button.test.js │ │ │ │ │ │ ├── ErrorMessage │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── error-message.styled.js │ │ │ │ │ │ └── error-message.component.js │ │ │ │ │ │ ├── DateTimePicker │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── date-time.styles.js │ │ │ │ │ │ └── date-time-picker.test.js │ │ │ │ │ │ ├── ColorPicker │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── color-picker.styles.js │ │ │ │ │ │ ├── color-picker.test.js │ │ │ │ │ │ └── color-picker.component.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── component-mapping.js │ │ │ │ ├── Viewer │ │ │ │ │ ├── index.js │ │ │ │ │ ├── UI │ │ │ │ │ │ ├── DateLine │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── date-line.style.js │ │ │ │ │ │ │ ├── date-line.component.js │ │ │ │ │ │ │ └── date-line.test.js │ │ │ │ │ │ ├── ColorLine │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── color-line.style.js │ │ │ │ │ │ │ ├── color-line.component.js │ │ │ │ │ │ │ └── color-line.test.js │ │ │ │ │ │ ├── MultiLine │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── multi-line.style.js │ │ │ │ │ │ │ ├── multi-line.component.js │ │ │ │ │ │ │ └── multi-line.test.js │ │ │ │ │ │ ├── SingleLine │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── single-line.style.js │ │ │ │ │ │ │ ├── single-line.component.js │ │ │ │ │ │ │ └── single-line.test.js │ │ │ │ │ │ ├── BoolLine │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── bool-line.component.js │ │ │ │ │ │ │ ├── bool-line.test.js │ │ │ │ │ │ │ └── bool-line.style.js │ │ │ │ │ │ ├── MultipleViewer │ │ │ │ │ │ │ └── multiple-viewer.component.js │ │ │ │ │ │ └── ui-mapping.js │ │ │ │ │ ├── viewer.style.js │ │ │ │ │ └── viewer.component.js │ │ │ │ ├── Group │ │ │ │ │ ├── index.js │ │ │ │ │ ├── group.style.js │ │ │ │ │ └── group.component.js │ │ │ │ ├── Multiple │ │ │ │ │ ├── index.js │ │ │ │ │ └── multiple.component.js │ │ │ │ └── Spinner │ │ │ │ │ ├── index.js │ │ │ │ │ └── spinner.component.js │ │ │ ├── index.js │ │ │ └── live-form-model.component.js │ │ ├── ShexForm │ │ │ ├── index.js │ │ │ ├── children │ │ │ │ ├── Field │ │ │ │ │ ├── index.js │ │ │ │ │ ├── field.component.test.js │ │ │ │ │ └── field.component.js │ │ │ │ ├── AddButton │ │ │ │ │ ├── index.js │ │ │ │ │ ├── add-button.component.js │ │ │ │ │ └── add-button.component.test.js │ │ │ │ ├── InputField │ │ │ │ │ ├── index.js │ │ │ │ │ ├── styled.component.js │ │ │ │ │ ├── input-field.component.test.js │ │ │ │ │ └── input-field.component.js │ │ │ │ ├── DeleteButton │ │ │ │ │ ├── index.js │ │ │ │ │ ├── delete-button.component.js │ │ │ │ │ └── delete-button.component.test.js │ │ │ │ ├── DropDownField │ │ │ │ │ ├── index.js │ │ │ │ │ ├── styled.component.js │ │ │ │ │ ├── dropdown-field.component.test.js │ │ │ │ │ └── dropdown-field.component.js │ │ │ │ ├── index.js │ │ │ │ └── expression-fields.component.js │ │ │ ├── styled.component.js │ │ │ └── shex-form.component.js │ │ ├── Uploader │ │ │ ├── index.js │ │ │ └── uploader.test.js │ │ ├── ProfileViewer │ │ │ ├── index.js │ │ │ ├── profile-viewer.style.js │ │ │ └── profile-viewer.component.js │ │ ├── ProviderLogin │ │ │ ├── children │ │ │ │ └── Form │ │ │ │ │ ├── index.js │ │ │ │ │ └── form.presentational.js │ │ │ ├── index.js │ │ │ └── provider-login.container.test.js │ │ ├── ProfileUploader │ │ │ ├── index.js │ │ │ ├── profile-uploader.style.js │ │ │ ├── profile-uploader.test.js │ │ │ └── profile-uploader.component.js │ │ ├── ProviderSelect │ │ │ ├── index.js │ │ │ ├── provider.select.component.test.js │ │ │ ├── styled.components.js │ │ │ └── provider.select.component.js │ │ ├── ShexFormBuilder │ │ │ ├── index.js │ │ │ ├── children │ │ │ │ └── ShexFormLive │ │ │ │ │ ├── index.js │ │ │ │ │ ├── styled.component.js │ │ │ │ │ └── shex-form-live.component.js │ │ │ ├── shex-form-builder.component.test.js │ │ │ └── shex-form-builder.component.js │ │ ├── PrivateRoute │ │ │ ├── index.js │ │ │ ├── private-route.style.js │ │ │ ├── private-route.component.js │ │ │ └── private-route.component.test.js │ │ ├── withAuthorization │ │ │ ├── index.js │ │ │ ├── with-authorization.component.js │ │ │ └── with-authorization.test.js │ │ └── index.js │ ├── utils │ │ ├── statusMessage.js │ │ ├── error.js │ │ ├── index.js │ │ ├── datestimes.test.js │ │ ├── datetimes.js │ │ ├── shexFormValidator.js │ │ └── solidFetch.js │ ├── styled-components │ │ ├── index.js │ │ └── form.js │ ├── context │ │ ├── ThemeContext.js │ │ ├── shex.provider.js │ │ ├── formModel.provider.js │ │ └── index.js │ ├── hooks │ │ ├── index.js │ │ ├── useShex.test.js │ │ └── useNotification.test.js │ ├── classes │ │ ├── index.js │ │ ├── access-control-factory.js │ │ ├── access-control-list.test.js │ │ ├── notifications.test.js │ │ └── app-permissions.js │ ├── constants │ │ └── index.js │ ├── index.js │ ├── entities │ │ └── index.js │ └── shapes │ │ └── notification.json ├── assets │ ├── inrupt_logo.png │ └── solid_logo.png ├── demo │ ├── components │ │ ├── index.js │ │ └── HandleShexForm │ │ │ ├── index.js │ │ │ └── handle-shex-form.component.js │ └── index.js └── test │ └── __mocks__ │ ├── @solid │ └── query-ldflex.js │ └── solid-auth-client.js ├── .prettierrc ├── .travis.yml ├── public ├── favicon.ico ├── manifest.json └── index.html ├── .storybook ├── addons.js └── config.js ├── CONTRIBUTING.md ├── config ├── jest │ ├── fileTransform.js │ └── cssTransform.js ├── polyfills.js ├── paths.js └── env.js ├── .gitignore ├── scripts ├── test.js └── start.js ├── .eslintrc └── LICENSE /.nvmrc: -------------------------------------------------------------------------------- 1 | v12.7.0 2 | -------------------------------------------------------------------------------- /stories/Image/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /stories/ShexForm/README.md: -------------------------------------------------------------------------------- 1 | # Shex Form Component 2 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/RadioButtonList/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "printWidth": 100 4 | } 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'node' 4 | script: 5 | - npm run test 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inrupt/solid-react-components/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './viewer.component'; 2 | -------------------------------------------------------------------------------- /src/assets/inrupt_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inrupt/solid-react-components/HEAD/src/assets/inrupt_logo.png -------------------------------------------------------------------------------- /src/assets/solid_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inrupt/solid-react-components/HEAD/src/assets/solid_logo.png -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/DateLine/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './date-line.component'; 2 | -------------------------------------------------------------------------------- /src/demo/components/index.js: -------------------------------------------------------------------------------- 1 | import HandleShexForm from './HandleShexForm'; 2 | 3 | export default HandleShexForm; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Classifier/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './classifier.component'; 2 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/ColorLine/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './color-line.component'; 2 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/MultiLine/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './multi-line.component'; 2 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/index.js: -------------------------------------------------------------------------------- 1 | import ShexForm from './shex-form.component'; 2 | 3 | export default ShexForm; 4 | -------------------------------------------------------------------------------- /src/lib/components/Uploader/index.js: -------------------------------------------------------------------------------- 1 | import Uploader from './uploader.component'; 2 | 3 | export default Uploader; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Group/index.js: -------------------------------------------------------------------------------- 1 | import { Group } from './group.component'; 2 | 3 | export { Group }; 4 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/children/Field/index.js: -------------------------------------------------------------------------------- 1 | import Field from './field.component'; 2 | 3 | export default Field; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Email/index.js: -------------------------------------------------------------------------------- 1 | import { Email } from './email.component'; 2 | 3 | export { Email }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Float/index.js: -------------------------------------------------------------------------------- 1 | import { Float } from './float.component'; 2 | 3 | export { Float }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Input/index.js: -------------------------------------------------------------------------------- 1 | import { Input } from './input.component'; 2 | 3 | export { Input }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Phone/index.js: -------------------------------------------------------------------------------- 1 | import { Phone } from './phone.component'; 2 | 3 | export { Phone }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Select/index.js: -------------------------------------------------------------------------------- 1 | import Select from './select.component'; 2 | 3 | export default Select; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Multiple/index.js: -------------------------------------------------------------------------------- 1 | import { Multiple } from './multiple.component'; 2 | 3 | export { Multiple }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Comment/index.js: -------------------------------------------------------------------------------- 1 | import { Comment } from './comment.component'; 2 | 3 | export { Comment }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Decimal/index.js: -------------------------------------------------------------------------------- 1 | import { Decimal } from './decimal.component'; 2 | 3 | export { Decimal }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Heading/index.js: -------------------------------------------------------------------------------- 1 | import { Heading } from './heading.component'; 2 | 3 | export { Heading }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Integer/index.js: -------------------------------------------------------------------------------- 1 | import { Integer } from './integer.component'; 2 | 3 | export { Integer }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Spinner/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { Spinner } from './spinner.component'; 3 | 4 | export { Spinner }; 5 | -------------------------------------------------------------------------------- /src/lib/components/ProfileViewer/index.js: -------------------------------------------------------------------------------- 1 | import ProfileViewer from './profile-viewer.component'; 2 | 3 | export default ProfileViewer; 4 | -------------------------------------------------------------------------------- /src/lib/components/ProviderLogin/children/Form/index.js: -------------------------------------------------------------------------------- 1 | import LoginForm from './form.presentational'; 2 | 3 | export default LoginForm; 4 | -------------------------------------------------------------------------------- /src/lib/components/ProviderLogin/index.js: -------------------------------------------------------------------------------- 1 | import ProviderLogin from './provider-login.container'; 2 | 3 | export default ProviderLogin; 4 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/children/AddButton/index.js: -------------------------------------------------------------------------------- 1 | import AddButton from './add-button.component'; 2 | 3 | export default AddButton; 4 | -------------------------------------------------------------------------------- /src/demo/components/HandleShexForm/index.js: -------------------------------------------------------------------------------- 1 | import HandleShexForm from './handle-shex-form.component'; 2 | 3 | export default HandleShexForm; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/CheckBox/index.js: -------------------------------------------------------------------------------- 1 | import { CheckBox } from './check-box.component'; 2 | 3 | export { CheckBox }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/TextArea/index.js: -------------------------------------------------------------------------------- 1 | import { TextArea } from './text-area.component'; 2 | 3 | export { TextArea }; 4 | -------------------------------------------------------------------------------- /src/lib/components/ProfileUploader/index.js: -------------------------------------------------------------------------------- 1 | import ProfileUploader from './profile-uploader.component'; 2 | 3 | export default ProfileUploader; 4 | -------------------------------------------------------------------------------- /src/lib/components/ProviderSelect/index.js: -------------------------------------------------------------------------------- 1 | import ProviderSelect from './provider.select.component'; 2 | 3 | export default ProviderSelect; 4 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/children/InputField/index.js: -------------------------------------------------------------------------------- 1 | import InputField from './input-field.component'; 2 | 3 | export default InputField; 4 | -------------------------------------------------------------------------------- /src/lib/components/ShexFormBuilder/index.js: -------------------------------------------------------------------------------- 1 | import ShexFormBuilder from './shex-form-builder.component'; 2 | 3 | export default ShexFormBuilder; 4 | -------------------------------------------------------------------------------- /src/lib/utils/statusMessage.js: -------------------------------------------------------------------------------- 1 | export default function solidResponse(code, message, optionals) { 2 | return { code, message, ...optionals }; 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/SingleLine/index.js: -------------------------------------------------------------------------------- 1 | import { SingleLine } from './single-line.component'; 2 | 3 | export { SingleLine }; 4 | -------------------------------------------------------------------------------- /src/lib/components/PrivateRoute/index.js: -------------------------------------------------------------------------------- 1 | import PrivateRouteWithWebId from './private-route.component'; 2 | 3 | export default PrivateRouteWithWebId; 4 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/children/DeleteButton/index.js: -------------------------------------------------------------------------------- 1 | import DeleteButton from './delete-button.component'; 2 | 3 | export default DeleteButton; 4 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/children/DropDownField/index.js: -------------------------------------------------------------------------------- 1 | import DropDownField from './dropdown-field.component'; 2 | 3 | export default DropDownField; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/RadioButton/index.js: -------------------------------------------------------------------------------- 1 | import { RadioButton } from './radio-button.component'; 2 | 3 | export { RadioButton }; 4 | -------------------------------------------------------------------------------- /src/lib/components/ShexFormBuilder/children/ShexFormLive/index.js: -------------------------------------------------------------------------------- 1 | import ShexFormLive from './shex-form-live.component'; 2 | 3 | export default ShexFormLive; 4 | -------------------------------------------------------------------------------- /src/lib/components/withAuthorization/index.js: -------------------------------------------------------------------------------- 1 | import { withAuthorization } from './with-authorization.component'; 2 | 3 | export default withAuthorization; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/CheckBoxList/index.js: -------------------------------------------------------------------------------- 1 | import CheckBoxList from './check-box-list.component'; 2 | 3 | export default CheckBoxList; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/DeleteButton/index.js: -------------------------------------------------------------------------------- 1 | import { DeleteButton } from './delete-button.component'; 2 | 3 | export default DeleteButton; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/ErrorMessage/index.js: -------------------------------------------------------------------------------- 1 | import { ErrorMessage } from './error-message.component'; 2 | 3 | export default ErrorMessage; 4 | -------------------------------------------------------------------------------- /stories/ProfileUploader/README.md: -------------------------------------------------------------------------------- 1 | ### ProfileUploader 2 | 3 | Here's an example of a basic ProfileUploader component, demonstrating how to add your own Uploader UI 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/DateTimePicker/index.js: -------------------------------------------------------------------------------- 1 | import { DateTimePicker } from './date-time-picker.component'; 2 | 3 | export { DateTimePicker }; 4 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/BoolLine/index.js: -------------------------------------------------------------------------------- 1 | import { BoolLine } from './bool-line.component'; 2 | 3 | export default BoolLine; 4 | export { BoolLine }; 5 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/index.js: -------------------------------------------------------------------------------- 1 | import { FormModel } from './form-model.component'; 2 | import { Spinner } from './children/Spinner'; 3 | 4 | export { FormModel, Spinner }; 5 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/ColorPicker/index.js: -------------------------------------------------------------------------------- 1 | import ColorPicker from './color-picker.component'; 2 | 3 | export default ColorPicker; 4 | export { ColorPicker }; 5 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Select/select.component.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Select = () =>
Select
; 4 | 5 | export default Select; 6 | -------------------------------------------------------------------------------- /src/lib/styled-components/index.js: -------------------------------------------------------------------------------- 1 | import { SolidInput, SolidLinkButton, SolidButton, ErrorMessage } from './form'; 2 | 3 | export { SolidInput, SolidLinkButton, SolidButton, ErrorMessage }; 4 | -------------------------------------------------------------------------------- /src/lib/context/ThemeContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const defaultContext = { 4 | theme: {} 5 | }; 6 | 7 | export const ThemeContext = createContext(defaultContext); 8 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Group/group.style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const ComponentWrapper = styled.div` 4 | display: flex; 5 | align-items: center; 6 | `; 7 | -------------------------------------------------------------------------------- /src/lib/components/PrivateRoute/private-route.style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Loader = styled.div` 4 | max-width: 300; 5 | margin: 0 auto; 6 | text-align: center; 7 | `; 8 | -------------------------------------------------------------------------------- /src/lib/hooks/index.js: -------------------------------------------------------------------------------- 1 | import useShex from './useShex'; 2 | import { useNotification } from './useNotification'; 3 | 4 | export { useShex, useNotification }; // eslint-disable-line import/prefer-default-export 5 | -------------------------------------------------------------------------------- /src/lib/context/shex.provider.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const ShexConfig = React.createContext({ 4 | theme: {}, 5 | languageTheme: {}, 6 | config: {} 7 | }); 8 | 9 | export default ShexConfig; 10 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/DateTimePicker/date-time.styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const ErrorMessage = styled.p` 4 | color: red; 5 | font-size: 0.8rem; 6 | margin: 5px 0 10px; 7 | `; 8 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/ErrorMessage/error-message.styled.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const ErrorWrapper = styled.p` 4 | color: red; 5 | font-size: 1.1rem; 6 | margin-top: 0; 7 | `; 8 | -------------------------------------------------------------------------------- /src/lib/context/formModel.provider.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const FormModelConfig = React.createContext({ 4 | theme: {}, 5 | languageTheme: { 6 | save: 'Save' 7 | }, 8 | config: {} 9 | }); 10 | 11 | export default FormModelConfig; 12 | -------------------------------------------------------------------------------- /src/demo/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import registerServiceWorker from './registerServiceWorker'; 5 | 6 | ReactDOM.render(, document.getElementById('root')); 7 | registerServiceWorker(); 8 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Classifier/classifier.style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const SelectWrapper = styled.div` 4 | box-sizing: border-box; 5 | padding: 0.5em 1em; 6 | display: flex; 7 | align-items: center; 8 | `; 9 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/ErrorMessage/error-message.component.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ErrorWrapper } from './error-message.styled'; 3 | 4 | export const ErrorMessage = ({ valid, errorMessage }) => 5 | !valid && {errorMessage}; 6 | -------------------------------------------------------------------------------- /src/lib/context/index.js: -------------------------------------------------------------------------------- 1 | import ShexConfig from './shex.provider'; 2 | import FormModelConfig from './formModel.provider'; 3 | import { ThemeContext } from './ThemeContext'; 4 | 5 | // eslint-disable-next-line import/prefer-default-export 6 | export { ShexConfig, FormModelConfig, ThemeContext }; 7 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addons'; 2 | import '@storybook/addon-console'; 3 | import 'storybook-readme/register'; 4 | import '@storybook/addon-knobs/register'; 5 | import '@storybook/addon-actions/register'; 6 | import '@storybook/addon-jest/register'; 7 | import 'storybook-addon-jsx/register'; 8 | -------------------------------------------------------------------------------- /src/lib/classes/index.js: -------------------------------------------------------------------------------- 1 | import { Notification } from './notification'; 2 | import AccessControlList from './access-control-list'; 3 | import ACLFactory from './access-control-factory'; 4 | import AppPermission from './app-permissions'; 5 | 6 | export { Notification, AccessControlList, ACLFactory, AppPermission }; 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Solid React Components Library 2 | 3 | Thank you for your interest in contributing to the Solid React Components Library! 4 | 5 | Before getting started, please review the [Solid React SDK Contributor Guide](https://github.com/Inrupt-inc/solid-react-sdk/blob/master/CONTRIBUTING.md). 6 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Heading/heading.component.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | 3 | import { UI } from '@inrupt/lit-generated-vocab-common'; 4 | 5 | export const Heading = props => { 6 | const { data } = props; 7 | 8 | return

{data[UI.contents]}

; 9 | }; 10 | -------------------------------------------------------------------------------- /src/lib/utils/error.js: -------------------------------------------------------------------------------- 1 | export default class SolidError extends Error { 2 | constructor(message, name, code) { 3 | super(message); 4 | this.message = message; 5 | this.statusText = message; 6 | this.name = name || 'SolidError'; 7 | this.type = this.name; 8 | this.code = code || 0; 9 | this.status = code || 0; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | // This is a custom Jest transformer turning file imports into filenames. 4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 5 | 6 | module.exports = { 7 | process(src, filename) { 8 | return `module.exports = ${JSON.stringify(path.basename(filename))};`; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | // This is a custom Jest transformer turning style imports into empty objects. 2 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 3 | 4 | module.exports = { 5 | process() { 6 | return 'module.exports = {};'; 7 | }, 8 | getCacheKey() { 9 | // The output is always the same. 10 | return 'cssTransform'; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/lib/components/ShexFormBuilder/children/ShexFormLive/styled.component.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | import styled from 'styled-components'; 3 | 4 | export const FormComponent = styled.form` 5 | button { 6 | margin: 20px 10px; 7 | border: 1px solid hsl(0, 0%, 80%); 8 | cursor: pointer; 9 | padding: 10px 30px; 10 | } 11 | `; 12 | -------------------------------------------------------------------------------- /stories/LogoutButton/README.md: -------------------------------------------------------------------------------- 1 | ### LogoutButton 2 | 3 | This component uses solid-auth-client to provide a simple button that logs out the user. It is a simple helper component to integrate with solid-auth-client. 4 | 5 | We re-expose this component from [@solid/react](https://github.com/solid/react-components) library. 6 | 7 | ```javascript 8 | 9 | ``` 10 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/DateLine/date-line.style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Wrapper = styled.div` 4 | //display: flex; 5 | padding: 8px 0; 6 | flex-direction: column; 7 | `; 8 | 9 | export const Label = styled.span` 10 | font-size: 16px; 11 | letter-spacing: 0.4px; 12 | `; 13 | 14 | export const Value = styled.span``; 15 | -------------------------------------------------------------------------------- /stories/withAuthorization/README.md: -------------------------------------------------------------------------------- 1 | ### withAuthorization 2 | 3 | This component is a wrapper for withWebId. It provides additional functionality, such as discovering when a user is not authenticated and redirecting them to a custom route, or to /login, when the user is not authenticated. 4 | 5 | ```javascript 6 | export default withAuthorization(WelcomeComponent, ); 7 | ``` 8 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/SingleLine/single-line.style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Wrapper = styled.div` 4 | display: flex; 5 | padding: 8px 0; 6 | flex-direction: column; 7 | `; 8 | 9 | export const Label = styled.span` 10 | font-size: 16px; 11 | letter-spacing: 0.4px; 12 | `; 13 | 14 | export const Value = styled.span``; 15 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Input/input.styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const InputGroup = styled.div` 4 | box-sizing: border-box; 5 | padding: 0.5em 1em; 6 | display: flex; 7 | align-items: center; 8 | & input { 9 | border-radius: 2px; 10 | border: solid 1px #ccc; 11 | padding: 0.5em; 12 | margin-left: 1em; 13 | } 14 | `; 15 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/children/index.js: -------------------------------------------------------------------------------- 1 | import ExpressionFields from './expression-fields.component'; 2 | import AddButton from './AddButton'; 3 | import DeleteButton from './DeleteButton'; 4 | import Field from './Field'; 5 | import InputField from './InputField'; 6 | import DropDownField from './DropDownField'; 7 | 8 | export { ExpressionFields, AddButton, DeleteButton, Field, InputField, DropDownField }; 9 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/RadioButtonList/radio-button-list.component.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import RadioButton from '../RadioButton'; 3 | 4 | const RadioButtonList = ({ list, name }) => { 5 | return ( 6 |
7 | {list.map(check => ( 8 | 9 | ))} 10 |
11 | ); 12 | }; 13 | 14 | export default RadioButtonList; 15 | -------------------------------------------------------------------------------- /stories/Image/image.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { Image } from '@solid-react-components'; 4 | import Readme from './README.md'; 5 | 6 | storiesOf('Image', module) 7 | .addParameters({ 8 | readme: { 9 | // Show readme at the addons panel 10 | sidebar: Readme 11 | } 12 | }) 13 | .add('default', () => ); 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # production 7 | /build 8 | /demo 9 | 10 | # testing 11 | /coverage 12 | 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | # editors 22 | .idea 23 | *.iml 24 | 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | -------------------------------------------------------------------------------- /src/lib/components/ProviderSelect/provider.select.component.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { ProviderSelect } from '@components'; 4 | 5 | afterAll(cleanup); 6 | 7 | describe('ProviderSelect', () => { 8 | const { container } = render(); 9 | it('should render without crashing', () => { 10 | expect(container).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/children/DropDownField/styled.component.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const ErrorMessage = styled.p` 4 | margin: 0; 5 | color: red; 6 | `; 7 | 8 | export const SelectWrapper = styled.div` 9 | position: relative; 10 | &.error { 11 | margin-bottom: 0; 12 | } 13 | `; 14 | 15 | export const Select = styled.select` 16 | .error & { 17 | margin-bottom: 5px; 18 | } 19 | `; 20 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/MultiLine/multi-line.style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Wrapper = styled.div` 4 | display: flex; 5 | padding: 8px 0; 6 | flex-direction: column; 7 | `; 8 | 9 | export const Label = styled.label` 10 | font-weight: bold; 11 | font-size: 16px; 12 | letter-spacing: 0.4px; 13 | `; 14 | 15 | export const Value = styled.p` 16 | white-space: pre-wrap; 17 | `; 18 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/CheckBoxList/check-box-list.component.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CheckBox from '../CheckBox/check-box.component'; 3 | 4 | type Props = { 5 | list: any[] 6 | }; 7 | 8 | const CheckBoxList = ({ list }: Props) => { 9 | return ( 10 |
11 | {list.map(check => ( 12 | 13 | ))} 14 |
15 | ); 16 | }; 17 | 18 | export default CheckBoxList; 19 | -------------------------------------------------------------------------------- /src/lib/components/ProfileUploader/profile-uploader.style.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const ProfileWrapper = styled.div` 4 | border-radius: 60px; 5 | text-align: center; 6 | width: 129px; 7 | height: 129px; 8 | `; 9 | 10 | export const ImgStyle = styled.img` 11 | border-radius: 60px; 12 | width: 100%; 13 | height: 100%; 14 | `; 15 | 16 | export const ButtonStyle = styled.button` 17 | margin-top: 10px; 18 | `; 19 | -------------------------------------------------------------------------------- /stories/LogoutButton/logout-button.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { LogoutButton } from '@solid-react-components'; 4 | 5 | import LogoutButtonReadme from './README.md'; 6 | 7 | storiesOf('Logout button', module) 8 | .addParameters({ 9 | readme: { 10 | // Show readme at the addons panel 11 | sidebar: LogoutButtonReadme 12 | } 13 | }) 14 | .add('default', () => ); 15 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Select/select.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import Select from './select.component'; 4 | import 'jest-dom/extend-expect'; 5 | 6 | afterAll(cleanup); 7 | 8 | describe('Provider Login Container', () => { 9 | const { container } = render( 28 | 29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/ColorPicker/color-picker.styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const PickerGroup = styled.div` 4 | box-sizing: border-box; 5 | padding: 0.5em 1em; 6 | display: flex; 7 | align-items: center; 8 | & label { 9 | padding: 0.5em; 10 | margin-right: 1em; 11 | } 12 | `; 13 | 14 | export const ColorSwatch = styled.div` 15 | width: 36px; 16 | height: 14px; 17 | padding: 5px; 18 | background: ${props => props.color}; 19 | border-radius: 1px; 20 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); 21 | display: inline-block; 22 | cursor: pointer; 23 | `; 24 | 25 | export const Cover = styled.div` 26 | position: fixed; 27 | top: 0; 28 | right: 0; 29 | bottom: 0; 30 | left: 0; 31 | `; 32 | 33 | export const Popover = styled.div` 34 | position: absolute; 35 | z-index: 2; 36 | `; 37 | -------------------------------------------------------------------------------- /src/lib/styled-components/form.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const SolidInput = styled.input` 4 | background-color: hsl(0, 0%, 100%); 5 | border-color: hsl(0, 0%, 80%); 6 | border-radius: 4px; 7 | border-style: solid; 8 | border-width: 1px; 9 | box-sizing: border-box; 10 | width: 100%; 11 | padding: 2px 8px; 12 | height: 30px; 13 | `; 14 | 15 | export const SolidLinkButton = styled.button` 16 | border: none; 17 | background: transparent; 18 | cursor: pointer; 19 | 20 | &:hover { 21 | text-decoration: underline; 22 | } 23 | `; 24 | 25 | export const SolidButton = styled.button` 26 | border: 1px solid hsl(0, 0%, 80%); 27 | cursor: pointer; 28 | padding: 10px 30px; 29 | 30 | &:hover { 31 | opacity: 0.7; 32 | } 33 | `; 34 | 35 | export const ErrorMessage = styled.p` 36 | color: red; 37 | margin: 0; 38 | `; 39 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/DeleteButton/delete-button.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { getByText } from '@testing-library/dom'; 4 | import { DeleteButton } from './delete-button.component'; 5 | import 'jest-dom/extend-expect'; 6 | 7 | afterAll(cleanup); 8 | 9 | test('Renders without crashing', () => { 10 | const props = { 11 | type: 'Group' 12 | }; 13 | const { container } = render(); 14 | expect(getByText(container, 'Delete')).toBeTruthy(); 15 | expect(container).toBeTruthy(); 16 | }); 17 | 18 | test('Renders the text', () => { 19 | const props = { 20 | type: 'Group', 21 | text: 'Button Text' 22 | }; 23 | const { container } = render(); 24 | expect(getByText(container, 'Button Text')).toBeTruthy(); 25 | }); 26 | -------------------------------------------------------------------------------- /config/polyfills.js: -------------------------------------------------------------------------------- 1 | if (typeof Promise === 'undefined') { 2 | // Rejection tracking prevents a common issue where React gets into an 3 | // inconsistent state due to an error, but it gets swallowed by a Promise, 4 | // and the user has no idea what causes React's erratic future behavior. 5 | require('promise/lib/rejection-tracking').enable(); 6 | window.Promise = require('promise/lib/es6-extensions.js'); 7 | } 8 | 9 | // fetch() polyfill for making API calls. 10 | require('whatwg-fetch'); 11 | 12 | // Object.assign() is commonly used with React. 13 | // It will use the native implementation if it's present and isn't buggy. 14 | Object.assign = require('object-assign'); 15 | 16 | // In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet. 17 | // We don't polyfill it in the browser--this is user's responsibility. 18 | if (process.env.NODE_ENV === 'test') { 19 | require('raf').polyfill(global); 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/MultiLine/multi-line.component.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { UI } from '@inrupt/lit-generated-vocab-common'; 3 | import { ThemeContext } from '@context'; 4 | import { Wrapper, Label, Value } from './multi-line.style'; 5 | 6 | type Props = { 7 | id: string, 8 | data: object 9 | }; 10 | 11 | export const MultiLine = (props: Props) => { 12 | const { id, data } = props; 13 | const { theme } = useContext(ThemeContext); 14 | const { [UI.label]: label, [UI.value]: value } = data; 15 | 16 | return ( 17 |
18 | 19 | 22 | 23 | {value || ''} 24 | 25 | 26 |
27 | ); 28 | }; 29 | 30 | export default MultiLine; 31 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/styled.component.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Panel = styled.div` 4 | border: solid 1px red; 5 | padding: 10px; 6 | position: relative; 7 | margin: 10px 0; 8 | 9 | ul { 10 | padding: 0; 11 | margin: 0; 12 | } 13 | 14 | li { 15 | list-style: none; 16 | } 17 | 18 | select { 19 | display: block; 20 | margin: 20px 0; 21 | padding: 10px; 22 | } 23 | 24 | label { 25 | display: block; 26 | margin-top: 15px; 27 | } 28 | 29 | button { 30 | margin: 20px 0; 31 | border: 1px solid hsl(0, 0%, 80%); 32 | cursor: pointer; 33 | padding: 10px 30px; 34 | top: 0; 35 | } 36 | `; 37 | 38 | export const DeleteButton = styled.button` 39 | display: inline-flex; 40 | position: absolute; 41 | right: 8px; 42 | top: 5px; 43 | color: red; 44 | border: none; 45 | background: none; 46 | cursor: pointer; 47 | z-index: 100; 48 | `; 49 | -------------------------------------------------------------------------------- /src/lib/components/ShexFormBuilder/shex-form-builder.component.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | import ShexFormBuilder from './shex-form-builder.component'; 4 | import { act } from 'react-dom/test-utils'; 5 | import 'jest-dom/extend-expect'; 6 | 7 | afterAll(cleanup); 8 | 9 | const setup = props => { 10 | return ; 11 | }; 12 | 13 | const defaultProps = { 14 | documentUri: '', 15 | shexUri: 'https://jpablo.solid.community/public/shapes/profile.shex', 16 | successCallback: null, 17 | errorCallback: null 18 | }; 19 | describe('Shex ShapeForm Component', () => { 20 | let container; 21 | act(() => { 22 | const component = setup(defaultProps); 23 | const options = render(component); 24 | container = options.container; 25 | }); 26 | 27 | it('should render without crashing', () => { 28 | expect(container).toBeTruthy(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/lib/components/withAuthorization/with-authorization.component.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { withWebId } from '@solid/react'; 3 | 4 | export const withAuthorization = (Component, Loader) => 5 | withWebId( 6 | class WithAuthorization extends React.Component { 7 | render() { 8 | const { webId } = this.props; 9 | switch (webId) { 10 | case undefined: 11 | return Loader || null; 12 | case null: 13 | // Using the non-SPA redirect here to clear the state when the user is not logged in 14 | // This helps with making sure state is fully clean on login, and addresses an issue with 15 | // the react-router-dom v5 upgrade, which didn't like using here 16 | window.location.href = '/login'; 17 | return null; 18 | default: 19 | return ; 20 | } 21 | } 22 | } 23 | ); 24 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/live-form-model.component.js: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | import { LiveUpdate } from '@solid/react'; 3 | import FormModel from './form-model.component'; 4 | 5 | type Props = { 6 | modelPath: String, 7 | podPath: String, 8 | title: String, 9 | autoSave: boolean, 10 | onInit: () => void, 11 | onLoaded: () => void, 12 | onError: () => void, 13 | onSuccess: () => void, 14 | onSave: () => void, 15 | onAddNewField: () => void, 16 | onDelete: () => void, 17 | settings: { 18 | theme: object, 19 | languageTheme: object, 20 | config: object 21 | } 22 | }; 23 | 24 | const LiveFormModel = memo(({ liveUpdate = false, podPath, ...props }: Props) => { 25 | return liveUpdate ? ( 26 | 27 | 28 | 29 | ) : ( 30 | 31 | ); 32 | }); 33 | 34 | export default LiveFormModel; 35 | -------------------------------------------------------------------------------- /stories/PrivateRoute/README.md: -------------------------------------------------------------------------------- 1 | ### PrivateRoute 2 | 3 | Protected routes are an important part of any web application. Here we provide a custom component that can be used to check Solid authentication for you. 4 | 5 | The component will check to see if the user is logged in, using the withWebId component from the [@solid/react library](https://github.com/solid/react-components). If the user is not authenticated, they will be redirected to a route of your choosing, passed in via the props. If none is provided it will redirect to a /login route. 6 | 7 | ```javascript 8 | 9 | ``` 10 | 11 | | Props | Type | Default | Description | 12 | | --------- | ------ | ------- | -------------------------------------------------- | 13 | | component | Node | null | Component to render after check if user is logged. | 14 | | redirect | String | /login | Redirect to login if user is not logged. | 15 | -------------------------------------------------------------------------------- /src/lib/classes/access-control-factory.js: -------------------------------------------------------------------------------- 1 | import solid from 'solid-auth-client'; 2 | import * as parse from 'parse-link-header'; 3 | import AccessControlList from './access-control-list'; 4 | 5 | /** 6 | * This factory will create and return a new ACL object while also fetching the Link 7 | * Header and returning the acl file location 8 | */ 9 | export default class ACLFactory { 10 | static createNewAcl = async (owner, documentUri) => { 11 | const aclUrl = await this.getAclUriFromHeader(documentUri); 12 | const aclUrlValidated = new URL(aclUrl, documentUri).href; 13 | return new AccessControlList(owner, documentUri, aclUrlValidated); 14 | }; 15 | 16 | static getAclUriFromHeader = async documentUri => { 17 | try { 18 | const response = await solid.fetch(documentUri, { method: 'HEAD' }); 19 | const parsedLinks = parse(response.headers.get('Link')); 20 | return parsedLinks.acl ? parsedLinks.acl.url : ''; 21 | } catch (error) { 22 | throw error; 23 | } 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": ["react-app", "airbnb", "prettier"], 4 | "plugins": ["react", "prettier"], 5 | "rules": { 6 | "prettier/prettier": [1], 7 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 8 | "no-underscore-dangle": [0], 9 | "import/no-unresolved": [0], 10 | "no-unused-vars": [1], 11 | "react/prop-types": [1], 12 | "no-shadow": [0], 13 | "no-restricted-syntax": [0], 14 | "consistent-return": [0], 15 | "import/prefer-default-export": [0], 16 | "import/no-cycle": [0], 17 | "quotes": [1, "single"], 18 | "react/no-array-index-key": [1], 19 | "react/jsx-one-expression-per-line": [0], 20 | "jsx-a11y/label-has-for": [0] 21 | }, 22 | "settings": { 23 | "import/resolver": { "babel-module": {} } 24 | }, 25 | "parserOptions": { 26 | "ecmaFeatures": { 27 | "jsx": true, 28 | "modules": true 29 | } 30 | }, 31 | "env": { 32 | "browser": true, 33 | "jest": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/lib/utils/index.js: -------------------------------------------------------------------------------- 1 | import SolidError from './error'; 2 | import * as shexUtil from './shex'; 3 | import solidResponse from './statusMessage'; 4 | import ShexFormValidator from './shexFormValidator'; 5 | import { 6 | parseInitialValue, 7 | getLocale, 8 | isValidDate, 9 | getFormattedLocale, 10 | getClosestLocale 11 | } from './datetimes'; 12 | 13 | import { 14 | fetchSchema, 15 | existDocument, 16 | createDocument, 17 | fetchLdflexDocument, 18 | getBasicPod, 19 | getIdpFromWebId 20 | } from './solidFetch'; 21 | 22 | const getFileName = path => { 23 | // eslint-disable-next-line no-useless-escape 24 | return path.replace(/^.*[\\\/]/, ''); 25 | }; 26 | 27 | export { 28 | shexUtil, 29 | SolidError, 30 | solidResponse, 31 | fetchSchema, 32 | existDocument, 33 | createDocument, 34 | fetchLdflexDocument, 35 | ShexFormValidator, 36 | getFileName, 37 | getBasicPod, 38 | getLocale, 39 | parseInitialValue, 40 | isValidDate, 41 | getFormattedLocale, 42 | getClosestLocale, 43 | getIdpFromWebId 44 | }; 45 | -------------------------------------------------------------------------------- /src/test/__mocks__/solid-auth-client.js: -------------------------------------------------------------------------------- 1 | import EventEmitter from 'events'; 2 | // import jest from 'jest'; 3 | 4 | class SolidAuthClient extends EventEmitter { 5 | constructor() { 6 | super(); 7 | this.session = undefined; 8 | } 9 | 10 | login() {} 11 | 12 | logout() {} 13 | 14 | trackSession(callback) { 15 | if (this.session !== undefined) callback(this.session); 16 | this.on('session', callback); 17 | } 18 | mockWebId(webId) { 19 | this.session = webId ? { webId } : null; 20 | this.emit('session', this.session); 21 | return new Promise(resolve => setImmediate(resolve)); 22 | } 23 | currentSession() {} 24 | 25 | fetch() { 26 | return { ok: true, status: 200, url: 'https://example.org/public/test.ttl.acl' }; 27 | } 28 | } 29 | 30 | const instance = new SolidAuthClient(); 31 | jest.spyOn(instance, 'login'); 32 | jest.spyOn(instance, 'logout'); 33 | jest.spyOn(instance, 'trackSession'); 34 | jest.spyOn(instance, 'removeListener'); 35 | jest.spyOn(instance, 'fetch'); 36 | 37 | export default instance; 38 | -------------------------------------------------------------------------------- /src/lib/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | withWebId, 3 | LogoutButton, 4 | Image, 5 | LiveUpdate, 6 | useWebId, 7 | UpdateContext, 8 | useLiveUpdate 9 | } from '@solid/react'; 10 | import { 11 | ProviderLogin, 12 | PrivateRoute, 13 | withAuthorization, 14 | Uploader, 15 | ProfileUploader, 16 | ShexForm, 17 | ShexFormBuilder, 18 | FormModel, 19 | ProfileViewer, 20 | Spinner 21 | } from '@components'; 22 | import { shexUtil } from '@utils'; 23 | 24 | import { useNotification } from '@hooks'; 25 | 26 | import { AccessControlList, ACLFactory, AppPermission } from '@classes'; 27 | 28 | export { 29 | ProviderLogin, 30 | PrivateRoute, 31 | withAuthorization, 32 | Uploader, 33 | ProfileUploader, 34 | withWebId, 35 | LogoutButton, 36 | Image, 37 | LiveUpdate, 38 | useWebId, 39 | UpdateContext, 40 | useLiveUpdate, 41 | ShexForm, 42 | ShexFormBuilder, 43 | useNotification, 44 | AccessControlList, 45 | AppPermission, 46 | FormModel, 47 | Spinner, 48 | ProfileViewer, 49 | ACLFactory, 50 | shexUtil 51 | }; 52 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/children/InputField/input-field.component.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ShexConfig } from '@context'; 3 | import { cleanup, render } from '@testing-library/react'; 4 | import InputField from './input-field.component'; 5 | import 'jest-dom/extend-expect'; 6 | 7 | afterAll(cleanup); 8 | 9 | const config = { theme: {}, languageTheme: {}, config: {} }; 10 | 11 | const setup = props => { 12 | return ( 13 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | describe('Shex ShapeForm Component', () => { 20 | const component = setup({}); 21 | const { container, rerender } = render(component); 22 | 23 | it('should renders without crashing', () => { 24 | expect(container).toBeTruthy(); 25 | }); 26 | 27 | it('should renders error when come from props', () => { 28 | const component = setup({ inputData: { error: 'Error' } }); 29 | 30 | rerender(component); 31 | expect(container).toHaveTextContent('Error'); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /stories/Uploader/uploader.stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { action } from '@storybook/addon-actions'; 4 | import { Uploader, ProfileUploader } from '@solid-react-components'; 5 | import UploaderReadme from './README.md'; 6 | 7 | storiesOf('Uploader', module) 8 | .addParameters({ 9 | readme: { 10 | // Show readme at the addons panel 11 | sidebar: UploaderReadme 12 | }, 13 | jest: ['uploader.test.js'] 14 | }) 15 | .add('default', () => ( 16 | , 19 | limitFiles: 1, 20 | limitSize: 2100000, 21 | accept: 'png,jpg,jpeg', 22 | errorsText: { 23 | sizeLimit: 'Size limit', 24 | unsupported: 'Unsupported', 25 | maximumFiles: 'Max files' 26 | }, 27 | onError: action('onError'), 28 | onComplete: action('onComplete'), 29 | onDrop: action('onDrop'), 30 | onStart: action('onStart') 31 | }} 32 | /> 33 | )); 34 | -------------------------------------------------------------------------------- /src/lib/components/PrivateRoute/private-route.component.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { withWebId } from '@solid/react'; 3 | import { Redirect, Route } from 'react-router-dom'; 4 | 5 | import { Loader } from './private-route.style'; 6 | 7 | type Props = { 8 | webId: String | null, 9 | redirect?: String, 10 | component: Node, 11 | loaderComponent?: Node 12 | }; 13 | 14 | export class PrivateRoute extends Component { 15 | renderRouter = (): React.Element => { 16 | const { webId, redirect, component: RenderComponent, ...rest } = this.props; 17 | return webId ? : ; 18 | }; 19 | 20 | render() { 21 | const { webId, loaderComponent } = this.props; 22 | return webId === null || webId === undefined ? loaderComponent() : this.renderRouter(); 23 | } 24 | } 25 | 26 | PrivateRoute.defaultProps = { 27 | redirect: '/login', 28 | loaderComponent: () => We are validating your data... 29 | }; 30 | 31 | export default withWebId(PrivateRoute); 32 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/ColorPicker/color-picker.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { getByText } from '@testing-library/dom'; 4 | import ColorPicker from './color-picker.component'; 5 | import 'jest-dom/extend-expect'; 6 | import { UI } from '@inrupt/lit-generated-vocab-common'; 7 | 8 | afterAll(cleanup); 9 | 10 | test('Renders without crashing', () => { 11 | const data = {}; 12 | const { container } = render(); 13 | expect(container).toBeTruthy(); 14 | }); 15 | 16 | test('Renders the label', () => { 17 | const data = { 18 | [UI.label]: 'choose color' 19 | }; 20 | const { container } = render(); 21 | expect(getByText(container, 'choose color')).toBeTruthy(); 22 | }); 23 | 24 | test('Renders the color in text', () => { 25 | const data = { 26 | [UI.label]: 'choose color', 27 | [UI.value]: '#aabbcc' 28 | }; 29 | const { container } = render(); 30 | expect(getByText(container, '#aabbcc')).toBeTruthy(); 31 | }); 32 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Float/float.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { getByText, getByLabelText } from '@testing-library/dom'; 4 | import { Float } from './float.component'; 5 | import 'jest-dom/extend-expect'; 6 | import { UI } from '@inrupt/lit-generated-vocab-common'; 7 | 8 | afterAll(cleanup); 9 | 10 | test('Renders without crashing', () => { 11 | const data = {}; 12 | const { container } = render(); 13 | expect(container).toBeTruthy(); 14 | }); 15 | 16 | test('Renders the label', () => { 17 | const data = { 18 | [UI.label]: 'float label' 19 | }; 20 | const { container } = render(); 21 | expect(getByText(container, 'float label')).toBeTruthy(); 22 | }); 23 | 24 | test('Renders the float value', () => { 25 | const data = { 26 | [UI.value]: '123.43', 27 | [UI.label]: 'float label' 28 | }; 29 | 30 | const { container } = render(); 31 | expect(getByLabelText(container, 'float label').value).toBe('123.43'); 32 | }); 33 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Input/input.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { getByText, getByLabelText } from '@testing-library/dom'; 4 | import { Input } from './input.component'; 5 | import 'jest-dom/extend-expect'; 6 | import { UI } from '@inrupt/lit-generated-vocab-common'; 7 | 8 | afterAll(cleanup); 9 | 10 | test('Renders without crashing', () => { 11 | const data = {}; 12 | const { container } = render(); 13 | expect(container).toBeTruthy(); 14 | }); 15 | 16 | test('Renders the label', () => { 17 | const data = { 18 | [UI.label]: 'input label' 19 | }; 20 | const { container } = render(); 21 | expect(getByText(container, 'input label')).toBeTruthy(); 22 | }); 23 | 24 | test('Renders the input content', () => { 25 | const data = { 26 | [UI.label]: 'input label', 27 | [UI.value]: 'any content' 28 | }; 29 | const { container } = render(); 30 | expect(getByLabelText(container, 'input label').value).toBe('any content'); 31 | }); 32 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Email/email.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { getByText, getByLabelText } from '@testing-library/dom'; 4 | import { Email } from './email.component'; 5 | import 'jest-dom/extend-expect'; 6 | import { UI } from '@inrupt/lit-generated-vocab-common'; 7 | 8 | afterAll(cleanup); 9 | 10 | test('Renders without crashing', () => { 11 | const data = {}; 12 | const { container } = render(); 13 | expect(container).toBeTruthy(); 14 | }); 15 | 16 | test('Renders the label', () => { 17 | const data = { 18 | [UI.label]: 'email label' 19 | }; 20 | const { container } = render(); 21 | expect(getByText(container, 'email label')).toBeTruthy(); 22 | }); 23 | 24 | test('Renders the email address', () => { 25 | const data = { 26 | [UI.label]: 'email label', 27 | [UI.value]: 'test@email.com' 28 | }; 29 | const { container } = render(); 30 | expect(getByLabelText(container, 'email label').value).toBe('test@email.com'); 31 | }); 32 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Integer/integer.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { getByText, getByLabelText } from '@testing-library/dom'; 4 | import { Integer } from './integer.component'; 5 | import 'jest-dom/extend-expect'; 6 | import { UI } from '@inrupt/lit-generated-vocab-common'; 7 | 8 | afterAll(cleanup); 9 | 10 | test('Renders without crashing', () => { 11 | const data = {}; 12 | const { container } = render(); 13 | expect(container).toBeTruthy(); 14 | }); 15 | 16 | test('Renders the label', () => { 17 | const data = { 18 | [UI.label]: 'integer label' 19 | }; 20 | const { container } = render(); 21 | expect(getByText(container, 'integer label')).toBeTruthy(); 22 | }); 23 | 24 | test('Renders the integer value', () => { 25 | const data = { 26 | [UI.label]: 'integer label', 27 | [UI.value]: '123' 28 | }; 29 | const { container } = render(); 30 | expect(getByLabelText(container, 'integer label').value).toBe('123'); 31 | }); 32 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/Phone/phone.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { getByText, getByLabelText } from '@testing-library/dom'; 4 | import { Phone } from './phone.component'; 5 | import 'jest-dom/extend-expect'; 6 | import { UI } from '@inrupt/lit-generated-vocab-common'; 7 | 8 | afterAll(cleanup); 9 | 10 | test('Renders without crashing', () => { 11 | const data = {}; 12 | const { container } = render(); 13 | expect(container).toBeTruthy(); 14 | }); 15 | 16 | test('Renders the label', () => { 17 | const data = { 18 | [UI.label]: 'Phone label' 19 | }; 20 | const { container } = render(); 21 | expect(getByText(container, 'Phone label')).toBeTruthy(); 22 | }); 23 | 24 | test('Renders the Phone address', () => { 25 | const data = { 26 | [UI.label]: 'Phone label', 27 | [UI.value]: '(555) 555-5555' 28 | }; 29 | const { container } = render(); 30 | expect(getByLabelText(container, 'Phone label').value).toBe('(555) 555-5555'); 31 | }); 32 | -------------------------------------------------------------------------------- /src/lib/components/Uploader/uploader.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import Uploader from './uploader.component'; 4 | 5 | const BasicComponent = () =>
Basic Component
; 6 | 7 | afterAll(cleanup); 8 | 9 | describe('Solid Uploader', () => { 10 | describe('render without crashing', () => { 11 | it('should render uploader component', () => { 12 | const { container } = render( } />); 13 | expect(container).toBeTruthy(); 14 | }); 15 | 16 | it('should render component by prop', () => { 17 | const { getByTestId } = render( } />); 18 | const childComponent = getByTestId('render-component'); 19 | expect(childComponent).toBeTruthy(); 20 | }); 21 | 22 | it('should render input file', () => { 23 | const { getByTestId } = render( } />); 24 | const inputEl = getByTestId('input-file'); 25 | expect(inputEl).toBeTruthy(); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Inrupt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib/components/ShexForm/children/DropDownField/dropdown-field.component.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ShexConfig } from '@context'; 3 | import { cleanup, render } from '@testing-library/react'; 4 | import DropDownField from './dropdown-field.component'; 5 | import 'jest-dom/extend-expect'; 6 | 7 | afterAll(cleanup); 8 | 9 | const config = { theme: {}, languageTheme: {}, config: {} }; 10 | 11 | const setup = props => { 12 | return ( 13 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | describe('Shex ShapeForm Component', () => { 20 | const component = setup({ values: ['option1', ['option 1']] }); 21 | const { container, rerender } = render(component); 22 | 23 | it('should renders without crashing', () => { 24 | expect(container).toBeTruthy(); 25 | }); 26 | 27 | it('should renders with object values', () => { 28 | const component = setup({ 29 | values: [{ value: 'option1' }, { value: 'option 2' }] 30 | }); 31 | 32 | rerender(component); 33 | expect(container).toBeTruthy(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Viewer/UI/SingleLine/single-line.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { getByText, getByLabelText } from '@testing-library/dom'; 4 | import { SingleLine } from './single-line.component'; 5 | import { UI } from '@inrupt/lit-generated-vocab-common'; 6 | 7 | import 'jest-dom/extend-expect'; 8 | 9 | afterAll(cleanup); 10 | 11 | test('Renders without crashing', () => { 12 | const data = {}; 13 | const { container } = render(); 14 | expect(container).toBeTruthy(); 15 | }); 16 | 17 | test('Renders the label', () => { 18 | const data = { 19 | [UI.label]: 'single' 20 | }; 21 | const { container } = render(); 22 | expect(getByText(container, 'single')).toBeTruthy(); 23 | }); 24 | 25 | test('Renders the value', () => { 26 | const data = { 27 | [UI.label]: 'single', 28 | [UI.value]: 'test value' 29 | }; 30 | 31 | const { container } = render(); 32 | expect(getByLabelText(container, 'single').textContent).toBe('test value'); 33 | }); 34 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/RadioButton/radio-button.component.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import { ThemeContext } from '@context'; 3 | import { UI } from '@inrupt/lit-generated-vocab-common'; 4 | 5 | type Props = { 6 | id: string, 7 | data: object, 8 | updateData: (string, string) => void 9 | }; 10 | 11 | export const RadioButton = (props: Props) => { 12 | const { id, data, updateData } = props; 13 | const { theme } = useContext(ThemeContext); 14 | 15 | const { [UI.label]: label, [UI.value]: initialValue } = data; 16 | 17 | const [value, setValue] = useState(initialValue); 18 | 19 | const onChange = event => setValue(event.target.value); 20 | 21 | const onBlur = () => { 22 | const updatedPart = { ...data, value }; 23 | updateData(id, updatedPart); 24 | }; 25 | 26 | return ( 27 |
28 | 29 | 38 |
39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /src/lib/components/FormModel/children/Form/UI/TextArea/text-area.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { getByText, getByLabelText } from '@testing-library/dom'; 4 | import { TextArea } from './text-area.component'; 5 | import 'jest-dom/extend-expect'; 6 | import { UI } from '@inrupt/lit-generated-vocab-common'; 7 | 8 | afterAll(cleanup); 9 | 10 | test('Renders without crashing', () => { 11 | const data = {}; 12 | const { container } = render(