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