@bottom-sheet/state-machine
Version:
The bottom-sheet brains, built on xstate
1 lines • 16.5 kB
Source Map (JSON)
{"mappings":";AAiBA,OAAO,MAAM,kCAAmC,aAAa,oFAqBzD,CAAA;AAEJ,OAAO,MAAM,wCAAyC,gBAAgB,oFA2BlE,CAAA;AAEJ,kCACE,KAAK,EAAE,MAAM,GAAG,UAAU,EAC1B,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CAcV;AAMD,yCACE,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,UAAU,GACrB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAiBjD;AACD,OAAO,MAAM,wFAGZ,CAAA;AAED,kCACE,EACE,SAAS,EACT,YAAY,EACZ,YAAY,GACb,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,GAAG,cAAc,GAAG,cAAc,CAAC,EAC1E,SAAS,SAAK,UAGf;AAED,kCACE,EACE,SAAS,EACT,YAAY,EACZ,aAAa,EACb,YAAY,GACb,EAAE,IAAI,CACL,kBAAkB,EAClB,WAAW,GAAG,cAAc,GAAG,eAAe,GAAG,cAAc,CAChE,EACD,SAAS,CAAC,EAAE,MAAM,UASnB;AAED,OAAO,MAAM,mBAAmB,aAE/B,CAAA;AAED,OAAO,MAAM,sBAAsB,gBAKlC,CAAA;AErID,+BACI;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAGhB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,GAC3B;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAA;AAEpE;IAGE,MAAM,EAAE,MAAM,CAAA;IAGd,aAAa,EAAE,MAAM,CAAA;IAGrB,UAAU,EAAE,MAAM,EAAE,CAAA;IAEpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAKzB,UAAU,EAAE,MAAM,CAAA;IAKlB,UAAU,EAAE,MAAM,CAAA;IAElB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAI3B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,OAAO,MAAM;;;2NAuSV,CAAA","sources":["src/src/utils.ts","src/src/index.typegen.ts","src/src/index.ts","src/index.ts"],"sourcesContent":[null,null,null,"import type { SnapPoints } from '@bottom-sheet/types'\nimport { assign, createMachine } from 'xstate'\n\nimport {\n addDescription,\n assignInitialHeight,\n assignSnapPoints,\n computeMaxContent,\n computeMinContent,\n computeSnapPointBounds,\n computeSnapPoints,\n defaultInitialHeight,\n defaultSnapPoints,\n} from './utils'\n\nexport {\n assignInitialHeight,\n assignSnapPoints,\n computeMaxContent,\n computeMinContent,\n computeSnapPointBounds,\n computeSnapPoints,\n defaultInitialHeight,\n defaultSnapPoints,\n}\n\nexport type BottomSheetEvent =\n | { type: 'OPEN' }\n // @TODO: implement support for an initally open state that doesn't animate from a closed position\n // | { type: 'INITIALLY_OPEN' }\n | { type: 'AUTOFOCUS' }\n | { type: 'TRANSITION_OPEN' }\n | { type: 'OPENED' }\n | { type: 'RESIZE'; payload: { height: number } }\n | { type: 'RESIZED' }\n | { type: 'SNAP'; payload: { height: number } }\n | { type: 'SNAPPED' }\n | { type: 'DRAG' }\n | { type: 'TRANSITION_DRAG'; payload: { height: number } }\n | { type: 'DRAGGED' }\n | { type: 'CLOSE' }\n | { type: 'CLOSED' }\n | { type: 'SET_MAX_HEIGHT'; payload: { maxHeight: number } }\n | { type: 'SET_HEADER_HEIGHT'; payload: { headerHeight: number } }\n | { type: 'SET_CONTENT_HEIGHT'; payload: { contentHeight: number } }\n | { type: 'SET_FOOTER_HEIGHT'; payload: { footerHeight: number } }\n\nexport interface BottomSheetContext {\n // basically the \"current snap point\"\n // input: SET_HEIGHT, payload number, selects nearest snap point, is zero while 'closed' and 'opening.waiting', non-zero after 'opening.waiting.leave'\n height: number\n // used to set the context.height when moving from 'closed' to 'open', when 'open.closing' to 'open.opening' 'context.height' stays the same instead of setting to 'context.initialHeight'\n // input: SET_INITIAL_HEIGHT, number, calls userland method that needs snapPoints, lastHeight, and the same input as snapPoints\n initialHeight: number\n // super important, used all the time, should be a normalized array resulting from the snapPoints prop\n // input: SET_SNAP_POINTS, number[], calls userland method that needs headerHeight, contentHeight, footerHeight, minContent, maxContent, maxHeight,\n snapPoints: number[]\n // The last snap point the sheet was rendered in, or null if it haven't been opened yet. DRAG, OPEN, RESIZE, SNAP writes to this value, its purpose is to allow userland initialHeight to restore the previous height.\n lastHeight: number | null\n // The intrinsic preferred height to show as much of the content as possible.\n // Always less than or equal to maxHeight, similar to CSS max-content\n // Calculated as: Math.min(maxHeight, headerHeight + contentHeight + footerHeight)\n // Never equal to or lower than zero\n maxContent: number\n // Consider specific variants: lastDragHeight, lastSnapHeight, lastResizeHeight, and lastOpenHeight\n // Smallest possible height, like CSS min-content\n // Calculated as: Math.min(maxHeight, Math.max(headerHeight + footerHeight, 50))\n // It's never lower than 50, even if there is no header, content or footer elements, as 50 is considered the smallest usable tap target size\n minContent: number\n // null if there is no header element to measure, 0 if it exists but have no height\n headerHeight: number | null\n contentHeight: number | null\n footerHeight: number | null\n // Usually matches window.innerHeight, but can be a userland prop value\n // Never equal to or lower than zero\n // Consider capping it to 50 for the same reasons as minContent? As weird things happen when smaller than 50\n maxHeight: number\n}\n\nexport const BottomSheetMachine =\n /** @xstate-layout N4IgpgJg5mDOIC5QGUAWYwBcB0BjANgPayQDEA8gAoCiAcoqAA7ECWmLhAdgyAB6IBGAJwB2bABZxQgEwCRABnnShkgKyqANCACeg+aoBs2AeJGmF06fIP6Avra1oMOAsTIBJWu4Aq7gIIAMgEAmgD6VHQ8zLBsHNxIfIICAMzYZoryIqri0qq50lq6CAICAByq2EJCAjbWyWUC8qX2juhY2ISMYJzYLJyxAIb4+NqkAErUfgAiwVGs7Fw8-AiqyRXJ4gbJBiJlKiIbhYiWm9irWSK51aUC0i0gTu2d3R1d-ZxQ2ADuA7Ef45MZnMYgt4qBlqUhPJsJDktI4ZDbiJSqUjghqhUDAJsupdslkkJSsl7o8cM8euS+p8fn8oKQ-ABVbzkABi5AAwgzkMDYosEhCoTChHCEdVpMjUTpECJqsYrIp8dJNkS7g4Hm0yW9Xt0qdgBgBXTCEABmhFw+pi-wm01mCWivLBiWKsiM0iJN2xyVKIhsyTRMoEcoyiuVcJJGu1FLeuoG-QAtgN2P8IrRqFMeaClohxKs0iIDuITHsZAY0WVxNDMqJbpYhKpLgZw85I5GY-HE1TSFMxn4AOIZuJZ4p5aGrVQpNaNAySNEGGQwsxzgyIpr4ptPLWUj569tJunIWh+SgDvng7NbPMFouQktlr2Yr1VKRNTb19eal4AJzge67Pf7drzIO-KIFs4iVMulzyGUBiwViZZQWcKImNB9a3Js74tt+sC-hMyDuAAWtQJ6OssOapPmV6Fje0illKxR1kIZy7G64jJEoHGNmqpJYT+nYHkeJFDlC4GmASWRNGYCh0UUwg1DCUi0ViAYlKomHktgECfgMUBQJ23Z9r2aZCSBCBgRB3pWDBcECGWOzSNgNjjgSTlKsS3ERhpWk6Xp-wCcegEgsBZ5mUqFlQdZsG2fRNRhQYlgpFCqzbNi6lathLAAF6dnhhHGYFDpDoWFH5hs15VLRaJWDK2DWG6hjJGYypqR5zYaRl2V+YeAVMEBp5OhWJVUcWlX0bI4q1ZsGTjsK04ta0bXpXAWX6f+JkhdijRnJO+LjtYM70cKgblKVSmPmurUbi8sCcAMjCMPx3U0OmBWZqZIkSAcoiqJJpjWGWQjTjCcKFvIIOKJcaXXbd92rX261Oli4GA5Z0GlHB8ExT9FQpPIUjjqUkh1FDPSuJadLsgE5DIPlvVBf1yzCGIkgyHIijKGomj0ZIqTo1WKOA8i7kLVdpNEOTFA0PQr3BYjtHYMoYNEviMiWf6c5yjmDU4pc4gk6QlPU8RMsM4gXpDWV1EVTJ0o2JUqjCmY5SK4D76kDT3ihAAsn4AAaoQABLUO4vYB94CPLMiFRWKIaNiuUVWXJUSg5HCNSxYYbse4HgLUGMOch2HEfSrsjmqKU8LsSqpVluUlQbCoyGZBJeuXZg7vUJ77LkLQ3h0J7QeF+HJukbbFTjoY4qNW5QhooSEFSUTqzenkWed6EbLkH3+eD6Hw904Vpn5oGWK0Zs2wE-iZaqmqnCEBAcA8DxZOQMXCCmGikilDC2RYhi1W5GFuqRaLw+iDGGEUA+b0QoEm-pRS2I0bYIBOKOfEBh6z6E2HIEmrZtw0j3G-LIDktibXkFUNY9YCj0RlKkN0twyi7HUFOHBW5PgGiNKac05M36NEasYSebFyilEyJKIoUdjA1EyNBfMKcWHRm3LGFgCYCEjyHCkMojkTDl3KIWZQ8J-QqAkVrKw4gUSCLkTqD4hC3SOXqHtchuIqFiNuHKZy5QNj5kJjg7CKioGy0jvFSokJy4Bi2FkAG44JCCx+qYH66CcHeV0lSN+OY4GlULFbW8MUFDQi9HOJKEk5zNDbrxGInUoBvwJBbDJiCyx4yYtOG4f1aJeiUDgm6d0HpWNUaZXhYhtg5hUHWMG7EuayShK6MwhgK6pOyDgsmySekhVMczG4QsvS5GXAdMR2R7a-29IScUqoRYfkdPaaBTo1hMXgTUmiSCbBiBRI1dBSonnInfG-fR9FGrQnRoSZceMzBwh9PYewQA */\n createMachine(\n {\n context: {\n height: 0,\n initialHeight: 0,\n snapPoints: [],\n lastHeight: null,\n maxContent: 0,\n minContent: 0,\n headerHeight: null,\n contentHeight: null,\n footerHeight: null,\n maxHeight: 0,\n },\n tsTypes: {} as import('./index.typegen').Typegen0,\n schema: {\n context: {} as BottomSheetContext,\n events: {} as BottomSheetEvent,\n },\n preserveActionOrder: true,\n id: 'bs',\n initial: 'closed',\n states: {\n closed: {\n on: {\n OPEN: {\n actions: [\n 'setMinContent',\n 'setMaxContent',\n 'setSnapPoints',\n 'setInitialHeight',\n ],\n target: 'open',\n },\n },\n },\n open: {\n initial: 'opening',\n states: {\n opening: {\n initial: 'waiting',\n states: {\n waiting: {\n exit: 'setHeight',\n on: {\n TRANSITION_OPEN: {\n target: 'transition',\n },\n AUTOFOCUS: {\n target: 'autofocusing',\n },\n },\n },\n autofocusing: {\n exit: 'setLastHeight',\n on: {\n TRANSITION_OPEN: {\n target: 'transition',\n },\n },\n },\n transition: {\n exit: 'setLastHeight',\n on: {\n OPENED: {\n target: '#bs.open.resting',\n },\n DRAG: {\n ...addDescription('redirect'),\n target: '#bs.open.dragging',\n },\n SNAP: {\n ...addDescription('redirect'),\n target: '#bs.open.snapping',\n },\n },\n },\n },\n },\n resting: {\n on: {\n DRAG: {\n target: 'dragging',\n },\n RESIZE: {\n target: 'resizing',\n },\n SNAP: {\n target: 'snapping',\n },\n },\n },\n dragging: {\n initial: 'gesture',\n states: {\n gesture: {\n on: {\n TRANSITION_DRAG: {\n target: 'transition',\n },\n },\n },\n transition: {\n entry: 'setHeight',\n exit: 'setLastHeight',\n on: {\n DRAGGED: {\n target: '#bs.open.resting',\n },\n },\n },\n },\n on: {\n SNAP: {\n ...addDescription('redirect'),\n target: 'snapping',\n },\n },\n },\n resizing: {\n entry: 'setHeight',\n exit: 'setLastHeight',\n on: {\n RESIZED: {\n target: 'resting',\n },\n SNAP: {\n ...addDescription('redirect'),\n target: 'snapping',\n },\n DRAG: {\n ...addDescription('redirect'),\n target: 'dragging',\n },\n },\n },\n snapping: {\n entry: 'setHeight',\n exit: 'setLastHeight',\n on: {\n SNAPPED: {\n target: 'resting',\n },\n DRAG: {\n ...addDescription('redirect'),\n target: 'dragging',\n },\n },\n },\n closing: {\n entry: 'setHeight',\n exit: 'setLastHeight',\n on: {\n CLOSED: {\n target: '#bs.closed',\n },\n OPEN: {\n ...addDescription('redirect'),\n target: 'opening',\n },\n },\n },\n },\n on: {\n CLOSE: {\n target: '.closing',\n },\n },\n },\n },\n on: {\n SET_MAX_HEIGHT: {\n actions: [\n 'setMaxHeight',\n 'setMinContent',\n 'setMaxContent',\n 'setSnapPoints',\n 'setInitialHeight',\n 'setHeight',\n ],\n },\n SET_HEADER_HEIGHT: {\n actions: [\n 'setHeaderHeight',\n 'setMinContent',\n 'setMaxContent',\n 'setSnapPoints',\n 'setInitialHeight',\n 'setHeight',\n ],\n },\n SET_CONTENT_HEIGHT: {\n actions: [\n 'setContentHeight',\n 'setMaxContent',\n 'setSnapPoints',\n 'setInitialHeight',\n 'setHeight',\n ],\n },\n SET_FOOTER_HEIGHT: {\n actions: [\n 'setFooterHeight',\n 'setMinContent',\n 'setMaxContent',\n 'setSnapPoints',\n 'setInitialHeight',\n 'setHeight',\n ],\n },\n },\n },\n {\n actions: {\n setMaxHeight: assign({\n maxHeight: (context, event) => {\n if (event.type !== 'SET_MAX_HEIGHT') return\n return event.payload.maxHeight\n },\n }),\n setHeaderHeight: assign({\n headerHeight: (context, event) => {\n if (event.type !== 'SET_HEADER_HEIGHT') return\n return event.payload.headerHeight\n },\n }),\n setContentHeight: assign({\n contentHeight: (context, event) => {\n if (event.type !== 'SET_CONTENT_HEIGHT') return\n return event.payload.contentHeight\n },\n }),\n setFooterHeight: assign({\n footerHeight: (context, event) => {\n if (event.type !== 'SET_FOOTER_HEIGHT') return\n return event.payload.footerHeight\n },\n }),\n setMinContent: assign({\n minContent: ({ maxHeight, headerHeight, footerHeight }) =>\n computeMinContent({ maxHeight, headerHeight, footerHeight }),\n }),\n setMaxContent: assign({\n maxContent: ({\n maxHeight,\n headerHeight,\n contentHeight,\n footerHeight,\n }) =>\n computeMaxContent({\n maxHeight,\n headerHeight,\n contentHeight,\n footerHeight,\n }),\n }),\n setSnapPoints: assignSnapPoints(defaultSnapPoints),\n setInitialHeight: assignInitialHeight(defaultInitialHeight),\n setHeight: assign({\n height: (context, event) => {\n const { snapPoints } = context\n switch (event.type) {\n case 'CLOSE':\n return 0\n case 'TRANSITION_DRAG':\n case 'RESIZE':\n case 'SNAP':\n return snapPoints.length < 1\n ? 0\n : computeSnapPointBounds(\n event.payload.height,\n snapPoints as SnapPoints\n )[0]\n case 'SET_MAX_HEIGHT':\n case 'SET_HEADER_HEIGHT':\n case 'SET_CONTENT_HEIGHT':\n case 'SET_FOOTER_HEIGHT':\n return context.height < 1\n ? 0\n : computeSnapPointBounds(\n context.height,\n snapPoints as SnapPoints\n )[0]\n default:\n return context.initialHeight\n }\n },\n }),\n setLastHeight: assign({\n lastHeight: (context) => context.height || context.lastHeight,\n }),\n },\n }\n )\n"],"names":[],"version":3,"file":"index.d.ts.map"}