hazo_ui 2.4.0 → 2.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,6 +57,10 @@ That's it! The components will now render correctly with proper styling.
57
57
 
58
58
  - **[HazoUiRte](#hazouirte)** - A comprehensive rich text editor for email template generation with variable insertion support, file attachments, and full formatting controls. Built on Tiptap with support for tables, lists, images, and multiple view modes (HTML, Plain Text, Raw HTML).
59
59
 
60
+ - **[HazoUiTextbox](#hazouitextbox)** - A single-line input component with command pill support. Allows users to insert prefix-triggered commands (e.g., @mentions, /commands, #tags) that appear as interactive pills. Includes click-to-edit functionality for modifying or removing inserted commands.
61
+
62
+ - **[HazoUiTextarea](#hazouitextarea)** - A multi-line textarea component with command pill support. Similar to HazoUiTextbox but supports multi-line input with Shift+Enter for new lines and Cmd/Ctrl+Enter to submit. Features the same interactive pill editing capabilities.
63
+
60
64
  ---
61
65
 
62
66
  ## HazoUiMultiFilterDialog
@@ -1234,6 +1238,435 @@ The toolbar includes the following controls (left to right):
1234
1238
 
1235
1239
  ---
1236
1240
 
1241
+ ## HazoUiTextbox
1242
+
1243
+ A single-line text input component with prefix-triggered command pill support. Perfect for mention systems, command inputs, tag fields, and any input that needs to convert text patterns into interactive elements.
1244
+
1245
+ #### Features
1246
+
1247
+ - **Command Pills**: Convert prefix-triggered text (e.g., @mention, /command, #tag) into interactive pills
1248
+ - **Click to Edit**: Click any pill to open an edit popover with options to change or remove the command
1249
+ - **Keyboard Navigation**: Navigate edit options with Arrow Up/Down, select with Enter, close with Escape
1250
+ - **Multiple Prefixes**: Support multiple prefix types simultaneously (e.g., @ for users, # for tags, / for commands)
1251
+ - **Visual Variants**: Three pill styles - default (blue), outline (transparent), subtle (muted)
1252
+ - **Auto-complete Dropdown**: Searchable dropdown appears when typing a prefix character
1253
+ - **Controlled & Uncontrolled**: Supports both controlled and uncontrolled usage patterns
1254
+ - **Single-line Input**: Press Enter to submit (triggers `on_submit` callback)
1255
+ - **TypeScript Support**: Fully typed with comprehensive interfaces
1256
+
1257
+ #### Type Definitions
1258
+
1259
+ ```typescript
1260
+ interface HazoUiTextboxProps {
1261
+ // Controlled value (plain text with prefix+action format, e.g., "Hello @john_doe!")
1262
+ value?: string;
1263
+
1264
+ // Uncontrolled default value
1265
+ default_value?: string;
1266
+
1267
+ // Prefix configurations (required)
1268
+ prefixes: PrefixConfig[];
1269
+
1270
+ // Input properties
1271
+ placeholder?: string; // default: "Type here..."
1272
+ disabled?: boolean; // default: false
1273
+ className?: string;
1274
+
1275
+ // Pill styling
1276
+ pill_variant?: "default" | "outline" | "subtle"; // default: "default"
1277
+
1278
+ // Callbacks
1279
+ on_change?: (output: CommandTextOutput) => void;
1280
+ on_submit?: (output: CommandTextOutput) => void; // Triggered on Enter key
1281
+ on_command_insert?: (command: CommandItem, prefix: string) => void;
1282
+ on_command_change?: (old_command: InsertedCommand, new_command: CommandItem) => void;
1283
+ on_command_remove?: (command: InsertedCommand) => void;
1284
+ }
1285
+
1286
+ interface PrefixConfig {
1287
+ char: string; // Prefix character (e.g., "@", "/", "#")
1288
+ commands: CommandItem[]; // Available commands for this prefix
1289
+ }
1290
+
1291
+ interface CommandItem {
1292
+ action: string; // Unique action identifier (e.g., "john_doe")
1293
+ action_label: string; // Display label (e.g., "John Doe")
1294
+ action_description?: string; // Optional description shown in dropdown
1295
+ icon?: React.ReactNode; // Optional icon
1296
+ }
1297
+
1298
+ interface CommandTextOutput {
1299
+ plain_text: string; // Plain text with prefix+action (e.g., "Hello @john_doe!")
1300
+ display_text: string; // Display text with labels (e.g., "Hello @John Doe!")
1301
+ commands: InsertedCommand[]; // Array of inserted commands with positions
1302
+ }
1303
+
1304
+ interface InsertedCommand {
1305
+ id: string; // Unique ID for this instance
1306
+ prefix: string; // The prefix character
1307
+ action: string; // The action identifier
1308
+ action_label: string; // The display label
1309
+ position: number; // Character position in plain_text
1310
+ length: number; // Length of the command in plain_text
1311
+ }
1312
+ ```
1313
+
1314
+ #### Basic Usage
1315
+
1316
+ ```tsx
1317
+ import { HazoUiTextbox, type PrefixConfig, type CommandTextOutput } from 'hazo_ui';
1318
+ import { useState } from 'react';
1319
+
1320
+ function MentionInput() {
1321
+ const [value, setValue] = useState<string>("");
1322
+
1323
+ // Define available mentions
1324
+ const prefixes: PrefixConfig[] = [
1325
+ {
1326
+ char: "@",
1327
+ commands: [
1328
+ { action: "john_doe", action_label: "John Doe" },
1329
+ { action: "jane_smith", action_label: "Jane Smith" },
1330
+ { action: "bob_wilson", action_label: "Bob Wilson" },
1331
+ ],
1332
+ },
1333
+ ];
1334
+
1335
+ const handleChange = (output: CommandTextOutput) => {
1336
+ setValue(output.plain_text);
1337
+ console.log('Plain text:', output.plain_text);
1338
+ console.log('Display text:', output.display_text);
1339
+ console.log('Commands:', output.commands);
1340
+ };
1341
+
1342
+ return (
1343
+ <HazoUiTextbox
1344
+ value={value}
1345
+ prefixes={prefixes}
1346
+ placeholder="Type @ to mention someone..."
1347
+ on_change={handleChange}
1348
+ />
1349
+ );
1350
+ }
1351
+ ```
1352
+
1353
+ #### Multiple Prefix Types
1354
+
1355
+ ```tsx
1356
+ import { HazoUiTextbox, type PrefixConfig } from 'hazo_ui';
1357
+
1358
+ function MultiPrefixInput() {
1359
+ const prefixes: PrefixConfig[] = [
1360
+ {
1361
+ char: "@",
1362
+ commands: [
1363
+ { action: "john", action_label: "John Doe", action_description: "Software Engineer" },
1364
+ { action: "jane", action_label: "Jane Smith", action_description: "Product Manager" },
1365
+ ],
1366
+ },
1367
+ {
1368
+ char: "#",
1369
+ commands: [
1370
+ { action: "bug", action_label: "Bug", action_description: "Something is broken" },
1371
+ { action: "feature", action_label: "Feature", action_description: "New functionality" },
1372
+ { action: "docs", action_label: "Documentation", action_description: "Documentation update" },
1373
+ ],
1374
+ },
1375
+ {
1376
+ char: "/",
1377
+ commands: [
1378
+ { action: "assign", action_label: "Assign", action_description: "Assign to user" },
1379
+ { action: "close", action_label: "Close", action_description: "Close this issue" },
1380
+ { action: "archive", action_label: "Archive", action_description: "Archive this item" },
1381
+ ],
1382
+ },
1383
+ ];
1384
+
1385
+ return (
1386
+ <HazoUiTextbox
1387
+ prefixes={prefixes}
1388
+ placeholder="Type @, #, or / for commands..."
1389
+ on_change={(output) => console.log(output)}
1390
+ />
1391
+ );
1392
+ }
1393
+ ```
1394
+
1395
+ #### With Command Callbacks
1396
+
1397
+ ```tsx
1398
+ import { HazoUiTextbox, type CommandItem, type InsertedCommand } from 'hazo_ui';
1399
+
1400
+ function CommandInput() {
1401
+ const prefixes = [
1402
+ {
1403
+ char: "@",
1404
+ commands: [
1405
+ { action: "alice", action_label: "Alice Johnson" },
1406
+ { action: "bob", action_label: "Bob Smith" },
1407
+ ],
1408
+ },
1409
+ ];
1410
+
1411
+ const handleInsert = (command: CommandItem, prefix: string) => {
1412
+ console.log(`Inserted ${prefix}${command.action_label}`);
1413
+ // Track analytics, send notifications, etc.
1414
+ };
1415
+
1416
+ const handleChange = (old_command: InsertedCommand, new_command: CommandItem) => {
1417
+ console.log(`Changed from ${old_command.action} to ${new_command.action}`);
1418
+ // Update references, notify backend, etc.
1419
+ };
1420
+
1421
+ const handleRemove = (command: InsertedCommand) => {
1422
+ console.log(`Removed ${command.prefix}${command.action_label}`);
1423
+ // Clean up references, update state, etc.
1424
+ };
1425
+
1426
+ return (
1427
+ <HazoUiTextbox
1428
+ prefixes={prefixes}
1429
+ placeholder="Mention someone..."
1430
+ on_command_insert={handleInsert}
1431
+ on_command_change={handleChange}
1432
+ on_command_remove={handleRemove}
1433
+ on_submit={(output) => console.log('Submitted:', output)}
1434
+ />
1435
+ );
1436
+ }
1437
+ ```
1438
+
1439
+ #### Pill Variants
1440
+
1441
+ ```tsx
1442
+ import { HazoUiTextbox } from 'hazo_ui';
1443
+
1444
+ function VariantExample() {
1445
+ const prefixes = [
1446
+ {
1447
+ char: "@",
1448
+ commands: [{ action: "user", action_label: "Username" }],
1449
+ },
1450
+ ];
1451
+
1452
+ return (
1453
+ <div className="space-y-4">
1454
+ {/* Default: Blue background */}
1455
+ <HazoUiTextbox
1456
+ prefixes={prefixes}
1457
+ pill_variant="default"
1458
+ placeholder="Default variant (blue)..."
1459
+ />
1460
+
1461
+ {/* Outline: Transparent with border */}
1462
+ <HazoUiTextbox
1463
+ prefixes={prefixes}
1464
+ pill_variant="outline"
1465
+ placeholder="Outline variant (transparent)..."
1466
+ />
1467
+
1468
+ {/* Subtle: Muted background */}
1469
+ <HazoUiTextbox
1470
+ prefixes={prefixes}
1471
+ pill_variant="subtle"
1472
+ placeholder="Subtle variant (muted)..."
1473
+ />
1474
+ </div>
1475
+ );
1476
+ }
1477
+ ```
1478
+
1479
+ #### Edit Popover Behavior
1480
+
1481
+ When a user clicks on an inserted command pill:
1482
+
1483
+ 1. **Edit Popover Opens**: A dropdown appears below the clicked pill
1484
+ 2. **Command Options**: Shows all available commands for that prefix
1485
+ 3. **Current Selection**: The current command is highlighted with "current" label
1486
+ 4. **Change Command**: Click any command to change to that option (triggers `on_command_change`)
1487
+ 5. **Remove Command**: Click "Remove" at the bottom to delete the pill (triggers `on_command_remove`)
1488
+ 6. **Keyboard Navigation**:
1489
+ - Arrow Up/Down: Navigate options
1490
+ - Enter: Select highlighted option
1491
+ - Escape: Close popover without changes
1492
+ 7. **Click Outside**: Click anywhere outside the popover to close without changes
1493
+
1494
+ #### Expected Output
1495
+
1496
+ ```typescript
1497
+ // Example input: "Hello @john_doe and #feature request"
1498
+ // With prefixes: @ for users, # for tags
1499
+
1500
+ const output: CommandTextOutput = {
1501
+ plain_text: "Hello @john_doe and #feature request",
1502
+ display_text: "Hello @John Doe and #Feature request",
1503
+ commands: [
1504
+ {
1505
+ id: "cmd_abc123",
1506
+ prefix: "@",
1507
+ action: "john_doe",
1508
+ action_label: "John Doe",
1509
+ position: 6, // Character position of "@" in plain_text
1510
+ length: 9, // Length of "@john_doe"
1511
+ },
1512
+ {
1513
+ id: "cmd_def456",
1514
+ prefix: "#",
1515
+ action: "feature",
1516
+ action_label: "Feature",
1517
+ position: 20, // Character position of "#" in plain_text
1518
+ length: 8, // Length of "#feature"
1519
+ },
1520
+ ],
1521
+ };
1522
+ ```
1523
+
1524
+ ---
1525
+
1526
+ ## HazoUiTextarea
1527
+
1528
+ A multi-line text input component with prefix-triggered command pill support. Similar to HazoUiTextbox but supports multiple paragraphs and line breaks.
1529
+
1530
+ #### Features
1531
+
1532
+ - **All HazoUiTextbox Features**: Inherits all command pill functionality
1533
+ - **Multi-line Support**: Supports multiple paragraphs with line breaks
1534
+ - **Shift+Enter**: Create new lines within the textarea
1535
+ - **Cmd/Ctrl+Enter to Submit**: Submit with keyboard shortcut (triggers `on_submit` callback)
1536
+ - **Configurable Height**: Set min/max height or use rows prop
1537
+ - **Click to Edit Pills**: Same interactive pill editing as HazoUiTextbox
1538
+ - **Auto-scrolling**: Scrollable content when exceeding max height
1539
+
1540
+ #### Type Definitions
1541
+
1542
+ ```typescript
1543
+ interface HazoUiTextareaProps {
1544
+ // Same as HazoUiTextbox plus:
1545
+ value?: string;
1546
+ default_value?: string;
1547
+ prefixes: PrefixConfig[];
1548
+ placeholder?: string;
1549
+ disabled?: boolean;
1550
+ className?: string;
1551
+ pill_variant?: "default" | "outline" | "subtle";
1552
+ on_change?: (output: CommandTextOutput) => void;
1553
+ on_submit?: (output: CommandTextOutput) => void; // Triggered on Cmd/Ctrl+Enter
1554
+ on_command_insert?: (command: CommandItem, prefix: string) => void;
1555
+ on_command_change?: (old_command: InsertedCommand, new_command: CommandItem) => void;
1556
+ on_command_remove?: (command: InsertedCommand) => void;
1557
+
1558
+ // Textarea-specific properties
1559
+ min_height?: string; // default: "80px"
1560
+ max_height?: string; // default: "200px"
1561
+ rows?: number; // Alternative to min_height (calculates as rows * 1.5em)
1562
+ }
1563
+ ```
1564
+
1565
+ #### Basic Usage
1566
+
1567
+ ```tsx
1568
+ import { HazoUiTextarea, type PrefixConfig } from 'hazo_ui';
1569
+ import { useState } from 'react';
1570
+
1571
+ function CommentBox() {
1572
+ const [value, setValue] = useState<string>("");
1573
+
1574
+ const prefixes: PrefixConfig[] = [
1575
+ {
1576
+ char: "@",
1577
+ commands: [
1578
+ { action: "alice", action_label: "Alice Johnson" },
1579
+ { action: "bob", action_label: "Bob Smith" },
1580
+ ],
1581
+ },
1582
+ {
1583
+ char: "#",
1584
+ commands: [
1585
+ { action: "bug", action_label: "Bug" },
1586
+ { action: "feature", action_label: "Feature Request" },
1587
+ ],
1588
+ },
1589
+ ];
1590
+
1591
+ return (
1592
+ <HazoUiTextarea
1593
+ value={value}
1594
+ prefixes={prefixes}
1595
+ placeholder="Write a comment... (Cmd+Enter to submit)"
1596
+ min_height="100px"
1597
+ max_height="300px"
1598
+ on_change={(output) => setValue(output.plain_text)}
1599
+ on_submit={(output) => {
1600
+ console.log('Submitting:', output);
1601
+ // Submit comment to backend
1602
+ setValue(""); // Clear after submit
1603
+ }}
1604
+ />
1605
+ );
1606
+ }
1607
+ ```
1608
+
1609
+ #### With Custom Height
1610
+
1611
+ ```tsx
1612
+ import { HazoUiTextarea } from 'hazo_ui';
1613
+
1614
+ function CustomHeightExample() {
1615
+ const prefixes = [
1616
+ { char: "@", commands: [{ action: "user", action_label: "User" }] },
1617
+ ];
1618
+
1619
+ return (
1620
+ <div className="space-y-4">
1621
+ {/* Using rows */}
1622
+ <HazoUiTextarea
1623
+ prefixes={prefixes}
1624
+ rows={3}
1625
+ placeholder="3 rows tall..."
1626
+ />
1627
+
1628
+ {/* Using min/max height */}
1629
+ <HazoUiTextarea
1630
+ prefixes={prefixes}
1631
+ min_height="120px"
1632
+ max_height="400px"
1633
+ placeholder="Custom height..."
1634
+ />
1635
+ </div>
1636
+ );
1637
+ }
1638
+ ```
1639
+
1640
+ #### Keyboard Shortcuts
1641
+
1642
+ - **Enter**: Insert a new line (Shift+Enter also works)
1643
+ - **Cmd+Enter** (Mac) or **Ctrl+Enter** (Windows/Linux): Submit (triggers `on_submit`)
1644
+ - **Arrow Up/Down**: Navigate command suggestions or edit options
1645
+ - **Escape**: Close popover/dropdown
1646
+ - **Typing `@`, `#`, `/`** (or any configured prefix): Open command dropdown
1647
+
1648
+ #### Props Reference
1649
+
1650
+ | Prop | Type | Default | Description |
1651
+ |------|------|---------|-------------|
1652
+ | `value` | `string` | - | Controlled value (plain text with commands) |
1653
+ | `default_value` | `string` | - | Uncontrolled default value |
1654
+ | `prefixes` | `PrefixConfig[]` | **Required** | Prefix configurations |
1655
+ | `placeholder` | `string` | `"Type here..."` | Placeholder text |
1656
+ | `disabled` | `boolean` | `false` | Disable input |
1657
+ | `className` | `string` | - | Additional CSS classes |
1658
+ | `pill_variant` | `"default" \| "outline" \| "subtle"` | `"default"` | Pill styling variant |
1659
+ | `min_height` | `string` | `"80px"` | Minimum textarea height |
1660
+ | `max_height` | `string` | `"200px"` | Maximum textarea height |
1661
+ | `rows` | `number` | - | Number of rows (overrides min_height) |
1662
+ | `on_change` | `(output: CommandTextOutput) => void` | - | Called when content changes |
1663
+ | `on_submit` | `(output: CommandTextOutput) => void` | - | Called on Cmd/Ctrl+Enter |
1664
+ | `on_command_insert` | `(command, prefix) => void` | - | Called when command is inserted |
1665
+ | `on_command_change` | `(old, new) => void` | - | Called when command is changed via edit popover |
1666
+ | `on_command_remove` | `(command) => void` | - | Called when command is removed via edit popover |
1667
+
1668
+ ---
1669
+
1237
1670
  ## Styling
1238
1671
 
1239
1672
  Both components use Tailwind CSS and follow shadcn/ui design patterns. Make sure your project has Tailwind CSS configured with the following CSS variables: