@annotation-studio/components

annotation-components React component

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
@annotation-studio/components
1.0.0-rc.352 years ago5 years agoMinified + gzip package size for @annotation-studio/components in KB

Readme

Annotation Studio Components

Components

  • Composites
- Canvas
- Confirmation Form
- Selector
- Viewer (@todo)
- Router
  • Domain
- Validation
  • Inputs
- DatePicker
- Form
- TextArea
- TextBox
  • Navigation
- Navigation Resource
  • Selectors
- BoxSelector
- WholeCanvasSelector
  • Viewers
- StaticImageViewer
- ScaledImageViewer
- OpenSeadragonViewer

Composites

These are React components that are composed of other react components. They are still mostly pure components, handing off their state management to Redux. Some offer APIs for choosing between different components (like selectors) with the goal in the future to be smart and delegate based on different contexts to choose the best component for the job. (Think A/V IIIF content)

Canvas

This is the abstract concept of space occupied so far by Selectors, Viewers and drawn Regions or annotations.

Prop types

propType = {
   onUpdateSelector: PropTypes.func,
   onSaveSelector: PropTypes.func,
   selector: PropTypes.shape({
     type: PropTypes.string.isRequired,
     left: PropTypes.number,
     top: PropTypes.number,
     height: PropTypes.number,
     width: PropTypes.number,
   }),
   image: PropTypes.shape({
     src: PropTypes.string.isRequired,
     height: PropTypes.number.isRequired,
     width: PropTypes.number.isRequired,
   }).isRequired,
   displayWidth: PropTypes.number.isRequired,
}

Minimum example usage

```jsx harmony
#### ConfirmationForm
The confirmation form is a composite of form elements and display values. It adds a "preview" to forms to allow a better and customisable representation of the values.

#### Prop types
```javascript
propTypes = {
  draft: PropTypes.shape({
    id: PropTypes.string.isRequired,
    isPreviewing: PropTypes.bool.isRequired,
    input: PropTypes.object.isRequired,
  }),
  bem: PropTypes.object,
  nextLabel: PropTypes.string,
  editLabel: PropTypes.string,
  saveLabel: PropTypes.string,
  updateField: PropTypes.func.isRequired,
  onEdit: PropTypes.func,
  onSave: PropTypes.func,
  previewDraft: PropTypes.func.isRequired,
};

Minimum example usage

```jsx harmony draft={{ id: 1, isPreviewing: this.state.previewing, input: { title: 'testing' } }} updateField={e => console.log(e)} previewDraft={e => this.setState({ previewing: true })} onEdit={e => this.setState({ previewing: false })} />
### Selector
This is the composite selector that will be most used in apps to get any selector that you require without duplicating code elsewhere.


#### Prop Types
```javascript
propTypes = {
  type: PropTypes.string.isRequired,
  onSave: PropTypes.func.isRequired,
  onCancel: PropTypes.func,
  initialPosition: PropTypes.shape({
    left: PropTypes.number,
    top: PropTypes.number,
    height: PropTypes.number,
    width: PropTypes.number,
  }),
}

Minimum example usage

```jsx harmony
#### Router
The router is a very basic routing component that will route in a similar way to a switch/case or if/elseif. You can define boolean logic to create complex flows through components, while remaining pure and quick.

#### Prop types
```javascript
propTypes = {
  routes: PropTypes.arrayOf(
    PropTypes.shape({
      matches: PropTypes.func.isRequired,
      render: PropTypes.func.isRequired,
    }).isRequired
  ),
  state: PropTypes.any,
  renderNotFound: PropTypes.func,
};

Minimum example usage

```jsx harmony routes={[ { matches: (state) => state.isFirst, render: () => <StepOne /> }, { matches: (state) => !state.isFinished && !state.isFirst, render: () => <StepTwo /> }, { matches: (state) => state.isFinished, render: () => <LastStep /> } ]} state={{ isFirst: true }} />
### Domain
**Note:** this is likely to be removed from this part of the library as it is not strictly a component.

#### Validation
This is a library that will try and validate a variety of JSON-LD fields and contexts. 

#### Usage
```javascript
import validation from '@annotation-studio/components/es/domain/validation';

const fields = [
    {context: 'https://schema.org/jobTitle', value: 'Some job title'},
    {context: 'https://schema.org/birthDate', value: '31st Feb 1990'},
];

function validate(field) {
  if (validation[field.context]) {
    return validation[field.context](field.value);
  }
  return true;
}

function validateAll(fields) {
    return fields.reduce((acc, cur) => acc && validate(field))
}

const isValid = validateAll(fields); // False since 31st Feb is invalid.

Inputs

Inputs are combined by a unified input field, offering an easy to compose interface to render a variety of fields. In the future this will be expanded to be more smart when choosing which field to render. Currently we have 3 example fields.

Date Picker

The date picker is a wrapper around a 3rd-party React component that really was meant to show off how these interfaces can be driven and expanded without re-inventing various wheels.

Prop types

propTypes = {
  id: PropTypes.string.isRequired,
  value: PropTypes.string.isRequired,
  update: PropTypes.func.isRequired,
  metaData: PropTypes.shape({
    title: PropTypes.string.isRequired,
    description: PropTypes.string
  }).isRequired,
  preview: PropTypes.bool,
};

Minimum example usage

```jsx harmony id={123} value={this.state.value} update={(value) => this.setState({ value })} metaData={{ title: 'Pick a date' }} />
#### BEM class customisation
List of classes:

- `.input-text-box`
    - `.input-text-box__label`
    - `.input-text-box__description`
    - `.input-text-box__preview`
    - `.input-text-box__input`
        - `.input-text-box__input--datepicker`

#### Form
The form is a composition of form elements, with associated meta data to drive both styling and display of elements. This will also be expanded to be more introspective of fields and perform "best guess" when choosing fields. Currently its all driven by type.

#### Prop types
```javascript
propTypes = {
  draft: PropTypes.shape({
    id: PropTypes.string.isRequired,
    input: PropTypes.objectOf(PropTypes.string).isRequired,
    isPreviewing: PropTypes.bool
  }).isRequired,
  fields: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.string.isRequired,
    inputType: PropTypes.oneOf(['madoc:textarea', 'madoc:datepicker', 'madoc:textbox']),
    metaData: PropTypes.shape({
      title: PropTypes.string.isRequired,
      description: PropTypes.string,
      conformsTo: PropTypes.shape({
        id: PropTypes.oneOf([
          'http://xmlns.com/foaf/name',
          'https://schema.org/birthDate',
          'https://schema.org/jobTitle',
          'http://dublincore.org/documents/dcmi-terms/#terms-description'
        ]),
        label: PropTypes.string.isRequired,
      }),
    }).isRequired,
  })).isRequired,
  updateField: PropTypes.func.isRequired,
};

Minimum example usage

```jsx harmony draft={{ id: 1, input: this.state.values || {name: '', familyName: ''} }} fields={[ { id: 'name', inputType: 'madoc:textbox', metaData: { title: 'First name' }}, { id: 'familyName', inputType: 'madoc:textbox', metaData: { title: 'Family name' }}, ]} updateField={(field, value) => this.setState(s => s.values[field.id] = value)} />
#### BEM class customisation
List of classes:

- `.input-form`
    - `.input-form__error`
        - `.input-form__error--hidden`


### TextArea
The text area is one of the most basic components binding to the DOM.

#### Prop Types
```javascript
propTypes = {
  id: PropTypes.string.isRequired,
  value: PropTypes.string.isRequired,
  update: PropTypes.func.isRequired,
  metaData: PropTypes.shape({
    title: PropTypes.string.isRequired,
    description: PropTypes.string
  }).isRequired,
  preview: PropTypes.bool,
};

Minimum example usage

```jsx harmony id={123} value={this.state.value} update={(value) => this.setState({ value })} metaData={{ title: 'Tell a story' }} />
#### BEM class customisation
List of classes:

- `.input-text-box`
    - `.input-text-box__label`
    - `.input-text-box__description`
    - `.input-text-box__preview`
    - `.input-text-box__input`
        - `.input-text-box__input--textarea`

### TextField
The text area is one of the most basic components binding to the DOM.

#### Prop Types
```javascript
propTypes = {
  id: PropTypes.string.isRequired,
  value: PropTypes.string.isRequired,
  update: PropTypes.func.isRequired,
  metaData: PropTypes.shape({
    title: PropTypes.string.isRequired,
    description: PropTypes.string
  }).isRequired,
  preview: PropTypes.bool,
};

Minimum example usage

```jsx harmony harmony id={123} value={this.state.value} update={(value) => this.setState({ value })} metaData={{ title: 'First name' }} />
#### BEM class customisation
List of classes:

- `.input-text-box`
    - `.input-text-box__label`
    - `.input-text-box__description`
    - `.input-text-box__preview`
    - `.input-text-box__input`

## Navigation
The navigation section is one of the latest additions.

### ResourceNavigator
The resource navigator focuses on building a UI around navigating through state by providing a path similar to `path1.path2.path3` in Object notation. It binds to a UI and logic, allowing for state to be changed and the user to navigate through and render various things based on the current "location" in the state.

#### Prop Types
propTypes = { selections: PropTypes.arrayOf(PropTypes.any).isRequired, bem: PropTypes.object, renderSelection: PropTypes.func, onSelect: PropTypes.func.isRequired, };
#### Minimum example usage
```jsx harmony
<ResourceNavigator 
    selections={['apples', 'oranges']}
    onSelect={selection => console.log(selection)}>
    Choose a fruit
</ResourceNavigator>

BEM class customisation

List of classes:
  • .resource-navigator
- `.resource-navigator__selection`

Selectors

Selectors are built around highlighting a section or region of an image using a variety of tools, and being able to generate W3C valid selectors. This includes the media frags selector and also the SVG selector specifications.

BoxSelector

The box selector is a draggable box that is initially placed on a canvas. It is dragged around and is responsible for relaying back the co-ordinates that it currently exists at on the canvas (relative to the view port, for OSD)

Prop Types

propTypes = {
  onSave: PropTypes.func.isRequired,
  onUpdate: PropTypes.func.isRequired,
  onCancel: PropTypes.func,
  initialPosition: PropTypes.shape({
    left: PropTypes.number,
    top: PropTypes.number,
    height: PropTypes.number,
    width: PropTypes.number,
  }),
};

Minimum example usage

```jsx harmony console.log(position)} onUpdate={position => console.log(position)} />
**Note:** the box selector can be dragged around its parents bounds. Make sure you have an appropriate container for dragging the box around and that it matches the height and width of your content.

#### BEM class customisation
List of classes:
- `.box-selector`
    - `.box-selector__button`


### WholeCanvasSelector
The whole canvas selector is a unique component, as it doesn't require a UI to work. Its job is simply to conform to the interface of other selectors and provide a way for the onSave method to be called to let the application know that it needs to target the whole application.

There is support for making the user confirm their selection before hand. You could envision cancel buttons being added at an application level too, if that fits with the user experience.

#### Prop types
```javascript
propTypes = {
  skipConfirm: PropTypes.bool,
  onSave: PropTypes.func.isRequired,
  onCancel: PropTypes.func, // unused
};

Minimum example usage

```jsx harmony console.log('called on render')} />
## Viewers
Viewers are components that display various kinds of content that you might want to annotate or surface annotations on.

### Static Image Viewer
This is the most basic viewer, it takes an image, and displays it full size.

```javascript
propTypes = {
  resource: PropTypes.string.isRequired,
  height: PropTypes.number.isRequired,
  width: PropTypes.number.isRequired,
  regions: PropTypes.arrayOf(
    PropTypes.shape({
      onClick: PropTypes.func,
      left: PropTypes.number.isRequired,
      top: PropTypes.number.isRequired,
      height: PropTypes.number.isRequired,
      width: PropTypes.number.isRequired,
      selected: PropTypes.bool.isRequired,
    })
  )
}

Minimum example usage

```jsx harmony resource="http://.../portrait.jpg" height={200} width={100} />
### Scaled Image Viewer
This was the next iteration from the static image viewer, this component internally uses the static image viewer, but simply scales it down. You must specify a scale for this one to work. *Note: because of the way react works, you can change the height, width and scale interactively and still achieve accurate positions of regions, this aids with responsive design*

#### Prop types
```javascript
propTypes = {
  resource: PropTypes.string.isRequired,
  height: PropTypes.number.isRequired,
  width: PropTypes.number.isRequired,
  regions: PropTypes.arrayOf(
    PropTypes.shape({
      onClick: PropTypes.func,
      left: PropTypes.number.isRequired,
      top: PropTypes.number.isRequired,
      height: PropTypes.number.isRequired,
      width: PropTypes.number.isRequired,
      selected: PropTypes.bool.isRequired,
    })
  ),
  scale: PropTypes.number.isRequired // this is unique to this component.
}

Minimum example usage

```jsx harmony resource="http://.../portrait.jpg" height={400} width={200} scale={0.5} />
This will display the image at half the size (i.e. 100x200). You can also scale up, if required.


### OpenSeadragonViewer
This is the most common choice for viewer, it consumes IIIF resources and enables deep zoom functionality. Unfortunately, not all content is the same, so this viewer will fallback as often as it can if it cannot read the resource provided.

#### Prop types
```javascript
propTypes = {
  resource: PropTypes.string.isRequired,
  height: PropTypes.number.isRequired,
  width: PropTypes.number.isRequired,
  regions: PropTypes.arrayOf(
    PropTypes.shape({
      onClick: PropTypes.func,
      left: PropTypes.number.isRequired,
      top: PropTypes.number.isRequired,
      height: PropTypes.number.isRequired,
      width: PropTypes.number.isRequired,
      selected: PropTypes.bool.isRequired,
    })
  ),
  scale: PropTypes.number.isRequired,
  canvas: PropTypes.object.isRequired, // this is the IIIF Canvas, fully loaded, not an ID.
  maxHeight: PropTypes.number // Defaults to height*scale
}

Minimum example usage

```jsx harmony resource="http://.../portrait.jpg" // this is required in case a fallback is required height={400} width={200} scale={0.5} canvas={{ '@id': '...', '@type': 'sc:Canvas', /*...*/ }} /> ```