hunk.code_window:   fontWeight: '600',
     display: 'flex',
     alignItems: 'center',
     justifyContent: 'center',
     height: '22px',
     marginLeft: '10px',
     marginRight: '10px',
   });
   export const popperStyle = style({
     boxShadow: 'var(--affine-shadow-2)',
     padding: '0 10px',
  
hunk.labels: keep keep keep keep keep replace replace keep keep keep keep
hunk.after_edit:   textAlign: 'center',
     ':hover': {
       background: 'var(--affine-hover-color)',
       borderRadius: '4px',
     },
  
hunk.file_path: packages/component/src/components/date-picker/index.css.ts
hunk.type: replace
file: /**
   * @vitest-environment happy-dom
   */
  import 'fake-indexeddb/auto';
  
  import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
  import type { Page } from '@blocksuite/store';
  import { assertExists, uuidv4, Workspace } from '@blocksuite/store';
  import { openDB } from 'idb';
  import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
  import { IndexeddbPersistence } from 'y-indexeddb';
  import { applyUpdate, Doc, encodeStateAsUpdate } from 'yjs';
  
  import type { WorkspacePersist } from '../index';
  import {
    CleanupWhenConnectingError,
    createIndexedDBProvider,
    dbVersion,
    DEFAULT_DB_NAME,
    downloadBinary,
    getMilestones,
    markMilestone,
    revertUpdate,
    setMergeCount,
  } from '../index';
  
  function initEmptyPage(page: Page) {
    const pageBlockId = page.addBlock('affine:page', {
      title: new page.Text(''),
    });
    const surfaceBlockId = page.addBlock('affine:surface', {}, pageBlockId);
    const frameBlockId = page.addBlock('affine:note', {}, pageBlockId);
    const paragraphBlockId = page.addBlock('affine:paragraph', {}, frameBlockId);
    return {
      pageBlockId,
      surfaceBlockId,
      frameBlockId,
      paragraphBlockId,
    };
  }
  
  async function getUpdates(id: string): Promise<Uint8Array[]> {
    const db = await openDB(rootDBName, dbVersion);
    const store = await db
      .transaction('workspace', 'readonly')
      .objectStore('workspace');
    const data = (await store.get(id)) as WorkspacePersist | undefined;
    assertExists(data, 'data should not be undefined');
    expect(data.id).toBe(id);
    return data.updates.map(({ update }) => update);
  }
  
  let id: string;
  let workspace: Workspace;
  const rootDBName = DEFAULT_DB_NAME;
  
  beforeEach(() => {
    id = uuidv4();
    workspace = new Workspace({
      id,
      isSSR: true,
    });
    workspace.register(AffineSchemas).register(__unstableSchemas);
  });
  
  afterEach(() => {
    indexedDB.deleteDatabase('affine-local');
    localStorage.clear();
  });
  
  describe('indexeddb provider', () => {
    test('connect', async () => {
      const provider = createIndexedDBProvider(workspace.doc);
      provider.connect();
      await provider.whenSynced;
      const db = await openDB(rootDBName, dbVersion);
      {
        const store = db
          .transaction('workspace', 'readonly')
          .objectStore('workspace');
        const data = await store.get(id);
        expect(data).toEqual({
          id,
          updates: [
            {
              timestamp: expect.any(Number),
              update: encodeStateAsUpdate(workspace.doc),
            },
          ],
        });
        const page = workspace.createPage({ id: 'page0' });
        await page.waitForLoaded();
        const pageBlockId = page.addBlock('affine:page', { title: '' });
        const frameId = page.addBlock('affine:note', {}, pageBlockId);
        page.addBlock('affine:paragraph', {}, frameId);
      }
      await new Promise(resolve => setTimeout(resolve, 1000));
      {
        const store = await db
          .transaction('workspace', 'readonly')
          .objectStore('workspace');
        const data = (await store.get(id)) as WorkspacePersist | undefined;
        assertExists(data);
        expect(data.id).toBe(id);
        const testWorkspace = new Workspace({
          id: 'test',
        })
          .register(AffineSchemas)
          .register(__unstableSchemas);
        // data should only contain updates for the root doc
        data.updates.forEach(({ update }) => {
          Workspace.Y.applyUpdate(testWorkspace.doc, update);
        });
        const subPage = testWorkspace.doc.spaces.get('space:page0');
        {
          assertExists(subPage);
          await store.get(subPage.guid);
          const data = (await store.get(subPage.guid)) as
            | WorkspacePersist
            | undefined;
          assertExists(data);
          await testWorkspace.getPage('page0')?.waitForLoaded();
          data.updates.forEach(({ update }) => {
            Workspace.Y.applyUpdate(subPage, update);
          });
        }
        expect(workspace.doc.toJSON()).toEqual(testWorkspace.doc.toJSON());
      }
    });
  
    test('disconnect suddenly', async () => {
      const provider = createIndexedDBProvider(workspace.doc, rootDBName);
      const fn = vi.fn();
      provider.connect();
      provider.disconnect();
      expect(fn).toBeCalledTimes(0);
      await provider.whenSynced.catch(fn);
      expect(fn).toBeCalledTimes(1);
    });
  
    test('connect and disconnect', async () => {
      const provider = createIndexedDBProvider(workspace.doc, rootDBName);
      provider.connect();
      expect(provider.connected).toBe(true);
      const p1 = provider.whenSynced;
      await p1;
      const snapshot = encodeStateAsUpdate(workspace.doc);
      provider.disconnect();
      expect(provider.connected).toBe(false);
      {
        const page = workspace.createPage({ id: 'page0' });
        await page.waitForLoaded();
        const pageBlockId = page.addBlock('affine:page', { title: '' });
        const frameId = page.addBlock('affine:note', {}, pageBlockId);
        page.addBlock('affine:paragraph', {}, frameId);
      }
      {
        const updates = await getUpdates(workspace.id);
        expect(updates.length).toBe(1);
        expect(updates[0]).toEqual(snapshot);
      }
      expect(provider.connected).toBe(false);
      provider.connect();
      expect(provider.connected).toBe(true);
      const p2 = provider.whenSynced;
      await p2;
      {
        const updates = await getUpdates(workspace.id);
        expect(updates).not.toEqual([]);
      }
      expect(provider.connected).toBe(true);
      provider.disconnect();
      expect(provider.connected).toBe(false);
      expect(p1).not.toBe(p2);
    });
  
    test('cleanup', async () => {
      const provider = createIndexedDBProvider(workspace.doc);
      provider.connect();
      await provider.whenSynced;
      const db = await openDB(rootDBName, dbVersion);
  
      {
        const store = db
          .transaction('workspace', 'readonly')
          .objectStore('workspace');
        const keys = await store.getAllKeys();
        expect(keys).contain(workspace.id);
      }
  
      provider.disconnect();
      await provider.cleanup();
  
      {
        const store = db
          .transaction('workspace', 'readonly')
          .objectStore('workspace');
        const keys = await store.getAllKeys();
        expect(keys).not.contain(workspace.id);
      }
    });
  
    test('cleanup when connecting', async () => {
      const provider = createIndexedDBProvider(workspace.doc);
      provider.connect();
      await expect(() => provider.cleanup()).rejects.toThrowError(
        CleanupWhenConnectingError
      );
      await provider.whenSynced;
      provider.disconnect();
      await provider.cleanup();
    });
  
    test('merge', async () => {
      setMergeCount(5);
      const provider = createIndexedDBProvider(workspace.doc, rootDBName);
      provider.connect();
      {
        const page = workspace.createPage({ id: 'page0' });
        await page.waitForLoaded();
        const pageBlockId = page.addBlock('affine:page', { title: '' });
        const frameId = page.addBlock('affine:note', {}, pageBlockId);
        for (let i = 0; i < 99; i++) {
          page.addBlock('affine:paragraph', {}, frameId);
        }
      }
      await provider.whenSynced;
      {
        const updates = await getUpdates(id);
        expect(updates.length).lessThanOrEqual(5);
      }
    });
  
    test("data won't be lost", async () => {
      const doc = new Workspace.Y.Doc();
      const map = doc.getMap('map');
      for (let i = 0; i < 100; i++) {
        map.set(`${i}`, i);
      }
      {
        const provider = createIndexedDBProvider(doc, rootDBName);
        provider.connect();
        await provider.whenSynced;
        provider.disconnect();
      }
      {
        const newDoc = new Workspace.Y.Doc();
        const provider = createIndexedDBProvider(newDoc, rootDBName);
        provider.connect();
        await provider.whenSynced;
        provider.disconnect();
        newDoc.getMap('map').forEach((value, key) => {
          expect(value).toBe(parseInt(key));
        });
      }
    });
  
    test('migration', async () => {
      {
        const yDoc = new Doc();
        yDoc.getMap().set('foo', 'bar');
        const persistence = new IndexeddbPersistence('test', yDoc);
        await persistence.whenSynced;
        await persistence.destroy();
      }
      {
        const yDoc = new Doc({
          guid: 'test',
        });
        const provider = createIndexedDBProvider(yDoc);
        provider.connect();
        await provider.whenSynced;
        await new Promise(resolve => setTimeout(resolve, 0));
        expect(yDoc.getMap().get('foo')).toBe('bar');
      }
      localStorage.clear();
      {
        indexedDB.databases = vi.fn(async () => {
          throw new Error('not supported');
        });
        await expect(indexedDB.databases).rejects.toThrow('not supported');
        const yDoc = new Doc({
          guid: 'test',
        });
        expect(indexedDB.databases).toBeCalledTimes(1);
        const provider = createIndexedDBProvider(yDoc);
        provider.connect();
        await provider.whenSynced;
        expect(indexedDB.databases).toBeCalledTimes(2);
        expect(yDoc.getMap().get('foo')).toBe('bar');
      }
    });
  
    test('beforeunload', async () => {
      const oldAddEventListener = window.addEventListener;
      window.addEventListener = vi.fn((event: string, fn, options) => {
        expect(event).toBe('beforeunload');
        return oldAddEventListener(event, fn, options);
      });
      const oldRemoveEventListener = window.removeEventListener;
      window.removeEventListener = vi.fn((event: string, fn, options) => {
        expect(event).toBe('beforeunload');
        return oldRemoveEventListener(event, fn, options);
      });
      const doc = new Doc({
        guid: '1',
      });
      const provider = createIndexedDBProvider(doc);
      const map = doc.getMap('map');
      map.set('1', 1);
      provider.connect();
      await provider.whenSynced;
  
      expect(window.addEventListener).toBeCalledTimes(1);
      expect(window.removeEventListener).toBeCalledTimes(1);
  
      window.addEventListener = oldAddEventListener;
      window.removeEventListener = oldRemoveEventListener;
    });
  });
  
  describe('milestone', () => {
    test('milestone', async () => {
      const doc = new Doc();
      const map = doc.getMap('map');
      const array = doc.getArray('array');
      map.set('1', 1);
      array.push([1]);
      await markMilestone('1', doc, 'test1');
      const milestones = await getMilestones('1');
      assertExists(milestones);
      expect(milestones).toBeDefined();
      expect(Object.keys(milestones).length).toBe(1);
      expect(milestones.test1).toBeInstanceOf(Uint8Array);
      const snapshot = new Doc();
      applyUpdate(snapshot, milestones.test1);
      {
        const map = snapshot.getMap('map');
        expect(map.get('1')).toBe(1);
      }
      map.set('1', 2);
      {
        const map = snapshot.getMap('map');
        expect(map.get('1')).toBe(1);
      }
      revertUpdate(doc, milestones.test1, key =>
        key === 'map' ? 'Map' : 'Array'
      );
      {
        const map = doc.getMap('map');
        expect(map.get('1')).toBe(1);
      }
  
      const fn = vi.fn(() => true);
      doc.gcFilter = fn;
      expect(fn).toBeCalledTimes(0);
  
      for (let i = 0; i < 1e5; i++) {
        map.set(`${i}`, i + 1);
      }
      for (let i = 0; i < 1e5; i++) {
        map.delete(`${i}`);
      }
      for (let i = 0; i < 1e5; i++) {
        map.set(`${i}`, i - 1);
      }
  
      expect(fn).toBeCalled();
  
      const doc2 = new Doc();
      applyUpdate(doc2, encodeStateAsUpdate(doc));
  
      revertUpdate(doc2, milestones.test1, key =>
        key === 'map' ? 'Map' : 'Array'
      );
      {
        const map = doc2.getMap('map');
        expect(map.get('1')).toBe(1);
      }
    });
  });
  
  describe('subDoc', () => {
    test('basic', async () => {
      let json1: any, json2: any;
      {
        const doc = new Doc({
          guid: 'test',
        });
        const map = doc.getMap();
        const subDoc = new Doc();
        subDoc.load();
        map.set('1', subDoc);
        map.set('2', 'test');
        const provider = createIndexedDBProvider(doc);
        provider.connect();
        await provider.whenSynced;
        provider.disconnect();
        json1 = doc.toJSON();
      }
      {
        const doc = new Doc({
          guid: 'test',
        });
        const provider = createIndexedDBProvider(doc);
        provider.connect();
        await provider.whenSynced;
        const map = doc.getMap();
        const subDoc = map.get('1') as Doc;
        subDoc.load();
        provider.disconnect();
        json2 = doc.toJSON();
      }
      // the following line compares {} with {}
      expect(json1['']['1'].toJSON()).toEqual(json2['']['1'].toJSON());
      expect(json1['']['2']).toEqual(json2['']['2']);
    });
  
    test('blocksuite', async () => {
      const page0 = workspace.createPage({
        id: 'page0',
      });
      await page0.waitForLoaded();
      const { paragraphBlockId: paragraphBlockIdPage1 } = initEmptyPage(page0);
      const provider = createIndexedDBProvider(workspace.doc, rootDBName);
      provider.connect();
      const page1 = workspace.createPage({
        id: 'page1',
      });
      await page1.waitForLoaded();
      const { paragraphBlockId: paragraphBlockIdPage2 } = initEmptyPage(page1);
      await new Promise(resolve => setTimeout(resolve, 1000));
      provider.disconnect();
      {
        const newWorkspace = new Workspace({
          id,
          isSSR: true,
        });
        newWorkspace.register(AffineSchemas).register(__unstableSchemas);
        const provider = createIndexedDBProvider(newWorkspace.doc, rootDBName);
        provider.connect();
        await provider.whenSynced;
        const page0 = newWorkspace.getPage('page0') as Page;
        await page0.waitForLoaded();
        {
          const block = page0.getBlockById(paragraphBlockIdPage1);
          assertExists(block);
        }
        const page1 = newWorkspace.getPage('page1') as Page;
        await page1.waitForLoaded();
        {
          const block = page1.getBlockById(paragraphBlockIdPage2);
          assertExists(block);
        }
      }
    });
  });
  
  describe('utils', () => {
    test('download binary', async () => {
      const page = workspace.createPage({ id: 'page0' });
      await page.waitForLoaded();
      initEmptyPage(page);
      const provider = createIndexedDBProvider(workspace.doc, rootDBName);
      provider.connect();
      await provider.whenSynced;
      provider.disconnect();
      const update = (await downloadBinary(
        workspace.id,
        rootDBName
      )) as Uint8Array;
      expect(update).toBeInstanceOf(Uint8Array);
      const newWorkspace = new Workspace({
        id,
        isSSR: true,
      });
      newWorkspace.register(AffineSchemas).register(__unstableSchemas);
      applyUpdate(newWorkspace.doc, update);
      await new Promise<void>(resolve =>
        setTimeout(() => {
          expect(workspace.doc.toJSON()['meta']).toEqual(
            newWorkspace.doc.toJSON()['meta']
          );
          expect(Object.keys(workspace.doc.toJSON()['spaces'])).toEqual(
            Object.keys(newWorkspace.doc.toJSON()['spaces'])
          );
          resolve();
        }, 0)
      );
    });
  });
  