FluentPanel.jsx (3479B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // eslint-disable-next-line no-unused-vars 6 import React, { useEffect, useState } from "react"; 7 import { addons, useGlobals, useStorybookApi } from "@storybook/manager-api"; 8 // eslint-disable-next-line no-unused-vars 9 import { AddonPanel, Table, Form } from "@storybook/components"; 10 import { FLUENT_CHANGED, FLUENT_SET_STRINGS } from "./constants.mjs"; 11 // eslint-disable-next-line import/no-unassigned-import 12 import "./fluent-panel.css"; 13 14 export const FluentPanel = ({ active }) => { 15 const [fileName, setFileName] = useState(null); 16 const [strings, setStrings] = useState([]); 17 const [{ fluentStrings }, updateGlobals] = useGlobals(); 18 const channel = addons.getChannel(); 19 const api = useStorybookApi(); 20 21 useEffect(() => { 22 channel.on(FLUENT_CHANGED, handleFluentChanged); 23 return () => { 24 channel.off(FLUENT_CHANGED, handleFluentChanged); 25 }; 26 }, [channel]); 27 28 const handleFluentChanged = (nextStrings, fluentFile) => { 29 setFileName(fluentFile); 30 setStrings(nextStrings); 31 }; 32 33 const onInput = e => { 34 let nextStrings = []; 35 for (let [key, value] of strings) { 36 if (key == e.target.name) { 37 let stringValue = e.target.value; 38 if (stringValue.startsWith(".")) { 39 stringValue = "\n" + stringValue; 40 } 41 nextStrings.push([key, stringValue]); 42 } else { 43 nextStrings.push([key, value]); 44 } 45 } 46 let stringified = nextStrings 47 .map(([key, value]) => `${key} = ${value}`) 48 .join("\n"); 49 channel.emit(FLUENT_SET_STRINGS, stringified); 50 updateGlobals({ 51 fluentStrings: { ...fluentStrings, [fileName]: nextStrings }, 52 }); 53 return { fileName, strings }; 54 }; 55 56 const addonTemplate = () => { 57 if (strings.length === 0) { 58 return ( 59 <AddonPanel active={!!active} api={api}> 60 <div className="addon-panel-body"> 61 <div className="addon-panel-message"> 62 This story is not configured to use Fluent. 63 </div> 64 </div> 65 </AddonPanel> 66 ); 67 } 68 69 return ( 70 <AddonPanel active={!!active} api={api}> 71 <div className="addon-panel-body"> 72 <Table aria-hidden="false" className="addon-panel-table"> 73 <thead className="addon-panel-table-head"> 74 <tr> 75 <th> 76 <span>Identifier</span> 77 </th> 78 <th> 79 <span>String</span> 80 </th> 81 </tr> 82 </thead> 83 <tbody className="addon-panel-table-body"> 84 {strings.map(([identifier, value]) => ( 85 <tr key={identifier}> 86 <td> 87 <span>{identifier}</span> 88 </td> 89 <td> 90 <Form.Textarea 91 name={identifier} 92 onInput={onInput} 93 defaultValue={value 94 .trim() 95 .split("\n") 96 .map(s => s.trim()) 97 .join("\n")} 98 ></Form.Textarea> 99 </td> 100 </tr> 101 ))} 102 </tbody> 103 </Table> 104 </div> 105 </AddonPanel> 106 ); 107 }; 108 109 return addonTemplate(); 110 };