@stonecrop/beam 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # BEAM UI Components
2
+
3
+ - Navbar
4
+ - Dropdown or drawer menu depending on client
5
+ - ListView
6
+ - List Item
7
+ - ItemCounter
8
+ - Needs count logic and styling, should accept an object, not a string
9
+ - Implement v-model to parent
10
+ - Item Checkbox
11
+ - Implement v-model to parent
12
+ - ListAnchor
13
+ - Dynamic component so its swapable with `nuxt-link` or `router-link`
14
+ - Calculator/Number input
15
+ - Modal helper (sized depending on client)
16
+ - SCSS variables throughout
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@stonecrop/beam",
3
+ "version": "0.2.6",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "author": {
7
+ "name": "Tyler Matteson",
8
+ "email": "tyler@agritheory.com"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/agritheory/stonecrop",
13
+ "directory": "beam"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/agritheory/stonecrop/issues"
17
+ },
18
+ "exports": {
19
+ ".": {
20
+ "import": "./dist/beam-ui.es.js",
21
+ "require": "./dist/beam-ui.umd.js"
22
+ }
23
+ },
24
+ "main": "./dist/beam-ui.umd.js",
25
+ "module": "./dist/beam-ui.es.js",
26
+ "files": [
27
+ "dist/*",
28
+ "src/*"
29
+ ],
30
+ "dependencies": {
31
+ "portal-vue": "^3.0.0",
32
+ "vue": "^3.4.23"
33
+ },
34
+ "devDependencies": {
35
+ "@vitejs/plugin-vue": "^5.0.4",
36
+ "cypress": "^12.11.0",
37
+ "vite": "^5.2.9",
38
+ "vue-router": "^4"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "engines": {
44
+ "node": ">=20.11.0"
45
+ },
46
+ "scripts": {
47
+ "dev": "vite serve dev/ -c dev/vite.config.js -d",
48
+ "build": "vite build dev/ -c dev/vite.config.js -d",
49
+ "serve": "vite preview"
50
+ }
51
+ }
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <footer class="beam__actionfooter">
3
+ <span class="footer-action-wrapper">
4
+ <button class="footer-action btn" @click="handleFooterAction">
5
+ <slot />
6
+ </button>
7
+ </span>
8
+ </footer>
9
+ </template>
10
+ <script>
11
+ export default {
12
+ name: 'ActionFooter',
13
+ methods: {
14
+ handleFooterAction() {
15
+ this.$emit('click')
16
+ },
17
+ },
18
+ }
19
+ </script>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <portal to="beam__modal_outlet">
3
+ <div class="beam__modal" v-show="showModal">
4
+ <button class="btn" @click="$emit('closemodal')">Close Modal</button>
5
+ <slot @closemodal="$emit('closemodal')" @confirmmodal="$emit('confirmmodal')"></slot>
6
+ </div>
7
+ </portal>
8
+ </template>
9
+ <script>
10
+ export default {
11
+ name: 'BeamModal',
12
+ props: ['showModal'],
13
+ }
14
+ </script>
15
+ <style scoped></style>
@@ -0,0 +1,8 @@
1
+ <template>
2
+ <portal-target name="beam__modal_outlet" />
3
+ </template>
4
+ <script>
5
+ export default {
6
+ name: 'BeamModalOutlet',
7
+ }
8
+ </script>
@@ -0,0 +1,20 @@
1
+ <template>
2
+ <div class="beam__modal-confirm">
3
+ <h2>Would you like to continue?</h2>
4
+ <button class="btn" @click="confirmModal">Yes</button>
5
+ <button class="btn" @click="closeModal">No</button>
6
+ </div>
7
+ </template>
8
+ <script>
9
+ export default {
10
+ name: 'ConfirmDialog',
11
+ methods: {
12
+ confirmModal() {
13
+ this.$emit('confirmmodal')
14
+ },
15
+ closeModal() {
16
+ this.$emit('closemodal')
17
+ },
18
+ },
19
+ }
20
+ </script>
@@ -0,0 +1,95 @@
1
+ <template>
2
+ <label class="container">
3
+ <input type="checkbox" :checked="value" @input="handleInput" tabindex="-1" />
4
+ <div class="checkmark" tabindex="0"></div>
5
+ </label>
6
+ </template>
7
+ <script>
8
+ export default {
9
+ // make this v-model sensitive from parent
10
+ name: 'ItemCheck',
11
+ props: {
12
+ value: {
13
+ type: Boolean,
14
+ required: false,
15
+ default: false,
16
+ },
17
+ },
18
+ data() {
19
+ return {
20
+ checked: this.value,
21
+ }
22
+ },
23
+ methods: {
24
+ handleInput(e) {
25
+ this.$emit('input', this.checked)
26
+ },
27
+ },
28
+ }
29
+ </script>
30
+
31
+ <style scoped>
32
+ .container {
33
+ display: block;
34
+ position: relative;
35
+ padding-left: 2.5ch;
36
+ margin: 0;
37
+ margin-top: 0.5rem;
38
+ cursor: pointer;
39
+ font-size: 2rem;
40
+ -webkit-user-select: none;
41
+ -moz-user-select: none;
42
+ -ms-user-select: none;
43
+ user-select: none;
44
+ }
45
+
46
+ /* hide default checkbox */
47
+ .container input {
48
+ position: absolute;
49
+ opacity: 0;
50
+ cursor: pointer;
51
+ height: 0;
52
+ width: 0;
53
+ }
54
+
55
+ .checkmark {
56
+ position: absolute;
57
+ top: 0;
58
+ left: 0;
59
+ height: 2rem;
60
+ width: 2rem;
61
+ background-color: #eee;
62
+ outline: 2px solid transparent;
63
+ border: 1px solid var(--highlight);
64
+ }
65
+
66
+ .container:hover input ~ .checkmark {
67
+ background-color: white;
68
+ }
69
+
70
+ .container input:checked ~ .checkmark {
71
+ background-color: var(--brand-secondary);
72
+ }
73
+
74
+ .checkmark:after {
75
+ content: '';
76
+ position: absolute;
77
+ display: none;
78
+ }
79
+
80
+ .container input:checked ~ .checkmark:after {
81
+ display: block;
82
+ }
83
+
84
+ .container .checkmark:after {
85
+ left: 25%;
86
+ top: 50%;
87
+ width: 0.5rem;
88
+ height: 1rem;
89
+ border: solid var(--text-color);
90
+ border-width: 0 3px 3px 0;
91
+ -webkit-transform: rotate(45deg);
92
+ -ms-transform: rotate(45deg);
93
+ transform: rotate(45deg) translate(-50%, -50%);
94
+ }
95
+ </style>
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <div class="beam__itemcount">
3
+ <span
4
+ :contenteditable="editable"
5
+ :class="{ alert: countColor === false }"
6
+ @input="handleInput($event)"
7
+ @click="handleInput($event)"
8
+ >{{ count }}</span
9
+ >
10
+ <span>/{{ denominator }}</span
11
+ ><span v-if="uom">&nbsp; {{ uom }}</span>
12
+ </div>
13
+ </template>
14
+ <script>
15
+ export default {
16
+ name: 'ItemCount',
17
+ props: {
18
+ value: {
19
+ type: Number,
20
+ required: false,
21
+ default: 0,
22
+ },
23
+ denominator: {
24
+ type: Number,
25
+ required: true,
26
+ },
27
+ uom: {
28
+ type: String,
29
+ required: false,
30
+ default: null,
31
+ },
32
+ editable: {
33
+ type: Boolean,
34
+ required: false,
35
+ default: false,
36
+ },
37
+ },
38
+ data() {
39
+ return {
40
+ count: this.value,
41
+ }
42
+ },
43
+ methods: {
44
+ handleInput(event) {
45
+ event.preventDefault()
46
+ event.stopPropagation()
47
+ this.count = Number(event.target.innerHTML.replace(/[^0-9]/g, ''))
48
+ this.$emit('input', this.count)
49
+ },
50
+ },
51
+ computed: {
52
+ countColor() {
53
+ return this.count === this.denominator
54
+ },
55
+ },
56
+ watch: {
57
+ value() {
58
+ this.count = this.value
59
+ },
60
+ },
61
+ }
62
+ </script>
@@ -0,0 +1,17 @@
1
+ <template>
2
+ <a :href="to" class="beam__listanchor">
3
+ <slot />
4
+ </a>
5
+ </template>
6
+ <script>
7
+ export default {
8
+ name: 'ListAnchor',
9
+ props: {
10
+ to: {
11
+ type: String,
12
+ required: false,
13
+ default: '',
14
+ },
15
+ },
16
+ }
17
+ </script>
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <li tabindex="0" class="beam__listitem">
3
+ <div class="beam__listtext">
4
+ <label>{{ item.label }}</label>
5
+ <p>{{ item.description }}</p>
6
+ </div>
7
+
8
+ <ItemCount
9
+ v-if="item.count"
10
+ v-model="item.count.count"
11
+ :denominator="item.count.of"
12
+ :uom="item.count.uom"
13
+ :editable="true" />
14
+ <ItemCheck v-if="item.hasOwnProperty('checked')" v-model="item.checked" />
15
+ </li>
16
+ </template>
17
+ <script>
18
+ import ItemCount from './ItemCount.vue'
19
+ import ItemCheck from './ItemCheck.vue'
20
+
21
+ export default {
22
+ name: 'ListItem',
23
+ components: {
24
+ ItemCount,
25
+ ItemCheck,
26
+ },
27
+ props: {
28
+ item: {
29
+ type: Object,
30
+ required: true,
31
+ },
32
+ },
33
+ }
34
+ </script>
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <ul class="beam__listview">
3
+ <li v-for="(item, index) in items" :key="index">
4
+ <template v-if="item.linkComponent">
5
+ <component :is="item.linkComponent" :to="item.route" tabindex="-1">
6
+ <ListItem :item="item"></ListItem>
7
+ </component>
8
+ </template>
9
+ <template v-else>
10
+ <ListItem :item="item"></ListItem>
11
+ </template>
12
+ </li>
13
+ </ul>
14
+ </template>
15
+ <script>
16
+ import ListAnchor from './ListAnchor.vue'
17
+ import ListItem from './ListItem.vue'
18
+
19
+ export default {
20
+ name: 'ListView',
21
+ components: {
22
+ ListItem,
23
+ ListAnchor,
24
+ },
25
+ props: {
26
+ items: {
27
+ type: Array,
28
+ required: true,
29
+ },
30
+ },
31
+ created() {
32
+ window.addEventListener('scroll', this.handleScroll)
33
+ },
34
+ destroyed() {
35
+ window.removeEventListener('scroll', this.handleScroll)
36
+ },
37
+ methods: {
38
+ handleScroll() {
39
+ const scrollHeightDifference = document.documentElement.scrollHeight - window.innerHeight
40
+ const scrollposition = document.documentElement.scrollTop
41
+ if (scrollHeightDifference - scrollposition <= 2) {
42
+ this.$emit('scrollbottom')
43
+ }
44
+ },
45
+ },
46
+ }
47
+ </script>
package/src/Navbar.vue ADDED
@@ -0,0 +1,25 @@
1
+ <template>
2
+ <nav class="beam__navbar">
3
+ <slot name="icon">
4
+ <span class="home-icon">&#11043;</span>
5
+ </slot>
6
+ <slot name="title">
7
+ <h1 class="nav-title">TITLE</h1>
8
+ </slot>
9
+ <div class="navbar-action-wrapper">
10
+ <button class="navbar-action btn" @click="handlePrimaryAction">
11
+ <slot name="navbaraction">Action</slot>
12
+ </button>
13
+ </div>
14
+ </nav>
15
+ </template>
16
+ <script>
17
+ export default {
18
+ name: 'Navbar',
19
+ methods: {
20
+ handlePrimaryAction() {
21
+ this.$emit('click')
22
+ },
23
+ },
24
+ }
25
+ </script>
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <div id="scan_input"></div>
3
+ </template>
4
+ <script>
5
+ export default {
6
+ name: 'ScanInput',
7
+ data() {
8
+ return {
9
+ barcode: '',
10
+ }
11
+ },
12
+ methods: {
13
+ handleScanInput(event) {
14
+ if (event.target.tagName !== 'INPUT') {
15
+ if (event.key !== 'Enter') {
16
+ this.barcode += `${event.key}`
17
+ } else {
18
+ this.$emit('scaninput', this.barcode)
19
+ this.barcode = ''
20
+ }
21
+ }
22
+ },
23
+ },
24
+ mounted() {
25
+ document.addEventListener('keypress', event => {
26
+ this.handleScanInput(event)
27
+ })
28
+ },
29
+ destroyed() {
30
+ window.removeEventListener('keypress', event => {
31
+ this.handleScanInput(event)
32
+ })
33
+ },
34
+ }
35
+ </script>
package/src/index.js ADDED
@@ -0,0 +1,53 @@
1
+ import Navbar from './Navbar.vue'
2
+ import ListView from './ListView.vue'
3
+ import ListItem from './ListItem.vue'
4
+ import ListAnchor from './ListAnchor.vue'
5
+ import ItemCount from './ItemCount.vue'
6
+ import ItemCheck from './ItemCheck.vue'
7
+ import ScanInput from './ScanInput.vue'
8
+ import ActionFooter from './ActionFooter.vue'
9
+ import BeamModal from './BeamModal.vue'
10
+ import BeamModalOutlet from './BeamModalOutlet.vue'
11
+ import ConfirmDialog from './Confirm.vue'
12
+ import PortalVue from 'portal-vue'
13
+
14
+ const components = [
15
+ Navbar,
16
+ ListView,
17
+ ListItem,
18
+ ListAnchor,
19
+ ItemCount,
20
+ ItemCheck,
21
+ ScanInput,
22
+ ActionFooter,
23
+ BeamModal,
24
+ ConfirmDialog,
25
+ BeamModalOutlet,
26
+ ]
27
+
28
+ const install = function (Vue, opts = {}) {
29
+ Vue.use(PortalVue)
30
+ components.forEach(component => {
31
+ Vue.component(component.name, component)
32
+ })
33
+ }
34
+
35
+ if (typeof window !== 'undefined' && window.Vue) {
36
+ install(window.Vue)
37
+ }
38
+
39
+ export default {
40
+ version: '0.1.0',
41
+ install,
42
+ Navbar,
43
+ ListView,
44
+ ListItem,
45
+ ListAnchor,
46
+ ItemCount,
47
+ ItemCheck,
48
+ ScanInput,
49
+ ActionFooter,
50
+ BeamModal,
51
+ ConfirmDialog,
52
+ BeamModalOutlet,
53
+ }