Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/kufu/smarthr-ui into chor…
Browse files Browse the repository at this point in the history
…e-refactoring-SingleComboBox
  • Loading branch information
AtsushiM committed Feb 6, 2025
2 parents 7d25dcf + f2f34f6 commit 27dd66b
Show file tree
Hide file tree
Showing 54 changed files with 2,258 additions and 1,367 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ commands:
# fallback to using the latest cache if no exact match is found
- modules-cache-
- run: |
sudo npm install -g corepack@latest
sudo corepack enable
sudo corepack prepare
pnpm install
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/previewRelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
node-version: 20
- name: install dependencies
run: |
npm install -g corepack@latest
corepack enable
corepack prepare
pnpm ui install
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/publishRelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
git config user.name "github-actions[bot]"
- name: pnpm install
run: |
npm install -g corepack@latest
corepack enable
corepack prepare
pnpm ui install
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"commitmsg": "commitlint -e $GIT_PARAMS",
"prepare": "husky"
},
"packageManager": "pnpm@9.15.4",
"packageManager": "pnpm@10.2.0",
"pnpm": {
"overrides": {
"@babel/helper-compilation-targets": "^7.26.5",
Expand All @@ -37,7 +37,6 @@
"react-dom": "^19.0.0",
"micromatch@<4.0.8": ">=4.0.8",
"cross-spawn@<7.0.5": ">=7.0.5",
"tar@<6.2.1": ">=6.2.1",
"nanoid": "3.3.8"
}
}
Expand Down
8 changes: 8 additions & 0 deletions packages/smarthr-ui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [65.0.1](https://github.com/kufu/smarthr-ui/compare/v65.0.0...v65.0.1) (2025-02-04)


### Bug Fixes

* aria-describedbyがinputに紐づいている場合もFormControlのaria-describedbyを設定する ([#5344](https://github.com/kufu/smarthr-ui/issues/5344)) ([3c636f1](https://github.com/kufu/smarthr-ui/commit/3c636f109f9a93ba3e02663442a065d749473e2f))
* SegmentedControl内の選択済み項目でButton[variant=primary]を利用する ([#5310](https://github.com/kufu/smarthr-ui/issues/5310)) ([d286b90](https://github.com/kufu/smarthr-ui/commit/d286b9061bb232c23560b5700b6c8a1960ea1053))

## [65.0.0](https://github.com/kufu/smarthr-ui/compare/v64.0.1...v65.0.0) (2025-01-28)


Expand Down
4 changes: 2 additions & 2 deletions packages/smarthr-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "smarthr-ui",
"description": "SmartHR ui components built with React.",
"version": "65.0.0",
"version": "65.0.1",
"author": "SmartHR-UI Team",
"dependencies": {
"@smarthr/wareki": "^1.3.0",
Expand Down Expand Up @@ -39,7 +39,7 @@
"@storybook/test": "^8.4.7",
"@storybook/test-runner": "^0.21.0",
"@storybook/theming": "^8.4.7",
"@swc/core": "^1.10.9",
"@swc/core": "^1.10.12",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.1.0",
"@types/lodash.merge": "^4.6.9",
Expand Down
2 changes: 1 addition & 1 deletion packages/smarthr-ui/public/exports/smarthr-ui-props.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { useOuterClick } from '../../../hooks/useOuterClick'
import { genericsForwardRef } from '../../../libs/util'
import { textColor } from '../../../themes'
import { FaCaretDownIcon } from '../../Icon'
import { areComboBoxItemsEqual } from '../comboBoxHelper'
import { useFocusControl } from '../useFocusControl'
import { useListBox } from '../useListBox'
import { useOptions } from '../useOptions'
Expand Down Expand Up @@ -198,9 +199,7 @@ const ActualMultiComboBox = <T,>(
if (onDelete) onDelete(item)
if (onChangeSelected)
onChangeSelected(
selectedItems.filter(
(selected) => selected.label !== item.label || selected.value !== item.value,
),
selectedItems.filter((selected) => !areComboBoxItemsEqual(selected, item)),
)
})
},
Expand All @@ -211,8 +210,8 @@ const ActualMultiComboBox = <T,>(
// HINT: Dropdown系コンポーネント内でComboBoxを使うと、選択肢がportalで表現されている関係上Dropdownが閉じてしまう
// requestAnimationFrameを追加、処理を遅延させることで正常に閉じる/閉じないの判定を行えるようにする
requestAnimationFrame(() => {
const matchedSelectedItem = selectedItems.find(
(item) => item.label === selected.label && item.value === selected.value,
const matchedSelectedItem = selectedItems.find((item) =>
areComboBoxItemsEqual(item, selected),
)
if (matchedSelectedItem !== undefined) {
if (matchedSelectedItem.deletable !== false) {
Expand Down Expand Up @@ -468,7 +467,7 @@ const ActualMultiComboBox = <T,>(
className={selectedListStyle}
>
{selectedItems.map((selectedItem, i) => (
<li key={`${selectedItem.label}-${selectedItem.value}`}>
<li key={`${selectedItem.label}-${innerText(selectedItem.value)}`}>
<MultiSelectedItem
item={selectedItem}
disabled={disabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ describe('useOptions', () => {
expect(options[0].item).toEqual({ label: labelElement3, value: 'value3' })
})

it('isItemSelectedが渡されていなくてoptionのインスタンスが違うとき、selectedにならないこと', () => {
it('isItemSelectedが渡されていなくてvalueが同じかつlabelのインスタンスが違うとき、selectedになること', () => {
const newLabelElement1 = (
<div>
label<span>1</span>
Expand All @@ -250,7 +250,7 @@ describe('useOptions', () => {

expect(options.length).toBe(1)
expect(options[0].item).toEqual({ label: labelElement1, value: 'value1' })
expect(options[0].selected).toBeFalsy()
expect(options[0].selected).toBeTruthy()
expect(options[0].isNew).toBeFalsy()
})
})
Expand Down
8 changes: 8 additions & 0 deletions packages/smarthr-ui/src/components/ComboBox/comboBoxHelper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import innerText from 'react-innertext'

import { ComboBoxItem } from './types'

export function convertMatchableString(original: string) {
return (
original
Expand All @@ -13,3 +17,7 @@ export function convertMatchableString(original: string) {
.toLowerCase()
)
}

export function areComboBoxItemsEqual<T>(a: ComboBoxItem<T>, b: ComboBoxItem<T>) {
return a.value === b.value && innerText(a.label) === innerText(b.label)
}
10 changes: 3 additions & 7 deletions packages/smarthr-ui/src/components/ComboBox/useOptions.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { useCallback, useId, useMemo } from 'react'
import innerText from 'react-innertext'

import { convertMatchableString } from './comboBoxHelper'
import { areComboBoxItemsEqual, convertMatchableString } from './comboBoxHelper'
import { ComboBoxItem, ComboBoxOption } from './types'

const defaultIsItemSelected = <T>(
targetItem: ComboBoxItem<T>,
selectedItems: Array<ComboBoxItem<T>>,
) =>
selectedItems.find(
(selectedItem) =>
selectedItem.label === targetItem.label && selectedItem.value === targetItem.value,
) !== undefined
) => selectedItems.some((item) => areComboBoxItemsEqual(item, targetItem))

export function useOptions<T>({
items,
Expand Down Expand Up @@ -45,7 +41,7 @@ export function useOptions<T>({
if (Array.isArray(selected)) {
return isItemSelected(item, selected)
} else {
return selected !== null && selected.label === item.label
return selected !== null && areComboBoxItemsEqual(selected, item)
}
},
[isItemSelected, selected],
Expand Down
48 changes: 23 additions & 25 deletions packages/smarthr-ui/src/components/ComboBox/usePartialRendering.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'

const OPTION_INCREMENT_AMOUNT = 100
const RETURN_NULL = () => null

export function usePartialRendering<T>({
items,
Expand All @@ -9,37 +10,31 @@ export function usePartialRendering<T>({
items: T[]
minLength?: number
}) {
const [currentItemLength, setCurrentItemLength] = useState(
Math.max(OPTION_INCREMENT_AMOUNT, minLength),
)
// minLength も考慮した実際のアイテム数を算出
const actualLength = useMemo(
() => Math.max(currentItemLength, minLength),
[currentItemLength, minLength],
)
const partialItems = useMemo(() => items.slice(0, actualLength), [actualLength, items])
const limiter = useCallback((length: number) => Math.max(length, minLength), [minLength])

useEffect(() => {
// currentItemLength を実際の値に補正
setCurrentItemLength(actualLength)
}, [actualLength])
const [currentItemLength, setCurrentItemLength] = useState(limiter(OPTION_INCREMENT_AMOUNT))

const isAllItemsShown = useMemo(() => actualLength >= items.length, [actualLength, items.length])
useEffect(() => {
setCurrentItemLength((current) => limiter(current))
}, [limiter])

const handleIntersect = useCallback(() => {
setCurrentItemLength((current) => current + OPTION_INCREMENT_AMOUNT)
}, [])
// minLength も考慮した実際のアイテム数を算出
const partialItems = useMemo(() => items.slice(0, currentItemLength), [currentItemLength, items])

const renderIntersection = useCallback(() => {
if (isAllItemsShown) {
return null
}
return <Intersection onIntersect={handleIntersect} />
}, [handleIntersect, isAllItemsShown])
const renderIntersection = useCallback(
() => (
<Intersection
onIntersect={() => {
setCurrentItemLength((current) => limiter(current + OPTION_INCREMENT_AMOUNT))
}}
/>
),
[limiter],
)

return {
items: partialItems,
renderIntersection,
renderIntersection: currentItemLength >= items.length ? RETURN_NULL : renderIntersection,
}
}

Expand All @@ -48,9 +43,11 @@ const Intersection: FC<{ onIntersect: () => void }> = ({ onIntersect }) => {

useEffect(() => {
const target = ref.current

if (target === null) {
return
}

// スクロール最下部に到達する度に表示するアイテム数を増加させるための IntersectionObserver
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
Expand All @@ -59,8 +56,9 @@ const Intersection: FC<{ onIntersect: () => void }> = ({ onIntersect }) => {
})

observer.observe(target)

return () => observer.disconnect()
}, [onIntersect])

return <div ref={ref}></div>
return <div ref={ref} />
}
Loading

0 comments on commit 27dd66b

Please sign in to comment.