Repository: toeverything/AFFiNE
File: blocksuite/affine/widgets/toolbar/src/toolbar.ts (TypeScript)

Code before:

          sideOptions$.value = null;
          flavour$.value = flavour;
          placement$.value = toolbarRegistry.getModulePlacement(flavour);
          flags.refresh(Flag.Hovering);
        });
      })
    );

    // Updates toolbar theme when `app-theme` changing
    disposables.add(
      context.theme.app$.subscribe(theme => {
        toolbar.dataset.appTheme = theme;
      })
    );

    // Updates layout when placement changing to `inner`
    disposables.add(
      effect(() => {
        toolbar.dataset.placement = placement$.value;
      })
    );

    // Clears selection when switching doc mode
    disposables.add(
      context.docModeProvider.onPrimaryModeChange(() => {
        if (context.readonly) return;
        std.selection.clear();
      }, std.store.id)
    );

    disposables.add(
      effect(() => {
        const value = flags.value$.value;

        // Hides toolbar
        if (Flag.None === value || flags.check(Flag.Hiding, value)) {
          if (toolbar.dataset.open) delete toolbar.dataset.open;
          // Closes dropdown menus
          toolbar
            .querySelector<EditorMenuButton>('editor-menu-button[data-open]')
            ?.hide();
          return;
        }

        const flavour = flavour$.value;

        // Shows toolbar
        // 1. `Flag.Text`: formatting in note
        // 2. `Flag.Native`: formating in database/table
        // 3. `Flag.Block`: blocks in note

Review comment (suggestion):
I think we shouldn't watch and clear the selection on toolbar widget. you should create a new life cycle extension to do that. And the extension should be in `shared/services` instead of toolbar widget.

Code after:

          sideOptions$.value = null;
          flavour$.value = flavour;
          placement$.value = toolbarRegistry.getModulePlacement(flavour);
          flags.refresh(Flag.Hovering);
        });
      })
    );

    // Updates toolbar theme when `app-theme` changing
    disposables.add(
      context.theme.app$.subscribe(theme => {
        toolbar.dataset.appTheme = theme;
      })
    );

    // Updates layout when placement changing to `inner`
    disposables.add(
      effect(() => {
        toolbar.dataset.placement = placement$.value;
      })
    );

    disposables.add(
      effect(() => {
        const value = flags.value$.value;

        // Hides toolbar
        if (Flag.None === value || flags.check(Flag.Hiding, value)) {
          if (toolbar.dataset.open) delete toolbar.dataset.open;
          // Closes dropdown menus
          toolbar
            .querySelector<EditorMenuButton>('editor-menu-button[data-open]')
            ?.hide();
          return;
        }

        const flavour = flavour$.value;

        // Shows toolbar
        // 1. `Flag.Text`: formatting in note
        // 2. `Flag.Native`: formating in database/table
        // 3. `Flag.Block`: blocks in note
        // 4. `Flag.Hovering`: inline links in note/database/table
        // 5. `Flag.Surface`: elements in edgeless
        renderToolbar(toolbar, context, flavour);
      })
    );

    let abortController = new AbortController();