import type { Meta, StoryObj } from '@storybook/html'; import { SmsEditor, type SmsEditorOptions } from '@42/core/sms-editor'; import { Picker } from 'emoji-mart'; import '@42/styles/sms-editor.css'; /** Default emoji set — swap this array (or plug a 3rd-party picker) to change it. */ const DEFAULT_EMOJIS = ['😀', '😂', '❤️', '🔥', '👍', '🎉', '🚀', '✨', '💯', '🙌', '👏', '😎']; const HTML = `
0 chars 0 segment(s) GSM-7
`; /** Build a simple inline emoji grid from a customizable list. */ function gridPicker(emojis: string[]) { return (container: HTMLElement, insert: (emoji: string) => void): void => { container.classList.add('c42-sms-editor-panel--grid'); container.innerHTML = emojis .map((e) => ``) .join(''); container.addEventListener('click', (ev) => { const btn = (ev.target as HTMLElement).closest('button'); if (btn) insert(btn.textContent!); }); }; } const meta: Meta = { title: 'Core/Inputs & Forms/SmsEditor', tags: ['autodocs'], argTypes: { maxSegments: { control: { type: 'number', min: 1, max: 10 } }, }, args: {}, }; export default meta; type Story = StoryObj; /** * Live encoding + segment counting, with the emoji picker anchored bottom-right * (closed until you tap 🙂). Add an emoji to flip GSM-7 → UCS-2. */ export const Default: Story = { render: (args) => { const wrapper = document.createElement('div'); wrapper.innerHTML = HTML; const root = wrapper.querySelector('[data-c42-sms-editor]')!; new SmsEditor(root, { ...args, renderPicker: gridPicker(DEFAULT_EMOJIS) }); return wrapper; }, }; /** * ## Custom emoji set * * The emoji selection is fully user-controlled — pass any list (or a 3rd-party * picker) through `renderPicker`. Note: any emoji forces UCS-2 encoding. */ export const CustomEmojiSet: Story = { render: (args) => { const wrapper = document.createElement('div'); wrapper.innerHTML = HTML; const root = wrapper.querySelector('[data-c42-sms-editor]')!; const business = ['🥳', '🤝', '📦', '⏰', '✅', '❌', '💳', '📍', '📞', '⭐']; new SmsEditor(root, { ...args, renderPicker: gridPicker(business) }); return wrapper; }, }; /** With a 1-segment limit: typing past 160 GSM-7 chars flags `data-over-limit`. */ export const SingleSegmentLimit: Story = { render: (args) => { const wrapper = document.createElement('div'); wrapper.innerHTML = HTML; const root = wrapper.querySelector('[data-c42-sms-editor]')!; new SmsEditor(root, { ...args, maxSegments: 1, renderPicker: gridPicker(DEFAULT_EMOJIS) }); return wrapper; }, args: { maxSegments: 1 }, }; /** * ## Device preview (opt-in) * * Add a `[data-c42-sms-preview]` element (the controller fills it with the live, * escaped message text) and wrap it in `.c42-sms-editor-device` to render it on * an iPhone header background (the image ships with `@42/styles`). Entirely * optional — omit the wrapper for a plain bubble, or omit the preview element * entirely to keep the editor counters-only. Positioning is tunable via CSS * custom properties (`--c42-sms-device-pad-top`, `--c42-sms-device-pad-x`). * * ```html *
*
*
* ``` */ export const DevicePreview: Story = { render: (args) => { const wrapper = document.createElement('div'); wrapper.innerHTML = `
0 chars 0 segment(s) GSM-7
`; const root = wrapper.querySelector('[data-c42-sms-editor]')!; new SmsEditor(root, { ...args, value: 'Your code is 4242. It expires in 10 minutes.', emojis: false, }); return wrapper; }, }; /** * ## With emoji-mart (external plugin) * * `emoji-mart` is not bundled with `@42/core`. Install it separately and mount * it through `renderPicker`. Inserting any emoji forces UCS-2 encoding (watch * the segment count drop from 160 → 70). * * ```bash * pnpm add emoji-mart @emoji-mart/data * ``` */ export const WithEmojiMart: Story = { render: (args) => { const wrapper = document.createElement('div'); wrapper.innerHTML = `

Note: emoji-mart is not part of @42/core. Install separately: pnpm add emoji-mart @emoji-mart/data

${HTML}`; const root = wrapper.querySelector('[data-c42-sms-editor]')!; new SmsEditor(root, { ...args, renderPicker: (container, insert) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any new (Picker as any)({ parent: container, onEmojiSelect: (emoji: { native: string }) => insert(emoji.native), theme: 'light', previewPosition: 'none', searchPosition: 'none', data: async () => { const res = await fetch('https://cdn.jsdelivr.net/npm/@emoji-mart/data'); return res.json(); }, }); }, }); return wrapper; }, };