Skip to content
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
4d83e46
[refactor] stories: rewrite `Alert`
0x009922 Mar 14, 2023
634c473
[chore]: update configs
0x009922 Mar 14, 2023
d4d2677
[refactor] stories: rewrite `Badge`
0x009922 Mar 14, 2023
513d406
[refactor] stories: rewrite `Checkbox`
0x009922 Mar 14, 2023
53db760
[refactor] stories: remove `JsonInput` story
0x009922 Mar 14, 2023
551eaba
[refactor] stories: rewrite `Button`
0x009922 Mar 14, 2023
1cc2ae8
[refactor] stories: use `inline-radio` everywhere
0x009922 Mar 14, 2023
31297d7
[refactor] stories: rewrite `TextField`
0x009922 Mar 14, 2023
5c63d10
[refactor] stories: rewrite `Pagination`
0x009922 Mar 20, 2023
c07984a
[chore]: fix root-level SB dev script
0x009922 Mar 20, 2023
21c76a6
[refactor] stories: rewrite `ProgressBar`
0x009922 Mar 20, 2023
e116234
[refactor] stories: adopt `Table`
0x009922 Mar 20, 2023
09ca996
[refactor]: rewrite `Tabs` stories; fix components
0x009922 Mar 20, 2023
28e136f
[refactor]: rewrite `Switch` stories and update the component
0x009922 Mar 20, 2023
8ccb490
[refactor] stories: rewrite `notifications`
0x009922 Mar 20, 2023
84605c0
[refactor] stories: rewrite `Spinner`
0x009922 Mar 20, 2023
3fde037
[refactor] stories: rewrite `Link`
0x009922 Mar 20, 2023
5f2645f
[refactor] stories: rewrite `RadioGroup`
0x009922 Mar 20, 2023
b71d960
[refactor] stories: rewrite `DatePicker`
0x009922 Mar 20, 2023
1975b2c
[refactor] stories: rewrite `NavigationMenu`
0x009922 Mar 20, 2023
29d4898
[chore]: format
0x009922 Mar 20, 2023
6f8342e
[refactor] stories: rewrite `Tooltip`
0x009922 Mar 21, 2023
4417e4c
[refactor] stories: rewrite `Select`, review API
0x009922 Mar 21, 2023
8aefd9e
[test] `SSwitch`: update component tests
0x009922 Mar 21, 2023
d4aa6c3
Merge branch '512-stricter-type-script' into 514-csf-3
0x009922 Mar 21, 2023
8346bda
[chore]: format
0x009922 Mar 21, 2023
3f5e8c6
[refactor] stories: rewrite `Accordion`
0x009922 Mar 21, 2023
fe30447
[refactor] stories: rewrite `Modal`
0x009922 Mar 21, 2023
19a29a2
Merge branch 'fresh-breath' into 514-csf-3
0x009922 Mar 27, 2023
2639964
[refactor]: enable `vue/require-default-prop`
0x009922 Mar 27, 2023
06ec61e
[fix]: configure `vuejs-accessibility/label-has-for`
0x009922 Mar 27, 2023
383eb3a
[chore]: delay fixing, link issue #525
0x009922 Mar 27, 2023
b0f654c
[fix]: ignore a11y rule, add comment; link issues for the future
0x009922 Mar 27, 2023
bfbee09
[refactor]: ~~`useConditionalScope`~~ `useParamScope`
0x009922 Mar 27, 2023
c658d6c
Merge pull request #529 from soramitsu/513-enable-eslint-rules
0x009922 Mar 28, 2023
c47b27b
Merge pull request #530 from soramitsu/use-vue-kakuyaku
0x009922 Mar 28, 2023
adb8d38
[chore]: update build deps
0x009922 Mar 28, 2023
1209e99
[refactor]: rm `@vue/compiler-core`, use `vue/compiler-sfc`
0x009922 Mar 28, 2023
8c5726b
[fix]: `pnpm i --fix-lockfile`
0x009922 Mar 28, 2023
5e9fdfd
[build]: use specifically `[email protected]`
0x009922 Mar 28, 2023
c0e1928
Merge remote-tracking branch 'origin/fresh-breath' into 514-csf-3
0x009922 May 2, 2023
423e5c0
Merge branch 'fresh-breath' into 514-csf-3
0x009922 May 2, 2023
9a66c6e
Merge branch 'fresh-breath' into 514-csf-3
0x009922 May 2, 2023
e3194d7
[chore]: update core dev deps, use released Storybook
0x009922 May 2, 2023
81276e8
Merge remote-tracking branch 'origin/514-csf-3' into 514-csf-3
0x009922 May 2, 2023
d51d63c
[refactor]: use TS for storybook configs
0x009922 May 2, 2023
ea95d06
[revert]: use `[email protected]`
0x009922 May 2, 2023
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
5 changes: 5 additions & 0 deletions .changeset/curvy-moose-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@soramitsu-ui/ui': patch
---

**fix**(`STabsPanel`): fix `background` reactivity in the provided `TabsPanelApi`
5 changes: 5 additions & 0 deletions .changeset/good-eels-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@soramitsu-ui/ui': patch
---

**fix**(`STab`): don't destructure reactive `TabsPanelApi`
5 changes: 5 additions & 0 deletions .changeset/quiet-ghosts-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@soramitsu-ui/ui': minor
---

**refactor!**(`SSwitch`): remove `id` prop (it is generated automatically inside now); make `label` prop required - a11y first; add `label-hidden` optional bool prop in order to _visually_ hide the `label` (`false` by default); update doc comments
5 changes: 5 additions & 0 deletions .changeset/warm-zebras-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@soramitsu-ui/ui': minor
---

**refactor!**(`STabsPanel`): use passive `model-value`; allow it to be `null`
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"license": "Apache-2.0",
"scripts": {
"sb:serve": "pnpm --filter ui sb:serve",
"sb:dev": "pnpm --filter ui sb:dev",
"sb:build": "pnpm --filter ui sb:build",
"test:all": "run-s lint:check test:theme:unit build:vite-plugin-svg test:ui:unit test:ui:cy build:ui:only-vite test:ui:after-build",
"test:theme:unit": "pnpm --filter theme test",
Expand Down
9 changes: 7 additions & 2 deletions packages/ui/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/** @type { import('@storybook/vue3-vite').StorybookConfig } */
const config = {
// TODO use other stories as well
stories: ['../stories/**/Alert.stories.@(js|jsx|ts|tsx)'],
stories: [
{
directory: '../stories/components',
titlePrefix: 'Components',
files: '**/*.stories.@(js|jsx|ts|tsx)',
},
],
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'],
framework: {
name: '@storybook/vue3-vite',
Expand Down
65 changes: 37 additions & 28 deletions packages/ui/cypress/component/SSwitch.spec.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,58 @@ after(() => {
VueTestUtils.config.global.components = {}
})

it('SSwitch - renders with specified label', () => {
cy.mount(SSwitch, { props: { id: 'id', label: 'Label' } })
describe('SSwitch', () => {
it('renders with specified label', () => {
cy.mount(SSwitch, { props: { label: 'Label' } })

cy.contains('Label')
})
cy.contains('Label')
})

it('SSwitch - renders unchecked switch by default', () => {
cy.mount(SSwitch, { props: { id: 'id' } })
it('renders unchecked switch by default', () => {
cy.mount(SSwitch, { props: { label: 'Test' } })

cy.get('input').should('be.not.checked')
})
cy.get('input').should('be.not.checked')
})

it('SSwitch - renders disabled switch when prop is passed', () => {
cy.mount(SSwitch, { props: { id: 'id', disabled: true } })
it('renders disabled switch when prop is passed', () => {
cy.mount(SSwitch, { props: { label: 'Test', disabled: true } })

cy.get('input').should('be.disabled')
})
cy.get('input').should('be.disabled')
})

it('SSwitch - handles two-way data binding and rises value up', () => {
cy.mount({
setup() {
const checked = ref(false)
it('handles two-way data binding and rises value up', () => {
cy.mount({
setup() {
const checked = ref(false)

return { checked }
},
template: `
return { checked }
},
template: `
<div class="switch">{{ checked }}</div>
<SSwitch
id="id"
v-model="checked"
label="Label"
/>
`,
})

cy.contains('Label').click()
cy.get('.switch').contains('true')
})

cy.contains('Label').click()
cy.get('.switch').contains('true')
})
describe('a11y', () => {
beforeEach(() => {
cy.injectAxeAndConfigureCTDefaults()
})

it('SSwitch - has the same id for linking label with input element', () => {
const id = 'identificator'
cy.mount(SSwitch, { props: { id } })
it('SSwitch - a11y check with visible label', () => {
cy.mount(SSwitch, { props: { label: 'Test' } })
cy.checkA11y()
})

cy.get('input').should('have.id', id)
cy.get('label').should('have.attr', 'for', id)
it('SSwitch - a11y check with hidden label', () => {
cy.mount(SSwitch, { props: { label: 'Test', labelHidden: true } })
cy.checkA11y()
})
})
})
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"@types/lodash-es": "^4.17.6",
"@vitejs/plugin-vue": "^4.0.0",
"@vitejs/plugin-vue-jsx": "^3.0.0",
"@vue-kakuyaku/core": "^0.4.3",
"@vue/compiler-core": "^3.2",
"@vue/test-utils": "^2",
"axe-core": "^4.4.1",
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/components/Accordion/SAccordionItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const props = withDefaults(

const emit = defineEmits<(event: 'update:modelValue', value: boolean) => void>()

// FIXME replace with useVModel-passive?
const model = ref(props.modelValue)
watch(
() => props.modelValue,
Expand Down
7 changes: 6 additions & 1 deletion packages/ui/src/components/Notifications/SUseNotification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ export default /* @__PURE__ */ defineComponent({
showCloseBtn: Boolean,
description: String,
},
emits: ['update:show', 'click:close', 'timeout'],
emits: [
// FIXME avoid `v-model` for `show`, because it always emits `false` from the component
'update:show',
'click:close',
'timeout',
],
setup(props, { emit, slots }) {
const show = useVModel(props, 'show', emit)

Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/Select/SDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const props = defineProps<{
multiple?: boolean
label?: string
size?: SelectSize
inline?: boolean
noAutoClose?: boolean
loading?: boolean
inline?: boolean
dropdownSearch?: boolean
remoteSearch?: boolean
}>()
Expand Down
5 changes: 5 additions & 0 deletions packages/ui/src/components/Select/SSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ const props = defineProps<{
size?: SelectSize
noAutoClose?: boolean
loading?: boolean
// FIXME `triggerSearch` makes sense only in scope of `SSelectBase`
// I think here it is better to name it `search-in-input`
triggerSearch?: boolean
// FIXME `search-in-dropdown`?
dropdownSearch?: boolean
// FIXME `search-external`
remoteSearch?: boolean
}>()

Expand All @@ -27,6 +31,7 @@ const defaultOptionType = computed(() => (props.multiple ? SelectOptionType.Chec
v-bind="{ ...$attrs, ...$props } as any"
same-width-popper
>
<!-- FIXME no sense to get `search` from the slot bindings -->
<template #control="{ search }">
<SSelectInput
data-testid="select-trigger"
Expand Down
6 changes: 6 additions & 0 deletions packages/ui/src/components/Select/SSelectBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,22 @@ const props = withDefaults(
/**
* When enabled, passes `search: true` to the `trigger` slot
*/
// TODO rename to `searchSlotTrigger`?
// FIXME also, it passes `search:true` to CONTROL slot, not TRIGGER
// does it makes sense to pass it at all? cause it is controlled
// by the parent component anyway and isn't anyhow used in this component
triggerSearch?: boolean

/**
* When enabled, passes `search: true` to the `dropdown` slot
*/
// TODO rename to `searchSlotDropdown`?
dropdownSearch?: boolean

/**
* By default, the component filters options by their labels. Set `true` to disable automatic filtering.
*/
// TODO rename to `searchExternal`?
remoteSearch?: boolean
}>(),
{
Expand Down
28 changes: 17 additions & 11 deletions packages/ui/src/components/Switch/SSwitch.vue
Original file line number Diff line number Diff line change
@@ -1,49 +1,55 @@
<script setup lang="ts">
import { uniqueElementId } from '@/util'

type Props = {
/**
* v-model for two-way data binding
* Switch state
*/
modelValue?: boolean
/**
* Id for matching switch with label
* Text label for switch. Required for a11y. If you don't want it to be rendered, use {@link labelHidden}
*
* @default ''
*/
id: string
label: string
/**
* Text label for switch
* Whether to render label or not
*
* @default ''
* @default false
*/
label?: string
labelHidden?: boolean
/**
* Attr specfifies whether switch is disabled
* Whether the input is disabled or not
*
* @default false
*/
disabled?: boolean
}

const props = withDefaults(defineProps<Props>(), {
label: '',
disabled: false,
labelHidden: false,
})

const inputId = uniqueElementId()

const emit = defineEmits<(event: 'update:modelValue', value: boolean) => void>()
const model = useVModel(props, 'modelValue', emit)
</script>

<template>
<div class="s-switch">
<input
:id="id"
:id="inputId"
v-model="model"
type="checkbox"
:disabled="disabled"
class="s-switch__button"
>
<!-- note: `sr-only` class visually hides the element while keeping it accessible for Screen Reader -->
<label
:for="id"
class="s-switch__label sora-tpg-p3"
:for="inputId"
:class="['s-switch__label sora-tpg-p3', { 'sr-only': labelHidden }]"
>{{ label }}</label>
</div>
</template>
Expand Down
27 changes: 11 additions & 16 deletions packages/ui/src/components/Tabs/STab.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { useTabsPanelApi, type TabsPanelApi } from './api'
import { useTabsPanelApi } from './api'

const props = withDefaults(
defineProps<{
Expand All @@ -11,22 +11,17 @@ const props = withDefaults(
},
)

const state: TabsPanelApi = useTabsPanelApi()
const { active } = toRefs(state)
const { selectTab, background } = state
const tabIsActive = computed(() => props.name === active.value)
const api = useTabsPanelApi()
const { active } = toRefs(api)
const tabIsActive = eagerComputed(() => props.name === active.value)

const activateTab = () => {
selectTab(props.name)
const selectSelf = () => {
api.selectTab(props.name)
}

watch(
() => props.disabled,
(newVal) => {
if (newVal && tabIsActive.value) {
selectTab('')
}
},
whenever(
() => props.disabled && tabIsActive.value,
() => api.selectTab(null),
)
</script>

Expand All @@ -35,8 +30,8 @@ watch(
role="tab"
class="s-tab flex justify-center items-center sora-tpg-p2"
:disabled="disabled"
:class="[{ 's-tab_active': tabIsActive }, `s-tab_background_${background}`]"
@click="activateTab"
:class="[{ 's-tab_active': tabIsActive }, `s-tab_background_${api.background}`]"
@click="selectSelf"
>
<div class="s-tab__label-container flex justify-center items-center">
<div class="s-tab__label">
Expand Down
18 changes: 10 additions & 8 deletions packages/ui/src/components/Tabs/STabsPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { type TabsPanelApi, TABS_PANEL_API_KEY, type TabsPanelBackgroundType } f

const props = withDefaults(
defineProps<{
modelValue: string
modelValue: string | null
background?: TabsPanelBackgroundType
}>(),
{
Expand All @@ -14,19 +14,21 @@ const props = withDefaults(

const emit = defineEmits(['update:modelValue'])

const selectTab = (tab: string): void => {
emit('update:modelValue', tab)
const model = useVModel(props, 'modelValue', emit, { passive: true })

const selectTab = (tab: string | null): void => {
model.value = tab
}
const active = computed(() => props.modelValue)

const tabState: TabsPanelApi = reactive({
active: active,
const api: TabsPanelApi = reactive({
active: model,
selectTab,
background: props.background,
background: toRef(props, 'background'),
})

provide(TABS_PANEL_API_KEY, tabState)
provide(TABS_PANEL_API_KEY, api)
</script>

<template>
<div
role="tablist"
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/src/components/Tabs/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { forceInject } from '@/util'
import type { InjectionKey } from 'vue'

export interface TabsPanelApi {
active: string
selectTab: (tab: string) => void
background: TabsPanelBackgroundType
readonly active: string | null
readonly selectTab: (tab: string | null) => void
readonly background: TabsPanelBackgroundType
}

export const TABS_PANEL_BACKGROUND_TYPES = ['primary', 'secondary', 'none'] as const
Expand Down
Loading