streamlit-json-tip


Namestreamlit-json-tip JSON
Version 0.2.8 PyPI version JSON
download
home_pagehttps://github.com/yourusername/streamlit-json-tip
SummaryA Streamlit custom component for viewing JSON with interactive tooltips and tags
upload_time2025-08-21 02:39:19
maintainerNone
docs_urlNone
authorYour Name
requires_python>=3.6
licenseMIT
keywords streamlit json viewer tooltip component interactive
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Streamlit JSON Tip

[![PyPI version](https://badge.fury.io/py/streamlit-json-tip.svg)](https://pypi.org/project/streamlit-json-tip/)
[![Python Support](https://img.shields.io/pypi/pyversions/streamlit-json-tip.svg)](https://pypi.org/project/streamlit-json-tip/)
[![License](https://img.shields.io/pypi/l/streamlit-json-tip.svg)](https://github.com/kazuar/streamlit-json-tip/blob/main/LICENSE)
[![Tests](https://github.com/kazuar/streamlit-json-tip/workflows/Test/badge.svg)](https://github.com/kazuar/streamlit-json-tip/actions/workflows/test.yml)
[![Downloads](https://pepy.tech/badge/streamlit-json-tip)](https://pepy.tech/project/streamlit-json-tip)

A Streamlit custom component for viewing JSON data with interactive tooltips and tags for individual fields.

![Streamlit JSON Tip Example](https://github.com/kazuar/streamlit-json-tip/blob/main/resources/example.png?raw=true)

## Features

- 🔍 **Interactive JSON Viewer**: Expand/collapse objects and arrays
- 📝 **Interactive Tooltips**: Add contextual help for any field with professional Tippy.js tooltips
- đŸˇī¸ **Field Tags**: Categorize fields with colored tags (PII, CONFIG, etc.)
- đŸŽ¯ **Field Selection**: Click on fields to get detailed information
- 🎨 **Syntax Highlighting**: Color-coded JSON with proper formatting
- 📱 **Responsive Design**: Works well in different screen sizes

## Installation

### With uv (Recommended)

```bash
uv add streamlit-json-tip
```

Or for a one-off script:
```bash
uv run --with streamlit-json-tip streamlit run your_app.py
```

### With pip

```bash
pip install streamlit-json-tip
```

### From TestPyPI (Latest Development Version)

With uv:
```bash
uv add --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ streamlit-json-tip
```

With pip:
```bash
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ streamlit-json-tip
```

### Development Setup

#### Prerequisites

* Install task

```bash
brew install go-task/tap/go-task
```

* Install uv

```bash
   curl -LsSf https://astral.sh/uv/install.sh | sh
```

#### Build repo

1. Clone this repository:
   ```bash
   git clone https://github.com/isaac/streamlit-json-tip.git
   cd streamlit-json-tip
   ```

2. Set up development environment with uv:
   ```bash
   # Create virtual environment and install all dependencies (including dev dependencies)
   uv sync
   ```

3. Run the example app:
   ```bash
   uv run streamlit run example_app.py
   ```

## Usage

```python
import streamlit as st
from streamlit_json_tip import json_viewer

# Your JSON data
data = {
    "user": {
        "id": 123,
        "name": "John Doe",
        "email": "john@example.com"
    }
}

# Help text for specific fields
help_text = {
    "user.id": "Unique user identifier",
    "user.name": "Full display name",
    "user.email": "Primary contact email"
}

# Tags for categorizing fields
tags = {
    "user.id": "ID",
    "user.name": "PII",
    "user.email": "PII"
}

# Display the JSON viewer
selected = json_viewer(
    data=data,
    help_text=help_text,
    tags=tags,
    height=400
)

# Handle field selection
if selected:
    st.write(f"Selected field: {selected['path']}")
    st.write(f"Value: {selected['value']}")
    if selected.get('help_text'):
        st.write(f"Help: {selected['help_text']}")
```

## Advanced Examples

### Dynamic Tooltips

Dynamic tooltips allow you to generate contextual help text programmatically based on field paths, values, and the complete data structure:

```python
import streamlit as st
from streamlit_json_tip import json_viewer

# Sample data with various types
data = {
    "user": {
        "name": "Alice Johnson", 
        "score": 95,
        "email": "alice@company.com",
        "role": "admin"
    },
    "metrics": {
        "cpu_usage": 0.78,
        "memory_usage": 0.65,
        "disk_usage": 0.92
    },
    "items": [
        {"id": 1, "status": "active"},
        {"id": 2, "status": "pending"}
    ]
}

def dynamic_tooltip(path, value, data):
    """Generate contextual tooltips based on field path and value."""
    
    # Name fields
    if path.endswith(".name"):
        return f"👤 Full name: {len(value)} characters"
    
    # Score fields with conditional icons
    elif path.endswith(".score"):
        icon = "đŸŸĸ" if value >= 90 else "🟡" if value >= 70 else "🔴"
        return {
            "text": f"Performance score: {value}/100",
            "icon": icon
        }
    
    # Email fields
    elif path.endswith(".email"):
        domain = value.split("@")[1] if "@" in value else "unknown"
        return {
            "text": f"📧 Email domain: {domain}",
            "icon": "📧"
        }
    
    # Usage metrics with warnings
    elif "usage" in path:
        percentage = f"{value * 100:.1f}%"
        if value > 0.9:
            return {
                "text": f"âš ī¸ High usage: {percentage}",
                "icon": "âš ī¸"
            }
        elif value > 0.7:
            return f"🟡 Moderate usage: {percentage}"
        else:
            return f"đŸŸĸ Normal usage: {percentage}"
    
    # Status fields
    elif path.endswith(".status"):
        status_info = {
            "active": {"icon": "✅", "desc": "Currently active"},
            "pending": {"icon": "âŗ", "desc": "Awaiting approval"},
            "inactive": {"icon": "❌", "desc": "Not active"}
        }
        info = status_info.get(value, {"icon": "❓", "desc": "Unknown status"})
        return {
            "text": f"{info['desc']}: {value}",
            "icon": info["icon"]
        }
    
    # Role-based tooltips
    elif path.endswith(".role"):
        role_descriptions = {
            "admin": "👑 Full system access",
            "user": "👤 Standard user access", 
            "guest": "đŸ‘ī¸ Read-only access"
        }
        return role_descriptions.get(value, f"Role: {value}")
    
    return None

# Display with dynamic tooltips
json_viewer(
    data=data,
    dynamic_tooltips=dynamic_tooltip,
    height=500
)
```

### Custom Tooltip Configuration

Configure Tippy.js tooltip behavior and appearance:

```python
import streamlit as st
from streamlit_json_tip import json_viewer

data = {
    "api": {
        "endpoint": "https://api.example.com",
        "version": "v2.1",
        "rate_limit": 1000
    },
    "database": {
        "host": "db.example.com",
        "port": 5432,
        "ssl": True
    }
}

help_text = {
    "api.endpoint": "The base URL for API requests",
    "api.version": "Current API version - breaking changes in major versions",
    "api.rate_limit": "Maximum requests per hour",
    "database.host": "Database server hostname",
    "database.port": "Database connection port",
    "database.ssl": "SSL encryption enabled for secure connections"
}

# Custom tooltip configuration
tooltip_config = {
    "placement": "right",           # Position: top, bottom, left, right, auto
    "animation": "scale",           # Animation: fade, shift-away, shift-toward, scale, perspective
    "delay": [500, 100],           # [show_delay, hide_delay] in milliseconds
    "duration": [200, 150],        # [show_duration, hide_duration] in milliseconds
    "interactive": True,           # Allow hovering over tooltip content
    "maxWidth": 300,              # Maximum width in pixels
    "trigger": "mouseenter focus", # Events: mouseenter, focus, click, etc.
    "hideOnClick": False,         # Keep tooltip open when clicking
    "sticky": True,               # Tooltip follows cursor movement
    "arrow": True,                # Show pointing arrow
    "theme": "light"              # Theme: light, dark, or custom
}

json_viewer(
    data=data,
    help_text=help_text,
    tooltip_config=tooltip_config,
    tooltip_icon="💡",  # Custom global icon
    height=400
)
```

### Complex Data with Tags and Icons

Handle complex nested structures with comprehensive tooltips:

```python
import streamlit as st
from streamlit_json_tip import json_viewer

# Complex nested data structure
data = {
    "users": [
        {
            "id": 1,
            "profile": {
                "name": "John Doe",
                "email": "john@company.com", 
                "ssn": "***-**-1234",
                "department": "Engineering"
            },
            "permissions": ["read", "write", "admin"],
            "last_login": "2024-01-15T10:30:00Z",
            "settings": {
                "theme": "dark",
                "notifications": True,
                "api_key": "sk-abc123...xyz789"
            }
        }
    ],
    "system": {
        "version": "2.1.0",
        "environment": "production",
        "uptime": 99.9,
        "memory_usage": 0.78
    }
}

# Static help text for specific fields
help_text = {
    "users[0].id": "Unique user identifier in the system",
    "system.version": "Current application version following semantic versioning",
    "system.environment": "Deployment environment (dev/staging/production)"
}

# Field categorization with tags
tags = {
    "users[0].profile.email": "PII",
    "users[0].profile.ssn": "SENSITIVE", 
    "users[0].profile.name": "PII",
    "users[0].settings.api_key": "SECRET",
    "system.environment": "CONFIG",
    "system.version": "INFO"
}

# Advanced dynamic tooltips with context awareness
def advanced_tooltips(path, value, data):
    # Get user context for personalized tips
    if "users[0]" in path:
        user_name = data["users"][0]["profile"]["name"]
        
        if path.endswith(".permissions"):
            perm_count = len(value)
            return {
                "text": f"🔐 {user_name} has {perm_count} permission(s): {', '.join(value)}",
                "icon": "🔐"
            }
        
        elif path.endswith(".last_login"):
            return {
                "text": f"🕒 {user_name}'s last activity: {value}",
                "icon": "🕒"
            }
        
        elif path.endswith(".department"):
            dept_info = {
                "Engineering": "👨‍đŸ’ģ Technical development team",
                "Sales": "đŸ’ŧ Revenue generation team",
                "Marketing": "đŸ“ĸ Brand and promotion team"
            }
            return dept_info.get(value, f"Department: {value}")
    
    # System metrics with thresholds
    elif path.startswith("system."):
        if path.endswith(".uptime"):
            if value >= 99.9:
                return {"text": f"đŸŸĸ Excellent uptime: {value}%", "icon": "đŸŸĸ"}
            elif value >= 99.0:
                return {"text": f"🟡 Good uptime: {value}%", "icon": "🟡"}
            else:
                return {"text": f"🔴 Poor uptime: {value}%", "icon": "🔴"}
        
        elif path.endswith(".memory_usage"):
            percentage = f"{value * 100:.1f}%"
            if value > 0.9:
                return {"text": f"âš ī¸ Critical memory usage: {percentage}", "icon": "âš ī¸"}
            elif value > 0.7:
                return {"text": f"🟡 High memory usage: {percentage}", "icon": "🟡"}
            else:
                return {"text": f"đŸŸĸ Normal memory usage: {percentage}", "icon": "đŸŸĸ"}
    
    # Sensitive data warnings
    if any(keyword in path for keyword in ["ssn", "api_key", "password"]):
        return {
            "text": "🚨 Sensitive data - handle with care",
            "icon": "🚨"
        }
    
    return None

# Advanced tooltip configuration for better UX
advanced_config = {
    "placement": "auto",     # Auto-position based on available space
    "animation": "fade",     # Smooth fade animation
    "delay": [300, 100],    # Quick show, delayed hide
    "interactive": True,     # Allow interaction with tooltip content
    "maxWidth": 400,        # Wider tooltips for more content
    "hideOnClick": False,   # Keep tooltips persistent
    "appendTo": "parent"    # Better positioning within container
}

selected = json_viewer(
    data=data,
    help_text=help_text,
    tags=tags,
    dynamic_tooltips=advanced_tooltips,
    tooltip_config=advanced_config,
    tooltip_icon="â„šī¸",
    height=600
)

# Handle field selection with detailed information
if selected:
    st.sidebar.header("Field Details")
    st.sidebar.json({
        "Path": selected['path'],
        "Value": selected['value'],
        "Type": type(selected['value']).__name__,
        "Help": selected.get('help_text', 'No help available')
    })
```

## Parameters

- **data** (dict): The JSON data to display
- **help_text** (dict, optional): Dictionary mapping field paths to help text
- **tags** (dict, optional): Dictionary mapping field paths to tags/labels
- **dynamic_tooltips** (function, optional): Function that takes (field_path, field_value, full_data) and returns tooltip text or dict with text and icon
- **tooltip_config** (dict, optional): Tippy.js configuration options (see Tooltip Configuration below)
- **tooltip_icon** (str, optional): Default icon for tooltips (default: "â„šī¸")
- **height** (int, optional): Height of the component in pixels (default: 400)
- **key** (str, optional): Unique key for the component

### Tooltip Configuration Options

The `tooltip_config` parameter accepts any valid [Tippy.js options](https://atomiks.github.io/tippyjs/v6/all-props/):

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `placement` | str | "top" | Tooltip position: "top", "bottom", "left", "right", "auto" |
| `animation` | str | "fade" | Animation type: "fade", "shift-away", "shift-toward", "scale", "perspective" |
| `delay` | int/list | 0 | Show delay in ms, or [show_delay, hide_delay] |
| `duration` | int/list | [300, 250] | Animation duration in ms, or [show_duration, hide_duration] |
| `interactive` | bool | False | Allow hovering over tooltip content |
| `maxWidth` | int | 350 | Maximum width in pixels |
| `trigger` | str | "mouseenter focus" | Events that trigger tooltip |
| `hideOnClick` | bool | True | Hide tooltip when clicking |
| `sticky` | bool | False | Tooltip follows cursor movement |
| `arrow` | bool | True | Show pointing arrow |
| `theme` | str | "light" | Tooltip theme |

## Field Path Format

Field paths use dot notation for objects and bracket notation for arrays:
- `"user.name"` - Object field
- `"items[0].title"` - Array item field
- `"settings.preferences.theme"` - Nested object field

## Development

### Frontend Development

1. Set up the development environment (see Development Setup above)

2. Navigate to the frontend directory:
   ```bash
   cd streamlit_json_tip/frontend
   ```

3. Install frontend dependencies:
   ```bash
   npm install
   ```

4. Start development server:
   ```bash
   npm start
   ```

5. In your Python code, set `_RELEASE = False` in `__init__.py`

6. Run the example app in another terminal:
   ```bash
   uv run streamlit run example_app.py
   ```

### Running Tests

#### Python Tests
```bash
# Run all Python unit tests with coverage
uv run pytest

# Run tests with verbose output
uv run pytest -v

# Generate HTML coverage report
uv run pytest --cov-report=html
```

#### Frontend Tests
```bash
cd streamlit_json_tip/frontend

# Run Jest tests once
npm test -- --ci --watchAll=false

# Run tests with coverage
npm test -- --coverage --ci --watchAll=false

# Run tests in watch mode (for development)
npm test
```

#### Run All Tests
Both Python and frontend tests run automatically in GitHub Actions on every push and pull request.

### Building for Production

1. Build the frontend:
   ```bash
   cd streamlit_json_tip/frontend
   npm run build
   ```

2. Set `_RELEASE = True` in `__init__.py`

3. Build the Python package:
   ```bash
   uv run python -m build
   ```

4. Upload to PyPI:
   ```bash
   uv run python -m twine upload dist/*
   ```

### Build Scripts

The project includes convenient uv scripts for common development tasks:

#### Frontend Development
```bash
task build-frontend
```

#### Package Building
```bash
uv run clean                 # Clean build artifacts
uv run build                 # Clean + build Python package
uv run build-check           # Build + validate package with twine
```

#### Publishing
```bash
task release-test          # Build + upload to TestPyPI
task release               # Build + upload to PyPI
```

This will build the frontend, package the Python distribution, validate it, and upload to PyPI.

## Releasing a New Version

This project uses automated GitHub Actions for releases. Follow these steps to release a new version:

### 1. Update Version and Changelog

1. **Update the version** in `pyproject.toml`:
   ```toml
   version = "0.2.5"  # Increment according to semver
   ```

2. **Add changelog entry** in `CHANGELOG.md`:
   ```markdown
   ## [0.2.5] - 2025-01-26

   ### ✨ Added
   - New feature description

   ### 🔧 Fixed  
   - Bug fix description
   ```

3. **Commit your changes**:
   ```bash
   git add pyproject.toml CHANGELOG.md
   git commit -m "Bump version to 0.2.5"
   git push origin main
   ```

### 2. Create and Push Release Tag

```bash
git tag v0.2.5
git push origin v0.2.5
```

### 3. Automated Release Process

Once you push the tag, GitHub Actions will automatically:

- ✅ Build the frontend (React components)
- ✅ Build the Python package (wheel + source distribution)
- ✅ Extract changelog section for this version
- ✅ Create GitHub Release with changelog as release notes
- ✅ Upload distribution files as release assets
- ✅ Publish to PyPI

### 4. Monitor the Release

1. **Check GitHub Actions**: Go to the Actions tab to monitor the release workflow
2. **Verify GitHub Release**: Check that the release was created with proper changelog
3. **Verify PyPI**: Confirm the new version appears on PyPI

### Setup Requirements (One-time)

To use automated releases, you need:

1. **PyPI API Token**: Add `PYPI_API_TOKEN` to your repository secrets
   - Go to: Repository → Settings → Secrets and variables → Actions
   - Add your PyPI token as `PYPI_API_TOKEN`

### Manual Release (Alternative)

If you prefer manual releases or need to troubleshoot:

```bash
# Build everything
task build

# Upload to PyPI manually
export TWINE_PASSWORD=your_pypi_token_here
python -m twine upload --username __token__ dist/*
```

## License

MIT License

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/yourusername/streamlit-json-tip",
    "name": "streamlit-json-tip",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": null,
    "keywords": "streamlit, json, viewer, tooltip, component, interactive",
    "author": "Your Name",
    "author_email": "Isaac <isaac@example.com>",
    "download_url": "https://files.pythonhosted.org/packages/9b/40/e41de1c10de9e64e40c5f38f3d06a41720ad82a4c02b55215195c114e995/streamlit_json_tip-0.2.8.tar.gz",
    "platform": null,
    "description": "# Streamlit JSON Tip\n\n[![PyPI version](https://badge.fury.io/py/streamlit-json-tip.svg)](https://pypi.org/project/streamlit-json-tip/)\n[![Python Support](https://img.shields.io/pypi/pyversions/streamlit-json-tip.svg)](https://pypi.org/project/streamlit-json-tip/)\n[![License](https://img.shields.io/pypi/l/streamlit-json-tip.svg)](https://github.com/kazuar/streamlit-json-tip/blob/main/LICENSE)\n[![Tests](https://github.com/kazuar/streamlit-json-tip/workflows/Test/badge.svg)](https://github.com/kazuar/streamlit-json-tip/actions/workflows/test.yml)\n[![Downloads](https://pepy.tech/badge/streamlit-json-tip)](https://pepy.tech/project/streamlit-json-tip)\n\nA Streamlit custom component for viewing JSON data with interactive tooltips and tags for individual fields.\n\n![Streamlit JSON Tip Example](https://github.com/kazuar/streamlit-json-tip/blob/main/resources/example.png?raw=true)\n\n## Features\n\n- \ud83d\udd0d **Interactive JSON Viewer**: Expand/collapse objects and arrays\n- \ud83d\udcdd **Interactive Tooltips**: Add contextual help for any field with professional Tippy.js tooltips\n- \ud83c\udff7\ufe0f **Field Tags**: Categorize fields with colored tags (PII, CONFIG, etc.)\n- \ud83c\udfaf **Field Selection**: Click on fields to get detailed information\n- \ud83c\udfa8 **Syntax Highlighting**: Color-coded JSON with proper formatting\n- \ud83d\udcf1 **Responsive Design**: Works well in different screen sizes\n\n## Installation\n\n### With uv (Recommended)\n\n```bash\nuv add streamlit-json-tip\n```\n\nOr for a one-off script:\n```bash\nuv run --with streamlit-json-tip streamlit run your_app.py\n```\n\n### With pip\n\n```bash\npip install streamlit-json-tip\n```\n\n### From TestPyPI (Latest Development Version)\n\nWith uv:\n```bash\nuv add --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ streamlit-json-tip\n```\n\nWith pip:\n```bash\npip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ streamlit-json-tip\n```\n\n### Development Setup\n\n#### Prerequisites\n\n* Install task\n\n```bash\nbrew install go-task/tap/go-task\n```\n\n* Install uv\n\n```bash\n   curl -LsSf https://astral.sh/uv/install.sh | sh\n```\n\n#### Build repo\n\n1. Clone this repository:\n   ```bash\n   git clone https://github.com/isaac/streamlit-json-tip.git\n   cd streamlit-json-tip\n   ```\n\n2. Set up development environment with uv:\n   ```bash\n   # Create virtual environment and install all dependencies (including dev dependencies)\n   uv sync\n   ```\n\n3. Run the example app:\n   ```bash\n   uv run streamlit run example_app.py\n   ```\n\n## Usage\n\n```python\nimport streamlit as st\nfrom streamlit_json_tip import json_viewer\n\n# Your JSON data\ndata = {\n    \"user\": {\n        \"id\": 123,\n        \"name\": \"John Doe\",\n        \"email\": \"john@example.com\"\n    }\n}\n\n# Help text for specific fields\nhelp_text = {\n    \"user.id\": \"Unique user identifier\",\n    \"user.name\": \"Full display name\",\n    \"user.email\": \"Primary contact email\"\n}\n\n# Tags for categorizing fields\ntags = {\n    \"user.id\": \"ID\",\n    \"user.name\": \"PII\",\n    \"user.email\": \"PII\"\n}\n\n# Display the JSON viewer\nselected = json_viewer(\n    data=data,\n    help_text=help_text,\n    tags=tags,\n    height=400\n)\n\n# Handle field selection\nif selected:\n    st.write(f\"Selected field: {selected['path']}\")\n    st.write(f\"Value: {selected['value']}\")\n    if selected.get('help_text'):\n        st.write(f\"Help: {selected['help_text']}\")\n```\n\n## Advanced Examples\n\n### Dynamic Tooltips\n\nDynamic tooltips allow you to generate contextual help text programmatically based on field paths, values, and the complete data structure:\n\n```python\nimport streamlit as st\nfrom streamlit_json_tip import json_viewer\n\n# Sample data with various types\ndata = {\n    \"user\": {\n        \"name\": \"Alice Johnson\", \n        \"score\": 95,\n        \"email\": \"alice@company.com\",\n        \"role\": \"admin\"\n    },\n    \"metrics\": {\n        \"cpu_usage\": 0.78,\n        \"memory_usage\": 0.65,\n        \"disk_usage\": 0.92\n    },\n    \"items\": [\n        {\"id\": 1, \"status\": \"active\"},\n        {\"id\": 2, \"status\": \"pending\"}\n    ]\n}\n\ndef dynamic_tooltip(path, value, data):\n    \"\"\"Generate contextual tooltips based on field path and value.\"\"\"\n    \n    # Name fields\n    if path.endswith(\".name\"):\n        return f\"\ud83d\udc64 Full name: {len(value)} characters\"\n    \n    # Score fields with conditional icons\n    elif path.endswith(\".score\"):\n        icon = \"\ud83d\udfe2\" if value >= 90 else \"\ud83d\udfe1\" if value >= 70 else \"\ud83d\udd34\"\n        return {\n            \"text\": f\"Performance score: {value}/100\",\n            \"icon\": icon\n        }\n    \n    # Email fields\n    elif path.endswith(\".email\"):\n        domain = value.split(\"@\")[1] if \"@\" in value else \"unknown\"\n        return {\n            \"text\": f\"\ud83d\udce7 Email domain: {domain}\",\n            \"icon\": \"\ud83d\udce7\"\n        }\n    \n    # Usage metrics with warnings\n    elif \"usage\" in path:\n        percentage = f\"{value * 100:.1f}%\"\n        if value > 0.9:\n            return {\n                \"text\": f\"\u26a0\ufe0f High usage: {percentage}\",\n                \"icon\": \"\u26a0\ufe0f\"\n            }\n        elif value > 0.7:\n            return f\"\ud83d\udfe1 Moderate usage: {percentage}\"\n        else:\n            return f\"\ud83d\udfe2 Normal usage: {percentage}\"\n    \n    # Status fields\n    elif path.endswith(\".status\"):\n        status_info = {\n            \"active\": {\"icon\": \"\u2705\", \"desc\": \"Currently active\"},\n            \"pending\": {\"icon\": \"\u23f3\", \"desc\": \"Awaiting approval\"},\n            \"inactive\": {\"icon\": \"\u274c\", \"desc\": \"Not active\"}\n        }\n        info = status_info.get(value, {\"icon\": \"\u2753\", \"desc\": \"Unknown status\"})\n        return {\n            \"text\": f\"{info['desc']}: {value}\",\n            \"icon\": info[\"icon\"]\n        }\n    \n    # Role-based tooltips\n    elif path.endswith(\".role\"):\n        role_descriptions = {\n            \"admin\": \"\ud83d\udc51 Full system access\",\n            \"user\": \"\ud83d\udc64 Standard user access\", \n            \"guest\": \"\ud83d\udc41\ufe0f Read-only access\"\n        }\n        return role_descriptions.get(value, f\"Role: {value}\")\n    \n    return None\n\n# Display with dynamic tooltips\njson_viewer(\n    data=data,\n    dynamic_tooltips=dynamic_tooltip,\n    height=500\n)\n```\n\n### Custom Tooltip Configuration\n\nConfigure Tippy.js tooltip behavior and appearance:\n\n```python\nimport streamlit as st\nfrom streamlit_json_tip import json_viewer\n\ndata = {\n    \"api\": {\n        \"endpoint\": \"https://api.example.com\",\n        \"version\": \"v2.1\",\n        \"rate_limit\": 1000\n    },\n    \"database\": {\n        \"host\": \"db.example.com\",\n        \"port\": 5432,\n        \"ssl\": True\n    }\n}\n\nhelp_text = {\n    \"api.endpoint\": \"The base URL for API requests\",\n    \"api.version\": \"Current API version - breaking changes in major versions\",\n    \"api.rate_limit\": \"Maximum requests per hour\",\n    \"database.host\": \"Database server hostname\",\n    \"database.port\": \"Database connection port\",\n    \"database.ssl\": \"SSL encryption enabled for secure connections\"\n}\n\n# Custom tooltip configuration\ntooltip_config = {\n    \"placement\": \"right\",           # Position: top, bottom, left, right, auto\n    \"animation\": \"scale\",           # Animation: fade, shift-away, shift-toward, scale, perspective\n    \"delay\": [500, 100],           # [show_delay, hide_delay] in milliseconds\n    \"duration\": [200, 150],        # [show_duration, hide_duration] in milliseconds\n    \"interactive\": True,           # Allow hovering over tooltip content\n    \"maxWidth\": 300,              # Maximum width in pixels\n    \"trigger\": \"mouseenter focus\", # Events: mouseenter, focus, click, etc.\n    \"hideOnClick\": False,         # Keep tooltip open when clicking\n    \"sticky\": True,               # Tooltip follows cursor movement\n    \"arrow\": True,                # Show pointing arrow\n    \"theme\": \"light\"              # Theme: light, dark, or custom\n}\n\njson_viewer(\n    data=data,\n    help_text=help_text,\n    tooltip_config=tooltip_config,\n    tooltip_icon=\"\ud83d\udca1\",  # Custom global icon\n    height=400\n)\n```\n\n### Complex Data with Tags and Icons\n\nHandle complex nested structures with comprehensive tooltips:\n\n```python\nimport streamlit as st\nfrom streamlit_json_tip import json_viewer\n\n# Complex nested data structure\ndata = {\n    \"users\": [\n        {\n            \"id\": 1,\n            \"profile\": {\n                \"name\": \"John Doe\",\n                \"email\": \"john@company.com\", \n                \"ssn\": \"***-**-1234\",\n                \"department\": \"Engineering\"\n            },\n            \"permissions\": [\"read\", \"write\", \"admin\"],\n            \"last_login\": \"2024-01-15T10:30:00Z\",\n            \"settings\": {\n                \"theme\": \"dark\",\n                \"notifications\": True,\n                \"api_key\": \"sk-abc123...xyz789\"\n            }\n        }\n    ],\n    \"system\": {\n        \"version\": \"2.1.0\",\n        \"environment\": \"production\",\n        \"uptime\": 99.9,\n        \"memory_usage\": 0.78\n    }\n}\n\n# Static help text for specific fields\nhelp_text = {\n    \"users[0].id\": \"Unique user identifier in the system\",\n    \"system.version\": \"Current application version following semantic versioning\",\n    \"system.environment\": \"Deployment environment (dev/staging/production)\"\n}\n\n# Field categorization with tags\ntags = {\n    \"users[0].profile.email\": \"PII\",\n    \"users[0].profile.ssn\": \"SENSITIVE\", \n    \"users[0].profile.name\": \"PII\",\n    \"users[0].settings.api_key\": \"SECRET\",\n    \"system.environment\": \"CONFIG\",\n    \"system.version\": \"INFO\"\n}\n\n# Advanced dynamic tooltips with context awareness\ndef advanced_tooltips(path, value, data):\n    # Get user context for personalized tips\n    if \"users[0]\" in path:\n        user_name = data[\"users\"][0][\"profile\"][\"name\"]\n        \n        if path.endswith(\".permissions\"):\n            perm_count = len(value)\n            return {\n                \"text\": f\"\ud83d\udd10 {user_name} has {perm_count} permission(s): {', '.join(value)}\",\n                \"icon\": \"\ud83d\udd10\"\n            }\n        \n        elif path.endswith(\".last_login\"):\n            return {\n                \"text\": f\"\ud83d\udd52 {user_name}'s last activity: {value}\",\n                \"icon\": \"\ud83d\udd52\"\n            }\n        \n        elif path.endswith(\".department\"):\n            dept_info = {\n                \"Engineering\": \"\ud83d\udc68\u200d\ud83d\udcbb Technical development team\",\n                \"Sales\": \"\ud83d\udcbc Revenue generation team\",\n                \"Marketing\": \"\ud83d\udce2 Brand and promotion team\"\n            }\n            return dept_info.get(value, f\"Department: {value}\")\n    \n    # System metrics with thresholds\n    elif path.startswith(\"system.\"):\n        if path.endswith(\".uptime\"):\n            if value >= 99.9:\n                return {\"text\": f\"\ud83d\udfe2 Excellent uptime: {value}%\", \"icon\": \"\ud83d\udfe2\"}\n            elif value >= 99.0:\n                return {\"text\": f\"\ud83d\udfe1 Good uptime: {value}%\", \"icon\": \"\ud83d\udfe1\"}\n            else:\n                return {\"text\": f\"\ud83d\udd34 Poor uptime: {value}%\", \"icon\": \"\ud83d\udd34\"}\n        \n        elif path.endswith(\".memory_usage\"):\n            percentage = f\"{value * 100:.1f}%\"\n            if value > 0.9:\n                return {\"text\": f\"\u26a0\ufe0f Critical memory usage: {percentage}\", \"icon\": \"\u26a0\ufe0f\"}\n            elif value > 0.7:\n                return {\"text\": f\"\ud83d\udfe1 High memory usage: {percentage}\", \"icon\": \"\ud83d\udfe1\"}\n            else:\n                return {\"text\": f\"\ud83d\udfe2 Normal memory usage: {percentage}\", \"icon\": \"\ud83d\udfe2\"}\n    \n    # Sensitive data warnings\n    if any(keyword in path for keyword in [\"ssn\", \"api_key\", \"password\"]):\n        return {\n            \"text\": \"\ud83d\udea8 Sensitive data - handle with care\",\n            \"icon\": \"\ud83d\udea8\"\n        }\n    \n    return None\n\n# Advanced tooltip configuration for better UX\nadvanced_config = {\n    \"placement\": \"auto\",     # Auto-position based on available space\n    \"animation\": \"fade\",     # Smooth fade animation\n    \"delay\": [300, 100],    # Quick show, delayed hide\n    \"interactive\": True,     # Allow interaction with tooltip content\n    \"maxWidth\": 400,        # Wider tooltips for more content\n    \"hideOnClick\": False,   # Keep tooltips persistent\n    \"appendTo\": \"parent\"    # Better positioning within container\n}\n\nselected = json_viewer(\n    data=data,\n    help_text=help_text,\n    tags=tags,\n    dynamic_tooltips=advanced_tooltips,\n    tooltip_config=advanced_config,\n    tooltip_icon=\"\u2139\ufe0f\",\n    height=600\n)\n\n# Handle field selection with detailed information\nif selected:\n    st.sidebar.header(\"Field Details\")\n    st.sidebar.json({\n        \"Path\": selected['path'],\n        \"Value\": selected['value'],\n        \"Type\": type(selected['value']).__name__,\n        \"Help\": selected.get('help_text', 'No help available')\n    })\n```\n\n## Parameters\n\n- **data** (dict): The JSON data to display\n- **help_text** (dict, optional): Dictionary mapping field paths to help text\n- **tags** (dict, optional): Dictionary mapping field paths to tags/labels\n- **dynamic_tooltips** (function, optional): Function that takes (field_path, field_value, full_data) and returns tooltip text or dict with text and icon\n- **tooltip_config** (dict, optional): Tippy.js configuration options (see Tooltip Configuration below)\n- **tooltip_icon** (str, optional): Default icon for tooltips (default: \"\u2139\ufe0f\")\n- **height** (int, optional): Height of the component in pixels (default: 400)\n- **key** (str, optional): Unique key for the component\n\n### Tooltip Configuration Options\n\nThe `tooltip_config` parameter accepts any valid [Tippy.js options](https://atomiks.github.io/tippyjs/v6/all-props/):\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `placement` | str | \"top\" | Tooltip position: \"top\", \"bottom\", \"left\", \"right\", \"auto\" |\n| `animation` | str | \"fade\" | Animation type: \"fade\", \"shift-away\", \"shift-toward\", \"scale\", \"perspective\" |\n| `delay` | int/list | 0 | Show delay in ms, or [show_delay, hide_delay] |\n| `duration` | int/list | [300, 250] | Animation duration in ms, or [show_duration, hide_duration] |\n| `interactive` | bool | False | Allow hovering over tooltip content |\n| `maxWidth` | int | 350 | Maximum width in pixels |\n| `trigger` | str | \"mouseenter focus\" | Events that trigger tooltip |\n| `hideOnClick` | bool | True | Hide tooltip when clicking |\n| `sticky` | bool | False | Tooltip follows cursor movement |\n| `arrow` | bool | True | Show pointing arrow |\n| `theme` | str | \"light\" | Tooltip theme |\n\n## Field Path Format\n\nField paths use dot notation for objects and bracket notation for arrays:\n- `\"user.name\"` - Object field\n- `\"items[0].title\"` - Array item field\n- `\"settings.preferences.theme\"` - Nested object field\n\n## Development\n\n### Frontend Development\n\n1. Set up the development environment (see Development Setup above)\n\n2. Navigate to the frontend directory:\n   ```bash\n   cd streamlit_json_tip/frontend\n   ```\n\n3. Install frontend dependencies:\n   ```bash\n   npm install\n   ```\n\n4. Start development server:\n   ```bash\n   npm start\n   ```\n\n5. In your Python code, set `_RELEASE = False` in `__init__.py`\n\n6. Run the example app in another terminal:\n   ```bash\n   uv run streamlit run example_app.py\n   ```\n\n### Running Tests\n\n#### Python Tests\n```bash\n# Run all Python unit tests with coverage\nuv run pytest\n\n# Run tests with verbose output\nuv run pytest -v\n\n# Generate HTML coverage report\nuv run pytest --cov-report=html\n```\n\n#### Frontend Tests\n```bash\ncd streamlit_json_tip/frontend\n\n# Run Jest tests once\nnpm test -- --ci --watchAll=false\n\n# Run tests with coverage\nnpm test -- --coverage --ci --watchAll=false\n\n# Run tests in watch mode (for development)\nnpm test\n```\n\n#### Run All Tests\nBoth Python and frontend tests run automatically in GitHub Actions on every push and pull request.\n\n### Building for Production\n\n1. Build the frontend:\n   ```bash\n   cd streamlit_json_tip/frontend\n   npm run build\n   ```\n\n2. Set `_RELEASE = True` in `__init__.py`\n\n3. Build the Python package:\n   ```bash\n   uv run python -m build\n   ```\n\n4. Upload to PyPI:\n   ```bash\n   uv run python -m twine upload dist/*\n   ```\n\n### Build Scripts\n\nThe project includes convenient uv scripts for common development tasks:\n\n#### Frontend Development\n```bash\ntask build-frontend\n```\n\n#### Package Building\n```bash\nuv run clean                 # Clean build artifacts\nuv run build                 # Clean + build Python package\nuv run build-check           # Build + validate package with twine\n```\n\n#### Publishing\n```bash\ntask release-test          # Build + upload to TestPyPI\ntask release               # Build + upload to PyPI\n```\n\nThis will build the frontend, package the Python distribution, validate it, and upload to PyPI.\n\n## Releasing a New Version\n\nThis project uses automated GitHub Actions for releases. Follow these steps to release a new version:\n\n### 1. Update Version and Changelog\n\n1. **Update the version** in `pyproject.toml`:\n   ```toml\n   version = \"0.2.5\"  # Increment according to semver\n   ```\n\n2. **Add changelog entry** in `CHANGELOG.md`:\n   ```markdown\n   ## [0.2.5] - 2025-01-26\n\n   ### \u2728 Added\n   - New feature description\n\n   ### \ud83d\udd27 Fixed  \n   - Bug fix description\n   ```\n\n3. **Commit your changes**:\n   ```bash\n   git add pyproject.toml CHANGELOG.md\n   git commit -m \"Bump version to 0.2.5\"\n   git push origin main\n   ```\n\n### 2. Create and Push Release Tag\n\n```bash\ngit tag v0.2.5\ngit push origin v0.2.5\n```\n\n### 3. Automated Release Process\n\nOnce you push the tag, GitHub Actions will automatically:\n\n- \u2705 Build the frontend (React components)\n- \u2705 Build the Python package (wheel + source distribution)\n- \u2705 Extract changelog section for this version\n- \u2705 Create GitHub Release with changelog as release notes\n- \u2705 Upload distribution files as release assets\n- \u2705 Publish to PyPI\n\n### 4. Monitor the Release\n\n1. **Check GitHub Actions**: Go to the Actions tab to monitor the release workflow\n2. **Verify GitHub Release**: Check that the release was created with proper changelog\n3. **Verify PyPI**: Confirm the new version appears on PyPI\n\n### Setup Requirements (One-time)\n\nTo use automated releases, you need:\n\n1. **PyPI API Token**: Add `PYPI_API_TOKEN` to your repository secrets\n   - Go to: Repository \u2192 Settings \u2192 Secrets and variables \u2192 Actions\n   - Add your PyPI token as `PYPI_API_TOKEN`\n\n### Manual Release (Alternative)\n\nIf you prefer manual releases or need to troubleshoot:\n\n```bash\n# Build everything\ntask build\n\n# Upload to PyPI manually\nexport TWINE_PASSWORD=your_pypi_token_here\npython -m twine upload --username __token__ dist/*\n```\n\n## License\n\nMIT License\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A Streamlit custom component for viewing JSON with interactive tooltips and tags",
    "version": "0.2.8",
    "project_urls": {
        "Bug Tracker": "https://github.com/isaac/streamlit-json-tip/issues",
        "Documentation": "https://github.com/isaac/streamlit-json-tip#readme",
        "Homepage": "https://github.com/isaac/streamlit-json-tip",
        "Repository": "https://github.com/isaac/streamlit-json-tip"
    },
    "split_keywords": [
        "streamlit",
        " json",
        " viewer",
        " tooltip",
        " component",
        " interactive"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e7c910571810a0ba53bc013d111981feb2ba2f54b3845b953cb12a3c60672a96",
                "md5": "b4abc46f6e0451ffc7ac1b266161dd48",
                "sha256": "d0deec64c1b32a1288dea76f132c99baa4ca2de84895e386efcb1864c7476f92"
            },
            "downloads": -1,
            "filename": "streamlit_json_tip-0.2.8-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b4abc46f6e0451ffc7ac1b266161dd48",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 667939,
            "upload_time": "2025-08-21T02:39:18",
            "upload_time_iso_8601": "2025-08-21T02:39:18.155822Z",
            "url": "https://files.pythonhosted.org/packages/e7/c9/10571810a0ba53bc013d111981feb2ba2f54b3845b953cb12a3c60672a96/streamlit_json_tip-0.2.8-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "9b40e41de1c10de9e64e40c5f38f3d06a41720ad82a4c02b55215195c114e995",
                "md5": "acd75b55fa9d6627c5d01818dc1d8630",
                "sha256": "4a5083784e12e3e6b1821e7d5fcdd745546cc4ca16cd66691d279b73e1c6673c"
            },
            "downloads": -1,
            "filename": "streamlit_json_tip-0.2.8.tar.gz",
            "has_sig": false,
            "md5_digest": "acd75b55fa9d6627c5d01818dc1d8630",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 941818,
            "upload_time": "2025-08-21T02:39:19",
            "upload_time_iso_8601": "2025-08-21T02:39:19.519387Z",
            "url": "https://files.pythonhosted.org/packages/9b/40/e41de1c10de9e64e40c5f38f3d06a41720ad82a4c02b55215195c114e995/streamlit_json_tip-0.2.8.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-21 02:39:19",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "yourusername",
    "github_project": "streamlit-json-tip",
    "github_not_found": true,
    "lcname": "streamlit-json-tip"
}
        
Elapsed time: 1.46300s