Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(*): remove vue-bind-once [KHCP-14269] #2535

Merged
merged 18 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cypress/support/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { mount } from 'cypress/vue'
import { createMemoryHistory, createRouter } from 'vue-router/dist/vue-router.prod.cjs'
import type { RouteRecordRaw } from 'vue-router'
import type { App, ComputedOptions } from 'vue'
import { BindOncePlugin } from 'vue-bind-once'
import Chainable = Cypress.Chainable
import 'cypress-fail-fast'
// Import Kongponent styles
Expand Down Expand Up @@ -38,7 +37,7 @@ Cypress.Commands.add('mount', (component: ComputedOptions, options = {}): Chaina
app.use(options.router)
}
},
}, BindOncePlugin)
})

return mount(component, options)
})
Expand Down
28 changes: 20 additions & 8 deletions docs/guide/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,23 +218,35 @@ It's essential to choose context-aware and descriptive names. This practice ensu

#### Attributes

Sometimes you will need to generate a random string to be used as value for various attributes (e.g. accessibility-related attributes like `id`, `for`, `aria-labelledby`, etc.).
Sometimes you will need to generate a random string to be used as value for various attributes (e.g. accessibility-related attributes like `id`, `for`, `aria-labelledby`, etc.).

To generate a unique id so that it is safe for SSR, you **must** use the `useUniqueId` composable in your component:
To generate a unique id so that it is safe for SSR, you **must** use the [`useId` composable](https://vuejs.org/api/composition-api-helpers#useid) in your component:

```html
<script setup lang="ts">
import useUniqueId from '@/composables/useUniqueId'
import { useId } from 'vue'

const id = useUniqueId()
const id = useId()
</script>
```

Then you must use the [`v-bind-once` directive](https://github.com/danielroe/vue-bind-once) to bind the unique id to element attributes (this prevents hydration issues in SSR apps):
Note that `useId` can only be used at the root of the setup function. If you need a random ID in a template or in any of your component functions (e.g. to give each `key` in a `v-for` loop a unique value), you should use the `getUniqueStringId` helper function:

```html
<label v-bind-once="{ for: id }">Label</label>
<input v-bind-once="{ id: id }" />
```vue
<template>
<div v-for="item in items" :key="item.id">
<!-- some content -->
</div>
</template>

<script setup lang="ts">
import { getUniqueStringId } from '@/utilities'

const items = myArray.map(item => ({
...item,
id: getUniqueStringId(), // add a unique id
}))
</script>
```

## Testing your component
Expand Down
8 changes: 0 additions & 8 deletions docs/guide/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ Import and registration can be done individually in the app entry file (e.g. `ma
```ts
// main.ts (or Vue entry file)

// Kongponents rely on vue-bind-once directive to work properly
// The Kongponents bundle includes the vue-bind-once package so you won't need to install it separately, but it does need to be registered
import { BindOncePlugin } from 'vue-bind-once'
import { createApp } from 'vue'
import { KButton } from '@kong/kongponents'
import '@kong/kongponents/dist/style.css'
Expand All @@ -79,9 +76,6 @@ import '@kong/kongponents/dist/style.css'

const app = createApp(App)

// Register the vue-bind-once directive as a Vue Plugin
app.use(BindOncePlugin)

// Register an individual Kongponent
app.component('KButton', KButton)

Expand Down Expand Up @@ -115,8 +109,6 @@ this path instead: import '~@kong/kongponents/dist/style.css' */
</style>
```

When using Kongponents individually like this you will still need to register [`vue-bind-once` plugin](https://github.com/danielroe/vue-bind-once). Please refer to [global registration](#global-registration) section for example.

## TypeScript interfaces

:::tip NOTE
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,15 @@
"date-fns-tz": "^2.0.1",
"focus-trap": "^7.6.0",
"focus-trap-vue": "^4.0.3",
"nanoid": "^5.0.7",
"nanoid": "^5.0.9",
"sortablejs": "^1.15.3",
"swrv": "^1.0.4",
"v-calendar": "^3.1.2",
"vue-bind-once": "^0.2.1",
"vue-draggable-next": "^2.2.1"
},
"peerDependencies": {
"axios": "^1.7.7",
"vue": ">= 3.3.4 < 4",
"vue": ">= 3.5.0 < 4",
"vue-router": "^4.4.5"
},
"devDependencies": {
Expand Down
33 changes: 7 additions & 26 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions src/components/KCatalog/KCatalog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@

<div
v-else
v-bind-once="{ 'data-tableid': catalogId }"
class="catalog-page"
:class="`card-${cardSize}`"
:data-tableid="catalogId"
>
<slot
:data="data"
Expand Down Expand Up @@ -154,7 +154,7 @@

<script setup lang="ts">
import type { PropType } from 'vue'
import { ref, computed, onMounted, watch, useSlots } from 'vue'
import { ref, computed, onMounted, watch, useSlots, useId } from 'vue'
import type {
CatalogItem,
CatalogPreferences,
Expand All @@ -177,7 +177,6 @@ import KEmptyState from '@/components/KEmptyState/KEmptyState.vue'
import KButton from '@/components/KButton/KButton.vue'
import KPagination from '@/components/KPagination/KPagination.vue'
import KCatalogItem from './KCatalogItem.vue'
import useUniqueId from '@/composables/useUniqueId'

const { useRequest, useDebounce, useSwrvState } = useUtilities()
const DEFAULT_PAGE_SIZE = 15
Expand Down Expand Up @@ -372,7 +371,7 @@ const emit = defineEmits<{

const slots = useSlots()

const catalogId = useUniqueId()
const catalogId = useId()

const getInitialPageSize = (): number => {
const initialPageSize = props.paginationPageSizes?.[0]
Expand Down
10 changes: 5 additions & 5 deletions src/components/KCheckbox/KCheckbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
:class="{ 'has-label': hasLabel }"
>
<input
v-bind-once="{ id: inputId }"
:id="inputId"
v-bind="modifiedAttrs"
:aria-checked="modelValue"
class="checkbox-input"
Expand Down Expand Up @@ -36,9 +36,9 @@
<div class="checkbox-label-wrapper">
<KLabel
v-if="hasLabel"
v-bind-once="{ for: inputId }"
v-bind="labelAttributes"
class="checkbox-label"
:for="inputId"
>
<slot>{{ label }}</slot>

Expand All @@ -63,12 +63,11 @@

<script lang="ts" setup>
import type { PropType } from 'vue'
import { computed, useAttrs, useSlots } from 'vue'
import { computed, useAttrs, useId, useSlots } from 'vue'
import type { LabelAttributes } from '@/types'
import KLabel from '@/components/KLabel/KLabel.vue'
import { CheckSmallIcon, IndeterminateSmallIcon } from '@kong/icons'
import { KUI_ICON_SIZE_40 } from '@kong/design-tokens'
import useUniqueId from '@/composables/useUniqueId'

const props = defineProps({
modelValue: {
Expand Down Expand Up @@ -110,7 +109,8 @@ const emit = defineEmits<{
const slots = useSlots()
const attrs = useAttrs()

const inputId = attrs.id ? String(attrs.id) : useUniqueId()
const defaultId = useId()
const inputId = computed((): string => attrs.id ? String(attrs.id) : defaultId)
const hasLabel = computed((): boolean => !!(props.label || slots.default))
const isDisabled = computed((): boolean => attrs?.disabled !== undefined && String(attrs?.disabled) !== 'false')

Expand Down
9 changes: 4 additions & 5 deletions src/components/KCollapse/KCollapse.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
:toggle="toggleDisplay"
>
<button
v-bind-once="{ 'aria-controls': contentId }"
:aria-controls="contentId"
:aria-expanded="!collapsedState"
:aria-label="triggerLabel ? undefined : 'Toggle content'"
class="collapse-trigger-content"
Expand Down Expand Up @@ -59,7 +59,7 @@
<Transition name="kongponents-fade-transition">
<div
v-show="!collapsedState"
v-bind-once="{ id: contentId }"
:id="contentId"
class="collapse-hidden-content"
data-testid="collapse-hidden-content"
>
Expand All @@ -71,12 +71,11 @@

<script lang="ts" setup>
import type { PropType } from 'vue'
import { computed, ref, useSlots, watch } from 'vue'
import { computed, ref, useId, useSlots, watch } from 'vue'
import type { TriggerAlignment, HeaderTag } from '@/types'
import { TriggerAlignmentArray, HeaderTags } from '@/types'
import { ChevronRightIcon } from '@kong/icons'
import { KUI_ICON_SIZE_40 } from '@kong/design-tokens'
import useUniqueId from '@/composables/useUniqueId'

const props = defineProps({
// Is the KCollapse collapsed? Defaults to true-->
Expand Down Expand Up @@ -113,7 +112,7 @@ const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void;
}>()

const contentId = useUniqueId()
const contentId = useId()

const isCollapsed = ref<boolean>(true)
const modelValueChanged = ref<boolean>(false)
Expand Down
7 changes: 3 additions & 4 deletions src/components/KCopy/KCopy.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
>
<KClipboardProvider v-slot="{ copyToClipboard }">
<button
v-bind-once="{ id: copyButtonElementId }"
:id="copyButtonElementId"
:aria-label="tooltipText"
class="copy-to-clipboard-button"
data-testid="copy-to-clipboard"
Expand All @@ -56,13 +56,12 @@

<script setup lang="ts">
import type { PropType } from 'vue'
import { computed, ref, watch, onMounted, onUnmounted } from 'vue'
import { computed, ref, watch, onMounted, onUnmounted, useId } from 'vue'
import { ResizeObserverHelper } from '@/utilities/resizeObserverHelper'
import { CopyIcon } from '@kong/icons'
import KClipboardProvider from '@/components/KClipboardProvider'
import KTooltip from '@/components/KTooltip/KTooltip.vue'
import { KUI_ICON_SIZE_30 } from '@kong/design-tokens'
import useUniqueId from '@/composables/useUniqueId'

const props = defineProps({
/**
Expand Down Expand Up @@ -140,7 +139,7 @@ const props = defineProps({
},
})

const copyButtonElementId = useUniqueId()
const copyButtonElementId = useId()

const tooltipText = ref<string>('')
const nonSuccessText = computed((): string => {
Expand Down
Loading
Loading