@indielayer/ui 1.0.0-alpha.5 → 1.0.0-alpha.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indielayer/ui",
3
- "version": "1.0.0-alpha.5",
3
+ "version": "1.0.0-alpha.6",
4
4
  "description": "Indielayer UI Components with Tailwind CSS build for Vue 3",
5
5
  "author": {
6
6
  "name": "João Teixeira",
@@ -40,6 +40,18 @@
40
40
  "./tailwind.preset.js": "./lib/tailwind.preset.js"
41
41
  },
42
42
  "sideEffects": false,
43
+ "scripts": {
44
+ "dev": "pnpm build-only && chokidar \"./src/**\" -c \"pnpm build-only\"",
45
+ "dev2": "vite build --watch",
46
+ "build": "pnpm generate && vite build",
47
+ "build-prod": "pnpm build && pnpm gen-types",
48
+ "typecheck": "vue-tsc --noEmit",
49
+ "build-only": "vite build",
50
+ "generate": "pnpm gen-version",
51
+ "gen-types": "vue-tsc --declaration --emitDeclarationOnly",
52
+ "gen-version": "node .scripts/gen-version.js",
53
+ "test": "echo \"Error: no test specified\" && exit 1"
54
+ },
43
55
  "peerDependencies": {
44
56
  "tailwindcss": "^3.0.0",
45
57
  "vue": "^3.0.0"
@@ -83,17 +95,5 @@
83
95
  },
84
96
  "publishConfig": {
85
97
  "access": "public"
86
- },
87
- "scripts": {
88
- "dev": "pnpm build-only && chokidar \"./src/**\" -c \"pnpm build-only\"",
89
- "dev2": "vite build --watch",
90
- "build": "pnpm generate && vite build",
91
- "build-prod": "pnpm build && pnpm gen-types",
92
- "typecheck": "vue-tsc --noEmit",
93
- "build-only": "vite build",
94
- "generate": "pnpm gen-version",
95
- "gen-types": "vue-tsc --declaration --emitDeclarationOnly",
96
- "gen-version": "node .scripts/gen-version.js",
97
- "test": "echo \"Error: no test specified\" && exit 1"
98
98
  }
99
- }
99
+ }
@@ -22,6 +22,8 @@ export default defineComponent({
22
22
  type: String as PropType<'left' | 'right'>,
23
23
  default: 'right',
24
24
  },
25
+ offsetX: [Number, String],
26
+ offsetY: [Number, String],
25
27
  animated: Boolean,
26
28
  outlined: Boolean,
27
29
  icon: String,
@@ -57,8 +59,18 @@ export default defineComponent({
57
59
  return classes
58
60
  })
59
61
 
62
+ const offsetStyle = computed(() => {
63
+ const style: any = {}
64
+
65
+ if (props.offsetX) style[props.align === 'left' ? 'marginLeft' : 'marginRight'] = props.offsetX + 'px'
66
+ if (props.offsetY) style[props.position === 'top' ? 'marginTop' : 'marginBottom'] = props.offsetY + 'px'
67
+
68
+ return style
69
+ })
70
+
60
71
  return {
61
72
  styles,
73
+ offsetStyle,
62
74
  positionClasses,
63
75
  }
64
76
  },
@@ -76,6 +88,7 @@ export default defineComponent({
76
88
  <div
77
89
  v-if="show"
78
90
  class="absolute rounded-full z-10 bg-[color:var(--x-badge-bg)]"
91
+ :style="offsetStyle"
79
92
  :class="[
80
93
  positionClasses,
81
94
  {
@@ -108,8 +108,8 @@ export default defineComponent({
108
108
  bg: gray[800],
109
109
  text: 'white',
110
110
  border: gray[600],
111
- hover: { bg: !props.loading ? gray[800] : '' },
112
- active: { bg: !props.loading ? gray[700] : '' },
111
+ hover: { bg: !props.loading ? gray[700] : '' },
112
+ active: { bg: !props.loading ? gray[600] : '' },
113
113
  },
114
114
  }))
115
115
  }
@@ -38,7 +38,7 @@ export default defineComponent({
38
38
 
39
39
  watch(() => props.modelValue, (value) => {
40
40
  checked.value = !!value
41
- })
41
+ }, { immediate: true })
42
42
 
43
43
  watch(() => checked.value, (value) => {
44
44
  emit('update:modelValue', value)
@@ -24,7 +24,7 @@ export default defineComponent({
24
24
  },
25
25
 
26
26
  setup(props) {
27
- const icons: any = inject(injectIconsKey, {})
27
+ const icons: any = inject(injectIconsKey, () => {}, false)
28
28
  const sizeClasses = computed(() => {
29
29
  if (props.size === 'xs') return 'h-3 w-3'
30
30
  else if (props.size === 'sm') return 'h-4 w-4'
@@ -70,21 +70,21 @@ export default defineComponent({
70
70
  })
71
71
 
72
72
  function getSVG(svgString: string) {
73
- const temp = document.createElement('template')
73
+ svgString = svgString.trim()
74
+ const content = svgString.substring(svgString.indexOf('>') + 1, svgString.lastIndexOf('</svg>'))
75
+ const attrsRaw = svgString.substring(svgString.indexOf('<svg') + 4, svgString.indexOf('>')).trim().match(/[\w-]+="[^"]*"/g)
74
76
 
75
- temp.innerHTML = svgString.trim()
76
-
77
- const [svg] = temp.content.children
78
- const names = svg.getAttributeNames()
79
77
  const attributes: Record<string, string | null> = {}
80
78
 
81
- names.forEach((n) => {
82
- if (!['height', 'width', 'class'].includes(n)) attributes[n] = svg.getAttribute(n)
79
+ attrsRaw?.forEach((a) => {
80
+ const [attribute, value] = a.split('=')
81
+
82
+ if (!['height', 'width', 'class'].includes(attribute)) attributes[attribute] = value.replace(/(^"|"$)/g, '')
83
83
  })
84
84
 
85
85
  return {
86
86
  attributes,
87
- content: svg.innerHTML,
87
+ content,
88
88
  }
89
89
  }
90
90
 
@@ -39,6 +39,7 @@ export default defineComponent({
39
39
  default: 'text',
40
40
  },
41
41
  inputClass: String,
42
+ block: Boolean,
42
43
  },
43
44
 
44
45
  emits: useInputtable.emits(),
@@ -112,7 +113,7 @@ export default defineComponent({
112
113
  <template>
113
114
  <label
114
115
  class="inline-block relative align-bottom text-left"
115
- :class="{ 'mb-3': isInsideForm }"
116
+ :class="{ 'mb-3': isInsideForm, 'w-full': block }"
116
117
  >
117
118
  <p
118
119
  v-if="label"
@@ -157,7 +158,7 @@ export default defineComponent({
157
158
  :placeholder="placeholder"
158
159
  :readonly="readonly"
159
160
  :type="currentType"
160
- :value="modelValue"
161
+ :value="modelValue || ''"
161
162
  v-bind="$attrs"
162
163
  v-on="inputListeners"
163
164
  @change="onChange"
@@ -51,7 +51,7 @@ export default defineComponent({
51
51
  <component
52
52
  :is="to ? 'router-link' : tag"
53
53
  :to="to"
54
- class="transition duration-300 ease-in-out cursor-pointer
54
+ class="transition duration-300 ease-in-out cursor-pointer inline-flex
55
55
  text-[color:var(--x-text)]
56
56
  dark:text-[color:var(--x-dark-text)]
57
57
  "
@@ -27,8 +27,14 @@ export default defineComponent({
27
27
  collapseIcon: String,
28
28
  expanded: Boolean,
29
29
  disabled: Boolean,
30
- rounded: Boolean,
31
- filled: Boolean,
30
+ rounded: {
31
+ type: Boolean,
32
+ default: true,
33
+ },
34
+ filled: {
35
+ type: Boolean,
36
+ default: true,
37
+ },
32
38
  },
33
39
 
34
40
  emits: ['expand'],
@@ -34,8 +34,14 @@ export default defineComponent({
34
34
  icon: String,
35
35
  iconRight: String,
36
36
  loading: Boolean,
37
- rounded: Boolean,
38
- filled: Boolean,
37
+ rounded: {
38
+ type: Boolean,
39
+ default: true,
40
+ },
41
+ filled: {
42
+ type: Boolean,
43
+ default: true,
44
+ },
39
45
  selected: Boolean,
40
46
  disabled: Boolean,
41
47
  },
@@ -72,6 +78,13 @@ export default defineComponent({
72
78
  })
73
79
 
74
80
  function onItemClick(e: Event) {
81
+ if (cItem.value.disabled) {
82
+ e.stopPropagation()
83
+ e.preventDefault()
84
+
85
+ return
86
+ }
87
+
75
88
  cItem.value.onClick && cItem.value.onClick(e)
76
89
  emit('click', e)
77
90
  }
@@ -100,7 +113,12 @@ export default defineComponent({
100
113
  const color = colors.getPalette(cItem.value.color || 'gray')
101
114
  const gray = colors.getPalette('gray')
102
115
 
103
- if (cItem.value.disabled) return css.get('text', gray[300])
116
+ if (cItem.value.disabled) return css.variables({
117
+ text: gray[300],
118
+ dark: {
119
+ text: gray[600],
120
+ },
121
+ })
104
122
 
105
123
  if (filled.value) {
106
124
  if (isActive.value) {
@@ -193,7 +211,7 @@ export default defineComponent({
193
211
  :href="cItem.href"
194
212
  :target="cItem.target"
195
213
  :color="cItem.color"
196
- class="relative flex items-center whitespace-nowrap px-3 mt-1"
214
+ class="relative !flex items-center whitespace-nowrap px-3 mt-1"
197
215
  :style="cssVariables"
198
216
  :class="[
199
217
  $style['menu-item'],
@@ -4,12 +4,14 @@ import { computed, defineComponent, ref, watch, type PropType } from 'vue'
4
4
  import { onClickOutside, useEventListener } from '@vueuse/core'
5
5
 
6
6
  import XScroll from '../../components/scroll/Scroll.vue'
7
+ import XIcon from '../icon/Icon.vue'
7
8
 
8
9
  export default defineComponent({
9
10
  name: 'XModal',
10
11
 
11
12
  components: {
12
13
  XScroll,
14
+ XIcon,
13
15
  },
14
16
 
15
17
  props: {
@@ -144,7 +146,7 @@ export default defineComponent({
144
146
  >
145
147
  <div
146
148
  v-if="showClose"
147
- class="absolute p-1 top-4 right-4 rounded-full bg-opacity-10 hover:bg-opacity-30 cursor-pointer"
149
+ class="flex absolute p-1 top-4 z-10 right-4 rounded-full bg-opacity-10 hover:bg-opacity-30 cursor-pointer"
148
150
  :class="[
149
151
  $slots.image ? 'bg-gray-900 text-white' : 'bg-gray-500 text-gray-800 dark:text-gray-300'
150
152
  ]"
@@ -131,10 +131,11 @@ export default defineComponent({
131
131
  <template>
132
132
  <label
133
133
  ref="elRef"
134
- class="inline-block mb-1 relative cursor-pointer focus:outline-none"
134
+ tabindex="0"
135
+ class="inline-block mb-1 relative cursor-pointer focus:outline-none group"
135
136
  :aria-selected="selected ? 'true' : 'false'"
136
137
  :aria-disabled="(disabled || loading) ? 'true' : undefined"
137
- tabindex="0"
138
+ :style="styles"
138
139
  @keypress.prevent.stop.space="$emit('update:modelValue', value)"
139
140
  >
140
141
  <div
@@ -150,13 +151,12 @@ export default defineComponent({
150
151
  class="invisible absolute"
151
152
  />
152
153
  <div
153
- class="rounded-full flex justify-center items-center flex-shrink-0 border-2
154
+ class="rounded-full flex justify-center items-center flex-shrink-0 border-2 outline-offset-2 outline-slate-300 dark:outline-slate-500 group-focus:outline-1 group-focus:outline
154
155
  border-[color:var(--x-border)]
155
156
  bg-[color:var(--x-bg)]
156
157
  dark:border-[color:var(--x-dark-border)]
157
158
  dark:bg-[color:var(--x-dark-bg)]
158
159
  "
159
- :style="styles"
160
160
  :class="[
161
161
  [glow && !disabled && !loading ? $style['radio--glow'] : ''],
162
162
  {
@@ -25,7 +25,7 @@ export default defineComponent({
25
25
 
26
26
  if (props.horizontal && props.mousewheel)
27
27
  useEventListener(scrollEl, 'wheel', (e: WheelEvent) => {
28
- if (!scrollEl.value) return
28
+ if (!scrollEl.value || scrollEl.value.scrollWidth <= scrollEl.value.clientWidth) return
29
29
 
30
30
  e.preventDefault()
31
31
  scrollEl.value.scrollLeft += e.deltaY + e.deltaX
File without changes
@@ -1,16 +1,22 @@
1
1
  <script lang="ts">
2
- import { defineComponent, inject, reactive, computed, toRefs, ref, onMounted } from 'vue'
2
+ import { defineComponent, inject, reactive, computed, toRefs, ref, onMounted, onBeforeUnmount } from 'vue'
3
3
  import { injectTabKey } from '../../composables/keys'
4
4
  import { useCommon } from '../../composables/common'
5
+ import XIcon from '../icon/Icon.vue'
6
+ import XLink from '../link/Link.vue'
5
7
 
6
8
  export default defineComponent({
7
9
  name: 'XTab',
8
10
 
11
+ components: {
12
+ XIcon,
13
+ XLink,
14
+ },
15
+
9
16
  props: {
10
17
  ...useCommon.props(),
11
18
  value: {
12
19
  type: [String, Number],
13
- required: true,
14
20
  },
15
21
  tag: {
16
22
  type: String,
@@ -20,11 +26,14 @@ export default defineComponent({
20
26
  label: String,
21
27
  icon: String,
22
28
  disabled: Boolean,
29
+ exact: Boolean,
23
30
  },
24
31
 
25
32
  setup(props) {
33
+ const cValue = computed(() => props.to || props.value )
26
34
  const cLabel = computed(() => props.label || props.value)
27
35
  const teleportTo = ref(null)
36
+ const elRef = ref()
28
37
 
29
38
  const tabs = inject(injectTabKey, {
30
39
  tabsContentRef: ref(null),
@@ -36,24 +45,62 @@ export default defineComponent({
36
45
  }),
37
46
  })
38
47
 
48
+ const isSupported = window && 'MutationObserver' in window
49
+ const mutationObserver = isSupported ? new MutationObserver(check) : null
50
+
51
+ const cExact = computed(() => tabs.state.exact || props.exact)
52
+ const cSize = computed(() => props.size || tabs.state.size)
53
+
39
54
  onMounted(() => {
40
55
  teleportTo.value = tabs.tabsContentRef.value
56
+
57
+ if (props.to) check()
58
+
59
+ if (isSupported && props.to) mutationObserver?.observe(elRef.value.$el, {
60
+ attributes: true,
61
+ attributeFilter: ['class'],
62
+ })
63
+ })
64
+
65
+ onBeforeUnmount(() => {
66
+ if (mutationObserver) mutationObserver.disconnect()
41
67
  })
42
68
 
69
+ function check() {
70
+ if (elRef.value && elRef.value.$el && (props.to)) {
71
+ const active = elRef.value?.$el.classList.contains(cExact.value ? 'router-link-exact-active' : 'router-link-active')
72
+
73
+ if (active) tabs.activateTab(cValue.value)
74
+ }
75
+ }
76
+
43
77
  const state = reactive({
44
- selected: computed(() => tabs.state.active === props.value),
78
+ selected: computed(() => tabs.state.active === cValue.value),
45
79
  })
46
80
 
47
81
  function onClickTab() {
48
- tabs.activateTab(props.value)
82
+ if (!props.to) tabs.activateTab(cValue.value)
49
83
  }
50
84
 
85
+ const sizeClasses = computed(() => {
86
+ if (cSize.value === 'xs') return 'text-xs'
87
+ else if (cSize.value === 'sm') return 'text-sm'
88
+ else if (cSize.value === 'lg') return 'text-lg'
89
+ else if (cSize.value === 'xl') return 'text-xl'
90
+
91
+ return ''
92
+ })
93
+
51
94
  return {
52
95
  ...toRefs(state),
53
96
  variant: tabs.state.variant,
54
97
  grow: tabs.state.grow,
98
+ elRef,
55
99
  cLabel,
100
+ cValue,
101
+ cSize,
56
102
  tabs,
103
+ sizeClasses,
57
104
  teleportTo,
58
105
  onClickTab,
59
106
  }
@@ -62,12 +109,14 @@ export default defineComponent({
62
109
  </script>
63
110
 
64
111
  <template>
65
- <li :data-value="value" class="shrink-0 font-medium" :class="{ 'flex-1': grow }">
112
+ <li :data-value="cValue" class="shrink-0 font-medium" :class="{ 'flex-1': grow }">
66
113
  <component
67
- :is="to ? 'router-link' : tag"
114
+ :is="to ? 'x-link' : tag"
115
+ ref="elRef"
68
116
  :to="to"
69
117
  class="py-2 transition-colors duration-150 ease-in-out whitespace-nowrap text-center"
70
118
  :class="[
119
+ sizeClasses,
71
120
  {
72
121
  'px-8': variant === 'block',
73
122
  'text-[color:var(--x-tabs-text)] dark:text-[color:var(--x-dark-tabs-text)]': selected,
@@ -84,11 +133,11 @@ export default defineComponent({
84
133
  name="tab"
85
134
  :label="label"
86
135
  :value="value"
87
- :size="size"
136
+ :size="cSize"
88
137
  :icon="icon"
89
138
  >
90
139
  <div class="flex items-center justify-center">
91
- <x-icon v-if="icon" :icon="icon" :size="size" class="mr-1.5 shrink-0" />
140
+ <XIcon v-if="icon" :icon="icon" :size="cSize" class="mr-1.5 shrink-0" />
92
141
  <span>{{ cLabel }}</span>
93
142
  </div>
94
143
  </slot>
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
- import { defineComponent, reactive, computed, provide, type PropType, ref, watch, onMounted } from 'vue'
2
+ import { defineComponent, reactive, computed, provide, type PropType, ref, watch, onMounted, watchEffect } from 'vue'
3
3
  import { injectTabKey } from '../../composables/keys'
4
+ import { useCommon } from '../../composables/common'
4
5
  import { useCSS } from '../../composables/css'
5
6
  import { useColors } from '../../composables/colors'
6
7
 
@@ -16,14 +17,20 @@ export default defineComponent({
16
17
  },
17
18
 
18
19
  props: {
20
+ ...useCommon.props(),
19
21
  ...useColors.props('primary'),
20
22
  modelValue: [String, Number],
21
23
  variant: {
22
24
  type: String as PropType<'line' | 'block'>,
23
25
  default: 'line',
24
26
  },
27
+ align: {
28
+ type: String as PropType<'left' | 'center' | 'right'>,
29
+ default: 'left',
30
+ },
25
31
  ghost: Boolean,
26
32
  grow: Boolean,
33
+ exact: Boolean,
27
34
  },
28
35
 
29
36
  emits: ['update:modelValue'],
@@ -35,14 +42,23 @@ export default defineComponent({
35
42
  const tabsRef = ref<HTMLElement>()
36
43
  const tabsContentRef = ref<HTMLElement>()
37
44
 
45
+ const active = ref()
46
+
47
+ watchEffect(() => {
48
+ active.value = props.modelValue
49
+ })
50
+
38
51
  const state = reactive({
39
- active: computed(() => props.modelValue),
52
+ active: computed(() => active.value),
40
53
  variant: computed(() => props.variant),
41
54
  ghost: computed(() => props.ghost),
42
55
  grow: computed(() => props.grow),
56
+ exact: computed(() => props.exact),
57
+ size: computed(() => props.size),
43
58
  })
44
59
 
45
60
  function activateTab(tab: string | number) {
61
+ active.value = tab
46
62
  emit('update:modelValue', tab)
47
63
  }
48
64
 
@@ -70,14 +86,14 @@ export default defineComponent({
70
86
  if (scrollRef.value.scrollEl) scrollRef.value.scrollEl.scrollTo({ left: center, behavior: 'smooth' })
71
87
  }, 100)
72
88
 
73
- useResizeObserver(wrapperRef, () => { updateTracker(props.modelValue) })
89
+ useResizeObserver(wrapperRef, () => { updateTracker(active.value) })
74
90
 
75
- watch(() => props.modelValue, (value) => {
91
+ watch(() => active.value, (value) => {
76
92
  updateTracker(value)
77
93
  })
78
94
 
79
95
  onMounted(() => {
80
- updateTracker(props.modelValue)
96
+ updateTracker(active.value)
81
97
  })
82
98
 
83
99
  const css = useCSS('tabs')
@@ -131,7 +147,9 @@ export default defineComponent({
131
147
  :class="{
132
148
  'border-b border-gray-200 dark:border-gray-700': variant === 'line',
133
149
  'space-x-8': variant === 'line' && !grow,
134
- 'z-[1]': variant === 'block'
150
+ 'z-[1]': variant === 'block',
151
+ 'justify-center': align === 'center',
152
+ 'justify-end': align === 'right'
135
153
  }"
136
154
  >
137
155
  <slot></slot>
@@ -14,6 +14,7 @@ export type Header = {
14
14
  align?: Align,
15
15
  value: string,
16
16
  text: string,
17
+ width: string | number
17
18
  }
18
19
 
19
20
  export default defineComponent({
@@ -136,6 +137,7 @@ export default defineComponent({
136
137
  :text-align="header.align"
137
138
  :sort="getSort(header.value, sort)"
138
139
  :sortable="header.sortable"
140
+ :width="header.width"
139
141
  @click="header.sortable ? sortHeader(header) : null"
140
142
  >
141
143
  {{ header.text }}
@@ -23,6 +23,7 @@ export default defineComponent({
23
23
  type: String,
24
24
  default: 'ltr',
25
25
  },
26
+ rows: Number,
26
27
  max: Number,
27
28
  maxlength: Number,
28
29
  min: Number,
@@ -34,6 +35,7 @@ export default defineComponent({
34
35
  },
35
36
  preventEnter: Boolean,
36
37
  inputClass: String,
38
+ block: Boolean,
37
39
  },
38
40
 
39
41
  emits: useInputtable.emits(),
@@ -99,7 +101,7 @@ export default defineComponent({
99
101
  <template>
100
102
  <label
101
103
  class="inline-block relative align-bottom text-left"
102
- :class="{ 'mb-3': isInsideForm }"
104
+ :class="{ 'mb-3': isInsideForm, 'w-full': block }"
103
105
  >
104
106
  <p
105
107
  v-if="label"
@@ -140,6 +142,7 @@ export default defineComponent({
140
142
  :maxlength="maxlength"
141
143
  :min="min"
142
144
  :dir="dir"
145
+ :rows="rows"
143
146
  :minlength="minlength"
144
147
  :name="name"
145
148
  :placeholder="placeholder"
@@ -71,7 +71,7 @@ export default defineComponent({
71
71
 
72
72
  <template>
73
73
  <label
74
- class="inline-block mb-1 pb-2"
74
+ class="inline-block"
75
75
  :class="[!disabled ? 'cursor-pointer' : 'cursor-not-allowed']"
76
76
  >
77
77
  <div class="flex items-center">
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export default '1.0.0-alpha.5'
1
+ export default '1.0.0-alpha.6'
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2022 - Indielayer
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.