@mideind/netskrafl-react 2.0.0 → 2.0.1

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/dist/esm/index.js CHANGED
@@ -31226,6 +31226,23 @@ const TogglerFairplay = () => {
31226
31226
  const BLANK_TILES_PER_LINE = 6;
31227
31227
  const BlankDialog = () => {
31228
31228
  // A dialog for choosing the meaning of a blank tile
31229
+ function handleKeydown(game, ev) {
31230
+ // Escape key cancels the dialog
31231
+ let { key } = ev;
31232
+ if (key === 'Escape') {
31233
+ ev.preventDefault();
31234
+ game.cancelBlankDialog();
31235
+ return;
31236
+ }
31237
+ if (key.length === 1) {
31238
+ // Check if the pressed key matches a valid letter
31239
+ key = key.toLowerCase();
31240
+ if (game.alphabet.includes(key)) {
31241
+ ev.preventDefault();
31242
+ game.placeBlank(key);
31243
+ }
31244
+ }
31245
+ }
31229
31246
  function blankLetters(game) {
31230
31247
  const legalLetters = game.alphabet;
31231
31248
  let len = legalLetters.length;
@@ -31259,6 +31276,9 @@ const BlankDialog = () => {
31259
31276
  return m('.modal-dialog', {
31260
31277
  id: 'blank-dialog',
31261
31278
  style: { visibility: 'visible' },
31279
+ tabindex: -1,
31280
+ onkeydown: (ev) => handleKeydown(game, ev),
31281
+ oncreate: (vnode) => vnode.dom.focus(),
31262
31282
  }, m('.ui-widget.ui-widget-content.ui-corner-all', { id: 'blank-form' }, [
31263
31283
  mt('p', 'Hvaða staf táknar auða flísin?'),
31264
31284
  m('.rack.blank-rack', m('table.board', { id: 'blank-meaning' }, blankLetters(game))),
@@ -40799,60 +40819,34 @@ async function main(state, container) {
40799
40819
  }
40800
40820
  return 'success';
40801
40821
  }
40822
+ function unmount(container) {
40823
+ // Unmount the Mithril UI completely
40824
+ // First unmount via m.mount to clean up Mithril's internal state
40825
+ m.mount(container, null);
40826
+ // Then clear the container to ensure a clean slate for next mount
40827
+ container.innerHTML = '';
40828
+ }
40802
40829
 
40803
- const mountForUser = async (state) => {
40804
- // Return a DOM tree containing a mounted Netskrafl UI
40805
- // for the user specified in the state object
40830
+ const mountForUser = (state, container) => {
40831
+ // Mount a Netskrafl UI directly into the container
40806
40832
  const { userEmail } = state;
40807
40833
  if (!userEmail) {
40808
- // console.error("No user specified for Netskrafl UI");
40809
- throw new Error('No user specified for Netskrafl UI');
40810
- }
40811
- // Check whether we already have a mounted UI for this user
40812
- const elemId = `netskrafl-user-${userEmail}`;
40813
- const existing = document.getElementById(elemId);
40814
- if (existing) {
40815
- // console.log("Netskrafl UI already mounted for user", userEmail);
40816
- return existing;
40834
+ return Promise.reject(new Error('No user specified for Netskrafl UI'));
40817
40835
  }
40818
- // Create a new div element to hold the UI
40819
- const root = document.createElement('div');
40820
- root.id = elemId;
40821
- root.className = 'netskrafl-loading';
40822
- // Attach the partially-mounted div to the document body
40823
- // as a placeholder while the UI is being mounted
40824
- document.body.appendChild(root);
40825
- const loginResult = await main(state, root);
40826
- if (loginResult === 'success') {
40827
- // The UI was successfully mounted
40828
- root.className = 'netskrafl-user';
40829
- return root;
40830
- }
40831
- // console.error("Failed to mount Netskrafl UI for user", userEmail);
40832
- throw new Error('Failed to mount Netskrafl UI');
40836
+ return main(state, container).then((loginResult) => {
40837
+ if (loginResult !== 'success') {
40838
+ throw new Error('Failed to mount Netskrafl UI');
40839
+ }
40840
+ });
40833
40841
  };
40834
40842
  const NetskraflImpl = ({ state, tokenExpired }) => {
40835
- const ref = React.createRef();
40843
+ const ref = React.useRef(null);
40844
+ const mountedRef = React.useRef(false);
40836
40845
  const completeState = makeGlobalState({ ...state, tokenExpired });
40837
40846
  const { userEmail } = completeState;
40838
- /*
40839
- useEffect(() => {
40840
- // Check whether the stylesheet is already present
40841
- if (document.getElementById(CSS_LINK_ID)) return;
40842
- // Load and link the stylesheet into the document head
40843
- const link = document.createElement("link");
40844
- const styleUrl = `${window.location.origin}/static/css/netskrafl.css`;
40845
- link.id = CSS_LINK_ID;
40846
- link.rel = "stylesheet";
40847
- link.type = "text/css";
40848
- link.href = styleUrl;
40849
- document.head.appendChild(link);
40850
- // We don't bother to remove the stylesheet when the component is unmounted
40851
- }, []);
40852
- */
40853
40847
  // biome-ignore lint/correctness/useExhaustiveDependencies: The dependency is only on userEmail
40854
40848
  useEffect(() => {
40855
- // Load the Netskrafl (Mithril) UI for a new user
40849
+ // Mount the Netskrafl (Mithril) UI for the current user
40856
40850
  if (!userEmail)
40857
40851
  return;
40858
40852
  const container = ref.current;
@@ -40860,36 +40854,19 @@ const NetskraflImpl = ({ state, tokenExpired }) => {
40860
40854
  console.error('No container for Netskrafl UI');
40861
40855
  return;
40862
40856
  }
40863
- const elemId = `netskrafl-user-${userEmail}`;
40864
- if (container.firstElementChild?.id === elemId) {
40865
- // The Netskrafl UI is already correctly mounted
40866
- return;
40867
- }
40868
- try {
40869
- mountForUser(completeState).then((div) => {
40870
- // Attach the div as a child of the container
40871
- // instead of any previous children
40872
- const container = ref.current;
40873
- if (container) {
40874
- container.innerHTML = '';
40875
- container.appendChild(div);
40876
- }
40877
- });
40878
- }
40879
- catch (_) {
40880
- console.error('Failed to mount Netskrafl UI for user', userEmail);
40881
- const container = document.getElementById('netskrafl-container');
40882
- if (container)
40883
- container.innerHTML = '';
40884
- }
40857
+ // Mount Mithril directly into the container
40858
+ mountForUser(completeState, container)
40859
+ .then(() => {
40860
+ mountedRef.current = true;
40861
+ })
40862
+ .catch((error) => {
40863
+ console.error('Failed to mount Netskrafl UI:', error);
40864
+ });
40885
40865
  return () => {
40886
- // Move the Netskrafl UI to a hidden div under the body element
40887
- // when the component is unmounted
40888
- // console.log("Dismounting Netskrafl UI for user", userEmail);
40889
- const container = document.getElementById('netskrafl-container');
40890
- const div = container?.firstElementChild;
40891
- if (div?.id === elemId) {
40892
- document.body.appendChild(div);
40866
+ // Only unmount if mounting actually succeeded
40867
+ if (mountedRef.current) {
40868
+ unmount(container);
40869
+ mountedRef.current = false;
40893
40870
  }
40894
40871
  };
40895
40872
  }, [userEmail]);