Skip to content

feat: sync cloud-portal changes (datum-ui 0.7 minor)#78

Open
yahyafakhroji wants to merge 10 commits intomainfrom
feat/sync-from-cloud-portal-0.7
Open

feat: sync cloud-portal changes (datum-ui 0.7 minor)#78
yahyafakhroji wants to merge 10 commits intomainfrom
feat/sync-from-cloud-portal-0.7

Conversation

@yahyafakhroji
Copy link
Copy Markdown
Contributor

@yahyafakhroji yahyafakhroji commented Apr 15, 2026

Summary

Syncs @datum-cloud/datum-ui with behavior and primitives that landed in cloud-portal's vendored app/modules/datum-ui/ fork between 2026-03-01 and 2026-04-14. Version bump is handled by the changeset (minor); CI will compute the alpha build hash.

Added

  • useBreakpoint hook (mobile | tablet | desktop tier, SSR-safe, matchMedia-backed)
  • MobileSheet base primitive (bottom-sheet wrapper around Sheet)
  • ResponsiveDropdown base primitive (DropdownMenu on desktop/tablet, MobileSheet on mobile)
  • RichTextEditor feature component (TipTap 3.x, compound API: .Toolbar, .Bold, .Italic, .Underline, .Strike, .Link, .Content, .CharacterCount)
  • RichTextContent read-only renderer with DOMPurify sanitization
  • Optional Canela font export at @datum-cloud/datum-ui/styles/canela (opt-in; default is system sans)
  • Mobile long-press tooltip support via TouchTooltipBubble (500ms press → show, 1500ms auto-dismiss)

Changed

  • PageTitlefont-title text-3xl, description max-w-2xl, data-e2e="page-title"
  • TagsInput — new optional delimiters, normalizer, validator (Zod) props; auto-confirm pending input on blur
  • Form.Dialog — new optional showHeaderClose prop (default true)
  • Form.Fielditems-start alignment, showErrors prop, responsive help tooltip (w-[calc(100vw-2rem)] sm:w-auto sm:max-w-xs)
  • TimeRangePicker — mobile sheet layout on mobile viewports
  • TooltipTooltipContent gains max-w-[calc(100vw-2rem)]

Dependencies

  • New optional peer deps: @tiptap/{react,starter-kit,extension-link,extension-underline,extension-character-count,extension-placeholder} (>=3). Required only if consuming RichTextEditor.
  • New runtime dep: isomorphic-dompurify (required by RichTextContent sanitization).

Known items inherited from cloud-portal source

These behaviors match the cloud-portal source verbatim and ship with the sync. They are candidates for follow-up fixes but are out of scope for this PR:

  • ResponsiveDropdown mobile path wraps the user-provided trigger in a role="button" <div> with its own onClick — if the inner trigger is also clickable, the click can bubble and toggle onOpenChange twice.
  • Tooltip long-press path and Radix desktop tooltip both render role="tooltip" elements. On touch-capable desktops, both could appear simultaneously and be announced by screen readers as separate tooltips.
  • Form.Field label alignment changed from items-center to items-start. Multi-line labels now top-align with the help icon. Visual change only; no API break.

Test plan

  • pnpm vitest run — 560 tests pass (including new useBreakpoint, MobileSheet, ResponsiveDropdown, RichTextEditor, Tooltip long-press, TagsInput UX, TimeRangePicker mobile cases)
  • pnpm typecheck — clean
  • pnpm build — clean; dist/styles/canela.css, dist/styles/fonts/CanelaText-Regular.ttf, dist/mobile-sheet/index.mjs, dist/responsive-dropdown/index.mjs, dist/rich-text-editor/index.mjs all produced
  • Manual mobile device QA for long-press tooltip (iOS Safari, Android Chrome)
  • Alpha tarball smoke-installed in cloud-portal via the repo's standard alpha workflow

@yahyafakhroji yahyafakhroji force-pushed the feat/sync-from-cloud-portal-0.7 branch from d2c3170 to be23785 Compare April 15, 2026 02:09
Syncs behavior and primitives that landed in cloud-portal's vendored
app/modules/datum-ui/ fork between 2026-03-01 and 2026-04-14.

## Added

- useBreakpoint hook (mobile/tablet/desktop tier, SSR-safe, matchMedia-backed)
- MobileSheet base primitive (bottom-sheet wrapper around Sheet)
- ResponsiveDropdown base primitive (DropdownMenu on desktop/tablet,
  MobileSheet on mobile)
- RichTextEditor feature component (compound API: .Toolbar, .Bold, .Italic,
  .Underline, .Strike, .Link, .Content, .CharacterCount) with TipTap 3.x
  as optional peer deps
- RichTextContent read-only renderer with DOMPurify sanitization
- Optional Canela font export at @datum-cloud/datum-ui/styles/canela
  (opt-in; default stack is system sans)
- Mobile long-press tooltip support via TouchTooltipBubble (500ms press,
  1500ms auto-dismiss)

## Changed

- PageTitle: font-title text-3xl, description max-w-2xl, data-e2e hook
- TagsInput: new optional props delimiters, normalizer, validator (Zod);
  auto-confirm pending input on blur
- Form.Dialog: new optional showHeaderClose prop (default true)
- Form.Field: items-start alignment (visual change), showErrors prop,
  responsive help tooltip
- TimeRangePicker: mobile sheet layout on mobile viewports
- Tooltip: TooltipContent gains max-w-[calc(100vw-2rem)]

## Dependencies

- New optional peer deps: @tiptap/react, @tiptap/starter-kit,
  @tiptap/extension-link, @tiptap/extension-underline,
  @tiptap/extension-character-count, @tiptap/extension-placeholder (>=3)
- New runtime dep: isomorphic-dompurify (sanitizer for RichTextContent)
- Introduced a NavSkeleton component to display a loading state in the AppNavigation component.
- Added a loading prop to conditionally render the skeleton or the actual navigation items.
- Enhanced the sidebar structure with new Sidebar components for better organization and visual separation.
@yahyafakhroji yahyafakhroji force-pushed the feat/sync-from-cloud-portal-0.7 branch from 1ce3c86 to f3d7a0d Compare April 15, 2026 05:04
Stories for the new components and enhanced props landing in this sync:

Added
- base/mobile-sheet.stories.tsx (Default, WithDescription, NoFooter)
- base/responsive-dropdown.stories.tsx (Default menu, WithCustomContent).
  Children use plain buttons/rows — Radix DropdownMenuItem requires a
  DropdownMenu context that only exists on the desktop branch.
- features/rich-text-editor.stories.tsx (Editor, ReadOnly)
- features/form-dialog.stories.tsx (showHeaderClose toggle)

Enhanced
- features/tag-input.stories.tsx — WithCustomDelimiters, WithNormalizer,
  WithZodValidator, AutoConfirmOnBlur variants
- features/page-title.stories.tsx — LongDescription variant showing the
  new max-w-2xl constraint
- base/tooltip.stories.tsx — doc note describing mobile long-press
- stories/storybook.css — opt into canela.css so font-title renders
  Canela (previously fell back to system sans)
@yahyafakhroji yahyafakhroji force-pushed the feat/sync-from-cloud-portal-0.7 branch from f3d7a0d to 8049fdf Compare April 15, 2026 05:08
@yahyafakhroji yahyafakhroji linked an issue Apr 15, 2026 that may be closed by this pull request
…to MobileSheet/ResponsiveDropdown

- InSheetContext (co-located with MobileSheet) + useInSheet hook — lets
  responsive primitives detect when they're already inside a MobileSheet
  and suppress their own sheet branch to avoid sheet-in-sheet stacking.
- MobileSheet provides InSheetContext=true on its scrollable body.
- ResponsivePopover primitive: Popover on desktop/tablet, MobileSheet on
  mobile. Same decision logic as ResponsiveDropdown: responsive && mobile
  && !inSheet. Exposes align, side, sideOffset, alignOffset,
  avoidCollisions, contentClassName, modal, onOpenAutoFocus,
  onCloseAutoFocus, onInteractOutside, onEscapeKeyDown.
- ResponsiveDropdown back-filled with responsive?: boolean prop and
  InSheetContext read for nested-case suppression. Backward compatible —
  defaults preserve existing behavior.
…mers

All existing popover/dropdown consumers now render as a MobileSheet on
<768px viewports by default. Each gains optional responsive?: boolean
(default true) and sheetTitle?: string props. Desktop behavior unchanged.

Popover-based (→ ResponsivePopover):
- Combobox (sheetTitle fallback: placeholder ?? 'Select option')
- Autocomplete (fallback: placeholder ?? 'Search')
- Autosearch (fallback: placeholder ?? 'Search')
- CalendarDatePicker (fallback: placeholder ?? 'Pick a date')
- DateTimePicker (fallback: placeholder ?? 'Pick date & time')
- RichTextEditor link-toolbar (fallback: 'Insert link')
- TimeRangePicker AbsoluteRangePanel (context-suppressed — stays popover
  inside parent sheet)
- DataTable checkbox-filter + select-filter (fallback: title ?? 'Filter')

DropdownMenu-based (→ ResponsiveDropdown):
- MoreActions (fallback: 'Actions'). Actions refactored from Radix
  DropdownMenuItem to plain buttons so they render in both the desktop
  DropdownMenu and the mobile MobileSheet.
- DataTable row-actions (fallback: 'Actions'). Same refactor.

Each affected component now has a mobile-sheet test case verifying the
viewport branch.
Ports the MultiSelect component from cloud-portal. Uses ResponsivePopover
internally — no manual useBreakpoint + MobileSheet branching needed.
Exposes options, value, onValueChange, placeholder, variant, animation,
maxCount, modalPopover, asChild, className plus the standard responsive?
and sheetTitle? props (fallback: placeholder ?? 'Select options').

Fixed a latent bug from the cloud-portal source: defaultValue = [] as a
destructure default created a new array every render, causing an
infinite useEffect loop in React 19. Extracted to a module-level
EMPTY_ARRAY constant.
- New story: base/responsive-popover (Default, ResponsiveFalse)
- New story: features/multi-select (Default, WithPresetSelection)
- Changeset bullets added to sync-cloud-portal-0.7.md and
  storybook-sync-coverage.md documenting the new primitives, MultiSelect
  feature, and the responsive-by-default sweep across existing
  popover/dropdown consumers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sync @datum-cloud/datum-ui with cloud-portal component changes

1 participant