Skip to content
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
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.0] - 2026-01-27

### Added
- `ColumnSizingWithTargetFeature` and `AutoColumnOrderFeature` to Table for column size fixing and column ordering
- `Tooltip` to `TableColumnSwitcher`
- `forceMount` attribute to `Drawer`
- `TooltipRoot`, `TooltipTrigger`, and `TooltipDisplay` to make it decomposable
- `useResizeObserver` and `useScrollObserver` to react to resize and scroll events on HTMLElements
- added these to the `AnchoredFloatingContainer` as options
- `IconButton` to better capture the different accessibility requirements of both button types
- use `IconButton` instead of buttons with `layout="icon"`

### Changed
- `useLocalStorage` to be called `useStorage` and allow for listing to storage changes
- `ThemeDialog` is now split into `ThemeSelect` and `ThemeIcon`
- `useTransitionState` uses the window to get animations if no valid ref is provided, and it warns if a ref is provided and its value is null
- names for Tablefilters
- `tags` is now `multiTags`
- `tagsSingle` is now `singleTag`

### Fixed
- Table column sizing when toggling visibility and changing order

## [0.6.16] - 2026-01-26

### Fixed
Expand Down
9 changes: 8 additions & 1 deletion locales/de-DE.arb
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@
},
"goodToSeeYou": "Schön dich zu sehen",
"welcome": "Willkommen",
"rSortingOrderAfter": "Angewendet {otherSortings, plural, =0{als primäre Sortierung} =1{nach # anderen Sortierung} other{nach # anderen Sortierungen}}",
"rSortingOrderAfter": "Angewendet {otherSortings, plural, =0{als primäre Sortierung} =1{nach einer anderen Sortierung} other{nach # anderen Sortierungen}}",
"@rSortingOrderAfter": {
"placeholders": {
"otherSortings": { "type": "number" }
Expand All @@ -220,6 +220,13 @@
"unpin": "Loslösen",
"pinLeft": "Links anheften",
"pinRight": "Rechts anheften",
"changeVisibility": "Sichtbarkeit ändern",
"changePinning": "Anheften ändern",
"changeSelection": "Auswahl ändern",
"pinToRight": "Rechts anheften",
"pinToLeft": "Links anheften",
"increaseSortingPriority": "Sortierpriorität erhöhen",
"decreaseSortingPriority": "Sortierpriorität verringern",
"changeColumnDisplay": "Spaltenanzeige ändern",
"caseSensitive": "Groß-/Klein beachten",
"sorting": "Sortierung",
Expand Down
7 changes: 7 additions & 0 deletions locales/en-US.arb
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,13 @@
"unpin": "Unpin",
"pinLeft": "Pin to left",
"pinRight": "Pin to right",
"changeVisibility": "Change visibility",
"changePinning": "Change pinning",
"changeSelection": "Change selection",
"pinToRight": "Pin to right",
"pinToLeft": "Pin to left",
"increaseSortingPriority": "Increase sorting priority",
"decreaseSortingPriority": "Decrease sorting priority",
"caseSensitive": "Case Sensitive",
"sorting": "Sorting",
"sSortingState": "{sortDirection, select, asc{Sorting (Currently Ascending)} desc{Sorting (Currently Descending)} other{Sorting (Currently None)}}",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "git+https://github.com/helpwave/hightide.git"
},
"license": "MPL-2.0",
"version": "0.6.16",
"version": "0.7.0",
"files": [
"dist"
],
Expand Down
3 changes: 3 additions & 0 deletions src/components/layout/AnchoredFloatingContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ export type BackgroundOverlayProps = HTMLAttributes<HTMLDivElement>
export interface AnchoredFloatingContainerProps extends HTMLAttributes<HTMLDivElement> {
anchor?: RefObject<HTMLElement>,
options?: UseAnchoredPositionOptions,
active?: boolean,
}

export const AnchoredFloatingContainer = forwardRef<HTMLDivElement, AnchoredFloatingContainerProps>(function FloatingContainer({
children,
anchor,
options = {},
active = true,
...props
}, forwardRef) {
const innerRef = useRef<HTMLDivElement>(null)
Expand All @@ -23,6 +25,7 @@ export const AnchoredFloatingContainer = forwardRef<HTMLDivElement, AnchoredFloa
...options,
container: innerRef,
anchor: anchor,
active,
})

return (
Expand Down
14 changes: 7 additions & 7 deletions src/components/layout/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import React, {
import clsx from 'clsx'
import { ChevronLeft, ChevronRight } from 'lucide-react'
import { createLoopingListWithIndex, range } from '@/src/utils/array'
import { Button } from '../user-interaction/Button'
import { useHightideTranslation } from '@/src/i18n/useHightideTranslation'
import { IconButton } from '../user-interaction/IconButton'

//
// CarouselContext
Expand Down Expand Up @@ -411,24 +411,24 @@ export const Carousel = ({
)}
{arrows && (
<>
<Button
layout="icon"
<IconButton
tooltip={translation('previous')}
color="neutral"
className={clsx('absolute z-10 left-2 top-1/2 -translate-y-1/2 shadow-md', { hidden: !canGoLeft() })}
disabled={!canGoLeft()}
onClick={() => left()}
>
<ChevronLeft size={24}/>
</Button>
<Button
layout="icon"
</IconButton>
<IconButton
tooltip={translation('next')}
color="neutral"
className={clsx('absolute z-10 right-2 top-1/2 -translate-y-1/2 shadow-md', { hidden: !canGoRight() })}
disabled={!canGoRight()}
onClick={() => right()}
>
<ChevronRight size={24}/>
</Button>
</IconButton>
</>
)}
</div>
Expand Down
118 changes: 61 additions & 57 deletions src/components/layout/Drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { useOverlayRegistry } from '@/src/hooks/useOverlayRegistry'
import { useHightideTranslation } from '@/src/i18n/useHightideTranslation'
import type { ReactNode } from 'react'
import { forwardRef, useId, useImperativeHandle, useMemo, useRef, type HTMLAttributes } from 'react'
import { createPortal } from 'react-dom'
import { Visibility } from './Visibility'
import { Button } from '../user-interaction/Button'
import { X } from 'lucide-react'
import { useTransitionState } from '@/src/hooks/useTransitionState'
import { PropsUtil } from '@/src/utils/propsUtil'
import { Portal } from '../utils/Portal'
import { IconButton } from '../user-interaction/IconButton'

export type DrawerAligment = 'left' | 'right' | 'bottom' | 'top'

Expand All @@ -21,6 +21,7 @@ export type DrawerProps = HTMLAttributes<HTMLDivElement> & {
containerClassName?: string,
backgroundClassName?: string,
onClose: () => void,
forceMount?: boolean,
}

export const Drawer = forwardRef<HTMLDivElement, DrawerProps>(function Drawer({
Expand All @@ -32,6 +33,7 @@ export const Drawer = forwardRef<HTMLDivElement, DrawerProps>(function Drawer({
containerClassName,
backgroundClassName,
onClose,
forceMount = false,
...props
}, forwardedRef) {
const translation = useHightideTranslation()
Expand Down Expand Up @@ -59,74 +61,76 @@ export const Drawer = forwardRef<HTMLDivElement, DrawerProps>(function Drawer({
})
const depth = tagPositions && tagItemCounts ? ((tagItemCounts['drawer'] ?? 0) - (tagPositions['drawer'] ?? 0)) : 0

if (!isVisible) return
if (!isVisible && !forceMount) return

return createPortal(
<div
id={ids.container}

data-name="drawer-container"
data-open={PropsUtil.dataAttributes.bool(isOpen)}

className={containerClassName}
style={{ zIndex, '--drawer-depth': depth.toString() } as React.CSSProperties}
>
return (
<Portal>
<div
id={ids.background}
id={ids.container}

onClick={onClose}
data-name="drawer-container"
data-open={PropsUtil.dataAttributes.bool(isOpen)}

data-name="drawer-background"
data-state={transitionState}
data-depth={depth}
data-alignment={alignment}
hidden={!isVisible && forceMount}

aria-hidden={true}
className={containerClassName}
style={{ zIndex, '--drawer-depth': depth.toString() } as React.CSSProperties}
>
<div
id={ids.background}

className={backgroundClassName}
/>
<div
{...props}
id={ids.content}
ref={ref}
onClick={onClose}

onKeyDown={PropsUtil.aria.close(close)}
data-name="drawer-background"
data-state={transitionState}
data-depth={depth}
data-alignment={alignment}

data-name={PropsUtil.dataAttributes.name('drawer-content', props)}
data-state={transitionState}
data-depth={depth}
data-alignment={alignment}
aria-hidden={true}

className={props.className}
>
<div className="typography-title-lg mr-8">
{titleElement}
</div>
<Visibility isVisible={!!description}>
<div className="text-description">
{description}
</div>
</Visibility>
className={backgroundClassName}
/>
<div
className="absolute top-0 right-0"
style={{
paddingTop: 'inherit',
paddingRight: 'inherit'
}}
{...props}
id={ids.content}
ref={ref}

onKeyDown={PropsUtil.aria.close(close)}

data-name={PropsUtil.dataAttributes.name('drawer-content', props)}
data-state={transitionState}
data-depth={depth}
data-alignment={alignment}

className={props.className}
>
<Button
layout="icon"
color="neutral"
size="xs"
aria-label={translation('close')}
onClick={onClose}
<div className="typography-title-lg mr-8">
{titleElement}
</div>
<Visibility isVisible={!!description}>
<div className="text-description">
{description}
</div>
</Visibility>
<div
className="absolute top-0 right-0"
style={{
paddingTop: 'inherit',
paddingRight: 'inherit'
}}
>
<X />
</Button>
<IconButton
tooltip={translation('close')}
coloringStyle="text"
color="neutral"
onClick={onClose}
>
<X size={24}/>
</IconButton>
</div>
{children}
</div>
{children}
</div>
</div>
, document.body
</Portal>
)
})
14 changes: 7 additions & 7 deletions src/components/layout/dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { HTMLAttributes, ReactNode } from 'react'
import { forwardRef, useContext, useId, useImperativeHandle, useMemo, useRef } from 'react'
import { X } from 'lucide-react'
import { useHightideTranslation } from '@/src/i18n/useHightideTranslation'
import { Button } from '@/src/components/user-interaction/Button'
import { useFocusTrap } from '@/src/hooks/focus/useFocusTrap'
import { useLogOnce } from '@/src/hooks/useLogOnce'
import { useOverlayRegistry } from '@/src/hooks/useOverlayRegistry'
Expand All @@ -16,6 +15,7 @@ import clsx from 'clsx'
import { FocusTrap } from '../../utils/FocusTrap'
import { usePresenceRef } from '@/src/hooks/usePresenceRef'
import { DialogContext } from './DialogContext'
import { IconButton } from '../../user-interaction/IconButton'

export type DialogPosition = 'top' | 'center' | 'none'

Expand Down Expand Up @@ -151,15 +151,15 @@ export const Dialog = forwardRef<HTMLDivElement, DialogProps>(function Dialog({
paddingRight: 'inherit'
}}
>
<Button
layout="icon"
color="neutral"
<IconButton
tooltip={translation('closeDialog')}
size="xs"
aria-label={translation('closeDialog')}
color="neutral"
coloringStyle="text"
onClick={onCloseWrapper}
>
<X />
</Button>
<X size={24}/>
</IconButton>
</div>
</Visibility>
{children}
Expand Down
Loading