diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..d3bd82b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,15 @@ +# These are supported funding model platforms + +github: galangel +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +polar: # Replace with a single Polar username +buy_me_a_coffee: galangel +thanks_dev: # Replace with a single thanks.dev username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 596ed98..0441788 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -21,15 +21,7 @@ const preview: Preview = { options: { // Sort stories with Welcome first storySort: { - order: [ - 'Welcome', - 'Tooltip', - 'Flows', - 'Keyboard Shortcuts', - 'Transitions', - 'Examples', - '*', - ], + order: ['Welcome', 'The Tooltip', 'The Tourtip', 'The TipAdvisor', 'Tooltip', '*'], }, }, }, diff --git a/README.md b/README.md index a44d55c..8a59a30 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,23 @@ # React Tip Magic β¨ -A sophisticated, elegant, and performant tooltip library for React with an intelligent floating helper system. +A thoughtfully crafted tooltip library for Reactβsimple to use, delightful to experience.    -## Features +## Why React Tip Magic? -- π― **Zero-config tooltips** - Just add `data-tip="Hello"` to any element -- π **High performance** - Single global instance, minimal re-renders -- π¨ **Smooth transitions** - Tooltips gracefully move between elements -- π€ **Intelligent Helper** - Floating assistant with multiple states and actions -- π± **Accessible** - Full keyboard navigation and screen reader support -- π **Customizable** - Extensive theming and configuration options -- π¦ **Lightweight** - Tree-shakeable, minimal dependencies +Tooltips seem simple, but getting them right takes care. They should appear when needed, stay out of the way when not, and feel natural as users navigate your interface. -## Quick Start +React Tip Magic handles the details so you don't have toβpositioning, transitions, accessibility, keyboard supportβall with a clean, declarative API. -### Installation +## Quick Start ```bash npm install @galangel/react-tip-magic ``` -### Basic Setup - ```tsx import { TipMagicProvider } from '@galangel/react-tip-magic'; import '@galangel/react-tip-magic/styles.css'; @@ -39,185 +31,200 @@ function App() { } ``` -### Simple Tooltip +That's it. Now add `data-tip` to any element: ```tsx - + ``` -### Tooltip with Keyboard Shortcut +--- -```tsx - -``` +## Tooltips + +The core of React Tip Magic. One tooltip instance that gracefully moves between elements, providing a smooth, cohesive experience. -### Advanced Options +### Basic Usage ```tsx -
- Hover me -
+ + ``` -### Transition Behavior +### With Keyboard Shortcuts -Control how tooltips transition when moving between elements: +Display shortcuts alongside your tooltips using the `data-tip-shortcut` attribute: ```tsx -{/* Smooth move transition (default) */} - - - -{/* Jump transition (fade out/in) */} - + + + ``` -### Tooltip Groups - -Use `data-tip-group` to control move transitions between grouped elements. Tooltips will only smoothly move between elements in the **same group**: +### Positioning & Behavior ```tsx -{/* Group A - tooltips move smoothly within this group */} - - - -{/* Group B - tooltips move smoothly within this group */} - - +{ + /* Position control */ +} +; -{/* Moving from Group A to Group B will jump, not move */} +{ + /* Smooth transitions between grouped elements */ +} +; + +{ + /* Interactive tooltips that stay visible on hover */ +} + + More info +; ``` -**Group transition rules:** +--- -- **Same group** β Smooth move transition -- **Different groups** β Jump transition (tooltip appears at new position) -- **Grouped to ungrouped** (or vice versa) β Smooth move transition +## Guided Tours -## Helper System - -The Helper is an optional floating element that provides contextual information and actions. - -### Onboarding Flow Example +Walk users through your interface with step-by-step tours. Helpful for onboarding, feature introductions, or contextual guidance. ```tsx -import { useTipMagic } from '@galangel/react-tip-magic'; +import { useTour } from '@galangel/react-tip-magic'; -function OnboardingFlow() { - const { helper } = useTipMagic(); - - useEffect(() => { - helper.startFlow([ - { - targetId: 'welcome-1', - message: 'Welcome! This is your dashboard.', - actions: [{ label: 'Next', action: 'next' }], - }, - { - targetId: 'welcome-2', - message: 'Click here to create your first project.', - actions: [{ label: 'Got it!', action: 'complete' }], - }, - ]); - }, []); +function App() { + const tour = useTour({ + steps: [ + { target: 'dashboard', title: 'Welcome', message: 'This is your dashboard.' }, + { target: 'create-btn', title: 'Create', message: 'Click here to get started.' }, + ], + }); return (+ Made with care for the React community +
+ + diff --git a/package-lock.json b/package-lock.json index 419c849..32757f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "@galangel/react-tip-magic", - "version": "1.0.2", + "version": "1.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@galangel/react-tip-magic", - "version": "1.0.2", + "version": "1.0.3", "license": "Apache-2.0", "dependencies": { - "@floating-ui/react": "^0.27.16" + "@floating-ui/react": "^0.27.16", + "fuzzysort": "^3.1.0" }, "devDependencies": { "@eslint/js": "^9.28.0", @@ -4476,6 +4477,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuzzysort": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", + "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", + "license": "MIT" + }, "node_modules/generator-function": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", diff --git a/package.json b/package.json index d56567a..655d5de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@galangel/react-tip-magic", - "version": "1.0.3", + "version": "1.1.0", "description": "A sophisticated, elegant, and performant tooltip library for React with an intelligent floating helper system.", "type": "module", "main": "./dist/index.cjs", @@ -60,7 +60,8 @@ "react-dom": ">=18.0.0" }, "dependencies": { - "@floating-ui/react": "^0.27.16" + "@floating-ui/react": "^0.27.16", + "fuzzysort": "^3.1.0" }, "devDependencies": { "@eslint/js": "^9.28.0", diff --git a/src/KeyboardShortcuts.mdx b/src/KeyboardShortcuts.mdx index 3cdef5c..0a57644 100644 --- a/src/KeyboardShortcuts.mdx +++ b/src/KeyboardShortcuts.mdx @@ -8,125 +8,102 @@ Display keyboard shortcuts alongside tooltip content for better discoverability ## Overview -React Tip Magic automatically parses tooltip content to extract and style keyboard shortcuts. When a separator character is found in the tooltip content, everything after it is displayed as a styled keyboard shortcut badge. +React Tip Magic displays keyboard shortcuts as styled badges next to tooltip text. Use the `data-tip-shortcut` attribute to specify the shortcut. **Key features:** -- Automatic parsing β no extra markup needed -- Customizable separator (default: `;`) +- Simple attribute-based API - Styled `` element for the shortcut - CSS custom properties for theming -- Can be disabled globally or enabled per-element +- Can be disabled globally +- Works with TipAdvisor for shortcut discovery --- ## Quick Start -Use a semicolon (`;`) to separate the main text from the keyboard shortcut: +Use `data-tip-shortcut` to add a keyboard shortcut badge: ```tsx - - - + + + ``` -The library automatically: +The library displays: -1. Splits the content at the separator -2. Renders the main text normally -3. Displays the shortcut in a styled `` badge +1. The main text from `data-tip` +2. A styled `` badge with the shortcut --- ## API Reference -### Provider Options +### Data Attributes| Option | -Type | -Default | +Attribute | Description |
|---|---|---|---|---|
- contentSeparator
- |
- string | -
- ';'
+ data-tip
|
- Character(s) used to separate main text from keyboard shortcut | +Tooltip content (main text) |
- enableShortcutStyle
- |
- boolean | -
- true
- |
-
- Whether to render shortcuts with styled <kbd> badges
+ data-tip-shortcut
|
+ Keyboard shortcut to display as a styled badge |
| Attribute | +Option | +Type | +Default | Description |
|---|---|---|---|---|
- data-tip
+ enableShortcutStyle
|
+ boolean |
- Tooltip content. Format: "Main text; Shortcut"
+ true
|
- ||
- data-tip-separator
+ Whether to render shortcuts with styled <kbd> badges
|
- Override the separator for this element only |
| Prop | +Type | +Default | +Description | +
|---|---|---|---|
+ triggerKey
+ |
+ string | +
+ 'F1'
+ |
+ Key to toggle the TipAdvisor menu | +
+ position
+ |
+ TipAdvisorPosition | +
+ 'center'
+ |
+ + Menu position: 'center', 'top', 'bottom', 'top-left', 'top-right', 'bottom-left', + 'bottom-right' + | +
+ showCloseButton
+ |
+ boolean | +
+ true
+ |
+ Show close button in header | +
+ showBackdrop
+ |
+ boolean | +
+ true
+ |
+ Show backdrop overlay behind the menu | +
+ closeOnBackdropClick
+ |
+ boolean | +
+ true
+ |
+ Close menu when clicking the backdrop (only applies if showBackdrop is true) | +
+ searchPlaceholder
+ |
+ string | +
+ 'Search shortcuts...'
+ |
+ Placeholder text for the search input | +
+ selector
+ |
+ string | null | +
+ '[data-tip][data-tip-shortcut]'
+ |
+
+ CSS selector for elements to include. Set to null to disable DOM scanning
+ (useful for preset-only menus)
+ |
+
+ items
+ |
+ TipAdvisorPresetItem[] | +- | ++ Preset items for command palette patterns. These are added alongside DOM-scanned items + | +
+ className
+ |
+ string | +- | +Custom CSS class for the menu container | +
+ itemClassName
+ |
+ string | +- | +Custom CSS class for menu items | +
+ onOpen
+ |
+ function | +- | +Callback when menu opens | +
+ onClose
+ |
+ function | +- | +Callback when menu closes | +
| Property | +Type | +Description | +
|---|---|---|
+ ref
+ |
+ React.RefObject | +Ref to pass to TipAdvisor component | +
+ open
+ |
+ function | +Open the TipAdvisor menu | +
+ close
+ |
+ function | +Close the TipAdvisor menu | +
+ toggle
+ |
+ function | +Toggle the TipAdvisor menu | +
| Property | +Type | +Required | +Description | +
|---|---|---|---|
+ id
+ |
+ string | +Yes | +Unique identifier for the item | +
+ label
+ |
+ string | +Yes | +Text displayed in the menu | +
+ shortcut
+ |
+ string | +No | +Keyboard shortcut to display (optional) | +
+ onSelect
+ |
+ function | +Yes | +Callback executed when item is selected | +
| Key | +Action | +
|---|---|
+ F1
+ |
+
+ Toggle the TipAdvisor menu (configurable via triggerKey)
+ |
+
+ Escape
+ |
+ Close the menu | +
+ Arrow Down
+ |
+ Move to next item | +
+ Arrow Up
+ |
+ Move to previous item | +
+ Enter
+ |
+ Select focused item (triggers click on target element) | +
| Any character | +Start searching (input is autofocused) | +
| Property | +Default | +Description | +
|---|---|---|
+ --tip-advisor-bg
+ |
+
+ rgba(24, 24, 27, 0.95)
+ |
+ Menu background color | +
+ --tip-advisor-backdrop-bg
+ |
+
+ rgba(0, 0, 0, 0.5)
+ |
+ Backdrop overlay color | +
+ --tip-advisor-item-bg
+ |
+
+ transparent
+ |
+ Item background (default state) | +
+ --tip-advisor-item-hover-bg
+ |
+
+ rgba(255, 255, 255, 0.1)
+ |
+ Item background on hover | +
+ --tip-advisor-item-focus-bg
+ |
+
+ rgba(255, 255, 255, 0.15)
+ |
+ Item background on keyboard focus | +
| Property | +Default | +Description | +
|---|---|---|
+ --tip-advisor-text
+ |
+
+ #fafafa
+ |
+ Primary text color | +
+ --tip-advisor-text-secondary
+ |
+
+ #a1a1aa
+ |
+ Secondary/muted text color | +
+ --tip-advisor-shortcut-text
+ |
+
+ #e5e7eb
+ |
+ Shortcut badge text color | +
+ --tip-advisor-shortcut-bg
+ |
+
+ rgba(255, 255, 255, 0.15)
+ |
+ Shortcut badge background | +
| Property | +Default | +Description | +
|---|---|---|
+ --tip-advisor-search-bg
+ |
+
+ rgba(255, 255, 255, 0.1)
+ |
+ Search input background | +
+ --tip-advisor-search-border
+ |
+
+ rgba(255, 255, 255, 0.15)
+ |
+ Search input border color | +
+ --tip-advisor-search-focus-border
+ |
+
+ rgba(255, 255, 255, 0.3)
+ |
+ Search input border when focused | +
+ --tip-advisor-search-text
+ |
+
+ #fafafa
+ |
+ Search input text color | +
+ --tip-advisor-search-placeholder
+ |
+
+ #71717a
+ |
+ Search input placeholder color | +
| Property | +Default | +Description | +
|---|---|---|
+ --tip-advisor-highlight-bg
+ |
+
+ rgba(250, 204, 21, 0.4)
+ |
+ Highlighted match background | +
+ --tip-advisor-highlight-text
+ |
+
+ inherit
+ |
+ Highlighted match text color | +
| Property | +Default | +Description | +
|---|---|---|
+ --tip-advisor-border
+ |
+
+ 1px solid rgba(255, 255, 255, 0.1)
+ |
+ Menu border | +
+ --tip-advisor-border-radius
+ |
+
+ 12px
+ |
+ Menu border radius | +
+ --tip-advisor-item-border-radius
+ |
+
+ 8px
+ |
+ Item border radius | +
+ --tip-advisor-shadow
+ |
+
+ 0 25px 50px -12px rgba(0, 0, 0, 0.5)
+ |
+ Menu shadow | +
| Property | +Default | +Description | +
|---|---|---|
+ --tip-advisor-width
+ |
+
+ 320px
+ |
+ Menu width | +
+ --tip-advisor-max-height
+ |
+
+ 400px
+ |
+ Maximum menu height (scrollable) | +
+ --tip-advisor-padding
+ |
+
+ 8px
+ |
+ Menu padding | +
+ --tip-advisor-item-padding
+ |
+
+ 10px 12px
+ |
+ Item padding | +
+ --tip-advisor-gap
+ |
+
+ 4px
+ |
+ Gap between items | +
+ --tip-advisor-animation-duration
+ |
+
+ 150ms
+ |
+ Animation duration | +
| Class | +Description | +
|---|---|
+ .tip-advisor
+ |
+ Main container (fixed, full screen) | +
+ .tip-advisor--no-backdrop
+ |
+ Applied when showBackdrop is false | +
+ .tip-advisor-backdrop
+ |
+ Backdrop overlay | +
+ .tip-advisor-menu
+ |
+ Menu panel | +
+ .tip-advisor-header
+ |
+ Header section (contains search and close button) | +
+ .tip-advisor-search
+ |
+ Search input field | +
+ .tip-advisor-close
+ |
+ Close button | +
+ .tip-advisor-list
+ |
+ Items list container | +
+ .tip-advisor-item
+ |
+ Individual menu item | +
+ .tip-advisor-item--hover
+ |
+ Hovered item state | +
+ .tip-advisor-item--focus
+ |
+ Keyboard-focused item state | +
+ .tip-advisor-item-content
+ |
+ Item text content | +
+ .tip-advisor-item-shortcut
+ |
+ Shortcut badge | +
+ .tip-advisor-item-content mark
+ |
+ Highlighted search match in content | +
+ .tip-advisor-item-shortcut mark
+ |
+ Highlighted search match in shortcut | +
| Class | +Description | +
|---|---|
+ .tip-advisor-menu--center
+ |
+ Centered (default) | +
+ .tip-advisor-menu--top
+ |
+ Top center | +
+ .tip-advisor-menu--bottom
+ |
+ Bottom center | +
+ .tip-advisor-menu--top-left
+ |
+ Top left corner | +
+ .tip-advisor-menu--top-right
+ |
+ Top right corner | +
+ .tip-advisor-menu--bottom-left
+ |
+ Bottom left corner | +
+ .tip-advisor-menu--bottom-right
+ |
+ Bottom right corner | +
Sophisticated, elegant, and performant tooltips for React
+Thoughtfully crafted tooltips for React
Just add data-tip="Hello" to any element. No wrapper components needed.
Add data-tip="Hello" to any element. One tooltip instance moves gracefully between targets.
Single global instance with event delegation. Minimal re-renders and memory footprint.
+
+ Display shortcuts with data-tip-shortcut="βS". Styled badges that feel native to
+ your UI.
+
Tooltips gracefully animate between elements when hovering from one to another.
++ Walk users through your interface step by step. Great for onboarding or introducing new + features. +
- Optional floating assistant with multiple states for onboarding, actions, and contextual help. -
+A searchable menu of all shortcuts in your app. Press F1 to discover what's available.
+Tooltips animate between elements. Group related items for cohesive movement.
Keyboard navigation, screen reader support, and respects reduced motion preferences.
Single global instance with event delegation. Minimal re-renders and memory footprint.
+Extensive theming via CSS custom properties. Light, dark, and auto themes included.
+CSS custom properties for easy customization. Adapts to light, dark, or custom themes.
- Made with β€οΈ for the React community + Made with care for the React community
diff --git a/src/components/TipAdvisor/TipAdvisor.tsx b/src/components/TipAdvisor/TipAdvisor.tsx new file mode 100644 index 0000000..79f7e17 --- /dev/null +++ b/src/components/TipAdvisor/TipAdvisor.tsx @@ -0,0 +1,197 @@ +import { forwardRef, useCallback, useImperativeHandle, useRef } from 'react'; +import { createPortal } from 'react-dom'; +import { useTipMagicContext } from '../../context/TipMagicContext'; +import type { TipAdvisorAPI, TipAdvisorProps } from '../../types/tipAdvisor'; +import { useTipAdvisorState } from './useTipAdvisorState'; +import { highlightFuzzyMatch } from './utils'; + +const DEFAULT_TRIGGER_KEY = 'F1'; +const DEFAULT_SELECTOR = '[data-tip][data-tip-shortcut]'; +const DEFAULT_POSITION = 'center'; +const DEFAULT_SEARCH_PLACEHOLDER = 'Search shortcuts...'; + +/** + * TipAdvisor - An optional menu component that displays all tooltips with shortcuts. + * + * Features: + * - Fuzzy search with highlighting + * - Keyboard navigation (arrow keys, enter) + * - Hover preview of tooltips + * - Click to trigger target element + * + * @example + * ```tsx + *