packs-framework
v2.0.10
Published
The packs framework provides state management and a React-based container for loading [packs](https://gitlab.com/wiagl/packs) survey components. The framework takes in a list of components, declarative JSON "modules" (one for each survey screen), an initi
Downloads
28
Readme
Packs Framework ✌️
The packs framework provides state management and a React-based container for loading packs survey components. The framework takes in a list of components, declarative JSON "modules" (one for each survey screen), an initial state object, a "wrapper" component for wrapping components across all screens, and a recorder function to store responses. It's recommended to use the packs cli tool for generating and managing surveys, instead of directly using the framework.
Packs components
Packs components are the building blocks of a packs app. Each component returns response data that advances the survey to the next screen, or survey "module", using the push
function exposed from the framework.
Here is a simplified example of a component that asks for a binary response, 'A' or 'B' using radio buttons:
({ name='qux', options=['A', 'B'], push }) => (
<div>
{
options.map((option, i) => (
<label
key={i}
onClick={() => push({ [name]: option })}
>
{option}
<input type="radio" />
</label>
))
}
</div>
)
Each component can access variables from the global state / response object using a special $ syntax in its props, which is explained further below.
JSON modules
Each survey screen is defined by a declarative JSON object that references a specific component and provides parameters as props to the component. The following example references a component similar to the example component above, in the npm package "your-components". This component will return the response to the global state / response object under the variable "indent_preference" which can later be referenced inside props using the syntax "$indent_preference" or, embedded in a string, as "Really? You prefer ${indent_preference}??".
Example component:
{
"component": "your-components/ChooseOne",
"name": "indent_preference",
"text": "Which do you prefer?",
"options": [
"Tabs",
"Spaces"
]
}
Later example:
{
"component": "your-components/Message",
"text": "Really? You prefer ${indent_preference}??"
}
State management
The framework maintains an atomic state object that components can write to, in order to unmount, and read from during mounting. This works because surveys are generally a linear process. The StateList
state manager also handles browser history between survey modules automatically. It also provides a temporary screenState
object that modules can write to during instantiation through the exposed set
function, which will temporarily overwrite the global state object. For example, a component with a text input could update itself through the set
function:
const component = ({ value, set }) => (
<input
type="text"
value={value}
onChange={e => set({ v: e.target.value })}
/>
)
component.defaultProps = {
value: '$v'
}
Afterwards the framework will reset the screenState
object for the next module.
Recorder function
The framework uses a recorder function for storing response data which you can customize and pass in. The recorder function is initialized on page load and called after each push
call. Here is a simplified example:
const recorder = (endpoint, responseObject, index) => {
// you must initialize a session "key" so that the framework doesn't keep trying to initialize
sessionStorage.setItem("key", "INITIALIZED");
return new Promise((reject, resolve) => {
// handle the responseObject
resolve();
});
}
A response object looks like:
{
data: [{
module_0_component: 'your-components/ChooseOne',
module_0_t: 1508503142793,
indent_preference: 'Spaces'
}],
screenState: [
{
indent_preference: 'Tabs',
timestamp: 1508503141700
},
{
indent_preference: 'Spaces',
timestamp: 1508503142100
}
],
silent: false
}
The data field is an array in case the user goes back and changes their answer.
Silent components
Silent components are renderless components that simply process data, for example randomizing two states:
{
"component": "packs-components/Randomize",
"states": [
{ "coin": true },
{ "coin": false }
]
}
These components must pass a silent flag, by passing true as the second argument when calling push
to ensure that StateList doesn't create a new history entry (or else going back wouldn't work since the component instantly returns). For example:
push({ coin: Math.random() > 0.5 }, true);
Wrapper component
A wrapper component is a special container component to style and house a survey. It can access the survey state and display a progress bar or other useful information.
Advanced
pack
function
The pack function is a higher-order function that takes in a set of components and returns a special function that takes an initial state object, modules, element id where to mount, wrapper component and recorder function. It's recommended to use the packs cli tool instead of using this function directly.
Simplified example:
import { pack } from 'packs-framework'
import components from 'my-components'
import wrapper from 'my-wrapper'
import recorder from 'my-recorder'
const run = pack(components)
const initialState = {
start: Date.now()
}
const modules = [
{
"component": "Markdown",
"source": "### Instructions\nPlease be honest"
},
{
"component": "ChooseOne",
"name": "indent_preference",
"text": "Which do you prefer?",
"options": [
"Tabs",
"Spaces"
]
},
{
"component": "NumberInput",
"text": "How many spaces?",
"condition": {
"==": ["$indent_preference", "Spaces"]
}
}
]
const elementId = 'root' // id of div to mount app
run(initialState, modules, elementId, wrapper, recorder)
Browser support
Packwrap currently targets IE10+ and evergreen browsers. Compatibility table coming soon...
Thanks to BrowserStack for providing cross-browser testing for this project. They are an excellent service for testing your surveys across many browsers and devices and support open-source projects.
Version history
2.0.10
- queueUrl may not exist (undefined).
2.0.9
- Adding config.
2.0.8
- Adding queueUrl.
2.0.7
- update yarn
2.0.6
- save module name
2.0.5
- Remove lib from git, use eslint.
2.0.4
- lib/stateList.js was in camelcase for some reason, change to lib/StateList.js as it should be.
2.0.3
- Undo the changes in 2.0.2 which were done by accident.
2.0.2
- Move various Babel dependencies from dev-dependencies, because they are needed when packing surveys.
2.0.1
Last Robbie version