@asd20/ui-next 1.0.11 → 2.0.1

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +11 -15
  3. package/package.json +3 -3
  4. package/src/components/atoms/Asd20Checkbox/index.vue +2 -4
  5. package/src/components/atoms/Asd20CountUp/index.vue +2 -3
  6. package/src/components/atoms/Asd20Icon/index.vue +6 -62
  7. package/src/components/atoms/Asd20MultiselectInput/index.vue +6 -1
  8. package/src/components/atoms/Asd20SelectInput/index.vue +3 -1
  9. package/src/components/atoms/Asd20WidgetViewport/index.vue +2 -3
  10. package/src/components/molecules/Asd20Accordion/index.vue +2 -3
  11. package/src/components/molecules/Asd20Card/index.vue +10 -5
  12. package/src/components/molecules/Asd20CheckboxList/index.vue +4 -13
  13. package/src/components/molecules/Asd20FileInput/index.vue +3 -2
  14. package/src/components/molecules/Asd20Modal/index.vue +8 -3
  15. package/src/components/molecules/Asd20SearchField/index.vue +3 -5
  16. package/src/components/molecules/Asd20Share/index.vue +2 -3
  17. package/src/components/molecules/Asd20SliderInput/index.vue +3 -5
  18. package/src/components/molecules/Asd20Swipe/index.vue +2 -3
  19. package/src/components/molecules/Asd20Swiper/index.vue +2 -3
  20. package/src/components/molecules/Asd20TextAreaInput/index.vue +1 -3
  21. package/src/components/molecules/Asd20TextInput/index.vue +3 -1
  22. package/src/components/organisms/Asd20AiSearch/index.vue +2 -3
  23. package/src/components/organisms/Asd20Navbar/index.vue +9 -2
  24. package/src/components/organisms/Asd20SchoolHomepageVideoHeader/index.vue +2 -3
  25. package/src/components/organisms/Asd20SecondaryHeader/index.vue +2 -3
  26. package/src/components/organisms/Asd20SiteNavigation/index.vue +13 -4
  27. package/src/components/organisms/Asd20SiteSearch/index.vue +12 -11
  28. package/src/components/organisms/Asd20SwiperFeed/index.vue +1 -1
  29. package/src/components/organisms/Asd20TabBar/index.vue +2 -3
  30. package/src/components/organisms/Asd20VideoHeader/index.vue +2 -3
  31. package/src/components/templates/Asd20AppTemplate/index.vue +17 -10
  32. package/src/components/templates/Asd20ArticleDigestCompactTemplate/index.vue +4 -4
  33. package/src/components/templates/Asd20ArticleDigestTemplate/index.vue +5 -5
  34. package/src/components/templates/Asd20ArticleListTemplate/index.vue +4 -4
  35. package/src/components/templates/Asd20ClubsTemplate/index.vue +4 -4
  36. package/src/components/templates/Asd20SalaryCalculatorTemplate/index.vue +0 -2
  37. package/src/components/templates/Asd20SearchAppTemplate/index.vue +17 -10
  38. package/src/components/utils/FocusTrap.vue +2 -3
  39. package/src/components/utils/Intersect.vue +2 -3
  40. package/src/components/utils/MqLayout.vue +2 -3
  41. package/src/components/utils/Multiselect.vue +2 -3
  42. package/src/components/utils/Recaptcha.vue +2 -3
  43. package/src/directives/lazy-image.js +4 -2
  44. package/src/helpers/mapPageQueryResultToPageTemplateProps.js +2 -2
  45. package/src/mixins/inputComponentMixin.js +2 -7
  46. package/src/mixins/responsiveBreakpointMixin.js +2 -3
  47. package/src/utils/createLegacyDestroyHooks.js +0 -10
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.1](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.0.0...ui-next-v2.0.1) (2026-03-27)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * harden vue 3 navigation focus refs ([ba0bf4f](https://github.com/academydistrict20/asd20-ui-next/commit/ba0bf4f3b67661b2a837a6257ded847d8a0aabe8))
9
+
10
+ # [2.0.0](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v1.0.11...ui-next-v2.0.0) (2026-03-27)
11
+
12
+
13
+ * feat!: finalize Vue 3-only shared input contract ([8a4652e](https://github.com/academydistrict20/asd20-ui-next/commit/8a4652eaa09378b86a574951fa3996c000b12bb8))
14
+
15
+
16
+ ### BREAKING CHANGES
17
+
18
+ * @asd20/ui-next now publishes a Vue 3-only peer baseline and the shared input primitives no longer support the legacy value/input API. Asd20CheckboxList is now modelValue-only and no longer emits update:checkedValues.
19
+
3
20
  ## [1.0.11](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v1.0.10...ui-next-v1.0.11) (2026-03-26)
4
21
 
5
22
  ## [1.0.10](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v1.0.9...ui-next-v1.0.10) (2026-03-26)
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # @asd20/ui-next
2
2
 
3
- Vue component library migration workspace for ASD20.
3
+ Vue 3 component library for ASD20 shared UI surfaces.
4
+
5
+ The current published baseline is `@asd20/ui-next@2.0.0`. This release is Vue 3-only and ships the model-only shared input contract.
4
6
 
5
7
  ## Public Entry Points
6
8
 
@@ -22,7 +24,7 @@ npm run storybook
22
24
  npm run build
23
25
  ```
24
26
 
25
- ## Package Artifact
27
+ ## Release Validation
26
28
 
27
29
  Build the staged publish artifact with:
28
30
 
@@ -30,28 +32,22 @@ Build the staged publish artifact with:
30
32
  npm run build:package
31
33
  ```
32
34
 
33
- This writes a curated source-based package to `dist/package` so release and pack validation do not publish Storybook files, snapshot tests, or the local app shell.
34
-
35
- The staged package also trims undocumented heavyweight `public/` media. Only explicit runtime public assets still referenced by package source are copied into `dist/package/public`.
36
-
37
- The staged package also trims `src/data` down to the small runtime subset still used by exported source. Story/demo payloads remain in the repo but are not staged for publish.
38
-
39
- Verify the publish path end to end with:
35
+ Validate the publish shape end to end with:
40
36
 
41
37
  ```bash
42
38
  npm run verify:publish
43
39
  ```
44
40
 
45
- That command rebuilds `dist/package`, verifies the root and staged export contract, and runs `npm pack --dry-run` against the staged package with a temporary writable npm cache.
46
-
47
- It also validates the checked public API contract for package subpaths and public entrypoint named exports, so export-surface drift fails before release.
41
+ That flow rebuilds `dist/package`, verifies the root and staged export contract, checks the public API surface, and runs `npm pack --dry-run` against the staged package.
48
42
 
49
- Verify the release path against a throwaway packed consumer app with:
43
+ Validate the packed consumer install path with:
50
44
 
51
45
  ```bash
52
46
  npm run verify:release
53
47
  ```
54
48
 
55
- That command runs the publish verifier, packs the staged package into a tarball, installs that tarball into a temporary Vue 3 smoke app, and confirms the consumer build succeeds against the installed package shape.
49
+ That flow packs the staged package into a tarball, installs it into a temporary Vue 3 smoke app, and confirms the consumer build succeeds against the installed package shape.
50
+
51
+ ## Migration Record
56
52
 
57
- The smoke app also compiles `v-model` usage against the exported input primitives, so Vue 3 two-way-binding regressions are part of the release check.
53
+ The package is now release-ready and published, but the migration record is still kept under `docs/migration/` for downstream audit history, release decisions, and future cleanup planning.
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@asd20/ui-next",
3
- "version": "1.0.11",
3
+ "version": "2.0.1",
4
4
  "private": false,
5
- "description": "ASD20 UI component library migration workspace.",
5
+ "description": "ASD20 UI component library for Vue 3.",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
@@ -45,6 +45,6 @@
45
45
  "uuid": "^3.3.2"
46
46
  },
47
47
  "peerDependencies": {
48
- "vue": "^2.6.14 || ^3.0.0"
48
+ "vue": "^3.0.0"
49
49
  }
50
50
  }
@@ -40,8 +40,7 @@ export default {
40
40
  name: 'Asd20CheckboxIcon',
41
41
  components: { Asd20Badge },
42
42
  props: {
43
- value: { type: Boolean, default: false },
44
- modelValue: { type: Boolean, default: undefined },
43
+ modelValue: { type: Boolean, default: false },
45
44
  label: { type: String, default: '' },
46
45
  description: { type: String, default: '' },
47
46
  count: { type: Number, default: 0 },
@@ -57,7 +56,7 @@ export default {
57
56
  },
58
57
  computed: {
59
58
  resolvedValue() {
60
- return typeof this.modelValue === 'boolean' ? this.modelValue : this.value
59
+ return this.modelValue
61
60
  },
62
61
  checkboxAttrs() {
63
62
  return {
@@ -83,7 +82,6 @@ export default {
83
82
  methods: {
84
83
  toggle() {
85
84
  const nextValue = !this.resolvedValue
86
- this.$emit('input', nextValue)
87
85
  this.$emit('update:modelValue', nextValue)
88
86
  this.toggleIcon = nextValue
89
87
  },
@@ -5,7 +5,6 @@
5
5
  <script>
6
6
  import _isFunction from 'lodash/isFunction'
7
7
  import { CountUp } from 'countup.js'
8
- import createLegacyDestroyHooks from '../../../utils/createLegacyDestroyHooks'
9
8
 
10
9
  export default {
11
10
  __countup__: CountUp,
@@ -35,9 +34,9 @@ export default {
35
34
  mounted() {
36
35
  this.init()
37
36
  },
38
- ...createLegacyDestroyHooks(function() {
37
+ beforeUnmount() {
39
38
  this.uninit()
40
- }),
39
+ },
41
40
  methods: {
42
41
  init() {
43
42
  if (this.instance) {
@@ -18,6 +18,7 @@
18
18
  </template>
19
19
 
20
20
  <script>
21
+ import { defineAsyncComponent, markRaw } from 'vue'
21
22
  import camelCase from 'lodash/camelCase'
22
23
  import iconLoaders from '../icons/registry'
23
24
  import createComponentInstanceId from '../../../utils/createComponentInstanceId'
@@ -40,64 +41,11 @@ function normalizeIconName(name) {
40
41
  .toLowerCase()
41
42
  }
42
43
 
43
- function resolveDefineAsyncComponent() {
44
- let vueRuntime = {}
45
-
46
- try {
47
- vueRuntime = require('vue')
48
- } catch {
49
- return null
50
- }
51
-
52
- if (typeof vueRuntime.defineAsyncComponent === 'function') {
53
- return vueRuntime.defineAsyncComponent
54
- }
55
-
56
- if (
57
- vueRuntime.default &&
58
- typeof vueRuntime.default.defineAsyncComponent === 'function'
59
- ) {
60
- return vueRuntime.default.defineAsyncComponent
61
- }
62
-
63
- return null
64
- }
65
-
66
- function resolveMarkRaw() {
67
- let vueRuntime = {}
68
-
69
- try {
70
- vueRuntime = require('vue')
71
- } catch {
72
- return null
73
- }
74
-
75
- if (typeof vueRuntime.markRaw === 'function') {
76
- return vueRuntime.markRaw
77
- }
78
-
79
- if (
80
- vueRuntime.default &&
81
- typeof vueRuntime.default.markRaw === 'function'
82
- ) {
83
- return vueRuntime.default.markRaw
84
- }
85
-
86
- return null
87
- }
88
-
89
44
  function createAsyncComponent(loader) {
90
- const defineAsyncComponent = resolveDefineAsyncComponent()
91
-
92
- if (typeof defineAsyncComponent === 'function') {
93
- return defineAsyncComponent({
94
- loader,
95
- suspensible: false,
96
- })
97
- }
98
-
99
- // Vue 2 accepts the loader function directly for async components.
100
- return loader
45
+ return defineAsyncComponent({
46
+ loader,
47
+ suspensible: false,
48
+ })
101
49
  }
102
50
 
103
51
  export default {
@@ -174,11 +122,7 @@ export default {
174
122
  return
175
123
  }
176
124
 
177
- const asyncComponent = createAsyncComponent(this.loader)
178
- const markRaw = resolveMarkRaw()
179
-
180
- this.iconTemplate =
181
- typeof markRaw === 'function' ? markRaw(asyncComponent) : asyncComponent
125
+ this.iconTemplate = markRaw(createAsyncComponent(this.loader))
182
126
  },
183
127
  },
184
128
  }
@@ -89,6 +89,12 @@ export default {
89
89
  name: 'Asd20MultiselectInput',
90
90
  components: { Asd20Icon, Multiselect },
91
91
  mixins: [inputComponentMixin],
92
+ props: {
93
+ modelValue: {
94
+ type: [Array, Object, String, Number, Boolean],
95
+ default: () => [],
96
+ },
97
+ },
92
98
  data: () => ({
93
99
  taggedItems: [],
94
100
  }),
@@ -148,7 +154,6 @@ export default {
148
154
  },
149
155
  methods: {
150
156
  emitValue(value) {
151
- this.$emit('input', value)
152
157
  this.$emit('update:modelValue', value)
153
158
  },
154
159
  getItemKey(item) {
@@ -14,7 +14,6 @@
14
14
  <div class="asd20-select-input__select-wrapper">
15
15
  <select
16
16
  v-bind="mergedInputAttrs"
17
- v-on="legacyListeners"
18
17
  @input="input"
19
18
  >
20
19
  <option
@@ -59,6 +58,9 @@ export default {
59
58
  name: 'Asd20SelectInput',
60
59
  components: { Asd20Icon },
61
60
  mixins: [inputComponentMixin],
61
+ props: {
62
+ modelValue: { default: '' },
63
+ },
62
64
  computed: {
63
65
  mergedInputAttrs() {
64
66
  return this.mergeInputAttrs({
@@ -37,7 +37,6 @@
37
37
  </template>
38
38
 
39
39
  <script>
40
- import createLegacyDestroyHooks from '../../../utils/createLegacyDestroyHooks'
41
40
 
42
41
  export default {
43
42
  name: 'Asd20Viewport',
@@ -83,9 +82,9 @@ export default {
83
82
  this.checkForOverflow()
84
83
  window.addEventListener('resize', this.checkForOverflow)
85
84
  },
86
- ...createLegacyDestroyHooks(function() {
85
+ beforeUnmount() {
87
86
  window.removeEventListener('resize', this.checkForOverflow)
88
- }),
87
+ },
89
88
  methods: {
90
89
  checkForOverflow() {
91
90
  const viewport = this.$refs.viewport
@@ -71,7 +71,6 @@ import Asd20Badge from '../../atoms/Asd20Badge'
71
71
  import Asd20Button from '../../atoms/Asd20Button'
72
72
  import Asd20Viewport from '../../atoms/Asd20Viewport'
73
73
  import createComponentInstanceId from '../../../utils/createComponentInstanceId'
74
- import createLegacyDestroyHooks from '../../../utils/createLegacyDestroyHooks'
75
74
 
76
75
  const FOCUSABLE_SELECTOR = [
77
76
  'a[href]',
@@ -125,9 +124,9 @@ export default {
125
124
  updated() {
126
125
  this.syncCollapsedContentInteractivity()
127
126
  },
128
- ...createLegacyDestroyHooks(function() {
127
+ beforeUnmount() {
129
128
  this.restoreCollapsedContentInteractivity()
130
- }),
129
+ },
131
130
  methods: {
132
131
  toggleOpen: function() {
133
132
  this.open = !this.open
@@ -292,6 +292,7 @@ export default {
292
292
  reversed: { type: Boolean, default: false },
293
293
  pinned: { type: Boolean, default: false },
294
294
  zoom: { type: Boolean, default: false },
295
+ separateImage: { type: Boolean, default: false },
295
296
  seperateImage: { type: Boolean, default: false },
296
297
  expandedHeader: { type: Boolean, default: false },
297
298
  expandedDescription: { type: Boolean, default: false },
@@ -316,6 +317,8 @@ export default {
316
317
  return truncate(strippedDescription, { length: 150, separator: /,? +/ })
317
318
  },
318
319
  classes() {
320
+ const hasSeparateImage = this.separateImage || this.seperateImage
321
+
319
322
  return {
320
323
  'asd20-card': true,
321
324
  'asd20-card--without-image': !this.image || this.noCoverImage,
@@ -323,7 +326,8 @@ export default {
323
326
  'asd20-card--selected': this.selected,
324
327
  'asd20-card--reversed': this.reversed,
325
328
  'asd20-card--zoom': this.zoom,
326
- 'asd20-card--seperate-image': this.seperateImage,
329
+ 'asd20-card--separate-image': hasSeparateImage,
330
+ 'asd20-card--seperate-image': hasSeparateImage,
327
331
  'asd20-card--pinned': this.pinned,
328
332
  'asd20-card--emphasized-date': this.emphasizedDate,
329
333
  'asd20-card--expanded-header': this.expandedHeader,
@@ -801,7 +805,8 @@ export default {
801
805
  }
802
806
  }
803
807
 
804
- &--seperate-image:not(.asd20-card--without-image) {
808
+ &--seperate-image:not(.asd20-card--without-image),
809
+ &--separate-image:not(.asd20-card--without-image) {
805
810
  transform: rotate(0deg);
806
811
  justify-content: flex-start;
807
812
  background: var(--website-card__background-color);
@@ -835,14 +840,14 @@ export default {
835
840
  }
836
841
  }
837
842
 
838
- &--with-image:not(.asd20-card--seperate-image),
843
+ &--with-image:not(.asd20-card--seperate-image):not(.asd20-card--separate-image),
839
844
  &--without-image.asd20-card--reversed {
840
845
  .asd20-card__title {
841
846
  color: var(--website-card__reverse-foreground-color);
842
847
  }
843
848
  }
844
849
 
845
- &--with-image:not(.asd20-card--seperate-image) {
850
+ &--with-image:not(.asd20-card--seperate-image):not(.asd20-card--separate-image) {
846
851
  min-height: 30vh;
847
852
  .asd20-card__content {
848
853
  background: linear-gradient(
@@ -854,7 +859,7 @@ export default {
854
859
  }
855
860
 
856
861
  &--reversed,
857
- &--with-image:not(.asd20-card--seperate-image) {
862
+ &--with-image:not(.asd20-card--seperate-image):not(.asd20-card--separate-image) {
858
863
  color: var(--website-card__reverse-foreground-color);
859
864
  }
860
865
  &--reversed {
@@ -10,9 +10,9 @@
10
10
  :label="option.text"
11
11
  :count="option.count"
12
12
  :description="option.description"
13
- :value="resolvedCheckedValues.indexOf(option.value) > -1"
13
+ :model-value="resolvedCheckedValues.indexOf(option.value) > -1"
14
14
  :radio="radio"
15
- @input="onInput($event, option)"
15
+ @update:modelValue="onInput($event, option)"
16
16
  />
17
17
  <slot
18
18
  name="item"
@@ -29,20 +29,14 @@ import Asd20Checkbox from '../../atoms/Asd20Checkbox'
29
29
  export default {
30
30
  name: 'Asd20CheckboxList',
31
31
  components: { Asd20Checkbox },
32
- model: {
33
- prop: 'checkedValues',
34
- },
35
32
  props: {
36
- checkedValues: { type: Array, default: () => [] },
37
- modelValue: { type: Array, default: undefined },
33
+ modelValue: { type: Array, default: () => [] },
38
34
  options: { type: Array, default: () => [] },
39
35
  radio: { type: Boolean, default: false },
40
36
  },
41
37
  computed: {
42
38
  resolvedCheckedValues() {
43
- return Array.isArray(this.modelValue)
44
- ? this.modelValue
45
- : this.checkedValues
39
+ return this.modelValue
46
40
  },
47
41
  },
48
42
  methods: {
@@ -57,9 +51,6 @@ export default {
57
51
  )
58
52
  }
59
53
  this.$emit('change', { option, checked })
60
-
61
- this.$emit('input', modifiedCheckedValues, option, checked)
62
- this.$emit('update:checkedValues', modifiedCheckedValues)
63
54
  this.$emit('update:modelValue', modifiedCheckedValues)
64
55
  },
65
56
  },
@@ -14,7 +14,6 @@
14
14
 
15
15
  <input
16
16
  v-bind="mergedInputAttrs"
17
- v-on="legacyListeners"
18
17
  @input="input"
19
18
  />
20
19
 
@@ -43,6 +42,9 @@ export default {
43
42
  components: { Asd20Icon },
44
43
  mixins: [inputComponentMixin],
45
44
  inheritAttrs: false,
45
+ props: {
46
+ modelValue: { default: null },
47
+ },
46
48
  computed: {
47
49
  mergedInputAttrs() {
48
50
  return this.mergeInputAttrs({
@@ -56,7 +58,6 @@ export default {
56
58
  input(event) {
57
59
  this.isDirty = true
58
60
  this.validate(event.target.value)
59
- this.$emit('input', event.target.files)
60
61
  this.$emit('update:modelValue', event.target.files)
61
62
  },
62
63
  },
@@ -108,11 +108,16 @@ export default {
108
108
  this.$emit('update:open', value)
109
109
  this.$emit('update:modelValue', value)
110
110
  },
111
+ focusRef(refName) {
112
+ const ref = this.$refs[refName]
113
+ const focusTarget = ref?.$el || ref
114
+ if (typeof focusTarget?.focus === 'function') {
115
+ focusTarget.focus()
116
+ }
117
+ },
111
118
  setFocus() {
112
119
  this.$nextTick(() => {
113
- if (this.$refs.closeButton && this.$refs.closeButton.$el) {
114
- this.$refs.closeButton.$el.focus()
115
- }
120
+ this.focusRef('closeButton')
116
121
  })
117
122
  },
118
123
  },
@@ -43,14 +43,13 @@ export default {
43
43
  name: 'Asd20SearchField',
44
44
  components: { Asd20Icon },
45
45
  props: {
46
- value: { type: String, default: '' },
47
- modelValue: { type: String, default: undefined },
46
+ modelValue: { type: String, default: '' },
48
47
  extra: { type: String, default: '' },
49
48
  idTag: { type: String, default: '' },
50
49
  large: { type: Boolean, default: false },
51
50
  placeholder: { type: String, default: 'Search' },
52
51
  },
53
- emits: ['input', 'update:modelValue', 'click', 'focusin', 'keyup'],
52
+ emits: ['update:modelValue', 'click', 'focusin', 'keyup'],
54
53
  computed: {
55
54
  classes() {
56
55
  return {
@@ -58,13 +57,12 @@ export default {
58
57
  }
59
58
  },
60
59
  resolvedValue() {
61
- return this.modelValue !== undefined ? this.modelValue : this.value
60
+ return this.modelValue
62
61
  },
63
62
  },
64
63
  methods: {
65
64
  input(event) {
66
65
  const value = event.target.value
67
- this.$emit('input', value)
68
66
  this.$emit('update:modelValue', value)
69
67
  },
70
68
  },
@@ -60,7 +60,6 @@
60
60
 
61
61
  <script>
62
62
  import Asd20Button from '../../atoms/Asd20Button'
63
- import createLegacyDestroyHooks from '../../../utils/createLegacyDestroyHooks'
64
63
  export default {
65
64
  name: 'Asd20Share',
66
65
 
@@ -79,14 +78,14 @@ export default {
79
78
  document.addEventListener('click', this.onDocumentClick)
80
79
  }
81
80
  },
82
- ...createLegacyDestroyHooks(function() {
81
+ beforeUnmount() {
83
82
  if (typeof document !== 'undefined') {
84
83
  document.removeEventListener('click', this.onDocumentClick)
85
84
  }
86
85
  if (this.toastTimeoutId) {
87
86
  clearTimeout(this.toastTimeoutId)
88
87
  }
89
- }),
88
+ },
90
89
 
91
90
  methods: {
92
91
  share() {
@@ -27,18 +27,17 @@ export default {
27
27
 
28
28
  props: {
29
29
  label: { type: String, default: '' },
30
- value: { type: Number, default: 50 },
31
- modelValue: { type: Number, default: undefined },
30
+ modelValue: { type: Number, default: 50 },
32
31
  progressColor: { type: String, default: '' },
33
32
  min: { type: Number, default: 0 },
34
33
  max: { type: Number, default: 100 },
35
34
  step: { type: Number, default: 1 },
36
35
  },
37
- emits: ['input', 'update:modelValue'],
36
+ emits: ['update:modelValue'],
38
37
 
39
38
  computed: {
40
39
  resolvedValue() {
41
- return typeof this.modelValue === 'number' ? this.modelValue : this.value
40
+ return this.modelValue
42
41
  },
43
42
  percentage() {
44
43
  if (this.max === 0) return '0%'
@@ -48,7 +47,6 @@ export default {
48
47
  methods: {
49
48
  input(event) {
50
49
  const value = Number(event.target.value)
51
- this.$emit('input', value)
52
50
  this.$emit('update:modelValue', value)
53
51
  },
54
52
  },
@@ -65,7 +65,6 @@
65
65
  </template>
66
66
 
67
67
  <script>
68
- import createLegacyDestroyHooks from '../../../utils/createLegacyDestroyHooks'
69
68
 
70
69
  export default {
71
70
  name: 'Asd20Swipe',
@@ -140,9 +139,9 @@ export default {
140
139
  mounted() {
141
140
  this.init()
142
141
  },
143
- ...createLegacyDestroyHooks(function() {
142
+ beforeUnmount() {
144
143
  this.clearAutoplayTimer()
145
- }),
144
+ },
146
145
 
147
146
  methods: {
148
147
  clearAutoplayTimer() {
@@ -48,7 +48,6 @@ import {
48
48
  } from 'swiper/js/swiper.esm'
49
49
  import merge from 'lodash/merge'
50
50
  import 'swiper/css/swiper.css'
51
- import createLegacyDestroyHooks from '../../../utils/createLegacyDestroyHooks'
52
51
 
53
52
  // see http://idangero.us/swiper/api/#custom-build
54
53
  Swiper.use([A11y, Keyboard, Pagination, Navigation, Mousewheel])
@@ -85,9 +84,9 @@ export default {
85
84
  updated() {
86
85
  this.swiper.update()
87
86
  },
88
- ...createLegacyDestroyHooks(function() {
87
+ beforeUnmount() {
89
88
  this.destroySwiper()
90
- }),
89
+ },
91
90
 
92
91
  methods: {
93
92
  destroySwiper() {
@@ -18,7 +18,6 @@
18
18
 
19
19
  <textarea
20
20
  v-bind="mergedInputAttrs"
21
- v-on="legacyListeners"
22
21
  @input="input"
23
22
  />
24
23
 
@@ -48,8 +47,7 @@ export default {
48
47
  mixins: [inputComponentMixin],
49
48
  inheritAttrs: false,
50
49
  props: {
51
- value: { type: String, default: '' },
52
- label: { type: String, default: '' },
50
+ modelValue: { type: String, default: '' },
53
51
  },
54
52
  computed: {
55
53
  mergedInputAttrs() {
@@ -14,7 +14,6 @@
14
14
 
15
15
  <input
16
16
  v-bind="mergedInputAttrs"
17
- v-on="legacyListeners"
18
17
  @input="input"
19
18
  />
20
19
 
@@ -43,6 +42,9 @@ export default {
43
42
  components: { Asd20Icon },
44
43
  mixins: [inputComponentMixin],
45
44
  inheritAttrs: false,
45
+ props: {
46
+ modelValue: { type: String, default: '' },
47
+ },
46
48
  computed: {
47
49
  mergedInputAttrs() {
48
50
  return this.mergeInputAttrs({
@@ -103,7 +103,6 @@ import Asd20SearchField from '../../molecules/Asd20SearchField'
103
103
  import Asd20SiteSearch from '../Asd20SiteSearch'
104
104
  import Asd20Icon from '../../atoms/Asd20Icon'
105
105
  import Asd20Button from '../../atoms/Asd20Button'
106
- import createLegacyDestroyHooks from '../../../utils/createLegacyDestroyHooks'
107
106
 
108
107
  const SEARCH_SESSION_STORAGE_KEY = 'asd20-site-search-state-v1'
109
108
  const SEARCH_STATE_SYNC_EVENT = 'asd20-site-search:state-sync'
@@ -187,9 +186,9 @@ export default {
187
186
  window.addEventListener('focus', this.onWindowFocus, { passive: true })
188
187
  }
189
188
  },
190
- ...createLegacyDestroyHooks(function() {
189
+ beforeUnmount() {
191
190
  this.teardownWindowBindings()
192
- }),
191
+ },
193
192
  methods: {
194
193
  teardownWindowBindings() {
195
194
  if (typeof document !== 'undefined') {